diff options
| author | root <root@elwms02.(none)> | 2010-04-06 16:13:08 +0200 |
|---|---|---|
| committer | root <root@elwms02.(none)> | 2010-04-06 16:13:08 +0200 |
| commit | 0e7005fcc7483c01aa102fbea358c5ac65a48d62 (patch) | |
| tree | 11517ce0d3d2977c6732b3aa583b0008083e0bd3 /vdr | |
| download | x-vdr-0e7005fcc7483c01aa102fbea358c5ac65a48d62.tar.gz x-vdr-0e7005fcc7483c01aa102fbea358c5ac65a48d62.tar.bz2 | |
hello world
Diffstat (limited to 'vdr')
35 files changed, 92854 insertions, 0 deletions
diff --git a/vdr/conf/_xinitrc b/vdr/conf/_xinitrc new file mode 100644 index 0000000..4d9eab0 --- /dev/null +++ b/vdr/conf/_xinitrc @@ -0,0 +1,139 @@ +#!/bin/sh +xset s off +xset -dpms + +# xvdrplayer 0.0.1 (start-script for shmclient, tvtime, vdrtvtime, vdr-sxfe, xine or xineliboutput) +# by Marc Wernecke - www.zulu-entertainment.de +# 12.02.2009 + +#VDRIP=127.0.0.1 # 127.0.0.1 for localhost or any other ip for a vdr-server in your local-network +#VDRPLAYER=xine # shmclient, tvtime, vdr-sxfe, xine, xineliboutput or xine-network +DIALOG="Xdialog" + +[ -d "$HOME" -a "$HOME" != "/" ] || HOME=/etc +[ -r $HOME/vdrplayer.conf ] && . $HOME/vdrplayer.conf + +function _vdr() { + # Max waiting time in Seconds + n=10 + # Check if VDR is running + if [ `ps -C vdr | grep -cw "vdr"` -eq 0 ]; then + # test if vdr is running + while [ `ps -C vdr | grep -cw "vdr"` -eq 0 ] && [ $n -gt 0 ]; do + sleep 1 + (( n=$n-1 )) + [ $n -eq 0 ] && return 1 + done + fi + return 0 +} + +function _vdrip() { + VDRIP=`$DIALOG --inputbox "VDR Server IP" 10 50 "127.0.0.1" 3>&1 1>&2 2>&3` + [ $? != 0 ] && return 1 + [ "$VDRIP" = "" ] && return 1 + echo "VDRIP=$VDRIP" >> $HOME/vdrplayer.conf + return 0 +} + +function _shmclient() { + CMD="--fullscreen" + ShmClient $CMD + return 0 +} + +function _tvtime() { +# chmod 666 /dev/rtc +# echo 1024 > /proc/sys/dev/rtc/max-user-freq + CMD="--fullscreen --display=$DISPLAY" + tvtime $CMD + sleep 2 + tvtime-command MENU_EXIT + return 0 +} + +function _vdrtvtime() { +# chmod 666 /dev/rtc +# echo 1024 > /proc/sys/dev/rtc/max-user-freq + svdrpsend.pl PLUG vdrtvtime start + return 0 +} + +function _vdrsxfe() { + [ -n "$VDRIP" ] || _vdrip || return 1 + CMD="--video=xv --fullscreen --post tvtime:method=LinearBlend,cheap_mode=1,pulldown=0,use_progressive_frame_flag=1" + MRL="xvdr+tcp://$VDRIP" + vdr-sxfe $CMD $MRL + return 0 +} + +function _xineliboutput() { + [ -n "$VDRIP" ] || _vdrip || return 1 + CMD="--fullscreen --hide-gui" + MRL="xvdr+tcp://$VDRIP#nocache;demux:mpeg_block" + xine $CMD "$MRL" + return 0 +} + +function _xine() { + CMD="--fullscreen --hide-gui --post vdr --post vdr_audio" + MRL="vdr:/tmp/vdr-xine/stream#demux:mpeg_pes" + xine $CMD "$MRL" + return 0 +} + +function _xinenetwork() { + [ -n "$VDRIP" ] || _vdrip || return 1 + CMD="--fullscreen --hide-gui --post vdr --post vdr_audio" + MRL="netvdr://$VDRIP#demux:mpeg_pes" + xine $CMD "$MRL" + return 0 +} + +### Main Script ############################################################################### + +_vdr || exit 1 # Check if VDR is running + +[ -n "`ps x | grep ShmClient`" ] && killall -q -9 ShmClient # If ShmClient is running, stop it +[ -n "`ps x | grep tvtime`" ] && killall -q -9 tvtime # If tvtime is running, stop it +[ -n "`ps x | grep vdr-sxfe`" ] && killall -q -9 vdr-sxfe # If vdr-sxfe is running, stop it +[ -n "`ps cx | grep xine`" ] && killall -q -9 xine # If xine is running, stop it +[ "$VDRPLAYER" = "vdrtvtime" ] && svdrpsend.pl PLUG vdrtvtime stop + +# Player +if [ -n "$VDRPLAYER" ]; then + case $VDRPLAYER in + shmclient) _shmclient ;; + tvtime) _tvtime ;; + vdrtvtime) _vdrtvtime ;; + vdr-sxfe) _vdrsxfe ;; + xineliboutput) _xineliboutput ;; + xine) _xine ;; + xine-network) _xinenetwork ;; + *) VDRPLAYER="" ;; + esac +fi + +# Dialog +if [ -z "$VDRPLAYER" ]; then + option=`$DIALOG --menu \ + 'Aktiviere den Player, den du nutzen moechtest.' 0 0 8 \ + '1' 'ShmClient (Softdevice)' \ + '2' 'Tvtime (FF-Karte)' \ + '3' 'vdrtvtime (tvtime als Plugin, FF-Karte)' \ + '4' 'vdr-sxfe (Xineliboutput)' \ + '5' 'Xine' \ + '6' 'Xine (Xineliboutput)' \ + '7' 'Xine-Network' 3>&1 1>&2 2>&3` + [ $? != 0 ] && exit 1 + VDRIP= + case $option in + 1) echo "VDRPLAYER=\"shmclient\"" > $HOME/vdrplayer.conf && _shmclient ;; + 2) echo "VDRPLAYER=\"tvtime\"" > $HOME/vdrplayer.conf && _tvtime ;; + 3) echo "VDRPLAYER=\"vdrtvtime\"" > $HOME/vdrplayer.conf && _vdrtvtime ;; + 4) echo "VDRPLAYER=\"vdr-sxfe\"" > $HOME/vdrplayer.conf && _vdrsxfe ;; + 5) echo "VDRPLAYER=\"xine\"" > $HOME/vdrplayer.conf && _xine ;; + 6) echo "VDRPLAYER=\"xineliboutput\"" > $HOME/vdrplayer.conf && _xineliboutput ;; + 7) echo "VDRPLAYER=\"xine-network\"" > $HOME/vdrplayer.conf && _xinenetwork ;; + esac +fi diff --git a/vdr/conf/channels.conf b/vdr/conf/channels.conf new file mode 100644 index 0000000..6566ab0 --- /dev/null +++ b/vdr/conf/channels.conf @@ -0,0 +1,128 @@ +:Main TV +Das Erste;ARD:11836:hC34:S19.2E:27500:101:102=deu;106=deu:104:0:28106:1:1101:0 +ZDF;ZDFvision:11953:hC34:S19.2E:27500:110:120=deu,121=2ch;125=dd:130:0:28006:1:1079:0 +WDR Köln;ARD:11836:hC34:S19.2E:27500:601:602=deu:604:0:28111:1:1101:0 +SAT.1;ProSiebenSat.1:12480:vC34:S19.2E:27500:1791:1792=deu;1795=deu:34:0:46:133:33:0 +KABEL1;ProSiebenSat.1:12480:vC34:S19.2E:27500:511:512=deu:33:0:899:133:33:0 +ProSieben;ProSiebenSat.1:12480:vC34:S19.2E:27500:255:256=deu;257=deu:32:0:898:133:33:0 +RTL Television,RTL;RTL World:12187:hC34:S19.2E:27500:163:104=deu;106=deu:105:0:12003:1:1089:0 +RTL2;RTL World:12187:hC34:S19.2E:27500:166:128=deu:68:0:12020:1:1089:0 +Super RTL,S RTL;RTL World:12187:hC34:S19.2E:27500:165:120=deu:65:0:12040:1:1089:0 +VOX;RTL World:12187:hC34:S19.2E:27500:167:136=deu:71:0:12060:1:1089:0 +Bayerisches FS;ARD:11836:hC34:S19.2E:27500:201:202=deu:204:0:28107:1:1101:0 +hr-fernsehen;ARD:11836:hC34:S19.2E:27500:301:302=deu:304:0:28108:1:1101:0 +NDR FS NDS;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28226:1:1073:0 +MDR FERNSEHEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28204:1:1073:0 +rbb Berlin;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0 +SR SÜDWEST Ferns.;ARD:12265:hC34:S19.2E:27500:1301:1302=deu:1304:0:28486:1:1093:0 +BR-alpha;ARD:11836:hC34:S19.2E:27500:701:702=deu:704:0:28112:1:1101:0 +Phoenix;ARD:11836:hC34:S19.2E:27500:901:902=deu:904:0:28114:1:1101:0 +arte;ARD:11836:hC34:S19.2E:27500:401:402=deu,403=fra:404:0:28109:1:1101:0 +3sat;ZDFvision:11953:hC34:S19.2E:27500:210:220=deu,221=2ch;225=dd:230:0:28007:1:1079:0 +KiKa;ZDFvision:11953:hC34:S19.2E:27500:310:320=deu:330:0:28008:1:1079:0 +ZDFdokukanal;ZDFvision:11953:hC34:S19.2E:27500:660:670=deu:630:0:28014:1:1079:0 +ZDFinfokanal;ZDFvision:11953:hC34:S19.2E:27500:610:620=deu:630:0:28011:1:1079:0 +ZDFtheaterkanal;ZDFvision:11953:hC34:S19.2E:27500:1110:1120=deu:630:0:28016:1:1079:0 +EinsPlus;ARD:12109:hC34:S19.2E:27500:301:302=deu:0:0:28203:1:1073:0 +EinsExtra;ARD:12109:hC34:S19.2E:27500:101:102=deu:0:0:28201:1:1073:0 +EinsFestival;ARD:12109:hC34:S19.2E:27500:201:202=deu:204:0:28202:1:1073:0 +:More TV +DSF;BetaDigital:12480:vC34:S19.2E:27500:1023:1024=deu:39:0:900:133:33:0 +Eurosport;SES Astra:12226:hC34:S19.2E:27500:101+8190:103=deu:102:0:31200:1:1091:0 +n-tv;RTL World:12187:hC34:S19.2E:27500:169:73=deu:80:0:12090:1:1089:0 +N24;ProSiebenSat.1:12480:vC34:S19.2E:27500:2047:2048=deu:36:0:47:133:33:0 +EuroNews;GlobeCast:12226:hC34:S19.2E:27500:2432:2433=deu,2434=eng,2435=fra,2436=ita,2437=esl,2438=por,2439=rus,2440:0:0:31220:1:1091:0 +9Live;BetaDigital:12480:vC34:S19.2E:27500:767:768=deu:35:0:897:133:33:0 +XXP;T-Systems:12633:hC56:S19.2E:22000:203:303=deu:503:0:12602:1:1113:0 +:Music +MTV Germany;MTV Networks:11973:V:S19.2E:27500:4031:4032:4034:0:28673:1:1078:0 +NICK;MTV Networks:11973:vC34:S19.2E:27500:4101+8190:4102=deu:4104:0:28680:1:1078:0 +VIVA;MTV Networks:11973:vC34:S19.2E:27500:4061+8190:4062:4064:0:28676:1:1078:0 +VIVA PLUS;MTV Networks:11973:vC34:S19.2E:27500:4071+8190:4072:4074:0:28677:1:1078:0 +:@100 Radio +Antenne Brandenburg;ARD rbb:12265:hC34:S19.2E:27500:0:821=deu:0:0:28454:1:1093:0 +Bayern 1;ARD BR:12265:hC34:S19.2E:27500:0:101=deu:0:0:28400:1:1093:0 +Bayern2Radio;ARD BR:12265:hC34:S19.2E:27500:0:111=deu:0:0:28401:1:1093:0 +Bayern 3;ARD BR:12265:hC34:S19.2E:27500:0:121=deu:0:0:28402:1:1093:0 +Bayern 4 Klassik;ARD BR:12265:hC34:S19.2E:27500:0:131=deu;132=deu:0:0:28403:1:1093:0 +B5 aktuell;ARD BR:12265:hC34:S19.2E:27500:0:141=deu:0:0:28404:1:1093:0 +BAYERN MOBIL;ARD BR:12265:hC34:S19.2E:27500:0:151=deu:0:0:28405:1:1093:0 +BR Verkehrskanal;ARD BR:12265:hC34:S19.2E:27500:0:171=deu:0:0:28407:1:1093:0 +Bremen Eins;ARD RB:12265:hC34:S19.2E:27500:0:701=deu:0:0:28448:1:1093:0 +Bremen Vier;ARD RB:12265:hC34:S19.2E:27500:0:721=deu:0:0:28450:1:1093:0 +cont.ra;ARD SWR:12265:hC34:S19.2E:27500:0:1071=deu:0:0:28472:1:1093:0 +DASDING;ARD SWR:12265:hC34:S19.2E:27500:0:1061=deu:0:0:28471:1:1093:0 +DAS MODUL;ARD BR:12265:hC34:S19.2E:27500:0:161=deu:0:0:28406:1:1093:0 +DLF;ZDFvision:11953:hC34:S19.2E:27500:0:810=deu:0:0:28013:1:1079:0 +DKULTUR;ZDFvision:11953:hC34:S19.2E:27500:0:710=deu:0:0:28012:1:1079:0 +DW 1;ARD DW:12265:hC34:S19.2E:27500:0:301:0:0:28416:1:1093:0 +DW 4;ARD DW:12265:hC34:S19.2E:27500:0:311:0:0:28417:1:1093:0 +Eins Live;ARD WDR:12265:hC34:S19.2E:27500:0:1101=deu:0:0:28475:1:1093:0 +Eins Live diggi;ARD WDR:12265:hC34:S19.2E:27500:0:1161=deu:0:0:28481:1:1093:0 +Fritz;ARD rbb:12265:hC34:S19.2E:27500:0:851=deu:0:0:28457:1:1093:0 +hr1;ARD HR:12265:hC34:S19.2E:27500:0:401=deu:0:0:28419:1:1093:0 +hr2;ARD HR:12265:hC34:S19.2E:27500:0:411=deu;412=deu:0:0:28420:1:1093:0 +hr3;ARD HR:12265:hC34:S19.2E:27500:0:421=deu:0:0:28421:1:1093:0 +hr4;ARD HR:12265:hC34:S19.2E:27500:0:431=deu:0:0:28422:1:1093:0 +hr-info;ARD HR:12265:hC34:S19.2E:27500:0:461=deu:0:0:28424:1:1093:0 +hr-info +;ARD HR:12265:hC34:S19.2E:27500:0:471=deu:0:0:28425:1:1093:0 +InfoRadio;ARD rbb:12265:hC34:S19.2E:27500:0:801=deu:0:0:28452:1:1093:0 +Inselradio;T-Systems:12633:hC56:S19.2E:22000:0:702:0:0:12651:1:1113:0 +kulturradio;ARD rbb:12265:hC34:S19.2E:27500:0:811=deu:0:0:28453:1:1093:0 +MDR1 SACHSEN;ARD MDR:12265:hC34:S19.2E:27500:0:501=deu:0:0:28428:1:1093:0 +MDR1 S-ANHALT;ARD MDR:12265:hC34:S19.2E:27500:0:511=deu:0:0:28429:1:1093:0 +MDR1 THÜRINGEN;ARD MDR:12265:hC34:S19.2E:27500:0:521=deu:0:0:28430:1:1093:0 +MDR FIGARO;ARD MDR:12265:hC34:S19.2E:27500:0:531=deu:0:0:28431:1:1093:0 +MDR JUMP;ARD MDR:12265:hC34:S19.2E:27500:0:541=deu:0:0:28432:1:1093:0 +MDR INFO;ARD MDR:12265:hC34:S19.2E:27500:0:561=deu:0:0:28434:1:1093:0 +NDR 2;ARD NDR:12265:hC34:S19.2E:27500:0:601=deu:0:0:28437:1:1093:0 +NDR Kultur;ARD NDR:12265:hC34:S19.2E:27500:0:611=deu:0:0:28438:1:1093:0 +NDR Info;ARD NDR:12265:hC34:S19.2E:27500:0:621=deu:0:0:28439:1:1093:0 +NDR 90,3;ARD NDR:12265:hC34:S19.2E:27500:0:641=deu:0:0:28441:1:1093:0 +NDR 1 Welle Nord;ARD NDR:12265:hC34:S19.2E:27500:0:651=deu:0:0:28442:1:1093:0 +NDR 1 Radio MV;ARD NDR:12265:hC34:S19.2E:27500:0:661=deu:0:0:28443:1:1093:0 +NDR 1 Niedersachsen;ARD NDR:12265:hC34:S19.2E:27500:0:671=deu:0:0:28444:1:1093:0 +NDR Info Spezial;ARD NDR:12265:hC34:S19.2E:27500:0:681=deu:0:0:28445:1:1093:0 +Nordwestradio;ARD RB:12265:hC34:S19.2E:27500:0:711=deu:0:0:28449:1:1093:0 +N-JOY;ARD NDR:12265:hC34:S19.2E:27500:0:631=deu:0:0:28440:1:1093:0 +radioBERLIN 88,8;ARD rbb:12265:hC34:S19.2E:27500:0:831=deu:0:0:28455:1:1093:0 +radioeins;ARD rbb:12265:hC34:S19.2E:27500:0:841=deu:0:0:28456:1:1093:0 +radiomultikulti;ARD rbb:12265:hC34:S19.2E:27500:0:861=deu:0:0:28458:1:1093:0 +radio top40;T-Systems:12633:hC56:S19.2E:22000:0:353=deu:0:0:12653:1:1113:0 +SPUTNIK;ARD MDR:12265:hC34:S19.2E:27500:0:551=deu:0:0:28433:1:1093:0 +SR1;ARD SR:12265:hC34:S19.2E:27500:0:901=deu:0:0:28461:1:1093:0 +SR2;ARD SR:12265:hC34:S19.2E:27500:0:911=deu:0:0:28462:1:1093:0 +SR3;ARD SR:12265:hC34:S19.2E:27500:0:921=deu:0:0:28463:1:1093:0 +SWR1 BW;ARD SWR:12265:hC34:S19.2E:27500:0:1001=deu:0:0:28465:1:1093:0 +SWR1 RP;ARD SWR:12265:hC34:S19.2E:27500:0:1011=deu:0:0:28466:1:1093:0 +SWR2;ARD SWR:12265:hC34:S19.2E:27500:0:1021=deu;1022=deu:0:0:28467:1:1093:0 +SWR3;ARD SWR:12265:hC34:S19.2E:27500:0:1031=deu:0:0:28468:1:1093:0 +SWR4 BW;ARD SWR:12265:hC34:S19.2E:27500:0:1041=deu:0:0:28469:1:1093:0 +SWR4 RP;ARD SWR:12265:hC34:S19.2E:27500:0:1051=deu:0:0:28470:1:1093:0 +WDR 2;ARD WDR:12265:hC34:S19.2E:27500:0:1111=deu:0:0:28476:1:1093:0 +WDR 3;ARD WDR:12265:hC34:S19.2E:27500:0:1121=deu:0:0:28477:1:1093:0 +WDR 4;ARD WDR:12265:hC34:S19.2E:27500:0:1131=deu:0:0:28478:1:1093:0 +WDR 5;ARD WDR:12265:hC34:S19.2E:27500:0:1141=deu;1142=deu:0:0:28479:1:1093:0 +WDR 2 Klassik;ARD WDR:12265:hC34:S19.2E:27500:0:1171=deu:0:0:28482:1:1093:0 +WDR Event;ARD WDR:12265:hC34:S19.2E:27500:0:1181=deu:0:0:28483:1:1093:0 +WDR Funkhaus Europa;ARD WDR:12265:hC34:S19.2E:27500:0:1151=deu:0:0:28480:1:1093:0 +YOU FM;ARD HR:12265:hC34:S19.2E:27500:0:451=deu:0:0:28423:1:1093:0 +:@200 die dritten +MDR S-ANHALT;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28229:1:1073:0 +MDR SACHSEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28228:1:1073:0 +MDR THÜRINGEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28230:1:1073:0 +NDR FS HH;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28225:1:1073:0 +NDR FS SH;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28227:1:1073:0 +NDR FS MV;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28224:1:1073:0 +rbb Brandenburg;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28205:1:1073:0 +SÜDWEST Ferns. BW;ARD:11836:hC34:S19.2E:27500:801:802=deu:804:0:28113:1:1101:0 +SÜDWEST Ferns. RP;ARD:12109:hC34:S19.2E:27500:3101:3102=deu:3104:0:28231:1:1073:0 +WDR Aachen;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28305:1:1201:0 +WDR Bielefeld;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28306:1:1201:0 +WDR Dortmund;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28307:1:1201:0 +WDR Düsseldorf;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28308:1:1201:0 +WDR Essen;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28309:1:1201:0 +WDR Münster;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28310:1:1201:0 +WDR Siegen;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28311:1:1201:0 +WDR Wuppertal;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28312:1:1201:0 +:@1000 New channels diff --git a/vdr/conf/channels.conf.dvb-c_unity-media b/vdr/conf/channels.conf.dvb-c_unity-media new file mode 100644 index 0000000..709a925 --- /dev/null +++ b/vdr/conf/channels.conf.dvb-c_unity-media @@ -0,0 +1,168 @@ +:FreeTV +Das Erste;ARD:410000:C0M256:C:6900:101=2:102=deu,103=2ch;106=dd:104:0:28106:41985:1101:0 +ZDF;ZDFvision:394000:C0M256:C:6900:110=2:120=deu,121=2ch;125=deu:130:0:28006:1:1079:0 +WDR Köln;ARD:410000:C0M256:C:6900:601=2:602=deu,603=2ch:604:0:28111:41985:1101:0 +3sat;ZDFvision:394000:C0M256:C:6900:210=2:220=deu,221=2ch;225=dd:230:0:28007:1:1079:0 +KiKa;ZDFvision:394000:C0M256:C:6900:310=2:320=deu:330:0:28008:1:1079:0 +ZDFinfokanal;ZDFvision:394000:C0M256:C:6900:610=2:620=deu:630:0:28011:1:1079:0 +ZDFdokukanal;ZDFvision:394000:C0M256:C:6900:660=2:670=deu,671=2ch:630:0:28014:1:1079:0 +ZDFtheaterkanal;ZDFvision:394000:C0M256:C:6900:1110=2:1120=deu,1121=2ch:630:0:28016:1:1079:0 +EinsExtra;ARD:682000:C0M256:C:6900:101=2:102=deu:0:0:28721:41985:1051:0 +EinsFestival;ARD:682000:C0M256:C:6900:201=2:202=deu:204:0:28722:41985:1051:0 +EinsPlus;ARD:682000:C0M256:C:6900:301=2:302=deu:304:0:28723:41985:1051:0 +arte;ARD:682000:C0M256:C:6900:401=2:402=deu,403=fra:404:0:28724:41985:1051:0 +Phoenix;ARD:682000:C0M256:C:6900:501=2:502=deu:504:0:28725:41985:1051:0 +BR-alpha;ARD:682000:C0M256:C:6900:1401=2:1402=deu;1406=deu:1404:0:28487:41985:1051:0 +Bayerisches FS Süd;ARD:410000:C0M256:C:6900:201=2:202=deu,203=2ch;206=dd:204:0:28107:41985:1101:0 +Bayerisches FS Nord;ARD:410000:C0M256:C:6900:201=2:202=deu,203=deu;206=deu:204:0:28110:41985:1101:0 +hr-fernsehen;ARD:410000:C0M256:C:6900:301=2:302=deu,303=2ch:304:0:28108:41985:1101:0 +SWR Fernsehen BW;ARD:410000:C0M256:C:6900:801=2:802=deu:804:0:28113:41985:1101:0 +SWR Fernsehen RP;ARD:426000:C0M256:C:6900:3101=2:3102=deu:3104:0:28231:41985:1073:0 +rbb Brandenburg;ARD:426000:C0M256:C:6900:601=2:602=deu:604:0:28205:41985:1073:0 +rbb Berlin;ARD:426000:C0M256:C:6900:601=2:602=deu:604:0:28206:41985:1073:0 +NDR FS MV;ARD:426000:C0M256:C:6900:2601=2:2602=deu,2603=2ch:2604:0:28224:41985:1073:0 +NDR FS HH;ARD:426000:C0M256:C:6900:2601=2:2602=deu,2603=2ch:2604:0:28225:41985:1073:0 +NDR FS NDS;ARD:426000:C0M256:C:6900:2601=2:2602=deu,2603=2ch:2604:0:28226:41985:1073:0 +NDR FS SH;ARD:426000:C0M256:C:6900:2601=2:2602=deu,2603=2ch:2604:0:28227:41985:1073:0 +MDR Sachsen;ARD:426000:C0M256:C:6900:2901=2:2902=deu,2903=2ch:2904:0:28228:41985:1073:0 +MDR S-Anhalt;ARD:426000:C0M256:C:6900:2901=2:2902=deu,2903=2ch:2904:0:28229:41985:1073:0 +MDR Thüringen;ARD:426000:C0M256:C:6900:2901=2:2902=deu,2903=2ch:2904:0:28230:41985:1073:0 +EinsFestival HD;ARD:682000:C0M256:C:6900:1601=27:1602=deu;1606=deu:0:0:28396:41985:1051:0 +:Radio +Bayern 1;ARD BR:410000:C0M256:C:6900:0=2:3101=deu:0:0:28400:41985:1101:0 +Bayern 2;ARD BR:410000:C0M256:C:6900:0=2:3111=deu:0:0:28401:41985:1101:0 +BAYERN 3;ARD BR:410000:C0M256:C:6900:0=2:3121=deu:0:0:28402:41985:1101:0 +BAYERN 4 KLASSIK;ARD BR:410000:C0M256:C:6900:0=2:3131=deu;3132=deu:0:0:28403:41985:1101:0 +B5 aktuell;ARD BR:410000:C0M256:C:6900:0=2:3141=deu:0:0:28404:41985:1101:0 +BAYERN plus;ARD BR:410000:C0M256:C:6900:0=2:3151=deu:0:0:28405:41985:1101:0 +on3radio;ARD BR:410000:C0M256:C:6900:0=2:3161=deu:0:0:28406:41985:1101:0 +BR Verkehr;ARD BR:410000:C0M256:C:6900:0=2:3171=deu:0:0:28407:41985:1101:0 +B5 plus;ARD BR:410000:C0M256:C:6900:0=2:3181=deu:0:0:28408:41985:1101:0 +hr1;ARD HR:410000:C0M256:C:6900:0=2:3401=deu:0:0:28419:41985:1101:0 +hr2;ARD HR:410000:C0M256:C:6900:0=2:3411=deu;3412=deu:0:0:28420:41985:1101:0 +hr3;ARD HR:410000:C0M256:C:6900:0=2:3421=deu:0:0:28421:41985:1101:0 +hr4;ARD HR:410000:C0M256:C:6900:0=2:3431=deu:0:0:28422:41985:1101:0 +YOU FM;ARD HR:410000:C0M256:C:6900:0=2:3451=deu:0:0:28423:41985:1101:0 +hr iNFO;ARD HR:410000:C0M256:C:6900:0=2:3461=deu:0:0:28424:41985:1101:0 +hr iNFO +;ARD HR:410000:C0M256:C:6900:0=2:3471=deu:0:0:28425:41985:1101:0 +SR1 Europawelle;ARD SR:410000:C0M256:C:6900:0=2:3901=deu:0:0:28461:41985:1101:0 +SR2 KulturRadio;ARD SR:410000:C0M256:C:6900:0=2:3911=deu:0:0:28462:41985:1101:0 +SR3 Saarlandwelle;ARD SR:410000:C0M256:C:6900:0=2:3921=deu:0:0:28463:41985:1101:0 +1LIVE;ARD WDR:410000:C0M256:C:6900:0=2:4101=deu:0:0:28475:41985:1101:0 +WDR 2;ARD WDR:410000:C0M256:C:6900:0=2:4111=deu:0:0:28476:41985:1101:0 +WDR 3;ARD WDR:410000:C0M256:C:6900:0=2:4121=deu;4122=deu:0:0:28477:41985:1101:0 +WDR 4;ARD WDR:410000:C0M256:C:6900:0=2:4131=deu:0:0:28478:41985:1101:0 +WDR 5;ARD WDR:410000:C0M256:C:6900:0=2:4141=deu:0:0:28479:41985:1101:0 +WDR Funkhaus Europa;ARD WDR:410000:C0M256:C:6900:0=2:4151=deu:0:0:28480:41985:1101:0 +1LIVE diggi;ARD WDR:410000:C0M256:C:6900:0=2:4161=deu:0:0:28481:41985:1101:0 +WDR 2 Klassik;ARD WDR:410000:C0M256:C:6900:0=2:4171=deu:0:0:28482:41985:1101:0 +WDR Event;ARD WDR:410000:C0M256:C:6900:0=2:4181=deu:0:0:28483:41985:1101:0 +DKULTUR;ZDFvision:394000:C0M256:C:6900:0=2:710=deu:0:0:28012:1:1079:0 +DLF;ZDFvision:394000:C0M256:C:6900:0=2:810=deu:0:0:28013:1:1079:0 +Dok&Deb;ZDFvision:394000:C0M256:C:6900:0=2:410=deu:0:0:28017:1:1079:0 +DW 1;ARD DW:426000:C0M256:C:6900:0:3301=deu:0:0:28416:41985:1073:0 +DW 4;ARD DW:426000:C0M256:C:6900:0:3311=deu:0:0:28417:41985:1073:0 +MDR1 SACHSEN;ARD MDR:426000:C0M256:C:6900:0:3501=deu:0:0:28428:41985:1073:0 +MDR1 SA-ANHALT;ARD MDR:426000:C0M256:C:6900:0:3511=deu:0:0:28429:41985:1073:0 +MDR1 THÜRINGEN;ARD MDR:426000:C0M256:C:6900:0:3521=deu:0:0:28430:41985:1073:0 +MDR FIGARO;ARD MDR:426000:C0M256:C:6900:0:3531=deu:0:0:28431:41985:1073:0 +JUMP;ARD MDR:426000:C0M256:C:6900:0:3541=deu:0:0:28432:41985:1073:0 +MDR SPUTNIK;ARD MDR:426000:C0M256:C:6900:0:3551=deu:0:0:28433:41985:1073:0 +MDR Info;ARD MDR:426000:C0M256:C:6900:0:3561=deu:0:0:28434:41985:1073:0 +MDR KLASSIK;ARD MDR:426000:C0M256:C:6900:0:3571=deu:0:0:28435:41985:1073:0 +NDR 2;ARD NDR:426000:C0M256:C:6900:0:3601=deu:0:0:28437:41985:1073:0 +NDR Kultur;ARD NDR:426000:C0M256:C:6900:0:3611=deu:0:0:28438:41985:1073:0 +NDR Info;ARD NDR:426000:C0M256:C:6900:0:3621=deu:0:0:28439:41985:1073:0 +N-JOY;ARD NDR:426000:C0M256:C:6900:0:3631=deu:0:0:28440:41985:1073:0 +NDR 90,3;ARD NDR:426000:C0M256:C:6900:0:3641=deu:0:0:28441:41985:1073:0 +NDR1WelleNord;ARD NDR:426000:C0M256:C:6900:0:3651=deu:0:0:28442:41985:1073:0 +NDR 1 Radio MV;ARD NDR:426000:C0M256:C:6900:0:3661=deu:0:0:28443:41985:1073:0 +NDR 1 Nieders.;ARD NDR:426000:C0M256:C:6900:0:3671=deu:0:0:28444:41985:1073:0 +NDR Info Spez.;ARD NDR:426000:C0M256:C:6900:0:3681=deu:0:0:28445:41985:1073:0 +Bremen Eins;ARD RB:426000:C0M256:C:6900:0:3701=deu:0:0:28448:41985:1073:0 +Nordwestradio;ARD RB:426000:C0M256:C:6900:0:3711=deu:0:0:28449:41985:1073:0 +Bremen Vier;ARD RB:426000:C0M256:C:6900:0:3721=deu:0:0:28450:41985:1073:0 +Inforadio;ARD rbb:426000:C0M256:C:6900:0:3801=deu:0:0:28452:41985:1073:0 +Kulturradio;ARD rbb:426000:C0M256:C:6900:0:3811=deu:0:0:28453:41985:1073:0 +Antenne Brandenburg;ARD rbb:426000:C0M256:C:6900:0:3821=deu:0:0:28454:41985:1073:0 +radioBERLIN 88,8;ARD rbb:426000:C0M256:C:6900:0:3831=deu:0:0:28455:41985:1073:0 +radioeins;ARD rbb:426000:C0M256:C:6900:0:3841=deu:0:0:28456:41985:1073:0 +Fritz;ARD rbb:426000:C0M256:C:6900:0:3851=deu:0:0:28457:41985:1073:0 +SWR 1 BW;ARD SWR:426000:C0M256:C:6900:0:4001=deu:0:0:28465:41985:1073:0 +SWR 1 RP;ARD SWR:426000:C0M256:C:6900:0:4011=deu:0:0:28466:41985:1073:0 +SWR 2;ARD SWR:426000:C0M256:C:6900:0:4021=deu;4022=deu:0:0:28467:41985:1073:0 +SWR 3;ARD SWR:426000:C0M256:C:6900:0:4031=deu:0:0:28468:41985:1073:0 +SWR 4 BW;ARD SWR:426000:C0M256:C:6900:0:4041=deu:0:0:28469:41985:1073:0 +SWR 4 RP;ARD SWR:426000:C0M256:C:6900:0:4051=deu:0:0:28470:41985:1073:0 +DASDING;ARD SWR:426000:C0M256:C:6900:0:4061=deu:0:0:28471:41985:1073:0 +SWR cont.ra;ARD SWR:426000:C0M256:C:6900:0:4071=deu:0:0:28472:41985:1073:0 +:Radio +Bayern 1;ARD BR:410000:C0M256:C:6900:0:3101=deu:0:0:28400:41985:1101:0 +Bayern 2;ARD BR:410000:C0M256:C:6900:0:3111=deu:0:0:28401:41985:1101:0 +BAYERN 3;ARD BR:410000:C0M256:C:6900:0:3121=deu:0:0:28402:41985:1101:0 +BAYERN 4 KLASSIK;ARD BR:410000:C0M256:C:6900:0:3131=deu;3132=deu:0:0:28403:41985:1101:0 +B5 aktuell;ARD BR:410000:C0M256:C:6900:0:3141=deu:0:0:28404:41985:1101:0 +BAYERN plus;ARD BR:410000:C0M256:C:6900:0:3151=deu:0:0:28405:41985:1101:0 +on3radio;ARD BR:410000:C0M256:C:6900:0:3161=deu:0:0:28406:41985:1101:0 +BR Verkehr;ARD BR:410000:C0M256:C:6900:0:3171=deu:0:0:28407:41985:1101:0 +B5 plus;ARD BR:410000:C0M256:C:6900:0:3181=deu:0:0:28408:41985:1101:0 +hr1;ARD HR:410000:C0M256:C:6900:0:3401=deu:0:0:28419:41985:1101:0 +hr2;ARD HR:410000:C0M256:C:6900:0:3411=deu;3412=deu:0:0:28420:41985:1101:0 +hr3;ARD HR:410000:C0M256:C:6900:0:3421=deu:0:0:28421:41985:1101:0 +hr4;ARD HR:410000:C0M256:C:6900:0:3431=deu:0:0:28422:41985:1101:0 +YOU FM;ARD HR:410000:C0M256:C:6900:0:3451=deu:0:0:28423:41985:1101:0 +hr iNFO;ARD HR:410000:C0M256:C:6900:0:3461=deu:0:0:28424:41985:1101:0 +hr iNFO +;ARD HR:410000:C0M256:C:6900:0:3471=deu:0:0:28425:41985:1101:0 +SR1 Europawelle;ARD SR:410000:C0M256:C:6900:0:3901=deu:0:0:28461:41985:1101:0 +SR2 KulturRadio;ARD SR:410000:C0M256:C:6900:0:3911=deu:0:0:28462:41985:1101:0 +SR3 Saarlandwelle;ARD SR:410000:C0M256:C:6900:0:3921=deu:0:0:28463:41985:1101:0 +1LIVE;ARD WDR:410000:C0M256:C:6900:0:4101=deu:0:0:28475:41985:1101:0 +WDR 2;ARD WDR:410000:C0M256:C:6900:0:4111=deu:0:0:28476:41985:1101:0 +WDR 3;ARD WDR:410000:C0M256:C:6900:0:4121=deu;4122=deu:0:0:28477:41985:1101:0 +WDR 4;ARD WDR:410000:C0M256:C:6900:0:4131=deu:0:0:28478:41985:1101:0 +WDR 5;ARD WDR:410000:C0M256:C:6900:0:4141=deu:0:0:28479:41985:1101:0 +WDR Funkhaus Europa;ARD WDR:410000:C0M256:C:6900:0:4151=deu:0:0:28480:41985:1101:0 +1LIVE diggi;ARD WDR:410000:C0M256:C:6900:0:4161=deu:0:0:28481:41985:1101:0 +WDR 2 Klassik;ARD WDR:410000:C0M256:C:6900:0:4171=deu:0:0:28482:41985:1101:0 +WDR Event;ARD WDR:410000:C0M256:C:6900:0:4181=deu:0:0:28483:41985:1101:0 +DKULTUR;ZDFvision:394000:C0M256:C:6900:0=2:710=deu:0:0:28012:1:1079:0 +DLF;ZDFvision:394000:C0M256:C:6900:0=2:810=deu:0:0:28013:1:1079:0 +Dok&Deb;ZDFvision:394000:C0M256:C:6900:0=2:410=deu:0:0:28017:1:1079:0 +DW 1;ARD DW:426000:C0M256:C:6900:0:3301=deu:0:0:28416:41985:1073:0 +DW 4;ARD DW:426000:C0M256:C:6900:0:3311=deu:0:0:28417:41985:1073:0 +MDR1 SACHSEN;ARD MDR:426000:C0M256:C:6900:0:3501=deu:0:0:28428:41985:1073:0 +MDR1 SA-ANHALT;ARD MDR:426000:C0M256:C:6900:0:3511=deu:0:0:28429:41985:1073:0 +MDR1 THÜRINGEN;ARD MDR:426000:C0M256:C:6900:0:3521=deu:0:0:28430:41985:1073:0 +MDR FIGARO;ARD MDR:426000:C0M256:C:6900:0:3531=deu:0:0:28431:41985:1073:0 +JUMP;ARD MDR:426000:C0M256:C:6900:0:3541=deu:0:0:28432:41985:1073:0 +MDR SPUTNIK;ARD MDR:426000:C0M256:C:6900:0:3551=deu:0:0:28433:41985:1073:0 +MDR Info;ARD MDR:426000:C0M256:C:6900:0:3561=deu:0:0:28434:41985:1073:0 +MDR KLASSIK;ARD MDR:426000:C0M256:C:6900:0:3571=deu:0:0:28435:41985:1073:0 +NDR 2;ARD NDR:426000:C0M256:C:6900:0:3601=deu:0:0:28437:41985:1073:0 +NDR Kultur;ARD NDR:426000:C0M256:C:6900:0:3611=deu:0:0:28438:41985:1073:0 +NDR Info;ARD NDR:426000:C0M256:C:6900:0:3621=deu:0:0:28439:41985:1073:0 +N-JOY;ARD NDR:426000:C0M256:C:6900:0:3631=deu:0:0:28440:41985:1073:0 +NDR 90,3;ARD NDR:426000:C0M256:C:6900:0:3641=deu:0:0:28441:41985:1073:0 +NDR1WelleNord;ARD NDR:426000:C0M256:C:6900:0:3651=deu:0:0:28442:41985:1073:0 +NDR 1 Radio MV;ARD NDR:426000:C0M256:C:6900:0:3661=deu:0:0:28443:41985:1073:0 +NDR 1 Nieders.;ARD NDR:426000:C0M256:C:6900:0:3671=deu:0:0:28444:41985:1073:0 +NDR Info Spez.;ARD NDR:426000:C0M256:C:6900:0:3681=deu:0:0:28445:41985:1073:0 +Bremen Eins;ARD RB:426000:C0M256:C:6900:0:3701=deu:0:0:28448:41985:1073:0 +Nordwestradio;ARD RB:426000:C0M256:C:6900:0:3711=deu:0:0:28449:41985:1073:0 +Bremen Vier;ARD RB:426000:C0M256:C:6900:0:3721=deu:0:0:28450:41985:1073:0 +Inforadio;ARD rbb:426000:C0M256:C:6900:0:3801=deu:0:0:28452:41985:1073:0 +Kulturradio;ARD rbb:426000:C0M256:C:6900:0:3811=deu:0:0:28453:41985:1073:0 +Antenne Brandenburg;ARD rbb:426000:C0M256:C:6900:0:3821=deu:0:0:28454:41985:1073:0 +radioBERLIN 88,8;ARD rbb:426000:C0M256:C:6900:0:3831=deu:0:0:28455:41985:1073:0 +radioeins;ARD rbb:426000:C0M256:C:6900:0:3841=deu:0:0:28456:41985:1073:0 +Fritz;ARD rbb:426000:C0M256:C:6900:0:3851=deu:0:0:28457:41985:1073:0 +SWR 1 BW;ARD SWR:426000:C0M256:C:6900:0:4001=deu:0:0:28465:41985:1073:0 +SWR 1 RP;ARD SWR:426000:C0M256:C:6900:0:4011=deu:0:0:28466:41985:1073:0 +SWR 2;ARD SWR:426000:C0M256:C:6900:0:4021=deu;4022=deu:0:0:28467:41985:1073:0 +SWR 3;ARD SWR:426000:C0M256:C:6900:0:4031=deu:0:0:28468:41985:1073:0 +SWR 4 BW;ARD SWR:426000:C0M256:C:6900:0:4041=deu:0:0:28469:41985:1073:0 +SWR 4 RP;ARD SWR:426000:C0M256:C:6900:0:4051=deu:0:0:28470:41985:1073:0 +DASDING;ARD SWR:426000:C0M256:C:6900:0:4061=deu:0:0:28471:41985:1073:0 +SWR cont.ra;ARD SWR:426000:C0M256:C:6900:0:4071=deu:0:0:28472:41985:1073:0 +:More +Unitymedia Infokanal;UnityDigitalTV:610000:C0M64:C:6900:513=2:514=deu:0:0:25101:9999:251:0 diff --git a/vdr/conf/channels.conf.dvb-s_astra b/vdr/conf/channels.conf.dvb-s_astra new file mode 100644 index 0000000..6566ab0 --- /dev/null +++ b/vdr/conf/channels.conf.dvb-s_astra @@ -0,0 +1,128 @@ +:Main TV +Das Erste;ARD:11836:hC34:S19.2E:27500:101:102=deu;106=deu:104:0:28106:1:1101:0 +ZDF;ZDFvision:11953:hC34:S19.2E:27500:110:120=deu,121=2ch;125=dd:130:0:28006:1:1079:0 +WDR Köln;ARD:11836:hC34:S19.2E:27500:601:602=deu:604:0:28111:1:1101:0 +SAT.1;ProSiebenSat.1:12480:vC34:S19.2E:27500:1791:1792=deu;1795=deu:34:0:46:133:33:0 +KABEL1;ProSiebenSat.1:12480:vC34:S19.2E:27500:511:512=deu:33:0:899:133:33:0 +ProSieben;ProSiebenSat.1:12480:vC34:S19.2E:27500:255:256=deu;257=deu:32:0:898:133:33:0 +RTL Television,RTL;RTL World:12187:hC34:S19.2E:27500:163:104=deu;106=deu:105:0:12003:1:1089:0 +RTL2;RTL World:12187:hC34:S19.2E:27500:166:128=deu:68:0:12020:1:1089:0 +Super RTL,S RTL;RTL World:12187:hC34:S19.2E:27500:165:120=deu:65:0:12040:1:1089:0 +VOX;RTL World:12187:hC34:S19.2E:27500:167:136=deu:71:0:12060:1:1089:0 +Bayerisches FS;ARD:11836:hC34:S19.2E:27500:201:202=deu:204:0:28107:1:1101:0 +hr-fernsehen;ARD:11836:hC34:S19.2E:27500:301:302=deu:304:0:28108:1:1101:0 +NDR FS NDS;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28226:1:1073:0 +MDR FERNSEHEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28204:1:1073:0 +rbb Berlin;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0 +SR SÜDWEST Ferns.;ARD:12265:hC34:S19.2E:27500:1301:1302=deu:1304:0:28486:1:1093:0 +BR-alpha;ARD:11836:hC34:S19.2E:27500:701:702=deu:704:0:28112:1:1101:0 +Phoenix;ARD:11836:hC34:S19.2E:27500:901:902=deu:904:0:28114:1:1101:0 +arte;ARD:11836:hC34:S19.2E:27500:401:402=deu,403=fra:404:0:28109:1:1101:0 +3sat;ZDFvision:11953:hC34:S19.2E:27500:210:220=deu,221=2ch;225=dd:230:0:28007:1:1079:0 +KiKa;ZDFvision:11953:hC34:S19.2E:27500:310:320=deu:330:0:28008:1:1079:0 +ZDFdokukanal;ZDFvision:11953:hC34:S19.2E:27500:660:670=deu:630:0:28014:1:1079:0 +ZDFinfokanal;ZDFvision:11953:hC34:S19.2E:27500:610:620=deu:630:0:28011:1:1079:0 +ZDFtheaterkanal;ZDFvision:11953:hC34:S19.2E:27500:1110:1120=deu:630:0:28016:1:1079:0 +EinsPlus;ARD:12109:hC34:S19.2E:27500:301:302=deu:0:0:28203:1:1073:0 +EinsExtra;ARD:12109:hC34:S19.2E:27500:101:102=deu:0:0:28201:1:1073:0 +EinsFestival;ARD:12109:hC34:S19.2E:27500:201:202=deu:204:0:28202:1:1073:0 +:More TV +DSF;BetaDigital:12480:vC34:S19.2E:27500:1023:1024=deu:39:0:900:133:33:0 +Eurosport;SES Astra:12226:hC34:S19.2E:27500:101+8190:103=deu:102:0:31200:1:1091:0 +n-tv;RTL World:12187:hC34:S19.2E:27500:169:73=deu:80:0:12090:1:1089:0 +N24;ProSiebenSat.1:12480:vC34:S19.2E:27500:2047:2048=deu:36:0:47:133:33:0 +EuroNews;GlobeCast:12226:hC34:S19.2E:27500:2432:2433=deu,2434=eng,2435=fra,2436=ita,2437=esl,2438=por,2439=rus,2440:0:0:31220:1:1091:0 +9Live;BetaDigital:12480:vC34:S19.2E:27500:767:768=deu:35:0:897:133:33:0 +XXP;T-Systems:12633:hC56:S19.2E:22000:203:303=deu:503:0:12602:1:1113:0 +:Music +MTV Germany;MTV Networks:11973:V:S19.2E:27500:4031:4032:4034:0:28673:1:1078:0 +NICK;MTV Networks:11973:vC34:S19.2E:27500:4101+8190:4102=deu:4104:0:28680:1:1078:0 +VIVA;MTV Networks:11973:vC34:S19.2E:27500:4061+8190:4062:4064:0:28676:1:1078:0 +VIVA PLUS;MTV Networks:11973:vC34:S19.2E:27500:4071+8190:4072:4074:0:28677:1:1078:0 +:@100 Radio +Antenne Brandenburg;ARD rbb:12265:hC34:S19.2E:27500:0:821=deu:0:0:28454:1:1093:0 +Bayern 1;ARD BR:12265:hC34:S19.2E:27500:0:101=deu:0:0:28400:1:1093:0 +Bayern2Radio;ARD BR:12265:hC34:S19.2E:27500:0:111=deu:0:0:28401:1:1093:0 +Bayern 3;ARD BR:12265:hC34:S19.2E:27500:0:121=deu:0:0:28402:1:1093:0 +Bayern 4 Klassik;ARD BR:12265:hC34:S19.2E:27500:0:131=deu;132=deu:0:0:28403:1:1093:0 +B5 aktuell;ARD BR:12265:hC34:S19.2E:27500:0:141=deu:0:0:28404:1:1093:0 +BAYERN MOBIL;ARD BR:12265:hC34:S19.2E:27500:0:151=deu:0:0:28405:1:1093:0 +BR Verkehrskanal;ARD BR:12265:hC34:S19.2E:27500:0:171=deu:0:0:28407:1:1093:0 +Bremen Eins;ARD RB:12265:hC34:S19.2E:27500:0:701=deu:0:0:28448:1:1093:0 +Bremen Vier;ARD RB:12265:hC34:S19.2E:27500:0:721=deu:0:0:28450:1:1093:0 +cont.ra;ARD SWR:12265:hC34:S19.2E:27500:0:1071=deu:0:0:28472:1:1093:0 +DASDING;ARD SWR:12265:hC34:S19.2E:27500:0:1061=deu:0:0:28471:1:1093:0 +DAS MODUL;ARD BR:12265:hC34:S19.2E:27500:0:161=deu:0:0:28406:1:1093:0 +DLF;ZDFvision:11953:hC34:S19.2E:27500:0:810=deu:0:0:28013:1:1079:0 +DKULTUR;ZDFvision:11953:hC34:S19.2E:27500:0:710=deu:0:0:28012:1:1079:0 +DW 1;ARD DW:12265:hC34:S19.2E:27500:0:301:0:0:28416:1:1093:0 +DW 4;ARD DW:12265:hC34:S19.2E:27500:0:311:0:0:28417:1:1093:0 +Eins Live;ARD WDR:12265:hC34:S19.2E:27500:0:1101=deu:0:0:28475:1:1093:0 +Eins Live diggi;ARD WDR:12265:hC34:S19.2E:27500:0:1161=deu:0:0:28481:1:1093:0 +Fritz;ARD rbb:12265:hC34:S19.2E:27500:0:851=deu:0:0:28457:1:1093:0 +hr1;ARD HR:12265:hC34:S19.2E:27500:0:401=deu:0:0:28419:1:1093:0 +hr2;ARD HR:12265:hC34:S19.2E:27500:0:411=deu;412=deu:0:0:28420:1:1093:0 +hr3;ARD HR:12265:hC34:S19.2E:27500:0:421=deu:0:0:28421:1:1093:0 +hr4;ARD HR:12265:hC34:S19.2E:27500:0:431=deu:0:0:28422:1:1093:0 +hr-info;ARD HR:12265:hC34:S19.2E:27500:0:461=deu:0:0:28424:1:1093:0 +hr-info +;ARD HR:12265:hC34:S19.2E:27500:0:471=deu:0:0:28425:1:1093:0 +InfoRadio;ARD rbb:12265:hC34:S19.2E:27500:0:801=deu:0:0:28452:1:1093:0 +Inselradio;T-Systems:12633:hC56:S19.2E:22000:0:702:0:0:12651:1:1113:0 +kulturradio;ARD rbb:12265:hC34:S19.2E:27500:0:811=deu:0:0:28453:1:1093:0 +MDR1 SACHSEN;ARD MDR:12265:hC34:S19.2E:27500:0:501=deu:0:0:28428:1:1093:0 +MDR1 S-ANHALT;ARD MDR:12265:hC34:S19.2E:27500:0:511=deu:0:0:28429:1:1093:0 +MDR1 THÜRINGEN;ARD MDR:12265:hC34:S19.2E:27500:0:521=deu:0:0:28430:1:1093:0 +MDR FIGARO;ARD MDR:12265:hC34:S19.2E:27500:0:531=deu:0:0:28431:1:1093:0 +MDR JUMP;ARD MDR:12265:hC34:S19.2E:27500:0:541=deu:0:0:28432:1:1093:0 +MDR INFO;ARD MDR:12265:hC34:S19.2E:27500:0:561=deu:0:0:28434:1:1093:0 +NDR 2;ARD NDR:12265:hC34:S19.2E:27500:0:601=deu:0:0:28437:1:1093:0 +NDR Kultur;ARD NDR:12265:hC34:S19.2E:27500:0:611=deu:0:0:28438:1:1093:0 +NDR Info;ARD NDR:12265:hC34:S19.2E:27500:0:621=deu:0:0:28439:1:1093:0 +NDR 90,3;ARD NDR:12265:hC34:S19.2E:27500:0:641=deu:0:0:28441:1:1093:0 +NDR 1 Welle Nord;ARD NDR:12265:hC34:S19.2E:27500:0:651=deu:0:0:28442:1:1093:0 +NDR 1 Radio MV;ARD NDR:12265:hC34:S19.2E:27500:0:661=deu:0:0:28443:1:1093:0 +NDR 1 Niedersachsen;ARD NDR:12265:hC34:S19.2E:27500:0:671=deu:0:0:28444:1:1093:0 +NDR Info Spezial;ARD NDR:12265:hC34:S19.2E:27500:0:681=deu:0:0:28445:1:1093:0 +Nordwestradio;ARD RB:12265:hC34:S19.2E:27500:0:711=deu:0:0:28449:1:1093:0 +N-JOY;ARD NDR:12265:hC34:S19.2E:27500:0:631=deu:0:0:28440:1:1093:0 +radioBERLIN 88,8;ARD rbb:12265:hC34:S19.2E:27500:0:831=deu:0:0:28455:1:1093:0 +radioeins;ARD rbb:12265:hC34:S19.2E:27500:0:841=deu:0:0:28456:1:1093:0 +radiomultikulti;ARD rbb:12265:hC34:S19.2E:27500:0:861=deu:0:0:28458:1:1093:0 +radio top40;T-Systems:12633:hC56:S19.2E:22000:0:353=deu:0:0:12653:1:1113:0 +SPUTNIK;ARD MDR:12265:hC34:S19.2E:27500:0:551=deu:0:0:28433:1:1093:0 +SR1;ARD SR:12265:hC34:S19.2E:27500:0:901=deu:0:0:28461:1:1093:0 +SR2;ARD SR:12265:hC34:S19.2E:27500:0:911=deu:0:0:28462:1:1093:0 +SR3;ARD SR:12265:hC34:S19.2E:27500:0:921=deu:0:0:28463:1:1093:0 +SWR1 BW;ARD SWR:12265:hC34:S19.2E:27500:0:1001=deu:0:0:28465:1:1093:0 +SWR1 RP;ARD SWR:12265:hC34:S19.2E:27500:0:1011=deu:0:0:28466:1:1093:0 +SWR2;ARD SWR:12265:hC34:S19.2E:27500:0:1021=deu;1022=deu:0:0:28467:1:1093:0 +SWR3;ARD SWR:12265:hC34:S19.2E:27500:0:1031=deu:0:0:28468:1:1093:0 +SWR4 BW;ARD SWR:12265:hC34:S19.2E:27500:0:1041=deu:0:0:28469:1:1093:0 +SWR4 RP;ARD SWR:12265:hC34:S19.2E:27500:0:1051=deu:0:0:28470:1:1093:0 +WDR 2;ARD WDR:12265:hC34:S19.2E:27500:0:1111=deu:0:0:28476:1:1093:0 +WDR 3;ARD WDR:12265:hC34:S19.2E:27500:0:1121=deu:0:0:28477:1:1093:0 +WDR 4;ARD WDR:12265:hC34:S19.2E:27500:0:1131=deu:0:0:28478:1:1093:0 +WDR 5;ARD WDR:12265:hC34:S19.2E:27500:0:1141=deu;1142=deu:0:0:28479:1:1093:0 +WDR 2 Klassik;ARD WDR:12265:hC34:S19.2E:27500:0:1171=deu:0:0:28482:1:1093:0 +WDR Event;ARD WDR:12265:hC34:S19.2E:27500:0:1181=deu:0:0:28483:1:1093:0 +WDR Funkhaus Europa;ARD WDR:12265:hC34:S19.2E:27500:0:1151=deu:0:0:28480:1:1093:0 +YOU FM;ARD HR:12265:hC34:S19.2E:27500:0:451=deu:0:0:28423:1:1093:0 +:@200 die dritten +MDR S-ANHALT;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28229:1:1073:0 +MDR SACHSEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28228:1:1073:0 +MDR THÜRINGEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28230:1:1073:0 +NDR FS HH;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28225:1:1073:0 +NDR FS SH;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28227:1:1073:0 +NDR FS MV;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28224:1:1073:0 +rbb Brandenburg;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28205:1:1073:0 +SÜDWEST Ferns. BW;ARD:11836:hC34:S19.2E:27500:801:802=deu:804:0:28113:1:1101:0 +SÜDWEST Ferns. RP;ARD:12109:hC34:S19.2E:27500:3101:3102=deu:3104:0:28231:1:1073:0 +WDR Aachen;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28305:1:1201:0 +WDR Bielefeld;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28306:1:1201:0 +WDR Dortmund;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28307:1:1201:0 +WDR Düsseldorf;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28308:1:1201:0 +WDR Essen;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28309:1:1201:0 +WDR Münster;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28310:1:1201:0 +WDR Siegen;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28311:1:1201:0 +WDR Wuppertal;ARD:12421:hC34:S19.2E:27500:101:102=deu:104:0:28312:1:1201:0 +:@1000 New channels diff --git a/vdr/conf/keymacros.conf b/vdr/conf/keymacros.conf new file mode 100644 index 0000000..3b5d863 --- /dev/null +++ b/vdr/conf/keymacros.conf @@ -0,0 +1,22 @@ +# Remote control key macros for VDR +# +# Format: +# +# macrokey key1 key2 key3... +# macrokey @plugin key1 key2 key3... +# +# See man vdr(5) + +Red Recordings +Green Channels +Yellow Schedule +Blue Timers +User1 @pilotskin +User2 @epgsearch +User3 @extrecmenu +User4 Info +User5 @music +User6 Commands +User7 @osdteletext +User8 @sleeptimer +User9 @screenshot
\ No newline at end of file diff --git a/vdr/conf/noad-exclude-channels.conf b/vdr/conf/noad-exclude-channels.conf new file mode 100644 index 0000000..0b0ea5e --- /dev/null +++ b/vdr/conf/noad-exclude-channels.conf @@ -0,0 +1,53 @@ +PREMIERE START +PREMIERE 1 +PREMIERE 2 +PREMIERE 3 +PREMIERE 4 +PREMIERE Austria +PREMIERE DIREKT +D 1 +D 2 +D 3 +D 4 +D 5 +D 6 +D 7 +D 8 +D 9 +arena home (Premiere) +PREMIERE SPORT PORTAL +Bundesliga +Champ. League +Euroliga +Fussball +Motorsport +Wrestling +News +SCI FI +MGM +DISNEY CHANNEL +JETIX +JUNIOR +DISCOVERY CHANNEL +ANIMAL PLANET +DISCOVERY GESCHICHTE +FOCUS GESUNDHEIT +PREMIERE SERIE +PREMIERE KRIMI +PREMIERE FILMCLASSICS +PREMIERE FILMFEST +PREMIERE NOSTALGIE +13 TH STREET +HIT24 +CLASSICA +GOLDSTAR TV +HEIMATKANAL +BIG BROTHER +THEMA LIVE +BEATE-UHSE.TV +EROTIK +Erotik 1 +Erotik 2 +BLUE MOVIE +BLUE MOVIE Extra +BLUE MOVIE Gay diff --git a/vdr/conf/remote.conf b/vdr/conf/remote.conf new file mode 100644 index 0000000..ec40702 --- /dev/null +++ b/vdr/conf/remote.conf @@ -0,0 +1,180 @@ +KBD.Up 00000000001B5B41 +KBD.Down 00000000001B5B42 +KBD.Menu 000000000000006D +KBD.Ok 000000000000000D +KBD.Back 000000000000007F +KBD.Left 00000000001B5B44 +KBD.Right 00000000001B5B43 +KBD.Red 000000001B5B5B41 +KBD.Green 000000001B5B5B42 +KBD.Yellow 000000001B5B5B43 +KBD.Blue 000000001B5B5B44 +KBD.0 0000000000000030 +KBD.1 0000000000000031 +KBD.2 0000000000000032 +KBD.3 0000000000000033 +KBD.4 0000000000000034 +KBD.5 0000000000000035 +KBD.6 0000000000000036 +KBD.7 0000000000000037 +KBD.8 0000000000000038 +KBD.9 0000000000000039 +KBD.Volume+ 000000000000002B +KBD.Volume- 000000000000002D +KBD.Mute 0000000000000073 +remote-event2._Setup /proc/av7110_ir 00000000 31 +remote-event2.Up 0000000100010021 +remote-event2.Down 0000000100010022 +remote-event2.Menu 000000010001000E +remote-event2.Ok 0000000100010026 +remote-event2.Back 0000000100010020 +remote-event2.Left 0000000100010012 +remote-event2.Right 0000000100010011 +remote-event2.Red 000000010001000C +remote-event2.Green 000000010001002F +remote-event2.Yellow 0000000100010039 +remote-event2.Blue 000000010001002A +remote-event2.0 0000000100010001 +remote-event2.1 0000000100010002 +remote-event2.2 0000000100010003 +remote-event2.3 0000000100010004 +remote-event2.4 0000000100010005 +remote-event2.5 0000000100010006 +remote-event2.6 0000000100010007 +remote-event2.7 0000000100010008 +remote-event2.8 0000000100010009 +remote-event2.9 000000010001000A +remote-event2.Play 0000000100010036 +remote-event2.Pause 0000000100010031 +remote-event2.Stop 0000000100010037 +remote-event2.Record 0000000100010038 +remote-event2.FastFwd 0000000100010035 +remote-event2.FastRew 0000000100010033 +remote-event2.Channel+ 000000010001001F +remote-event2.Channel- 0000000100010025 +remote-event2.Volume+ 000000010001003D +remote-event2.Volume- 000000010001000D +remote-event2.Mute 0000000100010010 +remote-event2.Power 000000010001003C +LIRC.Up Up +LIRC.Down Down +LIRC.Menu Menu +LIRC.Ok Ok +LIRC.Back Back +LIRC.Left Left +LIRC.Right Right +LIRC.Red Red +LIRC.Green Green +LIRC.Yellow Yellow +LIRC.Blue Blue +LIRC.0 0 +LIRC.1 1 +LIRC.2 2 +LIRC.3 3 +LIRC.4 4 +LIRC.5 5 +LIRC.6 6 +LIRC.7 7 +LIRC.8 8 +LIRC.9 9 +LIRC.Info Info +LIRC.Play Play +LIRC.Pause Pause +LIRC.Stop Stop +LIRC.Record Record +LIRC.FastFwd FastFwd +LIRC.FastRew FastRew +LIRC.Next Next +LIRC.Prev Prev +LIRC.User1 User1 +LIRC.User2 User2 +LIRC.User3 User3 +LIRC.User4 User4 +LIRC.User5 User5 +LIRC.User6 User6 +LIRC.User7 User7 +LIRC.User8 User8 +LIRC.User9 User9 +LIRC.Channel+ Channel+ +LIRC.Channel- Channel- +LIRC.Volume+ Volume+ +LIRC.Volume- Volume- +LIRC.Mute Mute +LIRC.Audio Audio +LIRC.Power Power +softdevice-xv.Up 000000000000FF52 +softdevice-xv.Down 000000000000FF54 +softdevice-xv.Menu 000000000000006D +softdevice-xv.Ok 000000000000FF0D +softdevice-xv.Back 000000000000FF08 +softdevice-xv.Left 000000000000FF51 +softdevice-xv.Right 000000000000FF53 +softdevice-xv.Red 000000000000FFBE +softdevice-xv.Green 000000000000FFBF +softdevice-xv.Yellow 000000000000FFC0 +softdevice-xv.Blue 000000000000FFC1 +softdevice-xv.0 0000000000000030 +softdevice-xv.1 0000000000000031 +softdevice-xv.2 0000000000000032 +softdevice-xv.3 0000000000000033 +softdevice-xv.4 0000000000000034 +softdevice-xv.5 0000000000000035 +softdevice-xv.6 0000000000000036 +softdevice-xv.7 0000000000000037 +softdevice-xv.8 0000000000000038 +softdevice-xv.9 0000000000000039 +softdevice-xv.Channel+ 000000000000FF55 +softdevice-xv.Channel- 000000000000FF56 +softdevice-xv.Volume+ 000000000000FFAB +softdevice-xv.Volume- 000000000000FFAD +softdevice-xv.Mute 000000000000FFAA +softdevice-xv.Audio 000000000000FFAF +softdevice-xv.User1 000000000000FFC2 +softdevice-xv.User2 000000000000FFC3 +softdevice-xv.User3 000000000000FFC4 +softdevice-xv.User4 000000000000FFC5 +softdevice-xv.User5 000000000000FFC6 +softdevice-xv.User6 000000000000FFC7 +softdevice-xv.User7 000000000000FFC8 +softdevice-xv.User8 000000000000FFC9 +XKeySym.Up Up +XKeySym.Down Down +XKeySym.Menu m +XKeySym.Ok Return +XKeySym.Back BackSpace +XKeySym.Left Left +XKeySym.Right Right +XKeySym.Red F1 +XKeySym.Green F2 +XKeySym.Yellow F3 +XKeySym.Blue F4 +XKeySym.0 0 +XKeySym.1 1 +XKeySym.2 2 +XKeySym.3 3 +XKeySym.4 4 +XKeySym.5 5 +XKeySym.6 6 +XKeySym.7 7 +XKeySym.8 8 +XKeySym.9 9 +XKeySym.Info i +XKeySym.Play w +XKeySym.Pause p +XKeySym.Stop s +XKeySym.FastFwd v +XKeySym.FastRew c +XKeySym.Channel+ Prior +XKeySym.Channel- Next +XKeySym.Volume+ KP_Subtract +XKeySym.Volume- KP_Add +XKeySym.Mute KP_Multiply +XKeySym.Audio KP_Divide +XKeySym.User1 F5 +XKeySym.User2 F6 +XKeySym.User3 F7 +XKeySym.User4 F8 +XKeySym.User5 F9 +XKeySym.User6 F10 +XKeySym.User7 F11 +XKeySym.User8 F12 diff --git a/vdr/conf/shutdown.conf b/vdr/conf/shutdown.conf new file mode 100644 index 0000000..bb55a41 --- /dev/null +++ b/vdr/conf/shutdown.conf @@ -0,0 +1,68 @@ +# Global config file for vdrshutdown + +# Specify which wakeup-mode you prefer (0=none/1=acpi-wakeup/2=nvram-wakeup/3=extension-board) +WAKEUP_MODE="0" + + +### nvram-wakeup +## +# Read board configuration from specified configuration file (e.g: /etc/nvram-wakeup.conf) +NVRAM_CONFIG="" + +# Specify the iw (infowriter) name (e.g: gigabyte_5aa) +NVRAM_IWNAME="" + +# Try "nvram-wakeup --help", don't use --wakeupbefore here +NVRAM_OPT="" + +# Needs your mainboard a reboot? (0=false/1=true/2=allways) +NEED_REBOOT="0" + +# If you use grub-set-default X, enter (0-9) for X +GRUB_POWEROFF=2 + +# Do you use lilo instead of grub? (0=false/1=true) +LILO="0" + + +### acpi-wakeup, nvram-wakeup and extension-board +## +# Specify how many minutes before the programmed wakeuptime the computer should wake up +WAKEUP_BEFORE=5 + +# Set this to "0", "MAXIMAL", "INTERVAL" or your max-power-off-time in minutes +MAX_POWEROFF_TIME="0" + +# If you has set MAX_POWEROFF_TIME to "INTERVAL", specify the interval in days and your dreamtime in hours:minutes +INTERVAL="3" # days +DREAMTIME="03:00" # hours:minutes + +# Action if $MIN_WAKEUPTIME -gt $WAKEUPTIME +MIN_WAKEUP_VAR="0" + +# Waiting period in minutes if CHECK_PROCS is active +WAITING_PERIOD="15" + +# to abort the shutdown +# +# format: <tests> && <osd + logger message> +# +CHECK_PROCS=\ +" +test -s $VDRCONFDIR/plugins/queue.vdrrip && echo 'vdrrip laeuft' +pidof -x vdr-no-shutdown >/dev/null 2>&1 && echo 'vdr-no-shutdown laeuft' +pidof -x updateepg.sh >/dev/null 2>&1 && echo 'updateepg laeuft' +pidof -x tvm2vdr.pl >/dev/null 2>&1 && echo 'tvmovie2vdr laeuft' +pidof infosatepg >/dev/null 2>&1 && echo 'infosatepg laeuft' +pidof cutinplace >/dev/null 2>&1 && echo 'cutinplace laeuft' +pidof transcode >/dev/null 2>&1 && echo 'transcode laeuft' +pidof vcdimager >/dev/null 2>&1 && echo 'vcdimager laeuft' +pidof mencoder >/dev/null 2>&1 && echo 'mencoder laeuft' +pidof tosvcd >/dev/null 2>&1 && echo 'tosvcd laeuft' +pidof lame >/dev/null 2>&1 && echo 'lame laeuft' +pidof noad >/dev/null 2>&1 && echo 'noad laeuft' +netstat -n|grep ^tcp|egrep -q ':22 ' && echo 'ssh client(s) connected' +netstat -n|grep ^tcp|egrep -q ':139 ' && echo 'smb client(s) connected' +netstat -n|grep ^tcp|egrep -q ':2004 ' && echo 'streamdev client(s) connected' +grep -qs ^ /var/lib/nfs/rmtab && echo 'nfs client(s) connected' +" diff --git a/vdr/extensions/vdr-1.6.0-2-ext_dvb-api.diff b/vdr/extensions/vdr-1.6.0-2-ext_dvb-api.diff new file mode 100644 index 0000000..d7aedf6 --- /dev/null +++ b/vdr/extensions/vdr-1.6.0-2-ext_dvb-api.diff @@ -0,0 +1,14 @@ +diff -ruNp vdr-1.6.0-2-extensions/dvbdevice.h~ vdr-1.6.0-2-ext-softosd/dvbdevice.h +--- vdr-1.6.0-2-extensions/dvbdevice.h~ 2009-01-09 20:14:49.000000000 +0100 ++++ vdr-1.6.0-2-extensions/dvbdevice.h 2009-01-09 20:13:53.000000000 +0100 +@@ -15,8 +15,8 @@ + #include "device.h" + #include "dvbspu.h" + +-#if DVB_API_VERSION != 3 +-#error VDR requires Linux DVB driver API version 3! ++#if DVB_API_VERSION < 3 ++#error VDR requires Linux DVB driver API version 3 or greater! + #endif + + #define MAXDVBDEVICES 8 diff --git a/vdr/extensions/vdr-1.6.0-2_extensions.diff b/vdr/extensions/vdr-1.6.0-2_extensions.diff new file mode 100644 index 0000000..b168bab --- /dev/null +++ b/vdr/extensions/vdr-1.6.0-2_extensions.diff @@ -0,0 +1,27399 @@ +diff -ruNp vdr-1.6.0-2/channels.c vdr-1.6.0-2-extensions/channels.c +--- vdr-1.6.0-2/channels.c 2008-03-05 17:42:50.000000000 +0100 ++++ vdr-1.6.0-2-extensions/channels.c 2009-04-09 20:48:26.000000000 +0200 +@@ -13,6 +13,9 @@ + #include "device.h" + #include "epg.h" + #include "timers.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ + + // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' + // format characters in order to allow any number of blanks after a numeric +@@ -51,6 +54,9 @@ const tChannelParameterMap CoderateValue + + const tChannelParameterMap ModulationValues[] = { + { 0, QPSK }, ++#ifdef USE_ATSC ++ { 8, VSB_8 }, ++#endif /* ATSC */ + { 16, QAM_16 }, + { 32, QAM_32 }, + { 64, QAM_64 }, +@@ -166,6 +172,9 @@ cChannel::cChannel(void) + shortName = strdup(""); + provider = strdup(""); + portalName = strdup(""); ++#ifdef USE_PLUGINPARAM ++ pluginParam = strdup(""); ++#endif /* PLUGINPARAM */ + memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__); + inversion = INVERSION_AUTO; + bandwidth = BANDWIDTH_AUTO; +@@ -187,6 +196,9 @@ cChannel::cChannel(const cChannel &Chann + shortName = NULL; + provider = NULL; + portalName = NULL; ++#ifdef USE_PLUGINPARAM ++ pluginParam = NULL; ++#endif /* PLUGINPARAM */ + schedule = NULL; + linkChannels = NULL; + refChannel = NULL; +@@ -215,6 +227,9 @@ cChannel::~cChannel() + free(shortName); + free(provider); + free(portalName); ++#ifdef USE_PLUGINPARAM ++ free(pluginParam); ++#endif /* PLUGINPARAM */ + } + + cChannel& cChannel::operator= (const cChannel &Channel) +@@ -223,6 +238,9 @@ cChannel& cChannel::operator= (const cCh + shortName = strcpyrealloc(shortName, Channel.shortName); + provider = strcpyrealloc(provider, Channel.provider); + portalName = strcpyrealloc(portalName, Channel.portalName); ++#ifdef USE_PLUGINPARAM ++ pluginParam = strcpyrealloc(pluginParam, Channel.pluginParam); ++#endif /* PLUGINPARAM */ + memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__); + return *this; + } +@@ -280,9 +298,30 @@ void cChannel::CopyTransponderData(const + transmission = Channel->transmission; + guard = Channel->guard; + hierarchy = Channel->hierarchy; ++#ifdef USE_PLUGINPARAM ++ if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, Channel->pluginParam); ++#endif /* PLUGINPARAM */ + } + } + ++#ifdef USE_PLUGINPARAM ++bool cChannel::SetPlugTransponderData(int Source, int Frequency, const char *PluginParam) ++{ ++ if (source != Source || frequency != Frequency || (strcmp(pluginParam, PluginParam) != 0)) { ++ if (Number()) { ++ dsyslog("changing transponder data of channel %d from %s:%d:%s to %s:%d:%s", Number(), *cSource::ToString(source), frequency, pluginParam, *cSource::ToString(Source), Frequency, PluginParam); ++ modification |= CHANNELMOD_TRANSP; ++ Channels.SetModified(); ++ } ++ source = Source; ++ frequency = Frequency; ++ pluginParam = strcpyrealloc(pluginParam, PluginParam); ++ schedule = NULL; ++ } ++ return true; ++} ++#endif /* PLUGINPARAM */ ++ + bool cChannel::SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH) + { + // Workarounds for broadcaster stupidity: +@@ -382,6 +421,9 @@ void cChannel::SetName(const char *Name, + if (nn || ns || np) { + if (Number()) { + dsyslog("changing name of channel %d from '%s,%s;%s' to '%s,%s;%s'", Number(), name, shortName, provider, Name, ShortName, Provider); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(this, scMod); ++#endif /* STREAMDEVEXT */ + modification |= CHANNELMOD_NAME; + Channels.SetModified(); + } +@@ -407,6 +449,20 @@ void cChannel::SetPortalName(const char + } + } + ++#ifdef USE_PLUGINPARAM ++void cChannel::SetPluginParam(const char *PluginParam) ++{ ++ if (!isempty(PluginParam) && strcmp(pluginParam, PluginParam) != 0) { ++ if (Number()) { ++ dsyslog("changing plugin parameters of channel %d from '%s' to '%s'", Number(), pluginParam, PluginParam); ++ modification |= CHANNELMOD_TRANSP; ++ Channels.SetModified(); ++ } ++ pluginParam = strcpyrealloc(pluginParam, PluginParam); ++ } ++} ++#endif /* PLUGINPARAM */ ++ + #define STRDIFF 0x01 + #define VALDIFF 0x02 + +@@ -593,7 +649,11 @@ cString cChannel::ParametersToString(voi + if (isdigit(type)) + type = 'S'; + #define ST(s) if (strchr(s, type)) ++#ifdef USE_PLUGINPARAM ++ char buffer[256]; ++#else + char buffer[64]; ++#endif /* PLUGINPARAM */ + char *q = buffer; + *q = 0; + ST(" S ") q += sprintf(q, "%c", polarization); +@@ -605,6 +665,9 @@ cString cChannel::ParametersToString(voi + ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); + ST(" T") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues)); + ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); ++#ifdef USE_PLUGINPARAM ++ ST("P ") snprintf(buffer, sizeof(buffer), "%s", pluginParam); ++#endif /* PLUGINPARAM */ + return buffer; + } + +@@ -626,7 +689,11 @@ static const char *ParseParameter(const + + bool cChannel::StringToParameters(const char *s) + { ++#ifdef USE_PLUGINPARAM ++ while (s && *s && !IsPlug()) { ++#else + while (s && *s) { ++#endif /* PLUGINPARAM */ + switch (toupper(*s)) { + case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; + case 'C': s = ParseParameter(s, coderateH, CoderateValues); break; +@@ -736,7 +803,11 @@ bool cChannel::Parse(const char *s) + dpids[0] = 0; + ok = false; + if (parambuf && sourcebuf && vpidbuf && apidbuf) { ++#ifdef USE_PLUGINPARAM ++ ok = ((source = cSource::FromString(sourcebuf)) >= 0) && StringToParameters(parambuf); ++#else + ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; ++#endif /* PLUGINPARAM */ + + char *p = strchr(vpidbuf, '+'); + if (p) +@@ -827,6 +898,9 @@ bool cChannel::Parse(const char *s) + shortName = strcpyrealloc(shortName, p); + } + name = strcpyrealloc(name, namebuf); ++#ifdef USE_PLUGINPARAM ++ if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, parambuf); ++#endif /* PLUGINPARAM */ + + free(parambuf); + free(sourcebuf); +@@ -1072,6 +1146,9 @@ cChannel *cChannels::NewChannel(const cC + NewChannel->SetName(Name, ShortName, Provider); + Add(NewChannel); + ReNumber(); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NewChannel, scAdd); ++#endif /* STREAMDEVEXT */ + return NewChannel; + } + return NULL; +diff -ruNp vdr-1.6.0-2/channels.h vdr-1.6.0-2-extensions/channels.h +--- vdr-1.6.0-2/channels.h 2008-02-08 14:48:31.000000000 +0100 ++++ vdr-1.6.0-2-extensions/channels.h 2009-04-09 20:48:26.000000000 +0200 +@@ -114,6 +114,9 @@ private: + char *shortName; + char *provider; + char *portalName; ++#ifdef USE_PLUGINPARAM ++ char *pluginParam; ++#endif /* PLUGINPARAM */ + int __BeginData__; + int frequency; // MHz + int source; +@@ -165,6 +168,9 @@ public: + int Frequency(void) const { return frequency; } ///< Returns the actual frequency, as given in 'channels.conf' + int Transponder(void) const; ///< Returns the transponder frequency in MHz, plus the polarization in case of sat + static int Transponder(int Frequency, char Polarization); ///< builds the transponder from the given Frequency and Polarization ++#ifdef USE_PLUGINPARAM ++ const char *PluginParam(void) const { return pluginParam; } ++#endif /* PLUGINPARAM */ + int Source(void) const { return source; } + int Srate(void) const { return srate; } + int Vpid(void) const { return vpid; } +@@ -199,6 +205,9 @@ public: + int Hierarchy(void) const { return hierarchy; } + const cLinkChannels* LinkChannels(void) const { return linkChannels; } + const cChannel *RefChannel(void) const { return refChannel; } ++#ifdef USE_PLUGINPARAM ++ bool IsPlug(void) const { return cSource::IsPlug(source); } ++#endif /* PLUGINPARAM */ + bool IsCable(void) const { return cSource::IsCable(source); } + bool IsSat(void) const { return cSource::IsSat(source); } + bool IsTerr(void) const { return cSource::IsTerr(source); } +@@ -206,12 +215,18 @@ public: + bool HasTimer(void) const; + int Modification(int Mask = CHANNELMOD_ALL); + void CopyTransponderData(const cChannel *Channel); ++#ifdef USE_PLUGINPARAM ++ bool SetPlugTransponderData(int Source, int Frequency, const char *PluginParam); ++#endif /* PLUGINPARAM */ + bool SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH); + bool SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH); + bool SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CodeRateH, int CodeRateL, int Guard, int Transmission); + void SetId(int Nid, int Tid, int Sid, int Rid = 0); + void SetName(const char *Name, const char *ShortName, const char *Provider); + void SetPortalName(const char *PortalName); ++#ifdef USE_PLUGINPARAM ++ void SetPluginParam(const char *PluginParam); ++#endif /* PLUGINPARAM */ + void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid); + void SetCaIds(const int *CaIds); // list must be zero-terminated + void SetCaDescriptors(int Level); +diff -ruNp vdr-1.6.0-2/config.c vdr-1.6.0-2-extensions/config.c +--- vdr-1.6.0-2/config.c 2008-02-17 14:39:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/config.c 2009-04-09 20:48:26.000000000 +0200 +@@ -15,6 +15,9 @@ + #include "interface.h" + #include "plugin.h" + #include "recording.h" ++#ifdef USE_SOURCECAPS ++#include "sources.h" ++#endif /* SOURCECAPS */ + + // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' + // format characters in order to allow any number of blanks after a numeric +@@ -28,18 +31,32 @@ cCommand::cCommand(void) + { + title = command = NULL; + confirm = false; ++#ifdef USE_CMDSUBMENU ++ nIndent = 0; ++ childs = NULL; ++#endif /* CMDSUBMENU */ + } + + cCommand::~cCommand() + { + free(title); + free(command); ++#ifdef USE_CMDSUBMENU ++ delete childs; ++#endif /* CMDSUBMENU */ + } + + bool cCommand::Parse(const char *s) + { + const char *p = strchr(s, ':'); + if (p) { ++#ifdef USE_CMDSUBMENU ++ nIndent = 0; ++ while (*s == '-') { ++ nIndent++; ++ s++; ++ } ++#endif /* CMDSUBMENU */ + int l = p - s; + if (l > 0) { + title = MALLOC(char, l + 1); +@@ -85,6 +102,20 @@ const char *cCommand::Execute(const char + return result; + } + ++#ifdef USE_CMDSUBMENU ++int cCommand::getChildCount(void) ++{ ++ return childs ? childs->Count() : 0; ++} ++ ++void cCommand::addChild(cCommand *newChild) ++{ ++ if (!childs) ++ childs = new cCommands(); ++ childs->AddConfig(newChild); ++} ++#endif /* CMDSUBMENU */ ++ + // --- cSVDRPhost ------------------------------------------------------------ + + cSVDRPhost::cSVDRPhost(void) +@@ -125,6 +156,26 @@ bool cSVDRPhost::Accepts(in_addr_t Addre + + cCommands Commands; + cCommands RecordingCommands; ++#ifdef USE_TIMERCMD ++cCommands TimerCommands; ++#endif /* TIMERCMD */ ++ ++#ifdef USE_CMDSUBMENU ++void cCommands::AddConfig(cCommand *Object) ++{ ++ if (!Object) ++ return; ++ //isyslog ("Indent %d %s\n", Object->getIndent(), Object->Title()); ++ for (int index = Count() - 1; index >= 0; index--) { ++ cCommand *parent = Get(index); ++ if (parent->getIndent() < Object->getIndent()) { ++ parent->addChild(Object); ++ return; ++ } ++ } ++ cConfig<cCommand>::Add(Object); ++} ++#endif /* CMDSUBMENU */ + + // --- cSVDRPhosts ----------------------------------------------------------- + +@@ -216,6 +267,12 @@ cSetup::cSetup(void) + strcpy(OSDLanguage, ""); // default is taken from environment + strcpy(OSDSkin, "sttng"); + strcpy(OSDTheme, "default"); ++#ifdef USE_WAREAGLEICON ++ WarEagleIcons = 1; ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ ShowValidInput = 0; ++#endif /* VALIDINPUT */ + PrimaryDVB = 1; + ShowInfoOnChSwitch = 1; + TimeoutRequChInfo = 1; +@@ -260,6 +317,18 @@ cSetup::cSetup(void) + VideoFormat = 0; + UpdateChannels = 5; + UseDolbyDigital = 1; ++#ifdef USE_DOLBYINREC ++ UseDolbyInRecordings = 1; ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ DolbyTransferFix = 1; ++ ChannelBlocker = 0; ++ ChannelBlockerMode = 0; ++ ChannelBlockerList = strdup(""); ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ UseSyncEarlyPatch = 0; ++#endif /* SYNCEARLY */ + ChannelInfoPos = 0; + ChannelInfoTime = 5; + OSDLeft = 54; +@@ -276,24 +345,143 @@ cSetup::cSetup(void) + FontSmlSize = 18; + FontFixSize = 20; + MaxVideoFileSize = MAXVIDEOFILESIZE; ++#ifdef USE_HARDLINKCUTTER ++ MaxRecordingSize = DEFAULTRECORDINGSIZE; ++#endif /* HARDLINKCUTTER */ + SplitEditedFiles = 0; ++#ifdef USE_HARDLINKCUTTER ++ HardLinkCutter = 0; ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ DelTimeshiftRec = 0; ++#endif /* DELTIMESHIFTREC */ + MinEventTimeout = 30; + MinUserInactivity = 300; + NextWakeupTime = 0; + MultiSpeedMode = 0; + ShowReplayMode = 0; ++#ifdef USE_DDEPGENTRY ++ DoubleEpgTimeDelta = 15; ++ DoubleEpgAction = 0; ++ MixEpgAction = 0; ++ DisableVPS = 0; ++#endif /* DDEPGENTRY */ + ResumeID = 0; ++#ifdef USE_JUMPPLAY ++ JumpPlay = 0; ++ PlayJump = 0; ++ PauseLastMark = 0; ++ ReloadMarks = 0; ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ memset(SourceCaps, 0, sizeof SourceCaps); ++ SourceCapsSet = false; ++#endif /* SOURCECAPS */ + CurrentChannel = -1; + CurrentVolume = MAXVOLUME; + CurrentDolby = 0; + InitialChannel = 0; + InitialVolume = -1; ++#ifdef USE_VOLCTRL ++ LRVolumeControl = 0; ++ LRChannelGroups = 1; ++ LRForwardRewind = 1; ++#endif /* VOLCTRL */ + EmergencyExit = 1; ++#ifdef USE_NOEPG ++ noEPGMode = 0; ++ noEPGList = strdup(""); ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ LircRepeatDelay = 350; ++ LircRepeatFreq = 100; ++ LircRepeatTimeout = 500; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ ShowRecDate = 1; ++ ShowRecTime = 1; ++ ShowRecLength = 0; ++ ShowProgressBar = 0; ++ MenuCmdPosition = 0; ++ JumpSeconds = 60; ++ JumpSecondsSlow = 10; ++ ShowTimerStop = 1; ++ MainMenuTitle = 0; ++ strcpy(CustomMainMenuTitle, "Video Disk Recorder"); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ RecordingsSortMode = 0; ++ RecordingsSortDirsFirst = 0; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ CutterAutoDelete = 0; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ CutTime = 1; ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ LiveBuffer = false; ++ KeepPaused = false; ++ LiveBufferSize = 100; ++ InRAM = false; ++ MemBufSize = 5; ++ ExtendBuffer = false; ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ DvdDisplayMode = 1; ++ DvdDisplayZeros = 1; ++ DvdTrayMode = 0; ++ DvdSpeedLimit = 0; ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ UseSoftOsd = 0; ++ SoftOsdRate = 50; ++ SoftOsdFadeinSteps = 6; ++ SoftOsdFadeoutSteps = 16; ++ SoftOsdPaletteOnly = 0; ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ VerboseLNBlog = 0; ++ for (int i = 0; i < MAXDEVICES; i++) CardUsesLNBnr[i] = i + 1; ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ UseVidPrefer = 0; // default = disabled ++ nVidPrefer = 1; ++ for (int zz = 1; zz < DVLVIDPREFER_MAX; zz++) { ++ VidPreferPrio[ zz ] = 50; ++ VidPreferSize[ zz ] = 100; ++ } ++ VidPreferSize[ 0 ] = 800; ++ VidPreferPrio[ 0 ] = 50; ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ UseFriendlyFNames = 0; // default = disabled ++#endif /* DVLFRIENDLYFNAMES */ ++} ++ ++#if defined (USE_DVBSETUP) || defined (USE_NOEPG) ++cSetup::~cSetup() ++{ ++#ifdef USE_DVBSETUP ++ free(ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ free(noEPGList); ++#endif /* NOEPG */ + } ++#endif /* DVBSETUP + NOEPG */ + + cSetup& cSetup::operator= (const cSetup &s) + { + memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__); ++#ifdef USE_DVBSETUP ++ free(ChannelBlockerList); ++ ChannelBlockerList = strdup(s.ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ free(noEPGList); ++ noEPGList = strdup(s.noEPGList); ++#endif /* NOEPG */ + return *this; + } + +@@ -384,11 +572,62 @@ bool cSetup::ParseLanguages(const char * + return true; + } + ++#ifdef USE_SOURCECAPS ++void cSetup::StoreSourceCaps(const char *Name) ++{ ++ cSetupLine *l; ++ while ((l = Get(Name)) != NULL) ++ Del(l); ++ ++ for (int i = 0; i < MAXDEVICES; i++) { ++ char buffer[MAXSOURCECAPS*8]={0,}, *q = buffer; ++ int j = 0; ++ while (SourceCaps[i][j] && j < MAXSOURCECAPS) { ++ if (j==0) ++ q += snprintf(buffer, sizeof(buffer), "%i ", i+1); ++ q += snprintf(q, sizeof(buffer) - (q-buffer), "%s ", *cSource::ToString(SourceCaps[i][j++])); ++ } ++ if (*buffer) ++ Store(Name, buffer, NULL, true); ++ } ++} ++ ++bool cSetup::ParseSourceCaps(const char *Value) ++{ ++ char *p; ++ int d = strtol(Value, &p, 10)-1, i = 0; ++ while (p < Value+strlen(Value)) { ++ if (*p==0) return true; ++ if (isblank(*p)) ++p; ++ if (isalpha(*p)) { ++ int source = cSource::FromString(p); ++ if (source != cSource::stNone) { ++ SourceCaps[d][i++] = source; ++ SourceCapsSet = true; ++ } ++ else ++ return false; ++ while (!isblank(*p) && *p) ++ ++p; ++ if (i>MAXSOURCECAPS) ++ return false; ++ } ++ } ++ return true; ++} ++#endif /* SOURCECAPS */ ++ + bool cSetup::Parse(const char *Name, const char *Value) + { + if (!strcasecmp(Name, "OSDLanguage")) { strn0cpy(OSDLanguage, Value, sizeof(OSDLanguage)); I18nSetLocale(OSDLanguage); } + else if (!strcasecmp(Name, "OSDSkin")) Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName); + else if (!strcasecmp(Name, "OSDTheme")) Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName); ++#ifdef USE_WAREAGLEICON ++ else if (!strcasecmp(Name, "WarEagleIcons")) WarEagleIcons = atoi(Value); ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ else if (!strcasecmp(Name, "ShowValidInput")) ShowValidInput = atoi(Value); ++#endif /* VALIDINPUT */ + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "TimeoutRequChInfo")) TimeoutRequChInfo = atoi(Value); +@@ -433,6 +672,21 @@ bool cSetup::Parse(const char *Name, con + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value); + else if (!strcasecmp(Name, "UseDolbyDigital")) UseDolbyDigital = atoi(Value); ++#ifdef USE_DOLBYINREC ++ else if (!strcasecmp(Name, "UseDolbyInRecordings")) UseDolbyInRecordings = atoi(Value); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ else if (!strcasecmp(Name, "DolbyTransferFix")) DolbyTransferFix = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlocker")) ChannelBlocker = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlockerMode")) ChannelBlockerMode = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlockerList")) { ++ free(ChannelBlockerList); ++ ChannelBlockerList = strdup(Value ? Value : ""); ++ } ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ else if (!strcasecmp(Name, "UseSyncEarlyPatch")) UseSyncEarlyPatch = atoi(Value); ++#endif /* SYNCEARLY */ + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoTime")) ChannelInfoTime = atoi(Value); + else if (!strcasecmp(Name, "OSDLeft")) OSDLeft = atoi(Value); +@@ -449,21 +703,152 @@ bool cSetup::Parse(const char *Name, con + else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value); + else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); ++#ifdef USE_HARDLINKCUTTER ++ else if (!strcasecmp(Name, "MaxRecordingSize")) MaxRecordingSize = atoi(Value); ++#endif /* HARDLINKCUTTER */ + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); ++#ifdef USE_HARDLINKCUTTER ++ else if (!strcasecmp(Name, "HardLinkCutter")) HardLinkCutter = atoi(Value); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value); ++#endif /* DELTIMESHIFTREC */ + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); ++#ifdef USE_DDEPGENTRY ++ else if (!strcasecmp(Name, "DoubleEpgTimeDelta")) DoubleEpgTimeDelta = atoi(Value); ++ else if (!strcasecmp(Name, "DoubleEpgAction")) DoubleEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "MixEpgAction")) MixEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "DisableVPS")) DisableVPS = atoi(Value); ++#endif /* DDEPGENTRY */ + else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value); ++#ifdef USE_JUMPPLAY ++ else if (!strcasecmp(Name, "JumpPlay")) JumpPlay = atoi(Value); ++ else if (!strcasecmp(Name, "PlayJump")) PlayJump = atoi(Value); ++ else if (!strcasecmp(Name, "PauseLastMark")) PauseLastMark = atoi(Value); ++ else if (!strcasecmp(Name, "ReloadMarks")) ReloadMarks = atoi(Value); ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ else if (!strcasecmp(Name, "SourceCaps")) return ParseSourceCaps(Value); ++#endif /* SOURCECAPS */ + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); + else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value); + else if (!strcasecmp(Name, "InitialChannel")) InitialChannel = atoi(Value); + else if (!strcasecmp(Name, "InitialVolume")) InitialVolume = atoi(Value); ++#ifdef USE_VOLCTRL ++ else if (!strcasecmp(Name, "LRVolumeControl")) LRVolumeControl = atoi(Value); ++ else if (!strcasecmp(Name, "LRChannelGroups")) LRChannelGroups = atoi(Value); ++ else if (!strcasecmp(Name, "LRForwardRewind")) LRForwardRewind = atoi(Value); ++#endif /* VOLCTRL */ + else if (!strcasecmp(Name, "EmergencyExit")) EmergencyExit = atoi(Value); ++#ifdef USE_NOEPG ++ else if (!strcasecmp(Name, "noEPGMode")) noEPGMode = atoi(Value); ++ else if (!strcasecmp(Name, "noEPGList")) { ++ free(noEPGList); ++ noEPGList = strdup(Value ? Value : ""); ++ } ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ else if (!strcasecmp(Name, "LircRepeatDelay")) LircRepeatDelay = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatFreq")) LircRepeatFreq = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatTimeout")) LircRepeatTimeout = atoi(Value); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ else if (!strcasecmp(Name, "ShowRecDate")) ShowRecDate = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecTime")) ShowRecTime = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecLength")) ShowRecLength = atoi(Value); ++ else if (!strcasecmp(Name, "ShowProgressBar")) ShowProgressBar = atoi(Value); ++ else if (!strcasecmp(Name, "MenuCmdPosition")) MenuCmdPosition = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSeconds")) JumpSeconds = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSecondsSlow")) JumpSecondsSlow = atoi(Value); ++ else if (!strcasecmp(Name, "ShowTimerStop")) ShowTimerStop = atoi(Value); ++ else if (!strcasecmp(Name, "MainMenuTitle")) MainMenuTitle = atoi(Value); ++ else if (!strcasecmp(Name, "CustomMainMenuTitle")) Utf8Strn0Cpy(CustomMainMenuTitle, Value, MaxTitleName); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ else if (!strcasecmp(Name, "RecordingsSortMode")) RecordingsSortMode = atoi(Value); ++ else if (!strcasecmp(Name, "RecordingsSortDirsFirst")) RecordingsSortDirsFirst = atoi(Value); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ else if (!strcasecmp(Name, "CutterAutoDelete")) CutterAutoDelete = atoi(Value); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ else if (!strcasecmp(Name, "CutTime")) CutTime = atoi(Value); ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ else if (!strcasecmp(Name, "LiveBuffer")) LiveBuffer = atoi(Value); ++ else if (!strcasecmp(Name, "KeepPaused")) KeepPaused = atoi(Value); ++ else if (!strcasecmp(Name, "LiveBufferSize")) LiveBufferSize = atoi(Value); ++ else if (!strcasecmp(Name, "InRAM")) InRAM = atoi(Value); ++ else if (!strcasecmp(Name, "MemBufSize")) MemBufSize = atoi(Value); ++ else if (!strcasecmp(Name, "ExtendBuffer")) ExtendBuffer = atoi(Value); ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ else if (!strcasecmp(Name, "DvdDisplayMode")) DvdDisplayMode = atoi(Value); ++ else if (!strcasecmp(Name, "DvdDisplayZeros")) DvdDisplayZeros = atoi(Value); ++ else if (!strcasecmp(Name, "DvdTrayMode")) DvdTrayMode = atoi(Value); ++ else if (!strcasecmp(Name, "DvdSpeedLimit")) DvdSpeedLimit = atoi(Value); ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ else if (!strcasecmp(Name, "UseSoftOsd")) UseSoftOsd = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdRate")) SoftOsdRate = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdFadeinSteps")) SoftOsdFadeinSteps = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdFadeoutSteps")) SoftOsdFadeoutSteps = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdPaletteOnly")) SoftOsdPaletteOnly = atoi(Value); ++#endif /* SOFTOSD */ ++#ifdef USE_DVLVIDPREFER ++ else if (strcasecmp(Name, "UseVidPrefer") == 0) UseVidPrefer = atoi(Value); ++ else if (strcasecmp(Name, "nVidPrefer") == 0) nVidPrefer = atoi(Value); ++ else if (strstr(Name, "VidPrefer") == Name) { ++ char *x = (char *)&Name[ strlen(Name) - 1 ]; ++ int vN; ++ ++ if (isdigit(*x) != 0) { ++ while (isdigit(*x) != 0) ++ x--; ++ x++; ++ } ++ ++ vN = atoi(x); ++ if (vN < DVLVIDPREFER_MAX) { ++ if (strstr(Name, "VidPreferPrio") == Name) { ++ VidPreferPrio[ vN ] = atoi(Value); ++ if (VidPreferPrio[ vN ] > 99) ++ VidPreferPrio[ vN ] = 99; ++ } ++ else if (strstr(Name, "VidPreferSize") == Name) { ++ VidPreferSize[ vN ] = atoi(Value); ++ } ++ else ++ return false; ++ } ++ } ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ else if (strcasecmp(Name, "UseFriendlyFNames") == 0) UseFriendlyFNames = atoi(Value); ++#endif /* DVLFRIENDLYFNAMES */ + else ++#ifdef USE_LNBSHARE ++ if (!strcasecmp(Name, "VerboseLNBlog")) VerboseLNBlog = atoi(Value); ++ else { ++ char tmp[20]; ++ bool result = false; ++ for (int i = 1; i <= MAXDEVICES; i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ if (!strcasecmp(Name, tmp)) { ++ CardUsesLNBnr[i - 1] = atoi(Value); ++ result = true; ++ } ++ } ++ return result; ++ } ++#else + return false; ++#endif /* LNBSHARE */ + return true; + } + +@@ -472,6 +857,12 @@ bool cSetup::Save(void) + Store("OSDLanguage", OSDLanguage); + Store("OSDSkin", OSDSkin); + Store("OSDTheme", OSDTheme); ++#ifdef USE_WAREAGLEICON ++ Store("WarEagleIcons", WarEagleIcons); ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ Store("ShowValidInput", ShowValidInput); ++#endif /* VALIDINPUT */ + Store("PrimaryDVB", PrimaryDVB); + Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); + Store("TimeoutRequChInfo", TimeoutRequChInfo); +@@ -516,6 +907,18 @@ bool cSetup::Save(void) + Store("VideoFormat", VideoFormat); + Store("UpdateChannels", UpdateChannels); + Store("UseDolbyDigital", UseDolbyDigital); ++#ifdef USE_DOLBYINREC ++ Store("UseDolbyInRecordings", UseDolbyInRecordings); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ Store("DolbyTransferFix", DolbyTransferFix); ++ Store("ChannelBlocker", ChannelBlocker); ++ Store("ChannelBlockerMode", ChannelBlockerMode); ++ Store("ChannelBlockerList", ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ Store("UseSyncEarlyPatch", UseSyncEarlyPatch); ++#endif /* SYNCEARLY */ + Store("ChannelInfoPos", ChannelInfoPos); + Store("ChannelInfoTime", ChannelInfoTime); + Store("OSDLeft", OSDLeft); +@@ -532,25 +935,164 @@ bool cSetup::Save(void) + Store("FontSmlSize", FontSmlSize); + Store("FontFixSize", FontFixSize); + Store("MaxVideoFileSize", MaxVideoFileSize); ++#ifdef USE_HARDLINKCUTTER ++ Store("MaxRecordingSize", MaxRecordingSize); ++#endif /* HARDLINKCUTTER */ + Store("SplitEditedFiles", SplitEditedFiles); ++#ifdef USE_HARDLINKCUTTER ++ Store("HardLinkCutter", HardLinkCutter); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ Store("DelTimeshiftRec", DelTimeshiftRec); ++#endif /* DELTIMESHIFTREC */ + Store("MinEventTimeout", MinEventTimeout); + Store("MinUserInactivity", MinUserInactivity); + Store("NextWakeupTime", NextWakeupTime); ++#ifdef USE_DDEPGENTRY ++ Store("DoubleEpgAction", DoubleEpgAction); ++ Store("MixEpgAction", MixEpgAction); ++ Store("DisableVPS", DisableVPS); ++ Store("DoubleEpgTimeDelta", DoubleEpgTimeDelta); ++#endif /* DDEPGENTRY */ + Store("MultiSpeedMode", MultiSpeedMode); + Store("ShowReplayMode", ShowReplayMode); + Store("ResumeID", ResumeID); ++#ifdef USE_JUMPPLAY ++ Store("JumpPlay", JumpPlay); ++ Store("PlayJump", PlayJump); ++ Store("PauseLastMark", PauseLastMark); ++ Store("ReloadMarks", ReloadMarks); ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ if (SourceCapsSet) StoreSourceCaps("SourceCaps"); ++#endif /* SOURCECAPS */ + Store("CurrentChannel", CurrentChannel); + Store("CurrentVolume", CurrentVolume); + Store("CurrentDolby", CurrentDolby); + Store("InitialChannel", InitialChannel); + Store("InitialVolume", InitialVolume); ++#ifdef USE_VOLCTRL ++ Store("LRVolumeControl", LRVolumeControl); ++ Store("LRChannelGroups", LRChannelGroups); ++ Store("LRForwardRewind", LRForwardRewind); ++#endif /* VOLCTRL */ + Store("EmergencyExit", EmergencyExit); ++#ifdef USE_NOEPG ++ Store("noEPGMode", noEPGMode); ++ Store("noEPGList", noEPGList); ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ Store("LircRepeatDelay", LircRepeatDelay); ++ Store("LircRepeatFreq", LircRepeatFreq); ++ Store("LircRepeatTimeout", LircRepeatTimeout); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ Store("ShowRecDate", ShowRecDate); ++ Store("ShowRecTime", ShowRecTime); ++ Store("ShowRecLength", ShowRecLength); ++ Store("ShowProgressBar", ShowProgressBar); ++ Store("MenuCmdPosition", MenuCmdPosition); ++ Store("JumpSeconds", JumpSeconds); ++ Store("JumpSecondsSlow", JumpSecondsSlow); ++ Store("ShowTimerStop", ShowTimerStop); ++ Store("MainMenuTitle", MainMenuTitle); ++ Store("CustomMainMenuTitle",CustomMainMenuTitle); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ Store("RecordingsSortMode", RecordingsSortMode); ++ Store("RecordingsSortDirsFirst", RecordingsSortDirsFirst); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Store("CutterAutoDelete", CutterAutoDelete); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ Store("CutTime", CutTime); ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ Store("LiveBuffer", LiveBuffer); ++ Store("KeepPaused", KeepPaused); ++ Store("LiveBufferSize", LiveBufferSize); ++ Store("InRAM", InRAM); ++ Store("MemBufSize", MemBufSize); ++ Store("ExtendBuffer", ExtendBuffer); ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ Store("DvdDisplayMode", DvdDisplayMode); ++ Store("DvdDisplayZeros", DvdDisplayZeros); ++ Store("DvdTrayMode", DvdTrayMode); ++ Store("DvdSpeedLimit", DvdSpeedLimit); ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ Store("UseSoftOsd", UseSoftOsd); ++ Store("SoftOsdRate", SoftOsdRate); ++ Store("SoftOsdFadeinSteps", SoftOsdFadeinSteps); ++ Store("SoftOsdFadeoutSteps", SoftOsdFadeoutSteps); ++ Store("SoftOsdPaletteOnly", SoftOsdPaletteOnly); ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ Store("VerboseLNBlog", VerboseLNBlog); ++ char tmp[20]; ++ if (cDevice::NumDevices() > 1) { ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ Store(tmp, CardUsesLNBnr[i - 1]); ++ } ++ } ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ Store ("UseVidPrefer", UseVidPrefer); ++ Store ("nVidPrefer", nVidPrefer); ++ ++ char vidBuf[32]; ++ for (int zz = 0; zz < nVidPrefer; zz++) { ++ sprintf(vidBuf, "VidPreferPrio%d", zz); ++ Store (vidBuf, VidPreferPrio[zz]); ++ sprintf(vidBuf, "VidPreferSize%d", zz); ++ Store (vidBuf, VidPreferSize[zz]); ++ } ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ Store ("UseFriendlyFNames", UseFriendlyFNames); ++#endif /* DVLFRIENDLYFNAMES */ + + Sort(); + + if (cConfig<cSetupLine>::Save()) { + isyslog("saved setup to %s", FileName()); ++#ifdef USE_DVDARCHIVE ++ if (DvdDisplayMode >= 1) ::Recordings.Load(); ++#endif /* DVDARCHIVE */ + return true; + } + return false; + } ++ ++#ifdef USE_CMDRECCMDI18N ++bool LoadCommandsI18n(cCommands & cmds, const char *FileName, bool AllowComments, bool MustExist) ++{ ++ ++ bool bRet = true; ++ bool bLoadDefault = (bool)strcmp(Setup.OSDLanguage,"en_US"); ++ if (bLoadDefault) { ++ // attempt to load a translated file ++ char *FullPath = NULL; ++ asprintf(&FullPath, "%s.%s", FileName, Setup.OSDLanguage); ++ if (!cmds.Load((FullPath), AllowComments, true)) { ++ // require to exist, just to be able to log ++ // fallback ++ bLoadDefault = false; ++ esyslog("Failed to load translated '%s' for language (%s)", FullPath, Setup.OSDLanguage); ++ esyslog("Falling back to default '%s' (if any)", FileName); ++ } ++ free(FullPath); ++ } ++ if (!bLoadDefault) { ++ // let's do it the normal way ++ bRet = cmds.Load(FileName, AllowComments, MustExist); ++ } ++ // return status only for the default commands file ++ return bRet; ++} ++ ++#endif /* CMDRECCMDI18N */ ++ +diff -ruNp vdr-1.6.0-2/config.h vdr-1.6.0-2-extensions/config.h +--- vdr-1.6.0-2/config.h 2008-09-11 13:29:43.000000000 +0200 ++++ vdr-1.6.0-2-extensions/config.h 2009-04-09 20:48:26.000000000 +0200 +@@ -36,23 +36,74 @@ + // plugins to work with newer versions of the core VDR as long as no + // VDR header files have changed. + ++#define VDREXTENSIONS 70 ++ ++#ifdef USE_JUMPPLAY ++#define JUMPPLAYVERSNUM 100 ++#endif /* JUMPPLAY */ ++ ++#ifdef USE_LIEMIEXT ++#define LIEMIKUUTIO 121 ++#define MAXMAINMENUTITLE 4 ++#define MaxTitleName 64 ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_CMDSUBMENU ++#define CMDSUBMENUVERSNUM 7 ++#endif /* CMDSUBMENU */ ++ ++#ifdef USE_MAINMENUHOOKS ++#define MAINMENUHOOKSVERSNUM 1.0 ++#endif /* MAINMENUHOOKS */ ++ ++#ifdef USE_PINPLUGIN ++#define PIN_PLUGIN_PATCH 120 ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_PLUGINPARAM ++#define PLUGINPARAMPATCHVERSNUM 1 ++#endif /* PLUGINPARAM */ ++ + #define MAXPRIORITY 99 + #define MAXLIFETIME 99 + ++#ifdef USE_DVLVIDPREFER ++#define DVLVIDPREFER_MAX 12 ++#endif /* DVLVIDPREFER */ ++ + #define MINOSDWIDTH 480 + #define MAXOSDWIDTH 672 + #define MINOSDHEIGHT 324 + #define MAXOSDHEIGHT 567 + ++#ifdef USE_SOURCECAPS ++#define MAXDEVICES 16 // the maximum number of devices in the system ++#define MAXSOURCECAPS 128 // the maximum number of different sources per device ++#endif /* SOURCECAPS */ ++ ++#ifdef USE_LNBSHARE ++#ifndef MAXDEVICES ++#define MAXDEVICES 16 // the maximum number of devices in the system ++#endif ++#endif /* LNBSHARE */ ++ + #define MaxFileName 256 + #define MaxSkinName 16 + #define MaxThemeName 16 + ++#ifdef USE_CMDSUBMENU ++class cCommands; ++#endif /* CMDSUBMENU */ ++ + class cCommand : public cListObject { + private: + char *title; + char *command; + bool confirm; ++#ifdef USE_CMDSUBMENU ++ int nIndent; ++ cCommands *childs; ++#endif /* CMDSUBMENU */ + static char *result; + public: + cCommand(void); +@@ -61,6 +112,14 @@ public: + const char *Title(void) { return title; } + bool Confirm(void) { return confirm; } + const char *Execute(const char *Parameters = NULL); ++#ifdef USE_CMDSUBMENU ++ int getIndent(void) { return nIndent; } ++ void setIndent(int nNewIndent) { nIndent = nNewIndent; } ++ cCommands *getChilds(void) { return childs; } ++ int getChildCount(void); ++ bool hasChilds(void) { return getChildCount() > 0; } ++ void addChild(cCommand *newChild); ++#endif /* CMDSUBMENU */ + }; + + typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2) +@@ -88,6 +147,9 @@ private: + public: + cConfig(void) { fileName = NULL; } + virtual ~cConfig() { free(fileName); } ++#ifdef USE_CMDSUBMENU ++ virtual void AddConfig(T *Object) { cList<T>::Add(Object); } ++#endif /* CMDSUBMENU */ + const char *FileName(void) { return fileName; } + bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false) + { +@@ -117,7 +179,11 @@ public: + if (!isempty(s)) { + T *l = new T; + if (l->Parse(s)) ++#ifdef USE_CMDSUBMENU ++ AddConfig(l); ++#else + Add(l); ++#endif /* CMDSUBMENU */ + else { + esyslog("ERROR: error in %s, line %d", fileName, line); + delete l; +@@ -159,7 +225,14 @@ public: + } + }; + ++#ifdef USE_CMDSUBMENU ++class cCommands : public cConfig<cCommand> { ++public: ++ virtual void AddConfig(cCommand *Object); ++ }; ++#else + class cCommands : public cConfig<cCommand> {}; ++#endif /* CMDSUBMENU */ + + class cSVDRPhosts : public cConfig<cSVDRPhost> { + public: +@@ -168,6 +241,9 @@ public: + + extern cCommands Commands; + extern cCommands RecordingCommands; ++#ifdef USE_TIMERCMD ++extern cCommands TimerCommands; ++#endif /* TIMERCMD */ + extern cSVDRPhosts SVDRPhosts; + + class cSetupLine : public cListObject { +@@ -193,6 +269,10 @@ private: + void StoreLanguages(const char *Name, int *Values); + bool ParseLanguages(const char *Value, int *Values); + bool Parse(const char *Name, const char *Value); ++#ifdef USE_SOURCECAPS ++ void StoreSourceCaps(const char *Name); ++ bool ParseSourceCaps(const char *Value); ++#endif /* SOURCECAPS */ + cSetupLine *Get(const char *Name, const char *Plugin = NULL); + void Store(const char *Name, const char *Value, const char *Plugin = NULL, bool AllowMultiple = false); + void Store(const char *Name, int Value, const char *Plugin = NULL); +@@ -202,6 +282,12 @@ public: + char OSDLanguage[I18N_MAX_LOCALE_LEN]; + char OSDSkin[MaxSkinName]; + char OSDTheme[MaxThemeName]; ++#ifdef USE_WAREAGLEICON ++ int WarEagleIcons; ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ int ShowValidInput; ++#endif /* VALIDINPUT */ + int PrimaryDVB; + int ShowInfoOnChSwitch; + int TimeoutRequChInfo; +@@ -242,6 +328,17 @@ public: + int VideoFormat; + int UpdateChannels; + int UseDolbyDigital; ++#ifdef USE_DOLBYINREC ++ int UseDolbyInRecordings; ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ int DolbyTransferFix; ++ int ChannelBlocker; ++ int ChannelBlockerMode; ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ int UseSyncEarlyPatch; ++#endif /* SYNCEARLY */ + int ChannelInfoPos; + int ChannelInfoTime; + int OSDLeft, OSDTop, OSDWidth, OSDHeight; +@@ -255,20 +352,119 @@ public: + int FontSmlSize; + int FontFixSize; + int MaxVideoFileSize; ++#ifdef USE_HARDLINKCUTTER ++ int MaxRecordingSize; ++#endif /* HARDLINKCUTTER */ + int SplitEditedFiles; ++#ifdef USE_HARDLINKCUTTER ++ int HardLinkCutter; ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ int DelTimeshiftRec; ++#endif /* DELTIMESHIFTREC */ + int MinEventTimeout, MinUserInactivity; + time_t NextWakeupTime; + int MultiSpeedMode; + int ShowReplayMode; ++#ifdef USE_DDEPGENTRY ++ int DoubleEpgTimeDelta; ++ int DoubleEpgAction; ++ int MixEpgAction; ++ int DisableVPS; ++#endif /* DDEPGENTRY */ + int ResumeID; ++#ifdef USE_JUMPPLAY ++ int JumpPlay; ++ int PlayJump; ++ int PauseLastMark; ++ int ReloadMarks; ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ int SourceCaps[MAXDEVICES][MAXSOURCECAPS]; ++ bool SourceCapsSet; ++#endif /* SOURCECAPS */ + int CurrentChannel; + int CurrentVolume; + int CurrentDolby; + int InitialChannel; + int InitialVolume; ++#ifdef USE_VOLCTRL ++ int LRVolumeControl; ++ int LRChannelGroups; ++ int LRForwardRewind; ++#endif /* VOLCTRL */ + int EmergencyExit; ++#ifdef USE_NOEPG ++ int noEPGMode; ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ int LircRepeatDelay; ++ int LircRepeatFreq; ++ int LircRepeatTimeout; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ int ShowRecDate, ShowRecTime, ShowRecLength, ShowProgressBar, MenuCmdPosition; ++ int JumpSeconds; ++ int JumpSecondsSlow; ++ int ShowTimerStop; ++ int MainMenuTitle; ++ char CustomMainMenuTitle[MaxTitleName]; ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ int RecordingsSortMode; ++ int RecordingsSortDirsFirst; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ int CutterAutoDelete; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ int CutTime; ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ int LiveBuffer; ++ int KeepPaused; ++ int LiveBufferSize; ++ int InRAM; ++ int MemBufSize; ++ int ExtendBuffer; ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ int DvdDisplayMode; ++ int DvdDisplayZeros; ++ int DvdTrayMode; ++ int DvdSpeedLimit; ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ int UseSoftOsd; ++ int SoftOsdRate; ++ int SoftOsdFadeinSteps; ++ int SoftOsdFadeoutSteps; ++ int SoftOsdPaletteOnly; ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ int VerboseLNBlog; ++ int CardUsesLNBnr[MAXDEVICES]; ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ int UseVidPrefer; // 0 = VDR's default, 1 = use ++ int nVidPrefer; ++ int VidPreferPrio[DVLVIDPREFER_MAX]; ++ int VidPreferSize[DVLVIDPREFER_MAX]; ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ int UseFriendlyFNames; ++#endif /* DVLFRIENDLYFNAMES */ + int __EndData__; ++#ifdef USE_DVBSETUP ++ char *ChannelBlockerList; ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ char *noEPGList; // pointer not to be flat-copied ++#endif /* NOEPG */ + cSetup(void); ++#if defined (USE_DVBSETUP) || defined (USE_NOEPG) ++ ~cSetup(); ++#endif /* DVBSETUP + NOEPG */ + cSetup& operator= (const cSetup &s); + bool Load(const char *FileName); + bool Save(void); +@@ -276,4 +472,8 @@ public: + + extern cSetup Setup; + ++#ifdef USE_CMDRECCMDI18N ++bool LoadCommandsI18n(cCommands & cmds, const char *FileName = NULL, bool AllowComments = false, bool MustExist = false); ++#endif /* CMDRECCMDI18N */ ++ + #endif //__CONFIG_H +diff -ruNp vdr-1.6.0-2/cutter.c vdr-1.6.0-2-extensions/cutter.c +--- vdr-1.6.0-2/cutter.c 2008-01-13 13:22:21.000000000 +0100 ++++ vdr-1.6.0-2-extensions/cutter.c 2009-04-09 20:48:26.000000000 +0200 +@@ -15,6 +15,19 @@ + + // --- cCuttingThread -------------------------------------------------------- + ++#ifdef USE_CUTTERLIMIT ++#ifndef CUTTER_MAX_BANDWIDTH ++# define CUTTER_MAX_BANDWIDTH MEGABYTE(10) // 10 MB/s ++#endif ++#ifndef CUTTER_REL_BANDWIDTH ++# define CUTTER_REL_BANDWIDTH 75 // % ++#endif ++#ifndef CUTTER_PRIORITY ++# define CUTTER_PRIORITY sched_get_priority_min(SCHED_OTHER) ++#endif ++#define CUTTER_TIMESLICE 100 // ms ++#endif /* CUTTERLIMIT */ ++ + class cCuttingThread : public cThread { + private: + const char *error; +@@ -60,6 +73,22 @@ cCuttingThread::~cCuttingThread() + + void cCuttingThread::Action(void) + { ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) ++#endif /* HARDLINKCUTTER */ ++ { ++ sched_param tmp; ++ tmp.sched_priority = CUTTER_PRIORITY; ++ if (!pthread_setschedparam(pthread_self(), SCHED_OTHER, &tmp)) ++ printf("cCuttingThread::Action: cant set priority\n"); ++ } ++ ++ int bytes = 0; ++ int __attribute__((unused)) burst_size = CUTTER_MAX_BANDWIDTH * CUTTER_TIMESLICE / 1000; // max bytes/timeslice ++ cTimeMs __attribute__((unused)) t; ++#endif /* CUTTERLIMIT */ ++ + cMark *Mark = fromMarks.First(); + if (Mark) { + fromFile = fromFileName->Open(); +@@ -71,6 +100,9 @@ void cCuttingThread::Action(void) + Mark = fromMarks.Next(Mark); + int FileSize = 0; + int CurrentFileNumber = 0; ++#ifdef USE_HARDLINKCUTTER ++ bool SkipThisSourceFile = false; ++#endif /* HARDLINKCUTTER */ + int LastIFrame = 0; + toMarks.Add(0); + toMarks.Save(); +@@ -88,12 +120,99 @@ void cCuttingThread::Action(void) + + // Read one frame: + ++#ifndef USE_HARDLINKCUTTER + if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { + if (FileNumber != CurrentFileNumber) { + fromFile = fromFileName->SetOffset(FileNumber, FileOffset); + fromFile->SetReadAhead(MEGABYTE(20)); + CurrentFileNumber = FileNumber; + } ++#else ++ if (!fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { ++ error = "index"; ++ break; ++ } ++ ++ if (FileNumber != CurrentFileNumber) { ++ fromFile = fromFileName->SetOffset(FileNumber, FileOffset); ++ fromFile->SetReadAhead(MEGABYTE(20)); ++ CurrentFileNumber = FileNumber; ++ if (SkipThisSourceFile) { ++ // At end of fast forward: Always skip to next file ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 4"; ++ break; ++ } ++ FileSize = 0; ++ SkipThisSourceFile = false; ++ } ++ ++ ++ if (Setup.HardLinkCutter && FileOffset == 0) { ++ // We are at the beginning of a new source file. ++ // Do we need to copy the whole file? ++ ++ // if !Mark && LastMark, then we're past the last cut-out and continue to next I-frame ++ // if !Mark && !LastMark, then there's just a cut-in, but no cut-out ++ // if Mark, then we're between a cut-in and a cut-out ++ ++ uchar MarkFileNumber; ++ int MarkFileOffset; ++ // Get file number of next cut mark ++ if (!Mark && !LastMark ++ || Mark ++ && fromIndex->Get(Mark->position, &MarkFileNumber, &MarkFileOffset) ++ && (MarkFileNumber != CurrentFileNumber)) { ++ // The current source file will be copied completely. ++ // Start new output file unless we did that already ++ if (FileSize != 0) { ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 3"; ++ break; ++ } ++ FileSize = 0; ++ } ++ ++ // Safety check that file has zero size ++ struct stat buf; ++ if (stat(toFileName->Name(), &buf) == 0) { ++ if (buf.st_size != 0) { ++ esyslog("cCuttingThread: File %s exists and has nonzero size", toFileName->Name()); ++ error = "nonzero file exist"; ++ break; ++ } ++ } ++ else if (errno != ENOENT) { ++ esyslog("cCuttingThread: stat failed on %s", toFileName->Name()); ++ error = "stat"; ++ break; ++ } ++ ++ // Clean the existing 0-byte file ++ toFileName->Close(); ++ cString ActualToFileName(ReadLink(toFileName->Name()), true); ++ unlink(ActualToFileName); ++ unlink(toFileName->Name()); ++ ++ // Try to create a hard link ++ if (HardLinkVideoFile(fromFileName->Name(), toFileName->Name())) { ++ // Success. Skip all data transfer for this file ++ SkipThisSourceFile = true; ++ cutIn = false; ++ toFile = NULL; // was deleted by toFileName->Close() ++ } ++ else { ++ // Fallback: Re-open the file if necessary ++ toFile = toFileName->Open(); ++ } ++ } ++ } ++ } ++ ++ if (!SkipThisSourceFile) { ++#endif /* HARDLINKCUTTER */ + if (fromFile) { + int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); + if (len < 0) { +@@ -110,6 +229,7 @@ void cCuttingThread::Action(void) + break; + } + } ++#ifndef USE_HARDLINKCUTTER + else { + // Error, unless we're past the last cut-in and there's no cut-out + if (Mark || LastMark) +@@ -117,12 +237,17 @@ void cCuttingThread::Action(void) + break; + } + ++#endif /* HARDLINKCUTTER */ + // Write one frame: + + if (PictureType == I_FRAME) { // every file shall start with an I_FRAME + if (LastMark) // edited version shall end before next I-frame + break; ++#ifndef USE_HARDLINKCUTTER + if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { ++#else ++ if (!SkipThisSourceFile && FileSize > toFileName->MaxFileSize()) { ++#endif /* HARDLINKCUTTER */ + toFile = toFileName->NextFile(); + if (!toFile) { + error = "toFile 1"; +@@ -132,12 +257,20 @@ void cCuttingThread::Action(void) + } + LastIFrame = 0; + ++#ifndef USE_HARDLINKCUTTER + if (cutIn) { ++#else ++ if (!SkipThisSourceFile && cutIn) { ++#endif /* HARDLINKCUTTER */ + cRemux::SetBrokenLink(buffer, Length); + cutIn = false; + } + } ++#ifndef USE_HARDLINKCUTTER + if (toFile->Write(buffer, Length) < 0) { ++#else ++ if (!SkipThisSourceFile && toFile->Write(buffer, Length) < 0) { ++#endif /* HARDLINKCUTTER */ + error = "safe_write"; + break; + } +@@ -172,8 +305,44 @@ void cCuttingThread::Action(void) + } + } + else ++#ifndef USE_HARDLINKCUTTER + LastMark = true; ++#else ++ LastMark = true; // After last cut-out: Write on until next I-frame, then exit ++#endif /* HARDLINKCUTTER */ ++ } ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) { ++#endif /* HARDLINKCUTTER */ ++ bytes += Length; ++ if (bytes >= burst_size) { ++ int elapsed = t.Elapsed(); ++ int sleep = 0; ++ ++#if CUTTER_REL_BANDWIDTH > 0 && CUTTER_REL_BANDWIDTH < 100 ++ // stay under max. relative bandwidth ++ ++ sleep = (elapsed * 100 / CUTTER_REL_BANDWIDTH) - elapsed; ++ //if (sleep<=0 && elapsed<=2) sleep = 1; ++ //if (sleep) esyslog("cutter: relative bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++#endif ++ // stay under max. absolute bandwidth ++ if (elapsed < CUTTER_TIMESLICE) { ++ sleep = max(CUTTER_TIMESLICE - elapsed, sleep); ++ //if (sleep) esyslog("cutter: absolute bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++ } ++ ++ if (sleep>0) ++ cCondWait::SleepMs(sleep); ++ t.Set(); ++ bytes = 0; ++ } ++#ifdef USE_HARDLINKCUTTER + } ++#endif /* HARDLINKCUTTER */ ++#endif /* CUTTERLIMIT */ ++ + } + Recordings.TouchUpdate(); + } +@@ -183,18 +352,74 @@ void cCuttingThread::Action(void) + + // --- cCutter --------------------------------------------------------------- + ++#ifdef USE_CUTTERQUEUE ++#define WAIT_BEFORE_NEXT_CUT (10*1000) // 10 seconds ++ ++class cStringListObject : public cListObject { ++ public: ++ cStringListObject(const char *s) { str = strdup(s); } ++ ~cStringListObject() { free(str); } ++ ++ const char *Value() { return str; } ++ operator const char * () { return str; } ++ ++ private: ++ char *str; ++}; ++#endif /* CUTTERQUEUE */ ++ + char *cCutter::editedVersionName = NULL; + cCuttingThread *cCutter::cuttingThread = NULL; + bool cCutter::error = false; + bool cCutter::ended = false; ++#ifdef USE_CUTTERQUEUE ++cMutex *cCutter::cutterLock = new cMutex(); ++static uint64_t /*cCutter::*/lastCuttingEndTime = 0; ++static cList<cStringListObject> /**cCutter::*/cutterQueue /*= new cList<cStringListObject>*/; ++#endif /* CUTTERQUEUE */ + + bool cCutter::Start(const char *FileName) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++ if (FileName) { ++ /* Add file to queue. ++ * If cutter is still active, next cutting will be started ++ * when vdr.c:main calls cCutter::Active and previous cutting has ++ * been stopped > 10 s before ++ */ ++ cutterQueue.Add(new cStringListObject(FileName)); ++ } ++ if (cuttingThread) ++ return true; ++ /* cut next file from queue */ ++ if (!(cutterQueue.First())) ++ return false; ++ FileName = cutterQueue.First()->Value(); ++#endif /* CUTTERQUEUE */ + if (!cuttingThread) { + error = false; + ended = false; + cRecording Recording(FileName); ++#ifdef USE_CUTTIME ++ if (Setup.CutTime) { ++ cMarks FromMarks; ++ FromMarks.Load(FileName); ++ cMark *First = FromMarks.First(); ++ if (First) Recording.SetStartTime(Recording.start + ((First->position / FRAMESPERSEC + 30) / 60) * 60); ++ } ++#endif /* CUTTIME */ + const char *evn = Recording.PrefixFileName('%'); ++#ifdef USE_CUTTERQUEUE ++ if (!(Recordings.GetByName(FileName))) { ++ // Should _not_ remove any cutted recordings ++ // (original recording already deleted ?) ++ // so, just pop item from queue and return. ++ esyslog("can't cut non-existing recording %s", FileName); ++ cutterQueue.Del(cutterQueue.First()); ++ return true; // might be already queued recording ++ } ++#endif /* CUTTERQUEUE */ + if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { + // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) + // remove a possible deleted recording with the same name to avoid symlink mixups: +@@ -220,6 +445,9 @@ bool cCutter::Start(const char *FileName + + void cCutter::Stop(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool Interrupted = cuttingThread && cuttingThread->Active(); + const char *Error = cuttingThread ? cuttingThread->Error() : NULL; + delete cuttingThread; +@@ -231,11 +459,20 @@ void cCutter::Stop(void) + esyslog("ERROR: '%s' during editing process", Error); + RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? + Recordings.DelByName(editedVersionName); ++#ifdef USE_CUTTERQUEUE ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ + } ++#ifdef USE_CUTTERQUEUE ++ lastCuttingEndTime = cTimeMs::Now(); ++#endif /* CUTTERQUEUE */ + } + + bool cCutter::Active(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + if (cuttingThread) { + if (cuttingThread->Active()) + return true; +@@ -246,12 +483,40 @@ bool cCutter::Active(void) + free(editedVersionName); + editedVersionName = NULL; + ended = true; ++#ifdef USE_CUTTERQUEUE ++ if (Setup.CutterAutoDelete) { ++ /* Remove original (if cutting was successful) */ ++ if (!error) { ++ cRecording *recording = Recordings.GetByName(*cutterQueue.First()); ++ if (!recording) ++ esyslog("ERROR: Can't found '%s' after editing process", cutterQueue.First()->Value()); ++ else { ++ if (recording->Delete()) ++ Recordings.DelByName(recording->FileName()); ++ else ++ esyslog("ERROR: Can't delete '%s' after editing process", cutterQueue.First()->Value()); ++ } ++ } ++ lastCuttingEndTime = cTimeMs::Now(); ++ } ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ ++ } ++#ifdef USE_CUTTERQUEUE ++ if (!cuttingThread && cutterQueue.First()) { ++ /* start next cutting from queue*/ ++ if (cTimeMs::Now() > lastCuttingEndTime + WAIT_BEFORE_NEXT_CUT) ++ Start(NULL); + } ++#endif /* CUTTERQUEUE */ + return false; + } + + bool cCutter::Error(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = error; + error = false; + return result; +@@ -259,6 +524,9 @@ bool cCutter::Error(void) + + bool cCutter::Ended(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = ended; + ended = false; + return result; +diff -ruNp vdr-1.6.0-2/cutter.h vdr-1.6.0-2-extensions/cutter.h +--- vdr-1.6.0-2/cutter.h 2002-06-22 12:03:15.000000000 +0200 ++++ vdr-1.6.0-2-extensions/cutter.h 2009-04-09 20:48:26.000000000 +0200 +@@ -11,6 +11,9 @@ + #define __CUTTER_H + + class cCuttingThread; ++#ifdef USE_CUTTERQUEUE ++class cMutex; ++#endif /* CUTTERQUEUE */ + + class cCutter { + private: +@@ -18,6 +21,9 @@ private: + static cCuttingThread *cuttingThread; + static bool error; + static bool ended; ++#ifdef USE_CUTTERQUEUE ++ static cMutex *cutterLock; ++#endif /* CUTTERQUEUE */ + public: + static bool Start(const char *FileName); + static void Stop(void); +diff -ruNp vdr-1.6.0-2/device.c vdr-1.6.0-2-extensions/device.c +--- vdr-1.6.0-2/device.c 2008-09-11 13:29:39.000000000 +0200 ++++ vdr-1.6.0-2-extensions/device.c 2009-04-09 20:48:26.000000000 +0200 +@@ -14,11 +14,22 @@ + #include "audio.h" + #include "channels.h" + #include "i18n.h" ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "player.h" + #include "receiver.h" + #include "status.h" + #include "transfer.h" + ++#ifdef USE_LNBSHARE ++#include "diseqc.h" ++#endif /* LNBSHARE */ ++ ++#ifdef USE_CHANNELSCAN ++bool scanning_on_receiving_device = false; ++#endif /* CHANNELSCAN */ ++ + // --- cLiveSubtitle --------------------------------------------------------- + + #define LIVESUBTITLEBUFSIZE KILOBYTE(100) +@@ -228,6 +239,12 @@ cDevice::cDevice(void) + + SetVideoFormat(Setup.VideoFormat); + ++#ifdef USE_LNBSHARE ++ LNBstate = -1; ++ LNBnr = Setup.CardUsesLNBnr[cardIndex]; ++ LNBsource = NULL; ++#endif /* LNBSHARE */ ++ + mute = false; + volume = Setup.CurrentVolume; + +@@ -253,8 +270,15 @@ cDevice::cDevice(void) + for (int i = 0; i < MAXRECEIVERS; i++) + receiver[i] = NULL; + ++#ifdef USE_SOURCECAPS ++ if (numDevices < MAXDEVICES) { ++ device[numDevices++] = this; ++ SetSourceCaps(cardIndex); ++ } ++#else + if (numDevices < MAXDEVICES) + device[numDevices++] = this; ++#endif /* SOURCECAPS */ + else + esyslog("ERROR: too many devices!"); + } +@@ -290,6 +314,16 @@ void cDevice::SetUseDevice(int n) + useDevice |= (1 << n); + } + ++#ifdef USE_LNBSHARE ++void cDevice::SetLNBnr(void) ++{ ++ for (int i = 0; i < numDevices; i++) { ++ device[i]->LNBnr = Setup.CardUsesLNBnr[i]; ++ isyslog("LNB-sharing: setting device %d to use LNB %d", i, device[i]->LNBnr); ++ } ++} ++#endif /* LNBSHARE */ ++ + int cDevice::NextCardIndex(int n) + { + if (n > 0) { +@@ -350,6 +384,98 @@ cDevice *cDevice::ActualDevice(void) + return d; + } + ++#ifdef USE_LNBSHARE ++cDevice *cDevice::GetBadDevice(const cChannel *Channel) ++{ ++ if (!cSource::IsSat(Channel->Source())) ++ return NULL; ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d on device %d. LNB or DiSEq conflict with device %d", LNBnr, Channel->Number(), this->DeviceNumber(), i); ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for for channel %d on device %d. OK", LNBnr, Channel->Number(), this->DeviceNumber()); ++ } ++ else { ++ char requiredState; ++ ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1 ; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. Conflict with device %d, LNBstate %d", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate, i, device[i]->GetLNBconf()); ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. No other devices affected", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate); ++ } ++ return NULL; ++} ++ ++int cDevice::GetMaxBadPriority(const cChannel *Channel) ++{ ++ if (!cSource::IsSat(Channel->Source())) return -2; ++ bool PrimaryIsBad = false; ++ int maxBadPriority = -2; ++ ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) ++ maxBadPriority = device[i]->Priority(); ++ if (i == ActualDevice()->CardIndex()) ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ else { ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1 ; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) ++ maxBadPriority = device[i]->Priority(); ++ if (i == ActualDevice()->CardIndex()) ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ ++ if (PrimaryIsBad && maxBadPriority == -2) ++ maxBadPriority = -1; ++ ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Request for channel %d on device %d. MaxBadPriority is %d", LNBnr, Channel->Number(), this->DeviceNumber(), maxBadPriority); ++ ++ return maxBadPriority; ++} ++#endif /* LNBSHARE */ ++ + cDevice *cDevice::GetDevice(int Index) + { + return (0 <= Index && Index < numDevices) ? device[Index] : NULL; +@@ -384,6 +510,10 @@ cDevice *cDevice::GetDevice(const cChann + cCamSlot *s = NULL; + + uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact ++#ifdef USE_LNBSHARE ++ int badPriority; ++ uint imp2; ++#endif /* LNBSHARE */ + for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) { + if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY) + continue; // there is no CAM available in this slot +@@ -408,6 +538,9 @@ cDevice *cDevice::GetDevice(const cChann + imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers + imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode + imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving ++#ifdef USE_LIVEBUFFER ++ imp <<= 2; imp |= cLiveBufferManager::Impact(device[i], Channel, LiveView); ++#endif /* LIVEBUFFER */ + imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device + imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) + imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) +@@ -416,7 +549,31 @@ cDevice *cDevice::GetDevice(const cChann + imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels + imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards + imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel ++#ifdef USE_LNBSHARE ++ badPriority = device[i]->GetMaxBadPriority(Channel); ++ if (badPriority >= Priority || (badPriority == -1 && Priority < Setup.PrimaryLimit)) { ++ // channel is not available for the requested prioity ++ imp = 0xFFFFFFFF; ++ } ++ else { ++ switch (badPriority) { ++ case -2: // not affected by LNB-sharing ++ imp2 = 0; ++ break; ++ case -1: // the primary device would need a channel switch ++ imp += 1 << 17; ++ imp2 = 0xFFFFFFFF | 1 << 17; ++ break; ++ default: // a device receiving with lower priority would need to be stopped ++ imp += badPriority << 8; ++ imp2 = 0xFFFFFFFF | badPriority << 8; ++ break; ++ } ++ } ++ if (imp < Impact && imp2 < Impact) { ++#else + if (imp < Impact) { ++#endif /* LNBSHARE */ + // This device has less impact than any previous one, so we take it. + Impact = imp; + d = device[i]; +@@ -457,6 +614,18 @@ void cDevice::SetCamSlot(cCamSlot *CamSl + camSlot = CamSlot; + } + ++#ifdef USE_SOURCECAPS ++void cDevice::SetSourceCaps(int Index) ++{ ++ for (int d = 0; d < numDevices; d++) { ++ if (Index < 0 || Index == device[d]->CardIndex()) { ++ for (int i = 0; i < MAXSOURCECAPS; i++) ++ device[d]->sourceCaps[i] = Setup.SourceCaps[device[d]->CardIndex()][i]; ++ } ++ } ++} ++#endif /* SOURCECAPS */ ++ + void cDevice::Shutdown(void) + { + primaryDevice = NULL; +@@ -701,7 +870,11 @@ bool cDevice::ProvidesTransponder(const + bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const + { + for (int i = 0; i < numDevices; i++) { ++#ifdef USE_LNBSHARE ++ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel) && device[i]->GetLNBnr() != LNBnr) ++#else + if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel)) ++#endif /* LNBSHARE */ + return false; + } + return true; +@@ -724,6 +897,24 @@ bool cDevice::MaySwitchTransponder(void) + + bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) + { ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ if (this->GetMaxBadPriority(Channel) >= 0) { ++ Skins.Message(mtInfo, tr("Channel locked by LNB!")); ++ return false; ++ } ++ while ((tmpDevice = GetBadDevice(Channel)) != NULL) { ++ if (tmpDevice->IsPrimaryDevice() && LiveView) ++ tmpDevice->SwitchChannelForced(Channel, true); ++ else ++ tmpDevice->SwitchChannelForced(Channel, false); ++ } ++ return SwitchChannelForced(Channel, LiveView); ++} ++ ++bool cDevice::SwitchChannelForced(const cChannel *Channel, bool LiveView) ++{ ++#endif /* LNBSHARE */ + if (LiveView) { + isyslog("switching to channel %d", Channel->Number()); + cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer +@@ -753,7 +944,14 @@ bool cDevice::SwitchChannel(int Directio + cChannel *channel; + while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { + // try only channels which are currently available ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, channel) == false) ++#endif /* PINPLUGIN */ ++#ifdef USE_LNBSHARE ++ if (PrimaryDevice()->GetMaxBadPriority(channel) < 0 && (GetDevice(channel, 0, true))) ++#else + if (GetDevice(channel, 0, true)) ++#endif /* LNBSHARE */ + break; + n = channel->Number() + Direction; + } +@@ -774,7 +972,18 @@ bool cDevice::SwitchChannel(int Directio + + eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) + { ++#ifdef USE_PINPLUGIN ++ // I hope 'LiveView = false' indicates a channel switch for recording, ++ // I really don't know, but it works ... ++ if (LiveView && cStatus::MsgChannelProtected(this, Channel) == true) ++ return scrNotAvailable; ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_LIVEBUFFER ++ if (LiveView && !(Setup.LiveBuffer && dynamic_cast<cLivePlayer *>(player) != NULL)) { ++#else + if (LiveView) { ++#endif /* LIVEBUFFER */ + StopReplay(); + DELETENULL(liveSubtitle); + DELETENULL(dvbSubtitleConverter); +@@ -784,15 +993,51 @@ eSetChannelResult cDevice::SetChannel(co + + bool NeedsTransferMode = Device != this; + ++#ifdef USE_LIVEBUFFER ++ if (LiveView && Setup.LiveBuffer) ++ NeedsTransferMode = true; ++#endif /* LIVEBUFFER */ ++ + eSetChannelResult Result = scrOk; + ++#ifdef USE_LNBSHARE ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Switching device %d to channel %d", LNBnr, this->DeviceNumber(), Channel->Number()); ++#endif /* LNBSHARE */ ++ + // If this DVB card can't receive this channel, let's see if we can + // use the card that actually can receive it and transfer data from there: + + if (NeedsTransferMode) { + if (Device && CanReplay()) { ++#ifdef USE_LNBSHARE ++ if (Device->GetLNBnr() == LNBnr) { ++ if (LNBstate != requiredState || (Setup.DiSEqC && LNBsource != (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())) ) { ++ if (IsPrimaryDevice()) ++ SetChannelDevice(Channel, true); ++ else ++ SetChannelDevice(Channel, false); ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ } ++ } ++#endif /* LNBSHARE */ + cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel + if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! ++#ifdef USE_LIVEBUFFER ++ if (Setup.LiveBuffer) ++ cLiveBufferManager::ChannelSwitch(Device,Channel); ++ else ++#endif /* LIVEBUFFER */ + cControl::Launch(new cTransferControl(Device, Channel->GetChannelID(), Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids())); + else + Result = scrNoTransfer; +@@ -808,6 +1053,10 @@ eSetChannelResult cDevice::SetChannel(co + sectionHandler->SetStatus(false); + sectionHandler->SetChannel(NULL); + } ++#ifdef USE_LNBSHARE ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++#endif /* LNBSHARE */ + // Tell the camSlot about the channel switch and add all PIDs of this + // channel to it, for possible later decryption: + if (camSlot) +@@ -840,7 +1089,11 @@ eSetChannelResult cDevice::SetChannel(co + } + for (int i = 0; i < MAXSPIDS; i++) + SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i)); ++#ifdef USE_SYNCEARLY ++ if ((Setup.UseSyncEarlyPatch && (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone)) || (!Setup.UseSyncEarlyPatch && !NeedsTransferMode)) ++#else + if (!NeedsTransferMode) ++#endif /* SYNCEARLY */ + EnsureAudioTrack(true); + EnsureSubtitleTrack(); + } +@@ -1100,7 +1353,12 @@ void cDevice::EnsureSubtitleTrack(void) + int LanguagePreference = INT_MAX; // higher than the maximum possible value + for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) { + const tTrackId *TrackId = GetTrack(eTrackType(i)); ++#ifdef USE_LIEMIEXT ++ if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) || ++ ((i == ttSubtitleFirst + 8) && !(*TrackId->language) && (LanguagePreference == INT_MAX)))) ++#else + if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference)) ++#endif /* LIEMIEXT */ + PreferredTrack = eTrackType(i); + } + // Make sure we're set to an available subtitle track: +@@ -1164,7 +1422,11 @@ bool cDevice::Replaying(void) const + + bool cDevice::Transferring(void) const + { ++#ifdef USE_LIVEBUFFER ++ return ActualDevice() != PrimaryDevice() || dynamic_cast<cLivePlayer *>(player) != NULL; // TODO ++#else + return ActualDevice() != PrimaryDevice(); ++#endif /* LIVEBUFFER */ + } + + bool cDevice::AttachPlayer(cPlayer *Player) +@@ -1289,7 +1551,11 @@ pre_1_3_19_PrivateStreamDetected: + w = PlaySubtitle(Start, d); + break; + case 0x80: // AC3 & DTS ++#ifdef USE_DOLBYINREC ++ if (Setup.UseDolbyInRecordings) { ++#else + if (Setup.UseDolbyDigital) { ++#endif /* DOLBYINREC */ + SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId); + if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) { + w = PlayAudio(Start, d, SubStreamId); +diff -ruNp vdr-1.6.0-2/device.h vdr-1.6.0-2-extensions/device.h +--- vdr-1.6.0-2/device.h 2008-02-23 14:13:04.000000000 +0100 ++++ vdr-1.6.0-2-extensions/device.h 2009-04-09 20:48:26.000000000 +0200 +@@ -23,8 +23,13 @@ + #include "spu.h" + #include "thread.h" + #include "tools.h" ++#ifdef USE_ROTOR ++#include <linux/dvb/frontend.h> ++#endif /* ROTOR */ + ++#ifndef USE_SOURCECAPS + #define MAXDEVICES 16 // the maximum number of devices in the system ++#endif /* SOURCECAPS */ + #define MAXPIDHANDLES 64 // the maximum number of different PIDs per device + #define MAXRECEIVERS 16 // the maximum number of receivers per device + #define MAXVOLUME 255 +@@ -34,6 +39,10 @@ + #define TS_SYNC_BYTE 0x47 + #define PID_MASK_HI 0x1F + ++#ifdef USE_CHANNELSCAN ++extern bool scanning_on_receiving_device; ++#endif /* CHANNELSCAN */ ++ + enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed }; + + enum ePlayMode { pmNone, // audio/video from decoder +@@ -146,6 +155,35 @@ public: + ///< this device/CAM combination will be skipped in the next call to + ///< GetDevice(). + ///< See also ProvidesChannel(). ++#ifdef USE_SOURCECAPS ++ static void SetSourceCaps(int Index = -1); ++ ///< Sets the SourceCaps of the given device according to the Setup data. ++#endif /* SOURCECAPS */ ++#ifdef USE_LNBSHARE ++private: ++ char LNBstate; // Current frequency band and polarization of the DVB-tuner ++// cDiseqc *LNBsource; // can not #include "diseqc.h". A workaround follows: ++ int *LNBsource; // [DiSEqC] DiSEqC-Source ++ int LNBnr; // Number of LNB used ++public: ++ char GetLNBconf(void) { return LNBstate; } ++ int *GetLNBsource(void) { return LNBsource; } ++ int GetLNBnr(void) { return LNBnr; } ++ static void SetLNBnr(void); ++ cDevice *GetBadDevice(const cChannel *Channel); ++ ///< Returns NULL if there is no device which uses the same LNB or if ++ ///< all of those devices are tuned to the same frequency band and ++ ///< polarization as of the requested channel. ++ ///< Otherwise returns the first device found. ++ int GetMaxBadPriority(const cChannel *Channel); ++ ///< Returns the highest priority of all receiving devices which use ++ ///< the same LNB and are tuned to a different frequency band or ++ ///< polarization as of the requested channel. ++ ///< Returns -1 if there are no such devices, but the primary device ++ ///< would be affected by switching to the requested channel. ++ ///< Returns -2 if there are no such devices and the primary device ++ ///< would not be affected by switching to the requested channel. ++#endif /* LNBSHARE */ + static void SetAvoidDevice(cDevice *Device) { avoidDevice = Device; } + ///< Sets the given Device to be temporarily avoided in the next call to + ///< GetDevice(const cChannel, int, bool). +@@ -156,6 +194,9 @@ private: + static int nextCardIndex; + int cardIndex; + protected: ++#ifdef USE_SOURCECAPS ++ int sourceCaps[MAXSOURCECAPS]; ++#endif /* SOURCECAPS */ + cDevice(void); + virtual ~cDevice(); + virtual bool Ready(void); +@@ -237,17 +278,30 @@ public: + bool SwitchChannel(const cChannel *Channel, bool LiveView); + ///< Switches the device to the given Channel, initiating transfer mode + ///< if necessary. ++ ++#ifdef USE_LNBSHARE ++ bool SwitchChannelForced(const cChannel *Channel, bool LiveView); ++ ///< Switches the device to the given channel, initiating transfer mode ++ ///< if necessary. Forces the switch without taking care of the LNB configuration. ++#endif /* LNBSHARE */ ++ + static bool SwitchChannel(int Direction); + ///< Switches the primary device to the next available channel in the given + ///< Direction (only the sign of Direction is evaluated, positive values + ///< switch to higher channel numbers). + private: ++#ifndef USE_YAEPG + eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (actual physical setup). + public: ++#ifdef USE_YAEPG ++ eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); ++ ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; } + ///< Returns the number of the current channel on the primary device. + static void SetCurrentChannel(const cChannel *Channel) { currentChannel = Channel ? Channel->Number() : 0; } +@@ -265,6 +319,9 @@ public: + virtual bool HasProgramme(void); + ///< Returns true if the device is currently showing any programme to + ///< the user, either through replaying or live. ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd) { return false; } ++#endif /* ROTOR */ + + // PID handle facilities + +diff -ruNp vdr-1.6.0-2/dvbdevice.c vdr-1.6.0-2-extensions/dvbdevice.c +--- vdr-1.6.0-2/dvbdevice.c 2008-02-09 17:11:44.000000000 +0100 ++++ vdr-1.6.0-2-extensions/dvbdevice.c 2009-04-09 20:48:26.000000000 +0200 +@@ -71,6 +71,9 @@ static int DvbOpen(const char *Name, int + class cDvbTuner : public cThread { + private: + enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked }; ++#ifdef USE_ROTOR ++ bool SendDiseqc; ++#endif /* ROTOR */ + int fd_frontend; + int cardIndex; + int tuneTimeout; +@@ -83,6 +86,9 @@ private: + cMutex mutex; + cCondVar locked; + cCondVar newSet; ++#ifdef USE_ROTOR ++ dvb_diseqc_master_cmd diseqc_cmd; ++#endif /* ROTOR */ + bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0); + bool SetFrontend(void); + virtual void Action(void); +@@ -91,12 +97,18 @@ public: + virtual ~cDvbTuner(); + bool IsTunedTo(const cChannel *Channel) const; + void Set(const cChannel *Channel, bool Tune); ++#ifdef USE_ROTOR ++ bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + bool Locked(int TimeoutMs = 0); + }; + + cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType) + { + fd_frontend = Fd_Frontend; ++#ifdef USE_ROTOR ++ SendDiseqc = false; ++#endif /* ROTOR */ + cardIndex = CardIndex; + frontendType = FrontendType; + tuneTimeout = 0; +@@ -145,6 +157,19 @@ bool cDvbTuner::Locked(int TimeoutMs) + return tunerStatus >= tsLocked; + } + ++#ifdef USE_ROTOR ++bool cDvbTuner::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ cMutexLock MutexLock(&mutex); ++ if (frontendType != FE_QPSK || SendDiseqc) ++ return false; ++ diseqc_cmd = cmd; ++ SendDiseqc = true; ++ newSet.Broadcast(); ++ return true; ++} ++#endif /* ROTOR */ ++ + bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs) + { + if (TimeoutMs) { +@@ -210,6 +235,9 @@ bool cDvbTuner::SetFrontend(void) + } + } + diseqcCommands = diseqc->Commands(); ++#ifdef USE_DVBSETUP ++ isyslog("Sent DISEQC command: %s", diseqcCommands); ++#endif /* DVBSETUP */ + } + frequency -= diseqc->Lof(); + } +@@ -258,6 +286,20 @@ bool cDvbTuner::SetFrontend(void) + lockTimeout = DVBC_LOCK_TIMEOUT; + } + break; ++#ifdef USE_ATSC ++ case FE_ATSC: { // ATSC ++ ++ // Frequency and symbol rate: ++ ++ Frontend.frequency = FrequencyToHz(channel.Frequency()); ++ Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); ++ Frontend.u.vsb.modulation = fe_modulation_t(channel.Modulation()); ++ ++ tuneTimeout = DVBC_TUNE_TIMEOUT; ++ lockTimeout = DVBC_LOCK_TIMEOUT; ++ } ++ break; ++#endif /* ATSC */ + case FE_OFDM: { // DVB-T + + // Frequency and OFDM paramaters: +@@ -297,6 +339,12 @@ void cDvbTuner::Action(void) + if (GetFrontendStatus(NewStatus, 10)) + Status = NewStatus; + cMutexLock MutexLock(&mutex); ++#ifdef USE_ROTOR ++ if (SendDiseqc) { ++ CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &diseqc_cmd)); ++ SendDiseqc = false; ++ } ++#endif /* ROTOR */ + switch (tunerStatus) { + case tsIdle: + break; +@@ -419,6 +467,11 @@ cDvbDevice::cDvbDevice(int n) + if (fd_frontend >= 0) { + dvb_frontend_info feinfo; + if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlockerMode == 4) ++ frontendType = n == Setup.PrimaryDVB - 1 ? frontendType : feinfo.type; ++ else ++#endif /* DVBSETUP */ + frontendType = feinfo.type; + dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType); + } +@@ -638,6 +691,13 @@ eVideoSystem cDvbDevice::GetVideoSystem( + + bool cDvbDevice::SetAudioBypass(bool On) + { ++#ifdef USE_DVBSETUP ++ if (Setup.DolbyTransferFix && On) { ++ cChannel *c=Channels.GetByNumber(cDevice::CurrentChannel()); ++ if (c->Ca(0) != 0) ++ return false; ++ } ++#endif /* DVBSETUP */ + if (setTransferModeForDolbyDigital != 1) + return false; + return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0; +@@ -743,23 +803,74 @@ void cDvbDevice::TurnOffLiveMode(bool Li + bool cDvbDevice::ProvidesSource(int Source) const + { + int type = Source & cSource::st_Mask; ++#ifdef USE_SOURCECAPS ++ if (Setup.SourceCapsSet && type == cSource::stSat && frontendType == FE_QPSK) { ++ for (int i = 0; i < MAXSOURCECAPS; i++) ++ if (sourceCaps[i] == Source) ++ return true; ++ return false; ++ } ++ else ++#endif /* SOURCECAPS */ + return type == cSource::stNone + || type == cSource::stCable && frontendType == FE_QAM ++#ifdef USE_ATSC ++ || type == cSource::stCable && frontendType == FE_ATSC ++ || type == cSource::stTerr && frontendType == FE_ATSC ++#endif /* ATSC */ + || type == cSource::stSat && frontendType == FE_QPSK + || type == cSource::stTerr && frontendType == FE_OFDM; + } + + bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const + { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlocker != 0) { ++ if ((Setup.ChannelBlockerMode == 0) || ++ (Setup.ChannelBlockerMode == 1 && HasDecoder()) || ++ (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || ++ (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { ++ if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && fe_modulation_t(Channel->Modulation()) == QAM_256) || ++ (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || ++ (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || ++ (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist ++ (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist ++ (Setup.ChannelBlocker == 6)) ++ return false; ++ } ++ } ++#endif /* DVBSETUP */ ++ + return ProvidesSource(Channel->Source()) && (!cSource::IsSat(Channel->Source()) || !Setup.DiSEqC || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())); + } + + bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const + { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlocker != 0) { ++ if ((Setup.ChannelBlockerMode == 0) || ++ (Setup.ChannelBlockerMode == 1 && HasDecoder()) || ++ (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || ++ (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { ++ if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && fe_modulation_t(Channel->Modulation()) == QAM_256) || ++ (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || ++ (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || ++ (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist ++ (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist ++ (Setup.ChannelBlocker == 6)) ++ return false; ++ } ++ } ++#endif /* DVBSETUP */ + bool result = false; + bool hasPriority = Priority < 0 || Priority > this->Priority(); + bool needsDetachReceivers = false; + ++#ifdef USE_ANALOGTV ++ if ((Channel->Ca(0) == 0xA0) || (Channel->Ca(0) == 0xA1) || (Channel->Ca(0) == 0xA2)) ++ return false; ++#endif /* ANALOGTV */ ++ + if (ProvidesSource(Channel->Source())) { + result = hasPriority; + if (Priority >= 0 && Receiving(true)) { +@@ -815,7 +926,11 @@ bool cDvbDevice::SetChannelDevice(const + || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + ); + ++#ifdef USE_LIVEBUFFER ++ bool StartTransferMode = IsPrimaryDevice() && !DoTune && !Setup.LiveBuffer ++#else + bool StartTransferMode = IsPrimaryDevice() && !DoTune ++#endif /* LIVEBUFFER */ + && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER + || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + ); +@@ -871,6 +986,13 @@ bool cDvbDevice::HasLock(int TimeoutMs) + return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false; + } + ++#ifdef USE_ROTOR ++bool cDvbDevice::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ return dvbTuner->SendDiseqcCmd(cmd); ++} ++#endif /* ROTOR */ ++ + int cDvbDevice::GetAudioChannelDevice(void) + { + if (HasDecoder()) { +diff -ruNp vdr-1.6.0-2/dvbdevice.h vdr-1.6.0-2-extensions/dvbdevice.h +--- vdr-1.6.0-2/dvbdevice.h 2008-02-08 14:48:31.000000000 +0100 ++++ vdr-1.6.0-2-extensions/dvbdevice.h 2009-04-09 20:48:26.000000000 +0200 +@@ -71,6 +71,9 @@ protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + public: + virtual bool HasLock(int TimeoutMs = 0); ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + + // PID handle facilities + +diff -ruNp vdr-1.6.0-2/dvbosd.c vdr-1.6.0-2-extensions/dvbosd.c +--- vdr-1.6.0-2/dvbosd.c 2007-09-16 10:55:54.000000000 +0200 ++++ vdr-1.6.0-2-extensions/dvbosd.c 2009-04-09 20:48:26.000000000 +0200 +@@ -20,12 +20,26 @@ + #define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 + #define MAXOSDMEMORY 92000 // number of bytes available to the OSD (for unmodified DVB cards) + ++#ifdef USE_SOFTOSD ++ #define SOFTOSD_MAXSIZE (720*576) ++ #define SOFTOSD_MINSIZE (720*64) ++#endif ++ + class cDvbOsd : public cOsd { + private: + int osdDev; + int osdMem; + bool shown; + void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); ++#ifdef USE_SOFTOSD ++ int GetOsdSize() { ++ int OsdSize = 0; ++ cBitmap *Bitmap; ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) ++ OsdSize += Bitmap->Width() * Bitmap->Height(); ++ return OsdSize; ++ } ++#endif + protected: + virtual void SetActive(bool On); + public: +@@ -76,6 +90,44 @@ void cDvbOsd::SetActive(bool On) + } + else if (shown) { + cBitmap *Bitmap; ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { ++ for (int fade = Setup.SoftOsdFadeoutSteps - 1; fade > 0; fade--) { ++ int64_t flush_start = cTimeMs::Now(); ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { ++ Cmd(OSD_SetWindow, 0, i + 1); ++ int NumColors; ++ const tColor *Colors = Bitmap->Colors(NumColors); ++ if (Colors) { ++ tColor colors[NumColors]; ++ for (int i = 0; i < NumColors; i++) { ++ // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): ++ int alpha = (Colors[i] >> 24) & 0x000000FF; ++ alpha = (alpha * fade) / Setup.SoftOsdFadeoutSteps; ++ colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++ } ++ Colors = colors; ++ Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); ++ if (!Setup.SoftOsdPaletteOnly) { ++ //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); ++ Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); ++ } ++ } ++ } ++ int flush_time = cTimeMs::Now() - flush_start; ++ dsyslog("SOFTOSD: FadeOut Step %d from %d FlushTime = %d ms", ++ Setup.SoftOsdFadeoutSteps - fade, Setup.SoftOsdFadeoutSteps - 1, flush_time); ++ int wait_time = 1000 / Setup.SoftOsdRate; ++ while (flush_time > wait_time && fade > 2) { ++ fade--; ++ flush_time -= wait_time; ++ } ++ cCondWait::SleepMs(wait_time-flush_time); ++ } ++ } ++ } ++#endif /* SOFTOSD */ + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Close); +@@ -83,6 +135,12 @@ void cDvbOsd::SetActive(bool On) + shown = false; + } + } ++#ifdef USE_YAEPG ++ if (vidWin.bpp != 0) { ++ Cmd(OSD_SetWindow, 0, 5); ++ Cmd(OSD_Close); ++ } ++#endif /* YAEPG */ + } + + eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas) +@@ -182,6 +240,12 @@ void cDvbOsd::Flush(void) + for (int i = 0; i < NumColors; i++) { + // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): + colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd && !shown) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) ++ colors[i] = 0; ++ } ++#endif /* SOFTOSD */ + } + Colors = colors; + //TODO end of stuff that should be fixed in the driver +@@ -198,6 +262,51 @@ void cDvbOsd::Flush(void) + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0()); + } ++#ifdef USE_YAEPG ++ if (vidWin.bpp != 0) { ++ Cmd(OSD_SetWindow, 0, 5); ++ Cmd(OSD_OpenRaw, vidWin.bpp, vidWin.x1, vidWin.y1, vidWin.x2, vidWin.y2, (void *)0); ++ } ++#endif /* YAEPG */ ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { ++ for (int fade = 1; fade <= Setup.SoftOsdFadeinSteps; fade++) { ++ int64_t flush_start = cTimeMs::Now(); ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { ++ Cmd(OSD_SetWindow, 0, i + 1); ++ int NumColors; ++ const tColor *Colors = Bitmap->Colors(NumColors); ++ if (Colors) { ++ tColor colors[NumColors]; ++ for (int i = 0; i < NumColors; i++) { ++ // convert AARRGGBB to AABBGGRR: ++ int alpha = (Colors[i]>>24) & 0x000000FF; ++ alpha = (alpha * fade) / Setup.SoftOsdFadeinSteps; ++ colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++ } ++ Colors = colors; ++ Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); ++ if (!Setup.SoftOsdPaletteOnly) { ++ //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); ++ Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); ++ } ++ } ++ } ++ int flush_time = cTimeMs::Now() - flush_start; ++ dsyslog("SOFTOSD: FadeIn Step %d from %d FlushTime = %d ms", fade, Setup.SoftOsdFadeinSteps, flush_time); ++ int wait_time = 1000 / Setup.SoftOsdRate; ++ while (flush_time > wait_time && fade < Setup.SoftOsdFadeinSteps - 1) { ++ fade++; ++ flush_time -= wait_time; ++ } ++ if (fade == Setup.SoftOsdFadeinSteps) /* last step, don't wait */ ++ break; ++ cCondWait::SleepMs(wait_time - flush_time); ++ } ++ } ++ } ++#endif /* SOFTOSD */ + shown = true; + } + } +diff -ruNp vdr-1.6.0-2/dvbplayer.c vdr-1.6.0-2-extensions/dvbplayer.c +--- vdr-1.6.0-2/dvbplayer.c 2008-02-09 16:10:54.000000000 +0100 ++++ vdr-1.6.0-2-extensions/dvbplayer.c 2009-04-09 20:48:26.000000000 +0200 +@@ -14,6 +14,9 @@ + #include "ringbuffer.h" + #include "thread.h" + #include "tools.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + // --- cBackTrace ------------------------------------------------------------ + +@@ -193,6 +196,9 @@ private: + cNonBlockingFileReader *nonBlockingFileReader; + cRingBufferFrame *ringBuffer; + cBackTrace *backTrace; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#endif /* JUMPPLAY */ + cFileName *fileName; + cIndexFile *index; + cUnbufferedFile *replayFile; +@@ -234,7 +240,11 @@ public: + int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; + + cDvbPlayer::cDvbPlayer(const char *FileName) ++#ifdef USE_JUMPPLAY ++:cThread("dvbplayer"), marks(FileName) ++#else + :cThread("dvbplayer") ++#endif /* JUMPPLAY */ + { + nonBlockingFileReader = NULL; + ringBuffer = NULL; +@@ -312,6 +322,35 @@ void cDvbPlayer::Empty(void) + firstPacket = true; + } + ++ ++#ifdef USE_TTXTSUBS ++static void StripExtendedPackets(uchar *b, int Length) ++{ ++ for (int i = 0; i < Length - 6; i++) { ++ if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { ++ uchar c = b[i + 3]; ++ int l = b[i + 4] * 256 + b[i + 5] + 6; ++ switch (c) { ++ case 0xBD: // dolby ++ // EBU Teletext data, ETSI EN 300 472 ++ if (b[i + 8] == 0x24 && b[i + 45] >= 0x10 && b[i + 45] < 0x20) { ++ cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData(&b[i], l); ++ // continue with deleting the data - otherwise it disturbs DVB replay ++ int n = l; ++ for (int j = i; j < Length && n--; j++) ++ b[j] = 0x00; ++ } ++ break; ++ default: ++ break; ++ } ++ if (l) ++ i += l - 1; // the loop increments, too! ++ } ++ } ++} ++#endif /* TTXTSUBS */ ++ + bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset) + { + if (FileNumber > 0) +@@ -341,6 +380,11 @@ bool cDvbPlayer::Save(void) + if (index) { + int Index = writeIndex; + if (Index >= 0) { ++#ifdef USE_JUMPPLAY ++ // set resume position to 0 if replay stops at the first mark ++ if (Setup.PlayJump && marks.First() && abs(Index - marks.First()->position) <= RESUMEBACKUP) ++ Index = 0; ++#endif /* JUMPPLAY */ + Index -= RESUMEBACKUP; + if (Index > 0) + Index = index->GetNextIFrame(Index, false); +@@ -363,16 +407,154 @@ void cDvbPlayer::Activate(bool On) + Cancel(9); + } + ++#ifdef USE_DVBPLAYER ++// --- BEGIN fix for I frames ------------------------------------------- ++// ++// Prior to the introduction of cVideoRepacker, VDR didn't start a new ++// PES packet when a new frame started. So, it was likely that the tail ++// of an I frame was at the beginning of the packet which started the ++// following B frame. Due to the organisation of VDR's index file, VDR ++// typically didn't read the tail of the I frame and therefore caused ++// softdevice plugins to not render such a frame as it was incomplete, ++// e. g. when moving cutting marks. ++// ++// The following code tries to fix incomplete I frames for recordings ++// made prior to the introdcution of cVideoRepacker, to be able to ++// edit cutting marks for example with softdevice plugins like vdr-xine. ++// ++ ++static uchar *findStartCode(uchar *Data, int Length, int &PesPayloadOffset) ++{ ++ uchar *limit = Data + Length; ++ if (AnalyzePesHeader(Data, Length, PesPayloadOffset) <= phInvalid) ++ return 0; // neither MPEG1 nor MPEG2 ++ ++ Data += PesPayloadOffset + 3; // move to video payload and skip 00 00 01 ++ while (Data < limit) { ++ // possible start codes that appear before/after picture data ++ // 00 00 01 B3: sequence header code ++ // 00 00 01 B8: group start code ++ // 00 00 01 00: picture start code ++ // 00 00 01 B7: sequence end code ++ if (0x01 == Data[-1] && (0xB3 == Data[0] || 0xB8 == Data[0] || 0x00 == Data[0] || 0xB7 == Data[0]) && 0x00 == Data[-2] && 0x00 == Data[-3]) ++ return Data - 3; ++ Data++; ++ } ++ ++ return 0; ++} ++ ++static void fixIFrameHead(uchar *Data, int Length) ++{ ++ int pesPayloadOffset = 0; ++ uchar *p = findStartCode(Data, Length, pesPayloadOffset); ++ if (!p) { ++ esyslog("fixIframeHead: start code not found!\n"); ++ return; ++ } ++ ++ Data += pesPayloadOffset; // move to video payload ++ if (Data < p) ++ memset(Data, 0, p - Data); // zero preceeding bytes ++} ++ ++static int fixIFrameTail(uchar *Data, int Length) ++{ ++ int pesPayloadOffset = 0; ++ uchar *p = findStartCode(Data, Length, pesPayloadOffset); ++ if (!p) { ++ esyslog("fixIframeTail: start code not found!\n"); ++ return Length; ++ } ++ ++ // is this PES packet required? ++ uchar *videoPayload = Data + pesPayloadOffset; ++ if (videoPayload >= p) ++ return 0; // no ++ ++ // adjust PES length ++ int lenPES = (p - Data); ++ Data[4] = (lenPES - 6) >> 8; ++ Data[5] = (lenPES - 6) & 0xFF; ++ ++ return lenPES; ++} ++ ++#define IPACKS 2048 // originally defined in remux.c ++ ++static void fixIFrame(uchar *Data, int &Length, const int OriginalLength) ++{ ++ int done = 0; ++ ++ while (done < Length) { ++ if (0x00 != Data[0] || 0x00 != Data[1] || 0x01 != Data[2]) { ++ esyslog("fixIFrame: PES start code not found at offset %d (data length: %d, original length: %d)!", done, Length, OriginalLength); ++ if (Length > OriginalLength) // roll back additional data ++ Length = OriginalLength; ++ return; ++ } ++ ++ int lenPES = 6 + Data[4] * 256 + Data[5]; ++ if (0xBA == Data[3]) { // pack header has fixed length ++ if (0x00 == (0xC0 & Data[4])) ++ lenPES = 12; // MPEG1 ++ else ++ lenPES = 14 + (Data[13] & 0x07); // MPEG2 ++ } ++ else if (0xB9 == Data[3]) // stream end has fixed length ++ lenPES = 4; ++ else if (0xE0 == (0xF0 & Data[3])) { // video packet ++ int todo = Length - done; ++ int bite = (lenPES < todo) ? lenPES : todo; ++ if (0 == done) // first packet ++ fixIFrameHead(Data, bite); ++ else if (done >= OriginalLength) { // last packet ++ Length = done + fixIFrameTail(Data, bite); ++ return; ++ } ++ } ++ else if (0 == done && 0xC0 == (0xE0 & Data[3])) { ++ // if the first I frame packet is an audio packet then this is a radio recording: don't touch it! ++ if (Length > OriginalLength) // roll back additional data ++ Length = OriginalLength; ++ return; ++ } ++ ++ done += lenPES; ++ Data += lenPES; ++ } ++} ++ ++// --- END fix for I frames --------------------------------------------- ++#endif /* DVBPLAYER */ ++ + void cDvbPlayer::Action(void) + { + uchar *b = NULL; + uchar *p = NULL; + int pc = 0; ++#ifdef USE_JUMPPLAY ++ bool cutIn = false; ++ int total = -1; ++#endif /* JUMPPLAY */ + + readIndex = Resume(); + if (readIndex >= 0) + isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); + ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump && readIndex <= 0 && marks.First() && index) { ++ int Index = marks.First()->position; ++ uchar FileNumber; ++ int FileOffset; ++ if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset)) { ++ isyslog("PlayJump: start replay at first mark %d (%s)", Index, *IndexToHMSF(Index, true)); ++ readIndex = Index; ++ } ++ } ++ ++ bool LastMarkPause = false; ++#endif /* JUMPPLAY */ + nonBlockingFileReader = new cNonBlockingFileReader; + int Length = 0; + bool Sleep = false; +@@ -393,7 +575,11 @@ void cDvbPlayer::Action(void) + + // Read the next frame from the file: + ++#ifdef USE_JUMPPLAY ++ if (playMode != pmStill && playMode != pmPause && !LastMarkPause) { ++#else + if (playMode != pmStill && playMode != pmPause) { ++#endif /* JUMPPLAY */ + if (!readFrame && (replayFile || readIndex >= 0)) { + if (!nonBlockingFileReader->Reading()) { + if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { +@@ -411,6 +597,9 @@ void cDvbPlayer::Action(void) + if (!NextFile(FileNumber, FileOffset)) { + readIndex = Index; + continue; ++#ifdef USE_DVBPLAYER ++ Length += IPACKS; // fixIFrame needs next video packet ++#endif /* DVBPLAYER */ + } + } + else { +@@ -438,6 +627,43 @@ void cDvbPlayer::Action(void) + uchar FileNumber; + int FileOffset; + readIndex++; ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump || Setup.PauseLastMark) { ++ // check for end mark - jump to next mark or pause ++ marks.Reload(); ++ cMark *m = marks.Get(readIndex); ++ if (m && (m->Index() & 0x01) != 0) { ++ m = marks.Next(m); ++ int Index; ++ if (m) ++ Index = m->position; ++ else if (Setup.PauseLastMark) { ++ // pause at last mark ++ isyslog("PauseLastMark: pause at position %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); ++ LastMarkPause = true; ++ Index = -1; ++ } ++ else if (total == index->Last()) ++ // at last mark jump to end of recording ++ Index = index->Last() - 1; ++ else ++ // jump but stay off end of live-recordings ++ Index = index->GetNextIFrame(index->Last() - 150, true); ++ ++ // don't jump in edited recordings ++ if (Setup.PlayJump && Index > readIndex && Index > index->GetNextIFrame(readIndex, true)) { ++ isyslog("PlayJump: %d frames to %d (%s)", Index - readIndex, Index, *IndexToHMSF(Index, true)); ++ readIndex = Index; ++ cutIn = true; ++ } ++ } ++ } ++ // for detecting growing length of live-recordings ++ uchar PictureType; ++ if (index->Get(readIndex, &FileNumber, &FileOffset, &PictureType) && ++ PictureType == I_FRAME) ++ total = index->Last(); ++#endif /* JUMPPLAY */ + if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) { + readIndex = -1; + eof = true; +@@ -457,6 +683,10 @@ void cDvbPlayer::Action(void) + int r = nonBlockingFileReader->Read(replayFile, b, Length); + if (r > 0) { + WaitingForData = false; ++#ifdef USE_DVBPLAYER ++ if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) ++ fixIFrame(b, r, Length - IPACKS); ++#endif /* DVBPLAYER */ + readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer + b = NULL; + } +@@ -473,6 +703,12 @@ void cDvbPlayer::Action(void) + // Store the frame in the buffer: + + if (readFrame) { ++#ifdef USE_JUMPPLAY ++ if (cutIn) { ++ cRemux::SetBrokenLink(readFrame->Data(), readFrame->Count()); ++ cutIn = false; ++ } ++#endif /* JUMPPLAY */ + if (ringBuffer->Put(readFrame)) + readFrame = NULL; + } +@@ -503,6 +739,9 @@ void cDvbPlayer::Action(void) + } + } + if (p) { ++#ifdef USE_TTXTSUBS ++ StripExtendedPackets(p, pc); ++#endif /* TTXTSUBS */ + int w = PlayPes(p, pc, playMode != pmPlay); + if (w > 0) { + p += w; +@@ -521,8 +760,19 @@ void cDvbPlayer::Action(void) + p = NULL; + } + } ++#ifdef USE_JUMPPLAY ++ else { ++ if (LastMarkPause) { ++ LastMarkPause = false; ++ playMode = pmPause; ++ writeIndex = readIndex; ++ } ++ Sleep = true; ++ } ++#else + else + Sleep = true; ++#endif /* JUMPPLAY */ + } + } + +@@ -699,9 +949,15 @@ void cDvbPlayer::Goto(int Index, bool St + int FileOffset, Length; + Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); + if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { ++#ifdef USE_DVBPLAYER ++ Length += IPACKS; // fixIFrame needs next video packet ++#endif /* DVBPLAYER */ + uchar b[MAXFRAMESIZE + 4 + 5 + 4]; + int r = ReadFrame(replayFile, b, Length, sizeof(b)); + if (r > 0) { ++#ifdef USE_DVBPLAYER ++ fixIFrame(b, r, Length - IPACKS); ++#endif /* DVBPLAYER */ + if (playMode == pmPause) + DevicePlay(); + // append sequence end code to get the image shown immediately with softdevices +diff -ruNp vdr-1.6.0-2/eit.c vdr-1.6.0-2-extensions/eit.c +--- vdr-1.6.0-2/eit.c 2008-09-11 13:29:39.000000000 +0200 ++++ vdr-1.6.0-2-extensions/eit.c 2009-04-09 20:48:26.000000000 +0200 +@@ -17,13 +17,40 @@ + #include "libsi/section.h" + #include "libsi/descriptor.h" + ++#ifdef USE_SETTIME ++extern char *SetTime; ++#endif /* SETTIME */ ++ + // --- cEIT ------------------------------------------------------------------ + + class cEIT : public SI::EIT { + public: + cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus = false); ++#ifdef USE_NOEPG ++private: ++ bool allowedEPG(tChannelID kanalID); ++#endif /* NOEPG */ + }; + ++#ifdef USE_NOEPG ++bool cEIT::allowedEPG(tChannelID kanalID) { ++ bool rc; ++ ++ if (Setup.noEPGMode == 1) { ++ rc = false; ++ if (strstr(::Setup.noEPGList, kanalID.ToString()) != NULL) ++ rc = true; ++ } ++ else { ++ rc = true; ++ if (strstr(::Setup.noEPGList, kanalID.ToString()) != NULL) ++ rc = false; ++ } ++ ++ return rc; ++} ++#endif /* NOEPG */ ++ + cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) + :SI::EIT(Data, false) + { +@@ -35,6 +62,14 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (!channel) + return; // only collect data for known channels + ++#ifdef USE_NOEPG ++ // only use epg from channels not blocked by noEPG-patch ++ tChannelID kanalID; ++ kanalID = channel->GetChannelID(); ++ if (!allowedEPG(kanalID)) ++ return; ++#endif /* NOEPG */ ++ + cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); + + bool Empty = true; +@@ -71,8 +106,74 @@ cEIT::cEIT(cSchedules *Schedules, int So + // If the existing event has a zero table ID it was defined externally and shall + // not be overwritten. + if (pEvent->TableID() == 0x00) { ++#ifdef USE_DDEPGENTRY ++ if (pEvent->Version() == getVersionNumber()) { ++ if (Setup.MixEpgAction == 0) ++ continue; ++ //printf("in"); ++ //printf("%s", pEvent->GetTimeString()); ++ // to use the info of the original epg, update the extern one, ++ // if it has less info ++ SI::Descriptor *d; ++ SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; ++ //SI::ExtendedEventDescriptor *eed = NULL; ++ SI::ShortEventDescriptor *ShortEventDescriptor = NULL; ++ //SI::ShortEventDescriptor *sed = NULL; ++ //SI::TimeShiftedEventDescriptor *tsed = NULL; ++ //cLinkChannels *LinkChannels = NULL; ++ for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2));) { ++ if (d->getDescriptorTag() == SI::ShortEventDescriptorTag) { ++ int LanguagePreferenceShort = -1; ++ SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { ++ delete ShortEventDescriptor; ++ ShortEventDescriptor = sed; ++ d = NULL; // so that it is not deleted ++ } ++ } ++ else if (d->getDescriptorTag() == SI::ExtendedEventDescriptorTag) { ++ int LanguagePreferenceExt = -1; ++ bool UseExtendedEventDescriptor = false; ++ SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { ++ delete ExtendedEventDescriptors; ++ ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; ++ UseExtendedEventDescriptor = true; ++ } ++ if (UseExtendedEventDescriptor) { ++ ExtendedEventDescriptors->Add(eed); ++ d = NULL; // so that it is not deleted ++ } ++ if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) ++ UseExtendedEventDescriptor = false; ++ } ++ delete d; ++ } ++ if (pEvent) { ++ if (ShortEventDescriptor) { ++ char buffer[256]; ++ if (ShortEventDescriptor->text.getText(buffer, sizeof(buffer)) && pEvent->ShortText() && (strlen(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))) > strlen(pEvent->ShortText()))) { ++ pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))); ++ pEvent->FixEpgBugs(); ++ } ++ } ++ if (ExtendedEventDescriptors) { ++ char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ") + 1]; ++ //pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); ++ if (ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ") && pEvent->Description() && (strlen(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")) > strlen(pEvent->Description()))) { ++ pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); ++ pEvent->FixEpgBugs(); ++ } ++ } ++ } ++ delete ExtendedEventDescriptors; ++ delete ShortEventDescriptor; ++ continue; ++ } ++#else + if (pEvent->Version() == getVersionNumber()) + continue; ++#endif /* DDEPGENTRY */ + HasExternalData = ExternalData = true; + } + // If the new event has a higher table ID, let's skip it. +@@ -97,7 +198,11 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (newEvent) + pSchedule->AddEvent(newEvent); + if (Tid == 0x4E) { // we trust only the present/following info on the actual TS ++#ifdef USE_DDEPGENTRY ++ if (Setup.DisableVPS == 0 && SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) ++#else + if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) ++#endif /* DDEPGENTRY */ + pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel); + } + if (OnlyRunningStatus) +@@ -143,8 +248,46 @@ cEIT::cEIT(cSchedules *Schedules, int So + } + break; + case SI::ContentDescriptorTag: ++#ifdef USE_PARENTALRATING ++ { ++ int NumContents = 0; ++ uchar Contents[MAXEVCONTENTS + 1] = { 0 }; ++ SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d; ++ SI::ContentDescriptor::Nibble Nibble; ++ for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) { ++ if (NumContents < MAXEVCONTENTS) { ++ Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); ++ NumContents++; ++ } ++ } ++ pEvent->SetContents(Contents); ++ } ++#endif /* PARENTALRATING */ + break; + case SI::ParentalRatingDescriptorTag: ++#ifdef USE_PARENTALRATING ++ { ++ int LanguagePreferenceRating = -1; ++ SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d; ++ SI::ParentalRatingDescriptor::Rating Rating; ++ for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) { ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) { ++ int rate = (Rating.getRating() & 0xFF); ++ switch (rate) { ++ case 0x01 ... 0x0F: // minimum age = rating + 3 years ++ rate += 3; ++ break; ++ case 0: // undefined ++ case 0x10 ... 0xFF: // defined by the broadcaster ++ default: ++ rate = 0; ++ break; ++ } ++ pEvent->SetParentalRating(rate); ++ } ++ } ++ } ++#endif /* PARENTALRATING */ + break; + case SI::PDCDescriptorTag: { + SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d; +@@ -259,6 +402,62 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (LinkChannels) + channel->SetLinkChannels(LinkChannels); + Modified = true; ++#ifdef USE_DDEPGENTRY ++ //to avoid double epg-entrys from ext and int epg sources :EW ++ if (pEvent && pEvent->TableID() != 0x00) { ++ cEvent *pPreviousEvent = (cEvent *)pSchedule->GetPreviousEvent(pEvent); ++ if (pPreviousEvent) { ++ if (Setup.DoubleEpgAction == 0) { ++ pPreviousEvent->SetStartTime(pEvent->StartTime()); ++ pPreviousEvent->SetDuration(pEvent->Duration()); ++ if (Setup.DisableVPS == 0) { ++ if (channel) ++ pPreviousEvent->SetRunningStatus(pEvent->RunningStatus(), channel); ++ else ++ pPreviousEvent->SetRunningStatus(pEvent->RunningStatus()); ++ } ++ // to use the info of the original epg, update the extern one, ++ // if it has less info ++ char buffer_short_intern[256]; ++ char buffer_short_extern[256]; ++ int len_short_intern = 0; ++ int len_short_extern = 0; ++ if (pEvent->ShortText()) ++ len_short_intern = snprintf (buffer_short_intern, sizeof(buffer_short_intern)-1, "%s", pEvent->ShortText()); ++ if (pPreviousEvent->ShortText()) ++ len_short_extern = snprintf (buffer_short_extern, sizeof(buffer_short_extern)-1, "%s", pPreviousEvent->ShortText()); ++ if (len_short_intern > 0) { ++ if (len_short_extern < 1) ++ pPreviousEvent->SetShortText(buffer_short_intern); ++ else if (len_short_intern > len_short_extern) ++ pPreviousEvent->SetShortText(buffer_short_intern); ++ } ++ if (pEvent->Description()) { ++ char buffer_title_intern[4096]; ++ char buffer_title_extern[4096]; ++ int len_title_intern = 0; ++ int len_title_extern = 0; ++ if (pEvent->Description()) ++ len_title_intern = snprintf (buffer_title_intern, sizeof(buffer_title_intern)-1, "%s", pEvent->Description()); ++ if (pPreviousEvent->Description()) ++ len_title_extern = snprintf (buffer_title_extern, sizeof(buffer_title_extern)-1, "%s", pPreviousEvent->Description()); ++ if (len_title_intern > 0) { ++ if (len_title_extern < 1) ++ pPreviousEvent->SetDescription(buffer_title_intern); ++ else if (len_title_intern > len_title_extern) ++ pPreviousEvent->SetDescription(buffer_title_intern); ++ } ++ } ++ if (pPreviousEvent->Vps() == 0 && pEvent->Vps() != 0) ++ pPreviousEvent->SetVps(pEvent->Vps()); ++ pSchedule->DelEvent(pEvent); ++ pPreviousEvent->FixEpgBugs(); ++ } ++ else ++ pSchedule->DelEvent(pPreviousEvent); ++ } ++ } ++#endif /* DDEPGENTRY */ + } + if (Empty && Tid == 0x4E && getSectionNumber() == 0) + // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running +@@ -296,10 +495,26 @@ cTDT::cTDT(const u_char *Data) + time_t sattim = getTime(); + time_t loctim = time(NULL); + ++#ifdef USE_SETTIME ++ char timestr[20]; ++ struct tm *ptm; ++ struct tm tm_r; ++ ptm = localtime_r(&sattim, &tm_r); ++#endif /* SETTIME */ ++ + int diff = abs(sattim - loctim); + if (diff > 2) { + mutex.Lock(); + if (abs(diff - lastDiff) < 3) { ++#ifdef USE_SETTIME ++ if (SetTime) { ++ strftime(timestr, 20, "%m%d%H%M%Y.%S", ptm); ++ cString cmd = cString::sprintf("%s %s %ld", SetTime, timestr, sattim); ++ dsyslog("Executing: %s", *cmd); ++ SystemExec(cmd); ++ } ++ else ++#endif /* SETTIME */ + if (stime(&sattim) == 0) + isyslog("system time changed from %s (%ld) to %s (%ld)", *TimeToString(loctim), loctim, *TimeToString(sattim), sattim); + else +diff -ruNp vdr-1.6.0-2/eitscan.c vdr-1.6.0-2-extensions/eitscan.c +--- vdr-1.6.0-2/eitscan.c 2006-01-07 15:10:17.000000000 +0100 ++++ vdr-1.6.0-2-extensions/eitscan.c 2009-04-09 20:48:26.000000000 +0200 +@@ -151,9 +151,17 @@ void cEITScanner::Process(void) + if (Device->ProvidesTransponder(Channel)) { + if (!Device->Receiving()) { + bool MaySwitchTransponder = Device->MaySwitchTransponder(); ++#ifdef USE_LNBSHARE ++ if (MaySwitchTransponder && Device->GetMaxBadPriority(Channel) == -2 || Device->ProvidesTransponderExclusively(Channel) && Device->GetMaxBadPriority(Channel) <= -1 && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#else + if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#endif /* LNBSHARE */ + if (!MaySwitchTransponder) { ++#ifdef USE_LNBSHARE ++ if ((Device == cDevice::ActualDevice() || Device->GetMaxBadPriority(Channel) == -1) && !currentChannel) { ++#else + if (Device == cDevice::ActualDevice() && !currentChannel) { ++#endif /* LNBSHARE */ + cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode + currentChannel = Device->CurrentChannel(); + Skins.Message(mtInfo, tr("Starting EPG scan")); +diff -ruNp vdr-1.6.0-2/epg.c vdr-1.6.0-2-extensions/epg.c +--- vdr-1.6.0-2/epg.c 2008-02-16 17:09:12.000000000 +0100 ++++ vdr-1.6.0-2-extensions/epg.c 2009-04-09 20:48:26.000000000 +0200 +@@ -112,6 +112,11 @@ cEvent::cEvent(tEventID EventID) + components = NULL; + startTime = 0; + duration = 0; ++#ifdef USE_PARENTALRATING ++ for (int i = 0; i < MAXEVCONTENTS; i++) ++ contents[i] = 0; ++ parentalRating = 0; ++#endif /* PARENTALRATING */ + vps = 0; + SetSeen(); + } +@@ -200,6 +205,19 @@ void cEvent::SetDuration(int Duration) + duration = Duration; + } + ++#ifdef USE_PARENTALRATING ++void cEvent::SetContents(uchar *Contents) ++{ ++ for (int i = 0; i < MAXEVCONTENTS; i++) ++ contents[i] = Contents[i]; ++} ++ ++void cEvent::SetParentalRating(uchar ParentalRating) ++{ ++ parentalRating = ParentalRating; ++} ++#endif /* PARENTALRATING */ ++ + void cEvent::SetVps(time_t Vps) + { + vps = Vps; +@@ -255,6 +273,340 @@ cString cEvent::GetVpsString(void) const + return buf; + } + ++#ifdef USE_PARENTALRATING ++cString cEvent::GetContentsString(int i) const ++{ ++ cString str(""); ++ switch (contents[i] & 0xF0) { ++ case EVCONTENTMASK_MOVIEDRAMA: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Movie/Drama")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Detective/Thriller")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Adventure/Western/War")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Science Fiction/Fantasy/Horror")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Comedy")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Soap/Melodrama/Folkloric")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Romance")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Serious/Classical/Religious/Historical Movie/Drama")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Adult Movie/Drama")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_NEWSCURRENTAFFAIRS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$News/Current Affairs")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$News/Weather Report")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$News Magazine")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Documentary")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Discussion/Inverview/Debate")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SHOW: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Show/Game Show")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Game Show/Quiz/Contest")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Variety Show")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Talk Show")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SPORTS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Sports")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Special Event")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Sport Magazine")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Football")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Tennis/Squash")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Team Sports")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Athletics")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Motor Sport")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Water Sport")); ++ break; ++ case 0x09: ++ str = cString(tr("Content$Winter Sports")); ++ break; ++ case 0x0A: ++ str = cString(tr("Content$Equestrian")); ++ break; ++ case 0x0B: ++ str = cString(tr("Content$Martial Sports")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_CHILDRENYOUTH: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Children's/Youth Programmes")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Pre-school Children's Programmes")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Entertainment Programmes for 6 to 14")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Entertainment Programmes for 10 to 16")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Informational/Educational/School Programme")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Cartoons/Puppets")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_MUSICBALLETDANCE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Music/Ballet/Dance")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Rock/Pop")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Serious/Classical Music")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Folk/Tradional Music")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Jazz")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Musical/Opera")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Ballet")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_ARTSCULTURE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Arts/Culture")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Performing Arts")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Fine Arts")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Religion")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Popular Culture/Traditional Arts")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Literature")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Film/Cinema")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Experimental Film/Video")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Broadcasting/Press")); ++ break; ++ case 0x09: ++ str = cString(tr("Content$New Media")); ++ break; ++ case 0x0A: ++ str = cString(tr("Content$Arts/Culture Magazines")); ++ break; ++ case 0x0B: ++ str = cString(tr("Content$Fashion")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SOCIALPOLITICALECONOMICS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Social/Political/Economics")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Magazines/Reports/Documentary")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Economics/Social Advisory")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Remarkable People")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_EDUCATIONALSCIENCE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Education/Science/Factual")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Nature/Animals/Environment")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Technology/Natural Sciences")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Medicine/Physiology/Psychology")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Foreign Countries/Expeditions")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Social/Spiritual Sciences")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Further Education")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Languages")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_LEISUREHOBBIES: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Leisure/Hobbies")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Tourism/Travel")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Handicraft")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Motoring")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Fitness & Health")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Cooking")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Advertisement/Shopping")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Gardening")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SPECIAL: ++ switch (contents[i] & 0x0F) { ++ case 0x00: ++ str = cString(tr("Content$Original Language")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Black & White")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Unpublished")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Live Broadcast")); ++ break; ++ default: ++ str = cString(tr("Content$Special Characteristics")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_USERDEFINED: ++ switch (contents[i] & 0x0F) { ++ case 0x00: ++ str = cString(tr("Content$Drama")); // UK Freeview ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ return str; ++} ++ ++cString cEvent::GetParentalRatingString(void) const ++{ ++ if (parentalRating > 0) ++ return cString::sprintf(tr("Suitable for those aged %d and over"), parentalRating); ++ return NULL; ++} ++#endif /* PARENTALRATING */ ++ + void cEvent::Dump(FILE *f, const char *Prefix, bool InfoOnly) const + { + if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) { +@@ -742,6 +1094,28 @@ const cEvent *cSchedule::GetEventAround( + return pe; + } + ++#ifdef USE_DDEPGENTRY ++const cEvent *cSchedule::GetPreviousEvent(cEvent *Event) const ++{ ++ if (!Event || Event->Duration() == 0 || Event->StartTime() == 0) ++ return NULL; ++ // Returns either the event info to the previous/following event to the given EventID or, if that one can't be found NULL :EW ++ cEvent *pt = NULL; ++ int epgTimeDelta = Setup.DoubleEpgTimeDelta * 60 + 1; ++ for (pt = events.First(); pt; pt = events.Next(pt)) ++ if (pt && pt->TableID() == 0x00) ++ if ((Event->StartTime() - pt->StartTime()) > - epgTimeDelta && (Event->StartTime() - pt->StartTime()) < epgTimeDelta) { ++ if ((pt->Duration() + (pt->Duration()/ 5) + 1) > Event->Duration() && (pt->Duration() - (pt->Duration()/ 5) - 1) < Event->Duration()) ++ return pt; ++ else if (pt->Title() && Event->Title() && (strcmp(pt->Title(), ".") != 0 && strcmp(Event->Title(), ".") != 0)) { ++ if (strstr(pt->Title(), Event->Title()) != NULL || strstr(Event->Title(), pt->Title()) != NULL) ++ return pt; ++ } ++ } ++ return NULL; ++} ++#endif /* DDEPGENTRY */ ++ + void cSchedule::SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel) + { + hasRunning = false; +diff -ruNp vdr-1.6.0-2/epg.h vdr-1.6.0-2-extensions/epg.h +--- vdr-1.6.0-2/epg.h 2006-10-07 15:47:19.000000000 +0200 ++++ vdr-1.6.0-2-extensions/epg.h 2009-04-09 20:48:26.000000000 +0200 +@@ -50,6 +50,22 @@ class cSchedule; + + typedef u_int32_t tEventID; + ++#ifdef USE_PARENTALRATING ++#define MAXEVCONTENTS 4 ++#define EVCONTENTMASK_MOVIEDRAMA 0x10 ++#define EVCONTENTMASK_NEWSCURRENTAFFAIRS 0x20 ++#define EVCONTENTMASK_SHOW 0x30 ++#define EVCONTENTMASK_SPORTS 0x40 ++#define EVCONTENTMASK_CHILDRENYOUTH 0x50 ++#define EVCONTENTMASK_MUSICBALLETDANCE 0x60 ++#define EVCONTENTMASK_ARTSCULTURE 0x70 ++#define EVCONTENTMASK_SOCIALPOLITICALECONOMICS 0x80 ++#define EVCONTENTMASK_EDUCATIONALSCIENCE 0x90 ++#define EVCONTENTMASK_LEISUREHOBBIES 0xA0 ++#define EVCONTENTMASK_SPECIAL 0xB0 ++#define EVCONTENTMASK_USERDEFINED 0xF0 ++#endif /* PARENTALRATING */ ++ + class cEvent : public cListObject { + friend class cSchedule; + private: +@@ -64,6 +80,10 @@ private: + cComponents *components; // The stream components of this event + time_t startTime; // Start time of this event + int duration; // Duration of this event in seconds ++#ifdef USE_PARENTALRATING ++ uchar contents[MAXEVCONTENTS + 1]; // Contents of this event; list is zero-terminated ++ uchar parentalRating; // Parental rating of this event ++#endif /* PARENTALRATING */ + time_t vps; // Video Programming Service timestamp (VPS, aka "Programme Identification Label", PIL) + time_t seen; // When this event was last seen in the data stream + public: +@@ -83,6 +103,10 @@ public: + time_t StartTime(void) const { return startTime; } + time_t EndTime(void) const { return startTime + duration; } + int Duration(void) const { return duration; } ++#ifdef USE_PARENTALRATING ++ uchar Contents(int i = 0) const { return (0 <= i && i < MAXEVCONTENTS) ? contents[i] : 0; } ++ uchar ParentalRating(void) const { return parentalRating; } ++#endif /* PARENTALRATING */ + time_t Vps(void) const { return vps; } + time_t Seen(void) const { return seen; } + bool SeenWithin(int Seconds) const { return time(NULL) - seen < Seconds; } +@@ -92,6 +116,10 @@ public: + cString GetTimeString(void) const; + cString GetEndTimeString(void) const; + cString GetVpsString(void) const; ++#ifdef USE_PARENTALRATING ++ cString GetContentsString(int i = 0) const; ++ cString GetParentalRatingString(void) const; ++#endif /* PARENTALRATING */ + void SetEventID(tEventID EventID); + void SetTableID(uchar TableID); + void SetVersion(uchar Version); +@@ -102,6 +130,10 @@ public: + void SetComponents(cComponents *Components); // Will take ownership of Components! + void SetStartTime(time_t StartTime); + void SetDuration(int Duration); ++#ifdef USE_PARENTALRATING ++ void SetContents(uchar *Contents); ++ void SetParentalRating(uchar ParentalRating); ++#endif /* PARENTALRATING */ + void SetVps(time_t Vps); + void SetSeen(void); + cString ToDescr(void) const; +@@ -137,6 +169,9 @@ public: + void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); + void Cleanup(time_t Time); + void Cleanup(void); ++#ifdef USE_DDEPGENTRY ++ const cEvent *GetPreviousEvent(cEvent *Event) const; //:EW ++#endif /* DDEPGENTRY */ + cEvent *AddEvent(cEvent *Event); + void DelEvent(cEvent *Event); + void HashEvent(cEvent *Event); +diff -ruNp vdr-1.6.0-2/HISTORY-liemikuutio vdr-1.6.0-2-extensions/HISTORY-liemikuutio +--- vdr-1.6.0-2/HISTORY-liemikuutio 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/HISTORY-liemikuutio 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,108 @@ ++----------------------------------- ++Liemikuutio for Video Disc Recorder ++ ++Maintainer: Rolf Ahrenberg ++----------------------------------- ++ ++2006-01-08: Version 1.0 ++ ++- Based on enAIO with these original patches: ++ Simple recordings sorting by Walter@VDRPortal ++ Alternate rename recordings by Ralf Müller ++ Menu selection by Peter Dittmann ++ Recording length by Tobias Faust ++ ++2006-01-15: Version 1.1 ++ ++- Removed patches already found in vdr-1.3.39. ++ ++2006-01-25: Version 1.2 ++ ++- Added "Main menu command position" feature. ++ ++2006-02-05: Version 1.3 ++ ++- Improved menu selection response. ++ ++2006-04-18: Version 1.4 ++ ++- Added Estonian translation (Thanks to Arthur Konovalov). ++ ++2006-04-30: Version 1.5 ++ ++- Added progress bar view into "What's on now?" menu. ++ ++2006-06-06: Version 1.6 ++ ++- Added French translation (Thanks to ECLiPSE). ++ ++2006-06-14: Version 1.7 ++ ++- Fixed RENR crash. ++ ++2006-07-14: Version 1.8 ++ ++- Fixed RENR/OSD bug. ++ ++2006-08-27: Version 1.9 ++ ++- Some modifications to the recording length and rename recordings ++ patches (Thanks to Firefly). ++- Added k1_k3_jumps_20s patch by Petri Hintukainen. ++ ++2006-08-29: Version 1.10 ++ ++- The cRecording:Title() method now defaults to original formatting. ++ ++2006-09-04: Version 1.11 ++ ++- Removed unused variable from cRecording::Title() method (Thanks to ++ C.Y.M.). ++- Some modifications to the rename recordings patch (Thanks to Firefly). ++ ++2006-09-13: Version 1.12 ++ ++- More modifications to the rename recordings patch (Thanks to Firefly). ++ ++2006-10-01: Version 1.13 ++ ++- Removed unnecessary syslog printing (Thanks to Firefly). ++ ++2007-08-14: Version 1.14 ++ ++- Updated for vdr-1.5.7. ++ ++2007-10-16: Version 1.15 ++ ++- Added recmenu play patch (Thanks to Ville Skyttä). ++- Updated French translation (Thanks to ECLiPSE). ++ ++2007-11-04: Version 1.16 ++ ++- Updated for vdr-1.5.11. ++ ++2007-12-08: Version 1.17 ++ ++- Added binary skip patch. ++- Removed k1_k3_jumps_20s patch. ++ ++2008-02-17: Version 1.18 ++ ++- Updated for vdr-1.5.15. ++ ++2008-03-02: Version 1.19 ++ ++- Modified binary skip to use kPrev and kNext keys and the skip is now ++ always shortened after a direction change (Thanks to Timo Eskola). ++- Readded k1_k3_jumps_20s patch. ++ ++2008-04-04: Version 1.20 ++ ++- Added bitrate information into rename menu. ++- Readded the path editing support of rename recordings patch (Thanks ++ to Firefly). ++ ++2008-05-08: Version 1.21 ++ ++- Fixed rename recordings (Thanks to Firefly). ++- Added a DVB subtitles hack for old recordings (Thanks to Anssi Hannula). +diff -ruNp vdr-1.6.0-2/iconpatch.c vdr-1.6.0-2-extensions/iconpatch.c +--- vdr-1.6.0-2/iconpatch.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/iconpatch.c 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,31 @@ ++#ifdef USE_WAREAGLEICON ++ ++#include "iconpatch.h" ++ ++#include <langinfo.h> ++#include <locale.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++bool IsLangUtf8(void) ++{ ++ char *CodeSet = NULL; ++ if (setlocale(LC_CTYPE, "")) ++ CodeSet = nl_langinfo(CODESET); ++ else { ++ char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed ++ if (LangEnv) { ++ CodeSet = strchr(LangEnv, '.'); ++ if (CodeSet) ++ CodeSet++; // skip the dot ++ } ++ } ++ ++ if (CodeSet && strcasestr(CodeSet, "UTF-8") != 0) ++ return true; ++ ++ return false; ++} ++ ++#endif /* WAREAGLEICON */ +diff -ruNp vdr-1.6.0-2/iconpatch.h vdr-1.6.0-2-extensions/iconpatch.h +--- vdr-1.6.0-2/iconpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/iconpatch.h 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,73 @@ ++#ifdef USE_WAREAGLEICON ++/* ++ * iconpatch.h: Information of iconpatch ++ * ++ * Diese Datei ist die Übersichtsdatei für den Iconpatch. ++ * Hier werden kleine Infos abgelegt. ++ * Der Iconpatch ändert die Dateien: ++ * iconpatch.h ++ * menu.c ++ * recording.c ++ * fontosd.c ++ * ++ */ ++ ++// Iconpatch-Variablen - Anfang ++#define ICON_NUMBERSIGN "\x23" ++#define ICON_ASTERISK "\x2A" ++#define ICON_GREATER "\x3E" ++#define ICON_EXCLAM "\x21" ++#define ICON_PLUSMINUS "\xB1" ++ ++#define ICON_RESUME "\x80" ++#define ICON_DVD "\x81" ++#define ICON_FOLDER "\x82" ++#define ICON_BLANK "\x83" ++#define ICON_CUTTING "\x84" ++#define ICON_MOVE_FILE "\x85" ++#define ICON_MOVE_FOLDER "\x86" ++#define ICON_BAR_START "\x87" ++#define ICON_BAR_FILLED "\x88" ++#define ICON_BAR_CLEAR "\x89" ++#define ICON_BAR_END "\x8A" ++#define ICON_REC "\x8B" ++#define ICON_CLOCK "\x8C" ++#define ICON_TV_CRYPTED "\x8D" ++#define ICON_RADIO "\x8E" ++#define ICON_TV "\x8F" ++#define ICON_NEW "\x90" ++#define ICON_ARROW "\x91" ++#define ICON_RUNNING "\x92" ++#define ICON_VPS "\x93" ++#define ICON_CLOCK_UH "\x94" ++#define ICON_CLOCK_LH "\x95" ++ ++// UTF-8 Icons ++#define ICON_RESUME_UTF8 "\uE000" ++#define ICON_DVD_UTF8 "\uE001" ++#define ICON_FOLDER_UTF8 "\uE002" ++#define ICON_BLANK_UTF8 "\uE003" ++#define ICON_CUTTING_UTF8 "\uE004" ++#define ICON_MOVE_FILE_UTF8 "\uE005" ++#define ICON_MOVE_FOLDER_UTF8 "\uE006" ++#define ICON_BAR_START_UTF8 "\uE007" ++#define ICON_BAR_FILLED_UTF8 "\uE008" ++#define ICON_BAR_EMPTY_UTF8 "\uE009" ++#define ICON_BAR_CLOSE_UTF8 "\uE00A" ++#define ICON_REC_UTF8 "\uE00B" ++#define ICON_CLOCK_UTF8 "\uE00C" ++#define ICON_TV_CRYPTED_UTF8 "\uE00D" ++#define ICON_RADIO_UTF8 "\uE00E" ++#define ICON_TV_UTF8 "\uE00F" ++#define ICON_NEW_UTF8 "\uE010" ++#define ICON_ARROW_UTF8 "\uE011" ++#define ICON_RUNNING_UTF8 "\uE012" ++#define ICON_VPS_UTF8 "\uE013" ++#define ICON_CLOCK_UH_UTF8 "\uE014" ++#define ICON_CLOCK_LH_UTF8 "\uE015" ++ ++// Iconpatch-Variablen - Ende ++ ++bool IsLangUtf8(void); ++ ++#endif /* WAREAGLEICON */ +diff -ruNp vdr-1.6.0-2/keys.h vdr-1.6.0-2-extensions/keys.h +--- vdr-1.6.0-2/keys.h 2007-08-26 14:34:50.000000000 +0200 ++++ vdr-1.6.0-2-extensions/keys.h 2009-04-09 20:48:26.000000000 +0200 +@@ -71,6 +71,10 @@ enum eKeys { // "Up" and "Down" must be + #define kEditCut k2 + #define kEditTest k8 + ++#ifdef USE_DVDARCHIVE ++#define kDvdChapterJumpForward k6 ++#define kDvdChapterJumpBack k4 ++#endif /* DVDARCHIVE */ + #define RAWKEY(k) (eKeys((k) & ~k_Flags)) + #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) + #define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) +diff -ruNp vdr-1.6.0-2/lirc.c vdr-1.6.0-2-extensions/lirc.c +--- vdr-1.6.0-2/lirc.c 2006-05-28 10:48:13.000000000 +0200 ++++ vdr-1.6.0-2-extensions/lirc.c 2009-04-09 20:48:26.000000000 +0200 +@@ -12,6 +12,9 @@ + #include "lirc.h" + #include <netinet/in.h> + #include <sys/socket.h> ++#ifdef USE_LIRCSETTINGS ++#include "config.h" ++#endif /* LIRCSETTINGS */ + + #define REPEATDELAY 350 // ms + #define REPEATFREQ 100 // ms +@@ -94,7 +97,11 @@ void cLircRemote::Action(void) + continue; + } + if (count == 0) { ++#ifdef USE_LIRCSETTINGS ++ if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast + if (repeat) + Put(LastKeyName, false, true); +@@ -104,18 +111,34 @@ void cLircRemote::Action(void) + timeout = -1; + } + else { ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() < (unsigned int)Setup.LircRepeatFreq) ++#else + if (LastTime.Elapsed() < REPEATFREQ) ++#endif /* LIRCSETTINGS */ + continue; // repeat function kicks in after a short delay (after last key instead of first key) ++#ifdef USE_LIRCSETTINGS ++ if (FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast (for count != 0 as well) + repeat = true; ++#ifdef USE_LIRCSETTINGS ++ timeout = Setup.LircRepeatDelay; ++#else + timeout = REPEATDELAY; ++#endif /* LIRCSETTINGS */ + } + LastTime.Set(); + Put(KeyName, repeat); + } + else if (repeat) { // the last one was a repeat, so let's generate a release ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() >= (unsigned int)Setup.LircRepeatTimeout) { ++#else + if (LastTime.Elapsed() >= REPEATTIMEOUT) { ++#endif /* LIRCSETTINGS */ + Put(LastKeyName, false, true); + repeat = false; + *LastKeyName = 0; +diff -ruNp vdr-1.6.0-2/livebuffer.c vdr-1.6.0-2-extensions/livebuffer.c +--- vdr-1.6.0-2/livebuffer.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/livebuffer.c 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,1912 @@ ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#include "menu.h" ++#include "recording.h" ++#include "transfer.h" ++ ++#define RECORDERBUFSIZE MEGABYTE(2) ++ ++// --- cFileName ------------------------------------------------------------- ++ ++#include <errno.h> ++#include <unistd.h> ++#include "videodir.h" ++ ++#define MAXFILESPERRECORDING 255 ++#define RECORDFILESUFFIX "/%03d.vdr" ++#define RECORDFILESUFFIXLEN 20 ++ ++cFileName64::cFileName64(const char *FileName, bool Record, bool Blocking) ++{ ++ file = NULL; ++ record = Record; ++ blocking = Blocking; ++ // Prepare the file name: ++ fileName = MALLOC(char, strlen(FileName) + RECORDFILESUFFIXLEN); ++ if (!fileName) { ++ esyslog("ERROR: can't copy file name '%s'", fileName); ++ return; ++ } ++ strcpy(fileName, FileName); ++ pFileNumber = fileName + strlen(fileName); ++ ++ fileNumber = 1; ++ while (true) { ++ sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); ++ if (record) { ++ if (access(fileName, F_OK) == 0) { ++ struct stat64 buf; ++ if (stat64(fileName, &buf) == 0) { ++ fileNumber++; ++ continue; ++ } ++ } ++ else if (errno != ENOENT) ++ LOG_ERROR_STR(fileName); ++ } ++ break; ++ } ++} ++ ++cFileName64::~cFileName64() ++{ ++ Close(); ++ free(fileName); ++} ++ ++void cFileName64::SetNumber(int Number) ++{ ++ fileNumber = Number; ++ sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); ++} ++ ++cUnbufferedFile64 *cFileName64::Open(void) ++{ ++ if (!file) { ++ int BlockingFlag = blocking ? 0 : O_NONBLOCK; ++ if (record) { ++ file = cUnbufferedFile64::Create(fileName, O_RDWR | O_CREAT | BlockingFlag); ++ if (!file) ++ LOG_ERROR_STR(fileName); ++ } ++ else { ++ if (access(fileName, R_OK) == 0) { ++ file = cUnbufferedFile64::Create(fileName, O_RDONLY | BlockingFlag); ++ if (!file) ++ LOG_ERROR_STR(fileName); ++ } ++ else if (errno != ENOENT) ++ LOG_ERROR_STR(fileName); ++ } ++ } ++ return file; ++} ++ ++void cFileName64::Close(void) ++{ ++ if (file) { ++ if (file->Close() < 0) ++ LOG_ERROR_STR(fileName); ++ delete file; ++ file = NULL; ++ } ++} ++ ++void cFileName64::CloseAndRemove(void) ++{ ++ Close(); ++ remove(fileName); ++} ++ ++// --- cUnbufferedFile64 ----------------------------------------------------- ++ ++#define USE_FADVISE ++ ++#define WRITE_BUFFER KILOBYTE(800) ++ ++cUnbufferedFile64::cUnbufferedFile64(void) ++{ ++ fd = -1; ++} ++ ++cUnbufferedFile64::~cUnbufferedFile64() ++{ ++ Close(); ++} ++ ++int cUnbufferedFile64::Open(const char *FileName, int Flags, mode_t Mode) ++{ ++ Close(); ++ fd = open64(FileName, Flags, Mode); ++ curpos = 0; ++#ifdef USE_FADVISE ++ begin = lastpos = ahead = 0; ++ cachedstart = 0; ++ cachedend = 0; ++ readahead = KILOBYTE(128); ++ written = 0; ++ totwritten = 0; ++ if (fd >= 0) ++ posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); ++#endif ++ return fd; ++} ++ ++int cUnbufferedFile64::Close(void) ++{ ++#ifdef USE_FADVISE ++ if (fd >= 0) { ++ if (totwritten) ++ fdatasync(fd); ++ posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); ++ } ++#endif ++ int OldFd = fd; ++ fd = -1; ++ return close(OldFd); ++} ++ ++ ++#define FADVGRAN KILOBYTE(4) ++#define READCHUNK MEGABYTE(8) ++ ++int cUnbufferedFile64::FadviseDrop(off64_t Offset, off64_t Len) ++{ ++ return posix_fadvise64(fd, Offset - (FADVGRAN - 1), Len + (FADVGRAN - 1) * 2, POSIX_FADV_DONTNEED); ++} ++ ++ ++off64_t cUnbufferedFile64::Seek(off64_t Offset, int Whence) ++{ ++ if (Whence == SEEK_SET && Offset == curpos) ++ return curpos; ++ curpos = lseek64(fd, Offset, Whence); ++ return curpos; ++} ++ ++ssize_t cUnbufferedFile64::Read(void *Data, size_t Size) ++{ ++ if (fd >= 0) { ++#ifdef USE_FADVISE ++ off64_t jumped = curpos-lastpos; ++ if ((cachedstart < cachedend) && (curpos < cachedstart || curpos > cachedend)) { ++ FadviseDrop(cachedstart, cachedend-cachedstart); ++ cachedstart = curpos; ++ cachedend = curpos; ++ } ++ cachedstart = min(cachedstart, curpos); ++#endif ++ ssize_t bytesRead = safe_read(fd, Data, Size); ++#ifdef USE_FADVISE ++ if (bytesRead > 0) { ++ curpos += bytesRead; ++ cachedend = max(cachedend, curpos); ++ ++ if (jumped >= 0 && jumped <= (off64_t)readahead) { ++ if (ahead - curpos < (off64_t)(readahead / 2)) { ++ posix_fadvise64(fd, curpos, readahead, POSIX_FADV_WILLNEED); ++ ahead = curpos + readahead; ++ cachedend = max(cachedend, ahead); ++ } ++ if (readahead < Size * 32) { ++ readahead = Size * 32; ++ } ++ } ++ else ++ ahead = curpos; ++ } ++ ++ if (cachedstart < cachedend) { ++ if (curpos - cachedstart > READCHUNK * 2) { ++ FadviseDrop(cachedstart, curpos - READCHUNK - cachedstart); ++ cachedstart = curpos - READCHUNK; ++ } ++ else if (cachedend > ahead && cachedend - curpos > READCHUNK * 2) { ++ FadviseDrop(curpos + READCHUNK, cachedend - (curpos + READCHUNK)); ++ cachedend = curpos + READCHUNK; ++ } ++ } ++ lastpos = curpos; ++#endif ++ return bytesRead; ++ } ++ return -1; ++} ++ ++ssize_t cUnbufferedFile64::Write(const void *Data, size_t Size) ++{ ++ if (fd >=0) { ++ ssize_t bytesWritten = safe_write(fd, Data, Size); ++#ifdef USE_FADVISE ++ if (bytesWritten > 0) { ++ begin = min(begin, curpos); ++ curpos += bytesWritten; ++ written += bytesWritten; ++ lastpos = max(lastpos, curpos); ++ if (written > WRITE_BUFFER) { ++ if (lastpos > begin) { ++ off64_t headdrop = min(begin, (off64_t) WRITE_BUFFER * 2L); ++ posix_fadvise64(fd, begin - headdrop, lastpos - begin + headdrop, POSIX_FADV_DONTNEED); ++ } ++ begin = lastpos = curpos; ++ totwritten += written; ++ written = 0; ++ if (totwritten > MEGABYTE(32)) { ++ off64_t headdrop = min((off64_t) (curpos - totwritten), (off64_t) totwritten * 2L); ++ posix_fadvise64(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED); ++ totwritten = 0; ++ } ++ } ++ } ++#endif ++ return bytesWritten; ++ } ++ return -1; ++} ++ ++cUnbufferedFile64 *cUnbufferedFile64::Create(const char *FileName, int Flags, mode_t Mode) ++{ ++ cUnbufferedFile64 *File = new cUnbufferedFile64; ++ if (File->Open(FileName, Flags, Mode) < 0) { ++ delete File; ++ File = NULL; ++ } ++ return File; ++} ++ ++// --- cLiveIndex ------------------------------------------------------------ ++ ++cLiveIndex::cLiveIndex(int BufSize) ++{ ++ bufSize = BufSize; ++ headblock = tailblock = new block; ++ headblock->previous = headblock->next = headblock; ++ head = tail = 0; ++ blank = 0; ++ blockCount = 1; ++ writtenCount = delCount = 0; ++ lastWrittenSize = lastCount = 0; ++ fileSize = 0; ++ lastFrame = -1; ++ DPos = -1; ++ DCount = 0; ++ start = 0; ++ RwLock = new cRwLock(true); ++} ++ ++cLiveIndex::~cLiveIndex() ++{ ++ while (tailblock != headblock) { ++ block *n = tailblock->next; ++ delete tailblock; ++ tailblock = n; ++ } ++ delete headblock; ++ delete RwLock; ++} ++ ++void cLiveIndex::Add(uchar pt, int pos) ++{ ++ RwLock->Lock(true); ++ DCount=0; ++ DPos = pos; ++ headblock->Frame[head].offset = pos; ++ headblock->Frame[head].written = false; ++ headblock->Frame[head].pt = pt; ++ head++; ++ lastFrame++; ++ if (head == INDEXBLOCKSIZE) { ++ block* b = new block; ++ b->previous = headblock; ++ b->next = b; ++ headblock->next = b; ++ headblock = b; ++ head = 0; ++ blockCount++; ++ } ++ RwLock->Unlock(); ++} ++ ++void cLiveIndex::AddData(int pos) ++{ ++ RwLock->Lock(true); ++ DCount=pos-DPos; ++ RwLock->Unlock(); ++} ++ ++void cLiveIndex::Delete(off64_t FilePos) ++{ ++ RwLock->Lock(true); ++ if (tailblock->Frame[tail].offset <= FilePos) { ++ if (tailblock->Frame[tail].offset + MAXFRAMESIZE >= FilePos) { ++ int old_offset = tailblock->Frame[tail].offset; ++ while (tailblock->Frame[tail].written && tailblock->Frame[tail].offset < FilePos && tailblock->Frame[tail].offset >= old_offset) { ++ tail++; ++ delCount++; ++ if (tail == INDEXBLOCKSIZE) { ++ block *b = tailblock->next; ++ b->previous = b; ++ if (tailblock != headblock) ++ delete tailblock; ++ tailblock = b; ++ tail = 0; ++ blockCount--; ++ } ++ } ++ } ++ } ++ else { ++ if (tailblock->Frame[tail].offset - MAXFRAMESIZE > FilePos) { ++ int old_offset = tailblock->Frame[tail].offset; ++ while (tailblock->Frame[tail].written && (tailblock->Frame[tail].offset < FilePos || tailblock->Frame[tail].offset >= old_offset)) { ++ tail++; ++ delCount++; ++ if (tail == INDEXBLOCKSIZE) { ++ block *b = tailblock->next; ++ b->previous = b; ++ if (tailblock != headblock) ++ delete tailblock; ++ tailblock = b; ++ tail = 0; ++ blockCount--; ++ } ++ } ++ } ++ } ++ RwLock->Unlock(); ++} ++ ++int cLiveIndex::DelFirst(void) ++{ ++ RwLock->Lock(true); ++ tail++; ++ delCount++; ++ writtenCount++; ++ if (tail == INDEXBLOCKSIZE) { ++ block *b = tailblock->next; ++ b->previous = b; ++ if (tailblock != headblock) ++ delete tailblock; ++ tailblock = b; ++ tail = 0; ++ blockCount--; ++ } ++ int r = tailblock->Frame[tail].offset; ++ RwLock->Unlock(); ++ return r; ++} ++ ++void cLiveIndex::Clear(void) ++{ ++ RwLock->Lock(true); ++ while (tailblock != headblock) { ++ block *n = tailblock->next; ++ delete tailblock; ++ tailblock = n; ++ } ++ headblock->previous = headblock; ++ head = tail = blank = 0; ++ blockCount = 1; ++ writtenCount = delCount = 0; ++ DPos = -1; ++ DCount = 0; ++ start = 0; ++ lastFrame = -1; ++ lastWrittenSize = lastCount = 0; ++ fileSize = 0; ++ RwLock->Unlock(); ++} ++ ++int cLiveIndex::NextWrite(void) ++{ ++ RwLock->Lock(false); ++ block *b; ++ int i = GetFrame(&b,writtenCount); ++ int off = 0; ++ if (i+1 == INDEXBLOCKSIZE) ++ off = b->next->Frame[0].offset; ++ else ++ off = b->Frame[i+1].offset; ++ int r = 0; ++ if (off < b->Frame[i].offset) ++ r = bufSize - b->Frame[i].offset - blank; ++ else ++ r = off - b->Frame[i].offset; ++ RwLock->Unlock(); ++ return r; ++} ++ ++void cLiveIndex::WrittenTo(off64_t FilePos, int Count) ++{ ++ RwLock->Lock(true); ++ lastWrittenSize=Count; ++ block *b; ++ int i = GetFrame(&b, writtenCount); ++ writtenCount++; ++ if (FilePos == 0) { ++ if (i) ++ fileSize = b->Frame[i-1].offset + lastCount; ++ else if (b->previous != b) ++ fileSize = b->previous->Frame[INDEXBLOCKSIZE-1].offset + lastCount; ++ } ++ b->Frame[i].offset = FilePos; ++ b->Frame[i].written = true; ++ RwLock->Unlock(); ++ lastCount = Count; ++} ++ ++int cLiveIndex::GetFrame(block** Block, int Number) ++{ ++ int bc = 0; ++ int i = Number-delCount; ++ if (INDEXBLOCKSIZE-tail <= i) ++ bc = 1 + (i-INDEXBLOCKSIZE+tail)/INDEXBLOCKSIZE; ++ i-= bc*INDEXBLOCKSIZE-tail; ++ block *b = tailblock; ++ for (int j=0; j<bc; j++) ++ b = b->next; ++ *Block = b; ++ return i; ++} ++ ++off64_t cLiveIndex::GetOffset(int Number) ++{ ++ RwLock->Lock(false); ++ off64_t r = -1; ++ if (HasFrame(Number)) { ++ block *b; ++ int i = GetFrame(&b, Number); ++ r = b->Frame[i].offset; ++ } ++ else if (HasFrame(Number-1)) ++ r = DPos; ++ RwLock->Unlock(); ++ return r; ++} ++ ++int cLiveIndex::Size(int Number, uchar *PictureType) ++{ ++ int r = -1; ++ RwLock->Lock(false); ++ if (HasFrame(Number)) { ++ if (Number+1 == writtenCount) ++ r = lastWrittenSize; ++ else { ++ block *b; ++ int i = GetFrame(&b, Number); ++ if (PictureType) ++ *PictureType = b->Frame[i].pt; ++ off64_t off = 0; ++ if (i+1 == INDEXBLOCKSIZE) ++ off = b->next->Frame[0].offset; ++ else ++ off = b->Frame[i+1].offset; ++ if (off < b->Frame[i].offset) { ++ if (b->Frame[i].written) ++ r = fileSize - b->Frame[i].offset; ++ else ++ r = bufSize - b->Frame[i].offset - blank; ++ } ++ else ++ r = off - b->Frame[i].offset; ++ } ++ } ++ else if (HasFrame(Number-1) && DPos >= 0) ++ r = DCount; ++ RwLock->Unlock(); ++ return r; ++} ++ ++int cLiveIndex::GetNextIFrame(int Index, bool Forward) ++{ ++ int d = Forward ? 1 : -1; ++ Index += d; ++ while (Index >= delCount && Index < lastFrame) { ++ block *b; ++ RwLock->Lock(false); ++ int i = GetFrame(&b, Index); ++ uchar type = b->Frame[i].pt; ++ RwLock->Unlock(); ++ if (type == I_FRAME) ++ return Index; ++ Index +=d; ++ } ++ return -1; ++} ++ ++int cLiveIndex::FindIFrame(int64_t PTS, uchar *Buffer) ++{ ++ int r = -1; ++ RwLock->Lock(false); ++ int Index=writtenCount; ++ int64_t pts=0; ++ do { ++ Index = GetNextIFrame(Index, true); ++ if (Index < 0) ++ break; ++ block *b; ++ int i = GetFrame(&b, Index); ++ uchar *p = &Buffer[b->Frame[i].offset]; ++ if (p[0]==0x00 && p[1]==0x00 && p[2]==0x01 && (p[7] & 0x80) && p[3]>=0xC0 && p[3]<=0xEF) { ++ pts = (int64_t) (p[ 9] & 0x0E) << 29 ; ++ pts |= (int64_t) p[ 10] << 22 ; ++ pts |= (int64_t) (p[ 11] & 0xFE) << 14 ; ++ pts |= (int64_t) p[ 12] << 7 ; ++ pts |= (int64_t) (p[ 13] & 0xFE) >> 1 ; ++ } ++ } while (pts!=PTS); ++ if (pts==PTS) ++ r = Index; ++ RwLock->Unlock(); ++ return r; ++} ++ ++void cLiveIndex::Switched(void) ++{ ++ start = Last(); ++} ++ ++// --- cLiveFileReader ------------------------------------------------------- ++ ++cLiveFileReader::cLiveFileReader(const char *FileName, int Number) ++{ ++ fileName = new cFileName64(FileName, false); ++ fileName->SetNumber(Number); ++ readFile = fileName->Open(); ++ buffer = NULL; ++ filePos = 0; ++ Start(); ++} ++ ++cLiveFileReader::~cLiveFileReader() ++{ ++ Cancel(3); ++ delete fileName; ++} ++ ++void cLiveFileReader::Action(void) ++{ ++ while (Running()) { ++ Lock(); ++ if (buffer && !hasData) { ++ int r = readFile->Read(buffer + length, wanted - length); ++ if (r >= 0) { ++ length += r; ++ filePos += r; ++ if (length == wanted) ++ hasData = true; ++ } ++ else if (r < 0 && FATALERRNO) { ++ LOG_ERROR; ++ length = r; ++ hasData = true; ++ } ++ } ++ Unlock(); ++ newSet.Wait(1000); ++ } ++} ++ ++int cLiveFileReader::Read(uchar **Buffer, off64_t FilePos, int Size) ++{ ++ if (buffer && hasData) { ++ *Buffer = buffer; ++ buffer = NULL; ++ return length; ++ } ++ if (!buffer) { ++ uchar *b = MALLOC(uchar, Size); ++ if (filePos != FilePos) { ++ filePos = FilePos; ++ readFile->Seek(FilePos,0); ++ } ++ wanted = Size; ++ length = 0; ++ hasData = false; ++ buffer = b; ++ newSet.Signal(); ++ } ++ return -1; ++} ++ ++void cLiveFileReader::Clear(void) ++{ ++ Lock(); ++ delete buffer; ++ buffer = NULL; ++ Unlock(); ++} ++ ++// --- cLiveFileWriter ------------------------------------------------------- ++ ++cLiveFileWriter::cLiveFileWriter(const char *FileName) ++{ ++ MakeDirs(FileName, true); ++ SpinUpDisk(FileName); ++ fileName = new cFileName64(FileName, true); ++ writeFile = fileName->Open(); ++ buffer = NULL; ++ filePos = fileSize = 0; ++ lastCheck = time(NULL); ++ full = false; ++ Start(); ++} ++ ++cLiveFileWriter::~cLiveFileWriter() ++{ ++ Cancel(3); ++ fileName->CloseAndRemove(); ++ delete fileName; ++} ++ ++void cLiveFileWriter::Action(void) ++{ ++ while (Running()) { ++ Lock(); ++ if (buffer && !hasWritten) { ++ int r = writeFile->Write(buffer, wantWrite); ++ if (r >= 0) { ++ filePos += r; ++ hasWritten = true; ++ } ++ else if (r < 0 && FATALERRNO) { ++ LOG_ERROR; ++ hasWritten = true; ++ } ++ } ++ Unlock(); ++ newSet.Wait(1000); ++ } ++} ++ ++#define MINFREE 600 ++ ++bool cLiveFileWriter::LowDiskSpace() ++{ ++ if (!full && time (NULL) > lastCheck + 60 || full && filePos >= fileSize) { ++ int Free = FreeDiskSpaceMB(fileName->Name()); ++ lastCheck = time(NULL); ++ if (Free < MINFREE) ++ return true; ++ } ++ return false; ++} ++ ++off64_t cLiveFileWriter::Write(uchar *Buffer, int Size, bool Wait) ++{ ++ if (buffer && hasWritten) { ++ buffer = NULL; ++ return filePos; ++ } ++ if (!buffer) { ++ if (filePos + Size > (off64_t)Setup.LiveBufferSize*1024*1024 || LowDiskSpace()) { ++ fileSize = filePos > fileSize ? filePos : fileSize; ++ filePos = 0; ++ writeFile->Seek(0,0); ++ full = true; ++ } ++ if (Wait) { ++ writeFile->Write(Buffer, Size); ++ filePos += Size; ++ return filePos; ++ } ++ else { ++ wantWrite = Size; ++ hasWritten = false; ++ buffer = Buffer; ++ newSet.Signal(); ++ } ++ } ++ if (Wait) { ++ while (!hasWritten) ++ usleep(5); ++ buffer = NULL; ++ return filePos; ++ } ++ return -1; ++} ++ ++void cLiveFileWriter::Clear(void) ++{ ++ Lock(); ++ buffer = NULL; ++ filePos = 0; ++ full = false; ++ writeFile->Seek(0,0); ++ Unlock(); ++} ++ ++// --- cLiveCutterThread ----------------------------------------------------- ++ ++cLiveCutterThread::cLiveCutterThread(const char *FileName, int FileNumber, cLiveBuffer *LiveBuffer, int StartFrame, int EndFrame) ++{ ++ readFile = NULL; ++ ++ writeFileName = new cFileName64(FileName, true); ++ writeFileName->SetNumber(FileNumber); ++ writeFile = writeFileName->Open(); ++ ++ liveBuffer = LiveBuffer; ++ startFrame = StartFrame; ++ endFrame = EndFrame; ++ Start(); ++} ++ ++cLiveCutterThread::~cLiveCutterThread() ++{ ++ Cancel(3); ++ if (readFile) ++ readFileName->Close(); ++ writeFileName->Close(); ++} ++ ++void cLiveCutterThread::Action(void) ++{ ++ int Frame = startFrame; ++ int readPos = 0; ++ int writePos = 0; ++ while (Running() && Frame < endFrame) { ++ uchar pt; ++ liveBuffer->index->RwLock->Lock(false); ++ int size = liveBuffer->index->Size(Frame, &pt); ++ if (pt == I_FRAME && writePos > MEGABYTE(Setup.MaxVideoFileSize)) { ++ int Number = writeFileName->Number(); ++ writeFileName->Close(); ++ writeFileName->SetNumber(Number+1); ++ writeFile = writeFileName->Open(); ++ writePos = 0; ++ } ++ if (liveBuffer->index->IsWritten(Frame)) { ++ if (!readFile) { ++ readFileName = new cFileName64(liveBuffer->filestring, false); ++ readFileName->SetNumber(liveBuffer->fileWriter->FileNumber()); ++ readFile = readFileName->Open(); ++ } ++ uchar b[MAXFRAMESIZE]; ++ if (liveBuffer->index->GetOffset(Frame) != readPos) { ++ readPos = liveBuffer->index->GetOffset(Frame); ++ readFile->Seek(readPos,0); ++ } ++ int c = readFile->Read(b, size); ++ readPos += c; ++ writeFile->Write(b,c); ++ writePos+=size; ++ if (c != size) ++ writeFile->Seek(writePos,0); ++ } ++ else { ++ writeFile->Write(&liveBuffer->buffer[liveBuffer->index->GetOffset(Frame)], size); ++ writePos+=size; ++ } ++ liveBuffer->index->RwLock->Unlock(); ++ Frame++; ++ cCondWait::SleepMs(5); ++ } ++ if (readFile) ++ readFileName->Close(); ++ writeFileName->Close(); ++} ++ ++// --- cLiveBuffer ----------------------------------------------------------- ++ ++cLiveBuffer::cLiveBuffer(const char *FileName, cRemux *Remux, const cChannel *Channel, int Number) ++:cThread("livebuffer") ++{ ++ number = Number; ++ bufSize = (Setup.InRAM && Number == 0) ? MEGABYTE(Setup.MemBufSize) : LIVEBUFSIZE; ++ buffer = MALLOC(uchar, bufSize); ++ writeHD = !(Setup.InRAM && Number == 0); ++ lastRead = 0; ++ if (!buffer) { ++ dsyslog("Couldn't reserve memory for livebuffer\n"); ++ bufSize = LIVEBUFSIZE; ++ buffer = MALLOC(uchar, bufSize); ++ } ++ channel = Channel; ++ index = new cLiveIndex(bufSize); ++ remux = Remux; ++ filestring = strdup(FileName); ++ head = tail = blank = 0; ++ startFrame = -1; ++ liveCutter = NULL; ++ fileWriter = NULL; ++ fileReader = NULL; ++ if (writeHD) { ++ fileWriter = new cLiveFileWriter(FileName); ++ fileReader = new cLiveFileReader(FileName, fileWriter->FileNumber()); ++ } ++ status = 0; ++ Start(); ++} ++ ++cLiveBuffer::~cLiveBuffer() ++{ ++ Cancel(3); ++ delete liveCutter; ++ delete fileReader; ++ delete index; ++ delete fileWriter; ++ free(filestring); ++ free(buffer); ++} ++ ++void cLiveBuffer::SetStatus(int s) ++{ ++ if (s == -1 || status != 2 && s == 0) ++ status = 0; ++ if (status == 0 && s == 1) ++ status = 1; ++ if (s == 2) ++ status = 2; ++ if (s == -2 && status == 0) ++ status = -1; ++} ++ ++void cLiveBuffer::Write(bool Wait) ++{ ++ int wcount = index->NextWrite(); ++ off64_t pos=fileWriter->Write(&buffer[tail], wcount, Wait); ++ if (pos>=0) { ++ index->WrittenTo(pos-wcount, wcount); ++ tail += wcount; ++ if (tail + MAXFRAMESIZE > bufSize) { ++ tail = 0; ++ blank = 0; ++ index->SetBlank(blank); ++ } ++ if (fileWriter->Full()) ++ index->Delete(pos); ++ } ++} ++ ++void cLiveBuffer::Store(uchar *Data, int Count) ++{ ++ ++ if (pictureType != NO_PICTURE) { ++ if (head + MAXFRAMESIZE > bufSize) { ++ blank = bufSize - head; ++ head = 0; ++ index->SetBlank(blank); ++ } ++ index->Add(pictureType,head); ++ } ++ else ++ index->AddData(head); ++ memcpy(&buffer[head], Data, Count); ++ head += Count; ++ ++ int free = head >= tail ? max(tail,bufSize-head) : tail - head; ++ ++ while (free < MAXFRAMESIZE) { ++ if (writeHD) ++ Write(true); ++ else { ++ tail = index->DelFirst(); ++ if (tail == 0) { ++ blank = 0; ++ index->SetBlank(blank); ++ } ++ if (Setup.ExtendBuffer && lastRead < index->delCount+25 && status >= 0) { ++ writeHD = true; ++ fileWriter = new cLiveFileWriter(filestring); ++ fileReader = new cLiveFileReader(filestring, fileWriter->FileNumber()); ++ } ++ } ++ free = head >= tail ? max(tail,bufSize-head) : tail - head; ++ } ++} ++ ++void cLiveBuffer::Action(void) ++{ ++ while (Running()) { ++ int Count; ++ Lock(); ++ uchar *p = remux->Get(Count, &pictureType); ++ if (p) { ++ Store(p,Count); ++ remux->Del(Count); ++ } ++ Unlock(); ++ if (writeHD) { ++ int free = head >= tail ? max(tail,bufSize-head) : tail - head; ++ if (free < 2*MAXFRAMESIZE) ++ Write(false); ++ } ++ } ++ ++} ++ ++void cLiveBuffer::SetNewRemux(cRemux *Remux, const cChannel *Channel) ++{ ++ if (Channel != channel) { ++ index->Switched(); ++ } ++ channel = Channel; ++ if (!Remux) { ++ Cancel(3); ++ return; ++ } ++ if (fileReader) fileReader->Clear(); ++ if (!Running() && Remux) { ++ remux = Remux; ++ Start(); ++ } ++ else { ++ Cancel(-1); ++ Lock(); ++ if (writeHD && Setup.InRAM && number == 0 && !status) { ++ index->Clear(); ++ delete fileReader; fileReader = NULL; ++ delete fileWriter; fileWriter = NULL; ++ writeHD = false; ++ } ++ remux = Remux; ++ Unlock(); ++ Start(); ++ } ++} ++ ++int cLiveBuffer::GetFrame(uchar **Buffer, int Number, int Off) ++{ ++ if (!Buffer) { ++ if (fileReader) fileReader->Clear(); ++ return -1; ++ } ++ if (Number < FirstIndex()) ++ return -2; ++ if (!index->HasFrame(Number) && (Off < 0 || !index->HasFrame(Number-1))) ++ return -1; ++ lastRead = Number; ++ if (!index->IsWritten(Number)) { ++ index->RwLock->Lock(false); ++ int size=index->Size(Number); ++ int off = index->GetOffset(Number); ++ if (off >= 0) { ++ if (Off>=0) { ++ size -= Off; ++ off += Off; ++ } ++ if (size > 0) { ++ uchar *b = MALLOC(uchar, size); ++ *Buffer = b; ++ memcpy(b,&buffer[off],size); ++ } ++ if (!index->HasFrame(Number)) ++ size = -size; ++ } ++ else ++ size = -1; ++ index->RwLock->Unlock(); ++ return size; ++ } ++ else ++ return fileReader->Read(Buffer,index->GetOffset(Number),index->Size(Number)); ++ return -1; ++} ++ ++void cLiveBuffer::CreateIndexFile(const char *FileName, int64_t PTS, int EndFrame) ++{ ++ if (liveCutter) { ++ if (liveCutter->Active()) { ++ startFrame = -1; ++ return; ++ } ++ else { ++ delete liveCutter; ++ liveCutter = NULL; ++ } ++ } ++ if (startFrame < 0) ++ return; ++ cIndexFile *indexFile = new cIndexFile(FileName, true); ++ if (!indexFile) ++ return; ++ int endFrame = EndFrame ? EndFrame : index->FindIFrame(PTS, buffer); ++ int timeout = 0; ++ while (endFrame < 0 && timeout < 50) { ++ cCondWait::SleepMs(100); ++ endFrame = index->FindIFrame(PTS, buffer); ++ timeout++; ++ } ++ ++ char *data="LiveBuffer"; ++ cFileName fileName(FileName, true); ++ cUnbufferedFile *file = fileName.Open(); ++ file->Write(data,10); ++ int Number = fileName.Number(); ++ int FileOffset=0; ++ for (int Frame = startFrame; Frame < endFrame; Frame++) { ++ uchar pt; ++ int size = index->Size(Frame, &pt); ++ if (pt == I_FRAME && FileOffset > MEGABYTE(Setup.MaxVideoFileSize)) { ++ file = fileName.NextFile(); ++ file->Write(data,10); ++ FileOffset=0; ++ } ++ indexFile->Write(pt,fileName.Number(),FileOffset); ++ FileOffset+=size; ++ } ++ liveCutter = new cLiveCutterThread(FileName,Number,this,startFrame,endFrame); ++ startFrame = -1; ++ delete indexFile; ++} ++ ++// --- cLiveReceiver --------------------------------------------------------- ++ ++cLiveReceiver::cLiveReceiver(const cChannel *Channel) ++:cReceiver(Channel->GetChannelID(), -1, Channel->Vpid(), Channel->Apids(), Setup.UseDolbyDigital ? Channel->Dpids() : NULL, Channel->Spids()) ++{ ++ channel = Channel; ++ vpid = Channel->Vpid(); ++ for (int i = 0; i < MAXAPIDS; i++) ++ apids[i]=Channel->Apid(i); ++ for (int i = 0; i < MAXDPIDS; i++) ++ dpids[i]= Setup.UseDolbyDigital ? Channel->Dpid(i) : 0; ++ for (int i = 0; i < MAXSPIDS; i++) ++ spids[i]=Channel->Spid(i); ++ ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); ++ ringBuffer->SetTimeouts(0, 20); ++ remux = new cRemux(Channel->Vpid(), Channel->Apids(), Setup.UseDolbyDigital ? Channel->Dpids() : NULL, Channel->Spids()); ++ remux->SetTimeouts(0, 50); ++ attached = false; ++} ++ ++cLiveReceiver::~cLiveReceiver() ++{ ++ Detach(); ++ Cancel(3); ++ delete remux; ++ delete ringBuffer; ++} ++ ++void cLiveReceiver::Activate(bool On) ++{ ++ if (On) { ++ Start(); ++ attached = true; ++ } ++ else { ++ Cancel(-1); ++ attached = false; ++ } ++} ++ ++void cLiveReceiver::Receive(uchar *Data, int Length) ++{ ++ int p = ringBuffer->Put(Data, Length); ++ if (p != Length && Running()) ++ ringBuffer->ReportOverflow(Length - p); ++} ++ ++void cLiveReceiver::Action(void) ++{ ++ while (Running()) { ++ int r; ++ uchar *b = ringBuffer->Get(r); ++ if (b) { ++ int Count = remux->Put(b, r); ++ if (Count) ++ ringBuffer->Del(Count); ++ else ++ cCondWait::SleepMs(20); ++ } ++ } ++} ++ ++bool cLiveReceiver::IsReceiving(const cChannel *Channel) ++{ ++ if (vpid != Channel->Vpid()) ++ return false; ++ for (int i = 0; i < MAXAPIDS; i++) ++ if (apids[i] != Channel->Apid(i)) ++ return false; ++ for (int i = 0; i < MAXDPIDS && Setup.UseDolbyDigital; i++) ++ if (dpids[i] != Channel->Dpid(i)) ++ return false; ++ for (int i = 0; i < MAXSPIDS; i++) ++ if (spids[i] != Channel->Spid(i)) ++ return false; ++ ++ return true; ++} ++ ++// --- cLiveBackTrace -------------------------------------------------------- ++ ++#define AVG_FRAME_SIZE 15000 ++#define DVB_BUF_SIZE (256 * 1024) ++#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) ++ ++class cLiveBackTrace { ++private: ++ int index[BACKTRACE_ENTRIES]; ++ int length[BACKTRACE_ENTRIES]; ++ int pos, num; ++public: ++ cLiveBackTrace(void); ++ void Clear(void); ++ void Add(int Index, int Length); ++ int Get(bool Forward); ++ }; ++ ++cLiveBackTrace::cLiveBackTrace(void) ++{ ++ Clear(); ++} ++ ++void cLiveBackTrace::Clear(void) ++{ ++ pos = num = 0; ++} ++ ++void cLiveBackTrace::Add(int Index, int Length) ++{ ++ index[pos] = Index; ++ length[pos] = Length; ++ if (++pos >= BACKTRACE_ENTRIES) ++ pos = 0; ++ if (num < BACKTRACE_ENTRIES) ++ num++; ++} ++ ++int cLiveBackTrace::Get(bool Forward) ++{ ++ int p = pos; ++ int n = num; ++ int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); ++ int i = -1; ++ ++ while (n && l > 0) { ++ if (--p < 0) ++ p = BACKTRACE_ENTRIES - 1; ++ i = index[p] - 1; ++ l -= length[p]; ++ n--; ++ } ++ return i; ++} ++ ++// --- cLivePlayer ----------------------------------------------------------- ++ ++#define PLAYERBUFSIZE MEGABYTE(1) ++ ++#define MAX_VIDEO_SLOWMOTION 63 ++#define NORMAL_SPEED 4 ++#define MAX_SPEEDS 3 ++#define SPEED_MULT 12 ++int cLivePlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; ++ ++cLivePlayer::cLivePlayer(cLiveBuffer *LiveBuffer) ++:cThread("liveplayer") ++{ ++ liveBuffer = LiveBuffer; ++ ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE); ++ readIndex = writeIndex = -1; ++ readFrame = playFrame = NULL; ++ firstPacket = true; ++ playMode = pmPlay; ++ playDir = pdForward; ++ trickSpeed = NORMAL_SPEED; ++ Off = 0; ++ backTrace = new cLiveBackTrace; ++ liveBuffer->SetStatus(0); ++} ++ ++cLivePlayer::~cLivePlayer() ++{ ++ liveBuffer->SetStatus(-2); ++ Detach(); ++ Cancel(3); ++ liveBuffer->GetFrame(NULL,0); ++ delete readFrame; ++ delete backTrace; ++ delete ringBuffer; ++} ++ ++void cLivePlayer::TrickSpeed(int Increment) ++{ ++ int nts = trickSpeed + Increment; ++ if (Speeds[nts] == 1) { ++ trickSpeed = nts; ++ if (playMode == pmFast) ++ Play(); ++ else ++ Pause(); ++ } ++ else if (Speeds[nts]) { ++ trickSpeed = nts; ++ int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT; ++ int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult; ++ if (sp > MAX_VIDEO_SLOWMOTION) ++ sp = MAX_VIDEO_SLOWMOTION; ++ DeviceTrickSpeed(sp); ++ } ++} ++ ++void cLivePlayer::Empty(void) ++{ ++ LOCK_THREAD; ++ liveBuffer->GetFrame(NULL,0); ++ if ((readIndex = backTrace->Get(playDir == pdForward)) < 0) ++ readIndex = writeIndex; ++ delete readFrame; ++ readFrame = NULL; ++ playFrame = NULL; ++ ringBuffer->Clear(); ++ DeviceClear(); ++ backTrace->Clear(); ++ firstPacket = true; ++ Off = 0; ++} ++ ++void cLivePlayer::Activate(bool On) ++{ ++ if (On) ++ Start(); ++ else ++ Cancel(-1); ++} ++ ++void cLivePlayer::Action(void) ++{ ++ int PollTimeouts = 0; ++ uchar *b = NULL; ++ uchar **pb = &b; ++ uchar *p = NULL; ++ int pc = 0; ++ ++ if (liveBuffer->Stay()) ++ readIndex = liveBuffer->LastRead(); ++ else ++ readIndex = liveBuffer->LastIndex(); ++ ++ bool Sleep = false; ++ bool WaitingForData = false; ++ ++ while (Running()) { ++ if (Sleep) { ++ if (WaitingForData) ++ cCondWait::SleepMs(3); ++ else ++ cCondWait::SleepMs(3); ++ Sleep = false; ++ } ++ ++ cPoller Poller; ++ if (!DevicePoll(Poller, 100)) { ++ PollTimeouts++; ++ continue; ++ } ++ else ++ PollTimeouts = 0; ++ ++ if (PollTimeouts >= 6) { ++ DeviceClear(); ++ PlayPes(NULL, 0); ++ } ++ ++ LOCK_THREAD; ++ ++ if (playMode != pmStill && playMode != pmPause) { ++ if (!readFrame) { ++ if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { ++ int Index = liveBuffer->GetNextIFrame(readIndex, playDir == pdForward); ++ if (Index < 0) { ++ if (!DeviceFlush(100)) ++ continue; ++ DevicePlay(); ++ playMode = pmPlay; ++ playDir = pdForward; ++ continue; ++ } ++ int r = liveBuffer->GetFrame(pb, Index); ++ if (r>0) { ++ readIndex = Index; ++ WaitingForData = false; ++ readFrame = new cFrame(b, -r, ftUnknown, readIndex); ++ b = NULL; ++ } ++ else ++ WaitingForData = true; ++ } ++ else { ++ int r=liveBuffer->GetFrame(pb, readIndex+1, Off); ++ if (r>0) ++ readIndex++; ++ if (r > 0 || r < -10) { ++ WaitingForData = false; ++ readFrame = new cFrame(b, -abs(r), ftUnknown, readIndex); ++ b = NULL; ++ if (r<0) ++ Off += -r; ++ else ++ Off = 0; ++ } ++ else if (r==-2) ++ readIndex = liveBuffer->GetNextIFrame(liveBuffer->FirstIndex(), true)-1; ++ else ++ WaitingForData = true; ++ } ++ } ++ if (readFrame) { ++ if (ringBuffer->Put(readFrame)) ++ readFrame = NULL; ++ } ++ } ++ else ++ Sleep = true; ++ if (!playFrame) { ++ playFrame = ringBuffer->Get(); ++ p = NULL; ++ pc = 0; ++ } ++ if (playFrame) { ++ if (!p) { ++ p = playFrame->Data(); ++ pc = playFrame->Count(); ++ if (p) { ++ if (firstPacket) { ++ PlayPes(NULL, 0); ++ cRemux::SetBrokenLink(p, pc); ++ firstPacket = false; ++ } ++ } ++ } ++ if (p) { ++ int w = PlayPes(p, pc, playMode != pmPlay); ++ if (w > 0) { ++ p += w; ++ pc -= w; ++ } ++ else { ++ if (w < 0 && FATALERRNO) { ++ LOG_ERROR; ++ break; ++ } ++ } ++ } ++ if (pc == 0) { ++ writeIndex = playFrame->Index(); ++ backTrace->Add(playFrame->Index(), playFrame->Count()); ++ ringBuffer->Drop(playFrame); ++ playFrame = NULL; ++ p = NULL; ++ } ++ } ++ else ++ Sleep = true; ++ } ++} ++ ++void cLivePlayer::Pause(void) ++{ ++ if (playMode == pmPause || playMode == pmStill) ++ Play(); ++ else { ++ liveBuffer->SetStatus(1); ++ LOCK_THREAD; ++ if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) ++ Empty(); ++ DeviceFreeze(); ++ playMode = pmPause; ++ } ++} ++ ++void cLivePlayer::Play(void) ++{ ++ if (playMode != pmPlay) { ++ liveBuffer->SetStatus(0); ++ LOCK_THREAD; ++ if (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) ++ Empty(); ++ DevicePlay(); ++ playMode = pmPlay; ++ playDir = pdForward; ++ } ++} ++ ++void cLivePlayer::Forward(void) ++{ ++ switch (playMode) { ++ case pmFast: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdForward ? 1 : -1); ++ break; ++ } ++ else if (playDir == pdForward) { ++ Play(); ++ break; ++ } ++ case pmPlay: { ++ LOCK_THREAD; ++ Empty(); ++ DeviceMute(); ++ playMode = pmFast; ++ playDir = pdForward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); ++ } ++ break; ++ case pmSlow: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdForward ? -1 : 1); ++ break; ++ } ++ else if (playDir == pdForward) { ++ Pause(); ++ break; ++ } ++ case pmStill: ++ case pmPause: ++ DeviceMute(); ++ playMode = pmSlow; ++ playDir = pdForward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); ++ break; ++ } ++} ++ ++void cLivePlayer::Backward(void) ++{ ++ switch (playMode) { ++ case pmFast: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdBackward ? 1 : -1); ++ break; ++ } ++ else if (playDir == pdBackward) { ++ Play(); ++ break; ++ } ++ case pmPlay: { ++ LOCK_THREAD; ++ Empty(); ++ DeviceMute(); ++ playMode = pmFast; ++ playDir = pdBackward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); ++ } ++ break; ++ case pmSlow: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdBackward ? -1 : 1); ++ break; ++ } ++ else if (playDir == pdBackward) { ++ Pause(); ++ break; ++ } ++ case pmStill: ++ case pmPause: { ++ LOCK_THREAD; ++ Empty(); ++ DeviceMute(); ++ playMode = pmSlow; ++ playDir = pdBackward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); ++ } ++ break; ++ } ++} ++ ++bool cLivePlayer::Stop(void) ++{ ++ liveBuffer->SetStatus(-1); ++ if (readIndex >= liveBuffer->LastIndex() - 25) ++ return false; ++ LOCK_THREAD; ++ Empty(); ++ readIndex = writeIndex = liveBuffer->GetNextIFrame(liveBuffer->LastIndex()-1, false)-1; ++ Play(); ++ return true; ++} ++ ++void cLivePlayer::SkipSeconds(int Seconds) ++{ ++ if (Seconds) { ++ LOCK_THREAD; ++ Empty(); ++ int Index = writeIndex; ++ if (Index >= 0) { ++ Index = max(Index + Seconds * FRAMESPERSEC, liveBuffer->FirstIndex()); ++ if (Index > liveBuffer->FirstIndex()) ++ Index = liveBuffer->GetNextIFrame(Index, false); ++ if (Index >= 0) ++ readIndex = writeIndex = Index - 1; ++ } ++ Play(); ++ } ++} ++ ++bool cLivePlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame) ++{ ++ if (liveBuffer) { ++ if (playMode == pmStill) ++ Current = max(readIndex, 0); ++ else { ++ Current = max(writeIndex, 0); ++ // TODO SnapToIFrame ++ } ++ Total = liveBuffer->LastIndex() - liveBuffer->FirstIndex(); ++ Current -= liveBuffer->FirstIndex(); ++ return true; ++ } ++ Current = Total = -1; ++ return false; ++} ++ ++bool cLivePlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) ++{ ++ Play = (playMode == pmPlay || playMode == pmFast); ++ Forward = (playDir == pdForward); ++ if (playMode == pmFast || playMode == pmSlow) ++ Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0 ; ++ else ++ Speed = -1; ++ return true; ++} ++ ++// --- cLiveBufferControl ---------------------------------------------------- ++ ++cLiveBufferControl::cLiveBufferControl(cLivePlayer *Player) ++:cControl(Player, true) ++{ ++ player = Player; ++ displayReplay = NULL; ++ visible = modeOnly = shown = false; ++ lastCurrent = lastTotal = -1; ++ lastPlay = lastForward = false; ++ lastSpeed = -2; ++ timeoutShow = 0; ++} ++ ++cLiveBufferControl::~cLiveBufferControl() ++{ ++ Hide(); ++ cTransferControl::receiverDevice = NULL; ++ cLiveBufferManager::livePlayer = NULL; ++ delete player; ++ cLiveBufferManager::liveControl = NULL; ++ if (!Setup.LiveBuffer) ++ cLiveBufferManager::Shutdown(); ++} ++ ++bool cLiveBufferControl::GetIndex(int &Current, int &Total, bool SnapToIFrame) ++{ ++ if (player) { ++ player->GetIndex(Current, Total, SnapToIFrame); ++ return true; ++ } ++ return false; ++ ++} ++ ++bool cLiveBufferControl::GetReplayMode(bool &Play, bool &Forward, int &Speed) ++{ ++ return player && player->GetReplayMode(Play, Forward, Speed); ++} ++ ++void cLiveBufferControl::ShowTimed(int Seconds) ++{ ++ if (modeOnly) ++ Hide(); ++ if (!visible) { ++ shown = ShowProgress(true); ++ timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; ++ } ++} ++ ++void cLiveBufferControl::Show(void) ++{ ++ ShowTimed(); ++} ++ ++void cLiveBufferControl::Hide(void) ++{ ++ if (visible) { ++ delete displayReplay; ++ displayReplay = NULL; ++ SetNeedsFastResponse(false); ++ visible = false; ++ modeOnly = false; ++ lastPlay = lastForward = false; ++ lastSpeed = -2; // an invalid value ++// timeSearchActive = false; ++ } ++} ++ ++void cLiveBufferControl::ShowMode(void) ++{ ++ if (visible || Setup.ShowReplayMode && !cOsd::IsOpen()) { ++ bool Play, Forward; ++ int Speed; ++ if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) { ++ bool NormalPlay = (Play && Speed == -1); ++ ++ if (!visible) { ++ if (NormalPlay) ++ return; ++ visible = modeOnly = true; ++ displayReplay = Skins.Current()->DisplayReplay(modeOnly); ++ } ++ ++ if (modeOnly && !timeoutShow && NormalPlay) ++ timeoutShow = time(NULL) + 3; ++ displayReplay->SetMode(Play, Forward, Speed); ++ lastPlay = Play; ++ lastForward = Forward; ++ lastSpeed = Speed; ++ } ++ } ++} ++ ++bool cLiveBufferControl::ShowProgress(bool Initial) ++{ ++ int Current, Total; ++ ++ if (GetIndex(Current, Total) && Total > 0) { ++ if (!visible) { ++ displayReplay = Skins.Current()->DisplayReplay(modeOnly); ++ SetNeedsFastResponse(true); ++ visible = true; ++ } ++ if (Initial) { ++ lastCurrent = lastTotal = -1; ++ } ++ if (Total != lastTotal) { ++ displayReplay->SetTotal(IndexToHMSF(Total)); ++ if (!Initial) ++ displayReplay->Flush(); ++ } ++ if (Current != lastCurrent || Total != lastTotal) { ++ displayReplay->SetProgress(Current, Total); ++ if (!Initial) ++ displayReplay->Flush(); ++int displayFrames = false; ++ displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames)); ++ displayReplay->Flush(); ++ lastCurrent = Current; ++ } ++ lastTotal = Total; ++ ShowMode(); ++ return true; ++ } ++ return false; ++} ++ ++eOSState cLiveBufferControl::ProcessKey(eKeys Key) ++{ ++ if (visible) { ++ if (timeoutShow && time(NULL) > timeoutShow) { ++ Hide(); ++ ShowMode(); ++ timeoutShow = 0; ++ } ++ else if (modeOnly) ++ ShowMode(); ++ else ++ shown = ShowProgress(!shown) || shown; ++ } ++ bool DoShowMode = true; ++ switch (Key) { ++ case kDown: if (!visible || modeOnly) ++ return osUnknown; ++ case kPause: if (player) ++ player->Pause(); ++ break; ++ case kPlay: if (visible && !modeOnly) { ++ Hide(); ++ DoShowMode = true; ++ } ++ else ++ Show(); ++ case kUp: if (Key == kUp && (!visible || modeOnly)) ++ return osUnknown; ++ if (player) ++ player->Play(); ++ break; ++ case kLeft|k_Release: ++ if (!visible || modeOnly) ++ return osUnknown; ++ case kFastRew|k_Release: ++ if (Setup.MultiSpeedMode) break; ++ case kLeft: if (Key == kLeft && (!visible || modeOnly)) ++ return osUnknown; ++ case kFastRew: if (player) ++ player->Backward(); ++ break; ++ case kRight|k_Release: ++ if (!visible || modeOnly) ++ return osUnknown; ++ case kFastFwd|k_Release: ++ if (Setup.MultiSpeedMode) break; ++ case kRight: if (Key == kRight && (!visible || modeOnly)) ++ return osUnknown; ++ case kFastFwd: if (player) ++ player->Forward(); ++ break; ++ case kGreen|k_Repeat: ++ case kGreen: if (visible && !modeOnly && player) ++ player->SkipSeconds(-60); ++ else ++ return osUnknown; ++ break; ++ case kYellow|k_Repeat: ++ case kYellow: if (visible && !modeOnly && player) ++ player->SkipSeconds(60); ++ else ++ return osUnknown; ++ break; ++ default: { ++ DoShowMode = false; ++ switch (Key) { ++ case kStop: if (player) ++ if (player->Stop()) ++ break; ++ return osUnknown; ++ case kBack: if (visible && !modeOnly && player) ++ Hide(); ++ else ++ return osUnknown; ++ break; ++ case kRecord: { ++ cTimer *timer = new cTimer(true); ++ int Current, Total; ++ GetIndex(Current,Total); ++ time_t start = time(NULL) - (Total - Current) / FRAMESPERSEC; ++ time_t t = start; ++ struct tm tm_r; ++ struct tm *now = localtime_r(&t, &tm_r); ++ timer->start = now->tm_hour * 100 + now->tm_min; ++ timer->stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime; ++ timer->stop = (timer->stop / 60) * 100 + (timer->stop % 60); ++ if (timer->stop >= 2400) ++ timer->stop -= 2400; ++ timer->day = cTimer::SetTime(start, 0); ++ timer->channel = Channels.GetByNumber(cDevice::CurrentChannel()); ++ Timers.Add(timer); ++ Timers.SetModified(); ++ if (cRecordControls::Start(timer)) ++ Skins.Message(mtInfo, tr("Recording started")); ++ break; ++ } ++ default: return osUnknown; ++ } ++ } ++ } ++ if (DoShowMode) ++ ShowMode(); ++ return osContinue; ++} ++ ++// --- cLiveBufferManager ---------------------------------------------------- ++ ++cLiveReceiver *cLiveBufferManager::liveReceiver[MAXLIVEBUFFERS] = { NULL }; ++cLiveBuffer *cLiveBufferManager::liveBuffer[MAXLIVEBUFFERS] = { NULL }; ++cDevice *cLiveBufferManager::receiverDevice[MAXLIVEBUFFERS] = { NULL }; ++cLivePlayer *cLiveBufferManager::livePlayer = NULL; ++cLiveBufferControl *cLiveBufferManager::liveControl = NULL; ++ ++void cLiveBufferManager::ChannelSwitch(cDevice *ReceiverDevice, const cChannel *Channel) ++{ ++ int i; ++ for (i=0; i<MAXLIVEBUFFERS; i++) ++ if (liveBuffer[i] && liveBuffer[i]->Channel() == Channel) ++ break; ++ if (i == MAXLIVEBUFFERS) { ++ if (Setup.InRAM && !liveBuffer[0]) ++ i = 0; ++ else ++ for (i=0; i<MAXLIVEBUFFERS; i++) ++ if (liveBuffer[i] && (!liveBuffer[i]->Stay() || !liveReceiver[i]->IsAttached())) ++ break; ++ if (i == MAXLIVEBUFFERS) { ++ for (i = 0; i<MAXLIVEBUFFERS; i++) ++ if (!liveBuffer[i]) ++ break; ++ } ++ } ++ if (liveBuffer[i]) { ++ if (!(liveReceiver[i]->IsReceiving(Channel) && liveReceiver[i]->IsAttached())) { ++ cLiveReceiver *oldReceiver = liveReceiver[i]; ++ liveReceiver[i] = new cLiveReceiver(Channel); ++ ReceiverDevice->AttachReceiver(liveReceiver[i]); ++ liveBuffer[i]->SetNewRemux(liveReceiver[i]->remux, Channel); ++ delete oldReceiver; ++ receiverDevice[i] = ReceiverDevice; ++ } ++ else if (liveBuffer[i]->Stay()) ++ liveBuffer[i]->SetStatus(2); ++ } ++ else { ++ liveReceiver[i] = new cLiveReceiver(Channel); ++ ReceiverDevice->AttachReceiver(liveReceiver[i]); ++ receiverDevice[i] = ReceiverDevice; ++ char FileName[256]; ++ sprintf(FileName,"%s/LiveBuffer",BufferDirectory); ++ liveBuffer[i] = new cLiveBuffer(FileName,liveReceiver[i]->remux, Channel, i); ++ } ++ delete liveControl; ++ ++ cTransferControl::receiverDevice = receiverDevice[i]; ++ ++ livePlayer = new cLivePlayer(liveBuffer[i]); ++ cControl::Launch(liveControl = new cLiveBufferControl(livePlayer)); ++ ++ for (int j = 0; j < MAXLIVEBUFFERS; j++) ++ if (i!=j && liveBuffer[j] && !liveBuffer[j]->LiveCutterActive() && (!liveBuffer[j]->Stay() || !liveReceiver[j]->IsAttached())) { ++ delete liveBuffer[j]; ++ liveBuffer[j] = NULL; ++ delete liveReceiver[j]; ++ liveReceiver[j] = NULL; ++ } ++} ++ ++void cLiveBufferManager::Shutdown(void) ++{ ++ delete liveControl; ++ for (int i = 0; i < MAXLIVEBUFFERS; i++) { ++ delete liveBuffer[i]; ++ liveBuffer[i] = NULL; ++ delete liveReceiver[i]; ++ liveReceiver[i] = NULL; ++ } ++ char FileName[256]; ++ sprintf(FileName,"%s/LiveBuffer",BufferDirectory); ++ RemoveFileOrDir(FileName, true); ++} ++ ++cLiveBuffer *cLiveBufferManager::InLiveBuffer(cTimer *timer, int *StartFrame, int *EndFrame) ++{ ++ bool recstart = false; ++ if (timer && timer->HasFlags(tfRecording)) { ++ timer->SetFlags(tfhasLiveBuf); ++ recstart = true; ++ } ++ for (int i = 0; i < MAXLIVEBUFFERS; i++) ++ if (timer && timer->HasFlags(tfActive) && !timer->HasFlags(tfVps) && (!timer->HasFlags(tfhasLiveBuf) || recstart) && liveBuffer[i] && liveReceiver[i]->GetChannel() == timer->Channel()) { ++ int now = liveBuffer[i]->LastIndex(); ++ int first = liveBuffer[i]->FirstIndex() + 50; ++ if (now-first < 250) // Erst wenn LiveBuffer größer 10s ++ return NULL; ++ if (timer->StartTime() < time(NULL) && now-first > (time(NULL)-timer->StopTime())*FRAMESPERSEC) { ++ if (StartFrame) { ++ if ((time(NULL)-timer->StartTime())*FRAMESPERSEC < now - first) ++ *StartFrame = now - (time(NULL) - timer->StartTime())*FRAMESPERSEC; ++ else ++ *StartFrame = first; ++ } ++ if (EndFrame) { ++ if (time(NULL) > timer->StopTime()) ++ *EndFrame = now - (time(NULL) - timer->StopTime()) * FRAMESPERSEC; ++ else ++ *EndFrame = 0; ++ } ++ return liveBuffer[i]; ++ } ++ } ++ return NULL; ++} ++ ++int cLiveBufferManager::Impact(cDevice *device, const cChannel *Channel, bool LiveView) ++{ ++ if (!Setup.LiveBuffer) ++ return 0; ++ int r = 1; ++ for (int i=0; i < MAXLIVEBUFFERS; i++) ++ if (liveBuffer[i] && receiverDevice[i] == device) { ++ if (liveBuffer[i]->Stay() && liveReceiver[i]->IsAttached()) ++ if (liveBuffer[i]->Channel()->Transponder() != Channel->Transponder() || ++ liveBuffer[i]->Channel()->Source() != Channel->Source()) ++ r = 2; ++ } ++ return r; ++} ++ ++bool cLiveBufferManager::AllowsChannelSwitch(void) ++{ ++ return true; // return !liveBuffer || !liveBuffer->LiveCutterActive(); ++} ++#endif /* LIVEBUFFER */ +diff -ruNp vdr-1.6.0-2/livebuffer.h vdr-1.6.0-2-extensions/livebuffer.h +--- vdr-1.6.0-2/livebuffer.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/livebuffer.h 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,301 @@ ++#ifndef __LIVEBUFFER_H ++#define __LIVEBUFFER_H ++ ++#include "player.h" ++#include "receiver.h" ++#include "remux.h" ++#include "ringbuffer.h" ++#include "thread.h" ++ ++#define LIVEBUFSIZE MEGABYTE(5) ++ ++#define INDEXBLOCKSIZE 20000 ++ ++class cUnbufferedFile64 { ++private: ++ int fd; ++ off64_t curpos; ++ off64_t cachedstart; ++ off64_t cachedend; ++ off64_t begin; ++ off64_t lastpos; ++ off64_t ahead; ++ size_t readahead; ++ size_t written; ++ size_t totwritten; ++ int FadviseDrop(off64_t Offset, off64_t Len); ++public: ++ cUnbufferedFile64(void); ++ ~cUnbufferedFile64(); ++ int Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); ++ int Close(void); ++ off64_t Seek(off64_t Offset, int Whence); ++ ssize_t Read(void *Data, size_t Size); ++ ssize_t Write(const void *Data, size_t Size); ++ static cUnbufferedFile64 *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); ++ }; ++ ++class cFileName64 { ++private: ++ cUnbufferedFile64 *file; ++ int fileNumber; ++ char *fileName, *pFileNumber; ++ bool record; ++ bool blocking; ++public: ++ cFileName64(const char *FileName, bool Record, bool Blocking = false); ++ ~cFileName64(); ++ const char *Name(void) { return fileName; } ++ int Number(void) { return fileNumber; } ++ void SetNumber(int Number); ++ cUnbufferedFile64 *Open(void); ++ void Close(void); ++ void CloseAndRemove(void); ++ void Remove(void); ++ }; ++ ++class cLiveIndex { ++friend class cLiveCutterThread; ++friend class cLiveBuffer; ++private: ++ struct frame { ++ off64_t offset ; //:36; ++ bool written ; //:1 ; ++ uchar pt ; //:3 ; ++ }; ++ struct block { ++ frame Frame[INDEXBLOCKSIZE]; ++ block *previous, *next; ++ }; ++ block *headblock, *tailblock; ++ int blockCount; ++ int head, tail; ++ int blank; ++ int start; ++ int writtenCount, delCount; ++ int DPos, DCount; ++ int lastWrittenSize, lastCount; ++ off64_t fileSize; ++ int bufSize; ++ int lastFrame; ++ int GetFrame(block** Block, int Number); ++ cRwLock *RwLock; ++public: ++ cLiveIndex(int BufSize); ++ ~cLiveIndex(); ++ void Add(uchar pt, int pos); ++ void AddData(int pos); ++ void Delete(off64_t FilePos); ++ int DelFirst(void); ++ void Clear(void); ++ void SetBlank(int Blank) { RwLock->Lock(true); blank = Blank; RwLock->Unlock(); } ++ int NextWrite(); ++ void WrittenTo(off64_t FilePos, int Count); ++ bool HasFrame(int Number) { return lastFrame > Number && Number >=delCount; } ++ bool IsWritten(int Number) { return writtenCount > Number; } ++ off64_t GetOffset(int Number); ++ int Size(int Number, uchar *PictureType = NULL); ++ int GetNextIFrame(int Index, bool Forward); ++ int FindIFrame(int64_t PTS, uchar *Buffer); ++ void Switched(); ++ int Last(void) { return lastFrame+1; } ++ int First(void) { return start > delCount ? start : delCount; } ++}; ++ ++class cLiveFileReader : public cThread { ++private: ++ cFileName64 *fileName; ++ cUnbufferedFile64 *readFile; ++ cCondWait newSet; ++ off64_t filePos; ++ int hasData, length, wanted; ++ uchar *buffer; ++protected: ++ virtual void Action(void); ++public: ++ cLiveFileReader(const char *FileName, int Number); ++ ~cLiveFileReader(); ++ int Read(uchar **Buffer, off64_t FilePos, int Size); ++ void Clear(void); ++}; ++ ++class cLiveFileWriter : public cThread { ++private: ++ cFileName64 *fileName; ++ cUnbufferedFile64 *writeFile; ++ cCondWait newSet,written; ++ off64_t filePos,fileSize; ++ int hasWritten, length, wantWrite; ++ uchar *buffer; ++ time_t lastCheck; ++ bool full; ++ bool LowDiskSpace(void); ++protected: ++ virtual void Action(void); ++public: ++ cLiveFileWriter(const char *FileName); ++ ~cLiveFileWriter(); ++ off64_t Write(uchar *Buffer, int Size, bool Wait); ++ int FileNumber(void) { return fileName->Number(); } ++ void Clear(void); ++ bool Full(void) { return full; } ++}; ++ ++class cLiveBuffer; ++ ++class cLiveCutterThread : public cThread { ++private: ++ cFileName64 *readFileName, *writeFileName; ++ cUnbufferedFile64 *readFile, *writeFile; ++ cLiveBuffer *liveBuffer; ++ int startFrame, endFrame; ++protected: ++ virtual void Action(void); ++public: ++ cLiveCutterThread(const char *FileName, int FileNumber, cLiveBuffer *LiveBuffer, int StartFrame, int EndFrame); ++ ~cLiveCutterThread(); ++}; ++ ++class cLiveBuffer : public cThread { ++friend class cLiveCutterThread; ++private: ++ int number; ++ uchar *buffer; ++ int bufSize; ++ bool writeHD; ++ int lastRead; ++ int head, tail, blank; ++ cLiveIndex *index; ++ cRemux *remux; ++ cLiveFileWriter *fileWriter; ++ char *filestring; ++ uchar pictureType; ++ cLiveFileReader *fileReader; ++ int startFrame; ++ cLiveCutterThread *liveCutter; ++ const cChannel *channel; ++ int status; ++ void Write(bool Wait); ++ void Store(uchar *Data, int Count); ++protected: ++ virtual void Action(void); ++public: ++ cLiveBuffer(const char *FileName, cRemux *Remux, const cChannel *Channel, int Number); ++ virtual ~cLiveBuffer(); ++ void SetStatus(int s); ++ void SetNewRemux(cRemux *Remux, const cChannel *Channel); ++ int GetFrame(uchar **Buffer, int Number, int Off = -1); ++ int GetNextIFrame(int Index, bool Forward) { return index->GetNextIFrame(Index,Forward); } ++ int LastIndex(void) { return index->Last(); } ++ int FirstIndex(void) { return index->First(); } ++ int LastRead(void) { return lastRead; } ++ void CreateIndexFile(const char *FileName, int64_t PTS, int EndFrame = 0); ++ void SetStartFrame(int StartFrame) { startFrame = StartFrame; } ++ bool LiveCutterActive(void) { return liveCutter && liveCutter->Active(); } ++ const cChannel* Channel(void) { return channel; } ++ bool Stay(void) { return status>0 && Setup.KeepPaused; }; ++}; ++ ++class cLiveBackTrace; ++ ++class cLivePlayer : public cPlayer, public cThread { ++private: ++ enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill }; ++ enum ePlayDirs { pdForward, pdBackward }; ++ static int Speeds[]; ++ ePlayModes playMode; ++ ePlayDirs playDir; ++ int trickSpeed; ++ cLiveBuffer *liveBuffer; ++ cRingBufferFrame *ringBuffer; ++ cLiveBackTrace *backTrace; ++ int readIndex, writeIndex; ++ cFrame *readFrame; ++ cFrame *playFrame; ++ int Off; ++ bool firstPacket; ++ void TrickSpeed(int Increment); ++ void Empty(void); ++protected: ++ virtual void Activate(bool On); ++ virtual void Action(void); ++public: ++ cLivePlayer(cLiveBuffer *LiveBuffer); ++ virtual ~cLivePlayer(); ++ void Pause(void); ++ void Play(void); ++ void Forward(void); ++ void Backward(void); ++ bool Stop(void); ++ void SkipSeconds(int Seconds); ++ virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); ++ virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); ++}; ++ ++class cLiveReceiver : public cReceiver, cThread { ++friend class cLiveBufferManager; ++friend class cLiveBufferControl; ++private: ++ cRingBufferLinear *ringBuffer; ++ cRemux *remux; ++ const cChannel *channel; ++ bool attached; ++ int vpid; ++ int apids[MAXAPIDS]; ++ int dpids[MAXDPIDS]; ++ int spids[MAXSPIDS]; ++protected: ++ virtual void Activate(bool On); ++ virtual void Receive(uchar *Data, int Length); ++ virtual void Action(void); ++public: ++ cLiveReceiver(const cChannel *Channel); ++ virtual ~cLiveReceiver(); ++ const cChannel *GetChannel() { return channel; } ++ bool IsReceiving(const cChannel *Channel); ++ bool IsAttached() { return attached; } ++ }; ++ ++class cLiveBufferControl : public cControl { ++private: ++ cSkinDisplayReplay *displayReplay; ++ cLivePlayer *player; ++ bool visible, modeOnly, shown; ++ int lastCurrent, lastTotal; ++ bool lastPlay, lastForward; ++ int lastSpeed; ++ time_t timeoutShow; ++ void ShowTimed(int Seconds = 0); ++ void ShowMode(void); ++ bool ShowProgress(bool Initial); ++public: ++ cLiveBufferControl(cLivePlayer *Player); ++ ~cLiveBufferControl(); ++ bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); ++ bool GetReplayMode(bool &Play, bool &Forward, int &Speed); ++ virtual eOSState ProcessKey(eKeys Key); ++ virtual void Show(void); ++ virtual void Hide(void); ++ bool Visible(void) { return visible; } ++ }; ++ ++#define MAXLIVEBUFFERS 16 ++ ++class cLiveBufferManager { ++friend class cLiveBufferControl; ++private: ++ static cLiveReceiver* liveReceiver[MAXLIVEBUFFERS]; ++ static cLiveBuffer* liveBuffer[MAXLIVEBUFFERS]; ++ static cDevice* receiverDevice[MAXLIVEBUFFERS]; ++ static cLivePlayer* livePlayer; ++ static cLiveBufferControl* liveControl; ++public: ++ static void ChannelSwitch(cDevice *ReceiverDevice, const cChannel *Channel); ++ static void Shutdown(void); ++ static cLiveBufferControl *GetLiveBufferControl(void) { return liveControl; } ++ static cLiveBuffer *InLiveBuffer(cTimer *timer, int *StartFrame = NULL, int *EndFrame = NULL); ++ static int Impact(cDevice *device, const cChannel *Channel, bool LiveView); ++ static bool AllowsChannelSwitch(void); ++}; ++ ++#endif //__LIVEBUFFER_H +diff -ruNp vdr-1.6.0-2/mainmenuitemsprovider.h vdr-1.6.0-2-extensions/mainmenuitemsprovider.h +--- vdr-1.6.0-2/mainmenuitemsprovider.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/mainmenuitemsprovider.h 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,62 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MAINMENUITEMSPROVIDER_H ++#define __MAINMENUITEMSPROVIDER_H ++ ++#include <vector> ++ ++class cOsdItem; ++class cOsdMenu; ++ ++class IMenuItemDefinition ++{ ++ public: ++ virtual ~IMenuItemDefinition() {}; ++ virtual bool IsCustomOsdItem() = 0; ++ virtual bool IsPluginItem() = 0; ++ virtual bool IsSeparatorItem() = 0; ++ virtual cOsdItem* CustomOsdItem() = 0; ++ virtual const char* PluginMenuEntry() = 0; ++ virtual bool IsSelected() = 0; ++ virtual int PluginIndex() = 0; ++}; ++ ++typedef std::vector<IMenuItemDefinition*> MenuItemDefinitions; ++ ++#define MENU_ITEMS_PROVIDER_SERVICE_ID "MenuOrgPatch-v0.4.2::MainMenuItemsProvider" ++ ++class IMainMenuItemsProvider ++{ ++ public: ++ virtual ~IMainMenuItemsProvider() {}; ++ virtual bool IsCustomMenuAvailable() = 0; ++ virtual MenuItemDefinitions* MainMenuItems() = 0; ++ virtual void EnterRootMenu() = 0; ++ virtual void EnterSubMenu(cOsdItem* item) = 0; ++ virtual bool LeaveSubMenu() = 0; ++ virtual cOsdMenu* Execute(cOsdItem* item) = 0; ++}; ++ ++#endif //__MAINMENUITEMSPROVIDER_H ++#endif /* MENUORG */ +diff -ruNp vdr-1.6.0-2/Make.config.template vdr-1.6.0-2-extensions/Make.config.template +--- vdr-1.6.0-2/Make.config.template 2008-01-13 13:54:09.000000000 +0100 ++++ vdr-1.6.0-2-extensions/Make.config.template 2009-04-09 20:48:26.000000000 +0200 +@@ -41,8 +41,262 @@ RCU_DEVICE = /dev/ttyS1 + ## Define if you want vdr to not run as root + #VDR_USER = vdr + ++### VDR-Extensions: ++# Comment the patches you don't need ++# DVDCHAPJUMP needs DVDARCHIVE enabled ++# DVDARCHIVE needs LIEMIEXT enabled ++# SORTRECORDS needs LIEMIEXT enabled ++# you can only enable MENUORG or SETUP ++ ++#ANALOGTV = 1 ++#ATSC = 1 ++#CHANNELSCAN = 1 ++CMDRECCMDI18N = 1 ++CMDSUBMENU = 1 ++#CUTTERLIMIT = 1 ++#CUTTERQUEUE = 1 ++CUTTIME = 1 ++DDEPGENTRY = 1 ++#DELTIMESHIFTREC = 1 ++DOLBYINREC = 1 ++#DVBPLAYER = 1 ++#DVBSETUP = 1 ++#DVDARCHIVE = 1 ++#DVDCHAPJUMP = 1 ++#DVLFRIENDLYFNAMES = 1 ++#DVLRECSCRIPTADDON = 1 ++#DVLVIDPREFER = 1 ++#EM84XX = 1 ++#GRAPHTFT = 1 ++#HARDLINKCUTTER = 1 ++JUMPPLAY = 1 ++LIEMIEXT = 1 ++#LIRCSETTINGS = 1 ++#LIVEBUFFER = 1 ++#LNBSHARE = 1 ++#MAINMENUHOOKS = 1 ++#MENUORG = 1 ++#NOEPG = 1 ++#OSDMAXITEMS = 1 ++#PARENTALRATING = 1 ++#PINPLUGIN = 1 ++PLUGINAPI = 1 ++PLUGINMISSING = 1 ++#PLUGINPARAM = 1 ++#ROTOR = 1 ++SETTIME = 1 ++#SETUP = 1 ++#SOFTOSD = 1 ++#SOURCECAPS = 1 ++#SORTRECORDS = 1 ++#STREAMDEVEXT = 1 ++#SYNCEARLY = 1 ++#TIMERCMD = 1 ++#TIMERINFO = 1 ++#TTXTSUBS = 1 ++#VALIDINPUT = 1 ++#VOLCTRL = 1 ++#WAREAGLEICON = 1 ++#YAEPG = 1 ++ + ### You don't need to touch the following: + + ifdef DVBDIR + INCLUDES += -I$(DVBDIR)/include + endif ++ ++ifdef ANALOGTV ++DEFINES += -DUSE_ANALOGTV ++endif ++ ++ifdef ATSC ++DEFINES += -DUSE_ATSC ++endif ++ ++ifdef CHANNELSCAN ++DEFINES += -DUSE_CHANNELSCAN ++endif ++ ++ifdef CMDRECCMDI18N ++DEFINES += -DUSE_CMDRECCMDI18N ++endif ++ ++ifdef CMDSUBMENU ++DEFINES += -DUSE_CMDSUBMENU ++endif ++ ++ifdef CUTTERLIMIT ++DEFINES += -DUSE_CUTTERLIMIT ++endif ++ ++ifdef CUTTERQUEUE ++DEFINES += -DUSE_CUTTERQUEUE ++endif ++ ++ifdef CUTTIME ++DEFINES += -DUSE_CUTTIME ++endif ++ ++ifdef DDEPGENTRY ++DEFINES += -DUSE_DDEPGENTRY ++endif ++ ++ifdef DELTIMESHIFTREC ++DEFINES += -DUSE_DELTIMESHIFTREC ++endif ++ ++ifdef DOLBYINREC ++DEFINES += -DUSE_DOLBYINREC ++endif ++ ++ifdef DVBPLAYER ++DEFINES += -DUSE_DVBPLAYER ++endif ++ ++ifdef DVBSETUP ++DEFINES += -DUSE_DVBSETUP ++endif ++ ++ifdef DVDARCHIVE ++ifdef LIEMIEXT ++DEFINES += -DUSE_DVDARCHIVE ++endif ++endif ++ ++ifdef DVLRECSCRIPTADDON ++DEFINES += -DUSE_DVLRECSCRIPTADDON ++endif ++ ++ifdef DVLVIDPREFER ++DEFINES += -DUSE_DVLVIDPREFER ++endif ++ ++ifdef DVLFRIENDLYFNAMES ++DEFINES += -DUSE_DVLFRIENDLYFNAMES ++endif ++ ++ifdef EM84XX ++DEFINES += -DUSE_EM84XX ++endif ++ ++ifdef GRAPHTFT ++DEFINES += -DUSE_GRAPHTFT ++endif ++ ++ifdef HARDLINKCUTTER ++DEFINES += -DUSE_HARDLINKCUTTER ++endif ++ ++ifdef JUMPPLAY ++DEFINES += -DUSE_JUMPPLAY ++endif ++ ++ifdef LIEMIEXT ++DEFINES += -DUSE_LIEMIEXT ++endif ++ ++ifdef LIRCSETTINGS ++DEFINES += -DUSE_LIRCSETTINGS ++endif ++ ++ifdef LIVEBUFFER ++DEFINES += -DUSE_LIVEBUFFER ++endif ++ ++ifdef LNBSHARE ++DEFINES += -DUSE_LNBSHARE ++endif ++ ++ifdef MAINMENUHOOKS ++DEFINES += -DUSE_MAINMENUHOOKS ++endif ++ ++ifdef MENUORG ++DEFINES += -DUSE_MENUORG ++else ++ifdef SETUP ++DEFINES += -DUSE_SETUP ++endif ++endif ++ ++ifdef NOEPG ++DEFINES += -DUSE_NOEPG ++endif ++ ++ifdef OSDMAXITEMS ++DEFINES += -DUSE_OSDMAXITEMS ++endif ++ ++ifdef PARENTALRATING ++DEFINES += -DUSE_PARENTALRATING ++endif ++ ++ifdef PINPLUGIN ++DEFINES += -DUSE_PINPLUGIN ++endif ++ ++ifdef PLUGINMISSING ++DEFINES += -DUSE_PLUGINMISSING ++endif ++ ++ifdef PLUGINPARAM ++DEFINES += -DUSE_PLUGINPARAM ++endif ++ ++ifdef ROTOR ++DEFINES += -DUSE_ROTOR ++endif ++ ++ifdef SETTIME ++DEFINES += -DUSE_SETTIME ++endif ++ ++ifdef SOFTOSD ++DEFINES += -DUSE_SOFTOSD ++endif ++ ++ifdef SOURCECAPS ++DEFINES += -DUSE_SOURCECAPS ++endif ++ ++ifdef SORTRECORDS ++ifdef LIEMIEXT ++DEFINES += -DUSE_SORTRECORDS ++endif ++endif ++ ++ifdef SYNCEARLY ++DEFINES += -DUSE_SYNCEARLY ++endif ++ ++ifdef STREAMDEVEXT ++DEFINES += -DUSE_STREAMDEVEXT ++endif ++ ++ifdef TIMERCMD ++DEFINES += -DUSE_TIMERCMD ++endif ++ ++ifdef TIMERINFO ++DEFINES += -DUSE_TIMERINFO ++endif ++ ++ifdef TTXTSUBS ++DEFINES += -DUSE_TTXTSUBS ++endif ++ ++ifdef VALIDINPUT ++DEFINES += -DUSE_VALIDINPUT ++endif ++ ++ifdef VOLCTRL ++DEFINES += -DUSE_VOLCTRL ++endif ++ ++ifdef WAREAGLEICON ++DEFINES += -DUSE_WAREAGLEICON ++endif ++ ++ifdef YAEPG ++DEFINES += -DUSE_YAEPG ++endif +diff -ruNp vdr-1.6.0-2/Makefile vdr-1.6.0-2-extensions/Makefile +--- vdr-1.6.0-2/Makefile 2008-02-29 22:43:03.000000000 +0100 ++++ vdr-1.6.0-2-extensions/Makefile 2009-04-09 20:48:26.000000000 +0200 +@@ -43,6 +43,22 @@ OBJS = audio.o channels.o ci.o config.o + skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\ + timers.o tools.o transfer.o vdr.o videodir.o + ++ifdef WAREAGLEICON ++OBJS += iconpatch.o ++endif ++ ++ifdef LIVEBUFFER ++OBJS += livebuffer.o ++endif ++ ++ifdef SETUP ++OBJS += tinystr.o tinyxml.o tinyxmlerror.o tinyxmlparser.o submenu.o ++endif ++ ++ifdef TTXTSUBS ++OBJS += vdrttxtsubshooks.o ++endif ++ + ifndef NO_KBD + DEFINES += -DREMOTE_KBD + endif +@@ -75,6 +91,14 @@ ifdef VFAT + DEFINES += -DVFAT + endif + ++ifdef DVDARCHIVE ++ifdef DVDCHAPJUMP ++LIBS += -ldvdread ++INCLUDES += -I/usr/include/dvdread ++DEFINES += -DUSE_DVDCHAPJUMP ++endif ++endif ++ + all: vdr i18n + + # Implicit rules: +@@ -140,6 +164,26 @@ include-dir: + + # Plugins: + ++ifdef PLUGINAPI ++DEFINES += -DUSE_PLUGINAPI ++plugins: include-dir ++ @failed="";\ ++ noapiv="";\ ++ for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do\ ++ echo "Plugin $$i:";\ ++ if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ ++ sed -i -e s/VDRVERSION/APIVERSION/g $(PLUGINDIR)/src/$$i/Makefile;\ ++ if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ ++ echo "ERROR: plugin $$i doesn't honor APIVERSION - not compiled!";\ ++ noapiv="$$noapiv $$i";\ ++ continue;\ ++ fi;\ ++ fi;\ ++ $(MAKE) -C "$(PLUGINDIR)/src/$$i" all || failed="$$failed $$i";\ ++ done;\ ++ if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ ++ if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; fi ++else + plugins: include-dir + @failed="";\ + noapiv="";\ +@@ -154,6 +198,7 @@ plugins: include-dir + done;\ + if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ + if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; exit 1; fi ++endif + + clean-plugins: + @for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/src/$$i" clean; done +diff -ruNp vdr-1.6.0-2/MANUAL vdr-1.6.0-2-extensions/MANUAL +--- vdr-1.6.0-2/MANUAL 2008-02-24 11:09:17.000000000 +0100 ++++ vdr-1.6.0-2-extensions/MANUAL 2009-04-09 20:48:26.000000000 +0200 +@@ -813,6 +813,30 @@ Version 1.6 + 0 resulting in a file named 'resume.vdr', and any other + value resulting in 'resume.n.vdr'. + ++ Jump&Play = no Turns playing on or off after jumping forward to the ++ next editing mark with the '9' key. ++ ++ Play&Jump = no Turns automatic jumping over commercial breaks on or ++ off. This includes jumping to the first mark, if the ++ replay starts at the beginning of a recording - and ++ stopping the replay at the last mark. ++ With this setting enabled, the behaviour of the '8' ++ key during replay is changed too. It moves the actual ++ replay position not only three seconds before the ++ next "start" mark, but also before the next "end" ++ mark. This can be used to test, if the editing marks ++ are correctly positioned for a "smooth" jump over a ++ commercial break. ++ ++ Pause at last mark = no ++ Turns pausing of replay at the last editing mark on or ++ off. ++ ++ Reload marks = no Turns reloading of editing marks on or off. This can ++ be used if an external programme adjusts the editing ++ marks, e.g. noad in online mode. The marks are reloaded ++ in 10 seconds intervals. ++ + Miscellaneous: + + Min. event timeout = 30 +diff -ruNp vdr-1.6.0-2/menu.c vdr-1.6.0-2-extensions/menu.c +--- vdr-1.6.0-2/menu.c 2008-03-16 12:15:28.000000000 +0100 ++++ vdr-1.6.0-2-extensions/menu.c 2009-04-09 20:48:26.000000000 +0200 +@@ -8,11 +8,17 @@ + */ + + #include "menu.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <limits.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> ++#ifdef USE_LIEMIEXT ++#include <math.h> ++#endif /* LIEMIEXT */ + #include "channels.h" + #include "config.h" + #include "cutter.h" +@@ -28,7 +34,17 @@ + #include "themes.h" + #include "timers.h" + #include "transfer.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + #include "videodir.h" ++#ifdef USE_MENUORG ++#include "menuorgpatch.h" ++#endif /* MENUORG */ ++ ++#ifdef USE_CMDRECCMDI18N ++extern const char *ConfigDirectory; ++#endif /* CMDRECCMDI18N */ + + #define MAXWAIT4EPGINFO 3 // seconds + #define MODETIMEOUT 3 // seconds +@@ -253,10 +269,16 @@ private: + cChannel *channel; + cChannel data; + char name[256]; ++#ifdef USE_PLUGINPARAM ++ char pluginParam[256]; ++#endif /* PLUGINPARAM */ + void Setup(void); + public: + cMenuEditChannel(cChannel *Channel, bool New = false); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEditChannel"; } ++#endif /* GRAPHTFT */ + }; + + cMenuEditChannel::cMenuEditChannel(cChannel *Channel, bool New) +@@ -285,6 +307,9 @@ void cMenuEditChannel::Setup(void) + + // Parameters for all types of sources: + strn0cpy(name, data.name, sizeof(name)); ++#ifdef USE_PLUGINPARAM ++ strn0cpy(pluginParam, data.pluginParam, sizeof(pluginParam)); ++#endif /* PLUGINPARAM */ + Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name))); + Add(new cMenuEditSrcItem( tr("Source"), &data.source)); + Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); +@@ -315,6 +340,9 @@ void cMenuEditChannel::Setup(void) + ST(" T") Add(new cMenuEditMapItem( tr("Transmission"), &data.transmission, TransmissionValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Guard"), &data.guard, GuardValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Hierarchy"), &data.hierarchy, HierarchyValues, tr("none"))); ++#ifdef USE_PLUGINPARAM ++ ST("P ") Add(new cMenuEditStrItem( tr("Parameters"), pluginParam, sizeof(pluginParam), tr(FileNameChars))); ++#endif /* PLUGINPARAM */ + + SetCurrent(Get(current)); + Display(); +@@ -329,9 +357,15 @@ eOSState cMenuEditChannel::ProcessKey(eK + if (Key == kOk) { + if (Channels.HasUniqueChannelID(&data, channel)) { + data.name = strcpyrealloc(data.name, name); ++#ifdef USE_PLUGINPARAM ++ data.pluginParam = strcpyrealloc(data.pluginParam, pluginParam); ++#endif /* PLUGINPARAM */ + if (channel) { + *channel = data; + isyslog("edited channel %d %s", channel->Number(), *data.ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scMod); ++#endif /* STREAMDEVEXT */ + state = osBack; + } + else { +@@ -340,6 +374,9 @@ eOSState cMenuEditChannel::ProcessKey(eK + Channels.Add(channel); + Channels.ReNumber(); + isyslog("added channel %d %s", channel->Number(), *data.ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scAdd); ++#endif /* STREAMDEVEXT */ + state = osUser1; + } + Channels.SetModified(true); +@@ -402,6 +439,16 @@ void cMenuChannelItem::Set(void) + if (!channel->GroupSep()) { + if (sortMode == csmProvider) + buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name()); ++#ifdef USE_WAREAGLEICON ++ else if (Setup.WarEagleIcons) { ++ if (channel->Vpid() == 1 || channel->Vpid() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_RADIO_UTF8 : ICON_RADIO, channel->Name()); ++ else if (channel->Ca() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_UTF8 : ICON_TV, channel->Name()); ++ else ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_CRYPTED_UTF8 : ICON_TV_CRYPTED, channel->Name()); ++ } ++#endif /* WAREAGLEICON */ + else + buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name()); + } +@@ -432,6 +479,9 @@ public: + cMenuChannels(void); + ~cMenuChannels(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuChannels"; } ++#endif /* GRAPHTFT */ + }; + + cMenuChannels::cMenuChannels(void) +@@ -561,6 +611,9 @@ eOSState cMenuChannels::Delete(void) + Propagate(); + Channels.SetModified(true); + isyslog("channel %d deleted", DeletedChannel); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NULL, scDel); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -586,6 +639,9 @@ void cMenuChannels::Move(int From, int T + Propagate(); + Channels.SetModified(true); + isyslog("channel %d moved to %d", FromNumber, ToNumber); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(ToChannel, scMod); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -698,14 +754,47 @@ cMenuEditTimer::cMenuEditTimer(cTimer *T + data.SetFlags(tfActive); + channel = data.Channel()->Number(); + Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive)); ++#ifdef USE_PINPLUGIN ++ if (cOsd::pinValid) Add(new cMenuEditChanItem(tr("Channel"), &channel)); ++ else { ++ cString buf = cString::sprintf("%s\t%s", tr("Channel"), Channels.GetByNumber(channel)->Name()); ++ Add(new cOsdItem(buf)); ++ } ++#else + Add(new cMenuEditChanItem(tr("Channel"), &channel)); ++#endif /* PINPLUGIN */ + Add(new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays)); + Add(new cMenuEditTimeItem(tr("Start"), &data.start)); + Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); + Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps)); + Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); ++#ifdef USE_PINPLUGIN ++ if (cOsd::pinValid || !data.fskProtection) Add(new cMenuEditBoolItem(tr("Childlock"),&data.fskProtection)); ++ else { ++ cString buf = cString::sprintf("%s\t%s", tr("Childlock"), data.fskProtection ? tr("yes") : tr("no")); ++ Add(new cOsdItem(buf)); ++ } ++#endif /* PINPLUGIN */ ++#ifdef USE_LIEMIEXT ++ char* p = strrchr(data.file, '~'); ++ if (p) { ++ p++; ++ Utf8Strn0Cpy(name, p, sizeof(name)); ++ Utf8Strn0Cpy(path, data.file, sizeof(path)); ++ p = strrchr(path, '~'); ++ if (p) ++ p[0] = 0; ++ } ++ else { ++ Utf8Strn0Cpy(name, data.file, sizeof(name)); ++ Utf8Strn0Cpy(path, "", sizeof(path)); ++ } ++ Add(new cMenuEditStrItem(tr("File"), name, sizeof(name), tr(FileNameChars))); ++ Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path))); ++#else + Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); ++#endif /* LIEMIEXT */ + SetFirstDayItem(); + } + Timers.IncBeingEdited(); +@@ -745,6 +834,12 @@ eOSState cMenuEditTimer::ProcessKey(eKey + Skins.Message(mtError, tr("*** Invalid Channel ***")); + break; + } ++#ifdef USE_LIEMIEXT ++ if (strlen(path)) ++ snprintf(data.file, sizeof(data.file), "%s~%s", path, name); ++ else ++ snprintf(data.file, sizeof(data.file), "%s", name); ++#endif /* LIEMIEXT */ + if (!*data.file) + strcpy(data.file, data.Channel()->ShortName(true)); + if (timer) { +@@ -772,13 +867,37 @@ eOSState cMenuEditTimer::ProcessKey(eKey + return state; + } + ++#ifdef USE_TIMERCMD ++// --- cMenuCommands --------------------------------------------------------- ++// declaration shifted so it can be used in cMenuTimers ++class cMenuCommands : public cOsdMenu { ++private: ++ cCommands *commands; ++ char *parameters; ++ eOSState Execute(void); ++public: ++ cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); ++ virtual ~cMenuCommands(); ++ virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCommands"; } ++#endif /* GRAPHTFT - passt das so? */ ++ }; ++#endif /* TIMERCMD */ ++ + // --- cMenuTimerItem -------------------------------------------------------- + + class cMenuTimerItem : public cOsdItem { + private: + cTimer *timer; ++#ifdef USE_TIMERINFO ++ char diskStatus; ++#endif /* TIMERINFO */ + public: + cMenuTimerItem(cTimer *Timer); ++#ifdef USE_TIMERINFO ++ void SetDiskStatus(char DiskStatus); ++#endif /* TIMERINFO */ + virtual int Compare(const cListObject &ListObject) const; + virtual void Set(void); + cTimer *Timer(void) { return timer; } +@@ -787,6 +906,9 @@ public: + cMenuTimerItem::cMenuTimerItem(cTimer *Timer) + { + timer = Timer; ++#ifdef USE_TIMERINFO ++ diskStatus = ' '; ++#endif /* TIMERINFO */ + Set(); + } + +@@ -812,8 +934,56 @@ void cMenuTimerItem::Set(void) + strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r); + day = buffer; + } ++#ifdef USE_LIEMIEXT ++ if (!Setup.ShowTimerStop) { ++#ifdef USE_TIMERINFO ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++ diskStatus, ++#else ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++#endif /* TIMERINFO */ ++#ifdef USE_WAREAGLEICON ++ !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", ++#else ++ !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', ++#endif /* WAREAGLEICON */ ++ timer->Channel()->Number(), ++ *name, ++ *name && **name ? " " : "", ++ *day, ++ timer->Start() / 100, ++ timer->Start() % 100, ++ timer->File())); ++ } ++ else { ++#endif /* LIEMIEXT */ ++#ifdef USE_TIMERINFO ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++ diskStatus, ++#else ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#else + SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++#endif /* TIMERINFO */ ++#ifdef USE_WAREAGLEICON ++ !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", ++#else + !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', ++#endif /* WAREAGLEICON */ + timer->Channel()->Number(), + *name, + *name && **name ? " " : "", +@@ -823,8 +993,64 @@ void cMenuTimerItem::Set(void) + timer->Stop() / 100, + timer->Stop() % 100, + timer->File())); ++#ifdef USE_LIEMIEXT ++ } ++#endif /* LIEMIEXT */ ++} ++ ++#ifdef USE_TIMERINFO ++void cMenuTimerItem::SetDiskStatus(char DiskStatus) ++{ ++ diskStatus = DiskStatus; ++ Set(); ++} ++ ++// --- cTimerEntry ----------------------------------------------------------- ++ ++class cTimerEntry : public cListObject { ++private: ++ cMenuTimerItem *item; ++ const cTimer *timer; ++ time_t start; ++public: ++ cTimerEntry(cMenuTimerItem *item) : item(item), timer(item->Timer()), start(timer->StartTime()) {} ++ cTimerEntry(const cTimer *timer, time_t start) : item(NULL), timer(timer), start(start) {} ++ virtual int Compare(const cListObject &ListObject) const; ++ bool active(void) const { return timer->HasFlags(tfActive); } ++ time_t startTime(void) const { return start; } ++ int priority(void) const { return timer->Priority(); } ++ int duration(void) const; ++ bool repTimer(void) const { return !timer->IsSingleEvent(); } ++ bool isDummy(void) const { return item == NULL; } ++ const cTimer *Timer(void) const { return timer; } ++ void SetDiskStatus(char DiskStatus); ++ }; ++ ++int cTimerEntry::Compare(const cListObject &ListObject) const ++{ ++ cTimerEntry *entry = (cTimerEntry *)&ListObject; ++ int r = startTime() - entry->startTime(); ++ if (r == 0) ++ r = entry->priority() - priority(); ++ return r; + } + ++int cTimerEntry::duration(void) const ++{ ++ int dur = (timer->Stop() / 100 * 60 + timer->Stop() % 100) - ++ (timer->Start() / 100 * 60 + timer->Start() % 100); ++ if (dur < 0) ++ dur += 24 * 60; ++ return dur; ++} ++ ++void cTimerEntry::SetDiskStatus(char DiskStatus) ++{ ++ if (item) ++ item->SetDiskStatus(DiskStatus); ++} ++#endif /* TIMERINFO */ ++ + // --- cMenuTimers ----------------------------------------------------------- + + class cMenuTimers : public cOsdMenu { +@@ -837,14 +1063,31 @@ private: + eOSState Info(void); + cTimer *CurrentTimer(void); + void SetHelpKeys(void); ++#ifdef USE_TIMERINFO ++ void ActualiseDiskStatus(void); ++ bool actualiseDiskStatus; ++#endif /* TIMERINFO */ ++#ifdef USE_TIMERCMD ++ eOSState Commands(eKeys Key = kNone); ++#endif /* TIMERCMD */ + public: + cMenuTimers(void); + virtual ~cMenuTimers(); ++#ifdef USE_TIMERINFO ++ virtual void Display(void); ++#endif /* TIMERINFO */ + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuTimers"; } ++#endif /* GRAPHTFT */ + }; + + cMenuTimers::cMenuTimers(void) ++#ifdef USE_TIMERINFO ++:cOsdMenu(tr("Timers"), 3, CHNUMWIDTH, 10, 6, 6) ++#else + :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6) ++#endif /* TIMERINFO */ + { + helpKeys = -1; + for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { +@@ -855,6 +1098,9 @@ cMenuTimers::cMenuTimers(void) + SetCurrent(First()); + SetHelpKeys(); + Timers.IncBeingEdited(); ++#ifdef USE_TIMERINFO ++ actualiseDiskStatus = true; ++#endif /* TIMERINFO */ + } + + cMenuTimers::~cMenuTimers() +@@ -893,7 +1139,11 @@ eOSState cMenuTimers::OnOff(void) + timer->OnOff(); + timer->SetEventFromSchedule(); + RefreshCurrent(); ++#ifdef USE_TIMERINFO ++ Display(); ++#else + DisplayCurrent(true); ++#endif /* TIMERINFO */ + if (timer->FirstDay()) + isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay()); + else +@@ -952,6 +1202,117 @@ eOSState cMenuTimers::Info(void) + return osContinue; + } + ++#ifdef USE_TIMERCMD ++#define CHECK_2PTR_NULL(x_,y_) ((x_)? ((y_)? y_:""):"") ++ ++eOSState cMenuTimers::Commands(eKeys Key) ++{ ++ if (HasSubMenu() || Count() == 0) ++ return osContinue; ++ cTimer *ti = CurrentTimer(); ++ if (ti) { ++ const cEvent *pEvent = ti->Event(); ++ int iRecNumber=0; ++ ++ if (!pEvent) { ++ Timers.SetEvents(); ++ pEvent = ti->Event(); ++ } ++ if (pEvent) { ++ // create a dummy recording to get the real filename ++ cRecording *rc_dummy = new cRecording(ti, pEvent); ++ Recordings.Load(); ++ cRecording *rc = Recordings.GetByName(rc_dummy->FileName()); ++ ++ delete rc_dummy; ++ if (rc) ++ iRecNumber=rc->Index() + 1; ++ } ++ // TODO: Geht das so...? ++ // Parameter format TimerNumber 'ChannelId' Start Stop 'Titel' 'Subtitel' 'file' RecNumer ++ // 1 2 3 4 5 6 7 8 ++ cString parameter = cString::sprintf("%d '%s' %d %d '%s' '%s' '%s' %d", ti->Index(), ++ *ti->Channel()->GetChannelID().ToString(), ++ (int)ti->StartTime(), ++ (int)ti->StopTime(), ++ CHECK_2PTR_NULL(pEvent, pEvent->Title()), ++ CHECK_2PTR_NULL(pEvent, pEvent->ShortText()), ++ ti->File(), ++ iRecNumber); ++ isyslog("timercmd: %s", *parameter); ++ cMenuCommands *menu; ++ eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Timer commands"), &TimerCommands, parameter)); ++ if (Key != kNone) ++ state = menu->ProcessKey(Key); ++ return state; ++ } ++ return osContinue; ++} ++#endif /* TIMERCMD */ ++ ++#ifdef USE_TIMERINFO ++void cMenuTimers::ActualiseDiskStatus(void) ++{ ++ if (!actualiseDiskStatus || !Count()) ++ return; ++ ++ // compute free disk space ++ int freeMB, freeMinutes, runshortMinutes; ++ VideoDiskSpace(&freeMB); ++ freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent ++ runshortMinutes = freeMinutes / 5; // 20 Percent ++ ++ // fill entries list ++ cTimerEntry *entry; ++ cList<cTimerEntry> entries; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ entries.Add(new cTimerEntry((cMenuTimerItem *)item)); ++ ++ // search last start time ++ time_t last = 0; ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ last = max(entry->startTime(), last); ++ ++ // add entries for repeating timers ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ if (entry->repTimer() && !entry->isDummy()) ++ for (time_t start = cTimer::IncDay(entry->startTime(), 1); ++ start <= last; ++ start = cTimer::IncDay(start, 1)) ++ if (entry->Timer()->DayMatches(start)) ++ entries.Add(new cTimerEntry(entry->Timer(), start)); ++ ++ // set the disk-status ++ entries.Sort(); ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) { ++ char status = ' '; ++ if (entry->active()) { ++ freeMinutes -= entry->duration(); ++ status = freeMinutes > runshortMinutes ? '+' : freeMinutes > 0 ? '~' /* ± 177 +/- */ : '-'; ++ } ++ entry->SetDiskStatus(status); ++#ifdef DEBUG_TIMER_INFO ++ dsyslog("timer-info: %c | %d | %s | %s | %3d | %+5d -> %+5d", ++ status, ++ entry->startTime(), ++ entry->active() ? "aktiv " : "n.akt.", ++ entry->repTimer() ? entry->isDummy() ? " dummy " : "mehrmalig" : "einmalig ", ++ entry->duration(), ++ entry->active() ? freeMinutes + entry->duration() : freeMinutes, ++ freeMinutes); ++#endif ++ } ++ ++ actualiseDiskStatus = false; ++} ++ ++void cMenuTimers::Display(void) ++{ ++ ActualiseDiskStatus(); ++ cOsdMenu::Display(); ++} ++#endif /* TIMERINFO */ ++ + eOSState cMenuTimers::ProcessKey(eKeys Key) + { + int TimerNumber = HasSubMenu() ? Count() : -1; +@@ -960,18 +1321,40 @@ eOSState cMenuTimers::ProcessKey(eKeys K + if (state == osUnknown) { + switch (Key) { + case kOk: return Edit(); ++#ifdef USE_TIMERINFO ++ case kRed: actualiseDiskStatus = true; ++ state = OnOff(); break; // must go through SetHelpKeys()! ++#else + case kRed: state = OnOff(); break; // must go through SetHelpKeys()! ++#endif /* TIMERINFO */ + case kGreen: return New(); ++#ifdef USE_TIMERINFO ++ case kYellow: actualiseDiskStatus = true; ++ state = Delete(); break; ++#else + case kYellow: state = Delete(); break; ++#endif /* TIMERINFO */ + case kInfo: + case kBlue: return Info(); + break; ++#ifdef USE_TIMERCMD ++ case k1...k9: return Commands(Key); ++ case k0: return (TimerCommands.Count()? Commands():osContinue); ++#endif /* TIMERCMD */ + default: break; + } + } ++#ifdef USE_TIMERINFO ++ if (TimerNumber >= 0 && !HasSubMenu()) { ++ if (Timers.Get(TimerNumber)) // a newly created timer was confirmed with Ok ++ Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++ Sort(); ++ actualiseDiskStatus = true; ++#else + if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) { + // a newly created timer was confirmed with Ok + Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++#endif /* TIMERINFO */ + Display(); + } + if (Key != kNone) +@@ -1001,6 +1384,9 @@ void cMenuEvent::Display(void) + { + cOsdMenu::Display(); + DisplayMenu()->SetEvent(event); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetEvent(event); ++#endif /* GRAPHTFT */ + if (event->Description()) + cStatus::MsgOsdTextItem(event->Description()); + } +@@ -1048,7 +1434,12 @@ public: + const cChannel *channel; + bool withDate; + int timerMatch; ++#ifdef USE_LIEMIEXT ++ bool withBar; ++ cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false, bool WithBar = false); ++#else + cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false); ++#endif /* LIEMIEXT */ + static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; } + static void IncSortMode(void) { sortMode = eScheduleSortMode((sortMode == ssmAllAll) ? ssmAllThis : sortMode + 1); } + static eScheduleSortMode SortMode(void) { return sortMode; } +@@ -1058,12 +1449,19 @@ public: + + cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis; + ++#ifdef USE_LIEMIEXT ++cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate, bool WithBar) ++#else + cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate) ++#endif /* LIEMIEXT */ + { + event = Event; + channel = Channel; + withDate = WithDate; + timerMatch = tmNone; ++#ifdef USE_LIEMIEXT ++ withBar = WithBar; ++#endif /* LIEMIEXT */ + Update(true); + } + +@@ -1078,7 +1476,29 @@ int cMenuScheduleItem::Compare(const cLi + return r; + } + ++#ifdef USE_LIEMIEXT ++static const char * const ProgressBar[7] = ++{ ++ "[ ]", ++ "[| ]", ++ "[|| ]", ++ "[||| ]", ++ "[|||| ]", ++ "[||||| ]", ++ "[||||||]" ++}; ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_WAREAGLEICON ++static const char *TimerMatchChars[9] = ++{ ++ " ", "t", "T", ++ ICON_BLANK, ICON_CLOCK_UH, ICON_CLOCK, ++ ICON_BLANK_UTF8, ICON_CLOCK_UH_UTF8, ICON_CLOCK_UTF8 ++}; ++#else + static const char *TimerMatchChars = " tT"; ++#endif /* WAREAGLEICON */ + + bool cMenuScheduleItem::Update(bool Force) + { +@@ -1087,17 +1507,54 @@ bool cMenuScheduleItem::Update(bool Forc + Timers.GetMatch(event, &timerMatch); + if (Force || timerMatch != OldTimerMatch) { + cString buffer; ++#ifdef USE_WAREAGLEICON ++ const char *t = Setup.WarEagleIcons ? IsLangUtf8() ? TimerMatchChars[timerMatch+6] : TimerMatchChars[timerMatch+3] : TimerMatchChars[timerMatch]; ++ const char *v = event->Vps() && (event->Vps() - event->StartTime()) ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_VPS_UTF8 : ICON_VPS : "V" : " "; ++ const char *r = event->SeenWithin(30) && event->IsRunning() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_RUNNING_UTF8 : ICON_RUNNING : "*" : " "; ++#else + char t = TimerMatchChars[timerMatch]; + char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; + char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + const char *csn = channel ? channel->ShortName(true) : NULL; + cString eds = event->GetDateString(); + if (channel && withDate) ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + else if (channel) ++#ifdef USE_LIEMIEXT ++ if (Setup.ShowProgressBar && withBar) { ++ int progress = (int)roundf( (float)(time(NULL) - event->StartTime()) / (float)(event->Duration()) * 6.0 ); ++ if (progress < 0) progress = 0; ++ else if (progress > 6) progress = 6; ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++ } ++ else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#endif /* LIEMIEXT */ + else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%.*s\t%s\t%s%s%s\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + SetText(buffer); + result = true; + } +@@ -1123,13 +1580,21 @@ public: + static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } + static const cEvent *ScheduleEvent(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return now ? "MenuWhatsOnNow" : "MenuWhatsOnNext"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + int cMenuWhatsOn::currentChannel = 0; + const cEvent *cMenuWhatsOn::scheduleEvent = NULL; + + cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4, 4) ++#else + :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4) ++#endif /* LIEMIEXT */ + { + now = Now; + helpKeys = -1; +@@ -1141,7 +1606,11 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu + if (Schedule) { + const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); + if (Event) ++#ifdef USE_LIEMIEXT ++ Add(new cMenuScheduleItem(Event, Channel, false, Now), Channel->Number() == CurrentChannelNr); ++#else + Add(new cMenuScheduleItem(Event, Channel), Channel->Number() == CurrentChannelNr); ++#endif /* LIEMIEXT */ + } + } + } +@@ -1150,6 +1619,19 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu + SetHelpKeys(); + } + ++#ifdef USE_GRAPHTFT ++void cMenuWhatsOn::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++} ++#endif /* GRAPHTFT */ ++ + bool cMenuWhatsOn::Update(void) + { + bool result = false; +@@ -1290,6 +1772,10 @@ public: + cMenuSchedule(void); + virtual ~cMenuSchedule(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSchedule"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + cMenuSchedule::cMenuSchedule(void) +@@ -1315,6 +1801,19 @@ cMenuSchedule::~cMenuSchedule() + cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared + } + ++#ifdef USE_GRAPHTFT ++void cMenuSchedule::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++} ++#endif /* GRAPHTFT */ ++ + void cMenuSchedule::PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel) + { + Clear(); +@@ -1548,6 +2047,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys + + // --- cMenuCommands --------------------------------------------------------- + ++#ifndef USE_TIMERCMD + class cMenuCommands : public cOsdMenu { + private: + cCommands *commands; +@@ -1557,7 +2057,11 @@ public: + cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); + virtual ~cMenuCommands(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCommands"; } ++#endif /* GRAPHTFT */ + }; ++#endif /* TIMERCMD */ + + cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters) + :cOsdMenu(Title) +@@ -1579,6 +2083,12 @@ eOSState cMenuCommands::Execute(void) + cCommand *command = commands->Get(Current()); + if (command) { + bool confirmed = true; ++#ifdef USE_CMDSUBMENU ++ if (command->hasChilds()) { ++ AddSubMenu(new cMenuCommands(command->Title(), command->getChilds(), parameters)); ++ return osContinue; ++ } ++#endif /* CMDSUBMENU */ + if (command->Confirm()) + confirmed = Interface->Confirm(cString::sprintf("%s?", command->Title())); + if (confirmed) { +@@ -1629,6 +2139,9 @@ public: + cMenuCam(cCamSlot *CamSlot); + virtual ~cMenuCam(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuCam::cMenuCam(cCamSlot *CamSlot) +@@ -1808,6 +2321,9 @@ public: + cMenuRecording(const cRecording *Recording, bool WithButtons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRecording"; } ++#endif /* GRAPHTFT */ + }; + + cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons) +@@ -1823,6 +2339,9 @@ void cMenuRecording::Display(void) + { + cOsdMenu::Display(); + DisplayMenu()->SetRecording(recording); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetRecording(recording); ++#endif /* GRAPHTFT */ + if (recording->Info()->Description()) + cStatus::MsgOsdTextItem(recording->Info()->Description()); + } +@@ -1883,7 +2402,11 @@ cMenuRecordingItem::cMenuRecordingItem(c + fileName = strdup(Recording->FileName()); + name = NULL; + totalEntries = newEntries = 0; ++#ifdef USE_LIEMIEXT ++ SetText(Recording->Title('\t', true, Level, false)); ++#else + SetText(Recording->Title('\t', true, Level)); ++#endif /* LIEMIEXT */ + if (*Text() == '\t') + name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t' + } +@@ -1899,13 +2422,203 @@ void cMenuRecordingItem::IncrementCounte + totalEntries++; + if (New) + newEntries++; ++#ifdef USE_LIEMIEXT ++#ifdef USE_WAREAGLEICON ++ switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { ++ case 0: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s %s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, name)); ++ else ++ SetText(cString::sprintf("%s", name)); ++ break; ++ case 1: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s %d\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%s", totalEntries, name)); ++ break; ++ case 2: ++ default: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++ break; ++ case 3: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); ++ break; ++ } ++#else ++ switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { ++ case 0: ++ SetText(cString::sprintf("%s", name)); ++ break; ++ case 1: ++ SetText(cString::sprintf("%d\t%s", totalEntries, name)); ++ break; ++ case 2: ++ default: ++ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++ break; ++ case 3: ++ SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); ++ break; ++ } ++#endif /* WAREAGLEICON */ ++#else ++#ifdef USE_WAREAGLEICON ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++#endif /* WAREAGLEICON */ + SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++#endif /* LIEMIEXT */ + } + ++#ifdef USE_LIEMIEXT ++// --- cMenuRenameRecording -------------------------------------------------- ++ ++class cMenuRenameRecording : public cOsdMenu { ++private: ++ int lifetime; ++ int priority; ++ char name[MaxFileName]; ++ char path[MaxFileName]; ++ cOsdItem *marksItem, *resumeItem; ++ bool isResume, isMarks; ++ cRecording *recording; ++public: ++ cMenuRenameRecording(cRecording *Recording); ++ virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRenameRecording"; } ++#endif /* GRAPHTFT */ ++}; ++ ++cMenuRenameRecording::cMenuRenameRecording(cRecording *Recording) ++:cOsdMenu(tr("Rename recording"), 12) ++{ ++ cMarks marks; ++ ++ recording = Recording; ++ priority = recording->priority; ++ lifetime = recording->lifetime; ++ ++ char* p = strrchr(recording->Name(), '~'); ++ if (p) { ++ p++; ++ Utf8Strn0Cpy(name, p, sizeof(name)); ++ Utf8Strn0Cpy(path, recording->Name(), sizeof(path)); ++ p = strrchr(path, '~'); ++ if (p) ++ p[0] = 0; ++ } ++ else { ++ Utf8Strn0Cpy(name, recording->Name(), sizeof(name)); ++ Utf8Strn0Cpy(path, "", sizeof(path)); ++ } ++ Add(new cMenuEditStrItem(tr("Name"), name, sizeof(name), tr(FileNameChars))); ++ Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path) )); ++ Add(new cMenuEditIntItem(tr("Priority"), &priority, 0, MAXPRIORITY )); ++ Add(new cMenuEditIntItem(tr("Lifetime"), &lifetime, 0, MAXLIFETIME )); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Date"), *DayDateTime(recording->start)), osUnknown, false)); ++ ++ cChannel *channel = Channels.GetByChannelID(((cRecordingInfo *)recording->Info())->ChannelID()); ++ if (channel) ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Channel"), *ChannelString(channel, 0)), osUnknown, false)); ++ ++ cIndexFile *index = new cIndexFile(recording->FileName(), false); ++ int recLen = 0; ++ if (index) { ++ recLen = index->Last() / FRAMESPERSEC; ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Length"), *IndexToHMSF(index->Last())), osUnknown, false)); ++ delete index; ++ } ++ ++ int dirSize = DirSizeMB(recording->FileName()); ++ cString bitRate = recLen ? cString::sprintf(" (%.2f MBit/s)", 8.0 * dirSize / recLen) : cString(""); ++ Add(new cOsdItem((dirSize > 9999) ? cString::sprintf("%s:\t%.2f GB%s", tr("Size"), dirSize / 1024.0, *bitRate) : cString::sprintf("%s:\t%d MB%s", tr("Size"), dirSize, *bitRate), osUnknown, false)); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ isMarks = marks.Load(recording->FileName()) && marks.Count(); ++ marksItem = new cOsdItem(tr("Delete marks information?"), osUser1, isMarks); ++ Add(marksItem); ++ ++ cResumeFile ResumeFile(recording->FileName()); ++ isResume = (ResumeFile.Read() != -1); ++ resumeItem = new cOsdItem(tr("Delete resume information?"), osUser2, isResume); ++ Add(resumeItem); ++} ++ ++eOSState cMenuRenameRecording::ProcessKey(eKeys Key) ++{ ++ eOSState state = cOsdMenu::ProcessKey(Key); ++ ++ if (state == osUnknown) { ++ if (Key == kOk) { ++ char buffer[MaxFileName]; ++ if (Utf8StrLen(path)) ++ snprintf(buffer, sizeof(buffer), "%s~%s", path, name); ++ else ++ snprintf(buffer, sizeof(buffer), "%s", name); ++ if (recording->Rename(buffer, &priority, &lifetime)) { ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ return osRecordings; ++ } ++ else ++ Skins.Message(mtError, tr("Error while accessing recording!")); ++ } ++ return osContinue; ++ } ++ else if (state == osUser1) { ++ if (isMarks && Interface->Confirm(tr("Delete marks information?"))) { ++ cMarks marks; ++ marks.Load(recording->FileName()); ++ cMark *mark = marks.First(); ++ while (mark) { ++ cMark *nextmark = marks.Next(mark); ++ marks.Del(mark); ++ mark = nextmark; ++ } ++ marks.Save(); ++ isMarks = false; ++ marksItem->SetSelectable(isMarks); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ else if (state == osUser2) { ++ if (isResume && Interface->Confirm(tr("Delete resume information?"))) { ++ cResumeFile ResumeFile(recording->FileName()); ++ ResumeFile.Delete(); ++ isResume = false; ++ resumeItem->SetSelectable(isResume); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ return state; ++} ++#endif /* LIEMIEXT */ ++ + // --- cMenuRecordings ------------------------------------------------------- + + cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Base ? Base : tr("Recordings"), 9, 7, 7) ++#else + :cOsdMenu(Base ? Base : tr("Recordings"), 9, 7) ++#endif /* LIEMIEXT */ + { + base = Base ? strdup(Base) : NULL; + level = Setup.RecordingDirs ? Level : -1; +@@ -1982,7 +2695,12 @@ void cMenuRecordings::Set(bool Refresh) + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { + if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == '~')) { + cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); ++#ifdef USE_PINPLUGIN ++ if ((*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) ++ && (!cStatus::MsgReplayProtected(GetRecording(Item), Item->Name(), base, Item->IsDirectory(), true))) { ++#else + if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { ++#endif /* PINPLUGIN */ + Add(Item); + LastItem = Item; + free(LastItemText); +@@ -2032,13 +2750,43 @@ eOSState cMenuRecordings::Play(void) + { + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(GetRecording(ri), ri->Name(), base, ri->IsDirectory()) == true) ++ return osContinue; ++#endif /* PINPLUGIN */ + if (ri->IsDirectory()) + Open(); + else { + cRecording *recording = GetRecording(ri); + if (recording) { ++#ifdef USE_DVDARCHIVE ++ int mountRet = MOUNT_DVD_REPLAY; ++ if (recording->IsOnlyOnDvd()) { ++ mountRet = recording->MountDvd(); ++ } ++ if (mountRet == MOUNT_DVD_REPLAY) { ++ cReplayControl::SetRecording(recording->FileName(), recording->Title()); ++ return osReplay; ++ } ++ else if (mountRet == MOUNT_DVD_LAUNCH_DVD_PLUGIN) { ++ //launch DVD plugin here ++ cPlugin *p = cPluginManager::GetPlugin("dvd"); ++ cOsdObject *osd = NULL; ++ if (p) { ++ osd = p->MainMenuAction(); ++ delete osd; ++ osd = NULL; ++ return osEnd; ++ } ++ else { ++ Skins.Message(mtError, tr("DVD plugin is not installed!")); ++ Skins.Flush(); ++ } ++ } ++#else + cReplayControl::SetRecording(recording->FileName(), recording->Title()); + return osReplay; ++#endif /* DVDARCHIVE */ + } + } + } +@@ -2136,12 +2884,34 @@ eOSState cMenuRecordings::Commands(eKeys + return osContinue; + } + ++#ifdef USE_LIEMIEXT ++eOSState cMenuRecordings::Rename(void) ++{ ++ if (HasSubMenu() || Count() == 0) ++ return osContinue; ++ cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); ++ if (ri && !ri->IsDirectory()) { ++ cRecording *recording = GetRecording(ri); ++ if (recording) ++ return AddSubMenu(new cMenuRenameRecording(recording)); ++ } ++ return osContinue; ++} ++#endif /* LIEMIEXT */ ++ + eOSState cMenuRecordings::ProcessKey(eKeys Key) + { + bool HadSubMenu = HasSubMenu(); + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { ++#ifdef USE_SORTRECORDS ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ + switch (Key) { + case kPlay: + case kOk: return Play(); +@@ -2150,7 +2920,26 @@ eOSState cMenuRecordings::ProcessKey(eKe + case kYellow: return Delete(); + case kInfo: + case kBlue: return Info(); ++#ifdef USE_SORTRECORDS ++ case k0: Setup.RecordingsSortMode = ++Setup.RecordingsSortMode % MAXSORTMODES; ++ Set(true); ++ Skins.Message(mtStatus, cString::sprintf("%s %d: %s", tr("Sorting"), Setup.RecordingsSortMode, RecordingsSortModeTexts[Setup.RecordingsSortMode])); ++ return osContinue; ++ case k1...k7: return Commands(Key); ++ case k8: return Rename(); ++ case k9: Recordings.ToggleSortOrder(); ++ Set(true); ++ return osContinue; ++#elif defined (USE_LIEMIEXT) ++ case k0: DirOrderState = !DirOrderState; ++ Set(true); ++ return osContinue; ++ case k8: return Rename(); ++ case k9: ++ case k1...k7: return Commands(Key); ++#else + case k1...k9: return Commands(Key); ++#endif /* LIEMIEXT & SORTRECORDS */ + case kNone: if (Recordings.StateChanged(recordingsState)) + Set(true); + break; +@@ -2199,6 +2988,9 @@ void cMenuSetupBase::Store(void) + class cMenuSetupOSD : public cMenuSetupBase { + private: + const char *useSmallFontTexts[3]; ++#ifdef USE_LIEMIEXT ++ const char *mainMenuTitle[MAXMAINMENUTITLE]; ++#endif /* LIEMIEXT */ + int osdLanguageIndex; + int numSkins; + int originalSkinIndex; +@@ -2214,6 +3006,9 @@ public: + cMenuSetupOSD(void); + virtual ~cMenuSetupOSD(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupOsd"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupOSD::cMenuSetupOSD(void) +@@ -2249,12 +3044,21 @@ void cMenuSetupOSD::Set(void) + useSmallFontTexts[0] = tr("never"); + useSmallFontTexts[1] = tr("skin dependent"); + useSmallFontTexts[2] = tr("always"); ++#ifdef USE_LIEMIEXT ++ mainMenuTitle[0]=tr("default"); ++ mainMenuTitle[1]=tr("VDR - text"); ++ mainMenuTitle[2]=tr("text"); ++ mainMenuTitle[3]=tr("VDR - version"); ++#endif /* LIEMIEXT */ + Clear(); + SetSection(tr("OSD")); + Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0))); + Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions)); + if (themes.NumThemes()) + Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions())); ++#ifdef USE_WAREAGLEICON ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$WarEagle icons"), &data.WarEagleIcons)); ++#endif /* WAREAGLEICON */ + Add(new cMenuEditIntItem( tr("Setup.OSD$Left"), &data.OSDLeft, 0, MAXOSDWIDTH)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Top"), &data.OSDTop, 0, MAXOSDHEIGHT)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDWidth, MINOSDWIDTH, MAXOSDWIDTH)); +@@ -2276,6 +3080,24 @@ void cMenuSetupOSD::Set(void) + Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditStraItem(tr("Setup.OSD$Main menu title"), &data.MainMenuTitle, MAXMAINMENUTITLE, mainMenuTitle)); ++ if (data.MainMenuTitle == 1 || data.MainMenuTitle == 2) ++ Add(new cMenuEditStrItem(tr("Setup.OSD$- Text"), data.CustomMainMenuTitle, sizeof(data.CustomMainMenuTitle))); ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Main menu command position"), &data.MenuCmdPosition, tr("bottom"), tr("top"))); ++#endif /* LIEMIEXT */ ++#ifdef USE_VALIDINPUT ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Show valid input"), &data.ShowValidInput)); ++#endif /* VALIDINPUT */ ++#ifdef USE_SOFTOSD ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Use SoftOSD"), &data.UseSoftOsd)); ++ if (data.UseSoftOsd) { ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD Rate"), &data.SoftOsdRate, 10, 100)); ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeIn Steps"), &data.SoftOsdFadeinSteps, 1, 100)); ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeOut Steps"), &data.SoftOsdFadeoutSteps, 1, 100)); ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$SoftOSD Palette Only"), &data.SoftOsdPaletteOnly)); ++ } ++#endif /* SOFTOSD */ + SetCurrent(Get(current)); + Display(); + } +@@ -2324,6 +3146,12 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + + int oldSkinIndex = skinIndex; + int oldOsdLanguageIndex = osdLanguageIndex; ++#ifdef USE_LIEMIEXT ++ int oldMainMenuTitle = data.MainMenuTitle; ++#endif /* LIEMIEXT */ ++#ifdef USE_SOFTOSD ++ bool newUseSoftOsd = data.UseSoftOsd; ++#endif /* SOFTOSD */ + eOSState state = cMenuSetupBase::ProcessKey(Key); + + if (ModifiedApperance) +@@ -2346,6 +3174,25 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + Set(); + I18nSetLanguage(OriginalOSDLanguage); + } ++ ++#ifdef USE_LIEMIEXT ++ if (data.MainMenuTitle != oldMainMenuTitle) ++ Set(); ++#endif /* LIEMIEXT */ ++#ifdef USE_SOFTOSD ++ if (data.UseSoftOsd != newUseSoftOsd) ++ Set(); ++#endif /* SOFTOSD */ ++#ifdef USE_CMDRECCMDI18N ++ if (Key == kOk) { ++ // try to load translated command files if available, otherwise fallback to defaults ++ LoadCommandsI18n(Commands, AddDirectory(ConfigDirectory, "commands.conf"), true); ++ LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory, "reccmds.conf"), true); ++#ifdef USE_TIMERCMD ++ LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true); ++#endif /* TIMERCMD */ ++ } ++#endif /* CMDRECCMDI18N */ + return state; + } + +@@ -2353,12 +3200,18 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + + class cMenuSetupEPG : public cMenuSetupBase { + private: ++#ifdef USE_NOEPG ++ const char *noEPGModes[2]; ++#endif /* NOEPG */ + int originalNumLanguages; + int numLanguages; + void Setup(void); + public: + cMenuSetupEPG(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupEpg"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupEPG::cMenuSetupEPG(void) +@@ -2375,11 +3228,19 @@ void cMenuSetupEPG::Setup(void) + { + int current = Current(); + ++#ifdef USE_NOEPG ++ noEPGModes[0] = tr("blacklist"); ++ noEPGModes[1] = tr("whitelist"); ++#endif /* NOEPG */ ++ + Clear(); + + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Show progress bar"), &data.ShowProgressBar)); ++#endif /* LIEMIEXT */ + Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); + if (data.SetSystemTime) + Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource)); +@@ -2388,6 +3249,15 @@ void cMenuSetupEPG::Setup(void) + for (int i = 0; i < numLanguages; i++) + // TRANSLATORS: note the singular! + Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); ++#ifdef USE_DDEPGENTRY ++ Add(new cMenuEditIntItem( tr("Setup.EPG$Period for double EPG search(min)"), &data.DoubleEpgTimeDelta)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Extern double Epg entry"), &data.DoubleEpgAction, tr("adjust"), tr("delete"))); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Mix intern and extern EPG"), &data.MixEpgAction)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Disable running VPS event"), &data.DisableVPS)); ++#endif /* DDEPGENTRY */ ++#ifdef USE_NOEPG ++ Add(new cMenuEditStraItem(tr("Setup.EPG$Mode of noEPG-Patch"), &data.noEPGMode, 2, noEPGModes)); ++#endif /* NOEPG */ + + SetCurrent(Get(current)); + Display(); +@@ -2444,6 +3314,10 @@ eOSState cMenuSetupEPG::ProcessKey(eKeys + + class cMenuSetupDVB : public cMenuSetupBase { + private: ++#ifdef USE_DVBSETUP ++ const char *ChannelBlockers[7]; ++ const char *ChannelBlockerModes[4]; ++#endif /* DVBSETUP */ + int originalNumAudioLanguages; + int numAudioLanguages; + int originalNumSubtitleLanguages; +@@ -2454,6 +3328,9 @@ private: + public: + cMenuSetupDVB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupDvb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupDVB::cMenuSetupDVB(void) +@@ -2482,6 +3359,21 @@ void cMenuSetupDVB::Setup(void) + { + int current = Current(); + ++#ifdef USE_DVBSETUP ++ ChannelBlockers[0] = tr("none"); ++ ChannelBlockers[1] = tr("qam256"); ++ ChannelBlockers[2] = tr("dvb-c"); ++ ChannelBlockers[3] = tr("dvb-s"); ++ ChannelBlockers[4] = tr("blacklist"); ++ ChannelBlockers[5] = tr("whitelist"); ++ ChannelBlockers[6] = tr("all"); ++ ++ ChannelBlockerModes[0] = tr("none"); ++ ChannelBlockerModes[1] = tr("has decoder"); ++ ChannelBlockerModes[2] = tr("is primary"); ++ ChannelBlockerModes[3] = tr("has decoder + is primary"); ++#endif /* DVBSETUP */ ++ + Clear(); + + Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices())); +@@ -2502,6 +3394,14 @@ void cMenuSetupDVB::Setup(void) + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9)); + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10)); + } ++#ifdef USE_DVBSETUP ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$Use AC3-Transfer Fix"), &data.DolbyTransferFix)); ++ Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker"), &data.ChannelBlocker, 7, ChannelBlockers)); ++ Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker Filter Mode"), &data.ChannelBlockerMode, 4, ChannelBlockerModes)); ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Sync Early Patch"), &data.UseSyncEarlyPatch)); ++#endif /* SYNCEARLY */ + + SetCurrent(Get(current)); + Display(); +@@ -2583,6 +3483,9 @@ private: + public: + cMenuSetupLNB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupLnb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupLNB::cMenuSetupLNB(void) +@@ -2597,6 +3500,23 @@ void cMenuSetupLNB::Setup(void) + + Clear(); + ++#ifdef USE_LNBSHARE ++ int numSatDevices = 0; ++ for (int i = 0; i < cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat)) numSatDevices++; ++ } ++ if (numSatDevices > 1) { ++ char tmp[30]; ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i - 1)->ProvidesSource(cSource::stSat)) { ++ sprintf( tmp, tr("Setup.LNB$DVB device %d uses LNB No."), i); ++ Add(new cMenuEditIntItem( tmp, &data.CardUsesLNBnr[i - 1], 1, numSatDevices )); ++ } ++ } ++ } ++ Add(new cMenuEditBoolItem(tr("Setup.LNB$Log LNB usage"), &data.VerboseLNBlog)); ++#endif /* LNBSHARE */ ++ + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); + if (!data.DiSEqC) { + Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); +@@ -2613,6 +3533,10 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys + int oldDiSEqC = data.DiSEqC; + eOSState state = cMenuSetupBase::ProcessKey(Key); + ++#ifdef USE_LNBSHARE ++ if (Key == kOk) cDevice::SetLNBnr(); ++#endif /* LNBSHARE */ ++ + if (Key != kNone && data.DiSEqC != oldDiSEqC) + Setup(); + return state; +@@ -2663,6 +3587,9 @@ private: + public: + cMenuSetupCAM(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupCAM::cMenuSetupCAM(void) +@@ -2736,12 +3663,73 @@ eOSState cMenuSetupCAM::ProcessKey(eKeys + // --- cMenuSetupRecord ------------------------------------------------------ + + class cMenuSetupRecord : public cMenuSetupBase { ++#ifdef USE_SORTRECORDS ++private: ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++#endif /* SORTRECORDS */ ++#ifdef USE_DELTIMESHIFTREC ++private: ++ const char *DelTimeshiftRecValues[3]; ++#endif /* DELTIMESHIFTREC */ + public: + cMenuSetupRecord(void); ++#ifdef USE_DVLVIDPREFER ++ eOSState ProcessKey(eKeys key); ++ ++private: ++ void Set(void); ++ ++ int tmpNVidPrefer, ++ tmpUseVidPrefer; ++#endif /* DVLVIDPREFER */ + }; + ++#ifdef USE_DVLVIDPREFER + cMenuSetupRecord::cMenuSetupRecord(void) + { ++ Set(); ++} ++ ++eOSState cMenuSetupRecord::ProcessKey(eKeys key) ++{ ++ eOSState s = cMenuSetupBase::ProcessKey(key);; ++ ++ if (key != kNone) { ++ if (tmpNVidPrefer != data.nVidPrefer || tmpUseVidPrefer != data.UseVidPrefer) { ++ int cur = Current(); ++ ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Clear(); ++ Set(); ++ SetCurrent(Get(cur)); ++ Display(); ++ cMenuSetupBase::ProcessKey(kNone); ++ return osContinue; ++ } ++ } ++ return s; ++} ++ ++#else ++cMenuSetupRecord::cMenuSetupRecord(void) ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLVIDPREFER ++void cMenuSetupRecord::Set(void) ++#endif /* DVLVIDPREFER */ ++{ ++#ifdef USE_SORTRECORDS ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ ++#ifdef USE_DELTIMESHIFTREC ++ DelTimeshiftRecValues[0] = tr("request"); ++ DelTimeshiftRecValues[1] = tr("no"); ++ DelTimeshiftRecValues[2] = tr("yes"); ++#endif /* DELTIMESHIFTREC */ + SetSection(tr("Recording")); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop)); +@@ -2750,14 +3738,61 @@ cMenuSetupRecord::cMenuSetupRecord(void) + Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME)); ++#ifdef USE_DOLBYINREC ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.UseDolbyInRecordings)); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVLVIDPREFER ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Video directory policy"), &data.UseVidPrefer)); ++ if (data.UseVidPrefer != 0) { ++ char tmp[ 64 ]; ++ Add(new cMenuEditIntItem(tr("Setup.Recording$Number of video directories"), &data.nVidPrefer, 1, DVLVIDPREFER_MAX)); ++ for (int zz = 0; zz < data.nVidPrefer; zz++) { ++ sprintf(tmp, tr("Setup.Recording$Video %d priority"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferPrio[ zz ], 0, 99)); ++ sprintf(tmp, tr("Setup.Recording$Video %d min. free MB"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferSize[ zz ], -1, 99999)); ++ } ++ } ++#endif /* DVLVIDPREFER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); ++#ifdef USE_DVLFRIENDLYFNAMES ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Friendly filenames"), &data.UseFriendlyFNames)); ++#endif /* DVLFRIENDLYFNAMES */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps)); + Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord))); + Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); ++#ifdef USE_HARDLINKCUTTER ++ Add(new cMenuEditIntItem( tr("Setup.Recording$Max. recording size (GB)"), &data.MaxRecordingSize, MINRECORDINGSIZE, MAXRECORDINGSIZE)); ++#endif /* HARDLINKCUTTER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); ++#ifdef USE_HARDLINKCUTTER ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Hard Link Cutter"), &data.HardLinkCutter)); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"), &data.DelTimeshiftRec, 3, DelTimeshiftRecValues)); ++#endif /* DELTIMESHIFTREC */ ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show date"), &data.ShowRecDate)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show time"), &data.ShowRecTime)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show length"), &data.ShowRecLength)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show end of timer"), &data.ShowTimerStop)); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ Add(new cMenuEditStraItem(tr("Setup.Recording$Sort recordings by"), &data.RecordingsSortMode, MAXSORTMODES, RecordingsSortModeTexts)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Sort directories before recordings"), &data.RecordingsSortDirsFirst)); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter auto delete"), &data.CutterAutoDelete)); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter adjust starttime"), &data.CutTime)); ++#endif /* CUTTIME */ + } + + // --- cMenuSetupReplay ------------------------------------------------------ +@@ -2775,6 +3810,31 @@ cMenuSetupReplay::cMenuSetupReplay(void) + Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); + Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99)); ++#ifdef USE_JUMPPLAY ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Jump&Play"), &data.JumpPlay)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Play&Jump"), &data.PlayJump)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause at last mark"), &data.PauseLastMark)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Reload marks"), &data.ReloadMarks)); ++#endif /* JUMPPLAY */ ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds"), &data.JumpSeconds)); ++ Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds Slow"), &data.JumpSecondsSlow)); ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++ static const char *dvddisplaymode[3]; ++ dvddisplaymode[0]=tr("Setup.Replay$Length"); ++ dvddisplaymode[1]=tr("Setup.Replay$Length / Number"); ++ dvddisplaymode[2]=tr("Setup.Replay$Number"); ++ Add(new cMenuEditStraItem(tr("Setup.Replay$DVD display mode"), &data.DvdDisplayMode,3,dvddisplaymode)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$DVD display leading zeros"), &data.DvdDisplayZeros)); ++ static const char *dvdtraymode[4]; ++ dvdtraymode[0]=tr("Setup.Replay$never"); ++ dvdtraymode[1]=tr("Setup.Replay$on begin"); ++ dvdtraymode[2]=tr("Setup.Replay$on end"); ++ dvdtraymode[3]=tr("Setup.Replay$on begin and end"); ++ Add(new cMenuEditStraItem(tr("Setup.Replay$Tray open"), &data.DvdTrayMode,4,dvdtraymode)); ++ Add(new cMenuEditIntItem( tr("Setup.Replay$Limit DVD to speed"), &data.DvdSpeedLimit, 0, 50)); ++#endif /* DVDARCHIVE */ + } + + void cMenuSetupReplay::Store(void) +@@ -2787,13 +3847,48 @@ void cMenuSetupReplay::Store(void) + // --- cMenuSetupMisc -------------------------------------------------------- + + class cMenuSetupMisc : public cMenuSetupBase { ++#ifdef USE_VOLCTRL ++private: ++ const char *lrChannelGroupsTexts[3]; ++ const char *lrForwardRewindTexts[3]; ++ void Setup(void); ++#endif /* VOLCTRL */ + public: + cMenuSetupMisc(void); ++#ifdef USE_VOLCTRL ++ virtual eOSState ProcessKey(eKeys Key); ++#endif /* VOLCTRL */ + }; + + cMenuSetupMisc::cMenuSetupMisc(void) + { ++#ifdef USE_VOLCTRL ++ lrChannelGroupsTexts[0] = tr("no"); ++ lrChannelGroupsTexts[1] = tr("Setup.Miscellaneous$only in channelinfo"); ++ lrChannelGroupsTexts[2] = tr("yes"); ++ lrForwardRewindTexts[0] = tr("no"); ++ lrForwardRewindTexts[1] = tr("Setup.Miscellaneous$only in progress display"); ++ lrForwardRewindTexts[2] = tr("yes"); ++#endif /* VOLCTRL */ + SetSection(tr("Miscellaneous")); ++#ifdef USE_VOLCTRL ++ Setup(); ++} ++ ++eOSState cMenuSetupMisc::ProcessKey(eKeys Key) ++{ ++ int newLRVolumeControl = data.LRVolumeControl; ++ eOSState state = cMenuSetupBase::ProcessKey(Key); ++ if (Key != kNone && data.LRVolumeControl != newLRVolumeControl) ++ Setup(); ++ return state; ++} ++ ++void cMenuSetupMisc::Setup(void) ++{ ++ int current = Current(); ++ Clear(); ++#endif /* VOLCTRL */ + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); +@@ -2801,9 +3896,77 @@ cMenuSetupMisc::cMenuSetupMisc(void) + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0)); + Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before"))); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before"))); ++#ifdef USE_VOLCTRL ++ Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Volume ctrl with left/right"), &data.LRVolumeControl)); ++ if (data.LRVolumeControl) { ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Channelgroups with left/right"), &data.LRChannelGroups, 3, lrChannelGroupsTexts)); ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Search fwd/back with left/right"), &data.LRForwardRewind, 3, lrForwardRewindTexts)); ++ } ++ SetCurrent(Get(current)); ++ Display(); ++#endif /* VOLCTRL */ + Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit)); ++#ifdef USE_LIRCSETTINGS ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat delay"), &data.LircRepeatDelay, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat freq"), &data.LircRepeatFreq, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat timeout"), &data.LircRepeatTimeout, 0, 5000)); ++#endif /* LIRCSETTINGS */ ++} ++ ++#ifdef USE_LIVEBUFFER ++// --- cMenuSetupLiveBuffer -------------------------------------------------- ++ ++class cMenuSetupLiveBuffer : public cMenuSetupBase { ++private: ++ void Setup(); ++public: ++ eOSState ProcessKey(eKeys Key); ++ cMenuSetupLiveBuffer(void); ++ }; ++ ++cMenuSetupLiveBuffer::cMenuSetupLiveBuffer(void) ++{ ++ SetSection("permanentes Timeshift"); ++ Setup(); + } + ++void cMenuSetupLiveBuffer::Setup(void) ++{ ++ int current=Current(); ++ Clear(); ++ Add(new cMenuEditBoolItem(tr("Permanent Timeshift"), &data.LiveBuffer)); ++ if (data.LiveBuffer) { ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Location"), &data.InRAM,tr("Setup.LiveBuffer$harddisk"),tr("Setup.LiveBuffer$memory"))); ++ if (data.InRAM) { ++ Add(new cMenuEditIntItem( tr("Setup.LiveBuffer$Buffer size in memory (MB)"), &data.MemBufSize, 5, 1000)); ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Extend to harddisk if necessary"), &data.ExtendBuffer)); ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Keep paused Buffer"), &data.KeepPaused)); ++ if (data.ExtendBuffer || data.KeepPaused) ++ Add(new cMenuEditIntItem(tr("Setup.LiveBuffer$Buffer size on harddisk (MB)"), &data.LiveBufferSize, 1, 100000)); ++ } ++ else { ++ Add(new cMenuEditIntItem( tr("Setup.LiveBuffer$Buffer size (MB)"), &data.LiveBufferSize, 1, 100000)); ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Keep paused Buffer"), &data.KeepPaused)); ++ } ++ } ++ SetCurrent(Get(current)); ++ Display(); ++} ++ ++eOSState cMenuSetupLiveBuffer::ProcessKey(eKeys Key) ++{ ++ int oldLiveBuffer = data.LiveBuffer; ++ int oldInRAM = data.InRAM; ++ int oldExtendBuffer = data.ExtendBuffer; ++ int oldKeepPaused = data.KeepPaused; ++ eOSState state = cMenuSetupBase::ProcessKey(Key); ++ ++ if (Key != kNone && (data.LiveBuffer != oldLiveBuffer || data.InRAM != oldInRAM || data.ExtendBuffer != oldExtendBuffer || data.KeepPaused != oldKeepPaused)) ++ Setup(); ++ return state; ++} ++ ++#endif /* LIVEBUFFER */ + // --- cMenuSetupPluginItem -------------------------------------------------- + + class cMenuSetupPluginItem : public cOsdItem { +@@ -2826,6 +3989,9 @@ class cMenuSetupPlugins : public cMenuSe + public: + cMenuSetupPlugins(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupPlugins"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupPlugins::cMenuSetupPlugins(void) +@@ -2875,6 +4041,9 @@ private: + public: + cMenuSetup(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetup"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetup::cMenuSetup(void) +@@ -2898,6 +4067,9 @@ void cMenuSetup::Set(void) + Add(new cOsdItem(hk(tr("Recording")), osUser6)); + Add(new cOsdItem(hk(tr("Replay")), osUser7)); + Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8)); ++#ifdef USE_LIVEBUFFER ++ Add(new cOsdItem(hk(tr("Permanent Timeshift")),osLiveBuffer)); ++#endif /* LIVEBUFFER */ + if (cPluginManager::HasPlugins()) + Add(new cOsdItem(hk(tr("Plugins")), osUser9)); + Add(new cOsdItem(hk(tr("Restart")), osUser10)); +@@ -2928,6 +4100,9 @@ eOSState cMenuSetup::ProcessKey(eKeys Ke + case osUser8: return AddSubMenu(new cMenuSetupMisc); + case osUser9: return AddSubMenu(new cMenuSetupPlugins); + case osUser10: return Restart(); ++#ifdef USE_LIVEBUFFER ++ case osLiveBuffer: return AddSubMenu(new cMenuSetupLiveBuffer); ++#endif /* LIVEBUFFER */ + default: ; + } + if (I18nCurrentLanguage() != osdLanguage) { +@@ -2964,24 +4139,91 @@ cOsdObject *cMenuMain::pluginOsdObject = + cMenuMain::cMenuMain(eOSState State) + :cOsdMenu("") + { ++#ifdef USE_SETUP ++ // Load Menu Configuration ++ char *menuXML = NULL; ++ asprintf(&menuXML, "%s/setup/vdr-menu.%s.xml", cPlugin::ConfigDirectory(), Setup.OSDLanguage); ++ if (access(menuXML, 04) == -1) ++ asprintf(&menuXML, "%s/setup/vdr-menu.xml", cPlugin::ConfigDirectory()); ++ subMenu.LoadXml(menuXML); ++ free(menuXML); ++ nrDynamicMenuEntries=0; ++#endif /* SETUP */ + replaying = false; + stopReplayItem = NULL; + cancelEditingItem = NULL; + stopRecordingItem = NULL; + recordControlsState = 0; ++ ++#ifdef USE_MENUORG ++ MenuOrgPatch::EnterRootMenu(); ++#endif /* MENUORG */ ++ + Set(); + + // Initial submenus: + ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ + switch (State) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuSchedule; ++ } ++ break; ++ case osChannels: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuChannels; ++ } ++ break; ++ case osTimers: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuTimers; ++ } ++ break; ++ case osRecordings: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuRecordings(NULL, 0, true); ++ } ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: AddSubMenu(new cMenuSchedule); break; + case osChannels: AddSubMenu(new cMenuChannels); break; + case osTimers: AddSubMenu(new cMenuTimers); break; + case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; + case osSetup: AddSubMenu(new cMenuSetup); break; + case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break; ++#endif /* MAINMENUHOOKS */ + default: break; + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + } + + cOsdObject *cMenuMain::PluginOsdObject(void) +@@ -2991,38 +4233,155 @@ cOsdObject *cMenuMain::PluginOsdObject(v + return o; + } + ++#ifdef USE_SETUP ++void cMenuMain::Set(int current) ++#else + void cMenuMain::Set(void) ++#endif /* SETUP */ + { + Clear(); + SetTitle("VDR"); + SetHasHotkeys(); + ++#ifdef USE_MENUORG ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuItemDefinitions* menuItems = MenuOrgPatch::MainMenuItems(); ++ for (MenuItemDefinitions::iterator i = menuItems->begin(); i != menuItems->end(); i++) { ++ cOsdItem* osdItem = NULL; ++ if ((*i)->IsCustomOsdItem()) { ++ osdItem = (*i)->CustomOsdItem(); ++ if (osdItem && !(*i)->IsSeparatorItem()) ++ osdItem->SetText(hk(osdItem->Text())); ++ } ++ else if ((*i)->IsPluginItem()) { ++ const char *item = (*i)->PluginMenuEntry(); ++ if (item) ++ osdItem = new cMenuPluginItem(hk(item), (*i)->PluginIndex()); ++ } ++ if (osdItem) { ++ Add(osdItem); ++ if ((*i)->IsSelected()) ++ SetCurrent(osdItem); ++ } ++ } ++ } ++ else { ++#endif /* MENUORG */ ++ ++#ifdef USE_SETUP ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ ++ // remember initial dynamic MenuEntries added ++ nrDynamicMenuEntries = Count(); ++ for (cSubMenuNode *node = subMenu.GetMenuTree()->First(); node; node = subMenu.GetMenuTree()->Next(node)) { ++ cSubMenuNode::Type type = node->GetType(); ++ if (type==cSubMenuNode::PLUGIN) { ++ const char *item = node->GetPluginMainMenuEntry(); ++#ifdef USE_PINPLUGIN ++ if (item && !cStatus::MsgPluginProtected(cPluginManager::GetPlugin(node->GetPluginIndex()), true)) ++#else ++ if (item) ++#endif /* PINPLUGIN */ ++ Add(new cMenuPluginItem(hk(item), node->GetPluginIndex())); ++ } ++ else if (type==cSubMenuNode::MENU) { ++ cString item = cString::sprintf("%s%s", node->GetName(), subMenu.GetMenuSuffix()); ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(item, true)) ++ Add(new cOsdItem(hk(item), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(item))); ++#endif /* PINPLUGIN */ ++ } ++ else if ((type==cSubMenuNode::COMMAND) || (type==cSubMenuNode::THREAD)) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(node->GetName(), true)) ++ Add(new cOsdItem(hk(node->GetName()), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(node->GetName()))); ++#endif /* PINPLUGIN */ ++ } ++ else if (type==cSubMenuNode::SYSTEM) { ++ const char *item = node->GetName(); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgMenuItemProtected(item, true)) ++ ; // nothing to do ;) ++ else ++#endif /* PINPLUGIN */ ++ if (strcmp(item, "Schedule") == 0) ++ Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ else if (strcmp(item, "Channels") == 0) ++ Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ else if (strcmp(item, "Timers") == 0) ++ Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ else if (strcmp(item, "Recordings") == 0) ++ Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++ else if (strcmp(item, "Setup") == 0) ++ Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++ else if (strcmp(item, "Commands") == 0 && Commands.Count()>0) ++ Add(new cOsdItem(hk(tr("Commands")), osCommands)); ++ } ++ } ++ if (current >=0 && current<Count()) { ++ SetCurrent(Get(current)); ++ } ++ ++#else /* NO SETUP */ ++ + // Basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Schedule", true)) Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ if (!cStatus::MsgMenuItemProtected("Channels", true)) Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ if (!cStatus::MsgMenuItemProtected("Timers", true)) Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ if (!cStatus::MsgMenuItemProtected("Recordings", true)) Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#else + Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); + Add(new cOsdItem(hk(tr("Channels")), osChannels)); + Add(new cOsdItem(hk(tr("Timers")), osTimers)); + Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#endif /* PINPLUGIN */ + + // Plugins: + + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p, true)) { ++#endif /* PINPLUGIN */ + const char *item = p->MainMenuEntry(); + if (item) + Add(new cMenuPluginItem(hk(item), i)); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + break; + } + + // More basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Setup", true)) Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#else + Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#endif /* PINPLUGIN */ + if (Commands.Count()) ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Commands", true)) ++#endif /* PINPLUGIN */ + Add(new cOsdItem(hk(tr("Commands")), osCommands)); + ++#endif /* SETUP */ ++ ++#ifdef USE_MENUORG ++ } ++#endif /* MENUORG */ ++ + Update(true); + + Display(); +@@ -3032,12 +4391,40 @@ bool cMenuMain::Update(bool Force) + { + bool result = false; + ++#ifdef USE_SETUP ++ cOsdItem *fMenu = NULL; ++ if (Force && subMenu.isTopMenu()) { ++ fMenu = First(); ++ nrDynamicMenuEntries = 0; ++ } ++ ++ if (subMenu.isTopMenu()) { ++#endif /* SETUP */ ++#ifdef USE_LIEMIEXT ++// this extension is not included in the original Liemikuutio ++ if (Setup.MainMenuTitle) { ++ if (Setup.MainMenuTitle == 1) ++ SetTitle(cString::sprintf("%s - %s", tr("VDR"), Setup.CustomMainMenuTitle)); ++ else if (Setup.MainMenuTitle == 2) ++ SetTitle(cString::sprintf("%s", Setup.CustomMainMenuTitle)); ++ else if (Setup.MainMenuTitle == 3) ++ SetTitle(cString::sprintf("%s %s", tr("VDR"), VDRVERSION)); ++ } ++ else ++#endif /* LIEMIEXT */ + // Title with disk usage: + if (FreeDiskSpace.HasChanged(Force)) { + //XXX -> skin function!!! + SetTitle(cString::sprintf("%s - %s", tr("VDR"), FreeDiskSpace.FreeDiskSpaceString())); + result = true; + } ++#ifdef USE_SETUP ++ } ++ else { ++ SetTitle(cString::sprintf("%s - %s", tr("VDR"), subMenu.GetParentMenuTitel())); ++ result = true; ++ } ++#endif /* SETUP */ + + bool NewReplaying = cControl::Control() != NULL; + if (Force || NewReplaying != replaying) { +@@ -3045,6 +4432,9 @@ bool cMenuMain::Update(bool Force) + // Replay control: + if (replaying && !stopReplayItem) + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); else ++#endif /* LIEMIEXT */ + Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); + else if (stopReplayItem && !replaying) { + Del(stopReplayItem->Index()); +@@ -3059,6 +4449,9 @@ bool cMenuMain::Update(bool Force) + bool CutterActive = cCutter::Active(); + if (CutterActive && !cancelEditingItem) { + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); else ++#endif /* LIEMIEXT */ + Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); + result = true; + } +@@ -3079,6 +4472,9 @@ bool cMenuMain::Update(bool Force) + while ((s = cRecordControls::GetInstantId(s)) != NULL) { + cOsdItem *item = new cOsdItem(osStopRecord); + item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s)); ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(item); else ++#endif /* LIEMIEXT */ + Add(item); + if (!stopRecordingItem) + stopRecordingItem = item; +@@ -3086,6 +4482,12 @@ bool cMenuMain::Update(bool Force) + result = true; + } + ++#ifdef USE_SETUP ++ // adjust nrDynamicMenuEntries ++ if (fMenu != NULL) ++ nrDynamicMenuEntries = fMenu->Index(); ++#endif /* SETUP */ ++ + return result; + } + +@@ -3096,13 +4498,69 @@ eOSState cMenuMain::ProcessKey(eKeys Key + eOSState state = cOsdMenu::ProcessKey(Key); + HadSubMenu |= HasSubMenu(); + ++#ifdef USE_PINPLUGIN ++ cOsdItem* item = Get(Current()); ++ ++ if (item && item->Text() && state != osBack && state != osContinue && Key != kNone) ++ if (cStatus::MsgMenuItemProtected(item->Text())) ++ return osContinue; ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ + switch (state) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuSchedule; ++ } ++ break; ++ case osChannels: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuChannels; ++ } ++ break; ++ case osTimers: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuTimers; ++ } ++ break; ++ case osRecordings: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuRecordings; ++ } ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: return AddSubMenu(new cMenuSchedule); + case osChannels: return AddSubMenu(new cMenuChannels); + case osTimers: return AddSubMenu(new cMenuTimers); + case osRecordings: return AddSubMenu(new cMenuRecordings); + case osSetup: return AddSubMenu(new cMenuSetup); + case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); ++#endif /* MAINMENUHOOKS */ + case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { + cOsdItem *item = Get(Current()); + if (item) { +@@ -3121,6 +4579,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key + if (item) { + cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p)) { ++#endif /* PINPLUGIN */ + cOsdObject *menu = p->MainMenuAction(); + if (menu) { + if (menu->IsMenu()) +@@ -3132,9 +4593,60 @@ eOSState cMenuMain::ProcessKey(eKeys Key + } + } + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + state = osEnd; + } + break; ++#ifdef USE_SETUP ++ case osBack: { ++ int newCurrent = 0; ++ if (subMenu.Up(&newCurrent)) { ++ Set(newCurrent); ++ return osContinue; ++ } ++ else ++ return osEnd; ++ } ++ break; ++#endif /* SETUP */ ++#ifdef USE_MENUORG ++ case osBack: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ bool leavingMenuSucceeded = MenuOrgPatch::LeaveSubMenu(); ++ Set(); ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ recordControlsState = 0; ++ Update(true); ++ Display(); ++ if (leavingMenuSucceeded) ++ return osContinue; ++ else ++ return osEnd; ++ } ++ } ++ break; ++ case osUser1: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuOrgPatch::EnterSubMenu(Get(Current())); ++ Set(); ++ return osContinue; ++ } ++ } ++ break; ++ case osUser2: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ cOsdMenu* osdMenu = MenuOrgPatch::Execute(Get(Current())); ++ if (osdMenu) ++ return AddSubMenu(osdMenu); ++ return osEnd; ++ } ++ } ++ break; ++#endif /* MENUORG */ + default: switch (Key) { + case kRecord: + case kRed: if (!HadSubMenu) +@@ -3151,9 +4663,67 @@ eOSState cMenuMain::ProcessKey(eKeys Key + case kBlue: if (!HadSubMenu) + state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue; + break; ++#ifdef USE_SETUP ++ case kOk: if (state == osUnknown) { ++ cString buffer; ++#ifdef USE_PINPLUGIN ++ cSubMenuNode *node = Get(Current())->SubMenu(); ++#else ++ int index = Current()-nrDynamicMenuEntries; ++ cSubMenuNode *node = subMenu.GetNode(index); ++#endif /* PINPLUGIN */ ++ ++ if (node != NULL) { ++ if (node->GetType() == cSubMenuNode::MENU) { ++#ifdef USE_PINPLUGIN ++ subMenu.Down(node, Current()); ++#else ++ subMenu.Down(index); ++#endif /* PINPLUGIN */ ++ } ++ else if (node->GetType() == cSubMenuNode::COMMAND) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ const char *Result = subMenu.ExecuteCommand(node->GetCommand()); ++ if (Result) ++ return AddSubMenu(new cMenuText(node->GetName(), Result, fontFix)); ++ return osEnd; ++ } ++ } ++ else if (node->GetType() == cSubMenuNode::THREAD) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ buffer = cString::sprintf("%s", node->GetCommand()); ++ cExecCmdThread *execcmd = new cExecCmdThread(node->GetCommand()); ++ if (execcmd->Start()) ++ dsyslog("executing command '%s'", *buffer); ++ else ++ esyslog("ERROR: can't execute command '%s'", *buffer); ++ return osEnd; ++ } ++ } ++ } ++ ++ Set(); ++ return osContinue; ++ } ++ break; ++#endif /* SETUP */ + default: break; + } + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ return AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + if (!HasSubMenu() && Update(HadSubMenu)) + Display(); + if (Key != kNone) { +@@ -3297,7 +4867,14 @@ cChannel *cDisplayChannel::NextAvailable + if (Direction) { + while (Channel) { + Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, Channel) == false) ++#endif /* PINPLUGIN */ ++#ifdef USE_LNBSHARE ++ if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true) && cDevice::PrimaryDevice()->GetMaxBadPriority(Channel) < 0) ++#else + if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true)) ++#endif /* LNBSHARE */ + return Channel; + } + } +@@ -3355,6 +4932,13 @@ eOSState cDisplayChannel::ProcessKey(eKe + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && !Setup.LRChannelGroups) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kNext|k_Repeat: + case kNext: + case kPrev|k_Repeat: +@@ -3514,6 +5098,17 @@ void cDisplayVolume::Process(eKeys Key) + eOSState cDisplayVolume::ProcessKey(eKeys Key) + { + switch (Key) { ++#ifdef USE_VOLCTRL ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ if (Setup.LRVolumeControl) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: +@@ -3763,6 +5358,10 @@ eOSState cDisplaySubtitleTracks::Process + + cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) + { ++#ifdef USE_DVLRECSCRIPTADDON ++ const cChannel *recChan = NULL; ++ char *chanName = NULL; ++#endif /* DVLRECSCRIPTADDON */ + // We're going to manipulate an event here, so we need to prevent + // others from modifying any EPG data: + cSchedulesLock SchedulesLock; +@@ -3807,12 +5406,57 @@ cRecordControl::cRecordControl(cDevice * + return; + } + ++#ifdef USE_DVLRECSCRIPTADDON ++ if (timer) ++ if ((recChan = timer->Channel()) != NULL) ++ chanName = strdup(recChan->Name()); ++ if (chanName != NULL) { ++ cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName, chanName); ++ free(chanName); ++ } ++ else ++#endif /* DVLRECSCRIPTADDON */ + cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); + isyslog("record %s", fileName); + if (MakeDirs(fileName, true)) { + const cChannel *ch = timer->Channel(); ++#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) ++#ifdef USE_LIVEBUFFER ++ int startFrame=-1; ++ int endFrame=0; ++ cLiveBuffer *liveBuffer = cLiveBufferManager::InLiveBuffer(timer, &startFrame, &endFrame); ++ if (liveBuffer) { ++ timer->SetFlags(tfhasLiveBuf); ++ liveBuffer->SetStartFrame(startFrame); ++ if (endFrame) { ++ liveBuffer->CreateIndexFile(fileName, 0, endFrame); ++ Timers.Del(timer); ++ Timers.SetModified(); ++ timer = NULL; ++ Recording.WriteInfo(); ++ Recordings.AddByName(fileName); ++ return; ++ } ++ } ++#endif /* LIVEBUFFER */ ++#ifdef USE_TTXTSUBS ++ cTtxtSubsRecorderBase *subsRecorder = cVDRTtxtsubsHookListener::Hook()->NewTtxtSubsRecorder(device, ch); ++#endif /* TTXTSUBS */ ++ recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids() ++#ifdef USE_TTXTSUBS ++ ,subsRecorder ++#endif /* TTXTSUBS */ ++#ifdef USE_LIVEBUFFER ++ ,liveBuffer ++#endif /* LIVEBUFFER */ ++ ); ++#else + recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids()); ++#endif /* LIVEBUFFER || TTXTSUBS */ + if (device->AttachReceiver(recorder)) { ++#ifdef USE_TTXTSUBS ++ if (subsRecorder) subsRecorder->DeviceAttach(); ++#endif /* TTXTSUBS */ + Recording.WriteInfo(); + cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true); + if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo() +@@ -3869,11 +5513,25 @@ bool cRecordControl::GetEvent(void) + void cRecordControl::Stop(void) + { + if (timer) { ++#ifdef USE_DVLRECSCRIPTADDON ++ char *chanName = NULL; ++ const cChannel *recChan = NULL; ++ ++ recChan = timer -> Channel(); ++ if (recChan != NULL) ++ chanName = strdup(recChan -> Name()); ++#endif /* DVLRECSCRIPTADDON */ + DELETENULL(recorder); + timer->SetRecording(false); + timer = NULL; + cStatus::MsgRecording(device, NULL, fileName, false); ++#ifdef USE_DVLRECSCRIPTADDON ++ cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName, chanName); ++ if (chanName != NULL) ++ free(chanName); ++#else + cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); ++#endif /* DVLRECSCRIPTADDON */ + } + } + +@@ -3920,15 +5578,35 @@ bool cRecordControls::Start(cTimer *Time + int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority; + cDevice *device = cDevice::GetDevice(channel, Priority, false); + if (device) { ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ while ((tmpDevice = device->GetBadDevice(channel))) { ++ if (tmpDevice->Replaying() == false) { ++// Stop(tmpDevice); ++ if (tmpDevice->IsPrimaryDevice() ) ++ tmpDevice->SwitchChannelForced(channel, true); ++ else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } ++#endif /* LNBSHARE */ + dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number()); + if (!device->SwitchChannel(channel, false)) { + ShutdownHandler.RequestEmergencyExit(); + return false; + } ++#ifdef USE_LIVEBUFFER ++ if (!Timer || Timer->Matches() || cLiveBufferManager::InLiveBuffer(Timer)) { ++#else + if (!Timer || Timer->Matches()) { ++#endif /* LIVEBUFFER */ + for (int i = 0; i < MAXRECORDCONTROLS; i++) { + if (!RecordControls[i]) { + RecordControls[i] = new cRecordControl(device, Timer, Pause); ++#ifdef USE_PINPLUGIN ++ cStatus::MsgRecordingFile(RecordControls[i]->FileName()); ++#endif /* PINPLUGIN */ + return RecordControls[i]->Process(time(NULL)); + } + } +@@ -4059,12 +5737,22 @@ bool cRecordControls::StateChanged(int & + + // --- cReplayControl -------------------------------------------------------- + ++#ifdef USE_LIEMIEXT ++#define REPLAYCONTROLSKIPLIMIT 9 // s ++#define REPLAYCONTROLSKIPSECONDS 90 // s ++#define REPLAYCONTROLSKIPTIMEOUT 5000 // ms ++#endif /* LIEMIEXT */ ++ + cReplayControl *cReplayControl::currentReplayControl = NULL; + char *cReplayControl::fileName = NULL; + char *cReplayControl::title = NULL; + + cReplayControl::cReplayControl(void) ++#ifdef USE_JUMPPLAY ++:cDvbPlayerControl(fileName), marks(fileName) ++#else + :cDvbPlayerControl(fileName) ++#endif /* JUMPPLAY */ + { + currentReplayControl = this; + displayReplay = NULL; +@@ -4072,10 +5760,28 @@ cReplayControl::cReplayControl(void) + lastCurrent = lastTotal = -1; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value ++#ifdef USE_LIEMIEXT ++ lastSkipKey = kNone; ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipTimeout.Set(0); ++#endif /* LIEMIEXT */ + timeoutShow = 0; + timeSearchActive = false; ++#ifndef USE_JUMPPLAY + marks.Load(fileName); ++#endif /* JUMPPLAY */ + cRecording Recording(fileName); ++#ifdef USE_DVDARCHIVE ++ canJumpChapters = (Recording.GetDvdType() == DVD_VIDEO_ARCHIVE_TYPE); ++ dvdchapters = NULL; ++ if (canJumpChapters) { ++ const char *ret = Recording.GetDvdChapters(); ++ if (ret) ++ dvdchapters = strdup(ret); ++ else ++ canJumpChapters=false; ++ } ++#endif /* DVDARCHIVE */ + cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true); + SetTrackDescriptions(false); + } +@@ -4083,12 +5789,67 @@ cReplayControl::cReplayControl(void) + cReplayControl::~cReplayControl() + { + Hide(); ++#ifdef USE_DVDARCHIVE ++ free(dvdchapters); ++#endif /* DVDARCHIVE */ + cStatus::MsgReplaying(this, NULL, fileName, false); + Stop(); + if (currentReplayControl == this) + currentReplayControl = NULL; + } + ++#ifdef USE_DELTIMESHIFTREC ++void cReplayControl::Stop(void) ++{ ++ int dummy; ++ bool playing = GetIndex(dummy, dummy, false); ++ cRecordControl* rc = cRecordControls::GetRecordControl(fileName); ++ ++ if (playing && rc && rc->InstantId()) { ++ isyslog("found Timeshiftrecording"); ++ ++ if ((Setup.DelTimeshiftRec != 0 ) || (Interface->Confirm(tr("Delete recording?")))) { ++ cRecordControl *rc = cRecordControls::GetRecordControl(fileName); ++ if (rc) { ++ cTimer *timer = rc->Timer(); ++ if (timer) { ++ const char* reccmd_backup = cRecordingUserCommand::GetCommand(); ++ cRecordingUserCommand::SetCommand(NULL); ++ ++ timer->Skip(); ++ cRecordControls::Process(time(NULL)); ++ if (timer->IsSingleEvent()) { ++ isyslog("deleting timer %s", *timer->ToDescr()); ++ Timers.Del(timer); ++ } ++ Timers.SetModified(); ++ ++ // restore reccmd ++ cRecordingUserCommand::SetCommand(reccmd_backup); ++ } ++ } ++ isyslog("stop replaying %s", fileName); ++ cDvbPlayerControl::Stop(); ++ ++ if (Setup.DelTimeshiftRec != 1) { ++ cRecording *recording = Recordings.GetByName(fileName);; ++ if (recording) { ++ if (recording->Delete()) { ++ Recordings.DelByName(fileName); ++ ClearLastReplayed(fileName); ++ return; ++ } ++ else ++ Skins.Message(mtError, tr("Error while deleting recording!")); ++ } ++ } ++ } ++ else ++ cDvbPlayerControl::Stop(); ++ } ++} ++#endif /* DELTIMESHIFTREC */ ++ + void cReplayControl::SetRecording(const char *FileName, const char *Title) + { + free(fileName); +@@ -4183,6 +5944,9 @@ bool cReplayControl::ShowProgress(bool I + if (Initial) { + if (title) + displayReplay->SetTitle(title); ++#ifdef USE_OSDMAXITEMS ++ displayReplay->SetButtons(tr("Jump"), tr("Skip +60s"), tr("Skip -60s"), tr("Button$Stop")); ++#endif /* OSDMAXITEMS */ + lastCurrent = lastTotal = -1; + } + if (Total != lastTotal) { +@@ -4304,8 +6068,15 @@ void cReplayControl::MarkToggle(void) + ShowTimed(2); + bool Play, Forward; + int Speed; ++#ifdef USE_JUMPPLAY ++ if (GetReplayMode(Play, Forward, Speed) && !Play) { ++ Goto(Current, true); ++ displayFrames = true; ++ } ++#else + if (GetReplayMode(Play, Forward, Speed) && !Play) + Goto(Current, true); ++#endif /* JUMPPLAY */ + } + marks.Save(); + } +@@ -4318,8 +6089,22 @@ void cReplayControl::MarkJump(bool Forwa + if (GetIndex(Current, Total)) { + cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ bool Play2, Forward2; ++ int Speed; ++ if (Setup.JumpPlay && GetReplayMode(Play2, Forward2, Speed) && ++ Play2 && Forward && m->position < Total - SecondsToFrames(3)) { ++ Goto(m->position); ++ Play(); ++ } ++ else { ++ Goto(m->position, true); ++ displayFrames = true; ++ } ++#else + Goto(m->position, true); + displayFrames = true; ++#endif /* JUMPPLAY */ + } + } + } +@@ -4348,11 +6133,43 @@ void cReplayControl::MarkMove(bool Forwa + } + } + ++#ifdef USE_DVDARCHIVE ++void cReplayControl::ChaptersJump(bool Forward) ++{ ++ int Current, Total; ++ if (GetIndex(Current, Total)) { ++ int position = -1; ++ char *buf, *pos; ++ cString old1("-1"); ++ cString old2("-1"); ++ buf = strdup(dvdchapters); ++ pos = strtok(buf, ","); ++ while (pos != NULL && position == -1) { ++ if (pos && atoi(pos) > Current) ++ position = Forward ? atoi(pos) : ((Current - atoi(old1)) <= (3*FRAMESPERSEC)) ? atoi(old2) : atoi(old1); ++ old2 = old1; ++ old1 = strdup(pos); ++ if(position == -1) pos = strtok(NULL, ","); ++ } ++ if (!pos && !Forward) ++ position = ((Current - atoi(old1)) <= (3*FRAMESPERSEC)) ? atoi(old2) : atoi(old1); ++ if (position >= 0) { ++ Goto(position); ++ Play(); ++ } ++ } ++} ++ ++#endif /* DVDARCHIVE */ + void cReplayControl::EditCut(void) + { + if (fileName) { + Hide(); ++#ifdef USE_CUTTERQUEUE ++ if (!cCutter::Active() || Interface->Confirm(tr("Cutter already running - Add to cutting queue?"))) { ++#else + if (!cCutter::Active()) { ++#endif /* CUTTERQUEUE */ + if (!marks.Count()) + Skins.Message(mtError, tr("No editing marks defined!")); + else if (!cCutter::Start(fileName)) +@@ -4374,7 +6191,11 @@ void cReplayControl::EditTest(void) + if (!m) + m = marks.GetNext(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ if ((m->Index() & 0x01) != 0 && !Setup.PlayJump) ++#else + if ((m->Index() & 0x01) != 0) ++#endif /* JUMPPLAY */ + m = marks.Next(m); + if (m) { + Goto(m->position - SecondsToFrames(3)); +@@ -4396,6 +6217,9 @@ eOSState cReplayControl::ProcessKey(eKey + { + if (!Active()) + return osEnd; ++#ifdef USE_JUMPPLAY ++ marks.Reload(); ++#endif /* JUMPPLAY */ + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); +@@ -4413,7 +6237,32 @@ eOSState cReplayControl::ProcessKey(eKey + TimeSearchProcess(Key); + return osContinue; + } ++#ifdef USE_DVDARCHIVE ++ bool isOnMark = false; ++ if (canJumpChapters) { ++ int Current, Total; ++ GetIndex(Current, Total); ++ cMark *m = marks.Get(Current); ++ if (m && (m->position == Current)) isOnMark = true; ++ } ++#endif /* DVDARCHIVE */ + bool DoShowMode = true; ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && (!Setup.LRForwardRewind || (Setup.LRForwardRewind == 1 && !visible))) { ++ switch (Key) { ++ // Left/Right volume control ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ return osContinue; ++ break; ++ default: ++ break; ++ } ++ } ++#endif /* VOLCTRL */ + switch (Key) { + // Positioning: + case kPlay: +@@ -4431,25 +6280,82 @@ eOSState cReplayControl::ProcessKey(eKey + case kFastFwd: + case kRight: Forward(); break; + case kRed: TimeSearch(); break; ++#ifdef USE_LIEMIEXT ++ case kGreen|k_Repeat: ++ case kGreen: SkipSeconds(-Setup.JumpSeconds); break; ++ case kYellow|k_Repeat: ++ case kYellow: SkipSeconds( Setup.JumpSeconds); break; ++ case k1|k_Repeat: ++ case k1: SkipSeconds(-Setup.JumpSecondsSlow); break; ++ case k3|k_Repeat: ++ case k3: SkipSeconds( Setup.JumpSecondsSlow); break; ++ case kPrev|k_Repeat: ++ case kPrev: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kPrev; ++ } ++ else if (RAWKEY(lastSkipKey) != kPrev && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(-lastSkipSeconds); break; ++ case kNext|k_Repeat: ++ case kNext: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kNext; ++ } ++ else if (RAWKEY(lastSkipKey) != kNext && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(lastSkipSeconds); break; ++#else + case kGreen|k_Repeat: + case kGreen: SkipSeconds(-60); break; + case kYellow|k_Repeat: + case kYellow: SkipSeconds( 60); break; ++#endif /* LIEMIEXT */ + case kStop: + case kBlue: Hide(); + Stop(); + return osEnd; ++#ifdef USE_DVDARCHIVE ++ case kDvdChapterJumpForward|k_Repeat: ++ case kDvdChapterJumpForward: if (canJumpChapters && !isOnMark) { ++ ChaptersJump(true); ++ } ++ else { ++ DoShowMode = false; ++ MarkMove(true); ++ } ++ break; ++ case kDvdChapterJumpBack|k_Repeat: ++ case kDvdChapterJumpBack: if (canJumpChapters && !isOnMark) { ++ ChaptersJump(false); ++ } ++ else { ++ DoShowMode = false; ++ MarkMove(false); ++ } ++ break; ++#endif /* DVDARCHIVE */ + default: { + DoShowMode = false; + switch (Key) { + // Editing: + case kMarkToggle: MarkToggle(); break; ++#ifndef USE_LIEMIEXT + case kPrev|k_Repeat: + case kPrev: ++#endif /* LIEMIEXT */ + case kMarkJumpBack|k_Repeat: + case kMarkJumpBack: MarkJump(false); break; ++#ifndef USE_LIEMIEXT + case kNext|k_Repeat: + case kNext: ++#endif /* LIEMIEXT */ + case kMarkJumpForward|k_Repeat: + case kMarkJumpForward: MarkJump(true); break; + case kMarkMoveBack|k_Repeat: +@@ -4469,7 +6375,16 @@ eOSState cReplayControl::ProcessKey(eKey + else + Show(); + break; ++#ifdef USE_DELTIMESHIFTREC ++ case kBack: { cRecordControl* rc = cRecordControls::GetRecordControl(fileName); ++ if (rc && rc->InstantId()) ++ return osEnd; ++ else ++ return osRecordings; ++ } ++#else + case kBack: return osRecordings; ++#endif /* DELTIMESHIFTREC */ + default: return osUnknown; + } + } +diff -ruNp vdr-1.6.0-2/menu.h vdr-1.6.0-2-extensions/menu.h +--- vdr-1.6.0-2/menu.h 2008-02-10 17:01:53.000000000 +0100 ++++ vdr-1.6.0-2-extensions/menu.h 2009-04-09 20:48:26.000000000 +0200 +@@ -18,6 +18,9 @@ + #include "menuitems.h" + #include "recorder.h" + #include "skins.h" ++#ifdef USE_SETUP ++#include "submenu.h" ++#endif /* SETUP */ + + class cMenuText : public cOsdMenu { + private: +@@ -29,12 +32,19 @@ public: + void SetText(const char *Text); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuText"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuEditTimer : public cOsdMenu { + private: + cTimer *timer; + cTimer data; ++#ifdef USE_LIEMIEXT ++ char name[MaxFileName]; ++ char path[MaxFileName]; ++#endif /* LIEMIEXT */ + int channel; + bool addIfConfirmed; + cMenuEditDateItem *firstday; +@@ -43,6 +53,9 @@ public: + cMenuEditTimer(cTimer *Timer, bool New = false); + virtual ~cMenuEditTimer(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuTimerEdit"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuEvent : public cOsdMenu { +@@ -52,22 +65,37 @@ public: + cMenuEvent(const cEvent *Event, bool CanSwitch = false, bool Buttons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEvent"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuMain : public cOsdMenu { + private: ++#ifdef USE_SETUP ++ int nrDynamicMenuEntries; ++#endif /* SETUP */ + bool replaying; + cOsdItem *stopReplayItem; + cOsdItem *cancelEditingItem; + cOsdItem *stopRecordingItem; + int recordControlsState; + static cOsdObject *pluginOsdObject; ++#ifdef USE_SETUP ++ void Set(int current=0); ++ bool Update(bool Force = false); ++ cSubMenu subMenu; ++#else + void Set(void); + bool Update(bool Force = false); ++#endif /* SETUP */ + public: + cMenuMain(eOSState State = osUnknown); + virtual eOSState ProcessKey(eKeys Key); + static cOsdObject *PluginOsdObject(void); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuMain"; } ++#endif /* GRAPHTFT */ + }; + + class cDisplayChannel : public cOsdObject { +@@ -163,12 +191,18 @@ private: + eOSState Delete(void); + eOSState Info(void); + eOSState Commands(eKeys Key = kNone); ++#ifdef USE_LIEMIEXT ++ eOSState Rename(void); ++#endif /* LIEMIEXT */ + protected: + cRecording *GetRecording(cMenuRecordingItem *Item); + public: + cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false); + ~cMenuRecordings(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRecordings"; } ++#endif /* GRAPHTFT */ + }; + + class cRecordControl { +@@ -212,11 +246,21 @@ public: + class cReplayControl : public cDvbPlayerControl { + private: + cSkinDisplayReplay *displayReplay; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#else + cMarks marks; ++#endif /* JUMPPLAY */ + bool visible, modeOnly, shown, displayFrames; + int lastCurrent, lastTotal; + bool lastPlay, lastForward; + int lastSpeed; ++#ifdef USE_LIEMIEXT ++ int lastSkipSeconds; ++ int lastSkipSecondsSlow; ++ eKeys lastSkipKey; ++ cTimeMs lastSkipTimeout; ++#endif /* LIEMIEXT */ + time_t timeoutShow; + bool timeSearchActive, timeSearchHide; + int timeSearchTime, timeSearchPos; +@@ -234,9 +278,17 @@ private: + void MarkMove(bool Forward); + void EditCut(void); + void EditTest(void); ++#ifdef USE_DVDARCHIVE ++ void ChaptersJump(bool Forward); ++ bool canJumpChapters; ++ char *dvdchapters; ++#endif /* DVDARCHIVE */ + public: + cReplayControl(void); + virtual ~cReplayControl(); ++#ifdef USE_DELTIMESHIFTREC ++ void Stop(void); ++#endif /* DELTIMESHIFTREC */ + virtual cOsdObject *GetInfo(void); + virtual eOSState ProcessKey(eKeys Key); + virtual void Show(void); +diff -ruNp vdr-1.6.0-2/menuitems.c vdr-1.6.0-2-extensions/menuitems.c +--- vdr-1.6.0-2/menuitems.c 2008-02-10 17:03:30.000000000 +0100 ++++ vdr-1.6.0-2-extensions/menuitems.c 2009-04-09 20:48:26.000000000 +0200 +@@ -32,9 +32,20 @@ cMenuEditItem::~cMenuEditItem() + free(name); + } + ++#ifdef USE_VALIDINPUT ++void cMenuEditItem::SetValue(const char *Value, bool HasPre, bool HasSucc) ++#else + void cMenuEditItem::SetValue(const char *Value) ++#endif /* VALIDINPUT */ + { + cString buffer = cString::sprintf("%s:\t%s", name, Value); ++#ifdef USE_VALIDINPUT ++ if (Setup.ShowValidInput) { ++ if (HasPre && HasSucc) buffer = cString::sprintf("%s:\t<%s>", name, Value); ++ else if (HasPre) buffer = cString::sprintf("%s:\t<%s", name, Value); ++ else if (HasSucc) buffer = cString::sprintf("%s:\t%s>", name, Value); ++ } ++#endif /* VALIDINPUT */ + SetText(buffer); + cStatus::MsgOsdCurrentItem(buffer); + } +@@ -126,7 +137,11 @@ void cMenuEditBoolItem::Set(void) + { + char buf[16]; + snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); ++#ifdef USE_VALIDINPUT ++ SetValue(buf, *value, !*value); ++#else + SetValue(buf); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditBitItem ------------------------------------------------------ +@@ -619,6 +634,171 @@ eOSState cMenuEditStrItem::ProcessKey(eK + return osContinue; + } + ++#ifdef USE_LIEMIEXT ++// --- cMenuEditRecPathItem -------------------------------------------------- ++ ++cMenuEditRecPathItem::cMenuEditRecPathItem(const char* Name, char* Path, ++ int Length): cMenuEditStrItem(Name, Path, Length, tr(FileNameChars)) ++{ ++ SetBase(Path); ++} ++ ++cMenuEditRecPathItem::~cMenuEditRecPathItem() ++{ ++} ++ ++void cMenuEditRecPathItem::SetBase(const char* Path) ++{ ++ if (!Path) ++ base[0] = 0; ++ Utf8Strn0Cpy(base, Path, sizeof(base)); ++ char* p = strrchr(base, '~'); ++ if (p) ++ p[0] = 0; ++ else ++ base[0] = 0; ++} ++ ++void cMenuEditRecPathItem::FindNextLevel() ++{ ++ char item[MaxFileName]; ++ ++ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) ++ { ++ char* p; ++ Utf8Strn0Cpy(item, recording->Name(), sizeof(item)); ++ stripspace(value); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ if (!lengthUtf8) ++ p = strchr(item, '~'); ++ else { ++ if (strstr(item, value) != item) ++ continue; ++ if (item[strlen(value)] != '~') ++ continue; ++ p = strchr(item + strlen(value) + 1, '~'); ++ } ++ if (!p) ++ continue; ++ p[0] = 0; ++ Utf8Strn0Cpy(base, value, length); ++ Utf8Strn0Cpy(value, item, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++} ++ ++void cMenuEditRecPathItem::Find(bool Next) ++{ ++ char item[MaxFileName]; ++ char lastItem[MaxFileName] = ""; ++ ++ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) ++ { ++ const char* recName = recording->Name(); ++ if (Utf8StrLen(base) && strstr(recName, base) != recName) ++ continue; ++ if (strlen(base) && recName[strlen(base)] != '~') ++ continue; ++ Utf8Strn0Cpy(item, recName, sizeof(item)); ++ char* p = strchr(item + strlen(base) + 1, '~'); ++ if (!p) ++ continue; ++ p[0] = 0; ++ if (!Next && (strcmp(item, value) == 0)) { ++ if (strlen(lastItem)) ++ Utf8Strn0Cpy(value, lastItem, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++ if (strcmp(lastItem, item) != 0) { ++ if(Next && Utf8StrLen(lastItem) && strcmp(lastItem, value) == 0) { ++ Utf8Strn0Cpy(value, item, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++ Utf8Strn0Cpy(lastItem, item, sizeof(lastItem)); ++ } ++ } ++} ++ ++void cMenuEditRecPathItem::SetHelpKeys(void) ++{ ++ cSkinDisplay::Current()->SetButtons(tr("Rename$Up"), tr("Rename$Down"), tr("Rename$Previous"), tr("Rename$Next")); ++} ++ ++eOSState cMenuEditRecPathItem::ProcessKey(eKeys Key) ++{ ++ switch (Key) { ++ case kLeft: ++ case kRed: // one level up ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Utf8Strn0Cpy(value, base, lengthUtf8); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ SetBase(base); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ if (!lengthUtf8) { ++ Utf8Strn0Cpy(value, " ", length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ } ++ break; ++ case kRight: ++ case kGreen: // one level down ++ if (InEditMode()) ++ FindNextLevel(); ++ else ++ EnterEditMode(); ++ ++ if (!lengthUtf8) { ++ Utf8Strn0Cpy(value, " ", length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ } ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ SetHelpKeys(); ++ break; ++ case kUp|k_Repeat: ++ case kUp: ++ case kYellow|k_Repeat: ++ case kYellow: // previous directory in list ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Find(false); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ break; ++ case kDown|k_Repeat: ++ case kDown: ++ case kBlue|k_Repeat: ++ case kBlue: // next directory in list ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Find(true); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ break; ++ case kOk: // done ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ stripspace(value); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ cSkinDisplay::Current()->SetButtons(NULL); ++ LeaveEditMode(Key == kOk); ++ break; ++ default: ++ return cMenuEditItem::ProcessKey(Key); ++ } ++ Set(); ++ return osContinue; ++} ++#endif /* LIEMIEXT */ ++ + // --- cMenuEditStraItem ----------------------------------------------------- + + cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) +@@ -630,7 +810,11 @@ cMenuEditStraItem::cMenuEditStraItem(con + + void cMenuEditStraItem::Set(void) + { ++#ifdef USE_VALIDINPUT ++ SetValue(strings[*value], (*value > min), (*value < max)); ++#else + SetValue(strings[*value]); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditChanItem ----------------------------------------------------- +diff -ruNp vdr-1.6.0-2/menuitems.h vdr-1.6.0-2-extensions/menuitems.h +--- vdr-1.6.0-2/menuitems.h 2008-02-16 17:09:58.000000000 +0100 ++++ vdr-1.6.0-2-extensions/menuitems.h 2009-04-09 20:48:26.000000000 +0200 +@@ -21,7 +21,11 @@ private: + public: + cMenuEditItem(const char *Name); + ~cMenuEditItem(); ++#ifdef USE_VALIDINPUT ++ void SetValue(const char *Value, bool HasPre=false, bool HasSucc=false); ++#else + void SetValue(const char *Value); ++#endif /* VALIDINPUT */ + }; + + class cMenuEditIntItem : public cMenuEditItem { +@@ -78,26 +82,46 @@ public: + + class cMenuEditStrItem : public cMenuEditItem { + private: ++#ifdef USE_LIEMIEXT ++ int offset; ++#else + char *value; + int length; + const char *allowed; + int pos, offset; ++#endif /* LIEMIEXT */ + bool insert, newchar, uppercase; ++#ifndef USE_LIEMIEXT + int lengthUtf8; + uint *valueUtf8; ++#endif /* LIEMIEXT */ + uint *allowedUtf8; + uint *charMapUtf8; + uint *currentCharUtf8; + eKeys lastKey; + cTimeMs autoAdvanceTimeout; ++#ifndef USE_LIEMIEXT + void SetHelpKeys(void); ++#endif /* LIEMIEXT */ + uint *IsAllowed(uint c); + void AdvancePos(void); ++#ifndef USE_LIEMIEXT + virtual void Set(void); ++#endif /* LIEMIEXT */ + uint Inc(uint c, bool Up); + void Insert(void); + void Delete(void); + protected: ++#ifdef USE_LIEMIEXT ++ char *value; ++ int length; ++ uint *valueUtf8; ++ int lengthUtf8; ++ const char *allowed; ++ int pos; ++ void SetHelpKeys(void); ++ virtual void Set(void); ++#endif /* LIEMIEXT */ + void EnterEditMode(void); + void LeaveEditMode(bool SaveValue = false); + bool InEditMode(void) { return valueUtf8 != NULL; } +@@ -107,6 +131,21 @@ public: + virtual eOSState ProcessKey(eKeys Key); + }; + ++#ifdef USE_LIEMIEXT ++class cMenuEditRecPathItem : public cMenuEditStrItem { ++protected: ++ char base[MaxFileName]; ++ virtual void SetHelpKeys(void); ++ void SetBase(const char* Path); ++ void FindNextLevel(); ++ void Find(bool Next); ++public: ++ cMenuEditRecPathItem(const char* Name, char* Path, int Length); ++ ~cMenuEditRecPathItem(); ++ virtual eOSState ProcessKey(eKeys Key); ++ }; ++#endif /* LIEMIEXT */ ++ + class cMenuEditStraItem : public cMenuEditIntItem { + private: + const char * const *strings; +@@ -174,6 +213,9 @@ public: + cMenuSetupPage(void); + virtual eOSState ProcessKey(eKeys Key); + void SetPlugin(cPlugin *Plugin); ++#ifdef USE_GRAPHTFT ++ const char* MenuKind() { return "MenuSetupPage"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__MENUITEMS_H +diff -ruNp vdr-1.6.0-2/menuorgpatch.h vdr-1.6.0-2-extensions/menuorgpatch.h +--- vdr-1.6.0-2/menuorgpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/menuorgpatch.h 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,102 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MENUORGPATCH_H ++#define __MENUORGPATCH_H ++ ++#include "mainmenuitemsprovider.h" ++ ++class MenuOrgPatch ++{ ++ private: ++ static IMainMenuItemsProvider* _mainMenuItemsProvider; ++ ++ private: ++ static IMainMenuItemsProvider* MainMenuItemsProvider() ++ { ++ if (!_mainMenuItemsProvider) ++ { ++ IMainMenuItemsProvider* mainMenuItemsProvider; ++ ++ if (cPluginManager::CallFirstService(MENU_ITEMS_PROVIDER_SERVICE_ID, &mainMenuItemsProvider)) ++ { ++ _mainMenuItemsProvider = mainMenuItemsProvider; ++ } ++ } ++ return _mainMenuItemsProvider; ++ } ++ ++ public: ++ static bool IsCustomMenuAvailable() ++ { ++ return (MainMenuItemsProvider() != NULL) && (MainMenuItemsProvider()->IsCustomMenuAvailable()); ++ } ++ ++ static void EnterRootMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterRootMenu(); ++ } ++ } ++ ++ static bool LeaveSubMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->LeaveSubMenu(); ++ } ++ return false; ++ } ++ ++ static void EnterSubMenu(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterSubMenu(item); ++ } ++ } ++ ++ static MenuItemDefinitions* MainMenuItems() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->MainMenuItems(); ++ } ++ return NULL; ++ } ++ ++ static cOsdMenu* Execute(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->Execute(item); ++ } ++ return NULL; ++ } ++}; ++ ++IMainMenuItemsProvider* MenuOrgPatch::_mainMenuItemsProvider = NULL; ++ ++#endif //__MENUORGPATCH_H ++#endif /* MENUORG */ +diff -ruNp vdr-1.6.0-2/osdbase.c vdr-1.6.0-2-extensions/osdbase.c +--- vdr-1.6.0-2/osdbase.c 2008-02-17 12:33:04.000000000 +0100 ++++ vdr-1.6.0-2-extensions/osdbase.c 2009-04-09 20:48:26.000000000 +0200 +@@ -22,6 +22,9 @@ cOsdItem::cOsdItem(eOSState State) + state = State; + selectable = true; + fresh = true; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + + cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable) +@@ -31,8 +34,23 @@ cOsdItem::cOsdItem(const char *Text, eOS + selectable = Selectable; + fresh = true; + SetText(Text); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++cOsdItem::cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu) ++{ ++ text = NULL; ++ state = State; ++ selectable = true; ++ fresh = true; ++ SetText(Text); ++ subMenu = SubMenu; ++} ++#endif /* SETUP & PINPLUGIN */ ++ + cOsdItem::~cOsdItem() + { + free(text); +@@ -77,6 +95,9 @@ cOsdMenu::cOsdMenu(const char *Title, in + { + isMenu = true; + digit = 0; ++#ifdef USE_LIEMIEXT ++ key_nr = -1; ++#endif /* LIEMIEXT */ + hasHotkeys = false; + title = NULL; + SetTitle(Title); +@@ -97,6 +118,9 @@ cOsdMenu::~cOsdMenu() + free(status); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDestroy(); ++#endif /* GRAPHTFT */ + if (!--displayMenuCount) + DELETENULL(displayMenu); + } +@@ -119,7 +143,11 @@ const char *cOsdMenu::hk(const char *s) + digit = -1; // prevents automatic hotkeys - input already has them + if (digit >= 0) { + digit++; ++#ifdef USE_LIEMIEXT ++ buffer = cString::sprintf(" %2d%s %s", digit, (digit > 9) ? "" : " ", s); ++#else + buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s); ++#endif /* LIEMIEXT */ + s = buffer; + } + } +@@ -199,9 +227,15 @@ void cOsdMenu::Display(void) + subMenu->Display(); + return; + } ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + displayMenu->SetMessage(mtStatus, NULL); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDisplay(MenuKind()); ++#endif /* GRAPHTFT */ + displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX + displayMenu->SetTitle(title); + cStatus::MsgOsdTitle(title); +@@ -296,6 +330,9 @@ bool cOsdMenu::SelectableItem(int idx) + + void cOsdMenu::CursorUp(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int tmpCurrent = current; + int lastOnScreen = first + displayMenuItems - 1; + int last = Count() - 1; +@@ -334,6 +371,9 @@ void cOsdMenu::CursorUp(void) + + void cOsdMenu::CursorDown(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int tmpCurrent = current; + int lastOnScreen = first + displayMenuItems - 1; + int last = Count() - 1; +@@ -374,6 +414,9 @@ void cOsdMenu::CursorDown(void) + + void cOsdMenu::PageUp(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int oldCurrent = current; + int oldFirst = first; + current -= displayMenuItems; +@@ -408,6 +451,9 @@ void cOsdMenu::PageUp(void) + + void cOsdMenu::PageDown(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int oldCurrent = current; + int oldFirst = first; + current += displayMenuItems; +@@ -448,6 +494,64 @@ void cOsdMenu::Mark(void) + } + } + ++#ifdef USE_LIEMIEXT ++#define MENUKEY_TIMEOUT 1500 ++ ++eOSState cOsdMenu::HotKey(eKeys Key) ++{ ++ bool match = false; ++ bool highlight = false; ++ int item_nr; ++ int i; ++ ++ if (Key == kNone) { ++ if (lastActivity.TimedOut()) ++ Key = kOk; ++ else ++ return osContinue; ++ } ++ else { ++ lastActivity.Set(MENUKEY_TIMEOUT); ++ } ++ for (cOsdItem *item = Last(); item; item = Prev(item)) { ++ const char *s = item->Text(); ++ i = 0; ++ item_nr = 0; ++ if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') { ++ do { ++ item_nr = item_nr * 10 + (s[i] - '0'); ++ } ++ while (!((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9')); ++ if ((Key == kOk) && (item_nr == key_nr)) { ++ current = item->Index(); ++ RefreshCurrent(); ++ Display(); ++ cRemote::Put(kOk, true); ++ key_nr = -1; ++ break; ++ } ++ else if (Key != kOk) { ++ if (!highlight && (item_nr == (Key - k0))) { ++ highlight = true; ++ current = item->Index(); ++ } ++ if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) { ++ match = true; ++ key_nr = (Key - k0); ++ } ++ else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) { ++ current = item->Index(); ++ cRemote::Put(kOk, true); ++ key_nr = -1; ++ break; ++ } ++ } ++ } ++ } ++ if ((!match) && (Key != kNone)) { ++ key_nr = -1; ++ } ++#else + eOSState cOsdMenu::HotKey(eKeys Key) + { + for (cOsdItem *item = First(); item; item = Next(item)) { +@@ -462,6 +566,7 @@ eOSState cOsdMenu::HotKey(eKeys Key) + } + } + } ++#endif /* LIEMIEXT */ + return osContinue; + } + +@@ -500,8 +605,13 @@ eOSState cOsdMenu::ProcessKey(eKeys Key) + } + } + switch (Key) { ++#ifdef USE_LIEMIEXT ++ case kNone: ++ case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#else + case k0: return osUnknown; + case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#endif /* LIEMIEXT */ + case kUp|k_Repeat: + case kUp: CursorUp(); break; + case kDown|k_Repeat: +diff -ruNp vdr-1.6.0-2/osdbase.h vdr-1.6.0-2-extensions/osdbase.h +--- vdr-1.6.0-2/osdbase.h 2007-11-03 15:50:52.000000000 +0100 ++++ vdr-1.6.0-2-extensions/osdbase.h 2009-04-09 20:48:26.000000000 +0200 +@@ -15,6 +15,10 @@ + #include "skins.h" + #include "tools.h" + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++#include "submenu.h" ++#endif /* SETUP & PINPLUGIN */ ++ + enum eOSState { osUnknown, + osContinue, + osSchedule, +@@ -44,6 +48,9 @@ enum eOSState { osUnknown, + osUser8, + osUser9, + osUser10, ++#ifdef USE_LIVEBUFFER ++ osLiveBuffer, ++#endif /* LIVEBUFFER */ + }; + + class cOsdItem : public cListObject { +@@ -51,16 +58,26 @@ private: + char *text; + eOSState state; + bool selectable; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cSubMenuNode* subMenu; ++#endif /* SETUP & PINPLUGIN */ + protected: + bool fresh; + public: + cOsdItem(eOSState State = osUnknown); + cOsdItem(const char *Text, eOSState State = osUnknown, bool Selectable = true); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu); ++#endif /* SETUP & PINPLUGIN */ + virtual ~cOsdItem(); + bool Selectable(void) const { return selectable; } + void SetText(const char *Text, bool Copy = true); + void SetSelectable(bool Selectable); + void SetFresh(bool Fresh); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ void SetSubMenu(cSubMenuNode* SubMenu) { subMenu = SubMenu; } ++ cSubMenuNode* SubMenu() { return subMenu; } ++#endif /* SETUP & PINPLUGIN */ + const char *Text(void) const { return text; } + virtual void Set(void) {} + virtual eOSState ProcessKey(eKeys Key); +@@ -95,6 +112,10 @@ private: + char *status; + int digit; + bool hasHotkeys; ++#ifdef USE_LIEMIEXT ++ int key_nr; ++ cTimeMs lastActivity; ++#endif /* LIEMIEXT */ + protected: + void SetDisplayMenu(void); + cSkinDisplayMenu *DisplayMenu(void) { return displayMenu; } +@@ -129,6 +150,9 @@ public: + void Ins(cOsdItem *Item, bool Current = false, cOsdItem *Before = NULL); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuUnknown"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__OSDBASE_H +diff -ruNp vdr-1.6.0-2/osd.c vdr-1.6.0-2-extensions/osd.c +--- vdr-1.6.0-2/osd.c 2007-10-12 14:38:36.000000000 +0200 ++++ vdr-1.6.0-2-extensions/osd.c 2009-04-09 20:48:26.000000000 +0200 +@@ -15,6 +15,9 @@ + #include <sys/stat.h> + #include <sys/unistd.h> + #include "tools.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + // --- cPalette -------------------------------------------------------------- + +@@ -720,6 +723,9 @@ int cOsd::osdTop = 0; + int cOsd::osdWidth = 0; + int cOsd::osdHeight = 0; + cVector<cOsd *> cOsd::Osds; ++#ifdef USE_PINPLUGIN ++bool cOsd::pinValid = false; ++#endif /* PINPLUGIN */ + + cOsd::cOsd(int Left, int Top, uint Level) + { +@@ -730,6 +736,9 @@ cOsd::cOsd(int Left, int Top, uint Level + width = height = 0; + level = Level; + active = false; ++#ifdef USE_YAEPG ++ vidWin.bpp = 0; ++#endif /* YAEPG */ + for (int i = 0; i < Osds.Size(); i++) { + if (Osds[i]->level > level) { + Osds.Insert(this, i); +diff -ruNp vdr-1.6.0-2/osd.h vdr-1.6.0-2-extensions/osd.h +--- vdr-1.6.0-2/osd.h 2007-10-12 16:28:44.000000000 +0200 ++++ vdr-1.6.0-2-extensions/osd.h 2009-04-09 20:48:26.000000000 +0200 +@@ -400,6 +400,12 @@ public: + ///< 7: vertical, falling, upper + virtual void Flush(void); + ///< Actually commits all data to the OSD hardware. ++#ifdef USE_PINPLUGIN ++ static bool pinValid; ++#endif /* PINPLUGIN */ ++#ifdef USE_YAEPG ++ tArea vidWin; ++#endif /* YAEPG */ + }; + + class cOsdProvider { +diff -ruNp vdr-1.6.0-2/player.c vdr-1.6.0-2-extensions/player.c +--- vdr-1.6.0-2/player.c 2007-07-20 17:25:24.000000000 +0200 ++++ vdr-1.6.0-2-extensions/player.c 2009-04-09 20:48:26.000000000 +0200 +@@ -60,10 +60,18 @@ cOsdObject *cControl::GetInfo(void) + return NULL; + } + ++#ifdef USE_LIVEBUFFER ++cControl *cControl::Control(bool Hidden) ++#else + cControl *cControl::Control(void) ++#endif /* LIVEBUFFER */ + { + cMutexLock MutexLock(&mutex); ++#ifdef USE_LIVEBUFFER ++ return (control && (!control->hidden || Hidden)) ? control : NULL; ++#else + return (control && !control->hidden) ? control : NULL; ++#endif /* LIVEBUFFER */ + } + + void cControl::Launch(cControl *Control) +diff -ruNp vdr-1.6.0-2/player.h vdr-1.6.0-2-extensions/player.h +--- vdr-1.6.0-2/player.h 2008-02-16 14:50:11.000000000 +0100 ++++ vdr-1.6.0-2-extensions/player.h 2009-04-09 20:48:26.000000000 +0200 +@@ -83,7 +83,11 @@ public: + static void Launch(cControl *Control); + static void Attach(void); + static void Shutdown(void); ++#ifdef USE_LIVEBUFFER ++ static cControl *Control(bool Hidden = false); ++#else + static cControl *Control(void); ++#endif /* LIVEBUFFER */ + }; + + #endif //__PLAYER_H +diff -ruNp vdr-1.6.0-2/plugin.c vdr-1.6.0-2-extensions/plugin.c +--- vdr-1.6.0-2/plugin.c 2008-02-17 14:32:12.000000000 +0100 ++++ vdr-1.6.0-2-extensions/plugin.c 2009-04-09 20:48:26.000000000 +0200 +@@ -316,6 +316,14 @@ void cPluginManager::AddPlugin(const cha + char *p = strchr(s, ' '); + if (p) + *p = 0; ++#ifdef USE_PLUGINMISSING ++ struct stat st; ++ if (stat (cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), &st) && errno == ENOENT) { ++ esyslog("WARN: missing plugin '%s'", s); ++ fprintf(stderr, "vdr: missing plugin '%s'\n", s); ++ } ++ else ++#endif /* PLUGINMISSING */ + dlls.Add(new cDll(cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), Args)); + free(s); + } +@@ -324,7 +332,11 @@ bool cPluginManager::LoadPlugins(bool Lo + { + for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) { + if (!dll->Load(Log)) ++#ifdef USE_PLUGINMISSING ++ ; ++#else + return false; ++#endif /* PLUGINMISSING */ + } + return true; + } +diff -ruNp vdr-1.6.0-2/po/ca_ES.po vdr-1.6.0-2-extensions/po/ca_ES.po +--- vdr-1.6.0-2/po/ca_ES.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/ca_ES.po 2009-04-09 20:48:26.000000000 +0200 +@@ -1001,3 +1001,270 @@ msgstr "Prem qualsevol tecla per cancel· + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR s'apagarà en %s minuts" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/cs_CZ.po vdr-1.6.0-2-extensions/po/cs_CZ.po +--- vdr-1.6.0-2/po/cs_CZ.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/cs_CZ.po 2009-04-09 20:48:26.000000000 +0200 +@@ -999,3 +999,270 @@ msgstr "Jakákoliv klávesa zru¹í restart" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se vypne za %s minut" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/da_DK.po vdr-1.6.0-2-extensions/po/da_DK.po +--- vdr-1.6.0-2/po/da_DK.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/da_DK.po 2009-04-09 20:48:26.000000000 +0200 +@@ -998,3 +998,270 @@ msgstr "Tryk vilkårlig knap for at annul + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR slukker om %s minutter" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/de_DE.po vdr-1.6.0-2-extensions/po/de_DE.po +--- vdr-1.6.0-2/po/de_DE.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/de_DE.po 2009-04-09 20:48:26.000000000 +0200 +@@ -785,6 +785,30 @@ msgstr "Lautstärke beim Einschalten" + msgid "Setup.Miscellaneous$Emergency exit" + msgstr "Notausstieg" + ++msgid "Setup.Miscellaneous$Volume ctrl with left/right" ++msgstr "Lautstärke mit Rechts/Links regeln" ++ ++msgid "Setup.Miscellaneous$Channelgroups with left/right" ++msgstr "Kanalgruppen mit Rechts/Links" ++ ++msgid "Setup.Miscellaneous$only in channelinfo" ++msgstr "nur in Kanalinfo" ++ ++msgid "Setup.Miscellaneous$Search fwd/back with left/right" ++msgstr "Vor-/Rücklauf mit Rechts/Links" ++ ++msgid "Setup.Miscellaneous$only in progress display" ++msgstr "nur in Fortschrittsanzeige" ++ ++msgid "Setup.Miscellaneous$Lirc repeat delay" ++msgstr "Lirc Verzögerung" ++ ++msgid "Setup.Miscellaneous$Lirc repeat freq" ++msgstr "Lirc Frequenz" ++ ++msgid "Setup.Miscellaneous$Lirc repeat timeout" ++msgstr "Lirc Zeitbeschränkung" ++ + msgid "Plugins" + msgstr "Plugins" + +@@ -998,3 +1022,327 @@ msgstr "Taste drücken, um Neustart abzub + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR wird in %s Minuten ausschalten" ++ ++msgid "Parameters" ++msgstr "Parameter" ++ ++msgid "Channel locked by LNB!" ++msgstr "Kanal durch LNB gesperrt!" ++ ++msgid "Childlock" ++msgstr "Kindersicherung" ++ ++msgid "Path" ++msgstr "Pfad" ++ ++msgid "Timer commands" ++msgstr "Befehle für Aufzeichnungen" ++ ++msgid "Rename recording" ++msgstr "Aufzeichnung umbenennen" ++ ++msgid "Date" ++msgstr "Datum" ++ ++msgid "Length" ++msgstr "Länge" ++ ++msgid "Size" ++msgstr "Größe" ++ ++msgid "Delete marks information?" ++msgstr "Marks löschen?" ++ ++msgid "Delete resume information?" ++msgstr "Resume löschen?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "Das DVD-Plugin ist nicht installiert!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Alphabet für Haupt-, flexibel für Unterverzeichnisse" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Datum für Haupt-, flexibel für Unterverzeichnisse" ++ ++msgid "all alphabetically" ++msgstr "Alles alphabetisch" ++ ++msgid "all by date" ++msgstr "Alles nach Datum" ++ ++msgid "Sorting" ++msgstr "Sortierung" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle icons verwenden" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "Hauptmenü Titel" ++ ++msgid "Setup.OSD$- Text" ++msgstr "- Text" ++ ++msgid "default" ++msgstr "Voreinstellung" ++ ++msgid "VDR - text" ++msgstr "VDR - Text" ++ ++msgid "text" ++msgstr "Text" ++ ++msgid "VDR - version" ++msgstr "VDR - Version" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Befehle Position im Hauptmenü" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Zeige gültige Eingabe" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Zeitbalken anzeigen" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Zeitspanne für dop. EPG-Suche (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Doppelten externen EPG-Eintrag" ++ ++msgid "Setup.EPG$Mode of noEPG-Patch" ++msgstr "Art des noEPG-Patches" ++ ++msgid "adjust" ++msgstr "anwenden" ++ ++msgid "delete" ++msgstr "löschen" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Internes und externes EPG mischen" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Erk. des lauf. VPS-Events abschalten" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "AC3-Transfer Fix benutzen" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "Sperre Kanäle" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "Kanal Sperren Filter" ++ ++msgid "qam256" ++msgstr "qam256" ++ ++msgid "dvb-c" ++msgstr "dvb-c" ++ ++msgid "dvb-s" ++msgstr "dvb-s" ++ ++msgid "all" ++msgstr "alle" ++ ++msgid "blacklist" ++msgstr "Blacklist" ++ ++msgid "whitelist" ++msgstr "Whitelist" ++ ++msgid "has decoder" ++msgstr "mit Decoder" ++ ++msgid "is primary" ++msgstr "ist primär" ++ ++msgid "has decoder + is primary" ++msgstr "mit Decoder und primär" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Sync Early Patch benutzen" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "DVB-Empfänger %d nutzt LNB Nr." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "LNB-Nutzung protokollieren" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Dolby Digital Ton aufzeichnen" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Videoverzeichnispolitik" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Anzahl der Videoverzeichnisse" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d Priorität" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. MB frei" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Freundliche Dateinamen" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Max. Aufnahmengröße (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Hard Link Cutter" ++ ++msgid "Setup.Recording$Delete timeshift recording" ++msgstr "Zeitversetzte Aufnahme löschen" ++ ++msgid "request" ++msgstr "abfragen" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Aufnahmedatum anzeigen" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Aufnahmezeit anzeigen" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Länge der Aufnahme anzeigen" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Ende für Timer anzeigen" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Aufnahmen sortieren nach" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Verzeichnisse vor Aufnahmen einsortieren" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Aufnahmen nach dem Schneiden löschen" ++ ++msgid "Setup.Recording$Cutter adjust starttime" ++msgstr "Startzeit beim Schneiden anpassen" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Wiedergabe nach Sprung" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Sprung bei Schnittmarke" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause bei letzter Marke" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Marken aktualisieren" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Sprungweite in Sekunden" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Sprungweite in Sekunden Langsam" ++ ++msgid "Setup.Replay$Length" ++msgstr "Länge" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Länge / Nummer" ++ ++msgid "Setup.Replay$Number" ++msgstr "Nummer" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "DVD Anzeige" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "DVD führende Nullen anzeigen" ++ ++msgid "Setup.Replay$never" ++msgstr "nie" ++ ++msgid "Setup.Replay$on begin" ++msgstr "am Anfang" ++ ++msgid "Setup.Replay$on end" ++msgstr "am Ende" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "am Anfang und Ende" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "DVD-Schublade öffnen" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "DVD drosseln auf" ++ ++msgid "Jump" ++msgstr "Springen: " ++ ++msgid "Skip +60s" ++msgstr "Sprung +60s" ++ ++msgid "Skip -60s" ++msgstr "Sprung -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Schnitt bereits aktiv - zur Schnitt-Liste hinzufügen?" ++ ++msgid "Rename$Up" ++msgstr "Höher" ++ ++msgid "Rename$Down" ++msgstr "Tiefer" ++ ++msgid "Rename$Previous" ++msgstr "Vorheriger" ++ ++msgid "Rename$Next" ++msgstr "Nächster" ++ ++msgid "Please mount %s" ++msgstr "Bitte %s einlegen!" ++ ++msgid "Please mount DVD %04d" ++msgstr "Bitte DVD %04d einlegen!" ++ ++msgid "Please mount DVD %d" ++msgstr "Bitte DVD %d einlegen!" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Bitte warten. Überprüfe DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Keine Index-Datei gefunden. Erstellung kann Minuten dauern. Erstellen?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Bitte warten. Index-Datei wird erstellt..." ++ ++msgid "Wrong DVD!" ++msgstr "Falsche DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Permanentes Timeshift" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Speicherort" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "Festplatte" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "Arbeitsspeicher" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Puffergröße im Arbeitsspeicher (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Auf Festplatte ausweiten wenn nötig" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Pausierten Puffer beibehalten" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Puffergröße auf Festplatte (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Puffergröße (MB)" +diff -ruNp vdr-1.6.0-2/po/el_GR.po vdr-1.6.0-2-extensions/po/el_GR.po +--- vdr-1.6.0-2/po/el_GR.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/el_GR.po 2009-04-09 20:48:26.000000000 +0200 +@@ -998,3 +998,270 @@ msgstr "" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/es_ES.po vdr-1.6.0-2-extensions/po/es_ES.po +--- vdr-1.6.0-2/po/es_ES.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/es_ES.po 2009-04-09 20:48:26.000000000 +0200 +@@ -999,3 +999,270 @@ msgstr "Pulse cualquier tecla para cance + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se apagará en %s minutos" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/et_EE.po vdr-1.6.0-2-extensions/po/et_EE.po +--- vdr-1.6.0-2/po/et_EE.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/et_EE.po 2009-04-09 20:48:26.000000000 +0200 +@@ -998,3 +998,270 @@ msgstr "Restardi katkestamiseks vajuta s + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR lülitub välja %s minuti pärast" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "Ümbernimetamine" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Käsu asukoht peamenüüs" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Edenemisriba" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Salvestuse kuupäev" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Salvestuse kellaaeg" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Salvestuse pikkus" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "Üles" ++ ++msgid "Rename$Down" ++msgstr "Alla" ++ ++msgid "Rename$Previous" ++msgstr "Eelmine" ++ ++msgid "Rename$Next" ++msgstr "Järgmine" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/fi_FI.po vdr-1.6.0-2-extensions/po/fi_FI.po +--- vdr-1.6.0-2/po/fi_FI.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/fi_FI.po 2009-04-09 20:48:26.000000000 +0200 +@@ -30,6 +30,253 @@ msgstr "Siirtotilan aloitus epäonnistui! + msgid "Starting EPG scan" + msgstr "Ohjelmaoppaan päivitys aloitettu" + ++msgid "Content$Movie/Drama" ++msgstr "Elokuva/draama" ++ ++msgid "Content$Detective/Thriller" ++msgstr "Etsivä/trilleri" ++ ++msgid "Content$Adventure/Western/War" ++msgstr "Seikkailu/western/sota" ++ ++msgid "Content$Science Fiction/Fantasy/Horror" ++msgstr "Scifi/fantasia/kauhu" ++ ++msgid "Content$Comedy" ++msgstr "Komedia" ++ ++msgid "Content$Soap/Melodrama/Folkloric" ++msgstr "Saippua/melodraama/kansanperinne" ++ ++msgid "Content$Romance" ++msgstr "Romanssi" ++ ++msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" ++msgstr "Vakava/klassinen/uskonnollinen/historiallinen elokuva/draama" ++ ++msgid "Content$Adult Movie/Drama" ++msgstr "Aikuiselokuva/draama" ++ ++msgid "Content$News/Current Affairs" ++msgstr "Uutiset/ajankohtaisohjelma" ++ ++msgid "Content$News/Weather Report" ++msgstr "Uutiset/säätiedot" ++ ++msgid "Content$News Magazine" ++msgstr "Uutismakasiini" ++ ++msgid "Content$Documentary" ++msgstr "Dokumentti" ++ ++msgid "Content$Discussion/Inverview/Debate" ++msgstr "Keskustelu/haastattelu/väittely" ++ ++msgid "Content$Show/Game Show" ++msgstr "Show/visailu" ++ ++msgid "Content$Game Show/Quiz/Contest" ++msgstr "Visailu/kilpailu" ++ ++msgid "Content$Variety Show" ++msgstr "Varietee" ++ ++msgid "Content$Talk Show" ++msgstr "Keskusteluohjelma" ++ ++msgid "Content$Sports" ++msgstr "Urheilua" ++ ++msgid "Content$Special Event" ++msgstr "Erikoistapahtuma" ++ ++msgid "Content$Sport Magazine" ++msgstr "Urheilumakasiini" ++ ++msgid "Content$Football" ++msgstr "Jalkapallo" ++ ++msgid "Content$Tennis/Squash" ++msgstr "Tennis/Squash" ++ ++msgid "Content$Team Sports" ++msgstr "Joukkueurheilua" ++ ++msgid "Content$Athletics" ++msgstr "Yleisurheilua" ++ ++msgid "Content$Motor Sport" ++msgstr "Moottoriurheilua" ++ ++msgid "Content$Water Sport" ++msgstr "Vesiurheilua" ++ ++msgid "Content$Winter Sports" ++msgstr "Talviurheilua" ++ ++msgid "Content$Equestrian" ++msgstr "Ratsastusta" ++ ++msgid "Content$Martial Sports" ++msgstr "Kamppailu-urheilua" ++ ++msgid "Content$Children's/Youth Programmes" ++msgstr "Lasten ja nuorten ohjelma" ++ ++msgid "Content$Pre-school Children's Programmes" ++msgstr "Alle kouluikäisten ohjelma" ++ ++msgid "Content$Entertainment Programmes for 6 to 14" ++msgstr "Viihdeohjelma 6-14 vuotiaille" ++ ++msgid "Content$Entertainment Programmes for 10 to 16" ++msgstr "Viihdeohjelma 10-16 vuotiaille" ++ ++msgid "Content$Informational/Educational/School Programme" ++msgstr "Opetus/kouluohjelma" ++ ++msgid "Content$Cartoons/Puppets" ++msgstr "Piirretty/nukke-esitys" ++ ++msgid "Content$Music/Ballet/Dance" ++msgstr "Musiikki/baletti/tanssi" ++ ++msgid "Content$Rock/Pop" ++msgstr "Rock/pop" ++ ++msgid "Content$Serious/Classical Music" ++msgstr "Vakava/klassinen musiikki" ++ ++msgid "Content$Folk/Tradional Music" ++msgstr "Folk/kansanmusiikki" ++ ++msgid "Content$Jazz" ++msgstr "Jazz" ++ ++msgid "Content$Musical/Opera" ++msgstr "Musikaali/ooppera" ++ ++msgid "Content$Ballet" ++msgstr "Baletti" ++ ++msgid "Content$Arts/Culture" ++msgstr "Taide/kulttuuri" ++ ++msgid "Content$Performing Arts" ++msgstr "Performanssitaide" ++ ++msgid "Content$Fine Arts" ++msgstr "Kuvataide" ++ ++msgid "Content$Religion" ++msgstr "Uskonto" ++ ++msgid "Content$Popular Culture/Traditional Arts" ++msgstr "Populaarikulttuuri/perinnetaiteet" ++ ++msgid "Content$Literature" ++msgstr "Kirjallisuus" ++ ++msgid "Content$Film/Cinema" ++msgstr "Elokuvataide" ++ ++msgid "Content$Experimental Film/Video" ++msgstr "Kokeellinen elokuva/video" ++ ++msgid "Content$Broadcasting/Press" ++msgstr "Televisio/radio/lehdistö" ++ ++msgid "Content$New Media" ++msgstr "Uusmedia" ++ ++msgid "Content$Arts/Culture Magazines" ++msgstr "Taide/kulttuurimakasiini" ++ ++msgid "Content$Fashion" ++msgstr "Muoti" ++ ++msgid "Content$Social/Political/Economics" ++msgstr "Yhteiskunta/politiikka/talous" ++ ++msgid "Content$Magazines/Reports/Documentary" ++msgstr "Makasiini/reportaasi/dokumentti" ++ ++msgid "Content$Economics/Social Advisory" ++msgstr "Talous/yhteiskunnallinen neuvonta" ++ ++msgid "Content$Remarkable People" ++msgstr "Merkittävät henkilöt" ++ ++msgid "Content$Education/Science/Factual" ++msgstr "Koulutus/tiede" ++ ++msgid "Content$Nature/Animals/Environment" ++msgstr "Luonto/eläimet/ympäristö" ++ ++msgid "Content$Technology/Natural Sciences" ++msgstr "Teknologia/luonnontiede" ++ ++msgid "Content$Medicine/Physiology/Psychology" ++msgstr "Lääketiede/fysiologia/psykologia" ++ ++msgid "Content$Foreign Countries/Expeditions" ++msgstr "Vieraat maat/tutkimusretket" ++ ++msgid "Content$Social/Spiritual Sciences" ++msgstr "Yhteiskunta/hengelliset tieteet" ++ ++msgid "Content$Further Education" ++msgstr "Jatkokoulutus" ++ ++msgid "Content$Languages" ++msgstr "Kielet" ++ ++msgid "Content$Leisure/Hobbies" ++msgstr "Vapaa-aika ja harrastukset" ++ ++msgid "Content$Tourism/Travel" ++msgstr "Turismi/matkustaminen" ++ ++msgid "Content$Handicraft" ++msgstr "Käsityöt" ++ ++msgid "Content$Motoring" ++msgstr "Autoilu" ++ ++msgid "Content$Fitness & Health" ++msgstr "Kuntoilu & terveys" ++ ++msgid "Content$Cooking" ++msgstr "Ruuanlaitto" ++ ++msgid "Content$Advertisement/Shopping" ++msgstr "Mainostaminen/ostaminen" ++ ++msgid "Content$Gardening" ++msgstr "Puutarhanhoito" ++ ++msgid "Content$Original Language" ++msgstr "Alkuperäiskieli" ++ ++msgid "Content$Black & White" ++msgstr "Mustavalkoinen" ++ ++msgid "Content$Unpublished" ++msgstr "Julkaisematon" ++ ++msgid "Content$Live Broadcast" ++msgstr "Suoralähetys" ++ ++msgid "Content$Special Characteristics" ++msgstr "Erikoisominaisuus" ++ ++msgid "Content$Drama" ++msgstr "Draama" ++ ++#, c-format ++msgid "Suitable for those aged %d and over" ++msgstr "Kielletty alle %d vuotiailta" ++ + msgid "No title" + msgstr "Ei esitystä" + +@@ -1001,3 +1248,273 @@ msgstr "Peru uudelleenkäynnistys painama + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR sammuu %s minuutin kuluttua" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "Polku" ++ ++msgid "Timer commands" ++msgstr "Ajastinkomennot" ++ ++msgid "Rename recording" ++msgstr "Nimeä tallenne" ++ ++msgid "Date" ++msgstr "Päiväys" ++ ++msgid "Length" ++msgstr "Pituus" ++ ++msgid "Size" ++msgstr "Koko" ++ ++msgid "Delete marks information?" ++msgstr "Poista tallenteen merkinnät" ++ ++msgid "Delete resume information?" ++msgstr "Poista tallenteen paluutiedot" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Komentojen sijainti päävalikossa" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Näytä aikajana" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Dolby Digital tallennus" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Näytä tallenteen päiväys" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Näytä tallenteen ajankohta" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Näytä tallenteen kesto" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "Ylemmäs" ++ ++msgid "Rename$Down" ++msgstr "Alemmas" ++ ++msgid "Rename$Previous" ++msgstr "Edellinen" ++ ++msgid "Rename$Next" ++msgstr "Seuraava" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Parameters" ++msgstr "Parametrit" ++ ++msgid "Permanent Timeshift" ++msgstr "Jatkuva ajansiirto" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Puskurin sijainti" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "kovalevyllä" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "muistissa" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Puffergröße im Arbeitsspeicher (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Käytä kovalevyä tarvittaessa" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Pidä pysäytetty puskuri" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Puffergröße auf Festplatte (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Puskurin koko (MB)" +diff -ruNp vdr-1.6.0-2/po/fr_FR.po vdr-1.6.0-2-extensions/po/fr_FR.po +--- vdr-1.6.0-2/po/fr_FR.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/fr_FR.po 2009-04-09 20:48:26.000000000 +0200 +@@ -8,6 +8,7 @@ + # Pierre Briec <pbriec@free.fr>, 2006 + # Bruno Roussel <bruno.roussel@free.fr>, 2007 + # Michael Nival <mnival@club-internet.fr>, 2007 ++# Patrice Staudt <patrice.staudt@laposte.net>, 2007, 2008 + # + msgid "" + msgstr "" +@@ -1004,3 +1005,270 @@ msgstr "Appuyer sur une touche pour annu + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR s'arrêtera dans %s minutes" ++ ++msgid "Channel locked by LNB!" ++msgstr "Chaîne interdite par la LNB" ++ ++msgid "Childlock" ++msgstr "Adulte" ++ ++msgid "Path" ++msgstr "Dossiers" ++ ++msgid "Timer commands" ++msgstr "Commandes de programmation" ++ ++msgid "Rename recording" ++msgstr "Renommer l'enregistrement" ++ ++msgid "Date" ++msgstr "Date" ++ ++msgid "Length" ++msgstr "Longeur" ++ ++msgid "Size" ++msgstr "Taille" ++ ++msgid "Delete marks information?" ++msgstr "Effacer marque d'information?" ++ ++msgid "Delete resume information?" ++msgstr "Effacer resume information?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "Le plugin de DVD n'est pas installé!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Dir principal alphabétiquement, subdirs flexibles" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Dir principal à la date, subdirs flexibles" ++ ++msgid "all alphabetically" ++msgstr "tous alphabétiquement" ++ ++msgid "all by date" ++msgstr "tous à la date" ++ ++msgid "Sorting" ++msgstr "Triage" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "Icônes WarEagle" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Position des commandes dans le menu" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Afficher l'entrée valide" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Montrer la barre de progression" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Intervalle de recherche EPG de double(min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Double entrée EPG externe" ++ ++msgid "adjust" ++msgstr "ajuster" ++ ++msgid "delete" ++msgstr "effacer" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mélanger les EPG interne et externe" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Arreter la reconnaissance des événements VPS" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Utiliser le correctif AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Utilisez Sync début patch" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "La carte DVB %d utilise la LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Protocoller l'utilisation du LNB" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Enregistrer en Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Régles de répertoires vidéo" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Nombre de répertoires vidéo" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d prioritaires" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. librei Mo" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Noms de fichiers facile" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Taille max. de l'enregistrement (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Découpe Hard links" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Montrer la date d'enregistrement" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Montrer l'heure d'enregistrement" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Monter la longueur de l'enregistrement" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Montrer la fin du temporisateur" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Ordonner les enregistrement suivant" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Les dossiers devant les enregistrements" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Effacer l'enregistrement après la découpe" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Lecture après saut" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Saut sur les marques de découpes" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause après la dernière marque" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Actualiser les marques" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Longueur de saut en secondes" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Longueur de saut lent en secondes" ++ ++msgid "Setup.Replay$Length" ++msgstr "Longueur" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Longueur / Numéro" ++ ++msgid "Setup.Replay$Number" ++msgstr "Numéro" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "Afficher le DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "Afficher les zéros devant le numéro du DVD" ++ ++msgid "Setup.Replay$never" ++msgstr "jamais" ++ ++msgid "Setup.Replay$on begin" ++msgstr "au début" ++ ++msgid "Setup.Replay$on end" ++msgstr "à la fin" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "au début et à la fin" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Ouvrir le tiroir du lecteur DVD" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Ralentir la vitesse du DVD à" ++ ++msgid "Jump" ++msgstr "Saut" ++ ++msgid "Skip +60s" ++msgstr "Avance +60s" ++ ++msgid "Skip -60s" ++msgstr "Recule -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Découpe déjà active - l'ajouter à la liste de découpe?" ++ ++msgid "Rename$Up" ++msgstr "Haut" ++ ++msgid "Rename$Down" ++msgstr "Bas" ++ ++msgid "Rename$Previous" ++msgstr "Précédent" ++ ++msgid "Rename$Next" ++msgstr "Suivant" ++ ++msgid "Please mount %s" ++msgstr "Mettez %s dans le lecteur" ++ ++msgid "Please mount DVD %04d" ++msgstr "Mettez le DVD %04d dans le lecteur" ++ ++msgid "Please mount DVD %d" ++msgstr "Mettez le DVD %d dans le lecteur" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Un moment SVP. Vérification du DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Pas trouvé de fichiers index. La création de ce ficher prends quelques minutes. Créer?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Attendez, svp. Le fichier index est en cours de création..." ++ ++msgid "Wrong DVD!" ++msgstr "Mauvais DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Timeshift permanent" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Localisation" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "disque dur" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "mémoire" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Taille de la mémoire tampon dans la mémoire (Mo)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Ètendre au disque dur, si nécessaire" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Gardez en veille la mémoire tampon" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Taille de la mémoire tampon sur le disque dur (Mo)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Taille de la mémoire tampon (Mo)" +diff -ruNp vdr-1.6.0-2/po/hr_HR.po vdr-1.6.0-2-extensions/po/hr_HR.po +--- vdr-1.6.0-2/po/hr_HR.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/hr_HR.po 2009-04-09 20:48:26.000000000 +0200 +@@ -1000,3 +1000,270 @@ msgstr "Pritisnite jednu tipku za poni¹t + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR æe se iskljuèiti za %s minuta" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/hu_HU.po vdr-1.6.0-2-extensions/po/hu_HU.po +--- vdr-1.6.0-2/po/hu_HU.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/hu_HU.po 2009-04-09 20:48:26.000000000 +0200 +@@ -1002,3 +1002,270 @@ msgstr "Nyomj egy gombot az újraindítás + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "A VDR leáll %s perc múlva" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/it_IT.po vdr-1.6.0-2-extensions/po/it_IT.po +--- vdr-1.6.0-2/po/it_IT.po 2008-09-11 13:29:43.000000000 +0200 ++++ vdr-1.6.0-2-extensions/po/it_IT.po 2009-04-09 20:48:26.000000000 +0200 +@@ -11,8 +11,8 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-02-10 12:22+0100\n" +-"PO-Revision-Date: 2008-04-17 01:07+0100\n" ++"POT-Creation-Date: 2008-10-05 05:55+0200\n" ++"PO-Revision-Date: 2008-10-05 05:57+0100\n" + "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" + "Language-Team: Italian\n" + "MIME-Version: 1.0\n" +@@ -22,6 +22,9 @@ msgstr "" + msgid "*** Invalid Channel ***" + msgstr "*** Canale NON valido ***" + ++msgid "Channel locked by LNB!" ++msgstr "Canale bloccato dal LNB!" ++ + msgid "Channel not available!" + msgstr "Canale non disponibile!" + +@@ -31,6 +34,253 @@ msgstr "Impossibile avviare mod. trasfer + msgid "Starting EPG scan" + msgstr "Inizio scansione EPG" + ++msgid "Content$Movie/Drama" ++msgstr "Film/Dramma" ++ ++msgid "Content$Detective/Thriller" ++msgstr "Investigativo/Giallo" ++ ++msgid "Content$Adventure/Western/War" ++msgstr "Avventura/Western/Guerra" ++ ++msgid "Content$Science Fiction/Fantasy/Horror" ++msgstr "Finzione/Fantasia/Horror" ++ ++msgid "Content$Comedy" ++msgstr "Commedia" ++ ++msgid "Content$Soap/Melodrama/Folkloric" ++msgstr "Telenovella/Melodramma/Folcloristico" ++ ++msgid "Content$Romance" ++msgstr "Romanzo" ++ ++msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" ++msgstr "Serio/Classico/Religioso/Film storico/Dramma" ++ ++msgid "Content$Adult Movie/Drama" ++msgstr "Film per adulti/Dramma" ++ ++msgid "Content$News/Current Affairs" ++msgstr "Notizie/Ultima ora" ++ ++msgid "Content$News/Weather Report" ++msgstr "Notizie/Previsioni meteo" ++ ++msgid "Content$News Magazine" ++msgstr "Rivista di notizie" ++ ++msgid "Content$Documentary" ++msgstr "Documentario" ++ ++msgid "Content$Discussion/Inverview/Debate" ++msgstr "Discussione/Intervista/Dibattito" ++ ++msgid "Content$Show/Game Show" ++msgstr "Spettacolo/Gioco a premi" ++ ++msgid "Content$Game Show/Quiz/Contest" ++msgstr "Gioco a premi/Quiz/Gara" ++ ++msgid "Content$Variety Show" ++msgstr "Spettacolo di varietà" ++ ++msgid "Content$Talk Show" ++msgstr "Talk Show" ++ ++msgid "Content$Sports" ++msgstr "Sport" ++ ++msgid "Content$Special Event" ++msgstr "Evento speciale" ++ ++msgid "Content$Sport Magazine" ++msgstr "Rivista di sport" ++ ++msgid "Content$Football" ++msgstr "Calcio" ++ ++msgid "Content$Tennis/Squash" ++msgstr "Tennis/Squash" ++ ++msgid "Content$Team Sports" ++msgstr "Sport di squadra" ++ ++msgid "Content$Athletics" ++msgstr "Atletica" ++ ++msgid "Content$Motor Sport" ++msgstr "Sport motoristici" ++ ++msgid "Content$Water Sport" ++msgstr "Sport acquatici" ++ ++msgid "Content$Winter Sports" ++msgstr "Sport invernali" ++ ++msgid "Content$Equestrian" ++msgstr "Equitazione" ++ ++msgid "Content$Martial Sports" ++msgstr "Arti marziali" ++ ++msgid "Content$Children's/Youth Programmes" ++msgstr "Programmi per ragazzi/giovani" ++ ++msgid "Content$Pre-school Children's Programmes" ++msgstr "Programmi per ragazzi prescolastici" ++ ++msgid "Content$Entertainment Programmes for 6 to 14" ++msgstr "Programmi di intrattenimento da 6 a 14" ++ ++msgid "Content$Entertainment Programmes for 10 to 16" ++msgstr "Programmi di intrattenimento da 10 a 16" ++ ++msgid "Content$Informational/Educational/School Programme" ++msgstr "Informativo/Educativo/Programma scolastico" ++ ++msgid "Content$Cartoons/Puppets" ++msgstr "Cartoni/Pupazzi" ++ ++msgid "Content$Music/Ballet/Dance" ++msgstr "Musica/Balletto/Danza" ++ ++msgid "Content$Rock/Pop" ++msgstr "Rock/Pop" ++ ++msgid "Content$Serious/Classical Music" ++msgstr "Serio/Musica classica" ++ ++msgid "Content$Folk/Tradional Music" ++msgstr "Folclore/Musica tradizionale" ++ ++msgid "Content$Jazz" ++msgstr "Jazz" ++ ++msgid "Content$Musical/Opera" ++msgstr "Musical/Opera" ++ ++msgid "Content$Ballet" ++msgstr "Balletto" ++ ++msgid "Content$Arts/Culture" ++msgstr "Arte/Cultura" ++ ++msgid "Content$Performing Arts" ++msgstr "Arti di rendimento" ++ ++msgid "Content$Fine Arts" ++msgstr "Arti fine" ++ ++msgid "Content$Religion" ++msgstr "Religione" ++ ++msgid "Content$Popular Culture/Traditional Arts" ++msgstr "Cultura popolare/Arti tradizionali" ++ ++msgid "Content$Literature" ++msgstr "Letteratura" ++ ++msgid "Content$Film/Cinema" ++msgstr "Film/Cinema" ++ ++msgid "Content$Experimental Film/Video" ++msgstr "Film esperimentale/Video" ++ ++msgid "Content$Broadcasting/Press" ++msgstr "Trasmissione/Stampa" ++ ++msgid "Content$New Media" ++msgstr "Nuovo programma" ++ ++msgid "Content$Arts/Culture Magazines" ++msgstr "Arte/Riviste di cultura" ++ ++msgid "Content$Fashion" ++msgstr "Moda" ++ ++msgid "Content$Social/Political/Economics" ++msgstr "Società/Politica/Economia" ++ ++msgid "Content$Magazines/Reports/Documentary" ++msgstr "Riviste/Reportage/Documentari" ++ ++msgid "Content$Economics/Social Advisory" ++msgstr "Economia/Consulenza sociale" ++ ++msgid "Content$Remarkable People" ++msgstr "Personaggi importanti" ++ ++msgid "Content$Education/Science/Factual" ++msgstr "Educazione/Scienza/Fatti" ++ ++msgid "Content$Nature/Animals/Environment" ++msgstr "Natura/Animali/Ambiente" ++ ++msgid "Content$Technology/Natural Sciences" ++msgstr "Tecnologia/Scienze naturali" ++ ++msgid "Content$Medicine/Physiology/Psychology" ++msgstr "Medicina/Filosofia/Psicologia" ++ ++msgid "Content$Foreign Countries/Expeditions" ++msgstr "Paesi esteri/Spedizioni" ++ ++msgid "Content$Social/Spiritual Sciences" ++msgstr "Società/Scienze spirituali" ++ ++msgid "Content$Further Education" ++msgstr "Altra educazione" ++ ++msgid "Content$Languages" ++msgstr "Lingua" ++ ++msgid "Content$Leisure/Hobbies" ++msgstr "Tempo libero/Hobby" ++ ++msgid "Content$Tourism/Travel" ++msgstr "Turismo/Viaggi" ++ ++msgid "Content$Handicraft" ++msgstr "Artigianato" ++ ++msgid "Content$Motoring" ++msgstr "Motori" ++ ++msgid "Content$Fitness & Health" ++msgstr "Culturismo & Salute" ++ ++msgid "Content$Cooking" ++msgstr "Cucina" ++ ++msgid "Content$Advertisement/Shopping" ++msgstr "Pubblicità/Acquisti" ++ ++msgid "Content$Gardening" ++msgstr "Giardinaggio" ++ ++msgid "Content$Original Language" ++msgstr "Lingua madre" ++ ++msgid "Content$Black & White" ++msgstr "Bianco & Nero" ++ ++msgid "Content$Unpublished" ++msgstr "Non pubblicato" ++ ++msgid "Content$Live Broadcast" ++msgstr "ys" ++ ++msgid "Content$Special Characteristics" ++msgstr "Caratteristiche speciali" ++ ++msgid "Content$Drama" ++msgstr "Dramma" ++ ++#, c-format ++msgid "Suitable for those aged %d and over" ++msgstr "Adatto per coloro con %d di età e oltre" ++ + msgid "No title" + msgstr "Senza titolo" + +@@ -217,6 +467,9 @@ msgstr "Utente8" + msgid "Key$User9" + msgstr "Utente9" + ++msgid "Recording started" ++msgstr "Registrazione avviata" ++ + msgid "Disk" + msgstr "Disco" + +@@ -313,6 +566,9 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Gerarchia" + ++msgid "Parameters" ++msgstr "Parametri" ++ + msgid "Channel settings are not unique!" + msgstr "Parametri canale non univoci!" + +@@ -364,9 +620,21 @@ msgstr "Priorità" + msgid "Lifetime" + msgstr "Durata" + ++msgid "Childlock" ++msgstr "Filtro fam." ++ ++msgid "yes" ++msgstr "sì" ++ ++msgid "no" ++msgstr "no" ++ + msgid "File" + msgstr "Nome" + ++msgid "Path" ++msgstr "Percorso" ++ + msgid "First day" + msgstr "1° giorno" + +@@ -385,6 +653,9 @@ msgstr "Eliminare il timer?" + msgid "Timer still recording - really delete?" + msgstr "Timer in registrazione - eliminare?" + ++msgid "Timer commands" ++msgstr "Comandi timer" ++ + msgid "Event" + msgstr "Evento" + +@@ -445,6 +716,27 @@ msgstr "Riproduci" + msgid "Button$Rewind" + msgstr "Riavvolgi" + ++msgid "Rename recording" ++msgstr "Rinomina registrazione" ++ ++msgid "Date" ++msgstr "Data" ++ ++msgid "Length" ++msgstr "Durata" ++ ++msgid "Size" ++msgstr "Dimensione" ++ ++msgid "Delete marks information?" ++msgstr "Eliminare informazione marcatori?" ++ ++msgid "Delete resume information?" ++msgstr "Eliminare informazione ripristino?" ++ ++msgid "Error while accessing recording!" ++msgstr "Errore accesso alla registrazione!" ++ + msgid "Recordings" + msgstr "Registrazioni" + +@@ -454,8 +746,8 @@ msgstr "Apri" + msgid "Commands" + msgstr "Comandi" + +-msgid "Error while accessing recording!" +-msgstr "Errore accesso alla registrazione!" ++msgid "DVD plugin is not installed!" ++msgstr "Il plugin DVD non è installato!" + + msgid "Delete recording?" + msgstr "Eliminare la registrazione?" +@@ -466,6 +758,21 @@ msgstr "Errore eliminazione registrazion + msgid "Recording commands" + msgstr "Comandi di registrazione" + ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Dir. princ. in ordine alfabetico, sottodir. flessibili" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Dir. princ. per data, sottodir. flessibili" ++ ++msgid "all alphabetically" ++msgstr "Tutte in ordine alfabetico" ++ ++msgid "all by date" ++msgstr "Tutte per data" ++ ++msgid "Sorting" ++msgstr "Ordinamento" ++ + msgid "never" + msgstr "mai" + +@@ -475,6 +782,18 @@ msgstr "in base allo stile interfaccia" + msgid "always" + msgstr "sempre" + ++msgid "default" ++msgstr "predefinito" ++ ++msgid "VDR - text" ++msgstr "VDR - Testo" ++ ++msgid "text" ++msgstr "Testo" ++ ++msgid "VDR - version" ++msgstr "VDR - Versione" ++ + msgid "OSD" + msgstr "OSD" + +@@ -487,6 +806,9 @@ msgstr "Stile interfaccia" + msgid "Setup.OSD$Theme" + msgstr "Tema colori" + ++msgid "Setup.OSD$WarEagle icons" ++msgstr "Icone WarEagle" ++ + msgid "Setup.OSD$Left" + msgstr "Sinistra" + +@@ -556,12 +878,30 @@ msgstr "Tasto Menu per chiudere" + msgid "Setup.OSD$Recording directories" + msgstr "Directory di registrazione" + ++msgid "Setup.OSD$Main menu title" ++msgstr "Titolo menu principale" ++ ++msgid "Setup.OSD$- Text" ++msgstr "- Testo" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Posizione comandi menu princ." ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Mostra ingresso valido" ++ + msgid "EPG" + msgstr "Guida programmi EPG" + + msgid "Button$Scan" + msgstr "Scansione" + ++msgid "blacklist" ++msgstr "lista nera" ++ ++msgid "whitelist" ++msgstr "elenco autorizzati" ++ + msgid "Setup.EPG$EPG scan timeout (h)" + msgstr "Scadenza aggiorn. EPG (ore)" + +@@ -571,6 +911,9 @@ msgstr "Livello correzione EPG" + msgid "Setup.EPG$EPG linger time (min)" + msgstr "Mostra vecchi dati EPG (min)" + ++msgid "Setup.EPG$Show progress bar" ++msgstr "Mostra barra avanzamento" ++ + msgid "Setup.EPG$Set system time" + msgstr "Imposta orario di sistema" + +@@ -585,6 +928,27 @@ msgstr "Lingue preferite" + msgid "Setup.EPG$Preferred language" + msgstr "Lingua preferita" + ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Tempo doppia ricerca EPG (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Doppio valore EPG esterno" ++ ++msgid "adjust" ++msgstr "regola" ++ ++msgid "delete" ++msgstr "elimina" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mescola EPG interno e esterno" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Disabilita esec. evento VPS" ++ ++msgid "Setup.EPG$Mode of noEPG-Patch" ++msgstr "Modalità di noEPG-Patch" ++ + msgid "pan&scan" + msgstr "pan&scan" + +@@ -594,9 +958,6 @@ msgstr "letterbox" + msgid "center cut out" + msgstr "center cut out" + +-msgid "no" +-msgstr "no" +- + msgid "names only" + msgstr "solo nomi" + +@@ -615,6 +976,27 @@ msgstr "nuovi transponder" + msgid "DVB" + msgstr "Scheda DVB" + ++msgid "qam256" ++msgstr "qam256" ++ ++msgid "dvb-c" ++msgstr "dvb-c" ++ ++msgid "dvb-s" ++msgstr "dvb-s" ++ ++msgid "all" ++msgstr "tutti" ++ ++msgid "has decoder" ++msgstr "con decoder" ++ ++msgid "is primary" ++msgstr "primaria" ++ ++msgid "has decoder + is primary" ++msgstr "con decoder e primaria" ++ + msgid "Setup.DVB$Primary DVB interface" + msgstr "Scheda DVB primaria" + +@@ -654,9 +1036,28 @@ msgstr "Trasparenza sottotitoli" + msgid "Setup.DVB$Subtitle background transparency" + msgstr "Trasparenza sfondo sottotitoli" + ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Utilizza correzione AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "Blocco canale" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "Modalità filtro blocco canale" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Utilizza correzione Early Sync" ++ + msgid "LNB" + msgstr "LNB" + ++#, c-format ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "La scheda DVB %d utilizza LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Registra utilizzo LNB" ++ + msgid "Setup.LNB$Use DiSEqC" + msgstr "Utilizza DiSEqC" + +@@ -699,6 +1100,9 @@ msgstr "La CAM è in uso - vuoi reimposta + msgid "Can't reset CAM!" + msgstr "Impossibile reimpostare il modulo CAM!" + ++msgid "request" ++msgstr "chiedi" ++ + msgid "Recording" + msgstr "Registrazione" + +@@ -723,9 +1127,29 @@ msgstr "Priorità di pausa" + msgid "Setup.Recording$Pause lifetime (d)" + msgstr "Durata pausa (gg)" + ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Registra Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Regole directory video" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Numero di directory video" ++ ++#, c-format ++msgid "Setup.Recording$Video %d priority" ++msgstr "Priorità video %d " ++ ++#, c-format ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Min. MB disponibili video %d " ++ + msgid "Setup.Recording$Use episode name" + msgstr "Utilizza nome episodio" + ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Nomi file semplici" ++ + msgid "Setup.Recording$Use VPS" + msgstr "Utilizza VPS" + +@@ -744,9 +1168,39 @@ msgstr "Durata reg. immediata (min)" + msgid "Setup.Recording$Max. video file size (MB)" + msgstr "Dim. massima file video (MB)" + ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Dim. massima reg. (GB)" ++ + msgid "Setup.Recording$Split edited files" + msgstr "Dividi i file modificati" + ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Taglia collegamenti Hard" ++ ++msgid "Setup.Recording$Delete timeshift recording" ++msgstr "Elimina reg. timeshift" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Mostra data registrazione" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Mostra ora registrazione" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Mostra durata registrazione" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Mostra fine del timer" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Ordina registrazioni per" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Ordina directory prima di reg." ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Elimina taglio automatico" ++ + msgid "Replay" + msgstr "Riproduzione" + +@@ -759,6 +1213,63 @@ msgstr "Mostra modalità riproduzione" + msgid "Setup.Replay$Resume ID" + msgstr "ID di ripristino" + ++msgid "Setup.Replay$Jump&Play" ++msgstr "Vai a & Riproduci" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Riproduci & Vai a" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pausa all'ultimo marcatore" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Ricarica marcatori" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Salta secondi" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Salta secondi lentamente" ++ ++msgid "Setup.Replay$Length" ++msgstr "Durata" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Durata / Numero" ++ ++msgid "Setup.Replay$Number" ++msgstr "Numero" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "Mod. visualizzazione DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "Mostra zeri davanti al DVD" ++ ++msgid "Setup.Replay$never" ++msgstr "mai" ++ ++msgid "Setup.Replay$on begin" ++msgstr "all'inizio" ++ ++msgid "Setup.Replay$on end" ++msgstr "alla fine" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "all'inizio e alla fine" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Apri vassoio" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Limita velocità DVD a" ++ ++msgid "Setup.Miscellaneous$only in channelinfo" ++msgstr "solo nelle info canale" ++ ++msgid "Setup.Miscellaneous$only in progress display" ++msgstr "solo nel canale in esec." ++ + msgid "Miscellaneous" + msgstr "Generici" + +@@ -786,9 +1297,54 @@ msgstr "come prima" + msgid "Setup.Miscellaneous$Initial volume" + msgstr "Volume iniziale" + ++msgid "Setup.Miscellaneous$Volume ctrl with left/right" ++msgstr "Controllo volume con Sinistra/Destra" ++ ++msgid "Setup.Miscellaneous$Channelgroups with left/right" ++msgstr "Gruppi canali con Sinistra/Destra" ++ ++msgid "Setup.Miscellaneous$Search fwd/back with left/right" ++msgstr "Cerca avanti/indietro con Sinistra/Destra" ++ + msgid "Setup.Miscellaneous$Emergency exit" + msgstr "Uscita di emergenza" + ++msgid "Setup.Miscellaneous$Lirc repeat delay" ++msgstr "Ritardo ripetizione LIRC" ++ ++msgid "Setup.Miscellaneous$Lirc repeat freq" ++msgstr "Frequenza ripetizione LIRC" ++ ++msgid "Setup.Miscellaneous$Lirc repeat timeout" ++msgstr "Scadenza ripetizione LIRC" ++ ++msgid "Permanent Timeshift" ++msgstr "Timeshift permanente" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Posizione" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "Disco fisso" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "Memoria" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Dim. buffer in memoria (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Utilizza disco fisso se necessario" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Mantieni buffer di pausa" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Dim. buffer nel disco fisso (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Dimensione buffer (MB)" ++ + msgid "Plugins" + msgstr "Plugins" + +@@ -814,7 +1370,6 @@ msgstr "Programmi" + msgid "VDR" + msgstr "VDR" + +-#. TRANSLATORS: note the leading blank! + msgid " Stop replaying" + msgstr " Ferma riproduzione" + +@@ -830,7 +1385,6 @@ msgstr "Ferma" + msgid "Button$Resume" + msgstr "Riprendi" + +-#. TRANSLATORS: note the leading blank! + msgid " Cancel editing" + msgstr " Annulla modifiche" + +@@ -861,10 +1415,22 @@ msgstr "Nessuna periferica DVB disponibi + msgid "Pausing live video..." + msgstr "Pausa del canale in visione..." + ++msgid "Jump" ++msgstr "Vai a" ++ ++msgid "Skip +60s" ++msgstr "Salta +60s" ++ ++msgid "Skip -60s" ++msgstr "Salta - 60s" ++ + #. TRANSLATORS: note the trailing blank! + msgid "Jump: " + msgstr "Vai a: " + ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Taglio in esecuzione - Aggiungere alla coda tagli?" ++ + msgid "No editing marks defined!" + msgstr "Nessun marcatore di modifica definito!" + +@@ -880,9 +1446,6 @@ msgstr "Processo di modifica già attivo! + msgid "FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&" + msgstr " aáàbcdeéèfghiìîjklmnoòpqrstuùvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&°" + +-msgid "yes" +-msgstr "sì" +- + msgid "CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9" + msgstr " 0\t-.,1#~\\^$[]|()*+°?{}/:%@&\taàbc2\tdeèf3\tghiì4\tjkl5\tmnoò6\tpqrs7\ttuùv8\twxyz9" + +@@ -895,6 +1458,18 @@ msgstr "Sovrascrivi" + msgid "Button$Insert" + msgstr "Inserisci" + ++msgid "Rename$Up" ++msgstr "Su" ++ ++msgid "Rename$Down" ++msgstr "Giù" ++ ++msgid "Rename$Previous" ++msgstr "Precedente" ++ ++msgid "Rename$Next" ++msgstr "Successivo" ++ + msgid "Plugin" + msgstr "Plugin" + +@@ -907,6 +1482,30 @@ msgstr "Canale bloccato (in registrazion + msgid "Low disk space!" + msgstr "Poco spazio su disco!" + ++#, c-format ++msgid "Please mount %s" ++msgstr "Monta %s" ++ ++#, c-format ++msgid "Please mount DVD %04d" ++msgstr "Monta il DVD %04d" ++ ++#, c-format ++msgid "Please mount DVD %d" ++msgstr "Monta il DVD %d" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Attendere prego. Verifica DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Nessun indice trovato. La creazione può impiegare alcuni minuti. Crearne uno?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Attendere prego. Creazione indice..." ++ ++msgid "Wrong DVD!" ++msgstr "DVD errato!" ++ + msgid "Can't shutdown - option '-s' not given!" + msgstr "Impossibile spegnere - parametro '-s' non assegnato!" + +@@ -978,9 +1577,6 @@ msgstr "Domenica" + msgid "Upcoming recording!" + msgstr "Registrazione imminente!" + +-msgid "Recording started" +-msgstr "Registrazione avviata" +- + msgid "VDR will shut down later - press Power to force" + msgstr "VDR si spegnerà più tardi - premi Power per forzare" + +@@ -1002,3 +1598,4 @@ msgstr "Premi un tasto per annullare il + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR si spegnerà tra %s minuti" ++ +diff -ruNp vdr-1.6.0-2/po/nl_NL.po vdr-1.6.0-2-extensions/po/nl_NL.po +--- vdr-1.6.0-2/po/nl_NL.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/nl_NL.po 2009-04-09 20:48:26.000000000 +0200 +@@ -1002,3 +1002,270 @@ msgstr "Druk een willekeurige toets om h + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR zal na %s minuten uitschakelen" ++ ++msgid "Channel locked by LNB!" ++msgstr "Kanaal geblokkeerd door LNB" ++ ++msgid "Childlock" ++msgstr "Kinderslot" ++ ++msgid "Path" ++msgstr "Pad" ++ ++msgid "Timer commands" ++msgstr "Timer commando's" ++ ++msgid "Rename recording" ++msgstr "Hernoem opnamen" ++ ++msgid "Date" ++msgstr "Datum" ++ ++msgid "Length" ++msgstr "Lengte" ++ ++msgid "Size" ++msgstr "Grootte" ++ ++msgid "Delete marks information?" ++msgstr "Verwijder informatiemarkeringen?" ++ ++msgid "Delete resume information?" ++msgstr "Verwijder hervattingsmarkeringen?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "DVd plugin is niet geÃnstalleerd!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "hoofdmap alfabetisch, submappen flexibel" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "hoofdmap op datum, submappen flexibel" ++ ++msgid "all alphabetically" ++msgstr "alles alfabetisch" ++ ++msgid "all by date" ++msgstr "alles op datum" ++ ++msgid "Sorting" ++msgstr "Sortering" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle symbolen" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Positie commandobalk in hoofdmenu" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Toon geldige invoer" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Toon voortschreidingsbalk" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Tijdsduur starten dubbele EPG zoekactie (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "externe dubbele EPG invoer" ++ ++msgid "adjust" ++msgstr "afstellen" ++ ++msgid "delete" ++msgstr "verwijderen" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mix in- en externe EPG" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Schakel aktieve VPS uitzending uit" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Gebruik AC3-Transfer Fix" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Gebruik 'Sync Early' Patch" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "LNB kaart %d gebruikt LNB Nr." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Houd LNB gebruik bij" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Neem Dolby Digital spoor op" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Omgang m.b.t. Videomappen" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Aantal videomappen" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d prioriteit" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. vrij MB" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Handzame bestandsnamen" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Max. opnamegrootte (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "'Hard link' bestandsbewerker" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Toon datum" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Toon tijd" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Toon lengte" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Toon einde van timers" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Sorteer opnames op" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Sorteer mappen vÃÃr opnames" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Bestandsbewerker automatisch wissen" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Spring&Speel" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Speel&Spring" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pauzeer bij laatste markering" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Herlaadt markeringen" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Spring seconden" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Spring seconden langzaam" ++ ++msgid "Setup.Replay$Length" ++msgstr "Lengte" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Lengte / Nummer" ++ ++msgid "Setup.Replay$Number" ++msgstr "Nummer" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "DVD displayinstellingen" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "DVD toon voorloopnullen" ++ ++msgid "Setup.Replay$never" ++msgstr "nooit" ++ ++msgid "Setup.Replay$on begin" ++msgstr "aan het begin" ++ ++msgid "Setup.Replay$on end" ++msgstr "bij het einde" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "bij het begin en aan het einde" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Open DVD lade" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Beperk DVD omw. snelheid" ++ ++msgid "Jump" ++msgstr "Spring" ++ ++msgid "Skip +60s" ++msgstr "Spring +60s verder" ++ ++msgid "Skip -60s" ++msgstr "Spring -60s terug" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Bestandsbewerker aktief - aan wachtrij toeveogen?" ++ ++msgid "Rename$Up" ++msgstr "Boven" ++ ++msgid "Rename$Down" ++msgstr "Onder" ++ ++msgid "Rename$Previous" ++msgstr "Vorige" ++ ++msgid "Rename$Next" ++msgstr "Volgende" ++ ++msgid "Please mount %s" ++msgstr "Koppel %s aan a.u.b." ++ ++msgid "Please mount DVD %04d" ++msgstr "Koppel DVD %04d aan a.u.b." ++ ++msgid "Please mount DVD %d" ++msgstr "Koppel DVD %d aan a.u.b." ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Even wachten, DVD wordt gecontroleerd..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Geen indexbestand gevonden. Aanmaken duurt even, doorgaan?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Even wachten indexbestand wordt aangemaakt..." ++ ++msgid "Wrong DVD!" ++msgstr "Verkeerde DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Permanente livebuffer" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Opslaglocatie" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "hardeschijf" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "geheugen" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Buffergrootte in geheugen (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Overlopen naar hardeschijf indien noodzakelijk" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Bewaar gepauzeerde buffer" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Buffergrootte op harddisk (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Buffergrootte (MB)" +diff -ruNp vdr-1.6.0-2/po/nn_NO.po vdr-1.6.0-2-extensions/po/nn_NO.po +--- vdr-1.6.0-2/po/nn_NO.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/nn_NO.po 2009-04-09 20:48:26.000000000 +0200 +@@ -999,3 +999,270 @@ msgstr "" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/pl_PL.po vdr-1.6.0-2-extensions/po/pl_PL.po +--- vdr-1.6.0-2/po/pl_PL.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/pl_PL.po 2009-04-09 20:48:26.000000000 +0200 +@@ -999,3 +999,270 @@ msgstr "Naci¶nij dowolny klawisz aby nie + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR zostanie wy³±czony za %s minut" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/pt_PT.po vdr-1.6.0-2-extensions/po/pt_PT.po +--- vdr-1.6.0-2/po/pt_PT.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/pt_PT.po 2009-04-09 20:48:26.000000000 +0200 +@@ -998,3 +998,270 @@ msgstr "Pressione qualquer tecla para nã + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR vai desligar em %s minutos" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/ro_RO.po vdr-1.6.0-2-extensions/po/ro_RO.po +--- vdr-1.6.0-2/po/ro_RO.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/ro_RO.po 2009-04-09 20:48:26.000000000 +0200 +@@ -1001,3 +1001,270 @@ msgstr "Apãsaþi orice tastã pentru a anu + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se va închide în %s minute" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/ru_RU.po vdr-1.6.0-2-extensions/po/ru_RU.po +--- vdr-1.6.0-2/po/ru_RU.po 2008-03-23 11:31:29.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/ru_RU.po 2009-04-09 20:48:26.000000000 +0200 +@@ -999,3 +999,271 @@ msgstr "½ÐÖÜØâÕ ÛîÑãî ÚÝÞßÚã ÔÛï ÞâÜÕÝë + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR ÒëÚÛîçØâáï çÕàÕ× %s ÜØÝãâ" ++ ++msgid "Channel locked by LNB!" ++msgstr "ºÞÝÒÕàâÕà ÑÛÞÚØàãÕâ ÚÐÝÐÛ" ++ ++msgid "Childlock" ++msgstr "´ÕâáÚÐï ÑÛÞÚØàÞÒÚÐ" ++ ++msgid "Path" ++msgstr "¿ãâì" ++ ++msgid "Timer commands" ++msgstr "ºÞÜÜÐÝÔë âÐÙÜÕàÐ" ++ ++msgid "Rename recording" ++msgstr "¿ÕàÕØÜÕÝÞÒÐâì ×Ðߨáì" ++ ++msgid "Date" ++msgstr "´ÐâÐ" ++ ++msgid "Length" ++msgstr "´ÛØÝÐ" ++ ++msgid "Size" ++msgstr "ÀÐ×ÜÕà" ++ ++msgid "Delete marks information?" ++msgstr "ÃÔÐÛØâì ÜÕâÚØ?" ++ ++msgid "Delete resume information?" ++msgstr "²ÞááâÐÝÞÒØâì ÜÕâÚØ?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "¼ÞÔãÛì DVD ÝÕ ãáâÐÝÞÒÛÕÝ!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÐÛäÐÒØâã, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÒàÕÜÕÝØ, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" ++ ++msgid "all alphabetically" ++msgstr "ÒáÕ ßÞ ÐÛäÐÒØâã" ++ ++msgid "all by date" ++msgstr "ÒáÕ ßÞ ÒàÕÜÕÝØ" ++ ++msgid "Sorting" ++msgstr "ÁÞàâØàÞÒÚÐ" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle ØÚÞÝÚØ" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "ÀÐ×ÜÕéÕÝØÕ ÚÞÜÐÝÔ Ò ÓÛÐÒÝÞÜ ÜÕÝî" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "¿ÞÚÐ× ßàÐÒØÛìÝÞÓÞ ÒÒÞÔÐ" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "¿ÞÚÐ× ÑÐÛÚØ ßàÞÓàÕááÐ" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "¿ÕàØÞÔ ÔÛï ßÞØáÚÐ ÔÒÞÙÝëå EPG(min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "²ÝÕèÝØÙ ØáâÞçÝØÚ ÔÒÞÙÝÞÓÞ EPG" ++ ++msgid "adjust" ++msgstr "ÝÐáâàÞØâì" ++ ++msgid "delete" ++msgstr "ãÔÐÛØâì" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "ÁÜÕèØÒÐÝØÕ ÒÝãâàÕÝÝÕÓÞ Ø ÒÝÕèÝÕÓÞ EPG" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "·ÐßàÕâ VPS áÞÑëâØï" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "¸áßÞÛì×ÞÒÐâì ÚÞààÕÚâØàÞÒÚã AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "¸áßÞÛì×ÞÒÐâì Sync Early " ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "DVB ãáâàÞÙáâÒÞ %d ØáßÞÛì×ãÕâ LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "»ÞÓØàÞÒÐÝØÕ ØáßÞÛì×ÞÒÐÝØï LNB" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "·Ðߨáì Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "¿ÞàïÔÞÚ ÒØÔÕÞ ÔØàÕÚâÞàØØ" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "ºÞÛØçÕáâÒÞ ÒØÔÕÞ ÔØàÕÚâÞàØÙ" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d ßàØÞàØâÕâ" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d ÜØÝ. áÒÞÑÞÔÝÞ MB" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "ÇØâÐÑÕÛìÝëÕ ØÜÕÝÐ äÐÙÛÞÒ" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "¼ÐÚá. àÐ×ÜÕà ×ÐßØáØ (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "¼ÞÝâÐÖ á hard link" ++ ++msgid "Setup.Recording$Show date" ++msgstr "¿ÞÚÐ×ëÒÐâì ÔÐâã" ++ ++msgid "Setup.Recording$Show time" ++msgstr "¿ÞÚÐ×ëÒÐâì ÒàÕÜï ×ÐߨáØ" ++ ++msgid "Setup.Recording$Show length" ++msgstr "¿ÞÚÐ×ëÒÐâì ßàÞÔÞÛÖØâÕÛìÝÞáâì ×ÐߨáØ" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "½Ð×ÒÐÝØÕ ÓÛÐÒÝÞÓÞ ÜÕÝî" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "¿ÞÚÐ× ÞÚÞÝçÐÝØï âÐÙÜÕàÐ" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "ÁÞàâØàÞÒÚÐ ×ÐߨáÕÙ ßÞ" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "ÁÞàâØàÞÒÚÐ ÔØàÕÚâÞàØÙ ÔÞ ×ÐߨáØ" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "°ÒâÞÜÐâØçÕáÚÞÕ ãÔÐÛÕÝØÕ ÜÞÝâÐÖÐ" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Jump&Play" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Play&Jump" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "¿Ðã×Ð ÝÐ ßÞáÛÕÔÝÕÙ ÜÕâÚÕ" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "¿ÕàÕÓàãרâì ÜÕâÚØ" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "¿àÞßãáÚ áÕÚãÝÔ" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "¿àÞßãáÚ áÕÚãÝÔ ÜÕÔÛÕÝÝÞ" ++ ++msgid "Setup.Replay$Length" ++msgstr "´ÛØÝÐ" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "´ÛØÝÐ / ½ÞÜÕà" ++ ++msgid "Setup.Replay$Number" ++msgstr "½ÞÜÕà" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "ÀÕÖØÜ ßÞÚÐ×Ð DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "ßÞÚÐ× ÒÕÔãéØå ÝãÛÕÙ" ++ ++msgid "Setup.Replay$never" ++msgstr "ÝØÚÞÓÔÐ" ++ ++msgid "Setup.Replay$on begin" ++msgstr "Ò ÝÐçÐÛÕ" ++ ++msgid "Setup.Replay$on end" ++msgstr "² ÚÞÝæÕ" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "Ò ÝÐçÐÛÕ Ø Ò ÚÞÝæÕ" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "¾âÚàëâì" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "¿àÕÔÕÛ áÚÞàÞáâØ DVD" ++ ++msgid "Jump" ++msgstr "¿àëÖÞÚ" ++ ++msgid "Skip +60s" ++msgstr "¿àÞßãáÚ +60s" ++ ++msgid "Skip -60s" ++msgstr "¿àÞßãáÚ -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "¼ÞÝâÐÖÕà àÐÑÞâÐÕâ - ´ÞÑÐÒØâì Ò ÞçÕàÕÔì?" ++ ++msgid "Rename$Up" ++msgstr "²ÒÕàå" ++ ++msgid "Rename$Down" ++msgstr "²ÝØ×" ++ ++msgid "Rename$Previous" ++msgstr "¿àÕÔëÔãéØÙ" ++ ++msgid "Rename$Next" ++msgstr "ÁÛÕÔãîéØÙ" ++ ++msgid "Please mount %s" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ %s" ++ ++msgid "Please mount DVD %04d" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %04d" ++ ++msgid "Please mount DVD %d" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %d" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ¿àÞÒÕàÚÐ DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "¸ÝÔÕÚá äÐÙÛ ÝÕ ÝÐÙÔÕÝ. ÁÞ×ÔÐÝØÕ âàÕÑãÕâ ÒàÕÜÕÝØ. ÁÞ×ÔÐâì?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ÁÞ×ÔÐÝØÕ ØÝÔÕÚá äÐÙÛÐ..." ++ ++msgid "Wrong DVD!" ++msgstr "¾èØÑÚÐ DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "¿ÞáâÞïÝÝëÙ âÐÙÜèØäâ" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "¼ÕáâÞÝÐåÞÖÔÕÝØï" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "ÖÕáâÚØÙ ÔØáÚ" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "ßÐÜïâì" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ Ò ßÐÜïâØ (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "´ÞÑÐÒÛïâì ÖÕáâÚØÙ ÔØáÚ ÕáÛØ ÝÕÞÑåÞÔØÜÞ" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "ÅàÐÝÕÝØÕ ÑãäÕàÐ ßÐã×ë" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ ÝÐ ÖÕáâÚÞÜ ÔØáÚÕ (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ (MB)" ++ +diff -ruNp vdr-1.6.0-2/po/sl_SI.po vdr-1.6.0-2-extensions/po/sl_SI.po +--- vdr-1.6.0-2/po/sl_SI.po 2008-03-23 11:31:30.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/sl_SI.po 2009-04-09 20:48:26.000000000 +0200 +@@ -999,3 +999,270 @@ msgstr "Pritisni katerokoli tipko za pre + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se bo zaustavil v %s minutah" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/sv_SE.po vdr-1.6.0-2-extensions/po/sv_SE.po +--- vdr-1.6.0-2/po/sv_SE.po 2008-03-23 11:31:30.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/sv_SE.po 2009-04-09 20:48:26.000000000 +0200 +@@ -1001,3 +1001,270 @@ msgstr "Tryck valfri knapp för att återk + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR kommer att stängas ned om %s minuter" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/po/tr_TR.po vdr-1.6.0-2-extensions/po/tr_TR.po +--- vdr-1.6.0-2/po/tr_TR.po 2008-03-23 11:31:30.000000000 +0100 ++++ vdr-1.6.0-2-extensions/po/tr_TR.po 2009-04-09 20:48:26.000000000 +0200 +@@ -998,3 +998,270 @@ msgstr "Yeniden baþlatmayý iptal etmek i + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR %s dakikada kapanacak" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.6.0-2/README.cmdsubmenu vdr-1.6.0-2-extensions/README.cmdsubmenu +--- vdr-1.6.0-2/README.cmdsubmenu 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/README.cmdsubmenu 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,54 @@ ++CmdSubmenu patch for VDR ++------------------------ ++ ++With this patch the commands and recording commands menus can be organised ++hierarchically. To create a submenu entry, prefix the name by one ore more "-". ++ ++ ++Standard: ++ ++description_1 : cmd_1 ++description_2 : cmd_2 ++ ++ ++A submenu with two entries: ++ ++Submenu title ... : echo "submenu" ++-description_1 : cmd_1 ++-description_2 : cmd_2 ++ ++The dummy command in the title row is necessary. ++ ++ ++* History ++ ++ 2003-10-08: Version 0.1 - Albu at vdrportal.de ++ http://vdrportal.de/board/thread.php?threadid=6319 ++ ++ 2003-10-09: Version 0.2 - Tobias Grimm <tg@e-tobi.net> ++ - Added Define CMD_SUBMENUS in Makefile ++ ++ 2004-05-28: Version 0.3 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed compilation with gcc-3.3.3 ++ - Added new virtual method AddConfig in cConfig ++ - Redefining of method Add in cListBase to virtual no longer necessary ++ - Improved code in menu.c ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.3.diff ++ ++ 2004-12-20: Version 0.4 - Thomas Günther <tom@toms-cafe.de> ++ - Solved conflict with jumpplay patch 0.6 ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.4.diff ++ ++ 2006-04-22: Version 0.5 - Thomas Günther <tom@toms-cafe.de> ++ - Added version define CMDSUBMENUVERSNUM ++ - Reformated to VDR style indentions ++ - Added description in README.cmdsubmenu ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.5-1.3.47.diff ++ ++ 2006-04-23: Version 0.6 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed menus with more than one level ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.6-1.3.47.diff ++ ++ 2006-05-15: Version 0.7 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed build with G++ 4.1 (extra qualification) ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.7-1.4.0.diff +diff -ruNp vdr-1.6.0-2/README-HLCUTTER vdr-1.6.0-2-extensions/README-HLCUTTER +--- vdr-1.6.0-2/README-HLCUTTER 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/README-HLCUTTER 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,117 @@ ++ ++ VDR-HLCUTTER README ++ ++ ++Written by: Udo Richter ++Available at: http://www.udo-richter.de/vdr/patches.html#hlcutter ++ http://www.udo-richter.de/vdr/patches.en.html#hlcutter ++Contact: udo_richter@gmx.de ++ ++ ++ ++About ++----- ++ ++The hard link cutter patch changes the recording editing algorithms of VDR to ++use filesystem hard links to 'copy' recording files whenever possible to speed ++up editing recordings noticeably. ++ ++The patch has matured to be quite stable, at least I'm using it without issues. ++Nevertheless the patch is still in development and should be used with caution. ++The patch is EXPERIMENTAL for multiple /videoxx folders. The safety checks ++should prevent data loss, but you should always carefully check the results. ++ ++While editing a recording, the patch searches for any 00x.vdr files that dont ++contain editing marks and would normally be copied 1:1 unmodified to the edited ++recording. In this case the current target 00x.vdr file will be aborted, and ++the cutter process attempts to duplicate the source file as a hard link, so ++that both files share the same disk space. If this succeeds, the editing ++process fast-forwards through the duplicated file and continues normally ++beginning with the next source file. If hard linking fails, the cutter process ++continues with plain old copying. (but does not take up the aborted last file.) ++ ++After editing, the un-edited recording can be deleted as usual, the hard linked ++copies will continue to exist as the only remaining copy. ++ ++To be effective, the default 'Max. video file size (MB)' should be lowered. ++The patch lowers the smallest possible file size to 1mb. Since VDR only ++supports up to 255 files, this would limit the recording size to 255Mb or ++10 minutes, in other words: This setting is insane! ++ ++To make sure that the 255 file limit will not be reached, the patch also ++introduces "Max. recording size (GB)" with a default of 100Gb (66 hours), and ++increases the file size to 2000Mb early enough, so that 100Gb-recordings will ++fit into the 255 files. ++ ++Picking the right parameters can be tricky. The smaller the file size, the ++faster the editing process works. However, with a small file size, long ++recordings will fall back to 2000Mb files soon, that are slow on editing again. ++ ++Here are some examples: ++ ++Max file size: 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb ++Max recording size: 1Mb 10Mb 20Mb 30Mb 40Mb 50Mb 100Mb ++ ++Small files: 1-203 1-204 1-205 1-206 1-207 1-209 1-214 ++ GBytes: 0.2 2.0 4.0 6.0 8.1 10.2 20.9 ++ Hours: 0.13 1.3 2.65 4 5.4 6.8 13.9 ++ ++Big (2000mb) files: 204-255 204-255 206-255 207-255 208-255 210-255 215-255 ++ GBytes: 101.5 99.6 97.7 95.7 93.8 89.8 80.1 ++ Hours: 67 66 65 63 62 60 53 ++ ++A recording limit of 100Gb keeps plenty of reserve without blocking too much ++file numbers. And with a file size of 30-40Mb, recordings of 4-5 hours fit into ++small files completely. (depends on bit rate of course) ++ ++ ++ ++The patch must be enabled in Setup-> Recordings-> Hard Link Cutter. When ++disabled, the cutter process behaves identical to VDR's default cutter. ++ ++There's a //#define HARDLINK_TEST_ONLY in the videodir.c file that enables a ++test-mode that hard-links 00x.vdr_ files only, and continues the classic ++editing. The resulting 00x.vdr and 00x.vdr_ files should be identical. If you ++delete the un-edited recording, dont forget to delete the *.vdr_ files too, ++they will now eat real disk space. ++ ++Note: 'du' displays the disk space of hard links only on first appearance, and ++usually you will see a noticeably smaller size on the edited recording. ++ ++ ++History ++------- ++Version 0.2.0 ++ ++ New: Support for multiple /videoXX recording folders, using advanced searching ++ for matching file systems where a hard link can be created. ++ Also supports deep mounted file systems. ++ Fix: Do not fail if last mark is a cut-in. (Again.) ++ ++Version 0.1.4 ++ New: Dynamic increase of file size before running out of xxx.vdr files ++ Fix: Last edit mark is not a cut-out ++ Fix: Write error if link-copied file is smaller than allowed file size ++ Fix: Broken index/marks if cut-in is at the start of a new file ++ Fix: Clear dangeling pointer to free'd cUnbufferedFile, ++ thx to Matthias Schwarzott ++ ++Version 0.1.0 ++ Initial release ++ ++ ++ ++ ++Future plans ++------------ ++ ++Since original and edited copy share disk space, free space is wrong if one of ++them is moved to *.del. Free space should only count files with hard link ++count = 1. This still goes wrong if all copies get deleted. ++ ++ ++For more safety, the hard-linked files may be made read-only, as modifications ++to one copy will affect the other copy too. (except deleting, of course) ++ ++ ++SetBrokenLink may get lost on rare cases, this needs some more thoughts.Index: vdr-1.5.9/README.jumpplay +diff -ruNp vdr-1.6.0-2/README.jumpplay vdr-1.6.0-2-extensions/README.jumpplay +--- vdr-1.6.0-2/README.jumpplay 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/README.jumpplay 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,92 @@ ++JumpPlay patch for VDR ++---------------------- ++ ++This patch changes the replay behaviour for recordings that contain editing ++marks. It allows to immediately continue the replay after jumping forward to ++the next mark, and to automatically jump over the commercial break to the next ++"start" mark, if an "end" mark is reached. ++ ++The features of this patch can be turned on or off with parameters in the replay ++setup. See MANUAL for description of this parameters: "Jump&Play", "Play&Jump", ++"Pause at last mark" and "Reload marks". ++ ++ ++* History ++ ++ 2003-07-04: jumpandrun.diff - the Noad <theNoad@SoftHome.net> ++ Jump&Play ++ ++ 2003-12-06: Version 0.0 - Torsten Kunkel <vdr@tkunkel.de> ++ Play&Jump (only if progressbar is visible) ++ Setup parameters Jump&Play and Play&Jump in the replay setup ++ ++ 2004-01-20: Version 0.1 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed speed after jump ++ - fixed removing of marks ++ Play&Jump: ++ - jump only on "end" marks ++ ++ 2004-01-27: Version 0.2 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed double jump ++ Play&Jump: ++ - fixed mark detection: fuzzy detection (until 3 seconds after mark) ++ - jump without progressbar ++ - mode "progressbar only" for old behaviour ++ ++ 2004-01-31: Version 0.3 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed display frames ++ Play&Jump: ++ - fixed end of playing at last mark ++ ++ 2004-07-11: Version 0.4 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - don't play after jump to end ++ Play&Jump: ++ - don't prevent jumping after hide or show ++ Less conflicts with other patches (Elchi/AutoPID) ++ ++ 2004-08-21: Version 0.5 - Thomas Günther <tom@toms-cafe.de> ++ Play&Jump: ++ - exact jumps, replay like edited recording (no fuzzy mark detection) ++ - jump to first mark if replay starts at the beginning ++ - check jump marks with '8' key ++ - mode "progressbar only" removed ++ Description in README.jumpplay ++ ++ 2004-12-28: Version 0.6 - Thomas Günther <tom@toms-cafe.de> ++ Adapted noad extensions (from the Noad <theNoad@SoftHome.net>) to ++ jumpplay-0.5: ++ - cyclic reloading of marks found by noad online-scan ++ - don't stop after the last mark in case of live-recordings ++ New setup parameter "Load marks interval (s)" ++ Updated description in README.jumpplay ++ ++ 2006-04-14: Version 0.7 - Thomas Günther <tom@toms-cafe.de> ++ Fixed jump to first mark (crashed with plugin extrecmenu-0.9) ++ Added version define JUMPPLAYVERSNUM ++ Added placeholders for Czech language texts ++ Cleaned up i18n entries (support only VDR >= 1.3.29) ++ Improved description of i18n placeholders - hoping for real language texts ++ ++ 2006-05-12: Version 0.8 - Thomas Günther <tom@toms-cafe.de> ++ Fixed segfault in dvbplayer thread while the replaycontrol thread is ++ reloading the marks (thanks to horchi at vdrportal.de for reporting this - ++ see http://vdrportal.de/board/thread.php?postid=450463#post450463): ++ New class cMarksReload checks the timestamp of marks.vdr in 10 seconds ++ intervals, so the marks in the threads dvbplayer and replaycontrol can be ++ reloaded independently ++ Changed setup parameter "Load marks interval (s)" to "Reload marks" ++ Updated description in README.jumpplay ++ ++ 2006-05-28: Version 0.9 - Thomas Günther <tom@toms-cafe.de> ++ New setup parameter "Pause at last mark" ++ Updated description in README.jumpplay ++ Moved parameters description to MANUAL ++ ++ 2009-03-31: Version 1.0 - Thomas Günther <tom@toms-cafe.de> ++ Play&Jump: ++ - set resume position to 0 if replay stops at the first mark ++ Added French language texts (thanks to Michaël Nival) +diff -ruNp vdr-1.6.0-2/README.MainMenuHooks vdr-1.6.0-2-extensions/README.MainMenuHooks +--- vdr-1.6.0-2/README.MainMenuHooks 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/README.MainMenuHooks 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,55 @@ ++This is a "patch" for the Video Disk Recorder (VDR). ++ ++* Authors: ++Tobias Grimm <vdr at e-tobi dot net> ++Martin Prochnow <nordlicht at martins-kabuff dot de> ++Frank Schmirler <vdrdev at schmirler dot de> ++Christian Wieninger <cwieninger at gmx dot de> ++ ++* Description: ++This patch allows plugins to replace the VDR mainmenus "Schedule", ++"Channels", "Timers" and "Recordings" by a different implementation. ++ ++The patch is based on a suggestion of Christian Wieninger back in 2006 ++(http://www.linuxtv.org/pipermail/vdr/2006-March/008234.html). It is ++meant to be an interim solution for VDR 1.4 until (maybe) VDR 1.5 ++introduces an official API for this purpose. ++ ++* Installation ++Change into the VDR source directory, then issue ++ patch -p1 < path/to/MainMenuHooks-v1_0.patch ++and recompile. ++ ++* Notes for plugin authors ++The following code sample shows the required plugin code for replacing ++the original Schedule menu: ++ ++bool cMyPlugin::Service(const char *Id, void *Data) ++{ ++ cOsdMenu **menu = (cOsdMenu**) Data; ++ if (MySetup.replaceSchedule && ++ strcmp(Id, "MainMenuHooksPatch-v1.0::osSchedule") == 0) { ++ if (menu) ++ *menu = (cOsdMenu*) MainMenuAction(); ++ return true; ++ } ++ return false; ++} ++ ++A plugin can replace more than one menu at a time. Simply replace the ++call to MainMenuAction() in the sample above by appropriate code. ++ ++Note that a plugin *should* offer a setup option which allows the user ++to enable or disable the replacement. "Disabled" would be a reasonable ++default setting. By testing for define MAINMENUHOOKSVERSNUM, a plugin ++can leave the setup option out at compiletime. ++ ++In case there is an internal problem when trying to open the replacement ++menu, it is safe to return true even though Data is NULL. However an ++OSD message should indicate the problem to the user. ++ ++Feel free to ship this patch along with your plugin. However if you ++think you need to modify the patch, we'd encourage you to contact the ++authors first or at least use a service id which differs in more than ++just the version number. ++ +diff -ruNp vdr-1.6.0-2/README.sortrec vdr-1.6.0-2-extensions/README.sortrec +--- vdr-1.6.0-2/README.sortrec 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/README.sortrec 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,48 @@ ++Sort Recordings patch for VDR ++----------------------------- ++Copyright (C) 2005 Frank99 @vdr-portal.de ++Copyright (C) 2006-2008 Christoph Haubrich ++ ++Released under the same license as VDR itself, for details see vdr.c or ++http://firefly.vdr-developer.org/patches ++ ++This patch changes the sort behaviour of the recordings menu. It is based ++on the patch available here: http://www.vdr-portal.de/board/thread.php?threadid=36031 ++Required for this patch is the liemikuutio-patch for VDR which can be found here: ++http://www.saunalahti.fi/%7Erahrenbe/vdr/patches/ ++ ++There are four sorting modes available after this patch is applied: ++ ++mode behaviour for behaviour for ++ main directory sub directories ++-------------------------------------------------------------------------- ++ 0 alphabetically if special character(*) is found alphabetically, ++ else by date ++ 1 by date if special character(*) is found alphabetically, ++ else by date ++ 2 alphabetically alphabetically ++ 3 by date by date ++ ++(*) if the name of a subdirectory ends with one of ".-$" (dot, hyphen, dollar sign) ++ it is sorted alphabetically in sort mode 0 and 1 ++ ++Sort mode 0 with none of the special characters at the end of any subdir ++corresponds to the default sorting mode of the original VDR. ++ ++The sorting mode can be switched through in the recording menu with the '0' key ++(0->1->2->3->0->...), a default for startup can be set in the setup->recordings menu. ++ ++Additionally the sort order (ascending/descending) can be toggled by the '9' key ++(which is always set to ascending after a restart) ++ ++If you like the to see subdirectories before recordings you can select to put ++directories first in the setup->recordings menu. ++ ++If you would like the sorting to ignore a leading '%' (as normally displayed before ++cutted recordings) you can achive this by setting the environment variable LC_COLLATE ++properly (eg. LC_COLLATE=de_DE@euo in runvdr for germany). ++ ++History: ++2006-08-13 v3, sortrec release for VDR 1.4.1 and liemikuutio 1.8 ++2007-01-28 v3a, moved #ifdef from optimized-rename-patch to sortrec ++2008-03-29 v3b, removed ASCII-170 and ASCII-183 to make sortrec Utf8-ready +diff -ruNp vdr-1.6.0-2/README.timer-info vdr-1.6.0-2-extensions/README.timer-info +--- vdr-1.6.0-2/README.timer-info 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/README.timer-info 2009-04-09 20:48:26.000000000 +0200 +@@ -0,0 +1,53 @@ +++------------------------------------------------------------------------------+ ++| Info about the timer-info-patch by Brougs78 | ++| brougs78@gmx.net / home.pages.at/brougs78 | +++------------------------------------------------------------------------------+ ++ ++ ++README timer-info: ++------------------ ++ ++Features: ++ - Shows info, if it is possible to record an event in the timer menu of vdr. ++ For calculations the free space incl. the deleted recordings is used, ++ considering an average consumtion of 25.75 MB/min (also used by vdr itself). ++ The first column in the timer-list shows: ++ ( + ) recording will be most probably possible (enough space) ++ (+/-) recording may be possible ++ ( - ) recording will most probably fail (to less space) ++ The calculations also consider repeating timers. ++ - It is possible to deactivate the patch in the OSD-menu of VDR. ++ ++ ++HISTORY timer-info: ++------------------- ++ ++25.11.2004: v0.1 ++ - Initial release ++ ++11.01.2005: v0.1b ++ - Bugfixes for vdr-1.3.18 ++ - In the menu the free recording-time no longer includes the space of the ++ deleted recordings, because this slowed the vdr down to much. ++ ++08.07.2005: v0.1c ++ - Made the patch configurable ++ ++29.01.2006: v0.2 - Thomas Günther <tom@toms-cafe.de> ++ - Rewritten great parts for vdr-1.3.38+ ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.2-1.3.38+.diff ++ ++05.02.2006: v0.3 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed refresh of timer menu in cMenuTimers::OnOff ++ - Fixed check of repeating timers ++ - Syslog debug messages can be enabled with Define DEBUG_TIMER_INFO ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.3-1.3.38+.diff ++ ++03.03.2006: v0.4 - Thomas Günther <tom@toms-cafe.de> ++ - Adapted to vdr-1.3.44 ++ - Removed setup parameter "Show timer-info" ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.44.diff ++ ++03.03.2006: v0.5 - Tobias Grimm <tg@e-tobi.net> ++ - Adapted to vdr-1.3.45 ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.45.diff +diff -ruNp vdr-1.6.0-2/recorder.c vdr-1.6.0-2-extensions/recorder.c +--- vdr-1.6.0-2/recorder.c 2007-02-24 17:36:24.000000000 +0100 ++++ vdr-1.6.0-2-extensions/recorder.c 2009-04-09 20:48:27.000000000 +0200 +@@ -11,6 +11,9 @@ + #include <stdarg.h> + #include <stdio.h> + #include <unistd.h> ++#ifdef USE_TTXTSUBS ++#include <stdint.h> ++#endif /* TTXTSUBS */ + #include "shutdown.h" + + #define RECORDERBUFSIZE MEGABYTE(5) +@@ -26,6 +29,9 @@ + + class cFileWriter : public cThread { + private: ++#ifdef USE_TTXTSUBS ++ cTtxtSubsRecorderBase *ttxtSubsRecorder; ++#endif /* TTXTSUBS */ + cRemux *remux; + cFileName *fileName; + cIndexFile *index; +@@ -38,13 +44,24 @@ private: + protected: + virtual void Action(void); + public: ++#ifdef USE_TTXTSUBS ++ cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr); ++#else + cFileWriter(const char *FileName, cRemux *Remux); ++#endif /* TTXTSUBS */ + virtual ~cFileWriter(); + }; + ++#ifdef USE_TTXTSUBS ++cFileWriter::cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr) ++#else + cFileWriter::cFileWriter(const char *FileName, cRemux *Remux) ++#endif /* TTXTSUBS */ + :cThread("file writer") + { ++#ifdef USE_TTXTSUBS ++ ttxtSubsRecorder = tsr; ++#endif /* TTXTSUBS */ + fileName = NULL; + remux = Remux; + index = NULL; +@@ -67,6 +84,10 @@ cFileWriter::~cFileWriter() + Cancel(3); + delete index; + delete fileName; ++#ifdef USE_TTXTSUBS ++ if (ttxtSubsRecorder) ++ delete ttxtSubsRecorder; ++#endif /* TTXTSUBS */ + } + + bool cFileWriter::RunningLowOnDiskSpace(void) +@@ -85,7 +106,11 @@ bool cFileWriter::RunningLowOnDiskSpace( + bool cFileWriter::NextFile(void) + { + if (recordFile && pictureType == I_FRAME) { // every file shall start with an I_FRAME ++#ifndef USE_HARDLINKCUTTER + if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { ++#else ++ if (fileSize > fileName->MaxFileSize() || RunningLowOnDiskSpace()) { ++#endif /* HARDLINKCUTTER */ + recordFile = fileName->NextFile(); + fileSize = 0; + } +@@ -111,6 +136,18 @@ void cFileWriter::Action(void) + } + fileSize += Count; + remux->Del(Count); ++#ifdef USE_TTXTSUBS ++ // not sure if the pictureType test is needed, but it seems we can get ++ // incomplete pes packets from remux if we are not getting pictures? ++ if (ttxtSubsRecorder && pictureType != NO_PICTURE) { ++ uint8_t *subsp; ++ size_t len; ++ if (ttxtSubsRecorder->GetPacket(&subsp, &len)) { ++ recordFile->Write(subsp, len); ++ fileSize += len; ++ } ++ } ++#endif /* TTXTSUBS */ + } + else + break; +@@ -126,8 +163,23 @@ void cFileWriter::Action(void) + + // --- cRecorder ------------------------------------------------------------- + ++#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) ++cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids ++#ifdef USE_TTXTSUBS ++ ,cTtxtSubsRecorderBase *tsr ++#endif /* TTXTSUBS */ ++#ifdef USE_LIVEBUFFER ++ ,cLiveBuffer *LiveBuffer ++#endif /* LIVEBUFFER */ ++ ) ++#else + cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids) ++#endif /* LIVEBUFFER || TTXTSUBS */ ++#ifdef USE_DOLBYINREC ++:cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyInRecordings ? DPids : NULL, SPids) ++#else + :cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids) ++#endif /* DOLBYINREC */ + ,cThread("recording") + { + // Make sure the disk is up and running: +@@ -136,8 +188,22 @@ cRecorder::cRecorder(const char *FileNam + + ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); + ringBuffer->SetTimeouts(0, 100); ++#ifdef USE_DOLBYINREC ++ remux = new cRemux(VPid, APids, Setup.UseDolbyInRecordings ? DPids : NULL, SPids, true); ++#else + remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, true); ++#endif /* DOLBYINREC */ ++#ifdef USE_LIVEBUFFER ++ fileName = strdup(FileName); ++ writer = NULL; ++ liveBuffer = LiveBuffer; ++ if (!LiveBuffer) ++#endif /* LIVEBUFFER */ ++#ifdef USE_TTXTSUBS ++ writer = new cFileWriter(FileName, remux, tsr); ++#else + writer = new cFileWriter(FileName, remux); ++#endif /* TTXTSUBS */ + } + + cRecorder::~cRecorder() +@@ -146,11 +212,17 @@ cRecorder::~cRecorder() + delete writer; + delete remux; + delete ringBuffer; ++#ifdef USE_LIVEBUFFER ++ free(fileName); ++#endif /* LIVEBUFFER */ + } + + void cRecorder::Activate(bool On) + { + if (On) { ++#ifdef USE_LIVEBUFFER ++ if (writer) ++#endif /* LIVEBUFFER */ + writer->Start(); + Start(); + } +@@ -174,6 +246,29 @@ void cRecorder::Action(void) + uchar *b = ringBuffer->Get(r); + if (b) { + int Count = remux->Put(b, r); ++#ifdef USE_LIVEBUFFER ++ if (!writer && liveBuffer) { ++ int c; ++ uchar pictureType; ++ uchar *p = remux->Get(c, &pictureType); ++ if (pictureType == I_FRAME && p && p[0]==0x00 && p[1]==0x00 && p[2]==0x01 && (p[7] & 0x80) && p[3]>=0xC0 && p[3]<=0xEF) { ++ int64_t pts = (int64_t) (p[ 9] & 0x0E) << 29 ; ++ pts |= (int64_t) p[ 10] << 22 ; ++ pts |= (int64_t) (p[ 11] & 0xFE) << 14 ; ++ pts |= (int64_t) p[ 12] << 7 ; ++ pts |= (int64_t) (p[ 13] & 0xFE) >> 1 ; ++ liveBuffer->CreateIndexFile(fileName, pts); ++#ifdef USE_TTXTSUBS ++ writer = new cFileWriter(fileName, remux, ttxtSubsRecorder); ++#else ++ writer = new cFileWriter(fileName, remux); ++#endif /* TTXTSUBS */ ++ writer->Start(); ++ } ++ else ++ remux->Del(c); ++ } ++#endif /* LIVEBUFFER */ + if (Count) + ringBuffer->Del(Count); + else +diff -ruNp vdr-1.6.0-2/recorder.h vdr-1.6.0-2-extensions/recorder.h +--- vdr-1.6.0-2/recorder.h 2007-01-05 11:44:05.000000000 +0100 ++++ vdr-1.6.0-2-extensions/recorder.h 2009-04-09 20:48:27.000000000 +0200 +@@ -10,11 +10,17 @@ + #ifndef __RECORDER_H + #define __RECORDER_H + ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "receiver.h" + #include "recording.h" + #include "remux.h" + #include "ringbuffer.h" + #include "thread.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + class cFileWriter; + +@@ -23,12 +29,30 @@ private: + cRingBufferLinear *ringBuffer; + cRemux *remux; + cFileWriter *writer; ++#ifdef USE_LIVEBUFFER ++ char *fileName; ++ cLiveBuffer *liveBuffer; ++#ifdef USE_TTXTSUBS ++ cTtxtSubsRecorderBase *ttxtSubsRecorder; ++#endif /* TTXTSUBS */ ++#endif /* LIVEBUFFER */ + protected: + virtual void Activate(bool On); + virtual void Receive(uchar *Data, int Length); + virtual void Action(void); + public: ++#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) ++ cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids ++#ifdef USE_TTXTSUBS ++ ,cTtxtSubsRecorderBase *tsr ++#endif /* TTXTSUBS */ ++#ifdef USE_LIVEBUFFER ++ ,cLiveBuffer *LiveBuffer = NULL ++#endif /* LIVEBUFFER */ ++ ); ++#else + cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids); ++#endif /* LIVEBUFFER || TTXTSUBS */ + // Creates a new recorder for the channel with the given ChannelID and + // the given Priority that will record the given PIDs into the file FileName. + virtual ~cRecorder(); +diff -ruNp vdr-1.6.0-2/recording.c vdr-1.6.0-2-extensions/recording.c +--- vdr-1.6.0-2/recording.c 2008-02-24 11:28:53.000000000 +0100 ++++ vdr-1.6.0-2-extensions/recording.c 2009-04-09 20:48:27.000000000 +0200 +@@ -8,6 +8,9 @@ + */ + + #include "recording.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <dirent.h> + #include <errno.h> +@@ -23,6 +26,17 @@ + #include "skins.h" + #include "tools.h" + #include "videodir.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ ++ ++#if defined (USE_DVDCHAPJUMP) && defined (USE_DVDARCHIVE) ++#include <assert.h> ++/* libdvdread stuff */ ++#include <dvdread/dvd_reader.h> ++#include <dvdread/ifo_types.h> ++#include <dvdread/ifo_read.h> ++#endif /* DVDCHAPJUMP & DVDARCHIVE */ + + #define SUMMARYFALLBACK + +@@ -46,6 +60,12 @@ + #endif + #define INFOFILESUFFIX "/info.vdr" + #define MARKSFILESUFFIX "/marks.vdr" ++#ifdef USE_LIEMIEXT ++#define INDEXFILESUFFIX "/index.vdr" ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++#define DVDARCHIVEFILENAME "/dvd.vdr" ++#endif /* DVDARCHIVE */ + + #define MINDISKSPACE 1024 // MB + +@@ -62,6 +82,13 @@ + #define MAX_LINK_LEVEL 6 + + bool VfatFileSystem = false; ++#ifdef USE_LIEMIEXT ++bool DirOrderState = false; ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf); ++#endif /* DVLFRIENDLYFNAMES */ + + cRecordings DeletedRecordings(true); + +@@ -491,9 +518,24 @@ cRecording::cRecording(cTimer *Timer, co + { + resume = RESUME_NOT_INITIALIZED; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + fileName = NULL; + name = NULL; ++#ifdef USE_DVDARCHIVE ++ dvdname = NULL; ++ dvdtrack = NULL; ++ dvdchapters = NULL; ++ isArchived = false; ++ isOnlyOnDvd = false; ++ dvdtype = DVD_TYPE_UNKNOWN; ++#endif /* DVDARCHIVE */ + fileSizeMB = -1; // unknown + deleted = 0; + // set up the actual name: +@@ -524,6 +566,11 @@ cRecording::cRecording(cTimer *Timer, co + break; + } + if (Timer->IsSingleEvent()) { ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ Timer -> SetFile(MakeFriendlyFilename(&name)); ++ else ++#endif /* DVLFRIENDLYFNAMES */ + Timer->SetFile(name); // this was an instant recording, so let's set the actual data + Timers.SetModified(); + } +@@ -534,6 +581,10 @@ cRecording::cRecording(cTimer *Timer, co + name = strdup(cString::sprintf("%s~%s", Timer->File(), Subtitle)); + // substitute characters that would cause problems in file names: + strreplace(name, '\n', ' '); ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ MakeFriendlyFilename(&name); ++#endif /* DVLFRIENDLYFNAMES */ + start = Timer->StartTime(); + priority = Timer->Priority(); + lifetime = Timer->Lifetime(); +@@ -548,12 +599,27 @@ cRecording::cRecording(const char *FileN + fileSizeMB = -1; // unknown + deleted = 0; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + fileName = strdup(FileName); + FileName += strlen(VideoDirectory) + 1; + char *p = strrchr(FileName, '/'); + + name = NULL; ++#ifdef USE_DVDARCHIVE ++ dvdname = NULL; ++ dvdtrack = NULL; ++ dvdchapters = NULL; ++ isArchived = false; ++ isOnlyOnDvd = false; ++ dvdtype = DVD_TYPE_NOT_READ; ++#endif /* DVDARCHIVE */ + info = new cRecordingInfo; + if (p) { + time_t now = time(NULL); +@@ -633,15 +699,34 @@ cRecording::cRecording(const char *FileN + LOG_ERROR_STR(*SummaryFileName); + } + #endif ++#ifdef USE_DVDARCHIVE ++ if (CheckFileExistence("dvd.vdr")) { ++ GetDvdName(fileName); ++ isArchived = true; ++ if (!CheckFileExistence("001.vdr")) ++ isOnlyOnDvd = true; ++ } ++#endif /* DVDARCHIVE */ + } + } + + cRecording::~cRecording() + { + free(titleBuffer); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ } ++#else + free(sortBuffer); ++#endif /* SORTRECORDS */ + free(fileName); + free(name); ++#ifdef USE_DVDARCHIVE ++ free(dvdname); ++ free(dvdtrack); ++ free(dvdchapters); ++#endif /* DVDARCHIVE */ + delete info; + } + +@@ -661,21 +746,46 @@ char *cRecording::StripEpisodeName(char + t++; + } + if (s1 && s2) ++#ifdef USE_SORTRECORDS ++ if (Setup.RecordingsSortDirsFirst) ++ *s1 = 'b'; ++ ++ if ((Setup.RecordingsSortMode <= 1 && s1 != s && !strchr(".-$ª·", *(s1 - 1))) || ++ (Setup.RecordingsSortMode == 1 && s1 == s) || ++ (Setup.RecordingsSortMode == 3)) ++#endif /* SORTRECORDS */ + memmove(s1 + 1, s2, t - s2 + 1); + return s; + } + + char *cRecording::SortName(void) const + { ++#ifdef USE_SORTRECORDS ++ if (!sortBuffer[Setup.RecordingsSortMode] || ++ lastDirsFirst[Setup.RecordingsSortMode] != Setup.RecordingsSortDirsFirst) { ++ free(sortBuffer[Setup.RecordingsSortMode]); ++ lastDirsFirst[Setup.RecordingsSortMode] = Setup.RecordingsSortDirsFirst; ++ char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory))); ++#else + if (!sortBuffer) { + char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory) + 1)); ++#endif /* SORTRECORDS */ + strreplace(s, '/', 'a'); // some locales ignore '/' when sorting + int l = strxfrm(NULL, s, 0) + 1; ++#ifdef USE_SORTRECORDS ++ sortBuffer[Setup.RecordingsSortMode] = MALLOC(char, l); ++ strxfrm(sortBuffer[Setup.RecordingsSortMode], s, l); ++#else + sortBuffer = MALLOC(char, l); + strxfrm(sortBuffer, s, l); ++#endif /* SORTRECORDS */ + free(s); + } ++#ifdef USE_SORTRECORDS ++ return sortBuffer[Setup.RecordingsSortMode]; ++#else + return sortBuffer; ++#endif /* SORTRECORDS */ + } + + int cRecording::GetResume(void) const +@@ -690,7 +800,15 @@ int cRecording::GetResume(void) const + int cRecording::Compare(const cListObject &ListObject) const + { + cRecording *r = (cRecording *)&ListObject; ++#ifdef USE_SORTRECORDS ++ return Recordings.GetSortOrder() * strcasecmp(SortName(), r->SortName()); ++#else ++#ifdef USE_LIEMIEXT ++ if (DirOrderState) ++ return strcasecmp(FileName(), r->FileName()); ++#endif /* LIEMIEXT */ + return strcasecmp(SortName(), r->SortName()); ++#endif /* USE_SORTRECORDS */ + } + + const char *cRecording::FileName(void) const +@@ -705,9 +823,359 @@ const char *cRecording::FileName(void) c + return fileName; + } + ++#ifdef USE_DVDARCHIVE ++bool cRecording::CheckFileExistence(const char* FileNameToTest, const bool useVideoDir) const ++{ ++ if (!useVideoDir || (useVideoDir && FileName())) { ++ cString filename = cString::sprintf("%s%s%s", useVideoDir ? FileName() : "", ++ useVideoDir ? "/" : "", ++ FileNameToTest); ++ struct stat statBuf; ++ if (lstat(filename, &statBuf) == -1) return false; ++ return S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode); ++ } ++ return false; ++} ++ ++bool cRecording::GetDvdName(const char* Directory) const ++{ ++ char* filename = (char*)alloca(strlen(Directory) + strlen(DVDARCHIVEFILENAME) + 1); ++ if (filename) { ++ strcpy(filename, Directory); ++ char *end = filename + strlen(filename); ++ strcpy(end, DVDARCHIVEFILENAME); ++ FILE* file; ++ if ((file = fopen(filename, "r"))) { ++ cReadLine ReadLine; ++ char* buffer = (char*)alloca(BUFSIZ); ++ if (buffer) { ++ buffer = ReadLine.Read(file); ++ if (buffer) ++ ((cRecording*)this)->dvdname = strdup(buffer); ++ else ++ ((cRecording*)this)->dvdname = NULL; ++ ++ buffer = ReadLine.Read(file); ++ if (buffer) { ++ ((cRecording*)this)->dvdtrack = strdup(buffer); ++ if (atoi(buffer) == 0) ++ ((cRecording*)this)->dvdtype = DVD_VIDEO_TYPE; ++ else ++ ((cRecording*)this)->dvdtype = DVD_VIDEO_ARCHIVE_TYPE; ++ } ++ else { ++ ((cRecording*)this)->dvdtrack = NULL; ++ ((cRecording*)this)->dvdtype = DVD_ARCHIVE_TYPE; ++ } ++ ++ fclose(file); ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++bool cRecording::GetDvdChaptersFromDvd(int title) const ++{ ++#ifdef USE_DVDCHAPJUMP ++ cString buf; ++ ++ dvd_reader_t *dvd; ++ ifo_handle_t *ifo_file; ++ tt_srpt_t *tt_srpt; ++ ifo_handle_t *vts_file; ++ pgc_t *cur_pgc; ++ ++ dvd = DVDOpen(DVD_DEVICE); ++ if (!dvd) { ++ esyslog("DVD-ARCHIVE: Couldn't open DVD device %s!", DVD_DEVICE); ++ return false; ++ } ++ ++ /* open title manager */ ++ ifo_file = ifoOpen(dvd,0); ++ if (!ifo_file) { ++ esyslog("DVD-ARCHIVE: Can't open VMG info."); ++ DVDClose(dvd); ++ return false; ++ } ++ ++ /* read total_title */ ++ tt_srpt = ifo_file->tt_srpt; ++ ++ /* get total chapters */ ++ int title_set_nr = tt_srpt->title[title-1].title_set_nr; ++ int total_chap = tt_srpt->title[title-1].nr_of_ptts; ++ int local_title_id = tt_srpt->title[title-1].vts_ttn - 1; ++ ++ /* access title set file */ ++ vts_file = ifoOpen(dvd, title_set_nr); ++ if (!vts_file) { ++ esyslog("DVD-ARCHIVE: Can't open info file for title set %d!",title_set_nr); ++ DVDClose(dvd); ++ return false; ++ } ++ ++ /* find program chain and check programs ++ all chapters should be in the same prog chain and ++ should be numbered from 1 to <total_chap> ++ */ ++ { ++ vts_ptt_srpt_t *vts_ptt_srpt = vts_file->vts_ptt_srpt; ++ int pgc_nr = vts_ptt_srpt->title[local_title_id].ptt[0].pgcn; ++ int pg = vts_ptt_srpt->title[local_title_id].ptt[0].pgn; ++ int p; ++ ++ assert(pg==1); ++ for (p=1; p<total_chap; p++) { ++ int next_pg; ++ int this_pgc; ++ this_pgc = vts_ptt_srpt->title[local_title_id].ptt[p].pgcn; ++ assert(pgc_nr == this_pgc); ++ next_pg = vts_ptt_srpt->title[local_title_id].ptt[p].pgn; ++ assert(pg+1 == next_pg); ++ pg = next_pg; ++ } ++ ++ /* fetch program chain */ ++ cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_nr-1].pgc; ++ assert(cur_pgc->nr_of_programs == total_chap); ++ } ++ ++ /* --- main cell loop --- */ ++ { ++ pgc_program_map_t *chap_cell; ++ cell_playback_t *cell_pb; ++ int c; ++ int chap; ++ ++ /* total cells in chain */ ++ int total_cell = cur_pgc->nr_of_cells; ++ ++ /* get info */ ++ chap_cell = cur_pgc->program_map; ++ cell_pb = cur_pgc->cell_playback; ++ ++ /* loop through all cells */ ++ chap = -1; ++ int position = 0; ++ for (c=0; c<total_cell; c++) { ++ int cell_mode; ++ const char *mode; ++ ++ dvd_time_t *time = (dvd_time_t *)&cell_pb->playback_time; ++ ++ int framerate = time->frame_u>>6; ++ assert(framerate == 1 || framerate == 3); ++ int frames_per_sec = (framerate == 1) ? 25 : 30; ++ ++ /* upper 4 bits are first digit, down 4 bits are second digit */ ++ int hour = (time->hour>>4) * 10 + (time->hour&15); ++ int minute = (time->minute>>4) * 10 + (time->minute&15); ++ int second = (time->second>>4) * 10 + (time->second&15); ++ /* upper 4 bits are first digit, down 4 bits are second digit */ ++ int frame = (time->frame_u>>4&3) * 10 + (time->frame_u&15); ++ ++ int frames = ((hour * 3600) + (minute * 60) + second) * frames_per_sec + frame; ++ ++ /* this cell is the begin of a new chapter! */ ++ if (chap_cell[chap+1] == c+1) { ++ cString oldbuf = cString::sprintf("%s", *buf); ++ buf = cString::sprintf("%s%d%s", *oldbuf, position, ((chap+2) < total_chap) ? "," : ""); ++ chap++; ++ } ++ ++ /* cell_mode: 0=normal, 1=first of angle, 2=in angle, 3=last of angle */ ++ cell_mode = cell_pb->block_mode; ++ if ((cell_mode==0) || (cell_mode==1)) { ++ /* only account for normal or begin of angle cells */ ++ position += frames; ++ mode = "counted"; ++ } ++ else ++ mode = "skipped"; ++ ++ cell_pb++; ++ } ++ } ++ ++ ifoClose(ifo_file); ++ ifoClose(vts_file); ++ DVDClose(dvd); ++ ++ ((cRecording*)this)->dvdchapters = strdup(buf); ++ ++ return true; ++#else ++ return false; ++#endif /* DVDCHAPJUMP */ ++} ++ ++const char *cRecording::GetDvdChapters(void) const ++{ ++ // Read chapters from dvd ++ if (dvdtype == DVD_VIDEO_ARCHIVE_TYPE) { ++ if (dvdtrack) { ++ if (!GetDvdChaptersFromDvd(atoi(dvdtrack))) ++ ((cRecording*)this)->dvdchapters = NULL; ++ else ++ isyslog("DVD-ARCHIVE: Using following positions for chapter jumping: %s", dvdchapters); ++ return dvdchapters; ++ } ++ } ++ return NULL; ++} ++ ++int cRecording::MountDvd(void) const ++{ ++ cString cmd; ++ if (Setup.DvdSpeedLimit > 0) { ++ cmd = cString::sprintf("speedcontrol -x %d %s", Setup.DvdSpeedLimit, DVD_DEVICE); ++ SystemExec(cmd); ++ } ++ ++ cString msg; ++ if (atoi(dvdname) == 0) ++ msg = cString::sprintf(tr("Please mount %s"), dvdname); ++ else { ++ if (Setup.DvdDisplayZeros) ++ msg = cString::sprintf(tr("Please mount DVD %04d"), atoi(dvdname)); ++ else ++ msg = cString::sprintf(tr("Please mount DVD %d"), atoi(dvdname)); ++ } ++ ++ bool rep = true; ++ while (rep) { ++ if (Setup.DvdTrayMode==1 || Setup.DvdTrayMode==3) ++ cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); ++ else ++ cmd = cString::sprintf("umount %s", DVD_DEVICE); ++ SystemExec(cmd); ++ ++ if (Interface->Confirm(msg, 300)) { ++ Skins.Message(mtStatus, tr("Please wait. Checking DVD...")); ++ Skins.Flush(); ++ cmd = cString::sprintf("eject -t %s; mkdir -p %s; mount -o ro -t %s %s %s", ++ DVD_DEVICE, DVD_MOUNT_PATH, ++ (dvdtrack ? "udf" : "iso9660"), ++ DVD_DEVICE, DVD_MOUNT_PATH); ++ SystemExec(cmd); ++ ++ bool correctDvd = true; ++ ++ char *olddvdname, *olddvdtrack; ++ int olddvdtype; ++ olddvdname = dvdname; ++ olddvdtrack = dvdtrack; ++ olddvdtype = dvdtype; ++ if (GetDvdName(DVD_MOUNT_PATH)) { ++ if (atoi(dvdname) != atoi(olddvdname)) correctDvd = false; ++ } ++ ((cRecording*)this)->dvdname = olddvdname; ++ ((cRecording*)this)->dvdtrack = olddvdtrack; ++ ((cRecording*)this)->dvdtype = olddvdtype; ++ ++ if (correctDvd) { ++ if (dvdtrack == NULL) { ++ // Archived DVD in VDR format ++ char fn[BUFSIZ]; ++ strcpy(fn, FileName()); ++ char *p = strrchr(fn, '/'); ++ cmd = cString::sprintf("find '%s' -name '%s'", DVD_MOUNT_PATH, p+1); ++ } ++ else { ++ // Either archived DVD in DVD-Video format or DVD-Video which ++ // should be played with the DVD plugin ++ cmd = cString::sprintf("find '%s' -iname 'VIDEO_TS'", DVD_MOUNT_PATH); ++ } ++ ++ cReadLine pipe; ++ FILE* file; ++ char *dirname = NULL; ++ if ((file = popen(cmd, "r")) != (FILE *)NULL) { ++ if ((dirname = pipe.Read(file)) != NULL) { ++ pclose(file); ++ if (dvdtrack != NULL && atoi(dvdtrack) == 0) { ++ // It is a valid Video-DVD and DVD plugin can be started ++ return MOUNT_DVD_LAUNCH_DVD_PLUGIN; ++ } ++ else { ++ // It is a valid Archive-DVD or an archived Video-DVD ++ // and the links can now be established ++ cString srcFn; ++ int n = 1; ++ ++ do { ++ if (dvdtrack == NULL) ++ srcFn = cString::sprintf("%s/%03d.vdr", dirname, n); ++ else ++ srcFn = cString::sprintf("%s/VTS_%02d_%d.VOB", dirname, atoi(dvdtrack), n); ++ ++ if (!access(srcFn, R_OK)) { ++ cmd = cString::sprintf("ln -sf '%s' '%s/%03d.vdr'", *srcFn, FileName(), n); ++ SystemExec(cmd); ++ isyslog("DVD-ARCHIVE: Linking %s/%03d.vdr -> %s", FileName(), n, *srcFn); ++ } ++ else ++ break; ++ } while ( ++n < 999); ++ ++ if (!CheckFileExistence("index.vdr")) { ++ if (dvdtrack == NULL) ++ srcFn = cString::sprintf("%s/index.vdr", dirname); ++ else ++ srcFn = cString::sprintf("%s/index_%02d.vdr", dirname, atoi(dvdtrack)); ++ ++ if (!CheckFileExistence(srcFn, false)) { ++ msg = cString::sprintf(tr("No index-file found. Creating may take minutes. Create one?")); ++ if (Interface->Confirm(msg, 300)) { ++ Skins.Message(mtStatus, tr("Please wait. Creating index-file...")); ++ cmd = cString::sprintf("speedcontrol -x 999 %s; cd %s && genindex &", DVD_DEVICE, FileName()); ++ SystemExec(cmd); ++ return MOUNT_DVD_ABORT; ++ } ++ } ++ else { ++ cmd = cString::sprintf("ln -sf '%s' '%s/index.vdr'", *srcFn, FileName()); ++ SystemExec(cmd); ++ isyslog("DVD-ARCHIVE: Linking %s/index.vdr -> %s", FileName(), *srcFn); ++ } ++ } ++ return MOUNT_DVD_REPLAY; ++ } ++ } ++ else { ++ Skins.Message(mtError, tr("Wrong DVD!"), 3); ++ Skins.Flush(); ++ } ++ } ++ pclose(file); ++ } ++ else { ++ Skins.Message(mtError, tr("Wrong DVD!"), 3); ++ Skins.Flush(); ++ } ++ } ++ else { ++ rep = false; ++ } ++ } ++ return MOUNT_DVD_ABORT; ++} ++ ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level, bool Original) const ++#else + const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) const ++#endif /* LIEMIEXT */ + { ++#ifdef USE_WAREAGLEICON ++ const char *New = NewIndicator && IsNew() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_NEW_UTF8 : ICON_NEW : "*" : " "; ++#else + char New = NewIndicator && IsNew() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + free(titleBuffer); + titleBuffer = NULL; + if (Level < 0 || Level == HierarchyLevels()) { +@@ -718,7 +1186,14 @@ const char *cRecording::Title(char Delim + s++; + else + s = name; ++#ifdef USE_LIEMIEXT ++ if (Original) { ++#endif /* LIEMIEXT */ ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%s%c%s", ++#else + titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%c%c%s", ++#endif /* WAREAGLEICON */ + t->tm_mday, + t->tm_mon + 1, + t->tm_year % 100, +@@ -728,6 +1203,92 @@ const char *cRecording::Title(char Delim + New, + Delimiter, + s)); ++#ifdef USE_LIEMIEXT ++ } ++ else { ++ cString RecLength("---"); ++ if (Setup.ShowRecLength && FileName()) { ++ cString filename = cString::sprintf("%s%s", FileName(), INDEXFILESUFFIX); ++ if (*filename) { ++ if (access(filename, R_OK) == 0) { ++ struct stat buf; ++ if (stat(filename, &buf) == 0) { ++ struct tIndex { int offset; uchar type; uchar number; short reserved; }; ++ int delta = buf.st_size % sizeof(tIndex); ++ if (delta) { ++ delta = sizeof(tIndex) - delta; ++ esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, *filename); ++ } ++ RecLength = cString::sprintf("%ld'", (buf.st_size + delta) / sizeof(tIndex) / SecondsToFrames(60)); ++ } ++ } ++ } ++ } ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++#ifdef USE_WAREAGLEICON ++ if (isArchived && !isOnlyOnDvd) New = Setup.WarEagleIcons ? IsLangUtf8() ? ICON_DVD_UTF8 : ICON_DVD : "~"; ++#else ++ if (isArchived && !isOnlyOnDvd) New = '~'; ++#endif /* WAREAGLEICON */ ++ ++ if (isOnlyOnDvd && Setup.DvdDisplayMode >= 1) { ++ char oldLength[21]; ++ ++ if (strrchr(RecLength, '\'')) ++ sprintf(oldLength,"%s", *RecLength); ++ else ++ oldLength[0] = 0; ++ ++ if (dvdname) { ++ if (atoi(dvdname) != 0) { ++ cString tmp; ++ if (Setup.DvdDisplayZeros) ++ tmp = cString::sprintf("%04d", atoi(dvdname)); ++ else { ++ int num = atoi(dvdname); ++ bool displaySpace = !(Setup.DvdDisplayMode == 1 && oldLength[0] != 0); ++ // ugly hack to have 2 spaces instead of one 0 for each place ++ tmp = cString::sprintf("%s%s%s%d", displaySpace && (num < 1000) ? " " : "", ++ displaySpace && (num < 100) ? " " : "", ++ displaySpace && (num < 10) ? " " : "", ++ num); ++ } ++ ((cRecording*)this)->dvdname = strdup(tmp); ++ } ++ } ++ ++ RecLength = strdup(cString::sprintf("%s%s%s%s", (Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? oldLength : "", ++ (dvdname && isArchived && isOnlyOnDvd && Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? " / " : "", ++ (dvdname && isArchived && isOnlyOnDvd) ? dvdname : "", ++ (dvdname && isArchived && isOnlyOnDvd) ? " " : "" ++ )); ++ } ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++ cString RecDate = cString::sprintf("%02d.%02d.%02d", t->tm_mday, t->tm_mon + 1, t->tm_year % 100); ++ cString RecTime = cString::sprintf("%02d:%02d", t->tm_hour, t->tm_min); ++ cString RecDelimiter = cString::sprintf("%c", Delimiter); ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%s%s%s%s%s%s%s%s", ++#else ++ titleBuffer = strdup(cString::sprintf("%s%s%s%c%s%s%s%s", ++#endif /* WAREAGLEICON */ ++ (Setup.ShowRecDate ? *RecDate : ""), ++ (Setup.ShowRecDate && Setup.ShowRecTime ? *RecDelimiter : ""), ++ (Setup.ShowRecTime ? *RecTime : ""), ++ New, ++ (Setup.ShowRecTime || Setup.ShowRecDate ? *RecDelimiter : ""), ++#ifdef USE_DVDARCHIVE ++ (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecLength : ""), ++ (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecDelimiter : ""), ++#else ++ (Setup.ShowRecLength ? *RecLength : ""), ++ (Setup.ShowRecLength ? *RecDelimiter : ""), ++#endif /* DVDARCHIVE */ ++ s)); ++ } ++#endif /* LIEMIEXT */ + // let's not display a trailing '~': + if (!NewIndicator) + stripspace(titleBuffer); +@@ -756,6 +1317,17 @@ const char *cRecording::Title(char Delim + return titleBuffer; + } + ++#ifdef USE_CUTTIME ++void cRecording::SetStartTime(time_t Start) ++{ ++ start = Start; ++ if (fileName) { ++ free(fileName); ++ fileName = NULL; ++ } ++} ++#endif /* CUTTIME */ ++ + const char *cRecording::PrefixFileName(char Prefix) + { + cString p = PrefixVideoFileName(FileName(), Prefix); +@@ -809,10 +1381,20 @@ bool cRecording::Delete(void) + // the new name already exists, so let's remove that one first: + isyslog("removing recording '%s'", NewName); + RemoveVideoFile(NewName); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(this, scDel); ++#endif /* STREAMDEVEXT */ + } + isyslog("deleting recording '%s'", FileName()); ++#ifdef USE_STREAMDEVEXT ++ if (access(FileName(), F_OK) == 0) { ++ result = RenameVideoFile(FileName(), NewName); ++ cStatus::MsgRecordingChange(this, scDel); ++ } ++#else + if (access(FileName(), F_OK) == 0) + result = RenameVideoFile(FileName(), NewName); ++#endif /* STREAMDEVEXT */ + else { + isyslog("recording '%s' vanished", FileName()); + result = true; // well, we were going to delete it, anyway +@@ -830,7 +1412,13 @@ bool cRecording::Remove(void) + return false; + } + isyslog("removing recording %s", FileName()); ++#ifdef USE_STREAMDEVEXT ++ bool ret = RemoveVideoFile(FileName()); ++ cStatus::MsgRecordingChange(this, scDel); ++ return ret; ++#else + return RemoveVideoFile(FileName()); ++#endif /* STREAMDEVEXT */ + } + + bool cRecording::Undelete(void) +@@ -847,8 +1435,15 @@ bool cRecording::Undelete(void) + } + else { + isyslog("undeleting recording '%s'", FileName()); ++#ifdef USE_STREAMDEVEXT ++ if (access(FileName(), F_OK) == 0) { ++ result = RenameVideoFile(FileName(), NewName); ++ cStatus::MsgRecordingChange(this, scAdd); ++ } ++#else + if (access(FileName(), F_OK) == 0) + result = RenameVideoFile(FileName(), NewName); ++#endif /* STREAMDEVEXT */ + else { + isyslog("deleted recording '%s' vanished", FileName()); + result = false; +@@ -864,6 +1459,53 @@ void cRecording::ResetResume(void) const + resume = RESUME_NOT_INITIALIZED; + } + ++#ifdef USE_LIEMIEXT ++bool cRecording::Rename(const char *newName, int *newPriority, int *newLifetime) ++{ ++ bool result = false; ++ struct tm tm_r; ++ struct tm *t = localtime_r(&start, &tm_r); ++ char *localNewName = ExchangeChars(strdup(newName), true); ++ char *newFileName = strdup(cString::sprintf(NAMEFORMAT, VideoDirectory, localNewName, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, *newPriority, *newLifetime)); ++ free(localNewName); ++ if (strcmp(FileName(), newFileName)) { ++ if (access(newFileName, F_OK) == 0) { ++ isyslog("recording %s already exists", newFileName); ++ } ++ else { ++ isyslog("renaming recording %s to %s", FileName(), newFileName); ++ result = MakeDirs(newFileName, true); ++ if (result) ++ result = RenameVideoFile(FileName(), newFileName); ++ if (result) { ++ priority = *newPriority; ++ lifetime = *newLifetime; ++ free(fileName); ++ fileName = strdup(newFileName); ++ free(name); ++ name = strdup(newName); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ sortBuffer[i] = NULL; ++ } ++#else ++ free(sortBuffer); ++ sortBuffer = NULL; ++#endif /* SORTRECORDS */ ++ free(titleBuffer); ++ titleBuffer = NULL; ++ } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(this, scMod); ++#endif /* STREAMDEVEXT */ ++ } ++ } ++ free(newFileName); ++ return result; ++} ++#endif /* LIEMIEXT */ ++ + // --- cRecordings ----------------------------------------------------------- + + cRecordings Recordings; +@@ -876,6 +1518,9 @@ cRecordings::cRecordings(bool Deleted) + deleted = Deleted; + lastUpdate = 0; + state = 0; ++#ifdef USE_SORTRECORDS ++ SortOrder = 1; ++#endif /* SORTRECORDS */ + } + + cRecordings::~cRecordings() +@@ -1154,14 +1799,70 @@ cMark *cMarks::GetNext(int Position) + return NULL; + } + ++#ifdef USE_JUMPPLAY ++// --- cMarksReload ---------------------------------------------------------- ++ ++#define MARKS_RELOAD_MS 10000 ++ ++time_t cMarksReload::lastsavetime = 0; ++ ++cMarksReload::cMarksReload(const char *RecordingFileName) ++:recDir(RecordingFileName) ++{ ++ struct stat sbuf; ++ if (Load(recDir) && stat(FileName(), &sbuf) == 0) ++ lastmodtime = sbuf.st_mtime; ++ else ++ lastmodtime = 0; ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++} ++ ++bool cMarksReload::Reload(void) ++{ ++ // Check the timestamp of marks.vdr in 10 seconds intervals ++ // Independent but synchronized reloading of marks in two threads ++ if ((Setup.ReloadMarks && nextreload.TimedOut()) || lastsavetime > lastmodtime) { ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++ struct stat sbuf; ++ if (stat(FileName(), &sbuf) == 0 && sbuf.st_mtime != lastmodtime) { ++ lastmodtime = sbuf.st_mtime; ++ if (Load(recDir)) ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool cMarksReload::Save(void) ++{ ++ bool ok = cMarks::Save(); ++ struct stat sbuf; ++ if (ok && stat(FileName(), &sbuf) == 0) ++ lastsavetime = lastmodtime = sbuf.st_mtime; ++ return ok; ++} ++#endif /* JUMPPLAY */ ++ + // --- cRecordingUserCommand ------------------------------------------------- + + const char *cRecordingUserCommand::command = NULL; + ++#ifdef USE_DVLRECSCRIPTADDON ++void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName, char *chanName) ++#else + void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName) ++#endif /* DVLRECSCRIPTADDON */ + { + if (command) { ++#ifdef USE_DVLRECSCRIPTADDON ++ cString cmd; ++ if (chanName != NULL) ++ cmd = cString::sprintf("%s %s \"%s\" \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"), chanName); ++ else ++ cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#else + cString cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#endif /* DVLRECSCRIPTADDON */ + isyslog("executing '%s'", *cmd); + SystemExec(cmd); + } +@@ -1172,7 +1873,9 @@ void cRecordingUserCommand::InvokeComman + //XXX+ somewhere else??? + // --- cIndexFile ------------------------------------------------------------ + ++#ifndef USE_LIEMIEXT + #define INDEXFILESUFFIX "/index.vdr" ++#endif /* LIEMIEXT */ + + // The number of frames to stay off the end in case of time shift: + #define INDEXSAFETYLIMIT 150 // frames +@@ -1431,6 +2134,48 @@ cFileName::cFileName(const char *FileNam + cFileName::~cFileName() + { + Close(); ++#ifdef USE_DVDARCHIVE ++ ++ char fn[BUFSIZ]; ++ strcpy(fn, fileName); ++ ++ char *p; ++ if((p = strrchr(fn, '/'))) { ++ p[0] = 0; ++ } ++ ++ cString cmd = cString::sprintf("find \"%s\" -type l -lname \"%s/*\"", fn, DVD_MOUNT_PATH); ++ ++ bool isOnDvd = false; ++ ++ cReadLine pipe; ++ FILE* file; ++ char* filename; ++ if ((file = popen(cmd, "r")) != (FILE *)NULL) { ++ while ((filename = pipe.Read(file)) != NULL) { ++ isOnDvd = true; ++ unlink(filename); ++ isyslog("DVD-ARCHIVE: Deleting %s", filename); ++ } ++ pclose(file); ++ } ++ ++ if (isOnDvd) { ++ if (Setup.DvdTrayMode==2 || Setup.DvdTrayMode==3) ++ cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); ++ else ++ cmd = cString::sprintf("umount %s", DVD_DEVICE); ++ ++ SystemExec(cmd); ++ ++ if (Setup.DvdSpeedLimit > 0) { ++ cmd = cString::sprintf("speedcontrol -x 999 %s", DVD_DEVICE); ++ SystemExec(cmd); ++ } ++ } ++ ++#endif /* DVDARCHIVE */ ++ + free(fileName); + } + +@@ -1508,6 +2253,18 @@ cUnbufferedFile *cFileName::SetOffset(in + return NULL; + } + ++#ifdef USE_HARDLINKCUTTER ++int cFileName::MaxFileSize() { ++ const int smallFiles = (255 * MAXVIDEOFILESIZE - 1024 * Setup.MaxRecordingSize) ++ / max(MAXVIDEOFILESIZE - Setup.MaxVideoFileSize, 1); ++ ++ if (fileNumber <= smallFiles) ++ return MEGABYTE(Setup.MaxVideoFileSize); ++ ++ return MEGABYTE(MAXVIDEOFILESIZE); ++} ++#endif /* HARDLINKCUTTER */ ++ + cUnbufferedFile *cFileName::NextFile(void) + { + return SetOffset(fileNumber + 1); +@@ -1555,3 +2312,113 @@ int ReadFrame(cUnbufferedFile *f, uchar + LOG_ERROR; + return r; + } ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf) ++{ ++ char *b, *x, *y; ++ ++ if (buf == NULL || *buf == NULL) ++ return(NULL); ++ ++ b = (char *)malloc(strlen(*buf) * 2); ++ x = *buf; ++ y = b; ++ ++ while (*x != 0) { ++ switch (*x) { ++ case 'Ä': ++ *y = 'A'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ä': ++ *y = 'a'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ö': ++ *y = 'O'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ö': ++ *y = 'o'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ü': ++ *y = 'U'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ü': ++ *y = 'u'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ß': ++ *y = 's'; ++ y++; ++ *y = 's'; ++ y++; x++; ++ break; ++ ++ // chars to replace ++ case ':': ++ case ';': ++ case '?': ++ case ' ': ++ case '\t': ++ *y = '_'; ++ y++; x++; ++ break; ++ ++ // chars to simply strip ++ case '\"': ++ case '*': ++ case '{': ++ case '}': ++ case '[': ++ case ']': ++ case '=': ++ case '<': ++ case '>': ++ case '#': ++ case '`': ++ case '|': ++ case '\\': ++ case '\n': ++ case '\r': ++ x++; ++ break; ++ ++ default: ++ *y = *x; ++ y++; x++; ++ break; ++ } ++ } ++ *y = 0; ++ ++ x = strdup(b); ++ free(b); ++ ++ free(*buf); ++ *buf = x; ++ ++ return(*buf); ++} ++#endif /* DVLFRIENDLYFNAMES */ +diff -ruNp vdr-1.6.0-2/recording.h vdr-1.6.0-2-extensions/recording.h +--- vdr-1.6.0-2/recording.h 2007-10-14 12:11:34.000000000 +0200 ++++ vdr-1.6.0-2-extensions/recording.h 2009-04-09 20:48:27.000000000 +0200 +@@ -19,6 +19,9 @@ + #include "tools.h" + + extern bool VfatFileSystem; ++#ifdef USE_LIEMIEXT ++extern bool DirOrderState; ++#endif /* LIEMIEXT */ + + void RemoveDeletedRecordings(void); + void AssertFreeDiskSpace(int Priority = 0, bool Force = false); +@@ -52,9 +55,15 @@ private: + public: + ~cRecordingInfo(); + tChannelID ChannelID(void) const { return channelID; } ++#ifdef USE_STREAMDEVEXT ++ const cEvent *GetEvent(void) const { return event; } ++#endif /* STREAMDEVEXT */ + const char *ChannelName(void) const { return channelName; } + const char *Title(void) const { return event->Title(); } + const char *ShortText(void) const { return event->ShortText(); } ++#ifdef USE_GRAPHTFT ++ tEventID EventID(void) const { return event->EventID(); } ++#endif /* GRAPHTFT */ + const char *Description(void) const { return event->Description(); } + const cComponents *Components(void) const { return event->Components(); } + const char *Aux(void) const { return aux; } +@@ -62,16 +71,50 @@ public: + bool Write(FILE *f, const char *Prefix = "") const; + }; + ++#ifdef USE_SORTRECORDS ++#define SORTRECORDINGSVERSNUM 3 ++#define MAXSORTMODES 4 ++#endif /* SORTRECORDS */ ++ ++#ifdef USE_DVDARCHIVE ++#define MOUNT_DVD_ABORT 0 ++#define MOUNT_DVD_REPLAY 1 ++#define MOUNT_DVD_LAUNCH_DVD_PLUGIN 2 ++#define DVD_DEVICE "/dev/cdrom" ++#define DVD_MOUNT_PATH "/tmp/vdr.dvd" ++ ++#define DVD_TYPE_UNKNOWN -1 ++#define DVD_TYPE_NOT_READ 0 ++#define DVD_VIDEO_TYPE 1 ++#define DVD_ARCHIVE_TYPE 2 ++#define DVD_VIDEO_ARCHIVE_TYPE 3 ++#endif /* DVDARCHIVE */ ++ + class cRecording : public cListObject { + friend class cRecordings; + private: + mutable int resume; + mutable char *titleBuffer; ++ ++#ifdef USE_SORTRECORDS ++ mutable char *sortBuffer[MAXSORTMODES]; ++ mutable char lastDirsFirst[MAXSORTMODES]; ++#else + mutable char *sortBuffer; ++#endif /* SORTRECORDS */ + mutable char *fileName; + mutable char *name; + mutable int fileSizeMB; + cRecordingInfo *info; ++#ifdef USE_DVDARCHIVE ++ char *dvdname; ++ char *dvdtrack; ++ char *dvdchapters; ++ bool isArchived; ++ bool isOnlyOnDvd; ++ int dvdtype; ++ bool GetDvdChaptersFromDvd(int title) const; ++#endif /* DVDARCHIVE */ + cRecording(const cRecording&); // can't copy cRecording + cRecording &operator=(const cRecording &); // can't assign cRecording + static char *StripEpisodeName(char *s); +@@ -88,8 +131,23 @@ public: + virtual int Compare(const cListObject &ListObject) const; + const char *Name(void) const { return name; } + const char *FileName(void) const; ++#ifdef USE_DVDARCHIVE ++ bool CheckFileExistence(const char* FileNameToTest, const bool useVideoDir = true) const; ++ bool GetDvdName(const char* Directory) const; ++ bool IsOnlyOnDvd(void) const { return isOnlyOnDvd; } ++ int MountDvd(void) const; ++ int GetDvdType(void) const { return dvdtype; } ++ const char *GetDvdChapters(void) const ; ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++ const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1, bool Original = true) const; ++#else + const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const; ++#endif /* LIEMIEXT */ + const cRecordingInfo *Info(void) const { return info; } ++#ifdef USE_CUTTIME ++ void SetStartTime(time_t Start); ++#endif /* CUTTIME */ + const char *PrefixFileName(char Prefix); + int HierarchyLevels(void) const; + void ResetResume(void) const; +@@ -106,6 +164,11 @@ public: + // 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 ++#ifdef USE_LIEMIEXT ++ bool Rename(const char *newName, int *newPriority, int *newLifetime); ++ // Changes the file name ++ // Returns false in case of error ++#endif /* LIEMIEXT */ + }; + + class cRecordings : public cList<cRecording>, public cThread { +@@ -114,6 +177,9 @@ private: + bool deleted; + time_t lastUpdate; + int state; ++#ifdef USE_SORTRECORDS ++ int SortOrder; ++#endif /* SORTRECORDS */ + const char *UpdateFileName(void); + void Refresh(bool Foreground = false); + void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0); +@@ -144,6 +210,10 @@ public: + void AddByName(const char *FileName, bool TriggerUpdate = true); + void DelByName(const char *FileName); + int TotalFileSizeMB(void); ///< Only for deleted recordings! ++#ifdef USE_SORTRECORDS ++ void ToggleSortOrder(void) { SortOrder *= -1; } ++ const int GetSortOrder(void) { return SortOrder; } ++#endif /* SORTRECORDS */ + }; + + extern cRecordings Recordings; +@@ -170,6 +240,20 @@ public: + cMark *GetNext(int Position); + }; + ++#ifdef USE_JUMPPLAY ++class cMarksReload : public cMarks { ++private: ++ cString recDir; ++ cTimeMs nextreload; ++ time_t lastmodtime; ++ static time_t lastsavetime; ++public: ++ cMarksReload(const char *RecordingFileName); ++ bool Reload(void); ++ bool Save(void); ++ }; ++#endif /* JUMPPLAY */ ++ + #define RUC_BEFORERECORDING "before" + #define RUC_AFTERRECORDING "after" + #define RUC_EDITEDRECORDING "edited" +@@ -178,8 +262,15 @@ class cRecordingUserCommand { + private: + static const char *command; + public: ++#ifdef USE_DELTIMESHIFTREC ++ static const char *GetCommand(void) { return command; } ++#endif /* DELTIMESHIFTREC */ + static void SetCommand(const char *Command) { command = Command; } ++#ifdef USE_DVLRECSCRIPTADDON ++ static void InvokeCommand(const char *State, const char *RecordingFileName, char *chanName = NULL); ++#else + static void InvokeCommand(const char *State, const char *RecordingFileName); ++#endif /* DVLRECSCRIPTADDON */ + }; + + //XXX+ +@@ -195,7 +286,19 @@ public: + // may be slightly higher because we stop recording only before the next + // 'I' frame, to have a complete Group Of Pictures): + #define MAXVIDEOFILESIZE 2000 // MB ++#ifndef USE_HARDLINKCUTTER + #define MINVIDEOFILESIZE 100 // MB ++#else ++#define MINVIDEOFILESIZE 1 // MB ++ ++#define MINRECORDINGSIZE 25 // GB ++#define MAXRECORDINGSIZE 500 // GB ++#define DEFAULTRECORDINGSIZE 100 // GB ++// Dynamic recording size: ++// Keep recording file size at Setup.MaxVideoFileSize for as long as possible, ++// but switch to MAXVIDEOFILESIZE early enough, so that Setup.MaxRecordingSize ++// will be reached, before recording to file 255.vdr ++#endif /* HARDLINKCUTTER */ + + class cIndexFile { + private: +@@ -207,6 +310,9 @@ private: + cResumeFile resumeFile; + cMutex mutex; + bool CatchUp(int Index = -1); ++#ifdef USE_DVDARCHIVE ++ bool isOnDVD; ++#endif /* DVDARCHIVE */ + public: + cIndexFile(const char *FileName, bool Record); + ~cIndexFile(); +@@ -236,6 +342,10 @@ public: + cUnbufferedFile *Open(void); + void Close(void); + cUnbufferedFile *SetOffset(int Number, int Offset = 0); ++#ifdef USE_HARDLINKCUTTER ++ int MaxFileSize(); ++ // Dynamic file size for this file ++#endif /* HARDLINKCUTTER */ + cUnbufferedFile *NextFile(void); + }; + +diff -ruNp vdr-1.6.0-2/remux.c vdr-1.6.0-2-extensions/remux.c +--- vdr-1.6.0-2/remux.c 2007-11-25 14:56:03.000000000 +0100 ++++ vdr-1.6.0-2-extensions/remux.c 2009-04-09 20:48:27.000000000 +0200 +@@ -1829,8 +1829,15 @@ void cTS2PES::ts_to_pes(const uint8_t *B + if (Buf[1] & TS_ERROR) + tsErrors++; + ++#ifdef USE_DVBSETUP ++ if (!(Buf[3] & (ADAPT_FIELD | PAY_LOAD))) { ++ dsyslog("TS packet discarded due to invalid adaption_field_control"); ++ return; ++ } ++#else + if (!(Buf[3] & (ADAPT_FIELD | PAY_LOAD))) + return; // discard TS packet with adaption_field_control set to '00'. ++#endif /* DVBSETUP */ + + if ((Buf[3] & PAY_LOAD) && ((Buf[3] ^ ccCounter) & CONT_CNT_MASK)) { + // This should check duplicates and packets which do not increase the counter. +@@ -1842,6 +1849,9 @@ void cTS2PES::ts_to_pes(const uint8_t *B + // These are the errors I used to get with Nova-T when antenna + // was not positioned correcly (not transport errors). //tvr + //dsyslog("TS continuity error (%d)", ccCounter); ++#ifdef USE_DVBSETUP ++ dsyslog("TS continuity error (%d)", ccCounter); ++#endif /* DVBSETUP */ + } + ccCounter = Buf[3] & CONT_CNT_MASK; + } +@@ -1867,6 +1877,10 @@ void cTS2PES::ts_to_pes(const uint8_t *B + + if (Buf[3] & PAY_LOAD) + instant_repack(Buf + 4 + off, TS_SIZE - 4 - off); ++#ifdef USE_DVBSETUP ++ else if (off + 4 < 188) ++ dsyslog("adaption_field zu short or PAY_LOAD not set"); ++#endif /* DVBSETUP */ + } + + // --- cRingBufferLinearPes -------------------------------------------------- +@@ -1896,12 +1910,19 @@ int cRingBufferLinearPes::DataReady(cons + + #define RESULTBUFFERSIZE KILOBYTE(256) + ++#ifdef USE_SYNCEARLY ++cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly) ++#else + cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure) ++#endif /* SYNCEARLY */ + { + exitOnFailure = ExitOnFailure; + noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF; + numUPTerrors = 0; + synced = false; ++#ifdef USE_SYNCEARLY ++ syncEarly = SyncEarly; ++#endif /* SYNCEARLY */ + skipped = 0; + numTracks = 0; + resultSkipped = 0; +@@ -2105,12 +2126,26 @@ uchar *cRemux::Get(int &Count, uchar *Pi + } + } + else if (!synced) { ++#ifdef USE_SYNCEARLY ++ if (pt == I_FRAME || syncEarly) { ++#else + if (pt == I_FRAME) { ++#endif /* SYNCEARLY */ + if (PictureType) + *PictureType = pt; + resultSkipped = i; // will drop everything before this position ++#ifdef USE_SYNCEARLY ++ if (!syncEarly) ++#endif /* SYNCEARLY */ + SetBrokenLink(data + i, l); + synced = true; ++#ifdef USE_SYNCEARLY ++ if (syncEarly) { ++ if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink() ++ SetBrokenLink(data + i, l); ++ else fprintf(stderr, "video: synced early\n"); ++ } ++#endif /* SYNCEARLY */ + } + } + else if (Count) +@@ -2123,12 +2158,21 @@ uchar *cRemux::Get(int &Count, uchar *Pi + l = GetPacketLength(data, resultCount, i); + if (l < 0) + return resultData; ++#ifdef USE_SYNCEARLY ++ if (noVideo || !synced && syncEarly) { ++ if (!synced) { ++ if (PictureType && noVideo) ++#else + if (noVideo) { + if (!synced) { + if (PictureType) ++#endif /* SYNCEARLY */ + *PictureType = I_FRAME; + resultSkipped = i; // will drop everything before this position + synced = true; ++#ifdef USE_SYNCEARLY ++ if (!noVideo && syncEarly) fprintf(stderr, "audio: synced early\n"); ++#endif /* SYNCEARLY */ + } + else if (Count) + return resultData; +diff -ruNp vdr-1.6.0-2/remux.h vdr-1.6.0-2-extensions/remux.h +--- vdr-1.6.0-2/remux.h 2008-09-11 13:29:43.000000000 +0200 ++++ vdr-1.6.0-2-extensions/remux.h 2009-04-09 20:48:27.000000000 +0200 +@@ -38,6 +38,9 @@ private: + bool noVideo; + int numUPTerrors; + bool synced; ++#ifdef USE_SYNCEARLY ++ bool syncEarly; ++#endif /* SYNCEARLY */ + int skipped; + cTS2PES *ts2pes[MAXTRACKS]; + int numTracks; +@@ -45,12 +48,18 @@ private: + int resultSkipped; + int GetPid(const uchar *Data); + public: ++#ifdef USE_SYNCEARLY ++ cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false); ++#else + cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false); ++#endif /* SYNCEARLY */ + ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while + ///< APids, DPids and SPids are pointers to zero terminated lists of audio, + ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such + ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency + ///< exit" in case of problems with the data stream. ++ ///< If USE_SYNCEARLY is activated: SyncEarly causes cRemux to sync as soon ++ ///< as a video or audio frame is seen. + ~cRemux(); + void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); } + ///< By default cRemux assumes that Put() and Get() are called from different +diff -ruNp vdr-1.6.0-2/skinclassic.c vdr-1.6.0-2-extensions/skinclassic.c +--- vdr-1.6.0-2/skinclassic.c 2008-02-23 11:31:58.000000000 +0100 ++++ vdr-1.6.0-2-extensions/skinclassic.c 2009-04-09 20:48:27.000000000 +0200 +@@ -314,8 +314,52 @@ void cSkinClassicDisplayMenu::SetItem(co + for (int i = 0; i < MaxTabs; i++) { + const char *s = GetTabbedText(Text, i); + if (s) { ++#ifdef USE_LIEMIEXT ++ bool isprogressbar = false; ++ int now = 0, total = 0; ++ // check if progress bar: "[||||||| ]" ++ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { ++ const char *p = s + 1; ++ // update status ++ isprogressbar = true; ++ for (; *p != ']'; ++p) { ++ // check if progressbar characters ++ if (*p == ' ' || *p == '|') { ++ // update counters ++ ++total; ++ if (*p == '|') ++ ++now; ++ } ++ else { ++ // wrong character detected; not a progressbar ++ isprogressbar = false; ++ break; ++ } ++ } ++ } ++ int xt = x0 + Tab(i); ++ if (Setup.ShowProgressBar && isprogressbar) { ++ // define x coordinates of progressbar ++ int px0 = xt; ++ int px1 = (Tab(i + 1)?Tab(i+1):x1) - 5; ++ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); ++ // define y coordinates of progressbar ++ int py0 = y + 4; ++ int py1 = y + lineHeight - 4; ++ // draw background ++ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i+1):x1) - 1, y + lineHeight - 1, ColorBg); ++ // draw progressbar ++ osd->DrawRectangle(px0, py0, px, py1, ColorFg); ++ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); ++ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); ++ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); ++ } ++ else ++ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); ++#else + int xt = x0 + Tab(i); + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); ++#endif /* LIEMIEXT */ + } + if (!Tab(i + 1)) + break; +diff -ruNp vdr-1.6.0-2/skinsttng.c vdr-1.6.0-2-extensions/skinsttng.c +--- vdr-1.6.0-2/skinsttng.c 2008-02-23 11:23:44.000000000 +0100 ++++ vdr-1.6.0-2-extensions/skinsttng.c 2009-04-09 20:48:27.000000000 +0200 +@@ -558,8 +558,52 @@ void cSkinSTTNGDisplayMenu::SetItem(cons + for (int i = 0; i < MaxTabs; i++) { + const char *s = GetTabbedText(Text, i); + if (s) { ++#ifdef USE_LIEMIEXT ++ bool isprogressbar = false; ++ int now = 0, total = 0; ++ // check if progress bar: "[||||||| ]" ++ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { ++ const char *p = s + 1; ++ // update status ++ isprogressbar = true; ++ for (; *p != ']'; ++p) { ++ // check if progressbar characters ++ if (*p == ' ' || *p == '|') { ++ // update counters ++ ++total; ++ if (*p == '|') ++ ++now; ++ } ++ else { ++ // wrong character detected; not a progressbar ++ isprogressbar = false; ++ break; ++ } ++ } ++ } ++ int xt = x3 + 5 + Tab(i); ++ if (Setup.ShowProgressBar && isprogressbar) { ++ // define x coordinates of progressbar ++ int px0 = xt; ++ int px1 = x3 + (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1; ++ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); ++ // define y coordinates of progressbar ++ int py0 = y + 4; ++ int py1 = y + lineHeight - 4; ++ // draw background ++ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1, y + lineHeight - 1, ColorBg); ++ // draw progressbar ++ osd->DrawRectangle(px0, py0, px, py1, ColorFg); ++ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); ++ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); ++ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); ++ } ++ else ++ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); ++#else + int xt = x3 + 5 + Tab(i); + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); ++#endif /* LIEMIEXT */ + } + if (!Tab(i + 1)) + break; +@@ -602,6 +646,21 @@ void cSkinSTTNGDisplayMenu::SetEvent(con + y += ts.Height(); + } + y += font->Height(); ++#ifdef USE_PARENTALRATING ++ if (!isempty(Event->GetParentalRatingString())) { ++ const cFont *font = cFont::GetFont(fontSml); ++ ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetParentalRatingString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); ++ y += ts.Height(); ++ } ++ int i = 0; ++ while (Event->Contents(i++)) { ++ if (!isempty(Event->GetContentsString())) { ++ const cFont *font = cFont::GetFont(fontSml); ++ ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetContentsString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); ++ y += ts.Height(); ++ } ++ } ++#endif /* PARENTALRATING */ + if (!isempty(Event->Description())) { + int yt = y; + int yb = y4 - Roundness; +diff -ruNp vdr-1.6.0-2/sources.c vdr-1.6.0-2-extensions/sources.c +--- vdr-1.6.0-2/sources.c 2008-02-10 15:07:26.000000000 +0100 ++++ vdr-1.6.0-2-extensions/sources.c 2009-04-09 20:48:27.000000000 +0200 +@@ -37,6 +37,9 @@ cString cSource::ToString(int Code) + char buffer[16]; + char *q = buffer; + switch (Code & st_Mask) { ++#ifdef USE_PLUGINPARAM ++ case stPlug: *q++ = 'P'; break; ++#endif /* PLUGINPARAM */ + case stCable: *q++ = 'C'; break; + case stSat: *q++ = 'S'; + { +@@ -56,6 +59,9 @@ int cSource::FromString(const char *s) + { + int type = stNone; + switch (toupper(*s)) { ++#ifdef USE_PLUGINPARAM ++ case 'P': type = stPlug; break; ++#endif /* PLUGINPARAM */ + case 'C': type = stCable; break; + case 'S': type = stSat; break; + case 'T': type = stTerr; break; +@@ -68,7 +74,11 @@ int cSource::FromString(const char *s) + int pos = 0; + bool dot = false; + bool neg = false; ++#ifdef USE_SOURCECAPS ++ while (*++s && !isblank(*s)) { ++#else + while (*++s) { ++#endif /* SOURCECAPS */ + switch (toupper(*s)) { + case '0' ... '9': pos *= 10; + pos += *s - '0'; +diff -ruNp vdr-1.6.0-2/sources.conf vdr-1.6.0-2-extensions/sources.conf +--- vdr-1.6.0-2/sources.conf 2008-09-11 13:29:43.000000000 +0200 ++++ vdr-1.6.0-2-extensions/sources.conf 2009-04-09 20:48:27.000000000 +0200 +@@ -194,3 +194,7 @@ C Cable + # Terrestrial + + T Terrestrial ++ ++# Plugin PLUGINPARAM ++ ++#P Plugin +diff -ruNp vdr-1.6.0-2/sources.h vdr-1.6.0-2-extensions/sources.h +--- vdr-1.6.0-2/sources.h 2005-05-14 11:30:41.000000000 +0200 ++++ vdr-1.6.0-2-extensions/sources.h 2009-04-09 20:48:27.000000000 +0200 +@@ -16,10 +16,17 @@ class cSource : public cListObject { + public: + enum eSourceType { + stNone = 0x0000, ++#ifdef USE_PLUGINPARAM ++ stPlug = 0x2000, ++#endif /* PLUGINPARAM */ + stCable = 0x4000, + stSat = 0x8000, + stTerr = 0xC000, ++#ifdef USE_PLUGINPARAM ++ st_Mask = 0xE000, ++#else + st_Mask = 0xC000, ++#endif /* PLUGINPARAM */ + st_Neg = 0x0800, + st_Pos = 0x07FF, + }; +@@ -35,6 +42,9 @@ public: + static cString ToString(int Code); + static int FromString(const char *s); + static int FromData(eSourceType SourceType, int Position = 0, bool East = false); ++#ifdef USE_PLUGINPARAM ++ static bool IsPlug(int Code) { return (Code & st_Mask) == stPlug; } ++#endif /* PLUGINPARAM */ + static bool IsCable(int Code) { return (Code & st_Mask) == stCable; } + static bool IsSat(int Code) { return (Code & st_Mask) == stSat; } + static bool IsTerr(int Code) { return (Code & st_Mask) == stTerr; } +diff -ruNp vdr-1.6.0-2/status.c vdr-1.6.0-2-extensions/status.c +--- vdr-1.6.0-2/status.c 2008-02-16 15:46:31.000000000 +0100 ++++ vdr-1.6.0-2-extensions/status.c 2009-04-09 20:48:27.000000000 +0200 +@@ -29,6 +29,20 @@ void cStatus::MsgTimerChange(const cTime + sm->TimerChange(Timer, Change); + } + ++#ifdef USE_STREAMDEVEXT ++void cStatus::MsgRecordingChange(const cRecording *Recording, eStatusChange Change) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->RecordingChange(Recording, Change); ++} ++ ++void cStatus::MsgChannelChange(const cChannel *Channel, eStatusChange Change) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->ChannelChange(Channel, Change); ++} ++#endif /* STREAMDEVEXT */ ++ + void cStatus::MsgChannelSwitch(const cDevice *Device, int ChannelNumber) + { + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) +@@ -124,3 +138,87 @@ void cStatus::MsgOsdProgramme(time_t Pre + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle); + } ++ ++#ifdef USE_PINPLUGIN ++bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* Channel) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ChannelProtected(Device, Channel) == true) ++ return true; ++ return false; ++} ++ ++bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ReplayProtected(Recording, Name, Base, isDirectory, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgRecordingFile(const char* FileName) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->RecordingFile(FileName); ++} ++ ++void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->TimerCreation(Timer, Event); ++} ++ ++bool cStatus::MsgPluginProtected(cPlugin* Plugin, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->PluginProtected(Plugin, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgUserAction(const eKeys key, const cOsdObject* Interact) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->UserAction(key, Interact); ++} ++ ++bool cStatus::MsgMenuItemProtected(const char* Name, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->MenuItemProtected(Name, menuView) == true) ++ return true; ++ return false; ++} ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_GRAPHTFT ++void cStatus::MsgOsdSetEvent(const cEvent* event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetEvent(event); ++} ++ ++void cStatus::MsgOsdSetRecording(const cRecording* recording) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetRecording(recording); ++} ++ ++void cStatus::MsgOsdMenuDisplay(const char* kind) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDisplay(kind); ++} ++ ++void cStatus::MsgOsdMenuDestroy() ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDestroy(); ++} ++ ++void cStatus::MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdEventItem(Event, Text, Index, Count); ++} ++#endif /* GRAPHTFT */ +diff -ruNp vdr-1.6.0-2/status.h vdr-1.6.0-2-extensions/status.h +--- vdr-1.6.0-2/status.h 2008-02-16 16:00:33.000000000 +0100 ++++ vdr-1.6.0-2-extensions/status.h 2009-04-09 20:48:27.000000000 +0200 +@@ -14,8 +14,14 @@ + #include "device.h" + #include "player.h" + #include "tools.h" ++#ifdef USE_PINPLUGIN ++#include "plugin.h" ++#endif /* PINPLUGIN */ + + enum eTimerChange { tcMod, tcAdd, tcDel }; ++#ifdef USE_STREAMDEVEXT ++enum eStatusChange { scMod, scAdd, scDel }; ++#endif /* STREAMDEVEXT */ + + class cTimer; + +@@ -30,6 +36,16 @@ protected: + // been added or will be deleted, respectively. In case of tcMod, + // Timer is NULL; this indicates that some timer has been changed. + // Note that tcAdd and tcDel are always also followed by a tcMod. ++#ifdef USE_STREAMDEVEXT ++ virtual void RecordingChange(const cRecording *Recording, eStatusChange Change) {} ++ // Indicates a change in the recordings settings. ++ // If Change is scAdd or scDel, Recording points to the recording that has ++ // been added or will be deleted, respectively. In case of scMod, ++ // Timer is NULL; this indicates that some timer has been changed. ++ // Note that scAdd and scDel are always also followed by a scMod. ++ virtual void ChannelChange(const cChannel *Channel, eStatusChange Change) {} ++ // Indicates a change in the channel list. ++#endif /* STREAMDEVEXT */ + virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {} + // Indicates a channel switch on the given DVB device. + // If ChannelNumber is 0, this is before the channel is being switched, +@@ -80,11 +96,45 @@ protected: + // The OSD displays the single line Text with the current channel information. + virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {} + // The OSD displays the given programme information. ++#ifdef USE_PINPLUGIN ++ virtual bool ChannelProtected(const cDevice *Device, const cChannel* Channel) { return false; } ++ // Checks if a channel is protected. ++ virtual bool ReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false) { return false; } ++ // Checks if a recording is protected. ++ virtual void RecordingFile(const char* FileName) {} ++ // The given DVB device has started recording to FileName. FileName is the name of the ++ // recording directory ++ virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {} ++ // The given timer is created ++ virtual bool PluginProtected(cPlugin* Plugin, int menuView = false) { return false; } ++ // Checks if a plugin is protected. ++ virtual void UserAction(const eKeys key, const cOsdObject* Interact) {} ++ // report user action ++ virtual bool MenuItemProtected(const char* Name, int menuView = false) { return false; } ++ // Checks if a menu entry is protected. ++#endif /* PINPLUGIN */ ++#ifdef USE_GRAPHTFT ++ virtual void OsdSetRecording(const cRecording* recording) {} ++ // The OSD displays the recording information. ++ virtual void OsdSetEvent(const cEvent* event) {} ++ // The OSD displays the event information. ++ virtual void OsdMenuDisplay(const char* kind) {} ++ // report menu creation ++ virtual void OsdMenuDestroy() {} ++ // report menu destruvtion ++ virtual void OsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) {} ++ // The OSD displays the given single line Event as menu item at Index. ++#endif /* GRAPHTFT */ ++ + public: + cStatus(void); + virtual ~cStatus(); + // These functions are called whenever the related status information changes: + static void MsgTimerChange(const cTimer *Timer, eTimerChange Change); ++#ifdef USE_STREAMDEVEXT ++ static void MsgRecordingChange(const cRecording *Recording, eStatusChange Change); ++ static void MsgChannelChange(const cChannel *Channel, eStatusChange Change); ++#endif /* STREAMDEVEXT */ + static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber); + static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On); + static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On); +@@ -101,6 +151,22 @@ public: + static void MsgOsdTextItem(const char *Text, bool Scroll = false); + static void MsgOsdChannel(const char *Text); + static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle); ++#ifdef USE_PINPLUGIN ++ static bool MsgChannelProtected(const cDevice* Device, const cChannel* Channel); ++ static bool MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false); ++ static void MsgRecordingFile(const char* FileName); ++ static void MsgTimerCreation(cTimer* Timer, const cEvent *Event); ++ static bool MsgPluginProtected(cPlugin* Plugin, int menuView = false); ++ static void MsgUserAction(const eKeys key, const cOsdObject* Interact); ++ static bool MsgMenuItemProtected(const char* Name, int menuView = false); ++#endif /* PINPLUGIN */ ++#ifdef USE_GRAPHTFT ++ static void MsgOsdSetEvent(const cEvent* event); ++ static void MsgOsdSetRecording(const cRecording* recording); ++ static void MsgOsdMenuDisplay(const char* kind); ++ static void MsgOsdMenuDestroy(); ++ static void MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count); ++#endif /* GRAPHTFT */ + }; + + #endif //__STATUS_H +diff -ruNp vdr-1.6.0-2/submenu.c vdr-1.6.0-2-extensions/submenu.c +--- vdr-1.6.0-2/submenu.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/submenu.c 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,952 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#include "submenu.h" ++#include "plugin.h" ++ ++static const char* TAG_SYSTEM = "system"; ++static const char* TAG_PLUGIN = "plugin"; ++static const char* TAG_COMMAND = "command"; ++static const char* TAG_THREAD = "thread"; ++static const char* TAG_MENU = "menu"; ++static const char* TAG_UNDEFINED = "undefined"; ++static const char* TRUE_STR = "yes"; ++ ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++ ++cSubMenuNode::cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ _level = level; ++ ++ if (xml != NULL && xml->Type() == TiXmlNode::ELEMENT) { ++ const char *tag = xml->Value(); ++ ++ if (cSubMenuNode::IsType(tag) != cSubMenuNode::UNDEFINED) { ++ SetType(tag); ++ SetName(xml->Attribute("name")); ++ if ((_type == COMMAND) || (_type == THREAD)) { ++ SetCommand(xml->Attribute("execute")); ++ const char * confirmStr = xml->Attribute("confirm"); ++ if (confirmStr != NULL && strcmp(confirmStr, TRUE_STR) == 0) ++ _commandConfirm = true; ++ } ++ else if (_type == PLUGIN) { // Add Plugin Index ++ SetCustomTitle(xml->Attribute("title")); ++ SetPlugin(); ++ } ++ else if (_type == MENU && xml->NoChildren() == false) { ++ xml = xml->FirstChildElement(); ++ do { ++ cSubMenuNode *node = new cSubMenuNode(xml, level+1, &_subMenus, currentMenu); ++ _subMenus.Add(node); ++ } while ((xml=xml->NextSiblingElement()) != NULL); ++ } ++ } ++ } ++ else ++ throw "Invalid XML Node"; ++} ++ ++/** ++ * Construct new Node empty Node ++ * ++ * ++ */ ++cSubMenuNode::cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ ++} ++ ++ ++/** ++ * ++ */ ++void cSubMenuNode::init() ++{ ++ _name = NULL; ++ _command = NULL; ++ _title = NULL; ++ _pluginMainMenuEntry = NULL; ++ _type = UNDEFINED; ++ _level = 0; ++ _parentMenu = NULL; ++ _currentMenu = NULL; ++ _pluginIndex = 0; ++ _commandConfirm = false; ++} ++ ++ ++cSubMenuNode::~ cSubMenuNode() ++{ ++ if (_name != NULL) ++ free((void*)_name); ++ if (_command != NULL) ++ free((void*)_command); ++ if (_title != NULL) ++ free((void*)_title); ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++} ++ ++/** ++ * ++ */ ++void cSubMenuNode::SetPlugin() ++{ ++ bool found = false; ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) { ++ if (strcmp(_name, p->Name()) == 0 && p->MainMenuEntry() != NULL) { ++ SetPluginMainMenuEntry(p->MainMenuEntry()); ++ _pluginIndex = i; ++ found = true; ++ break; ++ } ++ } ++ else ++ break; ++ } ++ ++ if (!found) ++ _type = UNDEFINED; ++} ++ ++ ++bool cSubMenuNode::SaveXml(TiXmlElement * root) ++{ ++ bool ok = true; ++ ++ if (root!=NULL) { ++ TiXmlElement *e = NULL; ++ switch(_type) { ++ case SYSTEM: ++ e = new TiXmlElement(TAG_SYSTEM); ++ e->SetAttribute("name", GetName()); ++ break; ++ case COMMAND: ++ e = new TiXmlElement(TAG_COMMAND); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case THREAD: ++ e = new TiXmlElement(TAG_THREAD); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case PLUGIN: ++ e = new TiXmlElement(TAG_PLUGIN); ++ e->SetAttribute("name", GetName()); ++ if (GetCustomTitle() != NULL && strcmp(GetCustomTitle(), "") != 0) ++ e->SetAttribute("title", GetCustomTitle()); ++ break; ++ case MENU: ++ e = new TiXmlElement(TAG_MENU); ++ e->SetAttribute("name", GetName()); ++ break; ++ case UNDEFINED: ++ default: ++ ok = false; ++ break; ++ } ++ if (ok) { ++ root->LinkEndChild(e); ++ if (HasSubMenus()) ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SaveXml(e); ++ } ++ } ++ ++ return(ok); ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::IsType(const char *name) ++{ ++ Type type = UNDEFINED; ++ ++ if (strcmp(name ,TAG_SYSTEM) == 0) ++ type = cSubMenuNode::SYSTEM; ++ else if (strcmp(name ,TAG_PLUGIN) == 0) ++ type = cSubMenuNode::PLUGIN; ++ else if (strcmp(name ,TAG_COMMAND) == 0) ++ type = cSubMenuNode::COMMAND; ++ else if (strcmp(name ,TAG_THREAD) == 0) ++ type = cSubMenuNode::THREAD; ++ else if (strcmp(name ,TAG_MENU) == 0) ++ type = cSubMenuNode::MENU; ++ ++ return(type); ++} ++ ++void cSubMenuNode::SetType(const char * name) ++{ ++ _type = IsType(name); ++} ++ ++void cSubMenuNode::SetType(enum Type type) ++{ ++ _type = type; ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::GetType() ++{ ++ return(_type); ++} ++ ++const char * cSubMenuNode::GetTypeAsString() ++{ ++ const char *str=NULL; ++ switch(_type) { ++ case SYSTEM: ++ str = TAG_SYSTEM; ++ break; ++ case COMMAND: ++ str = TAG_COMMAND; ++ break; ++ case THREAD: ++ str = TAG_THREAD; ++ break; ++ case PLUGIN: ++ str = TAG_PLUGIN; ++ break; ++ case MENU: ++ str = TAG_MENU; ++ break; ++ case UNDEFINED: ++ str = TAG_UNDEFINED; ++ default: ++ break; ++ } ++ ++ return(str); ++} ++ ++void cSubMenuNode::SetCommand(const char * command) ++{ ++ if (_command != NULL) ++ free((void*)_command); ++ ++ if (command != NULL) ++ _command = strdup(command); ++ else ++ _command = NULL; ++} ++ ++const char * cSubMenuNode::GetCommand() ++{ ++ return(_command); ++} ++ ++bool cSubMenuNode::CommandConfirm() ++{ ++ return(_commandConfirm); ++} ++ ++void cSubMenuNode::SetCommandConfirm(int val) ++{ ++ if (val == 1) ++ _commandConfirm = true; ++ else ++ _commandConfirm = false; ++} ++ ++void cSubMenuNode::SetCustomTitle(const char * title) ++{ ++ if (_title != NULL) ++ free((void*)_title); ++ ++ if (title != NULL) ++ _title = strdup(title); ++ else ++ _title = NULL; ++} ++ ++const char * cSubMenuNode::GetCustomTitle() ++{ ++ return(_title); ++} ++ ++void cSubMenuNode::SetName(const char * name) ++{ ++ if (_name) ++ free ((void*)_name); ++ ++ if (name != NULL) ++ _name = strdup(name); ++ else ++ _name = NULL; ++} ++ ++const char * cSubMenuNode::GetName() ++{ ++ return(_name); ++} ++ ++int cSubMenuNode::GetLevel() ++{ ++ return(_level); ++} ++ ++void cSubMenuNode::SetLevel(int level) ++{ ++ _level = level; ++ if (HasSubMenus()) { //Adjust Levels of Subnodes ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SetLevel(level+1); ++ } ++} ++ ++int cSubMenuNode::GetPluginIndex() ++{ ++ return(_pluginIndex); ++} ++ ++void cSubMenuNode::SetPluginIndex(int index) ++{ ++ _pluginIndex = index; ++} ++ ++void cSubMenuNode::SetPluginMainMenuEntry(const char * mainMenuEntry) ++{ ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++ ++ if (_title != NULL && strcmp(_title, "") != 0) ++ _pluginMainMenuEntry = strdup(_title); ++ else if (mainMenuEntry != NULL) ++ _pluginMainMenuEntry = strdup(mainMenuEntry); ++ else ++ _pluginMainMenuEntry = NULL; ++} ++ ++const char * cSubMenuNode::GetPluginMainMenuEntry() ++{ ++ return(_pluginMainMenuEntry); ++} ++ ++ ++ ++cSubMenuNodes * cSubMenuNode::GetParentMenu() ++{ ++ return(_parentMenu); ++} ++ ++void cSubMenuNode::SetParentMenu(cSubMenuNodes * parent) ++{ ++ _parentMenu = parent; ++} ++ ++cSubMenuNodes * cSubMenuNode::GetCurrentMenu() ++{ ++ return(_currentMenu); ++} ++ ++void cSubMenuNode::SetCurrentMenu(cSubMenuNodes * current) ++{ ++ _currentMenu = current; ++} ++ ++ ++cSubMenuNodes * cSubMenuNode::GetSubMenus() ++{ ++ return(&_subMenus); ++} ++ ++bool cSubMenuNode::HasSubMenus() ++{ ++ if (_subMenus.Count() > 0) ++ return(true); ++ else ++ return(false); ++} ++ ++ ++void cSubMenuNode::Print(int index) ++{ ++ for (int i = 0; i < index; i++) ++ printf(" "); ++ ++ printf("Name=%s Type=%s Level=%d", _name, GetTypeAsString(), _level); ++ if (_type == COMMAND || _type == THREAD) ++ printf(" Command=%s", _command); ++ else if (_type == PLUGIN && _title != NULL) ++ printf(" Title=%s", _title); ++ printf("\n"); ++ ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->Print(index+4); ++} ++ ++ ++//################################################################################ ++//# ++//################################################################################ ++cSubMenu::cSubMenu() ++{ ++ _menuSuffix = NULL; ++ _fname = NULL; ++ _commandResult = NULL; ++ _currentMenuTree = &_menuTree; ++ _currentParentMenuTree = NULL; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = -1; ++#endif /* PINPLUGIN */ ++ _nodeArray = NULL; ++ _nrNodes = 0; ++} ++ ++ ++cSubMenu::~cSubMenu() ++{ ++ if (_menuSuffix) ++ free(_menuSuffix); ++ if (_fname) ++ free(_fname); ++ if (_commandResult) ++ free(_commandResult); ++ if (_nodeArray) ++ free(_nodeArray); ++ _nrNodes = 0; ++} ++ ++ ++bool cSubMenu::LoadXml(char *fname) ++{ ++ TiXmlDocument xmlDoc = TiXmlDocument(fname); ++ TiXmlElement *root = NULL; ++ cSubMenuNode *node = NULL; ++ ++ bool ok = true; ++ //Clear previously loaded Menu ++ if (_fname != NULL) ++ free(_fname); ++ _menuTree.Clear(); ++ _fname = strdup(fname); ++ ++ if ((ok = xmlDoc.LoadFile())) { ++ if ((root = xmlDoc.FirstChildElement("menus")) != NULL) { ++ char *tmp = NULL; ++ if ((tmp = (char*)root->Attribute("suffix")) == NULL) ++ asprintf(&_menuSuffix, " "); // set default menuSuffix // asprintf(&_menuSuffix, " ..."); ++ else ++ asprintf(&_menuSuffix, tmp); ++ ++ if ((root = root->FirstChildElement()) != NULL) { ++ do { ++ try { ++ node = new cSubMenuNode(root, 0, &_menuTree, NULL); ++ _menuTree.Add(node); ++ } ++ catch (char *message) { ++ esyslog("ERROR: while decoding XML Node"); ++ ok = false; ++ } ++ } while (ok == true && (root = root->NextSiblingElement()) != NULL); ++ addMissingPlugins(); ++ removeUndefinedNodes(); ++ } ++ } ++ else { ++ esyslog("ERROR: in %s, missing Tag <menus>\n", fname); ++ ok = false; ++ } ++ } ++ else { ++ esyslog("ERROR: in %s : %s Col=%d Row=%d\n", ++ fname, ++ xmlDoc.ErrorDesc(), ++ xmlDoc.ErrorCol(), ++ xmlDoc.ErrorRow()); ++ ok = false; ++ } ++ ++ return(ok); ++} ++ ++ ++bool cSubMenu::SaveXml() ++{ ++ return(SaveXml(_fname)); ++} ++ ++ ++bool cSubMenu::SaveXml(char *fname) ++{ ++ bool ok = true; ++ ++ if (_fname != NULL) { ++ TiXmlDocument xml = TiXmlDocument(fname); ++ TiXmlComment comment; ++ comment.SetValue("\n\ ++- VDR Menu-Configuration File\n\ ++-\n\ ++-\n\ ++- Example:\n\ ++-\n\ ++ <menus>\n\ ++ <system name=\"Schedule\" />\n\ ++ <system name=\"Channels\" />\n\ ++ <system name=\"Timers\" />\n\ ++ <system name=\"Recordings\" />\n\ ++ <menu name=\"System\">\n\ ++ <system name=\"Setup\" />\n\ ++ <system name=\"Commands\" />\n\ ++ <plugin name=\"setup\" title=\"My Setup\" />\n\ ++ <command name=\"myCommand1\" execute=\"/usr/bin/mycommand1\" />\n\ ++ <command name=\"myCommand2\" execute=\"/usr/bin/mycommand2\" confirm=\"yes\" />\n\ ++ <thread name=\"myCommand3\" execute=\"/usr/bin/mycommand3\" confirm=\"yes\" />\n\ ++ <plugin name=\"epgsearch\" title=\"myProgram\" />\n\ ++ <menu name=\"mySubSubMenu\">\n\ ++ ...\n\ ++ </menu>\n\ ++ </menu>\n\ ++ <menu name=\"Suche\">\n\ ++ <plugin name=\"epgsearch\" />\n\ ++ ...\n\ ++ </menu>\n\ ++ </menus>\n\ ++"); ++ ++ TiXmlElement root("menus"); ++ root.SetAttribute("suffix", _menuSuffix); ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->SaveXml(&root); ++ ++ if (xml.InsertEndChild(comment) != NULL && xml.InsertEndChild(root) != NULL) ++ ok = xml.SaveFile(fname); ++ } ++ else ++ ok = false; ++ ++ return(ok); ++} ++ ++ ++ ++cSubMenuNodes * cSubMenu::GetMenuTree() ++{ ++ return(_currentMenuTree); ++} ++ ++ ++void cSubMenu::PrintMenuTree() ++{ ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->Print(); ++} ++ ++ ++int cSubMenu::GetNrOfNodes() ++{ ++ if (_nrNodes == 0) { ++ if ((_nrNodes = countNodes(&_menuTree)) > 0) { ++ _nodeArray = (cSubMenuNode**) malloc(sizeof(cSubMenuNode*)*_nrNodes); ++ int index = 0; ++ tree2Array(&_menuTree, index); ++ } ++ } ++ ++ return(_nrNodes); ++} ++ ++ ++/** ++ * returns the specified node within the current menu ++ * @param index position in the current menu ++ * @return node or null if not found ++ */ ++cSubMenuNode * cSubMenu::GetNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ if (_currentMenuTree == NULL || (node=_currentMenuTree->Get(index)) == NULL) ++ esyslog("ERROR: illegal call of cSubMenu::GetNode(%d)", index); ++ ++ return(node); ++} ++ ++ ++/** ++ * Get the specified Node ++ * @param index specfies the absolut indes in the list of all nodes ++ * @return node or NULL if not found ++ */ ++cSubMenuNode * cSubMenu::GetAbsNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ GetNrOfNodes(); ++ if (_nrNodes > 0 && index >= 0 && index < _nrNodes) ++ node = _nodeArray[index]; ++ ++ return(node); ++} ++ ++ ++#ifdef USE_PINPLUGIN ++bool cSubMenu::Down(cSubMenuNode *node, int currentIndex) ++#else ++bool cSubMenu::Down(int index) ++#endif /* PINPLUGIN */ ++{ ++ bool ok = true; ++#ifdef USE_PINPLUGIN ++ if (_currentMenuTree != NULL && node && node->GetType() == cSubMenuNode::MENU) { ++#else ++ cSubMenuNode *node = NULL; ++ ++ if (_currentMenuTree != NULL && (node=_currentMenuTree->Get(index)) != NULL && node->GetType() == cSubMenuNode::MENU) { ++#endif /* PINPLUGIN */ ++ _currentParentMenuTree = _currentMenuTree; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = currentIndex; ++#endif /* PINPLUGIN */ ++ _currentMenuTree = node->GetSubMenus(); ++ } ++ else { ++ ok = false; ++#ifdef USE_PINPLUGIN ++ esyslog("ERROR: illegal call of cSubMenu::Down"); ++#else ++ esyslog("ERROR: illegal call of cSubMenu::Down(%d)", index); ++#endif /* PINPLUGIN */ ++ } ++ ++ return(ok); ++} ++ ++bool cSubMenu::Up(int *parentIndex) ++{ ++ bool ok = true; ++ ++ if (_currentMenuTree != NULL && parentIndex != NULL) { ++#ifndef USE_PINPLUGIN ++ cSubMenuNode *node = NULL; ++#endif /* PINPLUGIN */ ++ *parentIndex = 0; ++#ifdef USE_PINPLUGIN ++ if (_currentParentIndex >= 0) ++ *parentIndex = _currentParentIndex; ++#else ++ if (_currentParentMenuTree != NULL) ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ *parentIndex = i; ++ break; ++ } ++ } ++#endif /* PINPLUGIN */ ++ ++ _currentMenuTree = _currentParentMenuTree; ++ if (_currentMenuTree != NULL) ++ _currentParentMenuTree = _currentMenuTree->Get(0)->GetParentMenu(); ++ else ++ ok = false; ++ } ++ else { ++ ok = false; ++ esyslog("ERROR: illegal call of cSubMenu::Up()"); ++ } ++ ++ return(ok); ++} ++ ++const char * cSubMenu::ExecuteCommand(const char * cmd) ++{ ++ free(_commandResult); ++ _commandResult = NULL; ++ ++ dsyslog("executing command '%s'", cmd); ++ FILE *p = popen(cmd, "r"); ++ if (p) { ++ int l = 0; ++ int c; ++ while ((c = fgetc(p)) != EOF) { ++ if (l % 20 == 0) ++ _commandResult = (char *)realloc(_commandResult, l + 21); ++ _commandResult[l++] = c; ++ } ++ if (_commandResult) ++ _commandResult[l] = 0; ++ pclose(p); ++ } ++ else ++ esyslog("ERROR: can't open pipe for command '%s'", cmd); ++ ++ return _commandResult; ++} ++ ++/** ++ * Move Menu Entry to new Position ++ * @param index index of menu entry to move ++ * @param toIndex index of destination ++ * @param where After ore before the destination index ++ */ ++void cSubMenu::MoveMenu(int index, int toIndex, enum Where where) ++{ ++ if (index < 0 || index > _nrNodes || // invalid index is ignored ++ toIndex < 0 || toIndex > _nrNodes || index == toIndex) ++ return; ++ ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ cSubMenuNode *destNode = GetAbsNode(toIndex); ++ ++ if (where == cSubMenu::INTO && destNode->GetType() != cSubMenuNode::MENU) ++ return; ++ ++ if (where == cSubMenu::INTO) { ++ if (destNode->GetType() == cSubMenuNode::MENU) { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()+1); ++ srcNode->SetParentMenu(destNode->GetCurrentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetSubMenus()); ++ ++ destNode->GetSubMenus()->Add(srcNode); ++ reloadNodeArray(); ++ } ++ } ++ else { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()); ++ srcNode->SetParentMenu(destNode->GetParentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetCurrentMenu()); ++ ++ if (where == cSubMenu::BEHIND) { ++ destNode->GetCurrentMenu()->Add(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ else { ++ destNode->GetCurrentMenu()->Ins(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * Create a new Menu Entry ++ * @param index index of destination ++ * @param menuTitle Titel of new Menu entry ++ */ ++void cSubMenu::CreateMenu(int index, const char * menuTitle) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(menuTitle); ++ newNode->SetType(cSubMenuNode::MENU); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * delete the specified entry, or subtree if the specified entry is a menu ++ * @param index destion index ++ */ ++void cSubMenu::DeleteMenu(int index) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ srcNode->GetCurrentMenu()->Del(srcNode, true); ++ reloadNodeArray(); ++ } ++} ++ ++ ++// Private Methods ++ ++int cSubMenu::countNodes(cSubMenuNodes * tree) ++{ ++ int count = 0; ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ count++; ++ if (node->HasSubMenus()) ++ count += countNodes(node->GetSubMenus()); ++ } ++ } ++ return(count); ++} ++ ++ ++void cSubMenu::tree2Array(cSubMenuNodes * tree, int &index) ++{ ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ _nodeArray[index++]=node; ++ if (node->HasSubMenus()) ++ tree2Array(node->GetSubMenus(), index); ++ } ++ } ++ ++} ++ ++bool cSubMenu::IsPluginInMenu(const char * name) ++{ ++ bool found = false; ++ for (int i = 0; i < _nrNodes && found == false; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::PLUGIN && strcmp(name, node->GetName()) == 0) ++ found = true; ++ } ++ return(found); ++} ++ ++/** ++ * Adds the given plugin to the Menu-Tree if not allready in List ++ * @param name specifies the name of the plugin ++ */ ++void cSubMenu::AddPlugin(const char * name) ++{ ++ if (! IsPluginInMenu(name)) { ++ cSubMenuNode *node = new cSubMenuNode(&_menuTree, NULL); ++ node->SetName(name); ++ node->SetType("plugin"); ++ node->SetPlugin(); ++ _menuTree.Add(node); ++ } ++} ++ ++void cSubMenu::addMissingPlugins() ++{ ++ _nrNodes = GetNrOfNodes(); ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) ++ AddPlugin(p->Name()); ++ else ++ break; ++ } ++ reloadNodeArray(); ++} ++ ++/** ++ * Adds the given command to the Menu-Tree ++ * @param name specifies the name of the command ++ */ ++void cSubMenu::CreateCommand(int index, const char * name, const char * execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("command"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++void cSubMenu::CreateThread(int index, const char * name, const char * execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("thread"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * reloads the internal Array of Nodes ++ */ ++void cSubMenu::reloadNodeArray() ++{ ++ if (_nrNodes > 0) ++ free(_nodeArray); ++ _nodeArray = NULL; ++ _nrNodes = 0; ++ _nrNodes = GetNrOfNodes(); ++} ++ ++/** ++ * remove Undefined Nodes ++ */ ++void cSubMenu::removeUndefinedNodes() ++{ ++ bool remove = false; ++ ++ reloadNodeArray(); ++ for (int i = 0; i < _nrNodes; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::UNDEFINED) { ++ cSubMenuNodes *pMenu = node->GetCurrentMenu(); ++ pMenu->Del(node, true); ++ remove = true; ++ } ++ } ++ if (remove) ++ reloadNodeArray(); ++} ++ ++ ++/** ++* Retrieves the Menutitel of the parent Menu ++*/ ++const char *cSubMenu::GetParentMenuTitel() ++{ ++ const char * result = ""; ++ ++ if (_currentMenuTree != NULL && _currentParentMenuTree != NULL) { ++ cSubMenuNode *node = NULL; ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ result = node->GetName(); ++ break; ++ } ++ } ++ } ++ ++ return(result); ++} ++ ++#endif ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/submenu.h vdr-1.6.0-2-extensions/submenu.h +--- vdr-1.6.0-2/submenu.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/submenu.h 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,160 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#define SUBMENU_H ++ ++#include "thread.h" ++#include "tools.h" ++#include "tinystr.h" ++ ++class cSubMenuNode; ++class cSubMenuNodes; ++class cSubMenu; ++ ++ ++class cSubMenuNodes : public cList<cSubMenuNode> {}; ++ ++// execute cmd thread ++class cExecCmdThread : public cThread { ++private: ++ char *ExecCmd; ++protected: ++ virtual void Action(void) { ++ if (system(ExecCmd) == 0) ++ esyslog("%s - finished", ExecCmd); ++ delete(this); ++ }; ++public: ++ cExecCmdThread(char *cmd) { ++ asprintf(&ExecCmd, "%s", cmd); ++ } ++ cExecCmdThread(const char *cmd) { ++ asprintf(&ExecCmd, "%s", cmd); ++ } ++ ~cExecCmdThread() { ++ free(ExecCmd); ++ }; ++ }; ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++class cSubMenuNode : public cListObject { ++public: ++ enum Type { UNDEFINED, SYSTEM, COMMAND, THREAD, PLUGIN, MENU }; ++ cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ ~cSubMenuNode(); ++ bool SaveXml(TiXmlElement * root); ++ static cSubMenuNode::Type IsType(const char *name); ++ void SetType(const char *name); ++ void SetType(enum Type type); ++ void SetPlugin(); ++ cSubMenuNode::Type GetType(); ++ const char *GetTypeAsString(); ++ void SetCommand(const char *command); ++ bool CommandConfirm(); ++ void SetCommandConfirm(int val); ++ const char *GetCommand(); ++ void SetCustomTitle(const char *title); ++ const char *GetCustomTitle(); ++ void SetName(const char *name); ++ const char*GetName(); ++ int GetLevel(); ++ void SetLevel(int level); ++ int GetPluginIndex(); ++ void SetPluginIndex(int index); ++ void SetPluginMainMenuEntry(const char *mainMenuEntry); ++ const char *GetPluginMainMenuEntry(); ++ cSubMenuNodes *GetParentMenu(); ++ void SetParentMenu(cSubMenuNodes *parent); ++ cSubMenuNodes *GetCurrentMenu(); ++ void SetCurrentMenu(cSubMenuNodes *current); ++ cSubMenuNodes *GetSubMenus(); ++ bool HasSubMenus(); ++ void Print(int index = 0); ++private: ++ Type _type; ++ int _level; ++ // Plugin Variables ++ int _pluginIndex; ++ const char *_pluginMainMenuEntry; ++ // common ++ const char *_name; ++ const char *_command; ++ bool _commandConfirm; ++ const char *_title; ++ cSubMenuNodes _subMenus; ++ cSubMenuNodes *_parentMenu; ++ cSubMenuNodes *_currentMenu; ++ void init(); ++ }; ++ ++ ++//################################################################################ ++//# SubMenu Class ++//################################################################################ ++class cSubMenu { ++public: ++ cSubMenu(); ++ ~cSubMenu(); ++ enum Where { BEFORE, BEHIND, INTO}; ++ bool LoadXml(char *fname); ++ bool SaveXml(char *fname); ++ bool SaveXml(); ++ cSubMenuNodes *GetMenuTree(); ++ bool Up(int *ParentIndex); ++#ifdef USE_PINPLUGIN ++ bool Down(cSubMenuNode* node, int currentIndex); ++#else ++ bool Down(int index); ++#endif /* PINPLUGIN */ ++ int GetNrOfNodes(); ++ cSubMenuNode* GetAbsNode(int index); ++ cSubMenuNode* GetNode(int index); ++ void PrintMenuTree(); ++ bool IsPluginInMenu(const char *name); ++ void AddPlugin(const char *name); ++ void CreateCommand(int index, const char *name, const char *execute, int confirm); ++ void CreateThread(int index, const char *name, const char *execute, int confirm); ++ const char *ExecuteCommand(const char *command); ++ void MoveMenu(int index, int toindex, enum Where); ++ void CreateMenu(int index, const char *menuTitle); ++ void DeleteMenu(int index); ++ char *GetMenuSuffix() { return _menuSuffix; } ++ void SetMenuSuffix(char *suffix) { if (_menuSuffix) free(_menuSuffix); asprintf(&_menuSuffix, suffix); } ++ bool isTopMenu() { return (_currentParentMenuTree == NULL); } ++ const char *GetParentMenuTitel(); ++private: ++ cSubMenuNodes _menuTree; ++ cSubMenuNodes *_currentMenuTree; ++ cSubMenuNodes *_currentParentMenuTree; ++#ifdef USE_PINPLUGIN ++ int _currentParentIndex; ++#endif /* PINPLUGIN */ ++ char *_fname; ++ char *_commandResult; ++ int _nrNodes; ++ cSubMenuNode **_nodeArray; ++ char *_menuSuffix; ++ int countNodes(cSubMenuNodes *tree); ++ void tree2Array(cSubMenuNodes *tree, int &index); ++ void addMissingPlugins(); ++ void reloadNodeArray(); ++ void removeUndefinedNodes(); ++ }; ++ ++#endif //__SUBMENU_H ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/svdrp.c vdr-1.6.0-2-extensions/svdrp.c +--- vdr-1.6.0-2/svdrp.c 2008-09-11 13:29:43.000000000 +0200 ++++ vdr-1.6.0-2-extensions/svdrp.c 2009-04-09 20:48:27.000000000 +0200 +@@ -39,6 +39,9 @@ + #include "timers.h" + #include "tools.h" + #include "videodir.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ + + // --- cSocket --------------------------------------------------------------- + +@@ -296,6 +299,10 @@ const char *HelpPages[] = { + "REMO [ on | off ]\n" + " Turns the remote control on or off. Without a parameter, the current\n" + " status of the remote control is reported.", ++#ifdef USE_LIEMIEXT ++ "RENR <number> <new name>\n" ++ " Rename recording. Number must be the Number as returned by LSTR command.", ++#endif /* LIEMIEXT */ + "SCAN\n" + " Forces an EPG scan. If this is a single DVB device system, the scan\n" + " will be done on the primary device unless it is currently recording.", +@@ -616,6 +623,9 @@ void cSVDRP::CmdDELC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("channel %s deleted", Option); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NULL, scDel); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -1135,6 +1145,9 @@ void cSVDRP::CmdMODC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("modifed channel %d %s", channel->Number(), *channel->ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scMod); ++#endif /* STREAMDEVEXT */ + Reply(250, "%d %s", channel->Number(), *channel->ToText()); + } + else +@@ -1221,6 +1234,9 @@ void cSVDRP::CmdMOVC(const char *Option) + else + cDevice::SetCurrentChannel(CurrentChannel); + } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(ToChannel, scMod); ++#endif /* STREAMDEVEXT */ + isyslog("channel %d moved to %d", FromNumber, ToNumber); + Reply(250,"Channel \"%d\" moved to \"%d\"", From, To); + } +@@ -1264,6 +1280,9 @@ void cSVDRP::CmdNEWC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("new channel %d %s", channel->Number(), *channel->ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scAdd); ++#endif /* STREAMDEVEXT */ + Reply(250, "%d %s", channel->Number(), *channel->ToText()); + } + else +@@ -1472,6 +1491,40 @@ void cSVDRP::CmdSCAN(const char *Option) + Reply(250, "EPG scan triggered"); + } + ++#ifdef USE_LIEMIEXT ++void cSVDRP::CmdRENR(const char *Option) ++{ ++ bool recordings = Recordings.Update(true); ++ if (recordings) { ++ if (*Option) { ++ char *tail; ++ int n = strtol(Option, &tail, 10); ++ cRecording *recording = Recordings.Get(n - 1); ++ if (recording && tail && tail != Option) { ++ int priority = recording->priority; ++ int lifetime = recording->lifetime; ++ char *oldName = strdup(recording->Name()); ++ tail = skipspace(tail); ++ if (recording->Rename(tail, &priority, &lifetime)) { ++ Reply(250, "Renamed \"%s\" to \"%s\"", oldName, recording->Name()); ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ } ++ else ++ Reply(501, "Renaming \"%s\" to \"%s\" failed", oldName, tail); ++ free(oldName); ++ } ++ else ++ Reply(501, "Recording not found or wrong syntax"); ++ } ++ else ++ Reply(501, "Missing Input settings"); ++ } ++ else ++ Reply(550, "No recordings available"); ++} ++#endif /* LIEMIEXT */ ++ + void cSVDRP::CmdSTAT(const char *Option) + { + if (*Option) { +@@ -1587,6 +1640,9 @@ void cSVDRP::Execute(char *Cmd) + else if (CMD("PLUG")) CmdPLUG(s); + else if (CMD("PUTE")) CmdPUTE(s); + else if (CMD("REMO")) CmdREMO(s); ++#ifdef USE_LIEMIEXT ++ else if (CMD("RENR")) CmdRENR(s); ++#endif /* LIEMIEXT */ + else if (CMD("SCAN")) CmdSCAN(s); + else if (CMD("STAT")) CmdSTAT(s); + else if (CMD("UPDT")) CmdUPDT(s); +diff -ruNp vdr-1.6.0-2/svdrp.h vdr-1.6.0-2-extensions/svdrp.h +--- vdr-1.6.0-2/svdrp.h 2007-04-30 14:28:28.000000000 +0200 ++++ vdr-1.6.0-2-extensions/svdrp.h 2009-04-09 20:48:27.000000000 +0200 +@@ -79,6 +79,9 @@ private: + void CmdPLUG(const char *Option); + void CmdPUTE(const char *Option); + void CmdREMO(const char *Option); ++#ifdef USE_LIEMIEXT ++ void CmdRENR(const char *Option); ++#endif /* LIEMIEXT */ + void CmdSCAN(const char *Option); + void CmdSTAT(const char *Option); + void CmdUPDT(const char *Option); +diff -ruNp vdr-1.6.0-2/timers.c vdr-1.6.0-2-extensions/timers.c +--- vdr-1.6.0-2/timers.c 2008-09-11 13:29:39.000000000 +0200 ++++ vdr-1.6.0-2-extensions/timers.c 2009-04-09 20:48:27.000000000 +0200 +@@ -13,6 +13,9 @@ + #include "device.h" + #include "i18n.h" + #include "libsi/si.h" ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "recording.h" + #include "remote.h" + #include "status.h" +@@ -46,6 +49,9 @@ cTimer::cTimer(bool Instant, bool Pause, + stop -= 2400; + priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; + lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + aux = NULL; + event = NULL; +@@ -79,12 +85,18 @@ cTimer::cTimer(const cEvent *Event) + stop -= 2400; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + const char *Title = Event->Title(); + if (!isempty(Title)) + Utf8Strn0Cpy(file, Event->Title(), sizeof(file)); + aux = NULL; + event = NULL; // let SetEvent() be called to get a log message ++#ifdef USE_PINPLUGIN ++ cStatus::MsgTimerCreation(this, Event); ++#endif /* PINPLUGIN */ + } + + cTimer::cTimer(const cTimer &Timer) +@@ -119,6 +131,9 @@ cTimer& cTimer::operator= (const cTimer + stop = Timer.stop; + priority = Timer.priority; + lifetime = Timer.lifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = Timer.fskProtection; ++#endif /* PINPLUGIN */ + strncpy(file, Timer.file, sizeof(file)); + free(aux); + aux = Timer.aux ? strdup(Timer.aux) : NULL; +@@ -313,6 +328,9 @@ bool cTimer::Parse(const char *s) + result = false; + } + } ++#ifdef USE_PINPLUGIN ++ fskProtection = aux && strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"); ++#endif /* PINPLUGIN */ + free(channelbuffer); + free(daybuffer); + free(filebuffer); +@@ -559,6 +577,9 @@ void cTimer::SetRecording(bool Recording + SetFlags(tfRecording); + else + ClrFlags(tfRecording); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(NULL, scAdd); ++#endif /* STREAMDEVEXT */ + isyslog("timer %s %s", *ToDescr(), recording ? "start" : "stop"); + } + +@@ -622,6 +643,35 @@ void cTimer::OnOff(void) + Matches(); // refresh start and end time + } + ++#ifdef USE_PINPLUGIN ++void cTimer::SetFskProtection(int aFlag) ++{ ++ char* p; ++ char* tmp = 0; ++ ++ fskProtection = aFlag; ++ ++ if (fskProtection && (!aux || !strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // add protection info to aux ++ ++ if (aux) { tmp = strdup(aux); free(aux); } ++ asprintf(&aux,"%s<pin-plugin><protected>yes</protected></pin-plugin>", tmp ? tmp : ""); ++ } ++ else if (!fskProtection && aux && (p = strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // remove protection info to aux ++ ++ asprintf(&tmp, "%.*s%s", p-aux, aux, p+strlen("<pin-plugin><protected>yes</protected></pin-plugin>")); ++ free(aux); ++ aux = strdup(tmp); ++ } ++ ++ if (tmp) ++ free(tmp); ++} ++#endif /* PINPLUGIN */ ++ + // --- cTimers --------------------------------------------------------------- + + cTimers Timers; +@@ -651,7 +701,11 @@ cTimer *cTimers::GetMatch(time_t t) + static int LastPending = -1; + cTimer *t0 = NULL; + for (cTimer *ti = First(); ti; ti = Next(ti)) { ++#ifdef USE_LIVEBUFFER ++ if (!ti->Recording() && (ti->Matches(t) || cLiveBufferManager::InLiveBuffer(ti))) { ++#else + if (!ti->Recording() && ti->Matches(t)) { ++#endif /* LIVEBUFFER */ + if (ti->Pending()) { + if (ti->Index() > LastPending) + LastPending = ti->Index(); +@@ -752,7 +806,11 @@ void cTimers::DeleteExpired(void) + cTimer *ti = First(); + while (ti) { + cTimer *next = Next(ti); ++#ifdef USE_LIVEBUFFER ++ if (ti->Expired() && (!cLiveBufferManager::InLiveBuffer(ti) || !ti->HasFlags(tfActive))) { ++#else + if (ti->Expired()) { ++#endif /* LIVEBUFFER */ + isyslog("deleting timer %s", *ti->ToDescr()); + Del(ti); + SetModified(); +diff -ruNp vdr-1.6.0-2/timers.h vdr-1.6.0-2-extensions/timers.h +--- vdr-1.6.0-2/timers.h 2008-02-16 15:33:23.000000000 +0100 ++++ vdr-1.6.0-2-extensions/timers.h 2009-04-09 20:48:27.000000000 +0200 +@@ -20,12 +20,18 @@ enum eTimerFlags { tfNone = 0x0000, + tfInstant = 0x0002, + tfVps = 0x0004, + tfRecording = 0x0008, ++#ifdef USE_LIVEBUFFER ++ tfhasLiveBuf= 0x0010, ++#endif /* LIVEBUFFER */ + tfAll = 0xFFFF, + }; + enum eTimerMatch { tmNone, tmPartial, tmFull }; + + class cTimer : public cListObject { + friend class cMenuEditTimer; ++#ifdef USE_LIVEBUFFER ++ friend class cLiveBufferControl; ++#endif /* LIVEBUFFER */ + private: + mutable time_t startTime, stopTime; + time_t lastSetEvent; +@@ -37,6 +43,9 @@ private: + int start; + int stop; + int priority; ++#ifdef USE_PINPLUGIN ++ int fskProtection; ++#endif /* PINPLUGIN */ + int lifetime; + mutable char file[MaxFileName]; + char *aux; +@@ -58,6 +67,9 @@ public: + int Start(void) const { return start; } + int Stop(void) const { return stop; } + int Priority(void) const { return priority; } ++#ifdef USE_PINPLUGIN ++ int FskProtection(void) const { return fskProtection; } ++#endif /* PINPLUGIN */ + int Lifetime(void) const { return lifetime; } + const char *File(void) const { return file; } + time_t FirstDay(void) const { return weekdays ? day : 0; } +@@ -86,6 +98,9 @@ public: + void SetInVpsMargin(bool InVpsMargin); + void SetPriority(int Priority); + void SetFlags(uint Flags); ++#ifdef USE_PINPLUGIN ++ void SetFskProtection(int aFlag); ++#endif /* PINPLUGIN */ + void ClrFlags(uint Flags); + void InvFlags(uint Flags); + bool HasFlags(uint Flags) const; +diff -ruNp vdr-1.6.0-2/tinystr.c vdr-1.6.0-2-extensions/tinystr.c +--- vdr-1.6.0-2/tinystr.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/tinystr.c 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,301 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++#ifndef TIXML_USE_STL ++ ++ ++#include <stdlib.h> ++#include <string.h> ++#include <ctype.h> ++ ++#include "tinystr.h" ++ ++// TiXmlString constructor, based on a C string ++TiXmlString::TiXmlString (const char* instring) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (!instring) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = strlen (instring) + 1; ++ newstring = new char [newlen]; ++ memcpy (newstring, instring, newlen); ++ // strcpy (newstring, instring); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString copy constructor ++TiXmlString::TiXmlString (const TiXmlString& copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ // Prevent copy to self! ++ if ( © == this ) ++ return; ++ ++ if (! copy . allocated) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . cstring); ++ memcpy (newstring, copy . cstring, newlen); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString = operator. Safe when assign own content ++void TiXmlString ::operator = (const char * content) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! content) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = strlen (content) + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, content); ++ memcpy (newstring, content, newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// = operator. Safe when assign own content ++void TiXmlString ::operator = (const TiXmlString & copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! copy . length ()) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . c_str ()); ++ memcpy (newstring, copy . c_str (), newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char* str, int len ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size, size_suffix; ++ ++ // don't use strlen - it can overrun the len passed in! ++ const char* p = str; ++ size_suffix = 0; ++ ++ while ( *p && size_suffix < (unsigned)len ) ++ { ++ ++p; ++ ++size_suffix; ++ } ++ if ( !size_suffix) ++ return; ++ ++ new_size = length () + size_suffix + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ // strcpy (new_string, cstring); ++ memcpy (new_string, cstring, length ()); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strncat (new_string, str, len); ++ memcpy (new_string + length (), ++ str, ++ size_suffix); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strncat (cstring, str, len); ++ memcpy (cstring + length (), ++ str, ++ size_suffix); ++ } ++ current_length = new_size - 1; ++ cstring [current_length] = 0; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char * suffix ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size; ++ ++ new_size = length () + strlen (suffix) + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ memcpy (new_string, cstring, 1 + length ()); ++ // strcpy (new_string, cstring); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strcat (new_string, suffix); ++ memcpy (new_string + length (), ++ suffix, ++ strlen (suffix) + 1); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strcat (cstring, suffix); ++ memcpy (cstring + length (), ++ suffix, ++ strlen (suffix) + 1); ++ } ++ current_length = new_size - 1; ++} ++ ++// Check for TiXmlString equuivalence ++//bool TiXmlString::operator == (const TiXmlString & compare) const ++//{ ++// return (! strcmp (c_str (), compare . c_str ())); ++//} ++ ++//unsigned TiXmlString::length () const ++//{ ++// if (allocated) ++// // return strlen (cstring); ++// return current_length; ++// return 0; ++//} ++ ++ ++unsigned TiXmlString::find (char tofind, unsigned offset) const ++{ ++ char * lookup; ++ ++ if (offset >= length ()) ++ return (unsigned) notfound; ++ for (lookup = cstring + offset; * lookup; lookup++) ++ if (* lookup == tofind) ++ return lookup - cstring; ++ return (unsigned) notfound; ++} ++ ++ ++bool TiXmlString::operator == (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) == 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator < (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) > 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator > (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) < 0 ); ++ } ++ return false; ++} ++ ++ ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/tinystr.h vdr-1.6.0-2-extensions/tinystr.h +--- vdr-1.6.0-2/tinystr.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/tinystr.h 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,244 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++ ++#ifndef TIXML_USE_STL ++ ++#ifndef TIXML_STRING_INCLUDED ++#define TIXML_STRING_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4786 ) // Debugger truncating names. ++#endif ++ ++#include <assert.h> ++ ++/* ++ TiXmlString is an emulation of the std::string template. ++ Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. ++ Only the member functions relevant to the TinyXML project have been implemented. ++ The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase ++ a string and there's no more room, we allocate a buffer twice as big as we need. ++*/ ++class TiXmlString ++{ ++ public : ++ // TiXmlString constructor, based on a string ++ TiXmlString (const char * instring); ++ ++ // TiXmlString empty constructor ++ TiXmlString () ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ } ++ ++ // TiXmlString copy constructor ++ TiXmlString (const TiXmlString& copy); ++ ++ // TiXmlString destructor ++ ~ TiXmlString () ++ { ++ empty_it (); ++ } ++ ++ // Convert a TiXmlString into a classical char * ++ const char * c_str () const ++ { ++ if (allocated) ++ return cstring; ++ return ""; ++ } ++ ++ // Return the length of a TiXmlString ++ unsigned length () const ++ { ++ return ( allocated ) ? current_length : 0; ++ } ++ ++ // TiXmlString = operator ++ void operator = (const char * content); ++ ++ // = operator ++ void operator = (const TiXmlString & copy); ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (const char * suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (char single) ++ { ++ append (single); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (TiXmlString & suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ bool operator == (const TiXmlString & compare) const; ++ bool operator < (const TiXmlString & compare) const; ++ bool operator > (const TiXmlString & compare) const; ++ ++ // Checks if a TiXmlString is empty ++ bool empty () const ++ { ++ return length () ? false : true; ++ } ++ ++ // single char extraction ++ const char& at (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // find a char in a string. Return TiXmlString::notfound if not found ++ unsigned find (char lookup) const ++ { ++ return find (lookup, 0); ++ } ++ ++ // find a char in a string from an offset. Return TiXmlString::notfound if not found ++ unsigned find (char tofind, unsigned offset) const; ++ ++ /* Function to reserve a big amount of data when we know we'll need it. Be aware that this ++ function clears the content of the TiXmlString if any exists. ++ */ ++ void reserve (unsigned size) ++ { ++ empty_it (); ++ if (size) ++ { ++ allocated = size; ++ cstring = new char [size]; ++ cstring [0] = 0; ++ current_length = 0; ++ } ++ } ++ ++ // [] operator ++ char& operator [] (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // Error value for find primitive ++ enum { notfound = 0xffffffff, ++ npos = notfound }; ++ ++ void append (const char *str, int len ); ++ ++ protected : ++ ++ // The base string ++ char * cstring; ++ // Number of chars allocated ++ unsigned allocated; ++ // Current string size ++ unsigned current_length; ++ ++ // New size computation. It is simplistic right now : it returns twice the amount ++ // we need ++ unsigned assign_new_size (unsigned minimum_to_allocate) ++ { ++ return minimum_to_allocate * 2; ++ } ++ ++ // Internal function that clears the content of a TiXmlString ++ void empty_it () ++ { ++ if (cstring) ++ delete [] cstring; ++ cstring = NULL; ++ allocated = 0; ++ current_length = 0; ++ } ++ ++ void append (const char *suffix ); ++ ++ // append function for another TiXmlString ++ void append (const TiXmlString & suffix) ++ { ++ append (suffix . c_str ()); ++ } ++ ++ // append for a single char. ++ void append (char single) ++ { ++ if ( cstring && current_length < (allocated-1) ) ++ { ++ cstring[ current_length ] = single; ++ ++current_length; ++ cstring[ current_length ] = 0; ++ } ++ else ++ { ++ char smallstr [2]; ++ smallstr [0] = single; ++ smallstr [1] = 0; ++ append (smallstr); ++ } ++ } ++ ++} ; ++ ++/* ++ TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. ++ Only the operators that we need for TinyXML have been developped. ++*/ ++class TiXmlOutStream : public TiXmlString ++{ ++public : ++ TiXmlOutStream () : TiXmlString () {} ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const char * in) ++ { ++ append (in); ++ return (* this); ++ } ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const TiXmlString & in) ++ { ++ append (in . c_str ()); ++ return (* this); ++ } ++} ; ++ ++#endif // TIXML_STRING_INCLUDED ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/tinyxml.c vdr-1.6.0-2-extensions/tinyxml.c +--- vdr-1.6.0-2/tinyxml.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/tinyxml.c 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,1429 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include <ctype.h> ++#include "tinyxml.h" ++ ++#ifdef TIXML_USE_STL ++#include <sstream> ++#endif ++ ++ ++bool TiXmlBase::condenseWhiteSpace = true; ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream ) ++{ ++ TIXML_STRING buffer; ++ PutString( str, &buffer ); ++ (*stream) << buffer; ++} ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) ++{ ++ int i=0; ++ ++ while( i<(int)str.length() ) ++ { ++ unsigned char c = (unsigned char) str[i]; ++ ++ if ( c == '&' ++ && i < ( (int)str.length() - 2 ) ++ && str[i+1] == '#' ++ && str[i+2] == 'x' ) ++ { ++ // Hexadecimal character reference. ++ // Pass through unchanged. ++ // © -- copyright symbol, for example. ++ // ++ // The -1 is a bug fix from Rob Laveaux. It keeps ++ // an overflow from happening if there is no ';'. ++ // There are actually 2 ways to exit this loop - ++ // while fails (error case) and break (semicolon found). ++ // However, there is no mechanism (currently) for ++ // this function to return an error. ++ while ( i<(int)str.length()-1 ) ++ { ++ outString->append( str.c_str() + i, 1 ); ++ ++i; ++ if ( str[i] == ';' ) ++ break; ++ } ++ } ++ else if ( c == '&' ) ++ { ++ outString->append( entity[0].str, entity[0].strLength ); ++ ++i; ++ } ++ else if ( c == '<' ) ++ { ++ outString->append( entity[1].str, entity[1].strLength ); ++ ++i; ++ } ++ else if ( c == '>' ) ++ { ++ outString->append( entity[2].str, entity[2].strLength ); ++ ++i; ++ } ++ else if ( c == '\"' ) ++ { ++ outString->append( entity[3].str, entity[3].strLength ); ++ ++i; ++ } ++ else if ( c == '\'' ) ++ { ++ outString->append( entity[4].str, entity[4].strLength ); ++ ++i; ++ } ++ else if ( c < 32 ) ++ { ++ // Easy pass at non-alpha/numeric/symbol ++ // Below 32 is symbolic. ++ char buf[ 32 ]; ++ sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); ++ outString->append( buf, strlen( buf ) ); ++ ++i; ++ } ++ else ++ { ++ //char realc = (char) c; ++ //outString->append( &realc, 1 ); ++ *outString += (char) c; // somewhat more efficient function call. ++ ++i; ++ } ++ } ++} ++ ++ ++// <-- Strange class for a bug fix. Search for STL_STRING_BUG ++TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str ) ++{ ++ buffer = new char[ str.length()+1 ]; ++ if ( buffer ) ++ { ++ strcpy( buffer, str.c_str() ); ++ } ++} ++ ++ ++TiXmlBase::StringToBuffer::~StringToBuffer() ++{ ++ delete [] buffer; ++} ++// End strange bug fix. --> ++ ++ ++TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() ++{ ++ parent = 0; ++ type = _type; ++ firstChild = 0; ++ lastChild = 0; ++ prev = 0; ++ next = 0; ++} ++ ++ ++TiXmlNode::~TiXmlNode() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++} ++ ++ ++void TiXmlNode::CopyTo( TiXmlNode* target ) const ++{ ++ target->SetValue (value.c_str() ); ++ target->userData = userData; ++} ++ ++ ++void TiXmlNode::Clear() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++ ++ firstChild = 0; ++ lastChild = 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) ++{ ++ node->parent = this; ++ ++ node->prev = lastChild; ++ node->next = 0; ++ ++ if ( lastChild ) ++ lastChild->next = node; ++ else ++ firstChild = node; // it was an empty list. ++ ++ lastChild = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) ++{ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ return LinkEndChild( node ); ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) ++{ ++ if ( !beforeThis || beforeThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->next = beforeThis; ++ node->prev = beforeThis->prev; ++ if ( beforeThis->prev ) ++ { ++ beforeThis->prev->next = node; ++ } ++ else ++ { ++ assert( firstChild == beforeThis ); ++ firstChild = node; ++ } ++ beforeThis->prev = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) ++{ ++ if ( !afterThis || afterThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->prev = afterThis; ++ node->next = afterThis->next; ++ if ( afterThis->next ) ++ { ++ afterThis->next->prev = node; ++ } ++ else ++ { ++ assert( lastChild == afterThis ); ++ lastChild = node; ++ } ++ afterThis->next = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) ++{ ++ if ( replaceThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = withThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ node->next = replaceThis->next; ++ node->prev = replaceThis->prev; ++ ++ if ( replaceThis->next ) ++ replaceThis->next->prev = node; ++ else ++ lastChild = node; ++ ++ if ( replaceThis->prev ) ++ replaceThis->prev->next = node; ++ else ++ firstChild = node; ++ ++ delete replaceThis; ++ node->parent = this; ++ return node; ++} ++ ++ ++bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) ++{ ++ if ( removeThis->parent != this ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ if ( removeThis->next ) ++ removeThis->next->prev = removeThis->prev; ++ else ++ lastChild = removeThis->prev; ++ ++ if ( removeThis->prev ) ++ removeThis->prev->next = removeThis->next; ++ else ++ firstChild = removeThis->next; ++ ++ delete removeThis; ++ return true; ++} ++ ++TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = firstChild; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING( _value )) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::LastChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = lastChild; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild(); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling(); ++ } ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild( val ); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling( val ); ++ } ++} ++ ++TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = next; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = prev; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++void TiXmlElement::RemoveAttribute( const char * name ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement* TiXmlNode::NextSiblingElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++ ++TiXmlDocument* TiXmlNode::GetDocument() const ++{ ++ const TiXmlNode* node; ++ ++ for( node = this; node; node = node->parent ) ++ { ++ if ( node->ToDocument() ) ++ return node->ToDocument(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement::TiXmlElement (const char * _value) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlElement::TiXmlElement( const std::string& _value ) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++#endif ++ ++ ++TiXmlElement::TiXmlElement( const TiXmlElement& copy) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlElement::operator=( const TiXmlElement& base ) ++{ ++ ClearThis(); ++ base.CopyTo( this ); ++} ++ ++ ++TiXmlElement::~TiXmlElement() ++{ ++ ClearThis(); ++} ++ ++ ++void TiXmlElement::ClearThis() ++{ ++ Clear(); ++ while( attributeSet.First() ) ++ { ++ TiXmlAttribute* node = attributeSet.First(); ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ ++ if ( node ) ++ return node->Value(); ++ ++ return 0; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, int* i ) const ++{ ++ const char * s = Attribute( name ); ++ if ( i ) ++ { ++ if ( s ) ++ *i = atoi( s ); ++ else ++ *i = 0; ++ } ++ return s; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, double* d ) const ++{ ++ const char * s = Attribute( name ); ++ if ( d ) ++ { ++ if ( s ) ++ *d = atof( s ); ++ else ++ *d = 0; ++ } ++ return s; ++} ++ ++ ++int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryIntValue( ival ); ++} ++ ++ ++int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryDoubleValue( dval ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, int val ) ++{ ++ char buf[64]; ++ sprintf( buf, "%d", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetDoubleAttribute( const char * name, double val ) ++{ ++ char buf[128]; ++ sprintf( buf, "%f", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, const char * _value ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ node->SetValue( _value ); ++ return; ++ } ++ ++ TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); ++ if ( attrib ) ++ { ++ attributeSet.Add( attrib ); ++ } ++ else ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++} ++ ++void TiXmlElement::Print( FILE* cfile, int depth ) const ++{ ++ int i; ++ for ( i=0; i<depth; i++ ) ++ { ++ fprintf( cfile, " " ); ++ } ++ ++ fprintf( cfile, "<%s", value.c_str() ); ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ fprintf( cfile, " " ); ++ attrib->Print( cfile, depth ); ++ } ++ ++ // There are 3 different formatting approaches: ++ // 1) An element without children is printed as a <foo /> node ++ // 2) An element with only a text child is printed as <foo> text </foo> ++ // 3) An element with children is printed on multiple lines. ++ TiXmlNode* node; ++ if ( !firstChild ) ++ { ++ fprintf( cfile, " />" ); ++ } ++ else if ( firstChild == lastChild && firstChild->ToText() ) ++ { ++ fprintf( cfile, ">" ); ++ firstChild->Print( cfile, depth + 1 ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++ else ++ { ++ fprintf( cfile, ">" ); ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ if ( !node->ToText() ) ++ { ++ fprintf( cfile, "\n" ); ++ } ++ node->Print( cfile, depth+1 ); ++ } ++ fprintf( cfile, "\n" ); ++ for( i=0; i<depth; ++i ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++} ++ ++void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value; ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ (*stream) << " "; ++ attrib->StreamOut( stream ); ++ } ++ ++ // If this node has children, give it a closing tag. Else ++ // make it an empty tag. ++ TiXmlNode* node; ++ if ( firstChild ) ++ { ++ (*stream) << ">"; ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ node->StreamOut( stream ); ++ } ++ (*stream) << "</" << value << ">"; ++ } ++ else ++ { ++ (*stream) << " />"; ++ } ++} ++ ++ ++void TiXmlElement::CopyTo( TiXmlElement* target ) const ++{ ++ // superclass: ++ TiXmlNode::CopyTo( target ); ++ ++ // Element class: ++ // Clone the attributes, then clone the children. ++ TiXmlAttribute* attribute = 0; ++ for( attribute = attributeSet.First(); ++ attribute; ++ attribute = attribute->Next() ) ++ { ++ target->SetAttribute( attribute->Name(), attribute->Value() ); ++ } ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlElement::Clone() const ++{ ++ TiXmlElement* clone = new TiXmlElement( Value() ); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ ClearError(); ++} ++ ++TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++#endif ++ ++ ++TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDocument::operator=( const TiXmlDocument& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && LoadFile( buf.buffer, encoding ) ) ++ return true; ++ ++ return false; ++} ++ ++ ++bool TiXmlDocument::SaveFile() const ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && SaveFile( buf.buffer ) ) ++ return true; ++ ++ return false; ++} ++ ++bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding ) ++{ ++ // Delete the existing data: ++ Clear(); ++ location.Clear(); ++ ++ // There was a really terrifying little bug here. The code: ++ // value = filename ++ // in the STL case, cause the assignment method of the std::string to ++ // be called. What is strange, is that the std::string had the same ++ // address as it's c_str() method, and so bad things happen. Looks ++ // like a bug in the Microsoft STL implementation. ++ // See STL_STRING_BUG above. ++ // Fixed with the StringToBuffer class. ++ value = filename; ++ ++ FILE* file = fopen( value.c_str (), "r" ); ++ ++ if ( file ) ++ { ++ // Get the file size, so we can pre-allocate the string. HUGE speed impact. ++ long length = 0; ++ fseek( file, 0, SEEK_END ); ++ length = ftell( file ); ++ fseek( file, 0, SEEK_SET ); ++ ++ // Strange case, but good to handle up front. ++ if ( length == 0 ) ++ { ++ fclose( file ); ++ return false; ++ } ++ ++ // If we have a file, assume it is all one big XML file, and read it in. ++ // The document parser may decide the document ends sooner than the entire file, however. ++ TIXML_STRING data; ++ data.reserve( length ); ++ ++ const int BUF_SIZE = 2048; ++ char buf[BUF_SIZE]; ++ ++ while( fgets( buf, BUF_SIZE, file ) ) ++ { ++ data += buf; ++ } ++ fclose( file ); ++ ++ Parse( data.c_str(), 0, encoding ); ++ ++ if ( Error() ) ++ return false; ++ else ++ return true; ++ } ++ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return false; ++} ++ ++bool TiXmlDocument::SaveFile( const char * filename ) const ++{ ++ // The old c stuff lives on... ++ FILE* fp = fopen( filename, "w" ); ++ if ( fp ) ++ { ++ Print( fp, 0 ); ++ fclose( fp ); ++ return true; ++ } ++ return false; ++} ++ ++ ++void TiXmlDocument::CopyTo( TiXmlDocument* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->error = error; ++ target->errorDesc = errorDesc.c_str (); ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlDocument::Clone() const ++{ ++ TiXmlDocument* clone = new TiXmlDocument(); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlDocument::Print( FILE* cfile, int depth ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->Print( cfile, depth ); ++ fprintf( cfile, "\n" ); ++ } ++} ++ ++void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->StreamOut( out ); ++ ++ // Special rule for streams: stop after the root element. ++ // The stream in code will only read one element, so don't ++ // write more than one. ++ if ( node->ToElement() ) ++ break; ++ } ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Next() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( next->value.empty() && next->name.empty() ) ++ return 0; ++ return next; ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Previous() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( prev->value.empty() && prev->name.empty() ) ++ return 0; ++ return prev; ++} ++ ++ ++void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING n, v; ++ ++ PutString( name, &n ); ++ PutString( value, &v ); ++ ++ if (value.find ('\"') == TIXML_STRING::npos) ++ fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); ++ else ++ fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); ++} ++ ++ ++void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ if (value.find( '\"' ) != TIXML_STRING::npos) ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "'"; ++ PutString( value, stream ); ++ (*stream) << "'"; ++ } ++ else ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "\""; ++ PutString( value, stream ); ++ (*stream) << "\""; ++ } ++} ++ ++int TiXmlAttribute::QueryIntValue( int* ival ) const ++{ ++ if ( sscanf( value.c_str(), "%d", ival ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++int TiXmlAttribute::QueryDoubleValue( double* dval ) const ++{ ++ if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++void TiXmlAttribute::SetIntValue( int _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%d", _value); ++ SetValue (buf); ++} ++ ++void TiXmlAttribute::SetDoubleValue( double _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%lf", _value); ++ SetValue (buf); ++} ++ ++const int TiXmlAttribute::IntValue() const ++{ ++ return atoi (value.c_str ()); ++} ++ ++const double TiXmlAttribute::DoubleValue() const ++{ ++ return atof (value.c_str ()); ++} ++ ++ ++TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::operator=( const TiXmlComment& base ) ++{ ++ Clear(); ++ base.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ { ++ fputs( " ", cfile ); ++ } ++ fprintf( cfile, "<!--%s-->", value.c_str() ); ++} ++ ++void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<!--"; ++ //PutString( value, stream ); ++ (*stream) << value; ++ (*stream) << "-->"; ++} ++ ++ ++void TiXmlComment::CopyTo( TiXmlComment* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlComment::Clone() const ++{ ++ TiXmlComment* clone = new TiXmlComment(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING buffer; ++ PutString( value, &buffer ); ++ fprintf( cfile, "%s", buffer.c_str() ); ++} ++ ++ ++void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ PutString( value, stream ); ++} ++ ++ ++void TiXmlText::CopyTo( TiXmlText* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlText::Clone() const ++{ ++ TiXmlText* clone = 0; ++ clone = new TiXmlText( "" ); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const char * _version, ++ const char * _encoding, ++ const char * _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++#endif ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ fprintf (cfile, "<?xml "); ++ ++ if ( !version.empty() ) ++ fprintf (cfile, "version=\"%s\" ", version.c_str ()); ++ if ( !encoding.empty() ) ++ fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); ++ if ( !standalone.empty() ) ++ fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); ++ fprintf (cfile, "?>"); ++} ++ ++void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<?xml "; ++ ++ if ( !version.empty() ) ++ { ++ (*stream) << "version=\""; ++ PutString( version, stream ); ++ (*stream) << "\" "; ++ } ++ if ( !encoding.empty() ) ++ { ++ (*stream) << "encoding=\""; ++ PutString( encoding, stream ); ++ (*stream ) << "\" "; ++ } ++ if ( !standalone.empty() ) ++ { ++ (*stream) << "standalone=\""; ++ PutString( standalone, stream ); ++ (*stream) << "\" "; ++ } ++ (*stream) << "?>"; ++} ++ ++ ++void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->version = version; ++ target->encoding = encoding; ++ target->standalone = standalone; ++} ++ ++ ++TiXmlNode* TiXmlDeclaration::Clone() const ++{ ++ TiXmlDeclaration* clone = new TiXmlDeclaration(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlUnknown::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "<%s>", value.c_str() ); ++} ++ ++ ++void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value << ">"; // Don't use entities here! It is unknown. ++} ++ ++ ++void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlUnknown::Clone() const ++{ ++ TiXmlUnknown* clone = new TiXmlUnknown(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlAttributeSet::TiXmlAttributeSet() ++{ ++ sentinel.next = &sentinel; ++ sentinel.prev = &sentinel; ++} ++ ++ ++TiXmlAttributeSet::~TiXmlAttributeSet() ++{ ++ assert( sentinel.next == &sentinel ); ++ assert( sentinel.prev == &sentinel ); ++} ++ ++ ++void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) ++{ ++ assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. ++ ++ addMe->next = &sentinel; ++ addMe->prev = sentinel.prev; ++ ++ sentinel.prev->next = addMe; ++ sentinel.prev = addMe; ++} ++ ++void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node == removeMe ) ++ { ++ node->prev->next = node->next; ++ node->next->prev = node->prev; ++ node->next = 0; ++ node->prev = 0; ++ return; ++ } ++ } ++ assert( 0 ); // we tried to remove a non-linked attribute. ++} ++ ++TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node->name == name ) ++ return node; ++ } ++ return 0; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base) ++{ ++ TIXML_STRING tag; ++ tag.reserve( 8 * 1000 ); ++ base.StreamIn( &in, &tag ); ++ ++ base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); ++ return in; ++} ++#endif ++ ++ ++TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base) ++{ ++ base.StreamOut (& out); ++ return out; ++} ++ ++ ++#ifdef TIXML_USE_STL ++std::string & operator<< (std::string& out, const TiXmlNode& base ) ++{ ++ std::ostringstream os_stream( std::ostringstream::out ); ++ base.StreamOut( &os_stream ); ++ ++ out.append( os_stream.str() ); ++ return out; ++} ++#endif ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild() const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement() const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/tinyxmlerror.c vdr-1.6.0-2-extensions/tinyxmlerror.c +--- vdr-1.6.0-2/tinyxmlerror.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/tinyxmlerror.c 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,53 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++// The goal of the seperate error file is to make the first ++// step towards localization. tinyxml (currently) only supports ++// latin-1, but at least the error messages could now be translated. ++// ++// It also cleans up the code a bit. ++// ++ ++const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = ++{ ++ "No error", ++ "Error", ++ "Failed to open file", ++ "Memory allocation failed.", ++ "Error parsing Element.", ++ "Failed to read Element name", ++ "Error reading Element value.", ++ "Error reading Attributes.", ++ "Error: empty tag.", ++ "Error reading end tag.", ++ "Error parsing Unknown.", ++ "Error parsing Comment.", ++ "Error parsing Declaration.", ++ "Error document empty.", ++ "Error null (0) or unexpected EOF found in input stream.", ++}; ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/tinyxml.h vdr-1.6.0-2-extensions/tinyxml.h +--- vdr-1.6.0-2/tinyxml.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/tinyxml.h 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,1372 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++ ++#ifndef TINYXML_INCLUDED ++#define TINYXML_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4530 ) ++#pragma warning( disable : 4786 ) ++#endif ++ ++#include <ctype.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <assert.h> ++ ++// Help out windows: ++#if defined( _DEBUG ) && !defined( DEBUG ) ++#define DEBUG ++#endif ++ ++#if defined( DEBUG ) && defined( _MSC_VER ) ++#include <windows.h> ++#define TIXML_LOG OutputDebugString ++#else ++#define TIXML_LOG printf ++#endif ++ ++#ifdef TIXML_USE_STL ++ #include <string> ++ #include <iostream> ++ #define TIXML_STRING std::string ++ #define TIXML_ISTREAM std::istream ++ #define TIXML_OSTREAM std::ostream ++#else ++ #include "tinystr.h" ++ #define TIXML_STRING TiXmlString ++ #define TIXML_OSTREAM TiXmlOutStream ++#endif ++ ++class TiXmlDocument; ++class TiXmlElement; ++class TiXmlComment; ++class TiXmlUnknown; ++class TiXmlAttribute; ++class TiXmlText; ++class TiXmlDeclaration; ++class TiXmlParsingData; ++ ++const int TIXML_MAJOR_VERSION = 2; ++const int TIXML_MINOR_VERSION = 3; ++const int TIXML_PATCH_VERSION = 2; ++ ++/* Internal structure for tracking location of items ++ in the XML file. ++*/ ++struct TiXmlCursor ++{ ++ TiXmlCursor() { Clear(); } ++ void Clear() { row = col = -1; } ++ ++ int row; // 0 based. ++ int col; // 0 based. ++}; ++ ++ ++// Only used by Attribute::Query functions ++enum ++{ ++ TIXML_SUCCESS, ++ TIXML_NO_ATTRIBUTE, ++ TIXML_WRONG_TYPE ++}; ++ ++ ++// Used by the parsing routines. ++enum TiXmlEncoding ++{ ++ TIXML_ENCODING_UNKNOWN, ++ TIXML_ENCODING_UTF8, ++ TIXML_ENCODING_LEGACY ++}; ++ ++const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; ++ ++/** TiXmlBase is a base class for every class in TinyXml. ++ It does little except to establish that TinyXml classes ++ can be printed and provide some utility functions. ++ ++ In XML, the document and elements can contain ++ other elements and other types of nodes. ++ ++ @verbatim ++ A Document can contain: Element (container or leaf) ++ Comment (leaf) ++ Unknown (leaf) ++ Declaration( leaf ) ++ ++ An Element can contain: Element (container or leaf) ++ Text (leaf) ++ Attributes (not on tree) ++ Comment (leaf) ++ Unknown (leaf) ++ ++ A Decleration contains: Attributes (not on tree) ++ @endverbatim ++*/ ++class TiXmlBase ++{ ++ friend class TiXmlNode; ++ friend class TiXmlElement; ++ friend class TiXmlDocument; ++ ++public: ++ TiXmlBase() : userData(0) {} ++ virtual ~TiXmlBase() {} ++ ++ /** All TinyXml classes can print themselves to a filestream. ++ This is a formatted print, and will insert tabs and newlines. ++ ++ (For an unformatted stream, use the << operator.) ++ */ ++ virtual void Print( FILE* cfile, int depth ) const = 0; ++ ++ /** The world does not agree on whether white space should be kept or ++ not. In order to make everyone happy, these global, static functions ++ are provided to set whether or not TinyXml will condense all white space ++ into a single space or not. The default is to condense. Note changing this ++ values is not thread safe. ++ */ ++ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } ++ ++ /// Return the current white space setting. ++ static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } ++ ++ /** Return the position, in the original source file, of this node or attribute. ++ The row and column are 1-based. (That is the first row and first column is ++ 1,1). If the returns values are 0 or less, then the parser does not have ++ a row and column value. ++ ++ Generally, the row and column value will be set when the TiXmlDocument::Load(), ++ TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set ++ when the DOM was created from operator>>. ++ ++ The values reflect the initial load. Once the DOM is modified programmatically ++ (by adding or changing nodes and attributes) the new values will NOT update to ++ reflect changes in the document. ++ ++ There is a minor performance cost to computing the row and column. Computation ++ can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. ++ ++ @sa TiXmlDocument::SetTabSize() ++ */ ++ int Row() const { return location.row + 1; } ++ int Column() const { return location.col + 1; } ///< See Row() ++ ++ void SetUserData( void* user ) { userData = user; } ++ void* GetUserData() { return userData; } ++ ++ // Table that returs, for a given lead byte, the total number of bytes ++ // in the UTF-8 sequence. ++ static const int utf8ByteTable[256]; ++ ++ virtual const char* Parse( const char* p, ++ TiXmlParsingData* data, ++ TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; ++ ++protected: ++ ++ // See STL_STRING_BUG ++ // Utility class to overcome a bug. ++ class StringToBuffer ++ { ++ public: ++ StringToBuffer( const TIXML_STRING& str ); ++ ~StringToBuffer(); ++ char* buffer; ++ }; ++ ++ static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); ++ inline static bool IsWhiteSpace( char c ) ++ { ++ return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); ++ } ++ ++ virtual void StreamOut (TIXML_OSTREAM *) const = 0; ++ ++ #ifdef TIXML_USE_STL ++ static bool StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ static bool StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ); ++ #endif ++ ++ /* Reads an XML name into the string provided. Returns ++ a pointer just past the last character of the name, ++ or 0 if the function has an error. ++ */ ++ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); ++ ++ /* Reads text. Returns a pointer past the given end tag. ++ Wickedly complex options, but it keeps the (sensitive) code in one place. ++ */ ++ static const char* ReadText( const char* in, // where to start ++ TIXML_STRING* text, // the string read ++ bool ignoreWhiteSpace, // whether to keep the white space ++ const char* endTag, // what ends this text ++ bool ignoreCase, // whether to ignore case in the end tag ++ TiXmlEncoding encoding ); // the current encoding ++ ++ // If an entity has been found, transform it into a character. ++ static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); ++ ++ // Get a character, while interpreting entities. ++ // The length can be from 0 to 4 bytes. ++ inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) ++ { ++ assert( p ); ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ *length = utf8ByteTable[ *((unsigned char*)p) ]; ++ assert( *length >= 0 && *length < 5 ); ++ } ++ else ++ { ++ *length = 1; ++ } ++ ++ if ( *length == 1 ) ++ { ++ if ( *p == '&' ) ++ return GetEntity( p, _value, length, encoding ); ++ *_value = *p; ++ return p+1; ++ } ++ else if ( *length ) ++ { ++ strncpy( _value, p, *length ); ++ return p + (*length); ++ } ++ else ++ { ++ // Not valid text. ++ return 0; ++ } ++ } ++ ++ // Puts a string to a stream, expanding entities as it goes. ++ // Note this should not contian the '<', '>', etc, or they will be transformed into entities! ++ static void PutString( const TIXML_STRING& str, TIXML_OSTREAM* out ); ++ ++ static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); ++ ++ // Return true if the next characters in the stream are any of the endTag sequences. ++ // Ignore case only works for english, and should only be relied on when comparing ++ // to Engilish words: StringEqual( p, "version", true ) is fine. ++ static bool StringEqual( const char* p, ++ const char* endTag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ); ++ ++ ++ enum ++ { ++ TIXML_NO_ERROR = 0, ++ TIXML_ERROR, ++ TIXML_ERROR_OPENING_FILE, ++ TIXML_ERROR_OUT_OF_MEMORY, ++ TIXML_ERROR_PARSING_ELEMENT, ++ TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, ++ TIXML_ERROR_READING_ELEMENT_VALUE, ++ TIXML_ERROR_READING_ATTRIBUTES, ++ TIXML_ERROR_PARSING_EMPTY, ++ TIXML_ERROR_READING_END_TAG, ++ TIXML_ERROR_PARSING_UNKNOWN, ++ TIXML_ERROR_PARSING_COMMENT, ++ TIXML_ERROR_PARSING_DECLARATION, ++ TIXML_ERROR_DOCUMENT_EMPTY, ++ TIXML_ERROR_EMBEDDED_NULL, ++ ++ TIXML_ERROR_STRING_COUNT ++ }; ++ static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; ++ ++ TiXmlCursor location; ++ ++ /// Field containing a generic user pointer ++ void* userData; ++ ++ // None of these methods are reliable for any language except English. ++ // Good for approximation, not great for accuracy. ++ static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); ++ static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); ++ inline static int ToLower( int v, TiXmlEncoding encoding ) ++ { ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( v < 128 ) return tolower( v ); ++ return v; ++ } ++ else ++ { ++ return tolower( v ); ++ } ++ } ++ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); ++ ++private: ++ TiXmlBase( const TiXmlBase& ); // not implemented. ++ void operator=( const TiXmlBase& base ); // not allowed. ++ ++ struct Entity ++ { ++ const char* str; ++ unsigned int strLength; ++ char chr; ++ }; ++ enum ++ { ++ NUM_ENTITY = 5, ++ MAX_ENTITY_LENGTH = 6 ++ ++ }; ++ static Entity entity[ NUM_ENTITY ]; ++ static bool condenseWhiteSpace; ++}; ++ ++ ++/** The parent class for everything in the Document Object Model. ++ (Except for attributes). ++ Nodes have siblings, a parent, and children. A node can be ++ in a document, or stand on its own. The type of a TiXmlNode ++ can be queried, and it can be cast to its more defined type. ++*/ ++class TiXmlNode : public TiXmlBase ++{ ++ friend class TiXmlDocument; ++ friend class TiXmlElement; ++ ++public: ++ #ifdef TIXML_USE_STL ++ ++ /** An input stream operator, for every class. Tolerant of newlines and ++ formatting, but doesn't expect them. ++ */ ++ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); ++ ++ /** An output stream operator, for every class. Note that this outputs ++ without any newlines or formatting, as opposed to Print(), which ++ includes tabs and new lines. ++ ++ The operator<< and operator>> are not completely symmetric. Writing ++ a node to a stream is very well defined. You'll get a nice stream ++ of output, without any extra whitespace or newlines. ++ ++ But reading is not as well defined. (As it always is.) If you create ++ a TiXmlElement (for example) and read that from an input stream, ++ the text needs to define an element or junk will result. This is ++ true of all input streams, but it's worth keeping in mind. ++ ++ A TiXmlDocument will read nodes until it reads a root element, and ++ all the children of that root element. ++ */ ++ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); ++ ++ /// Appends the XML node or attribute to a std::string. ++ friend std::string& operator<< (std::string& out, const TiXmlNode& base ); ++ ++ #else ++ // Used internally, not part of the public API. ++ friend TIXML_OSTREAM& operator<< (TIXML_OSTREAM& out, const TiXmlNode& base); ++ #endif ++ ++ /** The types of XML nodes supported by TinyXml. (All the ++ unsupported types are picked up by UNKNOWN.) ++ */ ++ enum NodeType ++ { ++ DOCUMENT, ++ ELEMENT, ++ COMMENT, ++ UNKNOWN, ++ TEXT, ++ DECLARATION, ++ TYPECOUNT ++ }; ++ ++ virtual ~TiXmlNode(); ++ ++ /** The meaning of 'value' changes for the specific type of ++ TiXmlNode. ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ ++ The subclasses will wrap this function. ++ */ ++ const char * Value() const { return value.c_str (); } ++ ++ /** Changes the value of the node. Defined as: ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ */ ++ void SetValue(const char * _value) { value = _value;} ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "" ); ++ } ++ #endif ++ ++ /// Delete all the children of this node. Does not affect 'this'. ++ void Clear(); ++ ++ /// One step up the DOM. ++ TiXmlNode* Parent() const { return parent; } ++ ++ TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. ++ TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. ++ ++ TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. ++ TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** An alternate way to walk the children of a node. ++ One way to iterate over nodes is: ++ @verbatim ++ for( child = parent->FirstChild(); child; child = child->NextSibling() ) ++ @endverbatim ++ ++ IterateChildren does the same thing with the syntax: ++ @verbatim ++ child = 0; ++ while( child = parent->IterateChildren( child ) ) ++ @endverbatim ++ ++ IterateChildren takes the previous child as input and finds ++ the next one. If the previous child is null, it returns the ++ first. IterateChildren will return null when done. ++ */ ++ TiXmlNode* IterateChildren( TiXmlNode* previous ) const; ++ ++ /// This flavor of IterateChildren searches for children with a particular 'value' ++ TiXmlNode* IterateChildren( const char * value, TiXmlNode* previous ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* IterateChildren( const std::string& _value, TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. ++ #endif ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); ++ ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ ++ NOTE: the node to be added is passed by pointer, and will be ++ henceforth owned (and deleted) by tinyXml. This method is efficient ++ and avoids an extra copy, but should be used with care as it ++ uses a different memory model than the other insert functions. ++ ++ @sa InsertEndChild ++ */ ++ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); ++ ++ /** Add a new node related to this. Adds a child before the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); ++ ++ /** Add a new node related to this. Adds a child after the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); ++ ++ /** Replace a child of this node. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); ++ ++ /// Delete a child of this node. ++ bool RemoveChild( TiXmlNode* removeThis ); ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling() const { return prev; } ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* NextSibling() const { return next; } ++ ++ /// Navigate to a sibling node with the given 'value'. ++ TiXmlNode* NextSibling( const char * ) const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement() const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement() const; ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement( const char * value ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** Query the type (as an enumerated value, above) of this node. ++ The possible types are: DOCUMENT, ELEMENT, COMMENT, ++ UNKNOWN, TEXT, and DECLARATION. ++ */ ++ virtual int Type() const { return type; } ++ ++ /** Return a pointer to the Document this node lives in. ++ Returns null if not in a document. ++ */ ++ TiXmlDocument* GetDocument() const; ++ ++ /// Returns true if this node has no children. ++ bool NoChildren() const { return !firstChild; } ++ ++ TiXmlDocument* ToDocument() const { return ( this && type == DOCUMENT ) ? (TiXmlDocument*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlElement* ToElement() const { return ( this && type == ELEMENT ) ? (TiXmlElement*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlComment* ToComment() const { return ( this && type == COMMENT ) ? (TiXmlComment*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlUnknown* ToUnknown() const { return ( this && type == UNKNOWN ) ? (TiXmlUnknown*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlText* ToText() const { return ( this && type == TEXT ) ? (TiXmlText*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlDeclaration* ToDeclaration() const { return ( this && type == DECLARATION ) ? (TiXmlDeclaration*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ ++ /** Create an exact duplicate of this node and return it. The memory must be deleted ++ by the caller. ++ */ ++ virtual TiXmlNode* Clone() const = 0; ++ ++protected: ++ TiXmlNode( NodeType _type ); ++ ++ // Copy to the allocated object. Shared functionality between Clone, Copy constructor, ++ // and the assignment operator. ++ void CopyTo( TiXmlNode* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ // The real work of the input operator. ++ virtual void StreamIn( TIXML_ISTREAM* in, TIXML_STRING* tag ) = 0; ++ #endif ++ ++ // Figure out what is at *p, and parse it. Returns null if it is not an xml node. ++ TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); ++ ++ // Internal Value function returning a TIXML_STRING ++ const TIXML_STRING& SValue() const { return value ; } ++ ++ TiXmlNode* parent; ++ NodeType type; ++ ++ TiXmlNode* firstChild; ++ TiXmlNode* lastChild; ++ ++ TIXML_STRING value; ++ ++ TiXmlNode* prev; ++ TiXmlNode* next; ++ ++private: ++ TiXmlNode( const TiXmlNode& ); // not implemented. ++ void operator=( const TiXmlNode& base ); // not allowed. ++}; ++ ++ ++/** An attribute is a name-value pair. Elements have an arbitrary ++ number of attributes, each with a unique name. ++ ++ @note The attributes are not TiXmlNodes, since they are not ++ part of the tinyXML document object model. There are other ++ suggested ways to look at this problem. ++*/ ++class TiXmlAttribute : public TiXmlBase ++{ ++ friend class TiXmlAttributeSet; ++ ++public: ++ /// Construct an empty attribute. ++ TiXmlAttribute() : TiXmlBase() ++ { ++ document = 0; ++ prev = next = 0; ++ } ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlAttribute( const std::string& _name, const std::string& _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ #endif ++ ++ /// Construct an attribute with a name and value. ++ TiXmlAttribute( const char * _name, const char * _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ ++ const char* Name() const { return name.c_str (); } ///< Return the name of this attribute. ++ const char* Value() const { return value.c_str (); } ///< Return the value of this attribute. ++ const int IntValue() const; ///< Return the value of this attribute, converted to an integer. ++ const double DoubleValue() const; ///< Return the value of this attribute, converted to a double. ++ ++ /** QueryIntValue examines the value string. It is an alternative to the ++ IntValue() method with richer error checking. ++ If the value is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. ++ ++ A specialized but useful call. Note that for success it returns 0, ++ which is the opposite of almost all other TinyXml calls. ++ */ ++ int QueryIntValue( int* value ) const; ++ /// QueryDoubleValue examines the value string. See QueryIntValue(). ++ int QueryDoubleValue( double* value ) const; ++ ++ void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. ++ void SetValue( const char* _value ) { value = _value; } ///< Set the value. ++ ++ void SetIntValue( int value ); ///< Set the value from an integer. ++ void SetDoubleValue( double value ); ///< Set the value from a double. ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetName( const std::string& _name ) ++ { ++ StringToBuffer buf( _name ); ++ SetName ( buf.buffer ? buf.buffer : "error" ); ++ } ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "error" ); ++ } ++ #endif ++ ++ /// Get the next sibling attribute in the DOM. Returns null at end. ++ TiXmlAttribute* Next() const; ++ /// Get the previous sibling attribute in the DOM. Returns null at beginning. ++ TiXmlAttribute* Previous() const; ++ ++ bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } ++ bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } ++ bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } ++ ++ /* Attribute parsing starts: first letter of the name ++ returns: the next char after the value end quote ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++ // Prints this Attribute to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ // [internal use] ++ // Set the document pointer so the attribute can report errors. ++ void SetDocument( TiXmlDocument* doc ) { document = doc; } ++ ++private: ++ TiXmlAttribute( const TiXmlAttribute& ); // not implemented. ++ void operator=( const TiXmlAttribute& base ); // not allowed. ++ ++ TiXmlDocument* document; // A pointer back to a document, for error reporting. ++ TIXML_STRING name; ++ TIXML_STRING value; ++ TiXmlAttribute* prev; ++ TiXmlAttribute* next; ++}; ++ ++ ++/* A class used to manage a group of attributes. ++ It is only used internally, both by the ELEMENT and the DECLARATION. ++ ++ The set can be changed transparent to the Element and Declaration ++ classes that use it, but NOT transparent to the Attribute ++ which has to implement a next() and previous() method. Which makes ++ it a bit problematic and prevents the use of STL. ++ ++ This version is implemented with circular lists because: ++ - I like circular lists ++ - it demonstrates some independence from the (typical) doubly linked list. ++*/ ++class TiXmlAttributeSet ++{ ++public: ++ TiXmlAttributeSet(); ++ ~TiXmlAttributeSet(); ++ ++ void Add( TiXmlAttribute* attribute ); ++ void Remove( TiXmlAttribute* attribute ); ++ ++ TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } ++ TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } ++ TiXmlAttribute* Find( const char * name ) const; ++ ++private: ++ TiXmlAttribute sentinel; ++}; ++ ++ ++/** The element is a container class. It has a value, the element name, ++ and can contain other elements, text, comments, and unknowns. ++ Elements also contain an arbitrary number of attributes. ++*/ ++class TiXmlElement : public TiXmlNode ++{ ++public: ++ /// Construct an element. ++ TiXmlElement (const char * in_value); ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlElement( const std::string& _value ); ++ #endif ++ ++ TiXmlElement( const TiXmlElement& ); ++ ++ void operator=( const TiXmlElement& base ); ++ ++ virtual ~TiXmlElement(); ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ */ ++ const char* Attribute( const char* name ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an integer, ++ the integer value will be put in the return 'i', if 'i' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, int* i ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an double, ++ the double value will be put in the return 'd', if 'd' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, double* d ) const; ++ ++ /** QueryIntAttribute examines the attribute - it is an alternative to the ++ Attribute() method with richer error checking. ++ If the attribute is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. If the attribute ++ does not exist, then TIXML_NO_ATTRIBUTE is returned. ++ */ ++ int QueryIntAttribute( const char* name, int* value ) const; ++ /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). ++ int QueryDoubleAttribute( const char* name, double* value ) const; ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char* name, const char * value ); ++ ++ #ifdef TIXML_USE_STL ++ const char* Attribute( const std::string& name ) const { return Attribute( name.c_str() ); } ++ const char* Attribute( const std::string& name, int* i ) const { return Attribute( name.c_str(), i ); } ++ const char* Attribute( const std::string& name, double* d ) const { return Attribute( name.c_str(), d ); } ++ int QueryIntAttribute( const std::string& name, int* value ) const { return QueryIntAttribute( name.c_str(), value ); } ++ int QueryDoubleAttribute( const std::string& name, double* value ) const { return QueryDoubleAttribute( name.c_str(), value ); } ++ ++ /// STL std::string form. ++ void SetAttribute( const std::string& name, const std::string& _value ) ++ { ++ StringToBuffer n( name ); ++ StringToBuffer v( _value ); ++ if ( n.buffer && v.buffer ) ++ SetAttribute (n.buffer, v.buffer ); ++ } ++ ///< STL std::string form. ++ void SetAttribute( const std::string& name, int _value ) ++ { ++ StringToBuffer n( name ); ++ if ( n.buffer ) ++ SetAttribute (n.buffer, _value); ++ } ++ #endif ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char * name, int value ); ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetDoubleAttribute( const char * name, double value ); ++ ++ /** Deletes an attribute with the given name. ++ */ ++ void RemoveAttribute( const char * name ); ++ #ifdef TIXML_USE_STL ++ void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. ++ TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. ++ ++ /// Creates a new Element and returns it - the returned element is a copy. ++ virtual TiXmlNode* Clone() const; ++ // Print the Element to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: next char past '<' ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ ++ void CopyTo( TiXmlElement* target ) const; ++ void ClearThis(); // like clear, but initializes 'this' object as well ++ ++ // Used to be public [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++ /* [internal use] ++ Reads the "value" of the element -- another element, or text. ++ This should terminate with the current end tag. ++ */ ++ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++private: ++ ++ TiXmlAttributeSet attributeSet; ++}; ++ ++ ++/** An XML comment. ++*/ ++class TiXmlComment : public TiXmlNode ++{ ++public: ++ /// Constructs an empty comment. ++ TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} ++ TiXmlComment( const TiXmlComment& ); ++ void operator=( const TiXmlComment& base ); ++ ++ virtual ~TiXmlComment() {} ++ ++ /// Returns a copy of this Comment. ++ virtual TiXmlNode* Clone() const; ++ /// Write this Comment to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: at the ! of the !-- ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlComment* target ) const; ++ ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** XML text. Contained in an element. ++*/ ++class TiXmlText : public TiXmlNode ++{ ++ friend class TiXmlElement; ++public: ++ /// Constructor. ++ TiXmlText (const char * initValue) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ virtual ~TiXmlText() {} ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ #endif ++ ++ TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlText& base ) { base.CopyTo( this ); } ++ ++ /// Write this text object to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected : ++ /// [internal use] Creates a new Element and returns it. ++ virtual TiXmlNode* Clone() const; ++ void CopyTo( TiXmlText* target ) const; ++ ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ bool Blank() const; // returns true if all white space and new lines ++ // [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++}; ++ ++ ++/** In correct XML the declaration is the first entry in the file. ++ @verbatim ++ <?xml version="1.0" standalone="yes"?> ++ @endverbatim ++ ++ TinyXml will happily read or write files without a declaration, ++ however. There are 3 possible attributes to the declaration: ++ version, encoding, and standalone. ++ ++ Note: In this version of the code, the attributes are ++ handled as special cases, not generic attributes, simply ++ because there can only be at most 3 and they are always the same. ++*/ ++class TiXmlDeclaration : public TiXmlNode ++{ ++public: ++ /// Construct an empty declaration. ++ TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} ++ ++#ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ); ++#endif ++ ++ /// Construct. ++ TiXmlDeclaration( const char* _version, ++ const char* _encoding, ++ const char* _standalone ); ++ ++ TiXmlDeclaration( const TiXmlDeclaration& copy ); ++ void operator=( const TiXmlDeclaration& copy ); ++ ++ virtual ~TiXmlDeclaration() {} ++ ++ /// Version. Will return an empty string if none was found. ++ const char *Version() const { return version.c_str (); } ++ /// Encoding. Will return an empty string if none was found. ++ const char *Encoding() const { return encoding.c_str (); } ++ /// Is this a standalone document? ++ const char *Standalone() const { return standalone.c_str (); } ++ ++ /// Creates a copy of this Declaration and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this declaration to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlDeclaration* target ) const; ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ ++private: ++ ++ TIXML_STRING version; ++ TIXML_STRING encoding; ++ TIXML_STRING standalone; ++}; ++ ++ ++/** Any tag that tinyXml doesn't recognize is saved as an ++ unknown. It is a tag of text, but should not be modified. ++ It will be written back to the XML, unchanged, when the file ++ is saved. ++ ++ DTD tags get thrown into TiXmlUnknowns. ++*/ ++class TiXmlUnknown : public TiXmlNode ++{ ++public: ++ TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} ++ virtual ~TiXmlUnknown() {} ++ ++ TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } ++ ++ /// Creates a copy of this Unknown and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this Unknown to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlUnknown* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** Always the top level node. A document binds together all the ++ XML pieces. It can be saved, loaded, and printed to the screen. ++ The 'value' of a document node is the xml file name. ++*/ ++class TiXmlDocument : public TiXmlNode ++{ ++public: ++ /// Create an empty document, that has no name. ++ TiXmlDocument(); ++ /// Create a document with a name. The name of the document is also the filename of the xml. ++ TiXmlDocument( const char * documentName ); ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDocument( const std::string& documentName ); ++ #endif ++ ++ TiXmlDocument( const TiXmlDocument& copy ); ++ void operator=( const TiXmlDocument& copy ); ++ ++ virtual ~TiXmlDocument() {} ++ ++ /** Load a file using the current document value. ++ Returns true if successful. Will delete any existing ++ document data before loading. ++ */ ++ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the current document value. Returns true if successful. ++ bool SaveFile() const; ++ /// Load a file using the given filename. Returns true if successful. ++ bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the given filename. Returns true if successful. ++ bool SaveFile( const char * filename ) const; ++ ++ #ifdef TIXML_USE_STL ++ bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && LoadFile( f.buffer, encoding )); ++ } ++ bool SaveFile( const std::string& filename ) const ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && SaveFile( f.buffer )); ++ } ++ #endif ++ ++ /** Parse the given null terminated block of xml data. Passing in an encoding to this ++ method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml ++ to use that encoding, regardless of what TinyXml might otherwise try to detect. ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ ++ /** Get the root element -- the only top level element -- of the document. ++ In well formed XML, there should only be one. TinyXml is tolerant of ++ multiple elements at the document level. ++ */ ++ TiXmlElement* RootElement() const { return FirstChildElement(); } ++ ++ /** If an error occurs, Error will be set to true. Also, ++ - The ErrorId() will contain the integer identifier of the error (not generally useful) ++ - The ErrorDesc() method will return the name of the error. (very useful) ++ - The ErrorRow() and ErrorCol() will return the location of the error (if known) ++ */ ++ bool Error() const { return error; } ++ ++ /// Contains a textual (english) description of the error if one occurs. ++ const char * ErrorDesc() const { return errorDesc.c_str (); } ++ ++ /** Generally, you probably want the error string ( ErrorDesc() ). But if you ++ prefer the ErrorId, this function will fetch it. ++ */ ++ const int ErrorId() const { return errorId; } ++ ++ /** Returns the location (if known) of the error. The first column is column 1, ++ and the first row is row 1. A value of 0 means the row and column wasn't applicable ++ (memory errors, for example, have no row/column) or the parser lost the error. (An ++ error in the error reporting, in that case.) ++ ++ @sa SetTabSize, Row, Column ++ */ ++ int ErrorRow() { return errorLocation.row+1; } ++ int ErrorCol() { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() ++ ++ /** By calling this method, with a tab size ++ greater than 0, the row and column of each node and attribute is stored ++ when the file is loaded. Very useful for tracking the DOM back in to ++ the source file. ++ ++ The tab size is required for calculating the location of nodes. If not ++ set, the default of 4 is used. The tabsize is set per document. Setting ++ the tabsize to 0 disables row/column tracking. ++ ++ Note that row and column tracking is not supported when using operator>>. ++ ++ The tab size needs to be enabled before the parse or load. Correct usage: ++ @verbatim ++ TiXmlDocument doc; ++ doc.SetTabSize( 8 ); ++ doc.Load( "myfile.xml" ); ++ @endverbatim ++ ++ @sa Row, Column ++ */ ++ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } ++ ++ int TabSize() const { return tabsize; } ++ ++ /** If you have handled the error, it can be reset with this call. The error ++ state is automatically cleared if you Parse a new XML block. ++ */ ++ void ClearError() { error = false; ++ errorId = 0; ++ errorDesc = ""; ++ errorLocation.row = errorLocation.col = 0; ++ //errorLocation.last = 0; ++ } ++ ++ /** Dump the document to standard out. */ ++ void Print() const { Print( stdout, 0 ); } ++ ++ /// Print this Document to a FILE stream. ++ virtual void Print( FILE* cfile, int depth = 0 ) const; ++ // [internal use] ++ void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++protected : ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ // [internal use] ++ virtual TiXmlNode* Clone() const; ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++ void CopyTo( TiXmlDocument* target ) const; ++ ++ bool error; ++ int errorId; ++ TIXML_STRING errorDesc; ++ int tabsize; ++ TiXmlCursor errorLocation; ++}; ++ ++ ++/** ++ A TiXmlHandle is a class that wraps a node pointer with null checks; this is ++ an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml ++ DOM structure. It is a separate utility class. ++ ++ Take an example: ++ @verbatim ++ <Document> ++ <Element attributeA = "valueA"> ++ <Child attributeB = "value1" /> ++ <Child attributeB = "value2" /> ++ </Element> ++ <Document> ++ @endverbatim ++ ++ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very ++ easy to write a *lot* of code that looks like: ++ ++ @verbatim ++ TiXmlElement* root = document.FirstChildElement( "Document" ); ++ if ( root ) ++ { ++ TiXmlElement* element = root->FirstChildElement( "Element" ); ++ if ( element ) ++ { ++ TiXmlElement* child = element->FirstChildElement( "Child" ); ++ if ( child ) ++ { ++ TiXmlElement* child2 = child->NextSiblingElement( "Child" ); ++ if ( child2 ) ++ { ++ // Finally do something useful. ++ @endverbatim ++ ++ And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity ++ of such code. A TiXmlHandle checks for null pointers so it is perfectly safe ++ and correct to use: ++ ++ @verbatim ++ TiXmlHandle docHandle( &document ); ++ TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).Element(); ++ if ( child2 ) ++ { ++ // do something useful ++ @endverbatim ++ ++ Which is MUCH more concise and useful. ++ ++ It is also safe to copy handles - internally they are nothing more than node pointers. ++ @verbatim ++ TiXmlHandle handleCopy = handle; ++ @endverbatim ++ ++ What they should not be used for is iteration: ++ ++ @verbatim ++ int i=0; ++ while ( true ) ++ { ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).Element(); ++ if ( !child ) ++ break; ++ // do something ++ ++i; ++ } ++ @endverbatim ++ ++ It seems reasonable, but it is in fact two embedded while loops. The Child method is ++ a linear walk to find the element, so this code would iterate much more than it needs ++ to. Instead, prefer: ++ ++ @verbatim ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).Element(); ++ ++ for( child; child; child=child->NextSiblingElement() ) ++ { ++ // do something ++ } ++ @endverbatim ++*/ ++class TiXmlHandle ++{ ++public: ++ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. ++ TiXmlHandle( TiXmlNode* node ) { this->node = node; } ++ /// Copy constructor ++ TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } ++ TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } ++ ++ /// Return a handle to the first child node. ++ TiXmlHandle FirstChild() const; ++ /// Return a handle to the first child node with the given name. ++ TiXmlHandle FirstChild( const char * value ) const; ++ /// Return a handle to the first child element. ++ TiXmlHandle FirstChildElement() const; ++ /// Return a handle to the first child element with the given name. ++ TiXmlHandle FirstChildElement( const char * value ) const; ++ ++ /** Return a handle to the "index" child with the given name. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( const char* value, int index ) const; ++ /** Return a handle to the "index" child. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( int index ) const; ++ /** Return a handle to the "index" child element with the given name. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( const char* value, int index ) const; ++ /** Return a handle to the "index" child element. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( int index ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } ++ TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } ++ ++ TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } ++ TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } ++ #endif ++ ++ /// Return the handle as a TiXmlNode. This may return null. ++ TiXmlNode* Node() const { return node; } ++ /// Return the handle as a TiXmlElement. This may return null. ++ TiXmlElement* Element() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } ++ /// Return the handle as a TiXmlText. This may return null. ++ TiXmlText* Text() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } ++ /// Return the handle as a TiXmlUnknown. This may return null; ++ TiXmlUnknown* Unknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } ++ ++private: ++ TiXmlNode* node; ++}; ++ ++ ++#endif ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/tinyxmlparser.c vdr-1.6.0-2-extensions/tinyxmlparser.c +--- vdr-1.6.0-2/tinyxmlparser.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/tinyxmlparser.c 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,1494 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++#include <ctype.h> ++ ++//#define DEBUG_PARSER ++ ++// Note tha "PutString" hardcodes the same list. This ++// is less flexible than it appears. Changing the entries ++// or order will break putstring. ++TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = ++{ ++ { "&", 5, '&' }, ++ { "<", 4, '<' }, ++ { ">", 4, '>' }, ++ { """, 6, '\"' }, ++ { "'", 6, '\'' } ++}; ++ ++// Bunch of unicode info at: ++// http://www.unicode.org/faq/utf_bom.html ++// Including the basic of this table, which determines the #bytes in the ++// sequence from the lead byte. 1 placed for invalid sequences -- ++// although the result will be junk, pass it through as much as possible. ++// Beware of the non-characters in UTF-8: ++// ef bb bf (Microsoft "lead bytes") ++// ef bf be ++// ef bf bf ++ ++ ++ ++const int TiXmlBase::utf8ByteTable[256] = ++{ ++ // 0 1 2 3 4 5 6 7 8 9 a b c d e f ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 ++ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte ++ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid ++}; ++ ++ ++void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) ++{ ++ const unsigned long BYTE_MASK = 0xBF; ++ const unsigned long BYTE_MARK = 0x80; ++ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; ++ ++ if (input < 0x80) ++ *length = 1; ++ else if ( input < 0x800 ) ++ *length = 2; ++ else if ( input < 0x10000 ) ++ *length = 3; ++ else if ( input < 0x200000 ) ++ *length = 4; ++ else ++ { *length = 0; return; } // This code won't covert this correctly anyway. ++ ++ output += *length; ++ ++ // Scary scary fall throughs. ++ switch (*length) ++ { ++ case 4: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 3: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 2: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 1: ++ --output; ++ *output = (char)(input | FIRST_BYTE_MARK[*length]); ++ } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalpha( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalpha( anyByte ); ++// } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalnum( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalnum( anyByte ); ++// } ++} ++ ++ ++class TiXmlParsingData ++{ ++ friend class TiXmlDocument; ++ public: ++ void Stamp( const char* now, TiXmlEncoding encoding ); ++ ++ const TiXmlCursor& Cursor() { return cursor; } ++ ++ private: ++ // Only used by the document! ++ TiXmlParsingData( const char* start, int _tabsize, int row, int col ) ++ { ++ assert( start ); ++ stamp = start; ++ tabsize = _tabsize; ++ cursor.row = row; ++ cursor.col = col; ++ } ++ ++ TiXmlCursor cursor; ++ const char* stamp; ++ int tabsize; ++}; ++ ++ ++void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) ++{ ++ assert( now ); ++ ++ // Do nothing if the tabsize is 0. ++ if ( tabsize < 1 ) ++ { ++ return; ++ } ++ ++ // Get the current row, column. ++ int row = cursor.row; ++ int col = cursor.col; ++ const char* p = stamp; ++ assert( p ); ++ ++ while ( p < now ) ++ { ++ // Code contributed by Fletcher Dunn: (modified by lee) ++ switch (*p) { ++ case 0: ++ // We *should* never get here, but in case we do, don't ++ // advance past the terminating null character, ever ++ return; ++ ++ case '\r': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ // Eat the character ++ ++p; ++ ++ // Check for \r\n sequence, and treat this as a single character ++ if (*p == '\n') { ++ ++p; ++ } ++ break; ++ ++ case '\n': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ ++ // Eat the character ++ ++p; ++ ++ // Check for \n\r sequence, and treat this as a single ++ // character. (Yes, this bizarre thing does occur still ++ // on some arcane platforms...) ++ if (*p == '\r') { ++ ++p; ++ } ++ break; ++ ++ case '\t': ++ // Eat the character ++ ++p; ++ ++ // Skip to next tab stop ++ col = (col / tabsize + 1) * tabsize; ++ break; ++ ++ case (char)(0xef): ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( *(p+1) && *(p+2) ) ++ { ++ // In these cases, don't advance the column. These are ++ // 0-width spaces. ++ if ( *(p+1)==(char)(0xbb) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbe) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else ++ { p +=3; ++col; } // A normal character. ++ } ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ ++ default: ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // Eat the 1 to 4 byte utf8 character. ++ int step = TiXmlBase::utf8ByteTable[*((unsigned char*)p)]; ++ if ( step == 0 ) ++ step = 1; // Error case from bad encoding, but handle gracefully. ++ p += step; ++ ++ // Just advance one column, of course. ++ ++col; ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ } ++ } ++ cursor.row = row; ++ cursor.col = col; ++ assert( cursor.row >= -1 ); ++ assert( cursor.col >= -1 ); ++ stamp = p; ++ assert( stamp ); ++} ++ ++ ++const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) ++{ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ while ( *p ) ++ { ++ // Skip the stupid Microsoft UTF-8 Byte order marks ++ if ( *(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbb ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbe ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ ++ if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. ++ ++p; ++ else ++ break; ++ } ++ } ++ else ++ { ++ while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) ++ ++p; ++ } ++ ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++/*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ for( ;; ) ++ { ++ if ( !in->good() ) return false; ++ ++ int c = in->peek(); ++ // At this scope, we can't get to a document. So fail silently. ++ if ( !IsWhiteSpace( c ) || c <= 0 ) ++ return true; ++ ++ *tag += (char) in->get(); ++ } ++} ++ ++/*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ) ++{ ++ //assert( character > 0 && character < 128 ); // else it won't work in utf-8 ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == character ) ++ return true; ++ if ( c <= 0 ) // Silent failure: can't get document at this scope ++ return false; ++ ++ in->get(); ++ *tag += (char) c; ++ } ++ return false; ++} ++#endif ++ ++const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) ++{ ++ *name = ""; ++ assert( p ); ++ ++ // Names start with letters or underscores. ++ // Of course, in unicode, tinyxml has no idea what a letter *is*. The ++ // algorithm is generous. ++ // ++ // After that, they can be letters, underscores, numbers, ++ // hyphens, or colons. (Colons are valid ony for namespaces, ++ // but tinyxml can't tell namespaces from names.) ++ if ( p && *p ++ && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) ++ { ++ while( p && *p ++ && ( IsAlphaNum( (unsigned char ) *p, encoding ) ++ || *p == '_' ++ || *p == '-' ++ || *p == '.' ++ || *p == ':' ) ) ++ { ++ (*name) += *p; ++ ++p; ++ } ++ return p; ++ } ++ return 0; ++} ++ ++const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) ++{ ++ // Presume an entity, and pull it out. ++ TIXML_STRING ent; ++ int i; ++ *length = 0; ++ ++ if ( *(p+1) && *(p+1) == '#' && *(p+2) ) ++ { ++ unsigned long ucs = 0; ++ unsigned delta = 0; ++ unsigned mult = 1; ++ ++ if ( *(p+2) == 'x' ) ++ { ++ // Hexadecimal. ++ if ( !*(p+3) ) return 0; ++ ++ const char* q = p+3; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != 'x' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else if ( *q >= 'a' && *q <= 'f' ) ++ ucs += mult * (*q - 'a' + 10); ++ else if ( *q >= 'A' && *q <= 'F' ) ++ ucs += mult * (*q - 'A' + 10 ); ++ else ++ return 0; ++ mult *= 16; ++ --q; ++ } ++ } ++ else ++ { ++ // Decimal. ++ if ( !*(p+2) ) return 0; ++ ++ const char* q = p+2; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != '#' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else ++ return 0; ++ mult *= 10; ++ --q; ++ } ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // convert the UCS to UTF-8 ++ ConvertUTF32ToUTF8( ucs, value, length ); ++ } ++ else ++ { ++ *value = (char)ucs; ++ *length = 1; ++ } ++ return p + delta + 1; ++ } ++ ++ // Now try to match it. ++ for( i=0; i<NUM_ENTITY; ++i ) ++ { ++ if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) ++ { ++ assert( strlen( entity[i].str ) == entity[i].strLength ); ++ *value = entity[i].chr; ++ *length = 1; ++ return ( p + entity[i].strLength ); ++ } ++ } ++ ++ // So it wasn't an entity, its unrecognized, or something like that. ++ *value = *p; // Don't put back the last one, since we return it! ++ return p+1; ++} ++ ++ ++bool TiXmlBase::StringEqual( const char* p, ++ const char* tag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ) ++{ ++ assert( p ); ++ assert( tag ); ++ if ( !p || !*p ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ const char* q = p; ++ ++ if ( ignoreCase ) ++ { ++ while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) ++ return true; ++ } ++ else ++ { ++ while ( *q && *tag && *q == *tag ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? ++ return true; ++ } ++ return false; ++} ++ ++const char* TiXmlBase::ReadText( const char* p, ++ TIXML_STRING * text, ++ bool trimWhiteSpace, ++ const char* endTag, ++ bool caseInsensitive, ++ TiXmlEncoding encoding ) ++{ ++ *text = ""; ++ if ( !trimWhiteSpace // certain tags always keep whitespace ++ || !condenseWhiteSpace ) // if true, whitespace is always kept ++ { ++ // Keep all the white space. ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ++ ) ++ { ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ text->append( cArr, len ); ++ } ++ } ++ else ++ { ++ bool whitespace = false; ++ ++ // Remove leading white space: ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ) ++ { ++ if ( *p == '\r' || *p == '\n' ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else if ( IsWhiteSpace( *p ) ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else ++ { ++ // If we've found whitespace, add it before the ++ // new character. Any whitespace just becomes a space. ++ if ( whitespace ) ++ { ++ (*text) += ' '; ++ whitespace = false; ++ } ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ if ( len == 1 ) ++ (*text) += cArr[0]; // more efficient ++ else ++ text->append( cArr, len ); ++ } ++ } ++ } ++ return p + strlen( endTag ); ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ // The basic issue with a document is that we don't know what we're ++ // streaming. Read something presumed to be a tag (and hope), then ++ // identify it, and call the appropriate stream method on the tag. ++ // ++ // This "pre-streaming" will never read the closing ">" so the ++ // sub-tag can orient itself. ++ ++ if ( !StreamTo( in, '<', tag ) ) ++ { ++ SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ while ( in->good() ) ++ { ++ int tagIndex = (int) tag->length(); ++ while ( in->good() && in->peek() != '>' ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ break; ++ } ++ (*tag) += (char) c; ++ } ++ ++ if ( in->good() ) ++ { ++ // We now have something we presume to be a node of ++ // some sort. Identify it, and call the node to ++ // continue streaming. ++ TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); ++ ++ if ( node ) ++ { ++ node->StreamIn( in, tag ); ++ bool isElement = node->ToElement() != 0; ++ delete node; ++ node = 0; ++ ++ // If this is the root element, we're done. Parsing will be ++ // done by the >> operator. ++ if ( isElement ) ++ { ++ return; ++ } ++ } ++ else ++ { ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ } ++ } ++ // We should have returned sooner. ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++} ++ ++#endif ++ ++const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) ++{ ++ ClearError(); ++ ++ // Parse away, at the document level. Since a document ++ // contains nothing but other tags, most of what happens ++ // here is skipping white space. ++ if ( !p || !*p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ // Note that, for a document, this needs to come ++ // before the while space skip, so that parsing ++ // starts from the pointer we are given. ++ location.Clear(); ++ if ( prevData ) ++ { ++ location.row = prevData->cursor.row; ++ location.col = prevData->cursor.col; ++ } ++ else ++ { ++ location.row = 0; ++ location.col = 0; ++ } ++ TiXmlParsingData data( p, TabSize(), location.row, location.col ); ++ location = data.Cursor(); ++ ++ if ( encoding == TIXML_ENCODING_UNKNOWN ) ++ { ++ // Check for the Microsoft UTF-8 lead bytes. ++ if ( *(p+0) && *(p+0) == (char)(0xef) ++ && *(p+1) && *(p+1) == (char)(0xbb) ++ && *(p+2) && *(p+2) == (char)(0xbf) ) ++ { ++ encoding = TIXML_ENCODING_UTF8; ++ } ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ while ( p && *p ) ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, &data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ break; ++ } ++ ++ // Did we get encoding info? ++ if ( encoding == TIXML_ENCODING_UNKNOWN ++ && node->ToDeclaration() ) ++ { ++ TiXmlDeclaration* dec = node->ToDeclaration(); ++ const char* enc = dec->Encoding(); ++ assert( enc ); ++ ++ if ( *enc == 0 ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice ++ else ++ encoding = TIXML_ENCODING_LEGACY; ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ // All is well. ++ return p; ++} ++ ++void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ // The first error in a chain is more accurate - don't set again! ++ if ( error ) ++ return; ++ ++ assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); ++ error = true; ++ errorId = err; ++ errorDesc = errorString[ errorId ]; ++ ++ errorLocation.Clear(); ++ if ( pError && data ) ++ { ++ //TiXmlParsingData data( pError, prevData ); ++ data->Stamp( pError, encoding ); ++ errorLocation = data->Cursor(); ++ } ++} ++ ++ ++TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) ++{ ++ TiXmlNode* returnNode = 0; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if( !p || !*p || *p != '<' ) ++ { ++ return 0; ++ } ++ ++ TiXmlDocument* doc = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ ++ // What is this thing? ++ // - Elements start with a letter or underscore, but xml is reserved. ++ // - Comments: <!-- ++ // - Decleration: <?xml ++ // - Everthing else is unknown to tinyxml. ++ // ++ ++ const char* xmlHeader = { "<?xml" }; ++ const char* commentHeader = { "<!--" }; ++ const char* dtdHeader = { "<!" }; ++ ++ if ( StringEqual( p, xmlHeader, true, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Declaration\n" ); ++ #endif ++ returnNode = new TiXmlDeclaration(); ++ } ++ else if ( StringEqual( p, commentHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Comment\n" ); ++ #endif ++ returnNode = new TiXmlComment(); ++ } ++ else if ( StringEqual( p, dtdHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(1)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ else if ( IsAlpha( *(p+1), encoding ) ++ || *(p+1) == '_' ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Element\n" ); ++ #endif ++ returnNode = new TiXmlElement( "" ); ++ } ++ else ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(2)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ ++ if ( returnNode ) ++ { ++ // Set the parent, so it can report errors ++ returnNode->parent = this; ++ } ++ else ++ { ++ if ( doc ) ++ doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++ return returnNode; ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag) ++{ ++ // We're called with some amount of pre-parsing. That is, some of "this" ++ // element is in "tag". Go ahead and stream to the closing ">" ++ while( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c ; ++ ++ if ( c == '>' ) ++ break; ++ } ++ ++ if ( tag->length() < 3 ) return; ++ ++ // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. ++ // If not, identify and stream. ++ ++ if ( tag->at( tag->length() - 1 ) == '>' ++ && tag->at( tag->length() - 2 ) == '/' ) ++ { ++ // All good! ++ return; ++ } ++ else if ( tag->at( tag->length() - 1 ) == '>' ) ++ { ++ // There is more. Could be: ++ // text ++ // closing tag ++ // another node. ++ for ( ;; ) ++ { ++ StreamWhiteSpace( in, tag ); ++ ++ // Do we have text? ++ if ( in->good() && in->peek() != '<' ) ++ { ++ // Yep, text. ++ TiXmlText text( "" ); ++ text.StreamIn( in, tag ); ++ ++ // What follows text is a closing tag or another node. ++ // Go around again and figure it out. ++ continue; ++ } ++ ++ // We now have either a closing tag...or another node. ++ // We should be at a "<", regardless. ++ if ( !in->good() ) return; ++ assert( in->peek() == '<' ); ++ int tagIndex = tag->length(); ++ ++ bool closingTag = false; ++ bool firstCharFound = false; ++ ++ for( ;; ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->peek(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ if ( c == '>' ) ++ break; ++ ++ *tag += (char) c; ++ in->get(); ++ ++ if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) ++ { ++ firstCharFound = true; ++ if ( c == '/' ) ++ closingTag = true; ++ } ++ } ++ // If it was a closing tag, then read in the closing '>' to clean up the input stream. ++ // If it was not, the streaming will be done by the tag. ++ if ( closingTag ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ assert( c == '>' ); ++ *tag += (char) c; ++ ++ // We are done, once we've found our closing tag. ++ return; ++ } ++ else ++ { ++ // If not a closing tag, id it, and stream. ++ const char* tagloc = tag->c_str() + tagIndex; ++ TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); ++ if ( !node ) ++ return; ++ node->StreamIn( in, tag ); ++ delete node; ++ node = 0; ++ ++ // No return: go around from the beginning: text, closing tag, or node. ++ } ++ } ++ } ++} ++#endif ++ ++const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ TiXmlDocument* document = GetDocument(); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); ++ return 0; ++ } ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ ++ if ( *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); ++ return 0; ++ } ++ ++ p = SkipWhiteSpace( p+1, encoding ); ++ ++ // Read the name. ++ const char* pErr = p; ++ ++ p = ReadName( p, &value, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); ++ return 0; ++ } ++ ++ TIXML_STRING endTag ("</"); ++ endTag += value; ++ endTag += ">"; ++ ++ // Check for and read attributes. Also look for an empty ++ // tag or an end tag. ++ while ( p && *p ) ++ { ++ pErr = p; ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ if ( *p == '/' ) ++ { ++ ++p; ++ // Empty tag. ++ if ( *p != '>' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); ++ return 0; ++ } ++ return (p+1); ++ } ++ else if ( *p == '>' ) ++ { ++ // Done with attributes (if there were any.) ++ // Read the value -- which can include other ++ // elements -- read the end tag, and return. ++ ++p; ++ p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. ++ if ( !p || !*p ) ++ return 0; ++ ++ // We should find the end tag now ++ if ( StringEqual( p, endTag.c_str(), false, encoding ) ) ++ { ++ p += endTag.length(); ++ return p; ++ } ++ else ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); ++ return 0; ++ } ++ } ++ else ++ { ++ // Try to read an attribute: ++ TiXmlAttribute* attrib = new TiXmlAttribute(); ++ if ( !attrib ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); ++ return 0; ++ } ++ ++ attrib->SetDocument( document ); ++ const char* pErr = p; ++ p = attrib->Parse( p, data, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); ++ delete attrib; ++ return 0; ++ } ++ ++ // Handle the strange case of double attributes: ++ TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); ++ if ( node ) ++ { ++ node->SetValue( attrib->Value() ); ++ delete attrib; ++ return 0; ++ } ++ ++ attributeSet.Add( attrib ); ++ } ++ } ++ return p; ++} ++ ++ ++const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ ++ const char* pWithWhiteSpace = p; ++ // Read in text and elements in any order. ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ) ++ { ++ if ( *p != '<' ) ++ { ++ // Take what we have, make a text element. ++ TiXmlText* textNode = new TiXmlText( "" ); ++ ++ if ( !textNode ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); ++ return 0; ++ } ++ ++ if ( TiXmlBase::IsWhiteSpaceCondensed() ) ++ { ++ p = textNode->Parse( p, data, encoding ); ++ } ++ else ++ { ++ // Special case: we want to keep the white space ++ // so that leading spaces aren't removed. ++ p = textNode->Parse( pWithWhiteSpace, data, encoding ); ++ } ++ ++ if ( !textNode->Blank() ) ++ LinkEndChild( textNode ); ++ else ++ delete textNode; ++ } ++ else ++ { ++ // We hit a '<' ++ // Have we hit a new element or an end tag? ++ if ( StringEqual( p, "</", false, encoding ) ) ++ { ++ return p; ++ } ++ else ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ return 0; ++ } ++ } ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); ++ } ++ return p; ++} ++ ++ ++#ifdef TIXML_USE_STL ++void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ if ( !p || !*p || *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); ++ return 0; ++ } ++ ++p; ++ value = ""; ++ ++ while ( p && *p && *p != '>' ) ++ { ++ value += *p; ++ ++p; ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); ++ } ++ if ( *p == '>' ) ++ return p+1; ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ ++ if ( c == '>' ++ && tag->at( tag->length() - 2 ) == '-' ++ && tag->at( tag->length() - 3 ) == '-' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ value = ""; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ const char* startTag = "<!--"; ++ const char* endTag = "-->"; ++ ++ if ( !StringEqual( p, startTag, false, encoding ) ) ++ { ++ document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); ++ return 0; ++ } ++ p += strlen( startTag ); ++ p = ReadText( p, &value, false, endTag, false, encoding ); ++ return p; ++} ++ ++ ++const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) return 0; ++ ++ int tabsize = 4; ++ if ( document ) ++ tabsize = document->TabSize(); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ // Read the name, the '=' and the value. ++ const char* pErr = p; ++ p = ReadName( p, &name, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p || *p != '=' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ ++p; // skip '=' ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ const char* end; ++ ++ if ( *p == '\'' ) ++ { ++ ++p; ++ end = "\'"; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else if ( *p == '"' ) ++ { ++ ++p; ++ end = "\""; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else ++ { ++ // All attribute values should be in single or double quotes. ++ // But this is such a common error that the parser will try ++ // its best, even without them. ++ value = ""; ++ while ( p && *p // existence ++ && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace ++ && *p != '/' && *p != '>' ) // tag end ++ { ++ value += *p; ++ ++p; ++ } ++ } ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == '<' ) ++ return; ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ in->get(); ++ } ++} ++#endif ++ ++const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ value = ""; ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ bool ignoreWhite = true; ++ ++ const char* end = "<"; ++ p = ReadText( p, &value, ignoreWhite, end, false, encoding ); ++ if ( p ) ++ return p-1; // don't truncate the '<' ++ return 0; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) ++{ ++ p = SkipWhiteSpace( p, _encoding ); ++ // Find the beginning, find the end, and look for ++ // the stuff in-between. ++ TiXmlDocument* document = GetDocument(); ++ if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); ++ return 0; ++ } ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, _encoding ); ++ location = data->Cursor(); ++ } ++ p += 5; ++ ++ version = ""; ++ encoding = ""; ++ standalone = ""; ++ ++ while ( p && *p ) ++ { ++ if ( *p == '>' ) ++ { ++ ++p; ++ return p; ++ } ++ ++ p = SkipWhiteSpace( p, _encoding ); ++ if ( StringEqual( p, "version", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ version = attrib.Value(); ++ } ++ else if ( StringEqual( p, "encoding", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ encoding = attrib.Value(); ++ } ++ else if ( StringEqual( p, "standalone", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ standalone = attrib.Value(); ++ } ++ else ++ { ++ // Read over whatever it is. ++ while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++ ++p; ++ } ++ } ++ return 0; ++} ++ ++bool TiXmlText::Blank() const ++{ ++ for ( unsigned i=0; i<value.length(); i++ ) ++ if ( !IsWhiteSpace( value[i] ) ) ++ return false; ++ return true; ++} ++#endif /* SETUP */ +diff -ruNp vdr-1.6.0-2/transfer.c vdr-1.6.0-2-extensions/transfer.c +--- vdr-1.6.0-2/transfer.c 2007-01-05 11:45:28.000000000 +0100 ++++ vdr-1.6.0-2-extensions/transfer.c 2009-04-09 20:48:27.000000000 +0200 +@@ -19,7 +19,11 @@ cTransfer::cTransfer(tChannelID ChannelI + ,cThread("transfer") + { + ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer"); ++#ifdef USE_SYNCEARLY ++ remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, Setup.UseSyncEarlyPatch); ++#else + remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids); ++#endif /* SYNCEARLY */ + } + + cTransfer::~cTransfer() +diff -ruNp vdr-1.6.0-2/transfer.h vdr-1.6.0-2-extensions/transfer.h +--- vdr-1.6.0-2/transfer.h 2007-01-05 11:45:45.000000000 +0100 ++++ vdr-1.6.0-2-extensions/transfer.h 2009-04-09 20:48:27.000000000 +0200 +@@ -30,6 +30,10 @@ public: + }; + + class cTransferControl : public cControl { ++#ifdef USE_LIVEBUFFER ++friend class cLiveBufferControl; ++friend class cLiveBufferManager; ++#endif /* LIVEBUFFER */ + private: + cTransfer *transfer; + static cDevice *receiverDevice; +diff -ruNp vdr-1.6.0-2/vdr.c vdr-1.6.0-2-extensions/vdr.c +--- vdr-1.6.0-2/vdr.c 2008-09-11 13:29:43.000000000 +0200 ++++ vdr-1.6.0-2-extensions/vdr.c 2009-04-09 20:48:27.000000000 +0200 +@@ -50,6 +50,9 @@ + #include "keys.h" + #include "libsi/si.h" + #include "lirc.h" ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "menu.h" + #include "osdbase.h" + #include "plugin.h" +@@ -139,10 +142,17 @@ static bool SetKeepCaps(bool On) + return true; + } + ++#ifdef USE_SETTIME ++char *SetTime = NULL; ++#endif /* SETTIME */ ++ + static void SignalHandler(int signum) + { + switch (signum) { + case SIGPIPE: ++#ifdef USE_EM84XX ++ case SIGINT: ++#endif /* EM84XX */ + break; + case SIGHUP: + LastSignal = signum; +@@ -163,6 +173,10 @@ static void Watchdog(int signum) + exit(1); + } + ++#ifdef USE_CMDRECCMDI18N ++const char *ConfigDirectory = NULL; ++#endif /* CMDRECCMDI18N */ ++ + int main(int argc, char *argv[]) + { + // Save terminal settings: +@@ -187,8 +201,11 @@ int main(int argc, char *argv[]) + bool UserDump = false; + int SVDRPport = DEFAULTSVDRPPORT; + const char *AudioCommand = NULL; ++#ifndef USE_CMDRECCMDI18N + const char *ConfigDirectory = NULL; ++#endif /* CMDRECCMDI18N */ + const char *EpgDataFileName = DEFAULTEPGDATAFILENAME; ++ bool DisplayExtensions = false; + bool DisplayHelp = false; + bool DisplayVersion = false; + bool DaemonMode = false; +@@ -220,10 +237,14 @@ int main(int argc, char *argv[]) + + static struct option long_options[] = { + { "audio", required_argument, NULL, 'a' }, ++#ifdef USE_LIVEBUFFER ++ { "buffer", required_argument, NULL, 'b' }, ++#endif /* LIVEBUFFER */ + { "config", required_argument, NULL, 'c' }, + { "daemon", no_argument, NULL, 'd' }, + { "device", required_argument, NULL, 'D' }, + { "epgfile", required_argument, NULL, 'E' }, ++ { "extensions",no_argument, NULL, 'e' | 0x100 }, + { "grab", required_argument, NULL, 'g' }, + { "help", no_argument, NULL, 'h' }, + { "lib", required_argument, NULL, 'L' }, +@@ -238,6 +259,9 @@ int main(int argc, char *argv[]) + { "record", required_argument, NULL, 'r' }, + { "shutdown", required_argument, NULL, 's' }, + { "terminal", required_argument, NULL, 't' }, ++#ifdef USE_SETTIME ++ { "timeset", required_argument, NULL, 'T' }, ++#endif /* SETTIME */ + { "user", required_argument, NULL, 'u' }, + { "userdump", no_argument, NULL, 'u' | 0x100 }, + { "version", no_argument, NULL, 'V' }, +@@ -248,10 +272,28 @@ int main(int argc, char *argv[]) + }; + + int c; ++#ifdef USE_SETTIME ++#ifdef USE_LIVEBUFFER ++ while ((c = getopt_long(argc, argv, "a::b:c:dD:E:g:hl:L:mp:P:r:s:t:T:u:v:Vw:", long_options, NULL)) != -1) { ++#else ++ while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:T:u:v:Vw:", long_options, NULL)) != -1) { ++#endif /* LIVEBUFFER */ ++#else ++#ifdef USE_LIVEBUFFER ++ while ((c = getopt_long(argc, argv, "a::b:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) { ++#else + while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) { ++#endif /* LIVEBUFFER */ ++#endif /* SETTIME */ + switch (c) { + case 'a': AudioCommand = optarg; + break; ++#ifdef USE_LIVEBUFFER ++ case 'b': BufferDirectory = optarg; ++ while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') ++ optarg[strlen(optarg) - 1] = 0; ++ break; ++#endif /* LIVEBUFFER */ + case 'c': ConfigDirectory = optarg; + break; + case 'd': DaemonMode = true; break; +@@ -265,6 +307,9 @@ int main(int argc, char *argv[]) + fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg); + return 2; + break; ++ case 'e' | 0x100: ++ DisplayExtensions = true; ++ break; + case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL); + break; + case 'g': cSVDRP::SetGrabImageDir(*optarg != '-' ? optarg : NULL); +@@ -336,6 +381,10 @@ int main(int argc, char *argv[]) + break; + case 's': ShutdownHandler.SetShutdownCommand(optarg); + break; ++#ifdef USE_SETTIME ++ case 'T': SetTime = strdup(optarg); ++ break; ++#endif /* SETTIME */ + case 't': Terminal = optarg; + if (access(Terminal, R_OK | W_OK) < 0) { + fprintf(stderr, "vdr: can't access terminal: %s\n", Terminal); +@@ -396,11 +445,16 @@ int main(int argc, char *argv[]) + if (DisplayHelp) { + printf("Usage: vdr [OPTIONS]\n\n" // for easier orientation, this is column 80| + " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n" ++#ifdef USE_LIVEBUFFER ++ " -b DIR, --buffer=DIR use DIR as LiveBuffer directory (default is to write\n" ++ " it to the video directory)\n" ++#endif /* LIVEBUFFER */ + " -c DIR, --config=DIR read config files from DIR (default: %s)\n" + " -d, --daemon run in daemon mode\n" + " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" + " there may be several -D options (default: all DVB\n" + " devices will be used)\n" ++ " --extensions print patchlevel and exit\n" + " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n" + " '%s' in the video directory)\n" + " '-E-' disables this\n" +@@ -431,6 +485,9 @@ int main(int argc, char *argv[]) + " -r CMD, --record=CMD call CMD before and after a recording\n" + " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" + " -t TTY, --terminal=TTY controlling tty\n" ++#ifdef USE_SETTIME ++ " -T CMD, --timeset=CMD call CMD to set the system time\n" ++#endif /* SETTIME */ + " -u USER, --user=USER run as user USER; only applicable if started as\n" + " root\n" + " --userdump allow coredumps if -u is given (debugging)\n" +@@ -474,6 +531,213 @@ int main(int argc, char *argv[]) + return 0; + } + ++ if (DisplayExtensions) { ++ printf("VDR %s\n", VDRVERSION); ++ printf("VDREXTENSIONS %d\n", VDREXTENSIONS); ++ ++#ifdef USE_ANALOGTV ++ printf(" ANALOGTV\n"); ++#endif /* ANALOGTV */ ++ ++#ifdef USE_ATSC ++ printf(" ATSC\n"); ++#endif /* ATSC */ ++ ++#ifdef USE_CHANNELSCAN ++ printf(" CHANNELSCAN\n"); ++#endif /* CHANNELSCAN */ ++ ++#ifdef USE_CMDRECCMDI18N ++ printf(" CMDRECCMDI18N\n"); ++#endif /* CMDRECCMDI18N */ ++ ++#ifdef USE_CMDSUBMENU ++ printf(" CMDSUBMENU %d\n", CMDSUBMENUVERSNUM); ++#endif /* CMDSUBMENU */ ++ ++#ifdef USE_CUTTERLIMIT ++ printf(" CUTTERLIMIT\n"); ++#endif /* CUTTERLIMIT */ ++ ++#ifdef USE_CUTTERQUEUE ++ printf(" CUTTERQUEUE\n"); ++#endif /* CUTTERQUEUE */ ++ ++#ifdef USE_CUTTIME ++ printf(" CUTTIME\n"); ++#endif /* CUTTIME */ ++ ++#ifdef USE_DDEPGENTRY ++ printf(" DDEPGENTRY\n"); ++#endif /* DDEPGENTRY */ ++ ++#ifdef USE_DELTIMESHIFTREC ++ printf(" DELTIMESHIFTREC\n"); ++#endif /* DELTIMESHIFTREC */ ++ ++#ifdef USE_DOLBYINREC ++ printf(" DOLBYINREC\n"); ++#endif /* DOLBYINREC */ ++ ++#ifdef USE_DVBPLAYER ++ printf(" DVBPLAYER\n"); ++#endif /* DVBPLAYER */ ++ ++#ifdef USE_DVBSETUP ++ printf(" DVBSETUP\n"); ++#endif /* DVBSETUP */ ++ ++#ifdef USE_DVDARCHIVE ++ printf(" DVDARCHIVE\n"); ++#endif /* DVDARCHIVE */ ++ ++#ifdef USE_DVDCHAPJUMP ++ printf(" DVDCHAPJUMP\n"); ++#endif /* DVDCHAPJUMP */ ++ ++#ifdef USE_DVLRECSCRIPTADDON ++ printf(" DVLRECSCRIPTADDON\n"); ++#endif /* DVLRECSCRIPTADDON */ ++ ++#ifdef USE_DVLVIDPREFER ++ printf(" DVLVIDPREFER\n"); ++#endif /* DVLVIDPREFER */ ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++ printf(" DVLFRIENDLYFNAMES\n"); ++#endif /* DVLFRIENDLYFNAMES */ ++ ++#ifdef USE_EM84XX ++ printf(" EM84XX\n"); ++#endif /* EM84XX */ ++ ++#ifdef USE_GRAPHTFT ++ printf(" GRAPHTFT\n"); ++#endif /* GRAPHTFT */ ++ ++#ifdef USE_HARDLINKCUTTER ++ printf(" HARDLINKCUTTER\n"); ++#endif /* HARDLINKCUTTER */ ++ ++#ifdef USE_JUMPPLAY ++ printf(" JUMPPLAY %d\n", JUMPPLAYVERSNUM); ++#endif /* JUMPPLAY */ ++ ++#ifdef USE_LIEMIEXT ++ printf(" LIEMIEXT %d\n", LIEMIKUUTIO); ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_LIRCSETTINGS ++ printf(" LIRCSETTINGS\n"); ++#endif /* LIRCSETTINGS */ ++ ++#ifdef USE_LIVEBUFFER ++ printf(" LIVEBUFFER\n"); ++#endif /* LIVEBUFFER */ ++ ++#ifdef USE_LNBSHARE ++ printf(" LNBSHARE\n"); ++#endif /* LNBSHARE */ ++ ++#ifdef USE_MAINMENUHOOKS ++ printf(" MAINMENUHOOKS %3.1f\n", MAINMENUHOOKSVERSNUM); ++#endif /* MAINMENUHOOKS */ ++ ++#ifdef USE_MENUORG ++ printf(" MENUORG\n"); ++#endif /* MENUORG */ ++ ++#ifdef USE_NOEPG ++ printf(" NOEPG\n"); ++#endif /* NOEPG */ ++ ++#ifdef USE_OSDMAXITEMS ++ printf(" OSDMAXITEMS\n"); ++#endif /* OSDMAXITEMS */ ++ ++#ifdef USE_PARENTALRATING ++ printf(" PARENTALRATING\n"); ++#endif /* PARENTALRATING */ ++ ++#ifdef USE_PINPLUGIN ++ printf(" PINPLUGIN %d\n", PIN_PLUGIN_PATCH); ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_PLUGINAPI ++ printf(" PLUGINAPI\n"); ++#endif /* PLUGINAPI */ ++ ++#ifdef USE_PLUGINMISSING ++ printf(" PLUGINMISSING\n"); ++#endif /* PLUGINMISSING */ ++ ++#ifdef USE_PLUGINPARAM ++ printf(" PLUGINPARAM %d\n", PLUGINPARAMPATCHVERSNUM); ++#endif /* PLUGINPARAM */ ++ ++#ifdef USE_ROTOR ++ printf(" ROTOR\n"); ++#endif /* ROTOR */ ++ ++#ifdef USE_SETTIME ++ printf(" SETTIME\n"); ++#endif /* SETTIME */ ++ ++#ifdef USE_SETUP ++ printf(" SETUP\n"); ++#endif /* SETUP */ ++ ++#ifdef USE_SOFTOSD ++ printf(" SOFTOSD\n"); ++#endif /* SOFTOSD */ ++ ++#ifdef USE_SOURCECAPS ++ printf(" SOURCECAPS\n"); ++#endif /* SOURCECAPS */ ++ ++#ifdef USE_SORTRECORDS ++ printf(" SORTRECORDS\n"); ++#endif /* SORTRECORDS */ ++ ++#ifdef USE_STREAMDEVEXT ++ printf(" STREAMDEVEXT\n"); ++#endif /* STREAMDEVEXT */ ++ ++#ifdef USE_SYNCEARLY ++ printf(" SYNCEARLY\n"); ++#endif /* SYNCEARLY */ ++ ++#ifdef USE_TIMERCMD ++ printf(" TIMERCMD\n"); ++#endif /* TIMERCMD */ ++ ++#ifdef USE_TIMERINFO ++ printf(" TIMERINFO\n"); ++#endif /* TIMERINFO */ ++ ++#ifdef USE_TTXTSUBS ++ printf(" TTXTSUBS\n"); ++#endif /* TTXTSUBS*/ ++ ++#ifdef USE_VALIDINPUT ++ printf(" VALIDINPUT\n"); ++#endif /* VALIDINPUT */ ++ ++#ifdef USE_VOLCTRL ++ printf(" VOLCTRL\n"); ++#endif /* VOLCTRL */ ++ ++#ifdef USE_WAREAGLEICON ++ printf(" WAREAGLEICON\n"); ++#endif /* WAREAGLEICON */ ++ ++#ifdef USE_YAEPG ++ printf(" YAEPG\n"); ++#endif /* YAEPG */ ++ ++ return 0; ++ } ++ + // Log file: + + if (SysLogLevel > 0) +@@ -553,6 +817,11 @@ int main(int argc, char *argv[]) + if (!PluginManager.LoadPlugins(true)) + EXIT(2); + ++#ifdef USE_LIVEBUFFER ++ if (!BufferDirectory) ++ BufferDirectory = VideoDirectory; ++#endif /* LIVEBUFFER */ ++ + // Configuration data: + + if (!ConfigDirectory) +@@ -566,8 +835,20 @@ int main(int argc, char *argv[]) + Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC) && + Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true) && + Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")) && ++#ifdef USE_CMDRECCMDI18N ++ LoadCommandsI18n(Commands,AddDirectory(ConfigDirectory, "commands.conf"), true) && ++ LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory, "reccmds.conf"), true) && ++#else + Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true) && + RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) && ++#endif /* CMDRECCMDI18N */ ++#ifdef USE_TIMERCMD ++#ifdef USE_CMDRECCMDI18N ++ LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true) && ++#else ++ TimerCommands.Load(AddDirectory(ConfigDirectory, "timercmds.conf"), true) && ++#endif /* CMDRECCMDI18N */ ++#endif /* TIMERCMD */ + SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) && + Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) && + KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true) +@@ -730,7 +1011,11 @@ int main(int argc, char *argv[]) + // Make sure we have a visible programme in case device usage has changed: + if (!EITScanner.Active() && cDevice::PrimaryDevice()->HasDecoder() && !cDevice::PrimaryDevice()->HasProgramme()) { + static time_t lastTime = 0; ++#ifdef USE_CHANNELSCAN ++ if (!scanning_on_receiving_device && (!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { ++#else + if ((!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { // !Menu to avoid interfering with the CAM if a CAM menu is open ++#endif /* CHANNELSCAN */ + cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel()); + if (Channel && (Channel->Vpid() || Channel->Apid(0))) { + if (!Channels.SwitchTo(cDevice::CurrentChannel()) // try to switch to the original channel... +@@ -786,8 +1071,17 @@ int main(int argc, char *argv[]) + } + // Channel display: + if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) { ++#ifdef USE_LIVEBUFFER ++ if (!Menu) { ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (!Menu) ++#endif /* LIVEBUFFER */ + Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0); ++#ifdef USE_LIVEBUFFER ++ } ++#endif /* LIVEBUFFER */ + LastChannel = cDevice::CurrentChannel(); + LastChannelChanged = Now; + } +@@ -902,9 +1196,19 @@ int main(int argc, char *argv[]) + if (!Skins.IsOpen()) + Skins.ProcessQueuedMessages(); + // User Input: ++#ifdef USE_LIVEBUFFER ++ cOsdObject *Interact = Menu ? Menu : cControl::Control(true); ++#else + cOsdObject *Interact = Menu ? Menu : cControl::Control(); ++#endif /* LIVEBUFFER */ + eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse()); ++#ifdef USE_LIVEBUFFER ++ Interact = Menu ? Menu : cControl::Control(); ++#endif /* LIVEBUFFER */ + if (ISREALKEY(key)) { ++#ifdef USE_PINPLUGIN ++ cStatus::MsgUserAction(key, Interact); ++#endif /* PINPLUGIN */ + EITScanner.Activity(); + // Cancel shutdown countdown: + if (ShutdownHandler.countdown) +@@ -921,9 +1225,17 @@ int main(int argc, char *argv[]) + bool WasMenu = Interact && Interact->IsMenu(); + if (Menu) + DELETE_MENU; ++#ifdef USE_LIVEBUFFER ++ else if (cControl::Control(true)) { ++#else + else if (cControl::Control()) { ++#endif /* LIVEBUFFER */ + if (cOsd::IsOpen()) ++#ifdef USE_LIVEBUFFER ++ cControl::Control(true)->Hide(); ++#else + cControl::Control()->Hide(); ++#endif /* LIVEBUFFER */ + else + WasOpen = false; + } +@@ -956,12 +1268,21 @@ int main(int argc, char *argv[]) + } + break; + // Direct main menu functions: ++#ifdef USE_LIVEBUFFER ++ #define DirectMainFunction(function)\ ++ DELETE_MENU;\ ++ if (cControl::Control(true))\ ++ cControl::Control(true)->Hide();\ ++ Menu = new cMenuMain(function);\ ++ key = kNone; // nobody else needs to see this key ++#else + #define DirectMainFunction(function)\ + DELETE_MENU;\ + if (cControl::Control())\ + cControl::Control()->Hide();\ + Menu = new cMenuMain(function);\ + key = kNone; // nobody else needs to see this key ++#endif /* LIVEBUFFER */ + case kSchedule: DirectMainFunction(osSchedule); break; + case kChannels: DirectMainFunction(osChannels); break; + case kTimers: DirectMainFunction(osTimers); break; +@@ -973,14 +1294,25 @@ int main(int argc, char *argv[]) + const char *PluginName = cRemote::GetPlugin(); + if (PluginName) { + DELETE_MENU; ++#ifdef USE_LIVEBUFFER ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (cControl::Control()) + cControl::Control()->Hide(); ++#endif /* LIVEBUFFER */ + cPlugin *plugin = cPluginManager::GetPlugin(PluginName); + if (plugin) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(plugin)) { ++#endif /* PINPLUGIN */ + Menu = plugin->MainMenuAction(); + if (Menu) + Menu->Show(); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + esyslog("ERROR: unknown plugin '%s'", PluginName); + } +@@ -992,8 +1324,17 @@ int main(int argc, char *argv[]) + case kChanUp: + case kChanDn|k_Repeat: + case kChanDn: ++#ifdef USE_LIVEBUFFER ++ if (!Interact) { ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (!Interact) ++#endif /* LIVEBUFFER */ + Menu = new cDisplayChannel(NORMALKEY(key)); ++#ifdef USE_LIVEBUFFER ++ } ++#endif /* LIVEBUFFER */ + else if (cDisplayChannel::IsOpen() || cControl::Control()) { + Interact->ProcessKey(key); + continue; +@@ -1023,8 +1364,13 @@ int main(int argc, char *argv[]) + break; + // Audio track control: + case kAudio: ++#ifdef USE_LIVEBUFFER ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (cControl::Control()) + cControl::Control()->Hide(); ++#endif /* LIVEBUFFER */ + if (!cDisplayTracks::IsOpen()) { + DELETE_MENU; + Menu = cDisplayTracks::Create(); +@@ -1047,7 +1393,11 @@ int main(int argc, char *argv[]) + break; + // Pausing live video: + case kPause: ++#ifdef USE_LIVEBUFFER ++ if (!cControl::Control() && !cLiveBufferManager::GetLiveBufferControl()) { ++#else + if (!cControl::Control()) { ++#endif /* LIVEBUFFER */ + DELETE_MENU; + if (!cRecordControls::PauseLiveVideo()) + Skins.Message(mtError, tr("No free DVB device to record!")); +@@ -1056,9 +1406,20 @@ int main(int argc, char *argv[]) + break; + // Instant recording: + case kRecord: ++#ifdef USE_LIVEBUFFER ++ if (!cControl::Control() && !cLiveBufferManager::GetLiveBufferControl()) { ++#else + if (!cControl::Control()) { ++#endif /* LIVEBUFFER */ ++#ifdef USE_STREAMDEVEXT ++ if (cRecordControls::Start()) { ++ Skins.Message(mtInfo, tr("Recording started")); ++ cStatus::MsgRecordingChange(NULL, scAdd); ++ } ++#else + if (cRecordControls::Start()) + Skins.Message(mtInfo, tr("Recording started")); ++#endif /* STREAMDEVEXT */ + key = kNone; // nobody else needs to see this key + } + break; +@@ -1108,14 +1469,42 @@ int main(int argc, char *argv[]) + state = osEnd; + } + switch (state) { ++#ifdef USE_LIVEBUFFER ++ case osPause: if (cLiveBufferManager::GetLiveBufferControl()) { ++ DELETE_MENU; ++ if (cControl::Control(true)) { ++ cControl::Control(true)->ProcessKey(kPlay); ++ cControl::Control(true)->ProcessKey(kPause); ++ } ++ break; ++ } ++ DELETE_MENU; ++#else + case osPause: DELETE_MENU; ++#endif /* LIVEBUFFER */ + cControl::Shutdown(); // just in case + if (!cRecordControls::PauseLiveVideo()) + Skins.Message(mtError, tr("No free DVB device to record!")); + break; ++#ifdef USE_LIVEBUFFER ++ case osRecord: if (cLiveBufferManager::GetLiveBufferControl()) { ++ if (cControl::Control(true)) ++ cControl::Control(true)->ProcessKey(kRecord); ++ break; ++ } ++ DELETE_MENU; ++#else + case osRecord: DELETE_MENU; ++#endif /* LIVEBUFFER */ ++#ifdef USE_STREAMDEVEXT ++ if (cRecordControls::Start()) { ++ Skins.Message(mtInfo, tr("Recording started")); ++ cStatus::MsgRecordingChange(NULL, scAdd); ++ } ++#else + if (cRecordControls::Start()) + Skins.Message(mtInfo, tr("Recording started")); ++#endif /* STREAMDEVEXT */ + break; + case osRecordings: + DELETE_MENU; +@@ -1152,6 +1541,12 @@ int main(int argc, char *argv[]) + } + } + else { ++#ifdef USE_LIVEBUFFER ++ eOSState state = osUnknown; ++ if (cLiveBufferManager::GetLiveBufferControl()) ++ state = cLiveBufferManager::GetLiveBufferControl()->ProcessKey(key); ++ if (state == osUnknown) { ++#endif /* LIVEBUFFER */ + // Key functions in "normal" viewing mode: + if (key != kNone && KeyMacros.Get(key)) { + cRemote::PutMacro(key); +@@ -1166,13 +1561,26 @@ int main(int argc, char *argv[]) + Channels.SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]); + break; + } ++#ifdef USE_VOLCTRL ++ // Left/Right volume control ++#else + // Direct Channel Select: + case k1 ... k9: + // Left/Right rotates through channel groups: ++#endif /* VOLCTRL */ + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && Setup.LRChannelGroups < 2) { ++ cRemote::Put(NORMALKEY(key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++ // Direct Channel Select: ++ case k1 ... k9: ++#endif /* VOLCTRL */ + // Previous/Next rotates through channel groups: + case kPrev|k_Repeat: + case kPrev: +@@ -1183,6 +1591,10 @@ int main(int argc, char *argv[]) + case kUp: + case kDown|k_Repeat: + case kDown: ++#ifdef USE_LIVEBUFFER ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#endif /* LIVEBUFFER */ + Menu = new cDisplayChannel(NORMALKEY(key)); + break; + // Viewing Control: +@@ -1190,13 +1602,22 @@ int main(int argc, char *argv[]) + // Instant resume of the last viewed recording: + case kPlay: + if (cReplayControl::LastReplayed()) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(0, cReplayControl::LastReplayed(), 0, false) == false) { ++#endif /* PINPLUGIN */ + cControl::Shutdown(); + cControl::Launch(new cReplayControl); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + break; + default: break; + } + } ++#ifdef USE_LIVEBUFFER ++ } ++#endif /* LIVEBUFFER */ + if (!Menu) { + if (!InhibitEpgScan) + EITScanner.Process(); +@@ -1266,6 +1687,9 @@ Exit: + signal(SIGPIPE, SIG_DFL); + signal(SIGALRM, SIG_DFL); + ++#ifdef USE_LIVEBUFFER ++ cLiveBufferManager::Shutdown(); ++#endif /* LIVEBUFFER */ + PluginManager.StopPlugins(); + cRecordControls::Shutdown(); + cCutter::Stop(); +diff -ruNp vdr-1.6.0-2/vdrttxtsubshooks.c vdr-1.6.0-2-extensions/vdrttxtsubshooks.c +--- vdr-1.6.0-2/vdrttxtsubshooks.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/vdrttxtsubshooks.c 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,46 @@ ++#ifdef USE_TTXTSUBS ++ ++#include <stdlib.h> ++#include <stdio.h> ++#include <stdint.h> ++ ++#include "vdrttxtsubshooks.h" ++ ++// XXX Really should be a list... ++static cVDRTtxtsubsHookListener *gListener; ++ ++// ------ class cVDRTtxtsubsHookProxy ------ ++ ++class cVDRTtxtsubsHookProxy : public cVDRTtxtsubsHookListener ++{ ++ public: ++ virtual void HideOSD(void) { if(gListener) gListener->HideOSD(); }; ++ virtual void ShowOSD(void) { if(gListener) gListener->ShowOSD(); }; ++ virtual void PlayerTeletextData(uint8_t *p, int length) ++ { if(gListener) gListener->PlayerTeletextData(p, length); }; ++ virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch) ++ { if(gListener) return gListener->NewTtxtSubsRecorder(dev, ch); else return NULL; }; ++}; ++ ++ ++// ------ class cVDRTtxtsubsHookListener ------ ++ ++cVDRTtxtsubsHookListener::~cVDRTtxtsubsHookListener() ++{ ++ gListener = 0; ++} ++ ++void cVDRTtxtsubsHookListener::HookAttach(void) ++{ ++ gListener = this; ++ //printf("cVDRTtxtsubsHookListener::HookAttach\n"); ++} ++ ++static cVDRTtxtsubsHookProxy gProxy; ++ ++cVDRTtxtsubsHookListener *cVDRTtxtsubsHookListener::Hook(void) ++{ ++ return &gProxy; ++} ++ ++#endif /* TTXTSUBS */ +diff -ruNp vdr-1.6.0-2/vdrttxtsubshooks.h vdr-1.6.0-2-extensions/vdrttxtsubshooks.h +--- vdr-1.6.0-2/vdrttxtsubshooks.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.6.0-2-extensions/vdrttxtsubshooks.h 2009-04-09 20:48:27.000000000 +0200 +@@ -0,0 +1,38 @@ ++#ifdef USE_TTXTSUBS ++ ++#ifndef __VDRTTXTSUBSHOOKS_H ++#define __VDRTTXTSUBSHOOKS_H ++ ++class cDevice; ++class cChannel; ++ ++#define VDRTTXTSUBSHOOKS ++ ++class cTtxtSubsRecorderBase { ++ public: ++ virtual ~cTtxtSubsRecorderBase() {}; ++ ++ // returns a PES packet if there is data to add to the recording ++ virtual uint8_t *GetPacket(uint8_t **buf, size_t *len) { return NULL; }; ++ virtual void DeviceAttach(void) {}; ++}; ++ ++class cVDRTtxtsubsHookListener { ++ public: ++ cVDRTtxtsubsHookListener(void) {}; ++ virtual ~cVDRTtxtsubsHookListener(); ++ ++ void HookAttach(void); ++ ++ virtual void HideOSD(void) {}; ++ virtual void ShowOSD(void) {}; ++ virtual void PlayerTeletextData(uint8_t *p, int length) {}; ++ virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch) ++ { return NULL; }; ++ ++ // used by VDR to call hook listeners ++ static cVDRTtxtsubsHookListener *Hook(void); ++}; ++ ++#endif /* __VDRTTXTSUBSHOOKS_H */ ++#endif /* TTXTSUBS */ +diff -ruNp vdr-1.6.0-2/videodir.c vdr-1.6.0-2-extensions/videodir.c +--- vdr-1.6.0-2/videodir.c 2008-02-16 14:00:03.000000000 +0100 ++++ vdr-1.6.0-2-extensions/videodir.c 2009-04-09 20:48:27.000000000 +0200 +@@ -19,7 +19,17 @@ + #include "recording.h" + #include "tools.h" + ++#ifdef USE_HARDLINKCUTTER ++//#define HARDLINK_TEST_ONLY ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ ++#endif /* HARDLINKCUTTER */ ++ + const char *VideoDirectory = VIDEODIR; ++#ifdef USE_LIVEBUFFER ++const char *BufferDirectory = NULL; ++#endif /* LIVEBUFFER */ + + class cVideoDirectory { + private: +@@ -36,6 +46,11 @@ public: + bool Next(void); + void Store(void); + const char *Adjust(const char *FileName); ++#ifdef USE_DVLVIDPREFER ++ char *GetVidPath(int nVid); ++ bool GetPreferedVideoDir(void); ++ bool IsVidDirOK(int nVid, int *freeMB = NULL); ++#endif /* DVLVIDPREFER */ + }; + + cVideoDirectory::cVideoDirectory(void) +@@ -117,6 +132,9 @@ cUnbufferedFile *OpenVideoFile(const cha + if ((Flags & O_CREAT) != 0) { + cVideoDirectory Dir; + if (Dir.IsDistributed()) { ++#ifdef USE_DVLVIDPREFER ++ if (Setup.UseVidPrefer == 0) { ++#endif /* DVLVIDPREFER */ + // Find the directory with the most free space: + int MaxFree = Dir.FreeMB(); + while (Dir.Next()) { +@@ -126,14 +144,24 @@ cUnbufferedFile *OpenVideoFile(const cha + MaxFree = Free; + } + } ++#ifdef USE_DVLVIDPREFER ++ } ++ else Dir.GetPreferedVideoDir(); ++#endif /* DVLVIDPREFER */ + if (Dir.Stored()) { + ActualFileName = Dir.Adjust(FileName); + if (!MakeDirs(ActualFileName, false)) + return NULL; // errno has been set by MakeDirs() ++#ifdef USE_DVLVIDPREFER ++ if (strcmp(ActualFileName, FileName) != 0) { ++#endif /* DVLVIDPREFER */ + if (symlink(ActualFileName, FileName) < 0) { + LOG_ERROR_STR(FileName); + return NULL; + } ++#ifdef USE_DVLVIDPREFER ++ } ++#endif /* DVLVIDPREFER */ + ActualFileName = strdup(ActualFileName); // must survive Dir! + } + } +@@ -168,6 +196,125 @@ bool RemoveVideoFile(const char *FileNam + return RemoveFileOrDir(FileName, true); + } + ++#ifdef USE_HARDLINKCUTTER ++static bool StatNearestDir(const char *FileName, struct stat *Stat) ++{ ++ cString Name(FileName); ++ char *p; ++ while ((p = strrchr((const char*)Name + 1, '/')) != NULL) { ++ *p = 0; // truncate at last '/' ++ if (stat(Name, Stat) == 0) { ++ isyslog("StatNearestDir: Stating %s", (const char*)Name); ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool HardLinkVideoFile(const char *OldName, const char *NewName) ++{ ++ // Incoming name must be in base video directory: ++ if (strstr(OldName, VideoDirectory) != OldName) { ++ esyslog("ERROR: %s not in %s", OldName, VideoDirectory); ++ return false; ++ } ++ if (strstr(NewName, VideoDirectory) != NewName) { ++ esyslog("ERROR: %s not in %s", NewName, VideoDirectory); ++ return false; ++ } ++ ++ const char *ActualNewName = NewName; ++ cString ActualOldName(ReadLink(OldName), true); ++ ++ // Some safety checks: ++ struct stat StatOldName; ++ if (lstat(ActualOldName, &StatOldName) == 0) { ++ if (S_ISLNK(StatOldName.st_mode)) { ++ esyslog("HardLinkVideoFile: Failed to resolve symbolic link %s", (const char*)ActualOldName); ++ return false; ++ } ++ } ++ else { ++ esyslog("HardLinkVideoFile: lstat failed on %s", (const char*)ActualOldName); ++ return false; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", (const char*)ActualOldName, (int)StatOldName.st_dev); ++ ++ // Find the video directory where ActualOldName is located ++ ++ cVideoDirectory Dir; ++ struct stat StatDir; ++ if (!StatNearestDir(NewName, &StatDir)) { ++ esyslog("HardLinkVideoFile: stat failed on %s", NewName); ++ return false; ++ } ++ ++ isyslog("HardLinkVideoFile: %s is on %i", NewName, (int)StatDir.st_dev); ++ if (StatDir.st_dev != StatOldName.st_dev) { ++ // Not yet found. ++ ++ if (!Dir.IsDistributed()) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Search in video01 and upwards ++ bool found = false; ++ while (Dir.Next()) { ++ Dir.Store(); ++ const char *TmpNewName = Dir.Adjust(NewName); ++ if (StatNearestDir(TmpNewName, &StatDir) && StatDir.st_dev == StatOldName.st_dev) { ++ isyslog("HardLinkVideoFile: %s is on %i (match)", TmpNewName, (int)StatDir.st_dev); ++ ActualNewName = TmpNewName; ++ found = true; ++ break; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", TmpNewName, (int)StatDir.st_dev); ++ } ++ if (ActualNewName == NewName) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Looking good, we have a match. Create necessary folders. ++ if (!MakeDirs(ActualNewName, false)) ++ return false; ++ // There's no guarantee that the directory of ActualNewName ++ // is on the same device as the dir that StatNearestDir found. ++ // But worst case is that the link fails. ++ } ++ ++#ifdef HARDLINK_TEST_ONLY ++ // Do the hard link to *.vdr_ for testing only ++ char *name = NULL; ++ asprintf(&name, "%s_", ActualNewName); ++ link(ActualOldName, name); ++ free(name); ++ return false; ++#endif // HARDLINK_TEST_ONLY ++ ++ // Try creating the hard link ++ if (link(ActualOldName, ActualNewName) != 0) { ++ // Failed to hard link. Maybe not allowed on file system. ++ LOG_ERROR_STR(ActualNewName); ++ isyslog("HardLinkVideoFile: failed to hard link from %s to %s", (const char*)ActualOldName, ActualNewName); ++ return false; ++ } ++ ++ if (ActualNewName != NewName) { ++ // video01 and up. Do the remaining symlink ++ if (symlink(ActualNewName, NewName) < 0) { ++ LOG_ERROR_STR(NewName); ++ return false; ++ } ++ } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(Recordings.GetByName(NewName), scMod); ++#endif /* STREAMDEVEXT */ ++ return true; ++} ++#endif /* HARDLINKCUTTER */ ++ + bool VideoFileSpaceAvailable(int SizeMB) + { + cVideoDirectory Dir; +@@ -232,6 +379,129 @@ void RemoveEmptyVideoDirectories(void) + } while (Dir.Next()); + } + ++#ifdef USE_DVLVIDPREFER ++// returns path to nVid'th video directory or NULL if not existing ++char *cVideoDirectory::GetVidPath(int nVid) ++{ ++ char *b = strdup(VideoDirectory); ++ int l = strlen(b), di, n; ++ ++ while (l-- > 0 && isdigit(b[ l ])); ++ ++ l++; ++ di = strlen(b) - l; ++ ++ // di == number of digits ++ n = atoi(&b[ l ]); ++ if (n != 0) ++ return NULL; ++ ++ // add requested number to dir name ++ sprintf(&b[ l ], "%0*d", di, nVid); ++ ++ if (DirectoryOk(b) == true) ++ return b; ++ ++ free(b); ++ return NULL; ++} ++ ++// checks if a video dir is 'valid' ++bool cVideoDirectory::IsVidDirOK(int nVid, int *freeMB) ++{ ++ char *dn; ++ int fMB; ++ ++ if (nVid >= Setup.nVidPrefer) ++ return false; ++ ++ if (Setup.VidPreferSize[ nVid ] == -1) ++ return false; ++ ++ dn = GetVidPath(nVid); ++ if (dn == NULL) ++ return false; ++ ++ fMB = FreeDiskSpaceMB(dn, NULL); ++ if (freeMB != NULL) ++ *freeMB = fMB; ++ ++ free(dn); ++ ++ if (Setup.VidPreferSize[ nVid ] >= fMB) ++ return false; ++ return true; ++} ++ ++ ++// calculates which video dir to use ++bool cVideoDirectory::GetPreferedVideoDir(void) ++{ ++ cVideoDirectory d; ++ int nDirs = 1, ++ vidUse = Setup.nVidPrefer; ++ int i, top, topFree, x; ++ ++ if (name == NULL) ++ return(false); ++ ++ // count available video dirs ++ while (d.Next() == true) ++ nDirs++; ++ ++ if (vidUse > nDirs) ++ vidUse = nDirs; ++ ++ // check for prefered video dir ++ for (i = 0, top = -1, topFree = 0; i < vidUse; i++) { ++ if (IsVidDirOK(i, &x) == true) { ++ if (top == -1) { ++ // nothing set yet, use first 'ok' dir ++ top = i; ++ topFree = x; ++ } ++ else { ++ // check if we got a higher priority ++ if (Setup.VidPreferPrio[ i ] >= Setup.VidPreferPrio[ top ]) { ++ top = i; ++ topFree = x; ++ } ++ // check if we got same priority but more space ++ else if (Setup.VidPreferPrio[ i ] == Setup.VidPreferPrio[ top ] && x >= topFree) { ++ top = i; ++ topFree = x; ++ } ++ } ++ } ++ } ++ ++ if (top == -1) { ++ isyslog("VidPrefer: no prefered video directory could be determined!"); ++ ++ // something went wrong here... ++ // let VDR determine the video directory ++ int MaxFree = FreeMB(); ++ ++ while (Next()) { ++ int Free = FreeDiskSpaceMB(Name()); ++ ++ if (Free > MaxFree) { ++ Store(); ++ MaxFree = Free; ++ } ++ } ++ } ++ else { ++ isyslog("VidPrefer: prefered video directory '%d' set.", top); ++ if (stored != NULL) ++ free(stored); ++ stored = GetVidPath(top); ++ } ++ ++ return true; ++} ++#endif /* DVLVIDPREFER */ ++ + bool IsOnVideoDirectoryFileSystem(const char *FileName) + { + cVideoDirectory Dir; +diff -ruNp vdr-1.6.0-2/videodir.h vdr-1.6.0-2-extensions/videodir.h +--- vdr-1.6.0-2/videodir.h 2008-02-16 13:53:11.000000000 +0100 ++++ vdr-1.6.0-2-extensions/videodir.h 2009-04-09 20:48:27.000000000 +0200 +@@ -14,11 +14,17 @@ + #include "tools.h" + + extern const char *VideoDirectory; ++#ifdef USE_LIVEBUFFER ++extern const char *BufferDirectory; ++#endif /* LIVEBUFFER */ + + cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags); + int CloseVideoFile(cUnbufferedFile *File); + bool RenameVideoFile(const char *OldName, const char *NewName); + bool RemoveVideoFile(const char *FileName); ++#ifdef USE_HARDLINKCUTTER ++bool HardLinkVideoFile(const char *OldName, const char *NewName); ++#endif /* HARDLINKCUTTER */ + bool VideoFileSpaceAvailable(int SizeMB); + int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent + cString PrefixVideoFileName(const char *FileName, char Prefix); diff --git a/vdr/extensions/vdr-1.7.0-ext_h264-s2ng-speedup.diff b/vdr/extensions/vdr-1.7.0-ext_h264-s2ng-speedup.diff new file mode 100644 index 0000000..b9e1beb --- /dev/null +++ b/vdr/extensions/vdr-1.7.0-ext_h264-s2ng-speedup.diff @@ -0,0 +1,5483 @@ +diff -ruNp vdr-1.7.0-extensions/channels.c vdr-1.7.0-ext-h264-s2ng-speedup/channels.c +--- vdr-1.7.0-extensions/channels.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/channels.c 2009-04-12 23:52:16.000000000 +0200 +@@ -4,7 +4,7 @@ + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * +- * $Id: channels.c 2.2 2008/04/12 13:49:12 kls Exp $ ++ * $Id: channels.c 2.5 2009/04/10 11:29:55 kls Exp $ + */ + + #include "channels.h" +@@ -24,114 +24,86 @@ + // --- Channel Parameter Maps ------------------------------------------------ + + const tChannelParameterMap InversionValues[] = { +- { 0, DVBFE_INVERSION_OFF, trNOOP("off") }, +- { 1, DVBFE_INVERSION_ON, trNOOP("on") }, +- { 999, DVBFE_INVERSION_AUTO }, ++ { 0, INVERSION_OFF, trNOOP("off") }, ++ { 1, INVERSION_ON, trNOOP("on") }, ++ { 999, INVERSION_AUTO, trNOOP("auto") }, + { -1 } + }; + + const tChannelParameterMap BandwidthValues[] = { +- { 5, DVBFE_BANDWIDTH_5_MHZ, "5 MHz" }, +- { 6, DVBFE_BANDWIDTH_6_MHZ, "6 MHz" }, +- { 7, DVBFE_BANDWIDTH_7_MHZ, "7 MHz" }, +- { 8, DVBFE_BANDWIDTH_8_MHZ, "8 MHz" }, +- { 999, DVBFE_BANDWIDTH_AUTO }, ++ { 6, 6000000, "6 MHz" }, ++ { 7, 7000000, "7 MHz" }, ++ { 8, 8000000, "8 MHz" }, + { -1 } + }; + + const tChannelParameterMap CoderateValues[] = { +- { 0, DVBFE_FEC_NONE, trNOOP("none") }, +- { 12, DVBFE_FEC_1_2, "1/2" }, +- { 13, DVBFE_FEC_1_3, "1/3" }, +- { 14, DVBFE_FEC_1_4, "1/4" }, +- { 23, DVBFE_FEC_2_3, "2/3" }, +- { 25, DVBFE_FEC_2_5, "2/5" }, +- { 34, DVBFE_FEC_3_4, "3/4" }, +- { 35, DVBFE_FEC_3_5, "3/5" }, +- { 45, DVBFE_FEC_4_5, "4/5" }, +- { 56, DVBFE_FEC_5_6, "5/6" }, +- { 67, DVBFE_FEC_6_7, "6/7" }, +- { 78, DVBFE_FEC_7_8, "7/8" }, +- { 89, DVBFE_FEC_8_9, "8/9" }, +- { 910, DVBFE_FEC_9_10, "9/10" }, +- { 999, DVBFE_FEC_AUTO }, ++ { 0, FEC_NONE, trNOOP("none") }, ++ { 12, FEC_1_2, "1/2" }, ++ { 23, FEC_2_3, "2/3" }, ++ { 34, FEC_3_4, "3/4" }, ++ { 35, FEC_3_5, "3/5" }, ++ { 45, FEC_4_5, "4/5" }, ++ { 56, FEC_5_6, "5/6" }, ++ { 67, FEC_6_7, "6/7" }, ++ { 78, FEC_7_8, "7/8" }, ++ { 89, FEC_8_9, "8/9" }, ++ { 910, FEC_9_10, "9/10" }, ++ { 999, FEC_AUTO, trNOOP("auto") }, + { -1 } + }; + + const tChannelParameterMap ModulationValues[] = { +- { 0, DVBFE_MOD_NONE, trNOOP("none") }, +- { 4, DVBFE_MOD_QAM4, "QAM4" }, +- { 16, DVBFE_MOD_QAM16, "QAM16" }, +- { 32, DVBFE_MOD_QAM32, "QAM32" }, +- { 64, DVBFE_MOD_QAM64, "QAM64" }, +- { 128, DVBFE_MOD_QAM128, "QAM128" }, +- { 256, DVBFE_MOD_QAM256, "QAM256" }, +- { 512, DVBFE_MOD_QAM512, "QAM512" }, +- {1024, DVBFE_MOD_QAM1024, "QAM1024" }, +- { 1, DVBFE_MOD_BPSK, "BPSK" }, +- { 2, DVBFE_MOD_QPSK, "QPSK" }, +- { 3, DVBFE_MOD_OQPSK, "OQPSK" }, +- { 5, DVBFE_MOD_8PSK, "8PSK" }, +- { 6, DVBFE_MOD_16APSK, "16APSK" }, +- { 7, DVBFE_MOD_32APSK, "32APSK" }, +- { 8, DVBFE_MOD_OFDM, "OFDM" }, +- { 9, DVBFE_MOD_COFDM, "COFDM" }, +- { 10, DVBFE_MOD_VSB8, "VSB8" }, +- { 11, DVBFE_MOD_VSB16, "VSB16" }, +- { 998, DVBFE_MOD_QAMAUTO, "QAMAUTO" }, +- { 999, DVBFE_MOD_AUTO }, ++ { 16, QAM_16, "QAM16" }, ++ { 32, QAM_32, "QAM32" }, ++ { 64, QAM_64, "QAM64" }, ++ { 128, QAM_128, "QAM128" }, ++ { 256, QAM_256, "QAM256" }, ++ { 2, QPSK, "QPSK" }, ++ { 5, PSK_8, "8PSK" }, ++ { 6, APSK_16, "16APSK" }, ++ { 10, VSB_8, "VSB8" }, ++ { 11, VSB_16, "VSB16" }, ++ { 998, QAM_AUTO, "QAMAUTO" }, + { -1 } + }; + + const tChannelParameterMap SystemValues[] = { +- { 0, DVBFE_DELSYS_DVBS, "DVB-S" }, +- { 1, DVBFE_DELSYS_DVBS2, "DVB-S2" }, ++ { 0, SYS_DVBS, "DVB-S" }, ++ { 1, SYS_DVBS2, "DVB-S2" }, + { -1 } + }; + + const tChannelParameterMap TransmissionValues[] = { +- { 2, DVBFE_TRANSMISSION_MODE_2K, "2K" }, +- { 4, DVBFE_TRANSMISSION_MODE_4K, "4K" }, +- { 8, DVBFE_TRANSMISSION_MODE_8K, "8K" }, +- { 999, DVBFE_TRANSMISSION_MODE_AUTO }, ++ { 2, TRANSMISSION_MODE_2K, "2K" }, ++ { 8, TRANSMISSION_MODE_8K, "8K" }, ++ { 999, TRANSMISSION_MODE_AUTO, trNOOP("auto") }, + { -1 } + }; + + const tChannelParameterMap GuardValues[] = { +- { 4, DVBFE_GUARD_INTERVAL_1_4, "1/4" }, +- { 8, DVBFE_GUARD_INTERVAL_1_8, "1/8" }, +- { 16, DVBFE_GUARD_INTERVAL_1_16, "1/16" }, +- { 32, DVBFE_GUARD_INTERVAL_1_32, "1/32" }, +- { 999, DVBFE_GUARD_INTERVAL_AUTO }, ++ { 4, GUARD_INTERVAL_1_4, "1/4" }, ++ { 8, GUARD_INTERVAL_1_8, "1/8" }, ++ { 16, GUARD_INTERVAL_1_16, "1/16" }, ++ { 32, GUARD_INTERVAL_1_32, "1/32" }, ++ { 999, GUARD_INTERVAL_AUTO, trNOOP("auto") }, + { -1 } + }; + + const tChannelParameterMap HierarchyValues[] = { +- { 0, DVBFE_HIERARCHY_OFF, trNOOP("off") }, +- { 1, DVBFE_HIERARCHY_ON, trNOOP("on") }, +- { 999, DVBFE_HIERARCHY_AUTO }, +- { -1 } +- }; +- +-const tChannelParameterMap AlphaValues[] = { +- { 0, 0 }, +- { 1, DVBFE_ALPHA_1 }, +- { 2, DVBFE_ALPHA_2 }, +- { 4, DVBFE_ALPHA_4 }, +- { -1 } +- }; +- +-const tChannelParameterMap PriorityValues[] = { +- { 0, DVBFE_STREAM_PRIORITY_HP, trNOOP("high") }, +- { 1, DVBFE_STREAM_PRIORITY_LP, trNOOP("low") }, ++ { 0, HIERARCHY_NONE, trNOOP("none") }, ++ { 1, HIERARCHY_1, "1" }, ++ { 2, HIERARCHY_2, "2" }, ++ { 4, HIERARCHY_4, "4" }, ++ { 999, HIERARCHY_AUTO, trNOOP("auto") }, + { -1 } + }; + + const tChannelParameterMap RollOffValues[] = { +- { 0, DVBFE_ROLLOFF_UNKNOWN }, +- { 20, DVBFE_ROLLOFF_20, "0.20" }, +- { 25, DVBFE_ROLLOFF_25, "0.25" }, +- { 35, DVBFE_ROLLOFF_35, "0.35" }, ++ { 0, ROLLOFF_AUTO, trNOOP("auto") }, ++ { 20, ROLLOFF_20, "0.20" }, ++ { 25, ROLLOFF_25, "0.25" }, ++ { 35, ROLLOFF_35, "0.35" }, + { -1 } + }; + +@@ -223,22 +195,20 @@ cChannel::cChannel(void) + pluginParam = strdup(""); + #endif /* PLUGINPARAM */ + memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__); +- inversion = DVBFE_INVERSION_AUTO; +- bandwidth = DVBFE_BANDWIDTH_AUTO; +- coderateH = DVBFE_FEC_AUTO; +- coderateL = DVBFE_FEC_AUTO; +- modulation = DVBFE_MOD_AUTO; +- system = DVBFE_DELSYS_DVBS; +- transmission = DVBFE_TRANSMISSION_MODE_AUTO; +- guard = DVBFE_GUARD_INTERVAL_AUTO; +- hierarchy = DVBFE_HIERARCHY_AUTO; +- alpha = 0; +- priority = DVBFE_STREAM_PRIORITY_HP; +- rollOff = DVBFE_ROLLOFF_UNKNOWN; ++ inversion = INVERSION_AUTO; ++ bandwidth = 8000000; ++ coderateH = FEC_AUTO; ++ coderateL = FEC_AUTO; ++ modulation = QPSK; ++ system = SYS_DVBS; ++ transmission = TRANSMISSION_MODE_AUTO; ++ guard = GUARD_INTERVAL_AUTO; ++ hierarchy = HIERARCHY_AUTO; ++ rollOff = ROLLOFF_AUTO; + modification = CHANNELMOD_NONE; + schedule = NULL; + linkChannels = NULL; +- refChannel = NULL; ++ refChannels = NULL; + } + + cChannel::cChannel(const cChannel &Channel) +@@ -252,28 +222,26 @@ cChannel::cChannel(const cChannel &Chann + #endif /* PLUGINPARAM */ + schedule = NULL; + linkChannels = NULL; +- refChannel = NULL; ++ refChannels = NULL; + *this = Channel; + } + + cChannel::~cChannel() + { +- delete linkChannels; +- linkChannels = NULL; // more than one channel can link to this one, so we need the following loop +- for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { +- if (Channel->linkChannels) { +- for (cLinkChannel *lc = Channel->linkChannels->First(); lc; lc = Channel->linkChannels->Next(lc)) { +- if (lc->Channel() == this) { +- Channel->linkChannels->Del(lc); +- break; +- } +- } +- if (Channel->linkChannels->Count() == 0) { +- delete Channel->linkChannels; +- Channel->linkChannels = NULL; +- } +- } +- } ++ if (linkChannels) { ++ // in all channels which we link to remove the reference to us ++ for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) ++ lc->Channel()->DelRefChannel(this); ++ delete linkChannels; ++ linkChannels = NULL; ++ } ++ if (refChannels) { ++ // in all channels which reference us remove their link to us ++ for (cLinkChannel *lc = refChannels->First(); lc; lc = refChannels->Next(lc)) ++ lc->Channel()->DelLinkChannel(this); ++ delete refChannels; ++ refChannels = NULL; ++ } + free(name); + free(shortName); + free(provider); +@@ -350,8 +318,6 @@ void cChannel::CopyTransponderData(const + transmission = Channel->transmission; + guard = Channel->guard; + hierarchy = Channel->hierarchy; +- alpha = Channel->alpha; +- priority = Channel->priority; + rollOff = Channel->rollOff; + #ifdef USE_PLUGINPARAM + if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, Channel->pluginParam); +@@ -430,9 +396,9 @@ bool cChannel::SetCableTransponderData(i + return true; + } + +-bool cChannel::SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CoderateH, int CoderateL, int Guard, int Transmission, int Alpha, int Priority) ++bool cChannel::SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CoderateH, int CoderateL, int Guard, int Transmission) + { +- if (source != Source || frequency != Frequency || bandwidth != Bandwidth || modulation != Modulation || hierarchy != Hierarchy || coderateH != CoderateH || coderateL != CoderateL || guard != Guard || transmission != Transmission || alpha != Alpha || priority != Priority) { ++ if (source != Source || frequency != Frequency || bandwidth != Bandwidth || modulation != Modulation || hierarchy != Hierarchy || coderateH != CoderateH || coderateL != CoderateL || guard != Guard || transmission != Transmission) { + cString OldTransponderData = TransponderDataToString(); + source = Source; + frequency = Frequency; +@@ -443,8 +409,6 @@ bool cChannel::SetTerrTransponderData(in + coderateL = CoderateL; + guard = Guard; + transmission = Transmission; +- alpha = Alpha; +- priority = Priority; + schedule = NULL; + if (Number()) { + dsyslog("changing transponder data of channel %d from %s to %s", Number(), *OldTransponderData, *TransponderDataToString()); +@@ -558,10 +522,10 @@ static int IntArrayToString(char *s, con + return q - s; + } + +-void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid) ++void cChannel::SetPids(int Vpid, int Ppid, int Vtype, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid) + { + int mod = CHANNELMOD_NONE; +- if (vpid != Vpid || ppid != Ppid || tpid != Tpid) ++ if (vpid != Vpid || ppid != Ppid || vtype != Vtype || tpid != Tpid) + mod |= CHANNELMOD_PIDS; + int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs) | IntArraysDiffer(spids, Spids, slangs, SLangs); + if (m & STRDIFF) +@@ -595,9 +559,10 @@ void cChannel::SetPids(int Vpid, int Ppi + q = NewSpidsBuf; + q += IntArrayToString(q, Spids, 10, SLangs); + *q = 0; +- dsyslog("changing pids of channel %d from %d+%d:%s:%s:%d to %d+%d:%s:%s:%d", Number(), vpid, ppid, OldApidsBuf, OldSpidsBuf, tpid, Vpid, Ppid, NewApidsBuf, NewSpidsBuf, Tpid); ++ dsyslog("changing pids of channel %d from %d+%d=%d:%s:%s:%d to %d+%d=%d:%s:%s:%d", Number(), vpid, ppid, vtype, OldApidsBuf, OldSpidsBuf, tpid, Vpid, Ppid, Vtype, NewApidsBuf, NewSpidsBuf, Tpid); + vpid = Vpid; + ppid = Ppid; ++ vtype = Vtype; + for (int i = 0; i < MAXAPIDS; i++) { + apids[i] = Apids[i]; + strn0cpy(alangs[i], ALangs[i], MAXLANGCODE2); +@@ -674,7 +639,7 @@ void cChannel::SetLinkChannels(cLinkChan + q += sprintf(q, "linking channel %d from", Number()); + if (linkChannels) { + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { +- lc->Channel()->SetRefChannel(NULL); ++ lc->Channel()->DelRefChannel(this); + q += sprintf(q, " %d", lc->Channel()->Number()); + } + delete linkChannels; +@@ -685,7 +650,7 @@ void cChannel::SetLinkChannels(cLinkChan + linkChannels = LinkChannels; + if (linkChannels) { + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { +- lc->Channel()->SetRefChannel(this); ++ lc->Channel()->AddRefChannel(this); + q += sprintf(q, " %d", lc->Channel()->Number()); + //dsyslog("link %4d -> %4d: %s", Number(), lc->Channel()->Number(), lc->Channel()->Name()); + } +@@ -695,9 +660,39 @@ void cChannel::SetLinkChannels(cLinkChan + dsyslog(buffer); + } + +-void cChannel::SetRefChannel(cChannel *RefChannel) ++void cChannel::AddRefChannel(cChannel *RefChannel) ++{ ++ if (!refChannels) ++ refChannels = new cLinkChannels; ++ refChannels->Add(new cLinkChannel(RefChannel)); ++} ++ ++void cChannel::DelRefChannel(cChannel *RefChannel) ++{ ++ for (cLinkChannel *lc = refChannels->First(); lc; lc = refChannels->Next(lc)) { ++ if (lc->Channel() == RefChannel) { ++ refChannels->Del(lc); ++ if (refChannels->Count() <= 0) { ++ delete refChannels; ++ refChannels = NULL; ++ } ++ return; ++ } ++ } ++} ++ ++void cChannel::DelLinkChannel(cChannel *LinkChannel) + { +- refChannel = RefChannel; ++ for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { ++ if (lc->Channel() == LinkChannel) { ++ linkChannels->Del(lc); ++ if (linkChannels->Count() <= 0) { ++ delete linkChannels; ++ linkChannels = NULL; ++ } ++ return; ++ } ++ } + } + + static int PrintParameter(char *p, char Name, int Value) +@@ -726,7 +721,6 @@ cString cChannel::ParametersToString(voi + char *q = buffer; + *q = 0; + ST(" S ") q += sprintf(q, "%c", polarization); +- ST(" T") q += PrintParameter(q, 'A', MapToUser(alpha, AlphaValues)); + ST(" T") q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues)); + ST("CST") q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues)); + ST(" T") q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues)); +@@ -734,7 +728,6 @@ cString cChannel::ParametersToString(voi + ST("CST") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues)); + ST("CST") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues)); + ST(" S ") q += PrintParameter(q, 'O', MapToUser(rollOff, RollOffValues)); +- ST(" T") q += PrintParameter(q, 'P', MapToUser(priority, PriorityValues)); + ST(" S ") q += PrintParameter(q, 'S', MapToUser(system, SystemValues)); + ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); + ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); +@@ -760,6 +753,13 @@ static const char *ParseParameter(const + return NULL; + } + ++static const char *SkipDigits(const char *s) ++{ ++ while (*++s && isdigit(*s)) ++ ; ++ return s; ++} ++ + bool cChannel::StringToParameters(const char *s) + { + #ifdef USE_PLUGINPARAM +@@ -768,7 +768,7 @@ bool cChannel::StringToParameters(const + while (s && *s) { + #endif /* PLUGINPARAM */ + switch (toupper(*s)) { +- case 'A': s = ParseParameter(s, alpha, AlphaValues); break; ++ case 'A': s = SkipDigits(s); break; // for compatibility with the "multiproto" approach - may be removed in future versions + case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; + case 'C': s = ParseParameter(s, coderateH, CoderateValues); break; + case 'D': s = ParseParameter(s, coderateL, CoderateValues); break; +@@ -777,14 +777,14 @@ bool cChannel::StringToParameters(const + case 'I': s = ParseParameter(s, inversion, InversionValues); break; + case 'L': polarization = *s++; break; + case 'M': s = ParseParameter(s, modulation, ModulationValues); break; +- case 'Z':// for compatibility with the original DVB-S2 patch - may be removed in future versions + case 'O': s = ParseParameter(s, rollOff, RollOffValues); break; +- case 'P': s = ParseParameter(s, priority, PriorityValues); break; ++ case 'P': s = SkipDigits(s); break; // for compatibility with the "multiproto" approach - may be removed in future versions + case 'R': polarization = *s++; break; + case 'S': s = ParseParameter(s, system, SystemValues); break; + case 'T': s = ParseParameter(s, transmission, TransmissionValues); break; + case 'V': polarization = *s++; break; + case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break; ++ case 'Z': s = SkipDigits(s); break; // for compatibility with the original DVB-S2 patch - may be removed in future versions + default: esyslog("ERROR: unknown parameter key '%c'", *s); + return false; + } +@@ -816,6 +816,8 @@ cString cChannel::ToText(const cChannel + q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid); + if (Channel->ppid && Channel->ppid != Channel->vpid) + q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid); ++ if (Channel->vpid && Channel->vtype) ++ q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "=%d", Channel->vtype); + *q = 0; + const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia + char apidbuf[BufferSize]; +@@ -877,6 +879,7 @@ bool cChannel::Parse(const char *s) + tpid = 0; + } + vpid = ppid = 0; ++ vtype = 2; // default is MPEG-2 + apids[0] = 0; + dpids[0] = 0; + ok = false; +@@ -887,16 +890,20 @@ bool cChannel::Parse(const char *s) + ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; + #endif /* PLUGINPARAM */ + +- char *p = strchr(vpidbuf, '+'); +- if (p) ++ char *p; ++ if ((p = strchr(vpidbuf, '=')) != NULL) { ++ *p++ = 0; ++ if (sscanf(p, "%d", &vtype) != 1) ++ return false; ++ } ++ if ((p = strchr(vpidbuf, '+')) != NULL) { + *p++ = 0; +- if (sscanf(vpidbuf, "%d", &vpid) != 1) +- return false; +- if (p) { + if (sscanf(p, "%d", &ppid) != 1) + return false; + } +- else ++ if (sscanf(vpidbuf, "%d", &vpid) != 1) ++ return false; ++ if (!ppid) + ppid = vpid; + + char *dpidbuf = strchr(apidbuf, ';'); +@@ -1057,14 +1064,72 @@ bool cChannels::Load(const char *FileNam + return false; + } + ++void cChannels::ClearChannelHashes(void) ++{ ++ channelsHashSid.Clear(); ++ channelsHashNidTid.Clear(); ++} ++ + void cChannels::HashChannel(cChannel *Channel) + { + channelsHashSid.Add(Channel, Channel->Sid()); ++ channelsHashNidTid.Add(Channel, HashKeyNidTid(Channel->Nid(), Channel->Tid())); + } + + void cChannels::UnhashChannel(cChannel *Channel) + { + channelsHashSid.Del(Channel, Channel->Sid()); ++ channelsHashNidTid.Del(Channel, HashKeyNidTid(Channel->Nid(), Channel->Tid())); ++} ++ ++unsigned int cChannels::HashKeyNidTid(unsigned short Nid, unsigned short Tid) ++{ ++ return Nid << 16 | Tid; ++} ++ ++cIterator<cChannel> cChannels::GetChannelsBySourceNidTid(int Source, unsigned short Nid, unsigned short Tid) ++{ ++ class cIteratorImplSourceNidTid : public cIteratorImpl { ++ private: ++ cList<cHashObject> *hashList; ++ cHashObject *current; ++ int source; ++ unsigned short nid; ++ unsigned short tid; ++ cChannel *FindMatchingChannel(bool reverse, bool reset = false) { ++ if (!hashList || (!current && !reset)) ++ return NULL; ++ while (true) { ++ if (reset) { ++ reset = false; ++ current = reverse ? hashList->Last() : hashList->First(); ++ } ++ else ++ current = reverse ? hashList->Prev(current) : hashList->Next(current); ++ if (!current) ++ break; ++ cChannel *Channel = (cChannel *)current->Object(); ++ if (Channel->Source() == source && Channel->Nid() == nid && Channel->Tid() == tid) ++ return Channel; ++ } ++ return NULL; ++ } ++ public: ++ cIteratorImplSourceNidTid(cList<cHashObject> *HashList, int Source, unsigned short Nid, unsigned short Tid) { ++ hashList = HashList; ++ source = Source; ++ nid = Nid; ++ tid = Tid; ++ current = NULL; ++ } ++ virtual void *First(void) { return FindMatchingChannel(false, true); } ++ virtual void *Last(void) { return FindMatchingChannel(true, true); } ++ virtual void *Prev(void) { return FindMatchingChannel(true); } ++ virtual void *Next(void) { return FindMatchingChannel(false); } ++ virtual void *Current(void) const { return current ? (cChannel *)current->Object() : NULL; } ++ }; ++ ++ return cIterator<cChannel>(new cIteratorImplSourceNidTid(channelsHashNidTid.GetList(HashKeyNidTid(Nid, Tid)), Source, Nid, Tid)); + } + + int cChannels::GetNextGroup(int Idx) +@@ -1101,7 +1166,7 @@ int cChannels::GetPrevNormal(int Idx) + + void cChannels::ReNumber(void) + { +- channelsHashSid.Clear(); ++ ClearChannelHashes(); + maxNumber = 0; + int Number = 1; + for (cChannel *channel = First(); channel; channel = Next(channel)) { +diff -ruNp vdr-1.7.0-extensions/channels.h vdr-1.7.0-ext-h264-s2ng-speedup/channels.h +--- vdr-1.7.0-extensions/channels.h 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/channels.h 2009-04-12 23:52:16.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.2 2008/04/12 13:46:50 kls Exp $ ++ * $Id: channels.h 2.4 2008/11/22 13:35:52 kls Exp $ + */ + + #ifndef __CHANNELS_H +@@ -66,8 +66,6 @@ extern const tChannelParameterMap System + extern const tChannelParameterMap TransmissionValues[]; + extern const tChannelParameterMap GuardValues[]; + extern const tChannelParameterMap HierarchyValues[]; +-extern const tChannelParameterMap AlphaValues[]; +-extern const tChannelParameterMap PriorityValues[]; + extern const tChannelParameterMap RollOffValues[]; + + struct tChannelID { +@@ -127,6 +125,7 @@ private: + int srate; + int vpid; + int ppid; ++ int vtype; + int apids[MAXAPIDS + 1]; // list is zero-terminated + char alangs[MAXAPIDS][MAXLANGCODE2]; + int dpids[MAXDPIDS + 1]; // list is zero-terminated +@@ -151,17 +150,18 @@ private: + int transmission; + int guard; + int hierarchy; +- int alpha; +- int priority; + int rollOff; + int __EndData__; + int modification; + mutable const cSchedule *schedule; + cLinkChannels *linkChannels; +- cChannel *refChannel; ++ cLinkChannels *refChannels; + cString TransponderDataToString(void) const; + cString ParametersToString(void) const; + bool StringToParameters(const char *s); ++ void AddRefChannel(cChannel *RefChannel); ++ void DelRefChannel(cChannel *RefChannel); ++ void DelLinkChannel(cChannel *RefChannel); + public: + cChannel(void); + cChannel(const cChannel &Channel); +@@ -184,6 +184,7 @@ public: + int Srate(void) const { return srate; } + int Vpid(void) const { return vpid; } + int Ppid(void) const { return ppid; } ++ int Vtype(void) const { return vtype; } + const int *Apids(void) const { return apids; } + const int *Dpids(void) const { return dpids; } + const int *Spids(void) const { return spids; } +@@ -213,11 +214,10 @@ public: + int Transmission(void) const { return transmission; } + int Guard(void) const { return guard; } + int Hierarchy(void) const { return hierarchy; } +- int Alpha(void) const { return alpha; } +- int Priority(void) const { return priority; } + int RollOff(void) const { return rollOff; } + const cLinkChannels* LinkChannels(void) const { return linkChannels; } +- const cChannel *RefChannel(void) const { return refChannel; } ++ const cChannel *RefChannel(void) const { return refChannels ? refChannels->Last()->Channel() : 0; } ++ const cLinkChannels* RefChannels(void) const { return refChannels; } + #ifdef USE_PLUGINPARAM + bool IsPlug(void) const { return cSource::IsPlug(source); } + #endif /* PLUGINPARAM */ +@@ -233,18 +233,50 @@ public: + #endif /* PLUGINPARAM */ + bool SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH, int Modulation, int System, int RollOff); + bool SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH); +- bool SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CodeRateH, int CodeRateL, int Guard, int Transmission, int Alpha, int Priority); ++ bool SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CodeRateH, int CodeRateL, int Guard, int Transmission); + void SetId(int Nid, int Tid, int Sid, int Rid = 0); + void SetName(const char *Name, const char *ShortName, const char *Provider); + void SetPortalName(const char *PortalName); + #ifdef USE_PLUGINPARAM + void SetPluginParam(const char *PluginParam); + #endif /* PLUGINPARAM */ +- void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid); ++ void SetPids(int Vpid, int Ppid, int Vtype, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid); + void SetCaIds(const int *CaIds); // list must be zero-terminated + void SetCaDescriptors(int Level); + void SetLinkChannels(cLinkChannels *LinkChannels); +- void SetRefChannel(cChannel *RefChannel); ++ }; ++ ++class cIteratorImpl { ++private: ++ int refCount; ++ cIteratorImpl(const cIteratorImpl &); ++ const cIteratorImpl &operator =(const cIteratorImpl &); ++public: ++ cIteratorImpl(void) { refCount = 0; } ++ virtual ~cIteratorImpl() {} ++ virtual int AddRef(void) { return ++refCount; } ++ virtual int DelRef(void) { int RefCount = --refCount; if (RefCount <= 0) delete this; return RefCount; } ++ virtual void *First(void) = 0; ++ virtual void *Last(void) = 0; ++ virtual void *Prev(void) = 0; ++ virtual void *Next(void) = 0; ++ virtual void *Current(void) const = 0; ++ }; ++ ++template <class T> class cIterator ++{ ++private: ++ cIteratorImpl *impl; ++public: ++ cIterator(cIteratorImpl *Impl) { impl = Impl; impl->AddRef(); } ++ cIterator(const cIterator &rhs) { impl = rhs.impl; impl->AddRef(); } ++ ~cIterator() { impl->DelRef(); } ++ const cIterator &operator =(const cIterator &rhs) { rhs.impl->AddRef(); impl->DelRef(); impl = rhs.impl; return *this; } ++ T *First(void) const { return (T *)impl->First(); } ++ T *Last(void) const { return (T *)impl->Last(); } ++ T *Prev(void) const { return (T *)impl->Prev(); } ++ T *Next(void) const { return (T *)impl->Next(); } ++ T *Current(void) const { return (T *)impl->Current(); } + }; + + class cChannels : public cRwLock, public cConfig<cChannel> { +@@ -253,7 +285,10 @@ private: + int modified; + int beingEdited; + cHash<cChannel> channelsHashSid; ++ cHash<cChannel> channelsHashNidTid; + void DeleteDuplicateChannels(void); ++ void ClearChannelHashes(void); ++ static unsigned int HashKeyNidTid(unsigned short Nid, unsigned short Tid); + public: + cChannels(void); + bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false); +@@ -268,6 +303,7 @@ public: + cChannel *GetByServiceID(int Source, int Transponder, unsigned short ServiceID); + cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false, bool TryWithoutPolarization = false); + cChannel *GetByTransponderID(tChannelID ChannelID); ++ cIterator<cChannel> GetChannelsBySourceNidTid(int Source, unsigned short Nid, unsigned short Tid); + int BeingEdited(void) { return beingEdited; } + void IncBeingEdited(void) { beingEdited++; } + void DecBeingEdited(void) { beingEdited--; } +diff -ruNp vdr-1.7.0-extensions/config.c vdr-1.7.0-ext-h264-s2ng-speedup/config.c +--- vdr-1.7.0-extensions/config.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/config.c 2009-04-12 23:57:23.000000000 +0200 +@@ -326,9 +326,6 @@ cSetup::cSetup(void) + ChannelBlockerMode = 0; + ChannelBlockerList = strdup(""); + #endif /* DVBSETUP */ +-#ifdef USE_SYNCEARLY +- UseSyncEarlyPatch = 0; +-#endif /* SYNCEARLY */ + ChannelInfoPos = 0; + ChannelInfoTime = 5; + OSDLeft = 54; +@@ -393,9 +390,12 @@ cSetup::cSetup(void) + noEPGList = strdup(""); + #endif /* NOEPG */ + #ifdef USE_LIRCSETTINGS ++ LircPushFreq = 3; + LircRepeatDelay = 350; +- LircRepeatFreq = 100; ++ LircRepeatFreq = 10; + LircRepeatTimeout = 500; ++ LircReconnectDelay = 3000; ++ LircPriorityBoost = 0; + #endif /* LIRCSETTINGS */ + #ifdef USE_LIEMIEXT + ShowRecDate = 1; +@@ -684,9 +684,6 @@ bool cSetup::Parse(const char *Name, con + ChannelBlockerList = strdup(Value ? Value : ""); + } + #endif /* DVBSETUP */ +-#ifdef USE_SYNCEARLY +- else if (!strcasecmp(Name, "UseSyncEarlyPatch")) UseSyncEarlyPatch = atoi(Value); +-#endif /* SYNCEARLY */ + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoTime")) ChannelInfoTime = atoi(Value); + else if (!strcasecmp(Name, "OSDLeft")) OSDLeft = atoi(Value); +@@ -753,9 +750,12 @@ bool cSetup::Parse(const char *Name, con + } + #endif /* NOEPG */ + #ifdef USE_LIRCSETTINGS ++ else if (!strcasecmp(Name, "LircPushFreq")) LircPushFreq = atoi(Value); + else if (!strcasecmp(Name, "LircRepeatDelay")) LircRepeatDelay = atoi(Value); + else if (!strcasecmp(Name, "LircRepeatFreq")) LircRepeatFreq = atoi(Value); + else if (!strcasecmp(Name, "LircRepeatTimeout")) LircRepeatTimeout = atoi(Value); ++ else if (!strcasecmp(Name, "LircReconnectDelay")) LircReconnectDelay = atoi(Value); ++ else if (!strcasecmp(Name, "LircPriorityBoost")) LircPriorityBoost = atoi(Value); + #endif /* LIRCSETTINGS */ + #ifdef USE_LIEMIEXT + else if (!strcasecmp(Name, "ShowRecDate")) ShowRecDate = atoi(Value); +@@ -916,9 +916,6 @@ bool cSetup::Save(void) + Store("ChannelBlockerMode", ChannelBlockerMode); + Store("ChannelBlockerList", ChannelBlockerList); + #endif /* DVBSETUP */ +-#ifdef USE_SYNCEARLY +- Store("UseSyncEarlyPatch", UseSyncEarlyPatch); +-#endif /* SYNCEARLY */ + Store("ChannelInfoPos", ChannelInfoPos); + Store("ChannelInfoTime", ChannelInfoTime); + Store("OSDLeft", OSDLeft); +@@ -982,9 +979,12 @@ bool cSetup::Save(void) + Store("noEPGList", noEPGList); + #endif /* NOEPG */ + #ifdef USE_LIRCSETTINGS ++ Store("LircPushFreq", LircPushFreq); + Store("LircRepeatDelay", LircRepeatDelay); + Store("LircRepeatFreq", LircRepeatFreq); + Store("LircRepeatTimeout", LircRepeatTimeout); ++ Store("LircReconnectDelay", LircReconnectDelay); ++ Store("LircPriorityBoost", LircPriorityBoost); + #endif /* LIRCSETTINGS */ + #ifdef USE_LIEMIEXT + Store("ShowRecDate", ShowRecDate); +diff -ruNp vdr-1.7.0-extensions/config.h vdr-1.7.0-ext-h264-s2ng-speedup/config.h +--- vdr-1.7.0-extensions/config.h 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/config.h 2009-04-12 23:57:23.000000000 +0200 +@@ -336,9 +336,6 @@ public: + int ChannelBlocker; + int ChannelBlockerMode; + #endif /* DVBSETUP */ +-#ifdef USE_SYNCEARLY +- int UseSyncEarlyPatch; +-#endif /* SYNCEARLY */ + int ChannelInfoPos; + int ChannelInfoTime; + int OSDLeft, OSDTop, OSDWidth, OSDHeight; +@@ -398,9 +395,12 @@ public: + int noEPGMode; + #endif /* NOEPG */ + #ifdef USE_LIRCSETTINGS ++ int LircPushFreq; + int LircRepeatDelay; + int LircRepeatFreq; + int LircRepeatTimeout; ++ int LircReconnectDelay; ++ int LircPriorityBoost; + #endif /* LIRCSETTINGS */ + #ifdef USE_LIEMIEXT + int ShowRecDate, ShowRecTime, ShowRecLength, ShowProgressBar, MenuCmdPosition; +diff -ruNp vdr-1.7.0-extensions/device.c vdr-1.7.0-ext-h264-s2ng-speedup/device.c +--- vdr-1.7.0-extensions/device.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/device.c 2009-04-12 23:57:23.000000000 +0200 +@@ -1110,11 +1110,7 @@ eSetChannelResult cDevice::SetChannel(co + } + for (int i = 0; i < MAXSPIDS; i++) + SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i)); +-#ifdef USE_SYNCEARLY +- if ((Setup.UseSyncEarlyPatch && (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone)) || (!Setup.UseSyncEarlyPatch && !NeedsTransferMode)) +-#else +- if (!NeedsTransferMode) +-#endif /* SYNCEARLY */ ++ if (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone) + EnsureAudioTrack(true); + EnsureSubtitleTrack(); + } +diff -ruNp vdr-1.7.0-extensions/dvbdevice.c vdr-1.7.0-ext-h264-s2ng-speedup/dvbdevice.c +--- vdr-1.7.0-extensions/dvbdevice.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/dvbdevice.c 2009-04-13 12:28:52.000000000 +0200 +@@ -4,13 +4,13 @@ + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * +- * $Id: dvbdevice.c 2.2 2008/04/13 14:15:35 kls Exp $ ++ * $Id: dvbdevice.c 2.14 2009/04/10 09:54:24 kls Exp $ + */ + + #include "dvbdevice.h" + #include <errno.h> + #include <limits.h> +-#include <linux/videodev.h> ++#include <linux/videodev2.h> + #include <linux/dvb/audio.h> + #include <linux/dvb/dmx.h> + #include <linux/dvb/frontend.h> +@@ -79,7 +79,7 @@ private: + int tuneTimeout; + int lockTimeout; + time_t lastTimeoutReport; +- dvbfe_delsys frontendType; ++ fe_delivery_system frontendType; + cChannel channel; + const char *diseqcCommands; + eTunerStatus tunerStatus; +@@ -93,7 +93,7 @@ private: + bool SetFrontend(void); + virtual void Action(void); + public: +- cDvbTuner(int Fd_Frontend, int CardIndex, dvbfe_delsys FrontendType); ++ cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType); + virtual ~cDvbTuner(); + bool IsTunedTo(const cChannel *Channel) const; + void Set(const cChannel *Channel, bool Tune); +@@ -103,7 +103,7 @@ public: + bool Locked(int TimeoutMs = 0); + }; + +-cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, dvbfe_delsys FrontendType) ++cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType) + { + fd_frontend = Fd_Frontend; + #ifdef USE_ROTOR +@@ -116,7 +116,7 @@ cDvbTuner::cDvbTuner(int Fd_Frontend, in + lastTimeoutReport = 0; + diseqcCommands = NULL; + tunerStatus = tsIdle; +- if (frontendType & (DVBFE_DELSYS_DVBS | DVBFE_DELSYS_DVBS2)) ++ if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power + SetDescription("tuner on device %d", cardIndex + 1); + Start(); +@@ -139,7 +139,6 @@ bool cDvbTuner::IsTunedTo(const cChannel + char Type = **cSource::ToString(Channel->Source()); + #define ST(s, p) if (strchr(s, Type)) if (channel.p() != Channel->p()) return false; + // Polarization is already checked as part of the Transponder. +- ST(" T", Alpha); + ST(" T", Bandwidth); + ST("CST", CoderateH); + ST(" T", CoderateL); +@@ -147,8 +146,8 @@ bool cDvbTuner::IsTunedTo(const cChannel + ST("CST", Inversion); + ST("CST", Modulation); + ST(" S ", RollOff); +- ST(" T", Priority); + ST(" S ", System); ++ ST("CS ", Srate); + ST(" T", Transmission); + ST(" T", Hierarchy); + return true; +@@ -180,7 +179,7 @@ bool cDvbTuner::Locked(int TimeoutMs) + bool cDvbTuner::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) + { + cMutexLock MutexLock(&mutex); +- if ((!DVBFE_DELSYS_DVBS & !DVBFE_DELSYS_DVBS2) || SendDiseqc) ++ if ((!SYS_DVBS & !SYS_DVBS2) || SendDiseqc) + return false; + diseqc_cmd = cmd; + SendDiseqc = true; +@@ -217,10 +216,27 @@ static unsigned int FrequencyToHz(unsign + + bool cDvbTuner::SetFrontend(void) + { +- dvbfe_params Frontend; ++#define MAXFRONTENDCMDS 16 ++#define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\ ++ Frontend[CmdSeq.num].u.data = (d);\ ++ if (CmdSeq.num++ > MAXFRONTENDCMDS) {\ ++ esyslog("ERROR: too many tuning commands on frontend %d", cardIndex);\ ++ return false;\ ++ }\ ++ } ++ dtv_property Frontend[MAXFRONTENDCMDS]; + memset(&Frontend, 0, sizeof(Frontend)); ++ dtv_properties CmdSeq; ++ memset(&CmdSeq, 0, sizeof(CmdSeq)); ++ CmdSeq.props = Frontend; ++ SETCMD(DTV_CLEAR, 0); ++ if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { ++ esyslog("ERROR: frontend %d: %m", cardIndex); ++ return false; ++ } ++ CmdSeq.num = 0; + +- if (frontendType & (DVBFE_DELSYS_DVBS | DVBFE_DELSYS_DVBS2)) { ++ if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) { + unsigned int frequency = channel.Frequency(); + if (Setup.DiSEqC) { + cDiseqc *diseqc = Diseqcs.Get(channel.Source(), channel.Frequency(), channel.Polarization()); +@@ -277,85 +293,78 @@ bool cDvbTuner::SetFrontend(void) + } + frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF + +- Frontend.delivery = dvbfe_delsys(channel.System()); +- Frontend.frequency = frequency * 1000UL; +- Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); +- if (Frontend.delivery == DVBFE_DELSYS_DVBS) { +- Frontend.delsys.dvbs.modulation = dvbfe_modulation(channel.Modulation()); +- Frontend.delsys.dvbs.symbol_rate = channel.Srate() * 1000UL; +- Frontend.delsys.dvbs.fec = dvbfe_fec(channel.CoderateH()); ++ // DVB-S/DVB-S2 (common parts) ++ SETCMD(DTV_DELIVERY_SYSTEM, channel.System()); ++ SETCMD(DTV_FREQUENCY, frequency * 1000UL); ++ SETCMD(DTV_MODULATION, channel.Modulation()); ++ SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL); ++ SETCMD(DTV_INNER_FEC, channel.CoderateH()); ++ SETCMD(DTV_INVERSION, channel.Inversion()); ++ if (channel.System() == SYS_DVBS2) { ++ if (frontendType == SYS_DVBS2) { ++ // DVB-S2 ++ SETCMD(DTV_PILOT, PILOT_AUTO); ++ SETCMD(DTV_ROLLOFF, channel.RollOff()); ++ } ++ else { ++ esyslog("ERROR: frontend %d doesn't provide DVB-S2", cardIndex); ++ return false; ++ } + } + else { +- Frontend.delsys.dvbs2.modulation = dvbfe_modulation(channel.Modulation()); +- Frontend.delsys.dvbs2.symbol_rate = channel.Srate() * 1000UL; +- Frontend.delsys.dvbs2.fec = dvbfe_fec(channel.CoderateH()); +- Frontend.delsys.dvbs2.rolloff = dvbfe_rolloff(channel.RollOff()); ++ // DVB-S ++ SETCMD(DTV_ROLLOFF, ROLLOFF_35); // DVB-S always has a ROLLOFF of 0.35 + } + + tuneTimeout = DVBS_TUNE_TIMEOUT; + lockTimeout = DVBS_LOCK_TIMEOUT; +- +- dvbfe_info feinfo; +- feinfo.delivery = Frontend.delivery; +- CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system +- } +- else if (frontendType & DVBFE_DELSYS_DVBC) { +- Frontend.delivery = DVBFE_DELSYS_DVBC; +- Frontend.frequency = FrequencyToHz(channel.Frequency()); +- Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); +- Frontend.delsys.dvbc.symbol_rate = channel.Srate() * 1000UL; +- Frontend.delsys.dvbc.fec = dvbfe_fec(channel.CoderateH()); +- Frontend.delsys.dvbc.modulation = dvbfe_modulation(channel.Modulation()); ++ } ++ else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) { ++ // DVB-C ++ SETCMD(DTV_DELIVERY_SYSTEM, frontendType); ++ SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())); ++ SETCMD(DTV_INVERSION, channel.Inversion()); ++ SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL); ++ SETCMD(DTV_INNER_FEC, channel.CoderateH()); ++ SETCMD(DTV_MODULATION, channel.Modulation()); + + tuneTimeout = DVBC_TUNE_TIMEOUT; + lockTimeout = DVBC_LOCK_TIMEOUT; +- +- dvbfe_info feinfo; +- feinfo.delivery = Frontend.delivery; +- CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system + } + #ifdef USE_ATSC +- else if (frontendType & DVBFE_DELSYS_ATSC) { +- // Frequency and symbol rate: ++ else if (frontendType == SYS_ATSC) { ++ // ATSC ++ SETCMD(DTV_DELIVERY_SYSTEM, frontendType); ++ SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())); ++ SETCMD(DTV_INVERSION, channel.Inversion()); ++ SETCMD(DTV_MODULATION, channel.Modulation()); + +- Frontend.frequency = FrequencyToHz(channel.Frequency()); +- Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); +- Frontend.delsys.atsc.modulation = dvbfe_modulation(channel.Modulation()); +- +- tuneTimeout = DVBC_TUNE_TIMEOUT; +- lockTimeout = DVBC_LOCK_TIMEOUT; +- +- dvbfe_info feinfo; +- feinfo.delivery = Frontend.delivery; +- CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system ++ tuneTimeout = DVBT_TUNE_TIMEOUT; ++ lockTimeout = DVBT_LOCK_TIMEOUT; + } + #endif /* ATSC */ +- else if (frontendType & DVBFE_DELSYS_DVBT) { +- Frontend.delivery = DVBFE_DELSYS_DVBT; +- Frontend.frequency = FrequencyToHz(channel.Frequency()); +- Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); +- Frontend.delsys.dvbt.bandwidth = dvbfe_bandwidth(channel.Bandwidth()); +- Frontend.delsys.dvbt.code_rate_HP = dvbfe_fec(channel.CoderateH()); +- Frontend.delsys.dvbt.code_rate_LP = dvbfe_fec(channel.CoderateL()); +- Frontend.delsys.dvbt.constellation = dvbfe_modulation(channel.Modulation()); +- Frontend.delsys.dvbt.transmission_mode = dvbfe_transmission_mode(channel.Transmission()); +- Frontend.delsys.dvbt.guard_interval = dvbfe_guard_interval(channel.Guard()); +- Frontend.delsys.dvbt.hierarchy = dvbfe_hierarchy(channel.Hierarchy()); +- Frontend.delsys.dvbt.alpha = dvbfe_alpha(channel.Alpha()); +- Frontend.delsys.dvbt.priority = dvbfe_stream_priority(channel.Priority()); ++ else if (frontendType == SYS_DVBT) { ++ // DVB-T ++ SETCMD(DTV_DELIVERY_SYSTEM, frontendType); ++ SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())); ++ SETCMD(DTV_INVERSION, channel.Inversion()); ++ SETCMD(DTV_BANDWIDTH_HZ, channel.Bandwidth()); ++ SETCMD(DTV_CODE_RATE_HP, channel.CoderateH()); ++ SETCMD(DTV_CODE_RATE_LP, channel.CoderateL()); ++ SETCMD(DTV_MODULATION, channel.Modulation()); ++ SETCMD(DTV_TRANSMISSION_MODE, channel.Transmission()); ++ SETCMD(DTV_GUARD_INTERVAL, channel.Guard()); ++ SETCMD(DTV_HIERARCHY, channel.Hierarchy()); + + tuneTimeout = DVBT_TUNE_TIMEOUT; + lockTimeout = DVBT_LOCK_TIMEOUT; +- +- dvbfe_info feinfo; +- feinfo.delivery = Frontend.delivery; +- CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system + } + else { + esyslog("ERROR: attempt to set channel with unknown DVB frontend type"); + return false; + } +- if (ioctl(fd_frontend, DVBFE_SET_PARAMS, &Frontend) < 0) { ++ SETCMD(DTV_TUNE, 0); ++ if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { + esyslog("ERROR: frontend %d: %m", cardIndex); + return false; + } +@@ -433,13 +442,22 @@ int cDvbDevice::devVideoOffset = -1; + int cDvbDevice::setTransferModeForDolbyDigital = 1; + + const char *DeliverySystems[] = { +- "DVBS", ++ "UNDEFINED", ++ "DVB-C", ++ "DVB-C", ++ "DVB-T", + "DSS", +- "DVBS2", +- "DVBC", +- "DVBT", +- "DVBH", ++ "DVB-S", ++ "DVB-S2", ++ "DVB-H", ++ "ISDBT", ++ "ISDBS", ++ "ISDBC", + "ATSC", ++ "ATSCMH", ++ "DMBTH", ++ "CMMB", ++ "DAB", + NULL + }; + +@@ -447,7 +465,7 @@ cDvbDevice::cDvbDevice(int n) + { + ciAdapter = NULL; + dvbTuner = NULL; +- frontendType = DVBFE_DELSYS_DUMMY; ++ frontendType = SYS_UNDEFINED; + numProvidedSystems = 0; + spuDecoder = NULL; + digitalAudio = false; +@@ -510,30 +528,29 @@ cDvbDevice::cDvbDevice(int n) + // We only check the devices that must be present - the others will be checked before accessing them://XXX + + if (fd_frontend >= 0) { +- if (ioctl(fd_frontend, DVBFE_GET_DELSYS, &frontendType) >= 0) { +- const char **DeliverySystem = DeliverySystems; +- cString ds; ++ if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) >= 0) { + #ifdef USE_DVBSETUP + if (Setup.ChannelBlockerMode == 4) +- frontendType = n == Setup.PrimaryDVB - 1 ? DVBFE_DELSYS_DUMMY : frontendType; ++ frontendType = (n == Setup.PrimaryDVB - 1) ? SYS_UNDEFINED : frontendType; ++ else + #endif /* DVBSETUP */ +- for (int i = 0; i < 32; i++) { +- if (frontendType & (1u << i)) { +- numProvidedSystems++; +- if (*DeliverySystem) +- ds = cString::sprintf("%s %s", *ds ? *ds : "", *DeliverySystem); +- else +- esyslog("ERROR: unknown delivery system %d", i); +- } +- if (*DeliverySystem) +- DeliverySystem++; +- } +- if (*ds) +- isyslog("device %d provides:%s", CardIndex() + 1, *ds); +- dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType); ++ switch (frontendInfo.type) { ++ case FE_QPSK: frontendType = (frontendInfo.caps & FE_CAN_2G_MODULATION) ? SYS_DVBS2 : SYS_DVBS; break; ++ case FE_OFDM: frontendType = SYS_DVBT; break; ++ case FE_QAM: frontendType = SYS_DVBC_ANNEX_AC; break; ++ case FE_ATSC: frontendType = SYS_ATSC; break; ++ default: esyslog("ERROR: unknown frontend type %d on device %d", frontendInfo.type, CardIndex() + 1); ++ } + } + else + LOG_ERROR; ++ if (frontendType != SYS_UNDEFINED) { ++ numProvidedSystems++; ++ if (frontendType == SYS_DVBS2) ++ numProvidedSystems++; ++ isyslog("device %d provides %s (\"%s\")", CardIndex() + 1, DeliverySystems[frontendType], frontendInfo.name); ++ dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType); ++ } + } + else + esyslog("ERROR: can't open DVB device %d", n); +@@ -631,69 +648,103 @@ uchar *cDvbDevice::GrabImage(int &Size, + int videoDev = open(buffer, O_RDWR); + if (videoDev >= 0) { + uchar *result = NULL; +- struct video_mbuf mbuf; +- if (ioctl(videoDev, VIDIOCGMBUF, &mbuf) == 0) { +- int msize = mbuf.size; +- unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); +- if (mem && mem != (unsigned char *)-1) { +- // set up the size and RGB +- struct video_capability vc; +- if (ioctl(videoDev, VIDIOCGCAP, &vc) == 0) { +- struct video_mmap vm; +- vm.frame = 0; +- if ((SizeX > 0) && (SizeX <= vc.maxwidth) && +- (SizeY > 0) && (SizeY <= vc.maxheight)) { +- vm.width = SizeX; +- vm.height = SizeY; +- } +- else { +- vm.width = vc.maxwidth; +- vm.height = vc.maxheight; +- } +- vm.format = VIDEO_PALETTE_RGB24; +- if (ioctl(videoDev, VIDIOCMCAPTURE, &vm) == 0 && ioctl(videoDev, VIDIOCSYNC, &vm.frame) == 0) { +- // make RGB out of BGR: +- int memsize = vm.width * vm.height; +- unsigned char *mem1 = mem; +- for (int i = 0; i < memsize; i++) { +- unsigned char tmp = mem1[2]; +- mem1[2] = mem1[0]; +- mem1[0] = tmp; +- mem1 += 3; +- } +- +- if (Quality < 0) +- Quality = 100; +- +- dsyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); +- if (Jpeg) { +- // convert to JPEG: +- result = RgbToJpeg(mem, vm.width, vm.height, Size, Quality); +- if (!result) +- esyslog("ERROR: failed to convert image to JPEG"); +- } +- else { +- // convert to PNM: +- char buf[32]; +- snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", vm.width, vm.height); +- int l = strlen(buf); +- int bytes = memsize * 3; +- Size = l + bytes; +- result = MALLOC(uchar, Size); +- if (result) { +- memcpy(result, buf, l); +- memcpy(result + l, mem, bytes); ++ // set up the size and RGB ++ v4l2_format fmt; ++ memset(&fmt, 0, sizeof(fmt)); ++ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ fmt.fmt.pix.width = SizeX; ++ fmt.fmt.pix.height = SizeY; ++ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; ++ fmt.fmt.pix.field = V4L2_FIELD_ANY; ++ if (ioctl(videoDev, VIDIOC_S_FMT, &fmt) == 0) { ++ v4l2_requestbuffers reqBuf; ++ memset(&reqBuf, 0, sizeof(reqBuf)); ++ reqBuf.count = 2; ++ reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ reqBuf.memory = V4L2_MEMORY_MMAP; ++ if (ioctl(videoDev, VIDIOC_REQBUFS, &reqBuf) >= 0) { ++ v4l2_buffer mbuf; ++ memset(&mbuf, 0, sizeof(mbuf)); ++ mbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ mbuf.memory = V4L2_MEMORY_MMAP; ++ if (ioctl(videoDev, VIDIOC_QUERYBUF, &mbuf) == 0) { ++ int msize = mbuf.length; ++ unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); ++ if (mem && mem != (unsigned char *)-1) { ++ v4l2_buffer buf; ++ memset(&buf, 0, sizeof(buf)); ++ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ buf.memory = V4L2_MEMORY_MMAP; ++ buf.index = 0; ++ if (ioctl(videoDev, VIDIOC_QBUF, &buf) == 0) { ++ v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ if (ioctl (videoDev, VIDIOC_STREAMON, &type) == 0) { ++ memset(&buf, 0, sizeof(buf)); ++ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ buf.memory = V4L2_MEMORY_MMAP; ++ buf.index = 0; ++ if (ioctl(videoDev, VIDIOC_DQBUF, &buf) == 0) { ++ if (ioctl(videoDev, VIDIOC_STREAMOFF, &type) == 0) { ++ // make RGB out of BGR: ++ int memsize = fmt.fmt.pix.width * fmt.fmt.pix.height; ++ unsigned char *mem1 = mem; ++ for (int i = 0; i < memsize; i++) { ++ unsigned char tmp = mem1[2]; ++ mem1[2] = mem1[0]; ++ mem1[0] = tmp; ++ mem1 += 3; ++ } ++ ++ if (Quality < 0) ++ Quality = 100; ++ ++ dsyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, fmt.fmt.pix.width, fmt.fmt.pix.height); ++ if (Jpeg) { ++ // convert to JPEG: ++ result = RgbToJpeg(mem, fmt.fmt.pix.width, fmt.fmt.pix.height, Size, Quality); ++ if (!result) ++ esyslog("ERROR: failed to convert image to JPEG"); ++ } ++ else { ++ // convert to PNM: ++ char buf[32]; ++ snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", fmt.fmt.pix.width, fmt.fmt.pix.height); ++ int l = strlen(buf); ++ int bytes = memsize * 3; ++ Size = l + bytes; ++ result = MALLOC(uchar, Size); ++ if (result) { ++ memcpy(result, buf, l); ++ memcpy(result + l, mem, bytes); ++ } ++ else ++ esyslog("ERROR: failed to convert image to PNM"); ++ } ++ } ++ else ++ esyslog("ERROR: video device VIDIOC_STREAMOFF failed"); ++ } ++ else ++ esyslog("ERROR: video device VIDIOC_DQBUF failed"); + } + else +- esyslog("ERROR: failed to convert image to PNM"); ++ esyslog("ERROR: video device VIDIOC_STREAMON failed"); + } ++ else ++ esyslog("ERROR: video device VIDIOC_QBUF failed"); ++ munmap(mem, msize); + } ++ else ++ esyslog("ERROR: failed to memmap video device"); + } +- munmap(mem, msize); ++ else ++ esyslog("ERROR: video device VIDIOC_QUERYBUF failed"); + } + else +- esyslog("ERROR: failed to memmap video device"); ++ esyslog("ERROR: video device VIDIOC_REQBUFS failed"); + } ++ else ++ esyslog("ERROR: video device VIDIOC_S_FMT failed"); + close(videoDev); + return result; + } +@@ -861,7 +912,7 @@ bool cDvbDevice::ProvidesSource(int Sour + { + int type = Source & cSource::st_Mask; + #ifdef USE_SOURCECAPS +- if (Setup.SourceCapsSet && type == cSource::stSat && (frontendType & (DVBFE_DELSYS_DVBS | DVBFE_DELSYS_DVBS2))) { ++ if (Setup.SourceCapsSet && type == cSource::stSat && (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)) { + for (int i = 0; i < MAXSOURCECAPS; i++) + if (sourceCaps[i] == Source) + return true; +@@ -870,13 +921,13 @@ bool cDvbDevice::ProvidesSource(int Sour + else + #endif /* SOURCECAPS */ + return type == cSource::stNone +- || type == cSource::stCable && (frontendType & DVBFE_DELSYS_DVBC) ++ || type == cSource::stCable && (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) ++ || type == cSource::stSat && (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) + #ifdef USE_ATSC +- || type == cSource::stCable && (frontendType & DVBFE_DELSYS_ATSC) +- || type == cSource::stTerr && (frontendType & DVBFE_DELSYS_ATSC) ++ || type == cSource::stTerr && (frontendType == SYS_DVBT || frontendType == SYS_ATSC); ++#else ++ || type == cSource::stTerr && (frontendType == SYS_DVBT); + #endif /* ATSC */ +- || type == cSource::stSat && (frontendType & (DVBFE_DELSYS_DVBS | DVBFE_DELSYS_DVBS2)) +- || type == cSource::stTerr && (frontendType & DVBFE_DELSYS_DVBT); + } + + bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const +@@ -901,7 +952,7 @@ bool cDvbDevice::ProvidesTransponder(con + return false; // doesn't provide source + if (!cSource::IsSat(Channel->Source())) + return true; // source is sufficient for non sat +- if (!(frontendType & Channel->System())) ++ if (frontendType == SYS_DVBS && Channel->System() == SYS_DVBS2) + return false; // requires modulation system which frontend doesn't provide + return !Setup.DiSEqC || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + } +@@ -1240,8 +1291,10 @@ void cDvbDevice::Play(void) + CHECK(ioctl(fd_audio, AUDIO_CONTINUE)); + } + else { +- if (fd_audio >= 0) ++ if (fd_audio >= 0) { + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); ++ CHECK(ioctl(fd_audio, AUDIO_CONTINUE)); ++ } + if (fd_video >= 0) + CHECK(ioctl(fd_video, VIDEO_CONTINUE)); + } +@@ -1255,8 +1308,10 @@ void cDvbDevice::Freeze(void) + CHECK(ioctl(fd_audio, AUDIO_PAUSE)); + } + else { +- if (fd_audio >= 0) ++ if (fd_audio >= 0) { + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); ++ CHECK(ioctl(fd_audio, AUDIO_PAUSE)); ++ } + if (fd_video >= 0) + CHECK(ioctl(fd_video, VIDEO_FREEZE)); + } +@@ -1274,7 +1329,13 @@ void cDvbDevice::Mute(void) + + void cDvbDevice::StillPicture(const uchar *Data, int Length) + { +- if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) { ++ if (!Data || Length < TS_SIZE) ++ return; ++ if (Data[0] == 0x47) { ++ // TS data ++ cDevice::StillPicture(Data, Length); ++ } ++ else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) { + // PES data + char *buf = MALLOC(char, Length); + if (!buf) +@@ -1369,6 +1430,16 @@ int cDvbDevice::PlayAudio(const uchar *D + return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); + } + ++int cDvbDevice::PlayTsVideo(const uchar *Data, int Length) ++{ ++ return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); ++} ++ ++int cDvbDevice::PlayTsAudio(const uchar *Data, int Length) ++{ ++ return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); ++} ++ + bool cDvbDevice::OpenDvr(void) + { + CloseDvr(); +diff -ruNp vdr-1.7.0-extensions/dvbdevice.h vdr-1.7.0-ext-h264-s2ng-speedup/dvbdevice.h +--- vdr-1.7.0-extensions/dvbdevice.h 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/dvbdevice.h 2009-04-12 13:37:59.000000000 +0200 +@@ -4,7 +4,7 @@ + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * +- * $Id: dvbdevice.h 2.1 2008/04/12 11:20:48 kls Exp $ ++ * $Id: dvbdevice.h 2.3 2008/12/06 13:31:12 kls Exp $ + */ + + #ifndef __DVBDEVICE_H +@@ -15,8 +15,8 @@ + #include "device.h" + #include "dvbspu.h" + +-#if DVB_API_VERSION != 3 || DVB_API_VERSION_MINOR != 3 +-#error VDR requires Linux DVB driver API version 3.3! ++#if DVB_API_VERSION != 5 || DVB_API_VERSION_MINOR != 0 ++#error VDR requires Linux DVB driver API version 5.0! + #endif + + #define MAXDVBDEVICES 8 +@@ -35,8 +35,9 @@ public: + ///< Must be called before accessing any DVB functions. + ///< \return True if any devices are available. + private: +- dvbfe_delsys frontendType; ++ dvb_frontend_info frontendInfo; + int numProvidedSystems; ++ fe_delivery_system frontendType; + int fd_osd, fd_audio, fd_video, fd_dvr, fd_stc, fd_ca; + protected: + virtual void MakePrimaryDevice(bool On); +@@ -141,6 +142,8 @@ protected: + virtual bool SetPlayMode(ePlayMode PlayMode); + virtual int PlayVideo(const uchar *Data, int Length); + virtual int PlayAudio(const uchar *Data, int Length, uchar Id); ++ virtual int PlayTsVideo(const uchar *Data, int Length); ++ virtual int PlayTsAudio(const uchar *Data, int Length); + public: + virtual int64_t GetSTC(void); + virtual void TrickSpeed(int Speed); +diff -ruNp vdr-1.7.0-extensions/dvbplayer.c vdr-1.7.0-ext-h264-s2ng-speedup/dvbplayer.c +--- vdr-1.7.0-extensions/dvbplayer.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/dvbplayer.c 2009-04-12 23:57:23.000000000 +0200 +@@ -185,8 +185,8 @@ bool cNonBlockingFileReader::WaitForData + + #define PLAYERBUFSIZE MEGABYTE(1) + +-// The number of frames to back up when resuming an interrupted replay session: +-#define RESUMEBACKUP (10 * FRAMESPERSEC) ++// The number of seconds to back up when resuming an interrupted replay session: ++#define RESUMEBACKUP 10 + + class cDvbPlayer : public cPlayer, cThread { + private: +@@ -202,6 +202,7 @@ private: + cFileName *fileName; + cIndexFile *index; + cUnbufferedFile *replayFile; ++ int framesPerSec; + bool eof; + bool firstPacket; + ePlayModes playMode; +@@ -231,6 +232,7 @@ public: + void Goto(int Position, bool Still = false); + virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); ++ int GetFramesPerSec(void) { return framesPerSec; } + }; + + #define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct? +@@ -263,6 +265,7 @@ cDvbPlayer::cDvbPlayer(const char *FileN + replayFile = fileName->Open(); + if (!replayFile) + return; ++ framesPerSec = replayFile->GetFramesPerSec(); + ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE); + // Create the index file: + index = new cIndexFile(FileName, false); +@@ -385,7 +388,7 @@ bool cDvbPlayer::Save(void) + if (Setup.PlayJump && marks.First() && abs(Index - marks.First()->position) <= RESUMEBACKUP) + Index = 0; + #endif /* JUMPPLAY */ +- Index -= RESUMEBACKUP; ++ Index -= RESUMEBACKUP * GetFramesPerSec(); + if (Index > 0) + Index = index->GetNextIFrame(Index, false); + else +@@ -407,127 +410,6 @@ void cDvbPlayer::Activate(bool On) + Cancel(9); + } + +-#ifdef USE_DVBPLAYER +-// --- BEGIN fix for I frames ------------------------------------------- +-// +-// Prior to the introduction of cVideoRepacker, VDR didn't start a new +-// PES packet when a new frame started. So, it was likely that the tail +-// of an I frame was at the beginning of the packet which started the +-// following B frame. Due to the organisation of VDR's index file, VDR +-// typically didn't read the tail of the I frame and therefore caused +-// softdevice plugins to not render such a frame as it was incomplete, +-// e. g. when moving cutting marks. +-// +-// The following code tries to fix incomplete I frames for recordings +-// made prior to the introdcution of cVideoRepacker, to be able to +-// edit cutting marks for example with softdevice plugins like vdr-xine. +-// +- +-static uchar *findStartCode(uchar *Data, int Length, int &PesPayloadOffset) +-{ +- uchar *limit = Data + Length; +- if (AnalyzePesHeader(Data, Length, PesPayloadOffset) <= phInvalid) +- return 0; // neither MPEG1 nor MPEG2 +- +- Data += PesPayloadOffset + 3; // move to video payload and skip 00 00 01 +- while (Data < limit) { +- // possible start codes that appear before/after picture data +- // 00 00 01 B3: sequence header code +- // 00 00 01 B8: group start code +- // 00 00 01 00: picture start code +- // 00 00 01 B7: sequence end code +- if (0x01 == Data[-1] && (0xB3 == Data[0] || 0xB8 == Data[0] || 0x00 == Data[0] || 0xB7 == Data[0]) && 0x00 == Data[-2] && 0x00 == Data[-3]) +- return Data - 3; +- Data++; +- } +- +- return 0; +-} +- +-static void fixIFrameHead(uchar *Data, int Length) +-{ +- int pesPayloadOffset = 0; +- uchar *p = findStartCode(Data, Length, pesPayloadOffset); +- if (!p) { +- esyslog("fixIframeHead: start code not found!\n"); +- return; +- } +- +- Data += pesPayloadOffset; // move to video payload +- if (Data < p) +- memset(Data, 0, p - Data); // zero preceeding bytes +-} +- +-static int fixIFrameTail(uchar *Data, int Length) +-{ +- int pesPayloadOffset = 0; +- uchar *p = findStartCode(Data, Length, pesPayloadOffset); +- if (!p) { +- esyslog("fixIframeTail: start code not found!\n"); +- return Length; +- } +- +- // is this PES packet required? +- uchar *videoPayload = Data + pesPayloadOffset; +- if (videoPayload >= p) +- return 0; // no +- +- // adjust PES length +- int lenPES = (p - Data); +- Data[4] = (lenPES - 6) >> 8; +- Data[5] = (lenPES - 6) & 0xFF; +- +- return lenPES; +-} +- +-#define IPACKS 2048 // originally defined in remux.c +- +-static void fixIFrame(uchar *Data, int &Length, const int OriginalLength) +-{ +- int done = 0; +- +- while (done < Length) { +- if (0x00 != Data[0] || 0x00 != Data[1] || 0x01 != Data[2]) { +- esyslog("fixIFrame: PES start code not found at offset %d (data length: %d, original length: %d)!", done, Length, OriginalLength); +- if (Length > OriginalLength) // roll back additional data +- Length = OriginalLength; +- return; +- } +- +- int lenPES = 6 + Data[4] * 256 + Data[5]; +- if (0xBA == Data[3]) { // pack header has fixed length +- if (0x00 == (0xC0 & Data[4])) +- lenPES = 12; // MPEG1 +- else +- lenPES = 14 + (Data[13] & 0x07); // MPEG2 +- } +- else if (0xB9 == Data[3]) // stream end has fixed length +- lenPES = 4; +- else if (0xE0 == (0xF0 & Data[3])) { // video packet +- int todo = Length - done; +- int bite = (lenPES < todo) ? lenPES : todo; +- if (0 == done) // first packet +- fixIFrameHead(Data, bite); +- else if (done >= OriginalLength) { // last packet +- Length = done + fixIFrameTail(Data, bite); +- return; +- } +- } +- else if (0 == done && 0xC0 == (0xE0 & Data[3])) { +- // if the first I frame packet is an audio packet then this is a radio recording: don't touch it! +- if (Length > OriginalLength) // roll back additional data +- Length = OriginalLength; +- return; +- } +- +- done += lenPES; +- Data += lenPES; +- } +-} +- +-// --- END fix for I frames --------------------------------------------- +-#endif /* DVBPLAYER */ +- + void cDvbPlayer::Action(void) + { + uchar *b = NULL; +@@ -540,7 +422,7 @@ void cDvbPlayer::Action(void) + + readIndex = Resume(); + if (readIndex >= 0) +- isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); ++ isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true, GetFramesPerSec())); + + #ifdef USE_JUMPPLAY + if (Setup.PlayJump && readIndex <= 0 && marks.First() && index) { +@@ -550,7 +432,7 @@ void cDvbPlayer::Action(void) + if (index->Get(Index, &FileNumber, &FileOffset) && + NextFile(FileNumber, FileOffset)) { + isyslog("PlayJump: start replay at first mark %d (%s)", +- Index, *IndexToHMSF(Index, true)); ++ Index, *IndexToHMSF(Index, true, GetFramesPerSec())); + readIndex = Index; + } + } +@@ -599,9 +481,6 @@ void cDvbPlayer::Action(void) + if (!NextFile(FileNumber, FileOffset)) { + readIndex = Index; + continue; +-#ifdef USE_DVBPLAYER +- Length += IPACKS; // fixIFrame needs next video packet +-#endif /* DVBPLAYER */ + } + } + else { +@@ -688,10 +567,6 @@ void cDvbPlayer::Action(void) + int r = nonBlockingFileReader->Read(replayFile, b, Length); + if (r > 0) { + WaitingForData = false; +-#ifdef USE_DVBPLAYER +- if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) +- fixIFrame(b, r, Length - IPACKS); +-#endif /* DVBPLAYER */ + readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer + b = NULL; + } +@@ -933,7 +808,7 @@ void cDvbPlayer::SkipSeconds(int Seconds + Empty(); + int Index = writeIndex; + if (Index >= 0) { +- Index = max(Index + Seconds * FRAMESPERSEC, 0); ++ Index = max(Index + Seconds * GetFramesPerSec(), 0); + if (Index > 0) + Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true); + if (Index >= 0) +@@ -954,15 +829,9 @@ void cDvbPlayer::Goto(int Index, bool St + int FileOffset, Length; + Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); + if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { +-#ifdef USE_DVBPLAYER +- Length += IPACKS; // fixIFrame needs next video packet +-#endif /* DVBPLAYER */ + uchar b[MAXFRAMESIZE + 4 + 5 + 4]; + int r = ReadFrame(replayFile, b, Length, sizeof(b)); + if (r > 0) { +-#ifdef USE_DVBPLAYER +- fixIFrame(b, r, Length - IPACKS); +-#endif /* DVBPLAYER */ + if (playMode == pmPause) + DevicePlay(); + // append sequence end code to get the image shown immediately with softdevices +@@ -986,7 +855,8 @@ void cDvbPlayer::Goto(int Index, bool St + b[r++] = 0x00; + b[r++] = 0x00; + b[r++] = 0x01; +- b[r++] = 0xB7; ++ b[r] = (cRemux::IsFrameH264(b, r) ? 10 : 0xB7); ++ r++; + } + DeviceStillPicture(b, r); + } +@@ -1106,3 +976,10 @@ void cDvbPlayerControl::Goto(int Positio + if (player) + player->Goto(Position, Still); + } ++ ++int cDvbPlayerControl::GetFramesPerSec() ++{ ++ if (player) ++ return player->GetFramesPerSec(); ++ return FRAMESPERSEC; ++} +diff -ruNp vdr-1.7.0-extensions/dvbplayer.h vdr-1.7.0-ext-h264-s2ng-speedup/dvbplayer.h +--- vdr-1.7.0-extensions/dvbplayer.h 2002-06-23 12:13:51.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/dvbplayer.h 2009-04-12 23:57:23.000000000 +0200 +@@ -54,6 +54,8 @@ public: + void Goto(int Index, bool Still = false); + // Positions to the given index and displays that frame as a still picture + // if Still is true. ++ int GetFramesPerSec(); ++ // Returns the number of frames per second for the current recording. + }; + + #endif //__DVBPLAYER_H +diff -ruNp vdr-1.7.0-extensions/epg.c vdr-1.7.0-ext-h264-s2ng-speedup/epg.c +--- vdr-1.7.0-extensions/epg.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/epg.c 2009-04-12 23:57:23.000000000 +0200 +@@ -1420,6 +1420,7 @@ cSchedule *cSchedules::AddSchedule(tChan + if (!p) { + p = new cSchedule(ChannelID); + Add(p); ++ HashSchedule(p); + cChannel *channel = Channels.GetByChannelID(ChannelID); + if (channel) + channel->schedule = p; +@@ -1430,10 +1431,14 @@ cSchedule *cSchedules::AddSchedule(tChan + const cSchedule *cSchedules::GetSchedule(tChannelID ChannelID) const + { + ChannelID.ClrRid(); +- for (cSchedule *p = First(); p; p = Next(p)) { +- if (p->ChannelID() == ChannelID) +- return p; +- } ++ cList<cHashObject> *list = schedulesHash.GetList(HashKey(ChannelID)); ++ if (list) { ++ for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { ++ cSchedule *p = (cSchedule *)hobj->Object(); ++ if (p->ChannelID() == ChannelID) ++ return p; ++ } ++ } + return NULL; + } + +@@ -1449,7 +1454,23 @@ const cSchedule *cSchedules::GetSchedule + if (Channel->schedule == &DummySchedule && AddIfMissing) { + cSchedule *Schedule = new cSchedule(Channel->GetChannelID()); + ((cSchedules *)this)->Add(Schedule); ++ ((cSchedules *)this)->HashSchedule(Schedule); + Channel->schedule = Schedule; + } + return Channel->schedule != &DummySchedule? Channel->schedule : NULL; + } ++ ++void cSchedules::HashSchedule(cSchedule *Schedule) ++{ ++ schedulesHash.Add(Schedule, HashKey(Schedule->ChannelID().ClrRid())); ++} ++ ++void cSchedules::UnhashSchedule(cSchedule *Schedule) ++{ ++ schedulesHash.Del(Schedule, HashKey(Schedule->ChannelID().ClrRid())); ++} ++ ++unsigned int cSchedules::HashKey(tChannelID ChannelID) ++{ ++ return (unsigned int)((ChannelID.Nid() << 16 | ChannelID.Source()) ^ (ChannelID.Tid() << 16 | ChannelID.Sid()) ^ ChannelID.Rid()); ++} +diff -ruNp vdr-1.7.0-extensions/epg.h vdr-1.7.0-ext-h264-s2ng-speedup/epg.h +--- vdr-1.7.0-extensions/epg.h 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/epg.h 2009-04-12 23:57:23.000000000 +0200 +@@ -199,11 +199,15 @@ class cSchedules : public cList<cSchedul + friend class cSchedulesLock; + private: + cRwLock rwlock; ++ cHash<cSchedule> schedulesHash; + static cSchedules schedules; + static const char *epgDataFileName; + static time_t lastCleanup; + static time_t lastDump; + static time_t modified; ++ void HashSchedule(cSchedule *Schedule); ++ void UnhashSchedule(cSchedule *Schedule); ++ static unsigned int HashKey(tChannelID ChannelID); + public: + static void SetEpgDataFileName(const char *FileName); + static const cSchedules *Schedules(cSchedulesLock &SchedulesLock); +diff -ruNp vdr-1.7.0-extensions/h264parser.c vdr-1.7.0-ext-h264-s2ng-speedup/h264parser.c +--- vdr-1.7.0-extensions/h264parser.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/h264parser.c 2009-04-12 23:57:23.000000000 +0200 +@@ -0,0 +1,461 @@ ++/* ++ * h264parser.c: a minimalistic H.264 video stream parser ++ * ++ * See the main source file 'vdr.c' for copyright information and ++ * how to reach the author. ++ * ++ * The code was originally written by Reinhard Nissl <rnissl@gmx.de>, ++ * and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de. ++ */ ++ ++#include "tools.h" ++#include "h264parser.h" ++ ++namespace H264 ++{ ++ // --- cContext ------------------------------------------------------------ ++ ++ int cContext::GetFramesPerSec(void) const ++ { ++ const cSequenceParameterSet *SPS = ActiveSPS(); ++ const cSliceHeader *SH = CurrentSlice(); ++ if (!SH || !SPS->timing_info_present_flag || !SPS->time_scale || !SPS->num_units_in_tick) ++ return -1; ++ uint32_t DeltaTfiDivisor; ++ if (SPS->pic_struct_present_flag) { ++ if (!SPS->pic_timing_sei.Defined()) ++ return -1; ++ switch (SPS->pic_timing_sei.pic_struct) { ++ case 1: ++ case 2: ++ DeltaTfiDivisor = 1; ++ break; ++ case 0: ++ case 3: ++ case 4: ++ DeltaTfiDivisor = 2; ++ break; ++ case 5: ++ case 6: ++ DeltaTfiDivisor = 3; ++ break; ++ case 7: ++ DeltaTfiDivisor = 4; ++ break; ++ case 8: ++ DeltaTfiDivisor = 6; ++ break; ++ default: ++ return -1; ++ } ++ } ++ else if (!SH->field_pic_flag) ++ DeltaTfiDivisor = 2; ++ else ++ DeltaTfiDivisor = 1; ++ ++ double FPS = (double)SPS->time_scale / SPS->num_units_in_tick / DeltaTfiDivisor / (SH->field_pic_flag ? 2 : 1); ++ int FramesPerSec = (int)FPS; ++ if ((FPS - FramesPerSec) >= 0.5) ++ FramesPerSec++; ++ return FramesPerSec; ++ } ++ ++ // --- cSimpleBuffer ------------------------------------------------------- ++ ++ cSimpleBuffer::cSimpleBuffer(int Size) ++ { ++ size = Size; ++ data = new uchar[size]; ++ avail = 0; ++ gotten = 0; ++ } ++ ++ cSimpleBuffer::~cSimpleBuffer() ++ { ++ delete [] data; ++ } ++ ++ int cSimpleBuffer::Put(const uchar *Data, int Count) ++ { ++ if (Count < 0) { ++ if (avail + Count < 0) ++ Count = 0 - avail; ++ if (avail + Count < gotten) ++ Count = gotten - avail; ++ avail += Count; ++ return Count; ++ } ++ if (avail + Count > size) ++ Count = size - avail; ++ memcpy(data + avail, Data, Count); ++ avail += Count; ++ return Count; ++ } ++ ++ uchar *cSimpleBuffer::Get(int &Count) ++ { ++ Count = gotten = avail; ++ return data; ++ } ++ ++ void cSimpleBuffer::Del(int Count) ++ { ++ if (Count < 0) ++ return; ++ if (Count > gotten) { ++ esyslog("ERROR: invalid Count in H264::cSimpleBuffer::Del: %d (limited to %d)", Count, gotten); ++ Count = gotten; ++ } ++ if (Count < avail) ++ memmove(data, data + Count, avail - Count); ++ avail -= Count; ++ gotten = 0; ++ } ++ ++ void cSimpleBuffer::Clear(void) ++ { ++ avail = gotten = 0; ++ } ++ ++ // --- cParser ------------------------------------------------------------- ++ ++ cParser::cParser(bool OmitPicTiming) ++ : nalUnitDataBuffer(1000) ++ { ++ // the above buffer size of 1000 bytes wont hold a complete NAL unit but ++ // should be sufficient for the relevant part used for parsing. ++ omitPicTiming = OmitPicTiming; // only necessary to determine frames per second ++ Reset(); ++ } ++ ++ void cParser::Reset(void) ++ { ++ context = cContext(); ++ nalUnitDataBuffer.Clear(); ++ syncing = true; ++ } ++ ++ void cParser::ParseSequenceParameterSet(uint8_t *Data, int Count) ++ { ++ cSequenceParameterSet SPS; ++ ++ cBitReader br(Data + 1, Count - 1); ++ uint32_t profile_idc = br.u(8); ++ /* uint32_t constraint_set0_flag = */ br.u(1); ++ /* uint32_t constraint_set1_flag = */ br.u(1); ++ /* uint32_t constraint_set2_flag = */ br.u(1); ++ /* uint32_t constraint_set3_flag = */ br.u(1); ++ /* uint32_t reserved_zero_4bits = */ br.u(4); ++ /* uint32_t level_idc = */ br.u(8); ++ SPS.seq_parameter_set_id = br.ue(); ++ if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) { ++ uint32_t chroma_format_idc = br.ue(); ++ if (chroma_format_idc == 3) { ++ /* uint32_t residual_colour_transform_flag = */ br.u(1); ++ } ++ /* uint32_t bit_depth_luma_minus8 = */ br.ue(); ++ /* uint32_t bit_depth_chroma_minus8 = */ br.ue(); ++ /* uint32_t qpprime_y_zero_transform_bypass_flag = */ br.u(1); ++ uint32_t seq_scaling_matrix_present_flag = br.u(1); ++ if (seq_scaling_matrix_present_flag) { ++ for (int i = 0; i < 8; i++) { ++ uint32_t seq_scaling_list_present_flag = br.u(1); ++ if (seq_scaling_list_present_flag) { ++ int sizeOfScalingList = (i < 6) ? 16 : 64; ++ int lastScale = 8; ++ int nextScale = 8; ++ for (int j = 0; j < sizeOfScalingList; j++) { ++ if (nextScale != 0) { ++ int32_t delta_scale = br.se(); ++ nextScale = (lastScale + delta_scale + 256) % 256; ++ } ++ lastScale = (nextScale == 0) ? lastScale : nextScale; ++ } ++ } ++ } ++ } ++ } ++ SPS.log2_max_frame_num_minus4(br.ue()); ++ SPS.pic_order_cnt_type = br.ue(); ++ if (SPS.pic_order_cnt_type == 0) ++ SPS.log2_max_pic_order_cnt_lsb_minus4(br.ue()); ++ else if (SPS.pic_order_cnt_type == 1) { ++ SPS.delta_pic_order_always_zero_flag = br.u(1); ++ /* int32_t offset_for_non_ref_pic = */ br.se(); ++ /* int32_t offset_for_top_to_bottom_field = */ br.se(); ++ uint32_t num_ref_frames_in_pic_order_cnt_cycle = br.ue(); ++ for (uint32_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) { ++ /* int32_t offset_for_ref_frame = */ br.se(); ++ } ++ } ++ /* uint32_t num_ref_frames = */ br.ue(); ++ /* uint32_t gaps_in_frame_num_value_allowed_flag = */ br.u(1); ++ /* uint32_t pic_width_in_mbs_minus1 = */ br.ue(); ++ /* uint32_t pic_height_in_map_units_minus1 = */ br.ue(); ++ SPS.frame_mbs_only_flag = br.u(1); ++ ++ if (!omitPicTiming) { ++ if (!SPS.frame_mbs_only_flag) { ++ /* uint32_t mb_adaptive_frame_field_flag = */ br.u(1); ++ } ++ /* uint32_t direct_8x8_inference_flag = */ br.u(1); ++ uint32_t frame_cropping_flag = br.u(1); ++ if (frame_cropping_flag) { ++ /* uint32_t frame_crop_left_offset = */ br.ue(); ++ /* uint32_t frame_crop_right_offset = */ br.ue(); ++ /* uint32_t frame_crop_top_offset = */ br.ue(); ++ /* uint32_t frame_crop_bottom_offset = */ br.ue(); ++ } ++ uint32_t vui_parameters_present_flag = br.u(1); ++ if (vui_parameters_present_flag) { ++ uint32_t aspect_ratio_info_present_flag = br.u(1); ++ if (aspect_ratio_info_present_flag) { ++ uint32_t aspect_ratio_idc = br.u(8); ++ const uint32_t Extended_SAR = 255; ++ if (aspect_ratio_idc == Extended_SAR) { ++ /* uint32_t sar_width = */ br.u(16); ++ /* uint32_t sar_height = */ br.u(16); ++ } ++ } ++ uint32_t overscan_info_present_flag = br.u(1); ++ if (overscan_info_present_flag) { ++ /* uint32_t overscan_appropriate_flag = */ br.u(1); ++ } ++ uint32_t video_signal_type_present_flag = br.u(1); ++ if (video_signal_type_present_flag) { ++ /* uint32_t video_format = */ br.u(3); ++ /* uint32_t video_full_range_flag = */ br.u(1); ++ uint32_t colour_description_present_flag = br.u(1); ++ if (colour_description_present_flag) { ++ /* uint32_t colour_primaries = */ br.u(8); ++ /* uint32_t transfer_characteristics = */ br.u(8); ++ /* uint32_t matrix_coefficients = */ br.u(8); ++ } ++ } ++ uint32_t chroma_loc_info_present_flag = br.u(1); ++ if (chroma_loc_info_present_flag) { ++ /* uint32_t chroma_sample_loc_type_top_field = */ br.ue(); ++ /* uint32_t chroma_sample_loc_type_bottom_field = */ br.ue(); ++ } ++ SPS.timing_info_present_flag = br.u(1); ++ if (SPS.timing_info_present_flag) { ++ SPS.num_units_in_tick = br.u(32); ++ SPS.time_scale = br.u(32); ++ SPS.fixed_frame_rate_flag = br.u(1); ++ } ++ SPS.nal_hrd_parameters_present_flag = br.u(1); ++ if (SPS.nal_hrd_parameters_present_flag) ++ hrd_parameters(SPS, br); ++ SPS.vcl_hrd_parameters_present_flag = br.u(1); ++ if (SPS.vcl_hrd_parameters_present_flag) ++ hrd_parameters(SPS, br); ++ if (SPS.nal_hrd_parameters_present_flag || SPS.vcl_hrd_parameters_present_flag) { ++ /* uint32_t low_delay_hrd_flag = */ br.u(1); ++ } ++ SPS.pic_struct_present_flag = br.u(1); ++ } ++ } ++ ++ context.Define(SPS); ++ } ++ ++ void cParser::hrd_parameters(cSequenceParameterSet &SPS, cBitReader &br) ++ { ++ uint32_t cpb_cnt_minus1 = br.ue(); ++ /* uint32_t bit_rate_scale = */ br.u(4); ++ /* uint32_t cpb_size_scale = */ br.u(4); ++ for (uint32_t i = 0; i <= cpb_cnt_minus1; i++) { ++ /* uint32_t bit_rate_value_minus1 = */ br.ue(); ++ /* uint32_t cpb_size_value_minus1 = */ br.ue(); ++ /* uint32_t cbr_flag = */ br.u(1); ++ } ++ /* uint32_t initial_cpb_removal_delay_length_minus1 = */ br.u(5); ++ SPS.cpb_removal_delay_length_minus1(br.u(5)); ++ SPS.dpb_output_delay_length_minus1(br.u(5)); ++ /* uint32_t time_offset_length = */ br.u(5); ++ } ++ ++ void cParser::ParsePictureParameterSet(uint8_t *Data, int Count) ++ { ++ cPictureParameterSet PPS; ++ ++ cBitReader br(Data + 1, Count - 1); ++ PPS.pic_parameter_set_id = br.ue(); ++ PPS.seq_parameter_set_id = br.ue(); ++ /* uint32_t entropy_coding_mode_flag = */ br.u(1); ++ PPS.pic_order_present_flag = br.u(1); ++ ++ context.Define(PPS); ++ } ++ ++ void cParser::ParseSlice(uint8_t *Data, int Count) ++ { ++ cSliceHeader SH; ++ ++ cBitReader br(Data + 1, Count - 1); ++ SH.nal_ref_idc(Data[0] >> 5); ++ SH.nal_unit_type(Data[0] & 0x1F); ++ /* uint32_t first_mb_in_slice = */ br.ue(); ++ SH.slice_type = br.ue(); ++ SH.pic_parameter_set_id = br.ue(); ++ ++ context.ActivatePPS(SH.pic_parameter_set_id); ++ const cSequenceParameterSet *SPS = context.ActiveSPS(); ++ ++ SH.frame_num = br.u(SPS->log2_max_frame_num()); ++ if (!SPS->frame_mbs_only_flag) { ++ SH.field_pic_flag = br.u(1); ++ if (SH.field_pic_flag) ++ SH.bottom_field_flag = br.u(1); ++ } ++ if (SH.nal_unit_type() == 5) ++ SH.idr_pic_id = br.ue(); ++ if (SPS->pic_order_cnt_type == 0) { ++ SH.pic_order_cnt_lsb = br.u(SPS->log2_max_pic_order_cnt_lsb()); ++ const cPictureParameterSet *PPS = context.ActivePPS(); ++ if (PPS->pic_order_present_flag && !SH.field_pic_flag) ++ SH.delta_pic_order_cnt_bottom = br.se(); ++ } ++ if (SPS->pic_order_cnt_type == 1 && !SPS->delta_pic_order_always_zero_flag) { ++ SH.delta_pic_order_cnt[0] = br.se(); ++ const cPictureParameterSet *PPS = context.ActivePPS(); ++ if (PPS->pic_order_present_flag && !SH.field_pic_flag) ++ SH.delta_pic_order_cnt[1] = br.se(); ++ } ++ ++ context.Define(SH); ++ } ++ ++ void cParser::ParseSEI(uint8_t *Data, int Count) ++ { ++ // currently only used to determine frames per second ++ if (omitPicTiming) ++ return; ++ cBitReader br(Data + 1, Count - 1); ++ do ++ sei_message(br); ++ while (br.GetBytesAvail()); ++ } ++ ++ void cParser::sei_message(cBitReader &br) ++ { ++ uint32_t payloadType = 0; ++ while (1) { ++ uint32_t last_payload_type_byte = br.u(8); ++ payloadType += last_payload_type_byte; ++ if (last_payload_type_byte != 0xFF) ++ break; ++ } ++ uint32_t payloadSize = 0; ++ while (1) { ++ uint32_t last_payload_size_byte = br.u(8); ++ payloadSize += last_payload_size_byte; ++ if (last_payload_size_byte != 0xFF) ++ break; ++ } ++ sei_payload(payloadType, payloadSize, br); ++ } ++ ++ void cParser::sei_payload(uint32_t payloadType, uint32_t payloadSize, cBitReader &br) ++ { ++ const cBitReader::cBookMark BookMark = br.BookMark(); ++ switch (payloadType) { ++ case 0: ++ buffering_period(payloadSize, br); ++ break; ++ case 1: ++ pic_timing(payloadSize, br); ++ break; ++ } ++ // instead of dealing with trailing bits in each message ++ // go back to start of message and skip it completely ++ br.BookMark(BookMark); ++ reserved_sei_message(payloadSize, br); ++ } ++ ++ void cParser::buffering_period(uint32_t payloadSize, cBitReader &br) ++ { ++ uint32_t seq_parameter_set_id = br.ue(); ++ ++ context.ActivateSPS(seq_parameter_set_id); ++ } ++ ++ void cParser::pic_timing(uint32_t payloadSize, cBitReader &br) ++ { ++ cPictureTiming PT; ++ ++ const cSequenceParameterSet *SPS = context.ActiveSPS(); ++ if (!SPS) ++ return; ++ uint32_t CpbDpbDelaysPresentFlag = SPS->nal_hrd_parameters_present_flag || SPS->vcl_hrd_parameters_present_flag; ++ if (CpbDpbDelaysPresentFlag) { ++ /* uint32_t cpb_removal_delay = */ br.u(SPS->cpb_removal_delay_length()); ++ /* uint32_t dpb_output_delay = */ br.u(SPS->dpb_output_delay_length()); ++ } ++ if (SPS->pic_struct_present_flag) { ++ PT.pic_struct = br.u(4); ++ } ++ ++ context.Define(PT); ++ } ++ ++ void cParser::reserved_sei_message(uint32_t payloadSize, cBitReader &br) ++ { ++ for (uint32_t i = 0; i < payloadSize; i++) { ++ /* uint32_t reserved_sei_message_payload_byte = */ br.u(8); ++ } ++ } ++ ++ void cParser::PutNalUnitData(const uchar *Data, int Count) ++ { ++ int n = nalUnitDataBuffer.Put(Data, Count); ++ // typically less than a complete NAL unit are needed for parsing the ++ // relevant data, so simply ignore the overflow condition. ++ if (false && n != Count) ++ esyslog("ERROR: H264::cParser::PutNalUnitData(): NAL unit data buffer overflow"); ++ } ++ ++ void cParser::Process() ++ { ++ // nalUnitDataBuffer contains the head of the current NAL unit -- let's parse it ++ int Count = 0; ++ uchar *Data = nalUnitDataBuffer.Get(Count); ++ if (Data && Count >= 4) { ++ if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01) { ++ int nal_unit_type = Data[3] & 0x1F; ++ try { ++ switch (nal_unit_type) { ++ case 1: // coded slice of a non-IDR picture ++ case 2: // coded slice data partition A ++ case 5: // coded slice of an IDR picture ++ ParseSlice(Data + 3, Count - 3); ++ break; ++ case 6: // supplemental enhancement information (SEI) ++ ParseSEI(Data + 3, Count - 3); ++ break; ++ case 7: // sequence parameter set ++ syncing = false; // from now on, we should get reliable results ++ ParseSequenceParameterSet(Data + 3, Count - 3); ++ break; ++ case 8: // picture parameter set ++ ParsePictureParameterSet(Data + 3, Count - 3); ++ break; ++ } ++ } ++ catch (cException *e) { ++ if (!syncing) // suppress typical error messages while syncing ++ esyslog(e->Message()); ++ delete e; ++ } ++ } ++ else if (!syncing) ++ esyslog("ERROR: H264::cParser::Process(): NAL unit data buffer content is invalid"); ++ } ++ else if (!syncing) ++ esyslog("ERROR: H264::cParser::Process(): NAL unit data buffer content is too short"); ++ // reset the buffer for the next NAL unit ++ nalUnitDataBuffer.Clear(); ++ } ++} ++ +diff -ruNp vdr-1.7.0-extensions/h264parser.h vdr-1.7.0-ext-h264-s2ng-speedup/h264parser.h +--- vdr-1.7.0-extensions/h264parser.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/h264parser.h 2009-04-12 23:57:23.000000000 +0200 +@@ -0,0 +1,397 @@ ++/* ++ * h264parser.h: a minimalistic H.264 video stream parser ++ * ++ * See the main source file 'vdr.c' for copyright information and ++ * how to reach the author. ++ */ ++ ++#ifndef __H264PARSER_H ++#define __H264PARSER_H ++ ++namespace H264 ++{ ++ // --- cException ---------------------------------------------------------- ++ ++ class cException { ++ private: ++ cString message; ++ public: ++ cException(const cString &Message) { message = Message; } ++ const cString &Message(void) const { return message; } ++ }; ++ ++ // --- cBitReader ---------------------------------------------------------- ++ ++ class cBitReader { ++ public: ++ class cBookMark { ++ private: ++ uint8_t *data; ++ int count; ++ uint32_t bits; ++ uint32_t bitsAvail; ++ int countZeros; ++ cBookMark(void) {} ++ friend class cBitReader; ++ }; ++ private: ++ cBookMark bm; ++ uint8_t NextByte(void); ++ uint32_t ReadBits(uint32_t n); ++ public: ++ cBitReader(uint8_t *Data, int Count); ++ uint32_t u(uint32_t n) { return ReadBits(n); } // read n bits as unsigned number ++ uint32_t ue(void); // read Exp-Golomb coded unsigned number ++ int32_t se(void); // read Exp-Golomb coded signed number ++ uint32_t GetBitsAvail(void) { return (bm.bitsAvail & 0x07); } ++ bool GetBytesAvail(void) { return (bm.count > 0); } ++ const cBookMark BookMark(void) const { return bm; } ++ void BookMark(const cBookMark &b) { bm = b; } ++ }; ++ ++ inline cBitReader::cBitReader(unsigned char *Data, int Count) ++ { ++ bm.data = Data; ++ bm.count = Count; ++ bm.bitsAvail = 0; ++ bm.countZeros = 0; ++ } ++ ++ inline uint8_t cBitReader::NextByte(void) ++ { ++ if (bm.count < 1) // there is no more data left in this NAL unit ++ throw new cException("ERROR: H264::cBitReader::NextByte(): premature end of data"); ++ // detect 00 00 00, 00 00 01 and 00 00 03 and handle them ++ if (*bm.data == 0x00) { ++ if (bm.countZeros >= 3) // 00 00 00: the current NAL unit should have been terminated already before this sequence ++ throw new cException("ERROR: H264::cBitReader::NextByte(): premature end of data"); ++ // increase the zero counter as we have a zero byte ++ bm.countZeros++; ++ } ++ else { ++ if (bm.countZeros >= 2) { ++ if (*bm.data == 0x01) // 00 00 01: the current NAL unit should have been terminated already before this sequence ++ throw new cException("ERROR: H264::cBitReader::NextByte(): premature end of data"); ++ if (*bm.data == 0x03) { ++ // 00 00 03 xx: the emulation prevention byte 03 needs to be removed and xx must be returned ++ if (bm.count < 2) ++ throw new cException("ERROR: H264::cBitReader::NextByte(): premature end of data"); ++ // drop 03 and xx will be returned below ++ bm.count--; ++ bm.data++; ++ } ++ } ++ // reset the zero counter as we had a non zero byte ++ bm.countZeros = 0; ++ } ++ bm.count--; ++ return *bm.data++; ++ } ++ ++ inline uint32_t cBitReader::ReadBits(uint32_t n) ++ { ++ // fill the "shift register" bits with sufficient data ++ while (n > bm.bitsAvail) { ++ bm.bits <<= 8; ++ bm.bits |= NextByte(); ++ bm.bitsAvail += 8; ++ if (bm.bitsAvail > 24) { // a further turn will overflow bitbuffer ++ if (n <= bm.bitsAvail) ++ break; // service non overflowing request ++ if (n <= 32) // split overflowing reads into concatenated reads ++ return (ReadBits(16) << 16) | ReadBits(n - 16); ++ // cannot read more than 32 bits at once ++ throw new cException("ERROR: H264::cBitReader::ReadBits(): bitbuffer overflow"); ++ } ++ } ++ // return n most significant bits ++ bm.bitsAvail -= n; ++ return (bm.bits >> bm.bitsAvail) & (((uint32_t)1 << n) - 1); ++ } ++ ++ inline uint32_t cBitReader::ue(void) ++ { ++ // read and decode an Exp-Golomb coded unsigned number ++ // ++ // bitstring resulting number ++ // 1 0 ++ // 0 1 x 1 ... 2 ++ // 0 0 1 x y 3 ... 6 ++ // 0 0 0 1 x y z 7 ... 14 ++ // ... ++ int LeadingZeroBits = 0; ++ while (ReadBits(1) == 0) ++ LeadingZeroBits++; ++ if (LeadingZeroBits == 0) ++ return 0; ++ if (LeadingZeroBits >= 32) ++ throw new cException("ERROR: H264::cBitReader::ue(): overflow"); ++ return ((uint32_t)1 << LeadingZeroBits) - 1 + ReadBits(LeadingZeroBits); ++ } ++ ++ inline int32_t cBitReader::se(void) ++ { ++ // read and decode an Exp-Golomb coded signed number ++ // ++ // unsigned value resulting signed value ++ // 0 0 ++ // 1 +1 ++ // 2 -1 ++ // 3 +2 ++ // 4 -2 ++ // ... ++ uint32_t r = ue(); ++ if (r > 0xFFFFFFFE) ++ throw new cException("ERROR: H264::cBitReader::se(): overflow"); ++ return (1 - 2 * (r & 1)) * ((r + 1) / 2); ++ } ++ ++ // --- cPictureTiming ------------------------------------------------------ ++ ++ class cPictureTiming { ++ private: ++ friend class cContext; ++ bool defined; ++ public: ++ cPictureTiming(void) { memset(this, 0, sizeof (*this)); } ++ bool Defined(void) const { return defined; } ++ uint32_t pic_struct; ++ }; ++ ++ // --- cSequenceParameterSet ----------------------------------------------- ++ ++ class cSequenceParameterSet { ++ private: ++ friend class cContext; ++ bool defined; ++ uint32_t log2MaxFrameNum; ++ uint32_t log2MaxPicOrderCntLsb; ++ uint32_t cpbRemovalDelayLength; ++ uint32_t dpbOutputDelayLength; ++ public: ++ cSequenceParameterSet(void); ++ bool Defined(void) { return defined; } ++ void log2_max_frame_num_minus4(uint32_t Value) { log2MaxFrameNum = Value + 4; } ++ uint32_t log2_max_frame_num_minus4(void) const { return log2MaxFrameNum - 4; } ++ uint32_t log2_max_frame_num(void) const { return log2MaxFrameNum; } ++ void log2_max_pic_order_cnt_lsb_minus4(uint32_t Value) { log2MaxPicOrderCntLsb = Value + 4; } ++ uint32_t log2_max_pic_order_cnt_lsb_minus4(void) const { return log2MaxPicOrderCntLsb - 4; } ++ uint32_t log2_max_pic_order_cnt_lsb(void) const { return log2MaxPicOrderCntLsb; } ++ void cpb_removal_delay_length_minus1(uint32_t Value) { cpbRemovalDelayLength = Value + 1; } ++ uint32_t cpb_removal_delay_length_minus1(void) const { return cpbRemovalDelayLength - 1; } ++ uint32_t cpb_removal_delay_length(void) const { return cpbRemovalDelayLength; } ++ void dpb_output_delay_length_minus1(uint32_t Value) { dpbOutputDelayLength = Value + 1; } ++ uint32_t dpb_output_delay_length_minus1(void) const { return dpbOutputDelayLength - 1; } ++ uint32_t dpb_output_delay_length(void) const { return dpbOutputDelayLength; } ++ uint32_t seq_parameter_set_id; ++ uint32_t pic_order_cnt_type; ++ uint32_t delta_pic_order_always_zero_flag; ++ uint32_t frame_mbs_only_flag; ++ uint32_t timing_info_present_flag; ++ uint32_t num_units_in_tick; ++ uint32_t time_scale; ++ uint32_t fixed_frame_rate_flag; ++ uint32_t nal_hrd_parameters_present_flag; ++ uint32_t vcl_hrd_parameters_present_flag; ++ uint32_t pic_struct_present_flag; ++ cPictureTiming pic_timing_sei; ++ }; ++ ++ inline cSequenceParameterSet::cSequenceParameterSet(void) ++ { ++ memset(this, 0, sizeof (*this)); ++ log2_max_frame_num_minus4(0); ++ log2_max_pic_order_cnt_lsb_minus4(0); ++ cpb_removal_delay_length_minus1(23); ++ dpb_output_delay_length_minus1(23); ++ } ++ ++ // --- cPictureParameterSet ------------------------------------------------ ++ ++ class cPictureParameterSet { ++ private: ++ friend class cContext; ++ bool defined; ++ public: ++ cPictureParameterSet(void) { memset(this, 0, sizeof (*this)); } ++ bool Defined(void) { return defined; } ++ uint32_t pic_parameter_set_id; ++ uint32_t seq_parameter_set_id; ++ uint32_t pic_order_present_flag; ++ }; ++ ++ // --- cSliceHeader -------------------------------------------------------- ++ ++ class cSliceHeader { ++ private: ++ friend class cContext; ++ bool defined; ++ bool isFirstSliceOfCurrentAccessUnit; ++ uint32_t picOrderCntType; ++ uint32_t nalRefIdc; ++ uint32_t nalUnitType; ++ public: ++ cSliceHeader(void) { memset(this, 0, sizeof (*this)); } ++ bool Defined(void) const { return defined; } ++ bool IsFirstSliceOfCurrentAccessUnit(void) const { return isFirstSliceOfCurrentAccessUnit; } ++ void nal_ref_idc(uint32_t Value) { nalRefIdc = Value; } ++ uint32_t nal_ref_idc(void) const { return nalRefIdc; } ++ void nal_unit_type(uint32_t Value) { nalUnitType = Value; } ++ uint32_t nal_unit_type(void) const { return nalUnitType; } ++ uint32_t slice_type; ++ uint32_t pic_parameter_set_id; ++ uint32_t frame_num; ++ uint32_t field_pic_flag; ++ uint32_t bottom_field_flag; ++ uint32_t idr_pic_id; ++ uint32_t pic_order_cnt_lsb; ++ int32_t delta_pic_order_cnt_bottom; ++ int32_t delta_pic_order_cnt[2]; ++ enum eAccessUnitType { ++ Frame = 0, ++ TopField, ++ BottomField ++ }; ++ eAccessUnitType GetAccessUnitType() const { return (eAccessUnitType)(field_pic_flag + bottom_field_flag); } ++ }; ++ ++ // --- cContext ------------------------------------------------------------ ++ ++ class cContext { ++ private: ++ cSequenceParameterSet spsStore[32]; ++ cPictureParameterSet ppsStore[256]; ++ cSequenceParameterSet *sps; // active Sequence Parameter Set ++ cPictureParameterSet *pps; // active Picture Parameter Set ++ cSliceHeader sh; ++ public: ++ cContext(void) { sps = 0; pps = 0; } ++ void Define(cSequenceParameterSet &SPS); ++ void Define(cPictureParameterSet &PPS); ++ void Define(cSliceHeader &SH); ++ void Define(cPictureTiming &PT); ++ void ActivateSPS(uint32_t ID); ++ void ActivatePPS(uint32_t ID); ++ const cSequenceParameterSet *ActiveSPS(void) const { return sps; } ++ const cPictureParameterSet *ActivePPS(void) const { return pps; } ++ const cSliceHeader *CurrentSlice(void) const { return sh.Defined() ? &sh : 0; } ++ int GetFramesPerSec(void) const; ++ }; ++ ++ inline void cContext::ActivateSPS(uint32_t ID) ++ { ++ if (ID >= (sizeof (spsStore) / sizeof (*spsStore))) ++ throw new cException("ERROR: H264::cContext::ActivateSPS(): id out of range"); ++ if (!spsStore[ID].Defined()) ++ throw new cException("ERROR: H264::cContext::ActivateSPS(): requested SPS is undefined"); ++ sps = &spsStore[ID]; ++ } ++ ++ inline void cContext::ActivatePPS(uint32_t ID) ++ { ++ if (ID >= (sizeof (ppsStore) / sizeof (*ppsStore))) ++ throw new cException("ERROR: H264::cContext::ActivatePPS(): id out of range"); ++ if (!ppsStore[ID].Defined()) ++ throw new cException("ERROR: H264::cContext::ActivatePPS(): requested PPS is undefined"); ++ pps = &ppsStore[ID]; ++ ActivateSPS(pps->seq_parameter_set_id); ++ } ++ ++ inline void cContext::Define(cSequenceParameterSet &SPS) ++ { ++ if (SPS.seq_parameter_set_id >= (sizeof (spsStore) / sizeof (*spsStore))) ++ throw new cException("ERROR: H264::cContext::DefineSPS(): id out of range"); ++ SPS.defined = true; ++ spsStore[SPS.seq_parameter_set_id] = SPS; ++ } ++ ++ inline void cContext::Define(cPictureParameterSet &PPS) ++ { ++ if (PPS.pic_parameter_set_id >= (sizeof (ppsStore) / sizeof (*ppsStore))) ++ throw new cException("ERROR: H264::cContext::DefinePPS(): id out of range"); ++ PPS.defined = true; ++ ppsStore[PPS.pic_parameter_set_id] = PPS; ++ } ++ ++ inline void cContext::Define(cSliceHeader &SH) ++ { ++ SH.defined = true; ++ SH.picOrderCntType = ActiveSPS()->pic_order_cnt_type; ++ ++ // ITU-T Rec. H.264 (03/2005): 7.4.1.2.4 ++ SH.isFirstSliceOfCurrentAccessUnit = !sh.Defined() ++ || (sh.frame_num != SH.frame_num) ++ || (sh.pic_parameter_set_id != SH.pic_parameter_set_id) ++ || (sh.field_pic_flag != SH.field_pic_flag) ++ || (sh.bottom_field_flag != SH.bottom_field_flag) ++ || (sh.nalRefIdc != SH.nalRefIdc ++ && (sh.nalRefIdc == 0 || SH.nalRefIdc == 0)) ++ || (sh.picOrderCntType == 0 && SH.picOrderCntType == 0 ++ && (sh.pic_order_cnt_lsb != SH.pic_order_cnt_lsb ++ || sh.delta_pic_order_cnt_bottom != SH.delta_pic_order_cnt_bottom)) ++ || (sh.picOrderCntType == 1 && SH.picOrderCntType == 1 ++ && (sh.delta_pic_order_cnt[0] != SH.delta_pic_order_cnt[0] ++ || sh.delta_pic_order_cnt[1] != SH.delta_pic_order_cnt[1])) ++ || (sh.nalUnitType != SH.nalUnitType ++ && (sh.nalUnitType == 5 || SH.nalUnitType == 5)) ++ || (sh.nalUnitType == 5 && SH.nalUnitType == 5 ++ && sh.idr_pic_id != SH.idr_pic_id); ++ ++ sh = SH; ++ } ++ ++ inline void cContext::Define(cPictureTiming &PT) ++ { ++ PT.defined = true; ++ ((cSequenceParameterSet *)ActiveSPS())->pic_timing_sei = PT; ++ } ++ ++ // --- cSimpleBuffer ------------------------------------------------------- ++ ++ class cSimpleBuffer { ++ private: ++ uchar *data; ++ int size; ++ int avail; ++ int gotten; ++ public: ++ cSimpleBuffer(int Size); ++ ~cSimpleBuffer(); ++ int Size(void) { return size; } ++ int Available(void) { return avail; } ++ int Free(void) { return size - avail; } ++ int Put(const uchar *Data, int Count); ++ uchar *Get(int &Count); ++ void Del(int Count); ++ void Clear(void); ++ }; ++ ++ // --- cParser ------------------------------------------------------------- ++ ++ class cParser { ++ private: ++ bool syncing; ++ bool omitPicTiming; ++ cContext context; ++ cSimpleBuffer nalUnitDataBuffer; ++ void hrd_parameters(cSequenceParameterSet &SPS, cBitReader &br); ++ void ParseSequenceParameterSet(uint8_t *Data, int Count); ++ void ParsePictureParameterSet(uint8_t *Data, int Count); ++ void ParseSlice(uint8_t *Data, int Count); ++ void reserved_sei_message(uint32_t payloadSize, cBitReader &br); ++ void pic_timing(uint32_t payloadSize, cBitReader &br); ++ void buffering_period(uint32_t payloadSize, cBitReader &br); ++ void sei_payload(uint32_t payloadType, uint32_t payloadSize, cBitReader &br); ++ void sei_message(cBitReader &br); ++ void ParseSEI(uint8_t *Data, int Count); ++ public: ++ cParser(bool OmitPicTiming = true); ++ const cContext &Context(void) const { return context; } ++ void PutNalUnitData(const uchar *Data, int Count); ++ void Reset(void); ++ void Process(void); ++ }; ++} ++ ++#endif // __H264PARSER_H ++ +diff -ruNp vdr-1.7.0-extensions/libsi/util.c vdr-1.7.0-ext-h264-s2ng-speedup/libsi/util.c +--- vdr-1.7.0-extensions/libsi/util.c 2006-02-18 12:17:50.000000000 +0100 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/libsi/util.c 2009-04-12 23:57:23.000000000 +0200 +@@ -219,58 +219,73 @@ time_t DVBTime::getDuration(unsigned cha + + //taken and adapted from libdtv, (c) Rolf Hakenes + // CRC32 lookup table for polynomial 0x04c11db7 ++// swapped bytes to avoid one shift operation in CRC loop (c) Reinhard Nissl + u_int32_t CRC32::crc_table[256] = { +- 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, +- 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, +- 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, +- 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, +- 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, +- 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, +- 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, +- 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, +- 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, +- 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, +- 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, +- 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, +- 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, +- 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, +- 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, +- 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, +- 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, +- 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, +- 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, +- 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, +- 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, +- 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, +- 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, +- 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, +- 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, +- 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, +- 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, +- 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, +- 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, +- 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, +- 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, +- 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, +- 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, +- 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, +- 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, +- 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, +- 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, +- 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, +- 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, +- 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, +- 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, +- 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, +- 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; ++ 0x00000000, 0xb71dc104, 0x6e3b8209, 0xd926430d, 0xdc760413, 0x6b6bc517, ++ 0xb24d861a, 0x0550471e, 0xb8ed0826, 0x0ff0c922, 0xd6d68a2f, 0x61cb4b2b, ++ 0x649b0c35, 0xd386cd31, 0x0aa08e3c, 0xbdbd4f38, 0x70db114c, 0xc7c6d048, ++ 0x1ee09345, 0xa9fd5241, 0xacad155f, 0x1bb0d45b, 0xc2969756, 0x758b5652, ++ 0xc836196a, 0x7f2bd86e, 0xa60d9b63, 0x11105a67, 0x14401d79, 0xa35ddc7d, ++ 0x7a7b9f70, 0xcd665e74, 0xe0b62398, 0x57abe29c, 0x8e8da191, 0x39906095, ++ 0x3cc0278b, 0x8bdde68f, 0x52fba582, 0xe5e66486, 0x585b2bbe, 0xef46eaba, ++ 0x3660a9b7, 0x817d68b3, 0x842d2fad, 0x3330eea9, 0xea16ada4, 0x5d0b6ca0, ++ 0x906d32d4, 0x2770f3d0, 0xfe56b0dd, 0x494b71d9, 0x4c1b36c7, 0xfb06f7c3, ++ 0x2220b4ce, 0x953d75ca, 0x28803af2, 0x9f9dfbf6, 0x46bbb8fb, 0xf1a679ff, ++ 0xf4f63ee1, 0x43ebffe5, 0x9acdbce8, 0x2dd07dec, 0x77708634, 0xc06d4730, ++ 0x194b043d, 0xae56c539, 0xab068227, 0x1c1b4323, 0xc53d002e, 0x7220c12a, ++ 0xcf9d8e12, 0x78804f16, 0xa1a60c1b, 0x16bbcd1f, 0x13eb8a01, 0xa4f64b05, ++ 0x7dd00808, 0xcacdc90c, 0x07ab9778, 0xb0b6567c, 0x69901571, 0xde8dd475, ++ 0xdbdd936b, 0x6cc0526f, 0xb5e61162, 0x02fbd066, 0xbf469f5e, 0x085b5e5a, ++ 0xd17d1d57, 0x6660dc53, 0x63309b4d, 0xd42d5a49, 0x0d0b1944, 0xba16d840, ++ 0x97c6a5ac, 0x20db64a8, 0xf9fd27a5, 0x4ee0e6a1, 0x4bb0a1bf, 0xfcad60bb, ++ 0x258b23b6, 0x9296e2b2, 0x2f2bad8a, 0x98366c8e, 0x41102f83, 0xf60dee87, ++ 0xf35da999, 0x4440689d, 0x9d662b90, 0x2a7bea94, 0xe71db4e0, 0x500075e4, ++ 0x892636e9, 0x3e3bf7ed, 0x3b6bb0f3, 0x8c7671f7, 0x555032fa, 0xe24df3fe, ++ 0x5ff0bcc6, 0xe8ed7dc2, 0x31cb3ecf, 0x86d6ffcb, 0x8386b8d5, 0x349b79d1, ++ 0xedbd3adc, 0x5aa0fbd8, 0xeee00c69, 0x59fdcd6d, 0x80db8e60, 0x37c64f64, ++ 0x3296087a, 0x858bc97e, 0x5cad8a73, 0xebb04b77, 0x560d044f, 0xe110c54b, ++ 0x38368646, 0x8f2b4742, 0x8a7b005c, 0x3d66c158, 0xe4408255, 0x535d4351, ++ 0x9e3b1d25, 0x2926dc21, 0xf0009f2c, 0x471d5e28, 0x424d1936, 0xf550d832, ++ 0x2c769b3f, 0x9b6b5a3b, 0x26d61503, 0x91cbd407, 0x48ed970a, 0xfff0560e, ++ 0xfaa01110, 0x4dbdd014, 0x949b9319, 0x2386521d, 0x0e562ff1, 0xb94beef5, ++ 0x606dadf8, 0xd7706cfc, 0xd2202be2, 0x653deae6, 0xbc1ba9eb, 0x0b0668ef, ++ 0xb6bb27d7, 0x01a6e6d3, 0xd880a5de, 0x6f9d64da, 0x6acd23c4, 0xddd0e2c0, ++ 0x04f6a1cd, 0xb3eb60c9, 0x7e8d3ebd, 0xc990ffb9, 0x10b6bcb4, 0xa7ab7db0, ++ 0xa2fb3aae, 0x15e6fbaa, 0xccc0b8a7, 0x7bdd79a3, 0xc660369b, 0x717df79f, ++ 0xa85bb492, 0x1f467596, 0x1a163288, 0xad0bf38c, 0x742db081, 0xc3307185, ++ 0x99908a5d, 0x2e8d4b59, 0xf7ab0854, 0x40b6c950, 0x45e68e4e, 0xf2fb4f4a, ++ 0x2bdd0c47, 0x9cc0cd43, 0x217d827b, 0x9660437f, 0x4f460072, 0xf85bc176, ++ 0xfd0b8668, 0x4a16476c, 0x93300461, 0x242dc565, 0xe94b9b11, 0x5e565a15, ++ 0x87701918, 0x306dd81c, 0x353d9f02, 0x82205e06, 0x5b061d0b, 0xec1bdc0f, ++ 0x51a69337, 0xe6bb5233, 0x3f9d113e, 0x8880d03a, 0x8dd09724, 0x3acd5620, ++ 0xe3eb152d, 0x54f6d429, 0x7926a9c5, 0xce3b68c1, 0x171d2bcc, 0xa000eac8, ++ 0xa550add6, 0x124d6cd2, 0xcb6b2fdf, 0x7c76eedb, 0xc1cba1e3, 0x76d660e7, ++ 0xaff023ea, 0x18ede2ee, 0x1dbda5f0, 0xaaa064f4, 0x738627f9, 0xc49be6fd, ++ 0x09fdb889, 0xbee0798d, 0x67c63a80, 0xd0dbfb84, 0xd58bbc9a, 0x62967d9e, ++ 0xbbb03e93, 0x0cadff97, 0xb110b0af, 0x060d71ab, 0xdf2b32a6, 0x6836f3a2, ++ 0x6d66b4bc, 0xda7b75b8, 0x035d36b5, 0xb440f7b1}; ++ ++inline void swap_bytes(u_int32_t &crc) ++{ ++ unsigned char a = crc >> 24; ++ unsigned char b = crc >> 16; ++ unsigned char c = crc >> 8; ++ unsigned char d = crc; ++ ++ crc = ((d << 8 | c) << 8 | b) << 8 | a; ++} + + u_int32_t CRC32::crc32 (const char *d, int len, u_int32_t crc) + { + register int i; + const unsigned char *u=(unsigned char*)d; // Saves '& 0xff' + ++ swap_bytes(crc); ++ + for (i=0; i<len; i++) +- crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)]; ++ crc = (crc >> 8) ^ crc_table[(unsigned char)crc ^ *u++]; ++ ++ swap_bytes(crc); + + return crc; + } +diff -ruNp vdr-1.7.0-extensions/lirc.c vdr-1.7.0-ext-h264-s2ng-speedup/lirc.c +--- vdr-1.7.0-extensions/lirc.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/lirc.c 2009-04-12 23:57:23.000000000 +0200 +@@ -71,17 +71,48 @@ void cLircRemote::Action(void) + bool repeat = false; + int timeout = -1; + ++#ifdef USE_LIRCSETTINGS ++ if (Setup.LircPriorityBoost) ++ SetPriority(GetPriority() - Setup.LircPriorityBoost); ++#endif /* LIRCSETTINGS */ + while (Running() && f >= 0) { + + bool ready = cFile::FileReady(f, timeout); ++#ifdef USE_LIRCSETTINGS ++ int ret = -1; ++ if (ready) { ++ // read one line of the line oriented lirc protocol ++ for (ret = 0; ret < (int)sizeof(buf); ret++) { ++ int ch = readchar(f); ++ if (ch < 0) { ++ ret = -1; ++ break; ++ } ++ if (ch == '\n') { ++ buf[ret++] = '\0'; ++ break; ++ } ++ buf[ret] = ch; ++ } ++ } ++#else + int ret = ready ? safe_read(f, buf, sizeof(buf)) : -1; ++#endif /* LIRCSETTINGS */ + + if (ready && ret <= 0 ) { ++#ifdef USE_LIRCSETTINGS ++ esyslog("ERROR: lircd connection broken, trying to reconnect every %.1f seconds", float(Setup.LircReconnectDelay) / 1000); ++#else + esyslog("ERROR: lircd connection broken, trying to reconnect every %.1f seconds", float(RECONNECTDELAY) / 1000); ++#endif /* LIRCSETTINGS */ + close(f); + f = -1; + while (Running() && f < 0) { ++#ifdef USE_LIRCSETTINGS ++ cCondWait::SleepMs(Setup.LircReconnectDelay); ++#else + cCondWait::SleepMs(RECONNECTDELAY); ++#endif /* LIRCSETTINGS */ + if (Connect()) { + isyslog("reconnected to lircd"); + break; +@@ -98,7 +129,7 @@ void cLircRemote::Action(void) + } + if (count == 0) { + #ifdef USE_LIRCSETTINGS +- if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++ if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (1000 / (unsigned int)Setup.LircPushFreq)) + #else + if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < REPEATDELAY) + #endif /* LIRCSETTINGS */ +@@ -112,7 +143,7 @@ void cLircRemote::Action(void) + } + else { + #ifdef USE_LIRCSETTINGS +- if (LastTime.Elapsed() < (unsigned int)Setup.LircRepeatFreq) ++ if (LastTime.Elapsed() < (1000 / (unsigned int)Setup.LircRepeatFreq)) + #else + if (LastTime.Elapsed() < REPEATFREQ) + #endif /* LIRCSETTINGS */ +diff -ruNp vdr-1.7.0-extensions/Make.config.template vdr-1.7.0-ext-h264-s2ng-speedup/Make.config.template +--- vdr-1.7.0-extensions/Make.config.template 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/Make.config.template 2009-04-12 23:57:23.000000000 +0200 +@@ -59,7 +59,6 @@ CUTTIME = 1 + DDEPGENTRY = 1 + #DELTIMESHIFTREC = 1 + DOLBYINREC = 1 +-#DVBPLAYER = 1 + #DVBSETUP = 1 + #DVDARCHIVE = 1 + #DVDCHAPJUMP = 1 +@@ -90,7 +89,6 @@ SETTIME = 1 + #SOURCECAPS = 1 + #SORTRECORDS = 1 + #STREAMDEVEXT = 1 +-#SYNCEARLY = 1 + #TIMERCMD = 1 + #TIMERINFO = 1 + #TTXTSUBS = 1 +@@ -149,10 +147,6 @@ ifdef DOLBYINREC + DEFINES += -DUSE_DOLBYINREC + endif + +-ifdef DVBPLAYER +-DEFINES += -DUSE_DVBPLAYER +-endif +- + ifdef DVBSETUP + DEFINES += -DUSE_DVBSETUP + endif +@@ -269,10 +263,6 @@ ifdef STREAMDEVEXT + DEFINES += -DUSE_STREAMDEVEXT + endif + +-ifdef SYNCEARLY +-DEFINES += -DUSE_SYNCEARLY +-endif +- + ifdef TIMERCMD + DEFINES += -DUSE_TIMERCMD + endif +diff -ruNp vdr-1.7.0-extensions/Makefile vdr-1.7.0-ext-h264-s2ng-speedup/Makefile +--- vdr-1.7.0-extensions/Makefile 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/Makefile 2009-04-12 23:57:23.000000000 +0200 +@@ -41,7 +41,7 @@ OBJS = audio.o channels.o ci.o config.o + lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\ + receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\ + skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\ +- timers.o tools.o transfer.o vdr.o videodir.o ++ timers.o tools.o transfer.o vdr.o videodir.o h264parser.o + + ifdef WAREAGLEICON + OBJS += iconpatch.o +diff -ruNp vdr-1.7.0-extensions/menu.c vdr-1.7.0-ext-h264-s2ng-speedup/menu.c +--- vdr-1.7.0-extensions/menu.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/menu.c 2009-04-12 23:57:23.000000000 +0200 +@@ -249,17 +249,17 @@ void cMenuEditChannel::Setup(void) + Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name))); + Add(new cMenuEditSrcItem( tr("Source"), &data.source)); + Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); +- Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0x1FFF)); +- Add(new cMenuEditIntItem( tr("Ppid"), &data.ppid, 0, 0x1FFF)); ++ Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0x1FFF)); ++ Add(new cMenuEditIntItem( tr("Ppid"), &data.ppid, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Apid1"), &data.apids[0], 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Apid2"), &data.apids[1], 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpids[0], 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpids[1], 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Spid1"), &data.spids[0], 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Spid2"), &data.spids[1], 0, 0x1FFF)); +- Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); ++ Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); + Add(new cMenuEditCaItem( tr("CA"), &data.caids[0])); +- Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF)); ++ Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF)); + /* XXX not yet used + Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0)); + Add(new cMenuEditIntItem( tr("Tid"), &data.tid, 0)); +@@ -280,8 +280,6 @@ void cMenuEditChannel::Setup(void) + #ifdef USE_PLUGINPARAM + ST("P ") Add(new cMenuEditStrItem( tr("Parameters"), pluginParam, sizeof(pluginParam), tr(FileNameChars))); + #endif /* PLUGINPARAM */ +- ST(" T") Add(new cMenuEditMapItem( tr("Alpha"), &data.alpha, AlphaValues)); +- ST(" T") Add(new cMenuEditMapItem( tr("Priority"), &data.priority, PriorityValues)); + ST(" S ") Add(new cMenuEditMapItem( tr("Rolloff"), &data.rollOff, RollOffValues)); + + SetCurrent(Get(current)); +@@ -3341,9 +3339,6 @@ void cMenuSetupDVB::Setup(void) + Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker"), &data.ChannelBlocker, 7, ChannelBlockers)); + Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker Filter Mode"), &data.ChannelBlockerMode, 4, ChannelBlockerModes)); + #endif /* DVBSETUP */ +-#ifdef USE_SYNCEARLY +- Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Sync Early Patch"), &data.UseSyncEarlyPatch)); +-#endif /* SYNCEARLY */ + + SetCurrent(Get(current)); + Display(); +@@ -3849,9 +3844,12 @@ void cMenuSetupMisc::Setup(void) + #endif /* VOLCTRL */ + Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit)); + #ifdef USE_LIRCSETTINGS ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc push freq"), &data.LircPushFreq, 0, 100)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat delay"), &data.LircRepeatDelay, 0, 1000)); +- Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat freq"), &data.LircRepeatFreq, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat freq"), &data.LircRepeatFreq, 0, 100)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat timeout"), &data.LircRepeatTimeout, 0, 5000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc reconnect delay"), &data.LircReconnectDelay, 0, 9999)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc priority boost"), &data.LircPriorityBoost, 0, 100)); + #endif /* LIRCSETTINGS */ + } + +@@ -5891,7 +5889,7 @@ bool cReplayControl::ShowProgress(bool I + lastCurrent = lastTotal = -1; + } + if (Total != lastTotal) { +- displayReplay->SetTotal(IndexToHMSF(Total)); ++ displayReplay->SetTotal(IndexToHMSF(Total, false, GetFramesPerSec())); + if (!Initial) + displayReplay->Flush(); + } +@@ -5899,7 +5897,7 @@ bool cReplayControl::ShowProgress(bool I + displayReplay->SetProgress(Current, Total); + if (!Initial) + displayReplay->Flush(); +- displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames)); ++ displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, GetFramesPerSec())); + displayReplay->Flush(); + lastCurrent = Current; + } +@@ -5932,8 +5930,8 @@ void cReplayControl::TimeSearchProcess(e + { + #define STAY_SECONDS_OFF_END 10 + int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60; +- int Current = (lastCurrent / FRAMESPERSEC); +- int Total = (lastTotal / FRAMESPERSEC); ++ int Current = (lastCurrent / GetFramesPerSec()); ++ int Total = (lastTotal / GetFramesPerSec()); + switch (Key) { + case k0 ... k9: + if (timeSearchPos < 4) { +@@ -5960,7 +5958,7 @@ void cReplayControl::TimeSearchProcess(e + case kDown: + case kOk: + Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds); +- Goto(Seconds * FRAMESPERSEC, Key == kDown || Key == kPause || Key == kOk); ++ Goto(Seconds * GetFramesPerSec(), Key == kDown || Key == kPause || Key == kOk); + timeSearchActive = false; + break; + default: +@@ -6139,7 +6137,7 @@ void cReplayControl::EditTest(void) + #endif /* JUMPPLAY */ + m = marks.Next(m); + if (m) { +- Goto(m->position - SecondsToFrames(3)); ++ Goto(m->position - SecondsToFrames(3, GetFramesPerSec())); + Play(); + } + } +diff -ruNp vdr-1.7.0-extensions/nit.c vdr-1.7.0-ext-h264-s2ng-speedup/nit.c +--- vdr-1.7.0-extensions/nit.c 2008-04-12 14:06:40.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/nit.c 2009-04-12 23:52:16.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.1 2008/04/12 12:06:40 kls Exp $ ++ * $Id: nit.c 2.3 2008/12/20 10:57:50 kls Exp $ + */ + + #include "nit.h" +@@ -127,13 +127,13 @@ void cNitFilter::Process(u_short Pid, u_ + int Frequency = Frequencies[0] = BCD2INT(sd->getFrequency()) / 100; + static char Polarizations[] = { 'h', 'v', 'l', 'r' }; + char Polarization = Polarizations[sd->getPolarization()]; +- static int CodeRates[] = { DVBFE_FEC_NONE, DVBFE_FEC_1_2, DVBFE_FEC_2_3, DVBFE_FEC_3_4, DVBFE_FEC_5_6, DVBFE_FEC_7_8, DVBFE_FEC_8_9, DVBFE_FEC_3_5, DVBFE_FEC_4_5, DVBFE_FEC_9_10, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_NONE }; ++ static int CodeRates[] = { FEC_NONE, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_8_9, FEC_3_5, FEC_4_5, FEC_9_10, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_NONE }; + int CodeRate = CodeRates[sd->getFecInner()]; +- static int Modulations[] = { DVBFE_MOD_AUTO, DVBFE_MOD_QPSK, DVBFE_MOD_8PSK, DVBFE_MOD_QAM16 }; ++ static int Modulations[] = { QAM_AUTO, QPSK, PSK_8, QAM_16 }; + int Modulation = Modulations[sd->getModulationType()]; +- int System = sd->getModulationSystem() ? DVBFE_DELSYS_DVBS2 : DVBFE_DELSYS_DVBS; +- static int RollOffs[] = { DVBFE_ROLLOFF_35, DVBFE_ROLLOFF_25, DVBFE_ROLLOFF_20, DVBFE_ROLLOFF_UNKNOWN }; +- int RollOff = sd->getModulationSystem() ? RollOffs[sd->getRollOff()] : DVBFE_ROLLOFF_UNKNOWN; ++ int System = sd->getModulationSystem() ? SYS_DVBS2 : SYS_DVBS; ++ static int RollOffs[] = { ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_AUTO }; ++ int RollOff = sd->getModulationSystem() ? RollOffs[sd->getRollOff()] : ROLLOFF_AUTO; + int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10; + if (ThisNIT >= 0) { + for (int n = 0; n < NumFrequencies; n++) { +@@ -147,21 +147,20 @@ void cNitFilter::Process(u_short Pid, u_ + } + if (Setup.UpdateChannels >= 5) { + bool found = 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(); +- found = true; +- if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), transponder)) { +- for (int n = 0; n < NumFrequencies; n++) { +- if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), transponder)) { +- Frequency = Frequencies[n]; +- break; +- } ++ cIterator<cChannel> ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId()); ++ for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) { ++ int transponder = Channel->Transponder(); ++ found = true; ++ if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), transponder)) { ++ for (int n = 0; n < NumFrequencies; n++) { ++ if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), transponder)) { ++ Frequency = Frequencies[n]; ++ break; + } +- } +- if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) // only modify channels if we're actually receiving this transponder +- Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate, Modulation, System, RollOff); ++ } + } ++ if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) // only modify channels if we're actually receiving this transponder ++ Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate, Modulation, System, RollOff); + } + if (!found) { + for (int n = 0; n < NumFrequencies; n++) { +@@ -181,9 +180,9 @@ void cNitFilter::Process(u_short Pid, u_ + int Source = cSource::FromData(cSource::stCable); + int Frequency = Frequencies[0] = BCD2INT(sd->getFrequency()) / 10; + //XXX FEC_outer??? +- static int CodeRates[] = { DVBFE_FEC_NONE, DVBFE_FEC_1_2, DVBFE_FEC_2_3, DVBFE_FEC_3_4, DVBFE_FEC_5_6, DVBFE_FEC_7_8, DVBFE_FEC_8_9, DVBFE_FEC_3_5, DVBFE_FEC_4_5, DVBFE_FEC_9_10, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_NONE }; ++ static int CodeRates[] = { FEC_NONE, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_8_9, FEC_3_5, FEC_4_5, FEC_9_10, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_NONE }; + int CodeRate = CodeRates[sd->getFecInner()]; +- static int Modulations[] = { DVBFE_MOD_NONE, DVBFE_MOD_QAM16, DVBFE_MOD_QAM32, DVBFE_MOD_QAM64, DVBFE_MOD_QAM128, DVBFE_MOD_QAM256, QAM_AUTO }; ++ static int Modulations[] = { QPSK, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256, QAM_AUTO }; + int Modulation = Modulations[min(sd->getModulation(), 6)]; + int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10; + if (ThisNIT >= 0) { +@@ -198,21 +197,20 @@ void cNitFilter::Process(u_short Pid, u_ + } + if (Setup.UpdateChannels >= 5) { + bool found = 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(); +- found = true; +- if (!ISTRANSPONDER(Frequency / 1000, transponder)) { +- for (int n = 0; n < NumFrequencies; n++) { +- if (ISTRANSPONDER(Frequencies[n] / 1000, transponder)) { +- Frequency = Frequencies[n]; +- break; +- } ++ cIterator<cChannel> ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId()); ++ for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) { ++ int transponder = Channel->Transponder(); ++ found = true; ++ if (!ISTRANSPONDER(Frequency / 1000, transponder)) { ++ for (int n = 0; n < NumFrequencies; n++) { ++ if (ISTRANSPONDER(Frequencies[n] / 1000, transponder)) { ++ Frequency = Frequencies[n]; ++ break; + } +- } +- if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder +- Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate); ++ } + } ++ if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder ++ Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate); + } + if (!found) { + for (int n = 0; n < NumFrequencies; n++) { +@@ -231,22 +229,19 @@ void cNitFilter::Process(u_short Pid, u_ + SI::TerrestrialDeliverySystemDescriptor *sd = (SI::TerrestrialDeliverySystemDescriptor *)d; + int Source = cSource::FromData(cSource::stTerr); + int Frequency = Frequencies[0] = sd->getFrequency() * 10; +- static int Bandwidths[] = { DVBFE_BANDWIDTH_8_MHZ, DVBFE_BANDWIDTH_7_MHZ, DVBFE_BANDWIDTH_6_MHZ, DVBFE_BANDWIDTH_5_MHZ, DVBFE_BANDWIDTH_AUTO, DVBFE_BANDWIDTH_AUTO, DVBFE_BANDWIDTH_AUTO, DVBFE_BANDWIDTH_AUTO }; ++ static int Bandwidths[] = { 8000000, 7000000, 6000000, 0, 0, 0, 0, 0 }; + int Bandwidth = Bandwidths[sd->getBandwidth()]; +- static int Constellations[] = { DVBFE_MOD_QPSK, DVBFE_MOD_QAM16, DVBFE_MOD_QAM64, DVBFE_MOD_AUTO }; ++ static int Constellations[] = { QPSK, QAM_16, QAM_64, QAM_AUTO }; + int Constellation = Constellations[sd->getConstellation()]; +- static int CodeRates[] = { DVBFE_FEC_1_2, DVBFE_FEC_2_3, DVBFE_FEC_3_4, DVBFE_FEC_5_6, DVBFE_FEC_7_8, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO, DVBFE_FEC_AUTO }; ++ static int Hierarchies[] = { HIERARCHY_NONE, HIERARCHY_1, HIERARCHY_2, HIERARCHY_4, HIERARCHY_AUTO, HIERARCHY_AUTO, HIERARCHY_AUTO, HIERARCHY_AUTO }; ++ int Hierarchy = Hierarchies[sd->getHierarchy()]; ++ static int CodeRates[] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_AUTO, FEC_AUTO, FEC_AUTO }; + int CodeRateHP = CodeRates[sd->getCodeRateHP()]; + int CodeRateLP = CodeRates[sd->getCodeRateLP()]; +- static int GuardIntervals[] = { DVBFE_GUARD_INTERVAL_1_32, DVBFE_GUARD_INTERVAL_1_16, DVBFE_GUARD_INTERVAL_1_8, DVBFE_GUARD_INTERVAL_1_4 }; ++ static int GuardIntervals[] = { GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_4 }; + int GuardInterval = GuardIntervals[sd->getGuardInterval()]; +- static int TransmissionModes[] = { DVBFE_TRANSMISSION_MODE_2K, DVBFE_TRANSMISSION_MODE_8K, DVBFE_TRANSMISSION_MODE_4K, DVBFE_TRANSMISSION_MODE_AUTO }; ++ static int TransmissionModes[] = { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO }; + int TransmissionMode = TransmissionModes[sd->getTransmissionMode()]; +- static int Priorities[] = { DVBFE_STREAM_PRIORITY_LP, DVBFE_STREAM_PRIORITY_HP }; +- int Priority = Priorities[sd->getPriority()]; +- static int Alphas[] = { 0, DVBFE_ALPHA_1, DVBFE_ALPHA_2, DVBFE_ALPHA_4 }; +- int Alpha = Alphas[sd->getHierarchy() & 3]; +- int Hierarchy = Alpha ? DVBFE_HIERARCHY_ON : DVBFE_HIERARCHY_OFF; + if (ThisNIT >= 0) { + for (int n = 0; n < NumFrequencies; n++) { + if (ISTRANSPONDER(Frequencies[n] / 1000000, Transponder())) { +@@ -259,32 +254,31 @@ void cNitFilter::Process(u_short Pid, u_ + } + if (Setup.UpdateChannels >= 5) { + bool found = 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(); +- found = true; +- if (!ISTRANSPONDER(Frequency / 1000000, transponder)) { +- for (int n = 0; n < NumFrequencies; n++) { +- if (ISTRANSPONDER(Frequencies[n] / 1000000, transponder)) { +- Frequency = Frequencies[n]; +- break; +- } ++ cIterator<cChannel> ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId()); ++ for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) { ++ int transponder = Channel->Transponder(); ++ found = true; ++ if (!ISTRANSPONDER(Frequency / 1000000, transponder)) { ++ for (int n = 0; n < NumFrequencies; n++) { ++ if (ISTRANSPONDER(Frequencies[n] / 1000000, transponder)) { ++ Frequency = Frequencies[n]; ++ break; + } +- } +- if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder +- Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode, Alpha, Priority); ++ } + } ++ if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder ++ Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode); + } + if (!found) { + for (int n = 0; n < NumFrequencies; n++) { + cChannel *Channel = new cChannel; + Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0); +- if (Channel->SetTerrTransponderData(Source, Frequencies[n], Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode, Alpha, Priority)) ++ if (Channel->SetTerrTransponderData(Source, Frequencies[n], Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode)) + EITScanner.AddTransponder(Channel); + else + delete Channel; + } +- } ++ } + } + } + break; +diff -ruNp vdr-1.7.0-extensions/osd.c vdr-1.7.0-ext-h264-s2ng-speedup/osd.c +--- vdr-1.7.0-extensions/osd.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/osd.c 2009-04-12 23:57:23.000000000 +0200 +@@ -220,6 +220,8 @@ bool cBitmap::Contains(int x, int y) con + + bool cBitmap::Covers(int x1, int y1, int x2, int y2) const + { ++ if (x1 > x2 || y1 > y2) // sanity check ++ return false; + x1 -= x0; + y1 -= y0; + x2 -= x0; +@@ -229,6 +231,8 @@ bool cBitmap::Covers(int x1, int y1, int + + bool cBitmap::Intersects(int x1, int y1, int x2, int y2) const + { ++ if (x1 > x2 || y1 > y2) // sanity check ++ return false; + x1 -= x0; + y1 -= y0; + x2 -= x0; +@@ -397,15 +401,20 @@ bool cBitmap::SetXpm(const char *const X + void cBitmap::SetIndex(int x, int y, tIndex Index) + { + if (bitmap) { +- if (0 <= x && x < width && 0 <= y && y < height) { +- if (bitmap[width * y + x] != Index) { +- bitmap[width * y + x] = Index; +- if (dirtyX1 > x) dirtyX1 = x; +- if (dirtyY1 > y) dirtyY1 = y; +- if (dirtyX2 < x) dirtyX2 = x; +- if (dirtyY2 < y) dirtyY2 = y; +- } +- } ++ if (0 <= x && x < width && 0 <= y && y < height) ++ SetIndexInternal(x, y, Index); ++ } ++} ++ ++void cBitmap::SetIndexInternal(int x, int y, tIndex Index) ++{ ++ // this function relies on existing bitmap and valid coordinates ++ if (bitmap[width * y + x] != Index) { ++ bitmap[width * y + x] = Index; ++ if (dirtyX1 > x) dirtyX1 = x; ++ if (dirtyY1 > y) dirtyY1 = y; ++ if (dirtyX2 < x) dirtyX2 = x; ++ if (dirtyY2 < y) dirtyY2 = y; + } + } + +@@ -413,37 +422,147 @@ void cBitmap::DrawPixel(int x, int y, tC + { + x -= x0; + y -= y0; +- if (0 <= x && x < width && 0 <= y && y < height) +- SetIndex(x, y, Index(Color)); ++ if (bitmap && 0 <= x && x < width && 0 <= y && y < height) ++ SetIndexInternal(x, y, Index(Color)); + } + + void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay) + { + if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) { +- if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) ++ bool Covered = Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1); ++ if (Covered) + Reset(); + x -= x0; + y -= y0; +- if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) { ++ // determine valid destination area [x1,x2]x[y1,y2] to avoid range checks inside the loops ++ int x1 = max(0, x), x2 = min(0 + width , x + Bitmap.width) - 1; ++ int y1 = max(0, y), y2 = min(0 + height, y + Bitmap.height) - 1; ++ ++#define FOR_Y_LOOP0 \ ++ tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ ++ tIndex *pRowDst = &bitmap[width * y1 + x1]; \ ++ for (int &yy = y1, ye = min(y2, dirtyY1 - 1); yy <= ye; yy++, pRowDst += width, pRowSrc += Bitmap.width) ++ ++#define FOR_Y_LOOP1 \ ++ tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y2 - y) + (x1 - x)]; \ ++ tIndex *pRowDst = &bitmap[width * y2 + x1]; \ ++ for (int &yy = y2, ye = max(y1, dirtyY2 + 1); yy >= ye; yy--, pRowDst -= width, pRowSrc -= Bitmap.width) ++ ++#define DETECT_DIRTY_AREA_Y(Reverse, TransferCondition, TransferOperation) \ ++ do { \ ++ FOR_Y_LOOP##Reverse { \ ++ tIndex *pSrc = pRowSrc; \ ++ tIndex *pDst = pRowDst; \ ++ bool GotDirty = false; \ ++ for (int xx = x1; xx <= x2; xx++) { \ ++ if (TransferCondition) { \ ++ if (*pDst != TransferOperation) { \ ++ GotDirty = true; \ ++ if (dirtyX1 > xx) dirtyX1 = xx; \ ++ if (dirtyX2 < xx) dirtyX2 = xx; \ ++ } \ ++ } \ ++ pSrc++; \ ++ pDst++; \ ++ } \ ++ if (GotDirty) { \ ++ if (dirtyY1 > yy) dirtyY1 = yy; \ ++ if (dirtyY2 < yy) dirtyY2 = yy; \ ++ break; \ ++ } \ ++ } \ ++ } \ ++ while (false) ++ ++#define FOR_X_LOOP0 \ ++ tIndex *pColSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ ++ tIndex *pColDst = &bitmap[width * y1 + x1]; \ ++ for (int &xx = x1, xe = min(x2, dirtyX1 - 1); xx <= xe; xx++, pColDst++, pColSrc++) ++ ++#define FOR_X_LOOP1 \ ++ tIndex *pColSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x2 - x)]; \ ++ tIndex *pColDst = &bitmap[width * y1 + x2]; \ ++ for (int &xx = x2, xe = max(x1, dirtyX2 + 1); xx >= xe; xx--, pColDst--, pColSrc--) ++ ++#define DETECT_DIRTY_AREA_X(Reverse, TransferCondition, TransferOperation) \ ++ do { \ ++ FOR_X_LOOP##Reverse { \ ++ tIndex *pSrc = pColSrc; \ ++ tIndex *pDst = pColDst; \ ++ bool GotDirty = false; \ ++ for (int yy = y1; yy <= y2; yy++) { \ ++ if (TransferCondition) { \ ++ if (*pDst != TransferOperation) { \ ++ GotDirty = true; \ ++ if (dirtyX1 > xx) dirtyX1 = xx; \ ++ if (dirtyX2 < xx) dirtyX2 = xx; \ ++ break; \ ++ } \ ++ } \ ++ pSrc += Bitmap.width; \ ++ pDst += width; \ ++ } \ ++ if (GotDirty) \ ++ break; \ ++ } \ ++ } \ ++ while (false) ++ ++#define DRAW_BITMAP(TransferCondition, TransferOperation, CanUseMemCpy) \ ++ do { \ ++ DETECT_DIRTY_AREA_Y(0, TransferCondition, TransferOperation); /* above */ \ ++ DETECT_DIRTY_AREA_Y(1, TransferCondition, TransferOperation); /* below */ \ ++ if (y2 < y1) /* nothing dirty */ \ ++ return; \ ++ DETECT_DIRTY_AREA_X(0, TransferCondition, TransferOperation); /* left */ \ ++ DETECT_DIRTY_AREA_X(1, TransferCondition, TransferOperation); /* right */ \ ++ /* process dirty area now */ \ ++ tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ ++ tIndex *pRowDst = &bitmap[width * y1 + x1]; \ ++ int n = sizeof(tIndex) * (x2 - x1 + 1); \ ++ for (int yy = y1; yy <= y2; yy++) { \ ++ tIndex *pSrc = pRowSrc; \ ++ tIndex *pDst = pRowDst; \ ++ if (CanUseMemCpy) \ ++ memcpy(pDst, pSrc, n); \ ++ else { \ ++ for (int xx = x1; xx <= x2; xx++) { \ ++ if (TransferCondition) \ ++ *pDst = TransferOperation; \ ++ pSrc++; \ ++ pDst++; \ ++ } \ ++ } \ ++ pRowSrc += Bitmap.width; \ ++ pRowDst += width; \ ++ } \ ++ } \ ++ while (false) ++ ++ if (ReplacePalette && Covered) { + Replace(Bitmap); +- for (int ix = 0; ix < Bitmap.width; ix++) { +- for (int iy = 0; iy < Bitmap.height; iy++) { +- if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) +- SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]); +- } +- } ++ if (Overlay) ++ DRAW_BITMAP(*pSrc != 0, *pSrc, false); ++ else ++ DRAW_BITMAP(true, *pSrc, true); + } + else { + tIndexes Indexes; + Take(Bitmap, &Indexes, ColorFg, ColorBg); +- for (int ix = 0; ix < Bitmap.width; ix++) { +- for (int iy = 0; iy < Bitmap.height; iy++) { +- if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) +- SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]); +- } +- } ++ if (Overlay) ++ DRAW_BITMAP(*pSrc != 0, Indexes[(int)*pSrc], false); ++ else ++ DRAW_BITMAP(true, Indexes[(int)*pSrc], false); + } + } ++ ++#undef DRAW_BITMAP ++#undef DETECT_DIRTY_AREA_Y ++#undef FOR_Y_LOOP0 ++#undef FOR_Y_LOOP1 ++#undef DETECT_DIRTY_AREA_X ++#undef FOR_X_LOOP0 ++#undef FOR_X_LOOP1 + } + + void cBitmap::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) +@@ -505,10 +624,91 @@ void cBitmap::DrawRectangle(int x1, int + x2 = min(x2, width - 1); + y2 = min(y2, height - 1); + tIndex c = Index(Color); +- for (int y = y1; y <= y2; y++) +- for (int x = x1; x <= x2; x++) +- SetIndex(x, y, c); ++ ++#define FOR_Y_LOOP0 \ ++ tIndex *pRowDst = &bitmap[width * y1 + x1]; \ ++ for (int &yy = y1, ye = min(y2, dirtyY1 - 1); yy <= ye; yy++, pRowDst += width) ++ ++#define FOR_Y_LOOP1 \ ++ tIndex *pRowDst = &bitmap[width * y2 + x1]; \ ++ for (int &yy = y2, ye = max(y1, dirtyY2 + 1); yy >= ye; yy--, pRowDst -= width) ++ ++#define DETECT_DIRTY_AREA_Y(Reverse) \ ++ do { \ ++ FOR_Y_LOOP##Reverse { \ ++ tIndex *pDst = pRowDst; \ ++ bool GotDirty = false; \ ++ for (int xx = x1; xx <= x2; xx++) { \ ++ if (*pDst != c) { \ ++ GotDirty = true; \ ++ if (dirtyX1 > xx) dirtyX1 = xx; \ ++ if (dirtyX2 < xx) dirtyX2 = xx; \ ++ } \ ++ pDst++; \ ++ } \ ++ if (GotDirty) { \ ++ if (dirtyY1 > yy) dirtyY1 = yy; \ ++ if (dirtyY2 < yy) dirtyY2 = yy; \ ++ break; \ ++ } \ ++ } \ ++ } \ ++ while (false) ++ ++#define FOR_X_LOOP0 \ ++ tIndex *pColDst = &bitmap[width * y1 + x1]; \ ++ for (int &xx = x1, xe = min(x2, dirtyX1 - 1); xx <= xe; xx++, pColDst++) ++ ++#define FOR_X_LOOP1 \ ++ tIndex *pColDst = &bitmap[width * y1 + x2]; \ ++ for (int &xx = x2, xe = max(x1, dirtyX2 + 1); xx >= xe; xx--, pColDst--) ++ ++#define DETECT_DIRTY_AREA_X(Reverse) \ ++ do { \ ++ FOR_X_LOOP##Reverse { \ ++ tIndex *pDst = pColDst; \ ++ bool GotDirty = false; \ ++ for (int yy = y1; yy <= y2; yy++) { \ ++ if (*pDst != c) { \ ++ GotDirty = true; \ ++ if (dirtyX1 > xx) dirtyX1 = xx; \ ++ if (dirtyX2 < xx) dirtyX2 = xx; \ ++ break; \ ++ } \ ++ pDst += width; \ ++ } \ ++ if (GotDirty) \ ++ break; \ ++ } \ ++ } \ ++ while (false) ++ ++ DETECT_DIRTY_AREA_Y(0); /* above */ ++ DETECT_DIRTY_AREA_Y(1); /* below */ ++ if (y2 < y1) /* nothing dirty */ ++ return; ++ DETECT_DIRTY_AREA_X(0); /* left */ ++ DETECT_DIRTY_AREA_X(1); /* right */ ++ // now fill only dirty area of rectangle ++ tIndex *pRowDst = &bitmap[width * y1 + x1]; ++ tIndex *pDst = pRowDst; ++ for (int x = x1; x <= x2; x++) ++ *pDst++ = c; ++ // copy the single line above to all other lines ++ tIndex *pRowSrc = pRowDst; ++ int n = sizeof(tIndex) * (x2 - x1 + 1); ++ for (int y = y1 + 1; y <= y2; y++) { ++ pRowDst += width; ++ memcpy(pRowDst, pRowSrc, n); ++ } + } ++ ++#undef DETECT_DIRTY_AREA_Y ++#undef FOR_Y_LOOP0 ++#undef FOR_Y_LOOP1 ++#undef DETECT_DIRTY_AREA_X ++#undef FOR_X_LOOP0 ++#undef FOR_X_LOOP1 + } + + void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants) +diff -ruNp vdr-1.7.0-extensions/osd.h vdr-1.7.0-ext-h264-s2ng-speedup/osd.h +--- vdr-1.7.0-extensions/osd.h 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/osd.h 2009-04-12 23:57:23.000000000 +0200 +@@ -135,6 +135,7 @@ private: + int x0, y0; + int width, height; + int dirtyX1, dirtyY1, dirtyX2, dirtyY2; ++ void SetIndexInternal(int x, int y, tIndex Index); + public: + cBitmap(int Width, int Height, int Bpp, int X0 = 0, int Y0 = 0); + ///< Creates a bitmap with the given Width, Height and color depth (Bpp). +diff -ruNp vdr-1.7.0-extensions/pat.c vdr-1.7.0-ext-h264-s2ng-speedup/pat.c +--- vdr-1.7.0-extensions/pat.c 2008-04-12 15:34:50.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/pat.c 2008-07-06 16:01:32.000000000 +0200 +@@ -4,7 +4,7 @@ + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * +- * $Id: pat.c 2.1 2008/04/12 13:34:50 kls Exp $ ++ * $Id: pat.c 2.2 2008/07/06 14:01:32 kls Exp $ + */ + + #include "pat.h" +@@ -328,7 +328,8 @@ void cPatFilter::Process(u_short Pid, u_ + // Scan the stream-specific loop: + SI::PMT::Stream stream; + int Vpid = 0; +- int Ppid = pmt.getPCRPid(); ++ int Ppid = 0; ++ int Vtype = 0; + int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated + int Dpids[MAXDPIDS + 1] = { 0 }; + int Spids[MAXSPIDS + 1] = { 0 }; +@@ -343,8 +344,10 @@ void cPatFilter::Process(u_short Pid, u_ + switch (stream.getStreamType()) { + case 1: // STREAMTYPE_11172_VIDEO + case 2: // STREAMTYPE_13818_VIDEO +-//TODO case 0x1B: // MPEG4 ++ case 0x1B: // MPEG4 + Vpid = stream.getPid(); ++ Ppid = pmt.getPCRPid(); ++ Vtype = stream.getStreamType(); + break; + case 3: // STREAMTYPE_11172_AUDIO + case 4: // STREAMTYPE_13818_AUDIO +@@ -440,7 +443,7 @@ void cPatFilter::Process(u_short Pid, u_ + } + } + if (Setup.UpdateChannels >= 2) { +- Channel->SetPids(Vpid, Vpid ? Ppid : 0, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid); ++ Channel->SetPids(Vpid, Ppid, Vtype, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid); + Channel->SetCaIds(CaDescriptors->CaIds()); + } + Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors)); +diff -ruNp vdr-1.7.0-extensions/po/de_DE.po vdr-1.7.0-ext-h264-s2ng-speedup/po/de_DE.po +--- vdr-1.7.0-extensions/po/de_DE.po 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/po/de_DE.po 2009-04-12 23:57:23.000000000 +0200 +@@ -809,6 +809,9 @@ msgstr "Vor-/Rücklauf mit Rechts/Links" + msgid "Setup.Miscellaneous$only in progress display" + msgstr "nur in Fortschrittsanzeige" + ++msgid "Setup.Miscellaneous$Lirc push freq" ++msgstr "Lirc Druck Frequenz" ++ + msgid "Setup.Miscellaneous$Lirc repeat delay" + msgstr "Lirc Verzögerung" + +@@ -818,6 +821,12 @@ msgstr "Lirc Frequenz" + msgid "Setup.Miscellaneous$Lirc repeat timeout" + msgstr "Lirc Zeitbeschränkung" + ++msgid "Setup.Miscellaneous$Lirc reconnect delay" ++msgstr "Lirc Verbindungs Verzögerung" ++ ++msgid "Setup.Miscellaneous$Lirc priority boost" ++msgstr "Lirc Prioritäts Verstärkung" ++ + msgid "Plugins" + msgstr "Plugins" + +@@ -1170,9 +1179,6 @@ msgstr "ist primär" + msgid "has decoder + is primary" + msgstr "mit Decoder und primär" + +-msgid "Setup.DVB$Use Sync Early Patch" +-msgstr "Sync Early Patch benutzen" +- + msgid "Setup.LNB$DVB device %d uses LNB No." + msgstr "DVB-Empfänger %d nutzt LNB Nr." + +diff -ruNp vdr-1.7.0-extensions/recording.c vdr-1.7.0-ext-h264-s2ng-speedup/recording.c +--- vdr-1.7.0-extensions/recording.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/recording.c 2009-04-12 23:57:23.000000000 +0200 +@@ -2272,11 +2272,11 @@ cUnbufferedFile *cFileName::NextFile(voi + + // --- Index stuff ----------------------------------------------------------- + +-cString IndexToHMSF(int Index, bool WithFrame) ++cString IndexToHMSF(int Index, bool WithFrame, int FramesPerSec) + { + char buffer[16]; +- int f = (Index % FRAMESPERSEC) + 1; +- int s = (Index / FRAMESPERSEC); ++ int f = (Index % FramesPerSec) + 1; ++ int s = (Index / FramesPerSec); + int m = s / 60 % 60; + int h = s / 3600; + s %= 60; +@@ -2284,17 +2284,17 @@ cString IndexToHMSF(int Index, bool With + return buffer; + } + +-int HMSFToIndex(const char *HMSF) ++int HMSFToIndex(const char *HMSF, int FramesPerSec) + { + int h, m, s, f = 0; + if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f)) +- return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1; ++ return (h * 3600 + m * 60 + s) * FramesPerSec + f - 1; + return 0; + } + +-int SecondsToFrames(int Seconds) ++int SecondsToFrames(int Seconds, int FramesPerSec) + { +- return Seconds * FRAMESPERSEC; ++ return Seconds * FramesPerSec; + } + + // --- ReadFrame ------------------------------------------------------------- +diff -ruNp vdr-1.7.0-extensions/recording.h vdr-1.7.0-ext-h264-s2ng-speedup/recording.h +--- vdr-1.7.0-extensions/recording.h 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/recording.h 2009-04-12 23:57:23.000000000 +0200 +@@ -349,11 +349,11 @@ public: + cUnbufferedFile *NextFile(void); + }; + +-cString IndexToHMSF(int Index, bool WithFrame = false); ++cString IndexToHMSF(int Index, bool WithFrame = false, int FramesPerSec = FRAMESPERSEC); + // Converts the given index to a string, optionally containing the frame number. +-int HMSFToIndex(const char *HMSF); ++int HMSFToIndex(const char *HMSF, int FramesPerSec = FRAMESPERSEC); + // Converts the given string (format: "hh:mm:ss.ff") to an index. +-int SecondsToFrames(int Seconds); //XXX+ ->player??? ++int SecondsToFrames(int Seconds, int FramesPerSec = FRAMESPERSEC); //XXX+ ->player??? + // Returns the number of frames corresponding to the given number of seconds. + + int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max); +diff -ruNp vdr-1.7.0-extensions/remux.c vdr-1.7.0-ext-h264-s2ng-speedup/remux.c +--- vdr-1.7.0-extensions/remux.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/remux.c 2009-04-12 23:57:23.000000000 +0200 +@@ -19,6 +19,8 @@ + #include "channels.h" + #include "shutdown.h" + #include "tools.h" ++#include "recording.h" ++#include "h264parser.h" + + ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader) + { +@@ -100,8 +102,9 @@ protected: + int suppressedLogMessages; + bool LogAllowed(void); + void DroppedData(const char *Reason, int Count) { LOG("%s (dropped %d bytes)", Reason, Count); } ++ virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded); + public: +- static int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded); ++ static int PutAllOrNothing(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded); + cRepacker(void); + virtual ~cRepacker() {} + virtual void Reset(void) { initiallySyncing = true; } +@@ -138,6 +141,11 @@ bool cRepacker::LogAllowed(void) + + int cRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded) + { ++ return PutAllOrNothing(ResultBuffer, Data, Count, CapacityNeeded); ++} ++ ++int cRepacker::PutAllOrNothing(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded) ++{ + if (CapacityNeeded >= Count && ResultBuffer->Free() < CapacityNeeded) { + esyslog("ERROR: possible result buffer overflow, dropped %d out of %d byte", CapacityNeeded, CapacityNeeded); + return 0; +@@ -156,7 +164,7 @@ protected: + int packetTodo; + uchar fragmentData[6 + 65535 + 3]; + int fragmentLen; +- uchar pesHeader[6 + 3 + 255 + 3]; ++ uchar pesHeader[6 + 3 + 255 + 5 + 3]; // 5: H.264 AUD + int pesHeaderLen; + uchar pesHeaderBackup[6 + 3 + 255]; + int pesHeaderBackupLen; +@@ -164,7 +172,7 @@ protected: + uint32_t localScanner; + int localStart; + bool PushOutPacket(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count); +- virtual int QuerySnoopSize() { return 4; } ++ virtual int QuerySnoopSize(void) { return 4; } + virtual void Reset(void); + }; + +@@ -238,8 +246,139 @@ bool cCommonRepacker::PushOutPacket(cRin + return true; + } + ++// --- cAudGenerator --------------------------------------------------------- ++ ++class cAudGenerator { ++private: ++ H264::cSimpleBuffer buffer; ++ int overflowByteCount; ++ H264::cSliceHeader::eAccessUnitType accessUnitType; ++ int sliceTypes; ++public: ++ cAudGenerator(void); ++ void CollectSliceType(const H264::cSliceHeader *SH); ++ int CollectData(const uchar *Data, int Count); ++ void Generate(cRingBufferLinear *const ResultBuffer); ++}; ++ ++cAudGenerator::cAudGenerator() ++ : buffer(MAXFRAMESIZE) ++{ ++ overflowByteCount = 0; ++ accessUnitType = H264::cSliceHeader::Frame; ++ sliceTypes = 0; ++} ++ ++int cAudGenerator::CollectData(const uchar *Data, int Count) ++{ ++ // buffer frame data until AUD can be generated ++ int n = buffer.Put(Data, Count); ++ overflowByteCount += (Count - n); ++ // always report "success" as an error message will be shown in Generate() ++ return Count; ++} ++ ++void cAudGenerator::CollectSliceType(const H264::cSliceHeader *SH) ++{ ++ if (!SH) ++ return; ++ // remember type of current access unit ++ accessUnitType = SH->GetAccessUnitType(); ++ // translate slice_type into part of primary_pic_type and merge them ++ switch (SH->slice_type) { ++ case 2: // I ++ case 7: // I only => I ++ sliceTypes |= 0x10000; ++ break; ++ case 0: // P ++ case 5: // P only => I, P ++ sliceTypes |= 0x11000; ++ break; ++ case 1: // B ++ case 6: // B only => I, P, B ++ sliceTypes |= 0x11100; ++ break; ++ case 4: // SI ++ case 9: // SI only => SI ++ sliceTypes |= 0x00010; ++ break; ++ case 3: // SP ++ case 8: // SP only => SI, SP ++ sliceTypes |= 0x00011; ++ break; ++ } ++} ++ ++void cAudGenerator::Generate(cRingBufferLinear *const ResultBuffer) ++{ ++ int primary_pic_type; ++ // translate the merged primary_pic_type parts into primary_pic_type ++ switch (sliceTypes) { ++ case 0x10000: // I ++ primary_pic_type = 0; ++ break; ++ case 0x11000: // I, P ++ primary_pic_type = 1; ++ break; ++ case 0x11100: // I, P, B ++ primary_pic_type = 2; ++ break; ++ case 0x00010: // SI ++ primary_pic_type = 3; ++ break; ++ case 0x00011: // SI, SP ++ primary_pic_type = 4; ++ break; ++ case 0x10010: // I, SI ++ primary_pic_type = 5; ++ break; ++ case 0x11011: // I, SI, P, SP ++ case 0x10011: // I, SI, SP ++ case 0x11010: // I, SI, P ++ primary_pic_type = 6; ++ break; ++ case 0x11111: // I, SI, P, SP, B ++ case 0x11110: // I, SI, P, B ++ primary_pic_type = 7; ++ break; ++ default: ++ primary_pic_type = -1; // frame without slices? ++ } ++ // drop an incorrect frame ++ if (primary_pic_type < 0) ++ esyslog("ERROR: cAudGenerator::Generate(): dropping frame without slices"); ++ else { ++ // drop a partitial frame ++ if (overflowByteCount > 0) ++ esyslog("ERROR: cAudGenerator::Generate(): frame exceeds MAXFRAMESIZE bytes (required size: %d bytes), dropping frame", buffer.Size() + overflowByteCount); ++ else { ++ int Count; ++ uchar *Data = buffer.Get(Count); ++ int PesPayloadOffset = 0; ++ AnalyzePesHeader(Data, Count, PesPayloadOffset); ++ // enter primary_pic_type into AUD ++ Data[ PesPayloadOffset + 4 ] |= primary_pic_type << 5; ++ // mangle the "start code" to pass the information that this access unit is a ++ // bottom field to ScanVideoPacket() where this modification will be reverted. ++ if (accessUnitType == H264::cSliceHeader::BottomField) ++ Data[ PesPayloadOffset + 3 ] |= 0x80; ++ // store the buffered frame ++ cRepacker::PutAllOrNothing(ResultBuffer, Data, Count, Count); ++ } ++ } ++ // prepare for next run ++ buffer.Clear(); ++ overflowByteCount = 0; ++ sliceTypes = 0; ++} ++ + // --- cVideoRepacker -------------------------------------------------------- + ++#define IPACKS 2048 ++#define SC_SEQUENCE 0xB3 // "sequence header code" ++#define SC_GROUP 0xB8 // "group start code" ++#define SC_PICTURE 0x00 // "picture start code" ++ + class cVideoRepacker : public cCommonRepacker { + private: + enum eState { +@@ -248,37 +387,243 @@ private: + scanPicture + }; + int state; +- void HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel); ++ bool framePicture; ++ bool pictureExtensionAhead; ++ bool collectChunkData; ++ H264::cSimpleBuffer chunkData; ++ H264::cParser *h264Parser; ++ bool &h264; ++ int sliceSeen; ++ bool audSeen; ++ cAudGenerator *audGenerator; ++ const uchar *startCodeLocations[(IPACKS + 3) / 4]; ++ int startCodeLocationCount; ++ int startCodeLocationIndex; ++ bool startCodeLocationsPrepared; ++ void CheckAudGeneration(bool SliceNalUnitType, bool SyncPoint, const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel); ++ void PushOutCurrentFrameAndStartNewPacket(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel); ++ void HandleNalUnit(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel, const uchar *&NalPayload); ++ void HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel, const uchar *&ChunkPayload); + inline bool ScanDataForStartCodeSlow(const uchar *const Data); + inline bool ScanDataForStartCodeFast(const uchar *&Data, const uchar *Limit); +- inline bool ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo); ++ inline bool ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo, int PesPayloadOffset); + inline void AdjustCounters(const int Delta, int &Done, int &Todo); + inline bool ScanForEndOfPictureSlow(const uchar *&Data); + inline bool ScanForEndOfPictureFast(const uchar *&Data, const uchar *Limit); + inline bool ScanForEndOfPicture(const uchar *&Data, const uchar *Limit); ++ inline void PushStartCodeLocation(const uchar *Data); ++ inline const uchar *PeekStartCodeLocation(void); ++ inline const uchar *PullStartCodeLocation(void); ++ void CollectData(const uchar *Data, int Count); ++ void BeginCollectingPictureExtension(void); ++ void EndCollectingPictureExtension(void); ++ bool DetermineFramePicture(void); ++ void GenerateFieldPicturesHint(bool FramePicture, const uchar *const Data, const uchar AndMask, const uchar OrMask); ++ void SwitchToMpeg12(void); ++protected: ++ virtual int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded); + public: +- cVideoRepacker(void); ++ cVideoRepacker(bool &H264); ++ ~cVideoRepacker(); + virtual void Reset(void); + virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count); + virtual int BreakAt(const uchar *Data, int Count); + }; + +-cVideoRepacker::cVideoRepacker(void) +-{ ++cVideoRepacker::cVideoRepacker(bool &H264) ++: chunkData(1024) ++, h264(H264) ++{ ++ // assume H.264 -- we'll fallback to MPEG1/2 when necessary ++ h264 = true; ++ h264Parser = (H264 ? new H264::cParser() : 0); ++ audGenerator = 0; + Reset(); + } + ++cVideoRepacker::~cVideoRepacker() ++{ ++ delete h264Parser; ++ delete audGenerator; ++} ++ + void cVideoRepacker::Reset(void) + { + cCommonRepacker::Reset(); ++ if (h264Parser) ++ h264Parser->Reset(); + scanner = 0xFFFFFFFF; + state = syncing; ++ framePicture = true; ++ pictureExtensionAhead = false; ++ collectChunkData = false; ++ chunkData.Clear(); ++ sliceSeen = -1; ++ audSeen = false; ++ delete audGenerator; ++ audGenerator = 0; ++ startCodeLocationCount = 0; ++ startCodeLocationsPrepared = false; + } + +-void cVideoRepacker::HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel) ++void cVideoRepacker::SwitchToMpeg12(void) + { +- // synchronisation is detected some bytes after frame start. +- const int SkippedBytesLimit = 4; ++ if (!h264Parser) ++ return; ++ dsyslog("cVideoRepacker: switching to MPEG1/2 mode"); ++ delete h264Parser; ++ h264Parser = 0; ++ delete audGenerator; ++ audGenerator = 0; ++ h264 = false; ++} ++ ++int cVideoRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded) ++{ ++ if (!audGenerator) ++ return cCommonRepacker::Put(ResultBuffer, Data, Count, CapacityNeeded); ++ ++ return audGenerator->CollectData(Data, Count); ++} ++ ++void cVideoRepacker::CollectData(const uchar *Data, int Count) ++{ ++ if (h264Parser) ++ h264Parser->PutNalUnitData(Data, Count); ++ else if (collectChunkData) ++ chunkData.Put(Data, Count); ++} ++ ++void cVideoRepacker::HandleNalUnit(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel, const uchar *&NalPayload) ++{ ++ // check whether we need to fall back to MPEG1/2 ++ if (initiallySyncing) { ++ switch (*Data) { ++ case SC_SEQUENCE: ++ case SC_GROUP: ++ case SC_PICTURE: ++ // the above start codes do not appear in H.264 so let's switch to MPEG1/2 ++ SwitchToMpeg12(); ++ // delegate startcode to appropriate handler ++ HandleStartCode(Data, ResultBuffer, Payload, StreamID, MpegLevel, NalPayload); ++ return; ++ } ++ } ++ ++ // valid NAL units start with a zero bit ++ if (*Data & 0x80) { ++ LOG("cVideoRepacker: found invalid NAL unit: stream seems to be scrambled or not demultiplexed"); ++ return; ++ } ++ ++ // collect NAL unit's remaining data and process it ++ CollectData(NalPayload, Data - 3 - NalPayload); ++ h264Parser->Process(); ++ ++ // which kind of NAL unit have we got? ++ const int nal_unit_type = *Data & 0x1F; ++ switch (nal_unit_type) { ++ case 1: // coded slice of a non-IDR picture ++ case 2: // coded slice data partition A ++ case 5: // coded slice of an IDR picture ++ CheckAudGeneration(true, false, Data, ResultBuffer, Payload, StreamID, MpegLevel); ++ break; ++ case 3: // coded slice data partition B ++ case 4: // coded slice data partition C ++ case 19: // coded slice of an auxiliary coded picture without partitioning ++ break; ++ case 6: // supplemental enhancement information (SEI) ++ case 7: // sequence parameter set ++ case 8: // picture parameter set ++ case 10: // end of sequence ++ case 11: // end of stream ++ case 13: // sequence parameter set extension ++ CheckAudGeneration(false, nal_unit_type == 7, Data, ResultBuffer, Payload, StreamID, MpegLevel); ++ break; ++ case 12: // filler data ++ break; ++ case 14 ... 18: // reserved ++ CheckAudGeneration(false, false, Data, ResultBuffer, Payload, StreamID, MpegLevel); ++ case 20 ... 23: // reserved ++ LOG("cVideoRepacker: found reserved NAL unit type: stream seems to be scrambled"); ++ break; ++ case 0: // unspecified ++ case 24 ... 31: // unspecified ++ LOG("cVideoRepacker: found unspecified NAL unit type: stream seems to be scrambled"); ++ break; ++ case 9: { // access unit delimiter ++ audSeen = true; ++ CheckAudGeneration(false, true, Data, ResultBuffer, Payload, StreamID, MpegLevel); ++ // mangle the "start code" to pass the information "the next access unit will be the ++ // second field of the current frame" to ScanVideoPacket() where this modification ++ // will be reverted. ++ const H264::cSliceHeader *SH = h264Parser->Context().CurrentSlice(); ++ GenerateFieldPicturesHint(!SH || SH->GetAccessUnitType() == H264::cSliceHeader::Frame, Data, 0xFF, 0x80); ++ } ++ break; ++ } ++ ++ // collect 0x00 0x00 0x01 for current NAL unit ++ static const uchar InitPayload[3] = { 0x00, 0x00, 0x01 }; ++ CollectData(InitPayload, sizeof (InitPayload)); ++ NalPayload = Data; ++} ++ ++void cVideoRepacker::GenerateFieldPicturesHint(bool FramePicture, const uchar *const Data, const uchar AndMask, const uchar OrMask) ++{ ++ if (FramePicture) ++ framePicture = true; ++ else { ++ framePicture ^= true; // toggle between frame/first field and second field ++ if (!framePicture) { ++ // the last picture was a field so set a hint for this second field ++ *(uchar *)Data &= AndMask; ++ *(uchar *)Data |= OrMask; ++ } ++ } ++} ++ ++void cVideoRepacker::CheckAudGeneration(bool SliceNalUnitType, bool SyncPoint, const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel) ++{ ++ // we cannot generate anything until we have reached the synchronisation point ++ if (sliceSeen < 0 && !SyncPoint) ++ return; ++ // detect transition from slice to non-slice NAL units ++ const bool WasSliceSeen = (sliceSeen != false); ++ const bool IsSliceSeen = SliceNalUnitType; ++ sliceSeen = IsSliceSeen; ++ // collect slice types for AUD generation ++ if (WasSliceSeen && audGenerator) ++ audGenerator->CollectSliceType(h264Parser->Context().CurrentSlice()); ++ // handle access unit delimiter at the transition from slice to non-slice NAL units ++ if (WasSliceSeen && !IsSliceSeen) { ++ // an Access Unit Delimiter indicates that the current picture is done. So let's ++ // push out the current frame to start a new packet for the next picture. ++ PushOutCurrentFrameAndStartNewPacket(Data, ResultBuffer, Payload, StreamID, MpegLevel); ++ if (state == findPicture) { ++ // go on with scanning the picture data ++ state++; ++ } ++ // generate the AUD and push out the buffered frame ++ if (audGenerator) { ++ audGenerator->Generate(ResultBuffer); ++ if (audSeen) { ++ // we nolonger need to generate AUDs as they are part of the stream ++ delete audGenerator; ++ audGenerator = 0; ++ } ++ } ++ else if (!audSeen) // we do need to generate AUDs ++ audGenerator = new cAudGenerator; ++ } ++} ++ ++void cVideoRepacker::HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel, const uchar *&ChunkPayload) ++{ ++ // collect chunk's remaining data ++ CollectData(ChunkPayload, Data - 3 - ChunkPayload); ++ // currently, only picture extension is collected, so end collecting now ++ EndCollectingPictureExtension(); + + // which kind of start code have we got? + switch (*Data) { +@@ -292,71 +637,25 @@ void cVideoRepacker::HandleStartCode(con + case 0xB4: // sequence error code + LOG("cVideoRepacker: found sequence error code: stream seems to be damaged"); + case 0xB2: // user data start code ++ break; + case 0xB5: // extension start code ++ if (pictureExtensionAhead) { ++ pictureExtensionAhead = false; ++ // mangle the "start code" to pass the information "the next access unit will be the ++ // second field of the current frame" to ScanVideoPacket() where this modification ++ // will be reverted. ++ GenerateFieldPicturesHint(DetermineFramePicture(), Data, 0x00, 0xB9); ++ BeginCollectingPictureExtension(); ++ } + break; +- case 0xB7: // sequence end code +- case 0xB3: // sequence header code +- case 0xB8: // group start code + case 0x00: // picture start code +- if (state == scanPicture) { +- // the above start codes indicate that the current picture is done. So +- // push out the packet to start a new packet for the next picuture. If +- // the byte count get's negative then the current buffer ends in a +- // partitial start code that must be stripped off, as it shall be put +- // in the next packet. +- PushOutPacket(ResultBuffer, Payload, Data - 3 - Payload); +- // go on with syncing to the next picture +- state = syncing; +- } +- if (state == syncing) { +- if (initiallySyncing) // omit report for the typical initial case +- initiallySyncing = false; +- else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes +- LOG("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit); +- skippedBytes = 0; +- // if there is a PES header available, then use it ... +- if (pesHeaderBackupLen > 0) { +- // ISO 13818-1 says: +- // In the case of video, if a PTS is present in a PES packet header +- // it shall refer to the access unit containing the first picture start +- // code that commences in this PES packet. A picture start code commences +- // in PES packet if the first byte of the picture start code is present +- // in the PES packet. +- memcpy(pesHeader, pesHeaderBackup, pesHeaderBackupLen); +- pesHeaderLen = pesHeaderBackupLen; +- pesHeaderBackupLen = 0; +- } +- else { +- // ... otherwise create a continuation PES header +- pesHeaderLen = 0; +- pesHeader[pesHeaderLen++] = 0x00; +- pesHeader[pesHeaderLen++] = 0x00; +- pesHeader[pesHeaderLen++] = 0x01; +- pesHeader[pesHeaderLen++] = StreamID; // video stream ID +- pesHeader[pesHeaderLen++] = 0x00; // length still unknown +- pesHeader[pesHeaderLen++] = 0x00; // length still unknown +- +- if (MpegLevel == phMPEG2) { +- pesHeader[pesHeaderLen++] = 0x80; +- pesHeader[pesHeaderLen++] = 0x00; +- pesHeader[pesHeaderLen++] = 0x00; +- } +- else +- pesHeader[pesHeaderLen++] = 0x0F; +- } +- // append the first three bytes of the start code +- pesHeader[pesHeaderLen++] = 0x00; +- pesHeader[pesHeaderLen++] = 0x00; +- pesHeader[pesHeaderLen++] = 0x01; +- // the next packet's payload will begin with the fourth byte of +- // the start code (= the actual code) +- Payload = Data; +- // as there is no length information available, assume the +- // maximum we can hold in one PES packet +- packetTodo = maxPacketSize - pesHeaderLen; +- // go on with finding the picture data +- state++; +- } ++ pictureExtensionAhead = true; ++ case 0xB8: // group start code ++ case 0xB3: // sequence header code ++ case 0xB7: // sequence end code ++ // the above start codes indicate that the current picture is done. So let's ++ // push out the current frame to start a new packet for the next picture. ++ PushOutCurrentFrameAndStartNewPacket(Data, ResultBuffer, Payload, StreamID, MpegLevel); + break; + case 0x01 ... 0xAF: // slice start codes + if (state == findPicture) { +@@ -365,6 +664,116 @@ void cVideoRepacker::HandleStartCode(con + } + break; + } ++ ++ // collect 0x00 0x00 0x01 for current chunk ++ static const uchar InitPayload[3] = { 0x00, 0x00, 0x01 }; ++ CollectData(InitPayload, sizeof (InitPayload)); ++ ChunkPayload = Data; ++} ++ ++void cVideoRepacker::BeginCollectingPictureExtension(void) ++{ ++ chunkData.Clear(); ++ collectChunkData = true; ++} ++ ++void cVideoRepacker::EndCollectingPictureExtension(void) ++{ ++ collectChunkData = false; ++} ++ ++bool cVideoRepacker::DetermineFramePicture(void) ++{ ++ bool FieldPicture = false; ++ int Count; ++ uchar *Data = chunkData.Get(Count); ++ if (Data && Count >= 7) { ++ if (!Data[0] && !Data[1] && Data[2] == 0x01 && (Data[3] == 0xB5 || Data[3] == 0xB9)) { // extension startcode or hint ++ if ((Data[4] & 0xF0) == 0x80) { // picture coding extension ++ int picture_structure = Data[6] & 0x03; ++ FieldPicture = picture_structure == 0x01 || picture_structure == 0x02; ++ } ++ } ++ } ++if (FieldPicture) fprintf(stderr, "----- MPEG2 field picture detected ---------------------------\n"); ++ return !FieldPicture; ++} ++ ++void cVideoRepacker::PushOutCurrentFrameAndStartNewPacket(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel) ++{ ++ // synchronisation is detected some bytes after frame start. ++ const int SkippedBytesLimit = 4; ++ ++ if (state == scanPicture) { ++ // picture data has been found so let's push out the current frame. ++ // If the byte count get's negative then the current buffer ends in a ++ // partitial start code that must be stripped off, as it shall be put ++ // in the next packet. ++ PushOutPacket(ResultBuffer, Payload, Data - 3 - Payload); ++ // go on with syncing to the next picture ++ state = syncing; ++ } ++ // when already synced to a picture, just go on collecting data ++ if (state != syncing) ++ return; ++ // we're synced to a picture so prepare a new packet ++ if (initiallySyncing) { // omit report for the typical initial case ++ initiallySyncing = false; ++ isyslog("cVideoRepacker: operating in %s mode", h264Parser ? "H.264" : "MPEG1/2"); ++ } ++ else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes ++ LOG("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit); ++ skippedBytes = 0; ++ // if there is a PES header available, then use it ... ++ if (pesHeaderBackupLen > 0) { ++ // ISO 13818-1 says: ++ // In the case of video, if a PTS is present in a PES packet header ++ // it shall refer to the access unit containing the first picture start ++ // code that commences in this PES packet. A picture start code commences ++ // in PES packet if the first byte of the picture start code is present ++ // in the PES packet. ++ memcpy(pesHeader, pesHeaderBackup, pesHeaderBackupLen); ++ pesHeaderLen = pesHeaderBackupLen; ++ pesHeaderBackupLen = 0; ++ } ++ else { ++ // ... otherwise create a continuation PES header ++ pesHeaderLen = 0; ++ pesHeader[pesHeaderLen++] = 0x00; ++ pesHeader[pesHeaderLen++] = 0x00; ++ pesHeader[pesHeaderLen++] = 0x01; ++ pesHeader[pesHeaderLen++] = StreamID; // video stream ID ++ pesHeader[pesHeaderLen++] = 0x00; // length still unknown ++ pesHeader[pesHeaderLen++] = 0x00; // length still unknown ++ ++ if (MpegLevel == phMPEG2) { ++ pesHeader[pesHeaderLen++] = 0x80; ++ pesHeader[pesHeaderLen++] = 0x00; ++ pesHeader[pesHeaderLen++] = 0x00; ++ } ++ else ++ pesHeader[pesHeaderLen++] = 0x0F; ++ } ++ // add an AUD in H.264 mode when not present in stream ++ if (h264Parser && !audSeen) { ++ pesHeader[pesHeaderLen++] = 0x00; ++ pesHeader[pesHeaderLen++] = 0x00; ++ pesHeader[pesHeaderLen++] = 0x01; ++ pesHeader[pesHeaderLen++] = 0x09; // access unit delimiter ++ pesHeader[pesHeaderLen++] = 0x10; // will be filled later ++ } ++ // append the first three bytes of the start code ++ pesHeader[pesHeaderLen++] = 0x00; ++ pesHeader[pesHeaderLen++] = 0x00; ++ pesHeader[pesHeaderLen++] = 0x01; ++ // the next packet's payload will begin with the fourth byte of ++ // the start code (= the actual code) ++ Payload = Data; ++ // as there is no length information available, assume the ++ // maximum we can hold in one PES packet ++ packetTodo = maxPacketSize - pesHeaderLen; ++ // go on with finding the picture data ++ state++; + } + + bool cVideoRepacker::ScanDataForStartCodeSlow(const uchar *const Data) +@@ -377,6 +786,13 @@ bool cVideoRepacker::ScanDataForStartCod + + bool cVideoRepacker::ScanDataForStartCodeFast(const uchar *&Data, const uchar *Limit) + { ++ // We enter here when it is safe to access at least 3 bytes before Data (e. g. ++ // the tail of a previous run) and one byte after Data (xx yy zz [aa] bb {cc}). ++ // On return, Data shall either point to the last valid byte of the block or to ++ // the byte qualifying the start code (00 00 01 [ss]). ++ // As we are searching for 0x01, we've to move pointers (xx yy [zz] aa {bb} cc) ++ // to find start code "aa" for example after a packet boundery. ++ Data--; + Limit--; + + while (Data < Limit && (Data = (const uchar *)memchr(Data, 0x01, Limit - Data))) { +@@ -394,29 +810,66 @@ bool cVideoRepacker::ScanDataForStartCod + return false; + } + +-bool cVideoRepacker::ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo) ++bool cVideoRepacker::ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo, int PesPayloadOffset) + { +- const uchar *const DataOrig = Data; +- const int MinDataSize = 4; ++ const int ReasonableDataSizeForFastScanning = 12; + +- if (Todo < MinDataSize || (state != syncing && packetTodo < MinDataSize)) +- return ScanDataForStartCodeSlow(Data); ++ if (!startCodeLocationsPrepared) { ++ // use slow scanning until it is safe to use fast scanning ++ if (Done < PesPayloadOffset + 3) ++ return ScanDataForStartCodeSlow(Data); ++ ++ // process available data but not more than needed for the current packet ++ int Limit = Todo; ++ if (state != syncing && Limit > packetTodo) ++ Limit = packetTodo; ++ ++ // use slow scanning when there is not enough data left ++ if (Limit < ReasonableDataSizeForFastScanning) ++ return ScanDataForStartCodeSlow(Data); ++ ++ // it's reasonable to use fast scanning ++ const uchar *const DataOrig = Data; ++ bool FoundStartCode = ScanDataForStartCodeFast(Data, Data + Limit); ++ AdjustCounters(Data - DataOrig, Done, Todo); ++ return FoundStartCode; ++ } + +- int Limit = Todo; +- if (state != syncing && Limit > packetTodo) +- Limit = packetTodo; ++ // process available data but not more than needed for the current packet ++ const uchar *Limit = Data + Todo - 1; ++ if (state != syncing && Todo > packetTodo) { ++ if (packetTodo <= 0) // overfill phase ++ Limit = Data; // do a single ScanDataForStartCodeSlow() below ++ else ++ Limit = Data + packetTodo - 1; ++ } + +- if (ScanDataForStartCodeSlow(Data)) +- return true; ++ // prepare the "not found" case ++ bool FoundStartCode = false; ++ const uchar *const DataOrig = Data; ++ Data = Limit; + +- if (ScanDataForStartCodeSlow(++Data)) { +- AdjustCounters(1, Done, Todo); +- return true; ++ // get the next start code location which fits into the limit ++ const uchar *p = PeekStartCodeLocation(); ++ if (p && p <= Limit) { ++ Data = PullStartCodeLocation(); ++ FoundStartCode = true; + } +- ++Data; + +- bool FoundStartCode = ScanDataForStartCodeFast(Data, DataOrig + Limit); +- AdjustCounters(Data - DataOrig, Done, Todo); ++ // setup the scanner variable ++ int bite = Data - DataOrig; ++ if (bite <= 3) { ++ // to few data, need to do byte shifting ++ for (int i = 0; i <= bite; i++) ++ ScanDataForStartCodeSlow(DataOrig + i); ++ } ++ else { ++ // it's safe to access the last 4 bytes directly ++ uint32_t *Scanner = (uint32_t *)(Data - 3); ++ scanner = ntohl(*Scanner); ++ } ++ ++ AdjustCounters(bite, Done, Todo); + return FoundStartCode; + } + +@@ -458,14 +911,19 @@ void cVideoRepacker::Repack(cRingBufferL + const uchar *data = Data + done; + // remember start of the data + const uchar *payload = data; +- ++ const uchar *ChunkPayload = payload; ++ startCodeLocationIndex = 0; + while (todo > 0) { + // collect number of skipped bytes while syncing + if (state <= syncing) + skippedBytes++; + // did we reach a start code? +- if (ScanDataForStartCode(data, done, todo)) +- HandleStartCode(data, ResultBuffer, payload, Data[3], mpegLevel); ++ if (ScanDataForStartCode(data, done, todo, pesPayloadOffset)) { ++ if (h264Parser) ++ HandleNalUnit(data, ResultBuffer, payload, Data[3], mpegLevel, ChunkPayload); ++ else ++ HandleStartCode(data, ResultBuffer, payload, Data[3], mpegLevel, ChunkPayload); ++ } + // move on + data++; + done++; +@@ -568,31 +1026,75 @@ void cVideoRepacker::Repack(cRingBufferL + fragmentLen += bite; + } + } ++ // collect data as needed ++ CollectData(ChunkPayload, data - ChunkPayload); + // report that syncing dropped some bytes + if (skippedBytes > SkippedBytesLimit) { + if (!initiallySyncing) // omit report for the typical initial case + LOG("cVideoRepacker: skipped %d bytes while syncing on next picture", skippedBytes - SkippedBytesLimit); + skippedBytes = SkippedBytesLimit; + } ++ startCodeLocationCount = 0; ++} ++ ++void cVideoRepacker::PushStartCodeLocation(const uchar *Data) ++{ ++ startCodeLocations[startCodeLocationCount++] = Data; ++} ++ ++const uchar *cVideoRepacker::PeekStartCodeLocation() ++{ ++ if (startCodeLocationIndex < startCodeLocationCount) ++ return startCodeLocations[startCodeLocationIndex]; ++ return 0; ++} ++ ++const uchar *cVideoRepacker::PullStartCodeLocation() ++{ ++ const uchar *p = PeekStartCodeLocation(); ++ if (p != 0) ++ startCodeLocationIndex++; ++ return p; + } + + bool cVideoRepacker::ScanForEndOfPictureSlow(const uchar *&Data) + { + localScanner <<= 8; ++ if (localScanner != 0x00000100) { ++ localScanner |= *Data++; ++ return false; ++ } ++ PushStartCodeLocation(Data); + localScanner |= *Data++; + // check start codes which follow picture data +- switch (localScanner) { +- case 0x00000100: // picture start code +- case 0x000001B8: // group start code +- case 0x000001B3: // sequence header code +- case 0x000001B7: // sequence end code +- return true; +- } ++ if (h264Parser) { ++ int nal_unit_type = localScanner & 0x1F; ++ switch (nal_unit_type) { ++ case 9: // access unit delimiter ++ return true; ++ } ++ } ++ else { ++ switch (localScanner) { ++ case 0x00000100: // picture start code ++ case 0x000001B8: // group start code ++ case 0x000001B3: // sequence header code ++ case 0x000001B7: // sequence end code ++ return true; ++ } ++ } + return false; + } + + bool cVideoRepacker::ScanForEndOfPictureFast(const uchar *&Data, const uchar *Limit) + { ++ // We enter here when it is safe to access at least 3 bytes before Data (e. g. ++ // the tail of a previous run) and one byte after Data (xx yy zz [aa] bb {cc}). ++ // On return, Data shall either point to the first byte outside of the block or ++ // to the byte following the start code (00 00 01 ss [tt]). ++ // As we are searching for 0x01, we've to move pointers (xx yy [zz] aa {bb} cc) ++ // to find start code "aa" for example after a packet boundery. ++ Data--; + Limit--; + + while (Data < Limit && (Data = (const uchar *)memchr(Data, 0x01, Limit - Data))) { +@@ -600,16 +1102,29 @@ bool cVideoRepacker::ScanForEndOfPicture + Data += 3; + else { + localScanner = 0x00000100 | *++Data; ++ PushStartCodeLocation(Data); + // check start codes which follow picture data +- switch (localScanner) { +- case 0x00000100: // picture start code +- case 0x000001B8: // group start code +- case 0x000001B3: // sequence header code +- case 0x000001B7: // sequence end code +- Data++; +- return true; +- default: +- Data += 3; ++ if (h264Parser) { ++ int nal_unit_type = localScanner & 0x1F; ++ switch (nal_unit_type) { ++ case 9: // access unit delimiter ++ Data++; ++ return true; ++ default: ++ Data += 3; ++ } ++ } ++ else { ++ switch (localScanner) { ++ case 0x00000100: // picture start code ++ case 0x000001B8: // group start code ++ case 0x000001B3: // sequence header code ++ case 0x000001B7: // sequence end code ++ Data++; ++ return true; ++ default: ++ Data += 3; ++ } + } + } + } +@@ -622,57 +1137,55 @@ bool cVideoRepacker::ScanForEndOfPicture + + bool cVideoRepacker::ScanForEndOfPicture(const uchar *&Data, const uchar *Limit) + { +- const uchar *const DataOrig = Data; +- const int MinDataSize = 4; +- bool FoundEndOfPicture; ++ const int ReasonableDataSizeForFastScanning = 12; + +- if (Limit - Data <= MinDataSize) { +- FoundEndOfPicture = false; +- while (Data < Limit) { ++ const uchar *const ReasonableLimit = Limit - ReasonableDataSizeForFastScanning; ++ bool FoundEndOfPicture = false; ++ ++ while (Data < Limit) { ++ // use slow scanning until it is safe or reasonable to use fast scanning ++ if (localStart < 3 || Data >= ReasonableLimit) { ++ localStart++; + if (ScanForEndOfPictureSlow(Data)) { + FoundEndOfPicture = true; + break; + } + } +- } +- else { +- FoundEndOfPicture = true; +- if (!ScanForEndOfPictureSlow(Data)) { +- if (!ScanForEndOfPictureSlow(Data)) { +- if (!ScanForEndOfPictureFast(Data, Limit)) +- FoundEndOfPicture = false; ++ else { ++ const uchar *const DataOrig = Data; ++ FoundEndOfPicture = ScanForEndOfPictureFast(Data, Limit); ++ localStart += (Data - DataOrig); ++ break; + } + } +- } + +- localStart += (Data - DataOrig); + return FoundEndOfPicture; + } + + int cVideoRepacker::BreakAt(const uchar *Data, int Count) + { +- if (initiallySyncing) +- return -1; // fill the packet buffer completely until we have synced once +- + int PesPayloadOffset = 0; + + if (AnalyzePesHeader(Data, Count, PesPayloadOffset) <= phInvalid) + return -1; // not enough data for test + +- // just detect end of picture +- if (state == scanPicture) { +- // setup local scanner +- if (localStart < 0) { +- localScanner = scanner; +- localStart = 0; +- } +- // start where we've stopped at the last run +- const uchar *data = Data + PesPayloadOffset + localStart; +- const uchar *limit = Data + Count; +- // scan data +- if (ScanForEndOfPicture(data, limit)) ++ // setup local scanner ++ if (localStart < 0) { ++ localScanner = scanner; ++ localStart = 0; ++ } ++ // start where we've stopped at the last run ++ const uchar *data = Data + PesPayloadOffset + localStart; ++ const uchar *limit = Data + Count; ++ // scan data ++ startCodeLocationsPrepared = true; ++ if (ScanForEndOfPicture(data, limit)) { ++ // just detect end of picture ++ if (state == scanPicture && !initiallySyncing) + return data - Data; + } ++ if (initiallySyncing) ++ return -1; // fill the packet buffer completely until we have synced once + // just fill up packet and append next start code + return PesPayloadOffset + packetTodo + 4; + } +@@ -690,12 +1203,13 @@ private: + int frameTodo; + int frameSize; + int cid; +- static bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL); ++ static bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL, int *FrameDuration = NULL); + public: + cAudioRepacker(int Cid); + virtual void Reset(void); + virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count); + virtual int BreakAt(const uchar *Data, int Count); ++ static int GetFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL); + }; + + int cAudioRepacker::bitRates[2][3][16] = { // all values are specified as kbits/s +@@ -711,6 +1225,25 @@ int cAudioRepacker::bitRates[2][3][16] = + } + }; + ++int cAudioRepacker::GetFrameDuration(const uchar *Data, int Count, int *TrackIndex) ++{ ++ int PesPayloadOffset = 0; ++ ePesHeader PH = AnalyzePesHeader(Data, Count, PesPayloadOffset); ++ if (PH < phMPEG1) ++ return -1; ++ ++ const uchar *Payload = Data + PesPayloadOffset; ++ const int PayloadCount = Count - PesPayloadOffset; ++ ++ int FrameDuration = -1; ++ if ((Data[3] & 0xE0) == 0xC0 && PayloadCount >= 4) { ++ if (IsValidAudioHeader(((Payload[0] << 8 | Payload[1]) << 8 | Payload[2]) << 8 | Payload[3], PH == phMPEG2, NULL, &FrameDuration) && TrackIndex) ++ *TrackIndex = Data[3] - 0xC0; ++ } ++ ++ return FrameDuration; ++} ++ + cAudioRepacker::cAudioRepacker(int Cid) + { + cid = Cid; +@@ -726,7 +1259,7 @@ void cAudioRepacker::Reset(void) + frameSize = 0; + } + +-bool cAudioRepacker::IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize) ++bool cAudioRepacker::IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize, int *FrameDuration) + { + int syncword = (Header & 0xFFF00000) >> 20; + int id = (Header & 0x00080000) >> 19; +@@ -760,32 +1293,36 @@ bool cAudioRepacker::IsValidAudioHeader( + if (emphasis == 2) // reserved + return false; + +- if (FrameSize) { +- if (bitrate_index == 0) +- *FrameSize = 0; +- else { +- static int samplingFrequencies[2][4] = { // all values are specified in Hz +- { 44100, 48000, 32000, -1 }, // MPEG 1 +- { 22050, 24000, 16000, -1 } // MPEG 2 +- }; +- +- static int slots_per_frame[2][3] = { +- { 12, 144, 144 }, // MPEG 1, Layer I, II, III +- { 12, 144, 72 } // MPEG 2, Layer I, II, III +- }; +- +- int mpegIndex = 1 - id; +- int layerIndex = 3 - layer; +- +- // Layer I (i. e., layerIndex == 0) has a larger slot size +- int slotSize = (layerIndex == 0) ? 4 : 1; // bytes +- +- int br = 1000 * bitRates[mpegIndex][layerIndex][bitrate_index]; // bits/s +- int sf = samplingFrequencies[mpegIndex][sampling_frequency]; +- +- int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots ++ if (FrameSize || FrameDuration) { ++ static int samplingFrequencies[2][4] = { // all values are specified in Hz ++ { 44100, 48000, 32000, -1 }, // MPEG 1 ++ { 22050, 24000, 16000, -1 } // MPEG 2 ++ }; ++ ++ static int slots_per_frame[2][3] = { ++ { 12, 144, 144 }, // MPEG 1, Layer I, II, III ++ { 12, 144, 72 } // MPEG 2, Layer I, II, III ++ }; ++ ++ int mpegIndex = 1 - id; ++ int layerIndex = 3 - layer; ++ ++ // Layer I (i. e., layerIndex == 0) has a larger slot size ++ int slotSize = (layerIndex == 0) ? 4 : 1; // bytes ++ int sf = samplingFrequencies[mpegIndex][sampling_frequency]; ++ ++ if (FrameDuration) ++ *FrameDuration = 90000 * 8 * slotSize * slots_per_frame[mpegIndex][layerIndex] / sf; ++ ++ if (FrameSize) { ++ if (bitrate_index == 0) ++ *FrameSize = 0; ++ else { ++ int br = 1000 * bitRates[mpegIndex][layerIndex][bitrate_index]; // bits/s ++ int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots + +- *FrameSize = (N + padding_bit) * slotSize; // bytes ++ *FrameSize = (N + padding_bit) * slotSize; // bytes ++ } + } + } + +@@ -895,6 +1432,22 @@ void cAudioRepacker::Repack(cRingBufferL + todo--; + // do we have to start a new packet as the current is done? + if (frameTodo > 0) { ++ // try to skip most loops for continuous memory ++ int bite = frameTodo; // jump to next audio frame ++ if (bite > packetTodo) ++ bite = packetTodo; // jump only to next output packet ++ if (--bite > todo) ++ bite = todo; // jump only to next input packet ++ // is there enough payload available to load the scanner? ++ if (bite > 0 && done + bite - pesPayloadOffset >= 4) { ++ data += bite; ++ done += bite; ++ todo -= bite; ++ frameTodo -= bite; ++ packetTodo -= bite; ++ uint32_t *Scanner = (uint32_t *)(data - 4); ++ scanner = ntohl(*Scanner); ++ } + if (--frameTodo == 0) { + // the current audio frame is is done now. So push out the packet to + // start a new packet for the next audio frame. +@@ -1086,6 +1639,7 @@ public: + virtual void Reset(void); + virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count); + virtual int BreakAt(const uchar *Data, int Count); ++ static int GetFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL); + }; + + // frameSizes are in words, i. e. multiply them by 2 to get bytes +@@ -1112,6 +1666,30 @@ int cDolbyRepacker::frameSizes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + ++int cDolbyRepacker::GetFrameDuration(const uchar *Data, int Count, int *TrackIndex) ++{ ++ int PesPayloadOffset = 0; ++ ePesHeader PH = AnalyzePesHeader(Data, Count, PesPayloadOffset); ++ if (PH < phMPEG1) ++ return -1; ++ ++ const uchar *Payload = Data + PesPayloadOffset; ++ const int PayloadCount = Count - PesPayloadOffset; ++ ++ if (Data[3] == 0xBD && PayloadCount >= 9 && ((Payload[0] & 0xF0) == 0x80) && Payload[4] == 0x0B && Payload[5] == 0x77 && frameSizes[Payload[8]] > 0) { ++ if (TrackIndex) ++ *TrackIndex = Payload[0] - 0x80; ++ ++ static int samplingFrequencies[4] = { // all values are specified in Hz ++ 48000, 44100, 32000, -1 ++ }; ++ ++ return 90000 * 1536 / samplingFrequencies[Payload[8] >> 6]; ++ } ++ ++ return -1; ++} ++ + cDolbyRepacker::cDolbyRepacker(void) + { + pesHeader[0] = 0x00; +@@ -1521,7 +2099,7 @@ void cTS2PES::store(uint8_t *Data, int C + if (repacker) + repacker->Repack(resultBuffer, Data, Count); + else +- cRepacker::Put(resultBuffer, Data, Count, Count); ++ cRepacker::PutAllOrNothing(resultBuffer, Data, Count, Count); + } + + void cTS2PES::reset_ipack(void) +@@ -1848,10 +2426,7 @@ void cTS2PES::ts_to_pes(const uint8_t *B + // Enable this if you are having problems with signal quality. + // These are the errors I used to get with Nova-T when antenna + // was not positioned correcly (not transport errors). //tvr +- //dsyslog("TS continuity error (%d)", ccCounter); +-#ifdef USE_DVBSETUP + dsyslog("TS continuity error (%d)", ccCounter); +-#endif /* DVBSETUP */ + } + ccCounter = Buf[3] & CONT_CNT_MASK; + } +@@ -1883,6 +2458,58 @@ void cTS2PES::ts_to_pes(const uint8_t *B + #endif /* DVBSETUP */ + } + ++// --- cAudioIndexer --------------------------------------------------------- ++ ++class cAudioIndexer { ++private: ++ int frameTrack; ++ int frameDuration; ++ int64_t trackTime[MAXAPIDS + MAXDPIDS]; ++ int64_t nextIndexTime; ++ ++public: ++ cAudioIndexer(void); ++ void Clear(void); ++ void PrepareFrame(const uchar *Data, int Count, int Offset, uchar &PictureType); ++ void ProcessFrame(void); ++ }; ++ ++cAudioIndexer::cAudioIndexer(void) ++{ ++ Clear(); ++} ++ ++void cAudioIndexer::Clear(void) ++{ ++ memset(trackTime, 0, sizeof (trackTime)); ++ nextIndexTime = 0; ++ frameTrack = -1; ++} ++ ++void cAudioIndexer::PrepareFrame(const uchar *Data, int Count, int Offset, uchar &PictureType) ++{ ++ frameDuration = cRemux::GetAudioFrameDuration(Data + Offset, Count - Offset, &frameTrack); ++ if (frameDuration <= 0) ++ return; ++ ++ if (Data[Offset + 3] == 0xBD) ++ frameTrack += MAXAPIDS; ++ ++ PictureType = (trackTime[frameTrack] >= nextIndexTime) ? I_FRAME : NO_PICTURE; ++} ++ ++void cAudioIndexer::ProcessFrame(void) ++{ ++ if (frameTrack < 0) ++ return; ++ ++ if (trackTime[frameTrack] >= nextIndexTime) ++ nextIndexTime += 90000 / FRAMESPERSEC; ++ ++ trackTime[frameTrack] += frameDuration; ++ frameTrack = -1; ++} ++ + // --- cRingBufferLinearPes -------------------------------------------------- + + class cRingBufferLinearPes : public cRingBufferLinear { +@@ -1910,19 +2537,14 @@ int cRingBufferLinearPes::DataReady(cons + + #define RESULTBUFFERSIZE KILOBYTE(256) + +-#ifdef USE_SYNCEARLY + cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly) +-#else +-cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure) +-#endif /* SYNCEARLY */ + { ++ h264 = false; + exitOnFailure = ExitOnFailure; + noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF; + numUPTerrors = 0; + synced = false; +-#ifdef USE_SYNCEARLY + syncEarly = SyncEarly; +-#endif /* SYNCEARLY */ + skipped = 0; + numTracks = 0; + resultSkipped = 0; +@@ -1931,7 +2553,7 @@ cRemux::cRemux(int VPid, const int *APid + if (VPid) + #define TEST_cVideoRepacker + #ifdef TEST_cVideoRepacker +- ts2pes[numTracks++] = new cTS2PES(VPid, resultBuffer, IPACKS, 0xE0, 0x00, new cVideoRepacker); ++ ts2pes[numTracks++] = new cTS2PES(VPid, resultBuffer, IPACKS, 0xE0, 0x00, new cVideoRepacker(h264)); + #else + ts2pes[numTracks++] = new cTS2PES(VPid, resultBuffer, IPACKS, 0xE0); + #endif +@@ -1957,6 +2579,7 @@ cRemux::cRemux(int VPid, const int *APid + while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS) + ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x20 + n++); + } ++ audioIndexer = (noVideo ? new cAudioIndexer : NULL); + } + + cRemux::~cRemux() +@@ -1964,6 +2587,18 @@ cRemux::~cRemux() + for (int t = 0; t < numTracks; t++) + delete ts2pes[t]; + delete resultBuffer; ++ delete audioIndexer; ++} ++ ++int cRemux::GetAudioFrameDuration(const uchar *Data, int Count, int *TrackIndex) ++{ ++ if (Count <= 4) ++ return -1; ++ ++ if (Data[3] == 0xBD) ++ return cDolbyRepacker::GetFrameDuration(Data, Count, TrackIndex); ++ ++ return cAudioRepacker::GetFrameDuration(Data, Count, TrackIndex); + } + + int cRemux::GetPid(const uchar *Data) +@@ -1981,12 +2616,33 @@ int cRemux::GetPacketLength(const uchar + return -1; + } + ++bool cRemux::IsFrameH264(const uchar *Data, int Length) ++{ ++ int PesPayloadOffset; ++ const uchar *limit = Data + Length; ++ if (AnalyzePesHeader(Data, Length, PesPayloadOffset) <= phInvalid) ++ return false; // neither MPEG1 nor MPEG2 ++ ++ Data += PesPayloadOffset + 3; // move to video payload and skip 00 00 01 ++ if (Data < limit) { ++ // cVideoRepacker ensures that in case of H264 we will see an access unit delimiter here ++ if (0x01 == Data[-1] && 9 == Data[0] && 0x00 == Data[-2] && 0x00 == Data[-3]) ++ return true; ++ } ++ ++ return false; ++} ++ + int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType) + { + // Scans the video packet starting at Offset and returns its length. + // If the return value is -1 the packet was not completely in the buffer. + int Length = GetPacketLength(Data, Count, Offset); + if (Length > 0) { ++#ifdef TEST_cVideoRepacker ++ bool FoundPicture = false; ++ bool FoundPictureCodingExtension = false; ++#endif + int PesPayloadOffset = 0; + if (AnalyzePesHeader(Data + Offset, Length, PesPayloadOffset) >= phMPEG1) { + const uchar *p = Data + Offset + PesPayloadOffset + 2; +@@ -1999,30 +2655,99 @@ int cRemux::ScanVideoPacket(const uchar + if (p[-2] || p[-1] || p[0] != 0x01) + pLimit = 0; // skip scanning: packet doesn't start with 0x000001 + else { +- switch (p[1]) { +- case SC_SEQUENCE: +- case SC_GROUP: +- case SC_PICTURE: +- break; +- default: // skip scanning: packet doesn't start a new sequence, group or picture +- pLimit = 0; +- } ++ if (h264) { ++ int nal_unit_type = p[1] & 0x1F; ++ switch (nal_unit_type) { ++ case 9: // access unit delimiter ++ // when the MSB in p[1] is set (which violates H.264) then this is a hint ++ // from cVideoRepacker that this second field of the current frame shall ++ // not be reported as picture. ++ if (p[1] & 0x80) ++ ((uchar *)p)[1] &= ~0x80; // revert the hint and fall through ++ else ++ break; ++ default: // skip scanning: packet doesn't start a new picture ++ pLimit = 0; ++ } ++ } ++ else { ++ switch (p[1]) { ++ case SC_SEQUENCE: ++ case SC_GROUP: ++ case SC_PICTURE: ++ break; ++ default: // skip scanning: packet doesn't start a new sequence, group or picture ++ pLimit = 0; ++ } ++ } + } + } + #endif + while (p < pLimit && (p = (const uchar *)memchr(p, 0x01, pLimit - p))) { + if (!p[-2] && !p[-1]) { // found 0x000001 +- switch (p[1]) { +- case SC_PICTURE: PictureType = (p[3] >> 3) & 0x07; +- return Length; +- } ++ if (h264) { ++ int nal_unit_type = p[1] & 0x1F; ++ switch (nal_unit_type) { ++ case 9: { // access unit delimiter ++ int primary_pic_type = p[2] >> 5; ++ switch (primary_pic_type) { ++ case 0: // I ++ case 3: // SI ++ case 5: // I, SI ++ PictureType = I_FRAME; ++ break; ++ case 1: // I, P ++ case 4: // SI, SP ++ case 6: // I, SI, P, SP ++ PictureType = P_FRAME; ++ break; ++ case 2: // I, P, B ++ case 7: // I, SI, P, SP, B ++ PictureType = B_FRAME; ++ break; ++ } ++ return Length; ++ } ++ } ++ } ++ else { ++ switch (p[1]) { ++ case SC_PICTURE: PictureType = (p[3] >> 3) & 0x07; ++#ifndef TEST_cVideoRepacker ++ return Length; ++#else ++ FoundPicture = true; ++ break; ++ case 0x01 ... 0xAF: // slice startcodes ++ break; ++ case 0xB5: // extension startcode ++ case 0xB9: // hint from cVideoRepacker ++ if (FoundPicture && p + 2 < pLimit && (p[2] & 0xF0) == 0x80) { // picture coding extension ++ FoundPictureCodingExtension = true; ++ // using 0xB9 instead of 0xB5 for an expected picture coding extension ++ // is a hint from cVideoRepacker that this second field of the current ++ // frame shall not be reported as picture. ++ if (p[1] == 0xB9) { ++ ((uchar *)p)[1] = 0xB5; // revert the hint ++ pLimit = 0; // return with NO_PICTURE below ++ } ++ else ++ return Length; ++ } ++ break; ++#endif ++ } ++ } + p += 4; // continue scanning after 0x01ssxxyy + } + else + p += 3; // continue scanning after 0x01xxyy + } + } +- PictureType = NO_PICTURE; ++#ifdef TEST_cVideoRepacker ++ if (!FoundPicture || FoundPictureCodingExtension) ++#endif ++ PictureType = NO_PICTURE; + return Length; + } + return -1; +@@ -2126,26 +2851,14 @@ uchar *cRemux::Get(int &Count, uchar *Pi + } + } + else if (!synced) { +-#ifdef USE_SYNCEARLY + if (pt == I_FRAME || syncEarly) { +-#else +- if (pt == I_FRAME) { +-#endif /* SYNCEARLY */ + if (PictureType) + *PictureType = pt; + resultSkipped = i; // will drop everything before this position +-#ifdef USE_SYNCEARLY +- if (!syncEarly) +-#endif /* SYNCEARLY */ +- SetBrokenLink(data + i, l); + synced = true; +-#ifdef USE_SYNCEARLY +- if (syncEarly) { +- if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink() +- SetBrokenLink(data + i, l); +- else fprintf(stderr, "video: synced early\n"); +- } +-#endif /* SYNCEARLY */ ++ if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink() ++ SetBrokenLink(data + i, l); ++ else fprintf(stderr, "video: synced early\n"); + } + } + else if (Count) +@@ -2158,26 +2871,21 @@ uchar *cRemux::Get(int &Count, uchar *Pi + l = GetPacketLength(data, resultCount, i); + if (l < 0) + return resultData; +-#ifdef USE_SYNCEARLY + if (noVideo || !synced && syncEarly) { ++ uchar pt = NO_PICTURE; ++ if (audioIndexer && !Count) ++ audioIndexer->PrepareFrame(data, resultCount, i, pt); + if (!synced) { + if (PictureType && noVideo) +-#else +- if (noVideo) { +- if (!synced) { +- if (PictureType) +-#endif /* SYNCEARLY */ +- *PictureType = I_FRAME; ++ *PictureType = pt; + resultSkipped = i; // will drop everything before this position + synced = true; +-#ifdef USE_SYNCEARLY +- if (!noVideo && syncEarly) fprintf(stderr, "audio: synced early\n"); +-#endif /* SYNCEARLY */ ++ if (!noVideo) fprintf(stderr, "audio: synced early\n"); + } + else if (Count) + return resultData; + else if (PictureType) +- *PictureType = I_FRAME; ++ *PictureType = pt; + } + } + if (synced) { +@@ -2198,6 +2906,8 @@ uchar *cRemux::Get(int &Count, uchar *Pi + void cRemux::Del(int Count) + { + resultBuffer->Del(Count); ++ if (audioIndexer && Count > 0) ++ audioIndexer->ProcessFrame(); + } + + void cRemux::Clear(void) +@@ -2205,6 +2915,8 @@ void cRemux::Clear(void) + for (int t = 0; t < numTracks; t++) + ts2pes[t]->Clear(); + resultBuffer->Clear(); ++ if (audioIndexer) ++ audioIndexer->Clear(); + synced = false; + skipped = 0; + resultSkipped = 0; +diff -ruNp vdr-1.7.0-extensions/remux.h vdr-1.7.0-ext-h264-s2ng-speedup/remux.h +--- vdr-1.7.0-extensions/remux.h 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/remux.h 2009-04-12 23:57:23.000000000 +0200 +@@ -33,35 +33,32 @@ ePesHeader AnalyzePesHeader(const uchar + #define MAXTRACKS 64 + + class cTS2PES; ++class cAudioIndexer; + + class cRemux { + private: + bool exitOnFailure; + bool noVideo; ++ bool h264; + int numUPTerrors; + bool synced; +-#ifdef USE_SYNCEARLY + bool syncEarly; +-#endif /* SYNCEARLY */ + int skipped; + cTS2PES *ts2pes[MAXTRACKS]; + int numTracks; + cRingBufferLinear *resultBuffer; + int resultSkipped; ++ cAudioIndexer *audioIndexer; + int GetPid(const uchar *Data); ++ int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); + public: +-#ifdef USE_SYNCEARLY + cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false); +-#else +- cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false); +-#endif /* SYNCEARLY */ + ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while + ///< APids, DPids and SPids are pointers to zero terminated lists of audio, + ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such + ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency +- ///< exit" in case of problems with the data stream. +- ///< If USE_SYNCEARLY is activated: SyncEarly causes cRemux to sync as soon +- ///< as a video or audio frame is seen. ++ ///< exit" in case of problems with the data stream. SyncEarly causes cRemux ++ ///< to sync as soon as a video or audio frame is seen. + ~cRemux(); + void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); } + ///< By default cRemux assumes that Put() and Get() are called from different +@@ -87,7 +84,8 @@ public: + ///< settings as they are. + static void SetBrokenLink(uchar *Data, int Length); + static int GetPacketLength(const uchar *Data, int Count, int Offset); +- static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); ++ static int GetAudioFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL); ++ static bool IsFrameH264(const uchar *Data, int Length); + }; + + #endif // __REMUX_H +diff -ruNp vdr-1.7.0-extensions/svdrp.c vdr-1.7.0-ext-h264-s2ng-speedup/svdrp.c +--- vdr-1.7.0-extensions/svdrp.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/svdrp.c 2009-04-12 23:57:23.000000000 +0200 +@@ -1362,8 +1362,10 @@ void cSVDRP::CmdPLAY(const char *Option) + int x = sscanf(option, "%d:%d:%d.%d", &h, &m, &s, &f); + if (x == 1) + pos = h; +- else if (x >= 3) +- pos = (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1; ++ else if (x >= 3) { ++ int FramesPerSec = cUnbufferedFile::GetFramesPerSec(recording->FileName()); ++ pos = (h * 3600 + m * 60 + s) * FramesPerSec + f - 1; ++ } + } + cResumeFile resume(recording->FileName()); + if (pos <= 0) +diff -ruNp vdr-1.7.0-extensions/thread.c vdr-1.7.0-ext-h264-s2ng-speedup/thread.c +--- vdr-1.7.0-extensions/thread.c 2008-04-13 13:53:56.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/thread.c 2009-04-12 23:57:23.000000000 +0200 +@@ -219,9 +219,20 @@ cThread::~cThread() + free(description); + } + ++int cThread::GetPriority(void) ++{ ++ errno = 0; ++ int Priority = getpriority(PRIO_PROCESS, 0); ++ if (Priority == -1 && errno != 0) { ++ LOG_ERROR; ++ Priority = 0; ++ } ++ return Priority; ++} ++ + void cThread::SetPriority(int Priority) + { +- if (setpriority(PRIO_PROCESS, 0, Priority) < 0) ++ if (setpriority(PRIO_PROCESS, 0, max(-20, min(Priority, 19))) < 0) + LOG_ERROR; + } + +diff -ruNp vdr-1.7.0-extensions/thread.h vdr-1.7.0-ext-h264-s2ng-speedup/thread.h +--- vdr-1.7.0-extensions/thread.h 2007-02-24 17:13:28.000000000 +0100 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/thread.h 2009-04-12 23:57:23.000000000 +0200 +@@ -86,6 +86,7 @@ private: + static tThreadId mainThreadId; + static void *StartThread(cThread *Thread); + protected: ++ int GetPriority(void); + void SetPriority(int Priority); + void Lock(void) { mutex.Lock(); } + void Unlock(void) { mutex.Unlock(); } +diff -ruNp vdr-1.7.0-extensions/tools.c vdr-1.7.0-ext-h264-s2ng-speedup/tools.c +--- vdr-1.7.0-extensions/tools.c 2008-03-05 18:23:47.000000000 +0100 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/tools.c 2009-04-12 23:57:23.000000000 +0200 +@@ -27,6 +27,8 @@ extern "C" { + #include <utime.h> + #include "i18n.h" + #include "thread.h" ++#include "remux.h" ++#include "recording.h" + + int SysLogLevel = 3; + +@@ -82,6 +84,14 @@ ssize_t safe_write(int filedes, const vo + return p < 0 ? p : written; + } + ++int readchar(int filedes) ++{ ++ char c; ++ if (safe_read(filedes, &c, sizeof(c)) != 1) ++ return -1; ++ return c; ++} ++ + void writechar(int filedes, char c) + { + safe_write(filedes, &c, sizeof(c)); +@@ -140,11 +150,8 @@ char *strreplace(char *s, char c1, char + { + if (s) { + char *p = s; +- while (*p) { +- if (*p == c1) +- *p = c2; +- p++; +- } ++ while ((p = strchr(p, c1))) ++ *p++ = c2; + } + return s; + } +@@ -1630,6 +1637,112 @@ cUnbufferedFile *cUnbufferedFile::Create + return File; + } + ++int cUnbufferedFile::GetFramesPerSec(const char *FileName) ++{ ++ // use this constant as a fallback value ++ int FramesPerSec = FRAMESPERSEC; ++ // open the file an determine frames per second ++ cFileName fn(FileName, false); ++ cUnbufferedFile *f = fn.Open(); ++ if (f) { ++ FramesPerSec = f->GetFramesPerSec(); ++ fn.Close(); ++ } ++ return FramesPerSec; ++} ++ ++#define ADD_H264_SUPPORT 1 ++ ++#ifdef ADD_H264_SUPPORT ++#include "h264parser.h" ++#endif ++ ++int cUnbufferedFile::GetFramesPerSec(void) ++{ ++ // use this constant as a fallback value ++ int FramesPerSec = FRAMESPERSEC; ++ // rember current file position to restore later ++ off_t OrigPos = curpos; ++ // seek to the beginning and read a chunk of data ++ if (0 == Seek(0, SEEK_SET)) { ++ uchar Data[2048]; ++ ssize_t Count = Read(Data, sizeof(Data)); ++ if (Count > 0) { ++ // this chunk of data should actually be a PES packet ++ uchar *Limit = Data + Count; ++ int PesPayloadOffset = 0; ++ if (AnalyzePesHeader(Data, Count, PesPayloadOffset) >= phMPEG1) { ++ // we need a video stream -- radio recordings use the default ++ if ((Data[3] & 0xF0) == 0xE0) { ++ uchar *p = Data + PesPayloadOffset; ++#ifdef ADD_H264_SUPPORT ++ // check whether this is a H.264 video frame ++ if (cRemux::IsFrameH264(Data, Count)) { ++ // need to have a H264 parser since picture timing is rather complex ++ H264::cParser H264parser(false); ++ // send NAL units to parser until it is able to provide frames per second ++ while (p < Limit) { ++ // find next NAL unit ++ uchar *pNext = (uchar *)memmem(p + 4, Limit - (p + 4), "\x00\x00\x01", 3); ++ if (!pNext) // just pass the remainder ++ pNext = Limit; ++ H264parser.PutNalUnitData(p, pNext - p); ++ // process NAL unit and check for frames per second ++ H264parser.Process(); ++ int FPS = H264parser.Context().GetFramesPerSec(); ++ if (FPS != -1) { // there we are ;-) ++ FramesPerSec = FPS; ++fprintf(stderr, "FramesPerSec: %d\n", FramesPerSec); ++ break; ++ } ++ // continue with next NAL unit ++ p = pNext; ++ } ++ } ++ else { ++#endif ++ // thanks to cVideoRepacker, the payload starts with a sequence header ++ if (p + 12 <= Limit) { ++ if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xB3) { ++ uint32_t frame_rate_code = p[7] & 0x0F; ++ uint32_t frame_rate_extension_n = 0; ++ uint32_t frame_rate_extension_d = 0; ++ // now we need to have a look at the next startcode, ++ // as it might be a sequence extension ++ p = (uchar *)memmem(p + 12, Limit - (p + 12), "\x00\x00\x01", 3); ++ if (p && p + 4 < Limit && p[3] == 0xB5) { // extension start code ++ if (p + 5 < Limit && (p[4] >> 4) == 0x1) { // sequence extension ++ if (p + 10 < Limit) { ++ frame_rate_extension_n = (p[9] & 0x60) >> 5; ++ frame_rate_extension_d = (p[9] & 0x1F); ++ } ++ } ++ } ++ // calculate frame rate and round it for compatibility ++ if (0x1 <= frame_rate_code && frame_rate_code <= 0x8) { ++ static const int n[] = { -1, 24000, 24, 25, 30000, 30, 50, 60000, 60 }; ++ static const int d[] = { -1, 1001, 1, 1, 1001, 1, 1, 1001, 1 }; ++ double frame_rate = n[frame_rate_code] * (frame_rate_extension_n + 1) ++ / (double)(d[frame_rate_code] * (frame_rate_extension_d + 1)); ++ FramesPerSec = (int)frame_rate; ++ if (frame_rate - FramesPerSec > 0.5) ++ FramesPerSec++; ++fprintf(stderr, "FramesPerSec: %d\n", FramesPerSec); ++ } ++ } ++ } ++#ifdef ADD_H264_SUPPORT ++ } ++#endif ++ } ++ } ++ } ++ } ++ // restore original position ++ Seek(OrigPos, SEEK_SET); ++ return FramesPerSec; ++} ++ + // --- cLockFile ------------------------------------------------------------- + + #define LOCKFILENAME ".lock-vdr" +diff -ruNp vdr-1.7.0-extensions/tools.h vdr-1.7.0-ext-h264-s2ng-speedup/tools.h +--- vdr-1.7.0-extensions/tools.h 2008-02-17 14:41:27.000000000 +0100 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/tools.h 2009-04-12 23:57:23.000000000 +0200 +@@ -167,6 +167,7 @@ public: + + ssize_t safe_read(int filedes, void *buffer, size_t size); + ssize_t safe_write(int filedes, const void *buffer, size_t size); ++int readchar(int filedes); + void writechar(int filedes, char c); + int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs = 0, int RetryMs = 0); + ///< Writes either all Data to the given file descriptor, or nothing at all. +@@ -353,6 +354,8 @@ public: + ssize_t Read(void *Data, size_t Size); + ssize_t Write(const void *Data, size_t Size); + static cUnbufferedFile *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); ++ static int GetFramesPerSec(const char *FileName); ++ int GetFramesPerSec(void); + }; + + class cLockFile { +diff -ruNp vdr-1.7.0-extensions/transfer.c vdr-1.7.0-ext-h264-s2ng-speedup/transfer.c +--- vdr-1.7.0-extensions/transfer.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/transfer.c 2009-04-12 23:57:23.000000000 +0200 +@@ -19,11 +19,7 @@ cTransfer::cTransfer(tChannelID ChannelI + ,cThread("transfer") + { + ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer"); +-#ifdef USE_SYNCEARLY +- remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, Setup.UseSyncEarlyPatch); +-#else +- remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids); +-#endif /* SYNCEARLY */ ++ remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, true); + } + + cTransfer::~cTransfer() +diff -ruNp vdr-1.7.0-extensions/vdr.c vdr-1.7.0-ext-h264-s2ng-speedup/vdr.c +--- vdr-1.7.0-extensions/vdr.c 2009-04-09 20:48:48.000000000 +0200 ++++ vdr-1.7.0-ext-h264-s2ng-speedup/vdr.c 2009-04-12 23:57:23.000000000 +0200 +@@ -580,10 +580,6 @@ int main(int argc, char *argv[]) + printf(" DOLBYINREC\n"); + #endif /* DOLBYINREC */ + +-#ifdef USE_DVBPLAYER +- printf(" DVBPLAYER\n"); +-#endif /* DVBPLAYER */ +- + #ifdef USE_DVBSETUP + printf(" DVBSETUP\n"); + #endif /* DVBSETUP */ +@@ -704,10 +700,6 @@ int main(int argc, char *argv[]) + printf(" STREAMDEVEXT\n"); + #endif /* STREAMDEVEXT */ + +-#ifdef USE_SYNCEARLY +- printf(" SYNCEARLY\n"); +-#endif /* SYNCEARLY */ +- + #ifdef USE_TIMERCMD + printf(" TIMERCMD\n"); + #endif /* TIMERCMD */ diff --git a/vdr/extensions/vdr-1.7.0_extensions.diff b/vdr/extensions/vdr-1.7.0_extensions.diff new file mode 100644 index 0000000..680aa02 --- /dev/null +++ b/vdr/extensions/vdr-1.7.0_extensions.diff @@ -0,0 +1,28873 @@ +diff -ruNp vdr-1.7.0/channels.c vdr-1.7.0-extensions/channels.c +--- vdr-1.7.0/channels.c 2008-04-12 15:49:12.000000000 +0200 ++++ vdr-1.7.0-extensions/channels.c 2009-04-09 20:48:48.000000000 +0200 +@@ -13,6 +13,9 @@ + #include "device.h" + #include "epg.h" + #include "timers.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ + + // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' + // format characters in order to allow any number of blanks after a numeric +@@ -216,6 +219,9 @@ cChannel::cChannel(void) + shortName = strdup(""); + provider = strdup(""); + portalName = strdup(""); ++#ifdef USE_PLUGINPARAM ++ pluginParam = strdup(""); ++#endif /* PLUGINPARAM */ + memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__); + inversion = DVBFE_INVERSION_AUTO; + bandwidth = DVBFE_BANDWIDTH_AUTO; +@@ -241,6 +247,9 @@ cChannel::cChannel(const cChannel &Chann + shortName = NULL; + provider = NULL; + portalName = NULL; ++#ifdef USE_PLUGINPARAM ++ pluginParam = NULL; ++#endif /* PLUGINPARAM */ + schedule = NULL; + linkChannels = NULL; + refChannel = NULL; +@@ -269,6 +278,9 @@ cChannel::~cChannel() + free(shortName); + free(provider); + free(portalName); ++#ifdef USE_PLUGINPARAM ++ free(pluginParam); ++#endif /* PLUGINPARAM */ + } + + cChannel& cChannel::operator= (const cChannel &Channel) +@@ -277,6 +289,9 @@ cChannel& cChannel::operator= (const cCh + shortName = strcpyrealloc(shortName, Channel.shortName); + provider = strcpyrealloc(provider, Channel.provider); + portalName = strcpyrealloc(portalName, Channel.portalName); ++#ifdef USE_PLUGINPARAM ++ pluginParam = strcpyrealloc(pluginParam, Channel.pluginParam); ++#endif /* PLUGINPARAM */ + memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__); + return *this; + } +@@ -338,6 +353,9 @@ void cChannel::CopyTransponderData(const + alpha = Channel->alpha; + priority = Channel->priority; + rollOff = Channel->rollOff; ++#ifdef USE_PLUGINPARAM ++ if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, Channel->pluginParam); ++#endif /* PLUGINPARAM */ + } + } + +@@ -375,6 +393,24 @@ bool cChannel::SetSatTransponderData(int + return true; + } + ++#ifdef USE_PLUGINPARAM ++bool cChannel::SetPlugTransponderData(int Source, int Frequency, const char *PluginParam) ++{ ++ if (source != Source || frequency != Frequency || (strcmp(pluginParam, PluginParam) != 0)) { ++ if (Number()) { ++ dsyslog("changing transponder data of channel %d from %s:%d:%s to %s:%d:%s", Number(), *cSource::ToString(source), frequency, pluginParam, *cSource::ToString(Source), Frequency, PluginParam); ++ modification |= CHANNELMOD_TRANSP; ++ Channels.SetModified(); ++ } ++ source = Source; ++ frequency = Frequency; ++ pluginParam = strcpyrealloc(pluginParam, PluginParam); ++ schedule = NULL; ++ } ++ return true; ++} ++#endif /* PLUGINPARAM */ ++ + bool cChannel::SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH) + { + if (source != Source || frequency != Frequency || modulation != Modulation || srate != Srate || coderateH != CoderateH) { +@@ -447,6 +483,9 @@ void cChannel::SetName(const char *Name, + if (nn || ns || np) { + if (Number()) { + dsyslog("changing name of channel %d from '%s,%s;%s' to '%s,%s;%s'", Number(), name, shortName, provider, Name, ShortName, Provider); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(this, scMod); ++#endif /* STREAMDEVEXT */ + modification |= CHANNELMOD_NAME; + Channels.SetModified(); + } +@@ -472,6 +511,20 @@ void cChannel::SetPortalName(const char + } + } + ++#ifdef USE_PLUGINPARAM ++void cChannel::SetPluginParam(const char *PluginParam) ++{ ++ if (!isempty(PluginParam) && strcmp(pluginParam, PluginParam) != 0) { ++ if (Number()) { ++ dsyslog("changing plugin parameters of channel %d from '%s' to '%s'", Number(), pluginParam, PluginParam); ++ modification |= CHANNELMOD_TRANSP; ++ Channels.SetModified(); ++ } ++ pluginParam = strcpyrealloc(pluginParam, PluginParam); ++ } ++} ++#endif /* PLUGINPARAM */ ++ + #define STRDIFF 0x01 + #define VALDIFF 0x02 + +@@ -665,7 +718,11 @@ cString cChannel::ParametersToString(voi + if (isdigit(type)) + type = 'S'; + #define ST(s) if (strchr(s, type)) ++#ifdef USE_PLUGINPARAM ++ char buffer[256]; ++#else + char buffer[64]; ++#endif /* PLUGINPARAM */ + char *q = buffer; + *q = 0; + ST(" S ") q += sprintf(q, "%c", polarization); +@@ -681,6 +738,9 @@ cString cChannel::ParametersToString(voi + ST(" S ") q += PrintParameter(q, 'S', MapToUser(system, SystemValues)); + ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); + ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); ++#ifdef USE_PLUGINPARAM ++ ST("P ") snprintf(buffer, sizeof(buffer), "%s", pluginParam); ++#endif /* PLUGINPARAM */ + return buffer; + } + +@@ -702,7 +762,11 @@ static const char *ParseParameter(const + + bool cChannel::StringToParameters(const char *s) + { ++#ifdef USE_PLUGINPARAM ++ while (s && *s && !IsPlug()) { ++#else + while (s && *s) { ++#endif /* PLUGINPARAM */ + switch (toupper(*s)) { + case 'A': s = ParseParameter(s, alpha, AlphaValues); break; + case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; +@@ -817,7 +881,11 @@ bool cChannel::Parse(const char *s) + dpids[0] = 0; + ok = false; + if (parambuf && sourcebuf && vpidbuf && apidbuf) { ++#ifdef USE_PLUGINPARAM ++ ok = ((source = cSource::FromString(sourcebuf)) >= 0) && StringToParameters(parambuf); ++#else + ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; ++#endif /* PLUGINPARAM */ + + char *p = strchr(vpidbuf, '+'); + if (p) +@@ -908,6 +976,9 @@ bool cChannel::Parse(const char *s) + shortName = strcpyrealloc(shortName, p); + } + name = strcpyrealloc(name, namebuf); ++#ifdef USE_PLUGINPARAM ++ if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, parambuf); ++#endif /* PLUGINPARAM */ + + free(parambuf); + free(sourcebuf); +@@ -1153,6 +1224,9 @@ cChannel *cChannels::NewChannel(const cC + NewChannel->SetName(Name, ShortName, Provider); + Add(NewChannel); + ReNumber(); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NewChannel, scAdd); ++#endif /* STREAMDEVEXT */ + return NewChannel; + } + return NULL; +diff -ruNp vdr-1.7.0/channels.h vdr-1.7.0-extensions/channels.h +--- vdr-1.7.0/channels.h 2008-04-12 15:46:50.000000000 +0200 ++++ vdr-1.7.0-extensions/channels.h 2009-04-09 20:48:48.000000000 +0200 +@@ -118,6 +118,9 @@ private: + char *shortName; + char *provider; + char *portalName; ++#ifdef USE_PLUGINPARAM ++ char *pluginParam; ++#endif /* PLUGINPARAM */ + int __BeginData__; + int frequency; // MHz + int source; +@@ -174,6 +177,9 @@ public: + int Frequency(void) const { return frequency; } ///< Returns the actual frequency, as given in 'channels.conf' + int Transponder(void) const; ///< Returns the transponder frequency in MHz, plus the polarization in case of sat + static int Transponder(int Frequency, char Polarization); ///< builds the transponder from the given Frequency and Polarization ++#ifdef USE_PLUGINPARAM ++ const char *PluginParam(void) const { return pluginParam; } ++#endif /* PLUGINPARAM */ + int Source(void) const { return source; } + int Srate(void) const { return srate; } + int Vpid(void) const { return vpid; } +@@ -212,6 +218,9 @@ public: + int RollOff(void) const { return rollOff; } + const cLinkChannels* LinkChannels(void) const { return linkChannels; } + const cChannel *RefChannel(void) const { return refChannel; } ++#ifdef USE_PLUGINPARAM ++ bool IsPlug(void) const { return cSource::IsPlug(source); } ++#endif /* PLUGINPARAM */ + bool IsCable(void) const { return cSource::IsCable(source); } + bool IsSat(void) const { return cSource::IsSat(source); } + bool IsTerr(void) const { return cSource::IsTerr(source); } +@@ -219,12 +228,18 @@ public: + bool HasTimer(void) const; + int Modification(int Mask = CHANNELMOD_ALL); + void CopyTransponderData(const cChannel *Channel); ++#ifdef USE_PLUGINPARAM ++ bool SetPlugTransponderData(int Source, int Frequency, const char *PluginParam); ++#endif /* PLUGINPARAM */ + bool SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH, int Modulation, int System, int RollOff); + bool SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH); + bool SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CodeRateH, int CodeRateL, int Guard, int Transmission, int Alpha, int Priority); + void SetId(int Nid, int Tid, int Sid, int Rid = 0); + void SetName(const char *Name, const char *ShortName, const char *Provider); + void SetPortalName(const char *PortalName); ++#ifdef USE_PLUGINPARAM ++ void SetPluginParam(const char *PluginParam); ++#endif /* PLUGINPARAM */ + void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid); + void SetCaIds(const int *CaIds); // list must be zero-terminated + void SetCaDescriptors(int Level); +diff -ruNp vdr-1.7.0/config.c vdr-1.7.0-extensions/config.c +--- vdr-1.7.0/config.c 2008-02-17 14:39:00.000000000 +0100 ++++ vdr-1.7.0-extensions/config.c 2009-04-09 20:48:48.000000000 +0200 +@@ -15,6 +15,9 @@ + #include "interface.h" + #include "plugin.h" + #include "recording.h" ++#ifdef USE_SOURCECAPS ++#include "sources.h" ++#endif /* SOURCECAPS */ + + // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' + // format characters in order to allow any number of blanks after a numeric +@@ -28,18 +31,32 @@ cCommand::cCommand(void) + { + title = command = NULL; + confirm = false; ++#ifdef USE_CMDSUBMENU ++ nIndent = 0; ++ childs = NULL; ++#endif /* CMDSUBMENU */ + } + + cCommand::~cCommand() + { + free(title); + free(command); ++#ifdef USE_CMDSUBMENU ++ delete childs; ++#endif /* CMDSUBMENU */ + } + + bool cCommand::Parse(const char *s) + { + const char *p = strchr(s, ':'); + if (p) { ++#ifdef USE_CMDSUBMENU ++ nIndent = 0; ++ while (*s == '-') { ++ nIndent++; ++ s++; ++ } ++#endif /* CMDSUBMENU */ + int l = p - s; + if (l > 0) { + title = MALLOC(char, l + 1); +@@ -85,6 +102,20 @@ const char *cCommand::Execute(const char + return result; + } + ++#ifdef USE_CMDSUBMENU ++int cCommand::getChildCount(void) ++{ ++ return childs ? childs->Count() : 0; ++} ++ ++void cCommand::addChild(cCommand *newChild) ++{ ++ if (!childs) ++ childs = new cCommands(); ++ childs->AddConfig(newChild); ++} ++#endif /* CMDSUBMENU */ ++ + // --- cSVDRPhost ------------------------------------------------------------ + + cSVDRPhost::cSVDRPhost(void) +@@ -125,6 +156,26 @@ bool cSVDRPhost::Accepts(in_addr_t Addre + + cCommands Commands; + cCommands RecordingCommands; ++#ifdef USE_TIMERCMD ++cCommands TimerCommands; ++#endif /* TIMERCMD */ ++ ++#ifdef USE_CMDSUBMENU ++void cCommands::AddConfig(cCommand *Object) ++{ ++ if (!Object) ++ return; ++ //isyslog ("Indent %d %s\n", Object->getIndent(), Object->Title()); ++ for (int index = Count() - 1; index >= 0; index--) { ++ cCommand *parent = Get(index); ++ if (parent->getIndent() < Object->getIndent()) { ++ parent->addChild(Object); ++ return; ++ } ++ } ++ cConfig<cCommand>::Add(Object); ++} ++#endif /* CMDSUBMENU */ + + // --- cSVDRPhosts ----------------------------------------------------------- + +@@ -216,6 +267,12 @@ cSetup::cSetup(void) + strcpy(OSDLanguage, ""); // default is taken from environment + strcpy(OSDSkin, "sttng"); + strcpy(OSDTheme, "default"); ++#ifdef USE_WAREAGLEICON ++ WarEagleIcons = 1; ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ ShowValidInput = 0; ++#endif /* VALIDINPUT */ + PrimaryDVB = 1; + ShowInfoOnChSwitch = 1; + TimeoutRequChInfo = 1; +@@ -260,6 +317,18 @@ cSetup::cSetup(void) + VideoFormat = 0; + UpdateChannels = 5; + UseDolbyDigital = 1; ++#ifdef USE_DOLBYINREC ++ UseDolbyInRecordings = 1; ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ DolbyTransferFix = 1; ++ ChannelBlocker = 0; ++ ChannelBlockerMode = 0; ++ ChannelBlockerList = strdup(""); ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ UseSyncEarlyPatch = 0; ++#endif /* SYNCEARLY */ + ChannelInfoPos = 0; + ChannelInfoTime = 5; + OSDLeft = 54; +@@ -276,24 +345,143 @@ cSetup::cSetup(void) + FontSmlSize = 18; + FontFixSize = 20; + MaxVideoFileSize = MAXVIDEOFILESIZE; ++#ifdef USE_HARDLINKCUTTER ++ MaxRecordingSize = DEFAULTRECORDINGSIZE; ++#endif /* HARDLINKCUTTER */ + SplitEditedFiles = 0; ++#ifdef USE_HARDLINKCUTTER ++ HardLinkCutter = 0; ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ DelTimeshiftRec = 0; ++#endif /* DELTIMESHIFTREC */ + MinEventTimeout = 30; + MinUserInactivity = 300; + NextWakeupTime = 0; + MultiSpeedMode = 0; + ShowReplayMode = 0; ++#ifdef USE_DDEPGENTRY ++ DoubleEpgTimeDelta = 15; ++ DoubleEpgAction = 0; ++ MixEpgAction = 0; ++ DisableVPS = 0; ++#endif /* DDEPGENTRY */ + ResumeID = 0; ++#ifdef USE_JUMPPLAY ++ JumpPlay = 0; ++ PlayJump = 0; ++ PauseLastMark = 0; ++ ReloadMarks = 0; ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ memset(SourceCaps, 0, sizeof SourceCaps); ++ SourceCapsSet = false; ++#endif /* SOURCECAPS */ + CurrentChannel = -1; + CurrentVolume = MAXVOLUME; + CurrentDolby = 0; + InitialChannel = 0; + InitialVolume = -1; ++#ifdef USE_VOLCTRL ++ LRVolumeControl = 0; ++ LRChannelGroups = 1; ++ LRForwardRewind = 1; ++#endif /* VOLCTRL */ + EmergencyExit = 1; ++#ifdef USE_NOEPG ++ noEPGMode = 0; ++ noEPGList = strdup(""); ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ LircRepeatDelay = 350; ++ LircRepeatFreq = 100; ++ LircRepeatTimeout = 500; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ ShowRecDate = 1; ++ ShowRecTime = 1; ++ ShowRecLength = 0; ++ ShowProgressBar = 0; ++ MenuCmdPosition = 0; ++ JumpSeconds = 60; ++ JumpSecondsSlow = 10; ++ ShowTimerStop = 1; ++ MainMenuTitle = 0; ++ strcpy(CustomMainMenuTitle, "Video Disk Recorder"); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ RecordingsSortMode = 0; ++ RecordingsSortDirsFirst = 0; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ CutterAutoDelete = 0; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ CutTime = 1; ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ LiveBuffer = false; ++ KeepPaused = false; ++ LiveBufferSize = 100; ++ InRAM = false; ++ MemBufSize = 5; ++ ExtendBuffer = false; ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ DvdDisplayMode = 1; ++ DvdDisplayZeros = 1; ++ DvdTrayMode = 0; ++ DvdSpeedLimit = 0; ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ UseSoftOsd = 0; ++ SoftOsdRate = 50; ++ SoftOsdFadeinSteps = 6; ++ SoftOsdFadeoutSteps = 16; ++ SoftOsdPaletteOnly = 0; ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ VerboseLNBlog = 0; ++ for (int i = 0; i < MAXDEVICES; i++) CardUsesLNBnr[i] = i + 1; ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ UseVidPrefer = 0; // default = disabled ++ nVidPrefer = 1; ++ for (int zz = 1; zz < DVLVIDPREFER_MAX; zz++) { ++ VidPreferPrio[ zz ] = 50; ++ VidPreferSize[ zz ] = 100; ++ } ++ VidPreferSize[ 0 ] = 800; ++ VidPreferPrio[ 0 ] = 50; ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ UseFriendlyFNames = 0; // default = disabled ++#endif /* DVLFRIENDLYFNAMES */ ++} ++ ++#if defined (USE_DVBSETUP) || defined (USE_NOEPG) ++cSetup::~cSetup() ++{ ++#ifdef USE_DVBSETUP ++ free(ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ free(noEPGList); ++#endif /* NOEPG */ + } ++#endif /* DVBSETUP + NOEPG */ + + cSetup& cSetup::operator= (const cSetup &s) + { + memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__); ++#ifdef USE_DVBSETUP ++ free(ChannelBlockerList); ++ ChannelBlockerList = strdup(s.ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ free(noEPGList); ++ noEPGList = strdup(s.noEPGList); ++#endif /* NOEPG */ + return *this; + } + +@@ -384,11 +572,62 @@ bool cSetup::ParseLanguages(const char * + return true; + } + ++#ifdef USE_SOURCECAPS ++void cSetup::StoreSourceCaps(const char *Name) ++{ ++ cSetupLine *l; ++ while ((l = Get(Name)) != NULL) ++ Del(l); ++ ++ for (int i = 0; i < MAXDEVICES; i++) { ++ char buffer[MAXSOURCECAPS*8]={0,}, *q = buffer; ++ int j = 0; ++ while (SourceCaps[i][j] && j < MAXSOURCECAPS) { ++ if (j==0) ++ q += snprintf(buffer, sizeof(buffer), "%i ", i+1); ++ q += snprintf(q, sizeof(buffer) - (q-buffer), "%s ", *cSource::ToString(SourceCaps[i][j++])); ++ } ++ if (*buffer) ++ Store(Name, buffer, NULL, true); ++ } ++} ++ ++bool cSetup::ParseSourceCaps(const char *Value) ++{ ++ char *p; ++ int d = strtol(Value, &p, 10)-1, i = 0; ++ while (p < Value+strlen(Value)) { ++ if (*p==0) return true; ++ if (isblank(*p)) ++p; ++ if (isalpha(*p)) { ++ int source = cSource::FromString(p); ++ if (source != cSource::stNone) { ++ SourceCaps[d][i++] = source; ++ SourceCapsSet = true; ++ } ++ else ++ return false; ++ while (!isblank(*p) && *p) ++ ++p; ++ if (i>MAXSOURCECAPS) ++ return false; ++ } ++ } ++ return true; ++} ++#endif /* SOURCECAPS */ ++ + bool cSetup::Parse(const char *Name, const char *Value) + { + if (!strcasecmp(Name, "OSDLanguage")) { strn0cpy(OSDLanguage, Value, sizeof(OSDLanguage)); I18nSetLocale(OSDLanguage); } + else if (!strcasecmp(Name, "OSDSkin")) Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName); + else if (!strcasecmp(Name, "OSDTheme")) Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName); ++#ifdef USE_WAREAGLEICON ++ else if (!strcasecmp(Name, "WarEagleIcons")) WarEagleIcons = atoi(Value); ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ else if (!strcasecmp(Name, "ShowValidInput")) ShowValidInput = atoi(Value); ++#endif /* VALIDINPUT */ + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "TimeoutRequChInfo")) TimeoutRequChInfo = atoi(Value); +@@ -433,6 +672,21 @@ bool cSetup::Parse(const char *Name, con + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value); + else if (!strcasecmp(Name, "UseDolbyDigital")) UseDolbyDigital = atoi(Value); ++#ifdef USE_DOLBYINREC ++ else if (!strcasecmp(Name, "UseDolbyInRecordings")) UseDolbyInRecordings = atoi(Value); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ else if (!strcasecmp(Name, "DolbyTransferFix")) DolbyTransferFix = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlocker")) ChannelBlocker = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlockerMode")) ChannelBlockerMode = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlockerList")) { ++ free(ChannelBlockerList); ++ ChannelBlockerList = strdup(Value ? Value : ""); ++ } ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ else if (!strcasecmp(Name, "UseSyncEarlyPatch")) UseSyncEarlyPatch = atoi(Value); ++#endif /* SYNCEARLY */ + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoTime")) ChannelInfoTime = atoi(Value); + else if (!strcasecmp(Name, "OSDLeft")) OSDLeft = atoi(Value); +@@ -449,21 +703,152 @@ bool cSetup::Parse(const char *Name, con + else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value); + else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); ++#ifdef USE_HARDLINKCUTTER ++ else if (!strcasecmp(Name, "MaxRecordingSize")) MaxRecordingSize = atoi(Value); ++#endif /* HARDLINKCUTTER */ + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); ++#ifdef USE_HARDLINKCUTTER ++ else if (!strcasecmp(Name, "HardLinkCutter")) HardLinkCutter = atoi(Value); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value); ++#endif /* DELTIMESHIFTREC */ + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); ++#ifdef USE_DDEPGENTRY ++ else if (!strcasecmp(Name, "DoubleEpgTimeDelta")) DoubleEpgTimeDelta = atoi(Value); ++ else if (!strcasecmp(Name, "DoubleEpgAction")) DoubleEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "MixEpgAction")) MixEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "DisableVPS")) DisableVPS = atoi(Value); ++#endif /* DDEPGENTRY */ + else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value); ++#ifdef USE_JUMPPLAY ++ else if (!strcasecmp(Name, "JumpPlay")) JumpPlay = atoi(Value); ++ else if (!strcasecmp(Name, "PlayJump")) PlayJump = atoi(Value); ++ else if (!strcasecmp(Name, "PauseLastMark")) PauseLastMark = atoi(Value); ++ else if (!strcasecmp(Name, "ReloadMarks")) ReloadMarks = atoi(Value); ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ else if (!strcasecmp(Name, "SourceCaps")) return ParseSourceCaps(Value); ++#endif /* SOURCECAPS */ + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); + else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value); + else if (!strcasecmp(Name, "InitialChannel")) InitialChannel = atoi(Value); + else if (!strcasecmp(Name, "InitialVolume")) InitialVolume = atoi(Value); ++#ifdef USE_VOLCTRL ++ else if (!strcasecmp(Name, "LRVolumeControl")) LRVolumeControl = atoi(Value); ++ else if (!strcasecmp(Name, "LRChannelGroups")) LRChannelGroups = atoi(Value); ++ else if (!strcasecmp(Name, "LRForwardRewind")) LRForwardRewind = atoi(Value); ++#endif /* VOLCTRL */ + else if (!strcasecmp(Name, "EmergencyExit")) EmergencyExit = atoi(Value); ++#ifdef USE_NOEPG ++ else if (!strcasecmp(Name, "noEPGMode")) noEPGMode = atoi(Value); ++ else if (!strcasecmp(Name, "noEPGList")) { ++ free(noEPGList); ++ noEPGList = strdup(Value ? Value : ""); ++ } ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ else if (!strcasecmp(Name, "LircRepeatDelay")) LircRepeatDelay = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatFreq")) LircRepeatFreq = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatTimeout")) LircRepeatTimeout = atoi(Value); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ else if (!strcasecmp(Name, "ShowRecDate")) ShowRecDate = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecTime")) ShowRecTime = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecLength")) ShowRecLength = atoi(Value); ++ else if (!strcasecmp(Name, "ShowProgressBar")) ShowProgressBar = atoi(Value); ++ else if (!strcasecmp(Name, "MenuCmdPosition")) MenuCmdPosition = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSeconds")) JumpSeconds = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSecondsSlow")) JumpSecondsSlow = atoi(Value); ++ else if (!strcasecmp(Name, "ShowTimerStop")) ShowTimerStop = atoi(Value); ++ else if (!strcasecmp(Name, "MainMenuTitle")) MainMenuTitle = atoi(Value); ++ else if (!strcasecmp(Name, "CustomMainMenuTitle")) Utf8Strn0Cpy(CustomMainMenuTitle, Value, MaxTitleName); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ else if (!strcasecmp(Name, "RecordingsSortMode")) RecordingsSortMode = atoi(Value); ++ else if (!strcasecmp(Name, "RecordingsSortDirsFirst")) RecordingsSortDirsFirst = atoi(Value); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ else if (!strcasecmp(Name, "CutterAutoDelete")) CutterAutoDelete = atoi(Value); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ else if (!strcasecmp(Name, "CutTime")) CutTime = atoi(Value); ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ else if (!strcasecmp(Name, "LiveBuffer")) LiveBuffer = atoi(Value); ++ else if (!strcasecmp(Name, "KeepPaused")) KeepPaused = atoi(Value); ++ else if (!strcasecmp(Name, "LiveBufferSize")) LiveBufferSize = atoi(Value); ++ else if (!strcasecmp(Name, "InRAM")) InRAM = atoi(Value); ++ else if (!strcasecmp(Name, "MemBufSize")) MemBufSize = atoi(Value); ++ else if (!strcasecmp(Name, "ExtendBuffer")) ExtendBuffer = atoi(Value); ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ else if (!strcasecmp(Name, "DvdDisplayMode")) DvdDisplayMode = atoi(Value); ++ else if (!strcasecmp(Name, "DvdDisplayZeros")) DvdDisplayZeros = atoi(Value); ++ else if (!strcasecmp(Name, "DvdTrayMode")) DvdTrayMode = atoi(Value); ++ else if (!strcasecmp(Name, "DvdSpeedLimit")) DvdSpeedLimit = atoi(Value); ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ else if (!strcasecmp(Name, "UseSoftOsd")) UseSoftOsd = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdRate")) SoftOsdRate = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdFadeinSteps")) SoftOsdFadeinSteps = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdFadeoutSteps")) SoftOsdFadeoutSteps = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdPaletteOnly")) SoftOsdPaletteOnly = atoi(Value); ++#endif /* SOFTOSD */ ++#ifdef USE_DVLVIDPREFER ++ else if (strcasecmp(Name, "UseVidPrefer") == 0) UseVidPrefer = atoi(Value); ++ else if (strcasecmp(Name, "nVidPrefer") == 0) nVidPrefer = atoi(Value); ++ else if (strstr(Name, "VidPrefer") == Name) { ++ char *x = (char *)&Name[ strlen(Name) - 1 ]; ++ int vN; ++ ++ if (isdigit(*x) != 0) { ++ while (isdigit(*x) != 0) ++ x--; ++ x++; ++ } ++ ++ vN = atoi(x); ++ if (vN < DVLVIDPREFER_MAX) { ++ if (strstr(Name, "VidPreferPrio") == Name) { ++ VidPreferPrio[ vN ] = atoi(Value); ++ if (VidPreferPrio[ vN ] > 99) ++ VidPreferPrio[ vN ] = 99; ++ } ++ else if (strstr(Name, "VidPreferSize") == Name) { ++ VidPreferSize[ vN ] = atoi(Value); ++ } ++ else ++ return false; ++ } ++ } ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ else if (strcasecmp(Name, "UseFriendlyFNames") == 0) UseFriendlyFNames = atoi(Value); ++#endif /* DVLFRIENDLYFNAMES */ + else ++#ifdef USE_LNBSHARE ++ if (!strcasecmp(Name, "VerboseLNBlog")) VerboseLNBlog = atoi(Value); ++ else { ++ char tmp[20]; ++ bool result = false; ++ for (int i = 1; i <= MAXDEVICES; i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ if (!strcasecmp(Name, tmp)) { ++ CardUsesLNBnr[i - 1] = atoi(Value); ++ result = true; ++ } ++ } ++ return result; ++ } ++#else + return false; ++#endif /* LNBSHARE */ + return true; + } + +@@ -472,6 +857,12 @@ bool cSetup::Save(void) + Store("OSDLanguage", OSDLanguage); + Store("OSDSkin", OSDSkin); + Store("OSDTheme", OSDTheme); ++#ifdef USE_WAREAGLEICON ++ Store("WarEagleIcons", WarEagleIcons); ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ Store("ShowValidInput", ShowValidInput); ++#endif /* VALIDINPUT */ + Store("PrimaryDVB", PrimaryDVB); + Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); + Store("TimeoutRequChInfo", TimeoutRequChInfo); +@@ -516,6 +907,18 @@ bool cSetup::Save(void) + Store("VideoFormat", VideoFormat); + Store("UpdateChannels", UpdateChannels); + Store("UseDolbyDigital", UseDolbyDigital); ++#ifdef USE_DOLBYINREC ++ Store("UseDolbyInRecordings", UseDolbyInRecordings); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ Store("DolbyTransferFix", DolbyTransferFix); ++ Store("ChannelBlocker", ChannelBlocker); ++ Store("ChannelBlockerMode", ChannelBlockerMode); ++ Store("ChannelBlockerList", ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ Store("UseSyncEarlyPatch", UseSyncEarlyPatch); ++#endif /* SYNCEARLY */ + Store("ChannelInfoPos", ChannelInfoPos); + Store("ChannelInfoTime", ChannelInfoTime); + Store("OSDLeft", OSDLeft); +@@ -532,25 +935,164 @@ bool cSetup::Save(void) + Store("FontSmlSize", FontSmlSize); + Store("FontFixSize", FontFixSize); + Store("MaxVideoFileSize", MaxVideoFileSize); ++#ifdef USE_HARDLINKCUTTER ++ Store("MaxRecordingSize", MaxRecordingSize); ++#endif /* HARDLINKCUTTER */ + Store("SplitEditedFiles", SplitEditedFiles); ++#ifdef USE_HARDLINKCUTTER ++ Store("HardLinkCutter", HardLinkCutter); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ Store("DelTimeshiftRec", DelTimeshiftRec); ++#endif /* DELTIMESHIFTREC */ + Store("MinEventTimeout", MinEventTimeout); + Store("MinUserInactivity", MinUserInactivity); + Store("NextWakeupTime", NextWakeupTime); ++#ifdef USE_DDEPGENTRY ++ Store("DoubleEpgAction", DoubleEpgAction); ++ Store("MixEpgAction", MixEpgAction); ++ Store("DisableVPS", DisableVPS); ++ Store("DoubleEpgTimeDelta", DoubleEpgTimeDelta); ++#endif /* DDEPGENTRY */ + Store("MultiSpeedMode", MultiSpeedMode); + Store("ShowReplayMode", ShowReplayMode); + Store("ResumeID", ResumeID); ++#ifdef USE_JUMPPLAY ++ Store("JumpPlay", JumpPlay); ++ Store("PlayJump", PlayJump); ++ Store("PauseLastMark", PauseLastMark); ++ Store("ReloadMarks", ReloadMarks); ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ if (SourceCapsSet) StoreSourceCaps("SourceCaps"); ++#endif /* SOURCECAPS */ + Store("CurrentChannel", CurrentChannel); + Store("CurrentVolume", CurrentVolume); + Store("CurrentDolby", CurrentDolby); + Store("InitialChannel", InitialChannel); + Store("InitialVolume", InitialVolume); ++#ifdef USE_VOLCTRL ++ Store("LRVolumeControl", LRVolumeControl); ++ Store("LRChannelGroups", LRChannelGroups); ++ Store("LRForwardRewind", LRForwardRewind); ++#endif /* VOLCTRL */ + Store("EmergencyExit", EmergencyExit); ++#ifdef USE_NOEPG ++ Store("noEPGMode", noEPGMode); ++ Store("noEPGList", noEPGList); ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ Store("LircRepeatDelay", LircRepeatDelay); ++ Store("LircRepeatFreq", LircRepeatFreq); ++ Store("LircRepeatTimeout", LircRepeatTimeout); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ Store("ShowRecDate", ShowRecDate); ++ Store("ShowRecTime", ShowRecTime); ++ Store("ShowRecLength", ShowRecLength); ++ Store("ShowProgressBar", ShowProgressBar); ++ Store("MenuCmdPosition", MenuCmdPosition); ++ Store("JumpSeconds", JumpSeconds); ++ Store("JumpSecondsSlow", JumpSecondsSlow); ++ Store("ShowTimerStop", ShowTimerStop); ++ Store("MainMenuTitle", MainMenuTitle); ++ Store("CustomMainMenuTitle",CustomMainMenuTitle); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ Store("RecordingsSortMode", RecordingsSortMode); ++ Store("RecordingsSortDirsFirst", RecordingsSortDirsFirst); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Store("CutterAutoDelete", CutterAutoDelete); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ Store("CutTime", CutTime); ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ Store("LiveBuffer", LiveBuffer); ++ Store("KeepPaused", KeepPaused); ++ Store("LiveBufferSize", LiveBufferSize); ++ Store("InRAM", InRAM); ++ Store("MemBufSize", MemBufSize); ++ Store("ExtendBuffer", ExtendBuffer); ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ Store("DvdDisplayMode", DvdDisplayMode); ++ Store("DvdDisplayZeros", DvdDisplayZeros); ++ Store("DvdTrayMode", DvdTrayMode); ++ Store("DvdSpeedLimit", DvdSpeedLimit); ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ Store("UseSoftOsd", UseSoftOsd); ++ Store("SoftOsdRate", SoftOsdRate); ++ Store("SoftOsdFadeinSteps", SoftOsdFadeinSteps); ++ Store("SoftOsdFadeoutSteps", SoftOsdFadeoutSteps); ++ Store("SoftOsdPaletteOnly", SoftOsdPaletteOnly); ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ Store("VerboseLNBlog", VerboseLNBlog); ++ char tmp[20]; ++ if (cDevice::NumDevices() > 1) { ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ Store(tmp, CardUsesLNBnr[i - 1]); ++ } ++ } ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ Store ("UseVidPrefer", UseVidPrefer); ++ Store ("nVidPrefer", nVidPrefer); ++ ++ char vidBuf[32]; ++ for (int zz = 0; zz < nVidPrefer; zz++) { ++ sprintf(vidBuf, "VidPreferPrio%d", zz); ++ Store (vidBuf, VidPreferPrio[zz]); ++ sprintf(vidBuf, "VidPreferSize%d", zz); ++ Store (vidBuf, VidPreferSize[zz]); ++ } ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ Store ("UseFriendlyFNames", UseFriendlyFNames); ++#endif /* DVLFRIENDLYFNAMES */ + + Sort(); + + if (cConfig<cSetupLine>::Save()) { + isyslog("saved setup to %s", FileName()); ++#ifdef USE_DVDARCHIVE ++ if (DvdDisplayMode >= 1) ::Recordings.Load(); ++#endif /* DVDARCHIVE */ + return true; + } + return false; + } ++ ++#ifdef USE_CMDRECCMDI18N ++bool LoadCommandsI18n(cCommands & cmds, const char *FileName, bool AllowComments, bool MustExist) ++{ ++ ++ bool bRet = true; ++ bool bLoadDefault = (bool)strcmp(Setup.OSDLanguage,"en_US"); ++ if (bLoadDefault) { ++ // attempt to load a translated file ++ char *FullPath = NULL; ++ asprintf(&FullPath, "%s.%s", FileName, Setup.OSDLanguage); ++ if (!cmds.Load((FullPath), AllowComments, true)) { ++ // require to exist, just to be able to log ++ // fallback ++ bLoadDefault = false; ++ esyslog("Failed to load translated '%s' for language (%s)", FullPath, Setup.OSDLanguage); ++ esyslog("Falling back to default '%s' (if any)", FileName); ++ } ++ free(FullPath); ++ } ++ if (!bLoadDefault) { ++ // let's do it the normal way ++ bRet = cmds.Load(FileName, AllowComments, MustExist); ++ } ++ // return status only for the default commands file ++ return bRet; ++} ++ ++#endif /* CMDRECCMDI18N */ ++ +diff -ruNp vdr-1.7.0/config.h vdr-1.7.0-extensions/config.h +--- vdr-1.7.0/config.h 2008-04-12 15:02:10.000000000 +0200 ++++ vdr-1.7.0-extensions/config.h 2009-04-09 20:48:48.000000000 +0200 +@@ -36,23 +36,74 @@ + // plugins to work with newer versions of the core VDR as long as no + // VDR header files have changed. + ++#define VDREXTENSIONS 70 ++ ++#ifdef USE_JUMPPLAY ++#define JUMPPLAYVERSNUM 100 ++#endif /* JUMPPLAY */ ++ ++#ifdef USE_LIEMIEXT ++#define LIEMIKUUTIO 121 ++#define MAXMAINMENUTITLE 4 ++#define MaxTitleName 64 ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_CMDSUBMENU ++#define CMDSUBMENUVERSNUM 7 ++#endif /* CMDSUBMENU */ ++ ++#ifdef USE_MAINMENUHOOKS ++#define MAINMENUHOOKSVERSNUM 1.0 ++#endif /* MAINMENUHOOKS */ ++ ++#ifdef USE_PINPLUGIN ++#define PIN_PLUGIN_PATCH 120 ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_PLUGINPARAM ++#define PLUGINPARAMPATCHVERSNUM 1 ++#endif /* PLUGINPARAM */ ++ + #define MAXPRIORITY 99 + #define MAXLIFETIME 99 + ++#ifdef USE_DVLVIDPREFER ++#define DVLVIDPREFER_MAX 12 ++#endif /* DVLVIDPREFER */ ++ + #define MINOSDWIDTH 480 + #define MAXOSDWIDTH 672 + #define MINOSDHEIGHT 324 + #define MAXOSDHEIGHT 567 + ++#ifdef USE_SOURCECAPS ++#define MAXDEVICES 16 // the maximum number of devices in the system ++#define MAXSOURCECAPS 128 // the maximum number of different sources per device ++#endif /* SOURCECAPS */ ++ ++#ifdef USE_LNBSHARE ++#ifndef MAXDEVICES ++#define MAXDEVICES 16 // the maximum number of devices in the system ++#endif ++#endif /* LNBSHARE */ ++ + #define MaxFileName 256 + #define MaxSkinName 16 + #define MaxThemeName 16 + ++#ifdef USE_CMDSUBMENU ++class cCommands; ++#endif /* CMDSUBMENU */ ++ + class cCommand : public cListObject { + private: + char *title; + char *command; + bool confirm; ++#ifdef USE_CMDSUBMENU ++ int nIndent; ++ cCommands *childs; ++#endif /* CMDSUBMENU */ + static char *result; + public: + cCommand(void); +@@ -61,6 +112,14 @@ public: + const char *Title(void) { return title; } + bool Confirm(void) { return confirm; } + const char *Execute(const char *Parameters = NULL); ++#ifdef USE_CMDSUBMENU ++ int getIndent(void) { return nIndent; } ++ void setIndent(int nNewIndent) { nIndent = nNewIndent; } ++ cCommands *getChilds(void) { return childs; } ++ int getChildCount(void); ++ bool hasChilds(void) { return getChildCount() > 0; } ++ void addChild(cCommand *newChild); ++#endif /* CMDSUBMENU */ + }; + + typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2) +@@ -88,6 +147,9 @@ private: + public: + cConfig(void) { fileName = NULL; } + virtual ~cConfig() { free(fileName); } ++#ifdef USE_CMDSUBMENU ++ virtual void AddConfig(T *Object) { cList<T>::Add(Object); } ++#endif /* CMDSUBMENU */ + const char *FileName(void) { return fileName; } + bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false) + { +@@ -117,7 +179,11 @@ public: + if (!isempty(s)) { + T *l = new T; + if (l->Parse(s)) ++#ifdef USE_CMDSUBMENU ++ AddConfig(l); ++#else + Add(l); ++#endif /* CMDSUBMENU */ + else { + esyslog("ERROR: error in %s, line %d", fileName, line); + delete l; +@@ -159,7 +225,14 @@ public: + } + }; + ++#ifdef USE_CMDSUBMENU ++class cCommands : public cConfig<cCommand> { ++public: ++ virtual void AddConfig(cCommand *Object); ++ }; ++#else + class cCommands : public cConfig<cCommand> {}; ++#endif /* CMDSUBMENU */ + + class cSVDRPhosts : public cConfig<cSVDRPhost> { + public: +@@ -168,6 +241,9 @@ public: + + extern cCommands Commands; + extern cCommands RecordingCommands; ++#ifdef USE_TIMERCMD ++extern cCommands TimerCommands; ++#endif /* TIMERCMD */ + extern cSVDRPhosts SVDRPhosts; + + class cSetupLine : public cListObject { +@@ -193,6 +269,10 @@ private: + void StoreLanguages(const char *Name, int *Values); + bool ParseLanguages(const char *Value, int *Values); + bool Parse(const char *Name, const char *Value); ++#ifdef USE_SOURCECAPS ++ void StoreSourceCaps(const char *Name); ++ bool ParseSourceCaps(const char *Value); ++#endif /* SOURCECAPS */ + cSetupLine *Get(const char *Name, const char *Plugin = NULL); + void Store(const char *Name, const char *Value, const char *Plugin = NULL, bool AllowMultiple = false); + void Store(const char *Name, int Value, const char *Plugin = NULL); +@@ -202,6 +282,12 @@ public: + char OSDLanguage[I18N_MAX_LOCALE_LEN]; + char OSDSkin[MaxSkinName]; + char OSDTheme[MaxThemeName]; ++#ifdef USE_WAREAGLEICON ++ int WarEagleIcons; ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ int ShowValidInput; ++#endif /* VALIDINPUT */ + int PrimaryDVB; + int ShowInfoOnChSwitch; + int TimeoutRequChInfo; +@@ -242,6 +328,17 @@ public: + int VideoFormat; + int UpdateChannels; + int UseDolbyDigital; ++#ifdef USE_DOLBYINREC ++ int UseDolbyInRecordings; ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ int DolbyTransferFix; ++ int ChannelBlocker; ++ int ChannelBlockerMode; ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ int UseSyncEarlyPatch; ++#endif /* SYNCEARLY */ + int ChannelInfoPos; + int ChannelInfoTime; + int OSDLeft, OSDTop, OSDWidth, OSDHeight; +@@ -255,20 +352,119 @@ public: + int FontSmlSize; + int FontFixSize; + int MaxVideoFileSize; ++#ifdef USE_HARDLINKCUTTER ++ int MaxRecordingSize; ++#endif /* HARDLINKCUTTER */ + int SplitEditedFiles; ++#ifdef USE_HARDLINKCUTTER ++ int HardLinkCutter; ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ int DelTimeshiftRec; ++#endif /* DELTIMESHIFTREC */ + int MinEventTimeout, MinUserInactivity; + time_t NextWakeupTime; + int MultiSpeedMode; + int ShowReplayMode; ++#ifdef USE_DDEPGENTRY ++ int DoubleEpgTimeDelta; ++ int DoubleEpgAction; ++ int MixEpgAction; ++ int DisableVPS; ++#endif /* DDEPGENTRY */ + int ResumeID; ++#ifdef USE_JUMPPLAY ++ int JumpPlay; ++ int PlayJump; ++ int PauseLastMark; ++ int ReloadMarks; ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ int SourceCaps[MAXDEVICES][MAXSOURCECAPS]; ++ bool SourceCapsSet; ++#endif /* SOURCECAPS */ + int CurrentChannel; + int CurrentVolume; + int CurrentDolby; + int InitialChannel; + int InitialVolume; ++#ifdef USE_VOLCTRL ++ int LRVolumeControl; ++ int LRChannelGroups; ++ int LRForwardRewind; ++#endif /* VOLCTRL */ + int EmergencyExit; ++#ifdef USE_NOEPG ++ int noEPGMode; ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ int LircRepeatDelay; ++ int LircRepeatFreq; ++ int LircRepeatTimeout; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ int ShowRecDate, ShowRecTime, ShowRecLength, ShowProgressBar, MenuCmdPosition; ++ int JumpSeconds; ++ int JumpSecondsSlow; ++ int ShowTimerStop; ++ int MainMenuTitle; ++ char CustomMainMenuTitle[MaxTitleName]; ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ int RecordingsSortMode; ++ int RecordingsSortDirsFirst; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ int CutterAutoDelete; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ int CutTime; ++#endif /* CUTTIME */ ++#ifdef USE_LIVEBUFFER ++ int LiveBuffer; ++ int KeepPaused; ++ int LiveBufferSize; ++ int InRAM; ++ int MemBufSize; ++ int ExtendBuffer; ++#endif /* LIVEBUFFER */ ++#ifdef USE_DVDARCHIVE ++ int DvdDisplayMode; ++ int DvdDisplayZeros; ++ int DvdTrayMode; ++ int DvdSpeedLimit; ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ int UseSoftOsd; ++ int SoftOsdRate; ++ int SoftOsdFadeinSteps; ++ int SoftOsdFadeoutSteps; ++ int SoftOsdPaletteOnly; ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ int VerboseLNBlog; ++ int CardUsesLNBnr[MAXDEVICES]; ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ int UseVidPrefer; // 0 = VDR's default, 1 = use ++ int nVidPrefer; ++ int VidPreferPrio[DVLVIDPREFER_MAX]; ++ int VidPreferSize[DVLVIDPREFER_MAX]; ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ int UseFriendlyFNames; ++#endif /* DVLFRIENDLYFNAMES */ + int __EndData__; ++#ifdef USE_DVBSETUP ++ char *ChannelBlockerList; ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ char *noEPGList; // pointer not to be flat-copied ++#endif /* NOEPG */ + cSetup(void); ++#if defined (USE_DVBSETUP) || defined (USE_NOEPG) ++ ~cSetup(); ++#endif /* DVBSETUP + NOEPG */ + cSetup& operator= (const cSetup &s); + bool Load(const char *FileName); + bool Save(void); +@@ -276,4 +472,8 @@ public: + + extern cSetup Setup; + ++#ifdef USE_CMDRECCMDI18N ++bool LoadCommandsI18n(cCommands & cmds, const char *FileName = NULL, bool AllowComments = false, bool MustExist = false); ++#endif /* CMDRECCMDI18N */ ++ + #endif //__CONFIG_H +diff -ruNp vdr-1.7.0/cutter.c vdr-1.7.0-extensions/cutter.c +--- vdr-1.7.0/cutter.c 2008-01-13 13:22:21.000000000 +0100 ++++ vdr-1.7.0-extensions/cutter.c 2009-04-09 20:48:48.000000000 +0200 +@@ -15,6 +15,19 @@ + + // --- cCuttingThread -------------------------------------------------------- + ++#ifdef USE_CUTTERLIMIT ++#ifndef CUTTER_MAX_BANDWIDTH ++# define CUTTER_MAX_BANDWIDTH MEGABYTE(10) // 10 MB/s ++#endif ++#ifndef CUTTER_REL_BANDWIDTH ++# define CUTTER_REL_BANDWIDTH 75 // % ++#endif ++#ifndef CUTTER_PRIORITY ++# define CUTTER_PRIORITY sched_get_priority_min(SCHED_OTHER) ++#endif ++#define CUTTER_TIMESLICE 100 // ms ++#endif /* CUTTERLIMIT */ ++ + class cCuttingThread : public cThread { + private: + const char *error; +@@ -60,6 +73,22 @@ cCuttingThread::~cCuttingThread() + + void cCuttingThread::Action(void) + { ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) ++#endif /* HARDLINKCUTTER */ ++ { ++ sched_param tmp; ++ tmp.sched_priority = CUTTER_PRIORITY; ++ if (!pthread_setschedparam(pthread_self(), SCHED_OTHER, &tmp)) ++ printf("cCuttingThread::Action: cant set priority\n"); ++ } ++ ++ int bytes = 0; ++ int __attribute__((unused)) burst_size = CUTTER_MAX_BANDWIDTH * CUTTER_TIMESLICE / 1000; // max bytes/timeslice ++ cTimeMs __attribute__((unused)) t; ++#endif /* CUTTERLIMIT */ ++ + cMark *Mark = fromMarks.First(); + if (Mark) { + fromFile = fromFileName->Open(); +@@ -71,6 +100,9 @@ void cCuttingThread::Action(void) + Mark = fromMarks.Next(Mark); + int FileSize = 0; + int CurrentFileNumber = 0; ++#ifdef USE_HARDLINKCUTTER ++ bool SkipThisSourceFile = false; ++#endif /* HARDLINKCUTTER */ + int LastIFrame = 0; + toMarks.Add(0); + toMarks.Save(); +@@ -88,12 +120,99 @@ void cCuttingThread::Action(void) + + // Read one frame: + ++#ifndef USE_HARDLINKCUTTER + if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { + if (FileNumber != CurrentFileNumber) { + fromFile = fromFileName->SetOffset(FileNumber, FileOffset); + fromFile->SetReadAhead(MEGABYTE(20)); + CurrentFileNumber = FileNumber; + } ++#else ++ if (!fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { ++ error = "index"; ++ break; ++ } ++ ++ if (FileNumber != CurrentFileNumber) { ++ fromFile = fromFileName->SetOffset(FileNumber, FileOffset); ++ fromFile->SetReadAhead(MEGABYTE(20)); ++ CurrentFileNumber = FileNumber; ++ if (SkipThisSourceFile) { ++ // At end of fast forward: Always skip to next file ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 4"; ++ break; ++ } ++ FileSize = 0; ++ SkipThisSourceFile = false; ++ } ++ ++ ++ if (Setup.HardLinkCutter && FileOffset == 0) { ++ // We are at the beginning of a new source file. ++ // Do we need to copy the whole file? ++ ++ // if !Mark && LastMark, then we're past the last cut-out and continue to next I-frame ++ // if !Mark && !LastMark, then there's just a cut-in, but no cut-out ++ // if Mark, then we're between a cut-in and a cut-out ++ ++ uchar MarkFileNumber; ++ int MarkFileOffset; ++ // Get file number of next cut mark ++ if (!Mark && !LastMark ++ || Mark ++ && fromIndex->Get(Mark->position, &MarkFileNumber, &MarkFileOffset) ++ && (MarkFileNumber != CurrentFileNumber)) { ++ // The current source file will be copied completely. ++ // Start new output file unless we did that already ++ if (FileSize != 0) { ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 3"; ++ break; ++ } ++ FileSize = 0; ++ } ++ ++ // Safety check that file has zero size ++ struct stat buf; ++ if (stat(toFileName->Name(), &buf) == 0) { ++ if (buf.st_size != 0) { ++ esyslog("cCuttingThread: File %s exists and has nonzero size", toFileName->Name()); ++ error = "nonzero file exist"; ++ break; ++ } ++ } ++ else if (errno != ENOENT) { ++ esyslog("cCuttingThread: stat failed on %s", toFileName->Name()); ++ error = "stat"; ++ break; ++ } ++ ++ // Clean the existing 0-byte file ++ toFileName->Close(); ++ cString ActualToFileName(ReadLink(toFileName->Name()), true); ++ unlink(ActualToFileName); ++ unlink(toFileName->Name()); ++ ++ // Try to create a hard link ++ if (HardLinkVideoFile(fromFileName->Name(), toFileName->Name())) { ++ // Success. Skip all data transfer for this file ++ SkipThisSourceFile = true; ++ cutIn = false; ++ toFile = NULL; // was deleted by toFileName->Close() ++ } ++ else { ++ // Fallback: Re-open the file if necessary ++ toFile = toFileName->Open(); ++ } ++ } ++ } ++ } ++ ++ if (!SkipThisSourceFile) { ++#endif /* HARDLINKCUTTER */ + if (fromFile) { + int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); + if (len < 0) { +@@ -110,6 +229,7 @@ void cCuttingThread::Action(void) + break; + } + } ++#ifndef USE_HARDLINKCUTTER + else { + // Error, unless we're past the last cut-in and there's no cut-out + if (Mark || LastMark) +@@ -117,12 +237,17 @@ void cCuttingThread::Action(void) + break; + } + ++#endif /* HARDLINKCUTTER */ + // Write one frame: + + if (PictureType == I_FRAME) { // every file shall start with an I_FRAME + if (LastMark) // edited version shall end before next I-frame + break; ++#ifndef USE_HARDLINKCUTTER + if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { ++#else ++ if (!SkipThisSourceFile && FileSize > toFileName->MaxFileSize()) { ++#endif /* HARDLINKCUTTER */ + toFile = toFileName->NextFile(); + if (!toFile) { + error = "toFile 1"; +@@ -132,12 +257,20 @@ void cCuttingThread::Action(void) + } + LastIFrame = 0; + ++#ifndef USE_HARDLINKCUTTER + if (cutIn) { ++#else ++ if (!SkipThisSourceFile && cutIn) { ++#endif /* HARDLINKCUTTER */ + cRemux::SetBrokenLink(buffer, Length); + cutIn = false; + } + } ++#ifndef USE_HARDLINKCUTTER + if (toFile->Write(buffer, Length) < 0) { ++#else ++ if (!SkipThisSourceFile && toFile->Write(buffer, Length) < 0) { ++#endif /* HARDLINKCUTTER */ + error = "safe_write"; + break; + } +@@ -172,8 +305,44 @@ void cCuttingThread::Action(void) + } + } + else ++#ifndef USE_HARDLINKCUTTER + LastMark = true; ++#else ++ LastMark = true; // After last cut-out: Write on until next I-frame, then exit ++#endif /* HARDLINKCUTTER */ ++ } ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) { ++#endif /* HARDLINKCUTTER */ ++ bytes += Length; ++ if (bytes >= burst_size) { ++ int elapsed = t.Elapsed(); ++ int sleep = 0; ++ ++#if CUTTER_REL_BANDWIDTH > 0 && CUTTER_REL_BANDWIDTH < 100 ++ // stay under max. relative bandwidth ++ ++ sleep = (elapsed * 100 / CUTTER_REL_BANDWIDTH) - elapsed; ++ //if (sleep<=0 && elapsed<=2) sleep = 1; ++ //if (sleep) esyslog("cutter: relative bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++#endif ++ // stay under max. absolute bandwidth ++ if (elapsed < CUTTER_TIMESLICE) { ++ sleep = max(CUTTER_TIMESLICE - elapsed, sleep); ++ //if (sleep) esyslog("cutter: absolute bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++ } ++ ++ if (sleep>0) ++ cCondWait::SleepMs(sleep); ++ t.Set(); ++ bytes = 0; ++ } ++#ifdef USE_HARDLINKCUTTER + } ++#endif /* HARDLINKCUTTER */ ++#endif /* CUTTERLIMIT */ ++ + } + Recordings.TouchUpdate(); + } +@@ -183,18 +352,72 @@ void cCuttingThread::Action(void) + + // --- cCutter --------------------------------------------------------------- + ++#ifdef USE_CUTTERQUEUE ++#define WAIT_BEFORE_NEXT_CUT (10*1000) // 10 seconds ++ ++class cStringListObject : public cListObject { ++ public: ++ cStringListObject(const char *s) { str = strdup(s); } ++ ~cStringListObject() { free(str); } ++ ++ const char *Value() { return str; } ++ operator const char * () { return str; } ++ ++ private: ++ char *str; ++}; ++#endif /* CUTTERQUEUE */ ++ + char *cCutter::editedVersionName = NULL; + cCuttingThread *cCutter::cuttingThread = NULL; + bool cCutter::error = false; + bool cCutter::ended = false; ++#ifdef USE_CUTTERQUEUE ++cMutex *cCutter::cutterLock = new cMutex(); ++static uint64_t /*cCutter::*/lastCuttingEndTime = 0; ++static cList<cStringListObject> /**cCutter::*/cutterQueue /*= new cList<cStringListObject>*/; ++#endif /* CUTTERQUEUE */ + + bool cCutter::Start(const char *FileName) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++ if (FileName) { ++ /* Add file to queue. ++ * If cutter is still active, next cutting will be started ++ * when vdr.c:main calls cCutter::Active and previous cutting has ++ * been stopped > 10 s before ++ */ ++ cutterQueue.Add(new cStringListObject(FileName)); ++ } ++ if (cuttingThread) ++ return true; ++ /* cut next file from queue */ ++ if (!(cutterQueue.First())) ++ return false; ++ FileName = cutterQueue.First()->Value(); ++#endif /* CUTTERQUEUE */ + if (!cuttingThread) { + error = false; + ended = false; + cRecording Recording(FileName); ++#ifdef USE_CUTTIME ++ cMarks FromMarks; ++ FromMarks.Load(FileName); ++ cMark *First=FromMarks.First(); ++ if (First) Recording.SetStartTime(Recording.start+((First->position/FRAMESPERSEC+30)/60)*60); ++#endif /* CUTTIME */ + const char *evn = Recording.PrefixFileName('%'); ++#ifdef USE_CUTTERQUEUE ++ if (!(Recordings.GetByName(FileName))) { ++ // Should _not_ remove any cutted recordings ++ // (original recording already deleted ?) ++ // so, just pop item from queue and return. ++ esyslog("can't cut non-existing recording %s", FileName); ++ cutterQueue.Del(cutterQueue.First()); ++ return true; // might be already queued recording ++ } ++#endif /* CUTTERQUEUE */ + if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { + // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) + // remove a possible deleted recording with the same name to avoid symlink mixups: +@@ -220,6 +443,9 @@ bool cCutter::Start(const char *FileName + + void cCutter::Stop(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool Interrupted = cuttingThread && cuttingThread->Active(); + const char *Error = cuttingThread ? cuttingThread->Error() : NULL; + delete cuttingThread; +@@ -231,11 +457,20 @@ void cCutter::Stop(void) + esyslog("ERROR: '%s' during editing process", Error); + RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? + Recordings.DelByName(editedVersionName); ++#ifdef USE_CUTTERQUEUE ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ + } ++#ifdef USE_CUTTERQUEUE ++ lastCuttingEndTime = cTimeMs::Now(); ++#endif /* CUTTERQUEUE */ + } + + bool cCutter::Active(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + if (cuttingThread) { + if (cuttingThread->Active()) + return true; +@@ -246,12 +481,40 @@ bool cCutter::Active(void) + free(editedVersionName); + editedVersionName = NULL; + ended = true; ++#ifdef USE_CUTTERQUEUE ++ if (Setup.CutterAutoDelete) { ++ /* Remove original (if cutting was successful) */ ++ if (!error) { ++ cRecording *recording = Recordings.GetByName(*cutterQueue.First()); ++ if (!recording) ++ esyslog("ERROR: Can't found '%s' after editing process", cutterQueue.First()->Value()); ++ else { ++ if (recording->Delete()) ++ Recordings.DelByName(recording->FileName()); ++ else ++ esyslog("ERROR: Can't delete '%s' after editing process", cutterQueue.First()->Value()); ++ } ++ } ++ lastCuttingEndTime = cTimeMs::Now(); ++ } ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ ++ } ++#ifdef USE_CUTTERQUEUE ++ if (!cuttingThread && cutterQueue.First()) { ++ /* start next cutting from queue*/ ++ if (cTimeMs::Now() > lastCuttingEndTime + WAIT_BEFORE_NEXT_CUT) ++ Start(NULL); + } ++#endif /* CUTTERQUEUE */ + return false; + } + + bool cCutter::Error(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = error; + error = false; + return result; +@@ -259,6 +522,9 @@ bool cCutter::Error(void) + + bool cCutter::Ended(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = ended; + ended = false; + return result; +diff -ruNp vdr-1.7.0/cutter.h vdr-1.7.0-extensions/cutter.h +--- vdr-1.7.0/cutter.h 2002-06-22 12:03:15.000000000 +0200 ++++ vdr-1.7.0-extensions/cutter.h 2009-04-09 20:48:48.000000000 +0200 +@@ -11,6 +11,9 @@ + #define __CUTTER_H + + class cCuttingThread; ++#ifdef USE_CUTTERQUEUE ++class cMutex; ++#endif /* CUTTERQUEUE */ + + class cCutter { + private: +@@ -18,6 +21,9 @@ private: + static cCuttingThread *cuttingThread; + static bool error; + static bool ended; ++#ifdef USE_CUTTERQUEUE ++ static cMutex *cutterLock; ++#endif /* CUTTERQUEUE */ + public: + static bool Start(const char *FileName); + static void Stop(void); +diff -ruNp vdr-1.7.0/device.c vdr-1.7.0-extensions/device.c +--- vdr-1.7.0/device.c 2008-04-12 16:12:14.000000000 +0200 ++++ vdr-1.7.0-extensions/device.c 2009-04-09 20:48:48.000000000 +0200 +@@ -14,11 +14,22 @@ + #include "audio.h" + #include "channels.h" + #include "i18n.h" ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "player.h" + #include "receiver.h" + #include "status.h" + #include "transfer.h" + ++#ifdef USE_LNBSHARE ++#include "diseqc.h" ++#endif /* LNBSHARE */ ++ ++#ifdef USE_CHANNELSCAN ++bool scanning_on_receiving_device = false; ++#endif /* CHANNELSCAN */ ++ + // --- cLiveSubtitle --------------------------------------------------------- + + #define LIVESUBTITLEBUFSIZE KILOBYTE(100) +@@ -228,6 +239,12 @@ cDevice::cDevice(void) + + SetVideoFormat(Setup.VideoFormat); + ++#ifdef USE_LNBSHARE ++ LNBstate = -1; ++ LNBnr = Setup.CardUsesLNBnr[cardIndex]; ++ LNBsource = NULL; ++#endif /* LNBSHARE */ ++ + mute = false; + volume = Setup.CurrentVolume; + +@@ -253,8 +270,15 @@ cDevice::cDevice(void) + for (int i = 0; i < MAXRECEIVERS; i++) + receiver[i] = NULL; + ++#ifdef USE_SOURCECAPS ++ if (numDevices < MAXDEVICES) { ++ device[numDevices++] = this; ++ SetSourceCaps(cardIndex); ++ } ++#else + if (numDevices < MAXDEVICES) + device[numDevices++] = this; ++#endif /* SOURCECAPS */ + else + esyslog("ERROR: too many devices!"); + } +@@ -290,6 +314,16 @@ void cDevice::SetUseDevice(int n) + useDevice |= (1 << n); + } + ++#ifdef USE_LNBSHARE ++void cDevice::SetLNBnr(void) ++{ ++ for (int i = 0; i < numDevices; i++) { ++ device[i]->LNBnr = Setup.CardUsesLNBnr[i]; ++ isyslog("LNB-sharing: setting device %d to use LNB %d", i, device[i]->LNBnr); ++ } ++} ++#endif /* LNBSHARE */ ++ + int cDevice::NextCardIndex(int n) + { + if (n > 0) { +@@ -350,6 +384,98 @@ cDevice *cDevice::ActualDevice(void) + return d; + } + ++#ifdef USE_LNBSHARE ++cDevice *cDevice::GetBadDevice(const cChannel *Channel) ++{ ++ if (!cSource::IsSat(Channel->Source())) ++ return NULL; ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d on device %d. LNB or DiSEq conflict with device %d", LNBnr, Channel->Number(), this->DeviceNumber(), i); ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for for channel %d on device %d. OK", LNBnr, Channel->Number(), this->DeviceNumber()); ++ } ++ else { ++ char requiredState; ++ ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1 ; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. Conflict with device %d, LNBstate %d", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate, i, device[i]->GetLNBconf()); ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. No other devices affected", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate); ++ } ++ return NULL; ++} ++ ++int cDevice::GetMaxBadPriority(const cChannel *Channel) ++{ ++ if (!cSource::IsSat(Channel->Source())) return -2; ++ bool PrimaryIsBad = false; ++ int maxBadPriority = -2; ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) { ++ maxBadPriority = device[i]->Priority(); ++ } ++ if (device[i]->IsPrimaryDevice()) { ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ } ++ else { ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1 ; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) ++ maxBadPriority = device[i]->Priority(); ++ if (device[i]->IsPrimaryDevice()) ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ if (PrimaryIsBad && maxBadPriority == -2) ++ maxBadPriority = -1; ++ ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Request for channel %d on device %d. MaxBadPriority is %d", LNBnr, Channel->Number(), this->DeviceNumber(), maxBadPriority); ++ ++ return maxBadPriority; ++} ++#endif /* LNBSHARE */ ++ + cDevice *cDevice::GetDevice(int Index) + { + return (0 <= Index && Index < numDevices) ? device[Index] : NULL; +@@ -399,6 +525,10 @@ cDevice *cDevice::GetDevice(const cChann + cCamSlot *s = NULL; + + uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact ++#ifdef USE_LNBSHARE ++ int badPriority; ++ uint imp2; ++#endif /* LNBSHARE */ + for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) { + if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY) + continue; // there is no CAM available in this slot +@@ -423,6 +553,9 @@ cDevice *cDevice::GetDevice(const cChann + imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers + imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode + imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving ++#ifdef USE_LIVEBUFFER ++ imp <<= 2; imp |= cLiveBufferManager::Impact(device[i], Channel, LiveView); ++#endif /* LIVEBUFFER */ + imp <<= 2; imp |= GetClippedNumProvidedSystems(2, device[i]) - 1; // avoid cards which support multiple delivery systems + imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device + imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) +@@ -432,7 +565,31 @@ cDevice *cDevice::GetDevice(const cChann + imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels + imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards + imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel ++#ifdef USE_LNBSHARE ++ badPriority = device[i]->GetMaxBadPriority(Channel); ++ if (badPriority >= Priority || (badPriority == -1 && Priority < Setup.PrimaryLimit)) { ++ // channel is not available for the requested prioity ++ imp = 0xFFFFFFFF; ++ } ++ else { ++ switch (badPriority) { ++ case -2: // not affected by LNB-sharing ++ imp2 = 0; ++ break; ++ case -1: // the primary device would need a channel switch ++ imp += 1 << 17; ++ imp2 = 0xFFFFFFFF | 1 << 17; ++ break; ++ default: // a device receiving with lower priority would need to be stopped ++ imp += badPriority << 8; ++ imp2 = 0xFFFFFFFF | badPriority << 8; ++ break; ++ } ++ } ++ if (imp < Impact && imp2 < Impact) { ++#else + if (imp < Impact) { ++#endif /* LNBSHARE */ + // This device has less impact than any previous one, so we take it. + Impact = imp; + d = device[i]; +@@ -473,6 +630,18 @@ void cDevice::SetCamSlot(cCamSlot *CamSl + camSlot = CamSlot; + } + ++#ifdef USE_SOURCECAPS ++void cDevice::SetSourceCaps(int Index) ++{ ++ for (int d = 0; d < numDevices; d++) { ++ if (Index < 0 || Index == device[d]->CardIndex()) { ++ for (int i = 0; i < MAXSOURCECAPS; i++) ++ device[d]->sourceCaps[i] = Setup.SourceCaps[device[d]->CardIndex()][i]; ++ } ++ } ++} ++#endif /* SOURCECAPS */ ++ + void cDevice::Shutdown(void) + { + primaryDevice = NULL; +@@ -717,7 +886,11 @@ bool cDevice::ProvidesTransponder(const + bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const + { + for (int i = 0; i < numDevices; i++) { ++#ifdef USE_LNBSHARE ++ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel) && device[i]->GetLNBnr() != LNBnr) ++#else + if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel)) ++#endif /* LNBSHARE */ + return false; + } + return true; +@@ -745,6 +918,24 @@ bool cDevice::MaySwitchTransponder(void) + + bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) + { ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ if (this->GetMaxBadPriority(Channel) >= 0) { ++ Skins.Message(mtInfo, tr("Channel locked by LNB!")); ++ return false; ++ } ++ while ((tmpDevice = GetBadDevice(Channel)) != NULL) { ++ if (tmpDevice->IsPrimaryDevice() && LiveView) ++ tmpDevice->SwitchChannelForced(Channel, true); ++ else ++ tmpDevice->SwitchChannelForced(Channel, false); ++ } ++ return SwitchChannelForced(Channel, LiveView); ++} ++ ++bool cDevice::SwitchChannelForced(const cChannel *Channel, bool LiveView) ++{ ++#endif /* LNBSHARE */ + if (LiveView) { + isyslog("switching to channel %d", Channel->Number()); + cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer +@@ -774,7 +965,14 @@ bool cDevice::SwitchChannel(int Directio + cChannel *channel; + while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { + // try only channels which are currently available ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, channel) == false) ++#endif /* PINPLUGIN */ ++#ifdef USE_LNBSHARE ++ if (PrimaryDevice()->GetMaxBadPriority(channel) < 0 && (GetDevice(channel, 0, true))) ++#else + if (GetDevice(channel, 0, true)) ++#endif /* LNBSHARE */ + break; + n = channel->Number() + Direction; + } +@@ -795,7 +993,18 @@ bool cDevice::SwitchChannel(int Directio + + eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) + { ++#ifdef USE_PINPLUGIN ++ // I hope 'LiveView = false' indicates a channel switch for recording, ++ // I really don't know, but it works ... ++ if (LiveView && cStatus::MsgChannelProtected(this, Channel) == true) ++ return scrNotAvailable; ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_LIVEBUFFER ++ if (LiveView && !(Setup.LiveBuffer && dynamic_cast<cLivePlayer *>(player) != NULL)) { ++#else + if (LiveView) { ++#endif /* LIVEBUFFER */ + StopReplay(); + DELETENULL(liveSubtitle); + DELETENULL(dvbSubtitleConverter); +@@ -805,15 +1014,51 @@ eSetChannelResult cDevice::SetChannel(co + + bool NeedsTransferMode = Device != this; + ++#ifdef USE_LIVEBUFFER ++ if (LiveView && Setup.LiveBuffer) ++ NeedsTransferMode = true; ++#endif /* LIVEBUFFER */ ++ + eSetChannelResult Result = scrOk; + ++#ifdef USE_LNBSHARE ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Switching device %d to channel %d", LNBnr, this->DeviceNumber(), Channel->Number()); ++#endif /* LNBSHARE */ ++ + // If this DVB card can't receive this channel, let's see if we can + // use the card that actually can receive it and transfer data from there: + + if (NeedsTransferMode) { + if (Device && CanReplay()) { ++#ifdef USE_LNBSHARE ++ if (Device->GetLNBnr() == LNBnr) { ++ if (LNBstate != requiredState || (Setup.DiSEqC && LNBsource != (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())) ) { ++ if (IsPrimaryDevice()) ++ SetChannelDevice(Channel, true); ++ else ++ SetChannelDevice(Channel, false); ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ } ++ } ++#endif /* LNBSHARE */ + cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel + if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! ++#ifdef USE_LIVEBUFFER ++ if (Setup.LiveBuffer) ++ cLiveBufferManager::ChannelSwitch(Device,Channel); ++ else ++#endif /* LIVEBUFFER */ + cControl::Launch(new cTransferControl(Device, Channel->GetChannelID(), Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids())); + else + Result = scrNoTransfer; +@@ -829,6 +1074,10 @@ eSetChannelResult cDevice::SetChannel(co + sectionHandler->SetStatus(false); + sectionHandler->SetChannel(NULL); + } ++#ifdef USE_LNBSHARE ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++#endif /* LNBSHARE */ + // Tell the camSlot about the channel switch and add all PIDs of this + // channel to it, for possible later decryption: + if (camSlot) +@@ -861,7 +1110,11 @@ eSetChannelResult cDevice::SetChannel(co + } + for (int i = 0; i < MAXSPIDS; i++) + SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i)); ++#ifdef USE_SYNCEARLY ++ if ((Setup.UseSyncEarlyPatch && (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone)) || (!Setup.UseSyncEarlyPatch && !NeedsTransferMode)) ++#else + if (!NeedsTransferMode) ++#endif /* SYNCEARLY */ + EnsureAudioTrack(true); + EnsureSubtitleTrack(); + } +@@ -1121,7 +1374,12 @@ void cDevice::EnsureSubtitleTrack(void) + int LanguagePreference = INT_MAX; // higher than the maximum possible value + for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) { + const tTrackId *TrackId = GetTrack(eTrackType(i)); ++#ifdef USE_LIEMIEXT ++ if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) || ++ ((i == ttSubtitleFirst + 8) && !(*TrackId->language) && (LanguagePreference == INT_MAX)))) ++#else + if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference)) ++#endif /* LIEMIEXT */ + PreferredTrack = eTrackType(i); + } + // Make sure we're set to an available subtitle track: +@@ -1185,7 +1443,11 @@ bool cDevice::Replaying(void) const + + bool cDevice::Transferring(void) const + { ++#ifdef USE_LIVEBUFFER ++ return ActualDevice() != PrimaryDevice() || dynamic_cast<cLivePlayer *>(player) != NULL; // TODO ++#else + return ActualDevice() != PrimaryDevice(); ++#endif /* LIVEBUFFER */ + } + + bool cDevice::AttachPlayer(cPlayer *Player) +@@ -1310,7 +1572,11 @@ pre_1_3_19_PrivateStreamDetected: + w = PlaySubtitle(Start, d); + break; + case 0x80: // AC3 & DTS ++#ifdef USE_DOLBYINREC ++ if (Setup.UseDolbyInRecordings) { ++#else + if (Setup.UseDolbyDigital) { ++#endif /* DOLBYINREC */ + SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId); + if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) { + w = PlayAudio(Start, d, SubStreamId); +diff -ruNp vdr-1.7.0/device.h vdr-1.7.0-extensions/device.h +--- vdr-1.7.0/device.h 2008-04-12 13:11:23.000000000 +0200 ++++ vdr-1.7.0-extensions/device.h 2009-04-09 20:48:48.000000000 +0200 +@@ -23,8 +23,13 @@ + #include "spu.h" + #include "thread.h" + #include "tools.h" ++#ifdef USE_ROTOR ++#include <linux/dvb/frontend.h> ++#endif /* ROTOR */ + ++#ifndef USE_SOURCECAPS + #define MAXDEVICES 16 // the maximum number of devices in the system ++#endif /* SOURCECAPS */ + #define MAXPIDHANDLES 64 // the maximum number of different PIDs per device + #define MAXRECEIVERS 16 // the maximum number of receivers per device + #define MAXVOLUME 255 +@@ -34,6 +39,10 @@ + #define TS_SYNC_BYTE 0x47 + #define PID_MASK_HI 0x1F + ++#ifdef USE_CHANNELSCAN ++extern bool scanning_on_receiving_device; ++#endif /* CHANNELSCAN */ ++ + enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed }; + + enum ePlayMode { pmNone, // audio/video from decoder +@@ -146,6 +155,35 @@ public: + ///< this device/CAM combination will be skipped in the next call to + ///< GetDevice(). + ///< See also ProvidesChannel(). ++#ifdef USE_SOURCECAPS ++ static void SetSourceCaps(int Index = -1); ++ ///< Sets the SourceCaps of the given device according to the Setup data. ++#endif /* SOURCECAPS */ ++#ifdef USE_LNBSHARE ++private: ++ char LNBstate; // Current frequency band and polarization of the DVB-tuner ++// cDiseqc *LNBsource; // can not #include "diseqc.h". A workaround follows: ++ int *LNBsource; // [DiSEqC] DiSEqC-Source ++ int LNBnr; // Number of LNB used ++public: ++ char GetLNBconf(void) { return LNBstate; } ++ int *GetLNBsource(void) { return LNBsource; } ++ int GetLNBnr(void) { return LNBnr; } ++ static void SetLNBnr(void); ++ cDevice *GetBadDevice(const cChannel *Channel); ++ ///< Returns NULL if there is no device which uses the same LNB or if ++ ///< all of those devices are tuned to the same frequency band and ++ ///< polarization as of the requested channel. ++ ///< Otherwise returns the first device found. ++ int GetMaxBadPriority(const cChannel *Channel); ++ ///< Returns the highest priority of all receiving devices which use ++ ///< the same LNB and are tuned to a different frequency band or ++ ///< polarization as of the requested channel. ++ ///< Returns -1 if there are no such devices, but the primary device ++ ///< would be affected by switching to the requested channel. ++ ///< Returns -2 if there are no such devices and the primary device ++ ///< would not be affected by switching to the requested channel. ++#endif /* LNBSHARE */ + static void SetAvoidDevice(cDevice *Device) { avoidDevice = Device; } + ///< Sets the given Device to be temporarily avoided in the next call to + ///< GetDevice(const cChannel, int, bool). +@@ -156,6 +194,9 @@ private: + static int nextCardIndex; + int cardIndex; + protected: ++#ifdef USE_SOURCECAPS ++ int sourceCaps[MAXSOURCECAPS]; ++#endif /* SOURCECAPS */ + cDevice(void); + virtual ~cDevice(); + virtual bool Ready(void); +@@ -243,17 +284,30 @@ public: + bool SwitchChannel(const cChannel *Channel, bool LiveView); + ///< Switches the device to the given Channel, initiating transfer mode + ///< if necessary. ++ ++#ifdef USE_LNBSHARE ++ bool SwitchChannelForced(const cChannel *Channel, bool LiveView); ++ ///< Switches the device to the given channel, initiating transfer mode ++ ///< if necessary. Forces the switch without taking care of the LNB configuration. ++#endif /* LNBSHARE */ ++ + static bool SwitchChannel(int Direction); + ///< Switches the primary device to the next available channel in the given + ///< Direction (only the sign of Direction is evaluated, positive values + ///< switch to higher channel numbers). + private: ++#ifndef USE_YAEPG + eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (actual physical setup). + public: ++#ifdef USE_YAEPG ++ eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); ++ ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; } + ///< Returns the number of the current channel on the primary device. + static void SetCurrentChannel(const cChannel *Channel) { currentChannel = Channel ? Channel->Number() : 0; } +@@ -271,6 +325,9 @@ public: + virtual bool HasProgramme(void); + ///< Returns true if the device is currently showing any programme to + ///< the user, either through replaying or live. ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd) { return false; } ++#endif /* ROTOR */ + + // PID handle facilities + +diff -ruNp vdr-1.7.0/dvbdevice.c vdr-1.7.0-extensions/dvbdevice.c +--- vdr-1.7.0/dvbdevice.c 2008-04-13 16:15:35.000000000 +0200 ++++ vdr-1.7.0-extensions/dvbdevice.c 2009-04-09 20:48:48.000000000 +0200 +@@ -71,6 +71,9 @@ static int DvbOpen(const char *Name, int + class cDvbTuner : public cThread { + private: + enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked }; ++#ifdef USE_ROTOR ++ bool SendDiseqc; ++#endif /* ROTOR */ + int fd_frontend; + int cardIndex; + int tuneTimeout; +@@ -83,6 +86,9 @@ private: + cMutex mutex; + cCondVar locked; + cCondVar newSet; ++#ifdef USE_ROTOR ++ dvb_diseqc_master_cmd diseqc_cmd; ++#endif /* ROTOR */ + bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0); + bool SetFrontend(void); + virtual void Action(void); +@@ -91,12 +97,18 @@ public: + virtual ~cDvbTuner(); + bool IsTunedTo(const cChannel *Channel) const; + void Set(const cChannel *Channel, bool Tune); ++#ifdef USE_ROTOR ++ bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + bool Locked(int TimeoutMs = 0); + }; + + cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, dvbfe_delsys FrontendType) + { + fd_frontend = Fd_Frontend; ++#ifdef USE_ROTOR ++ SendDiseqc = false; ++#endif /* ROTOR */ + cardIndex = CardIndex; + frontendType = FrontendType; + tuneTimeout = 0; +@@ -164,6 +176,19 @@ bool cDvbTuner::Locked(int TimeoutMs) + return tunerStatus >= tsLocked; + } + ++#ifdef USE_ROTOR ++bool cDvbTuner::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ cMutexLock MutexLock(&mutex); ++ if ((!DVBFE_DELSYS_DVBS & !DVBFE_DELSYS_DVBS2) || SendDiseqc) ++ return false; ++ diseqc_cmd = cmd; ++ SendDiseqc = true; ++ newSet.Broadcast(); ++ return true; ++} ++#endif /* ROTOR */ ++ + bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs) + { + if (TimeoutMs) { +@@ -225,6 +250,9 @@ bool cDvbTuner::SetFrontend(void) + } + } + diseqcCommands = diseqc->Commands(); ++#ifdef USE_DVBSETUP ++ isyslog("Sent DISEQC command: %s", diseqcCommands); ++#endif /* DVBSETUP */ + } + frequency -= diseqc->Lof(); + } +@@ -286,6 +314,22 @@ bool cDvbTuner::SetFrontend(void) + feinfo.delivery = Frontend.delivery; + CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system + } ++#ifdef USE_ATSC ++ else if (frontendType & DVBFE_DELSYS_ATSC) { ++ // Frequency and symbol rate: ++ ++ Frontend.frequency = FrequencyToHz(channel.Frequency()); ++ Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); ++ Frontend.delsys.atsc.modulation = dvbfe_modulation(channel.Modulation()); ++ ++ tuneTimeout = DVBC_TUNE_TIMEOUT; ++ lockTimeout = DVBC_LOCK_TIMEOUT; ++ ++ dvbfe_info feinfo; ++ feinfo.delivery = Frontend.delivery; ++ CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system ++ } ++#endif /* ATSC */ + else if (frontendType & DVBFE_DELSYS_DVBT) { + Frontend.delivery = DVBFE_DELSYS_DVBT; + Frontend.frequency = FrequencyToHz(channel.Frequency()); +@@ -328,6 +372,12 @@ void cDvbTuner::Action(void) + if (GetFrontendStatus(NewStatus, 10)) + Status = NewStatus; + cMutexLock MutexLock(&mutex); ++#ifdef USE_ROTOR ++ if (SendDiseqc) { ++ CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &diseqc_cmd)); ++ SendDiseqc = false; ++ } ++#endif /* ROTOR */ + switch (tunerStatus) { + case tsIdle: + break; +@@ -463,6 +513,10 @@ cDvbDevice::cDvbDevice(int n) + if (ioctl(fd_frontend, DVBFE_GET_DELSYS, &frontendType) >= 0) { + const char **DeliverySystem = DeliverySystems; + cString ds; ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlockerMode == 4) ++ frontendType = n == Setup.PrimaryDVB - 1 ? DVBFE_DELSYS_DUMMY : frontendType; ++#endif /* DVBSETUP */ + for (int i = 0; i < 32; i++) { + if (frontendType & (1u << i)) { + numProvidedSystems++; +@@ -694,6 +748,13 @@ eVideoSystem cDvbDevice::GetVideoSystem( + + bool cDvbDevice::SetAudioBypass(bool On) + { ++#ifdef USE_DVBSETUP ++ if (Setup.DolbyTransferFix && On) { ++ cChannel *c=Channels.GetByNumber(cDevice::CurrentChannel()); ++ if (c->Ca(0) != 0) ++ return false; ++ } ++#endif /* DVBSETUP */ + if (setTransferModeForDolbyDigital != 1) + return false; + return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0; +@@ -799,14 +860,43 @@ void cDvbDevice::TurnOffLiveMode(bool Li + bool cDvbDevice::ProvidesSource(int Source) const + { + int type = Source & cSource::st_Mask; ++#ifdef USE_SOURCECAPS ++ if (Setup.SourceCapsSet && type == cSource::stSat && (frontendType & (DVBFE_DELSYS_DVBS | DVBFE_DELSYS_DVBS2))) { ++ for (int i = 0; i < MAXSOURCECAPS; i++) ++ if (sourceCaps[i] == Source) ++ return true; ++ return false; ++ } ++ else ++#endif /* SOURCECAPS */ + return type == cSource::stNone + || type == cSource::stCable && (frontendType & DVBFE_DELSYS_DVBC) ++#ifdef USE_ATSC ++ || type == cSource::stCable && (frontendType & DVBFE_DELSYS_ATSC) ++ || type == cSource::stTerr && (frontendType & DVBFE_DELSYS_ATSC) ++#endif /* ATSC */ + || type == cSource::stSat && (frontendType & (DVBFE_DELSYS_DVBS | DVBFE_DELSYS_DVBS2)) + || type == cSource::stTerr && (frontendType & DVBFE_DELSYS_DVBT); + } + + bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const + { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlocker != 0) { ++ if ((Setup.ChannelBlockerMode == 0) || ++ (Setup.ChannelBlockerMode == 1 && HasDecoder()) || ++ (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || ++ (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { ++ if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && Channel->Modulation() == QAM_256) || ++ (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || ++ (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || ++ (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist ++ (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist ++ (Setup.ChannelBlocker == 6)) ++ return false; ++ } ++ } ++#endif /* DVBSETUP */ + if (!ProvidesSource(Channel->Source())) + return false; // doesn't provide source + if (!cSource::IsSat(Channel->Source())) +@@ -818,10 +908,31 @@ bool cDvbDevice::ProvidesTransponder(con + + bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const + { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlocker != 0) { ++ if ((Setup.ChannelBlockerMode == 0) || ++ (Setup.ChannelBlockerMode == 1 && HasDecoder()) || ++ (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || ++ (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { ++ if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && Channel->Modulation() == QAM_256) || ++ (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || ++ (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || ++ (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist ++ (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist ++ (Setup.ChannelBlocker == 6)) ++ return false; ++ } ++ } ++#endif /* DVBSETUP */ + bool result = false; + bool hasPriority = Priority < 0 || Priority > this->Priority(); + bool needsDetachReceivers = false; + ++#ifdef USE_ANALOGTV ++ if ((Channel->Ca(0) == 0xA0) || (Channel->Ca(0) == 0xA1) || (Channel->Ca(0) == 0xA2)) ++ return false; ++#endif /* ANALOGTV */ ++ + if (ProvidesTransponder(Channel)) { + result = hasPriority; + if (Priority >= 0 && Receiving(true)) { +@@ -882,7 +993,11 @@ bool cDvbDevice::SetChannelDevice(const + || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + ); + ++#ifdef USE_LIVEBUFFER ++ bool StartTransferMode = IsPrimaryDevice() && !DoTune && !Setup.LiveBuffer ++#else + bool StartTransferMode = IsPrimaryDevice() && !DoTune ++#endif /* LIVEBUFFER */ + && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER + || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + ); +@@ -938,6 +1053,13 @@ bool cDvbDevice::HasLock(int TimeoutMs) + return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false; + } + ++#ifdef USE_ROTOR ++bool cDvbDevice::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ return dvbTuner->SendDiseqcCmd(cmd); ++} ++#endif /* ROTOR */ ++ + int cDvbDevice::GetAudioChannelDevice(void) + { + if (HasDecoder()) { +diff -ruNp vdr-1.7.0/dvbdevice.h vdr-1.7.0-extensions/dvbdevice.h +--- vdr-1.7.0/dvbdevice.h 2008-04-12 13:20:48.000000000 +0200 ++++ vdr-1.7.0-extensions/dvbdevice.h 2009-04-09 20:48:48.000000000 +0200 +@@ -73,6 +73,9 @@ protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + public: + virtual bool HasLock(int TimeoutMs = 0); ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + + // PID handle facilities + +diff -ruNp vdr-1.7.0/dvbosd.c vdr-1.7.0-extensions/dvbosd.c +--- vdr-1.7.0/dvbosd.c 2007-09-16 10:55:54.000000000 +0200 ++++ vdr-1.7.0-extensions/dvbosd.c 2009-04-09 20:48:48.000000000 +0200 +@@ -20,12 +20,26 @@ + #define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 + #define MAXOSDMEMORY 92000 // number of bytes available to the OSD (for unmodified DVB cards) + ++#ifdef USE_SOFTOSD ++ #define SOFTOSD_MAXSIZE (720*576) ++ #define SOFTOSD_MINSIZE (720*64) ++#endif ++ + class cDvbOsd : public cOsd { + private: + int osdDev; + int osdMem; + bool shown; + void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); ++#ifdef USE_SOFTOSD ++ int GetOsdSize() { ++ int OsdSize = 0; ++ cBitmap *Bitmap; ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) ++ OsdSize += Bitmap->Width() * Bitmap->Height(); ++ return OsdSize; ++ } ++#endif + protected: + virtual void SetActive(bool On); + public: +@@ -76,6 +90,44 @@ void cDvbOsd::SetActive(bool On) + } + else if (shown) { + cBitmap *Bitmap; ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { ++ for (int fade = Setup.SoftOsdFadeoutSteps - 1; fade > 0; fade--) { ++ int64_t flush_start = cTimeMs::Now(); ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { ++ Cmd(OSD_SetWindow, 0, i + 1); ++ int NumColors; ++ const tColor *Colors = Bitmap->Colors(NumColors); ++ if (Colors) { ++ tColor colors[NumColors]; ++ for (int i = 0; i < NumColors; i++) { ++ // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): ++ int alpha = (Colors[i] >> 24) & 0x000000FF; ++ alpha = (alpha * fade) / Setup.SoftOsdFadeoutSteps; ++ colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++ } ++ Colors = colors; ++ Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); ++ if (!Setup.SoftOsdPaletteOnly) { ++ //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); ++ Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); ++ } ++ } ++ } ++ int flush_time = cTimeMs::Now() - flush_start; ++ dsyslog("SOFTOSD: FadeOut Step %d from %d FlushTime = %d ms", ++ Setup.SoftOsdFadeoutSteps - fade, Setup.SoftOsdFadeoutSteps - 1, flush_time); ++ int wait_time = 1000 / Setup.SoftOsdRate; ++ while (flush_time > wait_time && fade > 2) { ++ fade--; ++ flush_time -= wait_time; ++ } ++ cCondWait::SleepMs(wait_time-flush_time); ++ } ++ } ++ } ++#endif /* SOFTOSD */ + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Close); +@@ -83,6 +135,12 @@ void cDvbOsd::SetActive(bool On) + shown = false; + } + } ++#ifdef USE_YAEPG ++ if (vidWin.bpp != 0) { ++ Cmd(OSD_SetWindow, 0, 5); ++ Cmd(OSD_Close); ++ } ++#endif /* YAEPG */ + } + + eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas) +@@ -182,6 +240,12 @@ void cDvbOsd::Flush(void) + for (int i = 0; i < NumColors; i++) { + // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): + colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd && !shown) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) ++ colors[i] = 0; ++ } ++#endif /* SOFTOSD */ + } + Colors = colors; + //TODO end of stuff that should be fixed in the driver +@@ -198,6 +262,52 @@ void cDvbOsd::Flush(void) + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0()); + } ++#ifdef USE_YAEPG ++ if (vidWin.bpp != 0) { ++ Cmd(OSD_SetWindow, 0, 5); ++ Cmd(OSD_OpenRaw, vidWin.bpp, vidWin.x1, vidWin.y1, ++ vidWin.x2, vidWin.y2, (void *)0); ++ } ++#endif /* YAEPG */ ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { ++ for (int fade = 1; fade <= Setup.SoftOsdFadeinSteps; fade++) { ++ int64_t flush_start = cTimeMs::Now(); ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { ++ Cmd(OSD_SetWindow, 0, i + 1); ++ int NumColors; ++ const tColor *Colors = Bitmap->Colors(NumColors); ++ if (Colors) { ++ tColor colors[NumColors]; ++ for (int i = 0; i < NumColors; i++) { ++ // convert AARRGGBB to AABBGGRR: ++ int alpha = (Colors[i]>>24) & 0x000000FF; ++ alpha = (alpha * fade) / Setup.SoftOsdFadeinSteps; ++ colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++ } ++ Colors = colors; ++ Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); ++ if (!Setup.SoftOsdPaletteOnly) { ++ //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); ++ Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); ++ } ++ } ++ } ++ int flush_time = cTimeMs::Now() - flush_start; ++ dsyslog("SOFTOSD: FadeIn Step %d from %d FlushTime = %d ms", fade, Setup.SoftOsdFadeinSteps, flush_time); ++ int wait_time = 1000 / Setup.SoftOsdRate; ++ while (flush_time > wait_time && fade < Setup.SoftOsdFadeinSteps - 1) { ++ fade++; ++ flush_time -= wait_time; ++ } ++ if (fade == Setup.SoftOsdFadeinSteps) /* last step, don't wait */ ++ break; ++ cCondWait::SleepMs(wait_time - flush_time); ++ } ++ } ++ } ++#endif /* SOFTOSD */ + shown = true; + } + } +diff -ruNp vdr-1.7.0/dvbplayer.c vdr-1.7.0-extensions/dvbplayer.c +--- vdr-1.7.0/dvbplayer.c 2008-02-09 16:10:54.000000000 +0100 ++++ vdr-1.7.0-extensions/dvbplayer.c 2009-04-09 20:48:48.000000000 +0200 +@@ -14,6 +14,9 @@ + #include "ringbuffer.h" + #include "thread.h" + #include "tools.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + // --- cBackTrace ------------------------------------------------------------ + +@@ -193,6 +196,9 @@ private: + cNonBlockingFileReader *nonBlockingFileReader; + cRingBufferFrame *ringBuffer; + cBackTrace *backTrace; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#endif /* JUMPPLAY */ + cFileName *fileName; + cIndexFile *index; + cUnbufferedFile *replayFile; +@@ -234,7 +240,11 @@ public: + int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; + + cDvbPlayer::cDvbPlayer(const char *FileName) ++#ifdef USE_JUMPPLAY ++:cThread("dvbplayer"), marks(FileName) ++#else + :cThread("dvbplayer") ++#endif /* JUMPPLAY */ + { + nonBlockingFileReader = NULL; + ringBuffer = NULL; +@@ -312,6 +322,35 @@ void cDvbPlayer::Empty(void) + firstPacket = true; + } + ++ ++#ifdef USE_TTXTSUBS ++static void StripExtendedPackets(uchar *b, int Length) ++{ ++ for (int i = 0; i < Length - 6; i++) { ++ if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { ++ uchar c = b[i + 3]; ++ int l = b[i + 4] * 256 + b[i + 5] + 6; ++ switch (c) { ++ case 0xBD: // dolby ++ // EBU Teletext data, ETSI EN 300 472 ++ if (b[i + 8] == 0x24 && b[i + 45] >= 0x10 && b[i + 45] < 0x20) { ++ cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData(&b[i], l); ++ // continue with deleting the data - otherwise it disturbs DVB replay ++ int n = l; ++ for (int j = i; j < Length && n--; j++) ++ b[j] = 0x00; ++ } ++ break; ++ default: ++ break; ++ } ++ if (l) ++ i += l - 1; // the loop increments, too! ++ } ++ } ++} ++#endif /* TTXTSUBS */ ++ + bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset) + { + if (FileNumber > 0) +@@ -341,6 +380,11 @@ bool cDvbPlayer::Save(void) + if (index) { + int Index = writeIndex; + if (Index >= 0) { ++#ifdef USE_JUMPPLAY ++ // set resume position to 0 if replay stops at the first mark ++ if (Setup.PlayJump && marks.First() && abs(Index - marks.First()->position) <= RESUMEBACKUP) ++ Index = 0; ++#endif /* JUMPPLAY */ + Index -= RESUMEBACKUP; + if (Index > 0) + Index = index->GetNextIFrame(Index, false); +@@ -363,16 +407,156 @@ void cDvbPlayer::Activate(bool On) + Cancel(9); + } + ++#ifdef USE_DVBPLAYER ++// --- BEGIN fix for I frames ------------------------------------------- ++// ++// Prior to the introduction of cVideoRepacker, VDR didn't start a new ++// PES packet when a new frame started. So, it was likely that the tail ++// of an I frame was at the beginning of the packet which started the ++// following B frame. Due to the organisation of VDR's index file, VDR ++// typically didn't read the tail of the I frame and therefore caused ++// softdevice plugins to not render such a frame as it was incomplete, ++// e. g. when moving cutting marks. ++// ++// The following code tries to fix incomplete I frames for recordings ++// made prior to the introdcution of cVideoRepacker, to be able to ++// edit cutting marks for example with softdevice plugins like vdr-xine. ++// ++ ++static uchar *findStartCode(uchar *Data, int Length, int &PesPayloadOffset) ++{ ++ uchar *limit = Data + Length; ++ if (AnalyzePesHeader(Data, Length, PesPayloadOffset) <= phInvalid) ++ return 0; // neither MPEG1 nor MPEG2 ++ ++ Data += PesPayloadOffset + 3; // move to video payload and skip 00 00 01 ++ while (Data < limit) { ++ // possible start codes that appear before/after picture data ++ // 00 00 01 B3: sequence header code ++ // 00 00 01 B8: group start code ++ // 00 00 01 00: picture start code ++ // 00 00 01 B7: sequence end code ++ if (0x01 == Data[-1] && (0xB3 == Data[0] || 0xB8 == Data[0] || 0x00 == Data[0] || 0xB7 == Data[0]) && 0x00 == Data[-2] && 0x00 == Data[-3]) ++ return Data - 3; ++ Data++; ++ } ++ ++ return 0; ++} ++ ++static void fixIFrameHead(uchar *Data, int Length) ++{ ++ int pesPayloadOffset = 0; ++ uchar *p = findStartCode(Data, Length, pesPayloadOffset); ++ if (!p) { ++ esyslog("fixIframeHead: start code not found!\n"); ++ return; ++ } ++ ++ Data += pesPayloadOffset; // move to video payload ++ if (Data < p) ++ memset(Data, 0, p - Data); // zero preceeding bytes ++} ++ ++static int fixIFrameTail(uchar *Data, int Length) ++{ ++ int pesPayloadOffset = 0; ++ uchar *p = findStartCode(Data, Length, pesPayloadOffset); ++ if (!p) { ++ esyslog("fixIframeTail: start code not found!\n"); ++ return Length; ++ } ++ ++ // is this PES packet required? ++ uchar *videoPayload = Data + pesPayloadOffset; ++ if (videoPayload >= p) ++ return 0; // no ++ ++ // adjust PES length ++ int lenPES = (p - Data); ++ Data[4] = (lenPES - 6) >> 8; ++ Data[5] = (lenPES - 6) & 0xFF; ++ ++ return lenPES; ++} ++ ++#define IPACKS 2048 // originally defined in remux.c ++ ++static void fixIFrame(uchar *Data, int &Length, const int OriginalLength) ++{ ++ int done = 0; ++ ++ while (done < Length) { ++ if (0x00 != Data[0] || 0x00 != Data[1] || 0x01 != Data[2]) { ++ esyslog("fixIFrame: PES start code not found at offset %d (data length: %d, original length: %d)!", done, Length, OriginalLength); ++ if (Length > OriginalLength) // roll back additional data ++ Length = OriginalLength; ++ return; ++ } ++ ++ int lenPES = 6 + Data[4] * 256 + Data[5]; ++ if (0xBA == Data[3]) { // pack header has fixed length ++ if (0x00 == (0xC0 & Data[4])) ++ lenPES = 12; // MPEG1 ++ else ++ lenPES = 14 + (Data[13] & 0x07); // MPEG2 ++ } ++ else if (0xB9 == Data[3]) // stream end has fixed length ++ lenPES = 4; ++ else if (0xE0 == (0xF0 & Data[3])) { // video packet ++ int todo = Length - done; ++ int bite = (lenPES < todo) ? lenPES : todo; ++ if (0 == done) // first packet ++ fixIFrameHead(Data, bite); ++ else if (done >= OriginalLength) { // last packet ++ Length = done + fixIFrameTail(Data, bite); ++ return; ++ } ++ } ++ else if (0 == done && 0xC0 == (0xE0 & Data[3])) { ++ // if the first I frame packet is an audio packet then this is a radio recording: don't touch it! ++ if (Length > OriginalLength) // roll back additional data ++ Length = OriginalLength; ++ return; ++ } ++ ++ done += lenPES; ++ Data += lenPES; ++ } ++} ++ ++// --- END fix for I frames --------------------------------------------- ++#endif /* DVBPLAYER */ ++ + void cDvbPlayer::Action(void) + { + uchar *b = NULL; + uchar *p = NULL; + int pc = 0; ++#ifdef USE_JUMPPLAY ++ bool cutIn = false; ++ int total = -1; ++#endif /* JUMPPLAY */ + + readIndex = Resume(); + if (readIndex >= 0) + isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); + ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump && readIndex <= 0 && marks.First() && index) { ++ int Index = marks.First()->position; ++ uchar FileNumber; ++ int FileOffset; ++ if (index->Get(Index, &FileNumber, &FileOffset) && ++ NextFile(FileNumber, FileOffset)) { ++ isyslog("PlayJump: start replay at first mark %d (%s)", ++ Index, *IndexToHMSF(Index, true)); ++ readIndex = Index; ++ } ++ } ++ ++ bool LastMarkPause = false; ++#endif /* JUMPPLAY */ + nonBlockingFileReader = new cNonBlockingFileReader; + int Length = 0; + bool Sleep = false; +@@ -393,7 +577,11 @@ void cDvbPlayer::Action(void) + + // Read the next frame from the file: + ++#ifdef USE_JUMPPLAY ++ if (playMode != pmStill && playMode != pmPause && !LastMarkPause) { ++#else + if (playMode != pmStill && playMode != pmPause) { ++#endif /* JUMPPLAY */ + if (!readFrame && (replayFile || readIndex >= 0)) { + if (!nonBlockingFileReader->Reading()) { + if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { +@@ -411,6 +599,9 @@ void cDvbPlayer::Action(void) + if (!NextFile(FileNumber, FileOffset)) { + readIndex = Index; + continue; ++#ifdef USE_DVBPLAYER ++ Length += IPACKS; // fixIFrame needs next video packet ++#endif /* DVBPLAYER */ + } + } + else { +@@ -438,6 +629,46 @@ void cDvbPlayer::Action(void) + uchar FileNumber; + int FileOffset; + readIndex++; ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump || Setup.PauseLastMark) { ++ // check for end mark - jump to next mark or pause ++ marks.Reload(); ++ cMark *m = marks.Get(readIndex); ++ if (m && (m->Index() & 0x01) != 0) { ++ m = marks.Next(m); ++ int Index; ++ if (m) ++ Index = m->position; ++ else if (Setup.PauseLastMark) { ++ // pause at last mark ++ isyslog("PauseLastMark: pause at position %d (%s)", ++ readIndex, *IndexToHMSF(readIndex, true)); ++ LastMarkPause = true; ++ Index = -1; ++ } ++ else if (total == index->Last()) ++ // at last mark jump to end of recording ++ Index = index->Last() - 1; ++ else ++ // jump but stay off end of live-recordings ++ Index = index->GetNextIFrame(index->Last() - 150, true); ++ // don't jump in edited recordings ++ if (Setup.PlayJump && Index > readIndex && ++ Index > index->GetNextIFrame(readIndex, true)) { ++ isyslog("PlayJump: %d frames to %d (%s)", ++ Index - readIndex, Index, ++ *IndexToHMSF(Index, true)); ++ readIndex = Index; ++ cutIn = true; ++ } ++ } ++ } ++ // for detecting growing length of live-recordings ++ uchar PictureType; ++ if (index->Get(readIndex, &FileNumber, &FileOffset, &PictureType) && ++ PictureType == I_FRAME) ++ total = index->Last(); ++#endif /* JUMPPLAY */ + if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) { + readIndex = -1; + eof = true; +@@ -457,6 +688,10 @@ void cDvbPlayer::Action(void) + int r = nonBlockingFileReader->Read(replayFile, b, Length); + if (r > 0) { + WaitingForData = false; ++#ifdef USE_DVBPLAYER ++ if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) ++ fixIFrame(b, r, Length - IPACKS); ++#endif /* DVBPLAYER */ + readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer + b = NULL; + } +@@ -473,6 +708,12 @@ void cDvbPlayer::Action(void) + // Store the frame in the buffer: + + if (readFrame) { ++#ifdef USE_JUMPPLAY ++ if (cutIn) { ++ cRemux::SetBrokenLink(readFrame->Data(), readFrame->Count()); ++ cutIn = false; ++ } ++#endif /* JUMPPLAY */ + if (ringBuffer->Put(readFrame)) + readFrame = NULL; + } +@@ -503,6 +744,9 @@ void cDvbPlayer::Action(void) + } + } + if (p) { ++#ifdef USE_TTXTSUBS ++ StripExtendedPackets(p, pc); ++#endif /* TTXTSUBS */ + int w = PlayPes(p, pc, playMode != pmPlay); + if (w > 0) { + p += w; +@@ -521,8 +765,19 @@ void cDvbPlayer::Action(void) + p = NULL; + } + } ++#ifdef USE_JUMPPLAY ++ else { ++ if (LastMarkPause) { ++ LastMarkPause = false; ++ playMode = pmPause; ++ writeIndex = readIndex; ++ } ++ Sleep = true; ++ } ++#else + else + Sleep = true; ++#endif /* JUMPPLAY */ + } + } + +@@ -699,9 +954,15 @@ void cDvbPlayer::Goto(int Index, bool St + int FileOffset, Length; + Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); + if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { ++#ifdef USE_DVBPLAYER ++ Length += IPACKS; // fixIFrame needs next video packet ++#endif /* DVBPLAYER */ + uchar b[MAXFRAMESIZE + 4 + 5 + 4]; + int r = ReadFrame(replayFile, b, Length, sizeof(b)); + if (r > 0) { ++#ifdef USE_DVBPLAYER ++ fixIFrame(b, r, Length - IPACKS); ++#endif /* DVBPLAYER */ + if (playMode == pmPause) + DevicePlay(); + // append sequence end code to get the image shown immediately with softdevices +diff -ruNp vdr-1.7.0/eit.c vdr-1.7.0-extensions/eit.c +--- vdr-1.7.0/eit.c 2008-04-13 13:27:06.000000000 +0200 ++++ vdr-1.7.0-extensions/eit.c 2009-04-09 20:48:48.000000000 +0200 +@@ -17,13 +17,40 @@ + #include "libsi/section.h" + #include "libsi/descriptor.h" + ++#ifdef USE_SETTIME ++extern char *SetTime; ++#endif /* SETTIME */ ++ + // --- cEIT ------------------------------------------------------------------ + + class cEIT : public SI::EIT { + public: + cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus = false); ++#ifdef USE_NOEPG ++private: ++ bool allowedEPG(tChannelID kanalID); ++#endif /* NOEPG */ + }; + ++#ifdef USE_NOEPG ++bool cEIT::allowedEPG(tChannelID kanalID) { ++ bool rc; ++ ++ if (Setup.noEPGMode == 1) { ++ rc = false; ++ if (strstr(::Setup.noEPGList,kanalID.ToString()) != NULL) ++ rc = true; ++ } ++ else { ++ rc = true; ++ if (strstr(::Setup.noEPGList,kanalID.ToString()) != NULL) ++ rc = false; ++ } ++ ++ return rc; ++} ++#endif /* NOEPG */ ++ + cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) + :SI::EIT(Data, false) + { +@@ -35,6 +62,14 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (!channel) + return; // only collect data for known channels + ++#ifdef USE_NOEPG ++ // only use epg from channels not blocked by noEPG-patch ++ tChannelID kanalID; ++ kanalID = channel->GetChannelID(); ++ if (!allowedEPG(kanalID)) ++ return; ++#endif /* NOEPG */ ++ + cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); + + bool Empty = true; +@@ -71,8 +106,74 @@ cEIT::cEIT(cSchedules *Schedules, int So + // If the existing event has a zero table ID it was defined externally and shall + // not be overwritten. + if (pEvent->TableID() == 0x00) { ++#ifdef USE_DDEPGENTRY ++ if (pEvent->Version() == getVersionNumber()) { ++ if (Setup.MixEpgAction == 0) ++ continue; ++ //printf("in"); ++ //printf("%s", pEvent->GetTimeString()); ++ // to use the info of the original epg, update the extern one, ++ // if it has less info ++ SI::Descriptor *d; ++ SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; ++ //SI::ExtendedEventDescriptor *eed = NULL; ++ SI::ShortEventDescriptor *ShortEventDescriptor = NULL; ++ //SI::ShortEventDescriptor *sed = NULL; ++ //SI::TimeShiftedEventDescriptor *tsed = NULL; ++ //cLinkChannels *LinkChannels = NULL; ++ for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2));) { ++ if (d->getDescriptorTag() == SI::ShortEventDescriptorTag) { ++ int LanguagePreferenceShort = -1; ++ SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { ++ delete ShortEventDescriptor; ++ ShortEventDescriptor = sed; ++ d = NULL; // so that it is not deleted ++ } ++ } ++ else if (d->getDescriptorTag() == SI::ExtendedEventDescriptorTag) { ++ int LanguagePreferenceExt = -1; ++ bool UseExtendedEventDescriptor = false; ++ SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { ++ delete ExtendedEventDescriptors; ++ ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; ++ UseExtendedEventDescriptor = true; ++ } ++ if (UseExtendedEventDescriptor) { ++ ExtendedEventDescriptors->Add(eed); ++ d = NULL; // so that it is not deleted ++ } ++ if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) ++ UseExtendedEventDescriptor = false; ++ } ++ delete d; ++ } ++ if (pEvent) { ++ if (ShortEventDescriptor) { ++ char buffer[256]; ++ if (ShortEventDescriptor->text.getText(buffer, sizeof(buffer)) && pEvent->ShortText() && (strlen(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))) > strlen(pEvent->ShortText()))) { ++ pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))); ++ pEvent->FixEpgBugs(); ++ } ++ } ++ if (ExtendedEventDescriptors) { ++ char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ") + 1]; ++ //pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); ++ if (ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ") && pEvent->Description() && (strlen(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")) > strlen(pEvent->Description()))) { ++ pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); ++ pEvent->FixEpgBugs(); ++ } ++ } ++ } ++ delete ExtendedEventDescriptors; ++ delete ShortEventDescriptor; ++ continue; ++ } ++#else + if (pEvent->Version() == getVersionNumber()) + continue; ++#endif /* DDEPGENTRY */ + HasExternalData = ExternalData = true; + } + // If the new event has a higher table ID, let's skip it. +@@ -97,7 +198,11 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (newEvent) + pSchedule->AddEvent(newEvent); + if (Tid == 0x4E) { // we trust only the present/following info on the actual TS ++#ifdef USE_DDEPGENTRY ++ if (Setup.DisableVPS == 0 && SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) ++#else + if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) ++#endif /* DDEPGENTRY */ + pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel); + } + if (OnlyRunningStatus) +@@ -143,8 +248,46 @@ cEIT::cEIT(cSchedules *Schedules, int So + } + break; + case SI::ContentDescriptorTag: ++#ifdef USE_PARENTALRATING ++ { ++ int NumContents = 0; ++ uchar Contents[MAXEVCONTENTS + 1] = { 0 }; ++ SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d; ++ SI::ContentDescriptor::Nibble Nibble; ++ for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) { ++ if (NumContents < MAXEVCONTENTS) { ++ Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); ++ NumContents++; ++ } ++ } ++ pEvent->SetContents(Contents); ++ } ++#endif /* PARENTALRATING */ + break; + case SI::ParentalRatingDescriptorTag: ++#ifdef USE_PARENTALRATING ++ { ++ int LanguagePreferenceRating = -1; ++ SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d; ++ SI::ParentalRatingDescriptor::Rating Rating; ++ for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) { ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) { ++ int rate = (Rating.getRating() & 0xFF); ++ switch (rate) { ++ case 0x01 ... 0x0F: // minimum age = rating + 3 years ++ rate += 3; ++ break; ++ case 0: // undefined ++ case 0x10 ... 0xFF: // defined by the broadcaster ++ default: ++ rate = 0; ++ break; ++ } ++ pEvent->SetParentalRating(rate); ++ } ++ } ++ } ++#endif /* PARENTALRATING */ + break; + case SI::PDCDescriptorTag: { + SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d; +@@ -259,6 +402,62 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (LinkChannels) + channel->SetLinkChannels(LinkChannels); + Modified = true; ++#ifdef USE_DDEPGENTRY ++ //to avoid double epg-entrys from ext and int epg sources :EW ++ if (pEvent && pEvent->TableID() != 0x00) { ++ cEvent *pPreviousEvent = (cEvent *)pSchedule->GetPreviousEvent(pEvent); ++ if (pPreviousEvent) { ++ if (Setup.DoubleEpgAction == 0) { ++ pPreviousEvent->SetStartTime(pEvent->StartTime()); ++ pPreviousEvent->SetDuration(pEvent->Duration()); ++ if (Setup.DisableVPS == 0) { ++ if (channel) ++ pPreviousEvent->SetRunningStatus(pEvent->RunningStatus(), channel); ++ else ++ pPreviousEvent->SetRunningStatus(pEvent->RunningStatus()); ++ } ++ // to use the info of the original epg, update the extern one, ++ // if it has less info ++ char buffer_short_intern[256]; ++ char buffer_short_extern[256]; ++ int len_short_intern = 0; ++ int len_short_extern = 0; ++ if (pEvent->ShortText()) ++ len_short_intern = snprintf (buffer_short_intern, sizeof(buffer_short_intern)-1, "%s", pEvent->ShortText()); ++ if (pPreviousEvent->ShortText()) ++ len_short_extern = snprintf (buffer_short_extern, sizeof(buffer_short_extern)-1, "%s", pPreviousEvent->ShortText()); ++ if (len_short_intern > 0) { ++ if (len_short_extern < 1) ++ pPreviousEvent->SetShortText(buffer_short_intern); ++ else if (len_short_intern > len_short_extern) ++ pPreviousEvent->SetShortText(buffer_short_intern); ++ } ++ if (pEvent->Description()) { ++ char buffer_title_intern[4096]; ++ char buffer_title_extern[4096]; ++ int len_title_intern = 0; ++ int len_title_extern = 0; ++ if (pEvent->Description()) ++ len_title_intern = snprintf (buffer_title_intern, sizeof(buffer_title_intern)-1, "%s", pEvent->Description()); ++ if (pPreviousEvent->Description()) ++ len_title_extern = snprintf (buffer_title_extern, sizeof(buffer_title_extern)-1, "%s", pPreviousEvent->Description()); ++ if (len_title_intern > 0) { ++ if (len_title_extern < 1) ++ pPreviousEvent->SetDescription(buffer_title_intern); ++ else if (len_title_intern > len_title_extern) ++ pPreviousEvent->SetDescription(buffer_title_intern); ++ } ++ } ++ if (pPreviousEvent->Vps() == 0 && pEvent->Vps() != 0) ++ pPreviousEvent->SetVps(pEvent->Vps()); ++ pSchedule->DelEvent(pEvent); ++ pPreviousEvent->FixEpgBugs(); ++ } ++ else ++ pSchedule->DelEvent(pPreviousEvent); ++ } ++ } ++#endif /* DDEPGENTRY */ + } + if (Empty && Tid == 0x4E && getSectionNumber() == 0) + // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running +@@ -296,10 +495,26 @@ cTDT::cTDT(const u_char *Data) + time_t sattim = getTime(); + time_t loctim = time(NULL); + ++#ifdef USE_SETTIME ++ char timestr[20]; ++ struct tm *ptm; ++ struct tm tm_r; ++ ptm = localtime_r(&sattim, &tm_r); ++#endif /* SETTIME */ ++ + int diff = abs(sattim - loctim); + if (diff > 2) { + mutex.Lock(); + if (abs(diff - lastDiff) < 3) { ++#ifdef USE_SETTIME ++ if (SetTime) { ++ strftime(timestr, 20, "%m%d%H%M%Y.%S", ptm); ++ cString cmd = cString::sprintf("%s %s %ld", SetTime, timestr, sattim); ++ dsyslog("Executing: %s", *cmd); ++ SystemExec(cmd); ++ } ++ else ++#endif /* SETTIME */ + if (stime(&sattim) == 0) + isyslog("system time changed from %s (%ld) to %s (%ld)", *TimeToString(loctim), loctim, *TimeToString(sattim), sattim); + else +diff -ruNp vdr-1.7.0/eitscan.c vdr-1.7.0-extensions/eitscan.c +--- vdr-1.7.0/eitscan.c 2006-01-07 15:10:17.000000000 +0100 ++++ vdr-1.7.0-extensions/eitscan.c 2009-04-09 20:48:48.000000000 +0200 +@@ -151,9 +151,17 @@ void cEITScanner::Process(void) + if (Device->ProvidesTransponder(Channel)) { + if (!Device->Receiving()) { + bool MaySwitchTransponder = Device->MaySwitchTransponder(); ++#ifdef USE_LNBSHARE ++ if (MaySwitchTransponder && Device->GetMaxBadPriority(Channel) == -2 || Device->ProvidesTransponderExclusively(Channel) && Device->GetMaxBadPriority(Channel) <= -1 && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#else + if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#endif /* LNBSHARE */ + if (!MaySwitchTransponder) { ++#ifdef USE_LNBSHARE ++ if ((Device == cDevice::ActualDevice() || Device->GetMaxBadPriority(Channel) == -1) && !currentChannel) { ++#else + if (Device == cDevice::ActualDevice() && !currentChannel) { ++#endif /* LNBSHARE */ + cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode + currentChannel = Device->CurrentChannel(); + Skins.Message(mtInfo, tr("Starting EPG scan")); +diff -ruNp vdr-1.7.0/epg.c vdr-1.7.0-extensions/epg.c +--- vdr-1.7.0/epg.c 2008-02-16 17:09:12.000000000 +0100 ++++ vdr-1.7.0-extensions/epg.c 2009-04-09 20:48:48.000000000 +0200 +@@ -112,6 +112,11 @@ cEvent::cEvent(tEventID EventID) + components = NULL; + startTime = 0; + duration = 0; ++#ifdef USE_PARENTALRATING ++ for (int i = 0; i < MAXEVCONTENTS; i++) ++ contents[i] = 0; ++ parentalRating = 0; ++#endif /* PARENTALRATING */ + vps = 0; + SetSeen(); + } +@@ -200,6 +205,19 @@ void cEvent::SetDuration(int Duration) + duration = Duration; + } + ++#ifdef USE_PARENTALRATING ++void cEvent::SetContents(uchar *Contents) ++{ ++ for (int i = 0; i < MAXEVCONTENTS; i++) ++ contents[i] = Contents[i]; ++} ++ ++void cEvent::SetParentalRating(uchar ParentalRating) ++{ ++ parentalRating = ParentalRating; ++} ++#endif /* PARENTALRATING */ ++ + void cEvent::SetVps(time_t Vps) + { + vps = Vps; +@@ -255,6 +273,340 @@ cString cEvent::GetVpsString(void) const + return buf; + } + ++#ifdef USE_PARENTALRATING ++cString cEvent::GetContentsString(int i) const ++{ ++ cString str(""); ++ switch (contents[i] & 0xF0) { ++ case EVCONTENTMASK_MOVIEDRAMA: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Movie/Drama")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Detective/Thriller")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Adventure/Western/War")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Science Fiction/Fantasy/Horror")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Comedy")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Soap/Melodrama/Folkloric")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Romance")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Serious/Classical/Religious/Historical Movie/Drama")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Adult Movie/Drama")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_NEWSCURRENTAFFAIRS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$News/Current Affairs")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$News/Weather Report")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$News Magazine")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Documentary")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Discussion/Inverview/Debate")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SHOW: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Show/Game Show")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Game Show/Quiz/Contest")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Variety Show")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Talk Show")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SPORTS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Sports")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Special Event")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Sport Magazine")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Football")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Tennis/Squash")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Team Sports")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Athletics")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Motor Sport")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Water Sport")); ++ break; ++ case 0x09: ++ str = cString(tr("Content$Winter Sports")); ++ break; ++ case 0x0A: ++ str = cString(tr("Content$Equestrian")); ++ break; ++ case 0x0B: ++ str = cString(tr("Content$Martial Sports")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_CHILDRENYOUTH: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Children's/Youth Programmes")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Pre-school Children's Programmes")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Entertainment Programmes for 6 to 14")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Entertainment Programmes for 10 to 16")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Informational/Educational/School Programme")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Cartoons/Puppets")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_MUSICBALLETDANCE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Music/Ballet/Dance")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Rock/Pop")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Serious/Classical Music")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Folk/Tradional Music")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Jazz")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Musical/Opera")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Ballet")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_ARTSCULTURE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Arts/Culture")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Performing Arts")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Fine Arts")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Religion")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Popular Culture/Traditional Arts")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Literature")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Film/Cinema")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Experimental Film/Video")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Broadcasting/Press")); ++ break; ++ case 0x09: ++ str = cString(tr("Content$New Media")); ++ break; ++ case 0x0A: ++ str = cString(tr("Content$Arts/Culture Magazines")); ++ break; ++ case 0x0B: ++ str = cString(tr("Content$Fashion")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SOCIALPOLITICALECONOMICS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Social/Political/Economics")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Magazines/Reports/Documentary")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Economics/Social Advisory")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Remarkable People")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_EDUCATIONALSCIENCE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Education/Science/Factual")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Nature/Animals/Environment")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Technology/Natural Sciences")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Medicine/Physiology/Psychology")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Foreign Countries/Expeditions")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Social/Spiritual Sciences")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Further Education")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Languages")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_LEISUREHOBBIES: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Leisure/Hobbies")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Tourism/Travel")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Handicraft")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Motoring")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Fitness & Health")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Cooking")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Advertisement/Shopping")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Gardening")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SPECIAL: ++ switch (contents[i] & 0x0F) { ++ case 0x00: ++ str = cString(tr("Content$Original Language")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Black & White")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Unpublished")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Live Broadcast")); ++ break; ++ default: ++ str = cString(tr("Content$Special Characteristics")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_USERDEFINED: ++ switch (contents[i] & 0x0F) { ++ case 0x00: ++ str = cString(tr("Content$Drama")); // UK Freeview ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ return str; ++} ++ ++cString cEvent::GetParentalRatingString(void) const ++{ ++ if (parentalRating > 0) ++ return cString::sprintf(tr("Suitable for those aged %d and over"), parentalRating); ++ return NULL; ++} ++#endif /* PARENTALRATING */ ++ + void cEvent::Dump(FILE *f, const char *Prefix, bool InfoOnly) const + { + if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) { +@@ -742,6 +1094,28 @@ const cEvent *cSchedule::GetEventAround( + return pe; + } + ++#ifdef USE_DDEPGENTRY ++const cEvent *cSchedule::GetPreviousEvent(cEvent *Event) const ++{ ++ if (!Event || Event->Duration() == 0 || Event->StartTime() == 0) ++ return NULL; ++ // Returns either the event info to the previous/following event to the given EventID or, if that one can't be found NULL :EW ++ cEvent *pt = NULL; ++ int epgTimeDelta = Setup.DoubleEpgTimeDelta * 60 + 1; ++ for (pt = events.First(); pt; pt = events.Next(pt)) ++ if (pt && pt->TableID() == 0x00) ++ if ((Event->StartTime() - pt->StartTime()) > - epgTimeDelta && (Event->StartTime() - pt->StartTime()) < epgTimeDelta) { ++ if ((pt->Duration() + (pt->Duration()/ 5) + 1) > Event->Duration() && (pt->Duration() - (pt->Duration()/ 5) - 1) < Event->Duration()) ++ return pt; ++ else if (pt->Title() && Event->Title() && (strcmp(pt->Title(), ".") != 0 && strcmp(Event->Title(), ".") != 0)) { ++ if (strstr(pt->Title(), Event->Title()) != NULL || strstr(Event->Title(), pt->Title()) != NULL) ++ return pt; ++ } ++ } ++ return NULL; ++} ++#endif /* DDEPGENTRY */ ++ + void cSchedule::SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel) + { + hasRunning = false; +diff -ruNp vdr-1.7.0/epg.h vdr-1.7.0-extensions/epg.h +--- vdr-1.7.0/epg.h 2006-10-07 15:47:19.000000000 +0200 ++++ vdr-1.7.0-extensions/epg.h 2009-04-09 20:48:48.000000000 +0200 +@@ -50,6 +50,22 @@ class cSchedule; + + typedef u_int32_t tEventID; + ++#ifdef USE_PARENTALRATING ++#define MAXEVCONTENTS 4 ++#define EVCONTENTMASK_MOVIEDRAMA 0x10 ++#define EVCONTENTMASK_NEWSCURRENTAFFAIRS 0x20 ++#define EVCONTENTMASK_SHOW 0x30 ++#define EVCONTENTMASK_SPORTS 0x40 ++#define EVCONTENTMASK_CHILDRENYOUTH 0x50 ++#define EVCONTENTMASK_MUSICBALLETDANCE 0x60 ++#define EVCONTENTMASK_ARTSCULTURE 0x70 ++#define EVCONTENTMASK_SOCIALPOLITICALECONOMICS 0x80 ++#define EVCONTENTMASK_EDUCATIONALSCIENCE 0x90 ++#define EVCONTENTMASK_LEISUREHOBBIES 0xA0 ++#define EVCONTENTMASK_SPECIAL 0xB0 ++#define EVCONTENTMASK_USERDEFINED 0xF0 ++#endif /* PARENTALRATING */ ++ + class cEvent : public cListObject { + friend class cSchedule; + private: +@@ -64,6 +80,10 @@ private: + cComponents *components; // The stream components of this event + time_t startTime; // Start time of this event + int duration; // Duration of this event in seconds ++#ifdef USE_PARENTALRATING ++ uchar contents[MAXEVCONTENTS + 1]; // Contents of this event; list is zero-terminated ++ uchar parentalRating; // Parental rating of this event ++#endif /* PARENTALRATING */ + time_t vps; // Video Programming Service timestamp (VPS, aka "Programme Identification Label", PIL) + time_t seen; // When this event was last seen in the data stream + public: +@@ -83,6 +103,10 @@ public: + time_t StartTime(void) const { return startTime; } + time_t EndTime(void) const { return startTime + duration; } + int Duration(void) const { return duration; } ++#ifdef USE_PARENTALRATING ++ uchar Contents(int i = 0) const { return (0 <= i && i < MAXEVCONTENTS) ? contents[i] : 0; } ++ uchar ParentalRating(void) const { return parentalRating; } ++#endif /* PARENTALRATING */ + time_t Vps(void) const { return vps; } + time_t Seen(void) const { return seen; } + bool SeenWithin(int Seconds) const { return time(NULL) - seen < Seconds; } +@@ -92,6 +116,10 @@ public: + cString GetTimeString(void) const; + cString GetEndTimeString(void) const; + cString GetVpsString(void) const; ++#ifdef USE_PARENTALRATING ++ cString GetContentsString(int i = 0) const; ++ cString GetParentalRatingString(void) const; ++#endif /* PARENTALRATING */ + void SetEventID(tEventID EventID); + void SetTableID(uchar TableID); + void SetVersion(uchar Version); +@@ -102,6 +130,10 @@ public: + void SetComponents(cComponents *Components); // Will take ownership of Components! + void SetStartTime(time_t StartTime); + void SetDuration(int Duration); ++#ifdef USE_PARENTALRATING ++ void SetContents(uchar *Contents); ++ void SetParentalRating(uchar ParentalRating); ++#endif /* PARENTALRATING */ + void SetVps(time_t Vps); + void SetSeen(void); + cString ToDescr(void) const; +@@ -137,6 +169,9 @@ public: + void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); + void Cleanup(time_t Time); + void Cleanup(void); ++#ifdef USE_DDEPGENTRY ++ const cEvent *GetPreviousEvent(cEvent *Event) const; //:EW ++#endif /* DDEPGENTRY */ + cEvent *AddEvent(cEvent *Event); + void DelEvent(cEvent *Event); + void HashEvent(cEvent *Event); +diff -ruNp vdr-1.7.0/HISTORY-liemikuutio vdr-1.7.0-extensions/HISTORY-liemikuutio +--- vdr-1.7.0/HISTORY-liemikuutio 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/HISTORY-liemikuutio 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,108 @@ ++----------------------------------- ++Liemikuutio for Video Disc Recorder ++ ++Maintainer: Rolf Ahrenberg ++----------------------------------- ++ ++2006-01-08: Version 1.0 ++ ++- Based on enAIO with these original patches: ++ Simple recordings sorting by Walter@VDRPortal ++ Alternate rename recordings by Ralf Müller ++ Menu selection by Peter Dittmann ++ Recording length by Tobias Faust ++ ++2006-01-15: Version 1.1 ++ ++- Removed patches already found in vdr-1.3.39. ++ ++2006-01-25: Version 1.2 ++ ++- Added "Main menu command position" feature. ++ ++2006-02-05: Version 1.3 ++ ++- Improved menu selection response. ++ ++2006-04-18: Version 1.4 ++ ++- Added Estonian translation (Thanks to Arthur Konovalov). ++ ++2006-04-30: Version 1.5 ++ ++- Added progress bar view into "What's on now?" menu. ++ ++2006-06-06: Version 1.6 ++ ++- Added French translation (Thanks to ECLiPSE). ++ ++2006-06-14: Version 1.7 ++ ++- Fixed RENR crash. ++ ++2006-07-14: Version 1.8 ++ ++- Fixed RENR/OSD bug. ++ ++2006-08-27: Version 1.9 ++ ++- Some modifications to the recording length and rename recordings ++ patches (Thanks to Firefly). ++- Added k1_k3_jumps_20s patch by Petri Hintukainen. ++ ++2006-08-29: Version 1.10 ++ ++- The cRecording:Title() method now defaults to original formatting. ++ ++2006-09-04: Version 1.11 ++ ++- Removed unused variable from cRecording::Title() method (Thanks to ++ C.Y.M.). ++- Some modifications to the rename recordings patch (Thanks to Firefly). ++ ++2006-09-13: Version 1.12 ++ ++- More modifications to the rename recordings patch (Thanks to Firefly). ++ ++2006-10-01: Version 1.13 ++ ++- Removed unnecessary syslog printing (Thanks to Firefly). ++ ++2007-08-14: Version 1.14 ++ ++- Updated for vdr-1.5.7. ++ ++2007-10-16: Version 1.15 ++ ++- Added recmenu play patch (Thanks to Ville Skyttä). ++- Updated French translation (Thanks to ECLiPSE). ++ ++2007-11-04: Version 1.16 ++ ++- Updated for vdr-1.5.11. ++ ++2007-12-08: Version 1.17 ++ ++- Added binary skip patch. ++- Removed k1_k3_jumps_20s patch. ++ ++2008-02-17: Version 1.18 ++ ++- Updated for vdr-1.5.15. ++ ++2008-03-02: Version 1.19 ++ ++- Modified binary skip to use kPrev and kNext keys and the skip is now ++ always shortened after a direction change (Thanks to Timo Eskola). ++- Readded k1_k3_jumps_20s patch. ++ ++2008-04-04: Version 1.20 ++ ++- Added bitrate information into rename menu. ++- Readded the path editing support of rename recordings patch (Thanks ++ to Firefly). ++ ++2008-05-08: Version 1.21 ++ ++- Fixed rename recordings (Thanks to Firefly). ++- Added a DVB subtitles hack for old recordings (Thanks to Anssi Hannula). +diff -ruNp vdr-1.7.0/iconpatch.c vdr-1.7.0-extensions/iconpatch.c +--- vdr-1.7.0/iconpatch.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/iconpatch.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,31 @@ ++#ifdef USE_WAREAGLEICON ++ ++#include "iconpatch.h" ++ ++#include <langinfo.h> ++#include <locale.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++bool IsLangUtf8(void) ++{ ++ char *CodeSet = NULL; ++ if (setlocale(LC_CTYPE, "")) ++ CodeSet = nl_langinfo(CODESET); ++ else { ++ char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed ++ if (LangEnv) { ++ CodeSet = strchr(LangEnv, '.'); ++ if (CodeSet) ++ CodeSet++; // skip the dot ++ } ++ } ++ ++ if (CodeSet && strcasestr(CodeSet, "UTF-8") != 0) ++ return true; ++ ++ return false; ++} ++ ++#endif /* WAREAGLEICON */ +diff -ruNp vdr-1.7.0/iconpatch.h vdr-1.7.0-extensions/iconpatch.h +--- vdr-1.7.0/iconpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/iconpatch.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,73 @@ ++#ifdef USE_WAREAGLEICON ++/* ++ * iconpatch.h: Information of iconpatch ++ * ++ * Diese Datei ist die Übersichtsdatei für den Iconpatch. ++ * Hier werden kleine Infos abgelegt. ++ * Der Iconpatch ändert die Dateien: ++ * iconpatch.h ++ * menu.c ++ * recording.c ++ * fontosd.c ++ * ++ */ ++ ++// Iconpatch-Variablen - Anfang ++#define ICON_NUMBERSIGN "\x23" ++#define ICON_ASTERISK "\x2A" ++#define ICON_GREATER "\x3E" ++#define ICON_EXCLAM "\x21" ++#define ICON_PLUSMINUS "\xB1" ++ ++#define ICON_RESUME "\x80" ++#define ICON_DVD "\x81" ++#define ICON_FOLDER "\x82" ++#define ICON_BLANK "\x83" ++#define ICON_CUTTING "\x84" ++#define ICON_MOVE_FILE "\x85" ++#define ICON_MOVE_FOLDER "\x86" ++#define ICON_BAR_START "\x87" ++#define ICON_BAR_FILLED "\x88" ++#define ICON_BAR_CLEAR "\x89" ++#define ICON_BAR_END "\x8A" ++#define ICON_REC "\x8B" ++#define ICON_CLOCK "\x8C" ++#define ICON_TV_CRYPTED "\x8D" ++#define ICON_RADIO "\x8E" ++#define ICON_TV "\x8F" ++#define ICON_NEW "\x90" ++#define ICON_ARROW "\x91" ++#define ICON_RUNNING "\x92" ++#define ICON_VPS "\x93" ++#define ICON_CLOCK_UH "\x94" ++#define ICON_CLOCK_LH "\x95" ++ ++// UTF-8 Icons ++#define ICON_RESUME_UTF8 "\uE000" ++#define ICON_DVD_UTF8 "\uE001" ++#define ICON_FOLDER_UTF8 "\uE002" ++#define ICON_BLANK_UTF8 "\uE003" ++#define ICON_CUTTING_UTF8 "\uE004" ++#define ICON_MOVE_FILE_UTF8 "\uE005" ++#define ICON_MOVE_FOLDER_UTF8 "\uE006" ++#define ICON_BAR_START_UTF8 "\uE007" ++#define ICON_BAR_FILLED_UTF8 "\uE008" ++#define ICON_BAR_EMPTY_UTF8 "\uE009" ++#define ICON_BAR_CLOSE_UTF8 "\uE00A" ++#define ICON_REC_UTF8 "\uE00B" ++#define ICON_CLOCK_UTF8 "\uE00C" ++#define ICON_TV_CRYPTED_UTF8 "\uE00D" ++#define ICON_RADIO_UTF8 "\uE00E" ++#define ICON_TV_UTF8 "\uE00F" ++#define ICON_NEW_UTF8 "\uE010" ++#define ICON_ARROW_UTF8 "\uE011" ++#define ICON_RUNNING_UTF8 "\uE012" ++#define ICON_VPS_UTF8 "\uE013" ++#define ICON_CLOCK_UH_UTF8 "\uE014" ++#define ICON_CLOCK_LH_UTF8 "\uE015" ++ ++// Iconpatch-Variablen - Ende ++ ++bool IsLangUtf8(void); ++ ++#endif /* WAREAGLEICON */ +diff -ruNp vdr-1.7.0/keys.h vdr-1.7.0-extensions/keys.h +--- vdr-1.7.0/keys.h 2007-08-26 14:34:50.000000000 +0200 ++++ vdr-1.7.0-extensions/keys.h 2009-04-09 20:48:48.000000000 +0200 +@@ -71,6 +71,10 @@ enum eKeys { // "Up" and "Down" must be + #define kEditCut k2 + #define kEditTest k8 + ++#ifdef USE_DVDARCHIVE ++#define kDvdChapterJumpForward k6 ++#define kDvdChapterJumpBack k4 ++#endif /* DVDARCHIVE */ + #define RAWKEY(k) (eKeys((k) & ~k_Flags)) + #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) + #define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) +diff -ruNp vdr-1.7.0/lirc.c vdr-1.7.0-extensions/lirc.c +--- vdr-1.7.0/lirc.c 2006-05-28 10:48:13.000000000 +0200 ++++ vdr-1.7.0-extensions/lirc.c 2009-04-09 20:48:48.000000000 +0200 +@@ -12,6 +12,9 @@ + #include "lirc.h" + #include <netinet/in.h> + #include <sys/socket.h> ++#ifdef USE_LIRCSETTINGS ++#include "config.h" ++#endif /* LIRCSETTINGS */ + + #define REPEATDELAY 350 // ms + #define REPEATFREQ 100 // ms +@@ -94,7 +97,11 @@ void cLircRemote::Action(void) + continue; + } + if (count == 0) { ++#ifdef USE_LIRCSETTINGS ++ if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast + if (repeat) + Put(LastKeyName, false, true); +@@ -104,18 +111,34 @@ void cLircRemote::Action(void) + timeout = -1; + } + else { ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() < (unsigned int)Setup.LircRepeatFreq) ++#else + if (LastTime.Elapsed() < REPEATFREQ) ++#endif /* LIRCSETTINGS */ + continue; // repeat function kicks in after a short delay (after last key instead of first key) ++#ifdef USE_LIRCSETTINGS ++ if (FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast (for count != 0 as well) + repeat = true; ++#ifdef USE_LIRCSETTINGS ++ timeout = Setup.LircRepeatDelay; ++#else + timeout = REPEATDELAY; ++#endif /* LIRCSETTINGS */ + } + LastTime.Set(); + Put(KeyName, repeat); + } + else if (repeat) { // the last one was a repeat, so let's generate a release ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() >= (unsigned int)Setup.LircRepeatTimeout) { ++#else + if (LastTime.Elapsed() >= REPEATTIMEOUT) { ++#endif /* LIRCSETTINGS */ + Put(LastKeyName, false, true); + repeat = false; + *LastKeyName = 0; +diff -ruNp vdr-1.7.0/livebuffer.c vdr-1.7.0-extensions/livebuffer.c +--- vdr-1.7.0/livebuffer.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/livebuffer.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,1912 @@ ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#include "menu.h" ++#include "recording.h" ++#include "transfer.h" ++ ++#define RECORDERBUFSIZE MEGABYTE(2) ++ ++// --- cFileName ------------------------------------------------------------- ++ ++#include <errno.h> ++#include <unistd.h> ++#include "videodir.h" ++ ++#define MAXFILESPERRECORDING 255 ++#define RECORDFILESUFFIX "/%03d.vdr" ++#define RECORDFILESUFFIXLEN 20 ++ ++cFileName64::cFileName64(const char *FileName, bool Record, bool Blocking) ++{ ++ file = NULL; ++ record = Record; ++ blocking = Blocking; ++ // Prepare the file name: ++ fileName = MALLOC(char, strlen(FileName) + RECORDFILESUFFIXLEN); ++ if (!fileName) { ++ esyslog("ERROR: can't copy file name '%s'", fileName); ++ return; ++ } ++ strcpy(fileName, FileName); ++ pFileNumber = fileName + strlen(fileName); ++ ++ fileNumber = 1; ++ while (true) { ++ sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); ++ if (record) { ++ if (access(fileName, F_OK) == 0) { ++ struct stat64 buf; ++ if (stat64(fileName, &buf) == 0) { ++ fileNumber++; ++ continue; ++ } ++ } ++ else if (errno != ENOENT) ++ LOG_ERROR_STR(fileName); ++ } ++ break; ++ } ++} ++ ++cFileName64::~cFileName64() ++{ ++ Close(); ++ free(fileName); ++} ++ ++void cFileName64::SetNumber(int Number) ++{ ++ fileNumber = Number; ++ sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); ++} ++ ++cUnbufferedFile64 *cFileName64::Open(void) ++{ ++ if (!file) { ++ int BlockingFlag = blocking ? 0 : O_NONBLOCK; ++ if (record) { ++ file = cUnbufferedFile64::Create(fileName, O_RDWR | O_CREAT | BlockingFlag); ++ if (!file) ++ LOG_ERROR_STR(fileName); ++ } ++ else { ++ if (access(fileName, R_OK) == 0) { ++ file = cUnbufferedFile64::Create(fileName, O_RDONLY | BlockingFlag); ++ if (!file) ++ LOG_ERROR_STR(fileName); ++ } ++ else if (errno != ENOENT) ++ LOG_ERROR_STR(fileName); ++ } ++ } ++ return file; ++} ++ ++void cFileName64::Close(void) ++{ ++ if (file) { ++ if (file->Close() < 0) ++ LOG_ERROR_STR(fileName); ++ delete file; ++ file = NULL; ++ } ++} ++ ++void cFileName64::CloseAndRemove(void) ++{ ++ Close(); ++ remove(fileName); ++} ++ ++// --- cUnbufferedFile64 ----------------------------------------------------- ++ ++#define USE_FADVISE ++ ++#define WRITE_BUFFER KILOBYTE(800) ++ ++cUnbufferedFile64::cUnbufferedFile64(void) ++{ ++ fd = -1; ++} ++ ++cUnbufferedFile64::~cUnbufferedFile64() ++{ ++ Close(); ++} ++ ++int cUnbufferedFile64::Open(const char *FileName, int Flags, mode_t Mode) ++{ ++ Close(); ++ fd = open64(FileName, Flags, Mode); ++ curpos = 0; ++#ifdef USE_FADVISE ++ begin = lastpos = ahead = 0; ++ cachedstart = 0; ++ cachedend = 0; ++ readahead = KILOBYTE(128); ++ written = 0; ++ totwritten = 0; ++ if (fd >= 0) ++ posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); ++#endif ++ return fd; ++} ++ ++int cUnbufferedFile64::Close(void) ++{ ++#ifdef USE_FADVISE ++ if (fd >= 0) { ++ if (totwritten) ++ fdatasync(fd); ++ posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); ++ } ++#endif ++ int OldFd = fd; ++ fd = -1; ++ return close(OldFd); ++} ++ ++ ++#define FADVGRAN KILOBYTE(4) ++#define READCHUNK MEGABYTE(8) ++ ++int cUnbufferedFile64::FadviseDrop(off64_t Offset, off64_t Len) ++{ ++ return posix_fadvise64(fd, Offset - (FADVGRAN - 1), Len + (FADVGRAN - 1) * 2, POSIX_FADV_DONTNEED); ++} ++ ++ ++off64_t cUnbufferedFile64::Seek(off64_t Offset, int Whence) ++{ ++ if (Whence == SEEK_SET && Offset == curpos) ++ return curpos; ++ curpos = lseek64(fd, Offset, Whence); ++ return curpos; ++} ++ ++ssize_t cUnbufferedFile64::Read(void *Data, size_t Size) ++{ ++ if (fd >= 0) { ++#ifdef USE_FADVISE ++ off64_t jumped = curpos-lastpos; ++ if ((cachedstart < cachedend) && (curpos < cachedstart || curpos > cachedend)) { ++ FadviseDrop(cachedstart, cachedend-cachedstart); ++ cachedstart = curpos; ++ cachedend = curpos; ++ } ++ cachedstart = min(cachedstart, curpos); ++#endif ++ ssize_t bytesRead = safe_read(fd, Data, Size); ++#ifdef USE_FADVISE ++ if (bytesRead > 0) { ++ curpos += bytesRead; ++ cachedend = max(cachedend, curpos); ++ ++ if (jumped >= 0 && jumped <= (off64_t)readahead) { ++ if (ahead - curpos < (off64_t)(readahead / 2)) { ++ posix_fadvise64(fd, curpos, readahead, POSIX_FADV_WILLNEED); ++ ahead = curpos + readahead; ++ cachedend = max(cachedend, ahead); ++ } ++ if (readahead < Size * 32) { ++ readahead = Size * 32; ++ } ++ } ++ else ++ ahead = curpos; ++ } ++ ++ if (cachedstart < cachedend) { ++ if (curpos - cachedstart > READCHUNK * 2) { ++ FadviseDrop(cachedstart, curpos - READCHUNK - cachedstart); ++ cachedstart = curpos - READCHUNK; ++ } ++ else if (cachedend > ahead && cachedend - curpos > READCHUNK * 2) { ++ FadviseDrop(curpos + READCHUNK, cachedend - (curpos + READCHUNK)); ++ cachedend = curpos + READCHUNK; ++ } ++ } ++ lastpos = curpos; ++#endif ++ return bytesRead; ++ } ++ return -1; ++} ++ ++ssize_t cUnbufferedFile64::Write(const void *Data, size_t Size) ++{ ++ if (fd >=0) { ++ ssize_t bytesWritten = safe_write(fd, Data, Size); ++#ifdef USE_FADVISE ++ if (bytesWritten > 0) { ++ begin = min(begin, curpos); ++ curpos += bytesWritten; ++ written += bytesWritten; ++ lastpos = max(lastpos, curpos); ++ if (written > WRITE_BUFFER) { ++ if (lastpos > begin) { ++ off64_t headdrop = min(begin, (off64_t) WRITE_BUFFER * 2L); ++ posix_fadvise64(fd, begin - headdrop, lastpos - begin + headdrop, POSIX_FADV_DONTNEED); ++ } ++ begin = lastpos = curpos; ++ totwritten += written; ++ written = 0; ++ if (totwritten > MEGABYTE(32)) { ++ off64_t headdrop = min((off64_t) (curpos - totwritten), (off64_t) totwritten * 2L); ++ posix_fadvise64(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED); ++ totwritten = 0; ++ } ++ } ++ } ++#endif ++ return bytesWritten; ++ } ++ return -1; ++} ++ ++cUnbufferedFile64 *cUnbufferedFile64::Create(const char *FileName, int Flags, mode_t Mode) ++{ ++ cUnbufferedFile64 *File = new cUnbufferedFile64; ++ if (File->Open(FileName, Flags, Mode) < 0) { ++ delete File; ++ File = NULL; ++ } ++ return File; ++} ++ ++// --- cLiveIndex ------------------------------------------------------------ ++ ++cLiveIndex::cLiveIndex(int BufSize) ++{ ++ bufSize = BufSize; ++ headblock = tailblock = new block; ++ headblock->previous = headblock->next = headblock; ++ head = tail = 0; ++ blank = 0; ++ blockCount = 1; ++ writtenCount = delCount = 0; ++ lastWrittenSize = lastCount = 0; ++ fileSize = 0; ++ lastFrame = -1; ++ DPos = -1; ++ DCount = 0; ++ start = 0; ++ RwLock = new cRwLock(true); ++} ++ ++cLiveIndex::~cLiveIndex() ++{ ++ while (tailblock != headblock) { ++ block *n = tailblock->next; ++ delete tailblock; ++ tailblock = n; ++ } ++ delete headblock; ++ delete RwLock; ++} ++ ++void cLiveIndex::Add(uchar pt, int pos) ++{ ++ RwLock->Lock(true); ++ DCount=0; ++ DPos = pos; ++ headblock->Frame[head].offset = pos; ++ headblock->Frame[head].written = false; ++ headblock->Frame[head].pt = pt; ++ head++; ++ lastFrame++; ++ if (head == INDEXBLOCKSIZE) { ++ block* b = new block; ++ b->previous = headblock; ++ b->next = b; ++ headblock->next = b; ++ headblock = b; ++ head = 0; ++ blockCount++; ++ } ++ RwLock->Unlock(); ++} ++ ++void cLiveIndex::AddData(int pos) ++{ ++ RwLock->Lock(true); ++ DCount=pos-DPos; ++ RwLock->Unlock(); ++} ++ ++void cLiveIndex::Delete(off64_t FilePos) ++{ ++ RwLock->Lock(true); ++ if (tailblock->Frame[tail].offset <= FilePos) { ++ if (tailblock->Frame[tail].offset + MAXFRAMESIZE >= FilePos) { ++ int old_offset = tailblock->Frame[tail].offset; ++ while (tailblock->Frame[tail].written && tailblock->Frame[tail].offset < FilePos && tailblock->Frame[tail].offset >= old_offset) { ++ tail++; ++ delCount++; ++ if (tail == INDEXBLOCKSIZE) { ++ block *b = tailblock->next; ++ b->previous = b; ++ if (tailblock != headblock) ++ delete tailblock; ++ tailblock = b; ++ tail = 0; ++ blockCount--; ++ } ++ } ++ } ++ } ++ else { ++ if (tailblock->Frame[tail].offset - MAXFRAMESIZE > FilePos) { ++ int old_offset = tailblock->Frame[tail].offset; ++ while (tailblock->Frame[tail].written && (tailblock->Frame[tail].offset < FilePos || tailblock->Frame[tail].offset >= old_offset)) { ++ tail++; ++ delCount++; ++ if (tail == INDEXBLOCKSIZE) { ++ block *b = tailblock->next; ++ b->previous = b; ++ if (tailblock != headblock) ++ delete tailblock; ++ tailblock = b; ++ tail = 0; ++ blockCount--; ++ } ++ } ++ } ++ } ++ RwLock->Unlock(); ++} ++ ++int cLiveIndex::DelFirst(void) ++{ ++ RwLock->Lock(true); ++ tail++; ++ delCount++; ++ writtenCount++; ++ if (tail == INDEXBLOCKSIZE) { ++ block *b = tailblock->next; ++ b->previous = b; ++ if (tailblock != headblock) ++ delete tailblock; ++ tailblock = b; ++ tail = 0; ++ blockCount--; ++ } ++ int r = tailblock->Frame[tail].offset; ++ RwLock->Unlock(); ++ return r; ++} ++ ++void cLiveIndex::Clear(void) ++{ ++ RwLock->Lock(true); ++ while (tailblock != headblock) { ++ block *n = tailblock->next; ++ delete tailblock; ++ tailblock = n; ++ } ++ headblock->previous = headblock; ++ head = tail = blank = 0; ++ blockCount = 1; ++ writtenCount = delCount = 0; ++ DPos = -1; ++ DCount = 0; ++ start = 0; ++ lastFrame = -1; ++ lastWrittenSize = lastCount = 0; ++ fileSize = 0; ++ RwLock->Unlock(); ++} ++ ++int cLiveIndex::NextWrite(void) ++{ ++ RwLock->Lock(false); ++ block *b; ++ int i = GetFrame(&b,writtenCount); ++ int off = 0; ++ if (i+1 == INDEXBLOCKSIZE) ++ off = b->next->Frame[0].offset; ++ else ++ off = b->Frame[i+1].offset; ++ int r = 0; ++ if (off < b->Frame[i].offset) ++ r = bufSize - b->Frame[i].offset - blank; ++ else ++ r = off - b->Frame[i].offset; ++ RwLock->Unlock(); ++ return r; ++} ++ ++void cLiveIndex::WrittenTo(off64_t FilePos, int Count) ++{ ++ RwLock->Lock(true); ++ lastWrittenSize=Count; ++ block *b; ++ int i = GetFrame(&b, writtenCount); ++ writtenCount++; ++ if (FilePos == 0) { ++ if (i) ++ fileSize = b->Frame[i-1].offset + lastCount; ++ else if (b->previous != b) ++ fileSize = b->previous->Frame[INDEXBLOCKSIZE-1].offset + lastCount; ++ } ++ b->Frame[i].offset = FilePos; ++ b->Frame[i].written = true; ++ RwLock->Unlock(); ++ lastCount = Count; ++} ++ ++int cLiveIndex::GetFrame(block** Block, int Number) ++{ ++ int bc = 0; ++ int i = Number-delCount; ++ if (INDEXBLOCKSIZE-tail <= i) ++ bc = 1 + (i-INDEXBLOCKSIZE+tail)/INDEXBLOCKSIZE; ++ i-= bc*INDEXBLOCKSIZE-tail; ++ block *b = tailblock; ++ for (int j=0; j<bc; j++) ++ b = b->next; ++ *Block = b; ++ return i; ++} ++ ++off64_t cLiveIndex::GetOffset(int Number) ++{ ++ RwLock->Lock(false); ++ off64_t r = -1; ++ if (HasFrame(Number)) { ++ block *b; ++ int i = GetFrame(&b, Number); ++ r = b->Frame[i].offset; ++ } ++ else if (HasFrame(Number-1)) ++ r = DPos; ++ RwLock->Unlock(); ++ return r; ++} ++ ++int cLiveIndex::Size(int Number, uchar *PictureType) ++{ ++ int r = -1; ++ RwLock->Lock(false); ++ if (HasFrame(Number)) { ++ if (Number+1 == writtenCount) ++ r = lastWrittenSize; ++ else { ++ block *b; ++ int i = GetFrame(&b, Number); ++ if (PictureType) ++ *PictureType = b->Frame[i].pt; ++ off64_t off = 0; ++ if (i+1 == INDEXBLOCKSIZE) ++ off = b->next->Frame[0].offset; ++ else ++ off = b->Frame[i+1].offset; ++ if (off < b->Frame[i].offset) { ++ if (b->Frame[i].written) ++ r = fileSize - b->Frame[i].offset; ++ else ++ r = bufSize - b->Frame[i].offset - blank; ++ } ++ else ++ r = off - b->Frame[i].offset; ++ } ++ } ++ else if (HasFrame(Number-1) && DPos >= 0) ++ r = DCount; ++ RwLock->Unlock(); ++ return r; ++} ++ ++int cLiveIndex::GetNextIFrame(int Index, bool Forward) ++{ ++ int d = Forward ? 1 : -1; ++ Index += d; ++ while (Index >= delCount && Index < lastFrame) { ++ block *b; ++ RwLock->Lock(false); ++ int i = GetFrame(&b, Index); ++ uchar type = b->Frame[i].pt; ++ RwLock->Unlock(); ++ if (type == I_FRAME) ++ return Index; ++ Index +=d; ++ } ++ return -1; ++} ++ ++int cLiveIndex::FindIFrame(int64_t PTS, uchar *Buffer) ++{ ++ int r = -1; ++ RwLock->Lock(false); ++ int Index=writtenCount; ++ int64_t pts=0; ++ do { ++ Index = GetNextIFrame(Index, true); ++ if (Index < 0) ++ break; ++ block *b; ++ int i = GetFrame(&b, Index); ++ uchar *p = &Buffer[b->Frame[i].offset]; ++ if (p[0]==0x00 && p[1]==0x00 && p[2]==0x01 && (p[7] & 0x80) && p[3]>=0xC0 && p[3]<=0xEF) { ++ pts = (int64_t) (p[ 9] & 0x0E) << 29 ; ++ pts |= (int64_t) p[ 10] << 22 ; ++ pts |= (int64_t) (p[ 11] & 0xFE) << 14 ; ++ pts |= (int64_t) p[ 12] << 7 ; ++ pts |= (int64_t) (p[ 13] & 0xFE) >> 1 ; ++ } ++ } while (pts!=PTS); ++ if (pts==PTS) ++ r = Index; ++ RwLock->Unlock(); ++ return r; ++} ++ ++void cLiveIndex::Switched(void) ++{ ++ start = Last(); ++} ++ ++// --- cLiveFileReader ------------------------------------------------------- ++ ++cLiveFileReader::cLiveFileReader(const char *FileName, int Number) ++{ ++ fileName = new cFileName64(FileName, false); ++ fileName->SetNumber(Number); ++ readFile = fileName->Open(); ++ buffer = NULL; ++ filePos = 0; ++ Start(); ++} ++ ++cLiveFileReader::~cLiveFileReader() ++{ ++ Cancel(3); ++ delete fileName; ++} ++ ++void cLiveFileReader::Action(void) ++{ ++ while (Running()) { ++ Lock(); ++ if (buffer && !hasData) { ++ int r = readFile->Read(buffer + length, wanted - length); ++ if (r >= 0) { ++ length += r; ++ filePos += r; ++ if (length == wanted) ++ hasData = true; ++ } ++ else if (r < 0 && FATALERRNO) { ++ LOG_ERROR; ++ length = r; ++ hasData = true; ++ } ++ } ++ Unlock(); ++ newSet.Wait(1000); ++ } ++} ++ ++int cLiveFileReader::Read(uchar **Buffer, off64_t FilePos, int Size) ++{ ++ if (buffer && hasData) { ++ *Buffer = buffer; ++ buffer = NULL; ++ return length; ++ } ++ if (!buffer) { ++ uchar *b = MALLOC(uchar, Size); ++ if (filePos != FilePos) { ++ filePos = FilePos; ++ readFile->Seek(FilePos,0); ++ } ++ wanted = Size; ++ length = 0; ++ hasData = false; ++ buffer = b; ++ newSet.Signal(); ++ } ++ return -1; ++} ++ ++void cLiveFileReader::Clear(void) ++{ ++ Lock(); ++ delete buffer; ++ buffer = NULL; ++ Unlock(); ++} ++ ++// --- cLiveFileWriter ------------------------------------------------------- ++ ++cLiveFileWriter::cLiveFileWriter(const char *FileName) ++{ ++ MakeDirs(FileName, true); ++ SpinUpDisk(FileName); ++ fileName = new cFileName64(FileName, true); ++ writeFile = fileName->Open(); ++ buffer = NULL; ++ filePos = fileSize = 0; ++ lastCheck = time(NULL); ++ full = false; ++ Start(); ++} ++ ++cLiveFileWriter::~cLiveFileWriter() ++{ ++ Cancel(3); ++ fileName->CloseAndRemove(); ++ delete fileName; ++} ++ ++void cLiveFileWriter::Action(void) ++{ ++ while (Running()) { ++ Lock(); ++ if (buffer && !hasWritten) { ++ int r = writeFile->Write(buffer, wantWrite); ++ if (r >= 0) { ++ filePos += r; ++ hasWritten = true; ++ } ++ else if (r < 0 && FATALERRNO) { ++ LOG_ERROR; ++ hasWritten = true; ++ } ++ } ++ Unlock(); ++ newSet.Wait(1000); ++ } ++} ++ ++#define MINFREE 600 ++ ++bool cLiveFileWriter::LowDiskSpace() ++{ ++ if (!full && time (NULL) > lastCheck + 60 || full && filePos >= fileSize) { ++ int Free = FreeDiskSpaceMB(fileName->Name()); ++ lastCheck = time(NULL); ++ if (Free < MINFREE) ++ return true; ++ } ++ return false; ++} ++ ++off64_t cLiveFileWriter::Write(uchar *Buffer, int Size, bool Wait) ++{ ++ if (buffer && hasWritten) { ++ buffer = NULL; ++ return filePos; ++ } ++ if (!buffer) { ++ if (filePos + Size > (off64_t)Setup.LiveBufferSize*1024*1024 || LowDiskSpace()) { ++ fileSize = filePos > fileSize ? filePos : fileSize; ++ filePos = 0; ++ writeFile->Seek(0,0); ++ full = true; ++ } ++ if (Wait) { ++ writeFile->Write(Buffer, Size); ++ filePos += Size; ++ return filePos; ++ } ++ else { ++ wantWrite = Size; ++ hasWritten = false; ++ buffer = Buffer; ++ newSet.Signal(); ++ } ++ } ++ if (Wait) { ++ while (!hasWritten) ++ usleep(5); ++ buffer = NULL; ++ return filePos; ++ } ++ return -1; ++} ++ ++void cLiveFileWriter::Clear(void) ++{ ++ Lock(); ++ buffer = NULL; ++ filePos = 0; ++ full = false; ++ writeFile->Seek(0,0); ++ Unlock(); ++} ++ ++// --- cLiveCutterThread ----------------------------------------------------- ++ ++cLiveCutterThread::cLiveCutterThread(const char *FileName, int FileNumber, cLiveBuffer *LiveBuffer, int StartFrame, int EndFrame) ++{ ++ readFile = NULL; ++ ++ writeFileName = new cFileName64(FileName, true); ++ writeFileName->SetNumber(FileNumber); ++ writeFile = writeFileName->Open(); ++ ++ liveBuffer = LiveBuffer; ++ startFrame = StartFrame; ++ endFrame = EndFrame; ++ Start(); ++} ++ ++cLiveCutterThread::~cLiveCutterThread() ++{ ++ Cancel(3); ++ if (readFile) ++ readFileName->Close(); ++ writeFileName->Close(); ++} ++ ++void cLiveCutterThread::Action(void) ++{ ++ int Frame = startFrame; ++ int readPos = 0; ++ int writePos = 0; ++ while (Running() && Frame < endFrame) { ++ uchar pt; ++ liveBuffer->index->RwLock->Lock(false); ++ int size = liveBuffer->index->Size(Frame, &pt); ++ if (pt == I_FRAME && writePos > MEGABYTE(Setup.MaxVideoFileSize)) { ++ int Number = writeFileName->Number(); ++ writeFileName->Close(); ++ writeFileName->SetNumber(Number+1); ++ writeFile = writeFileName->Open(); ++ writePos = 0; ++ } ++ if (liveBuffer->index->IsWritten(Frame)) { ++ if (!readFile) { ++ readFileName = new cFileName64(liveBuffer->filestring, false); ++ readFileName->SetNumber(liveBuffer->fileWriter->FileNumber()); ++ readFile = readFileName->Open(); ++ } ++ uchar b[MAXFRAMESIZE]; ++ if (liveBuffer->index->GetOffset(Frame) != readPos) { ++ readPos = liveBuffer->index->GetOffset(Frame); ++ readFile->Seek(readPos,0); ++ } ++ int c = readFile->Read(b, size); ++ readPos += c; ++ writeFile->Write(b,c); ++ writePos+=size; ++ if (c != size) ++ writeFile->Seek(writePos,0); ++ } ++ else { ++ writeFile->Write(&liveBuffer->buffer[liveBuffer->index->GetOffset(Frame)], size); ++ writePos+=size; ++ } ++ liveBuffer->index->RwLock->Unlock(); ++ Frame++; ++ cCondWait::SleepMs(5); ++ } ++ if (readFile) ++ readFileName->Close(); ++ writeFileName->Close(); ++} ++ ++// --- cLiveBuffer ----------------------------------------------------------- ++ ++cLiveBuffer::cLiveBuffer(const char *FileName, cRemux *Remux, const cChannel *Channel, int Number) ++:cThread("livebuffer") ++{ ++ number = Number; ++ bufSize = (Setup.InRAM && Number == 0) ? MEGABYTE(Setup.MemBufSize) : LIVEBUFSIZE; ++ buffer = MALLOC(uchar, bufSize); ++ writeHD = !(Setup.InRAM && Number == 0); ++ lastRead = 0; ++ if (!buffer) { ++ dsyslog("Couldn't reserve memory for livebuffer\n"); ++ bufSize = LIVEBUFSIZE; ++ buffer = MALLOC(uchar, bufSize); ++ } ++ channel = Channel; ++ index = new cLiveIndex(bufSize); ++ remux = Remux; ++ filestring = strdup(FileName); ++ head = tail = blank = 0; ++ startFrame = -1; ++ liveCutter = NULL; ++ fileWriter = NULL; ++ fileReader = NULL; ++ if (writeHD) { ++ fileWriter = new cLiveFileWriter(FileName); ++ fileReader = new cLiveFileReader(FileName, fileWriter->FileNumber()); ++ } ++ status = 0; ++ Start(); ++} ++ ++cLiveBuffer::~cLiveBuffer() ++{ ++ Cancel(3); ++ delete liveCutter; ++ delete fileReader; ++ delete index; ++ delete fileWriter; ++ free(filestring); ++ free(buffer); ++} ++ ++void cLiveBuffer::SetStatus(int s) ++{ ++ if (s == -1 || status != 2 && s == 0) ++ status = 0; ++ if (status == 0 && s == 1) ++ status = 1; ++ if (s == 2) ++ status = 2; ++ if (s == -2 && status == 0) ++ status = -1; ++} ++ ++void cLiveBuffer::Write(bool Wait) ++{ ++ int wcount = index->NextWrite(); ++ off64_t pos=fileWriter->Write(&buffer[tail], wcount, Wait); ++ if (pos>=0) { ++ index->WrittenTo(pos-wcount, wcount); ++ tail += wcount; ++ if (tail + MAXFRAMESIZE > bufSize) { ++ tail = 0; ++ blank = 0; ++ index->SetBlank(blank); ++ } ++ if (fileWriter->Full()) ++ index->Delete(pos); ++ } ++} ++ ++void cLiveBuffer::Store(uchar *Data, int Count) ++{ ++ ++ if (pictureType != NO_PICTURE) { ++ if (head + MAXFRAMESIZE > bufSize) { ++ blank = bufSize - head; ++ head = 0; ++ index->SetBlank(blank); ++ } ++ index->Add(pictureType,head); ++ } ++ else ++ index->AddData(head); ++ memcpy(&buffer[head], Data, Count); ++ head += Count; ++ ++ int free = head >= tail ? max(tail,bufSize-head) : tail - head; ++ ++ while (free < MAXFRAMESIZE) { ++ if (writeHD) ++ Write(true); ++ else { ++ tail = index->DelFirst(); ++ if (tail == 0) { ++ blank = 0; ++ index->SetBlank(blank); ++ } ++ if (Setup.ExtendBuffer && lastRead < index->delCount+25 && status >= 0) { ++ writeHD = true; ++ fileWriter = new cLiveFileWriter(filestring); ++ fileReader = new cLiveFileReader(filestring, fileWriter->FileNumber()); ++ } ++ } ++ free = head >= tail ? max(tail,bufSize-head) : tail - head; ++ } ++} ++ ++void cLiveBuffer::Action(void) ++{ ++ while (Running()) { ++ int Count; ++ Lock(); ++ uchar *p = remux->Get(Count, &pictureType); ++ if (p) { ++ Store(p,Count); ++ remux->Del(Count); ++ } ++ Unlock(); ++ if (writeHD) { ++ int free = head >= tail ? max(tail,bufSize-head) : tail - head; ++ if (free < 2*MAXFRAMESIZE) ++ Write(false); ++ } ++ } ++ ++} ++ ++void cLiveBuffer::SetNewRemux(cRemux *Remux, const cChannel *Channel) ++{ ++ if (Channel != channel) { ++ index->Switched(); ++ } ++ channel = Channel; ++ if (!Remux) { ++ Cancel(3); ++ return; ++ } ++ if (fileReader) fileReader->Clear(); ++ if (!Running() && Remux) { ++ remux = Remux; ++ Start(); ++ } ++ else { ++ Cancel(-1); ++ Lock(); ++ if (writeHD && Setup.InRAM && number == 0 && !status) { ++ index->Clear(); ++ delete fileReader; fileReader = NULL; ++ delete fileWriter; fileWriter = NULL; ++ writeHD = false; ++ } ++ remux = Remux; ++ Unlock(); ++ Start(); ++ } ++} ++ ++int cLiveBuffer::GetFrame(uchar **Buffer, int Number, int Off) ++{ ++ if (!Buffer) { ++ if (fileReader) fileReader->Clear(); ++ return -1; ++ } ++ if (Number < FirstIndex()) ++ return -2; ++ if (!index->HasFrame(Number) && (Off < 0 || !index->HasFrame(Number-1))) ++ return -1; ++ lastRead = Number; ++ if (!index->IsWritten(Number)) { ++ index->RwLock->Lock(false); ++ int size=index->Size(Number); ++ int off = index->GetOffset(Number); ++ if (off >= 0) { ++ if (Off>=0) { ++ size -= Off; ++ off += Off; ++ } ++ if (size > 0) { ++ uchar *b = MALLOC(uchar, size); ++ *Buffer = b; ++ memcpy(b,&buffer[off],size); ++ } ++ if (!index->HasFrame(Number)) ++ size = -size; ++ } ++ else ++ size = -1; ++ index->RwLock->Unlock(); ++ return size; ++ } ++ else ++ return fileReader->Read(Buffer,index->GetOffset(Number),index->Size(Number)); ++ return -1; ++} ++ ++void cLiveBuffer::CreateIndexFile(const char *FileName, int64_t PTS, int EndFrame) ++{ ++ if (liveCutter) { ++ if (liveCutter->Active()) { ++ startFrame = -1; ++ return; ++ } ++ else { ++ delete liveCutter; ++ liveCutter = NULL; ++ } ++ } ++ if (startFrame < 0) ++ return; ++ cIndexFile *indexFile = new cIndexFile(FileName, true); ++ if (!indexFile) ++ return; ++ int endFrame = EndFrame ? EndFrame : index->FindIFrame(PTS, buffer); ++ int timeout = 0; ++ while (endFrame < 0 && timeout < 50) { ++ cCondWait::SleepMs(100); ++ endFrame = index->FindIFrame(PTS, buffer); ++ timeout++; ++ } ++ ++ char *data="LiveBuffer"; ++ cFileName fileName(FileName, true); ++ cUnbufferedFile *file = fileName.Open(); ++ file->Write(data,10); ++ int Number = fileName.Number(); ++ int FileOffset=0; ++ for (int Frame = startFrame; Frame < endFrame; Frame++) { ++ uchar pt; ++ int size = index->Size(Frame, &pt); ++ if (pt == I_FRAME && FileOffset > MEGABYTE(Setup.MaxVideoFileSize)) { ++ file = fileName.NextFile(); ++ file->Write(data,10); ++ FileOffset=0; ++ } ++ indexFile->Write(pt,fileName.Number(),FileOffset); ++ FileOffset+=size; ++ } ++ liveCutter = new cLiveCutterThread(FileName,Number,this,startFrame,endFrame); ++ startFrame = -1; ++ delete indexFile; ++} ++ ++// --- cLiveReceiver --------------------------------------------------------- ++ ++cLiveReceiver::cLiveReceiver(const cChannel *Channel) ++:cReceiver(Channel->GetChannelID(), -1, Channel->Vpid(), Channel->Apids(), Setup.UseDolbyDigital ? Channel->Dpids() : NULL, Channel->Spids()) ++{ ++ channel = Channel; ++ vpid = Channel->Vpid(); ++ for (int i = 0; i < MAXAPIDS; i++) ++ apids[i]=Channel->Apid(i); ++ for (int i = 0; i < MAXDPIDS; i++) ++ dpids[i]= Setup.UseDolbyDigital ? Channel->Dpid(i) : 0; ++ for (int i = 0; i < MAXSPIDS; i++) ++ spids[i]=Channel->Spid(i); ++ ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); ++ ringBuffer->SetTimeouts(0, 20); ++ remux = new cRemux(Channel->Vpid(), Channel->Apids(), Setup.UseDolbyDigital ? Channel->Dpids() : NULL, Channel->Spids()); ++ remux->SetTimeouts(0, 50); ++ attached = false; ++} ++ ++cLiveReceiver::~cLiveReceiver() ++{ ++ Detach(); ++ Cancel(3); ++ delete remux; ++ delete ringBuffer; ++} ++ ++void cLiveReceiver::Activate(bool On) ++{ ++ if (On) { ++ Start(); ++ attached = true; ++ } ++ else { ++ Cancel(-1); ++ attached = false; ++ } ++} ++ ++void cLiveReceiver::Receive(uchar *Data, int Length) ++{ ++ int p = ringBuffer->Put(Data, Length); ++ if (p != Length && Running()) ++ ringBuffer->ReportOverflow(Length - p); ++} ++ ++void cLiveReceiver::Action(void) ++{ ++ while (Running()) { ++ int r; ++ uchar *b = ringBuffer->Get(r); ++ if (b) { ++ int Count = remux->Put(b, r); ++ if (Count) ++ ringBuffer->Del(Count); ++ else ++ cCondWait::SleepMs(20); ++ } ++ } ++} ++ ++bool cLiveReceiver::IsReceiving(const cChannel *Channel) ++{ ++ if (vpid != Channel->Vpid()) ++ return false; ++ for (int i = 0; i < MAXAPIDS; i++) ++ if (apids[i] != Channel->Apid(i)) ++ return false; ++ for (int i = 0; i < MAXDPIDS && Setup.UseDolbyDigital; i++) ++ if (dpids[i] != Channel->Dpid(i)) ++ return false; ++ for (int i = 0; i < MAXSPIDS; i++) ++ if (spids[i] != Channel->Spid(i)) ++ return false; ++ ++ return true; ++} ++ ++// --- cLiveBackTrace -------------------------------------------------------- ++ ++#define AVG_FRAME_SIZE 15000 ++#define DVB_BUF_SIZE (256 * 1024) ++#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) ++ ++class cLiveBackTrace { ++private: ++ int index[BACKTRACE_ENTRIES]; ++ int length[BACKTRACE_ENTRIES]; ++ int pos, num; ++public: ++ cLiveBackTrace(void); ++ void Clear(void); ++ void Add(int Index, int Length); ++ int Get(bool Forward); ++ }; ++ ++cLiveBackTrace::cLiveBackTrace(void) ++{ ++ Clear(); ++} ++ ++void cLiveBackTrace::Clear(void) ++{ ++ pos = num = 0; ++} ++ ++void cLiveBackTrace::Add(int Index, int Length) ++{ ++ index[pos] = Index; ++ length[pos] = Length; ++ if (++pos >= BACKTRACE_ENTRIES) ++ pos = 0; ++ if (num < BACKTRACE_ENTRIES) ++ num++; ++} ++ ++int cLiveBackTrace::Get(bool Forward) ++{ ++ int p = pos; ++ int n = num; ++ int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); ++ int i = -1; ++ ++ while (n && l > 0) { ++ if (--p < 0) ++ p = BACKTRACE_ENTRIES - 1; ++ i = index[p] - 1; ++ l -= length[p]; ++ n--; ++ } ++ return i; ++} ++ ++// --- cLivePlayer ----------------------------------------------------------- ++ ++#define PLAYERBUFSIZE MEGABYTE(1) ++ ++#define MAX_VIDEO_SLOWMOTION 63 ++#define NORMAL_SPEED 4 ++#define MAX_SPEEDS 3 ++#define SPEED_MULT 12 ++int cLivePlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; ++ ++cLivePlayer::cLivePlayer(cLiveBuffer *LiveBuffer) ++:cThread("liveplayer") ++{ ++ liveBuffer = LiveBuffer; ++ ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE); ++ readIndex = writeIndex = -1; ++ readFrame = playFrame = NULL; ++ firstPacket = true; ++ playMode = pmPlay; ++ playDir = pdForward; ++ trickSpeed = NORMAL_SPEED; ++ Off = 0; ++ backTrace = new cLiveBackTrace; ++ liveBuffer->SetStatus(0); ++} ++ ++cLivePlayer::~cLivePlayer() ++{ ++ liveBuffer->SetStatus(-2); ++ Detach(); ++ Cancel(3); ++ liveBuffer->GetFrame(NULL,0); ++ delete readFrame; ++ delete backTrace; ++ delete ringBuffer; ++} ++ ++void cLivePlayer::TrickSpeed(int Increment) ++{ ++ int nts = trickSpeed + Increment; ++ if (Speeds[nts] == 1) { ++ trickSpeed = nts; ++ if (playMode == pmFast) ++ Play(); ++ else ++ Pause(); ++ } ++ else if (Speeds[nts]) { ++ trickSpeed = nts; ++ int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT; ++ int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult; ++ if (sp > MAX_VIDEO_SLOWMOTION) ++ sp = MAX_VIDEO_SLOWMOTION; ++ DeviceTrickSpeed(sp); ++ } ++} ++ ++void cLivePlayer::Empty(void) ++{ ++ LOCK_THREAD; ++ liveBuffer->GetFrame(NULL,0); ++ if ((readIndex = backTrace->Get(playDir == pdForward)) < 0) ++ readIndex = writeIndex; ++ delete readFrame; ++ readFrame = NULL; ++ playFrame = NULL; ++ ringBuffer->Clear(); ++ DeviceClear(); ++ backTrace->Clear(); ++ firstPacket = true; ++ Off = 0; ++} ++ ++void cLivePlayer::Activate(bool On) ++{ ++ if (On) ++ Start(); ++ else ++ Cancel(-1); ++} ++ ++void cLivePlayer::Action(void) ++{ ++ int PollTimeouts = 0; ++ uchar *b = NULL; ++ uchar **pb = &b; ++ uchar *p = NULL; ++ int pc = 0; ++ ++ if (liveBuffer->Stay()) ++ readIndex = liveBuffer->LastRead(); ++ else ++ readIndex = liveBuffer->LastIndex(); ++ ++ bool Sleep = false; ++ bool WaitingForData = false; ++ ++ while (Running()) { ++ if (Sleep) { ++ if (WaitingForData) ++ cCondWait::SleepMs(3); ++ else ++ cCondWait::SleepMs(3); ++ Sleep = false; ++ } ++ ++ cPoller Poller; ++ if (!DevicePoll(Poller, 100)) { ++ PollTimeouts++; ++ continue; ++ } ++ else ++ PollTimeouts = 0; ++ ++ if (PollTimeouts >= 6) { ++ DeviceClear(); ++ PlayPes(NULL, 0); ++ } ++ ++ LOCK_THREAD; ++ ++ if (playMode != pmStill && playMode != pmPause) { ++ if (!readFrame) { ++ if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { ++ int Index = liveBuffer->GetNextIFrame(readIndex, playDir == pdForward); ++ if (Index < 0) { ++ if (!DeviceFlush(100)) ++ continue; ++ DevicePlay(); ++ playMode = pmPlay; ++ playDir = pdForward; ++ continue; ++ } ++ int r = liveBuffer->GetFrame(pb, Index); ++ if (r>0) { ++ readIndex = Index; ++ WaitingForData = false; ++ readFrame = new cFrame(b, -r, ftUnknown, readIndex); ++ b = NULL; ++ } ++ else ++ WaitingForData = true; ++ } ++ else { ++ int r=liveBuffer->GetFrame(pb, readIndex+1, Off); ++ if (r>0) ++ readIndex++; ++ if (r > 0 || r < -10) { ++ WaitingForData = false; ++ readFrame = new cFrame(b, -abs(r), ftUnknown, readIndex); ++ b = NULL; ++ if (r<0) ++ Off += -r; ++ else ++ Off = 0; ++ } ++ else if (r==-2) ++ readIndex = liveBuffer->GetNextIFrame(liveBuffer->FirstIndex(), true)-1; ++ else ++ WaitingForData = true; ++ } ++ } ++ if (readFrame) { ++ if (ringBuffer->Put(readFrame)) ++ readFrame = NULL; ++ } ++ } ++ else ++ Sleep = true; ++ if (!playFrame) { ++ playFrame = ringBuffer->Get(); ++ p = NULL; ++ pc = 0; ++ } ++ if (playFrame) { ++ if (!p) { ++ p = playFrame->Data(); ++ pc = playFrame->Count(); ++ if (p) { ++ if (firstPacket) { ++ PlayPes(NULL, 0); ++ cRemux::SetBrokenLink(p, pc); ++ firstPacket = false; ++ } ++ } ++ } ++ if (p) { ++ int w = PlayPes(p, pc, playMode != pmPlay); ++ if (w > 0) { ++ p += w; ++ pc -= w; ++ } ++ else { ++ if (w < 0 && FATALERRNO) { ++ LOG_ERROR; ++ break; ++ } ++ } ++ } ++ if (pc == 0) { ++ writeIndex = playFrame->Index(); ++ backTrace->Add(playFrame->Index(), playFrame->Count()); ++ ringBuffer->Drop(playFrame); ++ playFrame = NULL; ++ p = NULL; ++ } ++ } ++ else ++ Sleep = true; ++ } ++} ++ ++void cLivePlayer::Pause(void) ++{ ++ if (playMode == pmPause || playMode == pmStill) ++ Play(); ++ else { ++ liveBuffer->SetStatus(1); ++ LOCK_THREAD; ++ if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) ++ Empty(); ++ DeviceFreeze(); ++ playMode = pmPause; ++ } ++} ++ ++void cLivePlayer::Play(void) ++{ ++ if (playMode != pmPlay) { ++ liveBuffer->SetStatus(0); ++ LOCK_THREAD; ++ if (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) ++ Empty(); ++ DevicePlay(); ++ playMode = pmPlay; ++ playDir = pdForward; ++ } ++} ++ ++void cLivePlayer::Forward(void) ++{ ++ switch (playMode) { ++ case pmFast: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdForward ? 1 : -1); ++ break; ++ } ++ else if (playDir == pdForward) { ++ Play(); ++ break; ++ } ++ case pmPlay: { ++ LOCK_THREAD; ++ Empty(); ++ DeviceMute(); ++ playMode = pmFast; ++ playDir = pdForward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); ++ } ++ break; ++ case pmSlow: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdForward ? -1 : 1); ++ break; ++ } ++ else if (playDir == pdForward) { ++ Pause(); ++ break; ++ } ++ case pmStill: ++ case pmPause: ++ DeviceMute(); ++ playMode = pmSlow; ++ playDir = pdForward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); ++ break; ++ } ++} ++ ++void cLivePlayer::Backward(void) ++{ ++ switch (playMode) { ++ case pmFast: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdBackward ? 1 : -1); ++ break; ++ } ++ else if (playDir == pdBackward) { ++ Play(); ++ break; ++ } ++ case pmPlay: { ++ LOCK_THREAD; ++ Empty(); ++ DeviceMute(); ++ playMode = pmFast; ++ playDir = pdBackward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); ++ } ++ break; ++ case pmSlow: ++ if (Setup.MultiSpeedMode) { ++ TrickSpeed(playDir == pdBackward ? -1 : 1); ++ break; ++ } ++ else if (playDir == pdBackward) { ++ Pause(); ++ break; ++ } ++ case pmStill: ++ case pmPause: { ++ LOCK_THREAD; ++ Empty(); ++ DeviceMute(); ++ playMode = pmSlow; ++ playDir = pdBackward; ++ trickSpeed = NORMAL_SPEED; ++ TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); ++ } ++ break; ++ } ++} ++ ++bool cLivePlayer::Stop(void) ++{ ++ liveBuffer->SetStatus(-1); ++ if (readIndex >= liveBuffer->LastIndex() - 25) ++ return false; ++ LOCK_THREAD; ++ Empty(); ++ readIndex = writeIndex = liveBuffer->GetNextIFrame(liveBuffer->LastIndex()-1, false)-1; ++ Play(); ++ return true; ++} ++ ++void cLivePlayer::SkipSeconds(int Seconds) ++{ ++ if (Seconds) { ++ LOCK_THREAD; ++ Empty(); ++ int Index = writeIndex; ++ if (Index >= 0) { ++ Index = max(Index + Seconds * FRAMESPERSEC, liveBuffer->FirstIndex()); ++ if (Index > liveBuffer->FirstIndex()) ++ Index = liveBuffer->GetNextIFrame(Index, false); ++ if (Index >= 0) ++ readIndex = writeIndex = Index - 1; ++ } ++ Play(); ++ } ++} ++ ++bool cLivePlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame) ++{ ++ if (liveBuffer) { ++ if (playMode == pmStill) ++ Current = max(readIndex, 0); ++ else { ++ Current = max(writeIndex, 0); ++ // TODO SnapToIFrame ++ } ++ Total = liveBuffer->LastIndex() - liveBuffer->FirstIndex(); ++ Current -= liveBuffer->FirstIndex(); ++ return true; ++ } ++ Current = Total = -1; ++ return false; ++} ++ ++bool cLivePlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) ++{ ++ Play = (playMode == pmPlay || playMode == pmFast); ++ Forward = (playDir == pdForward); ++ if (playMode == pmFast || playMode == pmSlow) ++ Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0 ; ++ else ++ Speed = -1; ++ return true; ++} ++ ++// --- cLiveBufferControl ---------------------------------------------------- ++ ++cLiveBufferControl::cLiveBufferControl(cLivePlayer *Player) ++:cControl(Player, true) ++{ ++ player = Player; ++ displayReplay = NULL; ++ visible = modeOnly = shown = false; ++ lastCurrent = lastTotal = -1; ++ lastPlay = lastForward = false; ++ lastSpeed = -2; ++ timeoutShow = 0; ++} ++ ++cLiveBufferControl::~cLiveBufferControl() ++{ ++ Hide(); ++ cTransferControl::receiverDevice = NULL; ++ cLiveBufferManager::livePlayer = NULL; ++ delete player; ++ cLiveBufferManager::liveControl = NULL; ++ if (!Setup.LiveBuffer) ++ cLiveBufferManager::Shutdown(); ++} ++ ++bool cLiveBufferControl::GetIndex(int &Current, int &Total, bool SnapToIFrame) ++{ ++ if (player) { ++ player->GetIndex(Current, Total, SnapToIFrame); ++ return true; ++ } ++ return false; ++ ++} ++ ++bool cLiveBufferControl::GetReplayMode(bool &Play, bool &Forward, int &Speed) ++{ ++ return player && player->GetReplayMode(Play, Forward, Speed); ++} ++ ++void cLiveBufferControl::ShowTimed(int Seconds) ++{ ++ if (modeOnly) ++ Hide(); ++ if (!visible) { ++ shown = ShowProgress(true); ++ timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; ++ } ++} ++ ++void cLiveBufferControl::Show(void) ++{ ++ ShowTimed(); ++} ++ ++void cLiveBufferControl::Hide(void) ++{ ++ if (visible) { ++ delete displayReplay; ++ displayReplay = NULL; ++ SetNeedsFastResponse(false); ++ visible = false; ++ modeOnly = false; ++ lastPlay = lastForward = false; ++ lastSpeed = -2; // an invalid value ++// timeSearchActive = false; ++ } ++} ++ ++void cLiveBufferControl::ShowMode(void) ++{ ++ if (visible || Setup.ShowReplayMode && !cOsd::IsOpen()) { ++ bool Play, Forward; ++ int Speed; ++ if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) { ++ bool NormalPlay = (Play && Speed == -1); ++ ++ if (!visible) { ++ if (NormalPlay) ++ return; ++ visible = modeOnly = true; ++ displayReplay = Skins.Current()->DisplayReplay(modeOnly); ++ } ++ ++ if (modeOnly && !timeoutShow && NormalPlay) ++ timeoutShow = time(NULL) + 3; ++ displayReplay->SetMode(Play, Forward, Speed); ++ lastPlay = Play; ++ lastForward = Forward; ++ lastSpeed = Speed; ++ } ++ } ++} ++ ++bool cLiveBufferControl::ShowProgress(bool Initial) ++{ ++ int Current, Total; ++ ++ if (GetIndex(Current, Total) && Total > 0) { ++ if (!visible) { ++ displayReplay = Skins.Current()->DisplayReplay(modeOnly); ++ SetNeedsFastResponse(true); ++ visible = true; ++ } ++ if (Initial) { ++ lastCurrent = lastTotal = -1; ++ } ++ if (Total != lastTotal) { ++ displayReplay->SetTotal(IndexToHMSF(Total)); ++ if (!Initial) ++ displayReplay->Flush(); ++ } ++ if (Current != lastCurrent || Total != lastTotal) { ++ displayReplay->SetProgress(Current, Total); ++ if (!Initial) ++ displayReplay->Flush(); ++int displayFrames = false; ++ displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames)); ++ displayReplay->Flush(); ++ lastCurrent = Current; ++ } ++ lastTotal = Total; ++ ShowMode(); ++ return true; ++ } ++ return false; ++} ++ ++eOSState cLiveBufferControl::ProcessKey(eKeys Key) ++{ ++ if (visible) { ++ if (timeoutShow && time(NULL) > timeoutShow) { ++ Hide(); ++ ShowMode(); ++ timeoutShow = 0; ++ } ++ else if (modeOnly) ++ ShowMode(); ++ else ++ shown = ShowProgress(!shown) || shown; ++ } ++ bool DoShowMode = true; ++ switch (Key) { ++ case kDown: if (!visible || modeOnly) ++ return osUnknown; ++ case kPause: if (player) ++ player->Pause(); ++ break; ++ case kPlay: if (visible && !modeOnly) { ++ Hide(); ++ DoShowMode = true; ++ } ++ else ++ Show(); ++ case kUp: if (Key == kUp && (!visible || modeOnly)) ++ return osUnknown; ++ if (player) ++ player->Play(); ++ break; ++ case kLeft|k_Release: ++ if (!visible || modeOnly) ++ return osUnknown; ++ case kFastRew|k_Release: ++ if (Setup.MultiSpeedMode) break; ++ case kLeft: if (Key == kLeft && (!visible || modeOnly)) ++ return osUnknown; ++ case kFastRew: if (player) ++ player->Backward(); ++ break; ++ case kRight|k_Release: ++ if (!visible || modeOnly) ++ return osUnknown; ++ case kFastFwd|k_Release: ++ if (Setup.MultiSpeedMode) break; ++ case kRight: if (Key == kRight && (!visible || modeOnly)) ++ return osUnknown; ++ case kFastFwd: if (player) ++ player->Forward(); ++ break; ++ case kGreen|k_Repeat: ++ case kGreen: if (visible && !modeOnly && player) ++ player->SkipSeconds(-60); ++ else ++ return osUnknown; ++ break; ++ case kYellow|k_Repeat: ++ case kYellow: if (visible && !modeOnly && player) ++ player->SkipSeconds(60); ++ else ++ return osUnknown; ++ break; ++ default: { ++ DoShowMode = false; ++ switch (Key) { ++ case kStop: if (player) ++ if (player->Stop()) ++ break; ++ return osUnknown; ++ case kBack: if (visible && !modeOnly && player) ++ Hide(); ++ else ++ return osUnknown; ++ break; ++ case kRecord: { ++ cTimer *timer = new cTimer(true); ++ int Current, Total; ++ GetIndex(Current,Total); ++ time_t start = time(NULL) - (Total - Current) / FRAMESPERSEC; ++ time_t t = start; ++ struct tm tm_r; ++ struct tm *now = localtime_r(&t, &tm_r); ++ timer->start = now->tm_hour * 100 + now->tm_min; ++ timer->stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime; ++ timer->stop = (timer->stop / 60) * 100 + (timer->stop % 60); ++ if (timer->stop >= 2400) ++ timer->stop -= 2400; ++ timer->day = cTimer::SetTime(start, 0); ++ timer->channel = Channels.GetByNumber(cDevice::CurrentChannel()); ++ Timers.Add(timer); ++ Timers.SetModified(); ++ if (cRecordControls::Start(timer)) ++ Skins.Message(mtInfo, tr("Recording started")); ++ break; ++ } ++ default: return osUnknown; ++ } ++ } ++ } ++ if (DoShowMode) ++ ShowMode(); ++ return osContinue; ++} ++ ++// --- cLiveBufferManager ---------------------------------------------------- ++ ++cLiveReceiver *cLiveBufferManager::liveReceiver[MAXLIVEBUFFERS] = { NULL }; ++cLiveBuffer *cLiveBufferManager::liveBuffer[MAXLIVEBUFFERS] = { NULL }; ++cDevice *cLiveBufferManager::receiverDevice[MAXLIVEBUFFERS] = { NULL }; ++cLivePlayer *cLiveBufferManager::livePlayer = NULL; ++cLiveBufferControl *cLiveBufferManager::liveControl = NULL; ++ ++void cLiveBufferManager::ChannelSwitch(cDevice *ReceiverDevice, const cChannel *Channel) ++{ ++ int i; ++ for (i=0; i<MAXLIVEBUFFERS; i++) ++ if (liveBuffer[i] && liveBuffer[i]->Channel() == Channel) ++ break; ++ if (i == MAXLIVEBUFFERS) { ++ if (Setup.InRAM && !liveBuffer[0]) ++ i = 0; ++ else ++ for (i=0; i<MAXLIVEBUFFERS; i++) ++ if (liveBuffer[i] && (!liveBuffer[i]->Stay() || !liveReceiver[i]->IsAttached())) ++ break; ++ if (i == MAXLIVEBUFFERS) { ++ for (i = 0; i<MAXLIVEBUFFERS; i++) ++ if (!liveBuffer[i]) ++ break; ++ } ++ } ++ if (liveBuffer[i]) { ++ if (!(liveReceiver[i]->IsReceiving(Channel) && liveReceiver[i]->IsAttached())) { ++ cLiveReceiver *oldReceiver = liveReceiver[i]; ++ liveReceiver[i] = new cLiveReceiver(Channel); ++ ReceiverDevice->AttachReceiver(liveReceiver[i]); ++ liveBuffer[i]->SetNewRemux(liveReceiver[i]->remux, Channel); ++ delete oldReceiver; ++ receiverDevice[i] = ReceiverDevice; ++ } ++ else if (liveBuffer[i]->Stay()) ++ liveBuffer[i]->SetStatus(2); ++ } ++ else { ++ liveReceiver[i] = new cLiveReceiver(Channel); ++ ReceiverDevice->AttachReceiver(liveReceiver[i]); ++ receiverDevice[i] = ReceiverDevice; ++ char FileName[256]; ++ sprintf(FileName,"%s/LiveBuffer",BufferDirectory); ++ liveBuffer[i] = new cLiveBuffer(FileName,liveReceiver[i]->remux, Channel, i); ++ } ++ delete liveControl; ++ ++ cTransferControl::receiverDevice = receiverDevice[i]; ++ ++ livePlayer = new cLivePlayer(liveBuffer[i]); ++ cControl::Launch(liveControl = new cLiveBufferControl(livePlayer)); ++ ++ for (int j = 0; j < MAXLIVEBUFFERS; j++) ++ if (i!=j && liveBuffer[j] && !liveBuffer[j]->LiveCutterActive() && (!liveBuffer[j]->Stay() || !liveReceiver[j]->IsAttached())) { ++ delete liveBuffer[j]; ++ liveBuffer[j] = NULL; ++ delete liveReceiver[j]; ++ liveReceiver[j] = NULL; ++ } ++} ++ ++void cLiveBufferManager::Shutdown(void) ++{ ++ delete liveControl; ++ for (int i = 0; i < MAXLIVEBUFFERS; i++) { ++ delete liveBuffer[i]; ++ liveBuffer[i] = NULL; ++ delete liveReceiver[i]; ++ liveReceiver[i] = NULL; ++ } ++ char FileName[256]; ++ sprintf(FileName,"%s/LiveBuffer",BufferDirectory); ++ RemoveFileOrDir(FileName, true); ++} ++ ++cLiveBuffer *cLiveBufferManager::InLiveBuffer(cTimer *timer, int *StartFrame, int *EndFrame) ++{ ++ bool recstart = false; ++ if (timer && timer->HasFlags(tfRecording)) { ++ timer->SetFlags(tfhasLiveBuf); ++ recstart = true; ++ } ++ for (int i = 0; i < MAXLIVEBUFFERS; i++) ++ if (timer && timer->HasFlags(tfActive) && !timer->HasFlags(tfVps) && (!timer->HasFlags(tfhasLiveBuf) || recstart) && liveBuffer[i] && liveReceiver[i]->GetChannel() == timer->Channel()) { ++ int now = liveBuffer[i]->LastIndex(); ++ int first = liveBuffer[i]->FirstIndex() + 50; ++ if (now-first < 250) // Erst wenn LiveBuffer größer 10s ++ return NULL; ++ if (timer->StartTime() < time(NULL) && now-first > (time(NULL)-timer->StopTime())*FRAMESPERSEC) { ++ if (StartFrame) { ++ if ((time(NULL)-timer->StartTime())*FRAMESPERSEC < now - first) ++ *StartFrame = now - (time(NULL) - timer->StartTime())*FRAMESPERSEC; ++ else ++ *StartFrame = first; ++ } ++ if (EndFrame) { ++ if (time(NULL) > timer->StopTime()) ++ *EndFrame = now - (time(NULL) - timer->StopTime()) * FRAMESPERSEC; ++ else ++ *EndFrame = 0; ++ } ++ return liveBuffer[i]; ++ } ++ } ++ return NULL; ++} ++ ++int cLiveBufferManager::Impact(cDevice *device, const cChannel *Channel, bool LiveView) ++{ ++ if (!Setup.LiveBuffer) ++ return 0; ++ int r = 1; ++ for (int i=0; i < MAXLIVEBUFFERS; i++) ++ if (liveBuffer[i] && receiverDevice[i] == device) { ++ if (liveBuffer[i]->Stay() && liveReceiver[i]->IsAttached()) ++ if (liveBuffer[i]->Channel()->Transponder() != Channel->Transponder() || ++ liveBuffer[i]->Channel()->Source() != Channel->Source()) ++ r = 2; ++ } ++ return r; ++} ++ ++bool cLiveBufferManager::AllowsChannelSwitch(void) ++{ ++ return true; // return !liveBuffer || !liveBuffer->LiveCutterActive(); ++} ++#endif /* LIVEBUFFER */ +diff -ruNp vdr-1.7.0/livebuffer.h vdr-1.7.0-extensions/livebuffer.h +--- vdr-1.7.0/livebuffer.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/livebuffer.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,301 @@ ++#ifndef __LIVEBUFFER_H ++#define __LIVEBUFFER_H ++ ++#include "player.h" ++#include "receiver.h" ++#include "remux.h" ++#include "ringbuffer.h" ++#include "thread.h" ++ ++#define LIVEBUFSIZE MEGABYTE(5) ++ ++#define INDEXBLOCKSIZE 20000 ++ ++class cUnbufferedFile64 { ++private: ++ int fd; ++ off64_t curpos; ++ off64_t cachedstart; ++ off64_t cachedend; ++ off64_t begin; ++ off64_t lastpos; ++ off64_t ahead; ++ size_t readahead; ++ size_t written; ++ size_t totwritten; ++ int FadviseDrop(off64_t Offset, off64_t Len); ++public: ++ cUnbufferedFile64(void); ++ ~cUnbufferedFile64(); ++ int Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); ++ int Close(void); ++ off64_t Seek(off64_t Offset, int Whence); ++ ssize_t Read(void *Data, size_t Size); ++ ssize_t Write(const void *Data, size_t Size); ++ static cUnbufferedFile64 *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); ++ }; ++ ++class cFileName64 { ++private: ++ cUnbufferedFile64 *file; ++ int fileNumber; ++ char *fileName, *pFileNumber; ++ bool record; ++ bool blocking; ++public: ++ cFileName64(const char *FileName, bool Record, bool Blocking = false); ++ ~cFileName64(); ++ const char *Name(void) { return fileName; } ++ int Number(void) { return fileNumber; } ++ void SetNumber(int Number); ++ cUnbufferedFile64 *Open(void); ++ void Close(void); ++ void CloseAndRemove(void); ++ void Remove(void); ++ }; ++ ++class cLiveIndex { ++friend class cLiveCutterThread; ++friend class cLiveBuffer; ++private: ++ struct frame { ++ off64_t offset ; //:36; ++ bool written ; //:1 ; ++ uchar pt ; //:3 ; ++ }; ++ struct block { ++ frame Frame[INDEXBLOCKSIZE]; ++ block *previous, *next; ++ }; ++ block *headblock, *tailblock; ++ int blockCount; ++ int head, tail; ++ int blank; ++ int start; ++ int writtenCount, delCount; ++ int DPos, DCount; ++ int lastWrittenSize, lastCount; ++ off64_t fileSize; ++ int bufSize; ++ int lastFrame; ++ int GetFrame(block** Block, int Number); ++ cRwLock *RwLock; ++public: ++ cLiveIndex(int BufSize); ++ ~cLiveIndex(); ++ void Add(uchar pt, int pos); ++ void AddData(int pos); ++ void Delete(off64_t FilePos); ++ int DelFirst(void); ++ void Clear(void); ++ void SetBlank(int Blank) { RwLock->Lock(true); blank = Blank; RwLock->Unlock(); } ++ int NextWrite(); ++ void WrittenTo(off64_t FilePos, int Count); ++ bool HasFrame(int Number) { return lastFrame > Number && Number >=delCount; } ++ bool IsWritten(int Number) { return writtenCount > Number; } ++ off64_t GetOffset(int Number); ++ int Size(int Number, uchar *PictureType = NULL); ++ int GetNextIFrame(int Index, bool Forward); ++ int FindIFrame(int64_t PTS, uchar *Buffer); ++ void Switched(); ++ int Last(void) { return lastFrame+1; } ++ int First(void) { return start > delCount ? start : delCount; } ++}; ++ ++class cLiveFileReader : public cThread { ++private: ++ cFileName64 *fileName; ++ cUnbufferedFile64 *readFile; ++ cCondWait newSet; ++ off64_t filePos; ++ int hasData, length, wanted; ++ uchar *buffer; ++protected: ++ virtual void Action(void); ++public: ++ cLiveFileReader(const char *FileName, int Number); ++ ~cLiveFileReader(); ++ int Read(uchar **Buffer, off64_t FilePos, int Size); ++ void Clear(void); ++}; ++ ++class cLiveFileWriter : public cThread { ++private: ++ cFileName64 *fileName; ++ cUnbufferedFile64 *writeFile; ++ cCondWait newSet,written; ++ off64_t filePos,fileSize; ++ int hasWritten, length, wantWrite; ++ uchar *buffer; ++ time_t lastCheck; ++ bool full; ++ bool LowDiskSpace(void); ++protected: ++ virtual void Action(void); ++public: ++ cLiveFileWriter(const char *FileName); ++ ~cLiveFileWriter(); ++ off64_t Write(uchar *Buffer, int Size, bool Wait); ++ int FileNumber(void) { return fileName->Number(); } ++ void Clear(void); ++ bool Full(void) { return full; } ++}; ++ ++class cLiveBuffer; ++ ++class cLiveCutterThread : public cThread { ++private: ++ cFileName64 *readFileName, *writeFileName; ++ cUnbufferedFile64 *readFile, *writeFile; ++ cLiveBuffer *liveBuffer; ++ int startFrame, endFrame; ++protected: ++ virtual void Action(void); ++public: ++ cLiveCutterThread(const char *FileName, int FileNumber, cLiveBuffer *LiveBuffer, int StartFrame, int EndFrame); ++ ~cLiveCutterThread(); ++}; ++ ++class cLiveBuffer : public cThread { ++friend class cLiveCutterThread; ++private: ++ int number; ++ uchar *buffer; ++ int bufSize; ++ bool writeHD; ++ int lastRead; ++ int head, tail, blank; ++ cLiveIndex *index; ++ cRemux *remux; ++ cLiveFileWriter *fileWriter; ++ char *filestring; ++ uchar pictureType; ++ cLiveFileReader *fileReader; ++ int startFrame; ++ cLiveCutterThread *liveCutter; ++ const cChannel *channel; ++ int status; ++ void Write(bool Wait); ++ void Store(uchar *Data, int Count); ++protected: ++ virtual void Action(void); ++public: ++ cLiveBuffer(const char *FileName, cRemux *Remux, const cChannel *Channel, int Number); ++ virtual ~cLiveBuffer(); ++ void SetStatus(int s); ++ void SetNewRemux(cRemux *Remux, const cChannel *Channel); ++ int GetFrame(uchar **Buffer, int Number, int Off = -1); ++ int GetNextIFrame(int Index, bool Forward) { return index->GetNextIFrame(Index,Forward); } ++ int LastIndex(void) { return index->Last(); } ++ int FirstIndex(void) { return index->First(); } ++ int LastRead(void) { return lastRead; } ++ void CreateIndexFile(const char *FileName, int64_t PTS, int EndFrame = 0); ++ void SetStartFrame(int StartFrame) { startFrame = StartFrame; } ++ bool LiveCutterActive(void) { return liveCutter && liveCutter->Active(); } ++ const cChannel* Channel(void) { return channel; } ++ bool Stay(void) { return status>0 && Setup.KeepPaused; }; ++}; ++ ++class cLiveBackTrace; ++ ++class cLivePlayer : public cPlayer, public cThread { ++private: ++ enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill }; ++ enum ePlayDirs { pdForward, pdBackward }; ++ static int Speeds[]; ++ ePlayModes playMode; ++ ePlayDirs playDir; ++ int trickSpeed; ++ cLiveBuffer *liveBuffer; ++ cRingBufferFrame *ringBuffer; ++ cLiveBackTrace *backTrace; ++ int readIndex, writeIndex; ++ cFrame *readFrame; ++ cFrame *playFrame; ++ int Off; ++ bool firstPacket; ++ void TrickSpeed(int Increment); ++ void Empty(void); ++protected: ++ virtual void Activate(bool On); ++ virtual void Action(void); ++public: ++ cLivePlayer(cLiveBuffer *LiveBuffer); ++ virtual ~cLivePlayer(); ++ void Pause(void); ++ void Play(void); ++ void Forward(void); ++ void Backward(void); ++ bool Stop(void); ++ void SkipSeconds(int Seconds); ++ virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); ++ virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); ++}; ++ ++class cLiveReceiver : public cReceiver, cThread { ++friend class cLiveBufferManager; ++friend class cLiveBufferControl; ++private: ++ cRingBufferLinear *ringBuffer; ++ cRemux *remux; ++ const cChannel *channel; ++ bool attached; ++ int vpid; ++ int apids[MAXAPIDS]; ++ int dpids[MAXDPIDS]; ++ int spids[MAXSPIDS]; ++protected: ++ virtual void Activate(bool On); ++ virtual void Receive(uchar *Data, int Length); ++ virtual void Action(void); ++public: ++ cLiveReceiver(const cChannel *Channel); ++ virtual ~cLiveReceiver(); ++ const cChannel *GetChannel() { return channel; } ++ bool IsReceiving(const cChannel *Channel); ++ bool IsAttached() { return attached; } ++ }; ++ ++class cLiveBufferControl : public cControl { ++private: ++ cSkinDisplayReplay *displayReplay; ++ cLivePlayer *player; ++ bool visible, modeOnly, shown; ++ int lastCurrent, lastTotal; ++ bool lastPlay, lastForward; ++ int lastSpeed; ++ time_t timeoutShow; ++ void ShowTimed(int Seconds = 0); ++ void ShowMode(void); ++ bool ShowProgress(bool Initial); ++public: ++ cLiveBufferControl(cLivePlayer *Player); ++ ~cLiveBufferControl(); ++ bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); ++ bool GetReplayMode(bool &Play, bool &Forward, int &Speed); ++ virtual eOSState ProcessKey(eKeys Key); ++ virtual void Show(void); ++ virtual void Hide(void); ++ bool Visible(void) { return visible; } ++ }; ++ ++#define MAXLIVEBUFFERS 16 ++ ++class cLiveBufferManager { ++friend class cLiveBufferControl; ++private: ++ static cLiveReceiver* liveReceiver[MAXLIVEBUFFERS]; ++ static cLiveBuffer* liveBuffer[MAXLIVEBUFFERS]; ++ static cDevice* receiverDevice[MAXLIVEBUFFERS]; ++ static cLivePlayer* livePlayer; ++ static cLiveBufferControl* liveControl; ++public: ++ static void ChannelSwitch(cDevice *ReceiverDevice, const cChannel *Channel); ++ static void Shutdown(void); ++ static cLiveBufferControl *GetLiveBufferControl(void) { return liveControl; } ++ static cLiveBuffer *InLiveBuffer(cTimer *timer, int *StartFrame = NULL, int *EndFrame = NULL); ++ static int Impact(cDevice *device, const cChannel *Channel, bool LiveView); ++ static bool AllowsChannelSwitch(void); ++}; ++ ++#endif //__LIVEBUFFER_H +diff -ruNp vdr-1.7.0/mainmenuitemsprovider.h vdr-1.7.0-extensions/mainmenuitemsprovider.h +--- vdr-1.7.0/mainmenuitemsprovider.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/mainmenuitemsprovider.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,62 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MAINMENUITEMSPROVIDER_H ++#define __MAINMENUITEMSPROVIDER_H ++ ++#include <vector> ++ ++class cOsdItem; ++class cOsdMenu; ++ ++class IMenuItemDefinition ++{ ++ public: ++ virtual ~IMenuItemDefinition() {}; ++ virtual bool IsCustomOsdItem() = 0; ++ virtual bool IsPluginItem() = 0; ++ virtual bool IsSeparatorItem() = 0; ++ virtual cOsdItem* CustomOsdItem() = 0; ++ virtual const char* PluginMenuEntry() = 0; ++ virtual bool IsSelected() = 0; ++ virtual int PluginIndex() = 0; ++}; ++ ++typedef std::vector<IMenuItemDefinition*> MenuItemDefinitions; ++ ++#define MENU_ITEMS_PROVIDER_SERVICE_ID "MenuOrgPatch-v0.4.2::MainMenuItemsProvider" ++ ++class IMainMenuItemsProvider ++{ ++ public: ++ virtual ~IMainMenuItemsProvider() {}; ++ virtual bool IsCustomMenuAvailable() = 0; ++ virtual MenuItemDefinitions* MainMenuItems() = 0; ++ virtual void EnterRootMenu() = 0; ++ virtual void EnterSubMenu(cOsdItem* item) = 0; ++ virtual bool LeaveSubMenu() = 0; ++ virtual cOsdMenu* Execute(cOsdItem* item) = 0; ++}; ++ ++#endif //__MAINMENUITEMSPROVIDER_H ++#endif /* MENUORG */ +diff -ruNp vdr-1.7.0/Make.config.template vdr-1.7.0-extensions/Make.config.template +--- vdr-1.7.0/Make.config.template 2008-01-13 13:54:09.000000000 +0100 ++++ vdr-1.7.0-extensions/Make.config.template 2009-04-09 20:48:48.000000000 +0200 +@@ -41,8 +41,262 @@ RCU_DEVICE = /dev/ttyS1 + ## Define if you want vdr to not run as root + #VDR_USER = vdr + ++### VDR-Extensions: ++# Comment the patches you don't need ++# DVDCHAPJUMP needs DVDARCHIVE enabled ++# DVDARCHIVE needs LIEMIEXT enabled ++# SORTRECORDS needs LIEMIEXT enabled ++# you can only enable MENUORG or SETUP ++ ++#ANALOGTV = 1 ++#ATSC = 1 ++#CHANNELSCAN = 1 ++CMDRECCMDI18N = 1 ++CMDSUBMENU = 1 ++#CUTTERLIMIT = 1 ++#CUTTERQUEUE = 1 ++CUTTIME = 1 ++DDEPGENTRY = 1 ++#DELTIMESHIFTREC = 1 ++DOLBYINREC = 1 ++#DVBPLAYER = 1 ++#DVBSETUP = 1 ++#DVDARCHIVE = 1 ++#DVDCHAPJUMP = 1 ++#DVLFRIENDLYFNAMES = 1 ++#DVLRECSCRIPTADDON = 1 ++#DVLVIDPREFER = 1 ++#EM84XX = 1 ++#GRAPHTFT = 1 ++#HARDLINKCUTTER = 1 ++JUMPPLAY = 1 ++LIEMIEXT = 1 ++#LIRCSETTINGS = 1 ++#LIVEBUFFER = 1 ++#LNBSHARE = 1 ++#MAINMENUHOOKS = 1 ++#MENUORG = 1 ++#NOEPG = 1 ++#OSDMAXITEMS = 1 ++#PARENTALRATING = 1 ++#PINPLUGIN = 1 ++PLUGINAPI = 1 ++PLUGINMISSING = 1 ++#PLUGINPARAM = 1 ++#ROTOR = 1 ++SETTIME = 1 ++#SETUP = 1 ++#SOFTOSD = 1 ++#SOURCECAPS = 1 ++#SORTRECORDS = 1 ++#STREAMDEVEXT = 1 ++#SYNCEARLY = 1 ++#TIMERCMD = 1 ++#TIMERINFO = 1 ++#TTXTSUBS = 1 ++#VALIDINPUT = 1 ++#VOLCTRL = 1 ++WAREAGLEICON = 1 ++#YAEPG = 1 ++ + ### You don't need to touch the following: + + ifdef DVBDIR + INCLUDES += -I$(DVBDIR)/include + endif ++ ++ifdef ANALOGTV ++DEFINES += -DUSE_ANALOGTV ++endif ++ ++ifdef ATSC ++DEFINES += -DUSE_ATSC ++endif ++ ++ifdef CHANNELSCAN ++DEFINES += -DUSE_CHANNELSCAN ++endif ++ ++ifdef CMDRECCMDI18N ++DEFINES += -DUSE_CMDRECCMDI18N ++endif ++ ++ifdef CMDSUBMENU ++DEFINES += -DUSE_CMDSUBMENU ++endif ++ ++ifdef CUTTERLIMIT ++DEFINES += -DUSE_CUTTERLIMIT ++endif ++ ++ifdef CUTTERQUEUE ++DEFINES += -DUSE_CUTTERQUEUE ++endif ++ ++ifdef CUTTIME ++DEFINES += -DUSE_CUTTIME ++endif ++ ++ifdef DDEPGENTRY ++DEFINES += -DUSE_DDEPGENTRY ++endif ++ ++ifdef DELTIMESHIFTREC ++DEFINES += -DUSE_DELTIMESHIFTREC ++endif ++ ++ifdef DOLBYINREC ++DEFINES += -DUSE_DOLBYINREC ++endif ++ ++ifdef DVBPLAYER ++DEFINES += -DUSE_DVBPLAYER ++endif ++ ++ifdef DVBSETUP ++DEFINES += -DUSE_DVBSETUP ++endif ++ ++ifdef DVDARCHIVE ++ifdef LIEMIEXT ++DEFINES += -DUSE_DVDARCHIVE ++endif ++endif ++ ++ifdef DVLRECSCRIPTADDON ++DEFINES += -DUSE_DVLRECSCRIPTADDON ++endif ++ ++ifdef DVLVIDPREFER ++DEFINES += -DUSE_DVLVIDPREFER ++endif ++ ++ifdef DVLFRIENDLYFNAMES ++DEFINES += -DUSE_DVLFRIENDLYFNAMES ++endif ++ ++ifdef EM84XX ++DEFINES += -DUSE_EM84XX ++endif ++ ++ifdef GRAPHTFT ++DEFINES += -DUSE_GRAPHTFT ++endif ++ ++ifdef HARDLINKCUTTER ++DEFINES += -DUSE_HARDLINKCUTTER ++endif ++ ++ifdef JUMPPLAY ++DEFINES += -DUSE_JUMPPLAY ++endif ++ ++ifdef LIEMIEXT ++DEFINES += -DUSE_LIEMIEXT ++endif ++ ++ifdef LIRCSETTINGS ++DEFINES += -DUSE_LIRCSETTINGS ++endif ++ ++ifdef LIVEBUFFER ++DEFINES += -DUSE_LIVEBUFFER ++endif ++ ++ifdef LNBSHARE ++DEFINES += -DUSE_LNBSHARE ++endif ++ ++ifdef MAINMENUHOOKS ++DEFINES += -DUSE_MAINMENUHOOKS ++endif ++ ++ifdef MENUORG ++DEFINES += -DUSE_MENUORG ++else ++ifdef SETUP ++DEFINES += -DUSE_SETUP ++endif ++endif ++ ++ifdef NOEPG ++DEFINES += -DUSE_NOEPG ++endif ++ ++ifdef OSDMAXITEMS ++DEFINES += -DUSE_OSDMAXITEMS ++endif ++ ++ifdef PARENTALRATING ++DEFINES += -DUSE_PARENTALRATING ++endif ++ ++ifdef PINPLUGIN ++DEFINES += -DUSE_PINPLUGIN ++endif ++ ++ifdef PLUGINMISSING ++DEFINES += -DUSE_PLUGINMISSING ++endif ++ ++ifdef PLUGINPARAM ++DEFINES += -DUSE_PLUGINPARAM ++endif ++ ++ifdef ROTOR ++DEFINES += -DUSE_ROTOR ++endif ++ ++ifdef SETTIME ++DEFINES += -DUSE_SETTIME ++endif ++ ++ifdef SOFTOSD ++DEFINES += -DUSE_SOFTOSD ++endif ++ ++ifdef SOURCECAPS ++DEFINES += -DUSE_SOURCECAPS ++endif ++ ++ifdef SORTRECORDS ++ifdef LIEMIEXT ++DEFINES += -DUSE_SORTRECORDS ++endif ++endif ++ ++ifdef STREAMDEVEXT ++DEFINES += -DUSE_STREAMDEVEXT ++endif ++ ++ifdef SYNCEARLY ++DEFINES += -DUSE_SYNCEARLY ++endif ++ ++ifdef TIMERCMD ++DEFINES += -DUSE_TIMERCMD ++endif ++ ++ifdef TIMERINFO ++DEFINES += -DUSE_TIMERINFO ++endif ++ ++ifdef TTXTSUBS ++DEFINES += -DUSE_TTXTSUBS ++endif ++ ++ifdef VALIDINPUT ++DEFINES += -DUSE_VALIDINPUT ++endif ++ ++ifdef VOLCTRL ++DEFINES += -DUSE_VOLCTRL ++endif ++ ++ifdef WAREAGLEICON ++DEFINES += -DUSE_WAREAGLEICON ++endif ++ ++ifdef YAEPG ++DEFINES += -DUSE_YAEPG ++endif +diff -ruNp vdr-1.7.0/Makefile vdr-1.7.0-extensions/Makefile +--- vdr-1.7.0/Makefile 2008-02-29 22:43:03.000000000 +0100 ++++ vdr-1.7.0-extensions/Makefile 2009-04-09 20:48:48.000000000 +0200 +@@ -43,6 +43,22 @@ OBJS = audio.o channels.o ci.o config.o + skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\ + timers.o tools.o transfer.o vdr.o videodir.o + ++ifdef WAREAGLEICON ++OBJS += iconpatch.o ++endif ++ ++ifdef LIVEBUFFER ++OBJS += livebuffer.o ++endif ++ ++ifdef SETUP ++OBJS += tinystr.o tinyxml.o tinyxmlerror.o tinyxmlparser.o submenu.o ++endif ++ ++ifdef TTXTSUBS ++OBJS += vdrttxtsubshooks.o ++endif ++ + ifndef NO_KBD + DEFINES += -DREMOTE_KBD + endif +@@ -75,6 +91,14 @@ ifdef VFAT + DEFINES += -DVFAT + endif + ++ifdef DVDARCHIVE ++ifdef DVDCHAPJUMP ++LIBS += -ldvdread ++INCLUDES += -I/usr/include/dvdread ++DEFINES += -DUSE_DVDCHAPJUMP ++endif ++endif ++ + all: vdr i18n + + # Implicit rules: +@@ -140,6 +164,26 @@ include-dir: + + # Plugins: + ++ifdef PLUGINAPI ++DEFINES += -DUSE_PLUGINAPI ++plugins: include-dir ++ @failed="";\ ++ noapiv="";\ ++ for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do\ ++ echo "Plugin $$i:";\ ++ if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ ++ sed -i -e s/VDRVERSION/APIVERSION/g $(PLUGINDIR)/src/$$i/Makefile;\ ++ if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ ++ echo "ERROR: plugin $$i doesn't honor APIVERSION - not compiled!";\ ++ noapiv="$$noapiv $$i";\ ++ continue;\ ++ fi;\ ++ fi;\ ++ $(MAKE) -C "$(PLUGINDIR)/src/$$i" all || failed="$$failed $$i";\ ++ done;\ ++ if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ ++ if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; fi ++else + plugins: include-dir + @failed="";\ + noapiv="";\ +@@ -154,6 +198,7 @@ plugins: include-dir + done;\ + if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ + if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; exit 1; fi ++endif + + clean-plugins: + @for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/src/$$i" clean; done +diff -ruNp vdr-1.7.0/MANUAL vdr-1.7.0-extensions/MANUAL +--- vdr-1.7.0/MANUAL 2008-02-24 11:09:17.000000000 +0100 ++++ vdr-1.7.0-extensions/MANUAL 2009-04-09 20:48:48.000000000 +0200 +@@ -813,6 +813,30 @@ Version 1.6 + 0 resulting in a file named 'resume.vdr', and any other + value resulting in 'resume.n.vdr'. + ++ Jump&Play = no Turns playing on or off after jumping forward to the ++ next editing mark with the '9' key. ++ ++ Play&Jump = no Turns automatic jumping over commercial breaks on or ++ off. This includes jumping to the first mark, if the ++ replay starts at the beginning of a recording - and ++ stopping the replay at the last mark. ++ With this setting enabled, the behaviour of the '8' ++ key during replay is changed too. It moves the actual ++ replay position not only three seconds before the ++ next "start" mark, but also before the next "end" ++ mark. This can be used to test, if the editing marks ++ are correctly positioned for a "smooth" jump over a ++ commercial break. ++ ++ Pause at last mark = no ++ Turns pausing of replay at the last editing mark on or ++ off. ++ ++ Reload marks = no Turns reloading of editing marks on or off. This can ++ be used if an external programme adjusts the editing ++ marks, e.g. noad in online mode. The marks are reloaded ++ in 10 seconds intervals. ++ + Miscellaneous: + + Min. event timeout = 30 +diff -ruNp vdr-1.7.0/menu.c vdr-1.7.0-extensions/menu.c +--- vdr-1.7.0/menu.c 2008-04-12 13:37:17.000000000 +0200 ++++ vdr-1.7.0-extensions/menu.c 2009-04-09 20:48:48.000000000 +0200 +@@ -8,11 +8,17 @@ + */ + + #include "menu.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <limits.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> ++#ifdef USE_LIEMIEXT ++#include <math.h> ++#endif /* LIEMIEXT */ + #include "channels.h" + #include "config.h" + #include "cutter.h" +@@ -28,7 +34,17 @@ + #include "themes.h" + #include "timers.h" + #include "transfer.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + #include "videodir.h" ++#ifdef USE_MENUORG ++#include "menuorgpatch.h" ++#endif /* MENUORG */ ++ ++#ifdef USE_CMDRECCMDI18N ++extern const char *ConfigDirectory; ++#endif /* MENUORG */ + + #define MAXWAIT4EPGINFO 3 // seconds + #define MODETIMEOUT 3 // seconds +@@ -189,10 +205,16 @@ private: + cChannel *channel; + cChannel data; + char name[256]; ++#ifdef USE_PLUGINPARAM ++ char pluginParam[256]; ++#endif /* PLUGINPARAM */ + void Setup(void); + public: + cMenuEditChannel(cChannel *Channel, bool New = false); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEditChannel"; } ++#endif /* GRAPHTFT */ + }; + + cMenuEditChannel::cMenuEditChannel(cChannel *Channel, bool New) +@@ -221,6 +243,9 @@ void cMenuEditChannel::Setup(void) + + // Parameters for all types of sources: + strn0cpy(name, data.name, sizeof(name)); ++#ifdef USE_PLUGINPARAM ++ strn0cpy(pluginParam, data.pluginParam, sizeof(pluginParam)); ++#endif /* PLUGINPARAM */ + Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name))); + Add(new cMenuEditSrcItem( tr("Source"), &data.source)); + Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); +@@ -252,6 +277,9 @@ void cMenuEditChannel::Setup(void) + ST(" T") Add(new cMenuEditMapItem( tr("Transmission"), &data.transmission, TransmissionValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Guard"), &data.guard, GuardValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Hierarchy"), &data.hierarchy, HierarchyValues)); ++#ifdef USE_PLUGINPARAM ++ ST("P ") Add(new cMenuEditStrItem( tr("Parameters"), pluginParam, sizeof(pluginParam), tr(FileNameChars))); ++#endif /* PLUGINPARAM */ + ST(" T") Add(new cMenuEditMapItem( tr("Alpha"), &data.alpha, AlphaValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Priority"), &data.priority, PriorityValues)); + ST(" S ") Add(new cMenuEditMapItem( tr("Rolloff"), &data.rollOff, RollOffValues)); +@@ -269,9 +297,15 @@ eOSState cMenuEditChannel::ProcessKey(eK + if (Key == kOk) { + if (Channels.HasUniqueChannelID(&data, channel)) { + data.name = strcpyrealloc(data.name, name); ++#ifdef USE_PLUGINPARAM ++ data.pluginParam = strcpyrealloc(data.pluginParam, pluginParam); ++#endif /* PLUGINPARAM */ + if (channel) { + *channel = data; + isyslog("edited channel %d %s", channel->Number(), *data.ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scMod); ++#endif /* STREAMDEVEXT */ + state = osBack; + } + else { +@@ -280,6 +314,9 @@ eOSState cMenuEditChannel::ProcessKey(eK + Channels.Add(channel); + Channels.ReNumber(); + isyslog("added channel %d %s", channel->Number(), *data.ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scAdd); ++#endif /* STREAMDEVEXT */ + state = osUser1; + } + Channels.SetModified(true); +@@ -342,6 +379,16 @@ void cMenuChannelItem::Set(void) + if (!channel->GroupSep()) { + if (sortMode == csmProvider) + buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name()); ++#ifdef USE_WAREAGLEICON ++ else if (Setup.WarEagleIcons) { ++ if (channel->Vpid() == 1 || channel->Vpid() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_RADIO_UTF8 : ICON_RADIO, channel->Name()); ++ else if (channel->Ca() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_UTF8 : ICON_TV, channel->Name()); ++ else ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_CRYPTED_UTF8 : ICON_TV_CRYPTED, channel->Name()); ++ } ++#endif /* WAREAGLEICON */ + else + buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name()); + } +@@ -372,6 +419,9 @@ public: + cMenuChannels(void); + ~cMenuChannels(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuChannels"; } ++#endif /* GRAPHTFT */ + }; + + cMenuChannels::cMenuChannels(void) +@@ -501,6 +551,9 @@ eOSState cMenuChannels::Delete(void) + Propagate(); + Channels.SetModified(true); + isyslog("channel %d deleted", DeletedChannel); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NULL, scDel); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -526,6 +579,9 @@ void cMenuChannels::Move(int From, int T + Propagate(); + Channels.SetModified(true); + isyslog("channel %d moved to %d", FromNumber, ToNumber); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(ToChannel, scMod); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -638,14 +694,47 @@ cMenuEditTimer::cMenuEditTimer(cTimer *T + data.SetFlags(tfActive); + channel = data.Channel()->Number(); + Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive)); ++#ifdef USE_PINPLUGIN ++ if (cOsd::pinValid) Add(new cMenuEditChanItem(tr("Channel"), &channel)); ++ else { ++ cString buf = cString::sprintf("%s\t%s", tr("Channel"), Channels.GetByNumber(channel)->Name()); ++ Add(new cOsdItem(buf)); ++ } ++#else + Add(new cMenuEditChanItem(tr("Channel"), &channel)); ++#endif /* PINPLUGIN */ + Add(new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays)); + Add(new cMenuEditTimeItem(tr("Start"), &data.start)); + Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); + Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps)); + Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); ++#ifdef USE_PINPLUGIN ++ if (cOsd::pinValid || !data.fskProtection) Add(new cMenuEditBoolItem(tr("Childlock"),&data.fskProtection)); ++ else { ++ cString buf = cString::sprintf("%s\t%s", tr("Childlock"), data.fskProtection ? tr("yes") : tr("no")); ++ Add(new cOsdItem(buf)); ++ } ++#endif /* PINPLUGIN */ ++#ifdef USE_LIEMIEXT ++ char* p = strrchr(data.file, '~'); ++ if (p) { ++ p++; ++ Utf8Strn0Cpy(name, p, sizeof(name)); ++ Utf8Strn0Cpy(path, data.file, sizeof(path)); ++ p = strrchr(path, '~'); ++ if (p) ++ p[0] = 0; ++ } ++ else { ++ Utf8Strn0Cpy(name, data.file, sizeof(name)); ++ Utf8Strn0Cpy(path, "", sizeof(path)); ++ } ++ Add(new cMenuEditStrItem(tr("File"), name, sizeof(name), tr(FileNameChars))); ++ Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path))); ++#else + Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); ++#endif /* LIEMIEXT */ + SetFirstDayItem(); + } + Timers.IncBeingEdited(); +@@ -685,6 +774,12 @@ eOSState cMenuEditTimer::ProcessKey(eKey + Skins.Message(mtError, tr("*** Invalid Channel ***")); + break; + } ++#ifdef USE_LIEMIEXT ++ if (strlen(path)) ++ snprintf(data.file, sizeof(data.file), "%s~%s", path, name); ++ else ++ snprintf(data.file, sizeof(data.file), "%s", name); ++#endif /* LIEMIEXT */ + if (!*data.file) + strcpy(data.file, data.Channel()->ShortName(true)); + if (timer) { +@@ -712,13 +807,37 @@ eOSState cMenuEditTimer::ProcessKey(eKey + return state; + } + ++#ifdef USE_TIMERCMD ++// --- cMenuCommands --------------------------------------------------------- ++// declaration shifted so it can be used in cMenuTimers ++class cMenuCommands : public cOsdMenu { ++private: ++ cCommands *commands; ++ char *parameters; ++ eOSState Execute(void); ++public: ++ cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); ++ virtual ~cMenuCommands(); ++ virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCommands"; } ++#endif /* GRAPHTFT - passt das so? */ ++ }; ++#endif /* TIMERCMD */ ++ + // --- cMenuTimerItem -------------------------------------------------------- + + class cMenuTimerItem : public cOsdItem { + private: + cTimer *timer; ++#ifdef USE_TIMERINFO ++ char diskStatus; ++#endif /* TIMERINFO */ + public: + cMenuTimerItem(cTimer *Timer); ++#ifdef USE_TIMERINFO ++ void SetDiskStatus(char DiskStatus); ++#endif /* TIMERINFO */ + virtual int Compare(const cListObject &ListObject) const; + virtual void Set(void); + cTimer *Timer(void) { return timer; } +@@ -727,6 +846,9 @@ public: + cMenuTimerItem::cMenuTimerItem(cTimer *Timer) + { + timer = Timer; ++#ifdef USE_TIMERINFO ++ diskStatus = ' '; ++#endif /* TIMERINFO */ + Set(); + } + +@@ -752,8 +874,56 @@ void cMenuTimerItem::Set(void) + strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r); + day = buffer; + } ++#ifdef USE_LIEMIEXT ++ if (!Setup.ShowTimerStop) { ++#ifdef USE_TIMERINFO ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++ diskStatus, ++#else ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++#endif /* TIMERINFO */ ++#ifdef USE_WAREAGLEICON ++ !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", ++#else ++ !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', ++#endif /* WAREAGLEICON */ ++ timer->Channel()->Number(), ++ *name, ++ *name && **name ? " " : "", ++ *day, ++ timer->Start() / 100, ++ timer->Start() % 100, ++ timer->File())); ++ } ++ else { ++#endif /* LIEMIEXT */ ++#ifdef USE_TIMERINFO ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++ diskStatus, ++#else ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#else + SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++#endif /* TIMERINFO */ ++#ifdef USE_WAREAGLEICON ++ !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", ++#else + !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', ++#endif /* WAREAGLEICON */ + timer->Channel()->Number(), + *name, + *name && **name ? " " : "", +@@ -763,8 +933,64 @@ void cMenuTimerItem::Set(void) + timer->Stop() / 100, + timer->Stop() % 100, + timer->File())); ++#ifdef USE_LIEMIEXT ++ } ++#endif /* LIEMIEXT */ ++} ++ ++#ifdef USE_TIMERINFO ++void cMenuTimerItem::SetDiskStatus(char DiskStatus) ++{ ++ diskStatus = DiskStatus; ++ Set(); ++} ++ ++// --- cTimerEntry ----------------------------------------------------------- ++ ++class cTimerEntry : public cListObject { ++private: ++ cMenuTimerItem *item; ++ const cTimer *timer; ++ time_t start; ++public: ++ cTimerEntry(cMenuTimerItem *item) : item(item), timer(item->Timer()), start(timer->StartTime()) {} ++ cTimerEntry(const cTimer *timer, time_t start) : item(NULL), timer(timer), start(start) {} ++ virtual int Compare(const cListObject &ListObject) const; ++ bool active(void) const { return timer->HasFlags(tfActive); } ++ time_t startTime(void) const { return start; } ++ int priority(void) const { return timer->Priority(); } ++ int duration(void) const; ++ bool repTimer(void) const { return !timer->IsSingleEvent(); } ++ bool isDummy(void) const { return item == NULL; } ++ const cTimer *Timer(void) const { return timer; } ++ void SetDiskStatus(char DiskStatus); ++ }; ++ ++int cTimerEntry::Compare(const cListObject &ListObject) const ++{ ++ cTimerEntry *entry = (cTimerEntry *)&ListObject; ++ int r = startTime() - entry->startTime(); ++ if (r == 0) ++ r = entry->priority() - priority(); ++ return r; + } + ++int cTimerEntry::duration(void) const ++{ ++ int dur = (timer->Stop() / 100 * 60 + timer->Stop() % 100) - ++ (timer->Start() / 100 * 60 + timer->Start() % 100); ++ if (dur < 0) ++ dur += 24 * 60; ++ return dur; ++} ++ ++void cTimerEntry::SetDiskStatus(char DiskStatus) ++{ ++ if (item) ++ item->SetDiskStatus(DiskStatus); ++} ++#endif /* TIMERINFO */ ++ + // --- cMenuTimers ----------------------------------------------------------- + + class cMenuTimers : public cOsdMenu { +@@ -777,14 +1003,31 @@ private: + eOSState Info(void); + cTimer *CurrentTimer(void); + void SetHelpKeys(void); ++#ifdef USE_TIMERINFO ++ void ActualiseDiskStatus(void); ++ bool actualiseDiskStatus; ++#endif /* TIMERINFO */ ++#ifdef USE_TIMERCMD ++ eOSState Commands(eKeys Key = kNone); ++#endif /* TIMERCMD */ + public: + cMenuTimers(void); + virtual ~cMenuTimers(); ++#ifdef USE_TIMERINFO ++ virtual void Display(void); ++#endif /* TIMERINFO */ + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuTimers"; } ++#endif /* GRAPHTFT */ + }; + + cMenuTimers::cMenuTimers(void) ++#ifdef USE_TIMERINFO ++:cOsdMenu(tr("Timers"), 3, CHNUMWIDTH, 10, 6, 6) ++#else + :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6) ++#endif /* TIMERINFO */ + { + helpKeys = -1; + for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { +@@ -795,6 +1038,9 @@ cMenuTimers::cMenuTimers(void) + SetCurrent(First()); + SetHelpKeys(); + Timers.IncBeingEdited(); ++#ifdef USE_TIMERINFO ++ actualiseDiskStatus = true; ++#endif /* TIMERINFO */ + } + + cMenuTimers::~cMenuTimers() +@@ -833,7 +1079,11 @@ eOSState cMenuTimers::OnOff(void) + timer->OnOff(); + timer->SetEventFromSchedule(); + RefreshCurrent(); ++#ifdef USE_TIMERINFO ++ Display(); ++#else + DisplayCurrent(true); ++#endif /* TIMERINFO */ + if (timer->FirstDay()) + isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay()); + else +@@ -892,6 +1142,117 @@ eOSState cMenuTimers::Info(void) + return osContinue; + } + ++#ifdef USE_TIMERCMD ++#define CHECK_2PTR_NULL(x_,y_) ((x_)? ((y_)? y_:""):"") ++ ++eOSState cMenuTimers::Commands(eKeys Key) ++{ ++ if (HasSubMenu() || Count() == 0) ++ return osContinue; ++ cTimer *ti = CurrentTimer(); ++ if (ti) { ++ const cEvent *pEvent = ti->Event(); ++ int iRecNumber=0; ++ ++ if (!pEvent) { ++ Timers.SetEvents(); ++ pEvent = ti->Event(); ++ } ++ if (pEvent) { ++ // create a dummy recording to get the real filename ++ cRecording *rc_dummy = new cRecording(ti, pEvent); ++ Recordings.Load(); ++ cRecording *rc = Recordings.GetByName(rc_dummy->FileName()); ++ ++ delete rc_dummy; ++ if (rc) ++ iRecNumber=rc->Index() + 1; ++ } ++ // TODO: Geht das so...? ++ // Parameter format TimerNumber 'ChannelId' Start Stop 'Titel' 'Subtitel' 'file' RecNumer ++ // 1 2 3 4 5 6 7 8 ++ cString parameter = cString::sprintf("%d '%s' %d %d '%s' '%s' '%s' %d", ti->Index(), ++ *ti->Channel()->GetChannelID().ToString(), ++ (int)ti->StartTime(), ++ (int)ti->StopTime(), ++ CHECK_2PTR_NULL(pEvent, pEvent->Title()), ++ CHECK_2PTR_NULL(pEvent, pEvent->ShortText()), ++ ti->File(), ++ iRecNumber); ++ isyslog("timercmd: %s", *parameter); ++ cMenuCommands *menu; ++ eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Timer commands"), &TimerCommands, parameter)); ++ if (Key != kNone) ++ state = menu->ProcessKey(Key); ++ return state; ++ } ++ return osContinue; ++} ++#endif /* TIMERCMD */ ++ ++#ifdef USE_TIMERINFO ++void cMenuTimers::ActualiseDiskStatus(void) ++{ ++ if (!actualiseDiskStatus || !Count()) ++ return; ++ ++ // compute free disk space ++ int freeMB, freeMinutes, runshortMinutes; ++ VideoDiskSpace(&freeMB); ++ freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent ++ runshortMinutes = freeMinutes / 5; // 20 Percent ++ ++ // fill entries list ++ cTimerEntry *entry; ++ cList<cTimerEntry> entries; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ entries.Add(new cTimerEntry((cMenuTimerItem *)item)); ++ ++ // search last start time ++ time_t last = 0; ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ last = max(entry->startTime(), last); ++ ++ // add entries for repeating timers ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ if (entry->repTimer() && !entry->isDummy()) ++ for (time_t start = cTimer::IncDay(entry->startTime(), 1); ++ start <= last; ++ start = cTimer::IncDay(start, 1)) ++ if (entry->Timer()->DayMatches(start)) ++ entries.Add(new cTimerEntry(entry->Timer(), start)); ++ ++ // set the disk-status ++ entries.Sort(); ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) { ++ char status = ' '; ++ if (entry->active()) { ++ freeMinutes -= entry->duration(); ++ status = freeMinutes > runshortMinutes ? '+' : freeMinutes > 0 ? '~' /* ± 177 +/- */ : '-'; ++ } ++ entry->SetDiskStatus(status); ++#ifdef DEBUG_TIMER_INFO ++ dsyslog("timer-info: %c | %d | %s | %s | %3d | %+5d -> %+5d", ++ status, ++ entry->startTime(), ++ entry->active() ? "aktiv " : "n.akt.", ++ entry->repTimer() ? entry->isDummy() ? " dummy " : "mehrmalig" : "einmalig ", ++ entry->duration(), ++ entry->active() ? freeMinutes + entry->duration() : freeMinutes, ++ freeMinutes); ++#endif ++ } ++ ++ actualiseDiskStatus = false; ++} ++ ++void cMenuTimers::Display(void) ++{ ++ ActualiseDiskStatus(); ++ cOsdMenu::Display(); ++} ++#endif /* TIMERINFO */ ++ + eOSState cMenuTimers::ProcessKey(eKeys Key) + { + int TimerNumber = HasSubMenu() ? Count() : -1; +@@ -900,18 +1261,40 @@ eOSState cMenuTimers::ProcessKey(eKeys K + if (state == osUnknown) { + switch (Key) { + case kOk: return Edit(); ++#ifdef USE_TIMERINFO ++ case kRed: actualiseDiskStatus = true; ++ state = OnOff(); break; // must go through SetHelpKeys()! ++#else + case kRed: state = OnOff(); break; // must go through SetHelpKeys()! ++#endif /* TIMERINFO */ + case kGreen: return New(); ++#ifdef USE_TIMERINFO ++ case kYellow: actualiseDiskStatus = true; ++ state = Delete(); break; ++#else + case kYellow: state = Delete(); break; ++#endif /* TIMERINFO */ + case kInfo: + case kBlue: return Info(); + break; ++#ifdef USE_TIMERCMD ++ case k1...k9: return Commands(Key); ++ case k0: return (TimerCommands.Count()? Commands():osContinue); ++#endif /* TIMERCMD */ + default: break; + } + } ++#ifdef USE_TIMERINFO ++ if (TimerNumber >= 0 && !HasSubMenu()) { ++ if (Timers.Get(TimerNumber)) // a newly created timer was confirmed with Ok ++ Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++ Sort(); ++ actualiseDiskStatus = true; ++#else + if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) { + // a newly created timer was confirmed with Ok + Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++#endif /* TIMERINFO */ + Display(); + } + if (Key != kNone) +@@ -941,6 +1324,9 @@ void cMenuEvent::Display(void) + { + cOsdMenu::Display(); + DisplayMenu()->SetEvent(event); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetEvent(event); ++#endif /* GRAPHTFT */ + if (event->Description()) + cStatus::MsgOsdTextItem(event->Description()); + } +@@ -988,7 +1374,12 @@ public: + const cChannel *channel; + bool withDate; + int timerMatch; ++#ifdef USE_LIEMIEXT ++ bool withBar; ++ cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false, bool WithBar = false); ++#else + cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false); ++#endif /* LIEMIEXT */ + static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; } + static void IncSortMode(void) { sortMode = eScheduleSortMode((sortMode == ssmAllAll) ? ssmAllThis : sortMode + 1); } + static eScheduleSortMode SortMode(void) { return sortMode; } +@@ -998,12 +1389,19 @@ public: + + cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis; + ++#ifdef USE_LIEMIEXT ++cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate, bool WithBar) ++#else + cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate) ++#endif /* LIEMIEXT */ + { + event = Event; + channel = Channel; + withDate = WithDate; + timerMatch = tmNone; ++#ifdef USE_LIEMIEXT ++ withBar = WithBar; ++#endif /* LIEMIEXT */ + Update(true); + } + +@@ -1018,7 +1416,29 @@ int cMenuScheduleItem::Compare(const cLi + return r; + } + ++#ifdef USE_LIEMIEXT ++static const char * const ProgressBar[7] = ++{ ++ "[ ]", ++ "[| ]", ++ "[|| ]", ++ "[||| ]", ++ "[|||| ]", ++ "[||||| ]", ++ "[||||||]" ++}; ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_WAREAGLEICON ++static const char *TimerMatchChars[9] = ++{ ++ " ", "t", "T", ++ ICON_BLANK, ICON_CLOCK_UH, ICON_CLOCK, ++ ICON_BLANK_UTF8, ICON_CLOCK_UH_UTF8, ICON_CLOCK_UTF8 ++}; ++#else + static const char *TimerMatchChars = " tT"; ++#endif /* WAREAGLEICON */ + + bool cMenuScheduleItem::Update(bool Force) + { +@@ -1027,17 +1447,54 @@ bool cMenuScheduleItem::Update(bool Forc + Timers.GetMatch(event, &timerMatch); + if (Force || timerMatch != OldTimerMatch) { + cString buffer; ++#ifdef USE_WAREAGLEICON ++ const char *t = Setup.WarEagleIcons ? IsLangUtf8() ? TimerMatchChars[timerMatch+6] : TimerMatchChars[timerMatch+3] : TimerMatchChars[timerMatch]; ++ const char *v = event->Vps() && (event->Vps() - event->StartTime()) ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_VPS_UTF8 : ICON_VPS : "V" : " "; ++ const char *r = event->SeenWithin(30) && event->IsRunning() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_RUNNING_UTF8 : ICON_RUNNING : "*" : " "; ++#else + char t = TimerMatchChars[timerMatch]; + char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; + char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + const char *csn = channel ? channel->ShortName(true) : NULL; + cString eds = event->GetDateString(); + if (channel && withDate) ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + else if (channel) ++#ifdef USE_LIEMIEXT ++ if (Setup.ShowProgressBar && withBar) { ++ int progress = (int)roundf( (float)(time(NULL) - event->StartTime()) / (float)(event->Duration()) * 6.0 ); ++ if (progress < 0) progress = 0; ++ else if (progress > 6) progress = 6; ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++ } ++ else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#endif /* LIEMIEXT */ + else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%.*s\t%s\t%s%s%s\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + SetText(buffer); + result = true; + } +@@ -1063,13 +1520,21 @@ public: + static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } + static const cEvent *ScheduleEvent(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return now ? "MenuWhatsOnNow" : "MenuWhatsOnNext"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + int cMenuWhatsOn::currentChannel = 0; + const cEvent *cMenuWhatsOn::scheduleEvent = NULL; + + cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4, 4) ++#else + :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4) ++#endif /* LIEMIEXT */ + { + now = Now; + helpKeys = -1; +@@ -1081,7 +1546,11 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu + if (Schedule) { + const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); + if (Event) ++#ifdef USE_LIEMIEXT ++ Add(new cMenuScheduleItem(Event, Channel, false, Now), Channel->Number() == CurrentChannelNr); ++#else + Add(new cMenuScheduleItem(Event, Channel), Channel->Number() == CurrentChannelNr); ++#endif /* LIEMIEXT */ + } + } + } +@@ -1090,6 +1559,20 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu + SetHelpKeys(); + } + ++#ifdef USE_GRAPHTFT ++void cMenuWhatsOn::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) { ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++ } ++} ++#endif /* GRAPHTFT */ ++ + bool cMenuWhatsOn::Update(void) + { + bool result = false; +@@ -1230,6 +1713,10 @@ public: + cMenuSchedule(void); + virtual ~cMenuSchedule(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSchedule"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + cMenuSchedule::cMenuSchedule(void) +@@ -1255,6 +1742,20 @@ cMenuSchedule::~cMenuSchedule() + cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared + } + ++#ifdef USE_GRAPHTFT ++void cMenuSchedule::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) { ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++ } ++} ++#endif /* GRAPHTFT */ ++ + void cMenuSchedule::PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel) + { + Clear(); +@@ -1488,6 +1989,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys + + // --- cMenuCommands --------------------------------------------------------- + ++#ifndef USE_TIMERCMD + class cMenuCommands : public cOsdMenu { + private: + cCommands *commands; +@@ -1497,7 +1999,11 @@ public: + cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); + virtual ~cMenuCommands(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCommands"; } ++#endif /* GRAPHTFT */ + }; ++#endif /* TIMERCMD */ + + cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters) + :cOsdMenu(Title) +@@ -1519,6 +2025,12 @@ eOSState cMenuCommands::Execute(void) + cCommand *command = commands->Get(Current()); + if (command) { + bool confirmed = true; ++#ifdef USE_CMDSUBMENU ++ if (command->hasChilds()) { ++ AddSubMenu(new cMenuCommands(command->Title(), command->getChilds(), parameters)); ++ return osContinue; ++ } ++#endif /* CMDSUBMENU */ + if (command->Confirm()) + confirmed = Interface->Confirm(cString::sprintf("%s?", command->Title())); + if (confirmed) { +@@ -1569,6 +2081,9 @@ public: + cMenuCam(cCamSlot *CamSlot); + virtual ~cMenuCam(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuCam::cMenuCam(cCamSlot *CamSlot) +@@ -1748,6 +2263,9 @@ public: + cMenuRecording(const cRecording *Recording, bool WithButtons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRecording"; } ++#endif /* GRAPHTFT */ + }; + + cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons) +@@ -1763,6 +2281,9 @@ void cMenuRecording::Display(void) + { + cOsdMenu::Display(); + DisplayMenu()->SetRecording(recording); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetRecording(recording); ++#endif /* GRAPHTFT */ + if (recording->Info()->Description()) + cStatus::MsgOsdTextItem(recording->Info()->Description()); + } +@@ -1823,7 +2344,11 @@ cMenuRecordingItem::cMenuRecordingItem(c + fileName = strdup(Recording->FileName()); + name = NULL; + totalEntries = newEntries = 0; ++#ifdef USE_LIEMIEXT ++ SetText(Recording->Title('\t', true, Level, false)); ++#else + SetText(Recording->Title('\t', true, Level)); ++#endif /* LIEMIEXT */ + if (*Text() == '\t') + name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t' + } +@@ -1839,13 +2364,203 @@ void cMenuRecordingItem::IncrementCounte + totalEntries++; + if (New) + newEntries++; ++#ifdef USE_LIEMIEXT ++#ifdef USE_WAREAGLEICON ++ switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { ++ case 0: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s %s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, name)); ++ else ++ SetText(cString::sprintf("%s", name)); ++ break; ++ case 1: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s %d\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%s", totalEntries, name)); ++ break; ++ case 2: ++ default: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++ break; ++ case 3: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); ++ break; ++ } ++#else ++ switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { ++ case 0: ++ SetText(cString::sprintf("%s", name)); ++ break; ++ case 1: ++ SetText(cString::sprintf("%d\t%s", totalEntries, name)); ++ break; ++ case 2: ++ default: ++ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++ break; ++ case 3: ++ SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); ++ break; ++ } ++#endif /* WAREAGLEICON */ ++#else ++#ifdef USE_WAREAGLEICON ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++#endif /* WAREAGLEICON */ + SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++#endif /* LIEMIEXT */ + } + ++#ifdef USE_LIEMIEXT ++// --- cMenuRenameRecording -------------------------------------------------- ++ ++class cMenuRenameRecording : public cOsdMenu { ++private: ++ int lifetime; ++ int priority; ++ char name[MaxFileName]; ++ char path[MaxFileName]; ++ cOsdItem *marksItem, *resumeItem; ++ bool isResume, isMarks; ++ cRecording *recording; ++public: ++ cMenuRenameRecording(cRecording *Recording); ++ virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRenameRecording"; } ++#endif /* GRAPHTFT */ ++}; ++ ++cMenuRenameRecording::cMenuRenameRecording(cRecording *Recording) ++:cOsdMenu(tr("Rename recording"), 12) ++{ ++ cMarks marks; ++ ++ recording = Recording; ++ priority = recording->priority; ++ lifetime = recording->lifetime; ++ ++ char* p = strrchr(recording->Name(), '~'); ++ if (p) { ++ p++; ++ Utf8Strn0Cpy(name, p, sizeof(name)); ++ Utf8Strn0Cpy(path, recording->Name(), sizeof(path)); ++ p = strrchr(path, '~'); ++ if (p) ++ p[0] = 0; ++ } ++ else { ++ Utf8Strn0Cpy(name, recording->Name(), sizeof(name)); ++ Utf8Strn0Cpy(path, "", sizeof(path)); ++ } ++ Add(new cMenuEditStrItem(tr("Name"), name, sizeof(name), tr(FileNameChars))); ++ Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path) )); ++ Add(new cMenuEditIntItem(tr("Priority"), &priority, 0, MAXPRIORITY )); ++ Add(new cMenuEditIntItem(tr("Lifetime"), &lifetime, 0, MAXLIFETIME )); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Date"), *DayDateTime(recording->start)), osUnknown, false)); ++ ++ cChannel *channel = Channels.GetByChannelID(((cRecordingInfo *)recording->Info())->ChannelID()); ++ if (channel) ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Channel"), *ChannelString(channel, 0)), osUnknown, false)); ++ ++ cIndexFile *index = new cIndexFile(recording->FileName(), false); ++ int recLen = 0; ++ if (index) { ++ recLen = index->Last() / FRAMESPERSEC; ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Length"), *IndexToHMSF(index->Last())), osUnknown, false)); ++ delete index; ++ } ++ ++ int dirSize = DirSizeMB(recording->FileName()); ++ cString bitRate = recLen ? cString::sprintf(" (%.2f MBit/s)", 8.0 * dirSize / recLen) : cString(""); ++ Add(new cOsdItem((dirSize > 9999) ? cString::sprintf("%s:\t%.2f GB%s", tr("Size"), dirSize / 1024.0, *bitRate) : cString::sprintf("%s:\t%d MB%s", tr("Size"), dirSize, *bitRate), osUnknown, false)); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ isMarks = marks.Load(recording->FileName()) && marks.Count(); ++ marksItem = new cOsdItem(tr("Delete marks information?"), osUser1, isMarks); ++ Add(marksItem); ++ ++ cResumeFile ResumeFile(recording->FileName()); ++ isResume = (ResumeFile.Read() != -1); ++ resumeItem = new cOsdItem(tr("Delete resume information?"), osUser2, isResume); ++ Add(resumeItem); ++} ++ ++eOSState cMenuRenameRecording::ProcessKey(eKeys Key) ++{ ++ eOSState state = cOsdMenu::ProcessKey(Key); ++ ++ if (state == osUnknown) { ++ if (Key == kOk) { ++ char buffer[MaxFileName]; ++ if (Utf8StrLen(path)) ++ snprintf(buffer, sizeof(buffer), "%s~%s", path, name); ++ else ++ snprintf(buffer, sizeof(buffer), "%s", name); ++ if (recording->Rename(buffer, &priority, &lifetime)) { ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ return osRecordings; ++ } ++ else ++ Skins.Message(mtError, tr("Error while accessing recording!")); ++ } ++ return osContinue; ++ } ++ else if (state == osUser1) { ++ if (isMarks && Interface->Confirm(tr("Delete marks information?"))) { ++ cMarks marks; ++ marks.Load(recording->FileName()); ++ cMark *mark = marks.First(); ++ while (mark) { ++ cMark *nextmark = marks.Next(mark); ++ marks.Del(mark); ++ mark = nextmark; ++ } ++ marks.Save(); ++ isMarks = false; ++ marksItem->SetSelectable(isMarks); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ else if (state == osUser2) { ++ if (isResume && Interface->Confirm(tr("Delete resume information?"))) { ++ cResumeFile ResumeFile(recording->FileName()); ++ ResumeFile.Delete(); ++ isResume = false; ++ resumeItem->SetSelectable(isResume); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ return state; ++} ++#endif /* LIEMIEXT */ ++ + // --- cMenuRecordings ------------------------------------------------------- + + cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Base ? Base : tr("Recordings"), 9, 7, 7) ++#else + :cOsdMenu(Base ? Base : tr("Recordings"), 9, 7) ++#endif /* LIEMIEXT */ + { + base = Base ? strdup(Base) : NULL; + level = Setup.RecordingDirs ? Level : -1; +@@ -1922,7 +2637,12 @@ void cMenuRecordings::Set(bool Refresh) + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { + if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == '~')) { + cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); ++#ifdef USE_PINPLUGIN ++ if ((*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) ++ && (!cStatus::MsgReplayProtected(GetRecording(Item), Item->Name(), base, Item->IsDirectory(), true))) { ++#else + if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { ++#endif /* PINPLUGIN */ + Add(Item); + LastItem = Item; + free(LastItemText); +@@ -1972,13 +2692,43 @@ eOSState cMenuRecordings::Play(void) + { + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(GetRecording(ri), ri->Name(), base, ri->IsDirectory()) == true) ++ return osContinue; ++#endif /* PINPLUGIN */ + if (ri->IsDirectory()) + Open(); + else { + cRecording *recording = GetRecording(ri); + if (recording) { ++#ifdef USE_DVDARCHIVE ++ int mountRet = MOUNT_DVD_REPLAY; ++ if (recording->IsOnlyOnDvd()) { ++ mountRet = recording->MountDvd(); ++ } ++ if (mountRet == MOUNT_DVD_REPLAY) { ++ cReplayControl::SetRecording(recording->FileName(), recording->Title()); ++ return osReplay; ++ } ++ else if (mountRet == MOUNT_DVD_LAUNCH_DVD_PLUGIN) { ++ //launch DVD plugin here ++ cPlugin *p = cPluginManager::GetPlugin("dvd"); ++ cOsdObject *osd = NULL; ++ if (p) { ++ osd = p->MainMenuAction(); ++ delete osd; ++ osd = NULL; ++ return osEnd; ++ } ++ else { ++ Skins.Message(mtError, tr("DVD plugin is not installed!")); ++ Skins.Flush(); ++ } ++ } ++#else + cReplayControl::SetRecording(recording->FileName(), recording->Title()); + return osReplay; ++#endif /* DVDARCHIVE */ + } + } + } +@@ -2076,12 +2826,34 @@ eOSState cMenuRecordings::Commands(eKeys + return osContinue; + } + ++#ifdef USE_LIEMIEXT ++eOSState cMenuRecordings::Rename(void) ++{ ++ if (HasSubMenu() || Count() == 0) ++ return osContinue; ++ cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); ++ if (ri && !ri->IsDirectory()) { ++ cRecording *recording = GetRecording(ri); ++ if (recording) ++ return AddSubMenu(new cMenuRenameRecording(recording)); ++ } ++ return osContinue; ++} ++#endif /* LIEMIEXT */ ++ + eOSState cMenuRecordings::ProcessKey(eKeys Key) + { + bool HadSubMenu = HasSubMenu(); + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { ++#ifdef USE_SORTRECORDS ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ + switch (Key) { + case kPlay: + case kOk: return Play(); +@@ -2090,7 +2862,26 @@ eOSState cMenuRecordings::ProcessKey(eKe + case kYellow: return Delete(); + case kInfo: + case kBlue: return Info(); ++#ifdef USE_SORTRECORDS ++ case k0: Setup.RecordingsSortMode = ++Setup.RecordingsSortMode % MAXSORTMODES; ++ Set(true); ++ Skins.Message(mtStatus, cString::sprintf("%s %d: %s", tr("Sorting"), Setup.RecordingsSortMode, RecordingsSortModeTexts[Setup.RecordingsSortMode])); ++ return osContinue; ++ case k1...k7: return Commands(Key); ++ case k8: return Rename(); ++ case k9: Recordings.ToggleSortOrder(); ++ Set(true); ++ return osContinue; ++#elif defined (USE_LIEMIEXT) ++ case k0: DirOrderState = !DirOrderState; ++ Set(true); ++ return osContinue; ++ case k8: return Rename(); ++ case k9: ++ case k1...k7: return Commands(Key); ++#else + case k1...k9: return Commands(Key); ++#endif /* LIEMIEXT & SORTRECORDS */ + case kNone: if (Recordings.StateChanged(recordingsState)) + Set(true); + break; +@@ -2139,6 +2930,9 @@ void cMenuSetupBase::Store(void) + class cMenuSetupOSD : public cMenuSetupBase { + private: + const char *useSmallFontTexts[3]; ++#ifdef USE_LIEMIEXT ++ const char *mainMenuTitle[MAXMAINMENUTITLE]; ++#endif /* LIEMIEXT */ + int osdLanguageIndex; + int numSkins; + int originalSkinIndex; +@@ -2154,6 +2948,9 @@ public: + cMenuSetupOSD(void); + virtual ~cMenuSetupOSD(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupOsd"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupOSD::cMenuSetupOSD(void) +@@ -2189,12 +2986,21 @@ void cMenuSetupOSD::Set(void) + useSmallFontTexts[0] = tr("never"); + useSmallFontTexts[1] = tr("skin dependent"); + useSmallFontTexts[2] = tr("always"); ++#ifdef USE_LIEMIEXT ++ mainMenuTitle[0]=tr("default"); ++ mainMenuTitle[1]=tr("VDR - text"); ++ mainMenuTitle[2]=tr("text"); ++ mainMenuTitle[3]=tr("VDR - version"); ++#endif /* LIEMIEXT */ + Clear(); + SetSection(tr("OSD")); + Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0))); + Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions)); + if (themes.NumThemes()) + Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions())); ++#ifdef USE_WAREAGLEICON ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$WarEagle icons"), &data.WarEagleIcons)); ++#endif /* WAREAGLEICON */ + Add(new cMenuEditIntItem( tr("Setup.OSD$Left"), &data.OSDLeft, 0, MAXOSDWIDTH)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Top"), &data.OSDTop, 0, MAXOSDHEIGHT)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDWidth, MINOSDWIDTH, MAXOSDWIDTH)); +@@ -2216,6 +3022,24 @@ void cMenuSetupOSD::Set(void) + Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditStraItem(tr("Setup.OSD$Main menu title"), &data.MainMenuTitle, MAXMAINMENUTITLE, mainMenuTitle)); ++ if (data.MainMenuTitle == 1 || data.MainMenuTitle == 2) ++ Add(new cMenuEditStrItem(tr("Setup.OSD$- Text"), data.CustomMainMenuTitle, sizeof(data.CustomMainMenuTitle))); ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Main menu command position"), &data.MenuCmdPosition, tr("bottom"), tr("top"))); ++#endif /* LIEMIEXT */ ++#ifdef USE_VALIDINPUT ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Show valid input"), &data.ShowValidInput)); ++#endif /* VALIDINPUT */ ++#ifdef USE_SOFTOSD ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Use SoftOSD"), &data.UseSoftOsd)); ++ if (data.UseSoftOsd) { ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD Rate"), &data.SoftOsdRate, 10, 100)); ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeIn Steps"), &data.SoftOsdFadeinSteps, 1, 100)); ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeOut Steps"), &data.SoftOsdFadeoutSteps, 1, 100)); ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$SoftOSD Palette Only"), &data.SoftOsdPaletteOnly)); ++ } ++#endif /* SOFTOSD */ + SetCurrent(Get(current)); + Display(); + } +@@ -2264,6 +3088,12 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + + int oldSkinIndex = skinIndex; + int oldOsdLanguageIndex = osdLanguageIndex; ++#ifdef USE_LIEMIEXT ++ int oldMainMenuTitle = data.MainMenuTitle; ++#endif /* LIEMIEXT */ ++#ifdef USE_SOFTOSD ++ bool newUseSoftOsd = data.UseSoftOsd; ++#endif /* SOFTOSD */ + eOSState state = cMenuSetupBase::ProcessKey(Key); + + if (ModifiedApperance) +@@ -2286,6 +3116,25 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + Set(); + I18nSetLanguage(OriginalOSDLanguage); + } ++ ++#ifdef USE_LIEMIEXT ++ if (data.MainMenuTitle != oldMainMenuTitle) ++ Set(); ++#endif /* LIEMIEXT */ ++#ifdef USE_SOFTOSD ++ if (data.UseSoftOsd != newUseSoftOsd) ++ Set(); ++#endif /* SOFTOSD */ ++#ifdef USE_CMDRECCMDI18N ++ if (Key == kOk) { ++ // try to load translated command files if available, otherwise fallback to defaults ++ LoadCommandsI18n(Commands,AddDirectory(ConfigDirectory, "commands.conf"), true); ++ LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory,"reccmds.conf"), true); ++#ifdef USE_TIMERCMD ++ LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true); ++#endif /* TIMERCMD */ ++ } ++#endif /* CMDRECCMDI18N */ + return state; + } + +@@ -2293,12 +3142,18 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + + class cMenuSetupEPG : public cMenuSetupBase { + private: ++#ifdef USE_NOEPG ++ const char *noEPGModes[2]; ++#endif /* NOEPG */ + int originalNumLanguages; + int numLanguages; + void Setup(void); + public: + cMenuSetupEPG(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupEpg"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupEPG::cMenuSetupEPG(void) +@@ -2315,11 +3170,19 @@ void cMenuSetupEPG::Setup(void) + { + int current = Current(); + ++#ifdef USE_NOEPG ++ noEPGModes[0] = tr("Blacklist"); ++ noEPGModes[1] = tr("Whitelist"); ++#endif /* NOEPG */ ++ + Clear(); + + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Show progress bar"), &data.ShowProgressBar)); ++#endif /* LIEMIEXT */ + Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); + if (data.SetSystemTime) + Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource)); +@@ -2328,6 +3191,15 @@ void cMenuSetupEPG::Setup(void) + for (int i = 0; i < numLanguages; i++) + // TRANSLATORS: note the singular! + Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); ++#ifdef USE_DDEPGENTRY ++ Add(new cMenuEditIntItem( tr("Setup.EPG$Period for double EPG search(min)"), &data.DoubleEpgTimeDelta)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Extern double Epg entry"), &data.DoubleEpgAction, tr("adjust"), tr("delete"))); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Mix intern and extern EPG"), &data.MixEpgAction)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Disable running VPS event"), &data.DisableVPS)); ++#endif /* DDEPGENTRY */ ++#ifdef USE_NOEPG ++ Add(new cMenuEditStraItem(tr("Setup.EPG$Mode of noEPG-Patch"), &data.noEPGMode, 2, noEPGModes)); ++#endif /* NOEPG */ + + SetCurrent(Get(current)); + Display(); +@@ -2384,6 +3256,10 @@ eOSState cMenuSetupEPG::ProcessKey(eKeys + + class cMenuSetupDVB : public cMenuSetupBase { + private: ++#ifdef USE_DVBSETUP ++ const char *ChannelBlockers[7]; ++ const char *ChannelBlockerModes[4]; ++#endif /* DVBSETUP */ + int originalNumAudioLanguages; + int numAudioLanguages; + int originalNumSubtitleLanguages; +@@ -2394,6 +3270,9 @@ private: + public: + cMenuSetupDVB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupDvb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupDVB::cMenuSetupDVB(void) +@@ -2422,6 +3301,21 @@ void cMenuSetupDVB::Setup(void) + { + int current = Current(); + ++#ifdef USE_DVBSETUP ++ ChannelBlockers[0] = tr("none"); ++ ChannelBlockers[1] = tr("qam256"); ++ ChannelBlockers[2] = tr("dvb-c"); ++ ChannelBlockers[3] = tr("dvb-s"); ++ ChannelBlockers[4] = tr("blacklist"); ++ ChannelBlockers[5] = tr("whitelist"); ++ ChannelBlockers[6] = tr("all"); ++ ++ ChannelBlockerModes[0] = tr("none"); ++ ChannelBlockerModes[1] = tr("has decoder"); ++ ChannelBlockerModes[2] = tr("is primary"); ++ ChannelBlockerModes[3] = tr("has decoder + is primary"); ++#endif /* DVBSETUP */ ++ + Clear(); + + Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices())); +@@ -2442,6 +3336,14 @@ void cMenuSetupDVB::Setup(void) + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9)); + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10)); + } ++#ifdef USE_DVBSETUP ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$Use AC3-Transfer Fix"), &data.DolbyTransferFix)); ++ Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker"), &data.ChannelBlocker, 7, ChannelBlockers)); ++ Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker Filter Mode"), &data.ChannelBlockerMode, 4, ChannelBlockerModes)); ++#endif /* DVBSETUP */ ++#ifdef USE_SYNCEARLY ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Sync Early Patch"), &data.UseSyncEarlyPatch)); ++#endif /* SYNCEARLY */ + + SetCurrent(Get(current)); + Display(); +@@ -2523,6 +3425,9 @@ private: + public: + cMenuSetupLNB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupLnb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupLNB::cMenuSetupLNB(void) +@@ -2537,6 +3442,23 @@ void cMenuSetupLNB::Setup(void) + + Clear(); + ++#ifdef USE_LNBSHARE ++ int numSatDevices = 0; ++ for (int i = 0; i < cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat)) numSatDevices++; ++ } ++ if (numSatDevices > 1) { ++ char tmp[30]; ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i - 1)->ProvidesSource(cSource::stSat)) { ++ sprintf( tmp, tr("Setup.LNB$DVB device %d uses LNB No."), i); ++ Add(new cMenuEditIntItem( tmp, &data.CardUsesLNBnr[i - 1], 1, numSatDevices )); ++ } ++ } ++ } ++ Add(new cMenuEditBoolItem(tr("Setup.LNB$Log LNB usage"), &data.VerboseLNBlog)); ++#endif /* LNBSHARE */ ++ + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); + if (!data.DiSEqC) { + Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); +@@ -2553,6 +3475,10 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys + int oldDiSEqC = data.DiSEqC; + eOSState state = cMenuSetupBase::ProcessKey(Key); + ++#ifdef USE_LNBSHARE ++ if (Key == kOk) cDevice::SetLNBnr(); ++#endif /* LNBSHARE */ ++ + if (Key != kNone && data.DiSEqC != oldDiSEqC) + Setup(); + return state; +@@ -2603,6 +3529,9 @@ private: + public: + cMenuSetupCAM(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupCAM::cMenuSetupCAM(void) +@@ -2676,12 +3605,73 @@ eOSState cMenuSetupCAM::ProcessKey(eKeys + // --- cMenuSetupRecord ------------------------------------------------------ + + class cMenuSetupRecord : public cMenuSetupBase { ++#ifdef USE_SORTRECORDS ++private: ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++#endif /* SORTRECORDS */ ++#ifdef USE_DELTIMESHIFTREC ++private: ++ const char *DelTimeshiftRecValues[3]; ++#endif /* DELTIMESHIFTREC */ + public: + cMenuSetupRecord(void); ++#ifdef USE_DVLVIDPREFER ++ eOSState ProcessKey(eKeys key); ++ ++private: ++ void Set(void); ++ ++ int tmpNVidPrefer, ++ tmpUseVidPrefer; ++#endif /* DVLVIDPREFER */ + }; + ++#ifdef USE_DVLVIDPREFER + cMenuSetupRecord::cMenuSetupRecord(void) + { ++ Set(); ++} ++ ++eOSState cMenuSetupRecord::ProcessKey(eKeys key) ++{ ++ eOSState s = cMenuSetupBase::ProcessKey(key);; ++ ++ if (key != kNone) { ++ if (tmpNVidPrefer != data.nVidPrefer || tmpUseVidPrefer != data.UseVidPrefer) { ++ int cur = Current(); ++ ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Clear(); ++ Set(); ++ SetCurrent(Get(cur)); ++ Display(); ++ cMenuSetupBase::ProcessKey(kNone); ++ return osContinue; ++ } ++ } ++ return s; ++} ++ ++#else ++cMenuSetupRecord::cMenuSetupRecord(void) ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLVIDPREFER ++void cMenuSetupRecord::Set(void) ++#endif /* DVLVIDPREFER */ ++{ ++#ifdef USE_SORTRECORDS ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ ++#ifdef USE_DELTIMESHIFTREC ++ DelTimeshiftRecValues[0] = tr("request"); ++ DelTimeshiftRecValues[1] = tr("no"); ++ DelTimeshiftRecValues[2] = tr("yes"); ++#endif /* DELTIMESHIFTREC */ + SetSection(tr("Recording")); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop)); +@@ -2690,14 +3680,61 @@ cMenuSetupRecord::cMenuSetupRecord(void) + Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME)); ++#ifdef USE_DOLBYINREC ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.UseDolbyInRecordings)); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVLVIDPREFER ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Video directory policy"), &data.UseVidPrefer)); ++ if (data.UseVidPrefer != 0) { ++ char tmp[ 64 ]; ++ Add(new cMenuEditIntItem(tr("Setup.Recording$Number of video directories"), &data.nVidPrefer, 1, DVLVIDPREFER_MAX)); ++ for (int zz = 0; zz < data.nVidPrefer; zz++) { ++ sprintf(tmp, tr("Setup.Recording$Video %d priority"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferPrio[ zz ], 0, 99)); ++ sprintf(tmp, tr("Setup.Recording$Video %d min. free MB"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferSize[ zz ], -1, 99999)); ++ } ++ } ++#endif /* DVLVIDPREFER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); ++#ifdef USE_DVLFRIENDLYFNAMES ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Friendly filenames"), &data.UseFriendlyFNames)); ++#endif /* DVLFRIENDLYFNAMES */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps)); + Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord))); + Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); ++#ifdef USE_HARDLINKCUTTER ++ Add(new cMenuEditIntItem( tr("Setup.Recording$Max. recording size (GB)"), &data.MaxRecordingSize, MINRECORDINGSIZE, MAXRECORDINGSIZE)); ++#endif /* HARDLINKCUTTER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); ++#ifdef USE_HARDLINKCUTTER ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Hard Link Cutter"), &data.HardLinkCutter)); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"), &data.DelTimeshiftRec, 3, DelTimeshiftRecValues)); ++#endif /* DELTIMESHIFTREC */ ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show date"), &data.ShowRecDate)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show time"), &data.ShowRecTime)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show length"), &data.ShowRecLength)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show end of timer"), &data.ShowTimerStop)); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ Add(new cMenuEditStraItem(tr("Setup.Recording$Sort recordings by"), &data.RecordingsSortMode, MAXSORTMODES, RecordingsSortModeTexts)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Sort directories before recordings"), &data.RecordingsSortDirsFirst)); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter auto delete"), &data.CutterAutoDelete)); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter adjust starttime"), &data.CutTime)); ++#endif /* CUTTIME */ + } + + // --- cMenuSetupReplay ------------------------------------------------------ +@@ -2715,6 +3752,31 @@ cMenuSetupReplay::cMenuSetupReplay(void) + Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); + Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99)); ++#ifdef USE_JUMPPLAY ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Jump&Play"), &data.JumpPlay)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Play&Jump"), &data.PlayJump)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause at last mark"), &data.PauseLastMark)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Reload marks"), &data.ReloadMarks)); ++#endif /* JUMPPLAY */ ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds"), &data.JumpSeconds)); ++ Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds Slow"), &data.JumpSecondsSlow)); ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++ static const char *dvddisplaymode[3]; ++ dvddisplaymode[0]=tr("Setup.Replay$Length"); ++ dvddisplaymode[1]=tr("Setup.Replay$Length / Number"); ++ dvddisplaymode[2]=tr("Setup.Replay$Number"); ++ Add(new cMenuEditStraItem(tr("Setup.Replay$DVD display mode"), &data.DvdDisplayMode,3,dvddisplaymode)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$DVD display leading zeros"), &data.DvdDisplayZeros)); ++ static const char *dvdtraymode[4]; ++ dvdtraymode[0]=tr("Setup.Replay$never"); ++ dvdtraymode[1]=tr("Setup.Replay$on begin"); ++ dvdtraymode[2]=tr("Setup.Replay$on end"); ++ dvdtraymode[3]=tr("Setup.Replay$on begin and end"); ++ Add(new cMenuEditStraItem(tr("Setup.Replay$Tray open"), &data.DvdTrayMode,4,dvdtraymode)); ++ Add(new cMenuEditIntItem( tr("Setup.Replay$Limit DVD to speed"), &data.DvdSpeedLimit, 0, 50)); ++#endif /* DVDARCHIVE */ + } + + void cMenuSetupReplay::Store(void) +@@ -2727,13 +3789,48 @@ void cMenuSetupReplay::Store(void) + // --- cMenuSetupMisc -------------------------------------------------------- + + class cMenuSetupMisc : public cMenuSetupBase { ++#ifdef USE_VOLCTRL ++private: ++ const char *lrChannelGroupsTexts[3]; ++ const char *lrForwardRewindTexts[3]; ++ void Setup(void); ++#endif /* VOLCTRL */ + public: + cMenuSetupMisc(void); ++#ifdef USE_VOLCTRL ++ virtual eOSState ProcessKey(eKeys Key); ++#endif /* VOLCTRL */ + }; + + cMenuSetupMisc::cMenuSetupMisc(void) + { ++#ifdef USE_VOLCTRL ++ lrChannelGroupsTexts[0] = tr("no"); ++ lrChannelGroupsTexts[1] = tr("Setup.Miscellaneous$only in channelinfo"); ++ lrChannelGroupsTexts[2] = tr("yes"); ++ lrForwardRewindTexts[0] = tr("no"); ++ lrForwardRewindTexts[1] = tr("Setup.Miscellaneous$only in progress display"); ++ lrForwardRewindTexts[2] = tr("yes"); ++#endif /* VOLCTRL */ + SetSection(tr("Miscellaneous")); ++#ifdef USE_VOLCTRL ++ Setup(); ++} ++ ++eOSState cMenuSetupMisc::ProcessKey(eKeys Key) ++{ ++ int newLRVolumeControl = data.LRVolumeControl; ++ eOSState state = cMenuSetupBase::ProcessKey(Key); ++ if (Key != kNone && data.LRVolumeControl != newLRVolumeControl) ++ Setup(); ++ return state; ++} ++ ++void cMenuSetupMisc::Setup(void) ++{ ++ int current = Current(); ++ Clear(); ++#endif /* VOLCTRL */ + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); +@@ -2741,9 +3838,77 @@ cMenuSetupMisc::cMenuSetupMisc(void) + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0)); + Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before"))); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before"))); ++#ifdef USE_VOLCTRL ++ Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Volume ctrl with left/right"), &data.LRVolumeControl)); ++ if (data.LRVolumeControl) { ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Channelgroups with left/right"), &data.LRChannelGroups, 3, lrChannelGroupsTexts)); ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Search fwd/back with left/right"), &data.LRForwardRewind, 3, lrForwardRewindTexts)); ++ } ++ SetCurrent(Get(current)); ++ Display(); ++#endif /* VOLCTRL */ + Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit)); ++#ifdef USE_LIRCSETTINGS ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat delay"), &data.LircRepeatDelay, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat freq"), &data.LircRepeatFreq, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat timeout"), &data.LircRepeatTimeout, 0, 5000)); ++#endif /* LIRCSETTINGS */ ++} ++ ++#ifdef USE_LIVEBUFFER ++// --- cMenuSetupLiveBuffer -------------------------------------------------- ++ ++class cMenuSetupLiveBuffer : public cMenuSetupBase { ++private: ++ void Setup(); ++public: ++ eOSState ProcessKey(eKeys Key); ++ cMenuSetupLiveBuffer(void); ++ }; ++ ++cMenuSetupLiveBuffer::cMenuSetupLiveBuffer(void) ++{ ++ SetSection("permanentes Timeshift"); ++ Setup(); + } + ++void cMenuSetupLiveBuffer::Setup(void) ++{ ++ int current=Current(); ++ Clear(); ++ Add(new cMenuEditBoolItem(tr("Permanent Timeshift"), &data.LiveBuffer)); ++ if (data.LiveBuffer) { ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Location"), &data.InRAM,tr("Setup.LiveBuffer$harddisk"),tr("Setup.LiveBuffer$memory"))); ++ if (data.InRAM) { ++ Add(new cMenuEditIntItem( tr("Setup.LiveBuffer$Buffer size in memory (MB)"), &data.MemBufSize, 5, 1000)); ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Extend to harddisk if necessary"), &data.ExtendBuffer)); ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Keep paused Buffer"), &data.KeepPaused)); ++ if (data.ExtendBuffer || data.KeepPaused) ++ Add(new cMenuEditIntItem(tr("Setup.LiveBuffer$Buffer size on harddisk (MB)"), &data.LiveBufferSize, 1, 100000)); ++ } ++ else { ++ Add(new cMenuEditIntItem( tr("Setup.LiveBuffer$Buffer size (MB)"), &data.LiveBufferSize, 1, 100000)); ++ Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Keep paused Buffer"), &data.KeepPaused)); ++ } ++ } ++ SetCurrent(Get(current)); ++ Display(); ++} ++ ++eOSState cMenuSetupLiveBuffer::ProcessKey(eKeys Key) ++{ ++ int oldLiveBuffer = data.LiveBuffer; ++ int oldInRAM = data.InRAM; ++ int oldExtendBuffer = data.ExtendBuffer; ++ int oldKeepPaused = data.KeepPaused; ++ eOSState state = cMenuSetupBase::ProcessKey(Key); ++ ++ if (Key != kNone && (data.LiveBuffer != oldLiveBuffer || data.InRAM != oldInRAM || data.ExtendBuffer != oldExtendBuffer || data.KeepPaused != oldKeepPaused)) ++ Setup(); ++ return state; ++} ++ ++#endif /* LIVEBUFFER */ + // --- cMenuSetupPluginItem -------------------------------------------------- + + class cMenuSetupPluginItem : public cOsdItem { +@@ -2766,6 +3931,9 @@ class cMenuSetupPlugins : public cMenuSe + public: + cMenuSetupPlugins(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupPlugins"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupPlugins::cMenuSetupPlugins(void) +@@ -2815,6 +3983,9 @@ private: + public: + cMenuSetup(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetup"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetup::cMenuSetup(void) +@@ -2838,6 +4009,9 @@ void cMenuSetup::Set(void) + Add(new cOsdItem(hk(tr("Recording")), osUser6)); + Add(new cOsdItem(hk(tr("Replay")), osUser7)); + Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8)); ++#ifdef USE_LIVEBUFFER ++ Add(new cOsdItem(hk(tr("Permanent Timeshift")),osLiveBuffer)); ++#endif /* LIVEBUFFER */ + if (cPluginManager::HasPlugins()) + Add(new cOsdItem(hk(tr("Plugins")), osUser9)); + Add(new cOsdItem(hk(tr("Restart")), osUser10)); +@@ -2868,6 +4042,9 @@ eOSState cMenuSetup::ProcessKey(eKeys Ke + case osUser8: return AddSubMenu(new cMenuSetupMisc); + case osUser9: return AddSubMenu(new cMenuSetupPlugins); + case osUser10: return Restart(); ++#ifdef USE_LIVEBUFFER ++ case osLiveBuffer: return AddSubMenu(new cMenuSetupLiveBuffer); ++#endif /* LIVEBUFFER */ + default: ; + } + if (I18nCurrentLanguage() != osdLanguage) { +@@ -2904,24 +4081,91 @@ cOsdObject *cMenuMain::pluginOsdObject = + cMenuMain::cMenuMain(eOSState State) + :cOsdMenu("") + { ++#ifdef USE_SETUP ++ // Load Menu Configuration ++ char *menuXML = NULL; ++ asprintf(&menuXML, "%s/setup/vdr-menu.%s.xml", cPlugin::ConfigDirectory(), Setup.OSDLanguage); ++ if (access(menuXML, 04) == -1) ++ asprintf(&menuXML, "%s/setup/vdr-menu.xml", cPlugin::ConfigDirectory()); ++ subMenu.LoadXml(menuXML); ++ free(menuXML); ++ nrDynamicMenuEntries=0; ++#endif /* SETUP */ + replaying = false; + stopReplayItem = NULL; + cancelEditingItem = NULL; + stopRecordingItem = NULL; + recordControlsState = 0; ++ ++#ifdef USE_MENUORG ++ MenuOrgPatch::EnterRootMenu(); ++#endif /* MENUORG */ ++ + Set(); + + // Initial submenus: + ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ + switch (State) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuSchedule; ++ } ++ break; ++ case osChannels: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuChannels; ++ } ++ break; ++ case osTimers: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuTimers; ++ } ++ break; ++ case osRecordings: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuRecordings(NULL, 0, true); ++ } ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: AddSubMenu(new cMenuSchedule); break; + case osChannels: AddSubMenu(new cMenuChannels); break; + case osTimers: AddSubMenu(new cMenuTimers); break; + case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; + case osSetup: AddSubMenu(new cMenuSetup); break; + case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break; ++#endif /* MAINMENUHOOKS */ + default: break; + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + } + + cOsdObject *cMenuMain::PluginOsdObject(void) +@@ -2931,38 +4175,155 @@ cOsdObject *cMenuMain::PluginOsdObject(v + return o; + } + ++#ifdef USE_SETUP ++void cMenuMain::Set(int current) ++#else + void cMenuMain::Set(void) ++#endif /* SETUP */ + { + Clear(); + SetTitle("VDR"); + SetHasHotkeys(); + ++#ifdef USE_MENUORG ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuItemDefinitions* menuItems = MenuOrgPatch::MainMenuItems(); ++ for (MenuItemDefinitions::iterator i = menuItems->begin(); i != menuItems->end(); i++) { ++ cOsdItem* osdItem = NULL; ++ if ((*i)->IsCustomOsdItem()) { ++ osdItem = (*i)->CustomOsdItem(); ++ if (osdItem && !(*i)->IsSeparatorItem()) ++ osdItem->SetText(hk(osdItem->Text())); ++ } ++ else if ((*i)->IsPluginItem()) { ++ const char *item = (*i)->PluginMenuEntry(); ++ if (item) ++ osdItem = new cMenuPluginItem(hk(item), (*i)->PluginIndex()); ++ } ++ if (osdItem) { ++ Add(osdItem); ++ if ((*i)->IsSelected()) ++ SetCurrent(osdItem); ++ } ++ } ++ } ++ else { ++#endif /* MENUORG */ ++ ++#ifdef USE_SETUP ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ ++ // remember initial dynamic MenuEntries added ++ nrDynamicMenuEntries = Count(); ++ for (cSubMenuNode *node = subMenu.GetMenuTree()->First(); node; node = subMenu.GetMenuTree()->Next(node)) { ++ cSubMenuNode::Type type = node->GetType(); ++ if (type==cSubMenuNode::PLUGIN) { ++ const char *item = node->GetPluginMainMenuEntry(); ++#ifdef USE_PINPLUGIN ++ if (item && !cStatus::MsgPluginProtected(cPluginManager::GetPlugin(node->GetPluginIndex()), true)) ++#else ++ if (item) ++#endif /* PINPLUGIN */ ++ Add(new cMenuPluginItem(hk(item), node->GetPluginIndex())); ++ } ++ else if (type==cSubMenuNode::MENU) { ++ cString item = cString::sprintf("%s%s", node->GetName(), subMenu.GetMenuSuffix()); ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(item, true)) ++ Add(new cOsdItem(hk(item), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(item))); ++#endif /* PINPLUGIN */ ++ } ++ else if ((type==cSubMenuNode::COMMAND) || (type==cSubMenuNode::THREAD)) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(node->GetName(), true)) ++ Add(new cOsdItem(hk(node->GetName()), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(node->GetName()))); ++#endif /* PINPLUGIN */ ++ } ++ else if (type==cSubMenuNode::SYSTEM) { ++ const char *item = node->GetName(); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgMenuItemProtected(item, true)) ++ ; // nothing to do ;) ++ else ++#endif /* PINPLUGIN */ ++ if (strcmp(item, "Schedule") == 0) ++ Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ else if (strcmp(item, "Channels") == 0) ++ Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ else if (strcmp(item, "Timers") == 0) ++ Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ else if (strcmp(item, "Recordings") == 0) ++ Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++ else if (strcmp(item, "Setup") == 0) ++ Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++ else if (strcmp(item, "Commands") == 0 && Commands.Count()>0) ++ Add(new cOsdItem(hk(tr("Commands")), osCommands)); ++ } ++ } ++ if (current >=0 && current<Count()) { ++ SetCurrent(Get(current)); ++ } ++ ++#else /* NO SETUP */ ++ + // Basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Schedule", true)) Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ if (!cStatus::MsgMenuItemProtected("Channels", true)) Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ if (!cStatus::MsgMenuItemProtected("Timers", true)) Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ if (!cStatus::MsgMenuItemProtected("Recordings", true)) Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#else + Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); + Add(new cOsdItem(hk(tr("Channels")), osChannels)); + Add(new cOsdItem(hk(tr("Timers")), osTimers)); + Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#endif /* PINPLUGIN */ + + // Plugins: + + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p, true)) { ++#endif /* PINPLUGIN */ + const char *item = p->MainMenuEntry(); + if (item) + Add(new cMenuPluginItem(hk(item), i)); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + break; + } + + // More basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Setup", true)) Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#else + Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#endif /* PINPLUGIN */ + if (Commands.Count()) ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Commands", true)) ++#endif /* PINPLUGIN */ + Add(new cOsdItem(hk(tr("Commands")), osCommands)); + ++#endif /* SETUP */ ++ ++#ifdef USE_MENUORG ++ } ++#endif /* MENUORG */ ++ + Update(true); + + Display(); +@@ -2971,13 +4332,40 @@ void cMenuMain::Set(void) + bool cMenuMain::Update(bool Force) + { + bool result = false; +- ++#ifdef USE_SETUP ++ cOsdItem *fMenu = NULL; ++ if (Force && subMenu.isTopMenu()) { ++ fMenu = First(); ++ nrDynamicMenuEntries = 0; ++ } ++ ++ if (subMenu.isTopMenu()) { ++#endif /* SETUP */ ++#ifdef USE_LIEMIEXT ++// this extension is not included in the original Liemikuutio ++ if (Setup.MainMenuTitle) { ++ if (Setup.MainMenuTitle == 1) ++ SetTitle(cString::sprintf("%s - %s", tr("VDR"), Setup.CustomMainMenuTitle)); ++ else if (Setup.MainMenuTitle == 2) ++ SetTitle(cString::sprintf("%s", Setup.CustomMainMenuTitle)); ++ else if (Setup.MainMenuTitle == 3) ++ SetTitle(cString::sprintf("%s %s", tr("VDR"), VDRVERSION)); ++ } ++ else ++#endif /* LIEMIEXT */ + // Title with disk usage: + if (FreeDiskSpace.HasChanged(Force)) { + //XXX -> skin function!!! + SetTitle(cString::sprintf("%s - %s", tr("VDR"), FreeDiskSpace.FreeDiskSpaceString())); + result = true; + } ++#ifdef USE_SETUP ++ } ++ else { ++ SetTitle(cString::sprintf("%s - %s", tr("VDR"), subMenu.GetParentMenuTitel())); ++ result = true; ++ } ++#endif /* SETUP */ + + bool NewReplaying = cControl::Control() != NULL; + if (Force || NewReplaying != replaying) { +@@ -2985,6 +4373,9 @@ bool cMenuMain::Update(bool Force) + // Replay control: + if (replaying && !stopReplayItem) + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); else ++#endif /* LIEMIEXT */ + Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); + else if (stopReplayItem && !replaying) { + Del(stopReplayItem->Index()); +@@ -2999,6 +4390,9 @@ bool cMenuMain::Update(bool Force) + bool CutterActive = cCutter::Active(); + if (CutterActive && !cancelEditingItem) { + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); else ++#endif /* LIEMIEXT */ + Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); + result = true; + } +@@ -3019,6 +4413,9 @@ bool cMenuMain::Update(bool Force) + while ((s = cRecordControls::GetInstantId(s)) != NULL) { + cOsdItem *item = new cOsdItem(osStopRecord); + item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s)); ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(item); else ++#endif /* LIEMIEXT */ + Add(item); + if (!stopRecordingItem) + stopRecordingItem = item; +@@ -3026,6 +4423,12 @@ bool cMenuMain::Update(bool Force) + result = true; + } + ++#ifdef USE_SETUP ++ // adjust nrDynamicMenuEntries ++ if (fMenu != NULL) ++ nrDynamicMenuEntries = fMenu->Index(); ++#endif /* SETUP */ ++ + return result; + } + +@@ -3036,13 +4439,69 @@ eOSState cMenuMain::ProcessKey(eKeys Key + eOSState state = cOsdMenu::ProcessKey(Key); + HadSubMenu |= HasSubMenu(); + ++#ifdef USE_PINPLUGIN ++ cOsdItem* item = Get(Current()); ++ ++ if (item && item->Text() && state != osBack && state != osContinue && Key != kNone) ++ if (cStatus::MsgMenuItemProtected(item->Text())) ++ return osContinue; ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ + switch (state) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuSchedule; ++ } ++ break; ++ case osChannels: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuChannels; ++ } ++ break; ++ case osTimers: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuTimers; ++ } ++ break; ++ case osRecordings: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuRecordings; ++ } ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: return AddSubMenu(new cMenuSchedule); + case osChannels: return AddSubMenu(new cMenuChannels); + case osTimers: return AddSubMenu(new cMenuTimers); + case osRecordings: return AddSubMenu(new cMenuRecordings); + case osSetup: return AddSubMenu(new cMenuSetup); + case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); ++#endif /* MAINMENUHOOKS */ + case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { + cOsdItem *item = Get(Current()); + if (item) { +@@ -3061,6 +4520,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key + if (item) { + cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p)) { ++#endif /* PINPLUGIN */ + cOsdObject *menu = p->MainMenuAction(); + if (menu) { + if (menu->IsMenu()) +@@ -3072,9 +4534,60 @@ eOSState cMenuMain::ProcessKey(eKeys Key + } + } + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + state = osEnd; + } + break; ++#ifdef USE_SETUP ++ case osBack: { ++ int newCurrent = 0; ++ if (subMenu.Up(&newCurrent)) { ++ Set(newCurrent); ++ return osContinue; ++ } ++ else ++ return osEnd; ++ } ++ break; ++#endif /* SETUP */ ++#ifdef USE_MENUORG ++ case osBack: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ bool leavingMenuSucceeded = MenuOrgPatch::LeaveSubMenu(); ++ Set(); ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ recordControlsState = 0; ++ Update(true); ++ Display(); ++ if (leavingMenuSucceeded) ++ return osContinue; ++ else ++ return osEnd; ++ } ++ } ++ break; ++ case osUser1: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuOrgPatch::EnterSubMenu(Get(Current())); ++ Set(); ++ return osContinue; ++ } ++ } ++ break; ++ case osUser2: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ cOsdMenu* osdMenu = MenuOrgPatch::Execute(Get(Current())); ++ if (osdMenu) ++ return AddSubMenu(osdMenu); ++ return osEnd; ++ } ++ } ++ break; ++#endif /* MENUORG */ + default: switch (Key) { + case kRecord: + case kRed: if (!HadSubMenu) +@@ -3091,9 +4604,67 @@ eOSState cMenuMain::ProcessKey(eKeys Key + case kBlue: if (!HadSubMenu) + state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue; + break; ++#ifdef USE_SETUP ++ case kOk: if (state == osUnknown) { ++ cString buffer; ++#ifdef USE_PINPLUGIN ++ cSubMenuNode *node = Get(Current())->SubMenu(); ++#else ++ int index = Current()-nrDynamicMenuEntries; ++ cSubMenuNode *node = subMenu.GetNode(index); ++#endif /* PINPLUGIN */ ++ ++ if (node != NULL) { ++ if (node->GetType() == cSubMenuNode::MENU) { ++#ifdef USE_PINPLUGIN ++ subMenu.Down(node, Current()); ++#else ++ subMenu.Down(index); ++#endif /* PINPLUGIN */ ++ } ++ else if (node->GetType() == cSubMenuNode::COMMAND) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ const char *Result = subMenu.ExecuteCommand(node->GetCommand()); ++ if (Result) ++ return AddSubMenu(new cMenuText(node->GetName(), Result, fontFix)); ++ return osEnd; ++ } ++ } ++ else if (node->GetType() == cSubMenuNode::THREAD) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ buffer = cString::sprintf("%s", node->GetCommand()); ++ cExecCmdThread *execcmd = new cExecCmdThread(node->GetCommand()); ++ if (execcmd->Start()) ++ dsyslog("executing command '%s'", *buffer); ++ else ++ esyslog("ERROR: can't execute command '%s'", *buffer); ++ return osEnd; ++ } ++ } ++ } ++ ++ Set(); ++ return osContinue; ++ } ++ break; ++#endif /* SETUP */ + default: break; + } + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ return AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + if (!HasSubMenu() && Update(HadSubMenu)) + Display(); + if (Key != kNone) { +@@ -3237,7 +4808,14 @@ cChannel *cDisplayChannel::NextAvailable + if (Direction) { + while (Channel) { + Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, Channel) == false) ++#endif /* PINPLUGIN */ ++#ifdef USE_LNBSHARE ++ if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true) && cDevice::PrimaryDevice()->GetMaxBadPriority(Channel) < 0) ++#else + if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true)) ++#endif /* LNBSHARE */ + return Channel; + } + } +@@ -3295,6 +4873,13 @@ eOSState cDisplayChannel::ProcessKey(eKe + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && !Setup.LRChannelGroups) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kNext|k_Repeat: + case kNext: + case kPrev|k_Repeat: +@@ -3454,6 +5039,17 @@ void cDisplayVolume::Process(eKeys Key) + eOSState cDisplayVolume::ProcessKey(eKeys Key) + { + switch (Key) { ++#ifdef USE_VOLCTRL ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ if (Setup.LRVolumeControl) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: +@@ -3703,6 +5299,10 @@ eOSState cDisplaySubtitleTracks::Process + + cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) + { ++#ifdef USE_DVLRECSCRIPTADDON ++ const cChannel *recChan = NULL; ++ char *chanName = NULL; ++#endif /* DVLRECSCRIPTADDON */ + // We're going to manipulate an event here, so we need to prevent + // others from modifying any EPG data: + cSchedulesLock SchedulesLock; +@@ -3747,12 +5347,57 @@ cRecordControl::cRecordControl(cDevice * + return; + } + ++#ifdef USE_DVLRECSCRIPTADDON ++ if (timer) ++ if ((recChan = timer->Channel()) != NULL) ++ chanName = strdup(recChan->Name()); ++ if (chanName != NULL) { ++ cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName, chanName); ++ free(chanName); ++ } ++ else ++#endif /* DVLRECSCRIPTADDON */ + cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); + isyslog("record %s", fileName); + if (MakeDirs(fileName, true)) { + const cChannel *ch = timer->Channel(); ++#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) ++#ifdef USE_LIVEBUFFER ++ int startFrame=-1; ++ int endFrame=0; ++ cLiveBuffer *liveBuffer = cLiveBufferManager::InLiveBuffer(timer, &startFrame, &endFrame); ++ if (liveBuffer) { ++ timer->SetFlags(tfhasLiveBuf); ++ liveBuffer->SetStartFrame(startFrame); ++ if (endFrame) { ++ liveBuffer->CreateIndexFile(fileName, 0, endFrame); ++ Timers.Del(timer); ++ Timers.SetModified(); ++ timer = NULL; ++ Recording.WriteInfo(); ++ Recordings.AddByName(fileName); ++ return; ++ } ++ } ++#endif /* LIVEBUFFER */ ++#ifdef USE_TTXTSUBS ++ cTtxtSubsRecorderBase *subsRecorder = cVDRTtxtsubsHookListener::Hook()->NewTtxtSubsRecorder(device, ch); ++#endif /* TTXTSUBS */ ++ recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids() ++#ifdef USE_TTXTSUBS ++ ,subsRecorder ++#endif /* TTXTSUBS */ ++#ifdef USE_LIVEBUFFER ++ ,liveBuffer ++#endif /* LIVEBUFFER */ ++ ); ++#else + recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids()); ++#endif /* LIVEBUFFER || TTXTSUBS */ + if (device->AttachReceiver(recorder)) { ++#ifdef USE_TTXTSUBS ++ if (subsRecorder) subsRecorder->DeviceAttach(); ++#endif /* TTXTSUBS */ + Recording.WriteInfo(); + cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true); + if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo() +@@ -3809,11 +5454,25 @@ bool cRecordControl::GetEvent(void) + void cRecordControl::Stop(void) + { + if (timer) { ++#ifdef USE_DVLRECSCRIPTADDON ++ char *chanName = NULL; ++ const cChannel *recChan = NULL; ++ ++ recChan = timer -> Channel(); ++ if (recChan != NULL) ++ chanName = strdup(recChan -> Name()); ++#endif /* DVLRECSCRIPTADDON */ + DELETENULL(recorder); + timer->SetRecording(false); + timer = NULL; + cStatus::MsgRecording(device, NULL, fileName, false); ++#ifdef USE_DVLRECSCRIPTADDON ++ cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName, chanName); ++ if (chanName != NULL) ++ free(chanName); ++#else + cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); ++#endif /* DVLRECSCRIPTADDON */ + } + } + +@@ -3860,15 +5519,35 @@ bool cRecordControls::Start(cTimer *Time + int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority; + cDevice *device = cDevice::GetDevice(channel, Priority, false); + if (device) { ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ while ((tmpDevice = device->GetBadDevice(channel))) { ++ if (tmpDevice->Replaying() == false) { ++// Stop(tmpDevice); ++ if (tmpDevice->IsPrimaryDevice() ) ++ tmpDevice->SwitchChannelForced(channel, true); ++ else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } ++#endif /* LNBSHARE */ + dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number()); + if (!device->SwitchChannel(channel, false)) { + ShutdownHandler.RequestEmergencyExit(); + return false; + } ++#ifdef USE_LIVEBUFFER ++ if (!Timer || Timer->Matches() || cLiveBufferManager::InLiveBuffer(Timer)) { ++#else + if (!Timer || Timer->Matches()) { ++#endif /* LIVEBUFFER */ + for (int i = 0; i < MAXRECORDCONTROLS; i++) { + if (!RecordControls[i]) { + RecordControls[i] = new cRecordControl(device, Timer, Pause); ++#ifdef USE_PINPLUGIN ++ cStatus::MsgRecordingFile(RecordControls[i]->FileName()); ++#endif /* PINPLUGIN */ + return RecordControls[i]->Process(time(NULL)); + } + } +@@ -3999,12 +5678,22 @@ bool cRecordControls::StateChanged(int & + + // --- cReplayControl -------------------------------------------------------- + ++#ifdef USE_LIEMIEXT ++#define REPLAYCONTROLSKIPLIMIT 9 // s ++#define REPLAYCONTROLSKIPSECONDS 90 // s ++#define REPLAYCONTROLSKIPTIMEOUT 5000 // ms ++#endif /* LIEMIEXT */ ++ + cReplayControl *cReplayControl::currentReplayControl = NULL; + char *cReplayControl::fileName = NULL; + char *cReplayControl::title = NULL; + + cReplayControl::cReplayControl(void) ++#ifdef USE_JUMPPLAY ++:cDvbPlayerControl(fileName), marks(fileName) ++#else + :cDvbPlayerControl(fileName) ++#endif /* JUMPPLAY */ + { + currentReplayControl = this; + displayReplay = NULL; +@@ -4012,10 +5701,28 @@ cReplayControl::cReplayControl(void) + lastCurrent = lastTotal = -1; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value ++#ifdef USE_LIEMIEXT ++ lastSkipKey = kNone; ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipTimeout.Set(0); ++#endif /* LIEMIEXT */ + timeoutShow = 0; + timeSearchActive = false; ++#ifndef USE_JUMPPLAY + marks.Load(fileName); ++#endif /* JUMPPLAY */ + cRecording Recording(fileName); ++#ifdef USE_DVDARCHIVE ++ canJumpChapters = (Recording.GetDvdType() == DVD_VIDEO_ARCHIVE_TYPE); ++ dvdchapters = NULL; ++ if (canJumpChapters) { ++ const char *ret = Recording.GetDvdChapters(); ++ if (ret) ++ dvdchapters = strdup(ret); ++ else ++ canJumpChapters=false; ++ } ++#endif /* DVDARCHIVE */ + cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true); + SetTrackDescriptions(false); + } +@@ -4023,12 +5730,67 @@ cReplayControl::cReplayControl(void) + cReplayControl::~cReplayControl() + { + Hide(); ++#ifdef USE_DVDARCHIVE ++ free(dvdchapters); ++#endif /* DVDARCHIVE */ + cStatus::MsgReplaying(this, NULL, fileName, false); + Stop(); + if (currentReplayControl == this) + currentReplayControl = NULL; + } + ++#ifdef USE_DELTIMESHIFTREC ++void cReplayControl::Stop(void) ++{ ++ int dummy; ++ bool playing = GetIndex(dummy, dummy, false); ++ cRecordControl* rc = cRecordControls::GetRecordControl(fileName); ++ ++ if (playing && rc && rc->InstantId()) { ++ isyslog("found Timeshiftrecording"); ++ ++ if ((Setup.DelTimeshiftRec != 0 ) || (Interface->Confirm(tr("Delete recording?")))) { ++ cRecordControl *rc = cRecordControls::GetRecordControl(fileName); ++ if (rc) { ++ cTimer *timer = rc->Timer(); ++ if (timer) { ++ const char* reccmd_backup = cRecordingUserCommand::GetCommand(); ++ cRecordingUserCommand::SetCommand(NULL); ++ ++ timer->Skip(); ++ cRecordControls::Process(time(NULL)); ++ if (timer->IsSingleEvent()) { ++ isyslog("deleting timer %s", *timer->ToDescr()); ++ Timers.Del(timer); ++ } ++ Timers.SetModified(); ++ ++ // restore reccmd ++ cRecordingUserCommand::SetCommand(reccmd_backup); ++ } ++ } ++ isyslog("stop replaying %s", fileName); ++ cDvbPlayerControl::Stop(); ++ ++ if (Setup.DelTimeshiftRec != 1) { ++ cRecording *recording = Recordings.GetByName(fileName);; ++ if (recording) { ++ if (recording->Delete()) { ++ Recordings.DelByName(fileName); ++ ClearLastReplayed(fileName); ++ return; ++ } ++ else ++ Skins.Message(mtError, tr("Error while deleting recording!")); ++ } ++ } ++ } ++ else ++ cDvbPlayerControl::Stop(); ++ } ++} ++#endif /* DELTIMESHIFTREC */ ++ + void cReplayControl::SetRecording(const char *FileName, const char *Title) + { + free(fileName); +@@ -4123,6 +5885,9 @@ bool cReplayControl::ShowProgress(bool I + if (Initial) { + if (title) + displayReplay->SetTitle(title); ++#ifdef USE_OSDMAXITEMS ++ displayReplay->SetButtons(tr("Jump"), tr("Skip +60s"), tr("Skip -60s"), tr("Button$Stop")); ++#endif /* OSDMAXITEMS */ + lastCurrent = lastTotal = -1; + } + if (Total != lastTotal) { +@@ -4244,8 +6009,15 @@ void cReplayControl::MarkToggle(void) + ShowTimed(2); + bool Play, Forward; + int Speed; ++#ifdef USE_JUMPPLAY ++ if (GetReplayMode(Play, Forward, Speed) && !Play) { ++ Goto(Current, true); ++ displayFrames = true; ++ } ++#else + if (GetReplayMode(Play, Forward, Speed) && !Play) + Goto(Current, true); ++#endif /* JUMPPLAY */ + } + marks.Save(); + } +@@ -4258,8 +6030,22 @@ void cReplayControl::MarkJump(bool Forwa + if (GetIndex(Current, Total)) { + cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ bool Play2, Forward2; ++ int Speed; ++ if (Setup.JumpPlay && GetReplayMode(Play2, Forward2, Speed) && ++ Play2 && Forward && m->position < Total - SecondsToFrames(3)) { ++ Goto(m->position); ++ Play(); ++ } ++ else { ++ Goto(m->position, true); ++ displayFrames = true; ++ } ++#else + Goto(m->position, true); + displayFrames = true; ++#endif /* JUMPPLAY */ + } + } + } +@@ -4288,11 +6074,43 @@ void cReplayControl::MarkMove(bool Forwa + } + } + ++#ifdef USE_DVDARCHIVE ++void cReplayControl::ChaptersJump(bool Forward) ++{ ++ int Current, Total; ++ if (GetIndex(Current, Total)) { ++ int position = -1; ++ char *buf, *pos; ++ cString old1("-1"); ++ cString old2("-1"); ++ buf = strdup(dvdchapters); ++ pos = strtok(buf, ","); ++ while (pos != NULL && position == -1) { ++ if (pos && atoi(pos) > Current) ++ position = Forward ? atoi(pos) : ((Current - atoi(old1)) <= (3*FRAMESPERSEC)) ? atoi(old2) : atoi(old1); ++ old2 = old1; ++ old1 = strdup(pos); ++ if(position == -1) pos = strtok(NULL, ","); ++ } ++ if (!pos && !Forward) ++ position = ((Current - atoi(old1)) <= (3*FRAMESPERSEC)) ? atoi(old2) : atoi(old1); ++ if (position >= 0) { ++ Goto(position); ++ Play(); ++ } ++ } ++} ++ ++#endif /* DVDARCHIVE */ + void cReplayControl::EditCut(void) + { + if (fileName) { + Hide(); ++#ifdef USE_CUTTERQUEUE ++ if (!cCutter::Active() || Interface->Confirm(tr("Cutter already running - Add to cutting queue?"))) { ++#else + if (!cCutter::Active()) { ++#endif /* CUTTERQUEUE */ + if (!marks.Count()) + Skins.Message(mtError, tr("No editing marks defined!")); + else if (!cCutter::Start(fileName)) +@@ -4314,7 +6132,11 @@ void cReplayControl::EditTest(void) + if (!m) + m = marks.GetNext(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ if ((m->Index() & 0x01) != 0 && !Setup.PlayJump) ++#else + if ((m->Index() & 0x01) != 0) ++#endif /* JUMPPLAY */ + m = marks.Next(m); + if (m) { + Goto(m->position - SecondsToFrames(3)); +@@ -4336,6 +6158,9 @@ eOSState cReplayControl::ProcessKey(eKey + { + if (!Active()) + return osEnd; ++#ifdef USE_JUMPPLAY ++ marks.Reload(); ++#endif /* JUMPPLAY */ + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); +@@ -4353,7 +6178,32 @@ eOSState cReplayControl::ProcessKey(eKey + TimeSearchProcess(Key); + return osContinue; + } ++#ifdef USE_DVDARCHIVE ++ bool isOnMark = false; ++ if (canJumpChapters) { ++ int Current, Total; ++ GetIndex(Current, Total); ++ cMark *m = marks.Get(Current); ++ if (m && (m->position == Current)) isOnMark = true; ++ } ++#endif /* DVDARCHIVE */ + bool DoShowMode = true; ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && (!Setup.LRForwardRewind || (Setup.LRForwardRewind == 1 && !visible))) { ++ switch (Key) { ++ // Left/Right volume control ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ return osContinue; ++ break; ++ default: ++ break; ++ } ++ } ++#endif /* VOLCTRL */ + switch (Key) { + // Positioning: + case kPlay: +@@ -4371,25 +6221,82 @@ eOSState cReplayControl::ProcessKey(eKey + case kFastFwd: + case kRight: Forward(); break; + case kRed: TimeSearch(); break; ++#ifdef USE_LIEMIEXT ++ case kGreen|k_Repeat: ++ case kGreen: SkipSeconds(-Setup.JumpSeconds); break; ++ case kYellow|k_Repeat: ++ case kYellow: SkipSeconds( Setup.JumpSeconds); break; ++ case k1|k_Repeat: ++ case k1: SkipSeconds(-Setup.JumpSecondsSlow); break; ++ case k3|k_Repeat: ++ case k3: SkipSeconds( Setup.JumpSecondsSlow); break; ++ case kPrev|k_Repeat: ++ case kPrev: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kPrev; ++ } ++ else if (RAWKEY(lastSkipKey) != kPrev && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(-lastSkipSeconds); break; ++ case kNext|k_Repeat: ++ case kNext: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kNext; ++ } ++ else if (RAWKEY(lastSkipKey) != kNext && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(lastSkipSeconds); break; ++#else + case kGreen|k_Repeat: + case kGreen: SkipSeconds(-60); break; + case kYellow|k_Repeat: + case kYellow: SkipSeconds( 60); break; ++#endif /* LIEMIEXT */ + case kStop: + case kBlue: Hide(); + Stop(); + return osEnd; ++#ifdef USE_DVDARCHIVE ++ case kDvdChapterJumpForward|k_Repeat: ++ case kDvdChapterJumpForward: if (canJumpChapters && !isOnMark) { ++ ChaptersJump(true); ++ } ++ else { ++ DoShowMode = false; ++ MarkMove(true); ++ } ++ break; ++ case kDvdChapterJumpBack|k_Repeat: ++ case kDvdChapterJumpBack: if (canJumpChapters && !isOnMark) { ++ ChaptersJump(false); ++ } ++ else { ++ DoShowMode = false; ++ MarkMove(false); ++ } ++ break; ++#endif /* DVDARCHIVE */ + default: { + DoShowMode = false; + switch (Key) { + // Editing: + case kMarkToggle: MarkToggle(); break; ++#ifndef USE_LIEMIEXT + case kPrev|k_Repeat: + case kPrev: ++#endif /* LIEMIEXT */ + case kMarkJumpBack|k_Repeat: + case kMarkJumpBack: MarkJump(false); break; ++#ifndef USE_LIEMIEXT + case kNext|k_Repeat: + case kNext: ++#endif /* LIEMIEXT */ + case kMarkJumpForward|k_Repeat: + case kMarkJumpForward: MarkJump(true); break; + case kMarkMoveBack|k_Repeat: +@@ -4409,7 +6316,16 @@ eOSState cReplayControl::ProcessKey(eKey + else + Show(); + break; ++#ifdef USE_DELTIMESHIFTREC ++ case kBack: { cRecordControl* rc = cRecordControls::GetRecordControl(fileName); ++ if (rc && rc->InstantId()) ++ return osEnd; ++ else ++ return osRecordings; ++ } ++#else + case kBack: return osRecordings; ++#endif /* DELTIMESHIFTREC */ + default: return osUnknown; + } + } +diff -ruNp vdr-1.7.0/menu.h vdr-1.7.0-extensions/menu.h +--- vdr-1.7.0/menu.h 2008-02-10 17:01:53.000000000 +0100 ++++ vdr-1.7.0-extensions/menu.h 2009-04-09 20:48:48.000000000 +0200 +@@ -18,6 +18,9 @@ + #include "menuitems.h" + #include "recorder.h" + #include "skins.h" ++#ifdef USE_SETUP ++#include "submenu.h" ++#endif /* SETUP */ + + class cMenuText : public cOsdMenu { + private: +@@ -29,12 +32,19 @@ public: + void SetText(const char *Text); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuText"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuEditTimer : public cOsdMenu { + private: + cTimer *timer; + cTimer data; ++#ifdef USE_LIEMIEXT ++ char name[MaxFileName]; ++ char path[MaxFileName]; ++#endif /* LIEMIEXT */ + int channel; + bool addIfConfirmed; + cMenuEditDateItem *firstday; +@@ -43,6 +53,9 @@ public: + cMenuEditTimer(cTimer *Timer, bool New = false); + virtual ~cMenuEditTimer(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuTimerEdit"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuEvent : public cOsdMenu { +@@ -52,22 +65,37 @@ public: + cMenuEvent(const cEvent *Event, bool CanSwitch = false, bool Buttons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEvent"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuMain : public cOsdMenu { + private: ++#ifdef USE_SETUP ++ int nrDynamicMenuEntries; ++#endif /* SETUP */ + bool replaying; + cOsdItem *stopReplayItem; + cOsdItem *cancelEditingItem; + cOsdItem *stopRecordingItem; + int recordControlsState; + static cOsdObject *pluginOsdObject; ++#ifdef USE_SETUP ++ void Set(int current=0); ++ bool Update(bool Force = false); ++ cSubMenu subMenu; ++#else + void Set(void); + bool Update(bool Force = false); ++#endif /* SETUP */ + public: + cMenuMain(eOSState State = osUnknown); + virtual eOSState ProcessKey(eKeys Key); + static cOsdObject *PluginOsdObject(void); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuMain"; } ++#endif /* GRAPHTFT */ + }; + + class cDisplayChannel : public cOsdObject { +@@ -163,12 +191,18 @@ private: + eOSState Delete(void); + eOSState Info(void); + eOSState Commands(eKeys Key = kNone); ++#ifdef USE_LIEMIEXT ++ eOSState Rename(void); ++#endif /* LIEMIEXT */ + protected: + cRecording *GetRecording(cMenuRecordingItem *Item); + public: + cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false); + ~cMenuRecordings(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRecordings"; } ++#endif /* GRAPHTFT */ + }; + + class cRecordControl { +@@ -212,11 +246,21 @@ public: + class cReplayControl : public cDvbPlayerControl { + private: + cSkinDisplayReplay *displayReplay; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#else + cMarks marks; ++#endif /* JUMPPLAY */ + bool visible, modeOnly, shown, displayFrames; + int lastCurrent, lastTotal; + bool lastPlay, lastForward; + int lastSpeed; ++#ifdef USE_LIEMIEXT ++ int lastSkipSeconds; ++ int lastSkipSecondsSlow; ++ eKeys lastSkipKey; ++ cTimeMs lastSkipTimeout; ++#endif /* LIEMIEXT */ + time_t timeoutShow; + bool timeSearchActive, timeSearchHide; + int timeSearchTime, timeSearchPos; +@@ -234,9 +278,17 @@ private: + void MarkMove(bool Forward); + void EditCut(void); + void EditTest(void); ++#ifdef USE_DVDARCHIVE ++ void ChaptersJump(bool Forward); ++ bool canJumpChapters; ++ char *dvdchapters; ++#endif /* DVDARCHIVE */ + public: + cReplayControl(void); + virtual ~cReplayControl(); ++#ifdef USE_DELTIMESHIFTREC ++ void Stop(void); ++#endif /* DELTIMESHIFTREC */ + virtual cOsdObject *GetInfo(void); + virtual eOSState ProcessKey(eKeys Key); + virtual void Show(void); +diff -ruNp vdr-1.7.0/menuitems.c vdr-1.7.0-extensions/menuitems.c +--- vdr-1.7.0/menuitems.c 2008-04-12 14:05:25.000000000 +0200 ++++ vdr-1.7.0-extensions/menuitems.c 2009-04-09 20:48:48.000000000 +0200 +@@ -32,9 +32,20 @@ cMenuEditItem::~cMenuEditItem() + free(name); + } + ++#ifdef USE_VALIDINPUT ++void cMenuEditItem::SetValue(const char *Value, bool HasPre, bool HasSucc) ++#else + void cMenuEditItem::SetValue(const char *Value) ++#endif /* VALIDINPUT */ + { + cString buffer = cString::sprintf("%s:\t%s", name, Value); ++#ifdef USE_VALIDINPUT ++ if (Setup.ShowValidInput) { ++ if (HasPre && HasSucc) buffer = cString::sprintf("%s:\t<%s>", name, Value); ++ else if (HasPre) buffer = cString::sprintf("%s:\t<%s", name, Value); ++ else if (HasSucc) buffer = cString::sprintf("%s:\t%s>", name, Value); ++ } ++#endif /* VALIDINPUT */ + SetText(buffer); + cStatus::MsgOsdCurrentItem(buffer); + } +@@ -126,7 +137,11 @@ void cMenuEditBoolItem::Set(void) + { + char buf[16]; + snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); ++#ifdef USE_VALIDINPUT ++ SetValue(buf, *value, !*value); ++#else + SetValue(buf); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditBitItem ------------------------------------------------------ +@@ -619,6 +634,171 @@ eOSState cMenuEditStrItem::ProcessKey(eK + return osContinue; + } + ++#ifdef USE_LIEMIEXT ++// --- cMenuEditRecPathItem -------------------------------------------------- ++ ++cMenuEditRecPathItem::cMenuEditRecPathItem(const char* Name, char* Path, ++ int Length): cMenuEditStrItem(Name, Path, Length, tr(FileNameChars)) ++{ ++ SetBase(Path); ++} ++ ++cMenuEditRecPathItem::~cMenuEditRecPathItem() ++{ ++} ++ ++void cMenuEditRecPathItem::SetBase(const char* Path) ++{ ++ if (!Path) ++ base[0] = 0; ++ Utf8Strn0Cpy(base, Path, sizeof(base)); ++ char* p = strrchr(base, '~'); ++ if (p) ++ p[0] = 0; ++ else ++ base[0] = 0; ++} ++ ++void cMenuEditRecPathItem::FindNextLevel() ++{ ++ char item[MaxFileName]; ++ ++ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) ++ { ++ char* p; ++ Utf8Strn0Cpy(item, recording->Name(), sizeof(item)); ++ stripspace(value); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ if (!lengthUtf8) ++ p = strchr(item, '~'); ++ else { ++ if (strstr(item, value) != item) ++ continue; ++ if (item[strlen(value)] != '~') ++ continue; ++ p = strchr(item + strlen(value) + 1, '~'); ++ } ++ if (!p) ++ continue; ++ p[0] = 0; ++ Utf8Strn0Cpy(base, value, length); ++ Utf8Strn0Cpy(value, item, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++} ++ ++void cMenuEditRecPathItem::Find(bool Next) ++{ ++ char item[MaxFileName]; ++ char lastItem[MaxFileName] = ""; ++ ++ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) ++ { ++ const char* recName = recording->Name(); ++ if (Utf8StrLen(base) && strstr(recName, base) != recName) ++ continue; ++ if (strlen(base) && recName[strlen(base)] != '~') ++ continue; ++ Utf8Strn0Cpy(item, recName, sizeof(item)); ++ char* p = strchr(item + strlen(base) + 1, '~'); ++ if (!p) ++ continue; ++ p[0] = 0; ++ if (!Next && (strcmp(item, value) == 0)) { ++ if (strlen(lastItem)) ++ Utf8Strn0Cpy(value, lastItem, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++ if (strcmp(lastItem, item) != 0) { ++ if(Next && Utf8StrLen(lastItem) && strcmp(lastItem, value) == 0) { ++ Utf8Strn0Cpy(value, item, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++ Utf8Strn0Cpy(lastItem, item, sizeof(lastItem)); ++ } ++ } ++} ++ ++void cMenuEditRecPathItem::SetHelpKeys(void) ++{ ++ cSkinDisplay::Current()->SetButtons(tr("Rename$Up"), tr("Rename$Down"), tr("Rename$Previous"), tr("Rename$Next")); ++} ++ ++eOSState cMenuEditRecPathItem::ProcessKey(eKeys Key) ++{ ++ switch (Key) { ++ case kLeft: ++ case kRed: // one level up ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Utf8Strn0Cpy(value, base, lengthUtf8); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ SetBase(base); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ if (!lengthUtf8) { ++ Utf8Strn0Cpy(value, " ", length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ } ++ break; ++ case kRight: ++ case kGreen: // one level down ++ if (InEditMode()) ++ FindNextLevel(); ++ else ++ EnterEditMode(); ++ ++ if (!lengthUtf8) { ++ Utf8Strn0Cpy(value, " ", length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ } ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ SetHelpKeys(); ++ break; ++ case kUp|k_Repeat: ++ case kUp: ++ case kYellow|k_Repeat: ++ case kYellow: // previous directory in list ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Find(false); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ break; ++ case kDown|k_Repeat: ++ case kDown: ++ case kBlue|k_Repeat: ++ case kBlue: // next directory in list ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Find(true); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ break; ++ case kOk: // done ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ stripspace(value); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ cSkinDisplay::Current()->SetButtons(NULL); ++ LeaveEditMode(Key == kOk); ++ break; ++ default: ++ return cMenuEditItem::ProcessKey(Key); ++ } ++ Set(); ++ return osContinue; ++} ++#endif /* LIEMIEXT */ ++ + // --- cMenuEditStraItem ----------------------------------------------------- + + cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) +@@ -630,7 +810,11 @@ cMenuEditStraItem::cMenuEditStraItem(con + + void cMenuEditStraItem::Set(void) + { ++#ifdef USE_VALIDINPUT ++ SetValue(strings[*value], (*value > min), (*value < max)); ++#else + SetValue(strings[*value]); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditChanItem ----------------------------------------------------- +diff -ruNp vdr-1.7.0/menuitems.h vdr-1.7.0-extensions/menuitems.h +--- vdr-1.7.0/menuitems.h 2008-04-12 14:03:59.000000000 +0200 ++++ vdr-1.7.0-extensions/menuitems.h 2009-04-09 20:48:48.000000000 +0200 +@@ -21,7 +21,11 @@ private: + public: + cMenuEditItem(const char *Name); + ~cMenuEditItem(); ++#ifdef USE_VALIDINPUT ++ void SetValue(const char *Value, bool HasPre=false, bool HasSucc=false); ++#else + void SetValue(const char *Value); ++#endif /* VALIDINPUT */ + }; + + class cMenuEditIntItem : public cMenuEditItem { +@@ -78,26 +82,46 @@ public: + + class cMenuEditStrItem : public cMenuEditItem { + private: ++#ifdef USE_LIEMIEXT ++ int offset; ++#else + char *value; + int length; + const char *allowed; + int pos, offset; ++#endif /* LIEMIEXT */ + bool insert, newchar, uppercase; ++#ifndef USE_LIEMIEXT + int lengthUtf8; + uint *valueUtf8; ++#endif /* LIEMIEXT */ + uint *allowedUtf8; + uint *charMapUtf8; + uint *currentCharUtf8; + eKeys lastKey; + cTimeMs autoAdvanceTimeout; ++#ifndef USE_LIEMIEXT + void SetHelpKeys(void); ++#endif /* LIEMIEXT */ + uint *IsAllowed(uint c); + void AdvancePos(void); ++#ifndef USE_LIEMIEXT + virtual void Set(void); ++#endif /* LIEMIEXT */ + uint Inc(uint c, bool Up); + void Insert(void); + void Delete(void); + protected: ++#ifdef USE_LIEMIEXT ++ char *value; ++ int length; ++ uint *valueUtf8; ++ int lengthUtf8; ++ const char *allowed; ++ int pos; ++ void SetHelpKeys(void); ++ virtual void Set(void); ++#endif /* LIEMIEXT */ + void EnterEditMode(void); + void LeaveEditMode(bool SaveValue = false); + bool InEditMode(void) { return valueUtf8 != NULL; } +@@ -107,6 +131,21 @@ public: + virtual eOSState ProcessKey(eKeys Key); + }; + ++#ifdef USE_LIEMIEXT ++class cMenuEditRecPathItem : public cMenuEditStrItem { ++protected: ++ char base[MaxFileName]; ++ virtual void SetHelpKeys(void); ++ void SetBase(const char* Path); ++ void FindNextLevel(); ++ void Find(bool Next); ++public: ++ cMenuEditRecPathItem(const char* Name, char* Path, int Length); ++ ~cMenuEditRecPathItem(); ++ virtual eOSState ProcessKey(eKeys Key); ++ }; ++#endif /* LIEMIEXT */ ++ + class cMenuEditStraItem : public cMenuEditIntItem { + private: + const char * const *strings; +@@ -185,6 +224,9 @@ public: + cMenuSetupPage(void); + virtual eOSState ProcessKey(eKeys Key); + void SetPlugin(cPlugin *Plugin); ++#ifdef USE_GRAPHTFT ++ const char* MenuKind() { return "MenuSetupPage"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__MENUITEMS_H +diff -ruNp vdr-1.7.0/menuorgpatch.h vdr-1.7.0-extensions/menuorgpatch.h +--- vdr-1.7.0/menuorgpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/menuorgpatch.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,102 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MENUORGPATCH_H ++#define __MENUORGPATCH_H ++ ++#include "mainmenuitemsprovider.h" ++ ++class MenuOrgPatch ++{ ++ private: ++ static IMainMenuItemsProvider* _mainMenuItemsProvider; ++ ++ private: ++ static IMainMenuItemsProvider* MainMenuItemsProvider() ++ { ++ if (!_mainMenuItemsProvider) ++ { ++ IMainMenuItemsProvider* mainMenuItemsProvider; ++ ++ if (cPluginManager::CallFirstService(MENU_ITEMS_PROVIDER_SERVICE_ID, &mainMenuItemsProvider)) ++ { ++ _mainMenuItemsProvider = mainMenuItemsProvider; ++ } ++ } ++ return _mainMenuItemsProvider; ++ } ++ ++ public: ++ static bool IsCustomMenuAvailable() ++ { ++ return (MainMenuItemsProvider() != NULL) && (MainMenuItemsProvider()->IsCustomMenuAvailable()); ++ } ++ ++ static void EnterRootMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterRootMenu(); ++ } ++ } ++ ++ static bool LeaveSubMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->LeaveSubMenu(); ++ } ++ return false; ++ } ++ ++ static void EnterSubMenu(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterSubMenu(item); ++ } ++ } ++ ++ static MenuItemDefinitions* MainMenuItems() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->MainMenuItems(); ++ } ++ return NULL; ++ } ++ ++ static cOsdMenu* Execute(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->Execute(item); ++ } ++ return NULL; ++ } ++}; ++ ++IMainMenuItemsProvider* MenuOrgPatch::_mainMenuItemsProvider = NULL; ++ ++#endif //__MENUORGPATCH_H ++#endif /* MENUORG */ +diff -ruNp vdr-1.7.0/osdbase.c vdr-1.7.0-extensions/osdbase.c +--- vdr-1.7.0/osdbase.c 2008-02-17 12:33:04.000000000 +0100 ++++ vdr-1.7.0-extensions/osdbase.c 2009-04-09 20:48:48.000000000 +0200 +@@ -22,6 +22,9 @@ cOsdItem::cOsdItem(eOSState State) + state = State; + selectable = true; + fresh = true; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + + cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable) +@@ -31,8 +34,23 @@ cOsdItem::cOsdItem(const char *Text, eOS + selectable = Selectable; + fresh = true; + SetText(Text); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++cOsdItem::cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu) ++{ ++ text = NULL; ++ state = State; ++ selectable = true; ++ fresh = true; ++ SetText(Text); ++ subMenu = SubMenu; ++} ++#endif /* SETUP & PINPLUGIN */ ++ + cOsdItem::~cOsdItem() + { + free(text); +@@ -77,6 +95,9 @@ cOsdMenu::cOsdMenu(const char *Title, in + { + isMenu = true; + digit = 0; ++#ifdef USE_LIEMIEXT ++ key_nr = -1; ++#endif /* LIEMIEXT */ + hasHotkeys = false; + title = NULL; + SetTitle(Title); +@@ -97,6 +118,9 @@ cOsdMenu::~cOsdMenu() + free(status); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDestroy(); ++#endif /* GRAPHTFT */ + if (!--displayMenuCount) + DELETENULL(displayMenu); + } +@@ -119,7 +143,11 @@ const char *cOsdMenu::hk(const char *s) + digit = -1; // prevents automatic hotkeys - input already has them + if (digit >= 0) { + digit++; ++#ifdef USE_LIEMIEXT ++ buffer = cString::sprintf(" %2d%s %s", digit, (digit > 9) ? "" : " ", s); ++#else + buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s); ++#endif /* LIEMIEXT */ + s = buffer; + } + } +@@ -199,9 +227,15 @@ void cOsdMenu::Display(void) + subMenu->Display(); + return; + } ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + displayMenu->SetMessage(mtStatus, NULL); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDisplay(MenuKind()); ++#endif /* GRAPHTFT */ + displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX + displayMenu->SetTitle(title); + cStatus::MsgOsdTitle(title); +@@ -296,6 +330,9 @@ bool cOsdMenu::SelectableItem(int idx) + + void cOsdMenu::CursorUp(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int tmpCurrent = current; + int lastOnScreen = first + displayMenuItems - 1; + int last = Count() - 1; +@@ -334,6 +371,9 @@ void cOsdMenu::CursorUp(void) + + void cOsdMenu::CursorDown(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int tmpCurrent = current; + int lastOnScreen = first + displayMenuItems - 1; + int last = Count() - 1; +@@ -374,6 +414,9 @@ void cOsdMenu::CursorDown(void) + + void cOsdMenu::PageUp(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int oldCurrent = current; + int oldFirst = first; + current -= displayMenuItems; +@@ -408,6 +451,9 @@ void cOsdMenu::PageUp(void) + + void cOsdMenu::PageDown(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int oldCurrent = current; + int oldFirst = first; + current += displayMenuItems; +@@ -448,6 +494,64 @@ void cOsdMenu::Mark(void) + } + } + ++#ifdef USE_LIEMIEXT ++#define MENUKEY_TIMEOUT 1500 ++ ++eOSState cOsdMenu::HotKey(eKeys Key) ++{ ++ bool match = false; ++ bool highlight = false; ++ int item_nr; ++ int i; ++ ++ if (Key == kNone) { ++ if (lastActivity.TimedOut()) ++ Key = kOk; ++ else ++ return osContinue; ++ } ++ else { ++ lastActivity.Set(MENUKEY_TIMEOUT); ++ } ++ for (cOsdItem *item = Last(); item; item = Prev(item)) { ++ const char *s = item->Text(); ++ i = 0; ++ item_nr = 0; ++ if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') { ++ do { ++ item_nr = item_nr * 10 + (s[i] - '0'); ++ } ++ while (!((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9')); ++ if ((Key == kOk) && (item_nr == key_nr)) { ++ current = item->Index(); ++ RefreshCurrent(); ++ Display(); ++ cRemote::Put(kOk, true); ++ key_nr = -1; ++ break; ++ } ++ else if (Key != kOk) { ++ if (!highlight && (item_nr == (Key - k0))) { ++ highlight = true; ++ current = item->Index(); ++ } ++ if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) { ++ match = true; ++ key_nr = (Key - k0); ++ } ++ else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) { ++ current = item->Index(); ++ cRemote::Put(kOk, true); ++ key_nr = -1; ++ break; ++ } ++ } ++ } ++ } ++ if ((!match) && (Key != kNone)) { ++ key_nr = -1; ++ } ++#else + eOSState cOsdMenu::HotKey(eKeys Key) + { + for (cOsdItem *item = First(); item; item = Next(item)) { +@@ -462,6 +566,7 @@ eOSState cOsdMenu::HotKey(eKeys Key) + } + } + } ++#endif /* LIEMIEXT */ + return osContinue; + } + +@@ -500,8 +605,13 @@ eOSState cOsdMenu::ProcessKey(eKeys Key) + } + } + switch (Key) { ++#ifdef USE_LIEMIEXT ++ case kNone: ++ case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#else + case k0: return osUnknown; + case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#endif /* LIEMIEXT */ + case kUp|k_Repeat: + case kUp: CursorUp(); break; + case kDown|k_Repeat: +diff -ruNp vdr-1.7.0/osdbase.h vdr-1.7.0-extensions/osdbase.h +--- vdr-1.7.0/osdbase.h 2007-11-03 15:50:52.000000000 +0100 ++++ vdr-1.7.0-extensions/osdbase.h 2009-04-09 20:48:48.000000000 +0200 +@@ -15,6 +15,10 @@ + #include "skins.h" + #include "tools.h" + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++#include "submenu.h" ++#endif /* SETUP & PINPLUGIN */ ++ + enum eOSState { osUnknown, + osContinue, + osSchedule, +@@ -44,6 +48,9 @@ enum eOSState { osUnknown, + osUser8, + osUser9, + osUser10, ++#ifdef USE_LIVEBUFFER ++ osLiveBuffer, ++#endif /* LIVEBUFFER */ + }; + + class cOsdItem : public cListObject { +@@ -51,16 +58,26 @@ private: + char *text; + eOSState state; + bool selectable; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cSubMenuNode* subMenu; ++#endif /* SETUP & PINPLUGIN */ + protected: + bool fresh; + public: + cOsdItem(eOSState State = osUnknown); + cOsdItem(const char *Text, eOSState State = osUnknown, bool Selectable = true); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu); ++#endif /* SETUP & PINPLUGIN */ + virtual ~cOsdItem(); + bool Selectable(void) const { return selectable; } + void SetText(const char *Text, bool Copy = true); + void SetSelectable(bool Selectable); + void SetFresh(bool Fresh); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ void SetSubMenu(cSubMenuNode* SubMenu) { subMenu = SubMenu; } ++ cSubMenuNode* SubMenu() { return subMenu; } ++#endif /* SETUP & PINPLUGIN */ + const char *Text(void) const { return text; } + virtual void Set(void) {} + virtual eOSState ProcessKey(eKeys Key); +@@ -95,6 +112,10 @@ private: + char *status; + int digit; + bool hasHotkeys; ++#ifdef USE_LIEMIEXT ++ int key_nr; ++ cTimeMs lastActivity; ++#endif /* LIEMIEXT */ + protected: + void SetDisplayMenu(void); + cSkinDisplayMenu *DisplayMenu(void) { return displayMenu; } +@@ -129,6 +150,9 @@ public: + void Ins(cOsdItem *Item, bool Current = false, cOsdItem *Before = NULL); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuUnknown"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__OSDBASE_H +diff -ruNp vdr-1.7.0/osd.c vdr-1.7.0-extensions/osd.c +--- vdr-1.7.0/osd.c 2007-10-12 14:38:36.000000000 +0200 ++++ vdr-1.7.0-extensions/osd.c 2009-04-09 20:48:48.000000000 +0200 +@@ -15,6 +15,9 @@ + #include <sys/stat.h> + #include <sys/unistd.h> + #include "tools.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + // --- cPalette -------------------------------------------------------------- + +@@ -720,6 +723,9 @@ int cOsd::osdTop = 0; + int cOsd::osdWidth = 0; + int cOsd::osdHeight = 0; + cVector<cOsd *> cOsd::Osds; ++#ifdef USE_PINPLUGIN ++bool cOsd::pinValid = false; ++#endif /* PINPLUGIN */ + + cOsd::cOsd(int Left, int Top, uint Level) + { +@@ -730,6 +736,9 @@ cOsd::cOsd(int Left, int Top, uint Level + width = height = 0; + level = Level; + active = false; ++#ifdef USE_YAEPG ++ vidWin.bpp = 0; ++#endif /* YAEPG */ + for (int i = 0; i < Osds.Size(); i++) { + if (Osds[i]->level > level) { + Osds.Insert(this, i); +diff -ruNp vdr-1.7.0/osd.h vdr-1.7.0-extensions/osd.h +--- vdr-1.7.0/osd.h 2007-10-12 16:28:44.000000000 +0200 ++++ vdr-1.7.0-extensions/osd.h 2009-04-09 20:48:48.000000000 +0200 +@@ -400,6 +400,12 @@ public: + ///< 7: vertical, falling, upper + virtual void Flush(void); + ///< Actually commits all data to the OSD hardware. ++#ifdef USE_PINPLUGIN ++ static bool pinValid; ++#endif /* PINPLUGIN */ ++#ifdef USE_YAEPG ++ tArea vidWin; ++#endif /* YAEPG */ + }; + + class cOsdProvider { +diff -ruNp vdr-1.7.0/player.c vdr-1.7.0-extensions/player.c +--- vdr-1.7.0/player.c 2007-07-20 17:25:24.000000000 +0200 ++++ vdr-1.7.0-extensions/player.c 2009-04-09 20:48:48.000000000 +0200 +@@ -60,10 +60,18 @@ cOsdObject *cControl::GetInfo(void) + return NULL; + } + ++#ifdef USE_LIVEBUFFER ++cControl *cControl::Control(bool Hidden) ++#else + cControl *cControl::Control(void) ++#endif /* LIVEBUFFER */ + { + cMutexLock MutexLock(&mutex); ++#ifdef USE_LIVEBUFFER ++ return (control && (!control->hidden || Hidden)) ? control : NULL; ++#else + return (control && !control->hidden) ? control : NULL; ++#endif /* LIVEBUFFER */ + } + + void cControl::Launch(cControl *Control) +diff -ruNp vdr-1.7.0/player.h vdr-1.7.0-extensions/player.h +--- vdr-1.7.0/player.h 2008-02-16 14:50:11.000000000 +0100 ++++ vdr-1.7.0-extensions/player.h 2009-04-09 20:48:48.000000000 +0200 +@@ -83,7 +83,11 @@ public: + static void Launch(cControl *Control); + static void Attach(void); + static void Shutdown(void); ++#ifdef USE_LIVEBUFFER ++ static cControl *Control(bool Hidden = false); ++#else + static cControl *Control(void); ++#endif /* LIVEBUFFER */ + }; + + #endif //__PLAYER_H +diff -ruNp vdr-1.7.0/plugin.c vdr-1.7.0-extensions/plugin.c +--- vdr-1.7.0/plugin.c 2008-02-17 14:32:12.000000000 +0100 ++++ vdr-1.7.0-extensions/plugin.c 2009-04-09 20:48:48.000000000 +0200 +@@ -316,6 +316,14 @@ void cPluginManager::AddPlugin(const cha + char *p = strchr(s, ' '); + if (p) + *p = 0; ++#ifdef USE_PLUGINMISSING ++ struct stat st; ++ if (stat (cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), &st) && errno == ENOENT) { ++ esyslog("WARN: missing plugin '%s'", s); ++ fprintf(stderr, "vdr: missing plugin '%s'\n", s); ++ } ++ else ++#endif /* PLUGINMISSING */ + dlls.Add(new cDll(cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), Args)); + free(s); + } +@@ -324,7 +332,11 @@ bool cPluginManager::LoadPlugins(bool Lo + { + for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) { + if (!dll->Load(Log)) ++#ifdef USE_PLUGINMISSING ++ ; ++#else + return false; ++#endif /* PLUGINMISSING */ + } + return true; + } +diff -ruNp vdr-1.7.0/po/ca_ES.po vdr-1.7.0-extensions/po/ca_ES.po +--- vdr-1.7.0/po/ca_ES.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/ca_ES.po 2009-04-09 20:48:48.000000000 +0200 +@@ -10,7 +10,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-02 19:02+0100\n" + "Last-Translator: Luca Olivetti <luca@ventoso.org>\n" + "Language-Team: Catalanian\n" +@@ -24,15 +24,12 @@ msgstr "off" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "cap" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Canal incorrecte ***" + +@@ -321,12 +318,6 @@ msgstr "Protegir" + msgid "Hierarchy" + msgstr "Jerarquia" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioritat" +- + msgid "Rolloff" + msgstr "" + +@@ -375,6 +366,9 @@ msgstr "Fi" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioritat" ++ + msgid "Lifetime" + msgstr "Durada" + +@@ -909,9 +903,6 @@ msgstr "Sobrescriure" + msgid "Button$Insert" + msgstr "Inserir" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1019,3 +1010,270 @@ msgstr "Prem qualsevol tecla per cancel· + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR s'apagarà en %s minuts" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/cs_CZ.po vdr-1.7.0-extensions/po/cs_CZ.po +--- vdr-1.7.0/po/cs_CZ.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/cs_CZ.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-02-28 15:00+0200\n" + "Last-Translator: Vladimír Bárta <vladimir.barta@k2atmitec.cz>, Jiøí Dobrý <jdobry@centrum.cz>\n" + "Language-Team: Czech\n" +@@ -22,15 +22,12 @@ msgstr "vyp." + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "¾ádný" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Neplatný kanál ***" + +@@ -319,12 +316,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarchy" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Priorita" +- + msgid "Rolloff" + msgstr "" + +@@ -373,6 +364,9 @@ msgstr "Konec" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Priorita" ++ + msgid "Lifetime" + msgstr "®ivotnost" + +@@ -907,9 +901,6 @@ msgstr "Pøepsat" + msgid "Button$Insert" + msgstr "Vlo¾it" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Modul" + +@@ -1017,3 +1008,270 @@ msgstr "Jakákoliv klávesa zru¹í restart" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se vypne za %s minut" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/da_DK.po vdr-1.7.0-extensions/po/da_DK.po +--- vdr-1.7.0/po/da_DK.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/da_DK.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2007-08-12 14:17+0200\n" + "Last-Translator: Mogens Elneff <mogens@elneff.dk>\n" + "Language-Team: Danish\n" +@@ -21,15 +21,12 @@ msgstr "fra" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "automatisk" ++ + msgid "none" + msgstr "ingen" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Ugyldig kanal! ***" + +@@ -318,12 +315,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarki" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioritet" +- + msgid "Rolloff" + msgstr "" + +@@ -372,6 +363,9 @@ msgstr "Stop" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioritet" ++ + msgid "Lifetime" + msgstr "Levetid" + +@@ -906,9 +900,6 @@ msgstr "Overskriv" + msgid "Button$Insert" + msgstr "Indsæt" + +-msgid "auto" +-msgstr "automatisk" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1016,3 +1007,270 @@ msgstr "Tryk vilkårlig knap for at annul + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR slukker om %s minutter" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/de_DE.po vdr-1.7.0-extensions/po/de_DE.po +--- vdr-1.7.0/po/de_DE.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/de_DE.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2007-11-25 15:19+0200\n" + "Last-Translator: Klaus Schmidinger <kls@cadsoft.de>\n" + "Language-Team: German\n" +@@ -21,15 +21,12 @@ msgstr "aus" + msgid "on" + msgstr "ein" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "keine" + +-msgid "high" +-msgstr "hoch" +- +-msgid "low" +-msgstr "niedrig" +- + msgid "*** Invalid Channel ***" + msgstr "*** Ungültiger Kanal ***" + +@@ -318,12 +315,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarchie" + +-msgid "Alpha" +-msgstr "Alpha" +- +-msgid "Priority" +-msgstr "Priorität" +- + msgid "Rolloff" + msgstr "Rolloff" + +@@ -372,6 +363,9 @@ msgstr "Ende" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Priorität" ++ + msgid "Lifetime" + msgstr "Lebensdauer" + +@@ -800,6 +794,30 @@ msgstr "Lautstärke beim Einschalten" + msgid "Setup.Miscellaneous$Emergency exit" + msgstr "Notausstieg" + ++msgid "Setup.Miscellaneous$Volume ctrl with left/right" ++msgstr "Lautstärke mit Rechts/Links regeln" ++ ++msgid "Setup.Miscellaneous$Channelgroups with left/right" ++msgstr "Kanalgruppen mit Rechts/Links" ++ ++msgid "Setup.Miscellaneous$only in channelinfo" ++msgstr "nur in Kanalinfo" ++ ++msgid "Setup.Miscellaneous$Search fwd/back with left/right" ++msgstr "Vor-/Rücklauf mit Rechts/Links" ++ ++msgid "Setup.Miscellaneous$only in progress display" ++msgstr "nur in Fortschrittsanzeige" ++ ++msgid "Setup.Miscellaneous$Lirc repeat delay" ++msgstr "Lirc Verzögerung" ++ ++msgid "Setup.Miscellaneous$Lirc repeat freq" ++msgstr "Lirc Frequenz" ++ ++msgid "Setup.Miscellaneous$Lirc repeat timeout" ++msgstr "Lirc Zeitbeschränkung" ++ + msgid "Plugins" + msgstr "Plugins" + +@@ -906,9 +924,6 @@ msgstr "Überschreiben" + msgid "Button$Insert" + msgstr "Einfügen" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1016,3 +1031,327 @@ msgstr "Taste drücken, um Neustart abzub + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR wird in %s Minuten ausschalten" ++ ++msgid "Parameters" ++msgstr "Parameter" ++ ++msgid "Channel locked by LNB!" ++msgstr "Kanal durch LNB gesperrt!" ++ ++msgid "Childlock" ++msgstr "Kindersicherung" ++ ++msgid "Path" ++msgstr "Pfad" ++ ++msgid "Timer commands" ++msgstr "Befehle für Aufzeichnungen" ++ ++msgid "Rename recording" ++msgstr "Aufzeichnung umbenennen" ++ ++msgid "Date" ++msgstr "Datum" ++ ++msgid "Length" ++msgstr "Länge" ++ ++msgid "Size" ++msgstr "Größe" ++ ++msgid "Delete marks information?" ++msgstr "Marks löschen?" ++ ++msgid "Delete resume information?" ++msgstr "Resume löschen?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "Das DVD-Plugin ist nicht installiert!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Alphabet für Haupt-, flexibel für Unterverzeichnisse" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Datum für Haupt-, flexibel für Unterverzeichnisse" ++ ++msgid "all alphabetically" ++msgstr "Alles alphabetisch" ++ ++msgid "all by date" ++msgstr "Alles nach Datum" ++ ++msgid "Sorting" ++msgstr "Sortierung" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle icons verwenden" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "Hauptmenü Titel" ++ ++msgid "Setup.OSD$- Text" ++msgstr "- Text" ++ ++msgid "default" ++msgstr "Voreinstellung" ++ ++msgid "VDR - text" ++msgstr "VDR - Text" ++ ++msgid "text" ++msgstr "Text" ++ ++msgid "VDR - version" ++msgstr "VDR - Version" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Befehle Position im Hauptmenü" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Zeige gültige Eingabe" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Zeitbalken anzeigen" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Zeitspanne für dop. EPG-Suche (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Doppelten externen EPG-Eintrag" ++ ++msgid "Setup.EPG$Mode of noEPG-Patch" ++msgstr "Art des noEPG-Patches" ++ ++msgid "adjust" ++msgstr "anwenden" ++ ++msgid "delete" ++msgstr "löschen" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Internes und externes EPG mischen" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Erk. des lauf. VPS-Events abschalten" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "AC3-Transfer Fix benutzen" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "Sperre Kanäle" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "Kanal Sperren Filter" ++ ++msgid "qam256" ++msgstr "qam256" ++ ++msgid "dvb-c" ++msgstr "dvb-c" ++ ++msgid "dvb-s" ++msgstr "dvb-s" ++ ++msgid "all" ++msgstr "alle" ++ ++msgid "blacklist" ++msgstr "Blacklist" ++ ++msgid "whitelist" ++msgstr "Whitelist" ++ ++msgid "has decoder" ++msgstr "mit Decoder" ++ ++msgid "is primary" ++msgstr "ist primär" ++ ++msgid "has decoder + is primary" ++msgstr "mit Decoder und primär" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Sync Early Patch benutzen" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "DVB-Empfänger %d nutzt LNB Nr." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "LNB-Nutzung protokollieren" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Dolby Digital Ton aufzeichnen" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Videoverzeichnispolitik" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Anzahl der Videoverzeichnisse" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d Priorität" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. MB frei" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Freundliche Dateinamen" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Max. Aufnahmengröße (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Hard Link Cutter" ++ ++msgid "Setup.Recording$Delete timeshift recording" ++msgstr "Zeitversetzte Aufnahme löschen" ++ ++msgid "request" ++msgstr "abfragen" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Aufnahmedatum anzeigen" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Aufnahmezeit anzeigen" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Länge der Aufnahme anzeigen" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Ende für Timer anzeigen" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Aufnahmen sortieren nach" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Verzeichnisse vor Aufnahmen einsortieren" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Aufnahmen nach dem Schneiden löschen" ++ ++msgid "Setup.Recording$Cutter adjust starttime" ++msgstr "Startzeit beim Schneiden anpassen" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Wiedergabe nach Sprung" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Sprung bei Schnittmarke" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause bei letzter Marke" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Marken aktualisieren" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Sprungweite in Sekunden" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Sprungweite in Sekunden Langsam" ++ ++msgid "Setup.Replay$Length" ++msgstr "Länge" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Länge / Nummer" ++ ++msgid "Setup.Replay$Number" ++msgstr "Nummer" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "DVD Anzeige" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "DVD führende Nullen anzeigen" ++ ++msgid "Setup.Replay$never" ++msgstr "nie" ++ ++msgid "Setup.Replay$on begin" ++msgstr "am Anfang" ++ ++msgid "Setup.Replay$on end" ++msgstr "am Ende" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "am Anfang und Ende" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "DVD-Schublade öffnen" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "DVD drosseln auf" ++ ++msgid "Jump" ++msgstr "Springen: " ++ ++msgid "Skip +60s" ++msgstr "Sprung +60s" ++ ++msgid "Skip -60s" ++msgstr "Sprung -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Schnitt bereits aktiv - zur Schnitt-Liste hinzufügen?" ++ ++msgid "Rename$Up" ++msgstr "Höher" ++ ++msgid "Rename$Down" ++msgstr "Tiefer" ++ ++msgid "Rename$Previous" ++msgstr "Vorheriger" ++ ++msgid "Rename$Next" ++msgstr "Nächster" ++ ++msgid "Please mount %s" ++msgstr "Bitte %s einlegen!" ++ ++msgid "Please mount DVD %04d" ++msgstr "Bitte DVD %04d einlegen!" ++ ++msgid "Please mount DVD %d" ++msgstr "Bitte DVD %d einlegen!" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Bitte warten. Überprüfe DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Keine Index-Datei gefunden. Erstellung kann Minuten dauern. Erstellen?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Bitte warten. Index-Datei wird erstellt..." ++ ++msgid "Wrong DVD!" ++msgstr "Falsche DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Permanentes Timeshift" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Speicherort" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "Festplatte" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "Arbeitsspeicher" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Puffergröße im Arbeitsspeicher (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Auf Festplatte ausweiten wenn nötig" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Pausierten Puffer beibehalten" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Puffergröße auf Festplatte (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Puffergröße (MB)" +diff -ruNp vdr-1.7.0/po/el_GR.po vdr-1.7.0-extensions/po/el_GR.po +--- vdr-1.7.0/po/el_GR.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/el_GR.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2007-08-12 14:17+0200\n" + "Last-Translator: Dimitrios Dimitrakos <mail@dimitrios.de>\n" + "Language-Team: Greek\n" +@@ -21,15 +21,12 @@ msgstr "êëåéóôü" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "áõôüìáôï" ++ + msgid "none" + msgstr "êáíÝíá" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Áêõñï êáíÜëç ***" + +@@ -318,12 +315,6 @@ msgstr "Ðñïóôáóßá" + msgid "Hierarchy" + msgstr "Éåñáñ÷åßá" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Ðñïôåñáéüôçôá" +- + msgid "Rolloff" + msgstr "" + +@@ -372,6 +363,9 @@ msgstr "ÔÝëïò" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Ðñïôåñáéüôçôá" ++ + msgid "Lifetime" + msgstr "ÄéÝñêåéá ÐáñáìïíÞò" + +@@ -906,9 +900,6 @@ msgstr "ÁíôéêáôÜóôáóç" + msgid "Button$Insert" + msgstr "ÅéóáãùãÞ" + +-msgid "auto" +-msgstr "áõôüìáôï" +- + msgid "Plugin" + msgstr "ÅðÝêôáóç" + +@@ -1016,3 +1007,270 @@ msgstr "" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/es_ES.po vdr-1.7.0-extensions/po/es_ES.po +--- vdr-1.7.0/po/es_ES.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/es_ES.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-02 19:02+0100\n" + "Last-Translator: Luca Olivetti <luca@ventoso.org>\n" + "Language-Team: Spanish\n" +@@ -22,15 +22,12 @@ msgstr "off" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "ninguno" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Canal no válido ***" + +@@ -319,12 +316,6 @@ msgstr "Int.Guarda" + msgid "Hierarchy" + msgstr "Jerarquía" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioridad" +- + msgid "Rolloff" + msgstr "" + +@@ -373,6 +364,9 @@ msgstr "Fin" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioridad" ++ + msgid "Lifetime" + msgstr "Duración" + +@@ -907,9 +901,6 @@ msgstr "Sobreescribir" + msgid "Button$Insert" + msgstr "Insertar" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1017,3 +1008,270 @@ msgstr "Pulse cualquier tecla para cance + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se apagará en %s minutos" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/et_EE.po vdr-1.7.0-extensions/po/et_EE.po +--- vdr-1.7.0/po/et_EE.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/et_EE.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2007-08-12 14:17+0200\n" + "Last-Translator: Arthur Konovalov <kasjas@hot.ee>\n" + "Language-Team: Estonian\n" +@@ -21,15 +21,12 @@ msgstr "väljas" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "automaatne" ++ + msgid "none" + msgstr "puudu" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Vigane kanal ***" + +@@ -318,12 +315,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarhia" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioriteet" +- + msgid "Rolloff" + msgstr "" + +@@ -372,6 +363,9 @@ msgstr "Stopp" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioriteet" ++ + msgid "Lifetime" + msgstr "Eluiga" + +@@ -906,9 +900,6 @@ msgstr "Asenda (OVR)" + msgid "Button$Insert" + msgstr "Lisa (INS)" + +-msgid "auto" +-msgstr "automaatne" +- + msgid "Plugin" + msgstr "Laiendusmoodul" + +@@ -1016,3 +1007,270 @@ msgstr "Restardi katkestamiseks vajuta s + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR lülitub välja %s minuti pärast" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "Ümbernimetamine" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Käsu asukoht peamenüüs" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Edenemisriba" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Salvestuse kuupäev" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Salvestuse kellaaeg" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Salvestuse pikkus" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "Üles" ++ ++msgid "Rename$Down" ++msgstr "Alla" ++ ++msgid "Rename$Previous" ++msgstr "Eelmine" ++ ++msgid "Rename$Next" ++msgstr "Järgmine" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/fi_FI.po vdr-1.7.0-extensions/po/fi_FI.po +--- vdr-1.7.0/po/fi_FI.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/fi_FI.po 2009-04-09 20:48:48.000000000 +0200 +@@ -10,7 +10,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2007-08-15 15:52+0200\n" + "Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n" + "Language-Team: Finnish\n" +@@ -24,15 +24,12 @@ msgstr "poissa" + msgid "on" + msgstr "päällä" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "tyhjä" + +-msgid "high" +-msgstr "korkea" +- +-msgid "low" +-msgstr "matala" +- + msgid "*** Invalid Channel ***" + msgstr "*** Virheellinen kanavavalinta ***" + +@@ -45,6 +42,253 @@ msgstr "Siirtotilan aloitus epäonnistui! + msgid "Starting EPG scan" + msgstr "Ohjelmaoppaan päivitys aloitettu" + ++msgid "Content$Movie/Drama" ++msgstr "Elokuva/draama" ++ ++msgid "Content$Detective/Thriller" ++msgstr "Etsivä/trilleri" ++ ++msgid "Content$Adventure/Western/War" ++msgstr "Seikkailu/western/sota" ++ ++msgid "Content$Science Fiction/Fantasy/Horror" ++msgstr "Scifi/fantasia/kauhu" ++ ++msgid "Content$Comedy" ++msgstr "Komedia" ++ ++msgid "Content$Soap/Melodrama/Folkloric" ++msgstr "Saippua/melodraama/kansanperinne" ++ ++msgid "Content$Romance" ++msgstr "Romanssi" ++ ++msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" ++msgstr "Vakava/klassinen/uskonnollinen/historiallinen elokuva/draama" ++ ++msgid "Content$Adult Movie/Drama" ++msgstr "Aikuiselokuva/draama" ++ ++msgid "Content$News/Current Affairs" ++msgstr "Uutiset/ajankohtaisohjelma" ++ ++msgid "Content$News/Weather Report" ++msgstr "Uutiset/säätiedot" ++ ++msgid "Content$News Magazine" ++msgstr "Uutismakasiini" ++ ++msgid "Content$Documentary" ++msgstr "Dokumentti" ++ ++msgid "Content$Discussion/Inverview/Debate" ++msgstr "Keskustelu/haastattelu/väittely" ++ ++msgid "Content$Show/Game Show" ++msgstr "Show/visailu" ++ ++msgid "Content$Game Show/Quiz/Contest" ++msgstr "Visailu/kilpailu" ++ ++msgid "Content$Variety Show" ++msgstr "Varietee" ++ ++msgid "Content$Talk Show" ++msgstr "Keskusteluohjelma" ++ ++msgid "Content$Sports" ++msgstr "Urheilua" ++ ++msgid "Content$Special Event" ++msgstr "Erikoistapahtuma" ++ ++msgid "Content$Sport Magazine" ++msgstr "Urheilumakasiini" ++ ++msgid "Content$Football" ++msgstr "Jalkapallo" ++ ++msgid "Content$Tennis/Squash" ++msgstr "Tennis/Squash" ++ ++msgid "Content$Team Sports" ++msgstr "Joukkueurheilua" ++ ++msgid "Content$Athletics" ++msgstr "Yleisurheilua" ++ ++msgid "Content$Motor Sport" ++msgstr "Moottoriurheilua" ++ ++msgid "Content$Water Sport" ++msgstr "Vesiurheilua" ++ ++msgid "Content$Winter Sports" ++msgstr "Talviurheilua" ++ ++msgid "Content$Equestrian" ++msgstr "Ratsastusta" ++ ++msgid "Content$Martial Sports" ++msgstr "Kamppailu-urheilua" ++ ++msgid "Content$Children's/Youth Programmes" ++msgstr "Lasten ja nuorten ohjelma" ++ ++msgid "Content$Pre-school Children's Programmes" ++msgstr "Alle kouluikäisten ohjelma" ++ ++msgid "Content$Entertainment Programmes for 6 to 14" ++msgstr "Viihdeohjelma 6-14 vuotiaille" ++ ++msgid "Content$Entertainment Programmes for 10 to 16" ++msgstr "Viihdeohjelma 10-16 vuotiaille" ++ ++msgid "Content$Informational/Educational/School Programme" ++msgstr "Opetus/kouluohjelma" ++ ++msgid "Content$Cartoons/Puppets" ++msgstr "Piirretty/nukke-esitys" ++ ++msgid "Content$Music/Ballet/Dance" ++msgstr "Musiikki/baletti/tanssi" ++ ++msgid "Content$Rock/Pop" ++msgstr "Rock/pop" ++ ++msgid "Content$Serious/Classical Music" ++msgstr "Vakava/klassinen musiikki" ++ ++msgid "Content$Folk/Tradional Music" ++msgstr "Folk/kansanmusiikki" ++ ++msgid "Content$Jazz" ++msgstr "Jazz" ++ ++msgid "Content$Musical/Opera" ++msgstr "Musikaali/ooppera" ++ ++msgid "Content$Ballet" ++msgstr "Baletti" ++ ++msgid "Content$Arts/Culture" ++msgstr "Taide/kulttuuri" ++ ++msgid "Content$Performing Arts" ++msgstr "Performanssitaide" ++ ++msgid "Content$Fine Arts" ++msgstr "Kuvataide" ++ ++msgid "Content$Religion" ++msgstr "Uskonto" ++ ++msgid "Content$Popular Culture/Traditional Arts" ++msgstr "Populaarikulttuuri/perinnetaiteet" ++ ++msgid "Content$Literature" ++msgstr "Kirjallisuus" ++ ++msgid "Content$Film/Cinema" ++msgstr "Elokuvataide" ++ ++msgid "Content$Experimental Film/Video" ++msgstr "Kokeellinen elokuva/video" ++ ++msgid "Content$Broadcasting/Press" ++msgstr "Televisio/radio/lehdistö" ++ ++msgid "Content$New Media" ++msgstr "Uusmedia" ++ ++msgid "Content$Arts/Culture Magazines" ++msgstr "Taide/kulttuurimakasiini" ++ ++msgid "Content$Fashion" ++msgstr "Muoti" ++ ++msgid "Content$Social/Political/Economics" ++msgstr "Yhteiskunta/politiikka/talous" ++ ++msgid "Content$Magazines/Reports/Documentary" ++msgstr "Makasiini/reportaasi/dokumentti" ++ ++msgid "Content$Economics/Social Advisory" ++msgstr "Talous/yhteiskunnallinen neuvonta" ++ ++msgid "Content$Remarkable People" ++msgstr "Merkittävät henkilöt" ++ ++msgid "Content$Education/Science/Factual" ++msgstr "Koulutus/tiede" ++ ++msgid "Content$Nature/Animals/Environment" ++msgstr "Luonto/eläimet/ympäristö" ++ ++msgid "Content$Technology/Natural Sciences" ++msgstr "Teknologia/luonnontiede" ++ ++msgid "Content$Medicine/Physiology/Psychology" ++msgstr "Lääketiede/fysiologia/psykologia" ++ ++msgid "Content$Foreign Countries/Expeditions" ++msgstr "Vieraat maat/tutkimusretket" ++ ++msgid "Content$Social/Spiritual Sciences" ++msgstr "Yhteiskunta/hengelliset tieteet" ++ ++msgid "Content$Further Education" ++msgstr "Jatkokoulutus" ++ ++msgid "Content$Languages" ++msgstr "Kielet" ++ ++msgid "Content$Leisure/Hobbies" ++msgstr "Vapaa-aika ja harrastukset" ++ ++msgid "Content$Tourism/Travel" ++msgstr "Turismi/matkustaminen" ++ ++msgid "Content$Handicraft" ++msgstr "Käsityöt" ++ ++msgid "Content$Motoring" ++msgstr "Autoilu" ++ ++msgid "Content$Fitness & Health" ++msgstr "Kuntoilu & terveys" ++ ++msgid "Content$Cooking" ++msgstr "Ruuanlaitto" ++ ++msgid "Content$Advertisement/Shopping" ++msgstr "Mainostaminen/ostaminen" ++ ++msgid "Content$Gardening" ++msgstr "Puutarhanhoito" ++ ++msgid "Content$Original Language" ++msgstr "Alkuperäiskieli" ++ ++msgid "Content$Black & White" ++msgstr "Mustavalkoinen" ++ ++msgid "Content$Unpublished" ++msgstr "Julkaisematon" ++ ++msgid "Content$Live Broadcast" ++msgstr "Suoralähetys" ++ ++msgid "Content$Special Characteristics" ++msgstr "Erikoisominaisuus" ++ ++msgid "Content$Drama" ++msgstr "Draama" ++ ++#, c-format ++msgid "Suitable for those aged %d and over" ++msgstr "Kielletty alle %d vuotiailta" ++ + msgid "No title" + msgstr "Ei esitystä" + +@@ -321,12 +565,6 @@ msgstr "Suojaväli" + msgid "Hierarchy" + msgstr "Hierarkia" + +-msgid "Alpha" +-msgstr "Alpha" +- +-msgid "Priority" +-msgstr "Prioriteetti" +- + msgid "Rolloff" + msgstr "Rolloff" + +@@ -375,6 +613,9 @@ msgstr "Lopetus" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioriteetti" ++ + msgid "Lifetime" + msgstr "Elinikä" + +@@ -909,9 +1150,6 @@ msgstr "Korvaa" + msgid "Button$Insert" + msgstr "Lisää" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Laajennos" + +@@ -1019,3 +1257,273 @@ msgstr "Peru uudelleenkäynnistys painama + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR sammuu %s minuutin kuluttua" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "Polku" ++ ++msgid "Timer commands" ++msgstr "Ajastinkomennot" ++ ++msgid "Rename recording" ++msgstr "Nimeä tallenne" ++ ++msgid "Date" ++msgstr "Päiväys" ++ ++msgid "Length" ++msgstr "Pituus" ++ ++msgid "Size" ++msgstr "Koko" ++ ++msgid "Delete marks information?" ++msgstr "Poista tallenteen merkinnät" ++ ++msgid "Delete resume information?" ++msgstr "Poista tallenteen paluutiedot" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Komentojen sijainti päävalikossa" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Näytä aikajana" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Dolby Digital tallennus" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Näytä tallenteen päiväys" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Näytä tallenteen ajankohta" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Näytä tallenteen kesto" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "Ylemmäs" ++ ++msgid "Rename$Down" ++msgstr "Alemmas" ++ ++msgid "Rename$Previous" ++msgstr "Edellinen" ++ ++msgid "Rename$Next" ++msgstr "Seuraava" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Parameters" ++msgstr "Parametrit" ++ ++msgid "Permanent Timeshift" ++msgstr "Jatkuva ajansiirto" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Puskurin sijainti" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "kovalevyllä" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "muistissa" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Puffergröße im Arbeitsspeicher (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Käytä kovalevyä tarvittaessa" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Pidä pysäytetty puskuri" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Puffergröße auf Festplatte (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Puskurin koko (MB)" +diff -ruNp vdr-1.7.0/po/fr_FR.po vdr-1.7.0-extensions/po/fr_FR.po +--- vdr-1.7.0/po/fr_FR.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/fr_FR.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,12 +8,13 @@ + # Pierre Briec <pbriec@free.fr>, 2006 + # Bruno Roussel <bruno.roussel@free.fr>, 2007 + # Michael Nival <mnival@club-internet.fr>, 2007 ++# Patrice Staudt <patrice.staudt@laposte.net>, 2007, 2008 + # + msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-02-27 18:14+0100\n" + "Last-Translator: Jean-Claude Repetto <jc@repetto.org>\n" + "Language-Team: French\n" +@@ -27,15 +28,12 @@ msgstr "off" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "aucun" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Chaîne invalide ! ***" + +@@ -324,12 +322,6 @@ msgstr "Intervalle de garde" + msgid "Hierarchy" + msgstr "Hiérarchie" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Priorité" +- + msgid "Rolloff" + msgstr "" + +@@ -378,6 +370,9 @@ msgstr "Fin" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Priorité" ++ + msgid "Lifetime" + msgstr "Durée de vie" + +@@ -912,9 +907,6 @@ msgstr "Ecraser" + msgid "Button$Insert" + msgstr "Insérer" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1022,3 +1014,270 @@ msgstr "Appuyer sur une touche pour annu + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR s'arrêtera dans %s minutes" ++ ++msgid "Channel locked by LNB!" ++msgstr "Chaîne interdite par la LNB" ++ ++msgid "Childlock" ++msgstr "Adulte" ++ ++msgid "Path" ++msgstr "Dossiers" ++ ++msgid "Timer commands" ++msgstr "Commandes de programmation" ++ ++msgid "Rename recording" ++msgstr "Renommer l'enregistrement" ++ ++msgid "Date" ++msgstr "Date" ++ ++msgid "Length" ++msgstr "Longeur" ++ ++msgid "Size" ++msgstr "Taille" ++ ++msgid "Delete marks information?" ++msgstr "Effacer marque d'information?" ++ ++msgid "Delete resume information?" ++msgstr "Effacer resume information?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "Le plugin de DVD n'est pas installé!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Dir principal alphabétiquement, subdirs flexibles" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Dir principal à la date, subdirs flexibles" ++ ++msgid "all alphabetically" ++msgstr "tous alphabétiquement" ++ ++msgid "all by date" ++msgstr "tous à la date" ++ ++msgid "Sorting" ++msgstr "Triage" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "Icônes WarEagle" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Position des commandes dans le menu" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Afficher l'entrée valide" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Montrer la barre de progression" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Intervalle de recherche EPG de double(min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Double entrée EPG externe" ++ ++msgid "adjust" ++msgstr "ajuster" ++ ++msgid "delete" ++msgstr "effacer" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mélanger les EPG interne et externe" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Arreter la reconnaissance des événements VPS" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Utiliser le correctif AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Utilisez Sync début patch" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "La carte DVB %d utilise la LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Protocoller l'utilisation du LNB" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Enregistrer en Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Régles de répertoires vidéo" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Nombre de répertoires vidéo" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d prioritaires" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. librei Mo" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Noms de fichiers facile" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Taille max. de l'enregistrement (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Découpe Hard links" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Montrer la date d'enregistrement" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Montrer l'heure d'enregistrement" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Monter la longueur de l'enregistrement" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Montrer la fin du temporisateur" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Ordonner les enregistrement suivant" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Les dossiers devant les enregistrements" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Effacer l'enregistrement après la découpe" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Lecture après saut" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Saut sur les marques de découpes" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause après la dernière marque" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Actualiser les marques" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Longueur de saut en secondes" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Longueur de saut lent en secondes" ++ ++msgid "Setup.Replay$Length" ++msgstr "Longueur" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Longueur / Numéro" ++ ++msgid "Setup.Replay$Number" ++msgstr "Numéro" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "Afficher le DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "Afficher les zéros devant le numéro du DVD" ++ ++msgid "Setup.Replay$never" ++msgstr "jamais" ++ ++msgid "Setup.Replay$on begin" ++msgstr "au début" ++ ++msgid "Setup.Replay$on end" ++msgstr "à la fin" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "au début et à la fin" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Ouvrir le tiroir du lecteur DVD" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Ralentir la vitesse du DVD à" ++ ++msgid "Jump" ++msgstr "Saut" ++ ++msgid "Skip +60s" ++msgstr "Avance +60s" ++ ++msgid "Skip -60s" ++msgstr "Recule -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Découpe déjà active - l'ajouter à la liste de découpe?" ++ ++msgid "Rename$Up" ++msgstr "Haut" ++ ++msgid "Rename$Down" ++msgstr "Bas" ++ ++msgid "Rename$Previous" ++msgstr "Précédent" ++ ++msgid "Rename$Next" ++msgstr "Suivant" ++ ++msgid "Please mount %s" ++msgstr "Mettez %s dans le lecteur" ++ ++msgid "Please mount DVD %04d" ++msgstr "Mettez le DVD %04d dans le lecteur" ++ ++msgid "Please mount DVD %d" ++msgstr "Mettez le DVD %d dans le lecteur" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Un moment SVP. Vérification du DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Pas trouvé de fichiers index. La création de ce ficher prends quelques minutes. Créer?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Attendez, svp. Le fichier index est en cours de création..." ++ ++msgid "Wrong DVD!" ++msgstr "Mauvais DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Timeshift permanent" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Localisation" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "disque dur" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "mémoire" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Taille de la mémoire tampon dans la mémoire (Mo)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Ètendre au disque dur, si nécessaire" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Gardez en veille la mémoire tampon" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Taille de la mémoire tampon sur le disque dur (Mo)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Taille de la mémoire tampon (Mo)" +diff -ruNp vdr-1.7.0/po/hr_HR.po vdr-1.7.0-extensions/po/hr_HR.po +--- vdr-1.7.0/po/hr_HR.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/hr_HR.po 2009-04-09 20:48:48.000000000 +0200 +@@ -9,7 +9,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-17 19:00+0100\n" + "Last-Translator: Adrian Caval <anrxc@sysphere.org>\n" + "Language-Team: Croatian\n" +@@ -23,15 +23,12 @@ msgstr "iskljuèi" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "automatski" ++ + msgid "none" + msgstr "ni¹ta" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Neispravan Program ***" + +@@ -320,12 +317,6 @@ msgstr "Za¹tita" + msgid "Hierarchy" + msgstr "Hijerarhija" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioritet" +- + msgid "Rolloff" + msgstr "" + +@@ -374,6 +365,9 @@ msgstr "Kraj" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioritet" ++ + msgid "Lifetime" + msgstr "Trajanje" + +@@ -908,9 +902,6 @@ msgstr "Prepi¹i" + msgid "Button$Insert" + msgstr "Umetni" + +-msgid "auto" +-msgstr "automatski" +- + msgid "Plugin" + msgstr "Dodatak" + +@@ -1018,3 +1009,270 @@ msgstr "Pritisnite jednu tipku za poni¹t + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR æe se iskljuèiti za %s minuta" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/hu_HU.po vdr-1.7.0-extensions/po/hu_HU.po +--- vdr-1.7.0/po/hu_HU.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/hu_HU.po 2009-04-09 20:48:48.000000000 +0200 +@@ -10,7 +10,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2007-12-01 21:42+0200\n" + "Last-Translator: István Füley <ifuley@tigercomp.ro>\n" + "Language-Team: Hungarian\n" +@@ -24,15 +24,12 @@ msgstr "ki" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "semmi" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Érvénytelen csatorna ***" + +@@ -321,12 +318,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarhia" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioritás" +- + msgid "Rolloff" + msgstr "" + +@@ -375,6 +366,9 @@ msgstr "Vége" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioritás" ++ + msgid "Lifetime" + msgstr "Élettartam" + +@@ -909,9 +903,6 @@ msgstr "Átírni" + msgid "Button$Insert" + msgstr "Beilleszteni" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1019,3 +1010,270 @@ msgstr "Nyomj egy gombot az újraindítás + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "A VDR leáll %s perc múlva" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/it_IT.po vdr-1.7.0-extensions/po/it_IT.po +--- vdr-1.7.0/po/it_IT.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/it_IT.po 2009-04-09 20:48:48.000000000 +0200 +@@ -11,10 +11,10 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" +-"PO-Revision-Date: 2008-03-08 21:06+0100\n" ++"POT-Creation-Date: 2008-10-05 05:55+0200\n" ++"PO-Revision-Date: 2008-10-05 05:57+0100\n" + "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" +-"Language-Team: Italian\n" ++"Language-Team: Italian\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=ISO-8859-15\n" + "Content-Transfer-Encoding: 8bit\n" +@@ -25,18 +25,18 @@ msgstr "off" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "automatico" ++ + msgid "none" + msgstr "nessuno" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Canale NON valido ***" + ++msgid "Channel locked by LNB!" ++msgstr "Canale bloccato dal LNB!" ++ + msgid "Channel not available!" + msgstr "Canale non disponibile!" + +@@ -46,6 +46,253 @@ msgstr "Impossibile avviare mod. trasfer + msgid "Starting EPG scan" + msgstr "Inizio scansione EPG" + ++msgid "Content$Movie/Drama" ++msgstr "Film/Dramma" ++ ++msgid "Content$Detective/Thriller" ++msgstr "Investigativo/Giallo" ++ ++msgid "Content$Adventure/Western/War" ++msgstr "Avventura/Western/Guerra" ++ ++msgid "Content$Science Fiction/Fantasy/Horror" ++msgstr "Finzione/Fantasia/Horror" ++ ++msgid "Content$Comedy" ++msgstr "Commedia" ++ ++msgid "Content$Soap/Melodrama/Folkloric" ++msgstr "Telenovella/Melodramma/Folcloristico" ++ ++msgid "Content$Romance" ++msgstr "Romanzo" ++ ++msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" ++msgstr "Serio/Classico/Religioso/Film storico/Dramma" ++ ++msgid "Content$Adult Movie/Drama" ++msgstr "Film per adulti/Dramma" ++ ++msgid "Content$News/Current Affairs" ++msgstr "Notizie/Ultima ora" ++ ++msgid "Content$News/Weather Report" ++msgstr "Notizie/Previsioni meteo" ++ ++msgid "Content$News Magazine" ++msgstr "Rivista di notizie" ++ ++msgid "Content$Documentary" ++msgstr "Documentario" ++ ++msgid "Content$Discussion/Inverview/Debate" ++msgstr "Discussione/Intervista/Dibattito" ++ ++msgid "Content$Show/Game Show" ++msgstr "Spettacolo/Gioco a premi" ++ ++msgid "Content$Game Show/Quiz/Contest" ++msgstr "Gioco a premi/Quiz/Gara" ++ ++msgid "Content$Variety Show" ++msgstr "Spettacolo di varietà" ++ ++msgid "Content$Talk Show" ++msgstr "Talk Show" ++ ++msgid "Content$Sports" ++msgstr "Sport" ++ ++msgid "Content$Special Event" ++msgstr "Evento speciale" ++ ++msgid "Content$Sport Magazine" ++msgstr "Rivista di sport" ++ ++msgid "Content$Football" ++msgstr "Calcio" ++ ++msgid "Content$Tennis/Squash" ++msgstr "Tennis/Squash" ++ ++msgid "Content$Team Sports" ++msgstr "Sport di squadra" ++ ++msgid "Content$Athletics" ++msgstr "Atletica" ++ ++msgid "Content$Motor Sport" ++msgstr "Sport motoristici" ++ ++msgid "Content$Water Sport" ++msgstr "Sport acquatici" ++ ++msgid "Content$Winter Sports" ++msgstr "Sport invernali" ++ ++msgid "Content$Equestrian" ++msgstr "Equitazione" ++ ++msgid "Content$Martial Sports" ++msgstr "Arti marziali" ++ ++msgid "Content$Children's/Youth Programmes" ++msgstr "Programmi per ragazzi/giovani" ++ ++msgid "Content$Pre-school Children's Programmes" ++msgstr "Programmi per ragazzi prescolastici" ++ ++msgid "Content$Entertainment Programmes for 6 to 14" ++msgstr "Programmi di intrattenimento da 6 a 14" ++ ++msgid "Content$Entertainment Programmes for 10 to 16" ++msgstr "Programmi di intrattenimento da 10 a 16" ++ ++msgid "Content$Informational/Educational/School Programme" ++msgstr "Informativo/Educativo/Programma scolastico" ++ ++msgid "Content$Cartoons/Puppets" ++msgstr "Cartoni/Pupazzi" ++ ++msgid "Content$Music/Ballet/Dance" ++msgstr "Musica/Balletto/Danza" ++ ++msgid "Content$Rock/Pop" ++msgstr "Rock/Pop" ++ ++msgid "Content$Serious/Classical Music" ++msgstr "Serio/Musica classica" ++ ++msgid "Content$Folk/Tradional Music" ++msgstr "Folclore/Musica tradizionale" ++ ++msgid "Content$Jazz" ++msgstr "Jazz" ++ ++msgid "Content$Musical/Opera" ++msgstr "Musical/Opera" ++ ++msgid "Content$Ballet" ++msgstr "Balletto" ++ ++msgid "Content$Arts/Culture" ++msgstr "Arte/Cultura" ++ ++msgid "Content$Performing Arts" ++msgstr "Arti di rendimento" ++ ++msgid "Content$Fine Arts" ++msgstr "Arti fine" ++ ++msgid "Content$Religion" ++msgstr "Religione" ++ ++msgid "Content$Popular Culture/Traditional Arts" ++msgstr "Cultura popolare/Arti tradizionali" ++ ++msgid "Content$Literature" ++msgstr "Letteratura" ++ ++msgid "Content$Film/Cinema" ++msgstr "Film/Cinema" ++ ++msgid "Content$Experimental Film/Video" ++msgstr "Film esperimentale/Video" ++ ++msgid "Content$Broadcasting/Press" ++msgstr "Trasmissione/Stampa" ++ ++msgid "Content$New Media" ++msgstr "Nuovo programma" ++ ++msgid "Content$Arts/Culture Magazines" ++msgstr "Arte/Riviste di cultura" ++ ++msgid "Content$Fashion" ++msgstr "Moda" ++ ++msgid "Content$Social/Political/Economics" ++msgstr "Società/Politica/Economia" ++ ++msgid "Content$Magazines/Reports/Documentary" ++msgstr "Riviste/Reportage/Documentari" ++ ++msgid "Content$Economics/Social Advisory" ++msgstr "Economia/Consulenza sociale" ++ ++msgid "Content$Remarkable People" ++msgstr "Personaggi importanti" ++ ++msgid "Content$Education/Science/Factual" ++msgstr "Educazione/Scienza/Fatti" ++ ++msgid "Content$Nature/Animals/Environment" ++msgstr "Natura/Animali/Ambiente" ++ ++msgid "Content$Technology/Natural Sciences" ++msgstr "Tecnologia/Scienze naturali" ++ ++msgid "Content$Medicine/Physiology/Psychology" ++msgstr "Medicina/Filosofia/Psicologia" ++ ++msgid "Content$Foreign Countries/Expeditions" ++msgstr "Paesi esteri/Spedizioni" ++ ++msgid "Content$Social/Spiritual Sciences" ++msgstr "Società/Scienze spirituali" ++ ++msgid "Content$Further Education" ++msgstr "Altra educazione" ++ ++msgid "Content$Languages" ++msgstr "Lingua" ++ ++msgid "Content$Leisure/Hobbies" ++msgstr "Tempo libero/Hobby" ++ ++msgid "Content$Tourism/Travel" ++msgstr "Turismo/Viaggi" ++ ++msgid "Content$Handicraft" ++msgstr "Artigianato" ++ ++msgid "Content$Motoring" ++msgstr "Motori" ++ ++msgid "Content$Fitness & Health" ++msgstr "Culturismo & Salute" ++ ++msgid "Content$Cooking" ++msgstr "Cucina" ++ ++msgid "Content$Advertisement/Shopping" ++msgstr "Pubblicità/Acquisti" ++ ++msgid "Content$Gardening" ++msgstr "Giardinaggio" ++ ++msgid "Content$Original Language" ++msgstr "Lingua madre" ++ ++msgid "Content$Black & White" ++msgstr "Bianco & Nero" ++ ++msgid "Content$Unpublished" ++msgstr "Non pubblicato" ++ ++msgid "Content$Live Broadcast" ++msgstr "ys" ++ ++msgid "Content$Special Characteristics" ++msgstr "Caratteristiche speciali" ++ ++msgid "Content$Drama" ++msgstr "Dramma" ++ ++#, c-format ++msgid "Suitable for those aged %d and over" ++msgstr "Adatto per coloro con %d di età e oltre" ++ + msgid "No title" + msgstr "Senza titolo" + +@@ -232,11 +479,14 @@ msgstr "Utente8" + msgid "Key$User9" + msgstr "Utente9" + ++msgid "Recording started" ++msgstr "Registrazione avviata" ++ + msgid "Disk" + msgstr "Disco" + + msgid "free" +-msgstr "liberi" ++msgstr "disponibili" + + msgid "Free To Air" + msgstr "in chiaro" +@@ -322,15 +572,12 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Gerarchia" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Priorità" +- + msgid "Rolloff" + msgstr "" + ++msgid "Parameters" ++msgstr "Parametri" ++ + msgid "Channel settings are not unique!" + msgstr "Parametri canale non univoci!" + +@@ -376,12 +623,27 @@ msgstr "Fine" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Priorità" ++ + msgid "Lifetime" +-msgstr "Durata" ++msgstr "Scadenza" ++ ++msgid "Childlock" ++msgstr "Filtro fam." ++ ++msgid "yes" ++msgstr "sì" ++ ++msgid "no" ++msgstr "no" + + msgid "File" + msgstr "Nome" + ++msgid "Path" ++msgstr "Percorso" ++ + msgid "First day" + msgstr "1° giorno" + +@@ -400,6 +662,9 @@ msgstr "Eliminare il timer?" + msgid "Timer still recording - really delete?" + msgstr "Timer in registrazione - eliminare?" + ++msgid "Timer commands" ++msgstr "Comandi timer" ++ + msgid "Event" + msgstr "Evento" + +@@ -419,20 +684,20 @@ msgid "What's on next?" + msgstr "Prossimi programmi" + + msgid "Button$Next" +-msgstr "Prossimo" ++msgstr "Prossimi" + + msgid "Button$Now" + msgstr "Adesso" + + msgid "Button$Schedule" +-msgstr "Programma" ++msgstr "Programmi" + + msgid "Can't switch channel!" + msgstr "Impossibile cambiare canale!" + + #, c-format + msgid "Schedule - %s" +-msgstr "Programma - %s" ++msgstr "Programmi - %s" + + #, c-format + msgid "This event - %s" +@@ -460,6 +725,27 @@ msgstr "Riproduci" + msgid "Button$Rewind" + msgstr "Riavvolgi" + ++msgid "Rename recording" ++msgstr "Rinomina registrazione" ++ ++msgid "Date" ++msgstr "Data" ++ ++msgid "Length" ++msgstr "Durata" ++ ++msgid "Size" ++msgstr "Dimensione" ++ ++msgid "Delete marks information?" ++msgstr "Eliminare informazione marcatori?" ++ ++msgid "Delete resume information?" ++msgstr "Eliminare informazione ripristino?" ++ ++msgid "Error while accessing recording!" ++msgstr "Errore accesso alla registrazione!" ++ + msgid "Recordings" + msgstr "Registrazioni" + +@@ -469,8 +755,8 @@ msgstr "Apri" + msgid "Commands" + msgstr "Comandi" + +-msgid "Error while accessing recording!" +-msgstr "Errore accesso alla registrazione!" ++msgid "DVD plugin is not installed!" ++msgstr "Il plugin DVD non è installato!" + + msgid "Delete recording?" + msgstr "Eliminare la registrazione?" +@@ -481,6 +767,21 @@ msgstr "Errore eliminazione registrazion + msgid "Recording commands" + msgstr "Comandi di registrazione" + ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Dir. princ. in ordine alfabetico, sottodir. flessibili" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Dir. princ. per data, sottodir. flessibili" ++ ++msgid "all alphabetically" ++msgstr "Tutte in ordine alfabetico" ++ ++msgid "all by date" ++msgstr "Tutte per data" ++ ++msgid "Sorting" ++msgstr "Ordinamento" ++ + msgid "never" + msgstr "mai" + +@@ -490,6 +791,18 @@ msgstr "in base allo stile interfaccia" + msgid "always" + msgstr "sempre" + ++msgid "default" ++msgstr "predefinito" ++ ++msgid "VDR - text" ++msgstr "VDR - Testo" ++ ++msgid "text" ++msgstr "Testo" ++ ++msgid "VDR - version" ++msgstr "VDR - Versione" ++ + msgid "OSD" + msgstr "OSD" + +@@ -502,6 +815,9 @@ msgstr "Stile interfaccia" + msgid "Setup.OSD$Theme" + msgstr "Tema colori" + ++msgid "Setup.OSD$WarEagle icons" ++msgstr "Icone WarEagle" ++ + msgid "Setup.OSD$Left" + msgstr "Sinistra" + +@@ -515,7 +831,7 @@ msgid "Setup.OSD$Height" + msgstr "Altezza OSD" + + msgid "Setup.OSD$Message time (s)" +-msgstr "Tempo del messaggio (s)" ++msgstr "Durata del messaggio (s)" + + msgid "Setup.OSD$Use small font" + msgstr "Utilizza caratteri piccoli" +@@ -571,12 +887,30 @@ msgstr "Tasto Menu per chiudere" + msgid "Setup.OSD$Recording directories" + msgstr "Directory di registrazione" + ++msgid "Setup.OSD$Main menu title" ++msgstr "Titolo menu principale" ++ ++msgid "Setup.OSD$- Text" ++msgstr "- Testo" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Posizione comandi menu princ." ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Mostra ingresso valido" ++ + msgid "EPG" + msgstr "Guida programmi EPG" + + msgid "Button$Scan" + msgstr "Scansione" + ++msgid "blacklist" ++msgstr "lista nera" ++ ++msgid "whitelist" ++msgstr "elenco autorizzati" ++ + msgid "Setup.EPG$EPG scan timeout (h)" + msgstr "Scadenza aggiorn. EPG (ore)" + +@@ -586,8 +920,11 @@ msgstr "Livello correzione EPG" + msgid "Setup.EPG$EPG linger time (min)" + msgstr "Mostra vecchi dati EPG (min)" + ++msgid "Setup.EPG$Show progress bar" ++msgstr "Mostra barra avanzamento" ++ + msgid "Setup.EPG$Set system time" +-msgstr "Imposta orario automatico" ++msgstr "Imposta orario di sistema" + + msgid "Setup.EPG$Use time from transponder" + msgstr "Utilizza orario da transponder" +@@ -600,6 +937,27 @@ msgstr "Lingue preferite" + msgid "Setup.EPG$Preferred language" + msgstr "Lingua preferita" + ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Tempo doppia ricerca EPG (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Doppio valore EPG esterno" ++ ++msgid "adjust" ++msgstr "regola" ++ ++msgid "delete" ++msgstr "elimina" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mescola EPG interno e esterno" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Disabilita esec. evento VPS" ++ ++msgid "Setup.EPG$Mode of noEPG-Patch" ++msgstr "Modalità di noEPG-Patch" ++ + msgid "pan&scan" + msgstr "pan&scan" + +@@ -609,9 +967,6 @@ msgstr "letterbox" + msgid "center cut out" + msgstr "center cut out" + +-msgid "no" +-msgstr "no" +- + msgid "names only" + msgstr "solo nomi" + +@@ -630,6 +985,27 @@ msgstr "nuovi transponder" + msgid "DVB" + msgstr "Scheda DVB" + ++msgid "qam256" ++msgstr "qam256" ++ ++msgid "dvb-c" ++msgstr "dvb-c" ++ ++msgid "dvb-s" ++msgstr "dvb-s" ++ ++msgid "all" ++msgstr "tutti" ++ ++msgid "has decoder" ++msgstr "con decoder" ++ ++msgid "is primary" ++msgstr "primaria" ++ ++msgid "has decoder + is primary" ++msgstr "con decoder e primaria" ++ + msgid "Setup.DVB$Primary DVB interface" + msgstr "Scheda DVB primaria" + +@@ -637,13 +1013,13 @@ msgid "Setup.DVB$Video format" + msgstr "Formato video" + + msgid "Setup.DVB$Video display format" +-msgstr "Formato di visualizz. video" ++msgstr "Formato visualizzazione video" + + msgid "Setup.DVB$Use Dolby Digital" + msgstr "Dolby Digital" + + msgid "Setup.DVB$Update channels" +-msgstr "Aggiorna i canali" ++msgstr "Aggiornamento canali" + + msgid "Setup.DVB$Audio languages" + msgstr "Lingue audio" +@@ -669,9 +1045,28 @@ msgstr "Trasparenza sottotitoli" + msgid "Setup.DVB$Subtitle background transparency" + msgstr "Trasparenza sfondo sottotitoli" + ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Utilizza correzione AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "Blocco canale" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "Modalità filtro blocco canale" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Utilizza correzione Early Sync" ++ + msgid "LNB" + msgstr "LNB" + ++#, c-format ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "La scheda DVB %d utilizza LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Registra utilizzo LNB" ++ + msgid "Setup.LNB$Use DiSEqC" + msgstr "Utilizza DiSEqC" + +@@ -714,6 +1109,9 @@ msgstr "La CAM è in uso - vuoi reimposta + msgid "Can't reset CAM!" + msgstr "Impossibile reimpostare il modulo CAM!" + ++msgid "request" ++msgstr "chiedi" ++ + msgid "Recording" + msgstr "Registrazione" + +@@ -730,17 +1128,37 @@ msgid "Setup.Recording$Default priority" + msgstr "Priorità predefinita" + + msgid "Setup.Recording$Default lifetime (d)" +-msgstr "Durata predefinita (gg)" ++msgstr "Scadenza predefinita (gg)" + + msgid "Setup.Recording$Pause priority" + msgstr "Priorità di pausa" + + msgid "Setup.Recording$Pause lifetime (d)" +-msgstr "Durata pausa (gg)" ++msgstr "Scadenza pausa (gg)" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Registra Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Regole directory video" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Numero di directory video" ++ ++#, c-format ++msgid "Setup.Recording$Video %d priority" ++msgstr "Priorità video %d " ++ ++#, c-format ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Min. MB disponibili video %d " + + msgid "Setup.Recording$Use episode name" + msgstr "Utilizza nome episodio" + ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Nomi file semplici" ++ + msgid "Setup.Recording$Use VPS" + msgstr "Utilizza VPS" + +@@ -754,14 +1172,44 @@ msgid "Setup.Recording$Name instant reco + msgstr "Nome reg. immediata" + + msgid "Setup.Recording$Instant rec. time (min)" +-msgstr "Tempo reg. immediata (min)" ++msgstr "Durata reg. immediata (min)" + + msgid "Setup.Recording$Max. video file size (MB)" + msgstr "Dim. massima file video (MB)" + ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Dim. massima reg. (GB)" ++ + msgid "Setup.Recording$Split edited files" + msgstr "Dividi i file modificati" + ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Taglia collegamenti Hard" ++ ++msgid "Setup.Recording$Delete timeshift recording" ++msgstr "Elimina reg. timeshift" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Mostra data registrazione" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Mostra ora registrazione" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Mostra durata registrazione" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Mostra fine del timer" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Ordina registrazioni per" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Ordina directory prima di reg." ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Elimina taglio automatico" ++ + msgid "Replay" + msgstr "Riproduzione" + +@@ -774,6 +1222,63 @@ msgstr "Mostra modalità riproduzione" + msgid "Setup.Replay$Resume ID" + msgstr "ID di ripristino" + ++msgid "Setup.Replay$Jump&Play" ++msgstr "Vai a & Riproduci" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Riproduci & Vai a" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pausa all'ultimo marcatore" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Ricarica marcatori" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Salta secondi" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Salta secondi lentamente" ++ ++msgid "Setup.Replay$Length" ++msgstr "Durata" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Durata / Numero" ++ ++msgid "Setup.Replay$Number" ++msgstr "Numero" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "Mod. visualizzazione DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "Mostra zeri davanti al DVD" ++ ++msgid "Setup.Replay$never" ++msgstr "mai" ++ ++msgid "Setup.Replay$on begin" ++msgstr "all'inizio" ++ ++msgid "Setup.Replay$on end" ++msgstr "alla fine" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "all'inizio e alla fine" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Apri vassoio" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Limita velocità DVD a" ++ ++msgid "Setup.Miscellaneous$only in channelinfo" ++msgstr "solo nelle info canale" ++ ++msgid "Setup.Miscellaneous$only in progress display" ++msgstr "solo nel canale in esec." ++ + msgid "Miscellaneous" + msgstr "Generici" + +@@ -801,9 +1306,54 @@ msgstr "come prima" + msgid "Setup.Miscellaneous$Initial volume" + msgstr "Volume iniziale" + ++msgid "Setup.Miscellaneous$Volume ctrl with left/right" ++msgstr "Controllo volume con Sinistra/Destra" ++ ++msgid "Setup.Miscellaneous$Channelgroups with left/right" ++msgstr "Gruppi canali con Sinistra/Destra" ++ ++msgid "Setup.Miscellaneous$Search fwd/back with left/right" ++msgstr "Cerca avanti/indietro con Sinistra/Destra" ++ + msgid "Setup.Miscellaneous$Emergency exit" + msgstr "Uscita di emergenza" + ++msgid "Setup.Miscellaneous$Lirc repeat delay" ++msgstr "Ritardo ripetizione LIRC" ++ ++msgid "Setup.Miscellaneous$Lirc repeat freq" ++msgstr "Frequenza ripetizione LIRC" ++ ++msgid "Setup.Miscellaneous$Lirc repeat timeout" ++msgstr "Scadenza ripetizione LIRC" ++ ++msgid "Permanent Timeshift" ++msgstr "Timeshift permanente" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Posizione" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "Disco fisso" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "Memoria" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Dim. buffer in memoria (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Utilizza disco fisso se necessario" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Mantieni buffer di pausa" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Dim. buffer nel disco fisso (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Dimensione buffer (MB)" ++ + msgid "Plugins" + msgstr "Plugins" + +@@ -829,7 +1379,6 @@ msgstr "Programmi" + msgid "VDR" + msgstr "VDR" + +-#. TRANSLATORS: note the leading blank! + msgid " Stop replaying" + msgstr " Ferma riproduzione" + +@@ -845,7 +1394,6 @@ msgstr "Ferma" + msgid "Button$Resume" + msgstr "Riprendi" + +-#. TRANSLATORS: note the leading blank! + msgid " Cancel editing" + msgstr " Annulla modifiche" + +@@ -876,10 +1424,22 @@ msgstr "Nessuna periferica DVB disponibi + msgid "Pausing live video..." + msgstr "Pausa del canale in visione..." + ++msgid "Jump" ++msgstr "Vai a" ++ ++msgid "Skip +60s" ++msgstr "Salta +60s" ++ ++msgid "Skip -60s" ++msgstr "Salta - 60s" ++ + #. TRANSLATORS: note the trailing blank! + msgid "Jump: " + msgstr "Vai a: " + ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Taglio in esecuzione - Aggiungere alla coda tagli?" ++ + msgid "No editing marks defined!" + msgstr "Nessun marcatore di modifica definito!" + +@@ -895,9 +1455,6 @@ msgstr "Processo di modifica già attivo! + msgid "FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&" + msgstr " aáàbcdeéèfghiìîjklmnoòpqrstuùvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&°" + +-msgid "yes" +-msgstr "sì" +- + msgid "CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9" + msgstr " 0\t-.,1#~\\^$[]|()*+°?{}/:%@&\taàbc2\tdeèf3\tghiì4\tjkl5\tmnoò6\tpqrs7\ttuùv8\twxyz9" + +@@ -910,14 +1467,23 @@ msgstr "Sovrascrivi" + msgid "Button$Insert" + msgstr "Inserisci" + +-msgid "auto" +-msgstr "automatico" ++msgid "Rename$Up" ++msgstr "Su" ++ ++msgid "Rename$Down" ++msgstr "Giù" ++ ++msgid "Rename$Previous" ++msgstr "Precedente" ++ ++msgid "Rename$Next" ++msgstr "Successivo" + + msgid "Plugin" + msgstr "Plugin" + + msgid "Up/Dn for new location - OK to move" +-msgstr "Su/Giù per nuova posizione - OK per muovere" ++msgstr "Su/Giù per nuova posizione - OK per spostare" + + msgid "Channel locked (recording)!" + msgstr "Canale bloccato (in registrazione)!" +@@ -925,6 +1491,30 @@ msgstr "Canale bloccato (in registrazion + msgid "Low disk space!" + msgstr "Poco spazio su disco!" + ++#, c-format ++msgid "Please mount %s" ++msgstr "Monta %s" ++ ++#, c-format ++msgid "Please mount DVD %04d" ++msgstr "Monta il DVD %04d" ++ ++#, c-format ++msgid "Please mount DVD %d" ++msgstr "Monta il DVD %d" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Attendere prego. Verifica DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Nessun indice trovato. La creazione può impiegare alcuni minuti. Crearne uno?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Attendere prego. Creazione indice..." ++ ++msgid "Wrong DVD!" ++msgstr "DVD errato!" ++ + msgid "Can't shutdown - option '-s' not given!" + msgstr "Impossibile spegnere - parametro '-s' non assegnato!" + +@@ -936,7 +1526,7 @@ msgstr "Registrazione in corso - spegner + + #, c-format + msgid "Recording in %ld minutes, shut down anyway?" +-msgstr "Registrazione fra %ld minuti - spegnere comunque?" ++msgstr "Registrazione tra %ld minuti - spegnere comunque?" + + msgid "shut down anyway?" + msgstr "spegnere comunque?" +@@ -996,9 +1586,6 @@ msgstr "Domenica" + msgid "Upcoming recording!" + msgstr "Registrazione imminente!" + +-msgid "Recording started" +-msgstr "Registrazione avviata" +- + msgid "VDR will shut down later - press Power to force" + msgstr "VDR si spegnerà più tardi - premi Power per forzare" + +@@ -1020,3 +1607,4 @@ msgstr "Premi un tasto per annullare il + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR si spegnerà tra %s minuti" ++ +diff -ruNp vdr-1.7.0/po/nl_NL.po vdr-1.7.0-extensions/po/nl_NL.po +--- vdr-1.7.0/po/nl_NL.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/nl_NL.po 2009-04-09 20:48:48.000000000 +0200 +@@ -11,7 +11,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-02-26 17:20+0100\n" + "Last-Translator: Johan Schuring <johan.schuring@vetteblei.nl>\n" + "Language-Team: Dutch\n" +@@ -25,15 +25,12 @@ msgstr "uit" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "geen" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Ongeldig kanaal ***" + +@@ -322,12 +319,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarchie" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioriteit" +- + msgid "Rolloff" + msgstr "" + +@@ -376,6 +367,9 @@ msgstr "Einde" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioriteit" ++ + msgid "Lifetime" + msgstr "Bewaarduur" + +@@ -910,9 +904,6 @@ msgstr "Overschrijven" + msgid "Button$Insert" + msgstr "Invoegen" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1020,3 +1011,270 @@ msgstr "Druk een willekeurige toets om h + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR zal na %s minuten uitschakelen" ++ ++msgid "Channel locked by LNB!" ++msgstr "Kanaal geblokkeerd door LNB" ++ ++msgid "Childlock" ++msgstr "Kinderslot" ++ ++msgid "Path" ++msgstr "Pad" ++ ++msgid "Timer commands" ++msgstr "Timer commando's" ++ ++msgid "Rename recording" ++msgstr "Hernoem opnamen" ++ ++msgid "Date" ++msgstr "Datum" ++ ++msgid "Length" ++msgstr "Lengte" ++ ++msgid "Size" ++msgstr "Grootte" ++ ++msgid "Delete marks information?" ++msgstr "Verwijder informatiemarkeringen?" ++ ++msgid "Delete resume information?" ++msgstr "Verwijder hervattingsmarkeringen?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "DVd plugin is niet geÃnstalleerd!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "hoofdmap alfabetisch, submappen flexibel" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "hoofdmap op datum, submappen flexibel" ++ ++msgid "all alphabetically" ++msgstr "alles alfabetisch" ++ ++msgid "all by date" ++msgstr "alles op datum" ++ ++msgid "Sorting" ++msgstr "Sortering" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle symbolen" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Positie commandobalk in hoofdmenu" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Toon geldige invoer" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Toon voortschreidingsbalk" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Tijdsduur starten dubbele EPG zoekactie (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "externe dubbele EPG invoer" ++ ++msgid "adjust" ++msgstr "afstellen" ++ ++msgid "delete" ++msgstr "verwijderen" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mix in- en externe EPG" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Schakel aktieve VPS uitzending uit" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Gebruik AC3-Transfer Fix" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Gebruik 'Sync Early' Patch" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "LNB kaart %d gebruikt LNB Nr." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Houd LNB gebruik bij" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Neem Dolby Digital spoor op" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Omgang m.b.t. Videomappen" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Aantal videomappen" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d prioriteit" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. vrij MB" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Handzame bestandsnamen" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Max. opnamegrootte (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "'Hard link' bestandsbewerker" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Toon datum" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Toon tijd" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Toon lengte" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Toon einde van timers" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Sorteer opnames op" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Sorteer mappen vÃÃr opnames" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Bestandsbewerker automatisch wissen" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Spring&Speel" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Speel&Spring" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pauzeer bij laatste markering" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Herlaadt markeringen" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Spring seconden" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Spring seconden langzaam" ++ ++msgid "Setup.Replay$Length" ++msgstr "Lengte" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Lengte / Nummer" ++ ++msgid "Setup.Replay$Number" ++msgstr "Nummer" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "DVD displayinstellingen" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "DVD toon voorloopnullen" ++ ++msgid "Setup.Replay$never" ++msgstr "nooit" ++ ++msgid "Setup.Replay$on begin" ++msgstr "aan het begin" ++ ++msgid "Setup.Replay$on end" ++msgstr "bij het einde" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "bij het begin en aan het einde" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Open DVD lade" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Beperk DVD omw. snelheid" ++ ++msgid "Jump" ++msgstr "Spring" ++ ++msgid "Skip +60s" ++msgstr "Spring +60s verder" ++ ++msgid "Skip -60s" ++msgstr "Spring -60s terug" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Bestandsbewerker aktief - aan wachtrij toeveogen?" ++ ++msgid "Rename$Up" ++msgstr "Boven" ++ ++msgid "Rename$Down" ++msgstr "Onder" ++ ++msgid "Rename$Previous" ++msgstr "Vorige" ++ ++msgid "Rename$Next" ++msgstr "Volgende" ++ ++msgid "Please mount %s" ++msgstr "Koppel %s aan a.u.b." ++ ++msgid "Please mount DVD %04d" ++msgstr "Koppel DVD %04d aan a.u.b." ++ ++msgid "Please mount DVD %d" ++msgstr "Koppel DVD %d aan a.u.b." ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Even wachten, DVD wordt gecontroleerd..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Geen indexbestand gevonden. Aanmaken duurt even, doorgaan?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Even wachten indexbestand wordt aangemaakt..." ++ ++msgid "Wrong DVD!" ++msgstr "Verkeerde DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Permanente livebuffer" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Opslaglocatie" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "hardeschijf" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "geheugen" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Buffergrootte in geheugen (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Overlopen naar hardeschijf indien noodzakelijk" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Bewaar gepauzeerde buffer" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Buffergrootte op harddisk (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Buffergrootte (MB)" +diff -ruNp vdr-1.7.0/po/nn_NO.po vdr-1.7.0-extensions/po/nn_NO.po +--- vdr-1.7.0/po/nn_NO.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/nn_NO.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2007-08-12 14:17+0200\n" + "Last-Translator: Truls Slevigen <truls@slevigen.no>\n" + "Language-Team: Norwegian\n" +@@ -22,13 +22,10 @@ msgstr "" + msgid "on" + msgstr "" + +-msgid "none" +-msgstr "" +- +-msgid "high" ++msgid "auto" + msgstr "" + +-msgid "low" ++msgid "none" + msgstr "" + + msgid "*** Invalid Channel ***" +@@ -319,12 +316,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarchy" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioritet" +- + msgid "Rolloff" + msgstr "" + +@@ -373,6 +364,9 @@ msgstr "Slutt" + msgid "VPS" + msgstr "" + ++msgid "Priority" ++msgstr "Prioritet" ++ + msgid "Lifetime" + msgstr "Levetid" + +@@ -907,9 +901,6 @@ msgstr "" + msgid "Button$Insert" + msgstr "" + +-msgid "auto" +-msgstr "" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1017,3 +1008,270 @@ msgstr "" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/pl_PL.po vdr-1.7.0-extensions/po/pl_PL.po +--- vdr-1.7.0/po/pl_PL.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/pl_PL.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-09 12:59+0100\n" + "Last-Translator: Michael Rakowski <mrak@gmx.de>\n" + "Language-Team: Polish\n" +@@ -22,15 +22,12 @@ msgstr "wy³±cz" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "auto" ++ + msgid "none" + msgstr "brak" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Niepoprawny kana³ ***" + +@@ -319,12 +316,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarchia" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Priorytet" +- + msgid "Rolloff" + msgstr "" + +@@ -373,6 +364,9 @@ msgstr "Koniec" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Priorytet" ++ + msgid "Lifetime" + msgstr "Czas ¿ycia" + +@@ -907,9 +901,6 @@ msgstr "Nadpisz" + msgid "Button$Insert" + msgstr "Wstaw" + +-msgid "auto" +-msgstr "auto" +- + msgid "Plugin" + msgstr "Wtyczka" + +@@ -1017,3 +1008,270 @@ msgstr "Naci¶nij dowolny klawisz aby nie + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR zostanie wy³±czony za %s minut" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/pt_PT.po vdr-1.7.0-extensions/po/pt_PT.po +--- vdr-1.7.0/po/pt_PT.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/pt_PT.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-18 17:04+0100\n" + "Last-Translator: anonymous\n" + "Language-Team: Portuguese\n" +@@ -21,15 +21,12 @@ msgstr "off" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "Automático" ++ + msgid "none" + msgstr "nenhum" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Canal inválido ***" + +@@ -318,12 +315,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarquia" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioridade" +- + msgid "Rolloff" + msgstr "" + +@@ -372,6 +363,9 @@ msgstr "Fim" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioridade" ++ + msgid "Lifetime" + msgstr "Duração" + +@@ -906,9 +900,6 @@ msgstr "Substituir" + msgid "Button$Insert" + msgstr "Inserir" + +-msgid "auto" +-msgstr "Automático" +- + msgid "Plugin" + msgstr "Plugin" + +@@ -1016,3 +1007,270 @@ msgstr "Pressione qualquer tecla para nã + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR vai desligar em %s minutos" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/ro_RO.po vdr-1.7.0-extensions/po/ro_RO.po +--- vdr-1.7.0/po/ro_RO.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/ro_RO.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-02-25 00:39+0100\n" + "Last-Translator: Lucian Muresan <lucianm@users.sourceforge.net>\n" + "Language-Team: Romanian\n" +@@ -24,15 +24,12 @@ msgstr "inactiv" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "automat" ++ + msgid "none" + msgstr "niciuna(ul)" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Canal invalid ***" + +@@ -321,12 +318,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Ierarhie" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioritate" +- + msgid "Rolloff" + msgstr "" + +@@ -375,6 +366,9 @@ msgstr "Sfârºit" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioritate" ++ + msgid "Lifetime" + msgstr "Timp de pãstrare" + +@@ -909,9 +903,6 @@ msgstr "Suprascrie" + msgid "Button$Insert" + msgstr "Insereazã" + +-msgid "auto" +-msgstr "automat" +- + msgid "Plugin" + msgstr "Plugin (modul adiþional)" + +@@ -1019,3 +1010,270 @@ msgstr "Apãsaþi orice tastã pentru a anu + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se va închide în %s minute" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/ru_RU.po vdr-1.7.0-extensions/po/ru_RU.po +--- vdr-1.7.0/po/ru_RU.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/ru_RU.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-02-15 16:37+0100\n" + "Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n" + "Language-Team: Russian\n" +@@ -22,15 +22,12 @@ msgstr "ÒëÚÛ" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "ÐÒâÞ" ++ + msgid "none" + msgstr "ÝØçÕÓÞ" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** ½ÕßàÐÒØÛìÝëÙ ÚÐÝÐÛ ***" + +@@ -319,12 +316,6 @@ msgstr "·ÐéØâÐ" + msgid "Hierarchy" + msgstr "¸ÕàÐàåØï" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "¿àØÞàØâÕâ" +- + msgid "Rolloff" + msgstr "" + +@@ -373,6 +364,9 @@ msgstr "ºÞÝÕæ" + msgid "VPS" + msgstr "VPS ßÞßàÐÒÚÐ" + ++msgid "Priority" ++msgstr "¿àØÞàØâÕâ" ++ + msgid "Lifetime" + msgstr "ÁàÞÚ åàÐÝÕÝØï" + +@@ -907,9 +901,6 @@ msgstr "·ÐÜÕÝÐ" + msgid "Button$Insert" + msgstr "²áâÐÒÚÐ" + +-msgid "auto" +-msgstr "ÐÒâÞ" +- + msgid "Plugin" + msgstr "¼ÞÔãÛì" + +@@ -1017,3 +1008,271 @@ msgstr "½ÐÖÜØâÕ ÛîÑãî ÚÝÞßÚã ÔÛï ÞâÜÕÝë + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR ÒëÚÛîçØâáï çÕàÕ× %s ÜØÝãâ" ++ ++msgid "Channel locked by LNB!" ++msgstr "ºÞÝÒÕàâÕà ÑÛÞÚØàãÕâ ÚÐÝÐÛ" ++ ++msgid "Childlock" ++msgstr "´ÕâáÚÐï ÑÛÞÚØàÞÒÚÐ" ++ ++msgid "Path" ++msgstr "¿ãâì" ++ ++msgid "Timer commands" ++msgstr "ºÞÜÜÐÝÔë âÐÙÜÕàÐ" ++ ++msgid "Rename recording" ++msgstr "¿ÕàÕØÜÕÝÞÒÐâì ×Ðߨáì" ++ ++msgid "Date" ++msgstr "´ÐâÐ" ++ ++msgid "Length" ++msgstr "´ÛØÝÐ" ++ ++msgid "Size" ++msgstr "ÀÐ×ÜÕà" ++ ++msgid "Delete marks information?" ++msgstr "ÃÔÐÛØâì ÜÕâÚØ?" ++ ++msgid "Delete resume information?" ++msgstr "²ÞááâÐÝÞÒØâì ÜÕâÚØ?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "¼ÞÔãÛì DVD ÝÕ ãáâÐÝÞÒÛÕÝ!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÐÛäÐÒØâã, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÒàÕÜÕÝØ, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" ++ ++msgid "all alphabetically" ++msgstr "ÒáÕ ßÞ ÐÛäÐÒØâã" ++ ++msgid "all by date" ++msgstr "ÒáÕ ßÞ ÒàÕÜÕÝØ" ++ ++msgid "Sorting" ++msgstr "ÁÞàâØàÞÒÚÐ" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle ØÚÞÝÚØ" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "ÀÐ×ÜÕéÕÝØÕ ÚÞÜÐÝÔ Ò ÓÛÐÒÝÞÜ ÜÕÝî" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "¿ÞÚÐ× ßàÐÒØÛìÝÞÓÞ ÒÒÞÔÐ" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "¿ÞÚÐ× ÑÐÛÚØ ßàÞÓàÕááÐ" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "¿ÕàØÞÔ ÔÛï ßÞØáÚÐ ÔÒÞÙÝëå EPG(min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "²ÝÕèÝØÙ ØáâÞçÝØÚ ÔÒÞÙÝÞÓÞ EPG" ++ ++msgid "adjust" ++msgstr "ÝÐáâàÞØâì" ++ ++msgid "delete" ++msgstr "ãÔÐÛØâì" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "ÁÜÕèØÒÐÝØÕ ÒÝãâàÕÝÝÕÓÞ Ø ÒÝÕèÝÕÓÞ EPG" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "·ÐßàÕâ VPS áÞÑëâØï" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "¸áßÞÛì×ÞÒÐâì ÚÞààÕÚâØàÞÒÚã AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "¸áßÞÛì×ÞÒÐâì Sync Early " ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "DVB ãáâàÞÙáâÒÞ %d ØáßÞÛì×ãÕâ LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "»ÞÓØàÞÒÐÝØÕ ØáßÞÛì×ÞÒÐÝØï LNB" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "·Ðߨáì Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "¿ÞàïÔÞÚ ÒØÔÕÞ ÔØàÕÚâÞàØØ" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "ºÞÛØçÕáâÒÞ ÒØÔÕÞ ÔØàÕÚâÞàØÙ" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d ßàØÞàØâÕâ" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d ÜØÝ. áÒÞÑÞÔÝÞ MB" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "ÇØâÐÑÕÛìÝëÕ ØÜÕÝÐ äÐÙÛÞÒ" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "¼ÐÚá. àÐ×ÜÕà ×ÐßØáØ (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "¼ÞÝâÐÖ á hard link" ++ ++msgid "Setup.Recording$Show date" ++msgstr "¿ÞÚÐ×ëÒÐâì ÔÐâã" ++ ++msgid "Setup.Recording$Show time" ++msgstr "¿ÞÚÐ×ëÒÐâì ÒàÕÜï ×ÐߨáØ" ++ ++msgid "Setup.Recording$Show length" ++msgstr "¿ÞÚÐ×ëÒÐâì ßàÞÔÞÛÖØâÕÛìÝÞáâì ×ÐߨáØ" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "½Ð×ÒÐÝØÕ ÓÛÐÒÝÞÓÞ ÜÕÝî" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "¿ÞÚÐ× ÞÚÞÝçÐÝØï âÐÙÜÕàÐ" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "ÁÞàâØàÞÒÚÐ ×ÐߨáÕÙ ßÞ" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "ÁÞàâØàÞÒÚÐ ÔØàÕÚâÞàØÙ ÔÞ ×ÐߨáØ" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "°ÒâÞÜÐâØçÕáÚÞÕ ãÔÐÛÕÝØÕ ÜÞÝâÐÖÐ" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Jump&Play" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Play&Jump" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "¿Ðã×Ð ÝÐ ßÞáÛÕÔÝÕÙ ÜÕâÚÕ" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "¿ÕàÕÓàãרâì ÜÕâÚØ" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "¿àÞßãáÚ áÕÚãÝÔ" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "¿àÞßãáÚ áÕÚãÝÔ ÜÕÔÛÕÝÝÞ" ++ ++msgid "Setup.Replay$Length" ++msgstr "´ÛØÝÐ" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "´ÛØÝÐ / ½ÞÜÕà" ++ ++msgid "Setup.Replay$Number" ++msgstr "½ÞÜÕà" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "ÀÕÖØÜ ßÞÚÐ×Ð DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "ßÞÚÐ× ÒÕÔãéØå ÝãÛÕÙ" ++ ++msgid "Setup.Replay$never" ++msgstr "ÝØÚÞÓÔÐ" ++ ++msgid "Setup.Replay$on begin" ++msgstr "Ò ÝÐçÐÛÕ" ++ ++msgid "Setup.Replay$on end" ++msgstr "² ÚÞÝæÕ" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "Ò ÝÐçÐÛÕ Ø Ò ÚÞÝæÕ" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "¾âÚàëâì" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "¿àÕÔÕÛ áÚÞàÞáâØ DVD" ++ ++msgid "Jump" ++msgstr "¿àëÖÞÚ" ++ ++msgid "Skip +60s" ++msgstr "¿àÞßãáÚ +60s" ++ ++msgid "Skip -60s" ++msgstr "¿àÞßãáÚ -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "¼ÞÝâÐÖÕà àÐÑÞâÐÕâ - ´ÞÑÐÒØâì Ò ÞçÕàÕÔì?" ++ ++msgid "Rename$Up" ++msgstr "²ÒÕàå" ++ ++msgid "Rename$Down" ++msgstr "²ÝØ×" ++ ++msgid "Rename$Previous" ++msgstr "¿àÕÔëÔãéØÙ" ++ ++msgid "Rename$Next" ++msgstr "ÁÛÕÔãîéØÙ" ++ ++msgid "Please mount %s" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ %s" ++ ++msgid "Please mount DVD %04d" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %04d" ++ ++msgid "Please mount DVD %d" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %d" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ¿àÞÒÕàÚÐ DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "¸ÝÔÕÚá äÐÙÛ ÝÕ ÝÐÙÔÕÝ. ÁÞ×ÔÐÝØÕ âàÕÑãÕâ ÒàÕÜÕÝØ. ÁÞ×ÔÐâì?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ÁÞ×ÔÐÝØÕ ØÝÔÕÚá äÐÙÛÐ..." ++ ++msgid "Wrong DVD!" ++msgstr "¾èØÑÚÐ DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "¿ÞáâÞïÝÝëÙ âÐÙÜèØäâ" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "¼ÕáâÞÝÐåÞÖÔÕÝØï" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "ÖÕáâÚØÙ ÔØáÚ" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "ßÐÜïâì" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ Ò ßÐÜïâØ (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "´ÞÑÐÒÛïâì ÖÕáâÚØÙ ÔØáÚ ÕáÛØ ÝÕÞÑåÞÔØÜÞ" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "ÅàÐÝÕÝØÕ ÑãäÕàÐ ßÐã×ë" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ ÝÐ ÖÕáâÚÞÜ ÔØáÚÕ (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ (MB)" ++ +diff -ruNp vdr-1.7.0/po/sl_SI.po vdr-1.7.0-extensions/po/sl_SI.po +--- vdr-1.7.0/po/sl_SI.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/sl_SI.po 2009-04-09 20:48:48.000000000 +0200 +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-02-28 19:44+0100\n" + "Last-Translator: Matjaz Thaler <matjaz.thaler@guest.arnes.si>\n" + "Language-Team: Slovenian\n" +@@ -22,15 +22,12 @@ msgstr "izklop" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "avtomatsko" ++ + msgid "none" + msgstr "nobeden" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Neznan kanal ***" + +@@ -319,12 +316,6 @@ msgstr "Za¹èita" + msgid "Hierarchy" + msgstr "Hierarhija" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioriteta" +- + msgid "Rolloff" + msgstr "" + +@@ -373,6 +364,9 @@ msgstr "Konec" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioriteta" ++ + msgid "Lifetime" + msgstr "Veljavnost" + +@@ -907,9 +901,6 @@ msgstr "Prepi¹i" + msgid "Button$Insert" + msgstr "Vstavi" + +-msgid "auto" +-msgstr "avtomatsko" +- + msgid "Plugin" + msgstr "Vstavek" + +@@ -1017,3 +1008,270 @@ msgstr "Pritisni katerokoli tipko za pre + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se bo zaustavil v %s minutah" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/sv_SE.po vdr-1.7.0-extensions/po/sv_SE.po +--- vdr-1.7.0/po/sv_SE.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/sv_SE.po 2009-04-09 20:48:48.000000000 +0200 +@@ -10,7 +10,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-12 18:25+0100\n" + "Last-Translator: Magnus Andersson <svankan@bahnhof.se>\n" + "Language-Team: Swedish\n" +@@ -24,15 +24,12 @@ msgstr "av" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "automatisk" ++ + msgid "none" + msgstr "ingen" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Felaktig kanal ***" + +@@ -321,12 +318,6 @@ msgstr "Guard" + msgid "Hierarchy" + msgstr "Hierarchy" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Prioritet" +- + msgid "Rolloff" + msgstr "" + +@@ -375,6 +366,9 @@ msgstr "Slutar" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Prioritet" ++ + msgid "Lifetime" + msgstr "Livstid" + +@@ -909,9 +903,6 @@ msgstr "Skriv över" + msgid "Button$Insert" + msgstr "Infoga" + +-msgid "auto" +-msgstr "automatisk" +- + msgid "Plugin" + msgstr "Modul" + +@@ -1019,3 +1010,270 @@ msgstr "Tryck valfri knapp för att återk + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR kommer att stängas ned om %s minuter" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/tr_TR.po vdr-1.7.0-extensions/po/tr_TR.po +--- vdr-1.7.0/po/tr_TR.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/tr_TR.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-02-28 00:33+0100\n" + "Last-Translator: Oktay Yolgeçen <oktay_73@yahoo.de>\n" + "Language-Team: Turkish\n" +@@ -21,15 +21,12 @@ msgstr "kapalý" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "otomatik" ++ + msgid "none" + msgstr "hiç" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** Geçersiz kanal ***" + +@@ -318,12 +315,6 @@ msgstr "Koruma" + msgid "Hierarchy" + msgstr "Hiyerarþi" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "Öncelik" +- + msgid "Rolloff" + msgstr "" + +@@ -372,6 +363,9 @@ msgstr "Bitiþ" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "Öncelik" ++ + msgid "Lifetime" + msgstr "Ömrü" + +@@ -906,9 +900,6 @@ msgstr "Üstüne yaz" + msgid "Button$Insert" + msgstr "Ekle" + +-msgid "auto" +-msgstr "otomatik" +- + msgid "Plugin" + msgstr "Eklenti" + +@@ -1016,3 +1007,270 @@ msgstr "Yeniden baþlatmayý iptal etmek i + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR %s dakikada kapanacak" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.0/po/uk_UA.po vdr-1.7.0-extensions/po/uk_UA.po +--- vdr-1.7.0/po/uk_UA.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/uk_UA.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-07 14:17+0200\n" + "Last-Translator: Yarema Aka Knedlyk <yupadmin@gmail.com>\n" + "Language-Team: Ukrainian\n" +@@ -21,15 +21,12 @@ msgstr "ÒØÚÛ" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "ÐÒâÞ" ++ + msgid "none" + msgstr "ÝöçÞÓÞ" + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "*** ½ÕßàÐÒØÛìÝØÙ ÚÐÝÐÛ ***" + +@@ -318,12 +315,6 @@ msgstr "·ÐåØáâ" + msgid "Hierarchy" + msgstr "¦ôàÐàåöï" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "¿àöÞàØâÕâ" +- + msgid "Rolloff" + msgstr "" + +@@ -372,6 +363,9 @@ msgstr "ºöÝÕæì" + msgid "VPS" + msgstr "VPS ßÞßàÐÒÚÐ" + ++msgid "Priority" ++msgstr "¿àöÞàØâÕâ" ++ + msgid "Lifetime" + msgstr "ÁâàÞÚ ×ÑÕàöÓÐÝÝï" + +@@ -906,9 +900,6 @@ msgstr "·ÐÜöÝÐ" + msgid "Button$Insert" + msgstr "²áâÐÒÚÐ" + +-msgid "auto" +-msgstr "ÐÒâÞ" +- + msgid "Plugin" + msgstr "¼ÞÔãÛì" + +diff -ruNp vdr-1.7.0/po/zh_CN.po vdr-1.7.0-extensions/po/zh_CN.po +--- vdr-1.7.0/po/zh_CN.po 2008-04-13 16:16:58.000000000 +0200 ++++ vdr-1.7.0-extensions/po/zh_CN.po 2009-04-09 20:48:48.000000000 +0200 +@@ -7,7 +7,7 @@ msgid "" + msgstr "" + "Project-Id-Version: VDR 1.6.0\n" + "Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n" +-"POT-Creation-Date: 2008-04-12 14:19+0200\n" ++"POT-Creation-Date: 2008-12-14 16:10+0100\n" + "PO-Revision-Date: 2008-03-21 08:44+0800\n" + "Last-Translator: Nan Feng <nfgx@21cn.com>\n" + "Language-Team: Chinese\n" +@@ -24,15 +24,12 @@ msgstr "å…³" + msgid "on" + msgstr "" + ++msgid "auto" ++msgstr "自动" ++ + msgid "none" + msgstr "æ— " + +-msgid "high" +-msgstr "" +- +-msgid "low" +-msgstr "" +- + msgid "*** Invalid Channel ***" + msgstr "***æ— æ•ˆé¢‘é�“ ***" + +@@ -321,12 +318,6 @@ msgstr "防护" + msgid "Hierarchy" + msgstr "层次" + +-msgid "Alpha" +-msgstr "" +- +-msgid "Priority" +-msgstr "优先" +- + msgid "Rolloff" + msgstr "" + +@@ -375,6 +366,9 @@ msgstr "å�œæ¢" + msgid "VPS" + msgstr "VPS" + ++msgid "Priority" ++msgstr "优先" ++ + msgid "Lifetime" + msgstr "终生" + +@@ -909,9 +903,6 @@ msgstr "覆盖" + msgid "Button$Insert" + msgstr "æ�’å…¥" + +-msgid "auto" +-msgstr "自动" +- + msgid "Plugin" + msgstr "æ�’ä»¶" + +diff -ruNp vdr-1.7.0/README.cmdsubmenu vdr-1.7.0-extensions/README.cmdsubmenu +--- vdr-1.7.0/README.cmdsubmenu 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/README.cmdsubmenu 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,54 @@ ++CmdSubmenu patch for VDR ++------------------------ ++ ++With this patch the commands and recording commands menus can be organised ++hierarchically. To create a submenu entry, prefix the name by one ore more "-". ++ ++ ++Standard: ++ ++description_1 : cmd_1 ++description_2 : cmd_2 ++ ++ ++A submenu with two entries: ++ ++Submenu title ... : echo "submenu" ++-description_1 : cmd_1 ++-description_2 : cmd_2 ++ ++The dummy command in the title row is necessary. ++ ++ ++* History ++ ++ 2003-10-08: Version 0.1 - Albu at vdrportal.de ++ http://vdrportal.de/board/thread.php?threadid=6319 ++ ++ 2003-10-09: Version 0.2 - Tobias Grimm <tg@e-tobi.net> ++ - Added Define CMD_SUBMENUS in Makefile ++ ++ 2004-05-28: Version 0.3 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed compilation with gcc-3.3.3 ++ - Added new virtual method AddConfig in cConfig ++ - Redefining of method Add in cListBase to virtual no longer necessary ++ - Improved code in menu.c ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.3.diff ++ ++ 2004-12-20: Version 0.4 - Thomas Günther <tom@toms-cafe.de> ++ - Solved conflict with jumpplay patch 0.6 ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.4.diff ++ ++ 2006-04-22: Version 0.5 - Thomas Günther <tom@toms-cafe.de> ++ - Added version define CMDSUBMENUVERSNUM ++ - Reformated to VDR style indentions ++ - Added description in README.cmdsubmenu ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.5-1.3.47.diff ++ ++ 2006-04-23: Version 0.6 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed menus with more than one level ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.6-1.3.47.diff ++ ++ 2006-05-15: Version 0.7 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed build with G++ 4.1 (extra qualification) ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.7-1.4.0.diff +diff -ruNp vdr-1.7.0/README-HLCUTTER vdr-1.7.0-extensions/README-HLCUTTER +--- vdr-1.7.0/README-HLCUTTER 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/README-HLCUTTER 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,117 @@ ++ ++ VDR-HLCUTTER README ++ ++ ++Written by: Udo Richter ++Available at: http://www.udo-richter.de/vdr/patches.html#hlcutter ++ http://www.udo-richter.de/vdr/patches.en.html#hlcutter ++Contact: udo_richter@gmx.de ++ ++ ++ ++About ++----- ++ ++The hard link cutter patch changes the recording editing algorithms of VDR to ++use filesystem hard links to 'copy' recording files whenever possible to speed ++up editing recordings noticeably. ++ ++The patch has matured to be quite stable, at least I'm using it without issues. ++Nevertheless the patch is still in development and should be used with caution. ++The patch is EXPERIMENTAL for multiple /videoxx folders. The safety checks ++should prevent data loss, but you should always carefully check the results. ++ ++While editing a recording, the patch searches for any 00x.vdr files that dont ++contain editing marks and would normally be copied 1:1 unmodified to the edited ++recording. In this case the current target 00x.vdr file will be aborted, and ++the cutter process attempts to duplicate the source file as a hard link, so ++that both files share the same disk space. If this succeeds, the editing ++process fast-forwards through the duplicated file and continues normally ++beginning with the next source file. If hard linking fails, the cutter process ++continues with plain old copying. (but does not take up the aborted last file.) ++ ++After editing, the un-edited recording can be deleted as usual, the hard linked ++copies will continue to exist as the only remaining copy. ++ ++To be effective, the default 'Max. video file size (MB)' should be lowered. ++The patch lowers the smallest possible file size to 1mb. Since VDR only ++supports up to 255 files, this would limit the recording size to 255Mb or ++10 minutes, in other words: This setting is insane! ++ ++To make sure that the 255 file limit will not be reached, the patch also ++introduces "Max. recording size (GB)" with a default of 100Gb (66 hours), and ++increases the file size to 2000Mb early enough, so that 100Gb-recordings will ++fit into the 255 files. ++ ++Picking the right parameters can be tricky. The smaller the file size, the ++faster the editing process works. However, with a small file size, long ++recordings will fall back to 2000Mb files soon, that are slow on editing again. ++ ++Here are some examples: ++ ++Max file size: 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb ++Max recording size: 1Mb 10Mb 20Mb 30Mb 40Mb 50Mb 100Mb ++ ++Small files: 1-203 1-204 1-205 1-206 1-207 1-209 1-214 ++ GBytes: 0.2 2.0 4.0 6.0 8.1 10.2 20.9 ++ Hours: 0.13 1.3 2.65 4 5.4 6.8 13.9 ++ ++Big (2000mb) files: 204-255 204-255 206-255 207-255 208-255 210-255 215-255 ++ GBytes: 101.5 99.6 97.7 95.7 93.8 89.8 80.1 ++ Hours: 67 66 65 63 62 60 53 ++ ++A recording limit of 100Gb keeps plenty of reserve without blocking too much ++file numbers. And with a file size of 30-40Mb, recordings of 4-5 hours fit into ++small files completely. (depends on bit rate of course) ++ ++ ++ ++The patch must be enabled in Setup-> Recordings-> Hard Link Cutter. When ++disabled, the cutter process behaves identical to VDR's default cutter. ++ ++There's a //#define HARDLINK_TEST_ONLY in the videodir.c file that enables a ++test-mode that hard-links 00x.vdr_ files only, and continues the classic ++editing. The resulting 00x.vdr and 00x.vdr_ files should be identical. If you ++delete the un-edited recording, dont forget to delete the *.vdr_ files too, ++they will now eat real disk space. ++ ++Note: 'du' displays the disk space of hard links only on first appearance, and ++usually you will see a noticeably smaller size on the edited recording. ++ ++ ++History ++------- ++Version 0.2.0 ++ ++ New: Support for multiple /videoXX recording folders, using advanced searching ++ for matching file systems where a hard link can be created. ++ Also supports deep mounted file systems. ++ Fix: Do not fail if last mark is a cut-in. (Again.) ++ ++Version 0.1.4 ++ New: Dynamic increase of file size before running out of xxx.vdr files ++ Fix: Last edit mark is not a cut-out ++ Fix: Write error if link-copied file is smaller than allowed file size ++ Fix: Broken index/marks if cut-in is at the start of a new file ++ Fix: Clear dangeling pointer to free'd cUnbufferedFile, ++ thx to Matthias Schwarzott ++ ++Version 0.1.0 ++ Initial release ++ ++ ++ ++ ++Future plans ++------------ ++ ++Since original and edited copy share disk space, free space is wrong if one of ++them is moved to *.del. Free space should only count files with hard link ++count = 1. This still goes wrong if all copies get deleted. ++ ++ ++For more safety, the hard-linked files may be made read-only, as modifications ++to one copy will affect the other copy too. (except deleting, of course) ++ ++ ++SetBrokenLink may get lost on rare cases, this needs some more thoughts.Index: vdr-1.5.9/README.jumpplay +diff -ruNp vdr-1.7.0/README.jumpplay vdr-1.7.0-extensions/README.jumpplay +--- vdr-1.7.0/README.jumpplay 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/README.jumpplay 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,92 @@ ++JumpPlay patch for VDR ++---------------------- ++ ++This patch changes the replay behaviour for recordings that contain editing ++marks. It allows to immediately continue the replay after jumping forward to ++the next mark, and to automatically jump over the commercial break to the next ++"start" mark, if an "end" mark is reached. ++ ++The features of this patch can be turned on or off with parameters in the replay ++setup. See MANUAL for description of this parameters: "Jump&Play", "Play&Jump", ++"Pause at last mark" and "Reload marks". ++ ++ ++* History ++ ++ 2003-07-04: jumpandrun.diff - the Noad <theNoad@SoftHome.net> ++ Jump&Play ++ ++ 2003-12-06: Version 0.0 - Torsten Kunkel <vdr@tkunkel.de> ++ Play&Jump (only if progressbar is visible) ++ Setup parameters Jump&Play and Play&Jump in the replay setup ++ ++ 2004-01-20: Version 0.1 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed speed after jump ++ - fixed removing of marks ++ Play&Jump: ++ - jump only on "end" marks ++ ++ 2004-01-27: Version 0.2 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed double jump ++ Play&Jump: ++ - fixed mark detection: fuzzy detection (until 3 seconds after mark) ++ - jump without progressbar ++ - mode "progressbar only" for old behaviour ++ ++ 2004-01-31: Version 0.3 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed display frames ++ Play&Jump: ++ - fixed end of playing at last mark ++ ++ 2004-07-11: Version 0.4 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - don't play after jump to end ++ Play&Jump: ++ - don't prevent jumping after hide or show ++ Less conflicts with other patches (Elchi/AutoPID) ++ ++ 2004-08-21: Version 0.5 - Thomas Günther <tom@toms-cafe.de> ++ Play&Jump: ++ - exact jumps, replay like edited recording (no fuzzy mark detection) ++ - jump to first mark if replay starts at the beginning ++ - check jump marks with '8' key ++ - mode "progressbar only" removed ++ Description in README.jumpplay ++ ++ 2004-12-28: Version 0.6 - Thomas Günther <tom@toms-cafe.de> ++ Adapted noad extensions (from the Noad <theNoad@SoftHome.net>) to ++ jumpplay-0.5: ++ - cyclic reloading of marks found by noad online-scan ++ - don't stop after the last mark in case of live-recordings ++ New setup parameter "Load marks interval (s)" ++ Updated description in README.jumpplay ++ ++ 2006-04-14: Version 0.7 - Thomas Günther <tom@toms-cafe.de> ++ Fixed jump to first mark (crashed with plugin extrecmenu-0.9) ++ Added version define JUMPPLAYVERSNUM ++ Added placeholders for Czech language texts ++ Cleaned up i18n entries (support only VDR >= 1.3.29) ++ Improved description of i18n placeholders - hoping for real language texts ++ ++ 2006-05-12: Version 0.8 - Thomas Günther <tom@toms-cafe.de> ++ Fixed segfault in dvbplayer thread while the replaycontrol thread is ++ reloading the marks (thanks to horchi at vdrportal.de for reporting this - ++ see http://vdrportal.de/board/thread.php?postid=450463#post450463): ++ New class cMarksReload checks the timestamp of marks.vdr in 10 seconds ++ intervals, so the marks in the threads dvbplayer and replaycontrol can be ++ reloaded independently ++ Changed setup parameter "Load marks interval (s)" to "Reload marks" ++ Updated description in README.jumpplay ++ ++ 2006-05-28: Version 0.9 - Thomas Günther <tom@toms-cafe.de> ++ New setup parameter "Pause at last mark" ++ Updated description in README.jumpplay ++ Moved parameters description to MANUAL ++ ++ 2009-03-31: Version 1.0 - Thomas Günther <tom@toms-cafe.de> ++ Play&Jump: ++ - set resume position to 0 if replay stops at the first mark ++ Added French language texts (thanks to Michaël Nival) +diff -ruNp vdr-1.7.0/README.MainMenuHooks vdr-1.7.0-extensions/README.MainMenuHooks +--- vdr-1.7.0/README.MainMenuHooks 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/README.MainMenuHooks 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,55 @@ ++This is a "patch" for the Video Disk Recorder (VDR). ++ ++* Authors: ++Tobias Grimm <vdr at e-tobi dot net> ++Martin Prochnow <nordlicht at martins-kabuff dot de> ++Frank Schmirler <vdrdev at schmirler dot de> ++Christian Wieninger <cwieninger at gmx dot de> ++ ++* Description: ++This patch allows plugins to replace the VDR mainmenus "Schedule", ++"Channels", "Timers" and "Recordings" by a different implementation. ++ ++The patch is based on a suggestion of Christian Wieninger back in 2006 ++(http://www.linuxtv.org/pipermail/vdr/2006-March/008234.html). It is ++meant to be an interim solution for VDR 1.4 until (maybe) VDR 1.5 ++introduces an official API for this purpose. ++ ++* Installation ++Change into the VDR source directory, then issue ++ patch -p1 < path/to/MainMenuHooks-v1_0.patch ++and recompile. ++ ++* Notes for plugin authors ++The following code sample shows the required plugin code for replacing ++the original Schedule menu: ++ ++bool cMyPlugin::Service(const char *Id, void *Data) ++{ ++ cOsdMenu **menu = (cOsdMenu**) Data; ++ if (MySetup.replaceSchedule && ++ strcmp(Id, "MainMenuHooksPatch-v1.0::osSchedule") == 0) { ++ if (menu) ++ *menu = (cOsdMenu*) MainMenuAction(); ++ return true; ++ } ++ return false; ++} ++ ++A plugin can replace more than one menu at a time. Simply replace the ++call to MainMenuAction() in the sample above by appropriate code. ++ ++Note that a plugin *should* offer a setup option which allows the user ++to enable or disable the replacement. "Disabled" would be a reasonable ++default setting. By testing for define MAINMENUHOOKSVERSNUM, a plugin ++can leave the setup option out at compiletime. ++ ++In case there is an internal problem when trying to open the replacement ++menu, it is safe to return true even though Data is NULL. However an ++OSD message should indicate the problem to the user. ++ ++Feel free to ship this patch along with your plugin. However if you ++think you need to modify the patch, we'd encourage you to contact the ++authors first or at least use a service id which differs in more than ++just the version number. ++ +diff -ruNp vdr-1.7.0/README.sortrec vdr-1.7.0-extensions/README.sortrec +--- vdr-1.7.0/README.sortrec 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/README.sortrec 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,48 @@ ++Sort Recordings patch for VDR ++----------------------------- ++Copyright (C) 2005 Frank99 @vdr-portal.de ++Copyright (C) 2006-2008 Christoph Haubrich ++ ++Released under the same license as VDR itself, for details see vdr.c or ++http://firefly.vdr-developer.org/patches ++ ++This patch changes the sort behaviour of the recordings menu. It is based ++on the patch available here: http://www.vdr-portal.de/board/thread.php?threadid=36031 ++Required for this patch is the liemikuutio-patch for VDR which can be found here: ++http://www.saunalahti.fi/%7Erahrenbe/vdr/patches/ ++ ++There are four sorting modes available after this patch is applied: ++ ++mode behaviour for behaviour for ++ main directory sub directories ++-------------------------------------------------------------------------- ++ 0 alphabetically if special character(*) is found alphabetically, ++ else by date ++ 1 by date if special character(*) is found alphabetically, ++ else by date ++ 2 alphabetically alphabetically ++ 3 by date by date ++ ++(*) if the name of a subdirectory ends with one of ".-$" (dot, hyphen, dollar sign) ++ it is sorted alphabetically in sort mode 0 and 1 ++ ++Sort mode 0 with none of the special characters at the end of any subdir ++corresponds to the default sorting mode of the original VDR. ++ ++The sorting mode can be switched through in the recording menu with the '0' key ++(0->1->2->3->0->...), a default for startup can be set in the setup->recordings menu. ++ ++Additionally the sort order (ascending/descending) can be toggled by the '9' key ++(which is always set to ascending after a restart) ++ ++If you like the to see subdirectories before recordings you can select to put ++directories first in the setup->recordings menu. ++ ++If you would like the sorting to ignore a leading '%' (as normally displayed before ++cutted recordings) you can achive this by setting the environment variable LC_COLLATE ++properly (eg. LC_COLLATE=de_DE@euo in runvdr for germany). ++ ++History: ++2006-08-13 v3, sortrec release for VDR 1.4.1 and liemikuutio 1.8 ++2007-01-28 v3a, moved #ifdef from optimized-rename-patch to sortrec ++2008-03-29 v3b, removed ASCII-170 and ASCII-183 to make sortrec Utf8-ready +diff -ruNp vdr-1.7.0/README.timer-info vdr-1.7.0-extensions/README.timer-info +--- vdr-1.7.0/README.timer-info 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/README.timer-info 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,53 @@ +++------------------------------------------------------------------------------+ ++| Info about the timer-info-patch by Brougs78 | ++| brougs78@gmx.net / home.pages.at/brougs78 | +++------------------------------------------------------------------------------+ ++ ++ ++README timer-info: ++------------------ ++ ++Features: ++ - Shows info, if it is possible to record an event in the timer menu of vdr. ++ For calculations the free space incl. the deleted recordings is used, ++ considering an average consumtion of 25.75 MB/min (also used by vdr itself). ++ The first column in the timer-list shows: ++ ( + ) recording will be most probably possible (enough space) ++ (+/-) recording may be possible ++ ( - ) recording will most probably fail (to less space) ++ The calculations also consider repeating timers. ++ - It is possible to deactivate the patch in the OSD-menu of VDR. ++ ++ ++HISTORY timer-info: ++------------------- ++ ++25.11.2004: v0.1 ++ - Initial release ++ ++11.01.2005: v0.1b ++ - Bugfixes for vdr-1.3.18 ++ - In the menu the free recording-time no longer includes the space of the ++ deleted recordings, because this slowed the vdr down to much. ++ ++08.07.2005: v0.1c ++ - Made the patch configurable ++ ++29.01.2006: v0.2 - Thomas Günther <tom@toms-cafe.de> ++ - Rewritten great parts for vdr-1.3.38+ ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.2-1.3.38+.diff ++ ++05.02.2006: v0.3 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed refresh of timer menu in cMenuTimers::OnOff ++ - Fixed check of repeating timers ++ - Syslog debug messages can be enabled with Define DEBUG_TIMER_INFO ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.3-1.3.38+.diff ++ ++03.03.2006: v0.4 - Thomas Günther <tom@toms-cafe.de> ++ - Adapted to vdr-1.3.44 ++ - Removed setup parameter "Show timer-info" ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.44.diff ++ ++03.03.2006: v0.5 - Tobias Grimm <tg@e-tobi.net> ++ - Adapted to vdr-1.3.45 ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.45.diff +diff -ruNp vdr-1.7.0/recorder.c vdr-1.7.0-extensions/recorder.c +--- vdr-1.7.0/recorder.c 2007-02-24 17:36:24.000000000 +0100 ++++ vdr-1.7.0-extensions/recorder.c 2009-04-09 20:48:48.000000000 +0200 +@@ -11,6 +11,9 @@ + #include <stdarg.h> + #include <stdio.h> + #include <unistd.h> ++#ifdef USE_TTXTSUBS ++#include <stdint.h> ++#endif /* TTXTSUBS */ + #include "shutdown.h" + + #define RECORDERBUFSIZE MEGABYTE(5) +@@ -26,6 +29,9 @@ + + class cFileWriter : public cThread { + private: ++#ifdef USE_TTXTSUBS ++ cTtxtSubsRecorderBase *ttxtSubsRecorder; ++#endif /* TTXTSUBS */ + cRemux *remux; + cFileName *fileName; + cIndexFile *index; +@@ -38,13 +44,24 @@ private: + protected: + virtual void Action(void); + public: ++#ifdef USE_TTXTSUBS ++ cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr); ++#else + cFileWriter(const char *FileName, cRemux *Remux); ++#endif /* TTXTSUBS */ + virtual ~cFileWriter(); + }; + ++#ifdef USE_TTXTSUBS ++cFileWriter::cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr) ++#else + cFileWriter::cFileWriter(const char *FileName, cRemux *Remux) ++#endif /* TTXTSUBS */ + :cThread("file writer") + { ++#ifdef USE_TTXTSUBS ++ ttxtSubsRecorder = tsr; ++#endif /* TTXTSUBS */ + fileName = NULL; + remux = Remux; + index = NULL; +@@ -67,6 +84,10 @@ cFileWriter::~cFileWriter() + Cancel(3); + delete index; + delete fileName; ++#ifdef USE_TTXTSUBS ++ if (ttxtSubsRecorder) ++ delete ttxtSubsRecorder; ++#endif /* TTXTSUBS */ + } + + bool cFileWriter::RunningLowOnDiskSpace(void) +@@ -85,7 +106,11 @@ bool cFileWriter::RunningLowOnDiskSpace( + bool cFileWriter::NextFile(void) + { + if (recordFile && pictureType == I_FRAME) { // every file shall start with an I_FRAME ++#ifndef USE_HARDLINKCUTTER + if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { ++#else ++ if (fileSize > fileName->MaxFileSize() || RunningLowOnDiskSpace()) { ++#endif /* HARDLINKCUTTER */ + recordFile = fileName->NextFile(); + fileSize = 0; + } +@@ -111,6 +136,18 @@ void cFileWriter::Action(void) + } + fileSize += Count; + remux->Del(Count); ++#ifdef USE_TTXTSUBS ++ // not sure if the pictureType test is needed, but it seems we can get ++ // incomplete pes packets from remux if we are not getting pictures? ++ if (ttxtSubsRecorder && pictureType != NO_PICTURE) { ++ uint8_t *subsp; ++ size_t len; ++ if (ttxtSubsRecorder->GetPacket(&subsp, &len)) { ++ recordFile->Write(subsp, len); ++ fileSize += len; ++ } ++ } ++#endif /* TTXTSUBS */ + } + else + break; +@@ -126,8 +163,23 @@ void cFileWriter::Action(void) + + // --- cRecorder ------------------------------------------------------------- + ++#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) ++cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids ++#ifdef USE_TTXTSUBS ++ ,cTtxtSubsRecorderBase *tsr ++#endif /* TTXTSUBS */ ++#ifdef USE_LIVEBUFFER ++ ,cLiveBuffer *LiveBuffer ++#endif /* LIVEBUFFER */ ++ ) ++#else + cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids) ++#endif /* LIVEBUFFER || TTXTSUBS */ ++#ifdef USE_DOLBYINREC ++:cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyInRecordings ? DPids : NULL, SPids) ++#else + :cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids) ++#endif /* DOLBYINREC */ + ,cThread("recording") + { + // Make sure the disk is up and running: +@@ -136,8 +188,22 @@ cRecorder::cRecorder(const char *FileNam + + ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); + ringBuffer->SetTimeouts(0, 100); ++#ifdef USE_DOLBYINREC ++ remux = new cRemux(VPid, APids, Setup.UseDolbyInRecordings ? DPids : NULL, SPids, true); ++#else + remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, true); ++#endif /* DOLBYINREC */ ++#ifdef USE_LIVEBUFFER ++ fileName = strdup(FileName); ++ writer = NULL; ++ liveBuffer = LiveBuffer; ++ if (!LiveBuffer) ++#endif /* LIVEBUFFER */ ++#ifdef USE_TTXTSUBS ++ writer = new cFileWriter(FileName, remux, tsr); ++#else + writer = new cFileWriter(FileName, remux); ++#endif /* TTXTSUBS */ + } + + cRecorder::~cRecorder() +@@ -146,11 +212,17 @@ cRecorder::~cRecorder() + delete writer; + delete remux; + delete ringBuffer; ++#ifdef USE_LIVEBUFFER ++ free(fileName); ++#endif /* LIVEBUFFER */ + } + + void cRecorder::Activate(bool On) + { + if (On) { ++#ifdef USE_LIVEBUFFER ++ if (writer) ++#endif /* LIVEBUFFER */ + writer->Start(); + Start(); + } +@@ -174,6 +246,29 @@ void cRecorder::Action(void) + uchar *b = ringBuffer->Get(r); + if (b) { + int Count = remux->Put(b, r); ++#ifdef USE_LIVEBUFFER ++ if (!writer && liveBuffer) { ++ int c; ++ uchar pictureType; ++ uchar *p = remux->Get(c, &pictureType); ++ if (pictureType == I_FRAME && p && p[0]==0x00 && p[1]==0x00 && p[2]==0x01 && (p[7] & 0x80) && p[3]>=0xC0 && p[3]<=0xEF) { ++ int64_t pts = (int64_t) (p[ 9] & 0x0E) << 29 ; ++ pts |= (int64_t) p[ 10] << 22 ; ++ pts |= (int64_t) (p[ 11] & 0xFE) << 14 ; ++ pts |= (int64_t) p[ 12] << 7 ; ++ pts |= (int64_t) (p[ 13] & 0xFE) >> 1 ; ++ liveBuffer->CreateIndexFile(fileName,pts); ++#ifdef USE_TTXTSUBS ++ writer = new cFileWriter(fileName, remux, ttxtSubsRecorder); ++#else ++ writer = new cFileWriter(fileName, remux); ++#endif /* TTXTSUBS */ ++ writer->Start(); ++ } ++ else ++ remux->Del(c); ++ } ++#endif /* LIVEBUFFER */ + if (Count) + ringBuffer->Del(Count); + else +diff -ruNp vdr-1.7.0/recorder.h vdr-1.7.0-extensions/recorder.h +--- vdr-1.7.0/recorder.h 2007-01-05 11:44:05.000000000 +0100 ++++ vdr-1.7.0-extensions/recorder.h 2009-04-09 20:48:48.000000000 +0200 +@@ -10,11 +10,17 @@ + #ifndef __RECORDER_H + #define __RECORDER_H + ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "receiver.h" + #include "recording.h" + #include "remux.h" + #include "ringbuffer.h" + #include "thread.h" ++#ifdef USE_TTXTSUBS ++#include "vdrttxtsubshooks.h" ++#endif /* TTXTSUBS */ + + class cFileWriter; + +@@ -23,12 +29,30 @@ private: + cRingBufferLinear *ringBuffer; + cRemux *remux; + cFileWriter *writer; ++#ifdef USE_LIVEBUFFER ++ char *fileName; ++ cLiveBuffer *liveBuffer; ++#ifdef USE_TTXTSUBS ++ cTtxtSubsRecorderBase *ttxtSubsRecorder; ++#endif /* TTXTSUBS */ ++#endif /* LIVEBUFFER */ + protected: + virtual void Activate(bool On); + virtual void Receive(uchar *Data, int Length); + virtual void Action(void); + public: ++#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) ++ cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids ++#ifdef USE_TTXTSUBS ++ ,cTtxtSubsRecorderBase *tsr ++#endif /* TTXTSUBS */ ++#ifdef USE_LIVEBUFFER ++ ,cLiveBuffer *LiveBuffer = NULL ++#endif /* LIVEBUFFER */ ++ ); ++#else + cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids); ++#endif /* LIVEBUFFER || TTXTSUBS */ + // Creates a new recorder for the channel with the given ChannelID and + // the given Priority that will record the given PIDs into the file FileName. + virtual ~cRecorder(); +diff -ruNp vdr-1.7.0/recording.c vdr-1.7.0-extensions/recording.c +--- vdr-1.7.0/recording.c 2008-02-24 11:28:53.000000000 +0100 ++++ vdr-1.7.0-extensions/recording.c 2009-04-09 20:48:48.000000000 +0200 +@@ -8,6 +8,9 @@ + */ + + #include "recording.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <dirent.h> + #include <errno.h> +@@ -23,6 +26,17 @@ + #include "skins.h" + #include "tools.h" + #include "videodir.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ ++ ++#if defined (USE_DVDCHAPJUMP) && defined (USE_DVDARCHIVE) ++#include <assert.h> ++/* libdvdread stuff */ ++#include <dvdread/dvd_reader.h> ++#include <dvdread/ifo_types.h> ++#include <dvdread/ifo_read.h> ++#endif /* DVDCHAPJUMP & DVDARCHIVE */ + + #define SUMMARYFALLBACK + +@@ -46,6 +60,12 @@ + #endif + #define INFOFILESUFFIX "/info.vdr" + #define MARKSFILESUFFIX "/marks.vdr" ++#ifdef USE_LIEMIEXT ++#define INDEXFILESUFFIX "/index.vdr" ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++#define DVDARCHIVEFILENAME "/dvd.vdr" ++#endif /* DVDARCHIVE */ + + #define MINDISKSPACE 1024 // MB + +@@ -62,6 +82,13 @@ + #define MAX_LINK_LEVEL 6 + + bool VfatFileSystem = false; ++#ifdef USE_LIEMIEXT ++bool DirOrderState = false; ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf); ++#endif /* DVLFRIENDLYFNAMES */ + + cRecordings DeletedRecordings(true); + +@@ -491,9 +518,24 @@ cRecording::cRecording(cTimer *Timer, co + { + resume = RESUME_NOT_INITIALIZED; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + fileName = NULL; + name = NULL; ++#ifdef USE_DVDARCHIVE ++ dvdname = NULL; ++ dvdtrack = NULL; ++ dvdchapters = NULL; ++ isArchived = false; ++ isOnlyOnDvd = false; ++ dvdtype = DVD_TYPE_UNKNOWN; ++#endif /* DVDARCHIVE */ + fileSizeMB = -1; // unknown + deleted = 0; + // set up the actual name: +@@ -524,6 +566,11 @@ cRecording::cRecording(cTimer *Timer, co + break; + } + if (Timer->IsSingleEvent()) { ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ Timer -> SetFile(MakeFriendlyFilename(&name)); ++ else ++#endif /* DVLFRIENDLYFNAMES */ + Timer->SetFile(name); // this was an instant recording, so let's set the actual data + Timers.SetModified(); + } +@@ -534,6 +581,10 @@ cRecording::cRecording(cTimer *Timer, co + name = strdup(cString::sprintf("%s~%s", Timer->File(), Subtitle)); + // substitute characters that would cause problems in file names: + strreplace(name, '\n', ' '); ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ MakeFriendlyFilename(&name); ++#endif /* DVLFRIENDLYFNAMES */ + start = Timer->StartTime(); + priority = Timer->Priority(); + lifetime = Timer->Lifetime(); +@@ -548,12 +599,27 @@ cRecording::cRecording(const char *FileN + fileSizeMB = -1; // unknown + deleted = 0; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + fileName = strdup(FileName); + FileName += strlen(VideoDirectory) + 1; + char *p = strrchr(FileName, '/'); + + name = NULL; ++#ifdef USE_DVDARCHIVE ++ dvdname = NULL; ++ dvdtrack = NULL; ++ dvdchapters = NULL; ++ isArchived = false; ++ isOnlyOnDvd = false; ++ dvdtype = DVD_TYPE_NOT_READ; ++#endif /* DVDARCHIVE */ + info = new cRecordingInfo; + if (p) { + time_t now = time(NULL); +@@ -633,15 +699,34 @@ cRecording::cRecording(const char *FileN + LOG_ERROR_STR(*SummaryFileName); + } + #endif ++#ifdef USE_DVDARCHIVE ++ if (CheckFileExistence("dvd.vdr")) { ++ GetDvdName(fileName); ++ isArchived = true; ++ if (!CheckFileExistence("001.vdr")) ++ isOnlyOnDvd = true; ++ } ++#endif /* DVDARCHIVE */ + } + } + + cRecording::~cRecording() + { + free(titleBuffer); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ } ++#else + free(sortBuffer); ++#endif /* SORTRECORDS */ + free(fileName); + free(name); ++#ifdef USE_DVDARCHIVE ++ free(dvdname); ++ free(dvdtrack); ++ free(dvdchapters); ++#endif /* DVDARCHIVE */ + delete info; + } + +@@ -661,21 +746,46 @@ char *cRecording::StripEpisodeName(char + t++; + } + if (s1 && s2) ++#ifdef USE_SORTRECORDS ++ if (Setup.RecordingsSortDirsFirst) ++ *s1 = 'b'; ++ ++ if ((Setup.RecordingsSortMode <= 1 && s1 != s && !strchr(".-$ª·", *(s1 - 1))) || ++ (Setup.RecordingsSortMode == 1 && s1 == s) || ++ (Setup.RecordingsSortMode == 3)) ++#endif /* SORTRECORDS */ + memmove(s1 + 1, s2, t - s2 + 1); + return s; + } + + char *cRecording::SortName(void) const + { ++#ifdef USE_SORTRECORDS ++ if (!sortBuffer[Setup.RecordingsSortMode] || ++ lastDirsFirst[Setup.RecordingsSortMode] != Setup.RecordingsSortDirsFirst) { ++ free(sortBuffer[Setup.RecordingsSortMode]); ++ lastDirsFirst[Setup.RecordingsSortMode] = Setup.RecordingsSortDirsFirst; ++ char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory))); ++#else + if (!sortBuffer) { + char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory) + 1)); ++#endif /* SORTRECORDS */ + strreplace(s, '/', 'a'); // some locales ignore '/' when sorting + int l = strxfrm(NULL, s, 0) + 1; ++#ifdef USE_SORTRECORDS ++ sortBuffer[Setup.RecordingsSortMode] = MALLOC(char, l); ++ strxfrm(sortBuffer[Setup.RecordingsSortMode], s, l); ++#else + sortBuffer = MALLOC(char, l); + strxfrm(sortBuffer, s, l); ++#endif /* SORTRECORDS */ + free(s); + } ++#ifdef USE_SORTRECORDS ++ return sortBuffer[Setup.RecordingsSortMode]; ++#else + return sortBuffer; ++#endif /* SORTRECORDS */ + } + + int cRecording::GetResume(void) const +@@ -690,7 +800,15 @@ int cRecording::GetResume(void) const + int cRecording::Compare(const cListObject &ListObject) const + { + cRecording *r = (cRecording *)&ListObject; ++#ifdef USE_SORTRECORDS ++ return Recordings.GetSortOrder() * strcasecmp(SortName(), r->SortName()); ++#else ++#ifdef USE_LIEMIEXT ++ if (DirOrderState) ++ return strcasecmp(FileName(), r->FileName()); ++#endif /* LIEMIEXT */ + return strcasecmp(SortName(), r->SortName()); ++#endif /* USE_SORTRECORDS */ + } + + const char *cRecording::FileName(void) const +@@ -705,9 +823,359 @@ const char *cRecording::FileName(void) c + return fileName; + } + ++#ifdef USE_DVDARCHIVE ++bool cRecording::CheckFileExistence(const char* FileNameToTest, const bool useVideoDir) const ++{ ++ if (!useVideoDir || (useVideoDir && FileName())) { ++ cString filename = cString::sprintf("%s%s%s", useVideoDir ? FileName() : "", ++ useVideoDir ? "/" : "", ++ FileNameToTest); ++ struct stat statBuf; ++ if (lstat(filename, &statBuf) == -1) return false; ++ return S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode); ++ } ++ return false; ++} ++ ++bool cRecording::GetDvdName(const char* Directory) const ++{ ++ char* filename = (char*)alloca(strlen(Directory) + strlen(DVDARCHIVEFILENAME) + 1); ++ if (filename) { ++ strcpy(filename, Directory); ++ char *end = filename + strlen(filename); ++ strcpy(end, DVDARCHIVEFILENAME); ++ FILE* file; ++ if ((file = fopen(filename, "r"))) { ++ cReadLine ReadLine; ++ char* buffer = (char*)alloca(BUFSIZ); ++ if (buffer) { ++ buffer = ReadLine.Read(file); ++ if (buffer) ++ ((cRecording*)this)->dvdname = strdup(buffer); ++ else ++ ((cRecording*)this)->dvdname = NULL; ++ ++ buffer = ReadLine.Read(file); ++ if (buffer) { ++ ((cRecording*)this)->dvdtrack = strdup(buffer); ++ if (atoi(buffer) == 0) ++ ((cRecording*)this)->dvdtype = DVD_VIDEO_TYPE; ++ else ++ ((cRecording*)this)->dvdtype = DVD_VIDEO_ARCHIVE_TYPE; ++ } ++ else { ++ ((cRecording*)this)->dvdtrack = NULL; ++ ((cRecording*)this)->dvdtype = DVD_ARCHIVE_TYPE; ++ } ++ ++ fclose(file); ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++bool cRecording::GetDvdChaptersFromDvd(int title) const ++{ ++#ifdef USE_DVDCHAPJUMP ++ cString buf; ++ ++ dvd_reader_t *dvd; ++ ifo_handle_t *ifo_file; ++ tt_srpt_t *tt_srpt; ++ ifo_handle_t *vts_file; ++ pgc_t *cur_pgc; ++ ++ dvd = DVDOpen(DVD_DEVICE); ++ if (!dvd) { ++ esyslog("DVD-ARCHIVE: Couldn't open DVD device %s!", DVD_DEVICE); ++ return false; ++ } ++ ++ /* open title manager */ ++ ifo_file = ifoOpen(dvd,0); ++ if (!ifo_file) { ++ esyslog("DVD-ARCHIVE: Can't open VMG info."); ++ DVDClose(dvd); ++ return false; ++ } ++ ++ /* read total_title */ ++ tt_srpt = ifo_file->tt_srpt; ++ ++ /* get total chapters */ ++ int title_set_nr = tt_srpt->title[title-1].title_set_nr; ++ int total_chap = tt_srpt->title[title-1].nr_of_ptts; ++ int local_title_id = tt_srpt->title[title-1].vts_ttn - 1; ++ ++ /* access title set file */ ++ vts_file = ifoOpen(dvd, title_set_nr); ++ if (!vts_file) { ++ esyslog("DVD-ARCHIVE: Can't open info file for title set %d!",title_set_nr); ++ DVDClose(dvd); ++ return false; ++ } ++ ++ /* find program chain and check programs ++ all chapters should be in the same prog chain and ++ should be numbered from 1 to <total_chap> ++ */ ++ { ++ vts_ptt_srpt_t *vts_ptt_srpt = vts_file->vts_ptt_srpt; ++ int pgc_nr = vts_ptt_srpt->title[local_title_id].ptt[0].pgcn; ++ int pg = vts_ptt_srpt->title[local_title_id].ptt[0].pgn; ++ int p; ++ ++ assert(pg==1); ++ for (p=1; p<total_chap; p++) { ++ int next_pg; ++ int this_pgc; ++ this_pgc = vts_ptt_srpt->title[local_title_id].ptt[p].pgcn; ++ assert(pgc_nr == this_pgc); ++ next_pg = vts_ptt_srpt->title[local_title_id].ptt[p].pgn; ++ assert(pg+1 == next_pg); ++ pg = next_pg; ++ } ++ ++ /* fetch program chain */ ++ cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_nr-1].pgc; ++ assert(cur_pgc->nr_of_programs == total_chap); ++ } ++ ++ /* --- main cell loop --- */ ++ { ++ pgc_program_map_t *chap_cell; ++ cell_playback_t *cell_pb; ++ int c; ++ int chap; ++ ++ /* total cells in chain */ ++ int total_cell = cur_pgc->nr_of_cells; ++ ++ /* get info */ ++ chap_cell = cur_pgc->program_map; ++ cell_pb = cur_pgc->cell_playback; ++ ++ /* loop through all cells */ ++ chap = -1; ++ int position = 0; ++ for (c=0; c<total_cell; c++) { ++ int cell_mode; ++ const char *mode; ++ ++ dvd_time_t *time = (dvd_time_t *)&cell_pb->playback_time; ++ ++ int framerate = time->frame_u>>6; ++ assert(framerate == 1 || framerate == 3); ++ int frames_per_sec = (framerate == 1) ? 25 : 30; ++ ++ /* upper 4 bits are first digit, down 4 bits are second digit */ ++ int hour = (time->hour>>4) * 10 + (time->hour&15); ++ int minute = (time->minute>>4) * 10 + (time->minute&15); ++ int second = (time->second>>4) * 10 + (time->second&15); ++ /* upper 4 bits are first digit, down 4 bits are second digit */ ++ int frame = (time->frame_u>>4&3) * 10 + (time->frame_u&15); ++ ++ int frames = ((hour * 3600) + (minute * 60) + second) * frames_per_sec + frame; ++ ++ /* this cell is the begin of a new chapter! */ ++ if (chap_cell[chap+1] == c+1) { ++ cString oldbuf = cString::sprintf("%s", *buf); ++ buf = cString::sprintf("%s%d%s", *oldbuf, position, ((chap+2) < total_chap) ? "," : ""); ++ chap++; ++ } ++ ++ /* cell_mode: 0=normal, 1=first of angle, 2=in angle, 3=last of angle */ ++ cell_mode = cell_pb->block_mode; ++ if ((cell_mode==0) || (cell_mode==1)) { ++ /* only account for normal or begin of angle cells */ ++ position += frames; ++ mode = "counted"; ++ } ++ else ++ mode = "skipped"; ++ ++ cell_pb++; ++ } ++ } ++ ++ ifoClose(ifo_file); ++ ifoClose(vts_file); ++ DVDClose(dvd); ++ ++ ((cRecording*)this)->dvdchapters = strdup(buf); ++ ++ return true; ++#else ++ return false; ++#endif /* DVDCHAPJUMP */ ++} ++ ++const char *cRecording::GetDvdChapters(void) const ++{ ++ // Read chapters from dvd ++ if (dvdtype == DVD_VIDEO_ARCHIVE_TYPE) { ++ if (dvdtrack) { ++ if (!GetDvdChaptersFromDvd(atoi(dvdtrack))) ++ ((cRecording*)this)->dvdchapters = NULL; ++ else ++ isyslog("DVD-ARCHIVE: Using following positions for chapter jumping: %s", dvdchapters); ++ return dvdchapters; ++ } ++ } ++ return NULL; ++} ++ ++int cRecording::MountDvd(void) const ++{ ++ cString cmd; ++ if (Setup.DvdSpeedLimit > 0) { ++ cmd = cString::sprintf("speedcontrol -x %d %s", Setup.DvdSpeedLimit, DVD_DEVICE); ++ SystemExec(cmd); ++ } ++ ++ cString msg; ++ if (atoi(dvdname) == 0) ++ msg = cString::sprintf(tr("Please mount %s"), dvdname); ++ else { ++ if (Setup.DvdDisplayZeros) ++ msg = cString::sprintf(tr("Please mount DVD %04d"), atoi(dvdname)); ++ else ++ msg = cString::sprintf(tr("Please mount DVD %d"), atoi(dvdname)); ++ } ++ ++ bool rep = true; ++ while (rep) { ++ if (Setup.DvdTrayMode==1 || Setup.DvdTrayMode==3) ++ cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); ++ else ++ cmd = cString::sprintf("umount %s", DVD_DEVICE); ++ SystemExec(cmd); ++ ++ if (Interface->Confirm(msg, 300)) { ++ Skins.Message(mtStatus, tr("Please wait. Checking DVD...")); ++ Skins.Flush(); ++ cmd = cString::sprintf("eject -t %s; mkdir -p %s; mount -o ro -t %s %s %s", ++ DVD_DEVICE, DVD_MOUNT_PATH, ++ (dvdtrack ? "udf" : "iso9660"), ++ DVD_DEVICE, DVD_MOUNT_PATH); ++ SystemExec(cmd); ++ ++ bool correctDvd = true; ++ ++ char *olddvdname, *olddvdtrack; ++ int olddvdtype; ++ olddvdname = dvdname; ++ olddvdtrack = dvdtrack; ++ olddvdtype = dvdtype; ++ if (GetDvdName(DVD_MOUNT_PATH)) { ++ if (atoi(dvdname) != atoi(olddvdname)) correctDvd = false; ++ } ++ ((cRecording*)this)->dvdname = olddvdname; ++ ((cRecording*)this)->dvdtrack = olddvdtrack; ++ ((cRecording*)this)->dvdtype = olddvdtype; ++ ++ if (correctDvd) { ++ if (dvdtrack == NULL) { ++ // Archived DVD in VDR format ++ char fn[BUFSIZ]; ++ strcpy(fn, FileName()); ++ char *p = strrchr(fn, '/'); ++ cmd = cString::sprintf("find '%s' -name '%s'", DVD_MOUNT_PATH, p+1); ++ } ++ else { ++ // Either archived DVD in DVD-Video format or DVD-Video which ++ // should be played with the DVD plugin ++ cmd = cString::sprintf("find '%s' -iname 'VIDEO_TS'", DVD_MOUNT_PATH); ++ } ++ ++ cReadLine pipe; ++ FILE* file; ++ char *dirname = NULL; ++ if ((file = popen(cmd, "r")) != (FILE *)NULL) { ++ if ((dirname = pipe.Read(file)) != NULL) { ++ pclose(file); ++ if (dvdtrack != NULL && atoi(dvdtrack) == 0) { ++ // It is a valid Video-DVD and DVD plugin can be started ++ return MOUNT_DVD_LAUNCH_DVD_PLUGIN; ++ } ++ else { ++ // It is a valid Archive-DVD or an archived Video-DVD ++ // and the links can now be established ++ cString srcFn; ++ int n = 1; ++ ++ do { ++ if (dvdtrack == NULL) ++ srcFn = cString::sprintf("%s/%03d.vdr", dirname, n); ++ else ++ srcFn = cString::sprintf("%s/VTS_%02d_%d.VOB", dirname, atoi(dvdtrack), n); ++ ++ if (!access(srcFn, R_OK)) { ++ cmd = cString::sprintf("ln -sf '%s' '%s/%03d.vdr'", *srcFn, FileName(), n); ++ SystemExec(cmd); ++ isyslog("DVD-ARCHIVE: Linking %s/%03d.vdr -> %s", FileName(), n, *srcFn); ++ } ++ else ++ break; ++ } while ( ++n < 999); ++ ++ if (!CheckFileExistence("index.vdr")) { ++ if (dvdtrack == NULL) ++ srcFn = cString::sprintf("%s/index.vdr", dirname); ++ else ++ srcFn = cString::sprintf("%s/index_%02d.vdr", dirname, atoi(dvdtrack)); ++ ++ if (!CheckFileExistence(srcFn, false)) { ++ msg = cString::sprintf(tr("No index-file found. Creating may take minutes. Create one?")); ++ if (Interface->Confirm(msg, 300)) { ++ Skins.Message(mtStatus, tr("Please wait. Creating index-file...")); ++ cmd = cString::sprintf("speedcontrol -x 999 %s; cd %s && genindex &", DVD_DEVICE, FileName()); ++ SystemExec(cmd); ++ return MOUNT_DVD_ABORT; ++ } ++ } ++ else { ++ cmd = cString::sprintf("ln -sf '%s' '%s/index.vdr'", *srcFn, FileName()); ++ SystemExec(cmd); ++ isyslog("DVD-ARCHIVE: Linking %s/index.vdr -> %s", FileName(), *srcFn); ++ } ++ } ++ return MOUNT_DVD_REPLAY; ++ } ++ } ++ else { ++ Skins.Message(mtError, tr("Wrong DVD!"), 3); ++ Skins.Flush(); ++ } ++ } ++ pclose(file); ++ } ++ else { ++ Skins.Message(mtError, tr("Wrong DVD!"), 3); ++ Skins.Flush(); ++ } ++ } ++ else { ++ rep = false; ++ } ++ } ++ return MOUNT_DVD_ABORT; ++} ++ ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level, bool Original) const ++#else + const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) const ++#endif /* LIEMIEXT */ + { ++#ifdef USE_WAREAGLEICON ++ const char *New = NewIndicator && IsNew() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_NEW_UTF8 : ICON_NEW : "*" : " "; ++#else + char New = NewIndicator && IsNew() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + free(titleBuffer); + titleBuffer = NULL; + if (Level < 0 || Level == HierarchyLevels()) { +@@ -718,7 +1186,14 @@ const char *cRecording::Title(char Delim + s++; + else + s = name; ++#ifdef USE_LIEMIEXT ++ if (Original) { ++#endif /* LIEMIEXT */ ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%s%c%s", ++#else + titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%c%c%s", ++#endif /* WAREAGLEICON */ + t->tm_mday, + t->tm_mon + 1, + t->tm_year % 100, +@@ -728,6 +1203,92 @@ const char *cRecording::Title(char Delim + New, + Delimiter, + s)); ++#ifdef USE_LIEMIEXT ++ } ++ else { ++ cString RecLength("---"); ++ if (Setup.ShowRecLength && FileName()) { ++ cString filename = cString::sprintf("%s%s", FileName(), INDEXFILESUFFIX); ++ if (*filename) { ++ if (access(filename, R_OK) == 0) { ++ struct stat buf; ++ if (stat(filename, &buf) == 0) { ++ struct tIndex { int offset; uchar type; uchar number; short reserved; }; ++ int delta = buf.st_size % sizeof(tIndex); ++ if (delta) { ++ delta = sizeof(tIndex) - delta; ++ esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, *filename); ++ } ++ RecLength = cString::sprintf("%ld'", (buf.st_size + delta) / sizeof(tIndex) / SecondsToFrames(60)); ++ } ++ } ++ } ++ } ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++#ifdef USE_WAREAGLEICON ++ if (isArchived && !isOnlyOnDvd) New = Setup.WarEagleIcons ? IsLangUtf8() ? ICON_DVD_UTF8 : ICON_DVD : "~"; ++#else ++ if (isArchived && !isOnlyOnDvd) New = '~'; ++#endif /* WAREAGLEICON */ ++ ++ if (isOnlyOnDvd && Setup.DvdDisplayMode >= 1) { ++ char oldLength[21]; ++ ++ if (strrchr(RecLength, '\'')) ++ sprintf(oldLength,"%s", *RecLength); ++ else ++ oldLength[0] = 0; ++ ++ if (dvdname) { ++ if (atoi(dvdname) != 0) { ++ cString tmp; ++ if (Setup.DvdDisplayZeros) ++ tmp = cString::sprintf("%04d", atoi(dvdname)); ++ else { ++ int num = atoi(dvdname); ++ bool displaySpace = !(Setup.DvdDisplayMode == 1 && oldLength[0] != 0); ++ // ugly hack to have 2 spaces instead of one 0 for each place ++ tmp = cString::sprintf("%s%s%s%d", displaySpace && (num < 1000) ? " " : "", ++ displaySpace && (num < 100) ? " " : "", ++ displaySpace && (num < 10) ? " " : "", ++ num); ++ } ++ ((cRecording*)this)->dvdname = strdup(tmp); ++ } ++ } ++ ++ RecLength = strdup(cString::sprintf("%s%s%s%s", (Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? oldLength : "", ++ (dvdname && isArchived && isOnlyOnDvd && Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? " / " : "", ++ (dvdname && isArchived && isOnlyOnDvd) ? dvdname : "", ++ (dvdname && isArchived && isOnlyOnDvd) ? " " : "" ++ )); ++ } ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++ cString RecDate = cString::sprintf("%02d.%02d.%02d", t->tm_mday, t->tm_mon + 1, t->tm_year % 100); ++ cString RecTime = cString::sprintf("%02d:%02d", t->tm_hour, t->tm_min); ++ cString RecDelimiter = cString::sprintf("%c", Delimiter); ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%s%s%s%s%s%s%s%s", ++#else ++ titleBuffer = strdup(cString::sprintf("%s%s%s%c%s%s%s%s", ++#endif /* WAREAGLEICON */ ++ (Setup.ShowRecDate ? *RecDate : ""), ++ (Setup.ShowRecDate && Setup.ShowRecTime ? *RecDelimiter : ""), ++ (Setup.ShowRecTime ? *RecTime : ""), ++ New, ++ (Setup.ShowRecTime || Setup.ShowRecDate ? *RecDelimiter : ""), ++#ifdef USE_DVDARCHIVE ++ (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecLength : ""), ++ (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecDelimiter : ""), ++#else ++ (Setup.ShowRecLength ? *RecLength : ""), ++ (Setup.ShowRecLength ? *RecDelimiter : ""), ++#endif /* DVDARCHIVE */ ++ s)); ++ } ++#endif /* LIEMIEXT */ + // let's not display a trailing '~': + if (!NewIndicator) + stripspace(titleBuffer); +@@ -756,6 +1317,17 @@ const char *cRecording::Title(char Delim + return titleBuffer; + } + ++#ifdef USE_CUTTIME ++void cRecording::SetStartTime(time_t Start) ++{ ++ start=Start; ++ if (fileName) { ++ free(fileName); ++ fileName = NULL; ++ } ++} ++#endif /* CUTTIME */ ++ + const char *cRecording::PrefixFileName(char Prefix) + { + cString p = PrefixVideoFileName(FileName(), Prefix); +@@ -809,10 +1381,20 @@ bool cRecording::Delete(void) + // the new name already exists, so let's remove that one first: + isyslog("removing recording '%s'", NewName); + RemoveVideoFile(NewName); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(this, scDel); ++#endif /* STREAMDEVEXT */ + } + isyslog("deleting recording '%s'", FileName()); ++#ifdef USE_STREAMDEVEXT ++ if (access(FileName(), F_OK) == 0) { ++ result = RenameVideoFile(FileName(), NewName); ++ cStatus::MsgRecordingChange(this, scDel); ++ } ++#else + if (access(FileName(), F_OK) == 0) + result = RenameVideoFile(FileName(), NewName); ++#endif /* STREAMDEVEXT */ + else { + isyslog("recording '%s' vanished", FileName()); + result = true; // well, we were going to delete it, anyway +@@ -830,7 +1412,13 @@ bool cRecording::Remove(void) + return false; + } + isyslog("removing recording %s", FileName()); ++#ifdef USE_STREAMDEVEXT ++ bool ret = RemoveVideoFile(FileName()); ++ cStatus::MsgRecordingChange(this, scDel); ++ return ret; ++#else + return RemoveVideoFile(FileName()); ++#endif /* STREAMDEVEXT */ + } + + bool cRecording::Undelete(void) +@@ -847,8 +1435,15 @@ bool cRecording::Undelete(void) + } + else { + isyslog("undeleting recording '%s'", FileName()); ++#ifdef USE_STREAMDEVEXT ++ if (access(FileName(), F_OK) == 0) { ++ result = RenameVideoFile(FileName(), NewName); ++ cStatus::MsgRecordingChange(this, scAdd); ++ } ++#else + if (access(FileName(), F_OK) == 0) + result = RenameVideoFile(FileName(), NewName); ++#endif /* STREAMDEVEXT */ + else { + isyslog("deleted recording '%s' vanished", FileName()); + result = false; +@@ -864,6 +1459,53 @@ void cRecording::ResetResume(void) const + resume = RESUME_NOT_INITIALIZED; + } + ++#ifdef USE_LIEMIEXT ++bool cRecording::Rename(const char *newName, int *newPriority, int *newLifetime) ++{ ++ bool result = false; ++ struct tm tm_r; ++ struct tm *t = localtime_r(&start, &tm_r); ++ char *localNewName = ExchangeChars(strdup(newName), true); ++ char *newFileName = strdup(cString::sprintf(NAMEFORMAT, VideoDirectory, localNewName, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, *newPriority, *newLifetime)); ++ free(localNewName); ++ if (strcmp(FileName(), newFileName)) { ++ if (access(newFileName, F_OK) == 0) { ++ isyslog("recording %s already exists", newFileName); ++ } ++ else { ++ isyslog("renaming recording %s to %s", FileName(), newFileName); ++ result = MakeDirs(newFileName, true); ++ if (result) ++ result = RenameVideoFile(FileName(), newFileName); ++ if (result) { ++ priority = *newPriority; ++ lifetime = *newLifetime; ++ free(fileName); ++ fileName = strdup(newFileName); ++ free(name); ++ name = strdup(newName); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ sortBuffer[i] = NULL; ++ } ++#else ++ free(sortBuffer); ++ sortBuffer = NULL; ++#endif /* SORTRECORDS */ ++ free(titleBuffer); ++ titleBuffer = NULL; ++ } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(this, scMod); ++#endif /* STREAMDEVEXT */ ++ } ++ } ++ free(newFileName); ++ return result; ++} ++#endif /* LIEMIEXT */ ++ + // --- cRecordings ----------------------------------------------------------- + + cRecordings Recordings; +@@ -876,6 +1518,9 @@ cRecordings::cRecordings(bool Deleted) + deleted = Deleted; + lastUpdate = 0; + state = 0; ++#ifdef USE_SORTRECORDS ++ SortOrder = 1; ++#endif /* SORTRECORDS */ + } + + cRecordings::~cRecordings() +@@ -1154,14 +1799,70 @@ cMark *cMarks::GetNext(int Position) + return NULL; + } + ++#ifdef USE_JUMPPLAY ++// --- cMarksReload ---------------------------------------------------------- ++ ++#define MARKS_RELOAD_MS 10000 ++ ++time_t cMarksReload::lastsavetime = 0; ++ ++cMarksReload::cMarksReload(const char *RecordingFileName) ++:recDir(RecordingFileName) ++{ ++ struct stat sbuf; ++ if (Load(recDir) && stat(FileName(), &sbuf) == 0) ++ lastmodtime = sbuf.st_mtime; ++ else ++ lastmodtime = 0; ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++} ++ ++bool cMarksReload::Reload(void) ++{ ++ // Check the timestamp of marks.vdr in 10 seconds intervals ++ // Independent but synchronized reloading of marks in two threads ++ if ((Setup.ReloadMarks && nextreload.TimedOut()) || lastsavetime > lastmodtime) { ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++ struct stat sbuf; ++ if (stat(FileName(), &sbuf) == 0 && sbuf.st_mtime != lastmodtime) { ++ lastmodtime = sbuf.st_mtime; ++ if (Load(recDir)) ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool cMarksReload::Save(void) ++{ ++ bool ok = cMarks::Save(); ++ struct stat sbuf; ++ if (ok && stat(FileName(), &sbuf) == 0) ++ lastsavetime = lastmodtime = sbuf.st_mtime; ++ return ok; ++} ++#endif /* JUMPPLAY */ ++ + // --- cRecordingUserCommand ------------------------------------------------- + + const char *cRecordingUserCommand::command = NULL; + ++#ifdef USE_DVLRECSCRIPTADDON ++void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName, char *chanName) ++#else + void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName) ++#endif /* DVLRECSCRIPTADDON */ + { + if (command) { ++#ifdef USE_DVLRECSCRIPTADDON ++ cString cmd; ++ if (chanName != NULL) ++ cmd = cString::sprintf("%s %s \"%s\" \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"), chanName); ++ else ++ cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#else + cString cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#endif /* DVLRECSCRIPTADDON */ + isyslog("executing '%s'", *cmd); + SystemExec(cmd); + } +@@ -1172,7 +1873,9 @@ void cRecordingUserCommand::InvokeComman + //XXX+ somewhere else??? + // --- cIndexFile ------------------------------------------------------------ + ++#ifndef USE_LIEMIEXT + #define INDEXFILESUFFIX "/index.vdr" ++#endif /* LIEMIEXT */ + + // The number of frames to stay off the end in case of time shift: + #define INDEXSAFETYLIMIT 150 // frames +@@ -1431,6 +2134,48 @@ cFileName::cFileName(const char *FileNam + cFileName::~cFileName() + { + Close(); ++#ifdef USE_DVDARCHIVE ++ ++ char fn[BUFSIZ]; ++ strcpy(fn, fileName); ++ ++ char *p; ++ if((p = strrchr(fn, '/'))) { ++ p[0] = 0; ++ } ++ ++ cString cmd = cString::sprintf("find \"%s\" -type l -lname \"%s/*\"", fn, DVD_MOUNT_PATH); ++ ++ bool isOnDvd = false; ++ ++ cReadLine pipe; ++ FILE* file; ++ char* filename; ++ if ((file = popen(cmd, "r")) != (FILE *)NULL) { ++ while ((filename = pipe.Read(file)) != NULL) { ++ isOnDvd = true; ++ unlink(filename); ++ isyslog("DVD-ARCHIVE: Deleting %s", filename); ++ } ++ pclose(file); ++ } ++ ++ if (isOnDvd) { ++ if (Setup.DvdTrayMode==2 || Setup.DvdTrayMode==3) ++ cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); ++ else ++ cmd = cString::sprintf("umount %s", DVD_DEVICE); ++ ++ SystemExec(cmd); ++ ++ if (Setup.DvdSpeedLimit > 0) { ++ cmd = cString::sprintf("speedcontrol -x 999 %s", DVD_DEVICE); ++ SystemExec(cmd); ++ } ++ } ++ ++#endif /* DVDARCHIVE */ ++ + free(fileName); + } + +@@ -1508,6 +2253,18 @@ cUnbufferedFile *cFileName::SetOffset(in + return NULL; + } + ++#ifdef USE_HARDLINKCUTTER ++int cFileName::MaxFileSize() { ++ const int smallFiles = (255 * MAXVIDEOFILESIZE - 1024 * Setup.MaxRecordingSize) ++ / max(MAXVIDEOFILESIZE - Setup.MaxVideoFileSize, 1); ++ ++ if (fileNumber <= smallFiles) ++ return MEGABYTE(Setup.MaxVideoFileSize); ++ ++ return MEGABYTE(MAXVIDEOFILESIZE); ++} ++#endif /* HARDLINKCUTTER */ ++ + cUnbufferedFile *cFileName::NextFile(void) + { + return SetOffset(fileNumber + 1); +@@ -1555,3 +2312,113 @@ int ReadFrame(cUnbufferedFile *f, uchar + LOG_ERROR; + return r; + } ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf) ++{ ++ char *b, *x, *y; ++ ++ if (buf == NULL || *buf == NULL) ++ return(NULL); ++ ++ b = (char *)malloc(strlen(*buf) * 2); ++ x = *buf; ++ y = b; ++ ++ while (*x != 0) { ++ switch (*x) { ++ case 'Ä': ++ *y = 'A'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ä': ++ *y = 'a'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ö': ++ *y = 'O'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ö': ++ *y = 'o'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ü': ++ *y = 'U'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ü': ++ *y = 'u'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ß': ++ *y = 's'; ++ y++; ++ *y = 's'; ++ y++; x++; ++ break; ++ ++ // chars to replace ++ case ':': ++ case ';': ++ case '?': ++ case ' ': ++ case '\t': ++ *y = '_'; ++ y++; x++; ++ break; ++ ++ // chars to simply strip ++ case '\"': ++ case '*': ++ case '{': ++ case '}': ++ case '[': ++ case ']': ++ case '=': ++ case '<': ++ case '>': ++ case '#': ++ case '`': ++ case '|': ++ case '\\': ++ case '\n': ++ case '\r': ++ x++; ++ break; ++ ++ default: ++ *y = *x; ++ y++; x++; ++ break; ++ } ++ } ++ *y = 0; ++ ++ x = strdup(b); ++ free(b); ++ ++ free(*buf); ++ *buf = x; ++ ++ return(*buf); ++} ++#endif /* DVLFRIENDLYFNAMES */ +diff -ruNp vdr-1.7.0/recording.h vdr-1.7.0-extensions/recording.h +--- vdr-1.7.0/recording.h 2007-10-14 12:11:34.000000000 +0200 ++++ vdr-1.7.0-extensions/recording.h 2009-04-09 20:48:48.000000000 +0200 +@@ -19,6 +19,9 @@ + #include "tools.h" + + extern bool VfatFileSystem; ++#ifdef USE_LIEMIEXT ++extern bool DirOrderState; ++#endif /* LIEMIEXT */ + + void RemoveDeletedRecordings(void); + void AssertFreeDiskSpace(int Priority = 0, bool Force = false); +@@ -52,9 +55,15 @@ private: + public: + ~cRecordingInfo(); + tChannelID ChannelID(void) const { return channelID; } ++#ifdef USE_STREAMDEVEXT ++ const cEvent *GetEvent(void) const { return event; } ++#endif /* STREAMDEVEXT */ + const char *ChannelName(void) const { return channelName; } + const char *Title(void) const { return event->Title(); } + const char *ShortText(void) const { return event->ShortText(); } ++#ifdef USE_GRAPHTFT ++ tEventID EventID(void) const { return event->EventID(); } ++#endif /* GRAPHTFT */ + const char *Description(void) const { return event->Description(); } + const cComponents *Components(void) const { return event->Components(); } + const char *Aux(void) const { return aux; } +@@ -62,16 +71,50 @@ public: + bool Write(FILE *f, const char *Prefix = "") const; + }; + ++#ifdef USE_SORTRECORDS ++#define SORTRECORDINGSVERSNUM 3 ++#define MAXSORTMODES 4 ++#endif /* SORTRECORDS */ ++ ++#ifdef USE_DVDARCHIVE ++#define MOUNT_DVD_ABORT 0 ++#define MOUNT_DVD_REPLAY 1 ++#define MOUNT_DVD_LAUNCH_DVD_PLUGIN 2 ++#define DVD_DEVICE "/dev/cdrom" ++#define DVD_MOUNT_PATH "/tmp/vdr.dvd" ++ ++#define DVD_TYPE_UNKNOWN -1 ++#define DVD_TYPE_NOT_READ 0 ++#define DVD_VIDEO_TYPE 1 ++#define DVD_ARCHIVE_TYPE 2 ++#define DVD_VIDEO_ARCHIVE_TYPE 3 ++#endif /* DVDARCHIVE */ ++ + class cRecording : public cListObject { + friend class cRecordings; + private: + mutable int resume; + mutable char *titleBuffer; ++ ++#ifdef USE_SORTRECORDS ++ mutable char *sortBuffer[MAXSORTMODES]; ++ mutable char lastDirsFirst[MAXSORTMODES]; ++#else + mutable char *sortBuffer; ++#endif /* SORTRECORDS */ + mutable char *fileName; + mutable char *name; + mutable int fileSizeMB; + cRecordingInfo *info; ++#ifdef USE_DVDARCHIVE ++ char *dvdname; ++ char *dvdtrack; ++ char *dvdchapters; ++ bool isArchived; ++ bool isOnlyOnDvd; ++ int dvdtype; ++ bool GetDvdChaptersFromDvd(int title) const; ++#endif /* DVDARCHIVE */ + cRecording(const cRecording&); // can't copy cRecording + cRecording &operator=(const cRecording &); // can't assign cRecording + static char *StripEpisodeName(char *s); +@@ -88,8 +131,23 @@ public: + virtual int Compare(const cListObject &ListObject) const; + const char *Name(void) const { return name; } + const char *FileName(void) const; ++#ifdef USE_DVDARCHIVE ++ bool CheckFileExistence(const char* FileNameToTest, const bool useVideoDir = true) const; ++ bool GetDvdName(const char* Directory) const; ++ bool IsOnlyOnDvd(void) const { return isOnlyOnDvd; } ++ int MountDvd(void) const; ++ int GetDvdType(void) const { return dvdtype; } ++ const char *GetDvdChapters(void) const ; ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++ const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1, bool Original = true) const; ++#else + const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const; ++#endif /* LIEMIEXT */ + const cRecordingInfo *Info(void) const { return info; } ++#ifdef USE_CUTTIME ++ void SetStartTime(time_t Start); ++#endif /* CUTTIME */ + const char *PrefixFileName(char Prefix); + int HierarchyLevels(void) const; + void ResetResume(void) const; +@@ -106,6 +164,11 @@ public: + // 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 ++#ifdef USE_LIEMIEXT ++ bool Rename(const char *newName, int *newPriority, int *newLifetime); ++ // Changes the file name ++ // Returns false in case of error ++#endif /* LIEMIEXT */ + }; + + class cRecordings : public cList<cRecording>, public cThread { +@@ -114,6 +177,9 @@ private: + bool deleted; + time_t lastUpdate; + int state; ++#ifdef USE_SORTRECORDS ++ int SortOrder; ++#endif /* SORTRECORDS */ + const char *UpdateFileName(void); + void Refresh(bool Foreground = false); + void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0); +@@ -144,6 +210,10 @@ public: + void AddByName(const char *FileName, bool TriggerUpdate = true); + void DelByName(const char *FileName); + int TotalFileSizeMB(void); ///< Only for deleted recordings! ++#ifdef USE_SORTRECORDS ++ void ToggleSortOrder(void) { SortOrder *= -1; } ++ const int GetSortOrder(void) { return SortOrder; } ++#endif /* SORTRECORDS */ + }; + + extern cRecordings Recordings; +@@ -170,6 +240,20 @@ public: + cMark *GetNext(int Position); + }; + ++#ifdef USE_JUMPPLAY ++class cMarksReload : public cMarks { ++private: ++ cString recDir; ++ cTimeMs nextreload; ++ time_t lastmodtime; ++ static time_t lastsavetime; ++public: ++ cMarksReload(const char *RecordingFileName); ++ bool Reload(void); ++ bool Save(void); ++ }; ++#endif /* JUMPPLAY */ ++ + #define RUC_BEFORERECORDING "before" + #define RUC_AFTERRECORDING "after" + #define RUC_EDITEDRECORDING "edited" +@@ -178,8 +262,15 @@ class cRecordingUserCommand { + private: + static const char *command; + public: ++#ifdef USE_DELTIMESHIFTREC ++ static const char *GetCommand(void) { return command; } ++#endif /* DELTIMESHIFTREC */ + static void SetCommand(const char *Command) { command = Command; } ++#ifdef USE_DVLRECSCRIPTADDON ++ static void InvokeCommand(const char *State, const char *RecordingFileName, char *chanName = NULL); ++#else + static void InvokeCommand(const char *State, const char *RecordingFileName); ++#endif /* DVLRECSCRIPTADDON */ + }; + + //XXX+ +@@ -195,7 +286,19 @@ public: + // may be slightly higher because we stop recording only before the next + // 'I' frame, to have a complete Group Of Pictures): + #define MAXVIDEOFILESIZE 2000 // MB ++#ifndef USE_HARDLINKCUTTER + #define MINVIDEOFILESIZE 100 // MB ++#else ++#define MINVIDEOFILESIZE 1 // MB ++ ++#define MINRECORDINGSIZE 25 // GB ++#define MAXRECORDINGSIZE 500 // GB ++#define DEFAULTRECORDINGSIZE 100 // GB ++// Dynamic recording size: ++// Keep recording file size at Setup.MaxVideoFileSize for as long as possible, ++// but switch to MAXVIDEOFILESIZE early enough, so that Setup.MaxRecordingSize ++// will be reached, before recording to file 255.vdr ++#endif /* HARDLINKCUTTER */ + + class cIndexFile { + private: +@@ -207,6 +310,9 @@ private: + cResumeFile resumeFile; + cMutex mutex; + bool CatchUp(int Index = -1); ++#ifdef USE_DVDARCHIVE ++ bool isOnDVD; ++#endif /* DVDARCHIVE */ + public: + cIndexFile(const char *FileName, bool Record); + ~cIndexFile(); +@@ -236,6 +342,10 @@ public: + cUnbufferedFile *Open(void); + void Close(void); + cUnbufferedFile *SetOffset(int Number, int Offset = 0); ++#ifdef USE_HARDLINKCUTTER ++ int MaxFileSize(); ++ // Dynamic file size for this file ++#endif /* HARDLINKCUTTER */ + cUnbufferedFile *NextFile(void); + }; + +diff -ruNp vdr-1.7.0/remux.c vdr-1.7.0-extensions/remux.c +--- vdr-1.7.0/remux.c 2007-11-25 14:56:03.000000000 +0100 ++++ vdr-1.7.0-extensions/remux.c 2009-04-09 20:48:48.000000000 +0200 +@@ -1829,8 +1829,15 @@ void cTS2PES::ts_to_pes(const uint8_t *B + if (Buf[1] & TS_ERROR) + tsErrors++; + ++#ifdef USE_DVBSETUP ++ if (!(Buf[3] & (ADAPT_FIELD | PAY_LOAD))) { ++ dsyslog("TS packet discarded due to invalid adaption_field_control"); ++ return; ++ } ++#else + if (!(Buf[3] & (ADAPT_FIELD | PAY_LOAD))) + return; // discard TS packet with adaption_field_control set to '00'. ++#endif /* DVBSETUP */ + + if ((Buf[3] & PAY_LOAD) && ((Buf[3] ^ ccCounter) & CONT_CNT_MASK)) { + // This should check duplicates and packets which do not increase the counter. +@@ -1842,6 +1849,9 @@ void cTS2PES::ts_to_pes(const uint8_t *B + // These are the errors I used to get with Nova-T when antenna + // was not positioned correcly (not transport errors). //tvr + //dsyslog("TS continuity error (%d)", ccCounter); ++#ifdef USE_DVBSETUP ++ dsyslog("TS continuity error (%d)", ccCounter); ++#endif /* DVBSETUP */ + } + ccCounter = Buf[3] & CONT_CNT_MASK; + } +@@ -1867,6 +1877,10 @@ void cTS2PES::ts_to_pes(const uint8_t *B + + if (Buf[3] & PAY_LOAD) + instant_repack(Buf + 4 + off, TS_SIZE - 4 - off); ++#ifdef USE_DVBSETUP ++ else if (off + 4 < 188) ++ dsyslog("adaption_field zu short or PAY_LOAD not set"); ++#endif /* DVBSETUP */ + } + + // --- cRingBufferLinearPes -------------------------------------------------- +@@ -1896,12 +1910,19 @@ int cRingBufferLinearPes::DataReady(cons + + #define RESULTBUFFERSIZE KILOBYTE(256) + ++#ifdef USE_SYNCEARLY ++cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly) ++#else + cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure) ++#endif /* SYNCEARLY */ + { + exitOnFailure = ExitOnFailure; + noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF; + numUPTerrors = 0; + synced = false; ++#ifdef USE_SYNCEARLY ++ syncEarly = SyncEarly; ++#endif /* SYNCEARLY */ + skipped = 0; + numTracks = 0; + resultSkipped = 0; +@@ -2105,12 +2126,26 @@ uchar *cRemux::Get(int &Count, uchar *Pi + } + } + else if (!synced) { ++#ifdef USE_SYNCEARLY ++ if (pt == I_FRAME || syncEarly) { ++#else + if (pt == I_FRAME) { ++#endif /* SYNCEARLY */ + if (PictureType) + *PictureType = pt; + resultSkipped = i; // will drop everything before this position ++#ifdef USE_SYNCEARLY ++ if (!syncEarly) ++#endif /* SYNCEARLY */ + SetBrokenLink(data + i, l); + synced = true; ++#ifdef USE_SYNCEARLY ++ if (syncEarly) { ++ if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink() ++ SetBrokenLink(data + i, l); ++ else fprintf(stderr, "video: synced early\n"); ++ } ++#endif /* SYNCEARLY */ + } + } + else if (Count) +@@ -2123,12 +2158,21 @@ uchar *cRemux::Get(int &Count, uchar *Pi + l = GetPacketLength(data, resultCount, i); + if (l < 0) + return resultData; ++#ifdef USE_SYNCEARLY ++ if (noVideo || !synced && syncEarly) { ++ if (!synced) { ++ if (PictureType && noVideo) ++#else + if (noVideo) { + if (!synced) { + if (PictureType) ++#endif /* SYNCEARLY */ + *PictureType = I_FRAME; + resultSkipped = i; // will drop everything before this position + synced = true; ++#ifdef USE_SYNCEARLY ++ if (!noVideo && syncEarly) fprintf(stderr, "audio: synced early\n"); ++#endif /* SYNCEARLY */ + } + else if (Count) + return resultData; +diff -ruNp vdr-1.7.0/remux.h vdr-1.7.0-extensions/remux.h +--- vdr-1.7.0/remux.h 2007-09-02 12:19:06.000000000 +0200 ++++ vdr-1.7.0-extensions/remux.h 2009-04-09 20:48:48.000000000 +0200 +@@ -40,6 +40,9 @@ private: + bool noVideo; + int numUPTerrors; + bool synced; ++#ifdef USE_SYNCEARLY ++ bool syncEarly; ++#endif /* SYNCEARLY */ + int skipped; + cTS2PES *ts2pes[MAXTRACKS]; + int numTracks; +@@ -47,12 +50,18 @@ private: + int resultSkipped; + int GetPid(const uchar *Data); + public: ++#ifdef USE_SYNCEARLY ++ cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false); ++#else + cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false); ++#endif /* SYNCEARLY */ + ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while + ///< APids, DPids and SPids are pointers to zero terminated lists of audio, + ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such + ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency + ///< exit" in case of problems with the data stream. ++ ///< If USE_SYNCEARLY is activated: SyncEarly causes cRemux to sync as soon ++ ///< as a video or audio frame is seen. + ~cRemux(); + void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); } + ///< By default cRemux assumes that Put() and Get() are called from different +diff -ruNp vdr-1.7.0/skinclassic.c vdr-1.7.0-extensions/skinclassic.c +--- vdr-1.7.0/skinclassic.c 2008-02-23 11:31:58.000000000 +0100 ++++ vdr-1.7.0-extensions/skinclassic.c 2009-04-09 20:48:48.000000000 +0200 +@@ -314,8 +314,52 @@ void cSkinClassicDisplayMenu::SetItem(co + for (int i = 0; i < MaxTabs; i++) { + const char *s = GetTabbedText(Text, i); + if (s) { ++#ifdef USE_LIEMIEXT ++ bool isprogressbar = false; ++ int now = 0, total = 0; ++ // check if progress bar: "[||||||| ]" ++ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { ++ const char *p = s + 1; ++ // update status ++ isprogressbar = true; ++ for (; *p != ']'; ++p) { ++ // check if progressbar characters ++ if (*p == ' ' || *p == '|') { ++ // update counters ++ ++total; ++ if (*p == '|') ++ ++now; ++ } ++ else { ++ // wrong character detected; not a progressbar ++ isprogressbar = false; ++ break; ++ } ++ } ++ } ++ int xt = x0 + Tab(i); ++ if (Setup.ShowProgressBar && isprogressbar) { ++ // define x coordinates of progressbar ++ int px0 = xt; ++ int px1 = (Tab(i + 1)?Tab(i+1):x1) - 5; ++ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); ++ // define y coordinates of progressbar ++ int py0 = y + 4; ++ int py1 = y + lineHeight - 4; ++ // draw background ++ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i+1):x1) - 1, y + lineHeight - 1, ColorBg); ++ // draw progressbar ++ osd->DrawRectangle(px0, py0, px, py1, ColorFg); ++ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); ++ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); ++ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); ++ } ++ else ++ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); ++#else + int xt = x0 + Tab(i); + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); ++#endif /* LIEMIEXT */ + } + if (!Tab(i + 1)) + break; +diff -ruNp vdr-1.7.0/skinsttng.c vdr-1.7.0-extensions/skinsttng.c +--- vdr-1.7.0/skinsttng.c 2008-02-23 11:23:44.000000000 +0100 ++++ vdr-1.7.0-extensions/skinsttng.c 2009-04-09 20:48:48.000000000 +0200 +@@ -558,8 +558,52 @@ void cSkinSTTNGDisplayMenu::SetItem(cons + for (int i = 0; i < MaxTabs; i++) { + const char *s = GetTabbedText(Text, i); + if (s) { ++#ifdef USE_LIEMIEXT ++ bool isprogressbar = false; ++ int now = 0, total = 0; ++ // check if progress bar: "[||||||| ]" ++ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { ++ const char *p = s + 1; ++ // update status ++ isprogressbar = true; ++ for (; *p != ']'; ++p) { ++ // check if progressbar characters ++ if (*p == ' ' || *p == '|') { ++ // update counters ++ ++total; ++ if (*p == '|') ++ ++now; ++ } ++ else { ++ // wrong character detected; not a progressbar ++ isprogressbar = false; ++ break; ++ } ++ } ++ } ++ int xt = x3 + 5 + Tab(i); ++ if (Setup.ShowProgressBar && isprogressbar) { ++ // define x coordinates of progressbar ++ int px0 = xt; ++ int px1 = x3 + (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1; ++ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); ++ // define y coordinates of progressbar ++ int py0 = y + 4; ++ int py1 = y + lineHeight - 4; ++ // draw background ++ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1, y + lineHeight - 1, ColorBg); ++ // draw progressbar ++ osd->DrawRectangle(px0, py0, px, py1, ColorFg); ++ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); ++ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); ++ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); ++ } ++ else ++ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); ++#else + int xt = x3 + 5 + Tab(i); + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); ++#endif /* LIEMIEXT */ + } + if (!Tab(i + 1)) + break; +@@ -602,6 +646,21 @@ void cSkinSTTNGDisplayMenu::SetEvent(con + y += ts.Height(); + } + y += font->Height(); ++#ifdef USE_PARENTALRATING ++ if (!isempty(Event->GetParentalRatingString())) { ++ const cFont *font = cFont::GetFont(fontSml); ++ ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetParentalRatingString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); ++ y += ts.Height(); ++ } ++ int i = 0; ++ while (Event->Contents(i++)) { ++ if (!isempty(Event->GetContentsString())) { ++ const cFont *font = cFont::GetFont(fontSml); ++ ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetContentsString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); ++ y += ts.Height(); ++ } ++ } ++#endif /* PARENTALRATING */ + if (!isempty(Event->Description())) { + int yt = y; + int yb = y4 - Roundness; +diff -ruNp vdr-1.7.0/sources.c vdr-1.7.0-extensions/sources.c +--- vdr-1.7.0/sources.c 2008-02-10 15:07:26.000000000 +0100 ++++ vdr-1.7.0-extensions/sources.c 2009-04-09 20:48:48.000000000 +0200 +@@ -37,6 +37,9 @@ cString cSource::ToString(int Code) + char buffer[16]; + char *q = buffer; + switch (Code & st_Mask) { ++#ifdef USE_PLUGINPARAM ++ case stPlug: *q++ = 'P'; break; ++#endif /* PLUGINPARAM */ + case stCable: *q++ = 'C'; break; + case stSat: *q++ = 'S'; + { +@@ -56,6 +59,9 @@ int cSource::FromString(const char *s) + { + int type = stNone; + switch (toupper(*s)) { ++#ifdef USE_PLUGINPARAM ++ case 'P': type = stPlug; break; ++#endif /* PLUGINPARAM */ + case 'C': type = stCable; break; + case 'S': type = stSat; break; + case 'T': type = stTerr; break; +@@ -68,7 +74,11 @@ int cSource::FromString(const char *s) + int pos = 0; + bool dot = false; + bool neg = false; ++#ifdef USE_SOURCECAPS ++ while (*++s && !isblank(*s)) { ++#else + while (*++s) { ++#endif /* SOURCECAPS */ + switch (toupper(*s)) { + case '0' ... '9': pos *= 10; + pos += *s - '0'; +diff -ruNp vdr-1.7.0/sources.conf vdr-1.7.0-extensions/sources.conf +--- vdr-1.7.0/sources.conf 2007-02-17 17:15:13.000000000 +0100 ++++ vdr-1.7.0-extensions/sources.conf 2009-04-09 20:48:48.000000000 +0200 +@@ -188,3 +188,7 @@ C Cable + # Terrestrial + + T Terrestrial ++ ++# Plugin PLUGINPARAM ++ ++#P Plugin +diff -ruNp vdr-1.7.0/sources.h vdr-1.7.0-extensions/sources.h +--- vdr-1.7.0/sources.h 2005-05-14 11:30:41.000000000 +0200 ++++ vdr-1.7.0-extensions/sources.h 2009-04-09 20:48:48.000000000 +0200 +@@ -16,10 +16,17 @@ class cSource : public cListObject { + public: + enum eSourceType { + stNone = 0x0000, ++#ifdef USE_PLUGINPARAM ++ stPlug = 0x2000, ++#endif /* PLUGINPARAM */ + stCable = 0x4000, + stSat = 0x8000, + stTerr = 0xC000, ++#ifdef USE_PLUGINPARAM ++ st_Mask = 0xE000, ++#else + st_Mask = 0xC000, ++#endif /* PLUGINPARAM */ + st_Neg = 0x0800, + st_Pos = 0x07FF, + }; +@@ -35,6 +42,9 @@ public: + static cString ToString(int Code); + static int FromString(const char *s); + static int FromData(eSourceType SourceType, int Position = 0, bool East = false); ++#ifdef USE_PLUGINPARAM ++ static bool IsPlug(int Code) { return (Code & st_Mask) == stPlug; } ++#endif /* PLUGINPARAM */ + static bool IsCable(int Code) { return (Code & st_Mask) == stCable; } + static bool IsSat(int Code) { return (Code & st_Mask) == stSat; } + static bool IsTerr(int Code) { return (Code & st_Mask) == stTerr; } +diff -ruNp vdr-1.7.0/status.c vdr-1.7.0-extensions/status.c +--- vdr-1.7.0/status.c 2008-02-16 15:46:31.000000000 +0100 ++++ vdr-1.7.0-extensions/status.c 2009-04-09 20:48:48.000000000 +0200 +@@ -29,6 +29,20 @@ void cStatus::MsgTimerChange(const cTime + sm->TimerChange(Timer, Change); + } + ++#ifdef USE_STREAMDEVEXT ++void cStatus::MsgRecordingChange(const cRecording *Recording, eStatusChange Change) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->RecordingChange(Recording, Change); ++} ++ ++void cStatus::MsgChannelChange(const cChannel *Channel, eStatusChange Change) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->ChannelChange(Channel, Change); ++} ++#endif /* STREAMDEVEXT */ ++ + void cStatus::MsgChannelSwitch(const cDevice *Device, int ChannelNumber) + { + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) +@@ -124,3 +138,88 @@ void cStatus::MsgOsdProgramme(time_t Pre + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle); + } ++ ++#ifdef USE_PINPLUGIN ++bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* Channel) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ChannelProtected(Device, Channel) == true) ++ return true; ++ return false; ++} ++ ++bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ReplayProtected(Recording, Name, Base, isDirectory, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgRecordingFile(const char* FileName) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->RecordingFile(FileName); ++} ++ ++void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->TimerCreation(Timer, Event); ++} ++ ++bool cStatus::MsgPluginProtected(cPlugin* Plugin, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->PluginProtected(Plugin, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgUserAction(const eKeys key, const cOsdObject* Interact) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->UserAction(key, Interact); ++} ++ ++bool cStatus::MsgMenuItemProtected(const char* Name, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->MenuItemProtected(Name, menuView) == true) ++ return true; ++ return false; ++} ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_GRAPHTFT ++void cStatus::MsgOsdSetEvent(const cEvent* event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetEvent(event); ++} ++ ++void cStatus::MsgOsdSetRecording(const cRecording* recording) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetRecording(recording); ++} ++ ++void cStatus::MsgOsdMenuDisplay(const char* kind) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDisplay(kind); ++} ++ ++void cStatus::MsgOsdMenuDestroy() ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDestroy(); ++} ++ ++void cStatus::MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdEventItem(Event, Text, Index, Count); ++} ++#endif /* GRAPHTFT */ ++ +diff -ruNp vdr-1.7.0/status.h vdr-1.7.0-extensions/status.h +--- vdr-1.7.0/status.h 2008-02-16 16:00:33.000000000 +0100 ++++ vdr-1.7.0-extensions/status.h 2009-04-09 20:48:48.000000000 +0200 +@@ -14,8 +14,14 @@ + #include "device.h" + #include "player.h" + #include "tools.h" ++#ifdef USE_PINPLUGIN ++#include "plugin.h" ++#endif /* PINPLUGIN */ + + enum eTimerChange { tcMod, tcAdd, tcDel }; ++#ifdef USE_STREAMDEVEXT ++enum eStatusChange { scMod, scAdd, scDel }; ++#endif /* STREAMDEVEXT */ + + class cTimer; + +@@ -30,6 +36,16 @@ protected: + // been added or will be deleted, respectively. In case of tcMod, + // Timer is NULL; this indicates that some timer has been changed. + // Note that tcAdd and tcDel are always also followed by a tcMod. ++#ifdef USE_STREAMDEVEXT ++ virtual void RecordingChange(const cRecording *Recording, eStatusChange Change) {} ++ // Indicates a change in the recordings settings. ++ // If Change is scAdd or scDel, Recording points to the recording that has ++ // been added or will be deleted, respectively. In case of scMod, ++ // Timer is NULL; this indicates that some timer has been changed. ++ // Note that scAdd and scDel are always also followed by a scMod. ++ virtual void ChannelChange(const cChannel *Channel, eStatusChange Change) {} ++ // Indicates a change in the channel list. ++#endif /* STREAMDEVEXT */ + virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {} + // Indicates a channel switch on the given DVB device. + // If ChannelNumber is 0, this is before the channel is being switched, +@@ -80,11 +96,46 @@ protected: + // The OSD displays the single line Text with the current channel information. + virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {} + // The OSD displays the given programme information. ++#ifdef USE_PINPLUGIN ++ virtual bool ChannelProtected(const cDevice *Device, const cChannel* Channel) { return false; } ++ // Checks if a channel is protected. ++ virtual bool ReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false) { return false; } ++ // Checks if a recording is protected. ++ virtual void RecordingFile(const char* FileName) {} ++ // The given DVB device has started recording to FileName. FileName is the name of the ++ // recording directory ++ virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {} ++ // The given timer is created ++ virtual bool PluginProtected(cPlugin* Plugin, int menuView = false) { return false; } ++ // Checks if a plugin is protected. ++ virtual void UserAction(const eKeys key, const cOsdObject* Interact) {} ++ // report user action ++ virtual bool MenuItemProtected(const char* Name, int menuView = false) { return false; } ++ // Checks if a menu entry is protected. ++#endif /* PINPLUGIN */ ++#ifdef USE_GRAPHTFT ++ virtual void OsdSetRecording(const cRecording* recording) {} ++ // The OSD displays the recording information. ++ virtual void OsdSetEvent(const cEvent* event) {} ++ // The OSD displays the event information. ++ virtual void OsdMenuDisplay(const char* kind) {} ++ // report menu creation ++ virtual void OsdMenuDestroy() {} ++ // report menu destruvtion ++ virtual void OsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) {} ++ // The OSD displays the given single line Event as menu item at Index. ++ ++#endif /* GRAPHTFT */ ++ + public: + cStatus(void); + virtual ~cStatus(); + // These functions are called whenever the related status information changes: + static void MsgTimerChange(const cTimer *Timer, eTimerChange Change); ++#ifdef USE_STREAMDEVEXT ++ static void MsgRecordingChange(const cRecording *Recording, eStatusChange Change); ++ static void MsgChannelChange(const cChannel *Channel, eStatusChange Change); ++#endif /* STREAMDEVEXT */ + static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber); + static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On); + static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On); +@@ -101,6 +152,22 @@ public: + static void MsgOsdTextItem(const char *Text, bool Scroll = false); + static void MsgOsdChannel(const char *Text); + static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle); ++#ifdef USE_PINPLUGIN ++ static bool MsgChannelProtected(const cDevice* Device, const cChannel* Channel); ++ static bool MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false); ++ static void MsgRecordingFile(const char* FileName); ++ static void MsgTimerCreation(cTimer* Timer, const cEvent *Event); ++ static bool MsgPluginProtected(cPlugin* Plugin, int menuView = false); ++ static void MsgUserAction(const eKeys key, const cOsdObject* Interact); ++ static bool MsgMenuItemProtected(const char* Name, int menuView = false); ++#endif /* PINPLUGIN */ ++#ifdef USE_GRAPHTFT ++ static void MsgOsdSetEvent(const cEvent* event); ++ static void MsgOsdSetRecording(const cRecording* recording); ++ static void MsgOsdMenuDisplay(const char* kind); ++ static void MsgOsdMenuDestroy(); ++ static void MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count); ++#endif /* GRAPHTFT */ + }; + + #endif //__STATUS_H +diff -ruNp vdr-1.7.0/submenu.c vdr-1.7.0-extensions/submenu.c +--- vdr-1.7.0/submenu.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/submenu.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,952 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#include "submenu.h" ++#include "plugin.h" ++ ++static const char* TAG_SYSTEM = "system"; ++static const char* TAG_PLUGIN = "plugin"; ++static const char* TAG_COMMAND = "command"; ++static const char* TAG_THREAD = "thread"; ++static const char* TAG_MENU = "menu"; ++static const char* TAG_UNDEFINED = "undefined"; ++static const char* TRUE_STR = "yes"; ++ ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++ ++cSubMenuNode::cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ _level = level; ++ ++ if (xml != NULL && xml->Type() == TiXmlNode::ELEMENT) { ++ const char *tag = xml->Value(); ++ ++ if (cSubMenuNode::IsType(tag) != cSubMenuNode::UNDEFINED) { ++ SetType(tag); ++ SetName(xml->Attribute("name")); ++ if ((_type == COMMAND) || (_type == THREAD)) { ++ SetCommand(xml->Attribute("execute")); ++ const char * confirmStr = xml->Attribute("confirm"); ++ if (confirmStr != NULL && strcmp(confirmStr, TRUE_STR) == 0) ++ _commandConfirm = true; ++ } ++ else if (_type == PLUGIN) { // Add Plugin Index ++ SetCustomTitle(xml->Attribute("title")); ++ SetPlugin(); ++ } ++ else if (_type == MENU && xml->NoChildren() == false) { ++ xml = xml->FirstChildElement(); ++ do { ++ cSubMenuNode *node = new cSubMenuNode(xml, level+1, &_subMenus, currentMenu); ++ _subMenus.Add(node); ++ } while ((xml=xml->NextSiblingElement()) != NULL); ++ } ++ } ++ } ++ else ++ throw "Invalid XML Node"; ++} ++ ++/** ++ * Construct new Node empty Node ++ * ++ * ++ */ ++cSubMenuNode::cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ ++} ++ ++ ++/** ++ * ++ */ ++void cSubMenuNode::init() ++{ ++ _name = NULL; ++ _command = NULL; ++ _title = NULL; ++ _pluginMainMenuEntry = NULL; ++ _type = UNDEFINED; ++ _level = 0; ++ _parentMenu = NULL; ++ _currentMenu = NULL; ++ _pluginIndex = 0; ++ _commandConfirm = false; ++} ++ ++ ++cSubMenuNode::~ cSubMenuNode() ++{ ++ if (_name != NULL) ++ free((void*)_name); ++ if (_command != NULL) ++ free((void*)_command); ++ if (_title != NULL) ++ free((void*)_title); ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++} ++ ++/** ++ * ++ */ ++void cSubMenuNode::SetPlugin() ++{ ++ bool found = false; ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) { ++ if (strcmp(_name, p->Name()) == 0 && p->MainMenuEntry() != NULL) { ++ SetPluginMainMenuEntry(p->MainMenuEntry()); ++ _pluginIndex = i; ++ found = true; ++ break; ++ } ++ } ++ else ++ break; ++ } ++ ++ if (!found) ++ _type = UNDEFINED; ++} ++ ++ ++bool cSubMenuNode::SaveXml(TiXmlElement * root) ++{ ++ bool ok = true; ++ ++ if (root!=NULL) { ++ TiXmlElement *e = NULL; ++ switch(_type) { ++ case SYSTEM: ++ e = new TiXmlElement(TAG_SYSTEM); ++ e->SetAttribute("name", GetName()); ++ break; ++ case COMMAND: ++ e = new TiXmlElement(TAG_COMMAND); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case THREAD: ++ e = new TiXmlElement(TAG_THREAD); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case PLUGIN: ++ e = new TiXmlElement(TAG_PLUGIN); ++ e->SetAttribute("name", GetName()); ++ if (GetCustomTitle() != NULL && strcmp(GetCustomTitle(), "") != 0) ++ e->SetAttribute("title", GetCustomTitle()); ++ break; ++ case MENU: ++ e = new TiXmlElement(TAG_MENU); ++ e->SetAttribute("name", GetName()); ++ break; ++ case UNDEFINED: ++ default: ++ ok = false; ++ break; ++ } ++ if (ok) { ++ root->LinkEndChild(e); ++ if (HasSubMenus()) ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SaveXml(e); ++ } ++ } ++ ++ return(ok); ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::IsType(const char *name) ++{ ++ Type type = UNDEFINED; ++ ++ if (strcmp(name ,TAG_SYSTEM) == 0) ++ type = cSubMenuNode::SYSTEM; ++ else if (strcmp(name ,TAG_PLUGIN) == 0) ++ type = cSubMenuNode::PLUGIN; ++ else if (strcmp(name ,TAG_COMMAND) == 0) ++ type = cSubMenuNode::COMMAND; ++ else if (strcmp(name ,TAG_THREAD) == 0) ++ type = cSubMenuNode::THREAD; ++ else if (strcmp(name ,TAG_MENU) == 0) ++ type = cSubMenuNode::MENU; ++ ++ return(type); ++} ++ ++void cSubMenuNode::SetType(const char * name) ++{ ++ _type = IsType(name); ++} ++ ++void cSubMenuNode::SetType(enum Type type) ++{ ++ _type = type; ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::GetType() ++{ ++ return(_type); ++} ++ ++const char * cSubMenuNode::GetTypeAsString() ++{ ++ const char *str=NULL; ++ switch(_type) { ++ case SYSTEM: ++ str = TAG_SYSTEM; ++ break; ++ case COMMAND: ++ str = TAG_COMMAND; ++ break; ++ case THREAD: ++ str = TAG_THREAD; ++ break; ++ case PLUGIN: ++ str = TAG_PLUGIN; ++ break; ++ case MENU: ++ str = TAG_MENU; ++ break; ++ case UNDEFINED: ++ str = TAG_UNDEFINED; ++ default: ++ break; ++ } ++ ++ return(str); ++} ++ ++void cSubMenuNode::SetCommand(const char * command) ++{ ++ if (_command != NULL) ++ free((void*)_command); ++ ++ if (command != NULL) ++ _command = strdup(command); ++ else ++ _command = NULL; ++} ++ ++const char * cSubMenuNode::GetCommand() ++{ ++ return(_command); ++} ++ ++bool cSubMenuNode::CommandConfirm() ++{ ++ return(_commandConfirm); ++} ++ ++void cSubMenuNode::SetCommandConfirm(int val) ++{ ++ if (val == 1) ++ _commandConfirm = true; ++ else ++ _commandConfirm = false; ++} ++ ++void cSubMenuNode::SetCustomTitle(const char * title) ++{ ++ if (_title != NULL) ++ free((void*)_title); ++ ++ if (title != NULL) ++ _title = strdup(title); ++ else ++ _title = NULL; ++} ++ ++const char * cSubMenuNode::GetCustomTitle() ++{ ++ return(_title); ++} ++ ++void cSubMenuNode::SetName(const char * name) ++{ ++ if (_name) ++ free ((void*)_name); ++ ++ if (name != NULL) ++ _name = strdup(name); ++ else ++ _name = NULL; ++} ++ ++const char * cSubMenuNode::GetName() ++{ ++ return(_name); ++} ++ ++int cSubMenuNode::GetLevel() ++{ ++ return(_level); ++} ++ ++void cSubMenuNode::SetLevel(int level) ++{ ++ _level = level; ++ if (HasSubMenus()) { //Adjust Levels of Subnodes ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SetLevel(level+1); ++ } ++} ++ ++int cSubMenuNode::GetPluginIndex() ++{ ++ return(_pluginIndex); ++} ++ ++void cSubMenuNode::SetPluginIndex(int index) ++{ ++ _pluginIndex = index; ++} ++ ++void cSubMenuNode::SetPluginMainMenuEntry(const char * mainMenuEntry) ++{ ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++ ++ if (_title != NULL && strcmp(_title, "") != 0) ++ _pluginMainMenuEntry = strdup(_title); ++ else if (mainMenuEntry != NULL) ++ _pluginMainMenuEntry = strdup(mainMenuEntry); ++ else ++ _pluginMainMenuEntry = NULL; ++} ++ ++const char * cSubMenuNode::GetPluginMainMenuEntry() ++{ ++ return(_pluginMainMenuEntry); ++} ++ ++ ++ ++cSubMenuNodes * cSubMenuNode::GetParentMenu() ++{ ++ return(_parentMenu); ++} ++ ++void cSubMenuNode::SetParentMenu(cSubMenuNodes * parent) ++{ ++ _parentMenu = parent; ++} ++ ++cSubMenuNodes * cSubMenuNode::GetCurrentMenu() ++{ ++ return(_currentMenu); ++} ++ ++void cSubMenuNode::SetCurrentMenu(cSubMenuNodes * current) ++{ ++ _currentMenu = current; ++} ++ ++ ++cSubMenuNodes * cSubMenuNode::GetSubMenus() ++{ ++ return(&_subMenus); ++} ++ ++bool cSubMenuNode::HasSubMenus() ++{ ++ if (_subMenus.Count() > 0) ++ return(true); ++ else ++ return(false); ++} ++ ++ ++void cSubMenuNode::Print(int index) ++{ ++ for (int i = 0; i < index; i++) ++ printf(" "); ++ ++ printf("Name=%s Type=%s Level=%d", _name, GetTypeAsString(), _level); ++ if (_type == COMMAND || _type == THREAD) ++ printf(" Command=%s", _command); ++ else if (_type == PLUGIN && _title != NULL) ++ printf(" Title=%s", _title); ++ printf("\n"); ++ ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->Print(index+4); ++} ++ ++ ++//################################################################################ ++//# ++//################################################################################ ++cSubMenu::cSubMenu() ++{ ++ _menuSuffix = NULL; ++ _fname = NULL; ++ _commandResult = NULL; ++ _currentMenuTree = &_menuTree; ++ _currentParentMenuTree = NULL; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = -1; ++#endif /* PINPLUGIN */ ++ _nodeArray = NULL; ++ _nrNodes = 0; ++} ++ ++ ++cSubMenu::~cSubMenu() ++{ ++ if (_menuSuffix) ++ free(_menuSuffix); ++ if (_fname) ++ free(_fname); ++ if (_commandResult) ++ free(_commandResult); ++ if (_nodeArray) ++ free(_nodeArray); ++ _nrNodes = 0; ++} ++ ++ ++bool cSubMenu::LoadXml(char *fname) ++{ ++ TiXmlDocument xmlDoc = TiXmlDocument(fname); ++ TiXmlElement *root = NULL; ++ cSubMenuNode *node = NULL; ++ ++ bool ok = true; ++ //Clear previously loaded Menu ++ if (_fname != NULL) ++ free(_fname); ++ _menuTree.Clear(); ++ _fname = strdup(fname); ++ ++ if ((ok = xmlDoc.LoadFile())) { ++ if ((root = xmlDoc.FirstChildElement("menus")) != NULL) { ++ char *tmp = NULL; ++ if ((tmp = (char*)root->Attribute("suffix")) == NULL) ++ asprintf(&_menuSuffix, " "); // set default menuSuffix // asprintf(&_menuSuffix, " ..."); ++ else ++ asprintf(&_menuSuffix, tmp); ++ ++ if ((root = root->FirstChildElement()) != NULL) { ++ do { ++ try { ++ node = new cSubMenuNode(root, 0, &_menuTree, NULL); ++ _menuTree.Add(node); ++ } ++ catch (char *message) { ++ esyslog("ERROR: while decoding XML Node"); ++ ok = false; ++ } ++ } while (ok == true && (root = root->NextSiblingElement()) != NULL); ++ addMissingPlugins(); ++ removeUndefinedNodes(); ++ } ++ } ++ else { ++ esyslog("ERROR: in %s, missing Tag <menus>\n", fname); ++ ok = false; ++ } ++ } ++ else { ++ esyslog("ERROR: in %s : %s Col=%d Row=%d\n", ++ fname, ++ xmlDoc.ErrorDesc(), ++ xmlDoc.ErrorCol(), ++ xmlDoc.ErrorRow()); ++ ok = false; ++ } ++ ++ return(ok); ++} ++ ++ ++bool cSubMenu::SaveXml() ++{ ++ return(SaveXml(_fname)); ++} ++ ++ ++bool cSubMenu::SaveXml(char *fname) ++{ ++ bool ok = true; ++ ++ if (_fname != NULL) { ++ TiXmlDocument xml = TiXmlDocument(fname); ++ TiXmlComment comment; ++ comment.SetValue("\n\ ++- VDR Menu-Configuration File\n\ ++-\n\ ++-\n\ ++- Example:\n\ ++-\n\ ++ <menus>\n\ ++ <system name=\"Schedule\" />\n\ ++ <system name=\"Channels\" />\n\ ++ <system name=\"Timers\" />\n\ ++ <system name=\"Recordings\" />\n\ ++ <menu name=\"System\">\n\ ++ <system name=\"Setup\" />\n\ ++ <system name=\"Commands\" />\n\ ++ <plugin name=\"setup\" title=\"My Setup\" />\n\ ++ <command name=\"myCommand1\" execute=\"/usr/bin/mycommand1\" />\n\ ++ <command name=\"myCommand2\" execute=\"/usr/bin/mycommand2\" confirm=\"yes\" />\n\ ++ <thread name=\"myCommand3\" execute=\"/usr/bin/mycommand3\" confirm=\"yes\" />\n\ ++ <plugin name=\"epgsearch\" title=\"myProgram\" />\n\ ++ <menu name=\"mySubSubMenu\">\n\ ++ ...\n\ ++ </menu>\n\ ++ </menu>\n\ ++ <menu name=\"Suche\">\n\ ++ <plugin name=\"epgsearch\" />\n\ ++ ...\n\ ++ </menu>\n\ ++ </menus>\n\ ++"); ++ ++ TiXmlElement root("menus"); ++ root.SetAttribute("suffix", _menuSuffix); ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->SaveXml(&root); ++ ++ if (xml.InsertEndChild(comment) != NULL && xml.InsertEndChild(root) != NULL) ++ ok = xml.SaveFile(fname); ++ } ++ else ++ ok = false; ++ ++ return(ok); ++} ++ ++ ++ ++cSubMenuNodes * cSubMenu::GetMenuTree() ++{ ++ return(_currentMenuTree); ++} ++ ++ ++void cSubMenu::PrintMenuTree() ++{ ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->Print(); ++} ++ ++ ++int cSubMenu::GetNrOfNodes() ++{ ++ if (_nrNodes == 0) { ++ if ((_nrNodes = countNodes(&_menuTree)) > 0) { ++ _nodeArray = (cSubMenuNode**) malloc(sizeof(cSubMenuNode*)*_nrNodes); ++ int index = 0; ++ tree2Array(&_menuTree, index); ++ } ++ } ++ ++ return(_nrNodes); ++} ++ ++ ++/** ++ * returns the specified node within the current menu ++ * @param index position in the current menu ++ * @return node or null if not found ++ */ ++cSubMenuNode * cSubMenu::GetNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ if (_currentMenuTree == NULL || (node=_currentMenuTree->Get(index)) == NULL) ++ esyslog("ERROR: illegal call of cSubMenu::GetNode(%d)", index); ++ ++ return(node); ++} ++ ++ ++/** ++ * Get the specified Node ++ * @param index specfies the absolut indes in the list of all nodes ++ * @return node or NULL if not found ++ */ ++cSubMenuNode * cSubMenu::GetAbsNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ GetNrOfNodes(); ++ if (_nrNodes > 0 && index >= 0 && index < _nrNodes) ++ node = _nodeArray[index]; ++ ++ return(node); ++} ++ ++ ++#ifdef USE_PINPLUGIN ++bool cSubMenu::Down(cSubMenuNode *node, int currentIndex) ++#else ++bool cSubMenu::Down(int index) ++#endif /* PINPLUGIN */ ++{ ++ bool ok = true; ++#ifdef USE_PINPLUGIN ++ if (_currentMenuTree != NULL && node && node->GetType() == cSubMenuNode::MENU) { ++#else ++ cSubMenuNode *node = NULL; ++ ++ if (_currentMenuTree != NULL && (node=_currentMenuTree->Get(index)) != NULL && node->GetType() == cSubMenuNode::MENU) { ++#endif /* PINPLUGIN */ ++ _currentParentMenuTree = _currentMenuTree; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = currentIndex; ++#endif /* PINPLUGIN */ ++ _currentMenuTree = node->GetSubMenus(); ++ } ++ else { ++ ok = false; ++#ifdef USE_PINPLUGIN ++ esyslog("ERROR: illegal call of cSubMenu::Down"); ++#else ++ esyslog("ERROR: illegal call of cSubMenu::Down(%d)", index); ++#endif /* PINPLUGIN */ ++ } ++ ++ return(ok); ++} ++ ++bool cSubMenu::Up(int *parentIndex) ++{ ++ bool ok = true; ++ ++ if (_currentMenuTree != NULL && parentIndex != NULL) { ++#ifndef USE_PINPLUGIN ++ cSubMenuNode *node = NULL; ++#endif /* PINPLUGIN */ ++ *parentIndex = 0; ++#ifdef USE_PINPLUGIN ++ if (_currentParentIndex >= 0) ++ *parentIndex = _currentParentIndex; ++#else ++ if (_currentParentMenuTree != NULL) ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ *parentIndex = i; ++ break; ++ } ++ } ++#endif /* PINPLUGIN */ ++ ++ _currentMenuTree = _currentParentMenuTree; ++ if (_currentMenuTree != NULL) ++ _currentParentMenuTree = _currentMenuTree->Get(0)->GetParentMenu(); ++ else ++ ok = false; ++ } ++ else { ++ ok = false; ++ esyslog("ERROR: illegal call of cSubMenu::Up()"); ++ } ++ ++ return(ok); ++} ++ ++const char * cSubMenu::ExecuteCommand(const char * cmd) ++{ ++ free(_commandResult); ++ _commandResult = NULL; ++ ++ dsyslog("executing command '%s'", cmd); ++ FILE *p = popen(cmd, "r"); ++ if (p) { ++ int l = 0; ++ int c; ++ while ((c = fgetc(p)) != EOF) { ++ if (l % 20 == 0) ++ _commandResult = (char *)realloc(_commandResult, l + 21); ++ _commandResult[l++] = c; ++ } ++ if (_commandResult) ++ _commandResult[l] = 0; ++ pclose(p); ++ } ++ else ++ esyslog("ERROR: can't open pipe for command '%s'", cmd); ++ ++ return _commandResult; ++} ++ ++/** ++ * Move Menu Entry to new Position ++ * @param index index of menu entry to move ++ * @param toIndex index of destination ++ * @param where After ore before the destination index ++ */ ++void cSubMenu::MoveMenu(int index, int toIndex, enum Where where) ++{ ++ if (index < 0 || index > _nrNodes || // invalid index is ignored ++ toIndex < 0 || toIndex > _nrNodes || index == toIndex) ++ return; ++ ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ cSubMenuNode *destNode = GetAbsNode(toIndex); ++ ++ if (where == cSubMenu::INTO && destNode->GetType() != cSubMenuNode::MENU) ++ return; ++ ++ if (where == cSubMenu::INTO) { ++ if (destNode->GetType() == cSubMenuNode::MENU) { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()+1); ++ srcNode->SetParentMenu(destNode->GetCurrentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetSubMenus()); ++ ++ destNode->GetSubMenus()->Add(srcNode); ++ reloadNodeArray(); ++ } ++ } ++ else { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()); ++ srcNode->SetParentMenu(destNode->GetParentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetCurrentMenu()); ++ ++ if (where == cSubMenu::BEHIND) { ++ destNode->GetCurrentMenu()->Add(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ else { ++ destNode->GetCurrentMenu()->Ins(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * Create a new Menu Entry ++ * @param index index of destination ++ * @param menuTitle Titel of new Menu entry ++ */ ++void cSubMenu::CreateMenu(int index, const char * menuTitle) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(menuTitle); ++ newNode->SetType(cSubMenuNode::MENU); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * delete the specified entry, or subtree if the specified entry is a menu ++ * @param index destion index ++ */ ++void cSubMenu::DeleteMenu(int index) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ srcNode->GetCurrentMenu()->Del(srcNode, true); ++ reloadNodeArray(); ++ } ++} ++ ++ ++// Private Methods ++ ++int cSubMenu::countNodes(cSubMenuNodes * tree) ++{ ++ int count = 0; ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ count++; ++ if (node->HasSubMenus()) ++ count += countNodes(node->GetSubMenus()); ++ } ++ } ++ return(count); ++} ++ ++ ++void cSubMenu::tree2Array(cSubMenuNodes * tree, int &index) ++{ ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ _nodeArray[index++]=node; ++ if (node->HasSubMenus()) ++ tree2Array(node->GetSubMenus(), index); ++ } ++ } ++ ++} ++ ++bool cSubMenu::IsPluginInMenu(const char * name) ++{ ++ bool found = false; ++ for (int i = 0; i < _nrNodes && found == false; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::PLUGIN && strcmp(name, node->GetName()) == 0) ++ found = true; ++ } ++ return(found); ++} ++ ++/** ++ * Adds the given plugin to the Menu-Tree if not allready in List ++ * @param name specifies the name of the plugin ++ */ ++void cSubMenu::AddPlugin(const char * name) ++{ ++ if (! IsPluginInMenu(name)) { ++ cSubMenuNode *node = new cSubMenuNode(&_menuTree, NULL); ++ node->SetName(name); ++ node->SetType("plugin"); ++ node->SetPlugin(); ++ _menuTree.Add(node); ++ } ++} ++ ++void cSubMenu::addMissingPlugins() ++{ ++ _nrNodes = GetNrOfNodes(); ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) ++ AddPlugin(p->Name()); ++ else ++ break; ++ } ++ reloadNodeArray(); ++} ++ ++/** ++ * Adds the given command to the Menu-Tree ++ * @param name specifies the name of the command ++ */ ++void cSubMenu::CreateCommand(int index, const char * name, const char * execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("command"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++void cSubMenu::CreateThread(int index, const char * name, const char * execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("thread"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * reloads the internal Array of Nodes ++ */ ++void cSubMenu::reloadNodeArray() ++{ ++ if (_nrNodes > 0) ++ free(_nodeArray); ++ _nodeArray = NULL; ++ _nrNodes = 0; ++ _nrNodes = GetNrOfNodes(); ++} ++ ++/** ++ * remove Undefined Nodes ++ */ ++void cSubMenu::removeUndefinedNodes() ++{ ++ bool remove = false; ++ ++ reloadNodeArray(); ++ for (int i = 0; i < _nrNodes; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::UNDEFINED) { ++ cSubMenuNodes *pMenu = node->GetCurrentMenu(); ++ pMenu->Del(node, true); ++ remove = true; ++ } ++ } ++ if (remove) ++ reloadNodeArray(); ++} ++ ++ ++/** ++* Retrieves the Menutitel of the parent Menu ++*/ ++const char *cSubMenu::GetParentMenuTitel() ++{ ++ const char * result = ""; ++ ++ if (_currentMenuTree != NULL && _currentParentMenuTree != NULL) { ++ cSubMenuNode *node = NULL; ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ result = node->GetName(); ++ break; ++ } ++ } ++ } ++ ++ return(result); ++} ++ ++#endif ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/submenu.h vdr-1.7.0-extensions/submenu.h +--- vdr-1.7.0/submenu.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/submenu.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,160 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#define SUBMENU_H ++ ++#include "thread.h" ++#include "tools.h" ++#include "tinystr.h" ++ ++class cSubMenuNode; ++class cSubMenuNodes; ++class cSubMenu; ++ ++ ++class cSubMenuNodes : public cList<cSubMenuNode> {}; ++ ++// execute cmd thread ++class cExecCmdThread : public cThread { ++private: ++ char *ExecCmd; ++protected: ++ virtual void Action(void) { ++ if (system(ExecCmd) == 0) ++ esyslog("%s - finished", ExecCmd); ++ delete(this); ++ }; ++public: ++ cExecCmdThread(char *cmd) { ++ asprintf(&ExecCmd, "%s", cmd); ++ } ++ cExecCmdThread(const char *cmd) { ++ asprintf(&ExecCmd, "%s", cmd); ++ } ++ ~cExecCmdThread() { ++ free(ExecCmd); ++ }; ++ }; ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++class cSubMenuNode : public cListObject { ++public: ++ enum Type { UNDEFINED, SYSTEM, COMMAND, THREAD, PLUGIN, MENU }; ++ cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ ~cSubMenuNode(); ++ bool SaveXml(TiXmlElement * root); ++ static cSubMenuNode::Type IsType(const char *name); ++ void SetType(const char *name); ++ void SetType(enum Type type); ++ void SetPlugin(); ++ cSubMenuNode::Type GetType(); ++ const char *GetTypeAsString(); ++ void SetCommand(const char *command); ++ bool CommandConfirm(); ++ void SetCommandConfirm(int val); ++ const char *GetCommand(); ++ void SetCustomTitle(const char *title); ++ const char *GetCustomTitle(); ++ void SetName(const char *name); ++ const char*GetName(); ++ int GetLevel(); ++ void SetLevel(int level); ++ int GetPluginIndex(); ++ void SetPluginIndex(int index); ++ void SetPluginMainMenuEntry(const char *mainMenuEntry); ++ const char *GetPluginMainMenuEntry(); ++ cSubMenuNodes *GetParentMenu(); ++ void SetParentMenu(cSubMenuNodes *parent); ++ cSubMenuNodes *GetCurrentMenu(); ++ void SetCurrentMenu(cSubMenuNodes *current); ++ cSubMenuNodes *GetSubMenus(); ++ bool HasSubMenus(); ++ void Print(int index = 0); ++private: ++ Type _type; ++ int _level; ++ // Plugin Variables ++ int _pluginIndex; ++ const char *_pluginMainMenuEntry; ++ // common ++ const char *_name; ++ const char *_command; ++ bool _commandConfirm; ++ const char *_title; ++ cSubMenuNodes _subMenus; ++ cSubMenuNodes *_parentMenu; ++ cSubMenuNodes *_currentMenu; ++ void init(); ++ }; ++ ++ ++//################################################################################ ++//# SubMenu Class ++//################################################################################ ++class cSubMenu { ++public: ++ cSubMenu(); ++ ~cSubMenu(); ++ enum Where { BEFORE, BEHIND, INTO}; ++ bool LoadXml(char *fname); ++ bool SaveXml(char *fname); ++ bool SaveXml(); ++ cSubMenuNodes *GetMenuTree(); ++ bool Up(int *ParentIndex); ++#ifdef USE_PINPLUGIN ++ bool Down(cSubMenuNode* node, int currentIndex); ++#else ++ bool Down(int index); ++#endif /* PINPLUGIN */ ++ int GetNrOfNodes(); ++ cSubMenuNode* GetAbsNode(int index); ++ cSubMenuNode* GetNode(int index); ++ void PrintMenuTree(); ++ bool IsPluginInMenu(const char *name); ++ void AddPlugin(const char *name); ++ void CreateCommand(int index, const char *name, const char *execute, int confirm); ++ void CreateThread(int index, const char *name, const char *execute, int confirm); ++ const char *ExecuteCommand(const char *command); ++ void MoveMenu(int index, int toindex, enum Where); ++ void CreateMenu(int index, const char *menuTitle); ++ void DeleteMenu(int index); ++ char *GetMenuSuffix() { return _menuSuffix; } ++ void SetMenuSuffix(char *suffix) { if (_menuSuffix) free(_menuSuffix); asprintf(&_menuSuffix, suffix); } ++ bool isTopMenu() { return (_currentParentMenuTree == NULL); } ++ const char *GetParentMenuTitel(); ++private: ++ cSubMenuNodes _menuTree; ++ cSubMenuNodes *_currentMenuTree; ++ cSubMenuNodes *_currentParentMenuTree; ++#ifdef USE_PINPLUGIN ++ int _currentParentIndex; ++#endif /* PINPLUGIN */ ++ char *_fname; ++ char *_commandResult; ++ int _nrNodes; ++ cSubMenuNode **_nodeArray; ++ char *_menuSuffix; ++ int countNodes(cSubMenuNodes *tree); ++ void tree2Array(cSubMenuNodes *tree, int &index); ++ void addMissingPlugins(); ++ void reloadNodeArray(); ++ void removeUndefinedNodes(); ++ }; ++ ++#endif //__SUBMENU_H ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/svdrp.c vdr-1.7.0-extensions/svdrp.c +--- vdr-1.7.0/svdrp.c 2008-02-17 14:36:01.000000000 +0100 ++++ vdr-1.7.0-extensions/svdrp.c 2009-04-09 20:48:48.000000000 +0200 +@@ -39,6 +39,9 @@ + #include "timers.h" + #include "tools.h" + #include "videodir.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ + + // --- cSocket --------------------------------------------------------------- + +@@ -296,6 +299,10 @@ const char *HelpPages[] = { + "REMO [ on | off ]\n" + " Turns the remote control on or off. Without a parameter, the current\n" + " status of the remote control is reported.", ++#ifdef USE_LIEMIEXT ++ "RENR <number> <new name>\n" ++ " Rename recording. Number must be the Number as returned by LSTR command.", ++#endif /* LIEMIEXT */ + "SCAN\n" + " Forces an EPG scan. If this is a single DVB device system, the scan\n" + " will be done on the primary device unless it is currently recording.", +@@ -616,6 +623,9 @@ void cSVDRP::CmdDELC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("channel %s deleted", Option); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NULL, scDel); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -1135,6 +1145,9 @@ void cSVDRP::CmdMODC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("modifed channel %d %s", channel->Number(), *channel->ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scMod); ++#endif /* STREAMDEVEXT */ + Reply(250, "%d %s", channel->Number(), *channel->ToText()); + } + else +@@ -1221,6 +1234,9 @@ void cSVDRP::CmdMOVC(const char *Option) + else + cDevice::SetCurrentChannel(CurrentChannel); + } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(ToChannel, scMod); ++#endif /* STREAMDEVEXT */ + isyslog("channel %d moved to %d", FromNumber, ToNumber); + Reply(250,"Channel \"%d\" moved to \"%d\"", From, To); + } +@@ -1264,6 +1280,9 @@ void cSVDRP::CmdNEWC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("new channel %d %s", channel->Number(), *channel->ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scAdd); ++#endif /* STREAMDEVEXT */ + Reply(250, "%d %s", channel->Number(), *channel->ToText()); + } + else +@@ -1472,6 +1491,40 @@ void cSVDRP::CmdSCAN(const char *Option) + Reply(250, "EPG scan triggered"); + } + ++#ifdef USE_LIEMIEXT ++void cSVDRP::CmdRENR(const char *Option) ++{ ++ bool recordings = Recordings.Update(true); ++ if (recordings) { ++ if (*Option) { ++ char *tail; ++ int n = strtol(Option, &tail, 10); ++ cRecording *recording = Recordings.Get(n - 1); ++ if (recording && tail && tail != Option) { ++ int priority = recording->priority; ++ int lifetime = recording->lifetime; ++ char *oldName = strdup(recording->Name()); ++ tail = skipspace(tail); ++ if (recording->Rename(tail, &priority, &lifetime)) { ++ Reply(250, "Renamed \"%s\" to \"%s\"", oldName, recording->Name()); ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ } ++ else ++ Reply(501, "Renaming \"%s\" to \"%s\" failed", oldName, tail); ++ free(oldName); ++ } ++ else ++ Reply(501, "Recording not found or wrong syntax"); ++ } ++ else ++ Reply(501, "Missing Input settings"); ++ } ++ else ++ Reply(550, "No recordings available"); ++} ++#endif /* LIEMIEXT */ ++ + void cSVDRP::CmdSTAT(const char *Option) + { + if (*Option) { +@@ -1587,6 +1640,9 @@ void cSVDRP::Execute(char *Cmd) + else if (CMD("PLUG")) CmdPLUG(s); + else if (CMD("PUTE")) CmdPUTE(s); + else if (CMD("REMO")) CmdREMO(s); ++#ifdef USE_LIEMIEXT ++ else if (CMD("RENR")) CmdRENR(s); ++#endif /* LIEMIEXT */ + else if (CMD("SCAN")) CmdSCAN(s); + else if (CMD("STAT")) CmdSTAT(s); + else if (CMD("UPDT")) CmdUPDT(s); +diff -ruNp vdr-1.7.0/svdrp.h vdr-1.7.0-extensions/svdrp.h +--- vdr-1.7.0/svdrp.h 2007-04-30 14:28:28.000000000 +0200 ++++ vdr-1.7.0-extensions/svdrp.h 2009-04-09 20:48:48.000000000 +0200 +@@ -79,6 +79,9 @@ private: + void CmdPLUG(const char *Option); + void CmdPUTE(const char *Option); + void CmdREMO(const char *Option); ++#ifdef USE_LIEMIEXT ++ void CmdRENR(const char *Option); ++#endif /* LIEMIEXT */ + void CmdSCAN(const char *Option); + void CmdSTAT(const char *Option); + void CmdUPDT(const char *Option); +diff -ruNp vdr-1.7.0/timers.c vdr-1.7.0-extensions/timers.c +--- vdr-1.7.0/timers.c 2008-04-13 14:41:41.000000000 +0200 ++++ vdr-1.7.0-extensions/timers.c 2009-04-09 20:48:48.000000000 +0200 +@@ -13,6 +13,9 @@ + #include "device.h" + #include "i18n.h" + #include "libsi/si.h" ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "recording.h" + #include "remote.h" + #include "status.h" +@@ -46,6 +49,9 @@ cTimer::cTimer(bool Instant, bool Pause, + stop -= 2400; + priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; + lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + aux = NULL; + event = NULL; +@@ -79,12 +85,18 @@ cTimer::cTimer(const cEvent *Event) + stop -= 2400; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + const char *Title = Event->Title(); + if (!isempty(Title)) + Utf8Strn0Cpy(file, Event->Title(), sizeof(file)); + aux = NULL; + event = NULL; // let SetEvent() be called to get a log message ++#ifdef USE_PINPLUGIN ++ cStatus::MsgTimerCreation(this, Event); ++#endif /* PINPLUGIN */ + } + + cTimer::cTimer(const cTimer &Timer) +@@ -119,6 +131,9 @@ cTimer& cTimer::operator= (const cTimer + stop = Timer.stop; + priority = Timer.priority; + lifetime = Timer.lifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = Timer.fskProtection; ++#endif /* PINPLUGIN */ + strncpy(file, Timer.file, sizeof(file)); + free(aux); + aux = Timer.aux ? strdup(Timer.aux) : NULL; +@@ -313,6 +328,9 @@ bool cTimer::Parse(const char *s) + result = false; + } + } ++#ifdef USE_PINPLUGIN ++ fskProtection = aux && strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"); ++#endif /* PINPLUGIN */ + free(channelbuffer); + free(daybuffer); + free(filebuffer); +@@ -559,6 +577,9 @@ void cTimer::SetRecording(bool Recording + SetFlags(tfRecording); + else + ClrFlags(tfRecording); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(NULL, scAdd); ++#endif /* STREAMDEVEXT */ + isyslog("timer %s %s", *ToDescr(), recording ? "start" : "stop"); + } + +@@ -622,6 +643,35 @@ void cTimer::OnOff(void) + Matches(); // refresh start and end time + } + ++#ifdef USE_PINPLUGIN ++void cTimer::SetFskProtection(int aFlag) ++{ ++ char* p; ++ char* tmp = 0; ++ ++ fskProtection = aFlag; ++ ++ if (fskProtection && (!aux || !strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // add protection info to aux ++ ++ if (aux) { tmp = strdup(aux); free(aux); } ++ asprintf(&aux,"%s<pin-plugin><protected>yes</protected></pin-plugin>", tmp ? tmp : ""); ++ } ++ else if (!fskProtection && aux && (p = strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // remove protection info to aux ++ ++ asprintf(&tmp, "%.*s%s", p-aux, aux, p+strlen("<pin-plugin><protected>yes</protected></pin-plugin>")); ++ free(aux); ++ aux = strdup(tmp); ++ } ++ ++ if (tmp) ++ free(tmp); ++} ++#endif /* PINPLUGIN */ ++ + // --- cTimers --------------------------------------------------------------- + + cTimers Timers; +@@ -651,7 +701,11 @@ cTimer *cTimers::GetMatch(time_t t) + static int LastPending = -1; + cTimer *t0 = NULL; + for (cTimer *ti = First(); ti; ti = Next(ti)) { ++#ifdef USE_LIVEBUFFER ++ if (!ti->Recording() && (ti->Matches(t) || cLiveBufferManager::InLiveBuffer(ti))) { ++#else + if (!ti->Recording() && ti->Matches(t)) { ++#endif /* LIVEBUFFER */ + if (ti->Pending()) { + if (ti->Index() > LastPending) + LastPending = ti->Index(); +@@ -752,7 +806,11 @@ void cTimers::DeleteExpired(void) + cTimer *ti = First(); + while (ti) { + cTimer *next = Next(ti); ++#ifdef USE_LIVEBUFFER ++ if (ti->Expired() && (!cLiveBufferManager::InLiveBuffer(ti) || !ti->HasFlags(tfActive))) { ++#else + if (ti->Expired()) { ++#endif /* LIVEBUFFER */ + isyslog("deleting timer %s", *ti->ToDescr()); + Del(ti); + SetModified(); +diff -ruNp vdr-1.7.0/timers.h vdr-1.7.0-extensions/timers.h +--- vdr-1.7.0/timers.h 2008-02-16 15:33:23.000000000 +0100 ++++ vdr-1.7.0-extensions/timers.h 2009-04-09 20:48:48.000000000 +0200 +@@ -20,12 +20,18 @@ enum eTimerFlags { tfNone = 0x0000, + tfInstant = 0x0002, + tfVps = 0x0004, + tfRecording = 0x0008, ++#ifdef USE_LIVEBUFFER ++ tfhasLiveBuf= 0x0010, ++#endif /* LIVEBUFFER */ + tfAll = 0xFFFF, + }; + enum eTimerMatch { tmNone, tmPartial, tmFull }; + + class cTimer : public cListObject { + friend class cMenuEditTimer; ++#ifdef USE_LIVEBUFFER ++ friend class cLiveBufferControl; ++#endif /* LIVEBUFFER */ + private: + mutable time_t startTime, stopTime; + time_t lastSetEvent; +@@ -37,6 +43,9 @@ private: + int start; + int stop; + int priority; ++#ifdef USE_PINPLUGIN ++ int fskProtection; ++#endif /* PINPLUGIN */ + int lifetime; + mutable char file[MaxFileName]; + char *aux; +@@ -58,6 +67,9 @@ public: + int Start(void) const { return start; } + int Stop(void) const { return stop; } + int Priority(void) const { return priority; } ++#ifdef USE_PINPLUGIN ++ int FskProtection(void) const { return fskProtection; } ++#endif /* PINPLUGIN */ + int Lifetime(void) const { return lifetime; } + const char *File(void) const { return file; } + time_t FirstDay(void) const { return weekdays ? day : 0; } +@@ -86,6 +98,9 @@ public: + void SetInVpsMargin(bool InVpsMargin); + void SetPriority(int Priority); + void SetFlags(uint Flags); ++#ifdef USE_PINPLUGIN ++ void SetFskProtection(int aFlag); ++#endif /* PINPLUGIN */ + void ClrFlags(uint Flags); + void InvFlags(uint Flags); + bool HasFlags(uint Flags) const; +diff -ruNp vdr-1.7.0/tinystr.c vdr-1.7.0-extensions/tinystr.c +--- vdr-1.7.0/tinystr.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/tinystr.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,301 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++#ifndef TIXML_USE_STL ++ ++ ++#include <stdlib.h> ++#include <string.h> ++#include <ctype.h> ++ ++#include "tinystr.h" ++ ++// TiXmlString constructor, based on a C string ++TiXmlString::TiXmlString (const char* instring) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (!instring) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = strlen (instring) + 1; ++ newstring = new char [newlen]; ++ memcpy (newstring, instring, newlen); ++ // strcpy (newstring, instring); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString copy constructor ++TiXmlString::TiXmlString (const TiXmlString& copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ // Prevent copy to self! ++ if ( © == this ) ++ return; ++ ++ if (! copy . allocated) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . cstring); ++ memcpy (newstring, copy . cstring, newlen); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString = operator. Safe when assign own content ++void TiXmlString ::operator = (const char * content) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! content) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = strlen (content) + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, content); ++ memcpy (newstring, content, newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// = operator. Safe when assign own content ++void TiXmlString ::operator = (const TiXmlString & copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! copy . length ()) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . c_str ()); ++ memcpy (newstring, copy . c_str (), newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char* str, int len ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size, size_suffix; ++ ++ // don't use strlen - it can overrun the len passed in! ++ const char* p = str; ++ size_suffix = 0; ++ ++ while ( *p && size_suffix < (unsigned)len ) ++ { ++ ++p; ++ ++size_suffix; ++ } ++ if ( !size_suffix) ++ return; ++ ++ new_size = length () + size_suffix + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ // strcpy (new_string, cstring); ++ memcpy (new_string, cstring, length ()); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strncat (new_string, str, len); ++ memcpy (new_string + length (), ++ str, ++ size_suffix); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strncat (cstring, str, len); ++ memcpy (cstring + length (), ++ str, ++ size_suffix); ++ } ++ current_length = new_size - 1; ++ cstring [current_length] = 0; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char * suffix ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size; ++ ++ new_size = length () + strlen (suffix) + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ memcpy (new_string, cstring, 1 + length ()); ++ // strcpy (new_string, cstring); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strcat (new_string, suffix); ++ memcpy (new_string + length (), ++ suffix, ++ strlen (suffix) + 1); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strcat (cstring, suffix); ++ memcpy (cstring + length (), ++ suffix, ++ strlen (suffix) + 1); ++ } ++ current_length = new_size - 1; ++} ++ ++// Check for TiXmlString equuivalence ++//bool TiXmlString::operator == (const TiXmlString & compare) const ++//{ ++// return (! strcmp (c_str (), compare . c_str ())); ++//} ++ ++//unsigned TiXmlString::length () const ++//{ ++// if (allocated) ++// // return strlen (cstring); ++// return current_length; ++// return 0; ++//} ++ ++ ++unsigned TiXmlString::find (char tofind, unsigned offset) const ++{ ++ char * lookup; ++ ++ if (offset >= length ()) ++ return (unsigned) notfound; ++ for (lookup = cstring + offset; * lookup; lookup++) ++ if (* lookup == tofind) ++ return lookup - cstring; ++ return (unsigned) notfound; ++} ++ ++ ++bool TiXmlString::operator == (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) == 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator < (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) > 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator > (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) < 0 ); ++ } ++ return false; ++} ++ ++ ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/tinystr.h vdr-1.7.0-extensions/tinystr.h +--- vdr-1.7.0/tinystr.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/tinystr.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,244 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++ ++#ifndef TIXML_USE_STL ++ ++#ifndef TIXML_STRING_INCLUDED ++#define TIXML_STRING_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4786 ) // Debugger truncating names. ++#endif ++ ++#include <assert.h> ++ ++/* ++ TiXmlString is an emulation of the std::string template. ++ Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. ++ Only the member functions relevant to the TinyXML project have been implemented. ++ The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase ++ a string and there's no more room, we allocate a buffer twice as big as we need. ++*/ ++class TiXmlString ++{ ++ public : ++ // TiXmlString constructor, based on a string ++ TiXmlString (const char * instring); ++ ++ // TiXmlString empty constructor ++ TiXmlString () ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ } ++ ++ // TiXmlString copy constructor ++ TiXmlString (const TiXmlString& copy); ++ ++ // TiXmlString destructor ++ ~ TiXmlString () ++ { ++ empty_it (); ++ } ++ ++ // Convert a TiXmlString into a classical char * ++ const char * c_str () const ++ { ++ if (allocated) ++ return cstring; ++ return ""; ++ } ++ ++ // Return the length of a TiXmlString ++ unsigned length () const ++ { ++ return ( allocated ) ? current_length : 0; ++ } ++ ++ // TiXmlString = operator ++ void operator = (const char * content); ++ ++ // = operator ++ void operator = (const TiXmlString & copy); ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (const char * suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (char single) ++ { ++ append (single); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (TiXmlString & suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ bool operator == (const TiXmlString & compare) const; ++ bool operator < (const TiXmlString & compare) const; ++ bool operator > (const TiXmlString & compare) const; ++ ++ // Checks if a TiXmlString is empty ++ bool empty () const ++ { ++ return length () ? false : true; ++ } ++ ++ // single char extraction ++ const char& at (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // find a char in a string. Return TiXmlString::notfound if not found ++ unsigned find (char lookup) const ++ { ++ return find (lookup, 0); ++ } ++ ++ // find a char in a string from an offset. Return TiXmlString::notfound if not found ++ unsigned find (char tofind, unsigned offset) const; ++ ++ /* Function to reserve a big amount of data when we know we'll need it. Be aware that this ++ function clears the content of the TiXmlString if any exists. ++ */ ++ void reserve (unsigned size) ++ { ++ empty_it (); ++ if (size) ++ { ++ allocated = size; ++ cstring = new char [size]; ++ cstring [0] = 0; ++ current_length = 0; ++ } ++ } ++ ++ // [] operator ++ char& operator [] (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // Error value for find primitive ++ enum { notfound = 0xffffffff, ++ npos = notfound }; ++ ++ void append (const char *str, int len ); ++ ++ protected : ++ ++ // The base string ++ char * cstring; ++ // Number of chars allocated ++ unsigned allocated; ++ // Current string size ++ unsigned current_length; ++ ++ // New size computation. It is simplistic right now : it returns twice the amount ++ // we need ++ unsigned assign_new_size (unsigned minimum_to_allocate) ++ { ++ return minimum_to_allocate * 2; ++ } ++ ++ // Internal function that clears the content of a TiXmlString ++ void empty_it () ++ { ++ if (cstring) ++ delete [] cstring; ++ cstring = NULL; ++ allocated = 0; ++ current_length = 0; ++ } ++ ++ void append (const char *suffix ); ++ ++ // append function for another TiXmlString ++ void append (const TiXmlString & suffix) ++ { ++ append (suffix . c_str ()); ++ } ++ ++ // append for a single char. ++ void append (char single) ++ { ++ if ( cstring && current_length < (allocated-1) ) ++ { ++ cstring[ current_length ] = single; ++ ++current_length; ++ cstring[ current_length ] = 0; ++ } ++ else ++ { ++ char smallstr [2]; ++ smallstr [0] = single; ++ smallstr [1] = 0; ++ append (smallstr); ++ } ++ } ++ ++} ; ++ ++/* ++ TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. ++ Only the operators that we need for TinyXML have been developped. ++*/ ++class TiXmlOutStream : public TiXmlString ++{ ++public : ++ TiXmlOutStream () : TiXmlString () {} ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const char * in) ++ { ++ append (in); ++ return (* this); ++ } ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const TiXmlString & in) ++ { ++ append (in . c_str ()); ++ return (* this); ++ } ++} ; ++ ++#endif // TIXML_STRING_INCLUDED ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/tinyxml.c vdr-1.7.0-extensions/tinyxml.c +--- vdr-1.7.0/tinyxml.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/tinyxml.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,1429 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include <ctype.h> ++#include "tinyxml.h" ++ ++#ifdef TIXML_USE_STL ++#include <sstream> ++#endif ++ ++ ++bool TiXmlBase::condenseWhiteSpace = true; ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream ) ++{ ++ TIXML_STRING buffer; ++ PutString( str, &buffer ); ++ (*stream) << buffer; ++} ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) ++{ ++ int i=0; ++ ++ while( i<(int)str.length() ) ++ { ++ unsigned char c = (unsigned char) str[i]; ++ ++ if ( c == '&' ++ && i < ( (int)str.length() - 2 ) ++ && str[i+1] == '#' ++ && str[i+2] == 'x' ) ++ { ++ // Hexadecimal character reference. ++ // Pass through unchanged. ++ // © -- copyright symbol, for example. ++ // ++ // The -1 is a bug fix from Rob Laveaux. It keeps ++ // an overflow from happening if there is no ';'. ++ // There are actually 2 ways to exit this loop - ++ // while fails (error case) and break (semicolon found). ++ // However, there is no mechanism (currently) for ++ // this function to return an error. ++ while ( i<(int)str.length()-1 ) ++ { ++ outString->append( str.c_str() + i, 1 ); ++ ++i; ++ if ( str[i] == ';' ) ++ break; ++ } ++ } ++ else if ( c == '&' ) ++ { ++ outString->append( entity[0].str, entity[0].strLength ); ++ ++i; ++ } ++ else if ( c == '<' ) ++ { ++ outString->append( entity[1].str, entity[1].strLength ); ++ ++i; ++ } ++ else if ( c == '>' ) ++ { ++ outString->append( entity[2].str, entity[2].strLength ); ++ ++i; ++ } ++ else if ( c == '\"' ) ++ { ++ outString->append( entity[3].str, entity[3].strLength ); ++ ++i; ++ } ++ else if ( c == '\'' ) ++ { ++ outString->append( entity[4].str, entity[4].strLength ); ++ ++i; ++ } ++ else if ( c < 32 ) ++ { ++ // Easy pass at non-alpha/numeric/symbol ++ // Below 32 is symbolic. ++ char buf[ 32 ]; ++ sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); ++ outString->append( buf, strlen( buf ) ); ++ ++i; ++ } ++ else ++ { ++ //char realc = (char) c; ++ //outString->append( &realc, 1 ); ++ *outString += (char) c; // somewhat more efficient function call. ++ ++i; ++ } ++ } ++} ++ ++ ++// <-- Strange class for a bug fix. Search for STL_STRING_BUG ++TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str ) ++{ ++ buffer = new char[ str.length()+1 ]; ++ if ( buffer ) ++ { ++ strcpy( buffer, str.c_str() ); ++ } ++} ++ ++ ++TiXmlBase::StringToBuffer::~StringToBuffer() ++{ ++ delete [] buffer; ++} ++// End strange bug fix. --> ++ ++ ++TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() ++{ ++ parent = 0; ++ type = _type; ++ firstChild = 0; ++ lastChild = 0; ++ prev = 0; ++ next = 0; ++} ++ ++ ++TiXmlNode::~TiXmlNode() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++} ++ ++ ++void TiXmlNode::CopyTo( TiXmlNode* target ) const ++{ ++ target->SetValue (value.c_str() ); ++ target->userData = userData; ++} ++ ++ ++void TiXmlNode::Clear() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++ ++ firstChild = 0; ++ lastChild = 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) ++{ ++ node->parent = this; ++ ++ node->prev = lastChild; ++ node->next = 0; ++ ++ if ( lastChild ) ++ lastChild->next = node; ++ else ++ firstChild = node; // it was an empty list. ++ ++ lastChild = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) ++{ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ return LinkEndChild( node ); ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) ++{ ++ if ( !beforeThis || beforeThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->next = beforeThis; ++ node->prev = beforeThis->prev; ++ if ( beforeThis->prev ) ++ { ++ beforeThis->prev->next = node; ++ } ++ else ++ { ++ assert( firstChild == beforeThis ); ++ firstChild = node; ++ } ++ beforeThis->prev = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) ++{ ++ if ( !afterThis || afterThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->prev = afterThis; ++ node->next = afterThis->next; ++ if ( afterThis->next ) ++ { ++ afterThis->next->prev = node; ++ } ++ else ++ { ++ assert( lastChild == afterThis ); ++ lastChild = node; ++ } ++ afterThis->next = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) ++{ ++ if ( replaceThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = withThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ node->next = replaceThis->next; ++ node->prev = replaceThis->prev; ++ ++ if ( replaceThis->next ) ++ replaceThis->next->prev = node; ++ else ++ lastChild = node; ++ ++ if ( replaceThis->prev ) ++ replaceThis->prev->next = node; ++ else ++ firstChild = node; ++ ++ delete replaceThis; ++ node->parent = this; ++ return node; ++} ++ ++ ++bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) ++{ ++ if ( removeThis->parent != this ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ if ( removeThis->next ) ++ removeThis->next->prev = removeThis->prev; ++ else ++ lastChild = removeThis->prev; ++ ++ if ( removeThis->prev ) ++ removeThis->prev->next = removeThis->next; ++ else ++ firstChild = removeThis->next; ++ ++ delete removeThis; ++ return true; ++} ++ ++TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = firstChild; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING( _value )) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::LastChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = lastChild; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild(); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling(); ++ } ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild( val ); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling( val ); ++ } ++} ++ ++TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = next; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = prev; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++void TiXmlElement::RemoveAttribute( const char * name ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement* TiXmlNode::NextSiblingElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++ ++TiXmlDocument* TiXmlNode::GetDocument() const ++{ ++ const TiXmlNode* node; ++ ++ for( node = this; node; node = node->parent ) ++ { ++ if ( node->ToDocument() ) ++ return node->ToDocument(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement::TiXmlElement (const char * _value) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlElement::TiXmlElement( const std::string& _value ) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++#endif ++ ++ ++TiXmlElement::TiXmlElement( const TiXmlElement& copy) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlElement::operator=( const TiXmlElement& base ) ++{ ++ ClearThis(); ++ base.CopyTo( this ); ++} ++ ++ ++TiXmlElement::~TiXmlElement() ++{ ++ ClearThis(); ++} ++ ++ ++void TiXmlElement::ClearThis() ++{ ++ Clear(); ++ while( attributeSet.First() ) ++ { ++ TiXmlAttribute* node = attributeSet.First(); ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ ++ if ( node ) ++ return node->Value(); ++ ++ return 0; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, int* i ) const ++{ ++ const char * s = Attribute( name ); ++ if ( i ) ++ { ++ if ( s ) ++ *i = atoi( s ); ++ else ++ *i = 0; ++ } ++ return s; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, double* d ) const ++{ ++ const char * s = Attribute( name ); ++ if ( d ) ++ { ++ if ( s ) ++ *d = atof( s ); ++ else ++ *d = 0; ++ } ++ return s; ++} ++ ++ ++int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryIntValue( ival ); ++} ++ ++ ++int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryDoubleValue( dval ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, int val ) ++{ ++ char buf[64]; ++ sprintf( buf, "%d", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetDoubleAttribute( const char * name, double val ) ++{ ++ char buf[128]; ++ sprintf( buf, "%f", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, const char * _value ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ node->SetValue( _value ); ++ return; ++ } ++ ++ TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); ++ if ( attrib ) ++ { ++ attributeSet.Add( attrib ); ++ } ++ else ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++} ++ ++void TiXmlElement::Print( FILE* cfile, int depth ) const ++{ ++ int i; ++ for ( i=0; i<depth; i++ ) ++ { ++ fprintf( cfile, " " ); ++ } ++ ++ fprintf( cfile, "<%s", value.c_str() ); ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ fprintf( cfile, " " ); ++ attrib->Print( cfile, depth ); ++ } ++ ++ // There are 3 different formatting approaches: ++ // 1) An element without children is printed as a <foo /> node ++ // 2) An element with only a text child is printed as <foo> text </foo> ++ // 3) An element with children is printed on multiple lines. ++ TiXmlNode* node; ++ if ( !firstChild ) ++ { ++ fprintf( cfile, " />" ); ++ } ++ else if ( firstChild == lastChild && firstChild->ToText() ) ++ { ++ fprintf( cfile, ">" ); ++ firstChild->Print( cfile, depth + 1 ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++ else ++ { ++ fprintf( cfile, ">" ); ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ if ( !node->ToText() ) ++ { ++ fprintf( cfile, "\n" ); ++ } ++ node->Print( cfile, depth+1 ); ++ } ++ fprintf( cfile, "\n" ); ++ for( i=0; i<depth; ++i ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++} ++ ++void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value; ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ (*stream) << " "; ++ attrib->StreamOut( stream ); ++ } ++ ++ // If this node has children, give it a closing tag. Else ++ // make it an empty tag. ++ TiXmlNode* node; ++ if ( firstChild ) ++ { ++ (*stream) << ">"; ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ node->StreamOut( stream ); ++ } ++ (*stream) << "</" << value << ">"; ++ } ++ else ++ { ++ (*stream) << " />"; ++ } ++} ++ ++ ++void TiXmlElement::CopyTo( TiXmlElement* target ) const ++{ ++ // superclass: ++ TiXmlNode::CopyTo( target ); ++ ++ // Element class: ++ // Clone the attributes, then clone the children. ++ TiXmlAttribute* attribute = 0; ++ for( attribute = attributeSet.First(); ++ attribute; ++ attribute = attribute->Next() ) ++ { ++ target->SetAttribute( attribute->Name(), attribute->Value() ); ++ } ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlElement::Clone() const ++{ ++ TiXmlElement* clone = new TiXmlElement( Value() ); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ ClearError(); ++} ++ ++TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++#endif ++ ++ ++TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDocument::operator=( const TiXmlDocument& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && LoadFile( buf.buffer, encoding ) ) ++ return true; ++ ++ return false; ++} ++ ++ ++bool TiXmlDocument::SaveFile() const ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && SaveFile( buf.buffer ) ) ++ return true; ++ ++ return false; ++} ++ ++bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding ) ++{ ++ // Delete the existing data: ++ Clear(); ++ location.Clear(); ++ ++ // There was a really terrifying little bug here. The code: ++ // value = filename ++ // in the STL case, cause the assignment method of the std::string to ++ // be called. What is strange, is that the std::string had the same ++ // address as it's c_str() method, and so bad things happen. Looks ++ // like a bug in the Microsoft STL implementation. ++ // See STL_STRING_BUG above. ++ // Fixed with the StringToBuffer class. ++ value = filename; ++ ++ FILE* file = fopen( value.c_str (), "r" ); ++ ++ if ( file ) ++ { ++ // Get the file size, so we can pre-allocate the string. HUGE speed impact. ++ long length = 0; ++ fseek( file, 0, SEEK_END ); ++ length = ftell( file ); ++ fseek( file, 0, SEEK_SET ); ++ ++ // Strange case, but good to handle up front. ++ if ( length == 0 ) ++ { ++ fclose( file ); ++ return false; ++ } ++ ++ // If we have a file, assume it is all one big XML file, and read it in. ++ // The document parser may decide the document ends sooner than the entire file, however. ++ TIXML_STRING data; ++ data.reserve( length ); ++ ++ const int BUF_SIZE = 2048; ++ char buf[BUF_SIZE]; ++ ++ while( fgets( buf, BUF_SIZE, file ) ) ++ { ++ data += buf; ++ } ++ fclose( file ); ++ ++ Parse( data.c_str(), 0, encoding ); ++ ++ if ( Error() ) ++ return false; ++ else ++ return true; ++ } ++ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return false; ++} ++ ++bool TiXmlDocument::SaveFile( const char * filename ) const ++{ ++ // The old c stuff lives on... ++ FILE* fp = fopen( filename, "w" ); ++ if ( fp ) ++ { ++ Print( fp, 0 ); ++ fclose( fp ); ++ return true; ++ } ++ return false; ++} ++ ++ ++void TiXmlDocument::CopyTo( TiXmlDocument* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->error = error; ++ target->errorDesc = errorDesc.c_str (); ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlDocument::Clone() const ++{ ++ TiXmlDocument* clone = new TiXmlDocument(); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlDocument::Print( FILE* cfile, int depth ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->Print( cfile, depth ); ++ fprintf( cfile, "\n" ); ++ } ++} ++ ++void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->StreamOut( out ); ++ ++ // Special rule for streams: stop after the root element. ++ // The stream in code will only read one element, so don't ++ // write more than one. ++ if ( node->ToElement() ) ++ break; ++ } ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Next() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( next->value.empty() && next->name.empty() ) ++ return 0; ++ return next; ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Previous() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( prev->value.empty() && prev->name.empty() ) ++ return 0; ++ return prev; ++} ++ ++ ++void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING n, v; ++ ++ PutString( name, &n ); ++ PutString( value, &v ); ++ ++ if (value.find ('\"') == TIXML_STRING::npos) ++ fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); ++ else ++ fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); ++} ++ ++ ++void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ if (value.find( '\"' ) != TIXML_STRING::npos) ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "'"; ++ PutString( value, stream ); ++ (*stream) << "'"; ++ } ++ else ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "\""; ++ PutString( value, stream ); ++ (*stream) << "\""; ++ } ++} ++ ++int TiXmlAttribute::QueryIntValue( int* ival ) const ++{ ++ if ( sscanf( value.c_str(), "%d", ival ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++int TiXmlAttribute::QueryDoubleValue( double* dval ) const ++{ ++ if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++void TiXmlAttribute::SetIntValue( int _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%d", _value); ++ SetValue (buf); ++} ++ ++void TiXmlAttribute::SetDoubleValue( double _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%lf", _value); ++ SetValue (buf); ++} ++ ++const int TiXmlAttribute::IntValue() const ++{ ++ return atoi (value.c_str ()); ++} ++ ++const double TiXmlAttribute::DoubleValue() const ++{ ++ return atof (value.c_str ()); ++} ++ ++ ++TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::operator=( const TiXmlComment& base ) ++{ ++ Clear(); ++ base.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ { ++ fputs( " ", cfile ); ++ } ++ fprintf( cfile, "<!--%s-->", value.c_str() ); ++} ++ ++void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<!--"; ++ //PutString( value, stream ); ++ (*stream) << value; ++ (*stream) << "-->"; ++} ++ ++ ++void TiXmlComment::CopyTo( TiXmlComment* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlComment::Clone() const ++{ ++ TiXmlComment* clone = new TiXmlComment(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING buffer; ++ PutString( value, &buffer ); ++ fprintf( cfile, "%s", buffer.c_str() ); ++} ++ ++ ++void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ PutString( value, stream ); ++} ++ ++ ++void TiXmlText::CopyTo( TiXmlText* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlText::Clone() const ++{ ++ TiXmlText* clone = 0; ++ clone = new TiXmlText( "" ); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const char * _version, ++ const char * _encoding, ++ const char * _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++#endif ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ fprintf (cfile, "<?xml "); ++ ++ if ( !version.empty() ) ++ fprintf (cfile, "version=\"%s\" ", version.c_str ()); ++ if ( !encoding.empty() ) ++ fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); ++ if ( !standalone.empty() ) ++ fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); ++ fprintf (cfile, "?>"); ++} ++ ++void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<?xml "; ++ ++ if ( !version.empty() ) ++ { ++ (*stream) << "version=\""; ++ PutString( version, stream ); ++ (*stream) << "\" "; ++ } ++ if ( !encoding.empty() ) ++ { ++ (*stream) << "encoding=\""; ++ PutString( encoding, stream ); ++ (*stream ) << "\" "; ++ } ++ if ( !standalone.empty() ) ++ { ++ (*stream) << "standalone=\""; ++ PutString( standalone, stream ); ++ (*stream) << "\" "; ++ } ++ (*stream) << "?>"; ++} ++ ++ ++void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->version = version; ++ target->encoding = encoding; ++ target->standalone = standalone; ++} ++ ++ ++TiXmlNode* TiXmlDeclaration::Clone() const ++{ ++ TiXmlDeclaration* clone = new TiXmlDeclaration(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlUnknown::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "<%s>", value.c_str() ); ++} ++ ++ ++void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value << ">"; // Don't use entities here! It is unknown. ++} ++ ++ ++void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlUnknown::Clone() const ++{ ++ TiXmlUnknown* clone = new TiXmlUnknown(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlAttributeSet::TiXmlAttributeSet() ++{ ++ sentinel.next = &sentinel; ++ sentinel.prev = &sentinel; ++} ++ ++ ++TiXmlAttributeSet::~TiXmlAttributeSet() ++{ ++ assert( sentinel.next == &sentinel ); ++ assert( sentinel.prev == &sentinel ); ++} ++ ++ ++void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) ++{ ++ assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. ++ ++ addMe->next = &sentinel; ++ addMe->prev = sentinel.prev; ++ ++ sentinel.prev->next = addMe; ++ sentinel.prev = addMe; ++} ++ ++void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node == removeMe ) ++ { ++ node->prev->next = node->next; ++ node->next->prev = node->prev; ++ node->next = 0; ++ node->prev = 0; ++ return; ++ } ++ } ++ assert( 0 ); // we tried to remove a non-linked attribute. ++} ++ ++TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node->name == name ) ++ return node; ++ } ++ return 0; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base) ++{ ++ TIXML_STRING tag; ++ tag.reserve( 8 * 1000 ); ++ base.StreamIn( &in, &tag ); ++ ++ base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); ++ return in; ++} ++#endif ++ ++ ++TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base) ++{ ++ base.StreamOut (& out); ++ return out; ++} ++ ++ ++#ifdef TIXML_USE_STL ++std::string & operator<< (std::string& out, const TiXmlNode& base ) ++{ ++ std::ostringstream os_stream( std::ostringstream::out ); ++ base.StreamOut( &os_stream ); ++ ++ out.append( os_stream.str() ); ++ return out; ++} ++#endif ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild() const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement() const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/tinyxmlerror.c vdr-1.7.0-extensions/tinyxmlerror.c +--- vdr-1.7.0/tinyxmlerror.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/tinyxmlerror.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,53 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++// The goal of the seperate error file is to make the first ++// step towards localization. tinyxml (currently) only supports ++// latin-1, but at least the error messages could now be translated. ++// ++// It also cleans up the code a bit. ++// ++ ++const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = ++{ ++ "No error", ++ "Error", ++ "Failed to open file", ++ "Memory allocation failed.", ++ "Error parsing Element.", ++ "Failed to read Element name", ++ "Error reading Element value.", ++ "Error reading Attributes.", ++ "Error: empty tag.", ++ "Error reading end tag.", ++ "Error parsing Unknown.", ++ "Error parsing Comment.", ++ "Error parsing Declaration.", ++ "Error document empty.", ++ "Error null (0) or unexpected EOF found in input stream.", ++}; ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/tinyxml.h vdr-1.7.0-extensions/tinyxml.h +--- vdr-1.7.0/tinyxml.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/tinyxml.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,1372 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++ ++#ifndef TINYXML_INCLUDED ++#define TINYXML_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4530 ) ++#pragma warning( disable : 4786 ) ++#endif ++ ++#include <ctype.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <assert.h> ++ ++// Help out windows: ++#if defined( _DEBUG ) && !defined( DEBUG ) ++#define DEBUG ++#endif ++ ++#if defined( DEBUG ) && defined( _MSC_VER ) ++#include <windows.h> ++#define TIXML_LOG OutputDebugString ++#else ++#define TIXML_LOG printf ++#endif ++ ++#ifdef TIXML_USE_STL ++ #include <string> ++ #include <iostream> ++ #define TIXML_STRING std::string ++ #define TIXML_ISTREAM std::istream ++ #define TIXML_OSTREAM std::ostream ++#else ++ #include "tinystr.h" ++ #define TIXML_STRING TiXmlString ++ #define TIXML_OSTREAM TiXmlOutStream ++#endif ++ ++class TiXmlDocument; ++class TiXmlElement; ++class TiXmlComment; ++class TiXmlUnknown; ++class TiXmlAttribute; ++class TiXmlText; ++class TiXmlDeclaration; ++class TiXmlParsingData; ++ ++const int TIXML_MAJOR_VERSION = 2; ++const int TIXML_MINOR_VERSION = 3; ++const int TIXML_PATCH_VERSION = 2; ++ ++/* Internal structure for tracking location of items ++ in the XML file. ++*/ ++struct TiXmlCursor ++{ ++ TiXmlCursor() { Clear(); } ++ void Clear() { row = col = -1; } ++ ++ int row; // 0 based. ++ int col; // 0 based. ++}; ++ ++ ++// Only used by Attribute::Query functions ++enum ++{ ++ TIXML_SUCCESS, ++ TIXML_NO_ATTRIBUTE, ++ TIXML_WRONG_TYPE ++}; ++ ++ ++// Used by the parsing routines. ++enum TiXmlEncoding ++{ ++ TIXML_ENCODING_UNKNOWN, ++ TIXML_ENCODING_UTF8, ++ TIXML_ENCODING_LEGACY ++}; ++ ++const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; ++ ++/** TiXmlBase is a base class for every class in TinyXml. ++ It does little except to establish that TinyXml classes ++ can be printed and provide some utility functions. ++ ++ In XML, the document and elements can contain ++ other elements and other types of nodes. ++ ++ @verbatim ++ A Document can contain: Element (container or leaf) ++ Comment (leaf) ++ Unknown (leaf) ++ Declaration( leaf ) ++ ++ An Element can contain: Element (container or leaf) ++ Text (leaf) ++ Attributes (not on tree) ++ Comment (leaf) ++ Unknown (leaf) ++ ++ A Decleration contains: Attributes (not on tree) ++ @endverbatim ++*/ ++class TiXmlBase ++{ ++ friend class TiXmlNode; ++ friend class TiXmlElement; ++ friend class TiXmlDocument; ++ ++public: ++ TiXmlBase() : userData(0) {} ++ virtual ~TiXmlBase() {} ++ ++ /** All TinyXml classes can print themselves to a filestream. ++ This is a formatted print, and will insert tabs and newlines. ++ ++ (For an unformatted stream, use the << operator.) ++ */ ++ virtual void Print( FILE* cfile, int depth ) const = 0; ++ ++ /** The world does not agree on whether white space should be kept or ++ not. In order to make everyone happy, these global, static functions ++ are provided to set whether or not TinyXml will condense all white space ++ into a single space or not. The default is to condense. Note changing this ++ values is not thread safe. ++ */ ++ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } ++ ++ /// Return the current white space setting. ++ static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } ++ ++ /** Return the position, in the original source file, of this node or attribute. ++ The row and column are 1-based. (That is the first row and first column is ++ 1,1). If the returns values are 0 or less, then the parser does not have ++ a row and column value. ++ ++ Generally, the row and column value will be set when the TiXmlDocument::Load(), ++ TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set ++ when the DOM was created from operator>>. ++ ++ The values reflect the initial load. Once the DOM is modified programmatically ++ (by adding or changing nodes and attributes) the new values will NOT update to ++ reflect changes in the document. ++ ++ There is a minor performance cost to computing the row and column. Computation ++ can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. ++ ++ @sa TiXmlDocument::SetTabSize() ++ */ ++ int Row() const { return location.row + 1; } ++ int Column() const { return location.col + 1; } ///< See Row() ++ ++ void SetUserData( void* user ) { userData = user; } ++ void* GetUserData() { return userData; } ++ ++ // Table that returs, for a given lead byte, the total number of bytes ++ // in the UTF-8 sequence. ++ static const int utf8ByteTable[256]; ++ ++ virtual const char* Parse( const char* p, ++ TiXmlParsingData* data, ++ TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; ++ ++protected: ++ ++ // See STL_STRING_BUG ++ // Utility class to overcome a bug. ++ class StringToBuffer ++ { ++ public: ++ StringToBuffer( const TIXML_STRING& str ); ++ ~StringToBuffer(); ++ char* buffer; ++ }; ++ ++ static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); ++ inline static bool IsWhiteSpace( char c ) ++ { ++ return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); ++ } ++ ++ virtual void StreamOut (TIXML_OSTREAM *) const = 0; ++ ++ #ifdef TIXML_USE_STL ++ static bool StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ static bool StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ); ++ #endif ++ ++ /* Reads an XML name into the string provided. Returns ++ a pointer just past the last character of the name, ++ or 0 if the function has an error. ++ */ ++ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); ++ ++ /* Reads text. Returns a pointer past the given end tag. ++ Wickedly complex options, but it keeps the (sensitive) code in one place. ++ */ ++ static const char* ReadText( const char* in, // where to start ++ TIXML_STRING* text, // the string read ++ bool ignoreWhiteSpace, // whether to keep the white space ++ const char* endTag, // what ends this text ++ bool ignoreCase, // whether to ignore case in the end tag ++ TiXmlEncoding encoding ); // the current encoding ++ ++ // If an entity has been found, transform it into a character. ++ static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); ++ ++ // Get a character, while interpreting entities. ++ // The length can be from 0 to 4 bytes. ++ inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) ++ { ++ assert( p ); ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ *length = utf8ByteTable[ *((unsigned char*)p) ]; ++ assert( *length >= 0 && *length < 5 ); ++ } ++ else ++ { ++ *length = 1; ++ } ++ ++ if ( *length == 1 ) ++ { ++ if ( *p == '&' ) ++ return GetEntity( p, _value, length, encoding ); ++ *_value = *p; ++ return p+1; ++ } ++ else if ( *length ) ++ { ++ strncpy( _value, p, *length ); ++ return p + (*length); ++ } ++ else ++ { ++ // Not valid text. ++ return 0; ++ } ++ } ++ ++ // Puts a string to a stream, expanding entities as it goes. ++ // Note this should not contian the '<', '>', etc, or they will be transformed into entities! ++ static void PutString( const TIXML_STRING& str, TIXML_OSTREAM* out ); ++ ++ static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); ++ ++ // Return true if the next characters in the stream are any of the endTag sequences. ++ // Ignore case only works for english, and should only be relied on when comparing ++ // to Engilish words: StringEqual( p, "version", true ) is fine. ++ static bool StringEqual( const char* p, ++ const char* endTag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ); ++ ++ ++ enum ++ { ++ TIXML_NO_ERROR = 0, ++ TIXML_ERROR, ++ TIXML_ERROR_OPENING_FILE, ++ TIXML_ERROR_OUT_OF_MEMORY, ++ TIXML_ERROR_PARSING_ELEMENT, ++ TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, ++ TIXML_ERROR_READING_ELEMENT_VALUE, ++ TIXML_ERROR_READING_ATTRIBUTES, ++ TIXML_ERROR_PARSING_EMPTY, ++ TIXML_ERROR_READING_END_TAG, ++ TIXML_ERROR_PARSING_UNKNOWN, ++ TIXML_ERROR_PARSING_COMMENT, ++ TIXML_ERROR_PARSING_DECLARATION, ++ TIXML_ERROR_DOCUMENT_EMPTY, ++ TIXML_ERROR_EMBEDDED_NULL, ++ ++ TIXML_ERROR_STRING_COUNT ++ }; ++ static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; ++ ++ TiXmlCursor location; ++ ++ /// Field containing a generic user pointer ++ void* userData; ++ ++ // None of these methods are reliable for any language except English. ++ // Good for approximation, not great for accuracy. ++ static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); ++ static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); ++ inline static int ToLower( int v, TiXmlEncoding encoding ) ++ { ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( v < 128 ) return tolower( v ); ++ return v; ++ } ++ else ++ { ++ return tolower( v ); ++ } ++ } ++ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); ++ ++private: ++ TiXmlBase( const TiXmlBase& ); // not implemented. ++ void operator=( const TiXmlBase& base ); // not allowed. ++ ++ struct Entity ++ { ++ const char* str; ++ unsigned int strLength; ++ char chr; ++ }; ++ enum ++ { ++ NUM_ENTITY = 5, ++ MAX_ENTITY_LENGTH = 6 ++ ++ }; ++ static Entity entity[ NUM_ENTITY ]; ++ static bool condenseWhiteSpace; ++}; ++ ++ ++/** The parent class for everything in the Document Object Model. ++ (Except for attributes). ++ Nodes have siblings, a parent, and children. A node can be ++ in a document, or stand on its own. The type of a TiXmlNode ++ can be queried, and it can be cast to its more defined type. ++*/ ++class TiXmlNode : public TiXmlBase ++{ ++ friend class TiXmlDocument; ++ friend class TiXmlElement; ++ ++public: ++ #ifdef TIXML_USE_STL ++ ++ /** An input stream operator, for every class. Tolerant of newlines and ++ formatting, but doesn't expect them. ++ */ ++ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); ++ ++ /** An output stream operator, for every class. Note that this outputs ++ without any newlines or formatting, as opposed to Print(), which ++ includes tabs and new lines. ++ ++ The operator<< and operator>> are not completely symmetric. Writing ++ a node to a stream is very well defined. You'll get a nice stream ++ of output, without any extra whitespace or newlines. ++ ++ But reading is not as well defined. (As it always is.) If you create ++ a TiXmlElement (for example) and read that from an input stream, ++ the text needs to define an element or junk will result. This is ++ true of all input streams, but it's worth keeping in mind. ++ ++ A TiXmlDocument will read nodes until it reads a root element, and ++ all the children of that root element. ++ */ ++ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); ++ ++ /// Appends the XML node or attribute to a std::string. ++ friend std::string& operator<< (std::string& out, const TiXmlNode& base ); ++ ++ #else ++ // Used internally, not part of the public API. ++ friend TIXML_OSTREAM& operator<< (TIXML_OSTREAM& out, const TiXmlNode& base); ++ #endif ++ ++ /** The types of XML nodes supported by TinyXml. (All the ++ unsupported types are picked up by UNKNOWN.) ++ */ ++ enum NodeType ++ { ++ DOCUMENT, ++ ELEMENT, ++ COMMENT, ++ UNKNOWN, ++ TEXT, ++ DECLARATION, ++ TYPECOUNT ++ }; ++ ++ virtual ~TiXmlNode(); ++ ++ /** The meaning of 'value' changes for the specific type of ++ TiXmlNode. ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ ++ The subclasses will wrap this function. ++ */ ++ const char * Value() const { return value.c_str (); } ++ ++ /** Changes the value of the node. Defined as: ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ */ ++ void SetValue(const char * _value) { value = _value;} ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "" ); ++ } ++ #endif ++ ++ /// Delete all the children of this node. Does not affect 'this'. ++ void Clear(); ++ ++ /// One step up the DOM. ++ TiXmlNode* Parent() const { return parent; } ++ ++ TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. ++ TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. ++ ++ TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. ++ TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** An alternate way to walk the children of a node. ++ One way to iterate over nodes is: ++ @verbatim ++ for( child = parent->FirstChild(); child; child = child->NextSibling() ) ++ @endverbatim ++ ++ IterateChildren does the same thing with the syntax: ++ @verbatim ++ child = 0; ++ while( child = parent->IterateChildren( child ) ) ++ @endverbatim ++ ++ IterateChildren takes the previous child as input and finds ++ the next one. If the previous child is null, it returns the ++ first. IterateChildren will return null when done. ++ */ ++ TiXmlNode* IterateChildren( TiXmlNode* previous ) const; ++ ++ /// This flavor of IterateChildren searches for children with a particular 'value' ++ TiXmlNode* IterateChildren( const char * value, TiXmlNode* previous ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* IterateChildren( const std::string& _value, TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. ++ #endif ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); ++ ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ ++ NOTE: the node to be added is passed by pointer, and will be ++ henceforth owned (and deleted) by tinyXml. This method is efficient ++ and avoids an extra copy, but should be used with care as it ++ uses a different memory model than the other insert functions. ++ ++ @sa InsertEndChild ++ */ ++ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); ++ ++ /** Add a new node related to this. Adds a child before the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); ++ ++ /** Add a new node related to this. Adds a child after the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); ++ ++ /** Replace a child of this node. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); ++ ++ /// Delete a child of this node. ++ bool RemoveChild( TiXmlNode* removeThis ); ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling() const { return prev; } ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* NextSibling() const { return next; } ++ ++ /// Navigate to a sibling node with the given 'value'. ++ TiXmlNode* NextSibling( const char * ) const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement() const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement() const; ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement( const char * value ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** Query the type (as an enumerated value, above) of this node. ++ The possible types are: DOCUMENT, ELEMENT, COMMENT, ++ UNKNOWN, TEXT, and DECLARATION. ++ */ ++ virtual int Type() const { return type; } ++ ++ /** Return a pointer to the Document this node lives in. ++ Returns null if not in a document. ++ */ ++ TiXmlDocument* GetDocument() const; ++ ++ /// Returns true if this node has no children. ++ bool NoChildren() const { return !firstChild; } ++ ++ TiXmlDocument* ToDocument() const { return ( this && type == DOCUMENT ) ? (TiXmlDocument*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlElement* ToElement() const { return ( this && type == ELEMENT ) ? (TiXmlElement*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlComment* ToComment() const { return ( this && type == COMMENT ) ? (TiXmlComment*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlUnknown* ToUnknown() const { return ( this && type == UNKNOWN ) ? (TiXmlUnknown*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlText* ToText() const { return ( this && type == TEXT ) ? (TiXmlText*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlDeclaration* ToDeclaration() const { return ( this && type == DECLARATION ) ? (TiXmlDeclaration*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ ++ /** Create an exact duplicate of this node and return it. The memory must be deleted ++ by the caller. ++ */ ++ virtual TiXmlNode* Clone() const = 0; ++ ++protected: ++ TiXmlNode( NodeType _type ); ++ ++ // Copy to the allocated object. Shared functionality between Clone, Copy constructor, ++ // and the assignment operator. ++ void CopyTo( TiXmlNode* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ // The real work of the input operator. ++ virtual void StreamIn( TIXML_ISTREAM* in, TIXML_STRING* tag ) = 0; ++ #endif ++ ++ // Figure out what is at *p, and parse it. Returns null if it is not an xml node. ++ TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); ++ ++ // Internal Value function returning a TIXML_STRING ++ const TIXML_STRING& SValue() const { return value ; } ++ ++ TiXmlNode* parent; ++ NodeType type; ++ ++ TiXmlNode* firstChild; ++ TiXmlNode* lastChild; ++ ++ TIXML_STRING value; ++ ++ TiXmlNode* prev; ++ TiXmlNode* next; ++ ++private: ++ TiXmlNode( const TiXmlNode& ); // not implemented. ++ void operator=( const TiXmlNode& base ); // not allowed. ++}; ++ ++ ++/** An attribute is a name-value pair. Elements have an arbitrary ++ number of attributes, each with a unique name. ++ ++ @note The attributes are not TiXmlNodes, since they are not ++ part of the tinyXML document object model. There are other ++ suggested ways to look at this problem. ++*/ ++class TiXmlAttribute : public TiXmlBase ++{ ++ friend class TiXmlAttributeSet; ++ ++public: ++ /// Construct an empty attribute. ++ TiXmlAttribute() : TiXmlBase() ++ { ++ document = 0; ++ prev = next = 0; ++ } ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlAttribute( const std::string& _name, const std::string& _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ #endif ++ ++ /// Construct an attribute with a name and value. ++ TiXmlAttribute( const char * _name, const char * _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ ++ const char* Name() const { return name.c_str (); } ///< Return the name of this attribute. ++ const char* Value() const { return value.c_str (); } ///< Return the value of this attribute. ++ const int IntValue() const; ///< Return the value of this attribute, converted to an integer. ++ const double DoubleValue() const; ///< Return the value of this attribute, converted to a double. ++ ++ /** QueryIntValue examines the value string. It is an alternative to the ++ IntValue() method with richer error checking. ++ If the value is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. ++ ++ A specialized but useful call. Note that for success it returns 0, ++ which is the opposite of almost all other TinyXml calls. ++ */ ++ int QueryIntValue( int* value ) const; ++ /// QueryDoubleValue examines the value string. See QueryIntValue(). ++ int QueryDoubleValue( double* value ) const; ++ ++ void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. ++ void SetValue( const char* _value ) { value = _value; } ///< Set the value. ++ ++ void SetIntValue( int value ); ///< Set the value from an integer. ++ void SetDoubleValue( double value ); ///< Set the value from a double. ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetName( const std::string& _name ) ++ { ++ StringToBuffer buf( _name ); ++ SetName ( buf.buffer ? buf.buffer : "error" ); ++ } ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "error" ); ++ } ++ #endif ++ ++ /// Get the next sibling attribute in the DOM. Returns null at end. ++ TiXmlAttribute* Next() const; ++ /// Get the previous sibling attribute in the DOM. Returns null at beginning. ++ TiXmlAttribute* Previous() const; ++ ++ bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } ++ bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } ++ bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } ++ ++ /* Attribute parsing starts: first letter of the name ++ returns: the next char after the value end quote ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++ // Prints this Attribute to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ // [internal use] ++ // Set the document pointer so the attribute can report errors. ++ void SetDocument( TiXmlDocument* doc ) { document = doc; } ++ ++private: ++ TiXmlAttribute( const TiXmlAttribute& ); // not implemented. ++ void operator=( const TiXmlAttribute& base ); // not allowed. ++ ++ TiXmlDocument* document; // A pointer back to a document, for error reporting. ++ TIXML_STRING name; ++ TIXML_STRING value; ++ TiXmlAttribute* prev; ++ TiXmlAttribute* next; ++}; ++ ++ ++/* A class used to manage a group of attributes. ++ It is only used internally, both by the ELEMENT and the DECLARATION. ++ ++ The set can be changed transparent to the Element and Declaration ++ classes that use it, but NOT transparent to the Attribute ++ which has to implement a next() and previous() method. Which makes ++ it a bit problematic and prevents the use of STL. ++ ++ This version is implemented with circular lists because: ++ - I like circular lists ++ - it demonstrates some independence from the (typical) doubly linked list. ++*/ ++class TiXmlAttributeSet ++{ ++public: ++ TiXmlAttributeSet(); ++ ~TiXmlAttributeSet(); ++ ++ void Add( TiXmlAttribute* attribute ); ++ void Remove( TiXmlAttribute* attribute ); ++ ++ TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } ++ TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } ++ TiXmlAttribute* Find( const char * name ) const; ++ ++private: ++ TiXmlAttribute sentinel; ++}; ++ ++ ++/** The element is a container class. It has a value, the element name, ++ and can contain other elements, text, comments, and unknowns. ++ Elements also contain an arbitrary number of attributes. ++*/ ++class TiXmlElement : public TiXmlNode ++{ ++public: ++ /// Construct an element. ++ TiXmlElement (const char * in_value); ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlElement( const std::string& _value ); ++ #endif ++ ++ TiXmlElement( const TiXmlElement& ); ++ ++ void operator=( const TiXmlElement& base ); ++ ++ virtual ~TiXmlElement(); ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ */ ++ const char* Attribute( const char* name ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an integer, ++ the integer value will be put in the return 'i', if 'i' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, int* i ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an double, ++ the double value will be put in the return 'd', if 'd' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, double* d ) const; ++ ++ /** QueryIntAttribute examines the attribute - it is an alternative to the ++ Attribute() method with richer error checking. ++ If the attribute is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. If the attribute ++ does not exist, then TIXML_NO_ATTRIBUTE is returned. ++ */ ++ int QueryIntAttribute( const char* name, int* value ) const; ++ /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). ++ int QueryDoubleAttribute( const char* name, double* value ) const; ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char* name, const char * value ); ++ ++ #ifdef TIXML_USE_STL ++ const char* Attribute( const std::string& name ) const { return Attribute( name.c_str() ); } ++ const char* Attribute( const std::string& name, int* i ) const { return Attribute( name.c_str(), i ); } ++ const char* Attribute( const std::string& name, double* d ) const { return Attribute( name.c_str(), d ); } ++ int QueryIntAttribute( const std::string& name, int* value ) const { return QueryIntAttribute( name.c_str(), value ); } ++ int QueryDoubleAttribute( const std::string& name, double* value ) const { return QueryDoubleAttribute( name.c_str(), value ); } ++ ++ /// STL std::string form. ++ void SetAttribute( const std::string& name, const std::string& _value ) ++ { ++ StringToBuffer n( name ); ++ StringToBuffer v( _value ); ++ if ( n.buffer && v.buffer ) ++ SetAttribute (n.buffer, v.buffer ); ++ } ++ ///< STL std::string form. ++ void SetAttribute( const std::string& name, int _value ) ++ { ++ StringToBuffer n( name ); ++ if ( n.buffer ) ++ SetAttribute (n.buffer, _value); ++ } ++ #endif ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char * name, int value ); ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetDoubleAttribute( const char * name, double value ); ++ ++ /** Deletes an attribute with the given name. ++ */ ++ void RemoveAttribute( const char * name ); ++ #ifdef TIXML_USE_STL ++ void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. ++ TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. ++ ++ /// Creates a new Element and returns it - the returned element is a copy. ++ virtual TiXmlNode* Clone() const; ++ // Print the Element to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: next char past '<' ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ ++ void CopyTo( TiXmlElement* target ) const; ++ void ClearThis(); // like clear, but initializes 'this' object as well ++ ++ // Used to be public [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++ /* [internal use] ++ Reads the "value" of the element -- another element, or text. ++ This should terminate with the current end tag. ++ */ ++ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++private: ++ ++ TiXmlAttributeSet attributeSet; ++}; ++ ++ ++/** An XML comment. ++*/ ++class TiXmlComment : public TiXmlNode ++{ ++public: ++ /// Constructs an empty comment. ++ TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} ++ TiXmlComment( const TiXmlComment& ); ++ void operator=( const TiXmlComment& base ); ++ ++ virtual ~TiXmlComment() {} ++ ++ /// Returns a copy of this Comment. ++ virtual TiXmlNode* Clone() const; ++ /// Write this Comment to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: at the ! of the !-- ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlComment* target ) const; ++ ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** XML text. Contained in an element. ++*/ ++class TiXmlText : public TiXmlNode ++{ ++ friend class TiXmlElement; ++public: ++ /// Constructor. ++ TiXmlText (const char * initValue) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ virtual ~TiXmlText() {} ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ #endif ++ ++ TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlText& base ) { base.CopyTo( this ); } ++ ++ /// Write this text object to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected : ++ /// [internal use] Creates a new Element and returns it. ++ virtual TiXmlNode* Clone() const; ++ void CopyTo( TiXmlText* target ) const; ++ ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ bool Blank() const; // returns true if all white space and new lines ++ // [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++}; ++ ++ ++/** In correct XML the declaration is the first entry in the file. ++ @verbatim ++ <?xml version="1.0" standalone="yes"?> ++ @endverbatim ++ ++ TinyXml will happily read or write files without a declaration, ++ however. There are 3 possible attributes to the declaration: ++ version, encoding, and standalone. ++ ++ Note: In this version of the code, the attributes are ++ handled as special cases, not generic attributes, simply ++ because there can only be at most 3 and they are always the same. ++*/ ++class TiXmlDeclaration : public TiXmlNode ++{ ++public: ++ /// Construct an empty declaration. ++ TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} ++ ++#ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ); ++#endif ++ ++ /// Construct. ++ TiXmlDeclaration( const char* _version, ++ const char* _encoding, ++ const char* _standalone ); ++ ++ TiXmlDeclaration( const TiXmlDeclaration& copy ); ++ void operator=( const TiXmlDeclaration& copy ); ++ ++ virtual ~TiXmlDeclaration() {} ++ ++ /// Version. Will return an empty string if none was found. ++ const char *Version() const { return version.c_str (); } ++ /// Encoding. Will return an empty string if none was found. ++ const char *Encoding() const { return encoding.c_str (); } ++ /// Is this a standalone document? ++ const char *Standalone() const { return standalone.c_str (); } ++ ++ /// Creates a copy of this Declaration and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this declaration to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlDeclaration* target ) const; ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ ++private: ++ ++ TIXML_STRING version; ++ TIXML_STRING encoding; ++ TIXML_STRING standalone; ++}; ++ ++ ++/** Any tag that tinyXml doesn't recognize is saved as an ++ unknown. It is a tag of text, but should not be modified. ++ It will be written back to the XML, unchanged, when the file ++ is saved. ++ ++ DTD tags get thrown into TiXmlUnknowns. ++*/ ++class TiXmlUnknown : public TiXmlNode ++{ ++public: ++ TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} ++ virtual ~TiXmlUnknown() {} ++ ++ TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } ++ ++ /// Creates a copy of this Unknown and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this Unknown to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlUnknown* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** Always the top level node. A document binds together all the ++ XML pieces. It can be saved, loaded, and printed to the screen. ++ The 'value' of a document node is the xml file name. ++*/ ++class TiXmlDocument : public TiXmlNode ++{ ++public: ++ /// Create an empty document, that has no name. ++ TiXmlDocument(); ++ /// Create a document with a name. The name of the document is also the filename of the xml. ++ TiXmlDocument( const char * documentName ); ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDocument( const std::string& documentName ); ++ #endif ++ ++ TiXmlDocument( const TiXmlDocument& copy ); ++ void operator=( const TiXmlDocument& copy ); ++ ++ virtual ~TiXmlDocument() {} ++ ++ /** Load a file using the current document value. ++ Returns true if successful. Will delete any existing ++ document data before loading. ++ */ ++ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the current document value. Returns true if successful. ++ bool SaveFile() const; ++ /// Load a file using the given filename. Returns true if successful. ++ bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the given filename. Returns true if successful. ++ bool SaveFile( const char * filename ) const; ++ ++ #ifdef TIXML_USE_STL ++ bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && LoadFile( f.buffer, encoding )); ++ } ++ bool SaveFile( const std::string& filename ) const ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && SaveFile( f.buffer )); ++ } ++ #endif ++ ++ /** Parse the given null terminated block of xml data. Passing in an encoding to this ++ method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml ++ to use that encoding, regardless of what TinyXml might otherwise try to detect. ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ ++ /** Get the root element -- the only top level element -- of the document. ++ In well formed XML, there should only be one. TinyXml is tolerant of ++ multiple elements at the document level. ++ */ ++ TiXmlElement* RootElement() const { return FirstChildElement(); } ++ ++ /** If an error occurs, Error will be set to true. Also, ++ - The ErrorId() will contain the integer identifier of the error (not generally useful) ++ - The ErrorDesc() method will return the name of the error. (very useful) ++ - The ErrorRow() and ErrorCol() will return the location of the error (if known) ++ */ ++ bool Error() const { return error; } ++ ++ /// Contains a textual (english) description of the error if one occurs. ++ const char * ErrorDesc() const { return errorDesc.c_str (); } ++ ++ /** Generally, you probably want the error string ( ErrorDesc() ). But if you ++ prefer the ErrorId, this function will fetch it. ++ */ ++ const int ErrorId() const { return errorId; } ++ ++ /** Returns the location (if known) of the error. The first column is column 1, ++ and the first row is row 1. A value of 0 means the row and column wasn't applicable ++ (memory errors, for example, have no row/column) or the parser lost the error. (An ++ error in the error reporting, in that case.) ++ ++ @sa SetTabSize, Row, Column ++ */ ++ int ErrorRow() { return errorLocation.row+1; } ++ int ErrorCol() { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() ++ ++ /** By calling this method, with a tab size ++ greater than 0, the row and column of each node and attribute is stored ++ when the file is loaded. Very useful for tracking the DOM back in to ++ the source file. ++ ++ The tab size is required for calculating the location of nodes. If not ++ set, the default of 4 is used. The tabsize is set per document. Setting ++ the tabsize to 0 disables row/column tracking. ++ ++ Note that row and column tracking is not supported when using operator>>. ++ ++ The tab size needs to be enabled before the parse or load. Correct usage: ++ @verbatim ++ TiXmlDocument doc; ++ doc.SetTabSize( 8 ); ++ doc.Load( "myfile.xml" ); ++ @endverbatim ++ ++ @sa Row, Column ++ */ ++ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } ++ ++ int TabSize() const { return tabsize; } ++ ++ /** If you have handled the error, it can be reset with this call. The error ++ state is automatically cleared if you Parse a new XML block. ++ */ ++ void ClearError() { error = false; ++ errorId = 0; ++ errorDesc = ""; ++ errorLocation.row = errorLocation.col = 0; ++ //errorLocation.last = 0; ++ } ++ ++ /** Dump the document to standard out. */ ++ void Print() const { Print( stdout, 0 ); } ++ ++ /// Print this Document to a FILE stream. ++ virtual void Print( FILE* cfile, int depth = 0 ) const; ++ // [internal use] ++ void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++protected : ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ // [internal use] ++ virtual TiXmlNode* Clone() const; ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++ void CopyTo( TiXmlDocument* target ) const; ++ ++ bool error; ++ int errorId; ++ TIXML_STRING errorDesc; ++ int tabsize; ++ TiXmlCursor errorLocation; ++}; ++ ++ ++/** ++ A TiXmlHandle is a class that wraps a node pointer with null checks; this is ++ an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml ++ DOM structure. It is a separate utility class. ++ ++ Take an example: ++ @verbatim ++ <Document> ++ <Element attributeA = "valueA"> ++ <Child attributeB = "value1" /> ++ <Child attributeB = "value2" /> ++ </Element> ++ <Document> ++ @endverbatim ++ ++ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very ++ easy to write a *lot* of code that looks like: ++ ++ @verbatim ++ TiXmlElement* root = document.FirstChildElement( "Document" ); ++ if ( root ) ++ { ++ TiXmlElement* element = root->FirstChildElement( "Element" ); ++ if ( element ) ++ { ++ TiXmlElement* child = element->FirstChildElement( "Child" ); ++ if ( child ) ++ { ++ TiXmlElement* child2 = child->NextSiblingElement( "Child" ); ++ if ( child2 ) ++ { ++ // Finally do something useful. ++ @endverbatim ++ ++ And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity ++ of such code. A TiXmlHandle checks for null pointers so it is perfectly safe ++ and correct to use: ++ ++ @verbatim ++ TiXmlHandle docHandle( &document ); ++ TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).Element(); ++ if ( child2 ) ++ { ++ // do something useful ++ @endverbatim ++ ++ Which is MUCH more concise and useful. ++ ++ It is also safe to copy handles - internally they are nothing more than node pointers. ++ @verbatim ++ TiXmlHandle handleCopy = handle; ++ @endverbatim ++ ++ What they should not be used for is iteration: ++ ++ @verbatim ++ int i=0; ++ while ( true ) ++ { ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).Element(); ++ if ( !child ) ++ break; ++ // do something ++ ++i; ++ } ++ @endverbatim ++ ++ It seems reasonable, but it is in fact two embedded while loops. The Child method is ++ a linear walk to find the element, so this code would iterate much more than it needs ++ to. Instead, prefer: ++ ++ @verbatim ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).Element(); ++ ++ for( child; child; child=child->NextSiblingElement() ) ++ { ++ // do something ++ } ++ @endverbatim ++*/ ++class TiXmlHandle ++{ ++public: ++ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. ++ TiXmlHandle( TiXmlNode* node ) { this->node = node; } ++ /// Copy constructor ++ TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } ++ TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } ++ ++ /// Return a handle to the first child node. ++ TiXmlHandle FirstChild() const; ++ /// Return a handle to the first child node with the given name. ++ TiXmlHandle FirstChild( const char * value ) const; ++ /// Return a handle to the first child element. ++ TiXmlHandle FirstChildElement() const; ++ /// Return a handle to the first child element with the given name. ++ TiXmlHandle FirstChildElement( const char * value ) const; ++ ++ /** Return a handle to the "index" child with the given name. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( const char* value, int index ) const; ++ /** Return a handle to the "index" child. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( int index ) const; ++ /** Return a handle to the "index" child element with the given name. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( const char* value, int index ) const; ++ /** Return a handle to the "index" child element. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( int index ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } ++ TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } ++ ++ TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } ++ TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } ++ #endif ++ ++ /// Return the handle as a TiXmlNode. This may return null. ++ TiXmlNode* Node() const { return node; } ++ /// Return the handle as a TiXmlElement. This may return null. ++ TiXmlElement* Element() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } ++ /// Return the handle as a TiXmlText. This may return null. ++ TiXmlText* Text() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } ++ /// Return the handle as a TiXmlUnknown. This may return null; ++ TiXmlUnknown* Unknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } ++ ++private: ++ TiXmlNode* node; ++}; ++ ++ ++#endif ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/tinyxmlparser.c vdr-1.7.0-extensions/tinyxmlparser.c +--- vdr-1.7.0/tinyxmlparser.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/tinyxmlparser.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,1494 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++#include <ctype.h> ++ ++//#define DEBUG_PARSER ++ ++// Note tha "PutString" hardcodes the same list. This ++// is less flexible than it appears. Changing the entries ++// or order will break putstring. ++TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = ++{ ++ { "&", 5, '&' }, ++ { "<", 4, '<' }, ++ { ">", 4, '>' }, ++ { """, 6, '\"' }, ++ { "'", 6, '\'' } ++}; ++ ++// Bunch of unicode info at: ++// http://www.unicode.org/faq/utf_bom.html ++// Including the basic of this table, which determines the #bytes in the ++// sequence from the lead byte. 1 placed for invalid sequences -- ++// although the result will be junk, pass it through as much as possible. ++// Beware of the non-characters in UTF-8: ++// ef bb bf (Microsoft "lead bytes") ++// ef bf be ++// ef bf bf ++ ++ ++ ++const int TiXmlBase::utf8ByteTable[256] = ++{ ++ // 0 1 2 3 4 5 6 7 8 9 a b c d e f ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 ++ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte ++ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid ++}; ++ ++ ++void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) ++{ ++ const unsigned long BYTE_MASK = 0xBF; ++ const unsigned long BYTE_MARK = 0x80; ++ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; ++ ++ if (input < 0x80) ++ *length = 1; ++ else if ( input < 0x800 ) ++ *length = 2; ++ else if ( input < 0x10000 ) ++ *length = 3; ++ else if ( input < 0x200000 ) ++ *length = 4; ++ else ++ { *length = 0; return; } // This code won't covert this correctly anyway. ++ ++ output += *length; ++ ++ // Scary scary fall throughs. ++ switch (*length) ++ { ++ case 4: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 3: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 2: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 1: ++ --output; ++ *output = (char)(input | FIRST_BYTE_MARK[*length]); ++ } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalpha( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalpha( anyByte ); ++// } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalnum( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalnum( anyByte ); ++// } ++} ++ ++ ++class TiXmlParsingData ++{ ++ friend class TiXmlDocument; ++ public: ++ void Stamp( const char* now, TiXmlEncoding encoding ); ++ ++ const TiXmlCursor& Cursor() { return cursor; } ++ ++ private: ++ // Only used by the document! ++ TiXmlParsingData( const char* start, int _tabsize, int row, int col ) ++ { ++ assert( start ); ++ stamp = start; ++ tabsize = _tabsize; ++ cursor.row = row; ++ cursor.col = col; ++ } ++ ++ TiXmlCursor cursor; ++ const char* stamp; ++ int tabsize; ++}; ++ ++ ++void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) ++{ ++ assert( now ); ++ ++ // Do nothing if the tabsize is 0. ++ if ( tabsize < 1 ) ++ { ++ return; ++ } ++ ++ // Get the current row, column. ++ int row = cursor.row; ++ int col = cursor.col; ++ const char* p = stamp; ++ assert( p ); ++ ++ while ( p < now ) ++ { ++ // Code contributed by Fletcher Dunn: (modified by lee) ++ switch (*p) { ++ case 0: ++ // We *should* never get here, but in case we do, don't ++ // advance past the terminating null character, ever ++ return; ++ ++ case '\r': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ // Eat the character ++ ++p; ++ ++ // Check for \r\n sequence, and treat this as a single character ++ if (*p == '\n') { ++ ++p; ++ } ++ break; ++ ++ case '\n': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ ++ // Eat the character ++ ++p; ++ ++ // Check for \n\r sequence, and treat this as a single ++ // character. (Yes, this bizarre thing does occur still ++ // on some arcane platforms...) ++ if (*p == '\r') { ++ ++p; ++ } ++ break; ++ ++ case '\t': ++ // Eat the character ++ ++p; ++ ++ // Skip to next tab stop ++ col = (col / tabsize + 1) * tabsize; ++ break; ++ ++ case (char)(0xef): ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( *(p+1) && *(p+2) ) ++ { ++ // In these cases, don't advance the column. These are ++ // 0-width spaces. ++ if ( *(p+1)==(char)(0xbb) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbe) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else ++ { p +=3; ++col; } // A normal character. ++ } ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ ++ default: ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // Eat the 1 to 4 byte utf8 character. ++ int step = TiXmlBase::utf8ByteTable[*((unsigned char*)p)]; ++ if ( step == 0 ) ++ step = 1; // Error case from bad encoding, but handle gracefully. ++ p += step; ++ ++ // Just advance one column, of course. ++ ++col; ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ } ++ } ++ cursor.row = row; ++ cursor.col = col; ++ assert( cursor.row >= -1 ); ++ assert( cursor.col >= -1 ); ++ stamp = p; ++ assert( stamp ); ++} ++ ++ ++const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) ++{ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ while ( *p ) ++ { ++ // Skip the stupid Microsoft UTF-8 Byte order marks ++ if ( *(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbb ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbe ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ ++ if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. ++ ++p; ++ else ++ break; ++ } ++ } ++ else ++ { ++ while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) ++ ++p; ++ } ++ ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++/*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ for( ;; ) ++ { ++ if ( !in->good() ) return false; ++ ++ int c = in->peek(); ++ // At this scope, we can't get to a document. So fail silently. ++ if ( !IsWhiteSpace( c ) || c <= 0 ) ++ return true; ++ ++ *tag += (char) in->get(); ++ } ++} ++ ++/*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ) ++{ ++ //assert( character > 0 && character < 128 ); // else it won't work in utf-8 ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == character ) ++ return true; ++ if ( c <= 0 ) // Silent failure: can't get document at this scope ++ return false; ++ ++ in->get(); ++ *tag += (char) c; ++ } ++ return false; ++} ++#endif ++ ++const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) ++{ ++ *name = ""; ++ assert( p ); ++ ++ // Names start with letters or underscores. ++ // Of course, in unicode, tinyxml has no idea what a letter *is*. The ++ // algorithm is generous. ++ // ++ // After that, they can be letters, underscores, numbers, ++ // hyphens, or colons. (Colons are valid ony for namespaces, ++ // but tinyxml can't tell namespaces from names.) ++ if ( p && *p ++ && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) ++ { ++ while( p && *p ++ && ( IsAlphaNum( (unsigned char ) *p, encoding ) ++ || *p == '_' ++ || *p == '-' ++ || *p == '.' ++ || *p == ':' ) ) ++ { ++ (*name) += *p; ++ ++p; ++ } ++ return p; ++ } ++ return 0; ++} ++ ++const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) ++{ ++ // Presume an entity, and pull it out. ++ TIXML_STRING ent; ++ int i; ++ *length = 0; ++ ++ if ( *(p+1) && *(p+1) == '#' && *(p+2) ) ++ { ++ unsigned long ucs = 0; ++ unsigned delta = 0; ++ unsigned mult = 1; ++ ++ if ( *(p+2) == 'x' ) ++ { ++ // Hexadecimal. ++ if ( !*(p+3) ) return 0; ++ ++ const char* q = p+3; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != 'x' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else if ( *q >= 'a' && *q <= 'f' ) ++ ucs += mult * (*q - 'a' + 10); ++ else if ( *q >= 'A' && *q <= 'F' ) ++ ucs += mult * (*q - 'A' + 10 ); ++ else ++ return 0; ++ mult *= 16; ++ --q; ++ } ++ } ++ else ++ { ++ // Decimal. ++ if ( !*(p+2) ) return 0; ++ ++ const char* q = p+2; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != '#' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else ++ return 0; ++ mult *= 10; ++ --q; ++ } ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // convert the UCS to UTF-8 ++ ConvertUTF32ToUTF8( ucs, value, length ); ++ } ++ else ++ { ++ *value = (char)ucs; ++ *length = 1; ++ } ++ return p + delta + 1; ++ } ++ ++ // Now try to match it. ++ for( i=0; i<NUM_ENTITY; ++i ) ++ { ++ if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) ++ { ++ assert( strlen( entity[i].str ) == entity[i].strLength ); ++ *value = entity[i].chr; ++ *length = 1; ++ return ( p + entity[i].strLength ); ++ } ++ } ++ ++ // So it wasn't an entity, its unrecognized, or something like that. ++ *value = *p; // Don't put back the last one, since we return it! ++ return p+1; ++} ++ ++ ++bool TiXmlBase::StringEqual( const char* p, ++ const char* tag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ) ++{ ++ assert( p ); ++ assert( tag ); ++ if ( !p || !*p ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ const char* q = p; ++ ++ if ( ignoreCase ) ++ { ++ while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) ++ return true; ++ } ++ else ++ { ++ while ( *q && *tag && *q == *tag ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? ++ return true; ++ } ++ return false; ++} ++ ++const char* TiXmlBase::ReadText( const char* p, ++ TIXML_STRING * text, ++ bool trimWhiteSpace, ++ const char* endTag, ++ bool caseInsensitive, ++ TiXmlEncoding encoding ) ++{ ++ *text = ""; ++ if ( !trimWhiteSpace // certain tags always keep whitespace ++ || !condenseWhiteSpace ) // if true, whitespace is always kept ++ { ++ // Keep all the white space. ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ++ ) ++ { ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ text->append( cArr, len ); ++ } ++ } ++ else ++ { ++ bool whitespace = false; ++ ++ // Remove leading white space: ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ) ++ { ++ if ( *p == '\r' || *p == '\n' ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else if ( IsWhiteSpace( *p ) ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else ++ { ++ // If we've found whitespace, add it before the ++ // new character. Any whitespace just becomes a space. ++ if ( whitespace ) ++ { ++ (*text) += ' '; ++ whitespace = false; ++ } ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ if ( len == 1 ) ++ (*text) += cArr[0]; // more efficient ++ else ++ text->append( cArr, len ); ++ } ++ } ++ } ++ return p + strlen( endTag ); ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ // The basic issue with a document is that we don't know what we're ++ // streaming. Read something presumed to be a tag (and hope), then ++ // identify it, and call the appropriate stream method on the tag. ++ // ++ // This "pre-streaming" will never read the closing ">" so the ++ // sub-tag can orient itself. ++ ++ if ( !StreamTo( in, '<', tag ) ) ++ { ++ SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ while ( in->good() ) ++ { ++ int tagIndex = (int) tag->length(); ++ while ( in->good() && in->peek() != '>' ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ break; ++ } ++ (*tag) += (char) c; ++ } ++ ++ if ( in->good() ) ++ { ++ // We now have something we presume to be a node of ++ // some sort. Identify it, and call the node to ++ // continue streaming. ++ TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); ++ ++ if ( node ) ++ { ++ node->StreamIn( in, tag ); ++ bool isElement = node->ToElement() != 0; ++ delete node; ++ node = 0; ++ ++ // If this is the root element, we're done. Parsing will be ++ // done by the >> operator. ++ if ( isElement ) ++ { ++ return; ++ } ++ } ++ else ++ { ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ } ++ } ++ // We should have returned sooner. ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++} ++ ++#endif ++ ++const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) ++{ ++ ClearError(); ++ ++ // Parse away, at the document level. Since a document ++ // contains nothing but other tags, most of what happens ++ // here is skipping white space. ++ if ( !p || !*p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ // Note that, for a document, this needs to come ++ // before the while space skip, so that parsing ++ // starts from the pointer we are given. ++ location.Clear(); ++ if ( prevData ) ++ { ++ location.row = prevData->cursor.row; ++ location.col = prevData->cursor.col; ++ } ++ else ++ { ++ location.row = 0; ++ location.col = 0; ++ } ++ TiXmlParsingData data( p, TabSize(), location.row, location.col ); ++ location = data.Cursor(); ++ ++ if ( encoding == TIXML_ENCODING_UNKNOWN ) ++ { ++ // Check for the Microsoft UTF-8 lead bytes. ++ if ( *(p+0) && *(p+0) == (char)(0xef) ++ && *(p+1) && *(p+1) == (char)(0xbb) ++ && *(p+2) && *(p+2) == (char)(0xbf) ) ++ { ++ encoding = TIXML_ENCODING_UTF8; ++ } ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ while ( p && *p ) ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, &data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ break; ++ } ++ ++ // Did we get encoding info? ++ if ( encoding == TIXML_ENCODING_UNKNOWN ++ && node->ToDeclaration() ) ++ { ++ TiXmlDeclaration* dec = node->ToDeclaration(); ++ const char* enc = dec->Encoding(); ++ assert( enc ); ++ ++ if ( *enc == 0 ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice ++ else ++ encoding = TIXML_ENCODING_LEGACY; ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ // All is well. ++ return p; ++} ++ ++void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ // The first error in a chain is more accurate - don't set again! ++ if ( error ) ++ return; ++ ++ assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); ++ error = true; ++ errorId = err; ++ errorDesc = errorString[ errorId ]; ++ ++ errorLocation.Clear(); ++ if ( pError && data ) ++ { ++ //TiXmlParsingData data( pError, prevData ); ++ data->Stamp( pError, encoding ); ++ errorLocation = data->Cursor(); ++ } ++} ++ ++ ++TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) ++{ ++ TiXmlNode* returnNode = 0; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if( !p || !*p || *p != '<' ) ++ { ++ return 0; ++ } ++ ++ TiXmlDocument* doc = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ ++ // What is this thing? ++ // - Elements start with a letter or underscore, but xml is reserved. ++ // - Comments: <!-- ++ // - Decleration: <?xml ++ // - Everthing else is unknown to tinyxml. ++ // ++ ++ const char* xmlHeader = { "<?xml" }; ++ const char* commentHeader = { "<!--" }; ++ const char* dtdHeader = { "<!" }; ++ ++ if ( StringEqual( p, xmlHeader, true, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Declaration\n" ); ++ #endif ++ returnNode = new TiXmlDeclaration(); ++ } ++ else if ( StringEqual( p, commentHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Comment\n" ); ++ #endif ++ returnNode = new TiXmlComment(); ++ } ++ else if ( StringEqual( p, dtdHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(1)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ else if ( IsAlpha( *(p+1), encoding ) ++ || *(p+1) == '_' ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Element\n" ); ++ #endif ++ returnNode = new TiXmlElement( "" ); ++ } ++ else ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(2)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ ++ if ( returnNode ) ++ { ++ // Set the parent, so it can report errors ++ returnNode->parent = this; ++ } ++ else ++ { ++ if ( doc ) ++ doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++ return returnNode; ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag) ++{ ++ // We're called with some amount of pre-parsing. That is, some of "this" ++ // element is in "tag". Go ahead and stream to the closing ">" ++ while( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c ; ++ ++ if ( c == '>' ) ++ break; ++ } ++ ++ if ( tag->length() < 3 ) return; ++ ++ // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. ++ // If not, identify and stream. ++ ++ if ( tag->at( tag->length() - 1 ) == '>' ++ && tag->at( tag->length() - 2 ) == '/' ) ++ { ++ // All good! ++ return; ++ } ++ else if ( tag->at( tag->length() - 1 ) == '>' ) ++ { ++ // There is more. Could be: ++ // text ++ // closing tag ++ // another node. ++ for ( ;; ) ++ { ++ StreamWhiteSpace( in, tag ); ++ ++ // Do we have text? ++ if ( in->good() && in->peek() != '<' ) ++ { ++ // Yep, text. ++ TiXmlText text( "" ); ++ text.StreamIn( in, tag ); ++ ++ // What follows text is a closing tag or another node. ++ // Go around again and figure it out. ++ continue; ++ } ++ ++ // We now have either a closing tag...or another node. ++ // We should be at a "<", regardless. ++ if ( !in->good() ) return; ++ assert( in->peek() == '<' ); ++ int tagIndex = tag->length(); ++ ++ bool closingTag = false; ++ bool firstCharFound = false; ++ ++ for( ;; ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->peek(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ if ( c == '>' ) ++ break; ++ ++ *tag += (char) c; ++ in->get(); ++ ++ if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) ++ { ++ firstCharFound = true; ++ if ( c == '/' ) ++ closingTag = true; ++ } ++ } ++ // If it was a closing tag, then read in the closing '>' to clean up the input stream. ++ // If it was not, the streaming will be done by the tag. ++ if ( closingTag ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ assert( c == '>' ); ++ *tag += (char) c; ++ ++ // We are done, once we've found our closing tag. ++ return; ++ } ++ else ++ { ++ // If not a closing tag, id it, and stream. ++ const char* tagloc = tag->c_str() + tagIndex; ++ TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); ++ if ( !node ) ++ return; ++ node->StreamIn( in, tag ); ++ delete node; ++ node = 0; ++ ++ // No return: go around from the beginning: text, closing tag, or node. ++ } ++ } ++ } ++} ++#endif ++ ++const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ TiXmlDocument* document = GetDocument(); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); ++ return 0; ++ } ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ ++ if ( *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); ++ return 0; ++ } ++ ++ p = SkipWhiteSpace( p+1, encoding ); ++ ++ // Read the name. ++ const char* pErr = p; ++ ++ p = ReadName( p, &value, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); ++ return 0; ++ } ++ ++ TIXML_STRING endTag ("</"); ++ endTag += value; ++ endTag += ">"; ++ ++ // Check for and read attributes. Also look for an empty ++ // tag or an end tag. ++ while ( p && *p ) ++ { ++ pErr = p; ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ if ( *p == '/' ) ++ { ++ ++p; ++ // Empty tag. ++ if ( *p != '>' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); ++ return 0; ++ } ++ return (p+1); ++ } ++ else if ( *p == '>' ) ++ { ++ // Done with attributes (if there were any.) ++ // Read the value -- which can include other ++ // elements -- read the end tag, and return. ++ ++p; ++ p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. ++ if ( !p || !*p ) ++ return 0; ++ ++ // We should find the end tag now ++ if ( StringEqual( p, endTag.c_str(), false, encoding ) ) ++ { ++ p += endTag.length(); ++ return p; ++ } ++ else ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); ++ return 0; ++ } ++ } ++ else ++ { ++ // Try to read an attribute: ++ TiXmlAttribute* attrib = new TiXmlAttribute(); ++ if ( !attrib ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); ++ return 0; ++ } ++ ++ attrib->SetDocument( document ); ++ const char* pErr = p; ++ p = attrib->Parse( p, data, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); ++ delete attrib; ++ return 0; ++ } ++ ++ // Handle the strange case of double attributes: ++ TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); ++ if ( node ) ++ { ++ node->SetValue( attrib->Value() ); ++ delete attrib; ++ return 0; ++ } ++ ++ attributeSet.Add( attrib ); ++ } ++ } ++ return p; ++} ++ ++ ++const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ ++ const char* pWithWhiteSpace = p; ++ // Read in text and elements in any order. ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ) ++ { ++ if ( *p != '<' ) ++ { ++ // Take what we have, make a text element. ++ TiXmlText* textNode = new TiXmlText( "" ); ++ ++ if ( !textNode ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); ++ return 0; ++ } ++ ++ if ( TiXmlBase::IsWhiteSpaceCondensed() ) ++ { ++ p = textNode->Parse( p, data, encoding ); ++ } ++ else ++ { ++ // Special case: we want to keep the white space ++ // so that leading spaces aren't removed. ++ p = textNode->Parse( pWithWhiteSpace, data, encoding ); ++ } ++ ++ if ( !textNode->Blank() ) ++ LinkEndChild( textNode ); ++ else ++ delete textNode; ++ } ++ else ++ { ++ // We hit a '<' ++ // Have we hit a new element or an end tag? ++ if ( StringEqual( p, "</", false, encoding ) ) ++ { ++ return p; ++ } ++ else ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ return 0; ++ } ++ } ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); ++ } ++ return p; ++} ++ ++ ++#ifdef TIXML_USE_STL ++void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ if ( !p || !*p || *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); ++ return 0; ++ } ++ ++p; ++ value = ""; ++ ++ while ( p && *p && *p != '>' ) ++ { ++ value += *p; ++ ++p; ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); ++ } ++ if ( *p == '>' ) ++ return p+1; ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ ++ if ( c == '>' ++ && tag->at( tag->length() - 2 ) == '-' ++ && tag->at( tag->length() - 3 ) == '-' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ value = ""; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ const char* startTag = "<!--"; ++ const char* endTag = "-->"; ++ ++ if ( !StringEqual( p, startTag, false, encoding ) ) ++ { ++ document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); ++ return 0; ++ } ++ p += strlen( startTag ); ++ p = ReadText( p, &value, false, endTag, false, encoding ); ++ return p; ++} ++ ++ ++const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) return 0; ++ ++ int tabsize = 4; ++ if ( document ) ++ tabsize = document->TabSize(); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ // Read the name, the '=' and the value. ++ const char* pErr = p; ++ p = ReadName( p, &name, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p || *p != '=' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ ++p; // skip '=' ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ const char* end; ++ ++ if ( *p == '\'' ) ++ { ++ ++p; ++ end = "\'"; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else if ( *p == '"' ) ++ { ++ ++p; ++ end = "\""; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else ++ { ++ // All attribute values should be in single or double quotes. ++ // But this is such a common error that the parser will try ++ // its best, even without them. ++ value = ""; ++ while ( p && *p // existence ++ && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace ++ && *p != '/' && *p != '>' ) // tag end ++ { ++ value += *p; ++ ++p; ++ } ++ } ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == '<' ) ++ return; ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ in->get(); ++ } ++} ++#endif ++ ++const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ value = ""; ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ bool ignoreWhite = true; ++ ++ const char* end = "<"; ++ p = ReadText( p, &value, ignoreWhite, end, false, encoding ); ++ if ( p ) ++ return p-1; // don't truncate the '<' ++ return 0; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) ++{ ++ p = SkipWhiteSpace( p, _encoding ); ++ // Find the beginning, find the end, and look for ++ // the stuff in-between. ++ TiXmlDocument* document = GetDocument(); ++ if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); ++ return 0; ++ } ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, _encoding ); ++ location = data->Cursor(); ++ } ++ p += 5; ++ ++ version = ""; ++ encoding = ""; ++ standalone = ""; ++ ++ while ( p && *p ) ++ { ++ if ( *p == '>' ) ++ { ++ ++p; ++ return p; ++ } ++ ++ p = SkipWhiteSpace( p, _encoding ); ++ if ( StringEqual( p, "version", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ version = attrib.Value(); ++ } ++ else if ( StringEqual( p, "encoding", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ encoding = attrib.Value(); ++ } ++ else if ( StringEqual( p, "standalone", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ standalone = attrib.Value(); ++ } ++ else ++ { ++ // Read over whatever it is. ++ while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++ ++p; ++ } ++ } ++ return 0; ++} ++ ++bool TiXmlText::Blank() const ++{ ++ for ( unsigned i=0; i<value.length(); i++ ) ++ if ( !IsWhiteSpace( value[i] ) ) ++ return false; ++ return true; ++} ++#endif /* SETUP */ +diff -ruNp vdr-1.7.0/transfer.c vdr-1.7.0-extensions/transfer.c +--- vdr-1.7.0/transfer.c 2007-01-05 11:45:28.000000000 +0100 ++++ vdr-1.7.0-extensions/transfer.c 2009-04-09 20:48:48.000000000 +0200 +@@ -19,7 +19,11 @@ cTransfer::cTransfer(tChannelID ChannelI + ,cThread("transfer") + { + ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer"); ++#ifdef USE_SYNCEARLY ++ remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, Setup.UseSyncEarlyPatch); ++#else + remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids); ++#endif /* SYNCEARLY */ + } + + cTransfer::~cTransfer() +diff -ruNp vdr-1.7.0/transfer.h vdr-1.7.0-extensions/transfer.h +--- vdr-1.7.0/transfer.h 2007-01-05 11:45:45.000000000 +0100 ++++ vdr-1.7.0-extensions/transfer.h 2009-04-09 20:48:48.000000000 +0200 +@@ -30,6 +30,10 @@ public: + }; + + class cTransferControl : public cControl { ++#ifdef USE_LIVEBUFFER ++friend class cLiveBufferControl; ++friend class cLiveBufferManager; ++#endif /* LIVEBUFFER */ + private: + cTransfer *transfer; + static cDevice *receiverDevice; +diff -ruNp vdr-1.7.0/vdr.c vdr-1.7.0-extensions/vdr.c +--- vdr-1.7.0/vdr.c 2008-03-14 14:22:39.000000000 +0100 ++++ vdr-1.7.0-extensions/vdr.c 2009-04-09 20:48:48.000000000 +0200 +@@ -50,6 +50,9 @@ + #include "keys.h" + #include "libsi/si.h" + #include "lirc.h" ++#ifdef USE_LIVEBUFFER ++#include "livebuffer.h" ++#endif /* LIVEBUFFER */ + #include "menu.h" + #include "osdbase.h" + #include "plugin.h" +@@ -139,11 +142,18 @@ static bool SetKeepCaps(bool On) + return true; + } + ++#ifdef USE_SETTIME ++char *SetTime=NULL; ++#endif /* SETTIME */ ++ + static void SignalHandler(int signum) + { + isyslog("caught signal %d", signum); + switch (signum) { + case SIGPIPE: ++#ifdef USE_EM84XX ++ case SIGINT: ++#endif /* EM84XX */ + break; + case SIGHUP: + LastSignal = signum; +@@ -164,6 +174,10 @@ static void Watchdog(int signum) + exit(1); + } + ++#ifdef USE_CMDRECCMDI18N ++const char *ConfigDirectory = NULL; ++#endif /* CMDRECCMDI18N */ ++ + int main(int argc, char *argv[]) + { + // Save terminal settings: +@@ -188,8 +202,11 @@ int main(int argc, char *argv[]) + bool UserDump = false; + int SVDRPport = DEFAULTSVDRPPORT; + const char *AudioCommand = NULL; ++#ifndef USE_CMDRECCMDI18N + const char *ConfigDirectory = NULL; ++#endif /* CMDRECCMDI18N */ + const char *EpgDataFileName = DEFAULTEPGDATAFILENAME; ++ bool DisplayExtensions = false; + bool DisplayHelp = false; + bool DisplayVersion = false; + bool DaemonMode = false; +@@ -221,10 +238,14 @@ int main(int argc, char *argv[]) + + static struct option long_options[] = { + { "audio", required_argument, NULL, 'a' }, ++#ifdef USE_LIVEBUFFER ++ { "buffer", required_argument, NULL, 'b' }, ++#endif /* LIVEBUFFER */ + { "config", required_argument, NULL, 'c' }, + { "daemon", no_argument, NULL, 'd' }, + { "device", required_argument, NULL, 'D' }, + { "epgfile", required_argument, NULL, 'E' }, ++ { "extensions",no_argument, NULL, 'e' | 0x100 }, + { "grab", required_argument, NULL, 'g' }, + { "help", no_argument, NULL, 'h' }, + { "lib", required_argument, NULL, 'L' }, +@@ -239,6 +260,9 @@ int main(int argc, char *argv[]) + { "record", required_argument, NULL, 'r' }, + { "shutdown", required_argument, NULL, 's' }, + { "terminal", required_argument, NULL, 't' }, ++#ifdef USE_SETTIME ++ { "timeset", required_argument, NULL, 'T' }, ++#endif /* SETTIME */ + { "user", required_argument, NULL, 'u' }, + { "userdump", no_argument, NULL, 'u' | 0x100 }, + { "version", no_argument, NULL, 'V' }, +@@ -249,10 +273,28 @@ int main(int argc, char *argv[]) + }; + + int c; ++#ifdef USE_SETTIME ++#ifdef USE_LIVEBUFFER ++ while ((c = getopt_long(argc, argv, "a::b:c:dD:E:g:hl:L:mp:P:r:s:t:T:u:v:Vw:", long_options, NULL)) != -1) { ++#else ++ while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:T:u:v:Vw:", long_options, NULL)) != -1) { ++#endif /* LIVEBUFFER */ ++#else ++#ifdef USE_LIVEBUFFER ++ while ((c = getopt_long(argc, argv, "a::b:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) { ++#else + while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) { ++#endif /* LIVEBUFFER */ ++#endif /* SETTIME */ + switch (c) { + case 'a': AudioCommand = optarg; + break; ++#ifdef USE_LIVEBUFFER ++ case 'b': BufferDirectory = optarg; ++ while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') ++ optarg[strlen(optarg) - 1] = 0; ++ break; ++#endif /* LIVEBUFFER */ + case 'c': ConfigDirectory = optarg; + break; + case 'd': DaemonMode = true; break; +@@ -266,6 +308,9 @@ int main(int argc, char *argv[]) + fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg); + return 2; + break; ++ case 'e' | 0x100: ++ DisplayExtensions = true; ++ break; + case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL); + break; + case 'g': cSVDRP::SetGrabImageDir(*optarg != '-' ? optarg : NULL); +@@ -337,6 +382,10 @@ int main(int argc, char *argv[]) + break; + case 's': ShutdownHandler.SetShutdownCommand(optarg); + break; ++#ifdef USE_SETTIME ++ case 'T': SetTime = strdup(optarg); ++ break; ++#endif /* SETTIME */ + case 't': Terminal = optarg; + if (access(Terminal, R_OK | W_OK) < 0) { + fprintf(stderr, "vdr: can't access terminal: %s\n", Terminal); +@@ -397,11 +446,16 @@ int main(int argc, char *argv[]) + if (DisplayHelp) { + printf("Usage: vdr [OPTIONS]\n\n" // for easier orientation, this is column 80| + " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n" ++#ifdef USE_LIVEBUFFER ++ " -b DIR, --buffer=DIR use DIR as LiveBuffer directory (default is to write\n" ++ " it to the video directory)\n" ++#endif /* LIVEBUFFER */ + " -c DIR, --config=DIR read config files from DIR (default: %s)\n" + " -d, --daemon run in daemon mode\n" + " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" + " there may be several -D options (default: all DVB\n" + " devices will be used)\n" ++ " --extensions print patchlevel and exit\n" + " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n" + " '%s' in the video directory)\n" + " '-E-' disables this\n" +@@ -432,6 +486,9 @@ int main(int argc, char *argv[]) + " -r CMD, --record=CMD call CMD before and after a recording\n" + " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" + " -t TTY, --terminal=TTY controlling tty\n" ++#ifdef USE_SETTIME ++ " -T CMD, --timeset=CMD call CMD to set the system time\n" ++#endif /* SETTIME */ + " -u USER, --user=USER run as user USER; only applicable if started as\n" + " root\n" + " --userdump allow coredumps if -u is given (debugging)\n" +@@ -475,6 +532,213 @@ int main(int argc, char *argv[]) + return 0; + } + ++ if (DisplayExtensions) { ++ printf("VDR %s\n", VDRVERSION); ++ printf("VDREXTENSIONS %d\n", VDREXTENSIONS); ++ ++#ifdef USE_ANALOGTV ++ printf(" ANALOGTV\n"); ++#endif /* ANALOGTV */ ++ ++#ifdef USE_ATSC ++ printf(" ATSC\n"); ++#endif /* ATSC */ ++ ++#ifdef USE_CHANNELSCAN ++ printf(" CHANNELSCAN\n"); ++#endif /* CHANNELSCAN */ ++ ++#ifdef USE_CMDRECCMDI18N ++ printf(" CMDRECCMDI18N\n"); ++#endif /* CMDRECCMDI18N */ ++ ++#ifdef USE_CMDSUBMENU ++ printf(" CMDSUBMENU %d\n", CMDSUBMENUVERSNUM); ++#endif /* CMDSUBMENU */ ++ ++#ifdef USE_CUTTERLIMIT ++ printf(" CUTTERLIMIT\n"); ++#endif /* CUTTERLIMIT */ ++ ++#ifdef USE_CUTTERQUEUE ++ printf(" CUTTERQUEUE\n"); ++#endif /* CUTTERQUEUE */ ++ ++#ifdef USE_CUTTIME ++ printf(" CUTTIME\n"); ++#endif /* CUTTIME */ ++ ++#ifdef USE_DDEPGENTRY ++ printf(" DDEPGENTRY\n"); ++#endif /* DDEPGENTRY */ ++ ++#ifdef USE_DELTIMESHIFTREC ++ printf(" DELTIMESHIFTREC\n"); ++#endif /* DELTIMESHIFTREC */ ++ ++#ifdef USE_DOLBYINREC ++ printf(" DOLBYINREC\n"); ++#endif /* DOLBYINREC */ ++ ++#ifdef USE_DVBPLAYER ++ printf(" DVBPLAYER\n"); ++#endif /* DVBPLAYER */ ++ ++#ifdef USE_DVBSETUP ++ printf(" DVBSETUP\n"); ++#endif /* DVBSETUP */ ++ ++#ifdef USE_DVDARCHIVE ++ printf(" DVDARCHIVE\n"); ++#endif /* DVDARCHIVE */ ++ ++#ifdef USE_DVDCHAPJUMP ++ printf(" DVDCHAPJUMP\n"); ++#endif /* DVDCHAPJUMP */ ++ ++#ifdef USE_DVLRECSCRIPTADDON ++ printf(" DVLRECSCRIPTADDON\n"); ++#endif /* DVLRECSCRIPTADDON */ ++ ++#ifdef USE_DVLVIDPREFER ++ printf(" DVLVIDPREFER\n"); ++#endif /* DVLVIDPREFER */ ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++ printf(" DVLFRIENDLYFNAMES\n"); ++#endif /* DVLFRIENDLYFNAMES */ ++ ++#ifdef USE_EM84XX ++ printf(" EM84XX\n"); ++#endif /* EM84XX */ ++ ++#ifdef USE_GRAPHTFT ++ printf(" GRAPHTFT\n"); ++#endif /* GRAPHTFT */ ++ ++#ifdef USE_HARDLINKCUTTER ++ printf(" HARDLINKCUTTER\n"); ++#endif /* HARDLINKCUTTER */ ++ ++#ifdef USE_JUMPPLAY ++ printf(" JUMPPLAY %d\n", JUMPPLAYVERSNUM); ++#endif /* JUMPPLAY */ ++ ++#ifdef USE_LIEMIEXT ++ printf(" LIEMIEXT %d\n", LIEMIKUUTIO); ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_LIRCSETTINGS ++ printf(" LIRCSETTINGS\n"); ++#endif /* LIRCSETTINGS */ ++ ++#ifdef USE_LIVEBUFFER ++ printf(" LIVEBUFFER\n"); ++#endif /* LIVEBUFFER */ ++ ++#ifdef USE_LNBSHARE ++ printf(" LNBSHARE\n"); ++#endif /* LNBSHARE */ ++ ++#ifdef USE_MAINMENUHOOKS ++ printf(" MAINMENUHOOKS %3.1f\n", MAINMENUHOOKSVERSNUM); ++#endif /* MAINMENUHOOKS */ ++ ++#ifdef USE_MENUORG ++ printf(" MENUORG\n"); ++#endif /* MENUORG */ ++ ++#ifdef USE_NOEPG ++ printf(" NOEPG\n"); ++#endif /* NOEPG */ ++ ++#ifdef USE_OSDMAXITEMS ++ printf(" OSDMAXITEMS\n"); ++#endif /* OSDMAXITEMS */ ++ ++#ifdef USE_PARENTALRATING ++ printf(" PARENTALRATING\n"); ++#endif /* PARENTALRATING */ ++ ++#ifdef USE_PINPLUGIN ++ printf(" PINPLUGIN %d\n", PIN_PLUGIN_PATCH); ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_PLUGINAPI ++ printf(" PLUGINAPI\n"); ++#endif /* PLUGINAPI */ ++ ++#ifdef USE_PLUGINMISSING ++ printf(" PLUGINMISSING\n"); ++#endif /* PLUGINMISSING */ ++ ++#ifdef USE_PLUGINPARAM ++ printf(" PLUGINPARAM %d\n", PLUGINPARAMPATCHVERSNUM); ++#endif /* PLUGINPARAM */ ++ ++#ifdef USE_ROTOR ++ printf(" ROTOR\n"); ++#endif /* ROTOR */ ++ ++#ifdef USE_SETTIME ++ printf(" SETTIME\n"); ++#endif /* SETTIME */ ++ ++#ifdef USE_SETUP ++ printf(" SETUP\n"); ++#endif /* SETUP */ ++ ++#ifdef USE_SOFTOSD ++ printf(" SOFTOSD\n"); ++#endif /* SOFTOSD */ ++ ++#ifdef USE_SOURCECAPS ++ printf(" SOURCECAPS\n"); ++#endif /* SOURCECAPS */ ++ ++#ifdef USE_SORTRECORDS ++ printf(" SORTRECORDS\n"); ++#endif /* SORTRECORDS */ ++ ++#ifdef USE_STREAMDEVEXT ++ printf(" STREAMDEVEXT\n"); ++#endif /* STREAMDEVEXT */ ++ ++#ifdef USE_SYNCEARLY ++ printf(" SYNCEARLY\n"); ++#endif /* SYNCEARLY */ ++ ++#ifdef USE_TIMERCMD ++ printf(" TIMERCMD\n"); ++#endif /* TIMERCMD */ ++ ++#ifdef USE_TIMERINFO ++ printf(" TIMERINFO\n"); ++#endif /* TIMERINFO */ ++ ++#ifdef USE_TTXTSUBS ++ printf(" TTXTSUBS\n"); ++#endif /* TTXTSUBS*/ ++ ++#ifdef USE_VALIDINPUT ++ printf(" VALIDINPUT\n"); ++#endif /* VALIDINPUT */ ++ ++#ifdef USE_VOLCTRL ++ printf(" VOLCTRL\n"); ++#endif /* VOLCTRL */ ++ ++#ifdef USE_WAREAGLEICON ++ printf(" WAREAGLEICON\n"); ++#endif /* WAREAGLEICON */ ++ ++#ifdef USE_YAEPG ++ printf(" YAEPG\n"); ++#endif /* YAEPG */ ++ ++ return 0; ++ } ++ + // Log file: + + if (SysLogLevel > 0) +@@ -554,6 +818,11 @@ int main(int argc, char *argv[]) + if (!PluginManager.LoadPlugins(true)) + EXIT(2); + ++#ifdef USE_LIVEBUFFER ++ if (!BufferDirectory) ++ BufferDirectory = VideoDirectory; ++#endif /* LIVEBUFFER */ ++ + // Configuration data: + + if (!ConfigDirectory) +@@ -567,8 +836,20 @@ int main(int argc, char *argv[]) + Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC) && + Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true) && + Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")) && ++#ifdef USE_CMDRECCMDI18N ++ LoadCommandsI18n(Commands,AddDirectory(ConfigDirectory, "commands.conf"), true) && ++ LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory, "reccmds.conf"), true) && ++#else + Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true) && + RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) && ++#endif /* CMDRECCMDI18N */ ++#ifdef USE_TIMERCMD ++#ifdef USE_CMDRECCMDI18N ++ LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true) && ++#else ++ TimerCommands.Load(AddDirectory(ConfigDirectory, "timercmds.conf"), true) && ++#endif /* CMDRECCMDI18N */ ++#endif /* TIMERCMD */ + SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) && + Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) && + KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true) +@@ -731,7 +1012,11 @@ int main(int argc, char *argv[]) + // Make sure we have a visible programme in case device usage has changed: + if (!EITScanner.Active() && cDevice::PrimaryDevice()->HasDecoder() && !cDevice::PrimaryDevice()->HasProgramme()) { + static time_t lastTime = 0; ++#ifdef USE_CHANNELSCAN ++ if (!scanning_on_receiving_device && (!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { ++#else + if ((!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { // !Menu to avoid interfering with the CAM if a CAM menu is open ++#endif /* CHANNELSCAN */ + cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel()); + if (Channel && (Channel->Vpid() || Channel->Apid(0))) { + if (!Channels.SwitchTo(cDevice::CurrentChannel()) // try to switch to the original channel... +@@ -787,8 +1072,17 @@ int main(int argc, char *argv[]) + } + // Channel display: + if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) { ++#ifdef USE_LIVEBUFFER ++ if (!Menu) { ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (!Menu) ++#endif /* LIVEBUFFER */ + Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0); ++#ifdef USE_LIVEBUFFER ++ } ++#endif /* LIVEBUFFER */ + LastChannel = cDevice::CurrentChannel(); + LastChannelChanged = Now; + } +@@ -903,9 +1197,19 @@ int main(int argc, char *argv[]) + if (!Skins.IsOpen()) + Skins.ProcessQueuedMessages(); + // User Input: ++#ifdef USE_LIVEBUFFER ++ cOsdObject *Interact = Menu ? Menu : cControl::Control(true); ++#else + cOsdObject *Interact = Menu ? Menu : cControl::Control(); ++#endif /* LIVEBUFFER */ + eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse()); ++#ifdef USE_LIVEBUFFER ++ Interact = Menu ? Menu : cControl::Control(); ++#endif /* LIVEBUFFER */ + if (ISREALKEY(key)) { ++#ifdef USE_PINPLUGIN ++ cStatus::MsgUserAction(key, Interact); ++#endif /* PINPLUGIN */ + EITScanner.Activity(); + // Cancel shutdown countdown: + if (ShutdownHandler.countdown) +@@ -922,9 +1226,17 @@ int main(int argc, char *argv[]) + bool WasMenu = Interact && Interact->IsMenu(); + if (Menu) + DELETE_MENU; ++#ifdef USE_LIVEBUFFER ++ else if (cControl::Control(true)) { ++#else + else if (cControl::Control()) { ++#endif /* LIVEBUFFER */ + if (cOsd::IsOpen()) ++#ifdef USE_LIVEBUFFER ++ cControl::Control(true)->Hide(); ++#else + cControl::Control()->Hide(); ++#endif /* LIVEBUFFER */ + else + WasOpen = false; + } +@@ -957,12 +1269,21 @@ int main(int argc, char *argv[]) + } + break; + // Direct main menu functions: ++#ifdef USE_LIVEBUFFER ++ #define DirectMainFunction(function)\ ++ DELETE_MENU;\ ++ if (cControl::Control(true))\ ++ cControl::Control(true)->Hide();\ ++ Menu = new cMenuMain(function);\ ++ key = kNone; // nobody else needs to see this key ++#else + #define DirectMainFunction(function)\ + DELETE_MENU;\ + if (cControl::Control())\ + cControl::Control()->Hide();\ + Menu = new cMenuMain(function);\ + key = kNone; // nobody else needs to see this key ++#endif /* LIVEBUFFER */ + case kSchedule: DirectMainFunction(osSchedule); break; + case kChannels: DirectMainFunction(osChannels); break; + case kTimers: DirectMainFunction(osTimers); break; +@@ -974,14 +1295,25 @@ int main(int argc, char *argv[]) + const char *PluginName = cRemote::GetPlugin(); + if (PluginName) { + DELETE_MENU; ++#ifdef USE_LIVEBUFFER ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (cControl::Control()) + cControl::Control()->Hide(); ++#endif /* LIVEBUFFER */ + cPlugin *plugin = cPluginManager::GetPlugin(PluginName); + if (plugin) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(plugin)) { ++#endif /* PINPLUGIN */ + Menu = plugin->MainMenuAction(); + if (Menu) + Menu->Show(); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + esyslog("ERROR: unknown plugin '%s'", PluginName); + } +@@ -993,8 +1325,17 @@ int main(int argc, char *argv[]) + case kChanUp: + case kChanDn|k_Repeat: + case kChanDn: ++#ifdef USE_LIVEBUFFER ++ if (!Interact) { ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (!Interact) ++#endif /* LIVEBUFFER */ + Menu = new cDisplayChannel(NORMALKEY(key)); ++#ifdef USE_LIVEBUFFER ++ } ++#endif /* LIVEBUFFER */ + else if (cDisplayChannel::IsOpen() || cControl::Control()) { + Interact->ProcessKey(key); + continue; +@@ -1024,8 +1365,13 @@ int main(int argc, char *argv[]) + break; + // Audio track control: + case kAudio: ++#ifdef USE_LIVEBUFFER ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#else + if (cControl::Control()) + cControl::Control()->Hide(); ++#endif /* LIVEBUFFER */ + if (!cDisplayTracks::IsOpen()) { + DELETE_MENU; + Menu = cDisplayTracks::Create(); +@@ -1048,7 +1394,11 @@ int main(int argc, char *argv[]) + break; + // Pausing live video: + case kPause: ++#ifdef USE_LIVEBUFFER ++ if (!cControl::Control() && !cLiveBufferManager::GetLiveBufferControl()) { ++#else + if (!cControl::Control()) { ++#endif /* LIVEBUFFER */ + DELETE_MENU; + if (!cRecordControls::PauseLiveVideo()) + Skins.Message(mtError, tr("No free DVB device to record!")); +@@ -1057,9 +1407,20 @@ int main(int argc, char *argv[]) + break; + // Instant recording: + case kRecord: ++#ifdef USE_LIVEBUFFER ++ if (!cControl::Control() && !cLiveBufferManager::GetLiveBufferControl()) { ++#else + if (!cControl::Control()) { ++#endif /* LIVEBUFFER */ ++#ifdef USE_STREAMDEVEXT ++ if (cRecordControls::Start()) { ++ Skins.Message(mtInfo, tr("Recording started")); ++ cStatus::MsgRecordingChange(NULL, scAdd); ++ } ++#else + if (cRecordControls::Start()) + Skins.Message(mtInfo, tr("Recording started")); ++#endif /* STREAMDEVEXT */ + key = kNone; // nobody else needs to see this key + } + break; +@@ -1109,14 +1470,42 @@ int main(int argc, char *argv[]) + state = osEnd; + } + switch (state) { ++#ifdef USE_LIVEBUFFER ++ case osPause: if (cLiveBufferManager::GetLiveBufferControl()) { ++ DELETE_MENU; ++ if (cControl::Control(true)) { ++ cControl::Control(true)->ProcessKey(kPlay); ++ cControl::Control(true)->ProcessKey(kPause); ++ } ++ break; ++ } ++ DELETE_MENU; ++#else + case osPause: DELETE_MENU; ++#endif /* LIVEBUFFER */ + cControl::Shutdown(); // just in case + if (!cRecordControls::PauseLiveVideo()) + Skins.Message(mtError, tr("No free DVB device to record!")); + break; ++#ifdef USE_LIVEBUFFER ++ case osRecord: if (cLiveBufferManager::GetLiveBufferControl()) { ++ if (cControl::Control(true)) ++ cControl::Control(true)->ProcessKey(kRecord); ++ break; ++ } ++ DELETE_MENU; ++#else + case osRecord: DELETE_MENU; ++#endif /* LIVEBUFFER */ ++#ifdef USE_STREAMDEVEXT ++ if (cRecordControls::Start()) { ++ Skins.Message(mtInfo, tr("Recording started")); ++ cStatus::MsgRecordingChange(NULL, scAdd); ++ } ++#else + if (cRecordControls::Start()) + Skins.Message(mtInfo, tr("Recording started")); ++#endif /* STREAMDEVEXT */ + break; + case osRecordings: + DELETE_MENU; +@@ -1153,6 +1542,12 @@ int main(int argc, char *argv[]) + } + } + else { ++#ifdef USE_LIVEBUFFER ++ eOSState state = osUnknown; ++ if (cLiveBufferManager::GetLiveBufferControl()) ++ state = cLiveBufferManager::GetLiveBufferControl()->ProcessKey(key); ++ if (state == osUnknown) { ++#endif /* LIVEBUFFER */ + // Key functions in "normal" viewing mode: + if (key != kNone && KeyMacros.Get(key)) { + cRemote::PutMacro(key); +@@ -1167,13 +1562,26 @@ int main(int argc, char *argv[]) + Channels.SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]); + break; + } ++#ifdef USE_VOLCTRL ++ // Left/Right volume control ++#else + // Direct Channel Select: + case k1 ... k9: + // Left/Right rotates through channel groups: ++#endif /* VOLCTRL */ + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && Setup.LRChannelGroups < 2) { ++ cRemote::Put(NORMALKEY(key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++ // Direct Channel Select: ++ case k1 ... k9: ++#endif /* VOLCTRL */ + // Previous/Next rotates through channel groups: + case kPrev|k_Repeat: + case kPrev: +@@ -1184,6 +1592,10 @@ int main(int argc, char *argv[]) + case kUp: + case kDown|k_Repeat: + case kDown: ++#ifdef USE_LIVEBUFFER ++ if (cControl::Control(true)) ++ cControl::Control(true)->Hide(); ++#endif /* LIVEBUFFER */ + Menu = new cDisplayChannel(NORMALKEY(key)); + break; + // Viewing Control: +@@ -1191,13 +1603,22 @@ int main(int argc, char *argv[]) + // Instant resume of the last viewed recording: + case kPlay: + if (cReplayControl::LastReplayed()) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(0, cReplayControl::LastReplayed(), 0, false) == false) { ++#endif /* PINPLUGIN */ + cControl::Shutdown(); + cControl::Launch(new cReplayControl); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + break; + default: break; + } + } ++#ifdef USE_LIVEBUFFER ++ } ++#endif /* LIVEBUFFER */ + if (!Menu) { + if (!InhibitEpgScan) + EITScanner.Process(); +@@ -1267,6 +1688,9 @@ Exit: + signal(SIGPIPE, SIG_DFL); + signal(SIGALRM, SIG_DFL); + ++#ifdef USE_LIVEBUFFER ++ cLiveBufferManager::Shutdown(); ++#endif /* LIVEBUFFER */ + PluginManager.StopPlugins(); + cRecordControls::Shutdown(); + cCutter::Stop(); +diff -ruNp vdr-1.7.0/vdrttxtsubshooks.c vdr-1.7.0-extensions/vdrttxtsubshooks.c +--- vdr-1.7.0/vdrttxtsubshooks.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/vdrttxtsubshooks.c 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,46 @@ ++#ifdef USE_TTXTSUBS ++ ++#include <stdlib.h> ++#include <stdio.h> ++#include <stdint.h> ++ ++#include "vdrttxtsubshooks.h" ++ ++// XXX Really should be a list... ++static cVDRTtxtsubsHookListener *gListener; ++ ++// ------ class cVDRTtxtsubsHookProxy ------ ++ ++class cVDRTtxtsubsHookProxy : public cVDRTtxtsubsHookListener ++{ ++ public: ++ virtual void HideOSD(void) { if(gListener) gListener->HideOSD(); }; ++ virtual void ShowOSD(void) { if(gListener) gListener->ShowOSD(); }; ++ virtual void PlayerTeletextData(uint8_t *p, int length) ++ { if(gListener) gListener->PlayerTeletextData(p, length); }; ++ virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch) ++ { if(gListener) return gListener->NewTtxtSubsRecorder(dev, ch); else return NULL; }; ++}; ++ ++ ++// ------ class cVDRTtxtsubsHookListener ------ ++ ++cVDRTtxtsubsHookListener::~cVDRTtxtsubsHookListener() ++{ ++ gListener = 0; ++} ++ ++void cVDRTtxtsubsHookListener::HookAttach(void) ++{ ++ gListener = this; ++ //printf("cVDRTtxtsubsHookListener::HookAttach\n"); ++} ++ ++static cVDRTtxtsubsHookProxy gProxy; ++ ++cVDRTtxtsubsHookListener *cVDRTtxtsubsHookListener::Hook(void) ++{ ++ return &gProxy; ++} ++ ++#endif /* TTXTSUBS */ +diff -ruNp vdr-1.7.0/vdrttxtsubshooks.h vdr-1.7.0-extensions/vdrttxtsubshooks.h +--- vdr-1.7.0/vdrttxtsubshooks.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.0-extensions/vdrttxtsubshooks.h 2009-04-09 20:48:48.000000000 +0200 +@@ -0,0 +1,38 @@ ++#ifdef USE_TTXTSUBS ++ ++#ifndef __VDRTTXTSUBSHOOKS_H ++#define __VDRTTXTSUBSHOOKS_H ++ ++class cDevice; ++class cChannel; ++ ++#define VDRTTXTSUBSHOOKS ++ ++class cTtxtSubsRecorderBase { ++ public: ++ virtual ~cTtxtSubsRecorderBase() {}; ++ ++ // returns a PES packet if there is data to add to the recording ++ virtual uint8_t *GetPacket(uint8_t **buf, size_t *len) { return NULL; }; ++ virtual void DeviceAttach(void) {}; ++}; ++ ++class cVDRTtxtsubsHookListener { ++ public: ++ cVDRTtxtsubsHookListener(void) {}; ++ virtual ~cVDRTtxtsubsHookListener(); ++ ++ void HookAttach(void); ++ ++ virtual void HideOSD(void) {}; ++ virtual void ShowOSD(void) {}; ++ virtual void PlayerTeletextData(uint8_t *p, int length) {}; ++ virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch) ++ { return NULL; }; ++ ++ // used by VDR to call hook listeners ++ static cVDRTtxtsubsHookListener *Hook(void); ++}; ++ ++#endif /* __VDRTTXTSUBSHOOKS_H */ ++#endif /* TTXTSUBS */ +diff -ruNp vdr-1.7.0/videodir.c vdr-1.7.0-extensions/videodir.c +--- vdr-1.7.0/videodir.c 2008-02-16 14:00:03.000000000 +0100 ++++ vdr-1.7.0-extensions/videodir.c 2009-04-09 20:48:48.000000000 +0200 +@@ -19,7 +19,17 @@ + #include "recording.h" + #include "tools.h" + ++#ifdef USE_HARDLINKCUTTER ++//#define HARDLINK_TEST_ONLY ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ ++#endif /* HARDLINKCUTTER */ ++ + const char *VideoDirectory = VIDEODIR; ++#ifdef USE_LIVEBUFFER ++const char *BufferDirectory = NULL; ++#endif /* LIVEBUFFER */ + + class cVideoDirectory { + private: +@@ -36,6 +46,11 @@ public: + bool Next(void); + void Store(void); + const char *Adjust(const char *FileName); ++#ifdef USE_DVLVIDPREFER ++ char *GetVidPath(int nVid); ++ bool GetPreferedVideoDir(void); ++ bool IsVidDirOK(int nVid, int *freeMB = NULL); ++#endif /* DVLVIDPREFER */ + }; + + cVideoDirectory::cVideoDirectory(void) +@@ -117,6 +132,9 @@ cUnbufferedFile *OpenVideoFile(const cha + if ((Flags & O_CREAT) != 0) { + cVideoDirectory Dir; + if (Dir.IsDistributed()) { ++#ifdef USE_DVLVIDPREFER ++ if (Setup.UseVidPrefer == 0) { ++#endif /* DVLVIDPREFER */ + // Find the directory with the most free space: + int MaxFree = Dir.FreeMB(); + while (Dir.Next()) { +@@ -126,14 +144,24 @@ cUnbufferedFile *OpenVideoFile(const cha + MaxFree = Free; + } + } ++#ifdef USE_DVLVIDPREFER ++ } ++ else Dir.GetPreferedVideoDir(); ++#endif /* DVLVIDPREFER */ + if (Dir.Stored()) { + ActualFileName = Dir.Adjust(FileName); + if (!MakeDirs(ActualFileName, false)) + return NULL; // errno has been set by MakeDirs() ++#ifdef USE_DVLVIDPREFER ++ if (strcmp(ActualFileName, FileName) != 0) { ++#endif /* DVLVIDPREFER */ + if (symlink(ActualFileName, FileName) < 0) { + LOG_ERROR_STR(FileName); + return NULL; + } ++#ifdef USE_DVLVIDPREFER ++ } ++#endif /* DVLVIDPREFER */ + ActualFileName = strdup(ActualFileName); // must survive Dir! + } + } +@@ -168,6 +196,125 @@ bool RemoveVideoFile(const char *FileNam + return RemoveFileOrDir(FileName, true); + } + ++#ifdef USE_HARDLINKCUTTER ++static bool StatNearestDir(const char *FileName, struct stat *Stat) ++{ ++ cString Name(FileName); ++ char *p; ++ while ((p = strrchr((const char*)Name + 1, '/')) != NULL) { ++ *p = 0; // truncate at last '/' ++ if (stat(Name, Stat) == 0) { ++ isyslog("StatNearestDir: Stating %s", (const char*)Name); ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool HardLinkVideoFile(const char *OldName, const char *NewName) ++{ ++ // Incoming name must be in base video directory: ++ if (strstr(OldName, VideoDirectory) != OldName) { ++ esyslog("ERROR: %s not in %s", OldName, VideoDirectory); ++ return false; ++ } ++ if (strstr(NewName, VideoDirectory) != NewName) { ++ esyslog("ERROR: %s not in %s", NewName, VideoDirectory); ++ return false; ++ } ++ ++ const char *ActualNewName = NewName; ++ cString ActualOldName(ReadLink(OldName), true); ++ ++ // Some safety checks: ++ struct stat StatOldName; ++ if (lstat(ActualOldName, &StatOldName) == 0) { ++ if (S_ISLNK(StatOldName.st_mode)) { ++ esyslog("HardLinkVideoFile: Failed to resolve symbolic link %s", (const char*)ActualOldName); ++ return false; ++ } ++ } ++ else { ++ esyslog("HardLinkVideoFile: lstat failed on %s", (const char*)ActualOldName); ++ return false; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", (const char*)ActualOldName, (int)StatOldName.st_dev); ++ ++ // Find the video directory where ActualOldName is located ++ ++ cVideoDirectory Dir; ++ struct stat StatDir; ++ if (!StatNearestDir(NewName, &StatDir)) { ++ esyslog("HardLinkVideoFile: stat failed on %s", NewName); ++ return false; ++ } ++ ++ isyslog("HardLinkVideoFile: %s is on %i", NewName, (int)StatDir.st_dev); ++ if (StatDir.st_dev != StatOldName.st_dev) { ++ // Not yet found. ++ ++ if (!Dir.IsDistributed()) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Search in video01 and upwards ++ bool found = false; ++ while (Dir.Next()) { ++ Dir.Store(); ++ const char *TmpNewName = Dir.Adjust(NewName); ++ if (StatNearestDir(TmpNewName, &StatDir) && StatDir.st_dev == StatOldName.st_dev) { ++ isyslog("HardLinkVideoFile: %s is on %i (match)", TmpNewName, (int)StatDir.st_dev); ++ ActualNewName = TmpNewName; ++ found = true; ++ break; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", TmpNewName, (int)StatDir.st_dev); ++ } ++ if (ActualNewName == NewName) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Looking good, we have a match. Create necessary folders. ++ if (!MakeDirs(ActualNewName, false)) ++ return false; ++ // There's no guarantee that the directory of ActualNewName ++ // is on the same device as the dir that StatNearestDir found. ++ // But worst case is that the link fails. ++ } ++ ++#ifdef HARDLINK_TEST_ONLY ++ // Do the hard link to *.vdr_ for testing only ++ char *name = NULL; ++ asprintf(&name, "%s_", ActualNewName); ++ link(ActualOldName, name); ++ free(name); ++ return false; ++#endif // HARDLINK_TEST_ONLY ++ ++ // Try creating the hard link ++ if (link(ActualOldName, ActualNewName) != 0) { ++ // Failed to hard link. Maybe not allowed on file system. ++ LOG_ERROR_STR(ActualNewName); ++ isyslog("HardLinkVideoFile: failed to hard link from %s to %s", (const char*)ActualOldName, ActualNewName); ++ return false; ++ } ++ ++ if (ActualNewName != NewName) { ++ // video01 and up. Do the remaining symlink ++ if (symlink(ActualNewName, NewName) < 0) { ++ LOG_ERROR_STR(NewName); ++ return false; ++ } ++ } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(Recordings.GetByName(NewName), scMod); ++#endif /* STREAMDEVEXT */ ++ return true; ++} ++#endif /* HARDLINKCUTTER */ ++ + bool VideoFileSpaceAvailable(int SizeMB) + { + cVideoDirectory Dir; +@@ -232,6 +379,129 @@ void RemoveEmptyVideoDirectories(void) + } while (Dir.Next()); + } + ++#ifdef USE_DVLVIDPREFER ++// returns path to nVid'th video directory or NULL if not existing ++char *cVideoDirectory::GetVidPath(int nVid) ++{ ++ char *b = strdup(VideoDirectory); ++ int l = strlen(b), di, n; ++ ++ while (l-- > 0 && isdigit(b[ l ])); ++ ++ l++; ++ di = strlen(b) - l; ++ ++ // di == number of digits ++ n = atoi(&b[ l ]); ++ if (n != 0) ++ return NULL; ++ ++ // add requested number to dir name ++ sprintf(&b[ l ], "%0*d", di, nVid); ++ ++ if (DirectoryOk(b) == true) ++ return b; ++ ++ free(b); ++ return NULL; ++} ++ ++// checks if a video dir is 'valid' ++bool cVideoDirectory::IsVidDirOK(int nVid, int *freeMB) ++{ ++ char *dn; ++ int fMB; ++ ++ if (nVid >= Setup.nVidPrefer) ++ return false; ++ ++ if (Setup.VidPreferSize[ nVid ] == -1) ++ return false; ++ ++ dn = GetVidPath(nVid); ++ if (dn == NULL) ++ return false; ++ ++ fMB = FreeDiskSpaceMB(dn, NULL); ++ if (freeMB != NULL) ++ *freeMB = fMB; ++ ++ free(dn); ++ ++ if (Setup.VidPreferSize[ nVid ] >= fMB) ++ return false; ++ return true; ++} ++ ++ ++// calculates which video dir to use ++bool cVideoDirectory::GetPreferedVideoDir(void) ++{ ++ cVideoDirectory d; ++ int nDirs = 1, ++ vidUse = Setup.nVidPrefer; ++ int i, top, topFree, x; ++ ++ if (name == NULL) ++ return(false); ++ ++ // count available video dirs ++ while (d.Next() == true) ++ nDirs++; ++ ++ if (vidUse > nDirs) ++ vidUse = nDirs; ++ ++ // check for prefered video dir ++ for (i = 0, top = -1, topFree = 0; i < vidUse; i++) { ++ if (IsVidDirOK(i, &x) == true) { ++ if (top == -1) { ++ // nothing set yet, use first 'ok' dir ++ top = i; ++ topFree = x; ++ } ++ else { ++ // check if we got a higher priority ++ if (Setup.VidPreferPrio[ i ] >= Setup.VidPreferPrio[ top ]) { ++ top = i; ++ topFree = x; ++ } ++ // check if we got same priority but more space ++ else if (Setup.VidPreferPrio[ i ] == Setup.VidPreferPrio[ top ] && x >= topFree) { ++ top = i; ++ topFree = x; ++ } ++ } ++ } ++ } ++ ++ if (top == -1) { ++ isyslog("VidPrefer: no prefered video directory could be determined!"); ++ ++ // something went wrong here... ++ // let VDR determine the video directory ++ int MaxFree = FreeMB(); ++ ++ while (Next()) { ++ int Free = FreeDiskSpaceMB(Name()); ++ ++ if (Free > MaxFree) { ++ Store(); ++ MaxFree = Free; ++ } ++ } ++ } ++ else { ++ isyslog("VidPrefer: prefered video directory '%d' set.", top); ++ if (stored != NULL) ++ free(stored); ++ stored = GetVidPath(top); ++ } ++ ++ return true; ++} ++#endif /* DVLVIDPREFER */ ++ + bool IsOnVideoDirectoryFileSystem(const char *FileName) + { + cVideoDirectory Dir; +diff -ruNp vdr-1.7.0/videodir.h vdr-1.7.0-extensions/videodir.h +--- vdr-1.7.0/videodir.h 2008-02-16 13:53:11.000000000 +0100 ++++ vdr-1.7.0-extensions/videodir.h 2009-04-09 20:48:48.000000000 +0200 +@@ -14,11 +14,17 @@ + #include "tools.h" + + extern const char *VideoDirectory; ++#ifdef USE_LIVEBUFFER ++extern const char *BufferDirectory; ++#endif /* LIVEBUFFER */ + + cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags); + int CloseVideoFile(cUnbufferedFile *File); + bool RenameVideoFile(const char *OldName, const char *NewName); + bool RemoveVideoFile(const char *FileName); ++#ifdef USE_HARDLINKCUTTER ++bool HardLinkVideoFile(const char *OldName, const char *NewName); ++#endif /* HARDLINKCUTTER */ + bool VideoFileSpaceAvailable(int SizeMB); + int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent + cString PrefixVideoFileName(const char *FileName, char Prefix); diff --git a/vdr/extensions/vdr-1.7.5_extensions.diff b/vdr/extensions/vdr-1.7.5_extensions.diff new file mode 100644 index 0000000..76341a9 --- /dev/null +++ b/vdr/extensions/vdr-1.7.5_extensions.diff @@ -0,0 +1,23830 @@ +diff -ruNp vdr-1.7.5/channels.c vdr-1.7.5-extensions/channels.c +--- vdr-1.7.5/channels.c 2009-04-10 13:29:55.000000000 +0200 ++++ vdr-1.7.5-extensions/channels.c 2009-04-12 13:37:59.000000000 +0200 +@@ -13,6 +13,9 @@ + #include "device.h" + #include "epg.h" + #include "timers.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ + + // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' + // format characters in order to allow any number of blanks after a numeric +@@ -188,6 +191,9 @@ cChannel::cChannel(void) + shortName = strdup(""); + provider = strdup(""); + portalName = strdup(""); ++#ifdef USE_PLUGINPARAM ++ pluginParam = strdup(""); ++#endif /* PLUGINPARAM */ + memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__); + inversion = INVERSION_AUTO; + bandwidth = 8000000; +@@ -211,6 +217,9 @@ cChannel::cChannel(const cChannel &Chann + shortName = NULL; + provider = NULL; + portalName = NULL; ++#ifdef USE_PLUGINPARAM ++ pluginParam = NULL; ++#endif /* PLUGINPARAM */ + schedule = NULL; + linkChannels = NULL; + refChannel = NULL; +@@ -239,6 +248,9 @@ cChannel::~cChannel() + free(shortName); + free(provider); + free(portalName); ++#ifdef USE_PLUGINPARAM ++ free(pluginParam); ++#endif /* PLUGINPARAM */ + } + + cChannel& cChannel::operator= (const cChannel &Channel) +@@ -247,6 +259,9 @@ cChannel& cChannel::operator= (const cCh + shortName = strcpyrealloc(shortName, Channel.shortName); + provider = strcpyrealloc(provider, Channel.provider); + portalName = strcpyrealloc(portalName, Channel.portalName); ++#ifdef USE_PLUGINPARAM ++ pluginParam = strcpyrealloc(pluginParam, Channel.pluginParam); ++#endif /* PLUGINPARAM */ + memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__); + return *this; + } +@@ -306,6 +321,9 @@ void cChannel::CopyTransponderData(const + guard = Channel->guard; + hierarchy = Channel->hierarchy; + rollOff = Channel->rollOff; ++#ifdef USE_PLUGINPARAM ++ if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, Channel->pluginParam); ++#endif /* PLUGINPARAM */ + } + } + +@@ -343,6 +361,24 @@ bool cChannel::SetSatTransponderData(int + return true; + } + ++#ifdef USE_PLUGINPARAM ++bool cChannel::SetPlugTransponderData(int Source, int Frequency, const char *PluginParam) ++{ ++ if (source != Source || frequency != Frequency || (strcmp(pluginParam, PluginParam) != 0)) { ++ if (Number()) { ++ dsyslog("changing transponder data of channel %d from %s:%d:%s to %s:%d:%s", Number(), *cSource::ToString(source), frequency, pluginParam, *cSource::ToString(Source), Frequency, PluginParam); ++ modification |= CHANNELMOD_TRANSP; ++ Channels.SetModified(); ++ } ++ source = Source; ++ frequency = Frequency; ++ pluginParam = strcpyrealloc(pluginParam, PluginParam); ++ schedule = NULL; ++ } ++ return true; ++} ++#endif /* PLUGINPARAM */ ++ + bool cChannel::SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH) + { + if (source != Source || frequency != Frequency || modulation != Modulation || srate != Srate || coderateH != CoderateH) { +@@ -413,6 +449,9 @@ void cChannel::SetName(const char *Name, + if (nn || ns || np) { + if (Number()) { + dsyslog("changing name of channel %d from '%s,%s;%s' to '%s,%s;%s'", Number(), name, shortName, provider, Name, ShortName, Provider); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(this, scMod); ++#endif /* STREAMDEVEXT */ + modification |= CHANNELMOD_NAME; + Channels.SetModified(); + } +@@ -438,6 +477,20 @@ void cChannel::SetPortalName(const char + } + } + ++#ifdef USE_PLUGINPARAM ++void cChannel::SetPluginParam(const char *PluginParam) ++{ ++ if (!isempty(PluginParam) && strcmp(pluginParam, PluginParam) != 0) { ++ if (Number()) { ++ dsyslog("changing plugin parameters of channel %d from '%s' to '%s'", Number(), pluginParam, PluginParam); ++ modification |= CHANNELMOD_TRANSP; ++ Channels.SetModified(); ++ } ++ pluginParam = strcpyrealloc(pluginParam, PluginParam); ++ } ++} ++#endif /* PLUGINPARAM */ ++ + #define STRDIFF 0x01 + #define VALDIFF 0x02 + +@@ -632,7 +685,11 @@ cString cChannel::ParametersToString(voi + if (isdigit(type)) + type = 'S'; + #define ST(s) if (strchr(s, type)) ++#ifdef USE_PLUGINPARAM ++ char buffer[256]; ++#else + char buffer[64]; ++#endif /* PLUGINPARAM */ + char *q = buffer; + *q = 0; + ST(" S ") q += sprintf(q, "%c", polarization); +@@ -646,6 +703,9 @@ cString cChannel::ParametersToString(voi + ST(" S ") q += PrintParameter(q, 'S', MapToUser(system, SystemValues)); + ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); + ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); ++#ifdef USE_PLUGINPARAM ++ ST("P ") snprintf(buffer, sizeof(buffer), "%s", pluginParam); ++#endif /* PLUGINPARAM */ + return buffer; + } + +@@ -674,7 +734,11 @@ static const char *SkipDigits(const char + + bool cChannel::StringToParameters(const char *s) + { ++#ifdef USE_PLUGINPARAM ++ while (s && *s && !IsPlug()) { ++#else + while (s && *s) { ++#endif /* PLUGINPARAM */ + switch (toupper(*s)) { + case 'A': s = SkipDigits(s); break; // for compatibility with the "multiproto" approach - may be removed in future versions + case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; +@@ -792,7 +856,11 @@ bool cChannel::Parse(const char *s) + dpids[0] = 0; + ok = false; + if (parambuf && sourcebuf && vpidbuf && apidbuf) { ++#ifdef USE_PLUGINPARAM ++ ok = ((source = cSource::FromString(sourcebuf)) >= 0) && StringToParameters(parambuf); ++#else + ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; ++#endif /* PLUGINPARAM */ + + char *p; + if ((p = strchr(vpidbuf, '=')) != NULL) { +@@ -887,6 +955,9 @@ bool cChannel::Parse(const char *s) + shortName = strcpyrealloc(shortName, p); + } + name = strcpyrealloc(name, namebuf); ++#ifdef USE_PLUGINPARAM ++ if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, parambuf); ++#endif /* PLUGINPARAM */ + + free(parambuf); + free(sourcebuf); +@@ -1132,6 +1203,9 @@ cChannel *cChannels::NewChannel(const cC + NewChannel->SetName(Name, ShortName, Provider); + Add(NewChannel); + ReNumber(); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NewChannel, scAdd); ++#endif /* STREAMDEVEXT */ + return NewChannel; + } + return NULL; +diff -ruNp vdr-1.7.5/channels.h vdr-1.7.5-extensions/channels.h +--- vdr-1.7.5/channels.h 2008-11-22 14:35:52.000000000 +0100 ++++ vdr-1.7.5-extensions/channels.h 2009-04-12 13:37:59.000000000 +0200 +@@ -116,6 +116,9 @@ private: + char *shortName; + char *provider; + char *portalName; ++#ifdef USE_PLUGINPARAM ++ char *pluginParam; ++#endif /* PLUGINPARAM */ + int __BeginData__; + int frequency; // MHz + int source; +@@ -171,6 +174,9 @@ public: + int Frequency(void) const { return frequency; } ///< Returns the actual frequency, as given in 'channels.conf' + int Transponder(void) const; ///< Returns the transponder frequency in MHz, plus the polarization in case of sat + static int Transponder(int Frequency, char Polarization); ///< builds the transponder from the given Frequency and Polarization ++#ifdef USE_PLUGINPARAM ++ const char *PluginParam(void) const { return pluginParam; } ++#endif /* PLUGINPARAM */ + int Source(void) const { return source; } + int Srate(void) const { return srate; } + int Vpid(void) const { return vpid; } +@@ -208,6 +214,9 @@ public: + int RollOff(void) const { return rollOff; } + const cLinkChannels* LinkChannels(void) const { return linkChannels; } + const cChannel *RefChannel(void) const { return refChannel; } ++#ifdef USE_PLUGINPARAM ++ bool IsPlug(void) const { return cSource::IsPlug(source); } ++#endif /* PLUGINPARAM */ + bool IsCable(void) const { return cSource::IsCable(source); } + bool IsSat(void) const { return cSource::IsSat(source); } + bool IsTerr(void) const { return cSource::IsTerr(source); } +@@ -215,12 +224,18 @@ public: + bool HasTimer(void) const; + int Modification(int Mask = CHANNELMOD_ALL); + void CopyTransponderData(const cChannel *Channel); ++#ifdef USE_PLUGINPARAM ++ bool SetPlugTransponderData(int Source, int Frequency, const char *PluginParam); ++#endif /* PLUGINPARAM */ + bool SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH, int Modulation, int System, int RollOff); + bool SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH); + bool SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CodeRateH, int CodeRateL, int Guard, int Transmission); + void SetId(int Nid, int Tid, int Sid, int Rid = 0); + void SetName(const char *Name, const char *ShortName, const char *Provider); + void SetPortalName(const char *PortalName); ++#ifdef USE_PLUGINPARAM ++ void SetPluginParam(const char *PluginParam); ++#endif /* PLUGINPARAM */ + void SetPids(int Vpid, int Ppid, int Vtype, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid); + void SetCaIds(const int *CaIds); // list must be zero-terminated + void SetCaDescriptors(int Level); +diff -ruNp vdr-1.7.5/config.c vdr-1.7.5-extensions/config.c +--- vdr-1.7.5/config.c 2009-01-24 16:05:32.000000000 +0100 ++++ vdr-1.7.5-extensions/config.c 2009-04-12 13:37:59.000000000 +0200 +@@ -15,6 +15,9 @@ + #include "interface.h" + #include "plugin.h" + #include "recording.h" ++#ifdef USE_SOURCECAPS ++#include "sources.h" ++#endif /* SOURCECAPS */ + + // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' + // format characters in order to allow any number of blanks after a numeric +@@ -28,18 +31,32 @@ cCommand::cCommand(void) + { + title = command = NULL; + confirm = false; ++#ifdef USE_CMDSUBMENU ++ nIndent = 0; ++ childs = NULL; ++#endif /* CMDSUBMENU */ + } + + cCommand::~cCommand() + { + free(title); + free(command); ++#ifdef USE_CMDSUBMENU ++ delete childs; ++#endif /* CMDSUBMENU */ + } + + bool cCommand::Parse(const char *s) + { + const char *p = strchr(s, ':'); + if (p) { ++#ifdef USE_CMDSUBMENU ++ nIndent = 0; ++ while (*s == '-') { ++ nIndent++; ++ s++; ++ } ++#endif /* CMDSUBMENU */ + int l = p - s; + if (l > 0) { + title = MALLOC(char, l + 1); +@@ -85,6 +102,20 @@ const char *cCommand::Execute(const char + return result; + } + ++#ifdef USE_CMDSUBMENU ++int cCommand::getChildCount(void) ++{ ++ return childs ? childs->Count() : 0; ++} ++ ++void cCommand::addChild(cCommand *newChild) ++{ ++ if (!childs) ++ childs = new cCommands(); ++ childs->AddConfig(newChild); ++} ++#endif /* CMDSUBMENU */ ++ + // --- cSVDRPhost ------------------------------------------------------------ + + cSVDRPhost::cSVDRPhost(void) +@@ -125,6 +156,26 @@ bool cSVDRPhost::Accepts(in_addr_t Addre + + cCommands Commands; + cCommands RecordingCommands; ++#ifdef USE_TIMERCMD ++cCommands TimerCommands; ++#endif /* TIMERCMD */ ++ ++#ifdef USE_CMDSUBMENU ++void cCommands::AddConfig(cCommand *Object) ++{ ++ if (!Object) ++ return; ++ //isyslog ("Indent %d %s\n", Object->getIndent(), Object->Title()); ++ for (int index = Count() - 1; index >= 0; index--) { ++ cCommand *parent = Get(index); ++ if (parent->getIndent() < Object->getIndent()) { ++ parent->addChild(Object); ++ return; ++ } ++ } ++ cConfig<cCommand>::Add(Object); ++} ++#endif /* CMDSUBMENU */ + + // --- cSVDRPhosts ----------------------------------------------------------- + +@@ -216,6 +267,12 @@ cSetup::cSetup(void) + strcpy(OSDLanguage, ""); // default is taken from environment + strcpy(OSDSkin, "sttng"); + strcpy(OSDTheme, "default"); ++#ifdef USE_WAREAGLEICON ++ WarEagleIcons = 1; ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ ShowValidInput = 0; ++#endif /* VALIDINPUT */ + PrimaryDVB = 1; + ShowInfoOnChSwitch = 1; + TimeoutRequChInfo = 1; +@@ -260,6 +317,15 @@ cSetup::cSetup(void) + VideoFormat = 0; + UpdateChannels = 5; + UseDolbyDigital = 1; ++#ifdef USE_DOLBYINREC ++ UseDolbyInRecordings = 1; ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ DolbyTransferFix = 1; ++ ChannelBlocker = 0; ++ ChannelBlockerMode = 0; ++ ChannelBlockerList = strdup(""); ++#endif /* DVBSETUP */ + ChannelInfoPos = 0; + ChannelInfoTime = 5; + OSDLeft = 54; +@@ -276,24 +342,135 @@ cSetup::cSetup(void) + FontSmlSize = 18; + FontFixSize = 20; + MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT; ++#ifdef USE_HARDLINKCUTTER ++ MaxRecordingSize = DEFAULTRECORDINGSIZE; ++#endif /* HARDLINKCUTTER */ + SplitEditedFiles = 0; ++#ifdef USE_HARDLINKCUTTER ++ HardLinkCutter = 0; ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ DelTimeshiftRec = 0; ++#endif /* DELTIMESHIFTREC */ + MinEventTimeout = 30; + MinUserInactivity = 300; + NextWakeupTime = 0; + MultiSpeedMode = 0; + ShowReplayMode = 0; ++#ifdef USE_DDEPGENTRY ++ DoubleEpgTimeDelta = 15; ++ DoubleEpgAction = 0; ++ MixEpgAction = 0; ++ DisableVPS = 0; ++#endif /* DDEPGENTRY */ + ResumeID = 0; ++#ifdef USE_JUMPPLAY ++ JumpPlay = 0; ++ PlayJump = 0; ++ PauseLastMark = 0; ++ ReloadMarks = 0; ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ memset(SourceCaps, 0, sizeof SourceCaps); ++ SourceCapsSet = false; ++#endif /* SOURCECAPS */ + CurrentChannel = -1; + CurrentVolume = MAXVOLUME; + CurrentDolby = 0; + InitialChannel = 0; + InitialVolume = -1; ++#ifdef USE_VOLCTRL ++ LRVolumeControl = 0; ++ LRChannelGroups = 1; ++ LRForwardRewind = 1; ++#endif /* VOLCTRL */ + EmergencyExit = 1; ++#ifdef USE_NOEPG ++ noEPGMode = 0; ++ noEPGList = strdup(""); ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ LircRepeatDelay = 350; ++ LircRepeatFreq = 100; ++ LircRepeatTimeout = 500; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ ShowRecDate = 1; ++ ShowRecTime = 1; ++ ShowRecLength = 0; ++ ShowProgressBar = 0; ++ MenuCmdPosition = 0; ++ JumpSeconds = 60; ++ JumpSecondsSlow = 10; ++ ShowTimerStop = 1; ++ MainMenuTitle = 0; ++ strcpy(CustomMainMenuTitle, "Video Disk Recorder"); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ RecordingsSortMode = 0; ++ RecordingsSortDirsFirst = 0; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ CutterAutoDelete = 0; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ CutTime = 1; ++#endif /* CUTTIME */ ++#ifdef USE_DVDARCHIVE ++ DvdDisplayMode = 1; ++ DvdDisplayZeros = 1; ++ DvdTrayMode = 0; ++ DvdSpeedLimit = 0; ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ UseSoftOsd = 0; ++ SoftOsdRate = 50; ++ SoftOsdFadeinSteps = 6; ++ SoftOsdFadeoutSteps = 16; ++ SoftOsdPaletteOnly = 0; ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ VerboseLNBlog = 0; ++ for (int i = 0; i < MAXDEVICES; i++) CardUsesLNBnr[i] = i + 1; ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ UseVidPrefer = 0; // default = disabled ++ nVidPrefer = 1; ++ for (int zz = 1; zz < DVLVIDPREFER_MAX; zz++) { ++ VidPreferPrio[ zz ] = 50; ++ VidPreferSize[ zz ] = 100; ++ } ++ VidPreferSize[ 0 ] = 800; ++ VidPreferPrio[ 0 ] = 50; ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ UseFriendlyFNames = 0; // default = disabled ++#endif /* DVLFRIENDLYFNAMES */ ++} ++ ++#if defined (USE_DVBSETUP) || defined (USE_NOEPG) ++cSetup::~cSetup() ++{ ++#ifdef USE_DVBSETUP ++ free(ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ free(noEPGList); ++#endif /* NOEPG */ + } ++#endif /* DVBSETUP + NOEPG */ + + cSetup& cSetup::operator= (const cSetup &s) + { + memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__); ++#ifdef USE_DVBSETUP ++ free(ChannelBlockerList); ++ ChannelBlockerList = strdup(s.ChannelBlockerList); ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ free(noEPGList); ++ noEPGList = strdup(s.noEPGList); ++#endif /* NOEPG */ + return *this; + } + +@@ -384,11 +561,62 @@ bool cSetup::ParseLanguages(const char * + return true; + } + ++#ifdef USE_SOURCECAPS ++void cSetup::StoreSourceCaps(const char *Name) ++{ ++ cSetupLine *l; ++ while ((l = Get(Name)) != NULL) ++ Del(l); ++ ++ for (int i = 0; i < MAXDEVICES; i++) { ++ char buffer[MAXSOURCECAPS*8]={0,}, *q = buffer; ++ int j = 0; ++ while (SourceCaps[i][j] && j < MAXSOURCECAPS) { ++ if (j==0) ++ q += snprintf(buffer, sizeof(buffer), "%i ", i+1); ++ q += snprintf(q, sizeof(buffer) - (q-buffer), "%s ", *cSource::ToString(SourceCaps[i][j++])); ++ } ++ if (*buffer) ++ Store(Name, buffer, NULL, true); ++ } ++} ++ ++bool cSetup::ParseSourceCaps(const char *Value) ++{ ++ char *p; ++ int d = strtol(Value, &p, 10)-1, i = 0; ++ while (p < Value+strlen(Value)) { ++ if (*p==0) return true; ++ if (isblank(*p)) ++p; ++ if (isalpha(*p)) { ++ int source = cSource::FromString(p); ++ if (source != cSource::stNone) { ++ SourceCaps[d][i++] = source; ++ SourceCapsSet = true; ++ } ++ else ++ return false; ++ while (!isblank(*p) && *p) ++ ++p; ++ if (i>MAXSOURCECAPS) ++ return false; ++ } ++ } ++ return true; ++} ++#endif /* SOURCECAPS */ ++ + bool cSetup::Parse(const char *Name, const char *Value) + { + if (!strcasecmp(Name, "OSDLanguage")) { strn0cpy(OSDLanguage, Value, sizeof(OSDLanguage)); I18nSetLocale(OSDLanguage); } + else if (!strcasecmp(Name, "OSDSkin")) Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName); + else if (!strcasecmp(Name, "OSDTheme")) Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName); ++#ifdef USE_WAREAGLEICON ++ else if (!strcasecmp(Name, "WarEagleIcons")) WarEagleIcons = atoi(Value); ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ else if (!strcasecmp(Name, "ShowValidInput")) ShowValidInput = atoi(Value); ++#endif /* VALIDINPUT */ + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "TimeoutRequChInfo")) TimeoutRequChInfo = atoi(Value); +@@ -433,6 +661,18 @@ bool cSetup::Parse(const char *Name, con + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value); + else if (!strcasecmp(Name, "UseDolbyDigital")) UseDolbyDigital = atoi(Value); ++#ifdef USE_DOLBYINREC ++ else if (!strcasecmp(Name, "UseDolbyInRecordings")) UseDolbyInRecordings = atoi(Value); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ else if (!strcasecmp(Name, "DolbyTransferFix")) DolbyTransferFix = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlocker")) ChannelBlocker = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlockerMode")) ChannelBlockerMode = atoi(Value); ++ else if (!strcasecmp(Name, "ChannelBlockerList")) { ++ free(ChannelBlockerList); ++ ChannelBlockerList = strdup(Value ? Value : ""); ++ } ++#endif /* DVBSETUP */ + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoTime")) ChannelInfoTime = atoi(Value); + else if (!strcasecmp(Name, "OSDLeft")) OSDLeft = atoi(Value); +@@ -449,21 +689,144 @@ bool cSetup::Parse(const char *Name, con + else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value); + else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); ++#ifdef USE_HARDLINKCUTTER ++ else if (!strcasecmp(Name, "MaxRecordingSize")) MaxRecordingSize = atoi(Value); ++#endif /* HARDLINKCUTTER */ + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); ++#ifdef USE_HARDLINKCUTTER ++ else if (!strcasecmp(Name, "HardLinkCutter")) HardLinkCutter = atoi(Value); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value); ++#endif /* DELTIMESHIFTREC */ + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); ++#ifdef USE_DDEPGENTRY ++ else if (!strcasecmp(Name, "DoubleEpgTimeDelta")) DoubleEpgTimeDelta = atoi(Value); ++ else if (!strcasecmp(Name, "DoubleEpgAction")) DoubleEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "MixEpgAction")) MixEpgAction = atoi(Value); ++ else if (!strcasecmp(Name, "DisableVPS")) DisableVPS = atoi(Value); ++#endif /* DDEPGENTRY */ + else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value); ++#ifdef USE_JUMPPLAY ++ else if (!strcasecmp(Name, "JumpPlay")) JumpPlay = atoi(Value); ++ else if (!strcasecmp(Name, "PlayJump")) PlayJump = atoi(Value); ++ else if (!strcasecmp(Name, "PauseLastMark")) PauseLastMark = atoi(Value); ++ else if (!strcasecmp(Name, "ReloadMarks")) ReloadMarks = atoi(Value); ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ else if (!strcasecmp(Name, "SourceCaps")) return ParseSourceCaps(Value); ++#endif /* SOURCECAPS */ + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); + else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value); + else if (!strcasecmp(Name, "InitialChannel")) InitialChannel = atoi(Value); + else if (!strcasecmp(Name, "InitialVolume")) InitialVolume = atoi(Value); ++#ifdef USE_VOLCTRL ++ else if (!strcasecmp(Name, "LRVolumeControl")) LRVolumeControl = atoi(Value); ++ else if (!strcasecmp(Name, "LRChannelGroups")) LRChannelGroups = atoi(Value); ++ else if (!strcasecmp(Name, "LRForwardRewind")) LRForwardRewind = atoi(Value); ++#endif /* VOLCTRL */ + else if (!strcasecmp(Name, "EmergencyExit")) EmergencyExit = atoi(Value); ++#ifdef USE_NOEPG ++ else if (!strcasecmp(Name, "noEPGMode")) noEPGMode = atoi(Value); ++ else if (!strcasecmp(Name, "noEPGList")) { ++ free(noEPGList); ++ noEPGList = strdup(Value ? Value : ""); ++ } ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ else if (!strcasecmp(Name, "LircRepeatDelay")) LircRepeatDelay = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatFreq")) LircRepeatFreq = atoi(Value); ++ else if (!strcasecmp(Name, "LircRepeatTimeout")) LircRepeatTimeout = atoi(Value); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ else if (!strcasecmp(Name, "ShowRecDate")) ShowRecDate = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecTime")) ShowRecTime = atoi(Value); ++ else if (!strcasecmp(Name, "ShowRecLength")) ShowRecLength = atoi(Value); ++ else if (!strcasecmp(Name, "ShowProgressBar")) ShowProgressBar = atoi(Value); ++ else if (!strcasecmp(Name, "MenuCmdPosition")) MenuCmdPosition = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSeconds")) JumpSeconds = atoi(Value); ++ else if (!strcasecmp(Name, "JumpSecondsSlow")) JumpSecondsSlow = atoi(Value); ++ else if (!strcasecmp(Name, "ShowTimerStop")) ShowTimerStop = atoi(Value); ++ else if (!strcasecmp(Name, "MainMenuTitle")) MainMenuTitle = atoi(Value); ++ else if (!strcasecmp(Name, "CustomMainMenuTitle")) Utf8Strn0Cpy(CustomMainMenuTitle, Value, MaxTitleName); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ else if (!strcasecmp(Name, "RecordingsSortMode")) RecordingsSortMode = atoi(Value); ++ else if (!strcasecmp(Name, "RecordingsSortDirsFirst")) RecordingsSortDirsFirst = atoi(Value); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ else if (!strcasecmp(Name, "CutterAutoDelete")) CutterAutoDelete = atoi(Value); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ else if (!strcasecmp(Name, "CutTime")) CutTime = atoi(Value); ++#endif /* CUTTIME */ ++#ifdef USE_DVDARCHIVE ++ else if (!strcasecmp(Name, "DvdDisplayMode")) DvdDisplayMode = atoi(Value); ++ else if (!strcasecmp(Name, "DvdDisplayZeros")) DvdDisplayZeros = atoi(Value); ++ else if (!strcasecmp(Name, "DvdTrayMode")) DvdTrayMode = atoi(Value); ++ else if (!strcasecmp(Name, "DvdSpeedLimit")) DvdSpeedLimit = atoi(Value); ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ else if (!strcasecmp(Name, "UseSoftOsd")) UseSoftOsd = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdRate")) SoftOsdRate = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdFadeinSteps")) SoftOsdFadeinSteps = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdFadeoutSteps")) SoftOsdFadeoutSteps = atoi(Value); ++ else if (!strcasecmp(Name, "SoftOsdPaletteOnly")) SoftOsdPaletteOnly = atoi(Value); ++#endif /* SOFTOSD */ ++#ifdef USE_DVLVIDPREFER ++ else if (strcasecmp(Name, "UseVidPrefer") == 0) UseVidPrefer = atoi(Value); ++ else if (strcasecmp(Name, "nVidPrefer") == 0) nVidPrefer = atoi(Value); ++ else if (strstr(Name, "VidPrefer") == Name) { ++ char *x = (char *)&Name[ strlen(Name) - 1 ]; ++ int vN; ++ ++ if (isdigit(*x) != 0) { ++ while (isdigit(*x) != 0) ++ x--; ++ x++; ++ } ++ ++ vN = atoi(x); ++ if (vN < DVLVIDPREFER_MAX) { ++ if (strstr(Name, "VidPreferPrio") == Name) { ++ VidPreferPrio[ vN ] = atoi(Value); ++ if (VidPreferPrio[ vN ] > 99) ++ VidPreferPrio[ vN ] = 99; ++ } ++ else if (strstr(Name, "VidPreferSize") == Name) { ++ VidPreferSize[ vN ] = atoi(Value); ++ } ++ else ++ return false; ++ } ++ } ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ else if (strcasecmp(Name, "UseFriendlyFNames") == 0) UseFriendlyFNames = atoi(Value); ++#endif /* DVLFRIENDLYFNAMES */ + else ++#ifdef USE_LNBSHARE ++ if (!strcasecmp(Name, "VerboseLNBlog")) VerboseLNBlog = atoi(Value); ++ else { ++ char tmp[20]; ++ bool result = false; ++ for (int i = 1; i <= MAXDEVICES; i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ if (!strcasecmp(Name, tmp)) { ++ CardUsesLNBnr[i - 1] = atoi(Value); ++ result = true; ++ } ++ } ++ return result; ++ } ++#else + return false; ++#endif /* LNBSHARE */ + return true; + } + +@@ -472,6 +835,12 @@ bool cSetup::Save(void) + Store("OSDLanguage", OSDLanguage); + Store("OSDSkin", OSDSkin); + Store("OSDTheme", OSDTheme); ++#ifdef USE_WAREAGLEICON ++ Store("WarEagleIcons", WarEagleIcons); ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ Store("ShowValidInput", ShowValidInput); ++#endif /* VALIDINPUT */ + Store("PrimaryDVB", PrimaryDVB); + Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); + Store("TimeoutRequChInfo", TimeoutRequChInfo); +@@ -516,6 +885,15 @@ bool cSetup::Save(void) + Store("VideoFormat", VideoFormat); + Store("UpdateChannels", UpdateChannels); + Store("UseDolbyDigital", UseDolbyDigital); ++#ifdef USE_DOLBYINREC ++ Store("UseDolbyInRecordings", UseDolbyInRecordings); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ Store("DolbyTransferFix", DolbyTransferFix); ++ Store("ChannelBlocker", ChannelBlocker); ++ Store("ChannelBlockerMode", ChannelBlockerMode); ++ Store("ChannelBlockerList", ChannelBlockerList); ++#endif /* DVBSETUP */ + Store("ChannelInfoPos", ChannelInfoPos); + Store("ChannelInfoTime", ChannelInfoTime); + Store("OSDLeft", OSDLeft); +@@ -532,25 +910,156 @@ bool cSetup::Save(void) + Store("FontSmlSize", FontSmlSize); + Store("FontFixSize", FontFixSize); + Store("MaxVideoFileSize", MaxVideoFileSize); ++#ifdef USE_HARDLINKCUTTER ++ Store("MaxRecordingSize", MaxRecordingSize); ++#endif /* HARDLINKCUTTER */ + Store("SplitEditedFiles", SplitEditedFiles); ++#ifdef USE_HARDLINKCUTTER ++ Store("HardLinkCutter", HardLinkCutter); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ Store("DelTimeshiftRec", DelTimeshiftRec); ++#endif /* DELTIMESHIFTREC */ + Store("MinEventTimeout", MinEventTimeout); + Store("MinUserInactivity", MinUserInactivity); + Store("NextWakeupTime", NextWakeupTime); ++#ifdef USE_DDEPGENTRY ++ Store("DoubleEpgAction", DoubleEpgAction); ++ Store("MixEpgAction", MixEpgAction); ++ Store("DisableVPS", DisableVPS); ++ Store("DoubleEpgTimeDelta", DoubleEpgTimeDelta); ++#endif /* DDEPGENTRY */ + Store("MultiSpeedMode", MultiSpeedMode); + Store("ShowReplayMode", ShowReplayMode); + Store("ResumeID", ResumeID); ++#ifdef USE_JUMPPLAY ++ Store("JumpPlay", JumpPlay); ++ Store("PlayJump", PlayJump); ++ Store("PauseLastMark", PauseLastMark); ++ Store("ReloadMarks", ReloadMarks); ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ if (SourceCapsSet) StoreSourceCaps("SourceCaps"); ++#endif /* SOURCECAPS */ + Store("CurrentChannel", CurrentChannel); + Store("CurrentVolume", CurrentVolume); + Store("CurrentDolby", CurrentDolby); + Store("InitialChannel", InitialChannel); + Store("InitialVolume", InitialVolume); ++#ifdef USE_VOLCTRL ++ Store("LRVolumeControl", LRVolumeControl); ++ Store("LRChannelGroups", LRChannelGroups); ++ Store("LRForwardRewind", LRForwardRewind); ++#endif /* VOLCTRL */ + Store("EmergencyExit", EmergencyExit); ++#ifdef USE_NOEPG ++ Store("noEPGMode", noEPGMode); ++ Store("noEPGList", noEPGList); ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ Store("LircRepeatDelay", LircRepeatDelay); ++ Store("LircRepeatFreq", LircRepeatFreq); ++ Store("LircRepeatTimeout", LircRepeatTimeout); ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ Store("ShowRecDate", ShowRecDate); ++ Store("ShowRecTime", ShowRecTime); ++ Store("ShowRecLength", ShowRecLength); ++ Store("ShowProgressBar", ShowProgressBar); ++ Store("MenuCmdPosition", MenuCmdPosition); ++ Store("JumpSeconds", JumpSeconds); ++ Store("JumpSecondsSlow", JumpSecondsSlow); ++ Store("ShowTimerStop", ShowTimerStop); ++ Store("MainMenuTitle", MainMenuTitle); ++ Store("CustomMainMenuTitle",CustomMainMenuTitle); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ Store("RecordingsSortMode", RecordingsSortMode); ++ Store("RecordingsSortDirsFirst", RecordingsSortDirsFirst); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Store("CutterAutoDelete", CutterAutoDelete); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ Store("CutTime", CutTime); ++#endif /* CUTTIME */ ++#ifdef USE_DVDARCHIVE ++ Store("DvdDisplayMode", DvdDisplayMode); ++ Store("DvdDisplayZeros", DvdDisplayZeros); ++ Store("DvdTrayMode", DvdTrayMode); ++ Store("DvdSpeedLimit", DvdSpeedLimit); ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ Store("UseSoftOsd", UseSoftOsd); ++ Store("SoftOsdRate", SoftOsdRate); ++ Store("SoftOsdFadeinSteps", SoftOsdFadeinSteps); ++ Store("SoftOsdFadeoutSteps", SoftOsdFadeoutSteps); ++ Store("SoftOsdPaletteOnly", SoftOsdPaletteOnly); ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ Store("VerboseLNBlog", VerboseLNBlog); ++ char tmp[20]; ++ if (cDevice::NumDevices() > 1) { ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ sprintf(tmp, "Card%dusesLNBnr", i); ++ Store(tmp, CardUsesLNBnr[i - 1]); ++ } ++ } ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ Store ("UseVidPrefer", UseVidPrefer); ++ Store ("nVidPrefer", nVidPrefer); ++ ++ char vidBuf[32]; ++ for (int zz = 0; zz < nVidPrefer; zz++) { ++ sprintf(vidBuf, "VidPreferPrio%d", zz); ++ Store (vidBuf, VidPreferPrio[zz]); ++ sprintf(vidBuf, "VidPreferSize%d", zz); ++ Store (vidBuf, VidPreferSize[zz]); ++ } ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ Store ("UseFriendlyFNames", UseFriendlyFNames); ++#endif /* DVLFRIENDLYFNAMES */ + + Sort(); + + if (cConfig<cSetupLine>::Save()) { + isyslog("saved setup to %s", FileName()); ++#ifdef USE_DVDARCHIVE ++ if (DvdDisplayMode >= 1) ::Recordings.Load(); ++#endif /* DVDARCHIVE */ + return true; + } + return false; + } ++ ++#ifdef USE_CMDRECCMDI18N ++bool LoadCommandsI18n(cCommands & cmds, const char *FileName, bool AllowComments, bool MustExist) ++{ ++ ++ bool bRet = true; ++ bool bLoadDefault = (bool)strcmp(Setup.OSDLanguage,"en_US"); ++ if (bLoadDefault) { ++ // attempt to load a translated file ++ char *FullPath = NULL; ++ asprintf(&FullPath, "%s.%s", FileName, Setup.OSDLanguage); ++ if (!cmds.Load((FullPath), AllowComments, true)) { ++ // require to exist, just to be able to log ++ // fallback ++ bLoadDefault = false; ++ esyslog("Failed to load translated '%s' for language (%s)", FullPath, Setup.OSDLanguage); ++ esyslog("Falling back to default '%s' (if any)", FileName); ++ } ++ free(FullPath); ++ } ++ if (!bLoadDefault) { ++ // let's do it the normal way ++ bRet = cmds.Load(FileName, AllowComments, MustExist); ++ } ++ // return status only for the default commands file ++ return bRet; ++} ++ ++#endif /* CMDRECCMDI18N */ ++ +diff -ruNp vdr-1.7.5/config.h vdr-1.7.5-extensions/config.h +--- vdr-1.7.5/config.h 2009-01-30 17:05:34.000000000 +0100 ++++ vdr-1.7.5-extensions/config.h 2009-04-12 13:37:59.000000000 +0200 +@@ -36,23 +36,74 @@ + // plugins to work with newer versions of the core VDR as long as no + // VDR header files have changed. + ++#define VDREXTENSIONS 70 ++ ++#ifdef USE_JUMPPLAY ++#define JUMPPLAYVERSNUM 100 ++#endif /* JUMPPLAY */ ++ ++#ifdef USE_LIEMIEXT ++#define LIEMIKUUTIO 123 ++#define MAXMAINMENUTITLE 4 ++#define MaxTitleName 64 ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_CMDSUBMENU ++#define CMDSUBMENUVERSNUM 7 ++#endif /* CMDSUBMENU */ ++ ++#ifdef USE_MAINMENUHOOKS ++#define MAINMENUHOOKSVERSNUM 1.0 ++#endif /* MAINMENUHOOKS */ ++ ++#ifdef USE_PINPLUGIN ++#define PIN_PLUGIN_PATCH 120 ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_PLUGINPARAM ++#define PLUGINPARAMPATCHVERSNUM 1 ++#endif /* PLUGINPARAM */ ++ + #define MAXPRIORITY 99 + #define MAXLIFETIME 99 + ++#ifdef USE_DVLVIDPREFER ++#define DVLVIDPREFER_MAX 12 ++#endif /* DVLVIDPREFER */ ++ + #define MINOSDWIDTH 480 + #define MAXOSDWIDTH 672 + #define MINOSDHEIGHT 324 + #define MAXOSDHEIGHT 567 + ++#ifdef USE_SOURCECAPS ++#define MAXDEVICES 16 // the maximum number of devices in the system ++#define MAXSOURCECAPS 128 // the maximum number of different sources per device ++#endif /* SOURCECAPS */ ++ ++#ifdef USE_LNBSHARE ++#ifndef MAXDEVICES ++#define MAXDEVICES 16 // the maximum number of devices in the system ++#endif ++#endif /* LNBSHARE */ ++ + #define MaxFileName 256 + #define MaxSkinName 16 + #define MaxThemeName 16 + ++#ifdef USE_CMDSUBMENU ++class cCommands; ++#endif /* CMDSUBMENU */ ++ + class cCommand : public cListObject { + private: + char *title; + char *command; + bool confirm; ++#ifdef USE_CMDSUBMENU ++ int nIndent; ++ cCommands *childs; ++#endif /* CMDSUBMENU */ + static char *result; + public: + cCommand(void); +@@ -61,6 +112,14 @@ public: + const char *Title(void) { return title; } + bool Confirm(void) { return confirm; } + const char *Execute(const char *Parameters = NULL); ++#ifdef USE_CMDSUBMENU ++ int getIndent(void) { return nIndent; } ++ void setIndent(int nNewIndent) { nIndent = nNewIndent; } ++ cCommands *getChilds(void) { return childs; } ++ int getChildCount(void); ++ bool hasChilds(void) { return getChildCount() > 0; } ++ void addChild(cCommand *newChild); ++#endif /* CMDSUBMENU */ + }; + + typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2) +@@ -88,6 +147,9 @@ private: + public: + cConfig(void) { fileName = NULL; } + virtual ~cConfig() { free(fileName); } ++#ifdef USE_CMDSUBMENU ++ virtual void AddConfig(T *Object) { cList<T>::Add(Object); } ++#endif /* CMDSUBMENU */ + const char *FileName(void) { return fileName; } + bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false) + { +@@ -117,7 +179,11 @@ public: + if (!isempty(s)) { + T *l = new T; + if (l->Parse(s)) ++#ifdef USE_CMDSUBMENU ++ AddConfig(l); ++#else + Add(l); ++#endif /* CMDSUBMENU */ + else { + esyslog("ERROR: error in %s, line %d", fileName, line); + delete l; +@@ -158,7 +224,14 @@ public: + } + }; + ++#ifdef USE_CMDSUBMENU ++class cCommands : public cConfig<cCommand> { ++public: ++ virtual void AddConfig(cCommand *Object); ++ }; ++#else + class cCommands : public cConfig<cCommand> {}; ++#endif /* CMDSUBMENU */ + + class cSVDRPhosts : public cConfig<cSVDRPhost> { + public: +@@ -167,6 +240,9 @@ public: + + extern cCommands Commands; + extern cCommands RecordingCommands; ++#ifdef USE_TIMERCMD ++extern cCommands TimerCommands; ++#endif /* TIMERCMD */ + extern cSVDRPhosts SVDRPhosts; + + class cSetupLine : public cListObject { +@@ -192,6 +268,10 @@ private: + void StoreLanguages(const char *Name, int *Values); + bool ParseLanguages(const char *Value, int *Values); + bool Parse(const char *Name, const char *Value); ++#ifdef USE_SOURCECAPS ++ void StoreSourceCaps(const char *Name); ++ bool ParseSourceCaps(const char *Value); ++#endif /* SOURCECAPS */ + cSetupLine *Get(const char *Name, const char *Plugin = NULL); + void Store(const char *Name, const char *Value, const char *Plugin = NULL, bool AllowMultiple = false); + void Store(const char *Name, int Value, const char *Plugin = NULL); +@@ -201,6 +281,12 @@ public: + char OSDLanguage[I18N_MAX_LOCALE_LEN]; + char OSDSkin[MaxSkinName]; + char OSDTheme[MaxThemeName]; ++#ifdef USE_WAREAGLEICON ++ int WarEagleIcons; ++#endif /* WAREAGLEICON */ ++#ifdef USE_VALIDINPUT ++ int ShowValidInput; ++#endif /* VALIDINPUT */ + int PrimaryDVB; + int ShowInfoOnChSwitch; + int TimeoutRequChInfo; +@@ -241,6 +327,14 @@ public: + int VideoFormat; + int UpdateChannels; + int UseDolbyDigital; ++#ifdef USE_DOLBYINREC ++ int UseDolbyInRecordings; ++#endif /* DOLBYINREC */ ++#ifdef USE_DVBSETUP ++ int DolbyTransferFix; ++ int ChannelBlocker; ++ int ChannelBlockerMode; ++#endif /* DVBSETUP */ + int ChannelInfoPos; + int ChannelInfoTime; + int OSDLeft, OSDTop, OSDWidth, OSDHeight; +@@ -254,20 +348,111 @@ public: + int FontSmlSize; + int FontFixSize; + int MaxVideoFileSize; ++#ifdef USE_HARDLINKCUTTER ++ int MaxRecordingSize; ++#endif /* HARDLINKCUTTER */ + int SplitEditedFiles; ++#ifdef USE_HARDLINKCUTTER ++ int HardLinkCutter; ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ int DelTimeshiftRec; ++#endif /* DELTIMESHIFTREC */ + int MinEventTimeout, MinUserInactivity; + time_t NextWakeupTime; + int MultiSpeedMode; + int ShowReplayMode; ++#ifdef USE_DDEPGENTRY ++ int DoubleEpgTimeDelta; ++ int DoubleEpgAction; ++ int MixEpgAction; ++ int DisableVPS; ++#endif /* DDEPGENTRY */ + int ResumeID; ++#ifdef USE_JUMPPLAY ++ int JumpPlay; ++ int PlayJump; ++ int PauseLastMark; ++ int ReloadMarks; ++#endif /* JUMPPLAY */ ++#ifdef USE_SOURCECAPS ++ int SourceCaps[MAXDEVICES][MAXSOURCECAPS]; ++ bool SourceCapsSet; ++#endif /* SOURCECAPS */ + int CurrentChannel; + int CurrentVolume; + int CurrentDolby; + int InitialChannel; + int InitialVolume; ++#ifdef USE_VOLCTRL ++ int LRVolumeControl; ++ int LRChannelGroups; ++ int LRForwardRewind; ++#endif /* VOLCTRL */ + int EmergencyExit; ++#ifdef USE_NOEPG ++ int noEPGMode; ++#endif /* NOEPG */ ++#ifdef USE_LIRCSETTINGS ++ int LircRepeatDelay; ++ int LircRepeatFreq; ++ int LircRepeatTimeout; ++#endif /* LIRCSETTINGS */ ++#ifdef USE_LIEMIEXT ++ int ShowRecDate, ShowRecTime, ShowRecLength, ShowProgressBar, MenuCmdPosition; ++ int JumpSeconds; ++ int JumpSecondsSlow; ++ int ShowTimerStop; ++ int MainMenuTitle; ++ char CustomMainMenuTitle[MaxTitleName]; ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ int RecordingsSortMode; ++ int RecordingsSortDirsFirst; ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ int CutterAutoDelete; ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ int CutTime; ++#endif /* CUTTIME */ ++#ifdef USE_DVDARCHIVE ++ int DvdDisplayMode; ++ int DvdDisplayZeros; ++ int DvdTrayMode; ++ int DvdSpeedLimit; ++#endif /* DVDARCHIVE */ ++#ifdef USE_SOFTOSD ++ int UseSoftOsd; ++ int SoftOsdRate; ++ int SoftOsdFadeinSteps; ++ int SoftOsdFadeoutSteps; ++ int SoftOsdPaletteOnly; ++#endif /* SOFTOSD */ ++#ifdef USE_LNBSHARE ++ int VerboseLNBlog; ++ int CardUsesLNBnr[MAXDEVICES]; ++#endif /* LNBSHARE */ ++#ifdef USE_DVLVIDPREFER ++ int UseVidPrefer; // 0 = VDR's default, 1 = use ++ int nVidPrefer; ++ int VidPreferPrio[DVLVIDPREFER_MAX]; ++ int VidPreferSize[DVLVIDPREFER_MAX]; ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLFRIENDLYFNAMES ++ int UseFriendlyFNames; ++#endif /* DVLFRIENDLYFNAMES */ + int __EndData__; ++#ifdef USE_DVBSETUP ++ char *ChannelBlockerList; ++#endif /* DVBSETUP */ ++#ifdef USE_NOEPG ++ char *noEPGList; // pointer not to be flat-copied ++#endif /* NOEPG */ + cSetup(void); ++#if defined (USE_DVBSETUP) || defined (USE_NOEPG) ++ ~cSetup(); ++#endif /* DVBSETUP + NOEPG */ + cSetup& operator= (const cSetup &s); + bool Load(const char *FileName); + bool Save(void); +@@ -275,4 +460,8 @@ public: + + extern cSetup Setup; + ++#ifdef USE_CMDRECCMDI18N ++bool LoadCommandsI18n(cCommands & cmds, const char *FileName = NULL, bool AllowComments = false, bool MustExist = false); ++#endif /* CMDRECCMDI18N */ ++ + #endif //__CONFIG_H +diff -ruNp vdr-1.7.5/cutter.c vdr-1.7.5-extensions/cutter.c +--- vdr-1.7.5/cutter.c 2009-01-24 16:19:26.000000000 +0100 ++++ vdr-1.7.5-extensions/cutter.c 2009-04-12 13:37:59.000000000 +0200 +@@ -15,6 +15,19 @@ + + // --- cCuttingThread -------------------------------------------------------- + ++#ifdef USE_CUTTERLIMIT ++#ifndef CUTTER_MAX_BANDWIDTH ++# define CUTTER_MAX_BANDWIDTH MEGABYTE(10) // 10 MB/s ++#endif ++#ifndef CUTTER_REL_BANDWIDTH ++# define CUTTER_REL_BANDWIDTH 75 // % ++#endif ++#ifndef CUTTER_PRIORITY ++# define CUTTER_PRIORITY sched_get_priority_min(SCHED_OTHER) ++#endif ++#define CUTTER_TIMESLICE 100 // ms ++#endif /* CUTTERLIMIT */ ++ + class cCuttingThread : public cThread { + private: + const char *error; +@@ -66,6 +79,22 @@ cCuttingThread::~cCuttingThread() + + void cCuttingThread::Action(void) + { ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) ++#endif /* HARDLINKCUTTER */ ++ { ++ sched_param tmp; ++ tmp.sched_priority = CUTTER_PRIORITY; ++ if (!pthread_setschedparam(pthread_self(), SCHED_OTHER, &tmp)) ++ printf("cCuttingThread::Action: cant set priority\n"); ++ } ++ ++ int bytes = 0; ++ int __attribute__((unused)) burst_size = CUTTER_MAX_BANDWIDTH * CUTTER_TIMESLICE / 1000; // max bytes/timeslice ++ cTimeMs __attribute__((unused)) t; ++#endif /* CUTTERLIMIT */ ++ + cMark *Mark = fromMarks.First(); + if (Mark) { + fromFile = fromFileName->Open(); +@@ -77,6 +106,9 @@ void cCuttingThread::Action(void) + Mark = fromMarks.Next(Mark); + off_t FileSize = 0; + int CurrentFileNumber = 0; ++#ifdef USE_HARDLINKCUTTER ++ bool SkipThisSourceFile = false; ++#endif /* HARDLINKCUTTER */ + int LastIFrame = 0; + toMarks.Add(0); + toMarks.Save(); +@@ -95,12 +127,101 @@ void cCuttingThread::Action(void) + + // Read one frame: + ++#ifndef USE_HARDLINKCUTTER + if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) { + if (FileNumber != CurrentFileNumber) { + fromFile = fromFileName->SetOffset(FileNumber, FileOffset); + fromFile->SetReadAhead(MEGABYTE(20)); + CurrentFileNumber = FileNumber; + } ++#else ++ if (!fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) { ++ // Error, unless we're past last cut-in and there's no cut-out ++ if (Mark || LastMark) ++ error = "index"; ++ break; ++ } ++ ++ if (FileNumber != CurrentFileNumber) { ++ fromFile = fromFileName->SetOffset(FileNumber, FileOffset); ++ fromFile->SetReadAhead(MEGABYTE(20)); ++ CurrentFileNumber = FileNumber; ++ if (SkipThisSourceFile) { ++ // At end of fast forward: Always skip to next file ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 4"; ++ break; ++ } ++ FileSize = 0; ++ SkipThisSourceFile = false; ++ } ++ ++ ++ if (Setup.HardLinkCutter && FileOffset == 0) { ++ // We are at the beginning of a new source file. ++ // Do we need to copy the whole file? ++ ++ // if !Mark && LastMark, then we're past the last cut-out and continue to next I-frame ++ // if !Mark && !LastMark, then there's just a cut-in, but no cut-out ++ // if Mark, then we're between a cut-in and a cut-out ++ ++ uint16_t MarkFileNumber; ++ off_t MarkFileOffset; ++ // Get file number of next cut mark ++ if (!Mark && !LastMark ++ || Mark ++ && fromIndex->Get(Mark->position, &MarkFileNumber, &MarkFileOffset) ++ && (MarkFileNumber != CurrentFileNumber)) { ++ // The current source file will be copied completely. ++ // Start new output file unless we did that already ++ if (FileSize != 0) { ++ toFile = toFileName->NextFile(); ++ if (!toFile) { ++ error = "toFile 3"; ++ break; ++ } ++ FileSize = 0; ++ } ++ ++ // Safety check that file has zero size ++ struct stat buf; ++ if (stat(toFileName->Name(), &buf) == 0) { ++ if (buf.st_size != 0) { ++ esyslog("cCuttingThread: File %s exists and has nonzero size", toFileName->Name()); ++ error = "nonzero file exist"; ++ break; ++ } ++ } ++ else if (errno != ENOENT) { ++ esyslog("cCuttingThread: stat failed on %s", toFileName->Name()); ++ error = "stat"; ++ break; ++ } ++ ++ // Clean the existing 0-byte file ++ toFileName->Close(); ++ cString ActualToFileName(ReadLink(toFileName->Name()), true); ++ unlink(ActualToFileName); ++ unlink(toFileName->Name()); ++ ++ // Try to create a hard link ++ if (HardLinkVideoFile(fromFileName->Name(), toFileName->Name())) { ++ // Success. Skip all data transfer for this file ++ SkipThisSourceFile = true; ++ cutIn = false; ++ toFile = NULL; // was deleted by toFileName->Close() ++ } ++ else { ++ // Fallback: Re-open the file if necessary ++ toFile = toFileName->Open(); ++ } ++ } ++ } ++ } ++ ++ if (!SkipThisSourceFile) { ++#endif /* HARDLINKCUTTER */ + if (fromFile) { + int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); + if (len < 0) { +@@ -117,6 +238,7 @@ void cCuttingThread::Action(void) + break; + } + } ++#ifndef USE_HARDLINKCUTTER + else { + // Error, unless we're past the last cut-in and there's no cut-out + if (Mark || LastMark) +@@ -124,12 +246,17 @@ void cCuttingThread::Action(void) + break; + } + ++#endif /* HARDLINKCUTTER */ + // Write one frame: + + if (Independent) { // every file shall start with an independent frame + if (LastMark) // edited version shall end before next I-frame + break; ++#ifndef USE_HARDLINKCUTTER + if (FileSize > maxVideoFileSize) { ++#else ++ if (!SkipThisSourceFile && FileSize > toFileName->MaxFileSize()) { ++#endif /* HARDLINKCUTTER */ + toFile = toFileName->NextFile(); + if (!toFile) { + error = "toFile 1"; +@@ -139,12 +266,20 @@ void cCuttingThread::Action(void) + } + LastIFrame = 0; + ++#ifndef USE_HARDLINKCUTTER + if (cutIn) { ++#else ++ if (!SkipThisSourceFile && cutIn) { ++#endif /* HARDLINKCUTTER */ + cRemux::SetBrokenLink(buffer, Length); + cutIn = false; + } + } ++#ifndef USE_HARDLINKCUTTER + if (toFile->Write(buffer, Length) < 0) { ++#else ++ if (!SkipThisSourceFile && toFile->Write(buffer, Length) < 0) { ++#endif /* HARDLINKCUTTER */ + error = "safe_write"; + break; + } +@@ -179,8 +314,44 @@ void cCuttingThread::Action(void) + } + } + else ++#ifndef USE_HARDLINKCUTTER + LastMark = true; ++#else ++ LastMark = true; // After last cut-out: Write on until next I-frame, then exit ++#endif /* HARDLINKCUTTER */ + } ++#ifdef USE_CUTTERLIMIT ++#ifdef USE_HARDLINKCUTTER ++ if (!Setup.HardLinkCutter) { ++#endif /* HARDLINKCUTTER */ ++ bytes += Length; ++ if (bytes >= burst_size) { ++ int elapsed = t.Elapsed(); ++ int sleep = 0; ++ ++#if CUTTER_REL_BANDWIDTH > 0 && CUTTER_REL_BANDWIDTH < 100 ++ // stay under max. relative bandwidth ++ ++ sleep = (elapsed * 100 / CUTTER_REL_BANDWIDTH) - elapsed; ++ //if (sleep<=0 && elapsed<=2) sleep = 1; ++ //if (sleep) esyslog("cutter: relative bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++#endif ++ // stay under max. absolute bandwidth ++ if (elapsed < CUTTER_TIMESLICE) { ++ sleep = max(CUTTER_TIMESLICE - elapsed, sleep); ++ //if (sleep) esyslog("cutter: absolute bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); ++ } ++ ++ if (sleep>0) ++ cCondWait::SleepMs(sleep); ++ t.Set(); ++ bytes = 0; ++ } ++#ifdef USE_HARDLINKCUTTER ++ } ++#endif /* HARDLINKCUTTER */ ++#endif /* CUTTERLIMIT */ ++ + } + Recordings.TouchUpdate(); + } +@@ -190,18 +361,74 @@ void cCuttingThread::Action(void) + + // --- cCutter --------------------------------------------------------------- + ++#ifdef USE_CUTTERQUEUE ++#define WAIT_BEFORE_NEXT_CUT (10*1000) // 10 seconds ++ ++class cStringListObject : public cListObject { ++ public: ++ cStringListObject(const char *s) { str = strdup(s); } ++ ~cStringListObject() { free(str); } ++ ++ const char *Value() { return str; } ++ operator const char * () { return str; } ++ ++ private: ++ char *str; ++}; ++#endif /* CUTTERQUEUE */ ++ + char *cCutter::editedVersionName = NULL; + cCuttingThread *cCutter::cuttingThread = NULL; + bool cCutter::error = false; + bool cCutter::ended = false; ++#ifdef USE_CUTTERQUEUE ++cMutex *cCutter::cutterLock = new cMutex(); ++static uint64_t /*cCutter::*/lastCuttingEndTime = 0; ++static cList<cStringListObject> /**cCutter::*/cutterQueue /*= new cList<cStringListObject>*/; ++#endif /* CUTTERQUEUE */ + + bool cCutter::Start(const char *FileName) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++ if (FileName) { ++ /* Add file to queue. ++ * If cutter is still active, next cutting will be started ++ * when vdr.c:main calls cCutter::Active and previous cutting has ++ * been stopped > 10 s before ++ */ ++ cutterQueue.Add(new cStringListObject(FileName)); ++ } ++ if (cuttingThread) ++ return true; ++ /* cut next file from queue */ ++ if (!(cutterQueue.First())) ++ return false; ++ FileName = cutterQueue.First()->Value(); ++#endif /* CUTTERQUEUE */ + if (!cuttingThread) { + error = false; + ended = false; + cRecording Recording(FileName); ++#ifdef USE_CUTTIME ++ if (Setup.CutTime) { ++ cMarks FromMarks; ++ FromMarks.Load(FileName); ++ cMark *First = FromMarks.First(); ++ if (First) Recording.SetStartTime(Recording.start + (int(First->position / Recording.FramesPerSecond() +30) / 60) * 60); ++ } ++#endif /* CUTTIME */ + const char *evn = Recording.PrefixFileName('%'); ++#ifdef USE_CUTTERQUEUE ++ if (!(Recordings.GetByName(FileName))) { ++ // Should _not_ remove any cutted recordings ++ // (original recording already deleted ?) ++ // so, just pop item from queue and return. ++ esyslog("can't cut non-existing recording %s", FileName); ++ cutterQueue.Del(cutterQueue.First()); ++ return true; // might be already queued recording ++ } ++#endif /* CUTTERQUEUE */ + if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { + // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) + // remove a possible deleted recording with the same name to avoid symlink mixups: +@@ -227,6 +454,9 @@ bool cCutter::Start(const char *FileName + + void cCutter::Stop(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool Interrupted = cuttingThread && cuttingThread->Active(); + const char *Error = cuttingThread ? cuttingThread->Error() : NULL; + delete cuttingThread; +@@ -238,11 +468,20 @@ void cCutter::Stop(void) + esyslog("ERROR: '%s' during editing process", Error); + RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? + Recordings.DelByName(editedVersionName); ++#ifdef USE_CUTTERQUEUE ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ + } ++#ifdef USE_CUTTERQUEUE ++ lastCuttingEndTime = cTimeMs::Now(); ++#endif /* CUTTERQUEUE */ + } + + bool cCutter::Active(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + if (cuttingThread) { + if (cuttingThread->Active()) + return true; +@@ -253,12 +492,40 @@ bool cCutter::Active(void) + free(editedVersionName); + editedVersionName = NULL; + ended = true; ++#ifdef USE_CUTTERQUEUE ++ if (Setup.CutterAutoDelete) { ++ /* Remove original (if cutting was successful) */ ++ if (!error) { ++ cRecording *recording = Recordings.GetByName(*cutterQueue.First()); ++ if (!recording) ++ esyslog("ERROR: Can't found '%s' after editing process", cutterQueue.First()->Value()); ++ else { ++ if (recording->Delete()) ++ Recordings.DelByName(recording->FileName()); ++ else ++ esyslog("ERROR: Can't delete '%s' after editing process", cutterQueue.First()->Value()); ++ } ++ } ++ lastCuttingEndTime = cTimeMs::Now(); ++ } ++ cutterQueue.Del(cutterQueue.First()); ++#endif /* CUTTERQUEUE */ ++ } ++#ifdef USE_CUTTERQUEUE ++ if (!cuttingThread && cutterQueue.First()) { ++ /* start next cutting from queue*/ ++ if (cTimeMs::Now() > lastCuttingEndTime + WAIT_BEFORE_NEXT_CUT) ++ Start(NULL); + } ++#endif /* CUTTERQUEUE */ + return false; + } + + bool cCutter::Error(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = error; + error = false; + return result; +@@ -266,6 +533,9 @@ bool cCutter::Error(void) + + bool cCutter::Ended(void) + { ++#ifdef USE_CUTTERQUEUE ++ cMutexLock(cutterLock); ++#endif /* CUTTERQUEUE */ + bool result = ended; + ended = false; + return result; +diff -ruNp vdr-1.7.5/cutter.h vdr-1.7.5-extensions/cutter.h +--- vdr-1.7.5/cutter.h 2002-06-22 12:03:15.000000000 +0200 ++++ vdr-1.7.5-extensions/cutter.h 2009-04-12 13:37:59.000000000 +0200 +@@ -11,6 +11,9 @@ + #define __CUTTER_H + + class cCuttingThread; ++#ifdef USE_CUTTERQUEUE ++class cMutex; ++#endif /* CUTTERQUEUE */ + + class cCutter { + private: +@@ -18,6 +21,9 @@ private: + static cCuttingThread *cuttingThread; + static bool error; + static bool ended; ++#ifdef USE_CUTTERQUEUE ++ static cMutex *cutterLock; ++#endif /* CUTTERQUEUE */ + public: + static bool Start(const char *FileName); + static void Stop(void); +diff -ruNp vdr-1.7.5/device.c vdr-1.7.5-extensions/device.c +--- vdr-1.7.5/device.c 2009-04-05 14:15:41.000000000 +0200 ++++ vdr-1.7.5-extensions/device.c 2009-04-12 13:37:59.000000000 +0200 +@@ -19,6 +19,14 @@ + #include "status.h" + #include "transfer.h" + ++#ifdef USE_LNBSHARE ++#include "diseqc.h" ++#endif /* LNBSHARE */ ++ ++#ifdef USE_CHANNELSCAN ++bool scanning_on_receiving_device = false; ++#endif /* CHANNELSCAN */ ++ + // --- cLiveSubtitle --------------------------------------------------------- + + class cLiveSubtitle : public cReceiver { +@@ -68,6 +76,12 @@ cDevice::cDevice(void) + + SetVideoFormat(Setup.VideoFormat); + ++#ifdef USE_LNBSHARE ++ LNBstate = -1; ++ LNBnr = Setup.CardUsesLNBnr[cardIndex]; ++ LNBsource = NULL; ++#endif /* LNBSHARE */ ++ + mute = false; + volume = Setup.CurrentVolume; + +@@ -93,8 +107,15 @@ cDevice::cDevice(void) + for (int i = 0; i < MAXRECEIVERS; i++) + receiver[i] = NULL; + ++#ifdef USE_SOURCECAPS ++ if (numDevices < MAXDEVICES) { ++ device[numDevices++] = this; ++ SetSourceCaps(cardIndex); ++ } ++#else + if (numDevices < MAXDEVICES) + device[numDevices++] = this; ++#endif /* SOURCECAPS */ + else + esyslog("ERROR: too many devices!"); + } +@@ -129,6 +150,16 @@ void cDevice::SetUseDevice(int n) + useDevice |= (1 << n); + } + ++#ifdef USE_LNBSHARE ++void cDevice::SetLNBnr(void) ++{ ++ for (int i = 0; i < numDevices; i++) { ++ device[i]->LNBnr = Setup.CardUsesLNBnr[i]; ++ isyslog("LNB-sharing: setting device %d to use LNB %d", i, device[i]->LNBnr); ++ } ++} ++#endif /* LNBSHARE */ ++ + int cDevice::NextCardIndex(int n) + { + if (n > 0) { +@@ -189,6 +220,98 @@ cDevice *cDevice::ActualDevice(void) + return d; + } + ++#ifdef USE_LNBSHARE ++cDevice *cDevice::GetBadDevice(const cChannel *Channel) ++{ ++ if (!cSource::IsSat(Channel->Source())) ++ return NULL; ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d on device %d. LNB or DiSEq conflict with device %d", LNBnr, Channel->Number(), this->DeviceNumber(), i); ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for for channel %d on device %d. OK", LNBnr, Channel->Number(), this->DeviceNumber()); ++ } ++ else { ++ char requiredState; ++ ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1 ; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. Conflict with device %d, LNBstate %d", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate, i, device[i]->GetLNBconf()); ++ return device[i]; ++ } ++ } ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. No other devices affected", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate); ++ } ++ return NULL; ++} ++ ++int cDevice::GetMaxBadPriority(const cChannel *Channel) ++{ ++ if (!cSource::IsSat(Channel->Source())) return -2; ++ bool PrimaryIsBad = false; ++ int maxBadPriority = -2; ++ ++ if (Setup.DiSEqC) { ++ cDiseqc *diseqc; ++ diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) ++ maxBadPriority = device[i]->Priority(); ++ if (i == ActualDevice()->CardIndex()) ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ else { ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1 ; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ for (int i = 0; i < numDevices; i++) { ++ if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { ++ if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) ++ maxBadPriority = device[i]->Priority(); ++ if (i == ActualDevice()->CardIndex()) ++ PrimaryIsBad = true; ++ } ++ } ++ } ++ ++ if (PrimaryIsBad && maxBadPriority == -2) ++ maxBadPriority = -1; ++ ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Request for channel %d on device %d. MaxBadPriority is %d", LNBnr, Channel->Number(), this->DeviceNumber(), maxBadPriority); ++ ++ return maxBadPriority; ++} ++#endif /* LNBSHARE */ ++ + cDevice *cDevice::GetDevice(int Index) + { + return (0 <= Index && Index < numDevices) ? device[Index] : NULL; +@@ -238,6 +361,10 @@ cDevice *cDevice::GetDevice(const cChann + cCamSlot *s = NULL; + + uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact ++#ifdef USE_LNBSHARE ++ int badPriority; ++ uint imp2; ++#endif /* LNBSHARE */ + for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) { + if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY) + continue; // there is no CAM available in this slot +@@ -271,7 +398,31 @@ cDevice *cDevice::GetDevice(const cChann + imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels + imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards + imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel ++#ifdef USE_LNBSHARE ++ badPriority = device[i]->GetMaxBadPriority(Channel); ++ if (badPriority >= Priority || (badPriority == -1 && Priority < Setup.PrimaryLimit)) { ++ // channel is not available for the requested prioity ++ imp = 0xFFFFFFFF; ++ } ++ else { ++ switch (badPriority) { ++ case -2: // not affected by LNB-sharing ++ imp2 = 0; ++ break; ++ case -1: // the primary device would need a channel switch ++ imp += 1 << 17; ++ imp2 = 0xFFFFFFFF | 1 << 17; ++ break; ++ default: // a device receiving with lower priority would need to be stopped ++ imp += badPriority << 8; ++ imp2 = 0xFFFFFFFF | badPriority << 8; ++ break; ++ } ++ } ++ if (imp < Impact && imp2 < Impact) { ++#else + if (imp < Impact) { ++#endif /* LNBSHARE */ + // This device has less impact than any previous one, so we take it. + Impact = imp; + d = device[i]; +@@ -312,6 +463,18 @@ void cDevice::SetCamSlot(cCamSlot *CamSl + camSlot = CamSlot; + } + ++#ifdef USE_SOURCECAPS ++void cDevice::SetSourceCaps(int Index) ++{ ++ for (int d = 0; d < numDevices; d++) { ++ if (Index < 0 || Index == device[d]->CardIndex()) { ++ for (int i = 0; i < MAXSOURCECAPS; i++) ++ device[d]->sourceCaps[i] = Setup.SourceCaps[device[d]->CardIndex()][i]; ++ } ++ } ++} ++#endif /* SOURCECAPS */ ++ + void cDevice::Shutdown(void) + { + primaryDevice = NULL; +@@ -556,7 +719,11 @@ bool cDevice::ProvidesTransponder(const + bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const + { + for (int i = 0; i < numDevices; i++) { ++#ifdef USE_LNBSHARE ++ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel) && device[i]->GetLNBnr() != LNBnr) ++#else + if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel)) ++#endif /* LNBSHARE */ + return false; + } + return true; +@@ -584,6 +751,24 @@ bool cDevice::MaySwitchTransponder(void) + + bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) + { ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ if (this->GetMaxBadPriority(Channel) >= 0) { ++ Skins.Message(mtInfo, tr("Channel locked by LNB!")); ++ return false; ++ } ++ while ((tmpDevice = GetBadDevice(Channel)) != NULL) { ++ if (tmpDevice->IsPrimaryDevice() && LiveView) ++ tmpDevice->SwitchChannelForced(Channel, true); ++ else ++ tmpDevice->SwitchChannelForced(Channel, false); ++ } ++ return SwitchChannelForced(Channel, LiveView); ++} ++ ++bool cDevice::SwitchChannelForced(const cChannel *Channel, bool LiveView) ++{ ++#endif /* LNBSHARE */ + if (LiveView) { + isyslog("switching to channel %d", Channel->Number()); + cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer +@@ -613,7 +798,14 @@ bool cDevice::SwitchChannel(int Directio + cChannel *channel; + while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { + // try only channels which are currently available ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, channel) == false) ++#endif /* PINPLUGIN */ ++#ifdef USE_LNBSHARE ++ if (PrimaryDevice()->GetMaxBadPriority(channel) < 0 && (GetDevice(channel, 0, true))) ++#else + if (GetDevice(channel, 0, true)) ++#endif /* LNBSHARE */ + break; + n = channel->Number() + Direction; + } +@@ -634,6 +826,13 @@ bool cDevice::SwitchChannel(int Directio + + eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) + { ++#ifdef USE_PINPLUGIN ++ // I hope 'LiveView = false' indicates a channel switch for recording, ++ // I really don't know, but it works ... ++ if (LiveView && cStatus::MsgChannelProtected(this, Channel) == true) ++ return scrNotAvailable; ++#endif /* PINPLUGIN */ ++ + if (LiveView) { + StopReplay(); + DELETENULL(liveSubtitle); +@@ -646,11 +845,37 @@ eSetChannelResult cDevice::SetChannel(co + + eSetChannelResult Result = scrOk; + ++#ifdef USE_LNBSHARE ++ char requiredState; ++ if (Channel->Frequency() >= Setup.LnbSLOF) ++ requiredState = 1; ++ else ++ requiredState = 0; ++ ++ if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ++ requiredState += 2; ++ ++ if (Setup.VerboseLNBlog) ++ isyslog("LNB %d: Switching device %d to channel %d", LNBnr, this->DeviceNumber(), Channel->Number()); ++#endif /* LNBSHARE */ ++ + // If this DVB card can't receive this channel, let's see if we can + // use the card that actually can receive it and transfer data from there: + + if (NeedsTransferMode) { + if (Device && CanReplay()) { ++#ifdef USE_LNBSHARE ++ if (Device->GetLNBnr() == LNBnr) { ++ if (LNBstate != requiredState || (Setup.DiSEqC && LNBsource != (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())) ) { ++ if (IsPrimaryDevice()) ++ SetChannelDevice(Channel, true); ++ else ++ SetChannelDevice(Channel, false); ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++ } ++ } ++#endif /* LNBSHARE */ + cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel + if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! + cControl::Launch(new cTransferControl(Device, Channel->GetChannelID(), Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids())); +@@ -668,6 +893,10 @@ eSetChannelResult cDevice::SetChannel(co + sectionHandler->SetStatus(false); + sectionHandler->SetChannel(NULL); + } ++#ifdef USE_LNBSHARE ++ LNBstate = requiredState; ++ LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); ++#endif /* LNBSHARE */ + // Tell the camSlot about the channel switch and add all PIDs of this + // channel to it, for possible later decryption: + if (camSlot) +@@ -960,7 +1189,12 @@ void cDevice::EnsureSubtitleTrack(void) + int LanguagePreference = INT_MAX; // higher than the maximum possible value + for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) { + const tTrackId *TrackId = GetTrack(eTrackType(i)); ++#ifdef USE_LIEMIEXT ++ if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) || ++ ((i == ttSubtitleFirst + 8) && !(*TrackId->language) && (LanguagePreference == INT_MAX)))) ++#else + if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference)) ++#endif /* LIEMIEXT */ + PreferredTrack = eTrackType(i); + } + // Make sure we're set to an available subtitle track: +@@ -1192,7 +1426,11 @@ pre_1_3_19_PrivateStreamDetected: + w = PlaySubtitle(Start, d); + break; + case 0x80: // AC3 & DTS ++#ifdef USE_DOLBYINREC ++ if (Setup.UseDolbyInRecordings) { ++#else + if (Setup.UseDolbyDigital) { ++#endif /* DOLBYINREC */ + SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId); + if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) { + w = PlayAudio(Start, d, SubStreamId); +diff -ruNp vdr-1.7.5/device.h vdr-1.7.5-extensions/device.h +--- vdr-1.7.5/device.h 2009-04-05 14:12:44.000000000 +0200 ++++ vdr-1.7.5-extensions/device.h 2009-04-12 13:37:59.000000000 +0200 +@@ -24,13 +24,22 @@ + #include "spu.h" + #include "thread.h" + #include "tools.h" ++#ifdef USE_ROTOR ++#include <linux/dvb/frontend.h> ++#endif /* ROTOR */ + ++#ifndef USE_SOURCECAPS + #define MAXDEVICES 16 // the maximum number of devices in the system ++#endif /* SOURCECAPS */ + #define MAXPIDHANDLES 64 // the maximum number of different PIDs per device + #define MAXRECEIVERS 16 // the maximum number of receivers per device + #define MAXVOLUME 255 + #define VOLUMEDELTA 5 // used to increase/decrease the volume + ++#ifdef USE_CHANNELSCAN ++extern bool scanning_on_receiving_device; ++#endif /* CHANNELSCAN */ ++ + enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed }; + + enum ePlayMode { pmNone, // audio/video from decoder +@@ -142,6 +151,35 @@ public: + ///< this device/CAM combination will be skipped in the next call to + ///< GetDevice(). + ///< See also ProvidesChannel(). ++#ifdef USE_SOURCECAPS ++ static void SetSourceCaps(int Index = -1); ++ ///< Sets the SourceCaps of the given device according to the Setup data. ++#endif /* SOURCECAPS */ ++#ifdef USE_LNBSHARE ++private: ++ char LNBstate; // Current frequency band and polarization of the DVB-tuner ++// cDiseqc *LNBsource; // can not #include "diseqc.h". A workaround follows: ++ int *LNBsource; // [DiSEqC] DiSEqC-Source ++ int LNBnr; // Number of LNB used ++public: ++ char GetLNBconf(void) { return LNBstate; } ++ int *GetLNBsource(void) { return LNBsource; } ++ int GetLNBnr(void) { return LNBnr; } ++ static void SetLNBnr(void); ++ cDevice *GetBadDevice(const cChannel *Channel); ++ ///< Returns NULL if there is no device which uses the same LNB or if ++ ///< all of those devices are tuned to the same frequency band and ++ ///< polarization as of the requested channel. ++ ///< Otherwise returns the first device found. ++ int GetMaxBadPriority(const cChannel *Channel); ++ ///< Returns the highest priority of all receiving devices which use ++ ///< the same LNB and are tuned to a different frequency band or ++ ///< polarization as of the requested channel. ++ ///< Returns -1 if there are no such devices, but the primary device ++ ///< would be affected by switching to the requested channel. ++ ///< Returns -2 if there are no such devices and the primary device ++ ///< would not be affected by switching to the requested channel. ++#endif /* LNBSHARE */ + static void SetAvoidDevice(cDevice *Device) { avoidDevice = Device; } + ///< Sets the given Device to be temporarily avoided in the next call to + ///< GetDevice(const cChannel, int, bool). +@@ -152,6 +190,9 @@ private: + static int nextCardIndex; + int cardIndex; + protected: ++#ifdef USE_SOURCECAPS ++ int sourceCaps[MAXSOURCECAPS]; ++#endif /* SOURCECAPS */ + cDevice(void); + virtual ~cDevice(); + virtual bool Ready(void); +@@ -239,17 +280,30 @@ public: + bool SwitchChannel(const cChannel *Channel, bool LiveView); + ///< Switches the device to the given Channel, initiating transfer mode + ///< if necessary. ++ ++#ifdef USE_LNBSHARE ++ bool SwitchChannelForced(const cChannel *Channel, bool LiveView); ++ ///< Switches the device to the given channel, initiating transfer mode ++ ///< if necessary. Forces the switch without taking care of the LNB configuration. ++#endif /* LNBSHARE */ ++ + static bool SwitchChannel(int Direction); + ///< Switches the primary device to the next available channel in the given + ///< Direction (only the sign of Direction is evaluated, positive values + ///< switch to higher channel numbers). + private: ++#ifndef USE_YAEPG + eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (actual physical setup). + public: ++#ifdef USE_YAEPG ++ eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); ++ ///< Sets the device to the given channel (general setup). ++#endif /* YAEPG */ + static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; } + ///< Returns the number of the current channel on the primary device. + static void SetCurrentChannel(const cChannel *Channel) { currentChannel = Channel ? Channel->Number() : 0; } +@@ -267,6 +321,9 @@ public: + virtual bool HasProgramme(void); + ///< Returns true if the device is currently showing any programme to + ///< the user, either through replaying or live. ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd) { return false; } ++#endif /* ROTOR */ + + // PID handle facilities + +diff -ruNp vdr-1.7.5/dvbdevice.c vdr-1.7.5-extensions/dvbdevice.c +--- vdr-1.7.5/dvbdevice.c 2009-04-10 11:54:24.000000000 +0200 ++++ vdr-1.7.5-extensions/dvbdevice.c 2009-04-12 13:37:59.000000000 +0200 +@@ -71,6 +71,9 @@ static int DvbOpen(const char *Name, int + class cDvbTuner : public cThread { + private: + enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked }; ++#ifdef USE_ROTOR ++ bool SendDiseqc; ++#endif /* ROTOR */ + int fd_frontend; + int cardIndex; + int tuneTimeout; +@@ -83,6 +86,9 @@ private: + cMutex mutex; + cCondVar locked; + cCondVar newSet; ++#ifdef USE_ROTOR ++ dvb_diseqc_master_cmd diseqc_cmd; ++#endif /* ROTOR */ + bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0); + bool SetFrontend(void); + virtual void Action(void); +@@ -91,12 +97,18 @@ public: + virtual ~cDvbTuner(); + bool IsTunedTo(const cChannel *Channel) const; + void Set(const cChannel *Channel, bool Tune); ++#ifdef USE_ROTOR ++ bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + bool Locked(int TimeoutMs = 0); + }; + + cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType) + { + fd_frontend = Fd_Frontend; ++#ifdef USE_ROTOR ++ SendDiseqc = false; ++#endif /* ROTOR */ + cardIndex = CardIndex; + frontendType = FrontendType; + tuneTimeout = 0; +@@ -163,6 +175,19 @@ bool cDvbTuner::Locked(int TimeoutMs) + return tunerStatus >= tsLocked; + } + ++#ifdef USE_ROTOR ++bool cDvbTuner::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ cMutexLock MutexLock(&mutex); ++ if ((!SYS_DVBS & !SYS_DVBS2) || SendDiseqc) ++ return false; ++ diseqc_cmd = cmd; ++ SendDiseqc = true; ++ newSet.Broadcast(); ++ return true; ++} ++#endif /* ROTOR */ ++ + bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs) + { + if (TimeoutMs) { +@@ -241,6 +266,9 @@ bool cDvbTuner::SetFrontend(void) + } + } + diseqcCommands = diseqc->Commands(); ++#ifdef USE_DVBSETUP ++ isyslog("Sent DISEQC command: %s", diseqcCommands); ++#endif /* DVBSETUP */ + } + frequency -= diseqc->Lof(); + } +@@ -303,6 +331,18 @@ bool cDvbTuner::SetFrontend(void) + tuneTimeout = DVBC_TUNE_TIMEOUT; + lockTimeout = DVBC_LOCK_TIMEOUT; + } ++#ifdef USE_ATSC ++ else if (frontendType == SYS_ATSC) { ++ // ATSC ++ SETCMD(DTV_DELIVERY_SYSTEM, frontendType); ++ SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())); ++ SETCMD(DTV_INVERSION, channel.Inversion()); ++ SETCMD(DTV_MODULATION, channel.Modulation()); ++ ++ tuneTimeout = DVBT_TUNE_TIMEOUT; ++ lockTimeout = DVBT_LOCK_TIMEOUT; ++ } ++#endif /* ATSC */ + else if (frontendType == SYS_DVBT) { + // DVB-T + SETCMD(DTV_DELIVERY_SYSTEM, frontendType); +@@ -341,6 +381,12 @@ void cDvbTuner::Action(void) + if (GetFrontendStatus(NewStatus, 10)) + Status = NewStatus; + cMutexLock MutexLock(&mutex); ++#ifdef USE_ROTOR ++ if (SendDiseqc) { ++ CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &diseqc_cmd)); ++ SendDiseqc = false; ++ } ++#endif /* ROTOR */ + switch (tunerStatus) { + case tsIdle: + break; +@@ -483,6 +529,11 @@ cDvbDevice::cDvbDevice(int n) + + if (fd_frontend >= 0) { + if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) >= 0) { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlockerMode == 4) ++ frontendType = (n == Setup.PrimaryDVB - 1) ? SYS_UNDEFINED : frontendType; ++ else ++#endif /* DVBSETUP */ + switch (frontendInfo.type) { + case FE_QPSK: frontendType = (frontendInfo.caps & FE_CAN_2G_MODULATION) ? SYS_DVBS2 : SYS_DVBS; break; + case FE_OFDM: frontendType = SYS_DVBT; break; +@@ -748,6 +799,13 @@ eVideoSystem cDvbDevice::GetVideoSystem( + + bool cDvbDevice::SetAudioBypass(bool On) + { ++#ifdef USE_DVBSETUP ++ if (Setup.DolbyTransferFix && On) { ++ cChannel *c=Channels.GetByNumber(cDevice::CurrentChannel()); ++ if (c->Ca(0) != 0) ++ return false; ++ } ++#endif /* DVBSETUP */ + if (setTransferModeForDolbyDigital != 1) + return false; + return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0; +@@ -853,14 +911,43 @@ void cDvbDevice::TurnOffLiveMode(bool Li + bool cDvbDevice::ProvidesSource(int Source) const + { + int type = Source & cSource::st_Mask; ++#ifdef USE_SOURCECAPS ++ if (Setup.SourceCapsSet && type == cSource::stSat && (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)) { ++ for (int i = 0; i < MAXSOURCECAPS; i++) ++ if (sourceCaps[i] == Source) ++ return true; ++ return false; ++ } ++ else ++#endif /* SOURCECAPS */ + return type == cSource::stNone + || type == cSource::stCable && (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) + || type == cSource::stSat && (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) ++#ifdef USE_ATSC ++ || type == cSource::stTerr && (frontendType == SYS_DVBT || frontendType == SYS_ATSC); ++#else + || type == cSource::stTerr && (frontendType == SYS_DVBT); ++#endif /* ATSC */ + } + + bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const + { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlocker != 0) { ++ if ((Setup.ChannelBlockerMode == 0) || ++ (Setup.ChannelBlockerMode == 1 && HasDecoder()) || ++ (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || ++ (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { ++ if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && Channel->Modulation() == QAM_256) || ++ (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || ++ (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || ++ (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist ++ (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist ++ (Setup.ChannelBlocker == 6)) ++ return false; ++ } ++ } ++#endif /* DVBSETUP */ + if (!ProvidesSource(Channel->Source())) + return false; // doesn't provide source + if (!cSource::IsSat(Channel->Source())) +@@ -872,10 +959,31 @@ bool cDvbDevice::ProvidesTransponder(con + + bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const + { ++#ifdef USE_DVBSETUP ++ if (Setup.ChannelBlocker != 0) { ++ if ((Setup.ChannelBlockerMode == 0) || ++ (Setup.ChannelBlockerMode == 1 && HasDecoder()) || ++ (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || ++ (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { ++ if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && Channel->Modulation() == QAM_256) || ++ (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || ++ (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || ++ (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist ++ (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist ++ (Setup.ChannelBlocker == 6)) ++ return false; ++ } ++ } ++#endif /* DVBSETUP */ + bool result = false; + bool hasPriority = Priority < 0 || Priority > this->Priority(); + bool needsDetachReceivers = false; + ++#ifdef USE_ANALOGTV ++ if ((Channel->Ca(0) == 0xA0) || (Channel->Ca(0) == 0xA1) || (Channel->Ca(0) == 0xA2)) ++ return false; ++#endif /* ANALOGTV */ ++ + if (ProvidesTransponder(Channel)) { + result = hasPriority; + if (Priority >= 0 && Receiving(true)) { +@@ -992,6 +1100,13 @@ bool cDvbDevice::HasLock(int TimeoutMs) + return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false; + } + ++#ifdef USE_ROTOR ++bool cDvbDevice::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) ++{ ++ return dvbTuner->SendDiseqcCmd(cmd); ++} ++#endif /* ROTOR */ ++ + int cDvbDevice::GetAudioChannelDevice(void) + { + if (HasDecoder()) { +diff -ruNp vdr-1.7.5/dvbdevice.h vdr-1.7.5-extensions/dvbdevice.h +--- vdr-1.7.5/dvbdevice.h 2008-12-06 14:31:12.000000000 +0100 ++++ vdr-1.7.5-extensions/dvbdevice.h 2009-04-12 13:37:59.000000000 +0200 +@@ -74,6 +74,9 @@ protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + public: + virtual bool HasLock(int TimeoutMs = 0); ++#ifdef USE_ROTOR ++ virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); ++#endif /* ROTOR */ + + // PID handle facilities + +diff -ruNp vdr-1.7.5/dvbosd.c vdr-1.7.5-extensions/dvbosd.c +--- vdr-1.7.5/dvbosd.c 2007-09-16 10:55:54.000000000 +0200 ++++ vdr-1.7.5-extensions/dvbosd.c 2009-04-12 13:37:59.000000000 +0200 +@@ -20,12 +20,26 @@ + #define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 + #define MAXOSDMEMORY 92000 // number of bytes available to the OSD (for unmodified DVB cards) + ++#ifdef USE_SOFTOSD ++ #define SOFTOSD_MAXSIZE (720*576) ++ #define SOFTOSD_MINSIZE (720*64) ++#endif ++ + class cDvbOsd : public cOsd { + private: + int osdDev; + int osdMem; + bool shown; + void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); ++#ifdef USE_SOFTOSD ++ int GetOsdSize() { ++ int OsdSize = 0; ++ cBitmap *Bitmap; ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) ++ OsdSize += Bitmap->Width() * Bitmap->Height(); ++ return OsdSize; ++ } ++#endif + protected: + virtual void SetActive(bool On); + public: +@@ -76,6 +90,44 @@ void cDvbOsd::SetActive(bool On) + } + else if (shown) { + cBitmap *Bitmap; ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { ++ for (int fade = Setup.SoftOsdFadeoutSteps - 1; fade > 0; fade--) { ++ int64_t flush_start = cTimeMs::Now(); ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { ++ Cmd(OSD_SetWindow, 0, i + 1); ++ int NumColors; ++ const tColor *Colors = Bitmap->Colors(NumColors); ++ if (Colors) { ++ tColor colors[NumColors]; ++ for (int i = 0; i < NumColors; i++) { ++ // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): ++ int alpha = (Colors[i] >> 24) & 0x000000FF; ++ alpha = (alpha * fade) / Setup.SoftOsdFadeoutSteps; ++ colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++ } ++ Colors = colors; ++ Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); ++ if (!Setup.SoftOsdPaletteOnly) { ++ //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); ++ Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); ++ } ++ } ++ } ++ int flush_time = cTimeMs::Now() - flush_start; ++ dsyslog("SOFTOSD: FadeOut Step %d from %d FlushTime = %d ms", ++ Setup.SoftOsdFadeoutSteps - fade, Setup.SoftOsdFadeoutSteps - 1, flush_time); ++ int wait_time = 1000 / Setup.SoftOsdRate; ++ while (flush_time > wait_time && fade > 2) { ++ fade--; ++ flush_time -= wait_time; ++ } ++ cCondWait::SleepMs(wait_time-flush_time); ++ } ++ } ++ } ++#endif /* SOFTOSD */ + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Close); +@@ -83,6 +135,12 @@ void cDvbOsd::SetActive(bool On) + shown = false; + } + } ++#ifdef USE_YAEPG ++ if (vidWin.bpp != 0) { ++ Cmd(OSD_SetWindow, 0, 5); ++ Cmd(OSD_Close); ++ } ++#endif /* YAEPG */ + } + + eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas) +@@ -182,6 +240,12 @@ void cDvbOsd::Flush(void) + for (int i = 0; i < NumColors; i++) { + // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): + colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd && !shown) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) ++ colors[i] = 0; ++ } ++#endif /* SOFTOSD */ + } + Colors = colors; + //TODO end of stuff that should be fixed in the driver +@@ -198,6 +262,51 @@ void cDvbOsd::Flush(void) + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0()); + } ++#ifdef USE_YAEPG ++ if (vidWin.bpp != 0) { ++ Cmd(OSD_SetWindow, 0, 5); ++ Cmd(OSD_OpenRaw, vidWin.bpp, vidWin.x1, vidWin.y1, vidWin.x2, vidWin.y2, (void *)0); ++ } ++#endif /* YAEPG */ ++#ifdef USE_SOFTOSD ++ if (Setup.UseSoftOsd) { ++ if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { ++ for (int fade = 1; fade <= Setup.SoftOsdFadeinSteps; fade++) { ++ int64_t flush_start = cTimeMs::Now(); ++ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { ++ Cmd(OSD_SetWindow, 0, i + 1); ++ int NumColors; ++ const tColor *Colors = Bitmap->Colors(NumColors); ++ if (Colors) { ++ tColor colors[NumColors]; ++ for (int i = 0; i < NumColors; i++) { ++ // convert AARRGGBB to AABBGGRR: ++ int alpha = (Colors[i]>>24) & 0x000000FF; ++ alpha = (alpha * fade) / Setup.SoftOsdFadeinSteps; ++ colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); ++ } ++ Colors = colors; ++ Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); ++ if (!Setup.SoftOsdPaletteOnly) { ++ //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); ++ Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); ++ } ++ } ++ } ++ int flush_time = cTimeMs::Now() - flush_start; ++ dsyslog("SOFTOSD: FadeIn Step %d from %d FlushTime = %d ms", fade, Setup.SoftOsdFadeinSteps, flush_time); ++ int wait_time = 1000 / Setup.SoftOsdRate; ++ while (flush_time > wait_time && fade < Setup.SoftOsdFadeinSteps - 1) { ++ fade++; ++ flush_time -= wait_time; ++ } ++ if (fade == Setup.SoftOsdFadeinSteps) /* last step, don't wait */ ++ break; ++ cCondWait::SleepMs(wait_time - flush_time); ++ } ++ } ++ } ++#endif /* SOFTOSD */ + shown = true; + } + } +diff -ruNp vdr-1.7.5/dvbplayer.c vdr-1.7.5-extensions/dvbplayer.c +--- vdr-1.7.5/dvbplayer.c 2009-04-05 15:04:33.000000000 +0200 ++++ vdr-1.7.5-extensions/dvbplayer.c 2009-04-12 13:37:59.000000000 +0200 +@@ -204,6 +204,9 @@ private: + cNonBlockingFileReader *nonBlockingFileReader; + cRingBufferFrame *ringBuffer; + cPtsIndex ptsIndex; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#endif /* JUMPPLAY */ + cFileName *fileName; + cIndexFile *index; + cUnbufferedFile *replayFile; +@@ -249,7 +252,11 @@ public: + int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; + + cDvbPlayer::cDvbPlayer(const char *FileName) ++#ifdef USE_JUMPPLAY ++:cThread("dvbplayer"), marks(FileName) ++#else + :cThread("dvbplayer") ++#endif /* JUMPPLAY */ + { + nonBlockingFileReader = NULL; + ringBuffer = NULL; +@@ -357,6 +364,11 @@ bool cDvbPlayer::Save(void) + if (index) { + int Index = ptsIndex.FindIndex(DeviceGetSTC()); + if (Index >= 0) { ++#ifdef USE_JUMPPLAY ++ // set resume position to 0 if replay stops at the first mark ++ if (Setup.PlayJump && marks.First() && abs(Index - marks.First()->position) <= RESUMEBACKUP) ++ Index = 0; ++#endif /* JUMPPLAY */ + Index -= int(round(RESUMEBACKUP * framesPerSecond)); + if (Index > 0) + Index = index->GetNextIFrame(Index, false); +@@ -384,11 +396,29 @@ void cDvbPlayer::Action(void) + uchar *b = NULL; + uchar *p = NULL; + int pc = 0; ++#ifdef USE_JUMPPLAY ++ bool cutIn = false; ++ int total = -1; ++#endif /* JUMPPLAY */ + + readIndex = Resume(); + if (readIndex >= 0) + isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true, framesPerSecond)); + ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump && readIndex <= 0 && marks.First() && index) { ++ int Index = marks.First()->position; ++ uint16_t FileNumber; ++ off_t FileOffset; ++ if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset)) { ++ isyslog("PlayJump: start replay at first mark %d (%s)", Index, *IndexToHMSF(Index, true)); ++ readIndex = Index; ++ } ++ } ++ ++ bool LastMarkPause = false; ++#endif /* JUMPPLAY */ ++ + nonBlockingFileReader = new cNonBlockingFileReader; + int Length = 0; + bool Sleep = false; +@@ -413,7 +443,11 @@ void cDvbPlayer::Action(void) + + // Read the next frame from the file: + ++#ifdef USE_JUMPPLAY ++ if (playMode != pmStill && playMode != pmPause && !LastMarkPause) { ++#else + if (playMode != pmStill && playMode != pmPause) { ++#endif /* JUMPPLAY */ + if (!readFrame && (replayFile || readIndex >= 0)) { + if (!nonBlockingFileReader->Reading()) { + if (!SwitchToPlayFrame && (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))) { +@@ -454,6 +488,42 @@ void cDvbPlayer::Action(void) + readIndex++; + else + eof = true; ++#ifdef USE_JUMPPLAY ++ if (Setup.PlayJump || Setup.PauseLastMark) { ++ // check for end mark - jump to next mark or pause ++ marks.Reload(); ++ cMark *m = marks.Get(readIndex); ++ if (m && (m->Index() & 0x01) != 0) { ++ m = marks.Next(m); ++ int Index; ++ if (m) ++ Index = m->position; ++ else if (Setup.PauseLastMark) { ++ // pause at last mark ++ isyslog("PauseLastMark: pause at position %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); ++ LastMarkPause = true; ++ Index = -1; ++ } ++ else if (total == index->Last()) ++ // at last mark jump to end of recording ++ Index = index->Last() - 1; ++ else ++ // jump but stay off end of live-recordings ++ Index = index->GetNextIFrame(index->Last() - 150, true); ++ ++ // don't jump in edited recordings ++ if (Setup.PlayJump && Index > readIndex && Index > index->GetNextIFrame(readIndex, true)) { ++ isyslog("PlayJump: %d frames to %d (%s)", Index - readIndex, Index, *IndexToHMSF(Index, true)); ++ readIndex = Index; ++ cutIn = true; ++ } ++ } ++ } ++ // for detecting growing length of live-recordings ++ bool Independent; ++ if (index->Get(readIndex, &FileNumber, &FileOffset, &Independent) && Independent) ++ total = index->Last(); ++#endif /* JUMPPLAY */ + } + else // allows replay even if the index file is missing + Length = MAXFRAMESIZE / TS_SIZE * TS_SIZE;// FIXME: use a linear ringbuffer in this case, and fix cDevice::PlayPes() +@@ -491,6 +561,12 @@ void cDvbPlayer::Action(void) + // Store the frame in the buffer: + + if (readFrame) { ++#ifdef USE_JUMPPLAY ++ if (cutIn) { ++ cRemux::SetBrokenLink(readFrame->Data(), readFrame->Count()); ++ cutIn = false; ++ } ++#endif /* JUMPPLAY */ + if (ringBuffer->Put(readFrame)) + readFrame = NULL; + } +@@ -546,8 +622,19 @@ void cDvbPlayer::Action(void) + p = NULL; + } + } ++#ifdef USE_JUMPPLAY ++ else { ++ if (LastMarkPause) { ++ LastMarkPause = false; ++ playMode = pmPause; ++// writeIndex = readIndex; ++ } ++ Sleep = true; ++ } ++#else + else + Sleep = true; ++#endif /* JUMPPLAY */ + + // Handle hitting begin/end of recording: + +diff -ruNp vdr-1.7.5/eit.c vdr-1.7.5-extensions/eit.c +--- vdr-1.7.5/eit.c 2009-04-11 12:03:24.000000000 +0200 ++++ vdr-1.7.5-extensions/eit.c 2009-04-12 13:37:59.000000000 +0200 +@@ -17,13 +17,40 @@ + #include "libsi/section.h" + #include "libsi/descriptor.h" + ++#ifdef USE_SETTIME ++extern char *SetTime; ++#endif /* SETTIME */ ++ + // --- cEIT ------------------------------------------------------------------ + + class cEIT : public SI::EIT { + public: + cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus = false); ++#ifdef USE_NOEPG ++private: ++ bool allowedEPG(tChannelID kanalID); ++#endif /* NOEPG */ + }; + ++#ifdef USE_NOEPG ++bool cEIT::allowedEPG(tChannelID kanalID) { ++ bool rc; ++ ++ if (Setup.noEPGMode == 1) { ++ rc = false; ++ if (strstr(::Setup.noEPGList, kanalID.ToString()) != NULL) ++ rc = true; ++ } ++ else { ++ rc = true; ++ if (strstr(::Setup.noEPGList, kanalID.ToString()) != NULL) ++ rc = false; ++ } ++ ++ return rc; ++} ++#endif /* NOEPG */ ++ + cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) + :SI::EIT(Data, false) + { +@@ -35,6 +62,14 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (!channel) + return; // only collect data for known channels + ++#ifdef USE_NOEPG ++ // only use epg from channels not blocked by noEPG-patch ++ tChannelID kanalID; ++ kanalID = channel->GetChannelID(); ++ if (!allowedEPG(kanalID)) ++ return; ++#endif /* NOEPG */ ++ + cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); + + bool Empty = true; +@@ -77,8 +112,74 @@ cEIT::cEIT(cSchedules *Schedules, int So + // not be overwritten. + uchar TableID = pEvent->TableID(); + if (TableID == 0x00) { ++#ifdef USE_DDEPGENTRY ++ if (pEvent->Version() == getVersionNumber()) { ++ if (Setup.MixEpgAction == 0) ++ continue; ++ //printf("in"); ++ //printf("%s", pEvent->GetTimeString()); ++ // to use the info of the original epg, update the extern one, ++ // if it has less info ++ SI::Descriptor *d; ++ SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; ++ //SI::ExtendedEventDescriptor *eed = NULL; ++ SI::ShortEventDescriptor *ShortEventDescriptor = NULL; ++ //SI::ShortEventDescriptor *sed = NULL; ++ //SI::TimeShiftedEventDescriptor *tsed = NULL; ++ //cLinkChannels *LinkChannels = NULL; ++ for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2));) { ++ if (d->getDescriptorTag() == SI::ShortEventDescriptorTag) { ++ int LanguagePreferenceShort = -1; ++ SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { ++ delete ShortEventDescriptor; ++ ShortEventDescriptor = sed; ++ d = NULL; // so that it is not deleted ++ } ++ } ++ else if (d->getDescriptorTag() == SI::ExtendedEventDescriptorTag) { ++ int LanguagePreferenceExt = -1; ++ bool UseExtendedEventDescriptor = false; ++ SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { ++ delete ExtendedEventDescriptors; ++ ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; ++ UseExtendedEventDescriptor = true; ++ } ++ if (UseExtendedEventDescriptor) { ++ ExtendedEventDescriptors->Add(eed); ++ d = NULL; // so that it is not deleted ++ } ++ if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) ++ UseExtendedEventDescriptor = false; ++ } ++ delete d; ++ } ++ if (pEvent) { ++ if (ShortEventDescriptor) { ++ char buffer[256]; ++ if (ShortEventDescriptor->text.getText(buffer, sizeof(buffer)) && pEvent->ShortText() && (strlen(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))) > strlen(pEvent->ShortText()))) { ++ pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))); ++ pEvent->FixEpgBugs(); ++ } ++ } ++ if (ExtendedEventDescriptors) { ++ char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ") + 1]; ++ //pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); ++ if (ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ") && pEvent->Description() && (strlen(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")) > strlen(pEvent->Description()))) { ++ pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); ++ pEvent->FixEpgBugs(); ++ } ++ } ++ } ++ delete ExtendedEventDescriptors; ++ delete ShortEventDescriptor; ++ continue; ++ } ++#else + if (pEvent->Version() == getVersionNumber()) + continue; ++#endif /* DDEPGENTRY */ + HasExternalData = ExternalData = true; + } + // If the new event has a higher table ID, let's skip it. +@@ -103,7 +204,11 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (newEvent) + pSchedule->AddEvent(newEvent); + if (Tid == 0x4E) { // we trust only the present/following info on the actual TS ++#ifdef USE_DDEPGENTRY ++ if (Setup.DisableVPS == 0 && SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) ++#else + if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) ++#endif /* DDEPGENTRY */ + pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel); + } + if (OnlyRunningStatus) +@@ -149,8 +254,46 @@ cEIT::cEIT(cSchedules *Schedules, int So + } + break; + case SI::ContentDescriptorTag: ++#ifdef USE_PARENTALRATING ++ { ++ int NumContents = 0; ++ uchar Contents[MAXEVCONTENTS + 1] = { 0 }; ++ SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d; ++ SI::ContentDescriptor::Nibble Nibble; ++ for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) { ++ if (NumContents < MAXEVCONTENTS) { ++ Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); ++ NumContents++; ++ } ++ } ++ pEvent->SetContents(Contents); ++ } ++#endif /* PARENTALRATING */ + break; + case SI::ParentalRatingDescriptorTag: ++#ifdef USE_PARENTALRATING ++ { ++ int LanguagePreferenceRating = -1; ++ SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d; ++ SI::ParentalRatingDescriptor::Rating Rating; ++ for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) { ++ if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) { ++ int rate = (Rating.getRating() & 0xFF); ++ switch (rate) { ++ case 0x01 ... 0x0F: // minimum age = rating + 3 years ++ rate += 3; ++ break; ++ case 0: // undefined ++ case 0x10 ... 0xFF: // defined by the broadcaster ++ default: ++ rate = 0; ++ break; ++ } ++ pEvent->SetParentalRating(rate); ++ } ++ } ++ } ++#endif /* PARENTALRATING */ + break; + case SI::PDCDescriptorTag: { + SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d; +@@ -261,6 +404,62 @@ cEIT::cEIT(cSchedules *Schedules, int So + if (LinkChannels) + channel->SetLinkChannels(LinkChannels); + Modified = true; ++#ifdef USE_DDEPGENTRY ++ //to avoid double epg-entrys from ext and int epg sources :EW ++ if (pEvent && pEvent->TableID() != 0x00) { ++ cEvent *pPreviousEvent = (cEvent *)pSchedule->GetPreviousEvent(pEvent); ++ if (pPreviousEvent) { ++ if (Setup.DoubleEpgAction == 0) { ++ pPreviousEvent->SetStartTime(pEvent->StartTime()); ++ pPreviousEvent->SetDuration(pEvent->Duration()); ++ if (Setup.DisableVPS == 0) { ++ if (channel) ++ pPreviousEvent->SetRunningStatus(pEvent->RunningStatus(), channel); ++ else ++ pPreviousEvent->SetRunningStatus(pEvent->RunningStatus()); ++ } ++ // to use the info of the original epg, update the extern one, ++ // if it has less info ++ char buffer_short_intern[256]; ++ char buffer_short_extern[256]; ++ int len_short_intern = 0; ++ int len_short_extern = 0; ++ if (pEvent->ShortText()) ++ len_short_intern = snprintf (buffer_short_intern, sizeof(buffer_short_intern)-1, "%s", pEvent->ShortText()); ++ if (pPreviousEvent->ShortText()) ++ len_short_extern = snprintf (buffer_short_extern, sizeof(buffer_short_extern)-1, "%s", pPreviousEvent->ShortText()); ++ if (len_short_intern > 0) { ++ if (len_short_extern < 1) ++ pPreviousEvent->SetShortText(buffer_short_intern); ++ else if (len_short_intern > len_short_extern) ++ pPreviousEvent->SetShortText(buffer_short_intern); ++ } ++ if (pEvent->Description()) { ++ char buffer_title_intern[4096]; ++ char buffer_title_extern[4096]; ++ int len_title_intern = 0; ++ int len_title_extern = 0; ++ if (pEvent->Description()) ++ len_title_intern = snprintf (buffer_title_intern, sizeof(buffer_title_intern)-1, "%s", pEvent->Description()); ++ if (pPreviousEvent->Description()) ++ len_title_extern = snprintf (buffer_title_extern, sizeof(buffer_title_extern)-1, "%s", pPreviousEvent->Description()); ++ if (len_title_intern > 0) { ++ if (len_title_extern < 1) ++ pPreviousEvent->SetDescription(buffer_title_intern); ++ else if (len_title_intern > len_title_extern) ++ pPreviousEvent->SetDescription(buffer_title_intern); ++ } ++ } ++ if (pPreviousEvent->Vps() == 0 && pEvent->Vps() != 0) ++ pPreviousEvent->SetVps(pEvent->Vps()); ++ pSchedule->DelEvent(pEvent); ++ pPreviousEvent->FixEpgBugs(); ++ } ++ else ++ pSchedule->DelEvent(pPreviousEvent); ++ } ++ } ++#endif /* DDEPGENTRY */ + } + if (Tid == 0x4E) { + if (Empty && getSectionNumber() == 0) +@@ -299,10 +498,26 @@ cTDT::cTDT(const u_char *Data) + time_t sattim = getTime(); + time_t loctim = time(NULL); + ++#ifdef USE_SETTIME ++ char timestr[20]; ++ struct tm *ptm; ++ struct tm tm_r; ++ ptm = localtime_r(&sattim, &tm_r); ++#endif /* SETTIME */ ++ + int diff = abs(sattim - loctim); + if (diff > 2) { + mutex.Lock(); + if (abs(diff - lastDiff) < 3) { ++#ifdef USE_SETTIME ++ if (SetTime) { ++ strftime(timestr, 20, "%m%d%H%M%Y.%S", ptm); ++ cString cmd = cString::sprintf("%s %s %ld", SetTime, timestr, sattim); ++ dsyslog("Executing: %s", *cmd); ++ SystemExec(cmd); ++ } ++ else ++#endif /* SETTIME */ + if (stime(&sattim) == 0) + isyslog("system time changed from %s (%ld) to %s (%ld)", *TimeToString(loctim), loctim, *TimeToString(sattim), sattim); + else +diff -ruNp vdr-1.7.5/eitscan.c vdr-1.7.5-extensions/eitscan.c +--- vdr-1.7.5/eitscan.c 2006-01-07 15:10:17.000000000 +0100 ++++ vdr-1.7.5-extensions/eitscan.c 2009-04-12 13:37:59.000000000 +0200 +@@ -151,9 +151,17 @@ void cEITScanner::Process(void) + if (Device->ProvidesTransponder(Channel)) { + if (!Device->Receiving()) { + bool MaySwitchTransponder = Device->MaySwitchTransponder(); ++#ifdef USE_LNBSHARE ++ if (MaySwitchTransponder && Device->GetMaxBadPriority(Channel) == -2 || Device->ProvidesTransponderExclusively(Channel) && Device->GetMaxBadPriority(Channel) <= -1 && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#else + if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) { ++#endif /* LNBSHARE */ + if (!MaySwitchTransponder) { ++#ifdef USE_LNBSHARE ++ if ((Device == cDevice::ActualDevice() || Device->GetMaxBadPriority(Channel) == -1) && !currentChannel) { ++#else + if (Device == cDevice::ActualDevice() && !currentChannel) { ++#endif /* LNBSHARE */ + cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode + currentChannel = Device->CurrentChannel(); + Skins.Message(mtInfo, tr("Starting EPG scan")); +diff -ruNp vdr-1.7.5/epg.c vdr-1.7.5-extensions/epg.c +--- vdr-1.7.5/epg.c 2008-05-01 16:53:55.000000000 +0200 ++++ vdr-1.7.5-extensions/epg.c 2009-04-12 13:37:59.000000000 +0200 +@@ -114,6 +114,11 @@ cEvent::cEvent(tEventID EventID) + components = NULL; + startTime = 0; + duration = 0; ++#ifdef USE_PARENTALRATING ++ for (int i = 0; i < MAXEVCONTENTS; i++) ++ contents[i] = 0; ++ parentalRating = 0; ++#endif /* PARENTALRATING */ + vps = 0; + SetSeen(); + } +@@ -202,6 +207,19 @@ void cEvent::SetDuration(int Duration) + duration = Duration; + } + ++#ifdef USE_PARENTALRATING ++void cEvent::SetContents(uchar *Contents) ++{ ++ for (int i = 0; i < MAXEVCONTENTS; i++) ++ contents[i] = Contents[i]; ++} ++ ++void cEvent::SetParentalRating(uchar ParentalRating) ++{ ++ parentalRating = ParentalRating; ++} ++#endif /* PARENTALRATING */ ++ + void cEvent::SetVps(time_t Vps) + { + vps = Vps; +@@ -257,6 +275,340 @@ cString cEvent::GetVpsString(void) const + return buf; + } + ++#ifdef USE_PARENTALRATING ++cString cEvent::GetContentsString(int i) const ++{ ++ cString str(""); ++ switch (contents[i] & 0xF0) { ++ case EVCONTENTMASK_MOVIEDRAMA: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Movie/Drama")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Detective/Thriller")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Adventure/Western/War")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Science Fiction/Fantasy/Horror")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Comedy")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Soap/Melodrama/Folkloric")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Romance")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Serious/Classical/Religious/Historical Movie/Drama")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Adult Movie/Drama")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_NEWSCURRENTAFFAIRS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$News/Current Affairs")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$News/Weather Report")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$News Magazine")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Documentary")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Discussion/Inverview/Debate")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SHOW: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Show/Game Show")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Game Show/Quiz/Contest")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Variety Show")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Talk Show")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SPORTS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Sports")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Special Event")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Sport Magazine")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Football")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Tennis/Squash")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Team Sports")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Athletics")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Motor Sport")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Water Sport")); ++ break; ++ case 0x09: ++ str = cString(tr("Content$Winter Sports")); ++ break; ++ case 0x0A: ++ str = cString(tr("Content$Equestrian")); ++ break; ++ case 0x0B: ++ str = cString(tr("Content$Martial Sports")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_CHILDRENYOUTH: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Children's/Youth Programmes")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Pre-school Children's Programmes")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Entertainment Programmes for 6 to 14")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Entertainment Programmes for 10 to 16")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Informational/Educational/School Programme")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Cartoons/Puppets")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_MUSICBALLETDANCE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Music/Ballet/Dance")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Rock/Pop")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Serious/Classical Music")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Folk/Tradional Music")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Jazz")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Musical/Opera")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Ballet")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_ARTSCULTURE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Arts/Culture")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Performing Arts")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Fine Arts")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Religion")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Popular Culture/Traditional Arts")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Literature")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Film/Cinema")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Experimental Film/Video")); ++ break; ++ case 0x08: ++ str = cString(tr("Content$Broadcasting/Press")); ++ break; ++ case 0x09: ++ str = cString(tr("Content$New Media")); ++ break; ++ case 0x0A: ++ str = cString(tr("Content$Arts/Culture Magazines")); ++ break; ++ case 0x0B: ++ str = cString(tr("Content$Fashion")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SOCIALPOLITICALECONOMICS: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Social/Political/Economics")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Magazines/Reports/Documentary")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Economics/Social Advisory")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Remarkable People")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_EDUCATIONALSCIENCE: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Education/Science/Factual")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Nature/Animals/Environment")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Technology/Natural Sciences")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Medicine/Physiology/Psychology")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Foreign Countries/Expeditions")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Social/Spiritual Sciences")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Further Education")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Languages")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_LEISUREHOBBIES: ++ switch (contents[i] & 0x0F) { ++ default: ++ case 0x00: ++ str = cString(tr("Content$Leisure/Hobbies")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Tourism/Travel")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Handicraft")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Motoring")); ++ break; ++ case 0x04: ++ str = cString(tr("Content$Fitness & Health")); ++ break; ++ case 0x05: ++ str = cString(tr("Content$Cooking")); ++ break; ++ case 0x06: ++ str = cString(tr("Content$Advertisement/Shopping")); ++ break; ++ case 0x07: ++ str = cString(tr("Content$Gardening")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_SPECIAL: ++ switch (contents[i] & 0x0F) { ++ case 0x00: ++ str = cString(tr("Content$Original Language")); ++ break; ++ case 0x01: ++ str = cString(tr("Content$Black & White")); ++ break; ++ case 0x02: ++ str = cString(tr("Content$Unpublished")); ++ break; ++ case 0x03: ++ str = cString(tr("Content$Live Broadcast")); ++ break; ++ default: ++ str = cString(tr("Content$Special Characteristics")); ++ break; ++ } ++ break; ++ ++ case EVCONTENTMASK_USERDEFINED: ++ switch (contents[i] & 0x0F) { ++ case 0x00: ++ str = cString(tr("Content$Drama")); // UK Freeview ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ return str; ++} ++ ++cString cEvent::GetParentalRatingString(void) const ++{ ++ if (parentalRating > 0) ++ return cString::sprintf(tr("Suitable for those aged %d and over"), parentalRating); ++ return NULL; ++} ++#endif /* PARENTALRATING */ ++ + void cEvent::Dump(FILE *f, const char *Prefix, bool InfoOnly) const + { + if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) { +@@ -744,6 +1096,28 @@ const cEvent *cSchedule::GetEventAround( + return pe; + } + ++#ifdef USE_DDEPGENTRY ++const cEvent *cSchedule::GetPreviousEvent(cEvent *Event) const ++{ ++ if (!Event || Event->Duration() == 0 || Event->StartTime() == 0) ++ return NULL; ++ // Returns either the event info to the previous/following event to the given EventID or, if that one can't be found NULL :EW ++ cEvent *pt = NULL; ++ int epgTimeDelta = Setup.DoubleEpgTimeDelta * 60 + 1; ++ for (pt = events.First(); pt; pt = events.Next(pt)) ++ if (pt && pt->TableID() == 0x00) ++ if ((Event->StartTime() - pt->StartTime()) > - epgTimeDelta && (Event->StartTime() - pt->StartTime()) < epgTimeDelta) { ++ if ((pt->Duration() + (pt->Duration()/ 5) + 1) > Event->Duration() && (pt->Duration() - (pt->Duration()/ 5) - 1) < Event->Duration()) ++ return pt; ++ else if (pt->Title() && Event->Title() && (strcmp(pt->Title(), ".") != 0 && strcmp(Event->Title(), ".") != 0)) { ++ if (strstr(pt->Title(), Event->Title()) != NULL || strstr(Event->Title(), pt->Title()) != NULL) ++ return pt; ++ } ++ } ++ return NULL; ++} ++#endif /* DDEPGENTRY */ ++ + void cSchedule::SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel) + { + hasRunning = false; +diff -ruNp vdr-1.7.5/epg.h vdr-1.7.5-extensions/epg.h +--- vdr-1.7.5/epg.h 2006-10-07 15:47:19.000000000 +0200 ++++ vdr-1.7.5-extensions/epg.h 2009-04-12 13:37:59.000000000 +0200 +@@ -50,6 +50,22 @@ class cSchedule; + + typedef u_int32_t tEventID; + ++#ifdef USE_PARENTALRATING ++#define MAXEVCONTENTS 4 ++#define EVCONTENTMASK_MOVIEDRAMA 0x10 ++#define EVCONTENTMASK_NEWSCURRENTAFFAIRS 0x20 ++#define EVCONTENTMASK_SHOW 0x30 ++#define EVCONTENTMASK_SPORTS 0x40 ++#define EVCONTENTMASK_CHILDRENYOUTH 0x50 ++#define EVCONTENTMASK_MUSICBALLETDANCE 0x60 ++#define EVCONTENTMASK_ARTSCULTURE 0x70 ++#define EVCONTENTMASK_SOCIALPOLITICALECONOMICS 0x80 ++#define EVCONTENTMASK_EDUCATIONALSCIENCE 0x90 ++#define EVCONTENTMASK_LEISUREHOBBIES 0xA0 ++#define EVCONTENTMASK_SPECIAL 0xB0 ++#define EVCONTENTMASK_USERDEFINED 0xF0 ++#endif /* PARENTALRATING */ ++ + class cEvent : public cListObject { + friend class cSchedule; + private: +@@ -64,6 +80,10 @@ private: + cComponents *components; // The stream components of this event + time_t startTime; // Start time of this event + int duration; // Duration of this event in seconds ++#ifdef USE_PARENTALRATING ++ uchar contents[MAXEVCONTENTS + 1]; // Contents of this event; list is zero-terminated ++ uchar parentalRating; // Parental rating of this event ++#endif /* PARENTALRATING */ + time_t vps; // Video Programming Service timestamp (VPS, aka "Programme Identification Label", PIL) + time_t seen; // When this event was last seen in the data stream + public: +@@ -83,6 +103,10 @@ public: + time_t StartTime(void) const { return startTime; } + time_t EndTime(void) const { return startTime + duration; } + int Duration(void) const { return duration; } ++#ifdef USE_PARENTALRATING ++ uchar Contents(int i = 0) const { return (0 <= i && i < MAXEVCONTENTS) ? contents[i] : 0; } ++ uchar ParentalRating(void) const { return parentalRating; } ++#endif /* PARENTALRATING */ + time_t Vps(void) const { return vps; } + time_t Seen(void) const { return seen; } + bool SeenWithin(int Seconds) const { return time(NULL) - seen < Seconds; } +@@ -92,6 +116,10 @@ public: + cString GetTimeString(void) const; + cString GetEndTimeString(void) const; + cString GetVpsString(void) const; ++#ifdef USE_PARENTALRATING ++ cString GetContentsString(int i = 0) const; ++ cString GetParentalRatingString(void) const; ++#endif /* PARENTALRATING */ + void SetEventID(tEventID EventID); + void SetTableID(uchar TableID); + void SetVersion(uchar Version); +@@ -102,6 +130,10 @@ public: + void SetComponents(cComponents *Components); // Will take ownership of Components! + void SetStartTime(time_t StartTime); + void SetDuration(int Duration); ++#ifdef USE_PARENTALRATING ++ void SetContents(uchar *Contents); ++ void SetParentalRating(uchar ParentalRating); ++#endif /* PARENTALRATING */ + void SetVps(time_t Vps); + void SetSeen(void); + cString ToDescr(void) const; +@@ -137,6 +169,9 @@ public: + void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); + void Cleanup(time_t Time); + void Cleanup(void); ++#ifdef USE_DDEPGENTRY ++ const cEvent *GetPreviousEvent(cEvent *Event) const; //:EW ++#endif /* DDEPGENTRY */ + cEvent *AddEvent(cEvent *Event); + void DelEvent(cEvent *Event); + void HashEvent(cEvent *Event); +diff -ruNp vdr-1.7.5/HISTORY-liemikuutio vdr-1.7.5-extensions/HISTORY-liemikuutio +--- vdr-1.7.5/HISTORY-liemikuutio 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/HISTORY-liemikuutio 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,116 @@ ++----------------------------------- ++Liemikuutio for Video Disc Recorder ++ ++Maintainer: Rolf Ahrenberg ++----------------------------------- ++ ++2006-01-08: Version 1.0 ++ ++- Based on enAIO with these original patches: ++ Simple recordings sorting by Walter@VDRPortal ++ Alternate rename recordings by Ralf Müller ++ Menu selection by Peter Dittmann ++ Recording length by Tobias Faust ++ ++2006-01-15: Version 1.1 ++ ++- Removed patches already found in vdr-1.3.39. ++ ++2006-01-25: Version 1.2 ++ ++- Added "Main menu command position" feature. ++ ++2006-02-05: Version 1.3 ++ ++- Improved menu selection response. ++ ++2006-04-18: Version 1.4 ++ ++- Added Estonian translation (Thanks to Arthur Konovalov). ++ ++2006-04-30: Version 1.5 ++ ++- Added progress bar view into "What's on now?" menu. ++ ++2006-06-06: Version 1.6 ++ ++- Added French translation (Thanks to ECLiPSE). ++ ++2006-06-14: Version 1.7 ++ ++- Fixed RENR crash. ++ ++2006-07-14: Version 1.8 ++ ++- Fixed RENR/OSD bug. ++ ++2006-08-27: Version 1.9 ++ ++- Some modifications to the recording length and rename recordings ++ patches (Thanks to Firefly). ++- Added k1_k3_jumps_20s patch by Petri Hintukainen. ++ ++2006-08-29: Version 1.10 ++ ++- The cRecording:Title() method now defaults to original formatting. ++ ++2006-09-04: Version 1.11 ++ ++- Removed unused variable from cRecording::Title() method (Thanks to ++ C.Y.M.). ++- Some modifications to the rename recordings patch (Thanks to Firefly). ++ ++2006-09-13: Version 1.12 ++ ++- More modifications to the rename recordings patch (Thanks to Firefly). ++ ++2006-10-01: Version 1.13 ++ ++- Removed unnecessary syslog printing (Thanks to Firefly). ++ ++2007-08-14: Version 1.14 ++ ++- Updated for vdr-1.5.7. ++ ++2007-10-16: Version 1.15 ++ ++- Added recmenu play patch (Thanks to Ville Skyttä). ++- Updated French translation (Thanks to ECLiPSE). ++ ++2007-11-04: Version 1.16 ++ ++- Updated for vdr-1.5.11. ++ ++2007-12-08: Version 1.17 ++ ++- Added binary skip patch. ++- Removed k1_k3_jumps_20s patch. ++ ++2008-02-17: Version 1.18 ++ ++- Updated for vdr-1.5.15. ++ ++2008-03-02: Version 1.19 ++ ++- Modified binary skip to use kPrev and kNext keys and the skip is now ++ always shortened after a direction change (Thanks to Timo Eskola). ++- Readded k1_k3_jumps_20s patch. ++ ++2008-04-04: Version 1.20 ++ ++- Added bitrate information into rename menu. ++- Readded the path editing support of rename recordings patch (Thanks ++ to Firefly). ++ ++2008-05-08: Version 1.21 ++ ++- Fixed rename recordings (Thanks to Firefly). ++- Added a DVB subtitles hack for old recordings (Thanks to Anssi Hannula). ++ ++2009-01-08: Version 1.22 ++ ++- Updated for vdr-1.7.3. ++ ++2009-01-25: Version 1.23 ++ ++- Updated for vdr-1.7.4. +diff -ruNp vdr-1.7.5/iconpatch.c vdr-1.7.5-extensions/iconpatch.c +--- vdr-1.7.5/iconpatch.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/iconpatch.c 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,31 @@ ++#ifdef USE_WAREAGLEICON ++ ++#include "iconpatch.h" ++ ++#include <langinfo.h> ++#include <locale.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++bool IsLangUtf8(void) ++{ ++ char *CodeSet = NULL; ++ if (setlocale(LC_CTYPE, "")) ++ CodeSet = nl_langinfo(CODESET); ++ else { ++ char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed ++ if (LangEnv) { ++ CodeSet = strchr(LangEnv, '.'); ++ if (CodeSet) ++ CodeSet++; // skip the dot ++ } ++ } ++ ++ if (CodeSet && strcasestr(CodeSet, "UTF-8") != 0) ++ return true; ++ ++ return false; ++} ++ ++#endif /* WAREAGLEICON */ +diff -ruNp vdr-1.7.5/iconpatch.h vdr-1.7.5-extensions/iconpatch.h +--- vdr-1.7.5/iconpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/iconpatch.h 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,73 @@ ++#ifdef USE_WAREAGLEICON ++/* ++ * iconpatch.h: Information of iconpatch ++ * ++ * Diese Datei ist die Übersichtsdatei für den Iconpatch. ++ * Hier werden kleine Infos abgelegt. ++ * Der Iconpatch ändert die Dateien: ++ * iconpatch.h ++ * menu.c ++ * recording.c ++ * fontosd.c ++ * ++ */ ++ ++// Iconpatch-Variablen - Anfang ++#define ICON_NUMBERSIGN "\x23" ++#define ICON_ASTERISK "\x2A" ++#define ICON_GREATER "\x3E" ++#define ICON_EXCLAM "\x21" ++#define ICON_PLUSMINUS "\xB1" ++ ++#define ICON_RESUME "\x80" ++#define ICON_DVD "\x81" ++#define ICON_FOLDER "\x82" ++#define ICON_BLANK "\x83" ++#define ICON_CUTTING "\x84" ++#define ICON_MOVE_FILE "\x85" ++#define ICON_MOVE_FOLDER "\x86" ++#define ICON_BAR_START "\x87" ++#define ICON_BAR_FILLED "\x88" ++#define ICON_BAR_CLEAR "\x89" ++#define ICON_BAR_END "\x8A" ++#define ICON_REC "\x8B" ++#define ICON_CLOCK "\x8C" ++#define ICON_TV_CRYPTED "\x8D" ++#define ICON_RADIO "\x8E" ++#define ICON_TV "\x8F" ++#define ICON_NEW "\x90" ++#define ICON_ARROW "\x91" ++#define ICON_RUNNING "\x92" ++#define ICON_VPS "\x93" ++#define ICON_CLOCK_UH "\x94" ++#define ICON_CLOCK_LH "\x95" ++ ++// UTF-8 Icons ++#define ICON_RESUME_UTF8 "\uE000" ++#define ICON_DVD_UTF8 "\uE001" ++#define ICON_FOLDER_UTF8 "\uE002" ++#define ICON_BLANK_UTF8 "\uE003" ++#define ICON_CUTTING_UTF8 "\uE004" ++#define ICON_MOVE_FILE_UTF8 "\uE005" ++#define ICON_MOVE_FOLDER_UTF8 "\uE006" ++#define ICON_BAR_START_UTF8 "\uE007" ++#define ICON_BAR_FILLED_UTF8 "\uE008" ++#define ICON_BAR_EMPTY_UTF8 "\uE009" ++#define ICON_BAR_CLOSE_UTF8 "\uE00A" ++#define ICON_REC_UTF8 "\uE00B" ++#define ICON_CLOCK_UTF8 "\uE00C" ++#define ICON_TV_CRYPTED_UTF8 "\uE00D" ++#define ICON_RADIO_UTF8 "\uE00E" ++#define ICON_TV_UTF8 "\uE00F" ++#define ICON_NEW_UTF8 "\uE010" ++#define ICON_ARROW_UTF8 "\uE011" ++#define ICON_RUNNING_UTF8 "\uE012" ++#define ICON_VPS_UTF8 "\uE013" ++#define ICON_CLOCK_UH_UTF8 "\uE014" ++#define ICON_CLOCK_LH_UTF8 "\uE015" ++ ++// Iconpatch-Variablen - Ende ++ ++bool IsLangUtf8(void); ++ ++#endif /* WAREAGLEICON */ +diff -ruNp vdr-1.7.5/keys.h vdr-1.7.5-extensions/keys.h +--- vdr-1.7.5/keys.h 2007-08-26 14:34:50.000000000 +0200 ++++ vdr-1.7.5-extensions/keys.h 2009-04-12 13:37:59.000000000 +0200 +@@ -71,6 +71,10 @@ enum eKeys { // "Up" and "Down" must be + #define kEditCut k2 + #define kEditTest k8 + ++#ifdef USE_DVDARCHIVE ++#define kDvdChapterJumpForward k6 ++#define kDvdChapterJumpBack k4 ++#endif /* DVDARCHIVE */ + #define RAWKEY(k) (eKeys((k) & ~k_Flags)) + #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) + #define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) +diff -ruNp vdr-1.7.5/lirc.c vdr-1.7.5-extensions/lirc.c +--- vdr-1.7.5/lirc.c 2006-05-28 10:48:13.000000000 +0200 ++++ vdr-1.7.5-extensions/lirc.c 2009-04-12 13:37:59.000000000 +0200 +@@ -12,6 +12,9 @@ + #include "lirc.h" + #include <netinet/in.h> + #include <sys/socket.h> ++#ifdef USE_LIRCSETTINGS ++#include "config.h" ++#endif /* LIRCSETTINGS */ + + #define REPEATDELAY 350 // ms + #define REPEATFREQ 100 // ms +@@ -94,7 +97,11 @@ void cLircRemote::Action(void) + continue; + } + if (count == 0) { ++#ifdef USE_LIRCSETTINGS ++ if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast + if (repeat) + Put(LastKeyName, false, true); +@@ -104,18 +111,34 @@ void cLircRemote::Action(void) + timeout = -1; + } + else { ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() < (unsigned int)Setup.LircRepeatFreq) ++#else + if (LastTime.Elapsed() < REPEATFREQ) ++#endif /* LIRCSETTINGS */ + continue; // repeat function kicks in after a short delay (after last key instead of first key) ++#ifdef USE_LIRCSETTINGS ++ if (FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) ++#else + if (FirstTime.Elapsed() < REPEATDELAY) ++#endif /* LIRCSETTINGS */ + continue; // skip keys coming in too fast (for count != 0 as well) + repeat = true; ++#ifdef USE_LIRCSETTINGS ++ timeout = Setup.LircRepeatDelay; ++#else + timeout = REPEATDELAY; ++#endif /* LIRCSETTINGS */ + } + LastTime.Set(); + Put(KeyName, repeat); + } + else if (repeat) { // the last one was a repeat, so let's generate a release ++#ifdef USE_LIRCSETTINGS ++ if (LastTime.Elapsed() >= (unsigned int)Setup.LircRepeatTimeout) { ++#else + if (LastTime.Elapsed() >= REPEATTIMEOUT) { ++#endif /* LIRCSETTINGS */ + Put(LastKeyName, false, true); + repeat = false; + *LastKeyName = 0; +diff -ruNp vdr-1.7.5/mainmenuitemsprovider.h vdr-1.7.5-extensions/mainmenuitemsprovider.h +--- vdr-1.7.5/mainmenuitemsprovider.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/mainmenuitemsprovider.h 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,62 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MAINMENUITEMSPROVIDER_H ++#define __MAINMENUITEMSPROVIDER_H ++ ++#include <vector> ++ ++class cOsdItem; ++class cOsdMenu; ++ ++class IMenuItemDefinition ++{ ++ public: ++ virtual ~IMenuItemDefinition() {}; ++ virtual bool IsCustomOsdItem() = 0; ++ virtual bool IsPluginItem() = 0; ++ virtual bool IsSeparatorItem() = 0; ++ virtual cOsdItem* CustomOsdItem() = 0; ++ virtual const char* PluginMenuEntry() = 0; ++ virtual bool IsSelected() = 0; ++ virtual int PluginIndex() = 0; ++}; ++ ++typedef std::vector<IMenuItemDefinition*> MenuItemDefinitions; ++ ++#define MENU_ITEMS_PROVIDER_SERVICE_ID "MenuOrgPatch-v0.4.2::MainMenuItemsProvider" ++ ++class IMainMenuItemsProvider ++{ ++ public: ++ virtual ~IMainMenuItemsProvider() {}; ++ virtual bool IsCustomMenuAvailable() = 0; ++ virtual MenuItemDefinitions* MainMenuItems() = 0; ++ virtual void EnterRootMenu() = 0; ++ virtual void EnterSubMenu(cOsdItem* item) = 0; ++ virtual bool LeaveSubMenu() = 0; ++ virtual cOsdMenu* Execute(cOsdItem* item) = 0; ++}; ++ ++#endif //__MAINMENUITEMSPROVIDER_H ++#endif /* MENUORG */ +diff -ruNp vdr-1.7.5/Make.config.template vdr-1.7.5-extensions/Make.config.template +--- vdr-1.7.5/Make.config.template 2009-01-18 11:46:13.000000000 +0100 ++++ vdr-1.7.5-extensions/Make.config.template 2009-04-12 13:37:59.000000000 +0200 +@@ -42,8 +42,242 @@ RCU_DEVICE = /dev/ttyS1 + ## Define if you want vdr to not run as root + #VDR_USER = vdr + ++### VDR-Extensions: ++# Comment the patches you don't need ++# DVDCHAPJUMP needs DVDARCHIVE enabled ++# DVDARCHIVE needs LIEMIEXT enabled ++# SORTRECORDS needs LIEMIEXT enabled ++# you can only enable MENUORG or SETUP ++ ++#ANALOGTV = 1 ++#ATSC = 1 ++#CHANNELSCAN = 1 ++CMDRECCMDI18N = 1 ++CMDSUBMENU = 1 ++#CUTTERLIMIT = 1 ++#CUTTERQUEUE = 1 ++CUTTIME = 1 ++DDEPGENTRY = 1 ++#DELTIMESHIFTREC = 1 ++DOLBYINREC = 1 ++#DVBSETUP = 1 ++#DVDARCHIVE = 1 ++#DVDCHAPJUMP = 1 ++#DVLFRIENDLYFNAMES = 1 ++#DVLRECSCRIPTADDON = 1 ++#DVLVIDPREFER = 1 ++#EM84XX = 1 ++#GRAPHTFT = 1 ++#HARDLINKCUTTER = 1 ++#JUMPPLAY = 1 ++LIEMIEXT = 1 ++#LIRCSETTINGS = 1 ++#LNBSHARE = 1 ++#MAINMENUHOOKS = 1 ++#MENUORG = 1 ++#NOEPG = 1 ++#OSDMAXITEMS = 1 ++#PARENTALRATING = 1 ++#PINPLUGIN = 1 ++PLUGINAPI = 1 ++PLUGINMISSING = 1 ++#PLUGINPARAM = 1 ++#ROTOR = 1 ++SETTIME = 1 ++#SETUP = 1 ++#SOFTOSD = 1 ++#SOURCECAPS = 1 ++#SORTRECORDS = 1 ++STREAMDEVEXT = 1 ++#TIMERCMD = 1 ++#TIMERINFO = 1 ++#VALIDINPUT = 1 ++#VOLCTRL = 1 ++WAREAGLEICON = 1 ++#YAEPG = 1 ++ + ### You don't need to touch the following: + + ifdef DVBDIR + INCLUDES += -I$(DVBDIR)/include + endif ++ ++ifdef ANALOGTV ++DEFINES += -DUSE_ANALOGTV ++endif ++ ++ifdef ATSC ++DEFINES += -DUSE_ATSC ++endif ++ ++ifdef CHANNELSCAN ++DEFINES += -DUSE_CHANNELSCAN ++endif ++ ++ifdef CMDRECCMDI18N ++DEFINES += -DUSE_CMDRECCMDI18N ++endif ++ ++ifdef CMDSUBMENU ++DEFINES += -DUSE_CMDSUBMENU ++endif ++ ++ifdef CUTTERLIMIT ++DEFINES += -DUSE_CUTTERLIMIT ++endif ++ ++ifdef CUTTERQUEUE ++DEFINES += -DUSE_CUTTERQUEUE ++endif ++ ++ifdef CUTTIME ++DEFINES += -DUSE_CUTTIME ++endif ++ ++ifdef DDEPGENTRY ++DEFINES += -DUSE_DDEPGENTRY ++endif ++ ++ifdef DELTIMESHIFTREC ++DEFINES += -DUSE_DELTIMESHIFTREC ++endif ++ ++ifdef DOLBYINREC ++DEFINES += -DUSE_DOLBYINREC ++endif ++ ++ifdef DVBSETUP ++DEFINES += -DUSE_DVBSETUP ++endif ++ ++ifdef DVDARCHIVE ++ifdef LIEMIEXT ++DEFINES += -DUSE_DVDARCHIVE ++endif ++endif ++ ++ifdef DVLRECSCRIPTADDON ++DEFINES += -DUSE_DVLRECSCRIPTADDON ++endif ++ ++ifdef DVLVIDPREFER ++DEFINES += -DUSE_DVLVIDPREFER ++endif ++ ++ifdef DVLFRIENDLYFNAMES ++DEFINES += -DUSE_DVLFRIENDLYFNAMES ++endif ++ ++ifdef EM84XX ++DEFINES += -DUSE_EM84XX ++endif ++ ++ifdef GRAPHTFT ++DEFINES += -DUSE_GRAPHTFT ++endif ++ ++ifdef HARDLINKCUTTER ++DEFINES += -DUSE_HARDLINKCUTTER ++endif ++ ++ifdef JUMPPLAY ++DEFINES += -DUSE_JUMPPLAY ++endif ++ ++ifdef LIEMIEXT ++DEFINES += -DUSE_LIEMIEXT ++endif ++ ++ifdef LIRCSETTINGS ++DEFINES += -DUSE_LIRCSETTINGS ++endif ++ ++ifdef LNBSHARE ++DEFINES += -DUSE_LNBSHARE ++endif ++ ++ifdef MAINMENUHOOKS ++DEFINES += -DUSE_MAINMENUHOOKS ++endif ++ ++ifdef MENUORG ++DEFINES += -DUSE_MENUORG ++else ++ifdef SETUP ++DEFINES += -DUSE_SETUP ++endif ++endif ++ ++ifdef NOEPG ++DEFINES += -DUSE_NOEPG ++endif ++ ++ifdef OSDMAXITEMS ++DEFINES += -DUSE_OSDMAXITEMS ++endif ++ ++ifdef PARENTALRATING ++DEFINES += -DUSE_PARENTALRATING ++endif ++ ++ifdef PINPLUGIN ++DEFINES += -DUSE_PINPLUGIN ++endif ++ ++ifdef PLUGINMISSING ++DEFINES += -DUSE_PLUGINMISSING ++endif ++ ++ifdef PLUGINPARAM ++DEFINES += -DUSE_PLUGINPARAM ++endif ++ ++ifdef ROTOR ++DEFINES += -DUSE_ROTOR ++endif ++ ++ifdef SETTIME ++DEFINES += -DUSE_SETTIME ++endif ++ ++ifdef SOFTOSD ++DEFINES += -DUSE_SOFTOSD ++endif ++ ++ifdef SOURCECAPS ++DEFINES += -DUSE_SOURCECAPS ++endif ++ ++ifdef SORTRECORDS ++ifdef LIEMIEXT ++DEFINES += -DUSE_SORTRECORDS ++endif ++endif ++ ++ifdef STREAMDEVEXT ++DEFINES += -DUSE_STREAMDEVEXT ++endif ++ ++ifdef TIMERCMD ++DEFINES += -DUSE_TIMERCMD ++endif ++ ++ifdef TIMERINFO ++DEFINES += -DUSE_TIMERINFO ++endif ++ ++ifdef VALIDINPUT ++DEFINES += -DUSE_VALIDINPUT ++endif ++ ++ifdef VOLCTRL ++DEFINES += -DUSE_VOLCTRL ++endif ++ ++ifdef WAREAGLEICON ++DEFINES += -DUSE_WAREAGLEICON ++endif ++ ++ifdef YAEPG ++DEFINES += -DUSE_YAEPG ++endif +diff -ruNp vdr-1.7.5/Makefile vdr-1.7.5-extensions/Makefile +--- vdr-1.7.5/Makefile 2008-12-24 16:21:09.000000000 +0100 ++++ vdr-1.7.5-extensions/Makefile 2009-04-12 13:37:59.000000000 +0200 +@@ -43,6 +43,14 @@ OBJS = audio.o channels.o ci.o config.o + skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\ + timers.o tools.o transfer.o vdr.o videodir.o + ++ifdef WAREAGLEICON ++OBJS += iconpatch.o ++endif ++ ++ifdef SETUP ++OBJS += tinystr.o tinyxml.o tinyxmlerror.o tinyxmlparser.o submenu.o ++endif ++ + ifndef NO_KBD + DEFINES += -DREMOTE_KBD + endif +@@ -72,6 +80,14 @@ DEFINES += -DLOCDIR=\"$(LOCDIR)\" + VDRVERSION = $(shell sed -ne '/define VDRVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h) + APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h) + ++ifdef DVDARCHIVE ++ifdef DVDCHAPJUMP ++LIBS += -ldvdread ++INCLUDES += -I/usr/include/dvdread ++DEFINES += -DUSE_DVDCHAPJUMP ++endif ++endif ++ + all: vdr i18n + + # Implicit rules: +@@ -137,6 +153,26 @@ include-dir: + + # Plugins: + ++ifdef PLUGINAPI ++DEFINES += -DUSE_PLUGINAPI ++plugins: include-dir ++ @failed="";\ ++ noapiv="";\ ++ for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do\ ++ echo "Plugin $$i:";\ ++ if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ ++ sed -i -e s/VDRVERSION/APIVERSION/g $(PLUGINDIR)/src/$$i/Makefile;\ ++ if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ ++ echo "ERROR: plugin $$i doesn't honor APIVERSION - not compiled!";\ ++ noapiv="$$noapiv $$i";\ ++ continue;\ ++ fi;\ ++ fi;\ ++ $(MAKE) -C "$(PLUGINDIR)/src/$$i" all || failed="$$failed $$i";\ ++ done;\ ++ if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ ++ if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; fi ++else + plugins: include-dir + @failed="";\ + noapiv="";\ +@@ -151,6 +187,7 @@ plugins: include-dir + done;\ + if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ + if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; exit 1; fi ++endif + + clean-plugins: + @for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/src/$$i" clean; done +diff -ruNp vdr-1.7.5/MANUAL vdr-1.7.5-extensions/MANUAL +--- vdr-1.7.5/MANUAL 2008-02-24 11:09:17.000000000 +0100 ++++ vdr-1.7.5-extensions/MANUAL 2009-04-12 13:37:59.000000000 +0200 +@@ -813,6 +813,30 @@ Version 1.6 + 0 resulting in a file named 'resume.vdr', and any other + value resulting in 'resume.n.vdr'. + ++ Jump&Play = no Turns playing on or off after jumping forward to the ++ next editing mark with the '9' key. ++ ++ Play&Jump = no Turns automatic jumping over commercial breaks on or ++ off. This includes jumping to the first mark, if the ++ replay starts at the beginning of a recording - and ++ stopping the replay at the last mark. ++ With this setting enabled, the behaviour of the '8' ++ key during replay is changed too. It moves the actual ++ replay position not only three seconds before the ++ next "start" mark, but also before the next "end" ++ mark. This can be used to test, if the editing marks ++ are correctly positioned for a "smooth" jump over a ++ commercial break. ++ ++ Pause at last mark = no ++ Turns pausing of replay at the last editing mark on or ++ off. ++ ++ Reload marks = no Turns reloading of editing marks on or off. This can ++ be used if an external programme adjusts the editing ++ marks, e.g. noad in online mode. The marks are reloaded ++ in 10 seconds intervals. ++ + Miscellaneous: + + Min. event timeout = 30 +diff -ruNp vdr-1.7.5/menu.c vdr-1.7.5-extensions/menu.c +--- vdr-1.7.5/menu.c 2009-01-24 16:05:43.000000000 +0100 ++++ vdr-1.7.5-extensions/menu.c 2009-04-12 13:37:59.000000000 +0200 +@@ -8,12 +8,18 @@ + */ + + #include "menu.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <limits.h> + #include <math.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> ++#ifdef USE_LIEMIEXT ++#include <math.h> ++#endif /* LIEMIEXT */ + #include "channels.h" + #include "config.h" + #include "cutter.h" +@@ -30,6 +36,13 @@ + #include "timers.h" + #include "transfer.h" + #include "videodir.h" ++#ifdef USE_MENUORG ++#include "menuorgpatch.h" ++#endif /* MENUORG */ ++ ++#ifdef USE_CMDRECCMDI18N ++extern const char *ConfigDirectory; ++#endif /* CMDRECCMDI18N */ + + #define MAXWAIT4EPGINFO 3 // seconds + #define MODETIMEOUT 3 // seconds +@@ -190,10 +203,16 @@ private: + cChannel *channel; + cChannel data; + char name[256]; ++#ifdef USE_PLUGINPARAM ++ char pluginParam[256]; ++#endif /* PLUGINPARAM */ + void Setup(void); + public: + cMenuEditChannel(cChannel *Channel, bool New = false); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEditChannel"; } ++#endif /* GRAPHTFT */ + }; + + cMenuEditChannel::cMenuEditChannel(cChannel *Channel, bool New) +@@ -222,6 +241,9 @@ void cMenuEditChannel::Setup(void) + + // Parameters for all types of sources: + strn0cpy(name, data.name, sizeof(name)); ++#ifdef USE_PLUGINPARAM ++ strn0cpy(pluginParam, data.pluginParam, sizeof(pluginParam)); ++#endif /* PLUGINPARAM */ + Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name))); + Add(new cMenuEditSrcItem( tr("Source"), &data.source)); + Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); +@@ -254,6 +276,9 @@ void cMenuEditChannel::Setup(void) + ST(" T") Add(new cMenuEditMapItem( tr("Guard"), &data.guard, GuardValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Hierarchy"), &data.hierarchy, HierarchyValues)); + ST(" S ") Add(new cMenuEditMapItem( tr("Rolloff"), &data.rollOff, RollOffValues)); ++#ifdef USE_PLUGINPARAM ++ ST("P ") Add(new cMenuEditStrItem( tr("Parameters"), pluginParam, sizeof(pluginParam), tr(FileNameChars))); ++#endif /* PLUGINPARAM */ + + SetCurrent(Get(current)); + Display(); +@@ -268,9 +293,15 @@ eOSState cMenuEditChannel::ProcessKey(eK + if (Key == kOk) { + if (Channels.HasUniqueChannelID(&data, channel)) { + data.name = strcpyrealloc(data.name, name); ++#ifdef USE_PLUGINPARAM ++ data.pluginParam = strcpyrealloc(data.pluginParam, pluginParam); ++#endif /* PLUGINPARAM */ + if (channel) { + *channel = data; + isyslog("edited channel %d %s", channel->Number(), *data.ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scMod); ++#endif /* STREAMDEVEXT */ + state = osBack; + } + else { +@@ -279,6 +310,9 @@ eOSState cMenuEditChannel::ProcessKey(eK + Channels.Add(channel); + Channels.ReNumber(); + isyslog("added channel %d %s", channel->Number(), *data.ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scAdd); ++#endif /* STREAMDEVEXT */ + state = osUser1; + } + Channels.SetModified(true); +@@ -341,6 +375,16 @@ void cMenuChannelItem::Set(void) + if (!channel->GroupSep()) { + if (sortMode == csmProvider) + buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name()); ++#ifdef USE_WAREAGLEICON ++ else if (Setup.WarEagleIcons) { ++ if (channel->Vpid() == 1 || channel->Vpid() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_RADIO_UTF8 : ICON_RADIO, channel->Name()); ++ else if (channel->Ca() == 0) ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_UTF8 : ICON_TV, channel->Name()); ++ else ++ buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_CRYPTED_UTF8 : ICON_TV_CRYPTED, channel->Name()); ++ } ++#endif /* WAREAGLEICON */ + else + buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name()); + } +@@ -371,6 +415,9 @@ public: + cMenuChannels(void); + ~cMenuChannels(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuChannels"; } ++#endif /* GRAPHTFT */ + }; + + cMenuChannels::cMenuChannels(void) +@@ -500,6 +547,9 @@ eOSState cMenuChannels::Delete(void) + Propagate(); + Channels.SetModified(true); + isyslog("channel %d deleted", DeletedChannel); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NULL, scDel); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -525,6 +575,9 @@ void cMenuChannels::Move(int From, int T + Propagate(); + Channels.SetModified(true); + isyslog("channel %d moved to %d", FromNumber, ToNumber); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(ToChannel, scMod); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -637,14 +690,47 @@ cMenuEditTimer::cMenuEditTimer(cTimer *T + data.SetFlags(tfActive); + channel = data.Channel()->Number(); + Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive)); ++#ifdef USE_PINPLUGIN ++ if (cOsd::pinValid) Add(new cMenuEditChanItem(tr("Channel"), &channel)); ++ else { ++ cString buf = cString::sprintf("%s\t%s", tr("Channel"), Channels.GetByNumber(channel)->Name()); ++ Add(new cOsdItem(buf)); ++ } ++#else + Add(new cMenuEditChanItem(tr("Channel"), &channel)); ++#endif /* PINPLUGIN */ + Add(new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays)); + Add(new cMenuEditTimeItem(tr("Start"), &data.start)); + Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); + Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps)); + Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); ++#ifdef USE_PINPLUGIN ++ if (cOsd::pinValid || !data.fskProtection) Add(new cMenuEditBoolItem(tr("Childlock"),&data.fskProtection)); ++ else { ++ cString buf = cString::sprintf("%s\t%s", tr("Childlock"), data.fskProtection ? tr("yes") : tr("no")); ++ Add(new cOsdItem(buf)); ++ } ++#endif /* PINPLUGIN */ ++#ifdef USE_LIEMIEXT ++ char* p = strrchr(data.file, '~'); ++ if (p) { ++ p++; ++ Utf8Strn0Cpy(name, p, sizeof(name)); ++ Utf8Strn0Cpy(path, data.file, sizeof(path)); ++ p = strrchr(path, '~'); ++ if (p) ++ p[0] = 0; ++ } ++ else { ++ Utf8Strn0Cpy(name, data.file, sizeof(name)); ++ Utf8Strn0Cpy(path, "", sizeof(path)); ++ } ++ Add(new cMenuEditStrItem(tr("File"), name, sizeof(name), tr(FileNameChars))); ++ Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path))); ++#else + Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); ++#endif /* LIEMIEXT */ + SetFirstDayItem(); + } + Timers.IncBeingEdited(); +@@ -684,6 +770,12 @@ eOSState cMenuEditTimer::ProcessKey(eKey + Skins.Message(mtError, tr("*** Invalid Channel ***")); + break; + } ++#ifdef USE_LIEMIEXT ++ if (strlen(path)) ++ snprintf(data.file, sizeof(data.file), "%s~%s", path, name); ++ else ++ snprintf(data.file, sizeof(data.file), "%s", name); ++#endif /* LIEMIEXT */ + if (!*data.file) + strcpy(data.file, data.Channel()->ShortName(true)); + if (timer) { +@@ -711,13 +803,37 @@ eOSState cMenuEditTimer::ProcessKey(eKey + return state; + } + ++#ifdef USE_TIMERCMD ++// --- cMenuCommands --------------------------------------------------------- ++// declaration shifted so it can be used in cMenuTimers ++class cMenuCommands : public cOsdMenu { ++private: ++ cCommands *commands; ++ char *parameters; ++ eOSState Execute(void); ++public: ++ cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); ++ virtual ~cMenuCommands(); ++ virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCommands"; } ++#endif /* GRAPHTFT - passt das so? */ ++ }; ++#endif /* TIMERCMD */ ++ + // --- cMenuTimerItem -------------------------------------------------------- + + class cMenuTimerItem : public cOsdItem { + private: + cTimer *timer; ++#ifdef USE_TIMERINFO ++ char diskStatus; ++#endif /* TIMERINFO */ + public: + cMenuTimerItem(cTimer *Timer); ++#ifdef USE_TIMERINFO ++ void SetDiskStatus(char DiskStatus); ++#endif /* TIMERINFO */ + virtual int Compare(const cListObject &ListObject) const; + virtual void Set(void); + cTimer *Timer(void) { return timer; } +@@ -726,6 +842,9 @@ public: + cMenuTimerItem::cMenuTimerItem(cTimer *Timer) + { + timer = Timer; ++#ifdef USE_TIMERINFO ++ diskStatus = ' '; ++#endif /* TIMERINFO */ + Set(); + } + +@@ -751,8 +870,56 @@ void cMenuTimerItem::Set(void) + strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r); + day = buffer; + } ++#ifdef USE_LIEMIEXT ++ if (!Setup.ShowTimerStop) { ++#ifdef USE_TIMERINFO ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++ diskStatus, ++#else ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++#endif /* TIMERINFO */ ++#ifdef USE_WAREAGLEICON ++ !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", ++#else ++ !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', ++#endif /* WAREAGLEICON */ ++ timer->Channel()->Number(), ++ *name, ++ *name && **name ? " " : "", ++ *day, ++ timer->Start() / 100, ++ timer->Start() % 100, ++ timer->File())); ++ } ++ else { ++#endif /* LIEMIEXT */ ++#ifdef USE_TIMERINFO ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#else ++ SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++ diskStatus, ++#else ++#ifdef USE_WAREAGLEICON ++ SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#else + SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", ++#endif /* WAREAGLEICON */ ++#endif /* TIMERINFO */ ++#ifdef USE_WAREAGLEICON ++ !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", ++#else + !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', ++#endif /* WAREAGLEICON */ + timer->Channel()->Number(), + *name, + *name && **name ? " " : "", +@@ -762,8 +929,64 @@ void cMenuTimerItem::Set(void) + timer->Stop() / 100, + timer->Stop() % 100, + timer->File())); ++#ifdef USE_LIEMIEXT ++ } ++#endif /* LIEMIEXT */ ++} ++ ++#ifdef USE_TIMERINFO ++void cMenuTimerItem::SetDiskStatus(char DiskStatus) ++{ ++ diskStatus = DiskStatus; ++ Set(); ++} ++ ++// --- cTimerEntry ----------------------------------------------------------- ++ ++class cTimerEntry : public cListObject { ++private: ++ cMenuTimerItem *item; ++ const cTimer *timer; ++ time_t start; ++public: ++ cTimerEntry(cMenuTimerItem *item) : item(item), timer(item->Timer()), start(timer->StartTime()) {} ++ cTimerEntry(const cTimer *timer, time_t start) : item(NULL), timer(timer), start(start) {} ++ virtual int Compare(const cListObject &ListObject) const; ++ bool active(void) const { return timer->HasFlags(tfActive); } ++ time_t startTime(void) const { return start; } ++ int priority(void) const { return timer->Priority(); } ++ int duration(void) const; ++ bool repTimer(void) const { return !timer->IsSingleEvent(); } ++ bool isDummy(void) const { return item == NULL; } ++ const cTimer *Timer(void) const { return timer; } ++ void SetDiskStatus(char DiskStatus); ++ }; ++ ++int cTimerEntry::Compare(const cListObject &ListObject) const ++{ ++ cTimerEntry *entry = (cTimerEntry *)&ListObject; ++ int r = startTime() - entry->startTime(); ++ if (r == 0) ++ r = entry->priority() - priority(); ++ return r; ++} ++ ++int cTimerEntry::duration(void) const ++{ ++ int dur = (timer->Stop() / 100 * 60 + timer->Stop() % 100) - ++ (timer->Start() / 100 * 60 + timer->Start() % 100); ++ if (dur < 0) ++ dur += 24 * 60; ++ return dur; + } + ++void cTimerEntry::SetDiskStatus(char DiskStatus) ++{ ++ if (item) ++ item->SetDiskStatus(DiskStatus); ++} ++#endif /* TIMERINFO */ ++ + // --- cMenuTimers ----------------------------------------------------------- + + class cMenuTimers : public cOsdMenu { +@@ -776,14 +999,31 @@ private: + eOSState Info(void); + cTimer *CurrentTimer(void); + void SetHelpKeys(void); ++#ifdef USE_TIMERINFO ++ void ActualiseDiskStatus(void); ++ bool actualiseDiskStatus; ++#endif /* TIMERINFO */ ++#ifdef USE_TIMERCMD ++ eOSState Commands(eKeys Key = kNone); ++#endif /* TIMERCMD */ + public: + cMenuTimers(void); + virtual ~cMenuTimers(); ++#ifdef USE_TIMERINFO ++ virtual void Display(void); ++#endif /* TIMERINFO */ + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuTimers"; } ++#endif /* GRAPHTFT */ + }; + + cMenuTimers::cMenuTimers(void) ++#ifdef USE_TIMERINFO ++:cOsdMenu(tr("Timers"), 3, CHNUMWIDTH, 10, 6, 6) ++#else + :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6) ++#endif /* TIMERINFO */ + { + helpKeys = -1; + for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { +@@ -794,6 +1034,9 @@ cMenuTimers::cMenuTimers(void) + SetCurrent(First()); + SetHelpKeys(); + Timers.IncBeingEdited(); ++#ifdef USE_TIMERINFO ++ actualiseDiskStatus = true; ++#endif /* TIMERINFO */ + } + + cMenuTimers::~cMenuTimers() +@@ -832,7 +1075,11 @@ eOSState cMenuTimers::OnOff(void) + timer->OnOff(); + timer->SetEventFromSchedule(); + RefreshCurrent(); ++#ifdef USE_TIMERINFO ++ Display(); ++#else + DisplayCurrent(true); ++#endif /* TIMERINFO */ + if (timer->FirstDay()) + isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay()); + else +@@ -891,6 +1138,117 @@ eOSState cMenuTimers::Info(void) + return osContinue; + } + ++#ifdef USE_TIMERCMD ++#define CHECK_2PTR_NULL(x_,y_) ((x_)? ((y_)? y_:""):"") ++ ++eOSState cMenuTimers::Commands(eKeys Key) ++{ ++ if (HasSubMenu() || Count() == 0) ++ return osContinue; ++ cTimer *ti = CurrentTimer(); ++ if (ti) { ++ const cEvent *pEvent = ti->Event(); ++ int iRecNumber=0; ++ ++ if (!pEvent) { ++ Timers.SetEvents(); ++ pEvent = ti->Event(); ++ } ++ if (pEvent) { ++ // create a dummy recording to get the real filename ++ cRecording *rc_dummy = new cRecording(ti, pEvent); ++ Recordings.Load(); ++ cRecording *rc = Recordings.GetByName(rc_dummy->FileName()); ++ ++ delete rc_dummy; ++ if (rc) ++ iRecNumber=rc->Index() + 1; ++ } ++ // TODO: Geht das so...? ++ // Parameter format TimerNumber 'ChannelId' Start Stop 'Titel' 'Subtitel' 'file' RecNumer ++ // 1 2 3 4 5 6 7 8 ++ cString parameter = cString::sprintf("%d '%s' %d %d '%s' '%s' '%s' %d", ti->Index(), ++ *ti->Channel()->GetChannelID().ToString(), ++ (int)ti->StartTime(), ++ (int)ti->StopTime(), ++ CHECK_2PTR_NULL(pEvent, pEvent->Title()), ++ CHECK_2PTR_NULL(pEvent, pEvent->ShortText()), ++ ti->File(), ++ iRecNumber); ++ isyslog("timercmd: %s", *parameter); ++ cMenuCommands *menu; ++ eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Timer commands"), &TimerCommands, parameter)); ++ if (Key != kNone) ++ state = menu->ProcessKey(Key); ++ return state; ++ } ++ return osContinue; ++} ++#endif /* TIMERCMD */ ++ ++#ifdef USE_TIMERINFO ++void cMenuTimers::ActualiseDiskStatus(void) ++{ ++ if (!actualiseDiskStatus || !Count()) ++ return; ++ ++ // compute free disk space ++ int freeMB, freeMinutes, runshortMinutes; ++ VideoDiskSpace(&freeMB); ++ freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent ++ runshortMinutes = freeMinutes / 5; // 20 Percent ++ ++ // fill entries list ++ cTimerEntry *entry; ++ cList<cTimerEntry> entries; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ entries.Add(new cTimerEntry((cMenuTimerItem *)item)); ++ ++ // search last start time ++ time_t last = 0; ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ last = max(entry->startTime(), last); ++ ++ // add entries for repeating timers ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) ++ if (entry->repTimer() && !entry->isDummy()) ++ for (time_t start = cTimer::IncDay(entry->startTime(), 1); ++ start <= last; ++ start = cTimer::IncDay(start, 1)) ++ if (entry->Timer()->DayMatches(start)) ++ entries.Add(new cTimerEntry(entry->Timer(), start)); ++ ++ // set the disk-status ++ entries.Sort(); ++ for (entry = entries.First(); entry; entry = entries.Next(entry)) { ++ char status = ' '; ++ if (entry->active()) { ++ freeMinutes -= entry->duration(); ++ status = freeMinutes > runshortMinutes ? '+' : freeMinutes > 0 ? '~' /* ± 177 +/- */ : '-'; ++ } ++ entry->SetDiskStatus(status); ++#ifdef DEBUG_TIMER_INFO ++ dsyslog("timer-info: %c | %d | %s | %s | %3d | %+5d -> %+5d", ++ status, ++ entry->startTime(), ++ entry->active() ? "aktiv " : "n.akt.", ++ entry->repTimer() ? entry->isDummy() ? " dummy " : "mehrmalig" : "einmalig ", ++ entry->duration(), ++ entry->active() ? freeMinutes + entry->duration() : freeMinutes, ++ freeMinutes); ++#endif ++ } ++ ++ actualiseDiskStatus = false; ++} ++ ++void cMenuTimers::Display(void) ++{ ++ ActualiseDiskStatus(); ++ cOsdMenu::Display(); ++} ++#endif /* TIMERINFO */ ++ + eOSState cMenuTimers::ProcessKey(eKeys Key) + { + int TimerNumber = HasSubMenu() ? Count() : -1; +@@ -899,18 +1257,40 @@ eOSState cMenuTimers::ProcessKey(eKeys K + if (state == osUnknown) { + switch (Key) { + case kOk: return Edit(); ++#ifdef USE_TIMERINFO ++ case kRed: actualiseDiskStatus = true; ++ state = OnOff(); break; // must go through SetHelpKeys()! ++#else + case kRed: state = OnOff(); break; // must go through SetHelpKeys()! ++#endif /* TIMERINFO */ + case kGreen: return New(); ++#ifdef USE_TIMERINFO ++ case kYellow: actualiseDiskStatus = true; ++ state = Delete(); break; ++#else + case kYellow: state = Delete(); break; ++#endif /* TIMERINFO */ + case kInfo: + case kBlue: return Info(); + break; ++#ifdef USE_TIMERCMD ++ case k1...k9: return Commands(Key); ++ case k0: return (TimerCommands.Count()? Commands():osContinue); ++#endif /* TIMERCMD */ + default: break; + } + } ++#ifdef USE_TIMERINFO ++ if (TimerNumber >= 0 && !HasSubMenu()) { ++ if (Timers.Get(TimerNumber)) // a newly created timer was confirmed with Ok ++ Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++ Sort(); ++ actualiseDiskStatus = true; ++#else + if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) { + // a newly created timer was confirmed with Ok + Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); ++#endif /* TIMERINFO */ + Display(); + } + if (Key != kNone) +@@ -940,6 +1320,9 @@ void cMenuEvent::Display(void) + { + cOsdMenu::Display(); + DisplayMenu()->SetEvent(event); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetEvent(event); ++#endif /* GRAPHTFT */ + if (event->Description()) + cStatus::MsgOsdTextItem(event->Description()); + } +@@ -987,7 +1370,12 @@ public: + const cChannel *channel; + bool withDate; + int timerMatch; ++#ifdef USE_LIEMIEXT ++ bool withBar; ++ cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false, bool WithBar = false); ++#else + cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false); ++#endif /* LIEMIEXT */ + static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; } + static void IncSortMode(void) { sortMode = eScheduleSortMode((sortMode == ssmAllAll) ? ssmAllThis : sortMode + 1); } + static eScheduleSortMode SortMode(void) { return sortMode; } +@@ -997,12 +1385,19 @@ public: + + cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis; + ++#ifdef USE_LIEMIEXT ++cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate, bool WithBar) ++#else + cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate) ++#endif /* LIEMIEXT */ + { + event = Event; + channel = Channel; + withDate = WithDate; + timerMatch = tmNone; ++#ifdef USE_LIEMIEXT ++ withBar = WithBar; ++#endif /* LIEMIEXT */ + Update(true); + } + +@@ -1017,7 +1412,29 @@ int cMenuScheduleItem::Compare(const cLi + return r; + } + ++#ifdef USE_LIEMIEXT ++static const char * const ProgressBar[7] = ++{ ++ "[ ]", ++ "[| ]", ++ "[|| ]", ++ "[||| ]", ++ "[|||| ]", ++ "[||||| ]", ++ "[||||||]" ++}; ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_WAREAGLEICON ++static const char *TimerMatchChars[9] = ++{ ++ " ", "t", "T", ++ ICON_BLANK, ICON_CLOCK_UH, ICON_CLOCK, ++ ICON_BLANK_UTF8, ICON_CLOCK_UH_UTF8, ICON_CLOCK_UTF8 ++}; ++#else + static const char *TimerMatchChars = " tT"; ++#endif /* WAREAGLEICON */ + + bool cMenuScheduleItem::Update(bool Force) + { +@@ -1026,17 +1443,54 @@ bool cMenuScheduleItem::Update(bool Forc + Timers.GetMatch(event, &timerMatch); + if (Force || timerMatch != OldTimerMatch) { + cString buffer; ++#ifdef USE_WAREAGLEICON ++ const char *t = Setup.WarEagleIcons ? IsLangUtf8() ? TimerMatchChars[timerMatch+6] : TimerMatchChars[timerMatch+3] : TimerMatchChars[timerMatch]; ++ const char *v = event->Vps() && (event->Vps() - event->StartTime()) ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_VPS_UTF8 : ICON_VPS : "V" : " "; ++ const char *r = event->SeenWithin(30) && event->IsRunning() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_RUNNING_UTF8 : ICON_RUNNING : "*" : " "; ++#else + char t = TimerMatchChars[timerMatch]; + char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; + char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + const char *csn = channel ? channel->ShortName(true) : NULL; + cString eds = event->GetDateString(); + if (channel && withDate) ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + else if (channel) ++#ifdef USE_LIEMIEXT ++ if (Setup.ShowProgressBar && withBar) { ++ int progress = (int)roundf( (float)(time(NULL) - event->StartTime()) / (float)(event->Duration()) * 6.0 ); ++ if (progress < 0) progress = 0; ++ else if (progress > 6) progress = 6; ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++ } ++ else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ ++#endif /* LIEMIEXT */ + else ++#ifdef USE_WAREAGLEICON ++ buffer = cString::sprintf("%.*s\t%s\t%s%s%s\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#else + buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); ++#endif /* WAREAGLEICON */ + SetText(buffer); + result = true; + } +@@ -1062,13 +1516,21 @@ public: + static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } + static const cEvent *ScheduleEvent(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return now ? "MenuWhatsOnNow" : "MenuWhatsOnNext"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + int cMenuWhatsOn::currentChannel = 0; + const cEvent *cMenuWhatsOn::scheduleEvent = NULL; + + cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4, 4) ++#else + :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4) ++#endif /* LIEMIEXT */ + { + now = Now; + helpKeys = -1; +@@ -1080,7 +1542,11 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu + if (Schedule) { + const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); + if (Event) ++#ifdef USE_LIEMIEXT ++ Add(new cMenuScheduleItem(Event, Channel, false, Now), Channel->Number() == CurrentChannelNr); ++#else + Add(new cMenuScheduleItem(Event, Channel), Channel->Number() == CurrentChannelNr); ++#endif /* LIEMIEXT */ + } + } + } +@@ -1089,6 +1555,19 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu + SetHelpKeys(); + } + ++#ifdef USE_GRAPHTFT ++void cMenuWhatsOn::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++} ++#endif /* GRAPHTFT */ ++ + bool cMenuWhatsOn::Update(void) + { + bool result = false; +@@ -1229,6 +1708,10 @@ public: + cMenuSchedule(void); + virtual ~cMenuSchedule(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSchedule"; } ++ virtual void Display(void); ++#endif /* GRAPHTFT */ + }; + + cMenuSchedule::cMenuSchedule(void) +@@ -1254,6 +1737,19 @@ cMenuSchedule::~cMenuSchedule() + cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared + } + ++#ifdef USE_GRAPHTFT ++void cMenuSchedule::Display(void) ++{ ++ cOsdMenu::Display(); ++ ++ if (Count() > 0) { ++ int ni = 0; ++ for (cOsdItem *item = First(); item; item = Next(item)) ++ cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); ++ } ++} ++#endif /* GRAPHTFT */ ++ + void cMenuSchedule::PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel) + { + Clear(); +@@ -1487,6 +1983,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys + + // --- cMenuCommands --------------------------------------------------------- + ++#ifndef USE_TIMERCMD + class cMenuCommands : public cOsdMenu { + private: + cCommands *commands; +@@ -1496,7 +1993,11 @@ public: + cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); + virtual ~cMenuCommands(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCommands"; } ++#endif /* GRAPHTFT */ + }; ++#endif /* TIMERCMD */ + + cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters) + :cOsdMenu(Title) +@@ -1518,6 +2019,12 @@ eOSState cMenuCommands::Execute(void) + cCommand *command = commands->Get(Current()); + if (command) { + bool confirmed = true; ++#ifdef USE_CMDSUBMENU ++ if (command->hasChilds()) { ++ AddSubMenu(new cMenuCommands(command->Title(), command->getChilds(), parameters)); ++ return osContinue; ++ } ++#endif /* CMDSUBMENU */ + if (command->Confirm()) + confirmed = Interface->Confirm(cString::sprintf("%s?", command->Title())); + if (confirmed) { +@@ -1568,6 +2075,9 @@ public: + cMenuCam(cCamSlot *CamSlot); + virtual ~cMenuCam(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuCam::cMenuCam(cCamSlot *CamSlot) +@@ -1747,6 +2257,9 @@ public: + cMenuRecording(const cRecording *Recording, bool WithButtons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRecording"; } ++#endif /* GRAPHTFT */ + }; + + cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons) +@@ -1762,6 +2275,9 @@ void cMenuRecording::Display(void) + { + cOsdMenu::Display(); + DisplayMenu()->SetRecording(recording); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdSetRecording(recording); ++#endif /* GRAPHTFT */ + if (recording->Info()->Description()) + cStatus::MsgOsdTextItem(recording->Info()->Description()); + } +@@ -1822,7 +2338,11 @@ cMenuRecordingItem::cMenuRecordingItem(c + fileName = strdup(Recording->FileName()); + name = NULL; + totalEntries = newEntries = 0; ++#ifdef USE_LIEMIEXT ++ SetText(Recording->Title('\t', true, Level, false)); ++#else + SetText(Recording->Title('\t', true, Level)); ++#endif /* LIEMIEXT */ + if (*Text() == '\t') + name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t' + } +@@ -1838,13 +2358,198 @@ void cMenuRecordingItem::IncrementCounte + totalEntries++; + if (New) + newEntries++; ++#ifdef USE_LIEMIEXT ++#ifdef USE_WAREAGLEICON ++ switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { ++ case 0: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s %s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, name)); ++ else ++ SetText(cString::sprintf("%s", name)); ++ break; ++ case 1: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s %d\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%s", totalEntries, name)); ++ break; ++ case 2: ++ default: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++ break; ++ case 3: ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++ SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); ++ break; ++ } ++#else ++ switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { ++ case 0: ++ SetText(cString::sprintf("%s", name)); ++ break; ++ case 1: ++ SetText(cString::sprintf("%d\t%s", totalEntries, name)); ++ break; ++ case 2: ++ default: ++ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++ break; ++ case 3: ++ SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); ++ break; ++ } ++#endif /* WAREAGLEICON */ ++#else ++#ifdef USE_WAREAGLEICON ++ if (Setup.WarEagleIcons) ++ SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); ++ else ++#endif /* WAREAGLEICON */ + SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); ++#endif /* LIEMIEXT */ ++} ++ ++#ifdef USE_LIEMIEXT ++// --- cMenuRenameRecording -------------------------------------------------- ++ ++class cMenuRenameRecording : public cOsdMenu { ++private: ++ char name[MaxFileName]; ++ char path[MaxFileName]; ++ cOsdItem *marksItem, *resumeItem; ++ bool isResume, isMarks; ++ cRecording *recording; ++public: ++ cMenuRenameRecording(cRecording *Recording); ++ virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRenameRecording"; } ++#endif /* GRAPHTFT */ ++}; ++ ++cMenuRenameRecording::cMenuRenameRecording(cRecording *Recording) ++:cOsdMenu(tr("Rename recording"), 12) ++{ ++ cMarks marks; ++ ++ recording = Recording; ++ ++ char* p = strrchr(recording->Name(), '~'); ++ if (p) { ++ p++; ++ Utf8Strn0Cpy(name, p, sizeof(name)); ++ Utf8Strn0Cpy(path, recording->Name(), sizeof(path)); ++ p = strrchr(path, '~'); ++ if (p) ++ p[0] = 0; ++ } ++ else { ++ Utf8Strn0Cpy(name, recording->Name(), sizeof(name)); ++ Utf8Strn0Cpy(path, "", sizeof(path)); ++ } ++ Add(new cMenuEditStrItem(tr("Name"), name, sizeof(name), tr(FileNameChars))); ++ Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path) )); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Date"), *DayDateTime(recording->start)), osUnknown, false)); ++ ++ cChannel *channel = Channels.GetByChannelID(((cRecordingInfo *)recording->Info())->ChannelID()); ++ if (channel) ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Channel"), *ChannelString(channel, 0)), osUnknown, false)); ++ ++ cIndexFile *index = new cIndexFile(recording->FileName(), false); ++ int recLen = 0; ++ if (index) { ++ recLen = int(index->Last() / recording->FramesPerSecond()); ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Length"), *IndexToHMSF(index->Last())), osUnknown, false)); ++ delete index; ++ } ++ ++ int dirSize = DirSizeMB(recording->FileName()); ++ cString bitRate = recLen ? cString::sprintf(" (%.2f MBit/s)", 8.0 * dirSize / recLen) : cString(""); ++ Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Format"), recording->IsPesRecording() ? tr("PES") : tr("TS")), osUnknown, false)); ++ Add(new cOsdItem((dirSize > 9999) ? cString::sprintf("%s:\t%.2f GB%s", tr("Size"), dirSize / 1024.0, *bitRate) : cString::sprintf("%s:\t%d MB%s", tr("Size"), dirSize, *bitRate), osUnknown, false)); ++ ++ Add(new cOsdItem("", osUnknown, false)); ++ ++ isMarks = marks.Load(recording->FileName()) && marks.Count(); ++ marksItem = new cOsdItem(tr("Delete marks information?"), osUser1, isMarks); ++ Add(marksItem); ++ ++ cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); ++ isResume = (ResumeFile.Read() != -1); ++ resumeItem = new cOsdItem(tr("Delete resume information?"), osUser2, isResume); ++ Add(resumeItem); ++} ++ ++eOSState cMenuRenameRecording::ProcessKey(eKeys Key) ++{ ++ eOSState state = cOsdMenu::ProcessKey(Key); ++ ++ if (state == osUnknown) { ++ if (Key == kOk) { ++ char buffer[MaxFileName]; ++ if (Utf8StrLen(path)) ++ snprintf(buffer, sizeof(buffer), "%s~%s", path, name); ++ else ++ snprintf(buffer, sizeof(buffer), "%s", name); ++ if (recording->Rename(buffer)) { ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ return osRecordings; ++ } ++ else ++ Skins.Message(mtError, tr("Error while accessing recording!")); ++ } ++ return osContinue; ++ } ++ else if (state == osUser1) { ++ if (isMarks && Interface->Confirm(tr("Delete marks information?"))) { ++ cMarks marks; ++ marks.Load(recording->FileName()); ++ cMark *mark = marks.First(); ++ while (mark) { ++ cMark *nextmark = marks.Next(mark); ++ marks.Del(mark); ++ mark = nextmark; ++ } ++ marks.Save(); ++ isMarks = false; ++ marksItem->SetSelectable(isMarks); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ else if (state == osUser2) { ++ if (isResume && Interface->Confirm(tr("Delete resume information?"))) { ++ cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); ++ ResumeFile.Delete(); ++ isResume = false; ++ resumeItem->SetSelectable(isResume); ++ SetCurrent(First()); ++ Display(); ++ } ++ return osContinue; ++ } ++ return state; + } ++#endif /* LIEMIEXT */ + + // --- cMenuRecordings ------------------------------------------------------- + + cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) ++#ifdef USE_LIEMIEXT ++:cOsdMenu(Base ? Base : tr("Recordings"), 9, 7, 7) ++#else + :cOsdMenu(Base ? Base : tr("Recordings"), 9, 7) ++#endif /* LIEMIEXT */ + { + base = Base ? strdup(Base) : NULL; + level = Setup.RecordingDirs ? Level : -1; +@@ -1921,7 +2626,12 @@ void cMenuRecordings::Set(bool Refresh) + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { + if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == '~')) { + cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); ++#ifdef USE_PINPLUGIN ++ if ((*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) ++ && (!cStatus::MsgReplayProtected(GetRecording(Item), Item->Name(), base, Item->IsDirectory(), true))) { ++#else + if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { ++#endif /* PINPLUGIN */ + Add(Item); + LastItem = Item; + free(LastItemText); +@@ -1971,13 +2681,43 @@ eOSState cMenuRecordings::Play(void) + { + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(GetRecording(ri), ri->Name(), base, ri->IsDirectory()) == true) ++ return osContinue; ++#endif /* PINPLUGIN */ + if (ri->IsDirectory()) + Open(); + else { + cRecording *recording = GetRecording(ri); + if (recording) { ++#ifdef USE_DVDARCHIVE ++ int mountRet = MOUNT_DVD_REPLAY; ++ if (recording->IsOnlyOnDvd()) { ++ mountRet = recording->MountDvd(); ++ } ++ if (mountRet == MOUNT_DVD_REPLAY) { ++ cReplayControl::SetRecording(recording->FileName(), recording->Title()); ++ return osReplay; ++ } ++ else if (mountRet == MOUNT_DVD_LAUNCH_DVD_PLUGIN) { ++ //launch DVD plugin here ++ cPlugin *p = cPluginManager::GetPlugin("dvd"); ++ cOsdObject *osd = NULL; ++ if (p) { ++ osd = p->MainMenuAction(); ++ delete osd; ++ osd = NULL; ++ return osEnd; ++ } ++ else { ++ Skins.Message(mtError, tr("DVD plugin is not installed!")); ++ Skins.Flush(); ++ } ++ } ++#else + cReplayControl::SetRecording(recording->FileName(), recording->Title()); + return osReplay; ++#endif /* DVDARCHIVE */ + } + } + } +@@ -2078,12 +2818,34 @@ eOSState cMenuRecordings::Commands(eKeys + return osContinue; + } + ++#ifdef USE_LIEMIEXT ++eOSState cMenuRecordings::Rename(void) ++{ ++ if (HasSubMenu() || Count() == 0) ++ return osContinue; ++ cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); ++ if (ri && !ri->IsDirectory()) { ++ cRecording *recording = GetRecording(ri); ++ if (recording) ++ return AddSubMenu(new cMenuRenameRecording(recording)); ++ } ++ return osContinue; ++} ++#endif /* LIEMIEXT */ ++ + eOSState cMenuRecordings::ProcessKey(eKeys Key) + { + bool HadSubMenu = HasSubMenu(); + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { ++#ifdef USE_SORTRECORDS ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ + switch (Key) { + case kPlay: + case kOk: return Play(); +@@ -2092,7 +2854,26 @@ eOSState cMenuRecordings::ProcessKey(eKe + case kYellow: return Delete(); + case kInfo: + case kBlue: return Info(); ++#ifdef USE_SORTRECORDS ++ case k0: Setup.RecordingsSortMode = ++Setup.RecordingsSortMode % MAXSORTMODES; ++ Set(true); ++ Skins.Message(mtStatus, cString::sprintf("%s %d: %s", tr("Sorting"), Setup.RecordingsSortMode, RecordingsSortModeTexts[Setup.RecordingsSortMode])); ++ return osContinue; ++ case k1...k7: return Commands(Key); ++ case k8: return Rename(); ++ case k9: Recordings.ToggleSortOrder(); ++ Set(true); ++ return osContinue; ++#elif defined (USE_LIEMIEXT) ++ case k0: DirOrderState = !DirOrderState; ++ Set(true); ++ return osContinue; ++ case k8: return Rename(); ++ case k9: ++ case k1...k7: return Commands(Key); ++#else + case k1...k9: return Commands(Key); ++#endif /* LIEMIEXT & SORTRECORDS */ + case kNone: if (Recordings.StateChanged(recordingsState)) + Set(true); + break; +@@ -2141,6 +2922,9 @@ void cMenuSetupBase::Store(void) + class cMenuSetupOSD : public cMenuSetupBase { + private: + const char *useSmallFontTexts[3]; ++#ifdef USE_LIEMIEXT ++ const char *mainMenuTitle[MAXMAINMENUTITLE]; ++#endif /* LIEMIEXT */ + int osdLanguageIndex; + int numSkins; + int originalSkinIndex; +@@ -2156,6 +2940,9 @@ public: + cMenuSetupOSD(void); + virtual ~cMenuSetupOSD(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupOsd"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupOSD::cMenuSetupOSD(void) +@@ -2191,12 +2978,21 @@ void cMenuSetupOSD::Set(void) + useSmallFontTexts[0] = tr("never"); + useSmallFontTexts[1] = tr("skin dependent"); + useSmallFontTexts[2] = tr("always"); ++#ifdef USE_LIEMIEXT ++ mainMenuTitle[0]=tr("default"); ++ mainMenuTitle[1]=tr("VDR - text"); ++ mainMenuTitle[2]=tr("text"); ++ mainMenuTitle[3]=tr("VDR - version"); ++#endif /* LIEMIEXT */ + Clear(); + SetSection(tr("OSD")); + Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0))); + Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions)); + if (themes.NumThemes()) + Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions())); ++#ifdef USE_WAREAGLEICON ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$WarEagle icons"), &data.WarEagleIcons)); ++#endif /* WAREAGLEICON */ + Add(new cMenuEditIntItem( tr("Setup.OSD$Left"), &data.OSDLeft, 0, MAXOSDWIDTH)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Top"), &data.OSDTop, 0, MAXOSDHEIGHT)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDWidth, MINOSDWIDTH, MAXOSDWIDTH)); +@@ -2218,6 +3014,24 @@ void cMenuSetupOSD::Set(void) + Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditStraItem(tr("Setup.OSD$Main menu title"), &data.MainMenuTitle, MAXMAINMENUTITLE, mainMenuTitle)); ++ if (data.MainMenuTitle == 1 || data.MainMenuTitle == 2) ++ Add(new cMenuEditStrItem(tr("Setup.OSD$- Text"), data.CustomMainMenuTitle, sizeof(data.CustomMainMenuTitle))); ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Main menu command position"), &data.MenuCmdPosition, tr("bottom"), tr("top"))); ++#endif /* LIEMIEXT */ ++#ifdef USE_VALIDINPUT ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Show valid input"), &data.ShowValidInput)); ++#endif /* VALIDINPUT */ ++#ifdef USE_SOFTOSD ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$Use SoftOSD"), &data.UseSoftOsd)); ++ if (data.UseSoftOsd) { ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD Rate"), &data.SoftOsdRate, 10, 100)); ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeIn Steps"), &data.SoftOsdFadeinSteps, 1, 100)); ++ Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeOut Steps"), &data.SoftOsdFadeoutSteps, 1, 100)); ++ Add(new cMenuEditBoolItem(tr("Setup.OSD$SoftOSD Palette Only"), &data.SoftOsdPaletteOnly)); ++ } ++#endif /* SOFTOSD */ + SetCurrent(Get(current)); + Display(); + } +@@ -2266,6 +3080,12 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + + int oldSkinIndex = skinIndex; + int oldOsdLanguageIndex = osdLanguageIndex; ++#ifdef USE_LIEMIEXT ++ int oldMainMenuTitle = data.MainMenuTitle; ++#endif /* LIEMIEXT */ ++#ifdef USE_SOFTOSD ++ bool newUseSoftOsd = data.UseSoftOsd; ++#endif /* SOFTOSD */ + eOSState state = cMenuSetupBase::ProcessKey(Key); + + if (ModifiedApperance) +@@ -2288,6 +3108,25 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + Set(); + I18nSetLanguage(OriginalOSDLanguage); + } ++ ++#ifdef USE_LIEMIEXT ++ if (data.MainMenuTitle != oldMainMenuTitle) ++ Set(); ++#endif /* LIEMIEXT */ ++#ifdef USE_SOFTOSD ++ if (data.UseSoftOsd != newUseSoftOsd) ++ Set(); ++#endif /* SOFTOSD */ ++#ifdef USE_CMDRECCMDI18N ++ if (Key == kOk) { ++ // try to load translated command files if available, otherwise fallback to defaults ++ LoadCommandsI18n(Commands, AddDirectory(ConfigDirectory, "commands.conf"), true); ++ LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory, "reccmds.conf"), true); ++#ifdef USE_TIMERCMD ++ LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true); ++#endif /* TIMERCMD */ ++ } ++#endif /* CMDRECCMDI18N */ + return state; + } + +@@ -2295,12 +3134,18 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys + + class cMenuSetupEPG : public cMenuSetupBase { + private: ++#ifdef USE_NOEPG ++ const char *noEPGModes[2]; ++#endif /* NOEPG */ + int originalNumLanguages; + int numLanguages; + void Setup(void); + public: + cMenuSetupEPG(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupEpg"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupEPG::cMenuSetupEPG(void) +@@ -2317,11 +3162,19 @@ void cMenuSetupEPG::Setup(void) + { + int current = Current(); + ++#ifdef USE_NOEPG ++ noEPGModes[0] = tr("blacklist"); ++ noEPGModes[1] = tr("whitelist"); ++#endif /* NOEPG */ ++ + Clear(); + + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0)); ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Show progress bar"), &data.ShowProgressBar)); ++#endif /* LIEMIEXT */ + Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); + if (data.SetSystemTime) + Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource)); +@@ -2330,6 +3183,15 @@ void cMenuSetupEPG::Setup(void) + for (int i = 0; i < numLanguages; i++) + // TRANSLATORS: note the singular! + Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); ++#ifdef USE_DDEPGENTRY ++ Add(new cMenuEditIntItem( tr("Setup.EPG$Period for double EPG search(min)"), &data.DoubleEpgTimeDelta)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Extern double Epg entry"), &data.DoubleEpgAction, tr("adjust"), tr("delete"))); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Mix intern and extern EPG"), &data.MixEpgAction)); ++ Add(new cMenuEditBoolItem(tr("Setup.EPG$Disable running VPS event"), &data.DisableVPS)); ++#endif /* DDEPGENTRY */ ++#ifdef USE_NOEPG ++ Add(new cMenuEditStraItem(tr("Setup.EPG$Mode of noEPG-Patch"), &data.noEPGMode, 2, noEPGModes)); ++#endif /* NOEPG */ + + SetCurrent(Get(current)); + Display(); +@@ -2386,6 +3248,10 @@ eOSState cMenuSetupEPG::ProcessKey(eKeys + + class cMenuSetupDVB : public cMenuSetupBase { + private: ++#ifdef USE_DVBSETUP ++ const char *ChannelBlockers[7]; ++ const char *ChannelBlockerModes[4]; ++#endif /* DVBSETUP */ + int originalNumAudioLanguages; + int numAudioLanguages; + int originalNumSubtitleLanguages; +@@ -2396,6 +3262,9 @@ private: + public: + cMenuSetupDVB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupDvb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupDVB::cMenuSetupDVB(void) +@@ -2424,6 +3293,21 @@ void cMenuSetupDVB::Setup(void) + { + int current = Current(); + ++#ifdef USE_DVBSETUP ++ ChannelBlockers[0] = tr("none"); ++ ChannelBlockers[1] = tr("qam256"); ++ ChannelBlockers[2] = tr("dvb-c"); ++ ChannelBlockers[3] = tr("dvb-s"); ++ ChannelBlockers[4] = tr("blacklist"); ++ ChannelBlockers[5] = tr("whitelist"); ++ ChannelBlockers[6] = tr("all"); ++ ++ ChannelBlockerModes[0] = tr("none"); ++ ChannelBlockerModes[1] = tr("has decoder"); ++ ChannelBlockerModes[2] = tr("is primary"); ++ ChannelBlockerModes[3] = tr("has decoder + is primary"); ++#endif /* DVBSETUP */ ++ + Clear(); + + Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices())); +@@ -2444,6 +3328,11 @@ void cMenuSetupDVB::Setup(void) + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9)); + Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10)); + } ++#ifdef USE_DVBSETUP ++ Add(new cMenuEditBoolItem(tr("Setup.DVB$Use AC3-Transfer Fix"), &data.DolbyTransferFix)); ++ Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker"), &data.ChannelBlocker, 7, ChannelBlockers)); ++ Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker Filter Mode"), &data.ChannelBlockerMode, 4, ChannelBlockerModes)); ++#endif /* DVBSETUP */ + + SetCurrent(Get(current)); + Display(); +@@ -2525,6 +3414,9 @@ private: + public: + cMenuSetupLNB(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupLnb"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupLNB::cMenuSetupLNB(void) +@@ -2539,6 +3431,23 @@ void cMenuSetupLNB::Setup(void) + + Clear(); + ++#ifdef USE_LNBSHARE ++ int numSatDevices = 0; ++ for (int i = 0; i < cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat)) numSatDevices++; ++ } ++ if (numSatDevices > 1) { ++ char tmp[30]; ++ for (int i = 1; i <= cDevice::NumDevices(); i++) { ++ if (cDevice::GetDevice(i - 1)->ProvidesSource(cSource::stSat)) { ++ sprintf( tmp, tr("Setup.LNB$DVB device %d uses LNB No."), i); ++ Add(new cMenuEditIntItem( tmp, &data.CardUsesLNBnr[i - 1], 1, numSatDevices )); ++ } ++ } ++ } ++ Add(new cMenuEditBoolItem(tr("Setup.LNB$Log LNB usage"), &data.VerboseLNBlog)); ++#endif /* LNBSHARE */ ++ + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); + if (!data.DiSEqC) { + Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); +@@ -2555,6 +3464,10 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys + int oldDiSEqC = data.DiSEqC; + eOSState state = cMenuSetupBase::ProcessKey(Key); + ++#ifdef USE_LNBSHARE ++ if (Key == kOk) cDevice::SetLNBnr(); ++#endif /* LNBSHARE */ ++ + if (Key != kNone && data.DiSEqC != oldDiSEqC) + Setup(); + return state; +@@ -2605,6 +3518,9 @@ private: + public: + cMenuSetupCAM(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupCam"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupCAM::cMenuSetupCAM(void) +@@ -2678,12 +3594,73 @@ eOSState cMenuSetupCAM::ProcessKey(eKeys + // --- cMenuSetupRecord ------------------------------------------------------ + + class cMenuSetupRecord : public cMenuSetupBase { ++#ifdef USE_SORTRECORDS ++private: ++ const char *RecordingsSortModeTexts[MAXSORTMODES]; ++#endif /* SORTRECORDS */ ++#ifdef USE_DELTIMESHIFTREC ++private: ++ const char *DelTimeshiftRecValues[3]; ++#endif /* DELTIMESHIFTREC */ + public: + cMenuSetupRecord(void); ++#ifdef USE_DVLVIDPREFER ++ eOSState ProcessKey(eKeys key); ++ ++private: ++ void Set(void); ++ ++ int tmpNVidPrefer, ++ tmpUseVidPrefer; ++#endif /* DVLVIDPREFER */ + }; + ++#ifdef USE_DVLVIDPREFER + cMenuSetupRecord::cMenuSetupRecord(void) + { ++ Set(); ++} ++ ++eOSState cMenuSetupRecord::ProcessKey(eKeys key) ++{ ++ eOSState s = cMenuSetupBase::ProcessKey(key);; ++ ++ if (key != kNone) { ++ if (tmpNVidPrefer != data.nVidPrefer || tmpUseVidPrefer != data.UseVidPrefer) { ++ int cur = Current(); ++ ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Clear(); ++ Set(); ++ SetCurrent(Get(cur)); ++ Display(); ++ cMenuSetupBase::ProcessKey(kNone); ++ return osContinue; ++ } ++ } ++ return s; ++} ++ ++#else ++cMenuSetupRecord::cMenuSetupRecord(void) ++#endif /* DVLVIDPREFER */ ++#ifdef USE_DVLVIDPREFER ++void cMenuSetupRecord::Set(void) ++#endif /* DVLVIDPREFER */ ++{ ++#ifdef USE_SORTRECORDS ++ RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); ++ RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); ++ RecordingsSortModeTexts[2] = tr("all alphabetically"); ++ RecordingsSortModeTexts[3] = tr("all by date"); ++#endif /* SORTRECORDS */ ++#ifdef USE_DELTIMESHIFTREC ++ DelTimeshiftRecValues[0] = tr("request"); ++ DelTimeshiftRecValues[1] = tr("no"); ++ DelTimeshiftRecValues[2] = tr("yes"); ++#endif /* DELTIMESHIFTREC */ + SetSection(tr("Recording")); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop)); +@@ -2692,14 +3669,61 @@ cMenuSetupRecord::cMenuSetupRecord(void) + Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME)); ++#ifdef USE_DOLBYINREC ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.UseDolbyInRecordings)); ++#endif /* DOLBYINREC */ ++#ifdef USE_DVLVIDPREFER ++ tmpNVidPrefer = data.nVidPrefer; ++ tmpUseVidPrefer = data.UseVidPrefer; ++ ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Video directory policy"), &data.UseVidPrefer)); ++ if (data.UseVidPrefer != 0) { ++ char tmp[ 64 ]; ++ Add(new cMenuEditIntItem(tr("Setup.Recording$Number of video directories"), &data.nVidPrefer, 1, DVLVIDPREFER_MAX)); ++ for (int zz = 0; zz < data.nVidPrefer; zz++) { ++ sprintf(tmp, tr("Setup.Recording$Video %d priority"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferPrio[ zz ], 0, 99)); ++ sprintf(tmp, tr("Setup.Recording$Video %d min. free MB"), zz); ++ Add(new cMenuEditIntItem(tmp, &data.VidPreferSize[ zz ], -1, 99999)); ++ } ++ } ++#endif /* DVLVIDPREFER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); ++#ifdef USE_DVLFRIENDLYFNAMES ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Friendly filenames"), &data.UseFriendlyFNames)); ++#endif /* DVLFRIENDLYFNAMES */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps)); + Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord))); + Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS)); ++#ifdef USE_HARDLINKCUTTER ++ Add(new cMenuEditIntItem( tr("Setup.Recording$Max. recording size (GB)"), &data.MaxRecordingSize, MINRECORDINGSIZE, MAXRECORDINGSIZE)); ++#endif /* HARDLINKCUTTER */ + Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); ++#ifdef USE_HARDLINKCUTTER ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Hard Link Cutter"), &data.HardLinkCutter)); ++#endif /* HARDLINKCUTTER */ ++#ifdef USE_DELTIMESHIFTREC ++ Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"), &data.DelTimeshiftRec, 3, DelTimeshiftRecValues)); ++#endif /* DELTIMESHIFTREC */ ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show date"), &data.ShowRecDate)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show time"), &data.ShowRecTime)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show length"), &data.ShowRecLength)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Show end of timer"), &data.ShowTimerStop)); ++#endif /* LIEMIEXT */ ++#ifdef USE_SORTRECORDS ++ Add(new cMenuEditStraItem(tr("Setup.Recording$Sort recordings by"), &data.RecordingsSortMode, MAXSORTMODES, RecordingsSortModeTexts)); ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Sort directories before recordings"), &data.RecordingsSortDirsFirst)); ++#endif /* SORTRECORDS */ ++#ifdef USE_CUTTERQUEUE ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter auto delete"), &data.CutterAutoDelete)); ++#endif /* CUTTERQUEUE */ ++#ifdef USE_CUTTIME ++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter adjust starttime"), &data.CutTime)); ++#endif /* CUTTIME */ + } + + // --- cMenuSetupReplay ------------------------------------------------------ +@@ -2717,6 +3741,31 @@ cMenuSetupReplay::cMenuSetupReplay(void) + Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); + Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99)); ++#ifdef USE_JUMPPLAY ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Jump&Play"), &data.JumpPlay)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Play&Jump"), &data.PlayJump)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause at last mark"), &data.PauseLastMark)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$Reload marks"), &data.ReloadMarks)); ++#endif /* JUMPPLAY */ ++#ifdef USE_LIEMIEXT ++ Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds"), &data.JumpSeconds)); ++ Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds Slow"), &data.JumpSecondsSlow)); ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++ static const char *dvddisplaymode[3]; ++ dvddisplaymode[0]=tr("Setup.Replay$Length"); ++ dvddisplaymode[1]=tr("Setup.Replay$Length / Number"); ++ dvddisplaymode[2]=tr("Setup.Replay$Number"); ++ Add(new cMenuEditStraItem(tr("Setup.Replay$DVD display mode"), &data.DvdDisplayMode,3,dvddisplaymode)); ++ Add(new cMenuEditBoolItem(tr("Setup.Replay$DVD display leading zeros"), &data.DvdDisplayZeros)); ++ static const char *dvdtraymode[4]; ++ dvdtraymode[0]=tr("Setup.Replay$never"); ++ dvdtraymode[1]=tr("Setup.Replay$on begin"); ++ dvdtraymode[2]=tr("Setup.Replay$on end"); ++ dvdtraymode[3]=tr("Setup.Replay$on begin and end"); ++ Add(new cMenuEditStraItem(tr("Setup.Replay$Tray open"), &data.DvdTrayMode,4,dvdtraymode)); ++ Add(new cMenuEditIntItem( tr("Setup.Replay$Limit DVD to speed"), &data.DvdSpeedLimit, 0, 50)); ++#endif /* DVDARCHIVE */ + } + + void cMenuSetupReplay::Store(void) +@@ -2729,13 +3778,48 @@ void cMenuSetupReplay::Store(void) + // --- cMenuSetupMisc -------------------------------------------------------- + + class cMenuSetupMisc : public cMenuSetupBase { ++#ifdef USE_VOLCTRL ++private: ++ const char *lrChannelGroupsTexts[3]; ++ const char *lrForwardRewindTexts[3]; ++ void Setup(void); ++#endif /* VOLCTRL */ + public: + cMenuSetupMisc(void); ++#ifdef USE_VOLCTRL ++ virtual eOSState ProcessKey(eKeys Key); ++#endif /* VOLCTRL */ + }; + + cMenuSetupMisc::cMenuSetupMisc(void) + { ++#ifdef USE_VOLCTRL ++ lrChannelGroupsTexts[0] = tr("no"); ++ lrChannelGroupsTexts[1] = tr("Setup.Miscellaneous$only in channelinfo"); ++ lrChannelGroupsTexts[2] = tr("yes"); ++ lrForwardRewindTexts[0] = tr("no"); ++ lrForwardRewindTexts[1] = tr("Setup.Miscellaneous$only in progress display"); ++ lrForwardRewindTexts[2] = tr("yes"); ++#endif /* VOLCTRL */ + SetSection(tr("Miscellaneous")); ++#ifdef USE_VOLCTRL ++ Setup(); ++} ++ ++eOSState cMenuSetupMisc::ProcessKey(eKeys Key) ++{ ++ int newLRVolumeControl = data.LRVolumeControl; ++ eOSState state = cMenuSetupBase::ProcessKey(Key); ++ if (Key != kNone && data.LRVolumeControl != newLRVolumeControl) ++ Setup(); ++ return state; ++} ++ ++void cMenuSetupMisc::Setup(void) ++{ ++ int current = Current(); ++ Clear(); ++#endif /* VOLCTRL */ + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); +@@ -2743,7 +3827,21 @@ cMenuSetupMisc::cMenuSetupMisc(void) + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0)); + Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before"))); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before"))); ++#ifdef USE_VOLCTRL ++ Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Volume ctrl with left/right"), &data.LRVolumeControl)); ++ if (data.LRVolumeControl) { ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Channelgroups with left/right"), &data.LRChannelGroups, 3, lrChannelGroupsTexts)); ++ Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Search fwd/back with left/right"), &data.LRForwardRewind, 3, lrForwardRewindTexts)); ++ } ++ SetCurrent(Get(current)); ++ Display(); ++#endif /* VOLCTRL */ + Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit)); ++#ifdef USE_LIRCSETTINGS ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat delay"), &data.LircRepeatDelay, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat freq"), &data.LircRepeatFreq, 0, 1000)); ++ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat timeout"), &data.LircRepeatTimeout, 0, 5000)); ++#endif /* LIRCSETTINGS */ + } + + // --- cMenuSetupPluginItem -------------------------------------------------- +@@ -2768,6 +3866,9 @@ class cMenuSetupPlugins : public cMenuSe + public: + cMenuSetupPlugins(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetupPlugins"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetupPlugins::cMenuSetupPlugins(void) +@@ -2817,6 +3918,9 @@ private: + public: + cMenuSetup(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuSetup"; } ++#endif /* GRAPHTFT */ + }; + + cMenuSetup::cMenuSetup(void) +@@ -2906,24 +4010,91 @@ cOsdObject *cMenuMain::pluginOsdObject = + cMenuMain::cMenuMain(eOSState State) + :cOsdMenu("") + { ++#ifdef USE_SETUP ++ // Load Menu Configuration ++ char *menuXML = NULL; ++ asprintf(&menuXML, "%s/setup/vdr-menu.%s.xml", cPlugin::ConfigDirectory(), Setup.OSDLanguage); ++ if (access(menuXML, 04) == -1) ++ asprintf(&menuXML, "%s/setup/vdr-menu.xml", cPlugin::ConfigDirectory()); ++ subMenu.LoadXml(menuXML); ++ free(menuXML); ++ nrDynamicMenuEntries=0; ++#endif /* SETUP */ + replaying = false; + stopReplayItem = NULL; + cancelEditingItem = NULL; + stopRecordingItem = NULL; + recordControlsState = 0; ++ ++#ifdef USE_MENUORG ++ MenuOrgPatch::EnterRootMenu(); ++#endif /* MENUORG */ ++ + Set(); + + // Initial submenus: + ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ + switch (State) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuSchedule; ++ } ++ break; ++ case osChannels: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuChannels; ++ } ++ break; ++ case osTimers: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuTimers; ++ } ++ break; ++ case osRecordings: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuRecordings(NULL, 0, true); ++ } ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: AddSubMenu(new cMenuSchedule); break; + case osChannels: AddSubMenu(new cMenuChannels); break; + case osTimers: AddSubMenu(new cMenuTimers); break; + case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; + case osSetup: AddSubMenu(new cMenuSetup); break; + case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break; ++#endif /* MAINMENUHOOKS */ + default: break; + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + } + + cOsdObject *cMenuMain::PluginOsdObject(void) +@@ -2933,38 +4104,155 @@ cOsdObject *cMenuMain::PluginOsdObject(v + return o; + } + ++#ifdef USE_SETUP ++void cMenuMain::Set(int current) ++#else + void cMenuMain::Set(void) ++#endif /* SETUP */ + { + Clear(); + SetTitle("VDR"); + SetHasHotkeys(); + ++#ifdef USE_MENUORG ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuItemDefinitions* menuItems = MenuOrgPatch::MainMenuItems(); ++ for (MenuItemDefinitions::iterator i = menuItems->begin(); i != menuItems->end(); i++) { ++ cOsdItem* osdItem = NULL; ++ if ((*i)->IsCustomOsdItem()) { ++ osdItem = (*i)->CustomOsdItem(); ++ if (osdItem && !(*i)->IsSeparatorItem()) ++ osdItem->SetText(hk(osdItem->Text())); ++ } ++ else if ((*i)->IsPluginItem()) { ++ const char *item = (*i)->PluginMenuEntry(); ++ if (item) ++ osdItem = new cMenuPluginItem(hk(item), (*i)->PluginIndex()); ++ } ++ if (osdItem) { ++ Add(osdItem); ++ if ((*i)->IsSelected()) ++ SetCurrent(osdItem); ++ } ++ } ++ } ++ else { ++#endif /* MENUORG */ ++ ++#ifdef USE_SETUP ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ ++ // remember initial dynamic MenuEntries added ++ nrDynamicMenuEntries = Count(); ++ for (cSubMenuNode *node = subMenu.GetMenuTree()->First(); node; node = subMenu.GetMenuTree()->Next(node)) { ++ cSubMenuNode::Type type = node->GetType(); ++ if (type==cSubMenuNode::PLUGIN) { ++ const char *item = node->GetPluginMainMenuEntry(); ++#ifdef USE_PINPLUGIN ++ if (item && !cStatus::MsgPluginProtected(cPluginManager::GetPlugin(node->GetPluginIndex()), true)) ++#else ++ if (item) ++#endif /* PINPLUGIN */ ++ Add(new cMenuPluginItem(hk(item), node->GetPluginIndex())); ++ } ++ else if (type==cSubMenuNode::MENU) { ++ cString item = cString::sprintf("%s%s", node->GetName(), subMenu.GetMenuSuffix()); ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(item, true)) ++ Add(new cOsdItem(hk(item), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(item))); ++#endif /* PINPLUGIN */ ++ } ++ else if ((type==cSubMenuNode::COMMAND) || (type==cSubMenuNode::THREAD)) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected(node->GetName(), true)) ++ Add(new cOsdItem(hk(node->GetName()), osUnknown, node)); ++#else ++ Add(new cOsdItem(hk(node->GetName()))); ++#endif /* PINPLUGIN */ ++ } ++ else if (type==cSubMenuNode::SYSTEM) { ++ const char *item = node->GetName(); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgMenuItemProtected(item, true)) ++ ; // nothing to do ;) ++ else ++#endif /* PINPLUGIN */ ++ if (strcmp(item, "Schedule") == 0) ++ Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ else if (strcmp(item, "Channels") == 0) ++ Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ else if (strcmp(item, "Timers") == 0) ++ Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ else if (strcmp(item, "Recordings") == 0) ++ Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++ else if (strcmp(item, "Setup") == 0) ++ Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++ else if (strcmp(item, "Commands") == 0 && Commands.Count()>0) ++ Add(new cOsdItem(hk(tr("Commands")), osCommands)); ++ } ++ } ++ if (current >=0 && current<Count()) { ++ SetCurrent(Get(current)); ++ } ++ ++#else /* NO SETUP */ ++ + // Basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Schedule", true)) Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); ++ if (!cStatus::MsgMenuItemProtected("Channels", true)) Add(new cOsdItem(hk(tr("Channels")), osChannels)); ++ if (!cStatus::MsgMenuItemProtected("Timers", true)) Add(new cOsdItem(hk(tr("Timers")), osTimers)); ++ if (!cStatus::MsgMenuItemProtected("Recordings", true)) Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#else + Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); + Add(new cOsdItem(hk(tr("Channels")), osChannels)); + Add(new cOsdItem(hk(tr("Timers")), osTimers)); + Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); ++#endif /* PINPLUGIN */ + + // Plugins: + + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p, true)) { ++#endif /* PINPLUGIN */ + const char *item = p->MainMenuEntry(); + if (item) + Add(new cMenuPluginItem(hk(item), i)); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + break; + } + + // More basic menu items: + ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Setup", true)) Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#else + Add(new cOsdItem(hk(tr("Setup")), osSetup)); ++#endif /* PINPLUGIN */ + if (Commands.Count()) ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgMenuItemProtected("Commands", true)) ++#endif /* PINPLUGIN */ + Add(new cOsdItem(hk(tr("Commands")), osCommands)); + ++#endif /* SETUP */ ++ ++#ifdef USE_MENUORG ++ } ++#endif /* MENUORG */ ++ + Update(true); + + Display(); +@@ -2973,13 +4261,40 @@ void cMenuMain::Set(void) + bool cMenuMain::Update(bool Force) + { + bool result = false; +- ++#ifdef USE_SETUP ++ cOsdItem *fMenu = NULL; ++ if (Force && subMenu.isTopMenu()) { ++ fMenu = First(); ++ nrDynamicMenuEntries = 0; ++ } ++ ++ if (subMenu.isTopMenu()) { ++#endif /* SETUP */ ++#ifdef USE_LIEMIEXT ++// this extension is not included in the original Liemikuutio ++ if (Setup.MainMenuTitle) { ++ if (Setup.MainMenuTitle == 1) ++ SetTitle(cString::sprintf("%s - %s", tr("VDR"), Setup.CustomMainMenuTitle)); ++ else if (Setup.MainMenuTitle == 2) ++ SetTitle(cString::sprintf("%s", Setup.CustomMainMenuTitle)); ++ else if (Setup.MainMenuTitle == 3) ++ SetTitle(cString::sprintf("%s %s", tr("VDR"), VDRVERSION)); ++ } ++ else ++#endif /* LIEMIEXT */ + // Title with disk usage: + if (FreeDiskSpace.HasChanged(Force)) { + //XXX -> skin function!!! + SetTitle(cString::sprintf("%s - %s", tr("VDR"), FreeDiskSpace.FreeDiskSpaceString())); + result = true; + } ++#ifdef USE_SETUP ++ } ++ else { ++ SetTitle(cString::sprintf("%s - %s", tr("VDR"), subMenu.GetParentMenuTitel())); ++ result = true; ++ } ++#endif /* SETUP */ + + bool NewReplaying = cControl::Control() != NULL; + if (Force || NewReplaying != replaying) { +@@ -2987,6 +4302,9 @@ bool cMenuMain::Update(bool Force) + // Replay control: + if (replaying && !stopReplayItem) + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); else ++#endif /* LIEMIEXT */ + Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); + else if (stopReplayItem && !replaying) { + Del(stopReplayItem->Index()); +@@ -3001,6 +4319,9 @@ bool cMenuMain::Update(bool Force) + bool CutterActive = cCutter::Active(); + if (CutterActive && !cancelEditingItem) { + // TRANSLATORS: note the leading blank! ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); else ++#endif /* LIEMIEXT */ + Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); + result = true; + } +@@ -3021,6 +4342,9 @@ bool cMenuMain::Update(bool Force) + while ((s = cRecordControls::GetInstantId(s)) != NULL) { + cOsdItem *item = new cOsdItem(osStopRecord); + item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s)); ++#ifdef USE_LIEMIEXT ++ if (Setup.MenuCmdPosition) Ins(item); else ++#endif /* LIEMIEXT */ + Add(item); + if (!stopRecordingItem) + stopRecordingItem = item; +@@ -3028,6 +4352,12 @@ bool cMenuMain::Update(bool Force) + result = true; + } + ++#ifdef USE_SETUP ++ // adjust nrDynamicMenuEntries ++ if (fMenu != NULL) ++ nrDynamicMenuEntries = fMenu->Index(); ++#endif /* SETUP */ ++ + return result; + } + +@@ -3038,13 +4368,69 @@ eOSState cMenuMain::ProcessKey(eKeys Key + eOSState state = cOsdMenu::ProcessKey(Key); + HadSubMenu |= HasSubMenu(); + ++#ifdef USE_PINPLUGIN ++ cOsdItem* item = Get(Current()); ++ ++ if (item && item->Text() && state != osBack && state != osContinue && Key != kNone) ++ if (cStatus::MsgMenuItemProtected(item->Text())) ++ return osContinue; ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_MAINMENUHOOKS ++ cOsdMenu *menu = NULL; ++#endif /* MAINMENUHOOKS */ + switch (state) { ++#ifdef USE_MAINMENUHOOKS ++ case osSchedule: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuSchedule; ++ } ++ break; ++ case osChannels: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuChannels; ++ } ++ break; ++ case osTimers: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuTimers; ++ } ++ break; ++ case osRecordings: ++ { ++ cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); ++ if (p && !menu) ++ isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); ++ ++ if (!menu) ++ menu = new cMenuRecordings; ++ } ++ break; ++ case osSetup: menu = new cMenuSetup; break; ++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; ++#else + case osSchedule: return AddSubMenu(new cMenuSchedule); + case osChannels: return AddSubMenu(new cMenuChannels); + case osTimers: return AddSubMenu(new cMenuTimers); + case osRecordings: return AddSubMenu(new cMenuRecordings); + case osSetup: return AddSubMenu(new cMenuSetup); + case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); ++#endif /* MAINMENUHOOKS */ + case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { + cOsdItem *item = Get(Current()); + if (item) { +@@ -3063,6 +4449,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key + if (item) { + cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); + if (p) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(p)) { ++#endif /* PINPLUGIN */ + cOsdObject *menu = p->MainMenuAction(); + if (menu) { + if (menu->IsMenu()) +@@ -3074,9 +4463,60 @@ eOSState cMenuMain::ProcessKey(eKeys Key + } + } + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + state = osEnd; + } + break; ++#ifdef USE_SETUP ++ case osBack: { ++ int newCurrent = 0; ++ if (subMenu.Up(&newCurrent)) { ++ Set(newCurrent); ++ return osContinue; ++ } ++ else ++ return osEnd; ++ } ++ break; ++#endif /* SETUP */ ++#ifdef USE_MENUORG ++ case osBack: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ bool leavingMenuSucceeded = MenuOrgPatch::LeaveSubMenu(); ++ Set(); ++ stopReplayItem = NULL; ++ cancelEditingItem = NULL; ++ stopRecordingItem = NULL; ++ recordControlsState = 0; ++ Update(true); ++ Display(); ++ if (leavingMenuSucceeded) ++ return osContinue; ++ else ++ return osEnd; ++ } ++ } ++ break; ++ case osUser1: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ MenuOrgPatch::EnterSubMenu(Get(Current())); ++ Set(); ++ return osContinue; ++ } ++ } ++ break; ++ case osUser2: { ++ if (MenuOrgPatch::IsCustomMenuAvailable()) { ++ cOsdMenu* osdMenu = MenuOrgPatch::Execute(Get(Current())); ++ if (osdMenu) ++ return AddSubMenu(osdMenu); ++ return osEnd; ++ } ++ } ++ break; ++#endif /* MENUORG */ + default: switch (Key) { + case kRecord: + case kRed: if (!HadSubMenu) +@@ -3093,9 +4533,67 @@ eOSState cMenuMain::ProcessKey(eKeys Key + case kBlue: if (!HadSubMenu) + state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue; + break; ++#ifdef USE_SETUP ++ case kOk: if (state == osUnknown) { ++ cString buffer; ++#ifdef USE_PINPLUGIN ++ cSubMenuNode *node = Get(Current())->SubMenu(); ++#else ++ int index = Current()-nrDynamicMenuEntries; ++ cSubMenuNode *node = subMenu.GetNode(index); ++#endif /* PINPLUGIN */ ++ ++ if (node != NULL) { ++ if (node->GetType() == cSubMenuNode::MENU) { ++#ifdef USE_PINPLUGIN ++ subMenu.Down(node, Current()); ++#else ++ subMenu.Down(index); ++#endif /* PINPLUGIN */ ++ } ++ else if (node->GetType() == cSubMenuNode::COMMAND) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ const char *Result = subMenu.ExecuteCommand(node->GetCommand()); ++ if (Result) ++ return AddSubMenu(new cMenuText(node->GetName(), Result, fontFix)); ++ return osEnd; ++ } ++ } ++ else if (node->GetType() == cSubMenuNode::THREAD) { ++ bool confirmed = true; ++ if (node->CommandConfirm()) { ++ buffer = cString::sprintf("%s?", node->GetName()); ++ confirmed = Interface->Confirm(buffer); ++ } ++ if (confirmed) { ++ buffer = cString::sprintf("%s", node->GetCommand()); ++ cExecCmdThread *execcmd = new cExecCmdThread(node->GetCommand()); ++ if (execcmd->Start()) ++ dsyslog("executing command '%s'", *buffer); ++ else ++ esyslog("ERROR: can't execute command '%s'", *buffer); ++ return osEnd; ++ } ++ } ++ } ++ ++ Set(); ++ return osContinue; ++ } ++ break; ++#endif /* SETUP */ + default: break; + } + } ++#ifdef USE_MAINMENUHOOKS ++ if (menu) ++ return AddSubMenu(menu); ++#endif /* MAINMENUHOOKS */ + if (!HasSubMenu() && Update(HadSubMenu)) + Display(); + if (Key != kNone) { +@@ -3241,7 +4739,14 @@ cChannel *cDisplayChannel::NextAvailable + if (Direction) { + while (Channel) { + Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel); ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgChannelProtected(0, Channel) == false) ++#endif /* PINPLUGIN */ ++#ifdef USE_LNBSHARE ++ if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true) && cDevice::PrimaryDevice()->GetMaxBadPriority(Channel) < 0) ++#else + if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true)) ++#endif /* LNBSHARE */ + return Channel; + } + } +@@ -3299,6 +4804,13 @@ eOSState cDisplayChannel::ProcessKey(eKe + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && !Setup.LRChannelGroups) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kNext|k_Repeat: + case kNext: + case kPrev|k_Repeat: +@@ -3458,6 +4970,17 @@ void cDisplayVolume::Process(eKeys Key) + eOSState cDisplayVolume::ProcessKey(eKeys Key) + { + switch (Key) { ++#ifdef USE_VOLCTRL ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ if (Setup.LRVolumeControl) { ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++#endif /* VOLCTRL */ + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: +@@ -3707,6 +5230,10 @@ eOSState cDisplaySubtitleTracks::Process + + cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) + { ++#ifdef USE_DVLRECSCRIPTADDON ++ const cChannel *recChan = NULL; ++ char *chanName = NULL; ++#endif /* DVLRECSCRIPTADDON */ + // We're going to manipulate an event here, so we need to prevent + // others from modifying any EPG data: + cSchedulesLock SchedulesLock; +@@ -3751,6 +5278,16 @@ cRecordControl::cRecordControl(cDevice * + return; + } + ++#ifdef USE_DVLRECSCRIPTADDON ++ if (timer) ++ if ((recChan = timer->Channel()) != NULL) ++ chanName = strdup(recChan->Name()); ++ if (chanName != NULL) { ++ cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName, chanName); ++ free(chanName); ++ } ++ else ++#endif /* DVLRECSCRIPTADDON */ + cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); + isyslog("record %s", fileName); + if (MakeDirs(fileName, true)) { +@@ -3813,11 +5350,25 @@ bool cRecordControl::GetEvent(void) + void cRecordControl::Stop(void) + { + if (timer) { ++#ifdef USE_DVLRECSCRIPTADDON ++ char *chanName = NULL; ++ const cChannel *recChan = NULL; ++ ++ recChan = timer -> Channel(); ++ if (recChan != NULL) ++ chanName = strdup(recChan -> Name()); ++#endif /* DVLRECSCRIPTADDON */ + DELETENULL(recorder); + timer->SetRecording(false); + timer = NULL; + cStatus::MsgRecording(device, NULL, fileName, false); ++#ifdef USE_DVLRECSCRIPTADDON ++ cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName, chanName); ++ if (chanName != NULL) ++ free(chanName); ++#else + cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); ++#endif /* DVLRECSCRIPTADDON */ + } + } + +@@ -3864,6 +5415,19 @@ bool cRecordControls::Start(cTimer *Time + int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority; + cDevice *device = cDevice::GetDevice(channel, Priority, false); + if (device) { ++#ifdef USE_LNBSHARE ++ cDevice *tmpDevice; ++ while ((tmpDevice = device->GetBadDevice(channel))) { ++ if (tmpDevice->Replaying() == false) { ++// Stop(tmpDevice); ++ if (tmpDevice->IsPrimaryDevice() ) ++ tmpDevice->SwitchChannelForced(channel, true); ++ else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } else ++ tmpDevice->SwitchChannelForced(channel, false); ++ } ++#endif /* LNBSHARE */ + dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number()); + if (!device->SwitchChannel(channel, false)) { + ShutdownHandler.RequestEmergencyExit(); +@@ -3873,6 +5437,9 @@ bool cRecordControls::Start(cTimer *Time + for (int i = 0; i < MAXRECORDCONTROLS; i++) { + if (!RecordControls[i]) { + RecordControls[i] = new cRecordControl(device, Timer, Pause); ++#ifdef USE_PINPLUGIN ++ cStatus::MsgRecordingFile(RecordControls[i]->FileName()); ++#endif /* PINPLUGIN */ + return RecordControls[i]->Process(time(NULL)); + } + } +@@ -4003,12 +5570,22 @@ bool cRecordControls::StateChanged(int & + + // --- cReplayControl -------------------------------------------------------- + ++#ifdef USE_LIEMIEXT ++#define REPLAYCONTROLSKIPLIMIT 9 // s ++#define REPLAYCONTROLSKIPSECONDS 90 // s ++#define REPLAYCONTROLSKIPTIMEOUT 5000 // ms ++#endif /* LIEMIEXT */ ++ + cReplayControl *cReplayControl::currentReplayControl = NULL; + char *cReplayControl::fileName = NULL; + char *cReplayControl::title = NULL; + + cReplayControl::cReplayControl(void) ++#ifdef USE_JUMPPLAY ++:cDvbPlayerControl(fileName), marks(fileName) ++#else + :cDvbPlayerControl(fileName) ++#endif /* JUMPPLAY */ + { + currentReplayControl = this; + displayReplay = NULL; +@@ -4016,23 +5593,96 @@ cReplayControl::cReplayControl(void) + lastCurrent = lastTotal = -1; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value ++#ifdef USE_LIEMIEXT ++ lastSkipKey = kNone; ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipTimeout.Set(0); ++#endif /* LIEMIEXT */ + timeoutShow = 0; + timeSearchActive = false; + cRecording Recording(fileName); ++#ifdef USE_DVDARCHIVE ++ canJumpChapters = (Recording.GetDvdType() == DVD_VIDEO_ARCHIVE_TYPE); ++ dvdchapters = NULL; ++ if (canJumpChapters) { ++ const char *ret = Recording.GetDvdChapters(); ++ if (ret) ++ dvdchapters = strdup(ret); ++ else ++ canJumpChapters=false; ++ } ++#endif /* DVDARCHIVE */ + cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true); ++#ifndef USE_JUMPPLAY + marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording()); ++#endif /* JUMPPLAY */ + SetTrackDescriptions(false); + } + + cReplayControl::~cReplayControl() + { + Hide(); ++#ifdef USE_DVDARCHIVE ++ free(dvdchapters); ++#endif /* DVDARCHIVE */ + cStatus::MsgReplaying(this, NULL, fileName, false); + Stop(); + if (currentReplayControl == this) + currentReplayControl = NULL; + } + ++#ifdef USE_DELTIMESHIFTREC ++void cReplayControl::Stop(void) ++{ ++ int dummy; ++ bool playing = GetIndex(dummy, dummy, false); ++ cRecordControl* rc = cRecordControls::GetRecordControl(fileName); ++ ++ if (playing && rc && rc->InstantId()) { ++ isyslog("found Timeshiftrecording"); ++ ++ if ((Setup.DelTimeshiftRec != 0 ) || (Interface->Confirm(tr("Delete recording?")))) { ++ cRecordControl *rc = cRecordControls::GetRecordControl(fileName); ++ if (rc) { ++ cTimer *timer = rc->Timer(); ++ if (timer) { ++ const char* reccmd_backup = cRecordingUserCommand::GetCommand(); ++ cRecordingUserCommand::SetCommand(NULL); ++ ++ timer->Skip(); ++ cRecordControls::Process(time(NULL)); ++ if (timer->IsSingleEvent()) { ++ isyslog("deleting timer %s", *timer->ToDescr()); ++ Timers.Del(timer); ++ } ++ Timers.SetModified(); ++ ++ // restore reccmd ++ cRecordingUserCommand::SetCommand(reccmd_backup); ++ } ++ } ++ isyslog("stop replaying %s", fileName); ++ cDvbPlayerControl::Stop(); ++ ++ if (Setup.DelTimeshiftRec != 1) { ++ cRecording *recording = Recordings.GetByName(fileName);; ++ if (recording) { ++ if (recording->Delete()) { ++ Recordings.DelByName(fileName); ++ ClearLastReplayed(fileName); ++ return; ++ } ++ else ++ Skins.Message(mtError, tr("Error while deleting recording!")); ++ } ++ } ++ } ++ else ++ cDvbPlayerControl::Stop(); ++ } ++} ++#endif /* DELTIMESHIFTREC */ ++ + void cReplayControl::SetRecording(const char *FileName, const char *Title) + { + free(fileName); +@@ -4127,6 +5777,9 @@ bool cReplayControl::ShowProgress(bool I + if (Initial) { + if (title) + displayReplay->SetTitle(title); ++#ifdef USE_OSDMAXITEMS ++ displayReplay->SetButtons(tr("Jump"), tr("Skip +60s"), tr("Skip -60s"), tr("Button$Stop")); ++#endif /* OSDMAXITEMS */ + lastCurrent = lastTotal = -1; + } + if (Total != lastTotal) { +@@ -4248,8 +5901,15 @@ void cReplayControl::MarkToggle(void) + ShowTimed(2); + bool Play, Forward; + int Speed; ++#ifdef USE_JUMPPLAY ++ if (GetReplayMode(Play, Forward, Speed) && !Play) { ++ Goto(Current, true); ++ displayFrames = true; ++ } ++#else + if (GetReplayMode(Play, Forward, Speed) && !Play) + Goto(Current, true); ++#endif /* JUMPPLAY */ + } + marks.Save(); + } +@@ -4262,8 +5922,22 @@ void cReplayControl::MarkJump(bool Forwa + if (GetIndex(Current, Total)) { + cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ bool Play2, Forward2; ++ int Speed; ++ if (Setup.JumpPlay && GetReplayMode(Play2, Forward2, Speed) && ++ Play2 && Forward && m->position < Total - SecondsToFrames(3)) { ++ Goto(m->position); ++ Play(); ++ } ++ else { ++ Goto(m->position, true); ++ displayFrames = true; ++ } ++#else + Goto(m->position, true); + displayFrames = true; ++#endif /* JUMPPLAY */ + } + } + } +@@ -4292,11 +5966,43 @@ void cReplayControl::MarkMove(bool Forwa + } + } + ++#ifdef USE_DVDARCHIVE ++void cReplayControl::ChaptersJump(bool Forward) ++{ ++ int Current, Total; ++ if (GetIndex(Current, Total)) { ++ int position = -1; ++ char *buf, *pos; ++ cString old1("-1"); ++ cString old2("-1"); ++ buf = strdup(dvdchapters); ++ pos = strtok(buf, ","); ++ while (pos != NULL && position == -1) { ++ if (pos && atoi(pos) > Current) ++ position = Forward ? atoi(pos) : ((Current - atoi(old1)) <= (3 * FramesPerSecond())) ? atoi(old2) : atoi(old1); ++ old2 = old1; ++ old1 = strdup(pos); ++ if(position == -1) pos = strtok(NULL, ","); ++ } ++ if (!pos && !Forward) ++ position = ((Current - atoi(old1)) <= (3 * FramesPerSecond())) ? atoi(old2) : atoi(old1); ++ if (position >= 0) { ++ Goto(position); ++ Play(); ++ } ++ } ++} ++ ++#endif /* DVDARCHIVE */ + void cReplayControl::EditCut(void) + { + if (fileName) { + Hide(); ++#ifdef USE_CUTTERQUEUE ++ if (!cCutter::Active() || Interface->Confirm(tr("Cutter already running - Add to cutting queue?"))) { ++#else + if (!cCutter::Active()) { ++#endif /* CUTTERQUEUE */ + if (!marks.Count()) + Skins.Message(mtError, tr("No editing marks defined!")); + else if (!cCutter::Start(fileName)) +@@ -4318,7 +6024,11 @@ void cReplayControl::EditTest(void) + if (!m) + m = marks.GetNext(Current); + if (m) { ++#ifdef USE_JUMPPLAY ++ if ((m->Index() & 0x01) != 0 && !Setup.PlayJump) ++#else + if ((m->Index() & 0x01) != 0) ++#endif /* JUMPPLAY */ + m = marks.Next(m); + if (m) { + Goto(m->position - SecondsToFrames(3, FramesPerSecond())); +@@ -4340,6 +6050,9 @@ eOSState cReplayControl::ProcessKey(eKey + { + if (!Active()) + return osEnd; ++#ifdef USE_JUMPPLAY ++ marks.Reload(); ++#endif /* JUMPPLAY */ + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); +@@ -4357,7 +6070,32 @@ eOSState cReplayControl::ProcessKey(eKey + TimeSearchProcess(Key); + return osContinue; + } ++#ifdef USE_DVDARCHIVE ++ bool isOnMark = false; ++ if (canJumpChapters) { ++ int Current, Total; ++ GetIndex(Current, Total); ++ cMark *m = marks.Get(Current); ++ if (m && (m->position == Current)) isOnMark = true; ++ } ++#endif /* DVDARCHIVE */ + bool DoShowMode = true; ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && (!Setup.LRForwardRewind || (Setup.LRForwardRewind == 1 && !visible))) { ++ switch (Key) { ++ // Left/Right volume control ++ case kLeft|k_Repeat: ++ case kLeft: ++ case kRight|k_Repeat: ++ case kRight: ++ cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); ++ return osContinue; ++ break; ++ default: ++ break; ++ } ++ } ++#endif /* VOLCTRL */ + switch (Key) { + // Positioning: + case kPlay: +@@ -4375,25 +6113,82 @@ eOSState cReplayControl::ProcessKey(eKey + case kFastFwd: + case kRight: Forward(); break; + case kRed: TimeSearch(); break; ++#ifdef USE_LIEMIEXT ++ case kGreen|k_Repeat: ++ case kGreen: SkipSeconds(-Setup.JumpSeconds); break; ++ case kYellow|k_Repeat: ++ case kYellow: SkipSeconds( Setup.JumpSeconds); break; ++ case k1|k_Repeat: ++ case k1: SkipSeconds(-Setup.JumpSecondsSlow); break; ++ case k3|k_Repeat: ++ case k3: SkipSeconds( Setup.JumpSecondsSlow); break; ++ case kPrev|k_Repeat: ++ case kPrev: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kPrev; ++ } ++ else if (RAWKEY(lastSkipKey) != kPrev && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(-lastSkipSeconds); break; ++ case kNext|k_Repeat: ++ case kNext: if (lastSkipTimeout.TimedOut()) { ++ lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; ++ lastSkipKey = kNext; ++ } ++ else if (RAWKEY(lastSkipKey) != kNext && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { ++ lastSkipSeconds /= 2; ++ lastSkipKey = kNone; ++ } ++ lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); ++ SkipSeconds(lastSkipSeconds); break; ++#else + case kGreen|k_Repeat: + case kGreen: SkipSeconds(-60); break; + case kYellow|k_Repeat: + case kYellow: SkipSeconds( 60); break; ++#endif /* LIEMIEXT */ + case kStop: + case kBlue: Hide(); + Stop(); + return osEnd; ++#ifdef USE_DVDARCHIVE ++ case kDvdChapterJumpForward|k_Repeat: ++ case kDvdChapterJumpForward: if (canJumpChapters && !isOnMark) { ++ ChaptersJump(true); ++ } ++ else { ++ DoShowMode = false; ++ MarkMove(true); ++ } ++ break; ++ case kDvdChapterJumpBack|k_Repeat: ++ case kDvdChapterJumpBack: if (canJumpChapters && !isOnMark) { ++ ChaptersJump(false); ++ } ++ else { ++ DoShowMode = false; ++ MarkMove(false); ++ } ++ break; ++#endif /* DVDARCHIVE */ + default: { + DoShowMode = false; + switch (Key) { + // Editing: + case kMarkToggle: MarkToggle(); break; ++#ifndef USE_LIEMIEXT + case kPrev|k_Repeat: + case kPrev: ++#endif /* LIEMIEXT */ + case kMarkJumpBack|k_Repeat: + case kMarkJumpBack: MarkJump(false); break; ++#ifndef USE_LIEMIEXT + case kNext|k_Repeat: + case kNext: ++#endif /* LIEMIEXT */ + case kMarkJumpForward|k_Repeat: + case kMarkJumpForward: MarkJump(true); break; + case kMarkMoveBack|k_Repeat: +@@ -4413,7 +6208,16 @@ eOSState cReplayControl::ProcessKey(eKey + else + Show(); + break; ++#ifdef USE_DELTIMESHIFTREC ++ case kBack: { cRecordControl* rc = cRecordControls::GetRecordControl(fileName); ++ if (rc && rc->InstantId()) ++ return osEnd; ++ else ++ return osRecordings; ++ } ++#else + case kBack: return osRecordings; ++#endif /* DELTIMESHIFTREC */ + default: return osUnknown; + } + } +diff -ruNp vdr-1.7.5/menu.h vdr-1.7.5-extensions/menu.h +--- vdr-1.7.5/menu.h 2008-02-10 17:01:53.000000000 +0100 ++++ vdr-1.7.5-extensions/menu.h 2009-04-12 13:37:59.000000000 +0200 +@@ -18,6 +18,9 @@ + #include "menuitems.h" + #include "recorder.h" + #include "skins.h" ++#ifdef USE_SETUP ++#include "submenu.h" ++#endif /* SETUP */ + + class cMenuText : public cOsdMenu { + private: +@@ -29,12 +32,19 @@ public: + void SetText(const char *Text); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuText"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuEditTimer : public cOsdMenu { + private: + cTimer *timer; + cTimer data; ++#ifdef USE_LIEMIEXT ++ char name[MaxFileName]; ++ char path[MaxFileName]; ++#endif /* LIEMIEXT */ + int channel; + bool addIfConfirmed; + cMenuEditDateItem *firstday; +@@ -43,6 +53,9 @@ public: + cMenuEditTimer(cTimer *Timer, bool New = false); + virtual ~cMenuEditTimer(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuTimerEdit"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuEvent : public cOsdMenu { +@@ -52,22 +65,37 @@ public: + cMenuEvent(const cEvent *Event, bool CanSwitch = false, bool Buttons = false); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuEvent"; } ++#endif /* GRAPHTFT */ + }; + + class cMenuMain : public cOsdMenu { + private: ++#ifdef USE_SETUP ++ int nrDynamicMenuEntries; ++#endif /* SETUP */ + bool replaying; + cOsdItem *stopReplayItem; + cOsdItem *cancelEditingItem; + cOsdItem *stopRecordingItem; + int recordControlsState; + static cOsdObject *pluginOsdObject; ++#ifdef USE_SETUP ++ void Set(int current=0); ++ bool Update(bool Force = false); ++ cSubMenu subMenu; ++#else + void Set(void); + bool Update(bool Force = false); ++#endif /* SETUP */ + public: + cMenuMain(eOSState State = osUnknown); + virtual eOSState ProcessKey(eKeys Key); + static cOsdObject *PluginOsdObject(void); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuMain"; } ++#endif /* GRAPHTFT */ + }; + + class cDisplayChannel : public cOsdObject { +@@ -163,12 +191,18 @@ private: + eOSState Delete(void); + eOSState Info(void); + eOSState Commands(eKeys Key = kNone); ++#ifdef USE_LIEMIEXT ++ eOSState Rename(void); ++#endif /* LIEMIEXT */ + protected: + cRecording *GetRecording(cMenuRecordingItem *Item); + public: + cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false); + ~cMenuRecordings(); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuRecordings"; } ++#endif /* GRAPHTFT */ + }; + + class cRecordControl { +@@ -212,11 +246,21 @@ public: + class cReplayControl : public cDvbPlayerControl { + private: + cSkinDisplayReplay *displayReplay; ++#ifdef USE_JUMPPLAY ++ cMarksReload marks; ++#else + cMarks marks; ++#endif /* JUMPPLAY */ + bool visible, modeOnly, shown, displayFrames; + int lastCurrent, lastTotal; + bool lastPlay, lastForward; + int lastSpeed; ++#ifdef USE_LIEMIEXT ++ int lastSkipSeconds; ++ int lastSkipSecondsSlow; ++ eKeys lastSkipKey; ++ cTimeMs lastSkipTimeout; ++#endif /* LIEMIEXT */ + time_t timeoutShow; + bool timeSearchActive, timeSearchHide; + int timeSearchTime, timeSearchPos; +@@ -234,9 +278,17 @@ private: + void MarkMove(bool Forward); + void EditCut(void); + void EditTest(void); ++#ifdef USE_DVDARCHIVE ++ void ChaptersJump(bool Forward); ++ bool canJumpChapters; ++ char *dvdchapters; ++#endif /* DVDARCHIVE */ + public: + cReplayControl(void); + virtual ~cReplayControl(); ++#ifdef USE_DELTIMESHIFTREC ++ void Stop(void); ++#endif /* DELTIMESHIFTREC */ + virtual cOsdObject *GetInfo(void); + virtual eOSState ProcessKey(eKeys Key); + virtual void Show(void); +diff -ruNp vdr-1.7.5/menuitems.c vdr-1.7.5-extensions/menuitems.c +--- vdr-1.7.5/menuitems.c 2009-04-05 12:15:12.000000000 +0200 ++++ vdr-1.7.5-extensions/menuitems.c 2009-04-12 13:37:59.000000000 +0200 +@@ -32,9 +32,20 @@ cMenuEditItem::~cMenuEditItem() + free(name); + } + ++#ifdef USE_VALIDINPUT ++void cMenuEditItem::SetValue(const char *Value, bool HasPre, bool HasSucc) ++#else + void cMenuEditItem::SetValue(const char *Value) ++#endif /* VALIDINPUT */ + { + cString buffer = cString::sprintf("%s:\t%s", name, Value); ++#ifdef USE_VALIDINPUT ++ if (Setup.ShowValidInput) { ++ if (HasPre && HasSucc) buffer = cString::sprintf("%s:\t<%s>", name, Value); ++ else if (HasPre) buffer = cString::sprintf("%s:\t<%s", name, Value); ++ else if (HasSucc) buffer = cString::sprintf("%s:\t%s>", name, Value); ++ } ++#endif /* VALIDINPUT */ + SetText(buffer); + cStatus::MsgOsdCurrentItem(buffer); + } +@@ -126,7 +137,11 @@ void cMenuEditBoolItem::Set(void) + { + char buf[16]; + snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); ++#ifdef USE_VALIDINPUT ++ SetValue(buf, *value, !*value); ++#else + SetValue(buf); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditBitItem ------------------------------------------------------ +@@ -619,6 +634,171 @@ eOSState cMenuEditStrItem::ProcessKey(eK + return osContinue; + } + ++#ifdef USE_LIEMIEXT ++// --- cMenuEditRecPathItem -------------------------------------------------- ++ ++cMenuEditRecPathItem::cMenuEditRecPathItem(const char* Name, char* Path, ++ int Length): cMenuEditStrItem(Name, Path, Length, tr(FileNameChars)) ++{ ++ SetBase(Path); ++} ++ ++cMenuEditRecPathItem::~cMenuEditRecPathItem() ++{ ++} ++ ++void cMenuEditRecPathItem::SetBase(const char* Path) ++{ ++ if (!Path) ++ base[0] = 0; ++ Utf8Strn0Cpy(base, Path, sizeof(base)); ++ char* p = strrchr(base, '~'); ++ if (p) ++ p[0] = 0; ++ else ++ base[0] = 0; ++} ++ ++void cMenuEditRecPathItem::FindNextLevel() ++{ ++ char item[MaxFileName]; ++ ++ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) ++ { ++ char* p; ++ Utf8Strn0Cpy(item, recording->Name(), sizeof(item)); ++ stripspace(value); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ if (!lengthUtf8) ++ p = strchr(item, '~'); ++ else { ++ if (strstr(item, value) != item) ++ continue; ++ if (item[strlen(value)] != '~') ++ continue; ++ p = strchr(item + strlen(value) + 1, '~'); ++ } ++ if (!p) ++ continue; ++ p[0] = 0; ++ Utf8Strn0Cpy(base, value, length); ++ Utf8Strn0Cpy(value, item, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++} ++ ++void cMenuEditRecPathItem::Find(bool Next) ++{ ++ char item[MaxFileName]; ++ char lastItem[MaxFileName] = ""; ++ ++ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) ++ { ++ const char* recName = recording->Name(); ++ if (Utf8StrLen(base) && strstr(recName, base) != recName) ++ continue; ++ if (strlen(base) && recName[strlen(base)] != '~') ++ continue; ++ Utf8Strn0Cpy(item, recName, sizeof(item)); ++ char* p = strchr(item + strlen(base) + 1, '~'); ++ if (!p) ++ continue; ++ p[0] = 0; ++ if (!Next && (strcmp(item, value) == 0)) { ++ if (strlen(lastItem)) ++ Utf8Strn0Cpy(value, lastItem, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++ if (strcmp(lastItem, item) != 0) { ++ if(Next && Utf8StrLen(lastItem) && strcmp(lastItem, value) == 0) { ++ Utf8Strn0Cpy(value, item, length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ return; ++ } ++ Utf8Strn0Cpy(lastItem, item, sizeof(lastItem)); ++ } ++ } ++} ++ ++void cMenuEditRecPathItem::SetHelpKeys(void) ++{ ++ cSkinDisplay::Current()->SetButtons(tr("Rename$Up"), tr("Rename$Down"), tr("Rename$Previous"), tr("Rename$Next")); ++} ++ ++eOSState cMenuEditRecPathItem::ProcessKey(eKeys Key) ++{ ++ switch (Key) { ++ case kLeft: ++ case kRed: // one level up ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Utf8Strn0Cpy(value, base, lengthUtf8); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ SetBase(base); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ if (!lengthUtf8) { ++ Utf8Strn0Cpy(value, " ", length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ } ++ break; ++ case kRight: ++ case kGreen: // one level down ++ if (InEditMode()) ++ FindNextLevel(); ++ else ++ EnterEditMode(); ++ ++ if (!lengthUtf8) { ++ Utf8Strn0Cpy(value, " ", length); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ } ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ SetHelpKeys(); ++ break; ++ case kUp|k_Repeat: ++ case kUp: ++ case kYellow|k_Repeat: ++ case kYellow: // previous directory in list ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Find(false); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ break; ++ case kDown|k_Repeat: ++ case kDown: ++ case kBlue|k_Repeat: ++ case kBlue: // next directory in list ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ Find(true); ++ pos = Utf8StrLen(base); ++ if (pos) ++ pos++; ++ break; ++ case kOk: // done ++ if (!InEditMode()) ++ return cMenuEditItem::ProcessKey(Key); ++ stripspace(value); ++ lengthUtf8 = Utf8ToArray(value, valueUtf8, length); ++ cSkinDisplay::Current()->SetButtons(NULL); ++ LeaveEditMode(Key == kOk); ++ break; ++ default: ++ return cMenuEditItem::ProcessKey(Key); ++ } ++ Set(); ++ return osContinue; ++} ++#endif /* LIEMIEXT */ ++ + // --- cMenuEditStraItem ----------------------------------------------------- + + cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) +@@ -630,7 +810,11 @@ cMenuEditStraItem::cMenuEditStraItem(con + + void cMenuEditStraItem::Set(void) + { ++#ifdef USE_VALIDINPUT ++ SetValue(strings[*value], (*value > min), (*value < max)); ++#else + SetValue(strings[*value]); ++#endif /* VALIDINPUT */ + } + + // --- cMenuEditChanItem ----------------------------------------------------- +diff -ruNp vdr-1.7.5/menuitems.h vdr-1.7.5-extensions/menuitems.h +--- vdr-1.7.5/menuitems.h 2008-04-12 14:03:59.000000000 +0200 ++++ vdr-1.7.5-extensions/menuitems.h 2009-04-12 13:37:59.000000000 +0200 +@@ -21,7 +21,11 @@ private: + public: + cMenuEditItem(const char *Name); + ~cMenuEditItem(); ++#ifdef USE_VALIDINPUT ++ void SetValue(const char *Value, bool HasPre=false, bool HasSucc=false); ++#else + void SetValue(const char *Value); ++#endif /* VALIDINPUT */ + }; + + class cMenuEditIntItem : public cMenuEditItem { +@@ -78,26 +82,46 @@ public: + + class cMenuEditStrItem : public cMenuEditItem { + private: ++#ifdef USE_LIEMIEXT ++ int offset; ++#else + char *value; + int length; + const char *allowed; + int pos, offset; ++#endif /* LIEMIEXT */ + bool insert, newchar, uppercase; ++#ifndef USE_LIEMIEXT + int lengthUtf8; + uint *valueUtf8; ++#endif /* LIEMIEXT */ + uint *allowedUtf8; + uint *charMapUtf8; + uint *currentCharUtf8; + eKeys lastKey; + cTimeMs autoAdvanceTimeout; ++#ifndef USE_LIEMIEXT + void SetHelpKeys(void); ++#endif /* LIEMIEXT */ + uint *IsAllowed(uint c); + void AdvancePos(void); ++#ifndef USE_LIEMIEXT + virtual void Set(void); ++#endif /* LIEMIEXT */ + uint Inc(uint c, bool Up); + void Insert(void); + void Delete(void); + protected: ++#ifdef USE_LIEMIEXT ++ char *value; ++ int length; ++ uint *valueUtf8; ++ int lengthUtf8; ++ const char *allowed; ++ int pos; ++ void SetHelpKeys(void); ++ virtual void Set(void); ++#endif /* LIEMIEXT */ + void EnterEditMode(void); + void LeaveEditMode(bool SaveValue = false); + bool InEditMode(void) { return valueUtf8 != NULL; } +@@ -107,6 +131,21 @@ public: + virtual eOSState ProcessKey(eKeys Key); + }; + ++#ifdef USE_LIEMIEXT ++class cMenuEditRecPathItem : public cMenuEditStrItem { ++protected: ++ char base[MaxFileName]; ++ virtual void SetHelpKeys(void); ++ void SetBase(const char* Path); ++ void FindNextLevel(); ++ void Find(bool Next); ++public: ++ cMenuEditRecPathItem(const char* Name, char* Path, int Length); ++ ~cMenuEditRecPathItem(); ++ virtual eOSState ProcessKey(eKeys Key); ++ }; ++#endif /* LIEMIEXT */ ++ + class cMenuEditStraItem : public cMenuEditIntItem { + private: + const char * const *strings; +@@ -185,6 +224,9 @@ public: + cMenuSetupPage(void); + virtual eOSState ProcessKey(eKeys Key); + void SetPlugin(cPlugin *Plugin); ++#ifdef USE_GRAPHTFT ++ const char* MenuKind() { return "MenuSetupPage"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__MENUITEMS_H +diff -ruNp vdr-1.7.5/menuorgpatch.h vdr-1.7.5-extensions/menuorgpatch.h +--- vdr-1.7.5/menuorgpatch.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/menuorgpatch.h 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,102 @@ ++#ifdef USE_MENUORG ++/* ++ * vdr-menuorg - A plugin for the Linux Video Disk Recorder ++ * Copyright (c) 2007 - 2008 Tobias Grimm <vdr@e-tobi.net> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * $Id$ ++ * ++ */ ++ ++#ifndef __MENUORGPATCH_H ++#define __MENUORGPATCH_H ++ ++#include "mainmenuitemsprovider.h" ++ ++class MenuOrgPatch ++{ ++ private: ++ static IMainMenuItemsProvider* _mainMenuItemsProvider; ++ ++ private: ++ static IMainMenuItemsProvider* MainMenuItemsProvider() ++ { ++ if (!_mainMenuItemsProvider) ++ { ++ IMainMenuItemsProvider* mainMenuItemsProvider; ++ ++ if (cPluginManager::CallFirstService(MENU_ITEMS_PROVIDER_SERVICE_ID, &mainMenuItemsProvider)) ++ { ++ _mainMenuItemsProvider = mainMenuItemsProvider; ++ } ++ } ++ return _mainMenuItemsProvider; ++ } ++ ++ public: ++ static bool IsCustomMenuAvailable() ++ { ++ return (MainMenuItemsProvider() != NULL) && (MainMenuItemsProvider()->IsCustomMenuAvailable()); ++ } ++ ++ static void EnterRootMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterRootMenu(); ++ } ++ } ++ ++ static bool LeaveSubMenu() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->LeaveSubMenu(); ++ } ++ return false; ++ } ++ ++ static void EnterSubMenu(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ MainMenuItemsProvider()->EnterSubMenu(item); ++ } ++ } ++ ++ static MenuItemDefinitions* MainMenuItems() ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->MainMenuItems(); ++ } ++ return NULL; ++ } ++ ++ static cOsdMenu* Execute(cOsdItem* item) ++ { ++ if (MainMenuItemsProvider()) ++ { ++ return MainMenuItemsProvider()->Execute(item); ++ } ++ return NULL; ++ } ++}; ++ ++IMainMenuItemsProvider* MenuOrgPatch::_mainMenuItemsProvider = NULL; ++ ++#endif //__MENUORGPATCH_H ++#endif /* MENUORG */ +diff -ruNp vdr-1.7.5/osdbase.c vdr-1.7.5-extensions/osdbase.c +--- vdr-1.7.5/osdbase.c 2008-02-17 12:33:04.000000000 +0100 ++++ vdr-1.7.5-extensions/osdbase.c 2009-04-12 13:37:59.000000000 +0200 +@@ -22,6 +22,9 @@ cOsdItem::cOsdItem(eOSState State) + state = State; + selectable = true; + fresh = true; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + + cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable) +@@ -31,8 +34,23 @@ cOsdItem::cOsdItem(const char *Text, eOS + selectable = Selectable; + fresh = true; + SetText(Text); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ subMenu = 0; ++#endif /* SETUP & PINPLUGIN */ + } + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++cOsdItem::cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu) ++{ ++ text = NULL; ++ state = State; ++ selectable = true; ++ fresh = true; ++ SetText(Text); ++ subMenu = SubMenu; ++} ++#endif /* SETUP & PINPLUGIN */ ++ + cOsdItem::~cOsdItem() + { + free(text); +@@ -77,6 +95,9 @@ cOsdMenu::cOsdMenu(const char *Title, in + { + isMenu = true; + digit = 0; ++#ifdef USE_LIEMIEXT ++ key_nr = -1; ++#endif /* LIEMIEXT */ + hasHotkeys = false; + title = NULL; + SetTitle(Title); +@@ -97,6 +118,9 @@ cOsdMenu::~cOsdMenu() + free(status); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDestroy(); ++#endif /* GRAPHTFT */ + if (!--displayMenuCount) + DELETENULL(displayMenu); + } +@@ -119,7 +143,11 @@ const char *cOsdMenu::hk(const char *s) + digit = -1; // prevents automatic hotkeys - input already has them + if (digit >= 0) { + digit++; ++#ifdef USE_LIEMIEXT ++ buffer = cString::sprintf(" %2d%s %s", digit, (digit > 9) ? "" : " ", s); ++#else + buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s); ++#endif /* LIEMIEXT */ + s = buffer; + } + } +@@ -199,9 +227,15 @@ void cOsdMenu::Display(void) + subMenu->Display(); + return; + } ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + displayMenu->SetMessage(mtStatus, NULL); + displayMenu->Clear(); + cStatus::MsgOsdClear(); ++#ifdef USE_GRAPHTFT ++ cStatus::MsgOsdMenuDisplay(MenuKind()); ++#endif /* GRAPHTFT */ + displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX + displayMenu->SetTitle(title); + cStatus::MsgOsdTitle(title); +@@ -296,6 +330,9 @@ bool cOsdMenu::SelectableItem(int idx) + + void cOsdMenu::CursorUp(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int tmpCurrent = current; + int lastOnScreen = first + displayMenuItems - 1; + int last = Count() - 1; +@@ -334,6 +371,9 @@ void cOsdMenu::CursorUp(void) + + void cOsdMenu::CursorDown(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int tmpCurrent = current; + int lastOnScreen = first + displayMenuItems - 1; + int last = Count() - 1; +@@ -374,6 +414,9 @@ void cOsdMenu::CursorDown(void) + + void cOsdMenu::PageUp(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int oldCurrent = current; + int oldFirst = first; + current -= displayMenuItems; +@@ -408,6 +451,9 @@ void cOsdMenu::PageUp(void) + + void cOsdMenu::PageDown(void) + { ++#ifdef USE_OSDMAXITEMS ++ displayMenuItems = displayMenu->MaxItems(); ++#endif /* OSDMAXITEMS */ + int oldCurrent = current; + int oldFirst = first; + current += displayMenuItems; +@@ -448,6 +494,64 @@ void cOsdMenu::Mark(void) + } + } + ++#ifdef USE_LIEMIEXT ++#define MENUKEY_TIMEOUT 1500 ++ ++eOSState cOsdMenu::HotKey(eKeys Key) ++{ ++ bool match = false; ++ bool highlight = false; ++ int item_nr; ++ int i; ++ ++ if (Key == kNone) { ++ if (lastActivity.TimedOut()) ++ Key = kOk; ++ else ++ return osContinue; ++ } ++ else { ++ lastActivity.Set(MENUKEY_TIMEOUT); ++ } ++ for (cOsdItem *item = Last(); item; item = Prev(item)) { ++ const char *s = item->Text(); ++ i = 0; ++ item_nr = 0; ++ if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') { ++ do { ++ item_nr = item_nr * 10 + (s[i] - '0'); ++ } ++ while (!((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9')); ++ if ((Key == kOk) && (item_nr == key_nr)) { ++ current = item->Index(); ++ RefreshCurrent(); ++ Display(); ++ cRemote::Put(kOk, true); ++ key_nr = -1; ++ break; ++ } ++ else if (Key != kOk) { ++ if (!highlight && (item_nr == (Key - k0))) { ++ highlight = true; ++ current = item->Index(); ++ } ++ if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) { ++ match = true; ++ key_nr = (Key - k0); ++ } ++ else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) { ++ current = item->Index(); ++ cRemote::Put(kOk, true); ++ key_nr = -1; ++ break; ++ } ++ } ++ } ++ } ++ if ((!match) && (Key != kNone)) { ++ key_nr = -1; ++ } ++#else + eOSState cOsdMenu::HotKey(eKeys Key) + { + for (cOsdItem *item = First(); item; item = Next(item)) { +@@ -462,6 +566,7 @@ eOSState cOsdMenu::HotKey(eKeys Key) + } + } + } ++#endif /* LIEMIEXT */ + return osContinue; + } + +@@ -500,8 +605,13 @@ eOSState cOsdMenu::ProcessKey(eKeys Key) + } + } + switch (Key) { ++#ifdef USE_LIEMIEXT ++ case kNone: ++ case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#else + case k0: return osUnknown; + case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown; ++#endif /* LIEMIEXT */ + case kUp|k_Repeat: + case kUp: CursorUp(); break; + case kDown|k_Repeat: +diff -ruNp vdr-1.7.5/osdbase.h vdr-1.7.5-extensions/osdbase.h +--- vdr-1.7.5/osdbase.h 2007-11-03 15:50:52.000000000 +0100 ++++ vdr-1.7.5-extensions/osdbase.h 2009-04-12 13:37:59.000000000 +0200 +@@ -15,6 +15,10 @@ + #include "skins.h" + #include "tools.h" + ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++#include "submenu.h" ++#endif /* SETUP & PINPLUGIN */ ++ + enum eOSState { osUnknown, + osContinue, + osSchedule, +@@ -51,16 +55,26 @@ private: + char *text; + eOSState state; + bool selectable; ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cSubMenuNode* subMenu; ++#endif /* SETUP & PINPLUGIN */ + protected: + bool fresh; + public: + cOsdItem(eOSState State = osUnknown); + cOsdItem(const char *Text, eOSState State = osUnknown, bool Selectable = true); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu); ++#endif /* SETUP & PINPLUGIN */ + virtual ~cOsdItem(); + bool Selectable(void) const { return selectable; } + void SetText(const char *Text, bool Copy = true); + void SetSelectable(bool Selectable); + void SetFresh(bool Fresh); ++#if defined (USE_SETUP) && defined (USE_PINPLUGIN) ++ void SetSubMenu(cSubMenuNode* SubMenu) { subMenu = SubMenu; } ++ cSubMenuNode* SubMenu() { return subMenu; } ++#endif /* SETUP & PINPLUGIN */ + const char *Text(void) const { return text; } + virtual void Set(void) {} + virtual eOSState ProcessKey(eKeys Key); +@@ -95,6 +109,10 @@ private: + char *status; + int digit; + bool hasHotkeys; ++#ifdef USE_LIEMIEXT ++ int key_nr; ++ cTimeMs lastActivity; ++#endif /* LIEMIEXT */ + protected: + void SetDisplayMenu(void); + cSkinDisplayMenu *DisplayMenu(void) { return displayMenu; } +@@ -129,6 +147,9 @@ public: + void Ins(cOsdItem *Item, bool Current = false, cOsdItem *Before = NULL); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); ++#ifdef USE_GRAPHTFT ++ virtual const char* MenuKind() { return "MenuUnknown"; } ++#endif /* GRAPHTFT */ + }; + + #endif //__OSDBASE_H +diff -ruNp vdr-1.7.5/osd.c vdr-1.7.5-extensions/osd.c +--- vdr-1.7.5/osd.c 2009-04-05 12:17:25.000000000 +0200 ++++ vdr-1.7.5-extensions/osd.c 2009-04-12 13:37:59.000000000 +0200 +@@ -724,6 +724,9 @@ int cOsd::osdTop = 0; + int cOsd::osdWidth = 0; + int cOsd::osdHeight = 0; + cVector<cOsd *> cOsd::Osds; ++#ifdef USE_PINPLUGIN ++bool cOsd::pinValid = false; ++#endif /* PINPLUGIN */ + + cOsd::cOsd(int Left, int Top, uint Level) + { +@@ -734,6 +737,9 @@ cOsd::cOsd(int Left, int Top, uint Level + width = height = 0; + level = Level; + active = false; ++#ifdef USE_YAEPG ++ vidWin.bpp = 0; ++#endif /* YAEPG */ + for (int i = 0; i < Osds.Size(); i++) { + if (Osds[i]->level > level) { + Osds.Insert(this, i); +diff -ruNp vdr-1.7.5/osd.h vdr-1.7.5-extensions/osd.h +--- vdr-1.7.5/osd.h 2009-04-05 12:16:05.000000000 +0200 ++++ vdr-1.7.5-extensions/osd.h 2009-04-12 13:37:59.000000000 +0200 +@@ -401,6 +401,12 @@ public: + ///< 7: vertical, falling, upper + virtual void Flush(void); + ///< Actually commits all data to the OSD hardware. ++#ifdef USE_PINPLUGIN ++ static bool pinValid; ++#endif /* PINPLUGIN */ ++#ifdef USE_YAEPG ++ tArea vidWin; ++#endif /* YAEPG */ + }; + + class cOsdProvider { +diff -ruNp vdr-1.7.5/plugin.c vdr-1.7.5-extensions/plugin.c +--- vdr-1.7.5/plugin.c 2009-04-05 12:16:48.000000000 +0200 ++++ vdr-1.7.5-extensions/plugin.c 2009-04-12 13:37:59.000000000 +0200 +@@ -317,6 +317,14 @@ void cPluginManager::AddPlugin(const cha + char *p = strchr(s, ' '); + if (p) + *p = 0; ++#ifdef USE_PLUGINMISSING ++ struct stat st; ++ if (stat (cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), &st) && errno == ENOENT) { ++ esyslog("WARN: missing plugin '%s'", s); ++ fprintf(stderr, "vdr: missing plugin '%s'\n", s); ++ } ++ else ++#endif /* PLUGINMISSING */ + dlls.Add(new cDll(cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), Args)); + free(s); + } +@@ -325,7 +333,11 @@ bool cPluginManager::LoadPlugins(bool Lo + { + for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) { + if (!dll->Load(Log)) ++#ifdef USE_PLUGINMISSING ++ ; ++#else + return false; ++#endif /* PLUGINMISSING */ + } + return true; + } +diff -ruNp vdr-1.7.5/po/ca_ES.po vdr-1.7.5-extensions/po/ca_ES.po +--- vdr-1.7.5/po/ca_ES.po 2009-04-12 11:08:04.000000000 +0200 ++++ vdr-1.7.5-extensions/po/ca_ES.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1010,3 +1010,270 @@ msgstr "Prem qualsevol tecla per cancel· + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR s'apagarà en %s minuts" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/cs_CZ.po vdr-1.7.5-extensions/po/cs_CZ.po +--- vdr-1.7.5/po/cs_CZ.po 2009-04-12 11:08:04.000000000 +0200 ++++ vdr-1.7.5-extensions/po/cs_CZ.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1008,3 +1008,270 @@ msgstr "Jakákoliv klávesa zru¹í restart" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se vypne za %s minut" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/da_DK.po vdr-1.7.5-extensions/po/da_DK.po +--- vdr-1.7.5/po/da_DK.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/da_DK.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1007,3 +1007,270 @@ msgstr "Tryk vilkårlig knap for at annul + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR slukker om %s minutter" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/de_DE.po vdr-1.7.5-extensions/po/de_DE.po +--- vdr-1.7.5/po/de_DE.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/de_DE.po 2009-04-12 13:37:59.000000000 +0200 +@@ -794,6 +794,30 @@ msgstr "Lautstärke beim Einschalten" + msgid "Setup.Miscellaneous$Emergency exit" + msgstr "Notausstieg" + ++msgid "Setup.Miscellaneous$Volume ctrl with left/right" ++msgstr "Lautstärke mit Rechts/Links regeln" ++ ++msgid "Setup.Miscellaneous$Channelgroups with left/right" ++msgstr "Kanalgruppen mit Rechts/Links" ++ ++msgid "Setup.Miscellaneous$only in channelinfo" ++msgstr "nur in Kanalinfo" ++ ++msgid "Setup.Miscellaneous$Search fwd/back with left/right" ++msgstr "Vor-/Rücklauf mit Rechts/Links" ++ ++msgid "Setup.Miscellaneous$only in progress display" ++msgstr "nur in Fortschrittsanzeige" ++ ++msgid "Setup.Miscellaneous$Lirc repeat delay" ++msgstr "Lirc Verzögerung" ++ ++msgid "Setup.Miscellaneous$Lirc repeat freq" ++msgstr "Lirc Frequenz" ++ ++msgid "Setup.Miscellaneous$Lirc repeat timeout" ++msgstr "Lirc Zeitbeschränkung" ++ + msgid "Plugins" + msgstr "Plugins" + +@@ -1007,3 +1031,336 @@ msgstr "Taste drücken, um Neustart abzub + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR wird in %s Minuten ausschalten" ++ ++msgid "Parameters" ++msgstr "Parameter" ++ ++msgid "Channel locked by LNB!" ++msgstr "Kanal durch LNB gesperrt!" ++ ++msgid "Childlock" ++msgstr "Kindersicherung" ++ ++msgid "Path" ++msgstr "Pfad" ++ ++msgid "Timer commands" ++msgstr "Befehle für Aufzeichnungen" ++ ++msgid "Rename recording" ++msgstr "Aufzeichnung umbenennen" ++ ++msgid "Date" ++msgstr "Datum" ++ ++msgid "Length" ++msgstr "Länge" ++ ++msgid "Size" ++msgstr "Größe" ++ ++msgid "Delete marks information?" ++msgstr "Marks löschen?" ++ ++msgid "Delete resume information?" ++msgstr "Resume löschen?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "Das DVD-Plugin ist nicht installiert!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Alphabet für Haupt-, flexibel für Unterverzeichnisse" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Datum für Haupt-, flexibel für Unterverzeichnisse" ++ ++msgid "all alphabetically" ++msgstr "Alles alphabetisch" ++ ++msgid "all by date" ++msgstr "Alles nach Datum" ++ ++msgid "Sorting" ++msgstr "Sortierung" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle icons verwenden" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "Hauptmenü Titel" ++ ++msgid "Setup.OSD$- Text" ++msgstr "- Text" ++ ++msgid "default" ++msgstr "Voreinstellung" ++ ++msgid "VDR - text" ++msgstr "VDR - Text" ++ ++msgid "text" ++msgstr "Text" ++ ++msgid "VDR - version" ++msgstr "VDR - Version" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Befehle Position im Hauptmenü" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Zeige gültige Eingabe" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Zeitbalken anzeigen" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Zeitspanne für dop. EPG-Suche (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Doppelten externen EPG-Eintrag" ++ ++msgid "Setup.EPG$Mode of noEPG-Patch" ++msgstr "Art des noEPG-Patches" ++ ++msgid "adjust" ++msgstr "anwenden" ++ ++msgid "delete" ++msgstr "löschen" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Internes und externes EPG mischen" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Erk. des lauf. VPS-Events abschalten" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "AC3-Transfer Fix benutzen" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "Sperre Kanäle" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "Kanal Sperren Filter" ++ ++msgid "qam256" ++msgstr "qam256" ++ ++msgid "dvb-c" ++msgstr "dvb-c" ++ ++msgid "dvb-s" ++msgstr "dvb-s" ++ ++msgid "all" ++msgstr "alle" ++ ++msgid "blacklist" ++msgstr "Blacklist" ++ ++msgid "whitelist" ++msgstr "Whitelist" ++ ++msgid "has decoder" ++msgstr "mit Decoder" ++ ++msgid "is primary" ++msgstr "ist primär" ++ ++msgid "has decoder + is primary" ++msgstr "mit Decoder und primär" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Sync Early Patch benutzen" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "DVB-Empfänger %d nutzt LNB Nr." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "LNB-Nutzung protokollieren" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Dolby Digital Ton aufzeichnen" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Videoverzeichnispolitik" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Anzahl der Videoverzeichnisse" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d Priorität" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. MB frei" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Freundliche Dateinamen" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Max. Aufnahmengröße (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Hard Link Cutter" ++ ++msgid "Setup.Recording$Delete timeshift recording" ++msgstr "Zeitversetzte Aufnahme löschen" ++ ++msgid "request" ++msgstr "abfragen" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Aufnahmedatum anzeigen" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Aufnahmezeit anzeigen" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Länge der Aufnahme anzeigen" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Ende für Timer anzeigen" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Aufnahmen sortieren nach" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Verzeichnisse vor Aufnahmen einsortieren" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Aufnahmen nach dem Schneiden löschen" ++ ++msgid "Setup.Recording$Cutter adjust starttime" ++msgstr "Startzeit beim Schneiden anpassen" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Wiedergabe nach Sprung" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Sprung bei Schnittmarke" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause bei letzter Marke" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Marken aktualisieren" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Sprungweite in Sekunden" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Sprungweite in Sekunden Langsam" ++ ++msgid "Setup.Replay$Length" ++msgstr "Länge" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Länge / Nummer" ++ ++msgid "Setup.Replay$Number" ++msgstr "Nummer" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "DVD Anzeige" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "DVD führende Nullen anzeigen" ++ ++msgid "Setup.Replay$never" ++msgstr "nie" ++ ++msgid "Setup.Replay$on begin" ++msgstr "am Anfang" ++ ++msgid "Setup.Replay$on end" ++msgstr "am Ende" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "am Anfang und Ende" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "DVD-Schublade öffnen" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "DVD drosseln auf" ++ ++msgid "Jump" ++msgstr "Springen: " ++ ++msgid "Skip +60s" ++msgstr "Sprung +60s" ++ ++msgid "Skip -60s" ++msgstr "Sprung -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Schnitt bereits aktiv - zur Schnitt-Liste hinzufügen?" ++ ++msgid "Format" ++msgstr "Format" ++ ++msgid "PES" ++msgstr "PES" ++ ++msgid "TS" ++msgstr "TS" ++ ++msgid "Rename$Up" ++msgstr "Höher" ++ ++msgid "Rename$Down" ++msgstr "Tiefer" ++ ++msgid "Rename$Previous" ++msgstr "Vorheriger" ++ ++msgid "Rename$Next" ++msgstr "Nächster" ++ ++msgid "Please mount %s" ++msgstr "Bitte %s einlegen!" ++ ++msgid "Please mount DVD %04d" ++msgstr "Bitte DVD %04d einlegen!" ++ ++msgid "Please mount DVD %d" ++msgstr "Bitte DVD %d einlegen!" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Bitte warten. Überprüfe DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Keine Index-Datei gefunden. Erstellung kann Minuten dauern. Erstellen?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Bitte warten. Index-Datei wird erstellt..." ++ ++msgid "Wrong DVD!" ++msgstr "Falsche DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Permanentes Timeshift" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Speicherort" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "Festplatte" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "Arbeitsspeicher" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Puffergröße im Arbeitsspeicher (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Auf Festplatte ausweiten wenn nötig" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Pausierten Puffer beibehalten" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Puffergröße auf Festplatte (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Puffergröße (MB)" +diff -ruNp vdr-1.7.5/po/el_GR.po vdr-1.7.5-extensions/po/el_GR.po +--- vdr-1.7.5/po/el_GR.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/el_GR.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1007,3 +1007,270 @@ msgstr "" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/es_ES.po vdr-1.7.5-extensions/po/es_ES.po +--- vdr-1.7.5/po/es_ES.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/es_ES.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1008,3 +1008,270 @@ msgstr "Pulse cualquier tecla para cance + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se apagará en %s minutos" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/et_EE.po vdr-1.7.5-extensions/po/et_EE.po +--- vdr-1.7.5/po/et_EE.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/et_EE.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1007,3 +1007,279 @@ msgstr "Restardi katkestamiseks vajuta s + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR lülitub välja %s minuti pärast" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "Ümbernimetamine" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Käsu asukoht peamenüüs" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Edenemisriba" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Salvestuse kuupäev" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Salvestuse kellaaeg" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Salvestuse pikkus" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Format" ++msgstr "" ++ ++msgid "PES" ++msgstr "" ++ ++msgid "TS" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "Üles" ++ ++msgid "Rename$Down" ++msgstr "Alla" ++ ++msgid "Rename$Previous" ++msgstr "Eelmine" ++ ++msgid "Rename$Next" ++msgstr "Järgmine" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/fi_FI.po vdr-1.7.5-extensions/po/fi_FI.po +--- vdr-1.7.5/po/fi_FI.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/fi_FI.po 2009-04-12 13:37:59.000000000 +0200 +@@ -42,6 +42,253 @@ msgstr "Siirtotilan aloitus epäonnistui! + msgid "Starting EPG scan" + msgstr "Ohjelmaoppaan päivitys aloitettu" + ++msgid "Content$Movie/Drama" ++msgstr "Elokuva/draama" ++ ++msgid "Content$Detective/Thriller" ++msgstr "Etsivä/trilleri" ++ ++msgid "Content$Adventure/Western/War" ++msgstr "Seikkailu/western/sota" ++ ++msgid "Content$Science Fiction/Fantasy/Horror" ++msgstr "Scifi/fantasia/kauhu" ++ ++msgid "Content$Comedy" ++msgstr "Komedia" ++ ++msgid "Content$Soap/Melodrama/Folkloric" ++msgstr "Saippua/melodraama/kansanperinne" ++ ++msgid "Content$Romance" ++msgstr "Romanssi" ++ ++msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" ++msgstr "Vakava/klassinen/uskonnollinen/historiallinen elokuva/draama" ++ ++msgid "Content$Adult Movie/Drama" ++msgstr "Aikuiselokuva/draama" ++ ++msgid "Content$News/Current Affairs" ++msgstr "Uutiset/ajankohtaisohjelma" ++ ++msgid "Content$News/Weather Report" ++msgstr "Uutiset/säätiedot" ++ ++msgid "Content$News Magazine" ++msgstr "Uutismakasiini" ++ ++msgid "Content$Documentary" ++msgstr "Dokumentti" ++ ++msgid "Content$Discussion/Inverview/Debate" ++msgstr "Keskustelu/haastattelu/väittely" ++ ++msgid "Content$Show/Game Show" ++msgstr "Show/visailu" ++ ++msgid "Content$Game Show/Quiz/Contest" ++msgstr "Visailu/kilpailu" ++ ++msgid "Content$Variety Show" ++msgstr "Varietee" ++ ++msgid "Content$Talk Show" ++msgstr "Keskusteluohjelma" ++ ++msgid "Content$Sports" ++msgstr "Urheilua" ++ ++msgid "Content$Special Event" ++msgstr "Erikoistapahtuma" ++ ++msgid "Content$Sport Magazine" ++msgstr "Urheilumakasiini" ++ ++msgid "Content$Football" ++msgstr "Jalkapallo" ++ ++msgid "Content$Tennis/Squash" ++msgstr "Tennis/Squash" ++ ++msgid "Content$Team Sports" ++msgstr "Joukkueurheilua" ++ ++msgid "Content$Athletics" ++msgstr "Yleisurheilua" ++ ++msgid "Content$Motor Sport" ++msgstr "Moottoriurheilua" ++ ++msgid "Content$Water Sport" ++msgstr "Vesiurheilua" ++ ++msgid "Content$Winter Sports" ++msgstr "Talviurheilua" ++ ++msgid "Content$Equestrian" ++msgstr "Ratsastusta" ++ ++msgid "Content$Martial Sports" ++msgstr "Kamppailu-urheilua" ++ ++msgid "Content$Children's/Youth Programmes" ++msgstr "Lasten ja nuorten ohjelma" ++ ++msgid "Content$Pre-school Children's Programmes" ++msgstr "Alle kouluikäisten ohjelma" ++ ++msgid "Content$Entertainment Programmes for 6 to 14" ++msgstr "Viihdeohjelma 6-14 vuotiaille" ++ ++msgid "Content$Entertainment Programmes for 10 to 16" ++msgstr "Viihdeohjelma 10-16 vuotiaille" ++ ++msgid "Content$Informational/Educational/School Programme" ++msgstr "Opetus/kouluohjelma" ++ ++msgid "Content$Cartoons/Puppets" ++msgstr "Piirretty/nukke-esitys" ++ ++msgid "Content$Music/Ballet/Dance" ++msgstr "Musiikki/baletti/tanssi" ++ ++msgid "Content$Rock/Pop" ++msgstr "Rock/pop" ++ ++msgid "Content$Serious/Classical Music" ++msgstr "Vakava/klassinen musiikki" ++ ++msgid "Content$Folk/Tradional Music" ++msgstr "Folk/kansanmusiikki" ++ ++msgid "Content$Jazz" ++msgstr "Jazz" ++ ++msgid "Content$Musical/Opera" ++msgstr "Musikaali/ooppera" ++ ++msgid "Content$Ballet" ++msgstr "Baletti" ++ ++msgid "Content$Arts/Culture" ++msgstr "Taide/kulttuuri" ++ ++msgid "Content$Performing Arts" ++msgstr "Performanssitaide" ++ ++msgid "Content$Fine Arts" ++msgstr "Kuvataide" ++ ++msgid "Content$Religion" ++msgstr "Uskonto" ++ ++msgid "Content$Popular Culture/Traditional Arts" ++msgstr "Populaarikulttuuri/perinnetaiteet" ++ ++msgid "Content$Literature" ++msgstr "Kirjallisuus" ++ ++msgid "Content$Film/Cinema" ++msgstr "Elokuvataide" ++ ++msgid "Content$Experimental Film/Video" ++msgstr "Kokeellinen elokuva/video" ++ ++msgid "Content$Broadcasting/Press" ++msgstr "Televisio/radio/lehdistö" ++ ++msgid "Content$New Media" ++msgstr "Uusmedia" ++ ++msgid "Content$Arts/Culture Magazines" ++msgstr "Taide/kulttuurimakasiini" ++ ++msgid "Content$Fashion" ++msgstr "Muoti" ++ ++msgid "Content$Social/Political/Economics" ++msgstr "Yhteiskunta/politiikka/talous" ++ ++msgid "Content$Magazines/Reports/Documentary" ++msgstr "Makasiini/reportaasi/dokumentti" ++ ++msgid "Content$Economics/Social Advisory" ++msgstr "Talous/yhteiskunnallinen neuvonta" ++ ++msgid "Content$Remarkable People" ++msgstr "Merkittävät henkilöt" ++ ++msgid "Content$Education/Science/Factual" ++msgstr "Koulutus/tiede" ++ ++msgid "Content$Nature/Animals/Environment" ++msgstr "Luonto/eläimet/ympäristö" ++ ++msgid "Content$Technology/Natural Sciences" ++msgstr "Teknologia/luonnontiede" ++ ++msgid "Content$Medicine/Physiology/Psychology" ++msgstr "Lääketiede/fysiologia/psykologia" ++ ++msgid "Content$Foreign Countries/Expeditions" ++msgstr "Vieraat maat/tutkimusretket" ++ ++msgid "Content$Social/Spiritual Sciences" ++msgstr "Yhteiskunta/hengelliset tieteet" ++ ++msgid "Content$Further Education" ++msgstr "Jatkokoulutus" ++ ++msgid "Content$Languages" ++msgstr "Kielet" ++ ++msgid "Content$Leisure/Hobbies" ++msgstr "Vapaa-aika ja harrastukset" ++ ++msgid "Content$Tourism/Travel" ++msgstr "Turismi/matkustaminen" ++ ++msgid "Content$Handicraft" ++msgstr "Käsityöt" ++ ++msgid "Content$Motoring" ++msgstr "Autoilu" ++ ++msgid "Content$Fitness & Health" ++msgstr "Kuntoilu & terveys" ++ ++msgid "Content$Cooking" ++msgstr "Ruuanlaitto" ++ ++msgid "Content$Advertisement/Shopping" ++msgstr "Mainostaminen/ostaminen" ++ ++msgid "Content$Gardening" ++msgstr "Puutarhanhoito" ++ ++msgid "Content$Original Language" ++msgstr "Alkuperäiskieli" ++ ++msgid "Content$Black & White" ++msgstr "Mustavalkoinen" ++ ++msgid "Content$Unpublished" ++msgstr "Julkaisematon" ++ ++msgid "Content$Live Broadcast" ++msgstr "Suoralähetys" ++ ++msgid "Content$Special Characteristics" ++msgstr "Erikoisominaisuus" ++ ++msgid "Content$Drama" ++msgstr "Draama" ++ ++#, c-format ++msgid "Suitable for those aged %d and over" ++msgstr "Kielletty alle %d vuotiailta" ++ + msgid "No title" + msgstr "Ei esitystä" + +@@ -1010,3 +1257,282 @@ msgstr "Peru uudelleenkäynnistys painama + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR sammuu %s minuutin kuluttua" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "Polku" ++ ++msgid "Timer commands" ++msgstr "Ajastinkomennot" ++ ++msgid "Rename recording" ++msgstr "Nimeä tallenne" ++ ++msgid "Date" ++msgstr "Päiväys" ++ ++msgid "Length" ++msgstr "Pituus" ++ ++msgid "Size" ++msgstr "Koko" ++ ++msgid "Delete marks information?" ++msgstr "Poista tallenteen merkinnät" ++ ++msgid "Delete resume information?" ++msgstr "Poista tallenteen paluutiedot" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Komentojen sijainti päävalikossa" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Näytä aikajana" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Dolby Digital tallennus" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Näytä tallenteen päiväys" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Näytä tallenteen ajankohta" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Näytä tallenteen kesto" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Format" ++msgstr "Tiedostomuoto" ++ ++msgid "PES" ++msgstr "PES" ++ ++msgid "TS" ++msgstr "TS" ++ ++msgid "Rename$Up" ++msgstr "Ylemmäs" ++ ++msgid "Rename$Down" ++msgstr "Alemmas" ++ ++msgid "Rename$Previous" ++msgstr "Edellinen" ++ ++msgid "Rename$Next" ++msgstr "Seuraava" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Parameters" ++msgstr "Parametrit" ++ ++msgid "Permanent Timeshift" ++msgstr "Jatkuva ajansiirto" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Puskurin sijainti" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "kovalevyllä" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "muistissa" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Puffergröße im Arbeitsspeicher (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Käytä kovalevyä tarvittaessa" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Pidä pysäytetty puskuri" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Puffergröße auf Festplatte (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Puskurin koko (MB)" +diff -ruNp vdr-1.7.5/po/fr_FR.po vdr-1.7.5-extensions/po/fr_FR.po +--- vdr-1.7.5/po/fr_FR.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/fr_FR.po 2009-04-12 13:37:59.000000000 +0200 +@@ -8,6 +8,7 @@ + # Pierre Briec <pbriec@free.fr>, 2006 + # Bruno Roussel <bruno.roussel@free.fr>, 2007 + # Michael Nival <mnival@club-internet.fr>, 2007 ++# Patrice Staudt <patrice.staudt@laposte.net>, 2007, 2008 + # + msgid "" + msgstr "" +@@ -1013,3 +1014,279 @@ msgstr "Appuyer sur une touche pour annu + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR s'arrêtera dans %s minutes" ++ ++msgid "Channel locked by LNB!" ++msgstr "Chaîne interdite par la LNB" ++ ++msgid "Childlock" ++msgstr "Adulte" ++ ++msgid "Path" ++msgstr "Dossiers" ++ ++msgid "Format" ++msgstr "Format" ++ ++msgid "PES" ++msgstr "PES" ++ ++msgid "TS" ++msgstr "TS" ++ ++msgid "Timer commands" ++msgstr "Commandes de programmation" ++ ++msgid "Rename recording" ++msgstr "Renommer l'enregistrement" ++ ++msgid "Date" ++msgstr "Date" ++ ++msgid "Length" ++msgstr "Longeur" ++ ++msgid "Size" ++msgstr "Taille" ++ ++msgid "Delete marks information?" ++msgstr "Effacer marque d'information?" ++ ++msgid "Delete resume information?" ++msgstr "Effacer resume information?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "Le plugin de DVD n'est pas installé!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Dir principal alphabétiquement, subdirs flexibles" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Dir principal à la date, subdirs flexibles" ++ ++msgid "all alphabetically" ++msgstr "tous alphabétiquement" ++ ++msgid "all by date" ++msgstr "tous à la date" ++ ++msgid "Sorting" ++msgstr "Triage" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "Icônes WarEagle" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Position des commandes dans le menu" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Afficher l'entrée valide" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Montrer la barre de progression" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Intervalle de recherche EPG de double(min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Double entrée EPG externe" ++ ++msgid "adjust" ++msgstr "ajuster" ++ ++msgid "delete" ++msgstr "effacer" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mélanger les EPG interne et externe" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Arreter la reconnaissance des événements VPS" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Utiliser le correctif AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Utilisez Sync début patch" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "La carte DVB %d utilise la LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Protocoller l'utilisation du LNB" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Enregistrer en Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Régles de répertoires vidéo" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Nombre de répertoires vidéo" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d prioritaires" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. librei Mo" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Noms de fichiers facile" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Taille max. de l'enregistrement (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Découpe Hard links" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Montrer la date d'enregistrement" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Montrer l'heure d'enregistrement" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Montrer la longueur de l'enregistrement" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Montrer la fin du temporisateur" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Ordonner les enregistrement suivant" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Les dossiers devant les enregistrements" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Effacer l'enregistrement après la découpe" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Lecture après saut" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Saut sur les marques de découpes" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pause après la dernière marque" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Actualiser les marques" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Longueur de saut en secondes" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Longueur de saut lent en secondes" ++ ++msgid "Setup.Replay$Length" ++msgstr "Longueur" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Longueur / Numéro" ++ ++msgid "Setup.Replay$Number" ++msgstr "Numéro" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "Afficher le DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "Afficher les zéros devant le numéro du DVD" ++ ++msgid "Setup.Replay$never" ++msgstr "jamais" ++ ++msgid "Setup.Replay$on begin" ++msgstr "au début" ++ ++msgid "Setup.Replay$on end" ++msgstr "à la fin" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "au début et à la fin" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Ouvrir le tiroir du lecteur DVD" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Ralentir la vitesse du DVD à" ++ ++msgid "Jump" ++msgstr "Saut" ++ ++msgid "Skip +60s" ++msgstr "Avance +60s" ++ ++msgid "Skip -60s" ++msgstr "Recule -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Découpe déjà active - l'ajouter à la liste de découpe?" ++ ++msgid "Rename$Up" ++msgstr "Haut" ++ ++msgid "Rename$Down" ++msgstr "Bas" ++ ++msgid "Rename$Previous" ++msgstr "Précédent" ++ ++msgid "Rename$Next" ++msgstr "Suivant" ++ ++msgid "Please mount %s" ++msgstr "Mettez %s dans le lecteur" ++ ++msgid "Please mount DVD %04d" ++msgstr "Mettez le DVD %04d dans le lecteur" ++ ++msgid "Please mount DVD %d" ++msgstr "Mettez le DVD %d dans le lecteur" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Un moment SVP. Vérification du DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Pas trouvé de fichiers index. La création de ce ficher prends quelques minutes. Créer?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Attendez, svp. Le fichier index est en cours de création..." ++ ++msgid "Wrong DVD!" ++msgstr "Mauvais DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Timeshift permanent" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Localisation" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "disque dur" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "mémoire" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Taille de la mémoire tampon dans la mémoire (Mo)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Ètendre au disque dur, si nécessaire" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Gardez en veille la mémoire tampon" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Taille de la mémoire tampon sur le disque dur (Mo)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Taille de la mémoire tampon (Mo)" +diff -ruNp vdr-1.7.5/po/hr_HR.po vdr-1.7.5-extensions/po/hr_HR.po +--- vdr-1.7.5/po/hr_HR.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/hr_HR.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1009,3 +1009,270 @@ msgstr "Pritisnite jednu tipku za poni¹t + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR æe se iskljuèiti za %s minuta" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/hu_HU.po vdr-1.7.5-extensions/po/hu_HU.po +--- vdr-1.7.5/po/hu_HU.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/hu_HU.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1010,3 +1010,270 @@ msgstr "Nyomj egy gombot az újraindítás + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "A VDR leáll %s perc múlva" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/it_IT.po vdr-1.7.5-extensions/po/it_IT.po +--- vdr-1.7.5/po/it_IT.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/it_IT.po 2009-04-12 13:37:59.000000000 +0200 +@@ -37,6 +37,9 @@ msgstr "nessuno" + msgid "*** Invalid Channel ***" + msgstr "*** Canale NON valido ***" + ++msgid "Channel locked by LNB!" ++msgstr "Canale bloccato dal LNB!" ++ + msgid "Channel not available!" + msgstr "Canale non disponibile!" + +@@ -46,6 +49,253 @@ msgstr "Impossibile avviare mod. trasfer + msgid "Starting EPG scan" + msgstr "Inizio scansione EPG" + ++msgid "Content$Movie/Drama" ++msgstr "Film/Dramma" ++ ++msgid "Content$Detective/Thriller" ++msgstr "Investigativo/Giallo" ++ ++msgid "Content$Adventure/Western/War" ++msgstr "Avventura/Western/Guerra" ++ ++msgid "Content$Science Fiction/Fantasy/Horror" ++msgstr "Finzione/Fantasia/Horror" ++ ++msgid "Content$Comedy" ++msgstr "Commedia" ++ ++msgid "Content$Soap/Melodrama/Folkloric" ++msgstr "Telenovella/Melodramma/Folcloristico" ++ ++msgid "Content$Romance" ++msgstr "Romanzo" ++ ++msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" ++msgstr "Serio/Classico/Religioso/Film storico/Dramma" ++ ++msgid "Content$Adult Movie/Drama" ++msgstr "Film per adulti/Dramma" ++ ++msgid "Content$News/Current Affairs" ++msgstr "Notizie/Ultima ora" ++ ++msgid "Content$News/Weather Report" ++msgstr "Notizie/Previsioni meteo" ++ ++msgid "Content$News Magazine" ++msgstr "Rivista di notizie" ++ ++msgid "Content$Documentary" ++msgstr "Documentario" ++ ++msgid "Content$Discussion/Inverview/Debate" ++msgstr "Discussione/Intervista/Dibattito" ++ ++msgid "Content$Show/Game Show" ++msgstr "Spettacolo/Gioco a premi" ++ ++msgid "Content$Game Show/Quiz/Contest" ++msgstr "Gioco a premi/Quiz/Gara" ++ ++msgid "Content$Variety Show" ++msgstr "Spettacolo di varietà" ++ ++msgid "Content$Talk Show" ++msgstr "Talk Show" ++ ++msgid "Content$Sports" ++msgstr "Sport" ++ ++msgid "Content$Special Event" ++msgstr "Evento speciale" ++ ++msgid "Content$Sport Magazine" ++msgstr "Rivista di sport" ++ ++msgid "Content$Football" ++msgstr "Calcio" ++ ++msgid "Content$Tennis/Squash" ++msgstr "Tennis/Squash" ++ ++msgid "Content$Team Sports" ++msgstr "Sport di squadra" ++ ++msgid "Content$Athletics" ++msgstr "Atletica" ++ ++msgid "Content$Motor Sport" ++msgstr "Sport motoristici" ++ ++msgid "Content$Water Sport" ++msgstr "Sport acquatici" ++ ++msgid "Content$Winter Sports" ++msgstr "Sport invernali" ++ ++msgid "Content$Equestrian" ++msgstr "Equitazione" ++ ++msgid "Content$Martial Sports" ++msgstr "Arti marziali" ++ ++msgid "Content$Children's/Youth Programmes" ++msgstr "Programmi per ragazzi/giovani" ++ ++msgid "Content$Pre-school Children's Programmes" ++msgstr "Programmi per ragazzi prescolastici" ++ ++msgid "Content$Entertainment Programmes for 6 to 14" ++msgstr "Programmi di intrattenimento da 6 a 14" ++ ++msgid "Content$Entertainment Programmes for 10 to 16" ++msgstr "Programmi di intrattenimento da 10 a 16" ++ ++msgid "Content$Informational/Educational/School Programme" ++msgstr "Informativo/Educativo/Programma scolastico" ++ ++msgid "Content$Cartoons/Puppets" ++msgstr "Cartoni/Pupazzi" ++ ++msgid "Content$Music/Ballet/Dance" ++msgstr "Musica/Balletto/Danza" ++ ++msgid "Content$Rock/Pop" ++msgstr "Rock/Pop" ++ ++msgid "Content$Serious/Classical Music" ++msgstr "Serio/Musica classica" ++ ++msgid "Content$Folk/Tradional Music" ++msgstr "Folclore/Musica tradizionale" ++ ++msgid "Content$Jazz" ++msgstr "Jazz" ++ ++msgid "Content$Musical/Opera" ++msgstr "Musical/Opera" ++ ++msgid "Content$Ballet" ++msgstr "Balletto" ++ ++msgid "Content$Arts/Culture" ++msgstr "Arte/Cultura" ++ ++msgid "Content$Performing Arts" ++msgstr "Arti di rendimento" ++ ++msgid "Content$Fine Arts" ++msgstr "Arti fine" ++ ++msgid "Content$Religion" ++msgstr "Religione" ++ ++msgid "Content$Popular Culture/Traditional Arts" ++msgstr "Cultura popolare/Arti tradizionali" ++ ++msgid "Content$Literature" ++msgstr "Letteratura" ++ ++msgid "Content$Film/Cinema" ++msgstr "Film/Cinema" ++ ++msgid "Content$Experimental Film/Video" ++msgstr "Film esperimentale/Video" ++ ++msgid "Content$Broadcasting/Press" ++msgstr "Trasmissione/Stampa" ++ ++msgid "Content$New Media" ++msgstr "Nuovo programma" ++ ++msgid "Content$Arts/Culture Magazines" ++msgstr "Arte/Riviste di cultura" ++ ++msgid "Content$Fashion" ++msgstr "Moda" ++ ++msgid "Content$Social/Political/Economics" ++msgstr "Società/Politica/Economia" ++ ++msgid "Content$Magazines/Reports/Documentary" ++msgstr "Riviste/Reportage/Documentari" ++ ++msgid "Content$Economics/Social Advisory" ++msgstr "Economia/Consulenza sociale" ++ ++msgid "Content$Remarkable People" ++msgstr "Personaggi importanti" ++ ++msgid "Content$Education/Science/Factual" ++msgstr "Educazione/Scienza/Fatti" ++ ++msgid "Content$Nature/Animals/Environment" ++msgstr "Natura/Animali/Ambiente" ++ ++msgid "Content$Technology/Natural Sciences" ++msgstr "Tecnologia/Scienze naturali" ++ ++msgid "Content$Medicine/Physiology/Psychology" ++msgstr "Medicina/Filosofia/Psicologia" ++ ++msgid "Content$Foreign Countries/Expeditions" ++msgstr "Paesi esteri/Spedizioni" ++ ++msgid "Content$Social/Spiritual Sciences" ++msgstr "Società/Scienze spirituali" ++ ++msgid "Content$Further Education" ++msgstr "Altra educazione" ++ ++msgid "Content$Languages" ++msgstr "Lingua" ++ ++msgid "Content$Leisure/Hobbies" ++msgstr "Tempo libero/Hobby" ++ ++msgid "Content$Tourism/Travel" ++msgstr "Turismo/Viaggi" ++ ++msgid "Content$Handicraft" ++msgstr "Artigianato" ++ ++msgid "Content$Motoring" ++msgstr "Motori" ++ ++msgid "Content$Fitness & Health" ++msgstr "Culturismo & Salute" ++ ++msgid "Content$Cooking" ++msgstr "Cucina" ++ ++msgid "Content$Advertisement/Shopping" ++msgstr "Pubblicità/Acquisti" ++ ++msgid "Content$Gardening" ++msgstr "Giardinaggio" ++ ++msgid "Content$Original Language" ++msgstr "Lingua madre" ++ ++msgid "Content$Black & White" ++msgstr "Bianco & Nero" ++ ++msgid "Content$Unpublished" ++msgstr "Non pubblicato" ++ ++msgid "Content$Live Broadcast" ++msgstr "ys" ++ ++msgid "Content$Special Characteristics" ++msgstr "Caratteristiche speciali" ++ ++msgid "Content$Drama" ++msgstr "Dramma" ++ ++#, c-format ++msgid "Suitable for those aged %d and over" ++msgstr "Adatto per coloro con %d di età e oltre" ++ + msgid "No title" + msgstr "Senza titolo" + +@@ -232,6 +482,9 @@ msgstr "Utente8" + msgid "Key$User9" + msgstr "Utente9" + ++msgid "Recording started" ++msgstr "Registrazione avviata" ++ + msgid "Disk" + msgstr "Disco" + +@@ -325,6 +578,9 @@ msgstr "Gerarchia" + msgid "Rolloff" + msgstr "Rolloff" + ++msgid "Parameters" ++msgstr "Parametri" ++ + msgid "Channel settings are not unique!" + msgstr "Parametri canale non univoci!" + +@@ -376,9 +632,15 @@ msgstr "Priorità " + msgid "Lifetime" + msgstr "Scadenza" + ++msgid "Childlock" ++msgstr "Filtro fam." ++ + msgid "File" + msgstr "Nome" + ++msgid "Path" ++msgstr "Percorso" ++ + msgid "First day" + msgstr "1° giorno" + +@@ -397,6 +659,9 @@ msgstr "Eliminare il timer?" + msgid "Timer still recording - really delete?" + msgstr "Timer in registrazione - eliminare?" + ++msgid "Timer commands" ++msgstr "Comandi timer" ++ + msgid "Event" + msgstr "Evento" + +@@ -457,6 +722,27 @@ msgstr "Riproduci" + msgid "Button$Rewind" + msgstr "Riavvolgi" + ++msgid "Rename recording" ++msgstr "Rinomina registrazione" ++ ++msgid "Date" ++msgstr "Data" ++ ++msgid "Length" ++msgstr "Durata" ++ ++msgid "Size" ++msgstr "Dimensione" ++ ++msgid "Delete marks information?" ++msgstr "Eliminare informazione marcatori?" ++ ++msgid "Delete resume information?" ++msgstr "Eliminare informazione ripristino?" ++ ++msgid "Error while accessing recording!" ++msgstr "Errore accesso alla registrazione!" ++ + msgid "Recordings" + msgstr "Registrazioni" + +@@ -466,8 +752,8 @@ msgstr "Apri" + msgid "Commands" + msgstr "Comandi" + +-msgid "Error while accessing recording!" +-msgstr "Errore accesso alla registrazione!" ++msgid "DVD plugin is not installed!" ++msgstr "Il plugin DVD non è installato!" + + msgid "Delete recording?" + msgstr "Eliminare la registrazione?" +@@ -478,6 +764,21 @@ msgstr "Errore eliminazione registrazion + msgid "Recording commands" + msgstr "Comandi di registrazione" + ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "Dir. princ. in ordine alfabetico, sottodir. flessibili" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "Dir. princ. per data, sottodir. flessibili" ++ ++msgid "all alphabetically" ++msgstr "Tutte in ordine alfabetico" ++ ++msgid "all by date" ++msgstr "Tutte per data" ++ ++msgid "Sorting" ++msgstr "Ordinamento" ++ + msgid "never" + msgstr "mai" + +@@ -487,6 +788,18 @@ msgstr "in base allo stile interfaccia" + msgid "always" + msgstr "sempre" + ++msgid "default" ++msgstr "predefinito" ++ ++msgid "VDR - text" ++msgstr "VDR - Testo" ++ ++msgid "text" ++msgstr "Testo" ++ ++msgid "VDR - version" ++msgstr "VDR - Versione" ++ + msgid "OSD" + msgstr "OSD" + +@@ -499,6 +812,9 @@ msgstr "Stile interfaccia" + msgid "Setup.OSD$Theme" + msgstr "Tema colori" + ++msgid "Setup.OSD$WarEagle icons" ++msgstr "Icone WarEagle" ++ + msgid "Setup.OSD$Left" + msgstr "Sinistra" + +@@ -568,12 +884,30 @@ msgstr "Tasto Menu per chiudere" + msgid "Setup.OSD$Recording directories" + msgstr "Directory di registrazione" + ++msgid "Setup.OSD$Main menu title" ++msgstr "Titolo menu principale" ++ ++msgid "Setup.OSD$- Text" ++msgstr "- Testo" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Posizione comandi menu princ." ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Mostra ingresso valido" ++ + msgid "EPG" + msgstr "Guida programmi EPG" + + msgid "Button$Scan" + msgstr "Scansione" + ++msgid "blacklist" ++msgstr "lista nera" ++ ++msgid "whitelist" ++msgstr "elenco autorizzati" ++ + msgid "Setup.EPG$EPG scan timeout (h)" + msgstr "Scadenza aggiorn. EPG (ore)" + +@@ -583,6 +917,9 @@ msgstr "Livello correzione EPG" + msgid "Setup.EPG$EPG linger time (min)" + msgstr "Mostra vecchi dati EPG (min)" + ++msgid "Setup.EPG$Show progress bar" ++msgstr "Mostra barra avanzamento" ++ + msgid "Setup.EPG$Set system time" + msgstr "Imposta orario di sistema" + +@@ -597,6 +934,27 @@ msgstr "Lingue preferite" + msgid "Setup.EPG$Preferred language" + msgstr "Lingua preferita" + ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Tempo doppia ricerca EPG (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "Doppio valore EPG esterno" ++ ++msgid "adjust" ++msgstr "regola" ++ ++msgid "delete" ++msgstr "elimina" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mescola EPG interno e esterno" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Disabilita esec. evento VPS" ++ ++msgid "Setup.EPG$Mode of noEPG-Patch" ++msgstr "Modalità di noEPG-Patch" ++ + msgid "pan&scan" + msgstr "pan&scan" + +@@ -627,6 +985,27 @@ msgstr "nuovi transponder" + msgid "DVB" + msgstr "Scheda DVB" + ++msgid "qam256" ++msgstr "qam256" ++ ++msgid "dvb-c" ++msgstr "dvb-c" ++ ++msgid "dvb-s" ++msgstr "dvb-s" ++ ++msgid "all" ++msgstr "tutti" ++ ++msgid "has decoder" ++msgstr "con decoder" ++ ++msgid "is primary" ++msgstr "primaria" ++ ++msgid "has decoder + is primary" ++msgstr "con decoder e primaria" ++ + msgid "Setup.DVB$Primary DVB interface" + msgstr "Scheda DVB primaria" + +@@ -666,9 +1045,28 @@ msgstr "Trasparenza sottotitoli" + msgid "Setup.DVB$Subtitle background transparency" + msgstr "Trasparenza sfondo sottotitoli" + ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Utilizza correzione AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "Blocco canale" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "Modalità filtro blocco canale" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Utilizza correzione Early Sync" ++ + msgid "LNB" + msgstr "LNB" + ++#, c-format ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "La scheda DVB %d utilizza LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Registra utilizzo LNB" ++ + msgid "Setup.LNB$Use DiSEqC" + msgstr "Utilizza DiSEqC" + +@@ -711,6 +1109,9 @@ msgstr "La CAM è in uso - vuoi reimpost + msgid "Can't reset CAM!" + msgstr "Impossibile reimpostare il modulo CAM!" + ++msgid "request" ++msgstr "chiedi" ++ + msgid "Recording" + msgstr "Registrazione" + +@@ -735,9 +1136,29 @@ msgstr "Priorità di pausa" + msgid "Setup.Recording$Pause lifetime (d)" + msgstr "Scadenza pausa (gg)" + ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Registra Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Regole directory video" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Numero di directory video" ++ ++#, c-format ++msgid "Setup.Recording$Video %d priority" ++msgstr "Priorità video %d " ++ ++#, c-format ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Min. MB disponibili video %d " ++ + msgid "Setup.Recording$Use episode name" + msgstr "Utilizza nome episodio" + ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Nomi file semplici" ++ + msgid "Setup.Recording$Use VPS" + msgstr "Utilizza VPS" + +@@ -756,9 +1177,39 @@ msgstr "Durata reg. immediata (min)" + msgid "Setup.Recording$Max. video file size (MB)" + msgstr "Dim. massima file video (MB)" + ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Dim. massima reg. (GB)" ++ + msgid "Setup.Recording$Split edited files" + msgstr "Dividi i file modificati" + ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "Taglia collegamenti Hard" ++ ++msgid "Setup.Recording$Delete timeshift recording" ++msgstr "Elimina reg. timeshift" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Mostra data registrazione" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Mostra ora registrazione" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Mostra durata registrazione" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Mostra fine del timer" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Ordina registrazioni per" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Ordina directory prima di reg." ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Elimina taglio automatico" ++ + msgid "Replay" + msgstr "Riproduzione" + +@@ -771,6 +1222,63 @@ msgstr "Mostra modalità riproduzione" + msgid "Setup.Replay$Resume ID" + msgstr "ID di ripristino" + ++msgid "Setup.Replay$Jump&Play" ++msgstr "Vai a & Riproduci" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Riproduci & Vai a" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pausa all'ultimo marcatore" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Ricarica marcatori" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Salta secondi" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Salta secondi lentamente" ++ ++msgid "Setup.Replay$Length" ++msgstr "Durata" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Durata / Numero" ++ ++msgid "Setup.Replay$Number" ++msgstr "Numero" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "Mod. visualizzazione DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "Mostra zeri davanti al DVD" ++ ++msgid "Setup.Replay$never" ++msgstr "mai" ++ ++msgid "Setup.Replay$on begin" ++msgstr "all'inizio" ++ ++msgid "Setup.Replay$on end" ++msgstr "alla fine" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "all'inizio e alla fine" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Apri vassoio" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Limita velocità DVD a" ++ ++msgid "Setup.Miscellaneous$only in channelinfo" ++msgstr "solo nelle info canale" ++ ++msgid "Setup.Miscellaneous$only in progress display" ++msgstr "solo nel canale in esec." ++ + msgid "Miscellaneous" + msgstr "Generici" + +@@ -798,9 +1306,54 @@ msgstr "come prima" + msgid "Setup.Miscellaneous$Initial volume" + msgstr "Volume iniziale" + ++msgid "Setup.Miscellaneous$Volume ctrl with left/right" ++msgstr "Controllo volume con Sinistra/Destra" ++ ++msgid "Setup.Miscellaneous$Channelgroups with left/right" ++msgstr "Gruppi canali con Sinistra/Destra" ++ ++msgid "Setup.Miscellaneous$Search fwd/back with left/right" ++msgstr "Cerca avanti/indietro con Sinistra/Destra" ++ + msgid "Setup.Miscellaneous$Emergency exit" + msgstr "Uscita di emergenza" + ++msgid "Setup.Miscellaneous$Lirc repeat delay" ++msgstr "Ritardo ripetizione LIRC" ++ ++msgid "Setup.Miscellaneous$Lirc repeat freq" ++msgstr "Frequenza ripetizione LIRC" ++ ++msgid "Setup.Miscellaneous$Lirc repeat timeout" ++msgstr "Scadenza ripetizione LIRC" ++ ++msgid "Permanent Timeshift" ++msgstr "Timeshift permanente" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Posizione" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "Disco fisso" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "Memoria" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Dim. buffer in memoria (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Utilizza disco fisso se necessario" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Mantieni buffer di pausa" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Dim. buffer nel disco fisso (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Dimensione buffer (MB)" ++ + msgid "Plugins" + msgstr "Plugins" + +@@ -826,7 +1379,6 @@ msgstr "Programmi" + msgid "VDR" + msgstr "VDR" + +-#. TRANSLATORS: note the leading blank! + msgid " Stop replaying" + msgstr " Ferma riproduzione" + +@@ -842,7 +1394,6 @@ msgstr "Ferma" + msgid "Button$Resume" + msgstr "Riprendi" + +-#. TRANSLATORS: note the leading blank! + msgid " Cancel editing" + msgstr " Annulla modifiche" + +@@ -873,10 +1424,22 @@ msgstr "Nessuna periferica DVB disponibi + msgid "Pausing live video..." + msgstr "Pausa del canale in visione..." + ++msgid "Jump" ++msgstr "Vai a" ++ ++msgid "Skip +60s" ++msgstr "Salta +60s" ++ ++msgid "Skip -60s" ++msgstr "Salta - 60s" ++ + #. TRANSLATORS: note the trailing blank! + msgid "Jump: " + msgstr "Vai a: " + ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Taglio in esecuzione - Aggiungere alla coda tagli?" ++ + msgid "No editing marks defined!" + msgstr "Nessun marcatore di modifica definito!" + +@@ -907,6 +1470,18 @@ msgstr "Sovrascrivi" + msgid "Button$Insert" + msgstr "Inserisci" + ++msgid "Rename$Up" ++msgstr "Su" ++ ++msgid "Rename$Down" ++msgstr "Giù" ++ ++msgid "Rename$Previous" ++msgstr "Precedente" ++ ++msgid "Rename$Next" ++msgstr "Successivo" ++ + msgid "Plugin" + msgstr "Plugin" + +@@ -919,6 +1494,30 @@ msgstr "Canale bloccato (in registrazion + msgid "Low disk space!" + msgstr "Poco spazio su disco!" + ++#, c-format ++msgid "Please mount %s" ++msgstr "Monta %s" ++ ++#, c-format ++msgid "Please mount DVD %04d" ++msgstr "Monta il DVD %04d" ++ ++#, c-format ++msgid "Please mount DVD %d" ++msgstr "Monta il DVD %d" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Attendere prego. Verifica DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Nessun indice trovato. La creazione può impiegare alcuni minuti. Crearne uno?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Attendere prego. Creazione indice..." ++ ++msgid "Wrong DVD!" ++msgstr "DVD errato!" ++ + msgid "Can't shutdown - option '-s' not given!" + msgstr "Impossibile spegnere - parametro '-s' non assegnato!" + +@@ -990,9 +1589,6 @@ msgstr "Domenica" + msgid "Upcoming recording!" + msgstr "Registrazione imminente!" + +-msgid "Recording started" +-msgstr "Registrazione avviata" +- + msgid "VDR will shut down later - press Power to force" + msgstr "VDR si spegnerà più tardi - premi Power per forzare" + +diff -ruNp vdr-1.7.5/po/nl_NL.po vdr-1.7.5-extensions/po/nl_NL.po +--- vdr-1.7.5/po/nl_NL.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/nl_NL.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1011,3 +1011,270 @@ msgstr "Druk een willekeurige toets om h + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR zal na %s minuten uitschakelen" ++ ++msgid "Channel locked by LNB!" ++msgstr "Kanaal geblokkeerd door LNB" ++ ++msgid "Childlock" ++msgstr "Kinderslot" ++ ++msgid "Path" ++msgstr "Pad" ++ ++msgid "Timer commands" ++msgstr "Timer commando's" ++ ++msgid "Rename recording" ++msgstr "Hernoem opnamen" ++ ++msgid "Date" ++msgstr "Datum" ++ ++msgid "Length" ++msgstr "Lengte" ++ ++msgid "Size" ++msgstr "Grootte" ++ ++msgid "Delete marks information?" ++msgstr "Verwijder informatiemarkeringen?" ++ ++msgid "Delete resume information?" ++msgstr "Verwijder hervattingsmarkeringen?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "DVd plugin is niet geÃnstalleerd!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "hoofdmap alfabetisch, submappen flexibel" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "hoofdmap op datum, submappen flexibel" ++ ++msgid "all alphabetically" ++msgstr "alles alfabetisch" ++ ++msgid "all by date" ++msgstr "alles op datum" ++ ++msgid "Sorting" ++msgstr "Sortering" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle symbolen" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "Positie commandobalk in hoofdmenu" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "Toon geldige invoer" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "Toon voortschreidingsbalk" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "Tijdsduur starten dubbele EPG zoekactie (min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "externe dubbele EPG invoer" ++ ++msgid "adjust" ++msgstr "afstellen" ++ ++msgid "delete" ++msgstr "verwijderen" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "Mix in- en externe EPG" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "Schakel aktieve VPS uitzending uit" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "Gebruik AC3-Transfer Fix" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "Gebruik 'Sync Early' Patch" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "LNB kaart %d gebruikt LNB Nr." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "Houd LNB gebruik bij" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "Neem Dolby Digital spoor op" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "Omgang m.b.t. Videomappen" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "Aantal videomappen" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d prioriteit" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d min. vrij MB" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "Handzame bestandsnamen" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "Max. opnamegrootte (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "'Hard link' bestandsbewerker" ++ ++msgid "Setup.Recording$Show date" ++msgstr "Toon datum" ++ ++msgid "Setup.Recording$Show time" ++msgstr "Toon tijd" ++ ++msgid "Setup.Recording$Show length" ++msgstr "Toon lengte" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "Toon einde van timers" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "Sorteer opnames op" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "Sorteer mappen vÃÃr opnames" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "Bestandsbewerker automatisch wissen" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Spring&Speel" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Speel&Spring" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "Pauzeer bij laatste markering" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "Herlaadt markeringen" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "Spring seconden" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "Spring seconden langzaam" ++ ++msgid "Setup.Replay$Length" ++msgstr "Lengte" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "Lengte / Nummer" ++ ++msgid "Setup.Replay$Number" ++msgstr "Nummer" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "DVD displayinstellingen" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "DVD toon voorloopnullen" ++ ++msgid "Setup.Replay$never" ++msgstr "nooit" ++ ++msgid "Setup.Replay$on begin" ++msgstr "aan het begin" ++ ++msgid "Setup.Replay$on end" ++msgstr "bij het einde" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "bij het begin en aan het einde" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "Open DVD lade" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "Beperk DVD omw. snelheid" ++ ++msgid "Jump" ++msgstr "Spring" ++ ++msgid "Skip +60s" ++msgstr "Spring +60s verder" ++ ++msgid "Skip -60s" ++msgstr "Spring -60s terug" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "Bestandsbewerker aktief - aan wachtrij toeveogen?" ++ ++msgid "Rename$Up" ++msgstr "Boven" ++ ++msgid "Rename$Down" ++msgstr "Onder" ++ ++msgid "Rename$Previous" ++msgstr "Vorige" ++ ++msgid "Rename$Next" ++msgstr "Volgende" ++ ++msgid "Please mount %s" ++msgstr "Koppel %s aan a.u.b." ++ ++msgid "Please mount DVD %04d" ++msgstr "Koppel DVD %04d aan a.u.b." ++ ++msgid "Please mount DVD %d" ++msgstr "Koppel DVD %d aan a.u.b." ++ ++msgid "Please wait. Checking DVD..." ++msgstr "Even wachten, DVD wordt gecontroleerd..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "Geen indexbestand gevonden. Aanmaken duurt even, doorgaan?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "Even wachten indexbestand wordt aangemaakt..." ++ ++msgid "Wrong DVD!" ++msgstr "Verkeerde DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "Permanente livebuffer" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "Opslaglocatie" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "hardeschijf" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "geheugen" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "Buffergrootte in geheugen (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "Overlopen naar hardeschijf indien noodzakelijk" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "Bewaar gepauzeerde buffer" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "Buffergrootte op harddisk (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "Buffergrootte (MB)" +diff -ruNp vdr-1.7.5/po/nn_NO.po vdr-1.7.5-extensions/po/nn_NO.po +--- vdr-1.7.5/po/nn_NO.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/nn_NO.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1008,3 +1008,270 @@ msgstr "" + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/pl_PL.po vdr-1.7.5-extensions/po/pl_PL.po +--- vdr-1.7.5/po/pl_PL.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/pl_PL.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1008,3 +1008,270 @@ msgstr "Naci¶nij dowolny klawisz aby nie + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR zostanie wy³±czony za %s minut" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/pt_PT.po vdr-1.7.5-extensions/po/pt_PT.po +--- vdr-1.7.5/po/pt_PT.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/pt_PT.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1007,3 +1007,270 @@ msgstr "Pressione qualquer tecla para nã + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR vai desligar em %s minutos" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/ro_RO.po vdr-1.7.5-extensions/po/ro_RO.po +--- vdr-1.7.5/po/ro_RO.po 2009-04-12 11:08:05.000000000 +0200 ++++ vdr-1.7.5-extensions/po/ro_RO.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1010,3 +1010,270 @@ msgstr "Apãsaþi orice tastã pentru a anu + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se va închide în %s minute" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/ru_RU.po vdr-1.7.5-extensions/po/ru_RU.po +--- vdr-1.7.5/po/ru_RU.po 2009-04-12 11:08:06.000000000 +0200 ++++ vdr-1.7.5-extensions/po/ru_RU.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1008,3 +1008,280 @@ msgstr "½ÐÖÜØâÕ ÛîÑãî ÚÝÞßÚã ÔÛï ÞâÜÕÝë + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR ÒëÚÛîçØâáï çÕàÕ× %s ÜØÝãâ" ++ ++msgid "Channel locked by LNB!" ++msgstr "ºÞÝÒÕàâÕà ÑÛÞÚØàãÕâ ÚÐÝÐÛ" ++ ++msgid "Childlock" ++msgstr "´ÕâáÚÐï ÑÛÞÚØàÞÒÚÐ" ++ ++msgid "Path" ++msgstr "¿ãâì" ++ ++msgid "Timer commands" ++msgstr "ºÞÜÜÐÝÔë âÐÙÜÕàÐ" ++ ++msgid "Rename recording" ++msgstr "¿ÕàÕØÜÕÝÞÒÐâì ×Ðߨáì" ++ ++msgid "Date" ++msgstr "´ÐâÐ" ++ ++msgid "Length" ++msgstr "´ÛØÝÐ" ++ ++msgid "Size" ++msgstr "ÀÐ×ÜÕà" ++ ++msgid "Format" ++msgstr "" ++ ++msgid "PES" ++msgstr "" ++ ++msgid "TS" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "ÃÔÐÛØâì ÜÕâÚØ?" ++ ++msgid "Delete resume information?" ++msgstr "²ÞááâÐÝÞÒØâì ÜÕâÚØ?" ++ ++msgid "DVD plugin is not installed!" ++msgstr "¼ÞÔãÛì DVD ÝÕ ãáâÐÝÞÒÛÕÝ!" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÐÛäÐÒØâã, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÒàÕÜÕÝØ, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" ++ ++msgid "all alphabetically" ++msgstr "ÒáÕ ßÞ ÐÛäÐÒØâã" ++ ++msgid "all by date" ++msgstr "ÒáÕ ßÞ ÒàÕÜÕÝØ" ++ ++msgid "Sorting" ++msgstr "ÁÞàâØàÞÒÚÐ" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "WarEagle ØÚÞÝÚØ" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "ÀÐ×ÜÕéÕÝØÕ ÚÞÜÐÝÔ Ò ÓÛÐÒÝÞÜ ÜÕÝî" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "¿ÞÚÐ× ßàÐÒØÛìÝÞÓÞ ÒÒÞÔÐ" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "¿ÞÚÐ× ÑÐÛÚØ ßàÞÓàÕááÐ" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "¿ÕàØÞÔ ÔÛï ßÞØáÚÐ ÔÒÞÙÝëå EPG(min)" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "²ÝÕèÝØÙ ØáâÞçÝØÚ ÔÒÞÙÝÞÓÞ EPG" ++ ++msgid "adjust" ++msgstr "ÝÐáâàÞØâì" ++ ++msgid "delete" ++msgstr "ãÔÐÛØâì" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "ÁÜÕèØÒÐÝØÕ ÒÝãâàÕÝÝÕÓÞ Ø ÒÝÕèÝÕÓÞ EPG" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "·ÐßàÕâ VPS áÞÑëâØï" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "¸áßÞÛì×ÞÒÐâì ÚÞààÕÚâØàÞÒÚã AC3-Transfer" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "¸áßÞÛì×ÞÒÐâì Sync Early " ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "DVB ãáâàÞÙáâÒÞ %d ØáßÞÛì×ãÕâ LNB No." ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "»ÞÓØàÞÒÐÝØÕ ØáßÞÛì×ÞÒÐÝØï LNB" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "·Ðߨáì Dolby Digital" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "¿ÞàïÔÞÚ ÒØÔÕÞ ÔØàÕÚâÞàØØ" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "ºÞÛØçÕáâÒÞ ÒØÔÕÞ ÔØàÕÚâÞàØÙ" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "Video %d ßàØÞàØâÕâ" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "Video %d ÜØÝ. áÒÞÑÞÔÝÞ MB" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "ÇØâÐÑÕÛìÝëÕ ØÜÕÝÐ äÐÙÛÞÒ" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "¼ÐÚá. àÐ×ÜÕà ×ÐßØáØ (GB)" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "¼ÞÝâÐÖ á hard link" ++ ++msgid "Setup.Recording$Show date" ++msgstr "¿ÞÚÐ×ëÒÐâì ÔÐâã" ++ ++msgid "Setup.Recording$Show time" ++msgstr "¿ÞÚÐ×ëÒÐâì ÒàÕÜï ×ÐߨáØ" ++ ++msgid "Setup.Recording$Show length" ++msgstr "¿ÞÚÐ×ëÒÐâì ßàÞÔÞÛÖØâÕÛìÝÞáâì ×ÐߨáØ" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "½Ð×ÒÐÝØÕ ÓÛÐÒÝÞÓÞ ÜÕÝî" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "¿ÞÚÐ× ÞÚÞÝçÐÝØï âÐÙÜÕàÐ" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "ÁÞàâØàÞÒÚÐ ×ÐߨáÕÙ ßÞ" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "ÁÞàâØàÞÒÚÐ ÔØàÕÚâÞàØÙ ÔÞ ×ÐߨáØ" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "°ÒâÞÜÐâØçÕáÚÞÕ ãÔÐÛÕÝØÕ ÜÞÝâÐÖÐ" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "Jump&Play" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "Play&Jump" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "¿Ðã×Ð ÝÐ ßÞáÛÕÔÝÕÙ ÜÕâÚÕ" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "¿ÕàÕÓàãרâì ÜÕâÚØ" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "¿àÞßãáÚ áÕÚãÝÔ" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "¿àÞßãáÚ áÕÚãÝÔ ÜÕÔÛÕÝÝÞ" ++ ++msgid "Setup.Replay$Length" ++msgstr "´ÛØÝÐ" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "´ÛØÝÐ / ½ÞÜÕà" ++ ++msgid "Setup.Replay$Number" ++msgstr "½ÞÜÕà" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "ÀÕÖØÜ ßÞÚÐ×Ð DVD" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "ßÞÚÐ× ÒÕÔãéØå ÝãÛÕÙ" ++ ++msgid "Setup.Replay$never" ++msgstr "ÝØÚÞÓÔÐ" ++ ++msgid "Setup.Replay$on begin" ++msgstr "Ò ÝÐçÐÛÕ" ++ ++msgid "Setup.Replay$on end" ++msgstr "² ÚÞÝæÕ" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "Ò ÝÐçÐÛÕ Ø Ò ÚÞÝæÕ" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "¾âÚàëâì" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "¿àÕÔÕÛ áÚÞàÞáâØ DVD" ++ ++msgid "Jump" ++msgstr "¿àëÖÞÚ" ++ ++msgid "Skip +60s" ++msgstr "¿àÞßãáÚ +60s" ++ ++msgid "Skip -60s" ++msgstr "¿àÞßãáÚ -60s" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "¼ÞÝâÐÖÕà àÐÑÞâÐÕâ - ´ÞÑÐÒØâì Ò ÞçÕàÕÔì?" ++ ++msgid "Rename$Up" ++msgstr "²ÒÕàå" ++ ++msgid "Rename$Down" ++msgstr "²ÝØ×" ++ ++msgid "Rename$Previous" ++msgstr "¿àÕÔëÔãéØÙ" ++ ++msgid "Rename$Next" ++msgstr "ÁÛÕÔãîéØÙ" ++ ++msgid "Please mount %s" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ %s" ++ ++msgid "Please mount DVD %04d" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %04d" ++ ++msgid "Please mount DVD %d" ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %d" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ¿àÞÒÕàÚÐ DVD..." ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "¸ÝÔÕÚá äÐÙÛ ÝÕ ÝÐÙÔÕÝ. ÁÞ×ÔÐÝØÕ âàÕÑãÕâ ÒàÕÜÕÝØ. ÁÞ×ÔÐâì?" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ÁÞ×ÔÐÝØÕ ØÝÔÕÚá äÐÙÛÐ..." ++ ++msgid "Wrong DVD!" ++msgstr "¾èØÑÚÐ DVD!" ++ ++msgid "Permanent Timeshift" ++msgstr "¿ÞáâÞïÝÝëÙ âÐÙÜèØäâ" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "¼ÕáâÞÝÐåÞÖÔÕÝØï" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "ÖÕáâÚØÙ ÔØáÚ" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "ßÐÜïâì" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ Ò ßÐÜïâØ (MB)" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "´ÞÑÐÒÛïâì ÖÕáâÚØÙ ÔØáÚ ÕáÛØ ÝÕÞÑåÞÔØÜÞ" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "ÅàÐÝÕÝØÕ ÑãäÕàÐ ßÐã×ë" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ ÝÐ ÖÕáâÚÞÜ ÔØáÚÕ (MB)" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "ÀÐ×ÜÕà ÑãäÕàÐ (MB)" ++ +diff -ruNp vdr-1.7.5/po/sl_SI.po vdr-1.7.5-extensions/po/sl_SI.po +--- vdr-1.7.5/po/sl_SI.po 2009-04-12 11:08:06.000000000 +0200 ++++ vdr-1.7.5-extensions/po/sl_SI.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1008,3 +1008,270 @@ msgstr "Pritisni katerokoli tipko za pre + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR se bo zaustavil v %s minutah" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/sv_SE.po vdr-1.7.5-extensions/po/sv_SE.po +--- vdr-1.7.5/po/sv_SE.po 2009-04-12 11:08:06.000000000 +0200 ++++ vdr-1.7.5-extensions/po/sv_SE.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1010,3 +1010,270 @@ msgstr "Tryck valfri knapp för att återk + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR kommer att stängas ned om %s minuter" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/po/tr_TR.po vdr-1.7.5-extensions/po/tr_TR.po +--- vdr-1.7.5/po/tr_TR.po 2009-04-12 11:08:06.000000000 +0200 ++++ vdr-1.7.5-extensions/po/tr_TR.po 2009-04-12 13:37:59.000000000 +0200 +@@ -1007,3 +1007,270 @@ msgstr "Yeniden baþlatmayý iptal etmek i + #, c-format + msgid "VDR will shut down in %s minutes" + msgstr "VDR %s dakikada kapanacak" ++ ++msgid "Channel locked by LNB!" ++msgstr "" ++ ++msgid "Childlock" ++msgstr "" ++ ++msgid "Path" ++msgstr "" ++ ++msgid "Timer commands" ++msgstr "" ++ ++msgid "Rename recording" ++msgstr "" ++ ++msgid "Date" ++msgstr "" ++ ++msgid "Length" ++msgstr "" ++ ++msgid "Size" ++msgstr "" ++ ++msgid "Delete marks information?" ++msgstr "" ++ ++msgid "Delete resume information?" ++msgstr "" ++ ++msgid "DVD plugin is not installed!" ++msgstr "" ++ ++msgid "main dir alphabetically, subdirs flexible" ++msgstr "" ++ ++msgid "main dir by date, subdirs flexible" ++msgstr "" ++ ++msgid "all alphabetically" ++msgstr "" ++ ++msgid "all by date" ++msgstr "" ++ ++msgid "Sorting" ++msgstr "" ++ ++msgid "Setup.OSD$WarEagle icons" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu command position" ++msgstr "" ++ ++msgid "Setup.OSD$Show valid input" ++msgstr "" ++ ++msgid "Setup.EPG$Show progress bar" ++msgstr "" ++ ++msgid "Setup.EPG$Period for double EPG search(min)" ++msgstr "" ++ ++msgid "Setup.EPG$Extern double Epg entry" ++msgstr "" ++ ++msgid "adjust" ++msgstr "" ++ ++msgid "delete" ++msgstr "" ++ ++msgid "Setup.EPG$Mix intern and extern EPG" ++msgstr "" ++ ++msgid "Setup.EPG$Disable running VPS event" ++msgstr "" ++ ++msgid "Setup.DVB$Use AC3-Transfer Fix" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker" ++msgstr "" ++ ++msgid "Setup.DVB$Channel Blocker Filter Mode" ++msgstr "" ++ ++msgid "Setup.DVB$Use Sync Early Patch" ++msgstr "" ++ ++msgid "Setup.LNB$DVB device %d uses LNB No." ++msgstr "" ++ ++msgid "Setup.LNB$Log LNB usage" ++msgstr "" ++ ++msgid "Setup.Recording$Record Dolby Digital" ++msgstr "" ++ ++msgid "Setup.Recording$Video directory policy" ++msgstr "" ++ ++msgid "Setup.Recording$Number of video directories" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d priority" ++msgstr "" ++ ++msgid "Setup.Recording$Video %d min. free MB" ++msgstr "" ++ ++msgid "Setup.Recording$Friendly filenames" ++msgstr "" ++ ++msgid "Setup.Recording$Max. recording size (GB)" ++msgstr "" ++ ++msgid "Setup.Recording$Hard Link Cutter" ++msgstr "" ++ ++msgid "Setup.Recording$Show date" ++msgstr "" ++ ++msgid "Setup.Recording$Show time" ++msgstr "" ++ ++msgid "Setup.Recording$Show length" ++msgstr "" ++ ++msgid "Setup.OSD$Main menu title" ++msgstr "" ++ ++msgid "Setup.Recording$Show end of timer" ++msgstr "" ++ ++msgid "Setup.Recording$Sort recordings by" ++msgstr "" ++ ++msgid "Setup.Recording$Sort directories before recordings" ++msgstr "" ++ ++msgid "Setup.Recording$Cutter auto delete" ++msgstr "" ++ ++msgid "Setup.Replay$Jump&Play" ++msgstr "" ++ ++msgid "Setup.Replay$Play&Jump" ++msgstr "" ++ ++msgid "Setup.Replay$Pause at last mark" ++msgstr "" ++ ++msgid "Setup.Replay$Reload marks" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds" ++msgstr "" ++ ++msgid "Setup.Replay$Skip Seconds Slow" ++msgstr "" ++ ++msgid "Setup.Replay$Length" ++msgstr "" ++ ++msgid "Setup.Replay$Length / Number" ++msgstr "" ++ ++msgid "Setup.Replay$Number" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display mode" ++msgstr "" ++ ++msgid "Setup.Replay$DVD display leading zeros" ++msgstr "" ++ ++msgid "Setup.Replay$never" ++msgstr "" ++ ++msgid "Setup.Replay$on begin" ++msgstr "" ++ ++msgid "Setup.Replay$on end" ++msgstr "" ++ ++msgid "Setup.Replay$on begin and end" ++msgstr "" ++ ++msgid "Setup.Replay$Tray open" ++msgstr "" ++ ++msgid "Setup.Replay$Limit DVD to speed" ++msgstr "" ++ ++msgid "Jump" ++msgstr "" ++ ++msgid "Skip +60s" ++msgstr "" ++ ++msgid "Skip -60s" ++msgstr "" ++ ++msgid "Cutter already running - Add to cutting queue?" ++msgstr "" ++ ++msgid "Rename$Up" ++msgstr "" ++ ++msgid "Rename$Down" ++msgstr "" ++ ++msgid "Rename$Previous" ++msgstr "" ++ ++msgid "Rename$Next" ++msgstr "" ++ ++msgid "Please mount %s" ++msgstr "" ++ ++msgid "Please mount DVD %04d" ++msgstr "" ++ ++msgid "Please mount DVD %d" ++msgstr "" ++ ++msgid "Please wait. Checking DVD..." ++msgstr "" ++ ++msgid "No index-file found. Creating may take minutes. Create one?" ++msgstr "" ++ ++msgid "Please wait. Creating index-file..." ++msgstr "" ++ ++msgid "Wrong DVD!" ++msgstr "" ++ ++msgid "Permanent Timeshift" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Location" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$harddisk" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$memory" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size in memory (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Extend to harddisk if necessary" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Keep paused Buffer" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" ++msgstr "" ++ ++msgid "Setup.LiveBuffer$Buffer size (MB)" ++msgstr "" +diff -ruNp vdr-1.7.5/README.cmdsubmenu vdr-1.7.5-extensions/README.cmdsubmenu +--- vdr-1.7.5/README.cmdsubmenu 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/README.cmdsubmenu 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,54 @@ ++CmdSubmenu patch for VDR ++------------------------ ++ ++With this patch the commands and recording commands menus can be organised ++hierarchically. To create a submenu entry, prefix the name by one ore more "-". ++ ++ ++Standard: ++ ++description_1 : cmd_1 ++description_2 : cmd_2 ++ ++ ++A submenu with two entries: ++ ++Submenu title ... : echo "submenu" ++-description_1 : cmd_1 ++-description_2 : cmd_2 ++ ++The dummy command in the title row is necessary. ++ ++ ++* History ++ ++ 2003-10-08: Version 0.1 - Albu at vdrportal.de ++ http://vdrportal.de/board/thread.php?threadid=6319 ++ ++ 2003-10-09: Version 0.2 - Tobias Grimm <tg@e-tobi.net> ++ - Added Define CMD_SUBMENUS in Makefile ++ ++ 2004-05-28: Version 0.3 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed compilation with gcc-3.3.3 ++ - Added new virtual method AddConfig in cConfig ++ - Redefining of method Add in cListBase to virtual no longer necessary ++ - Improved code in menu.c ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.3.diff ++ ++ 2004-12-20: Version 0.4 - Thomas Günther <tom@toms-cafe.de> ++ - Solved conflict with jumpplay patch 0.6 ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.4.diff ++ ++ 2006-04-22: Version 0.5 - Thomas Günther <tom@toms-cafe.de> ++ - Added version define CMDSUBMENUVERSNUM ++ - Reformated to VDR style indentions ++ - Added description in README.cmdsubmenu ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.5-1.3.47.diff ++ ++ 2006-04-23: Version 0.6 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed menus with more than one level ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.6-1.3.47.diff ++ ++ 2006-05-15: Version 0.7 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed build with G++ 4.1 (extra qualification) ++ http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.7-1.4.0.diff +diff -ruNp vdr-1.7.5/README-HLCUTTER vdr-1.7.5-extensions/README-HLCUTTER +--- vdr-1.7.5/README-HLCUTTER 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/README-HLCUTTER 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,117 @@ ++ ++ VDR-HLCUTTER README ++ ++ ++Written by: Udo Richter ++Available at: http://www.udo-richter.de/vdr/patches.html#hlcutter ++ http://www.udo-richter.de/vdr/patches.en.html#hlcutter ++Contact: udo_richter@gmx.de ++ ++ ++ ++About ++----- ++ ++The hard link cutter patch changes the recording editing algorithms of VDR to ++use filesystem hard links to 'copy' recording files whenever possible to speed ++up editing recordings noticeably. ++ ++The patch has matured to be quite stable, at least I'm using it without issues. ++Nevertheless the patch is still in development and should be used with caution. ++The patch is EXPERIMENTAL for multiple /videoxx folders. The safety checks ++should prevent data loss, but you should always carefully check the results. ++ ++While editing a recording, the patch searches for any 00x.vdr files that dont ++contain editing marks and would normally be copied 1:1 unmodified to the edited ++recording. In this case the current target 00x.vdr file will be aborted, and ++the cutter process attempts to duplicate the source file as a hard link, so ++that both files share the same disk space. If this succeeds, the editing ++process fast-forwards through the duplicated file and continues normally ++beginning with the next source file. If hard linking fails, the cutter process ++continues with plain old copying. (but does not take up the aborted last file.) ++ ++After editing, the un-edited recording can be deleted as usual, the hard linked ++copies will continue to exist as the only remaining copy. ++ ++To be effective, the default 'Max. video file size (MB)' should be lowered. ++The patch lowers the smallest possible file size to 1mb. Since VDR only ++supports up to 255 files, this would limit the recording size to 255Mb or ++10 minutes, in other words: This setting is insane! ++ ++To make sure that the 255 file limit will not be reached, the patch also ++introduces "Max. recording size (GB)" with a default of 100Gb (66 hours), and ++increases the file size to 2000Mb early enough, so that 100Gb-recordings will ++fit into the 255 files. ++ ++Picking the right parameters can be tricky. The smaller the file size, the ++faster the editing process works. However, with a small file size, long ++recordings will fall back to 2000Mb files soon, that are slow on editing again. ++ ++Here are some examples: ++ ++Max file size: 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb ++Max recording size: 1Mb 10Mb 20Mb 30Mb 40Mb 50Mb 100Mb ++ ++Small files: 1-203 1-204 1-205 1-206 1-207 1-209 1-214 ++ GBytes: 0.2 2.0 4.0 6.0 8.1 10.2 20.9 ++ Hours: 0.13 1.3 2.65 4 5.4 6.8 13.9 ++ ++Big (2000mb) files: 204-255 204-255 206-255 207-255 208-255 210-255 215-255 ++ GBytes: 101.5 99.6 97.7 95.7 93.8 89.8 80.1 ++ Hours: 67 66 65 63 62 60 53 ++ ++A recording limit of 100Gb keeps plenty of reserve without blocking too much ++file numbers. And with a file size of 30-40Mb, recordings of 4-5 hours fit into ++small files completely. (depends on bit rate of course) ++ ++ ++ ++The patch must be enabled in Setup-> Recordings-> Hard Link Cutter. When ++disabled, the cutter process behaves identical to VDR's default cutter. ++ ++There's a //#define HARDLINK_TEST_ONLY in the videodir.c file that enables a ++test-mode that hard-links 00x.vdr_ files only, and continues the classic ++editing. The resulting 00x.vdr and 00x.vdr_ files should be identical. If you ++delete the un-edited recording, dont forget to delete the *.vdr_ files too, ++they will now eat real disk space. ++ ++Note: 'du' displays the disk space of hard links only on first appearance, and ++usually you will see a noticeably smaller size on the edited recording. ++ ++ ++History ++------- ++Version 0.2.0 ++ ++ New: Support for multiple /videoXX recording folders, using advanced searching ++ for matching file systems where a hard link can be created. ++ Also supports deep mounted file systems. ++ Fix: Do not fail if last mark is a cut-in. (Again.) ++ ++Version 0.1.4 ++ New: Dynamic increase of file size before running out of xxx.vdr files ++ Fix: Last edit mark is not a cut-out ++ Fix: Write error if link-copied file is smaller than allowed file size ++ Fix: Broken index/marks if cut-in is at the start of a new file ++ Fix: Clear dangeling pointer to free'd cUnbufferedFile, ++ thx to Matthias Schwarzott ++ ++Version 0.1.0 ++ Initial release ++ ++ ++ ++ ++Future plans ++------------ ++ ++Since original and edited copy share disk space, free space is wrong if one of ++them is moved to *.del. Free space should only count files with hard link ++count = 1. This still goes wrong if all copies get deleted. ++ ++ ++For more safety, the hard-linked files may be made read-only, as modifications ++to one copy will affect the other copy too. (except deleting, of course) ++ ++ ++SetBrokenLink may get lost on rare cases, this needs some more thoughts.Index: vdr-1.5.9/README.jumpplay +diff -ruNp vdr-1.7.5/README.jumpplay vdr-1.7.5-extensions/README.jumpplay +--- vdr-1.7.5/README.jumpplay 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/README.jumpplay 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,92 @@ ++JumpPlay patch for VDR ++---------------------- ++ ++This patch changes the replay behaviour for recordings that contain editing ++marks. It allows to immediately continue the replay after jumping forward to ++the next mark, and to automatically jump over the commercial break to the next ++"start" mark, if an "end" mark is reached. ++ ++The features of this patch can be turned on or off with parameters in the replay ++setup. See MANUAL for description of this parameters: "Jump&Play", "Play&Jump", ++"Pause at last mark" and "Reload marks". ++ ++ ++* History ++ ++ 2003-07-04: jumpandrun.diff - the Noad <theNoad@SoftHome.net> ++ Jump&Play ++ ++ 2003-12-06: Version 0.0 - Torsten Kunkel <vdr@tkunkel.de> ++ Play&Jump (only if progressbar is visible) ++ Setup parameters Jump&Play and Play&Jump in the replay setup ++ ++ 2004-01-20: Version 0.1 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed speed after jump ++ - fixed removing of marks ++ Play&Jump: ++ - jump only on "end" marks ++ ++ 2004-01-27: Version 0.2 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed double jump ++ Play&Jump: ++ - fixed mark detection: fuzzy detection (until 3 seconds after mark) ++ - jump without progressbar ++ - mode "progressbar only" for old behaviour ++ ++ 2004-01-31: Version 0.3 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - fixed display frames ++ Play&Jump: ++ - fixed end of playing at last mark ++ ++ 2004-07-11: Version 0.4 - Thomas Günther <tom@toms-cafe.de> ++ Jump&Play: ++ - don't play after jump to end ++ Play&Jump: ++ - don't prevent jumping after hide or show ++ Less conflicts with other patches (Elchi/AutoPID) ++ ++ 2004-08-21: Version 0.5 - Thomas Günther <tom@toms-cafe.de> ++ Play&Jump: ++ - exact jumps, replay like edited recording (no fuzzy mark detection) ++ - jump to first mark if replay starts at the beginning ++ - check jump marks with '8' key ++ - mode "progressbar only" removed ++ Description in README.jumpplay ++ ++ 2004-12-28: Version 0.6 - Thomas Günther <tom@toms-cafe.de> ++ Adapted noad extensions (from the Noad <theNoad@SoftHome.net>) to ++ jumpplay-0.5: ++ - cyclic reloading of marks found by noad online-scan ++ - don't stop after the last mark in case of live-recordings ++ New setup parameter "Load marks interval (s)" ++ Updated description in README.jumpplay ++ ++ 2006-04-14: Version 0.7 - Thomas Günther <tom@toms-cafe.de> ++ Fixed jump to first mark (crashed with plugin extrecmenu-0.9) ++ Added version define JUMPPLAYVERSNUM ++ Added placeholders for Czech language texts ++ Cleaned up i18n entries (support only VDR >= 1.3.29) ++ Improved description of i18n placeholders - hoping for real language texts ++ ++ 2006-05-12: Version 0.8 - Thomas Günther <tom@toms-cafe.de> ++ Fixed segfault in dvbplayer thread while the replaycontrol thread is ++ reloading the marks (thanks to horchi at vdrportal.de for reporting this - ++ see http://vdrportal.de/board/thread.php?postid=450463#post450463): ++ New class cMarksReload checks the timestamp of marks.vdr in 10 seconds ++ intervals, so the marks in the threads dvbplayer and replaycontrol can be ++ reloaded independently ++ Changed setup parameter "Load marks interval (s)" to "Reload marks" ++ Updated description in README.jumpplay ++ ++ 2006-05-28: Version 0.9 - Thomas Günther <tom@toms-cafe.de> ++ New setup parameter "Pause at last mark" ++ Updated description in README.jumpplay ++ Moved parameters description to MANUAL ++ ++ 2009-03-31: Version 1.0 - Thomas Günther <tom@toms-cafe.de> ++ Play&Jump: ++ - set resume position to 0 if replay stops at the first mark ++ Added French language texts (thanks to Michaël Nival) +diff -ruNp vdr-1.7.5/README.MainMenuHooks vdr-1.7.5-extensions/README.MainMenuHooks +--- vdr-1.7.5/README.MainMenuHooks 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/README.MainMenuHooks 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,55 @@ ++This is a "patch" for the Video Disk Recorder (VDR). ++ ++* Authors: ++Tobias Grimm <vdr at e-tobi dot net> ++Martin Prochnow <nordlicht at martins-kabuff dot de> ++Frank Schmirler <vdrdev at schmirler dot de> ++Christian Wieninger <cwieninger at gmx dot de> ++ ++* Description: ++This patch allows plugins to replace the VDR mainmenus "Schedule", ++"Channels", "Timers" and "Recordings" by a different implementation. ++ ++The patch is based on a suggestion of Christian Wieninger back in 2006 ++(http://www.linuxtv.org/pipermail/vdr/2006-March/008234.html). It is ++meant to be an interim solution for VDR 1.4 until (maybe) VDR 1.5 ++introduces an official API for this purpose. ++ ++* Installation ++Change into the VDR source directory, then issue ++ patch -p1 < path/to/MainMenuHooks-v1_0.patch ++and recompile. ++ ++* Notes for plugin authors ++The following code sample shows the required plugin code for replacing ++the original Schedule menu: ++ ++bool cMyPlugin::Service(const char *Id, void *Data) ++{ ++ cOsdMenu **menu = (cOsdMenu**) Data; ++ if (MySetup.replaceSchedule && ++ strcmp(Id, "MainMenuHooksPatch-v1.0::osSchedule") == 0) { ++ if (menu) ++ *menu = (cOsdMenu*) MainMenuAction(); ++ return true; ++ } ++ return false; ++} ++ ++A plugin can replace more than one menu at a time. Simply replace the ++call to MainMenuAction() in the sample above by appropriate code. ++ ++Note that a plugin *should* offer a setup option which allows the user ++to enable or disable the replacement. "Disabled" would be a reasonable ++default setting. By testing for define MAINMENUHOOKSVERSNUM, a plugin ++can leave the setup option out at compiletime. ++ ++In case there is an internal problem when trying to open the replacement ++menu, it is safe to return true even though Data is NULL. However an ++OSD message should indicate the problem to the user. ++ ++Feel free to ship this patch along with your plugin. However if you ++think you need to modify the patch, we'd encourage you to contact the ++authors first or at least use a service id which differs in more than ++just the version number. ++ +diff -ruNp vdr-1.7.5/README.sortrec vdr-1.7.5-extensions/README.sortrec +--- vdr-1.7.5/README.sortrec 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/README.sortrec 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,48 @@ ++Sort Recordings patch for VDR ++----------------------------- ++Copyright (C) 2005 Frank99 @vdr-portal.de ++Copyright (C) 2006-2008 Christoph Haubrich ++ ++Released under the same license as VDR itself, for details see vdr.c or ++http://firefly.vdr-developer.org/patches ++ ++This patch changes the sort behaviour of the recordings menu. It is based ++on the patch available here: http://www.vdr-portal.de/board/thread.php?threadid=36031 ++Required for this patch is the liemikuutio-patch for VDR which can be found here: ++http://www.saunalahti.fi/%7Erahrenbe/vdr/patches/ ++ ++There are four sorting modes available after this patch is applied: ++ ++mode behaviour for behaviour for ++ main directory sub directories ++-------------------------------------------------------------------------- ++ 0 alphabetically if special character(*) is found alphabetically, ++ else by date ++ 1 by date if special character(*) is found alphabetically, ++ else by date ++ 2 alphabetically alphabetically ++ 3 by date by date ++ ++(*) if the name of a subdirectory ends with one of ".-$" (dot, hyphen, dollar sign) ++ it is sorted alphabetically in sort mode 0 and 1 ++ ++Sort mode 0 with none of the special characters at the end of any subdir ++corresponds to the default sorting mode of the original VDR. ++ ++The sorting mode can be switched through in the recording menu with the '0' key ++(0->1->2->3->0->...), a default for startup can be set in the setup->recordings menu. ++ ++Additionally the sort order (ascending/descending) can be toggled by the '9' key ++(which is always set to ascending after a restart) ++ ++If you like the to see subdirectories before recordings you can select to put ++directories first in the setup->recordings menu. ++ ++If you would like the sorting to ignore a leading '%' (as normally displayed before ++cutted recordings) you can achive this by setting the environment variable LC_COLLATE ++properly (eg. LC_COLLATE=de_DE@euo in runvdr for germany). ++ ++History: ++2006-08-13 v3, sortrec release for VDR 1.4.1 and liemikuutio 1.8 ++2007-01-28 v3a, moved #ifdef from optimized-rename-patch to sortrec ++2008-03-29 v3b, removed ASCII-170 and ASCII-183 to make sortrec Utf8-ready +diff -ruNp vdr-1.7.5/README.timer-info vdr-1.7.5-extensions/README.timer-info +--- vdr-1.7.5/README.timer-info 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/README.timer-info 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,53 @@ +++------------------------------------------------------------------------------+ ++| Info about the timer-info-patch by Brougs78 | ++| brougs78@gmx.net / home.pages.at/brougs78 | +++------------------------------------------------------------------------------+ ++ ++ ++README timer-info: ++------------------ ++ ++Features: ++ - Shows info, if it is possible to record an event in the timer menu of vdr. ++ For calculations the free space incl. the deleted recordings is used, ++ considering an average consumtion of 25.75 MB/min (also used by vdr itself). ++ The first column in the timer-list shows: ++ ( + ) recording will be most probably possible (enough space) ++ (+/-) recording may be possible ++ ( - ) recording will most probably fail (to less space) ++ The calculations also consider repeating timers. ++ - It is possible to deactivate the patch in the OSD-menu of VDR. ++ ++ ++HISTORY timer-info: ++------------------- ++ ++25.11.2004: v0.1 ++ - Initial release ++ ++11.01.2005: v0.1b ++ - Bugfixes for vdr-1.3.18 ++ - In the menu the free recording-time no longer includes the space of the ++ deleted recordings, because this slowed the vdr down to much. ++ ++08.07.2005: v0.1c ++ - Made the patch configurable ++ ++29.01.2006: v0.2 - Thomas Günther <tom@toms-cafe.de> ++ - Rewritten great parts for vdr-1.3.38+ ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.2-1.3.38+.diff ++ ++05.02.2006: v0.3 - Thomas Günther <tom@toms-cafe.de> ++ - Fixed refresh of timer menu in cMenuTimers::OnOff ++ - Fixed check of repeating timers ++ - Syslog debug messages can be enabled with Define DEBUG_TIMER_INFO ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.3-1.3.38+.diff ++ ++03.03.2006: v0.4 - Thomas Günther <tom@toms-cafe.de> ++ - Adapted to vdr-1.3.44 ++ - Removed setup parameter "Show timer-info" ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.44.diff ++ ++03.03.2006: v0.5 - Tobias Grimm <tg@e-tobi.net> ++ - Adapted to vdr-1.3.45 ++ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.45.diff +diff -ruNp vdr-1.7.5/recorder.c vdr-1.7.5-extensions/recorder.c +--- vdr-1.7.5/recorder.c 2009-03-20 16:49:02.000000000 +0100 ++++ vdr-1.7.5-extensions/recorder.c 2009-04-12 13:37:59.000000000 +0200 +@@ -22,7 +22,11 @@ + // --- cRecorder ------------------------------------------------------------- + + cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids) ++#ifdef USE_DOLBYINREC ++:cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyInRecordings ? DPids : NULL, SPids) ++#else + :cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids) ++#endif /* DOLBYINREC */ + ,cThread("recording") + ,recordingInfo(FileName) + { +@@ -85,7 +89,11 @@ bool cRecorder::RunningLowOnDiskSpace(vo + bool cRecorder::NextFile(void) + { + if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame ++#ifndef USE_HARDLINKCUTTER + if (fileSize > MEGABYTE(off_t(Setup.MaxVideoFileSize)) || RunningLowOnDiskSpace()) { ++#else ++ if (fileSize > fileName->MaxFileSize() || RunningLowOnDiskSpace()) { ++#endif /* HARDLINKCUTTER */ + recordFile = fileName->NextFile(); + fileSize = 0; + } +diff -ruNp vdr-1.7.5/recording.c vdr-1.7.5-extensions/recording.c +--- vdr-1.7.5/recording.c 2009-01-30 17:27:19.000000000 +0100 ++++ vdr-1.7.5-extensions/recording.c 2009-04-12 13:37:59.000000000 +0200 +@@ -8,6 +8,9 @@ + */ + + #include "recording.h" ++#ifdef USE_WAREAGLEICON ++#include "iconpatch.h" ++#endif /* WAREAGLEICON */ + #include <ctype.h> + #include <dirent.h> + #include <errno.h> +@@ -23,6 +26,17 @@ + #include "skins.h" + #include "tools.h" + #include "videodir.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ ++ ++#if defined (USE_DVDCHAPJUMP) && defined (USE_DVDARCHIVE) ++#include <assert.h> ++/* libdvdread stuff */ ++#include <dvdread/dvd_reader.h> ++#include <dvdread/ifo_types.h> ++#include <dvdread/ifo_read.h> ++#endif /* DVDCHAPJUMP & DVDARCHIVE */ + + #define SUMMARYFALLBACK + +@@ -48,6 +62,12 @@ + #endif + #define INFOFILESUFFIX "/info" + #define MARKSFILESUFFIX "/marks" ++#ifdef USE_LIEMIEXT ++#define INDEXFILESUFFIX "/index" ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE /* ??? */ ++#define DVDARCHIVEFILENAME "/dvd.vdr" ++#endif /* DVDARCHIVE */ + + #define MINDISKSPACE 1024 // MB + +@@ -65,6 +85,13 @@ + + bool VfatFileSystem = false; + int InstanceId = 0; ++#ifdef USE_LIEMIEXT ++bool DirOrderState = false; ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf); ++#endif /* DVLFRIENDLYFNAMES */ + + cRecordings DeletedRecordings(true); + +@@ -599,9 +626,24 @@ cRecording::cRecording(cTimer *Timer, co + { + resume = RESUME_NOT_INITIALIZED; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + fileName = NULL; + name = NULL; ++#ifdef USE_DVDARCHIVE ++ dvdname = NULL; ++ dvdtrack = NULL; ++ dvdchapters = NULL; ++ isArchived = false; ++ isOnlyOnDvd = false; ++ dvdtype = DVD_TYPE_UNKNOWN; ++#endif /* DVDARCHIVE */ + fileSizeMB = -1; // unknown + channel = Timer->Channel()->Number(); + instanceId = InstanceId; +@@ -636,6 +678,11 @@ cRecording::cRecording(cTimer *Timer, co + break; + } + if (Timer->IsSingleEvent()) { ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ Timer -> SetFile(MakeFriendlyFilename(&name)); ++ else ++#endif /* DVLFRIENDLYFNAMES */ + Timer->SetFile(name); // this was an instant recording, so let's set the actual data + Timers.SetModified(); + } +@@ -646,6 +693,10 @@ cRecording::cRecording(cTimer *Timer, co + name = strdup(cString::sprintf("%s~%s", Timer->File(), Subtitle)); + // substitute characters that would cause problems in file names: + strreplace(name, '\n', ' '); ++#ifdef USE_DVLFRIENDLYFNAMES ++ if (Setup.UseFriendlyFNames == 1) ++ MakeFriendlyFilename(&name); ++#endif /* DVLFRIENDLYFNAMES */ + start = Timer->StartTime(); + priority = Timer->Priority(); + lifetime = Timer->Lifetime(); +@@ -668,12 +719,27 @@ cRecording::cRecording(const char *FileN + framesPerSecond = DEFAULTFRAMESPERSECOND; + deleted = 0; + titleBuffer = NULL; ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ sortBuffer[i] = NULL; ++ lastDirsFirst[i] = -1; ++ } ++#else + sortBuffer = NULL; ++#endif /* SORTRECORDS */ + fileName = strdup(FileName); + FileName += strlen(VideoDirectory) + 1; + char *p = strrchr(FileName, '/'); + + name = NULL; ++#ifdef USE_DVDARCHIVE ++ dvdname = NULL; ++ dvdtrack = NULL; ++ dvdchapters = NULL; ++ isArchived = false; ++ isOnlyOnDvd = false; ++ dvdtype = DVD_TYPE_NOT_READ; ++#endif /* DVDARCHIVE */ + info = new cRecordingInfo; + if (p) { + time_t now = time(NULL); +@@ -762,15 +828,34 @@ cRecording::cRecording(const char *FileN + LOG_ERROR_STR(*SummaryFileName); + } + #endif ++#ifdef USE_DVDARCHIVE ++ if (CheckFileExistence("dvd.vdr")) { ++ GetDvdName(fileName); ++ isArchived = true; ++ if (!CheckFileExistence("001.vdr")) ++ isOnlyOnDvd = true; ++ } ++#endif /* DVDARCHIVE */ + } + } + + cRecording::~cRecording() + { + free(titleBuffer); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ } ++#else + free(sortBuffer); ++#endif /* SORTRECORDS */ + free(fileName); + free(name); ++#ifdef USE_DVDARCHIVE ++ free(dvdname); ++ free(dvdtrack); ++ free(dvdchapters); ++#endif /* DVDARCHIVE */ + delete info; + } + +@@ -790,21 +875,46 @@ char *cRecording::StripEpisodeName(char + t++; + } + if (s1 && s2) ++#ifdef USE_SORTRECORDS ++ if (Setup.RecordingsSortDirsFirst) ++ *s1 = 'b'; ++ ++ if ((Setup.RecordingsSortMode <= 1 && s1 != s && !strchr(".-$ª·", *(s1 - 1))) || ++ (Setup.RecordingsSortMode == 1 && s1 == s) || ++ (Setup.RecordingsSortMode == 3)) ++#endif /* SORTRECORDS */ + memmove(s1 + 1, s2, t - s2 + 1); + return s; + } + + char *cRecording::SortName(void) const + { ++#ifdef USE_SORTRECORDS ++ if (!sortBuffer[Setup.RecordingsSortMode] || ++ lastDirsFirst[Setup.RecordingsSortMode] != Setup.RecordingsSortDirsFirst) { ++ free(sortBuffer[Setup.RecordingsSortMode]); ++ lastDirsFirst[Setup.RecordingsSortMode] = Setup.RecordingsSortDirsFirst; ++ char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory))); ++#else + if (!sortBuffer) { + char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory) + 1)); ++#endif /* SORTRECORDS */ + strreplace(s, '/', 'a'); // some locales ignore '/' when sorting + int l = strxfrm(NULL, s, 0) + 1; ++#ifdef USE_SORTRECORDS ++ sortBuffer[Setup.RecordingsSortMode] = MALLOC(char, l); ++ strxfrm(sortBuffer[Setup.RecordingsSortMode], s, l); ++#else + sortBuffer = MALLOC(char, l); + strxfrm(sortBuffer, s, l); ++#endif /* SORTRECORDS */ + free(s); + } ++#ifdef USE_SORTRECORDS ++ return sortBuffer[Setup.RecordingsSortMode]; ++#else + return sortBuffer; ++#endif /* SORTRECORDS */ + } + + int cRecording::GetResume(void) const +@@ -819,7 +929,15 @@ int cRecording::GetResume(void) const + int cRecording::Compare(const cListObject &ListObject) const + { + cRecording *r = (cRecording *)&ListObject; ++#ifdef USE_SORTRECORDS ++ return Recordings.GetSortOrder() * strcasecmp(SortName(), r->SortName()); ++#else ++#ifdef USE_LIEMIEXT ++ if (DirOrderState) ++ return strcasecmp(FileName(), r->FileName()); ++#endif /* LIEMIEXT */ + return strcasecmp(SortName(), r->SortName()); ++#endif /* USE_SORTRECORDS */ + } + + const char *cRecording::FileName(void) const +@@ -837,9 +955,359 @@ const char *cRecording::FileName(void) c + return fileName; + } + ++#ifdef USE_DVDARCHIVE ++bool cRecording::CheckFileExistence(const char* FileNameToTest, const bool useVideoDir) const ++{ ++ if (!useVideoDir || (useVideoDir && FileName())) { ++ cString filename = cString::sprintf("%s%s%s", useVideoDir ? FileName() : "", ++ useVideoDir ? "/" : "", ++ FileNameToTest); ++ struct stat statBuf; ++ if (lstat(filename, &statBuf) == -1) return false; ++ return S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode); ++ } ++ return false; ++} ++ ++bool cRecording::GetDvdName(const char* Directory) const ++{ ++ char* filename = (char*)alloca(strlen(Directory) + strlen(DVDARCHIVEFILENAME) + 1); ++ if (filename) { ++ strcpy(filename, Directory); ++ char *end = filename + strlen(filename); ++ strcpy(end, DVDARCHIVEFILENAME); ++ FILE* file; ++ if ((file = fopen(filename, "r"))) { ++ cReadLine ReadLine; ++ char* buffer = (char*)alloca(BUFSIZ); ++ if (buffer) { ++ buffer = ReadLine.Read(file); ++ if (buffer) ++ ((cRecording*)this)->dvdname = strdup(buffer); ++ else ++ ((cRecording*)this)->dvdname = NULL; ++ ++ buffer = ReadLine.Read(file); ++ if (buffer) { ++ ((cRecording*)this)->dvdtrack = strdup(buffer); ++ if (atoi(buffer) == 0) ++ ((cRecording*)this)->dvdtype = DVD_VIDEO_TYPE; ++ else ++ ((cRecording*)this)->dvdtype = DVD_VIDEO_ARCHIVE_TYPE; ++ } ++ else { ++ ((cRecording*)this)->dvdtrack = NULL; ++ ((cRecording*)this)->dvdtype = DVD_ARCHIVE_TYPE; ++ } ++ ++ fclose(file); ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++bool cRecording::GetDvdChaptersFromDvd(int title) const ++{ ++#ifdef USE_DVDCHAPJUMP ++ cString buf; ++ ++ dvd_reader_t *dvd; ++ ifo_handle_t *ifo_file; ++ tt_srpt_t *tt_srpt; ++ ifo_handle_t *vts_file; ++ pgc_t *cur_pgc; ++ ++ dvd = DVDOpen(DVD_DEVICE); ++ if (!dvd) { ++ esyslog("DVD-ARCHIVE: Couldn't open DVD device %s!", DVD_DEVICE); ++ return false; ++ } ++ ++ /* open title manager */ ++ ifo_file = ifoOpen(dvd,0); ++ if (!ifo_file) { ++ esyslog("DVD-ARCHIVE: Can't open VMG info."); ++ DVDClose(dvd); ++ return false; ++ } ++ ++ /* read total_title */ ++ tt_srpt = ifo_file->tt_srpt; ++ ++ /* get total chapters */ ++ int title_set_nr = tt_srpt->title[title-1].title_set_nr; ++ int total_chap = tt_srpt->title[title-1].nr_of_ptts; ++ int local_title_id = tt_srpt->title[title-1].vts_ttn - 1; ++ ++ /* access title set file */ ++ vts_file = ifoOpen(dvd, title_set_nr); ++ if (!vts_file) { ++ esyslog("DVD-ARCHIVE: Can't open info file for title set %d!",title_set_nr); ++ DVDClose(dvd); ++ return false; ++ } ++ ++ /* find program chain and check programs ++ all chapters should be in the same prog chain and ++ should be numbered from 1 to <total_chap> ++ */ ++ { ++ vts_ptt_srpt_t *vts_ptt_srpt = vts_file->vts_ptt_srpt; ++ int pgc_nr = vts_ptt_srpt->title[local_title_id].ptt[0].pgcn; ++ int pg = vts_ptt_srpt->title[local_title_id].ptt[0].pgn; ++ int p; ++ ++ assert(pg==1); ++ for (p=1; p<total_chap; p++) { ++ int next_pg; ++ int this_pgc; ++ this_pgc = vts_ptt_srpt->title[local_title_id].ptt[p].pgcn; ++ assert(pgc_nr == this_pgc); ++ next_pg = vts_ptt_srpt->title[local_title_id].ptt[p].pgn; ++ assert(pg+1 == next_pg); ++ pg = next_pg; ++ } ++ ++ /* fetch program chain */ ++ cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_nr-1].pgc; ++ assert(cur_pgc->nr_of_programs == total_chap); ++ } ++ ++ /* --- main cell loop --- */ ++ { ++ pgc_program_map_t *chap_cell; ++ cell_playback_t *cell_pb; ++ int c; ++ int chap; ++ ++ /* total cells in chain */ ++ int total_cell = cur_pgc->nr_of_cells; ++ ++ /* get info */ ++ chap_cell = cur_pgc->program_map; ++ cell_pb = cur_pgc->cell_playback; ++ ++ /* loop through all cells */ ++ chap = -1; ++ int position = 0; ++ for (c=0; c<total_cell; c++) { ++ int cell_mode; ++ const char *mode; ++ ++ dvd_time_t *time = (dvd_time_t *)&cell_pb->playback_time; ++ ++ int framerate = time->frame_u>>6; ++ assert(framerate == 1 || framerate == 3); ++ int frames_per_sec = (framerate == 1) ? 25 : 30; ++ ++ /* upper 4 bits are first digit, down 4 bits are second digit */ ++ int hour = (time->hour>>4) * 10 + (time->hour&15); ++ int minute = (time->minute>>4) * 10 + (time->minute&15); ++ int second = (time->second>>4) * 10 + (time->second&15); ++ /* upper 4 bits are first digit, down 4 bits are second digit */ ++ int frame = (time->frame_u>>4&3) * 10 + (time->frame_u&15); ++ ++ int frames = ((hour * 3600) + (minute * 60) + second) * frames_per_sec + frame; ++ ++ /* this cell is the begin of a new chapter! */ ++ if (chap_cell[chap+1] == c+1) { ++ cString oldbuf = cString::sprintf("%s", *buf); ++ buf = cString::sprintf("%s%d%s", *oldbuf, position, ((chap+2) < total_chap) ? "," : ""); ++ chap++; ++ } ++ ++ /* cell_mode: 0=normal, 1=first of angle, 2=in angle, 3=last of angle */ ++ cell_mode = cell_pb->block_mode; ++ if ((cell_mode==0) || (cell_mode==1)) { ++ /* only account for normal or begin of angle cells */ ++ position += frames; ++ mode = "counted"; ++ } ++ else ++ mode = "skipped"; ++ ++ cell_pb++; ++ } ++ } ++ ++ ifoClose(ifo_file); ++ ifoClose(vts_file); ++ DVDClose(dvd); ++ ++ ((cRecording*)this)->dvdchapters = strdup(buf); ++ ++ return true; ++#else ++ return false; ++#endif /* DVDCHAPJUMP */ ++} ++ ++const char *cRecording::GetDvdChapters(void) const ++{ ++ // Read chapters from dvd ++ if (dvdtype == DVD_VIDEO_ARCHIVE_TYPE) { ++ if (dvdtrack) { ++ if (!GetDvdChaptersFromDvd(atoi(dvdtrack))) ++ ((cRecording*)this)->dvdchapters = NULL; ++ else ++ isyslog("DVD-ARCHIVE: Using following positions for chapter jumping: %s", dvdchapters); ++ return dvdchapters; ++ } ++ } ++ return NULL; ++} ++ ++int cRecording::MountDvd(void) const ++{ ++ cString cmd; ++ if (Setup.DvdSpeedLimit > 0) { ++ cmd = cString::sprintf("speedcontrol -x %d %s", Setup.DvdSpeedLimit, DVD_DEVICE); ++ SystemExec(cmd); ++ } ++ ++ cString msg; ++ if (atoi(dvdname) == 0) ++ msg = cString::sprintf(tr("Please mount %s"), dvdname); ++ else { ++ if (Setup.DvdDisplayZeros) ++ msg = cString::sprintf(tr("Please mount DVD %04d"), atoi(dvdname)); ++ else ++ msg = cString::sprintf(tr("Please mount DVD %d"), atoi(dvdname)); ++ } ++ ++ bool rep = true; ++ while (rep) { ++ if (Setup.DvdTrayMode==1 || Setup.DvdTrayMode==3) ++ cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); ++ else ++ cmd = cString::sprintf("umount %s", DVD_DEVICE); ++ SystemExec(cmd); ++ ++ if (Interface->Confirm(msg, 300)) { ++ Skins.Message(mtStatus, tr("Please wait. Checking DVD...")); ++ Skins.Flush(); ++ cmd = cString::sprintf("eject -t %s; mkdir -p %s; mount -o ro -t %s %s %s", ++ DVD_DEVICE, DVD_MOUNT_PATH, ++ (dvdtrack ? "udf" : "iso9660"), ++ DVD_DEVICE, DVD_MOUNT_PATH); ++ SystemExec(cmd); ++ ++ bool correctDvd = true; ++ ++ char *olddvdname, *olddvdtrack; ++ int olddvdtype; ++ olddvdname = dvdname; ++ olddvdtrack = dvdtrack; ++ olddvdtype = dvdtype; ++ if (GetDvdName(DVD_MOUNT_PATH)) { ++ if (atoi(dvdname) != atoi(olddvdname)) correctDvd = false; ++ } ++ ((cRecording*)this)->dvdname = olddvdname; ++ ((cRecording*)this)->dvdtrack = olddvdtrack; ++ ((cRecording*)this)->dvdtype = olddvdtype; ++ ++ if (correctDvd) { ++ if (dvdtrack == NULL) { ++ // Archived DVD in VDR format ++ char fn[BUFSIZ]; ++ strcpy(fn, FileName()); ++ char *p = strrchr(fn, '/'); ++ cmd = cString::sprintf("find '%s' -name '%s'", DVD_MOUNT_PATH, p+1); ++ } ++ else { ++ // Either archived DVD in DVD-Video format or DVD-Video which ++ // should be played with the DVD plugin ++ cmd = cString::sprintf("find '%s' -iname 'VIDEO_TS'", DVD_MOUNT_PATH); ++ } ++ ++ cReadLine pipe; ++ FILE* file; ++ char *dirname = NULL; ++ if ((file = popen(cmd, "r")) != (FILE *)NULL) { ++ if ((dirname = pipe.Read(file)) != NULL) { ++ pclose(file); ++ if (dvdtrack != NULL && atoi(dvdtrack) == 0) { ++ // It is a valid Video-DVD and DVD plugin can be started ++ return MOUNT_DVD_LAUNCH_DVD_PLUGIN; ++ } ++ else { ++ // It is a valid Archive-DVD or an archived Video-DVD ++ // and the links can now be established ++ cString srcFn; ++ int n = 1; ++ ++ do { ++ if (dvdtrack == NULL) ++ srcFn = cString::sprintf("%s/%03d.vdr", dirname, n); ++ else ++ srcFn = cString::sprintf("%s/VTS_%02d_%d.VOB", dirname, atoi(dvdtrack), n); ++ ++ if (!access(srcFn, R_OK)) { ++ cmd = cString::sprintf("ln -sf '%s' '%s/%03d.vdr'", *srcFn, FileName(), n); ++ SystemExec(cmd); ++ isyslog("DVD-ARCHIVE: Linking %s/%03d.vdr -> %s", FileName(), n, *srcFn); ++ } ++ else ++ break; ++ } while ( ++n < 999); ++ ++ if (!CheckFileExistence("index.vdr")) { ++ if (dvdtrack == NULL) ++ srcFn = cString::sprintf("%s/index.vdr", dirname); ++ else ++ srcFn = cString::sprintf("%s/index_%02d.vdr", dirname, atoi(dvdtrack)); ++ ++ if (!CheckFileExistence(srcFn, false)) { ++ msg = cString::sprintf(tr("No index-file found. Creating may take minutes. Create one?")); ++ if (Interface->Confirm(msg, 300)) { ++ Skins.Message(mtStatus, tr("Please wait. Creating index-file...")); ++ cmd = cString::sprintf("speedcontrol -x 999 %s; cd %s && genindex &", DVD_DEVICE, FileName()); ++ SystemExec(cmd); ++ return MOUNT_DVD_ABORT; ++ } ++ } ++ else { ++ cmd = cString::sprintf("ln -sf '%s' '%s/index.vdr'", *srcFn, FileName()); ++ SystemExec(cmd); ++ isyslog("DVD-ARCHIVE: Linking %s/index.vdr -> %s", FileName(), *srcFn); ++ } ++ } ++ return MOUNT_DVD_REPLAY; ++ } ++ } ++ else { ++ Skins.Message(mtError, tr("Wrong DVD!"), 3); ++ Skins.Flush(); ++ } ++ } ++ pclose(file); ++ } ++ else { ++ Skins.Message(mtError, tr("Wrong DVD!"), 3); ++ Skins.Flush(); ++ } ++ } ++ else { ++ rep = false; ++ } ++ } ++ return MOUNT_DVD_ABORT; ++} ++ ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level, bool Original) const ++#else + const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) const ++#endif /* LIEMIEXT */ + { ++#ifdef USE_WAREAGLEICON ++ const char *New = NewIndicator && IsNew() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_NEW_UTF8 : ICON_NEW : "*" : " "; ++#else + char New = NewIndicator && IsNew() ? '*' : ' '; ++#endif /* WAREAGLEICON */ + free(titleBuffer); + titleBuffer = NULL; + if (Level < 0 || Level == HierarchyLevels()) { +@@ -850,7 +1318,14 @@ const char *cRecording::Title(char Delim + s++; + else + s = name; ++#ifdef USE_LIEMIEXT ++ if (Original) { ++#endif /* LIEMIEXT */ ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%s%c%s", ++#else + titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%c%c%s", ++#endif /* WAREAGLEICON */ + t->tm_mday, + t->tm_mon + 1, + t->tm_year % 100, +@@ -860,6 +1335,92 @@ const char *cRecording::Title(char Delim + New, + Delimiter, + s)); ++#ifdef USE_LIEMIEXT ++ } ++ else { ++ cString RecLength("---"); ++ if (Setup.ShowRecLength && FileName()) { ++ cString filename = cString::sprintf("%s%s", FileName(), INDEXFILESUFFIX); ++ if (*filename) { ++ if (access(filename, R_OK) == 0) { ++ struct stat buf; ++ if (stat(filename, &buf) == 0) { ++ struct tIndex { int offset; uchar type; uchar number; short reserved; }; ++ int delta = buf.st_size % sizeof(tIndex); ++ if (delta) { ++ delta = sizeof(tIndex) - delta; ++ esyslog("ERROR: invalid file size (%ld) in '%s'", (long int)buf.st_size, *filename); ++ } ++ RecLength = cString::sprintf("%ld'", (long int)(buf.st_size + delta) / sizeof(tIndex) / SecondsToFrames(60)); ++ } ++ } ++ } ++ } ++#endif /* LIEMIEXT */ ++#ifdef USE_DVDARCHIVE ++#ifdef USE_WAREAGLEICON ++ if (isArchived && !isOnlyOnDvd) New = Setup.WarEagleIcons ? IsLangUtf8() ? ICON_DVD_UTF8 : ICON_DVD : "~"; ++#else ++ if (isArchived && !isOnlyOnDvd) New = '~'; ++#endif /* WAREAGLEICON */ ++ ++ if (isOnlyOnDvd && Setup.DvdDisplayMode >= 1) { ++ char oldLength[21]; ++ ++ if (strrchr(RecLength, '\'')) ++ sprintf(oldLength,"%s", *RecLength); ++ else ++ oldLength[0] = 0; ++ ++ if (dvdname) { ++ if (atoi(dvdname) != 0) { ++ cString tmp; ++ if (Setup.DvdDisplayZeros) ++ tmp = cString::sprintf("%04d", atoi(dvdname)); ++ else { ++ int num = atoi(dvdname); ++ bool displaySpace = !(Setup.DvdDisplayMode == 1 && oldLength[0] != 0); ++ // ugly hack to have 2 spaces instead of one 0 for each place ++ tmp = cString::sprintf("%s%s%s%d", displaySpace && (num < 1000) ? " " : "", ++ displaySpace && (num < 100) ? " " : "", ++ displaySpace && (num < 10) ? " " : "", ++ num); ++ } ++ ((cRecording*)this)->dvdname = strdup(tmp); ++ } ++ } ++ ++ RecLength = strdup(cString::sprintf("%s%s%s%s", (Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? oldLength : "", ++ (dvdname && isArchived && isOnlyOnDvd && Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? " / " : "", ++ (dvdname && isArchived && isOnlyOnDvd) ? dvdname : "", ++ (dvdname && isArchived && isOnlyOnDvd) ? " " : "" ++ )); ++ } ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++ cString RecDate = cString::sprintf("%02d.%02d.%02d", t->tm_mday, t->tm_mon + 1, t->tm_year % 100); ++ cString RecTime = cString::sprintf("%02d:%02d", t->tm_hour, t->tm_min); ++ cString RecDelimiter = cString::sprintf("%c", Delimiter); ++#ifdef USE_WAREAGLEICON ++ titleBuffer = strdup(cString::sprintf("%s%s%s%s%s%s%s%s", ++#else ++ titleBuffer = strdup(cString::sprintf("%s%s%s%c%s%s%s%s", ++#endif /* WAREAGLEICON */ ++ (Setup.ShowRecDate ? *RecDate : ""), ++ (Setup.ShowRecDate && Setup.ShowRecTime ? *RecDelimiter : ""), ++ (Setup.ShowRecTime ? *RecTime : ""), ++ New, ++ (Setup.ShowRecTime || Setup.ShowRecDate ? *RecDelimiter : ""), ++#ifdef USE_DVDARCHIVE ++ (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecLength : ""), ++ (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecDelimiter : ""), ++#else ++ (Setup.ShowRecLength ? *RecLength : ""), ++ (Setup.ShowRecLength ? *RecDelimiter : ""), ++#endif /* DVDARCHIVE */ ++ s)); ++ } ++#endif /* LIEMIEXT */ + // let's not display a trailing '~': + if (!NewIndicator) + stripspace(titleBuffer); +@@ -888,6 +1449,17 @@ const char *cRecording::Title(char Delim + return titleBuffer; + } + ++#ifdef USE_CUTTIME ++void cRecording::SetStartTime(time_t Start) ++{ ++ start = Start; ++ if (fileName) { ++ free(fileName); ++ fileName = NULL; ++ } ++} ++#endif /* CUTTIME */ ++ + const char *cRecording::PrefixFileName(char Prefix) + { + cString p = PrefixVideoFileName(FileName(), Prefix); +@@ -941,10 +1513,20 @@ bool cRecording::Delete(void) + // the new name already exists, so let's remove that one first: + isyslog("removing recording '%s'", NewName); + RemoveVideoFile(NewName); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(this, scDel); ++#endif /* STREAMDEVEXT */ + } + isyslog("deleting recording '%s'", FileName()); ++#ifdef USE_STREAMDEVEXT ++ if (access(FileName(), F_OK) == 0) { ++ result = RenameVideoFile(FileName(), NewName); ++ cStatus::MsgRecordingChange(this, scDel); ++ } ++#else + if (access(FileName(), F_OK) == 0) + result = RenameVideoFile(FileName(), NewName); ++#endif /* STREAMDEVEXT */ + else { + isyslog("recording '%s' vanished", FileName()); + result = true; // well, we were going to delete it, anyway +@@ -962,7 +1544,13 @@ bool cRecording::Remove(void) + return false; + } + isyslog("removing recording %s", FileName()); ++#ifdef USE_STREAMDEVEXT ++ bool ret = RemoveVideoFile(FileName()); ++ cStatus::MsgRecordingChange(this, scDel); ++ return ret; ++#else + return RemoveVideoFile(FileName()); ++#endif /* STREAMDEVEXT */ + } + + bool cRecording::Undelete(void) +@@ -979,8 +1567,15 @@ bool cRecording::Undelete(void) + } + else { + isyslog("undeleting recording '%s'", FileName()); ++#ifdef USE_STREAMDEVEXT ++ if (access(FileName(), F_OK) == 0) { ++ result = RenameVideoFile(FileName(), NewName); ++ cStatus::MsgRecordingChange(this, scAdd); ++ } ++#else + if (access(FileName(), F_OK) == 0) + result = RenameVideoFile(FileName(), NewName); ++#endif /* STREAMDEVEXT */ + else { + isyslog("deleted recording '%s' vanished", FileName()); + result = false; +@@ -996,6 +1591,54 @@ void cRecording::ResetResume(void) const + resume = RESUME_NOT_INITIALIZED; + } + ++#ifdef USE_LIEMIEXT ++bool cRecording::Rename(const char *newName) ++{ ++ bool result = false; ++ struct tm tm_r; ++ struct tm *t = localtime_r(&start, &tm_r); ++ char *localNewName = ExchangeChars(strdup(newName), true); ++ const char *fmt = isPesRecording ? NAMEFORMATPES : NAMEFORMATTS; ++ int ch = isPesRecording ? priority : channel; ++ int ri = isPesRecording ? lifetime : instanceId; ++ char *newFileName = strdup(cString::sprintf(fmt, VideoDirectory, localNewName, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, ch, ri)); ++ free(localNewName); ++ if (strcmp(FileName(), newFileName)) { ++ if (access(newFileName, F_OK) == 0) { ++ isyslog("recording %s already exists", newFileName); ++ } ++ else { ++ isyslog("renaming recording %s to %s", FileName(), newFileName); ++ result = MakeDirs(newFileName, true); ++ if (result) ++ result = RenameVideoFile(FileName(), newFileName); ++ if (result) { ++ free(fileName); ++ fileName = strdup(newFileName); ++ free(name); ++ name = strdup(newName); ++#ifdef USE_SORTRECORDS ++ for (int i = 0; i < MAXSORTMODES; i++) { ++ free(sortBuffer[i]); ++ sortBuffer[i] = NULL; ++ } ++#else ++ free(sortBuffer); ++ sortBuffer = NULL; ++#endif /* SORTRECORDS */ ++ free(titleBuffer); ++ titleBuffer = NULL; ++ } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(this, scMod); ++#endif /* STREAMDEVEXT */ ++ } ++ } ++ free(newFileName); ++ return result; ++} ++#endif /* LIEMIEXT */ ++ + // --- cRecordings ----------------------------------------------------------- + + cRecordings Recordings; +@@ -1008,6 +1651,9 @@ cRecordings::cRecordings(bool Deleted) + deleted = Deleted; + lastUpdate = 0; + state = 0; ++#ifdef USE_SORTRECORDS ++ SortOrder = 1; ++#endif /* SORTRECORDS */ + } + + cRecordings::~cRecordings() +@@ -1294,14 +1940,70 @@ cMark *cMarks::GetNext(int Position) + return NULL; + } + ++#ifdef USE_JUMPPLAY ++// --- cMarksReload ---------------------------------------------------------- ++ ++#define MARKS_RELOAD_MS 10000 ++ ++time_t cMarksReload::lastsavetime = 0; ++ ++cMarksReload::cMarksReload(const char *RecordingFileName) ++:recDir(RecordingFileName) ++{ ++ struct stat sbuf; ++ if (Load(recDir) && stat(FileName(), &sbuf) == 0) ++ lastmodtime = sbuf.st_mtime; ++ else ++ lastmodtime = 0; ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++} ++ ++bool cMarksReload::Reload(void) ++{ ++ // Check the timestamp of marks.vdr in 10 seconds intervals ++ // Independent but synchronized reloading of marks in two threads ++ if ((Setup.ReloadMarks && nextreload.TimedOut()) || lastsavetime > lastmodtime) { ++ nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); ++ struct stat sbuf; ++ if (stat(FileName(), &sbuf) == 0 && sbuf.st_mtime != lastmodtime) { ++ lastmodtime = sbuf.st_mtime; ++ if (Load(recDir)) ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool cMarksReload::Save(void) ++{ ++ bool ok = cMarks::Save(); ++ struct stat sbuf; ++ if (ok && stat(FileName(), &sbuf) == 0) ++ lastsavetime = lastmodtime = sbuf.st_mtime; ++ return ok; ++} ++#endif /* JUMPPLAY */ ++ + // --- cRecordingUserCommand ------------------------------------------------- + + const char *cRecordingUserCommand::command = NULL; + ++#ifdef USE_DVLRECSCRIPTADDON ++void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName, char *chanName) ++#else + void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName) ++#endif /* DVLRECSCRIPTADDON */ + { + if (command) { ++#ifdef USE_DVLRECSCRIPTADDON ++ cString cmd; ++ if (chanName != NULL) ++ cmd = cString::sprintf("%s %s \"%s\" \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"), chanName); ++ else ++ cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#else + cString cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); ++#endif /* DVLRECSCRIPTADDON */ + isyslog("executing '%s'", *cmd); + SystemExec(cmd); + } +@@ -1309,7 +2011,9 @@ void cRecordingUserCommand::InvokeComman + + // --- cIndexFile ------------------------------------------------------------ + ++#ifndef USE_LIEMIEXT + #define INDEXFILESUFFIX "/index" ++#endif /* LIEMIEXT */ + + // The number of frames to stay off the end in case of time shift: + #define INDEXSAFETYLIMIT 150 // frames +@@ -1625,6 +2329,48 @@ cFileName::cFileName(const char *FileNam + cFileName::~cFileName() + { + Close(); ++#ifdef USE_DVDARCHIVE ++ ++ char fn[BUFSIZ]; ++ strcpy(fn, fileName); ++ ++ char *p; ++ if((p = strrchr(fn, '/'))) { ++ p[0] = 0; ++ } ++ ++ cString cmd = cString::sprintf("find \"%s\" -type l -lname \"%s/*\"", fn, DVD_MOUNT_PATH); ++ ++ bool isOnDvd = false; ++ ++ cReadLine pipe; ++ FILE* file; ++ char* filename; ++ if ((file = popen(cmd, "r")) != (FILE *)NULL) { ++ while ((filename = pipe.Read(file)) != NULL) { ++ isOnDvd = true; ++ unlink(filename); ++ isyslog("DVD-ARCHIVE: Deleting %s", filename); ++ } ++ pclose(file); ++ } ++ ++ if (isOnDvd) { ++ if (Setup.DvdTrayMode==2 || Setup.DvdTrayMode==3) ++ cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); ++ else ++ cmd = cString::sprintf("umount %s", DVD_DEVICE); ++ ++ SystemExec(cmd); ++ ++ if (Setup.DvdSpeedLimit > 0) { ++ cmd = cString::sprintf("speedcontrol -x 999 %s", DVD_DEVICE); ++ SystemExec(cmd); ++ } ++ } ++ ++#endif /* DVDARCHIVE */ ++ + free(fileName); + } + +@@ -1703,6 +2449,22 @@ cUnbufferedFile *cFileName::SetOffset(in + return NULL; + } + ++#ifdef USE_HARDLINKCUTTER ++off_t cFileName::MaxFileSize() { ++ const int maxVideoFileSize = isPesRecording ? MAXVIDEOFILESIZEPES : MAXVIDEOFILESIZETS; ++ const int setupMaxVideoFileSize = min(maxVideoFileSize, Setup.MaxVideoFileSize); ++ const int maxFileNumber = isPesRecording ? 255 : 65535; ++ ++ const off_t smallFiles = (maxFileNumber * off_t(maxVideoFileSize) - 1024 * Setup.MaxRecordingSize) ++ / max(maxVideoFileSize - setupMaxVideoFileSize, 1); ++ ++ if (fileNumber <= smallFiles) ++ return MEGABYTE(off_t(setupMaxVideoFileSize)); ++ ++ return MEGABYTE(off_t(maxVideoFileSize)); ++} ++#endif /* HARDLINKCUTTER */ ++ + cUnbufferedFile *cFileName::NextFile(void) + { + return SetOffset(fileNumber + 1); +@@ -1754,3 +2516,113 @@ int ReadFrame(cUnbufferedFile *f, uchar + LOG_ERROR; + return r; + } ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++char *MakeFriendlyFilename(char **buf) ++{ ++ char *b, *x, *y; ++ ++ if (buf == NULL || *buf == NULL) ++ return(NULL); ++ ++ b = (char *)malloc(strlen(*buf) * 2); ++ x = *buf; ++ y = b; ++ ++ while (*x != 0) { ++ switch (*x) { ++ case 'Ä': ++ *y = 'A'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ä': ++ *y = 'a'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ö': ++ *y = 'O'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ö': ++ *y = 'o'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'Ü': ++ *y = 'U'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ü': ++ *y = 'u'; ++ y++; ++ *y = 'e'; ++ y++; x++; ++ break; ++ ++ case 'ß': ++ *y = 's'; ++ y++; ++ *y = 's'; ++ y++; x++; ++ break; ++ ++ // chars to replace ++ case ':': ++ case ';': ++ case '?': ++ case ' ': ++ case '\t': ++ *y = '_'; ++ y++; x++; ++ break; ++ ++ // chars to simply strip ++ case '\"': ++ case '*': ++ case '{': ++ case '}': ++ case '[': ++ case ']': ++ case '=': ++ case '<': ++ case '>': ++ case '#': ++ case '`': ++ case '|': ++ case '\\': ++ case '\n': ++ case '\r': ++ x++; ++ break; ++ ++ default: ++ *y = *x; ++ y++; x++; ++ break; ++ } ++ } ++ *y = 0; ++ ++ x = strdup(b); ++ free(b); ++ ++ free(*buf); ++ *buf = x; ++ ++ return(*buf); ++} ++#endif /* DVLFRIENDLYFNAMES */ +diff -ruNp vdr-1.7.5/recording.h vdr-1.7.5-extensions/recording.h +--- vdr-1.7.5/recording.h 2009-02-28 11:50:12.000000000 +0100 ++++ vdr-1.7.5-extensions/recording.h 2009-04-12 13:37:59.000000000 +0200 +@@ -20,6 +20,9 @@ + + extern bool VfatFileSystem; + extern int InstanceId; ++#ifdef USE_LIEMIEXT ++extern bool DirOrderState; ++#endif /* LIEMIEXT */ + + void RemoveDeletedRecordings(void); + void AssertFreeDiskSpace(int Priority = 0, bool Force = false); +@@ -63,6 +66,9 @@ public: + const cEvent *GetEvent(void) const { return event; } + const char *Title(void) const { return event->Title(); } + const char *ShortText(void) const { return event->ShortText(); } ++#ifdef USE_GRAPHTFT ++ tEventID EventID(void) const { return event->EventID(); } ++#endif /* GRAPHTFT */ + const char *Description(void) const { return event->Description(); } + const cComponents *Components(void) const { return event->Components(); } + const char *Aux(void) const { return aux; } +@@ -74,12 +80,36 @@ public: + bool Write(void) const; + }; + ++#ifdef USE_SORTRECORDS ++#define SORTRECORDINGSVERSNUM 3 ++#define MAXSORTMODES 4 ++#endif /* SORTRECORDS */ ++ ++#ifdef USE_DVDARCHIVE ++#define MOUNT_DVD_ABORT 0 ++#define MOUNT_DVD_REPLAY 1 ++#define MOUNT_DVD_LAUNCH_DVD_PLUGIN 2 ++#define DVD_DEVICE "/dev/cdrom" ++#define DVD_MOUNT_PATH "/tmp/vdr.dvd" ++ ++#define DVD_TYPE_UNKNOWN -1 ++#define DVD_TYPE_NOT_READ 0 ++#define DVD_VIDEO_TYPE 1 ++#define DVD_ARCHIVE_TYPE 2 ++#define DVD_VIDEO_ARCHIVE_TYPE 3 ++#endif /* DVDARCHIVE */ ++ + class cRecording : public cListObject { + friend class cRecordings; + private: + mutable int resume; + mutable char *titleBuffer; ++#ifdef USE_SORTRECORDS ++ mutable char *sortBuffer[MAXSORTMODES]; ++ mutable char lastDirsFirst[MAXSORTMODES]; ++#else + mutable char *sortBuffer; ++#endif /* SORTRECORDS */ + mutable char *fileName; + mutable char *name; + mutable int fileSizeMB; +@@ -88,6 +118,15 @@ private: + bool isPesRecording; + double framesPerSecond; + cRecordingInfo *info; ++#ifdef USE_DVDARCHIVE ++ char *dvdname; ++ char *dvdtrack; ++ char *dvdchapters; ++ bool isArchived; ++ bool isOnlyOnDvd; ++ int dvdtype; ++ bool GetDvdChaptersFromDvd(int title) const; ++#endif /* DVDARCHIVE */ + cRecording(const cRecording&); // can't copy cRecording + cRecording &operator=(const cRecording &); // can't assign cRecording + static char *StripEpisodeName(char *s); +@@ -104,8 +143,23 @@ public: + virtual int Compare(const cListObject &ListObject) const; + const char *Name(void) const { return name; } + const char *FileName(void) const; ++#ifdef USE_DVDARCHIVE ++ bool CheckFileExistence(const char* FileNameToTest, const bool useVideoDir = true) const; ++ bool GetDvdName(const char* Directory) const; ++ bool IsOnlyOnDvd(void) const { return isOnlyOnDvd; } ++ int MountDvd(void) const; ++ int GetDvdType(void) const { return dvdtype; } ++ const char *GetDvdChapters(void) const ; ++#endif /* DVDARCHIVE */ ++#ifdef USE_LIEMIEXT ++ const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1, bool Original = true) const; ++#else + const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const; ++#endif /* LIEMIEXT */ + const cRecordingInfo *Info(void) const { return info; } ++#ifdef USE_CUTTIME ++ void SetStartTime(time_t Start); ++#endif /* CUTTIME */ + const char *PrefixFileName(char Prefix); + int HierarchyLevels(void) const; + void ResetResume(void) const; +@@ -124,6 +178,11 @@ public: + // 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 ++#ifdef USE_LIEMIEXT ++ bool Rename(const char *newName); ++ // Changes the file name ++ // Returns false in case of error ++#endif /* LIEMIEXT */ + }; + + class cRecordings : public cList<cRecording>, public cThread { +@@ -132,6 +191,9 @@ private: + bool deleted; + time_t lastUpdate; + int state; ++#ifdef USE_SORTRECORDS ++ int SortOrder; ++#endif /* SORTRECORDS */ + const char *UpdateFileName(void); + void Refresh(bool Foreground = false); + void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0); +@@ -162,6 +224,10 @@ public: + void AddByName(const char *FileName, bool TriggerUpdate = true); + void DelByName(const char *FileName); + int TotalFileSizeMB(void); ///< Only for deleted recordings! ++#ifdef USE_SORTRECORDS ++ void ToggleSortOrder(void) { SortOrder *= -1; } ++ const int GetSortOrder(void) { return SortOrder; } ++#endif /* SORTRECORDS */ + }; + + extern cRecordings Recordings; +@@ -194,6 +260,20 @@ public: + cMark *GetNext(int Position); + }; + ++#ifdef USE_JUMPPLAY ++class cMarksReload : public cMarks { ++private: ++ cString recDir; ++ cTimeMs nextreload; ++ time_t lastmodtime; ++ static time_t lastsavetime; ++public: ++ cMarksReload(const char *RecordingFileName); ++ bool Reload(void); ++ bool Save(void); ++ }; ++#endif /* JUMPPLAY */ ++ + #define RUC_BEFORERECORDING "before" + #define RUC_AFTERRECORDING "after" + #define RUC_EDITEDRECORDING "edited" +@@ -202,8 +282,15 @@ class cRecordingUserCommand { + private: + static const char *command; + public: ++#ifdef USE_DELTIMESHIFTREC ++ static const char *GetCommand(void) { return command; } ++#endif /* DELTIMESHIFTREC */ + static void SetCommand(const char *Command) { command = Command; } ++#ifdef USE_DVLRECSCRIPTADDON ++ static void InvokeCommand(const char *State, const char *RecordingFileName, char *chanName = NULL); ++#else + static void InvokeCommand(const char *State, const char *RecordingFileName); ++#endif /* DVLRECSCRIPTADDON */ + }; + + // The maximum size of a single frame (up to HDTV 1920x1080): +@@ -216,9 +303,23 @@ public: + // before the next independent frame, to have a complete Group Of Pictures): + #define MAXVIDEOFILESIZETS 1048570 // MB + #define MAXVIDEOFILESIZEPES 2000 // MB ++#ifdef USE_HARDLINKCUTTER ++#define MINVIDEOFILESIZE 1 // MB ++#else + #define MINVIDEOFILESIZE 100 // MB ++#endif /* HARDLINKCUTTER */ + #define MAXVIDEOFILESIZEDEFAULT MAXVIDEOFILESIZEPES + ++#ifdef USE_HARDLINKCUTTER ++#define MINRECORDINGSIZE 25 // GB ++#define MAXRECORDINGSIZE 500 // GB ++#define DEFAULTRECORDINGSIZE 100 // GB ++// Dynamic recording size: ++// Keep recording file size at Setup.MaxVideoFileSize for as long as possible, ++// but switch to MAXVIDEOFILESIZE early enough, so that Setup.MaxRecordingSize ++// will be reached, before recording to file 255.vdr ++#endif /* HARDLINKCUTTER */ ++ + struct tIndexTs; + + class cIndexFile { +@@ -233,6 +334,9 @@ private: + void ConvertFromPes(tIndexTs *IndexTs, int Count); + void ConvertToPes(tIndexTs *IndexTs, int Count); + bool CatchUp(int Index = -1); ++#ifdef USE_DVDARCHIVE ++ bool isOnDVD; ++#endif /* DVDARCHIVE */ + public: + cIndexFile(const char *FileName, bool Record, bool IsPesRecording = false); + ~cIndexFile(); +@@ -263,6 +367,9 @@ public: + cUnbufferedFile *Open(void); + void Close(void); + cUnbufferedFile *SetOffset(int Number, off_t Offset = 0); ++#ifdef USE_HARDLINKCUTTER ++ off_t MaxFileSize(); // Dynamic file size for this file ++#endif /* HARDLINKCUTTER */ + cUnbufferedFile *NextFile(void); + }; + +diff -ruNp vdr-1.7.5/skinclassic.c vdr-1.7.5-extensions/skinclassic.c +--- vdr-1.7.5/skinclassic.c 2008-02-23 11:31:58.000000000 +0100 ++++ vdr-1.7.5-extensions/skinclassic.c 2009-04-12 13:37:59.000000000 +0200 +@@ -314,8 +314,52 @@ void cSkinClassicDisplayMenu::SetItem(co + for (int i = 0; i < MaxTabs; i++) { + const char *s = GetTabbedText(Text, i); + if (s) { ++#ifdef USE_LIEMIEXT ++ bool isprogressbar = false; ++ int now = 0, total = 0; ++ // check if progress bar: "[||||||| ]" ++ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { ++ const char *p = s + 1; ++ // update status ++ isprogressbar = true; ++ for (; *p != ']'; ++p) { ++ // check if progressbar characters ++ if (*p == ' ' || *p == '|') { ++ // update counters ++ ++total; ++ if (*p == '|') ++ ++now; ++ } ++ else { ++ // wrong character detected; not a progressbar ++ isprogressbar = false; ++ break; ++ } ++ } ++ } ++ int xt = x0 + Tab(i); ++ if (Setup.ShowProgressBar && isprogressbar) { ++ // define x coordinates of progressbar ++ int px0 = xt; ++ int px1 = (Tab(i + 1)?Tab(i+1):x1) - 5; ++ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); ++ // define y coordinates of progressbar ++ int py0 = y + 4; ++ int py1 = y + lineHeight - 4; ++ // draw background ++ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i+1):x1) - 1, y + lineHeight - 1, ColorBg); ++ // draw progressbar ++ osd->DrawRectangle(px0, py0, px, py1, ColorFg); ++ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); ++ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); ++ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); ++ } ++ else ++ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); ++#else + int xt = x0 + Tab(i); + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); ++#endif /* LIEMIEXT */ + } + if (!Tab(i + 1)) + break; +diff -ruNp vdr-1.7.5/skinsttng.c vdr-1.7.5-extensions/skinsttng.c +--- vdr-1.7.5/skinsttng.c 2008-02-23 11:23:44.000000000 +0100 ++++ vdr-1.7.5-extensions/skinsttng.c 2009-04-12 13:37:59.000000000 +0200 +@@ -558,8 +558,52 @@ void cSkinSTTNGDisplayMenu::SetItem(cons + for (int i = 0; i < MaxTabs; i++) { + const char *s = GetTabbedText(Text, i); + if (s) { ++#ifdef USE_LIEMIEXT ++ bool isprogressbar = false; ++ int now = 0, total = 0; ++ // check if progress bar: "[||||||| ]" ++ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { ++ const char *p = s + 1; ++ // update status ++ isprogressbar = true; ++ for (; *p != ']'; ++p) { ++ // check if progressbar characters ++ if (*p == ' ' || *p == '|') { ++ // update counters ++ ++total; ++ if (*p == '|') ++ ++now; ++ } ++ else { ++ // wrong character detected; not a progressbar ++ isprogressbar = false; ++ break; ++ } ++ } ++ } ++ int xt = x3 + 5 + Tab(i); ++ if (Setup.ShowProgressBar && isprogressbar) { ++ // define x coordinates of progressbar ++ int px0 = xt; ++ int px1 = x3 + (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1; ++ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); ++ // define y coordinates of progressbar ++ int py0 = y + 4; ++ int py1 = y + lineHeight - 4; ++ // draw background ++ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1, y + lineHeight - 1, ColorBg); ++ // draw progressbar ++ osd->DrawRectangle(px0, py0, px, py1, ColorFg); ++ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); ++ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); ++ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); ++ } ++ else ++ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); ++#else + int xt = x3 + 5 + Tab(i); + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); ++#endif /* LIEMIEXT */ + } + if (!Tab(i + 1)) + break; +@@ -602,6 +646,21 @@ void cSkinSTTNGDisplayMenu::SetEvent(con + y += ts.Height(); + } + y += font->Height(); ++#ifdef USE_PARENTALRATING ++ if (!isempty(Event->GetParentalRatingString())) { ++ const cFont *font = cFont::GetFont(fontSml); ++ ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetParentalRatingString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); ++ y += ts.Height(); ++ } ++ int i = 0; ++ while (Event->Contents(i++)) { ++ if (!isempty(Event->GetContentsString())) { ++ const cFont *font = cFont::GetFont(fontSml); ++ ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetContentsString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); ++ y += ts.Height(); ++ } ++ } ++#endif /* PARENTALRATING */ + if (!isempty(Event->Description())) { + int yt = y; + int yb = y4 - Roundness; +diff -ruNp vdr-1.7.5/sources.c vdr-1.7.5-extensions/sources.c +--- vdr-1.7.5/sources.c 2008-02-10 15:07:26.000000000 +0100 ++++ vdr-1.7.5-extensions/sources.c 2009-04-12 13:37:59.000000000 +0200 +@@ -37,6 +37,9 @@ cString cSource::ToString(int Code) + char buffer[16]; + char *q = buffer; + switch (Code & st_Mask) { ++#ifdef USE_PLUGINPARAM ++ case stPlug: *q++ = 'P'; break; ++#endif /* PLUGINPARAM */ + case stCable: *q++ = 'C'; break; + case stSat: *q++ = 'S'; + { +@@ -56,6 +59,9 @@ int cSource::FromString(const char *s) + { + int type = stNone; + switch (toupper(*s)) { ++#ifdef USE_PLUGINPARAM ++ case 'P': type = stPlug; break; ++#endif /* PLUGINPARAM */ + case 'C': type = stCable; break; + case 'S': type = stSat; break; + case 'T': type = stTerr; break; +@@ -68,7 +74,11 @@ int cSource::FromString(const char *s) + int pos = 0; + bool dot = false; + bool neg = false; ++#ifdef USE_SOURCECAPS ++ while (*++s && !isblank(*s)) { ++#else + while (*++s) { ++#endif /* SOURCECAPS */ + switch (toupper(*s)) { + case '0' ... '9': pos *= 10; + pos += *s - '0'; +diff -ruNp vdr-1.7.5/sources.conf vdr-1.7.5-extensions/sources.conf +--- vdr-1.7.5/sources.conf 2008-08-16 12:02:27.000000000 +0200 ++++ vdr-1.7.5-extensions/sources.conf 2009-04-12 13:37:59.000000000 +0200 +@@ -194,3 +194,7 @@ C Cable + # Terrestrial + + T Terrestrial ++ ++# Plugin PLUGINPARAM ++ ++#P Plugin +diff -ruNp vdr-1.7.5/sources.h vdr-1.7.5-extensions/sources.h +--- vdr-1.7.5/sources.h 2005-05-14 11:30:41.000000000 +0200 ++++ vdr-1.7.5-extensions/sources.h 2009-04-12 13:37:59.000000000 +0200 +@@ -16,10 +16,17 @@ class cSource : public cListObject { + public: + enum eSourceType { + stNone = 0x0000, ++#ifdef USE_PLUGINPARAM ++ stPlug = 0x2000, ++#endif /* PLUGINPARAM */ + stCable = 0x4000, + stSat = 0x8000, + stTerr = 0xC000, ++#ifdef USE_PLUGINPARAM ++ st_Mask = 0xE000, ++#else + st_Mask = 0xC000, ++#endif /* PLUGINPARAM */ + st_Neg = 0x0800, + st_Pos = 0x07FF, + }; +@@ -35,6 +42,9 @@ public: + static cString ToString(int Code); + static int FromString(const char *s); + static int FromData(eSourceType SourceType, int Position = 0, bool East = false); ++#ifdef USE_PLUGINPARAM ++ static bool IsPlug(int Code) { return (Code & st_Mask) == stPlug; } ++#endif /* PLUGINPARAM */ + static bool IsCable(int Code) { return (Code & st_Mask) == stCable; } + static bool IsSat(int Code) { return (Code & st_Mask) == stSat; } + static bool IsTerr(int Code) { return (Code & st_Mask) == stTerr; } +diff -ruNp vdr-1.7.5/status.c vdr-1.7.5-extensions/status.c +--- vdr-1.7.5/status.c 2008-02-16 15:46:31.000000000 +0100 ++++ vdr-1.7.5-extensions/status.c 2009-04-12 13:37:59.000000000 +0200 +@@ -29,6 +29,20 @@ void cStatus::MsgTimerChange(const cTime + sm->TimerChange(Timer, Change); + } + ++#ifdef USE_STREAMDEVEXT ++void cStatus::MsgRecordingChange(const cRecording *Recording, eStatusChange Change) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->RecordingChange(Recording, Change); ++} ++ ++void cStatus::MsgChannelChange(const cChannel *Channel, eStatusChange Change) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->ChannelChange(Channel, Change); ++} ++#endif /* STREAMDEVEXT */ ++ + void cStatus::MsgChannelSwitch(const cDevice *Device, int ChannelNumber) + { + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) +@@ -124,3 +138,88 @@ void cStatus::MsgOsdProgramme(time_t Pre + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle); + } ++ ++#ifdef USE_PINPLUGIN ++bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* Channel) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ChannelProtected(Device, Channel) == true) ++ return true; ++ return false; ++} ++ ++bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->ReplayProtected(Recording, Name, Base, isDirectory, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgRecordingFile(const char* FileName) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->RecordingFile(FileName); ++} ++ ++void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->TimerCreation(Timer, Event); ++} ++ ++bool cStatus::MsgPluginProtected(cPlugin* Plugin, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->PluginProtected(Plugin, menuView) == true) ++ return true; ++ return false; ++} ++ ++void cStatus::MsgUserAction(const eKeys key, const cOsdObject* Interact) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->UserAction(key, Interact); ++} ++ ++bool cStatus::MsgMenuItemProtected(const char* Name, int menuView) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ if (sm->MenuItemProtected(Name, menuView) == true) ++ return true; ++ return false; ++} ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_GRAPHTFT ++void cStatus::MsgOsdSetEvent(const cEvent* event) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetEvent(event); ++} ++ ++void cStatus::MsgOsdSetRecording(const cRecording* recording) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdSetRecording(recording); ++} ++ ++void cStatus::MsgOsdMenuDisplay(const char* kind) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDisplay(kind); ++} ++ ++void cStatus::MsgOsdMenuDestroy() ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdMenuDestroy(); ++} ++ ++void cStatus::MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) ++{ ++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) ++ sm->OsdEventItem(Event, Text, Index, Count); ++} ++#endif /* GRAPHTFT */ ++ +diff -ruNp vdr-1.7.5/status.h vdr-1.7.5-extensions/status.h +--- vdr-1.7.5/status.h 2008-02-16 16:00:33.000000000 +0100 ++++ vdr-1.7.5-extensions/status.h 2009-04-12 13:37:59.000000000 +0200 +@@ -14,8 +14,14 @@ + #include "device.h" + #include "player.h" + #include "tools.h" ++#ifdef USE_PINPLUGIN ++#include "plugin.h" ++#endif /* PINPLUGIN */ + + enum eTimerChange { tcMod, tcAdd, tcDel }; ++#ifdef USE_STREAMDEVEXT ++enum eStatusChange { scMod, scAdd, scDel }; ++#endif /* STREAMDEVEXT */ + + class cTimer; + +@@ -30,6 +36,16 @@ protected: + // been added or will be deleted, respectively. In case of tcMod, + // Timer is NULL; this indicates that some timer has been changed. + // Note that tcAdd and tcDel are always also followed by a tcMod. ++#ifdef USE_STREAMDEVEXT ++ virtual void RecordingChange(const cRecording *Recording, eStatusChange Change) {} ++ // Indicates a change in the recordings settings. ++ // If Change is scAdd or scDel, Recording points to the recording that has ++ // been added or will be deleted, respectively. In case of scMod, ++ // Timer is NULL; this indicates that some timer has been changed. ++ // Note that scAdd and scDel are always also followed by a scMod. ++ virtual void ChannelChange(const cChannel *Channel, eStatusChange Change) {} ++ // Indicates a change in the channel list. ++#endif /* STREAMDEVEXT */ + virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {} + // Indicates a channel switch on the given DVB device. + // If ChannelNumber is 0, this is before the channel is being switched, +@@ -80,11 +96,46 @@ protected: + // The OSD displays the single line Text with the current channel information. + virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {} + // The OSD displays the given programme information. ++#ifdef USE_PINPLUGIN ++ virtual bool ChannelProtected(const cDevice *Device, const cChannel* Channel) { return false; } ++ // Checks if a channel is protected. ++ virtual bool ReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false) { return false; } ++ // Checks if a recording is protected. ++ virtual void RecordingFile(const char* FileName) {} ++ // The given DVB device has started recording to FileName. FileName is the name of the ++ // recording directory ++ virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {} ++ // The given timer is created ++ virtual bool PluginProtected(cPlugin* Plugin, int menuView = false) { return false; } ++ // Checks if a plugin is protected. ++ virtual void UserAction(const eKeys key, const cOsdObject* Interact) {} ++ // report user action ++ virtual bool MenuItemProtected(const char* Name, int menuView = false) { return false; } ++ // Checks if a menu entry is protected. ++#endif /* PINPLUGIN */ ++#ifdef USE_GRAPHTFT ++ virtual void OsdSetRecording(const cRecording* recording) {} ++ // The OSD displays the recording information. ++ virtual void OsdSetEvent(const cEvent* event) {} ++ // The OSD displays the event information. ++ virtual void OsdMenuDisplay(const char* kind) {} ++ // report menu creation ++ virtual void OsdMenuDestroy() {} ++ // report menu destruvtion ++ virtual void OsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) {} ++ // The OSD displays the given single line Event as menu item at Index. ++ ++#endif /* GRAPHTFT */ ++ + public: + cStatus(void); + virtual ~cStatus(); + // These functions are called whenever the related status information changes: + static void MsgTimerChange(const cTimer *Timer, eTimerChange Change); ++#ifdef USE_STREAMDEVEXT ++ static void MsgRecordingChange(const cRecording *Recording, eStatusChange Change); ++ static void MsgChannelChange(const cChannel *Channel, eStatusChange Change); ++#endif /* STREAMDEVEXT */ + static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber); + static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On); + static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On); +@@ -101,6 +152,22 @@ public: + static void MsgOsdTextItem(const char *Text, bool Scroll = false); + static void MsgOsdChannel(const char *Text); + static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle); ++#ifdef USE_PINPLUGIN ++ static bool MsgChannelProtected(const cDevice* Device, const cChannel* Channel); ++ static bool MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false); ++ static void MsgRecordingFile(const char* FileName); ++ static void MsgTimerCreation(cTimer* Timer, const cEvent *Event); ++ static bool MsgPluginProtected(cPlugin* Plugin, int menuView = false); ++ static void MsgUserAction(const eKeys key, const cOsdObject* Interact); ++ static bool MsgMenuItemProtected(const char* Name, int menuView = false); ++#endif /* PINPLUGIN */ ++#ifdef USE_GRAPHTFT ++ static void MsgOsdSetEvent(const cEvent* event); ++ static void MsgOsdSetRecording(const cRecording* recording); ++ static void MsgOsdMenuDisplay(const char* kind); ++ static void MsgOsdMenuDestroy(); ++ static void MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count); ++#endif /* GRAPHTFT */ + }; + + #endif //__STATUS_H +diff -ruNp vdr-1.7.5/submenu.c vdr-1.7.5-extensions/submenu.c +--- vdr-1.7.5/submenu.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/submenu.c 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,952 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#include "submenu.h" ++#include "plugin.h" ++ ++static const char* TAG_SYSTEM = "system"; ++static const char* TAG_PLUGIN = "plugin"; ++static const char* TAG_COMMAND = "command"; ++static const char* TAG_THREAD = "thread"; ++static const char* TAG_MENU = "menu"; ++static const char* TAG_UNDEFINED = "undefined"; ++static const char* TRUE_STR = "yes"; ++ ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++ ++cSubMenuNode::cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ _level = level; ++ ++ if (xml != NULL && xml->Type() == TiXmlNode::ELEMENT) { ++ const char *tag = xml->Value(); ++ ++ if (cSubMenuNode::IsType(tag) != cSubMenuNode::UNDEFINED) { ++ SetType(tag); ++ SetName(xml->Attribute("name")); ++ if ((_type == COMMAND) || (_type == THREAD)) { ++ SetCommand(xml->Attribute("execute")); ++ const char * confirmStr = xml->Attribute("confirm"); ++ if (confirmStr != NULL && strcmp(confirmStr, TRUE_STR) == 0) ++ _commandConfirm = true; ++ } ++ else if (_type == PLUGIN) { // Add Plugin Index ++ SetCustomTitle(xml->Attribute("title")); ++ SetPlugin(); ++ } ++ else if (_type == MENU && xml->NoChildren() == false) { ++ xml = xml->FirstChildElement(); ++ do { ++ cSubMenuNode *node = new cSubMenuNode(xml, level+1, &_subMenus, currentMenu); ++ _subMenus.Add(node); ++ } while ((xml=xml->NextSiblingElement()) != NULL); ++ } ++ } ++ } ++ else ++ throw "Invalid XML Node"; ++} ++ ++/** ++ * Construct new Node empty Node ++ * ++ * ++ */ ++cSubMenuNode::cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) ++{ ++ init(); ++ _parentMenu = parentMenu; ++ _currentMenu = currentMenu; ++ ++} ++ ++ ++/** ++ * ++ */ ++void cSubMenuNode::init() ++{ ++ _name = NULL; ++ _command = NULL; ++ _title = NULL; ++ _pluginMainMenuEntry = NULL; ++ _type = UNDEFINED; ++ _level = 0; ++ _parentMenu = NULL; ++ _currentMenu = NULL; ++ _pluginIndex = 0; ++ _commandConfirm = false; ++} ++ ++ ++cSubMenuNode::~ cSubMenuNode() ++{ ++ if (_name != NULL) ++ free((void*)_name); ++ if (_command != NULL) ++ free((void*)_command); ++ if (_title != NULL) ++ free((void*)_title); ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++} ++ ++/** ++ * ++ */ ++void cSubMenuNode::SetPlugin() ++{ ++ bool found = false; ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) { ++ if (strcmp(_name, p->Name()) == 0 && p->MainMenuEntry() != NULL) { ++ SetPluginMainMenuEntry(p->MainMenuEntry()); ++ _pluginIndex = i; ++ found = true; ++ break; ++ } ++ } ++ else ++ break; ++ } ++ ++ if (!found) ++ _type = UNDEFINED; ++} ++ ++ ++bool cSubMenuNode::SaveXml(TiXmlElement * root) ++{ ++ bool ok = true; ++ ++ if (root!=NULL) { ++ TiXmlElement *e = NULL; ++ switch(_type) { ++ case SYSTEM: ++ e = new TiXmlElement(TAG_SYSTEM); ++ e->SetAttribute("name", GetName()); ++ break; ++ case COMMAND: ++ e = new TiXmlElement(TAG_COMMAND); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case THREAD: ++ e = new TiXmlElement(TAG_THREAD); ++ e->SetAttribute("name", GetName()); ++ e->SetAttribute("execute", GetCommand()); ++ if (_commandConfirm) ++ e->SetAttribute("confirm", TRUE_STR); ++ break; ++ case PLUGIN: ++ e = new TiXmlElement(TAG_PLUGIN); ++ e->SetAttribute("name", GetName()); ++ if (GetCustomTitle() != NULL && strcmp(GetCustomTitle(), "") != 0) ++ e->SetAttribute("title", GetCustomTitle()); ++ break; ++ case MENU: ++ e = new TiXmlElement(TAG_MENU); ++ e->SetAttribute("name", GetName()); ++ break; ++ case UNDEFINED: ++ default: ++ ok = false; ++ break; ++ } ++ if (ok) { ++ root->LinkEndChild(e); ++ if (HasSubMenus()) ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SaveXml(e); ++ } ++ } ++ ++ return(ok); ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::IsType(const char *name) ++{ ++ Type type = UNDEFINED; ++ ++ if (strcmp(name ,TAG_SYSTEM) == 0) ++ type = cSubMenuNode::SYSTEM; ++ else if (strcmp(name ,TAG_PLUGIN) == 0) ++ type = cSubMenuNode::PLUGIN; ++ else if (strcmp(name ,TAG_COMMAND) == 0) ++ type = cSubMenuNode::COMMAND; ++ else if (strcmp(name ,TAG_THREAD) == 0) ++ type = cSubMenuNode::THREAD; ++ else if (strcmp(name ,TAG_MENU) == 0) ++ type = cSubMenuNode::MENU; ++ ++ return(type); ++} ++ ++void cSubMenuNode::SetType(const char * name) ++{ ++ _type = IsType(name); ++} ++ ++void cSubMenuNode::SetType(enum Type type) ++{ ++ _type = type; ++} ++ ++ ++cSubMenuNode::Type cSubMenuNode::GetType() ++{ ++ return(_type); ++} ++ ++const char * cSubMenuNode::GetTypeAsString() ++{ ++ const char *str=NULL; ++ switch(_type) { ++ case SYSTEM: ++ str = TAG_SYSTEM; ++ break; ++ case COMMAND: ++ str = TAG_COMMAND; ++ break; ++ case THREAD: ++ str = TAG_THREAD; ++ break; ++ case PLUGIN: ++ str = TAG_PLUGIN; ++ break; ++ case MENU: ++ str = TAG_MENU; ++ break; ++ case UNDEFINED: ++ str = TAG_UNDEFINED; ++ default: ++ break; ++ } ++ ++ return(str); ++} ++ ++void cSubMenuNode::SetCommand(const char * command) ++{ ++ if (_command != NULL) ++ free((void*)_command); ++ ++ if (command != NULL) ++ _command = strdup(command); ++ else ++ _command = NULL; ++} ++ ++const char * cSubMenuNode::GetCommand() ++{ ++ return(_command); ++} ++ ++bool cSubMenuNode::CommandConfirm() ++{ ++ return(_commandConfirm); ++} ++ ++void cSubMenuNode::SetCommandConfirm(int val) ++{ ++ if (val == 1) ++ _commandConfirm = true; ++ else ++ _commandConfirm = false; ++} ++ ++void cSubMenuNode::SetCustomTitle(const char * title) ++{ ++ if (_title != NULL) ++ free((void*)_title); ++ ++ if (title != NULL) ++ _title = strdup(title); ++ else ++ _title = NULL; ++} ++ ++const char * cSubMenuNode::GetCustomTitle() ++{ ++ return(_title); ++} ++ ++void cSubMenuNode::SetName(const char * name) ++{ ++ if (_name) ++ free ((void*)_name); ++ ++ if (name != NULL) ++ _name = strdup(name); ++ else ++ _name = NULL; ++} ++ ++const char * cSubMenuNode::GetName() ++{ ++ return(_name); ++} ++ ++int cSubMenuNode::GetLevel() ++{ ++ return(_level); ++} ++ ++void cSubMenuNode::SetLevel(int level) ++{ ++ _level = level; ++ if (HasSubMenus()) { //Adjust Levels of Subnodes ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->SetLevel(level+1); ++ } ++} ++ ++int cSubMenuNode::GetPluginIndex() ++{ ++ return(_pluginIndex); ++} ++ ++void cSubMenuNode::SetPluginIndex(int index) ++{ ++ _pluginIndex = index; ++} ++ ++void cSubMenuNode::SetPluginMainMenuEntry(const char * mainMenuEntry) ++{ ++ if (_pluginMainMenuEntry != NULL) ++ free((void*)_pluginMainMenuEntry); ++ ++ if (_title != NULL && strcmp(_title, "") != 0) ++ _pluginMainMenuEntry = strdup(_title); ++ else if (mainMenuEntry != NULL) ++ _pluginMainMenuEntry = strdup(mainMenuEntry); ++ else ++ _pluginMainMenuEntry = NULL; ++} ++ ++const char * cSubMenuNode::GetPluginMainMenuEntry() ++{ ++ return(_pluginMainMenuEntry); ++} ++ ++ ++ ++cSubMenuNodes * cSubMenuNode::GetParentMenu() ++{ ++ return(_parentMenu); ++} ++ ++void cSubMenuNode::SetParentMenu(cSubMenuNodes * parent) ++{ ++ _parentMenu = parent; ++} ++ ++cSubMenuNodes * cSubMenuNode::GetCurrentMenu() ++{ ++ return(_currentMenu); ++} ++ ++void cSubMenuNode::SetCurrentMenu(cSubMenuNodes * current) ++{ ++ _currentMenu = current; ++} ++ ++ ++cSubMenuNodes * cSubMenuNode::GetSubMenus() ++{ ++ return(&_subMenus); ++} ++ ++bool cSubMenuNode::HasSubMenus() ++{ ++ if (_subMenus.Count() > 0) ++ return(true); ++ else ++ return(false); ++} ++ ++ ++void cSubMenuNode::Print(int index) ++{ ++ for (int i = 0; i < index; i++) ++ printf(" "); ++ ++ printf("Name=%s Type=%s Level=%d", _name, GetTypeAsString(), _level); ++ if (_type == COMMAND || _type == THREAD) ++ printf(" Command=%s", _command); ++ else if (_type == PLUGIN && _title != NULL) ++ printf(" Title=%s", _title); ++ printf("\n"); ++ ++ for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) ++ node->Print(index+4); ++} ++ ++ ++//################################################################################ ++//# ++//################################################################################ ++cSubMenu::cSubMenu() ++{ ++ _menuSuffix = NULL; ++ _fname = NULL; ++ _commandResult = NULL; ++ _currentMenuTree = &_menuTree; ++ _currentParentMenuTree = NULL; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = -1; ++#endif /* PINPLUGIN */ ++ _nodeArray = NULL; ++ _nrNodes = 0; ++} ++ ++ ++cSubMenu::~cSubMenu() ++{ ++ if (_menuSuffix) ++ free(_menuSuffix); ++ if (_fname) ++ free(_fname); ++ if (_commandResult) ++ free(_commandResult); ++ if (_nodeArray) ++ free(_nodeArray); ++ _nrNodes = 0; ++} ++ ++ ++bool cSubMenu::LoadXml(char *fname) ++{ ++ TiXmlDocument xmlDoc = TiXmlDocument(fname); ++ TiXmlElement *root = NULL; ++ cSubMenuNode *node = NULL; ++ ++ bool ok = true; ++ //Clear previously loaded Menu ++ if (_fname != NULL) ++ free(_fname); ++ _menuTree.Clear(); ++ _fname = strdup(fname); ++ ++ if ((ok = xmlDoc.LoadFile())) { ++ if ((root = xmlDoc.FirstChildElement("menus")) != NULL) { ++ char *tmp = NULL; ++ if ((tmp = (char*)root->Attribute("suffix")) == NULL) ++ asprintf(&_menuSuffix, " "); // set default menuSuffix // asprintf(&_menuSuffix, " ..."); ++ else ++ asprintf(&_menuSuffix, tmp); ++ ++ if ((root = root->FirstChildElement()) != NULL) { ++ do { ++ try { ++ node = new cSubMenuNode(root, 0, &_menuTree, NULL); ++ _menuTree.Add(node); ++ } ++ catch (char *message) { ++ esyslog("ERROR: while decoding XML Node"); ++ ok = false; ++ } ++ } while (ok == true && (root = root->NextSiblingElement()) != NULL); ++ addMissingPlugins(); ++ removeUndefinedNodes(); ++ } ++ } ++ else { ++ esyslog("ERROR: in %s, missing Tag <menus>\n", fname); ++ ok = false; ++ } ++ } ++ else { ++ esyslog("ERROR: in %s : %s Col=%d Row=%d\n", ++ fname, ++ xmlDoc.ErrorDesc(), ++ xmlDoc.ErrorCol(), ++ xmlDoc.ErrorRow()); ++ ok = false; ++ } ++ ++ return(ok); ++} ++ ++ ++bool cSubMenu::SaveXml() ++{ ++ return(SaveXml(_fname)); ++} ++ ++ ++bool cSubMenu::SaveXml(char *fname) ++{ ++ bool ok = true; ++ ++ if (_fname != NULL) { ++ TiXmlDocument xml = TiXmlDocument(fname); ++ TiXmlComment comment; ++ comment.SetValue("\n\ ++- VDR Menu-Configuration File\n\ ++-\n\ ++-\n\ ++- Example:\n\ ++-\n\ ++ <menus>\n\ ++ <system name=\"Schedule\" />\n\ ++ <system name=\"Channels\" />\n\ ++ <system name=\"Timers\" />\n\ ++ <system name=\"Recordings\" />\n\ ++ <menu name=\"System\">\n\ ++ <system name=\"Setup\" />\n\ ++ <system name=\"Commands\" />\n\ ++ <plugin name=\"setup\" title=\"My Setup\" />\n\ ++ <command name=\"myCommand1\" execute=\"/usr/bin/mycommand1\" />\n\ ++ <command name=\"myCommand2\" execute=\"/usr/bin/mycommand2\" confirm=\"yes\" />\n\ ++ <thread name=\"myCommand3\" execute=\"/usr/bin/mycommand3\" confirm=\"yes\" />\n\ ++ <plugin name=\"epgsearch\" title=\"myProgram\" />\n\ ++ <menu name=\"mySubSubMenu\">\n\ ++ ...\n\ ++ </menu>\n\ ++ </menu>\n\ ++ <menu name=\"Suche\">\n\ ++ <plugin name=\"epgsearch\" />\n\ ++ ...\n\ ++ </menu>\n\ ++ </menus>\n\ ++"); ++ ++ TiXmlElement root("menus"); ++ root.SetAttribute("suffix", _menuSuffix); ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->SaveXml(&root); ++ ++ if (xml.InsertEndChild(comment) != NULL && xml.InsertEndChild(root) != NULL) ++ ok = xml.SaveFile(fname); ++ } ++ else ++ ok = false; ++ ++ return(ok); ++} ++ ++ ++ ++cSubMenuNodes * cSubMenu::GetMenuTree() ++{ ++ return(_currentMenuTree); ++} ++ ++ ++void cSubMenu::PrintMenuTree() ++{ ++ for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) ++ node->Print(); ++} ++ ++ ++int cSubMenu::GetNrOfNodes() ++{ ++ if (_nrNodes == 0) { ++ if ((_nrNodes = countNodes(&_menuTree)) > 0) { ++ _nodeArray = (cSubMenuNode**) malloc(sizeof(cSubMenuNode*)*_nrNodes); ++ int index = 0; ++ tree2Array(&_menuTree, index); ++ } ++ } ++ ++ return(_nrNodes); ++} ++ ++ ++/** ++ * returns the specified node within the current menu ++ * @param index position in the current menu ++ * @return node or null if not found ++ */ ++cSubMenuNode * cSubMenu::GetNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ if (_currentMenuTree == NULL || (node=_currentMenuTree->Get(index)) == NULL) ++ esyslog("ERROR: illegal call of cSubMenu::GetNode(%d)", index); ++ ++ return(node); ++} ++ ++ ++/** ++ * Get the specified Node ++ * @param index specfies the absolut indes in the list of all nodes ++ * @return node or NULL if not found ++ */ ++cSubMenuNode * cSubMenu::GetAbsNode(int index) ++{ ++ cSubMenuNode *node = NULL; ++ GetNrOfNodes(); ++ if (_nrNodes > 0 && index >= 0 && index < _nrNodes) ++ node = _nodeArray[index]; ++ ++ return(node); ++} ++ ++ ++#ifdef USE_PINPLUGIN ++bool cSubMenu::Down(cSubMenuNode *node, int currentIndex) ++#else ++bool cSubMenu::Down(int index) ++#endif /* PINPLUGIN */ ++{ ++ bool ok = true; ++#ifdef USE_PINPLUGIN ++ if (_currentMenuTree != NULL && node && node->GetType() == cSubMenuNode::MENU) { ++#else ++ cSubMenuNode *node = NULL; ++ ++ if (_currentMenuTree != NULL && (node=_currentMenuTree->Get(index)) != NULL && node->GetType() == cSubMenuNode::MENU) { ++#endif /* PINPLUGIN */ ++ _currentParentMenuTree = _currentMenuTree; ++#ifdef USE_PINPLUGIN ++ _currentParentIndex = currentIndex; ++#endif /* PINPLUGIN */ ++ _currentMenuTree = node->GetSubMenus(); ++ } ++ else { ++ ok = false; ++#ifdef USE_PINPLUGIN ++ esyslog("ERROR: illegal call of cSubMenu::Down"); ++#else ++ esyslog("ERROR: illegal call of cSubMenu::Down(%d)", index); ++#endif /* PINPLUGIN */ ++ } ++ ++ return(ok); ++} ++ ++bool cSubMenu::Up(int *parentIndex) ++{ ++ bool ok = true; ++ ++ if (_currentMenuTree != NULL && parentIndex != NULL) { ++#ifndef USE_PINPLUGIN ++ cSubMenuNode *node = NULL; ++#endif /* PINPLUGIN */ ++ *parentIndex = 0; ++#ifdef USE_PINPLUGIN ++ if (_currentParentIndex >= 0) ++ *parentIndex = _currentParentIndex; ++#else ++ if (_currentParentMenuTree != NULL) ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ *parentIndex = i; ++ break; ++ } ++ } ++#endif /* PINPLUGIN */ ++ ++ _currentMenuTree = _currentParentMenuTree; ++ if (_currentMenuTree != NULL) ++ _currentParentMenuTree = _currentMenuTree->Get(0)->GetParentMenu(); ++ else ++ ok = false; ++ } ++ else { ++ ok = false; ++ esyslog("ERROR: illegal call of cSubMenu::Up()"); ++ } ++ ++ return(ok); ++} ++ ++const char * cSubMenu::ExecuteCommand(const char * cmd) ++{ ++ free(_commandResult); ++ _commandResult = NULL; ++ ++ dsyslog("executing command '%s'", cmd); ++ FILE *p = popen(cmd, "r"); ++ if (p) { ++ int l = 0; ++ int c; ++ while ((c = fgetc(p)) != EOF) { ++ if (l % 20 == 0) ++ _commandResult = (char *)realloc(_commandResult, l + 21); ++ _commandResult[l++] = c; ++ } ++ if (_commandResult) ++ _commandResult[l] = 0; ++ pclose(p); ++ } ++ else ++ esyslog("ERROR: can't open pipe for command '%s'", cmd); ++ ++ return _commandResult; ++} ++ ++/** ++ * Move Menu Entry to new Position ++ * @param index index of menu entry to move ++ * @param toIndex index of destination ++ * @param where After ore before the destination index ++ */ ++void cSubMenu::MoveMenu(int index, int toIndex, enum Where where) ++{ ++ if (index < 0 || index > _nrNodes || // invalid index is ignored ++ toIndex < 0 || toIndex > _nrNodes || index == toIndex) ++ return; ++ ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ cSubMenuNode *destNode = GetAbsNode(toIndex); ++ ++ if (where == cSubMenu::INTO && destNode->GetType() != cSubMenuNode::MENU) ++ return; ++ ++ if (where == cSubMenu::INTO) { ++ if (destNode->GetType() == cSubMenuNode::MENU) { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()+1); ++ srcNode->SetParentMenu(destNode->GetCurrentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetSubMenus()); ++ ++ destNode->GetSubMenus()->Add(srcNode); ++ reloadNodeArray(); ++ } ++ } ++ else { ++ srcNode->GetCurrentMenu()->Del(srcNode, false); ++ srcNode->SetLevel(destNode->GetLevel()); ++ srcNode->SetParentMenu(destNode->GetParentMenu()); ++ srcNode->SetCurrentMenu(destNode->GetCurrentMenu()); ++ ++ if (where == cSubMenu::BEHIND) { ++ destNode->GetCurrentMenu()->Add(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ else { ++ destNode->GetCurrentMenu()->Ins(srcNode, GetAbsNode(toIndex)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * Create a new Menu Entry ++ * @param index index of destination ++ * @param menuTitle Titel of new Menu entry ++ */ ++void cSubMenu::CreateMenu(int index, const char * menuTitle) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(menuTitle); ++ newNode->SetType(cSubMenuNode::MENU); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * delete the specified entry, or subtree if the specified entry is a menu ++ * @param index destion index ++ */ ++void cSubMenu::DeleteMenu(int index) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ srcNode->GetCurrentMenu()->Del(srcNode, true); ++ reloadNodeArray(); ++ } ++} ++ ++ ++// Private Methods ++ ++int cSubMenu::countNodes(cSubMenuNodes * tree) ++{ ++ int count = 0; ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ count++; ++ if (node->HasSubMenus()) ++ count += countNodes(node->GetSubMenus()); ++ } ++ } ++ return(count); ++} ++ ++ ++void cSubMenu::tree2Array(cSubMenuNodes * tree, int &index) ++{ ++ if (tree != NULL) { ++ for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { ++ _nodeArray[index++]=node; ++ if (node->HasSubMenus()) ++ tree2Array(node->GetSubMenus(), index); ++ } ++ } ++ ++} ++ ++bool cSubMenu::IsPluginInMenu(const char * name) ++{ ++ bool found = false; ++ for (int i = 0; i < _nrNodes && found == false; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::PLUGIN && strcmp(name, node->GetName()) == 0) ++ found = true; ++ } ++ return(found); ++} ++ ++/** ++ * Adds the given plugin to the Menu-Tree if not allready in List ++ * @param name specifies the name of the plugin ++ */ ++void cSubMenu::AddPlugin(const char * name) ++{ ++ if (! IsPluginInMenu(name)) { ++ cSubMenuNode *node = new cSubMenuNode(&_menuTree, NULL); ++ node->SetName(name); ++ node->SetType("plugin"); ++ node->SetPlugin(); ++ _menuTree.Add(node); ++ } ++} ++ ++void cSubMenu::addMissingPlugins() ++{ ++ _nrNodes = GetNrOfNodes(); ++ for (int i = 0; ; i++) { ++ cPlugin *p = cPluginManager::GetPlugin(i); ++ if (p) ++ AddPlugin(p->Name()); ++ else ++ break; ++ } ++ reloadNodeArray(); ++} ++ ++/** ++ * Adds the given command to the Menu-Tree ++ * @param name specifies the name of the command ++ */ ++void cSubMenu::CreateCommand(int index, const char * name, const char * execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("command"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++void cSubMenu::CreateThread(int index, const char * name, const char * execute, int confirm) ++{ ++ if (index >= 0 && index < _nrNodes) { ++ cSubMenuNode *srcNode = GetAbsNode(index); ++ if (srcNode != NULL) { ++ cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); ++ newNode->SetLevel(srcNode->GetLevel()); ++ newNode->SetName(name); ++ newNode->SetType("thread"); ++ newNode->SetCommand(execute); ++ newNode->SetCommandConfirm(confirm); ++ newNode->SetParentMenu(srcNode->GetParentMenu()); ++ newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); ++ ++ srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); ++ reloadNodeArray(); ++ } ++ } ++} ++ ++/** ++ * reloads the internal Array of Nodes ++ */ ++void cSubMenu::reloadNodeArray() ++{ ++ if (_nrNodes > 0) ++ free(_nodeArray); ++ _nodeArray = NULL; ++ _nrNodes = 0; ++ _nrNodes = GetNrOfNodes(); ++} ++ ++/** ++ * remove Undefined Nodes ++ */ ++void cSubMenu::removeUndefinedNodes() ++{ ++ bool remove = false; ++ ++ reloadNodeArray(); ++ for (int i = 0; i < _nrNodes; i++) { ++ cSubMenuNode *node = GetAbsNode(i); ++ if (node != NULL && node->GetType() == cSubMenuNode::UNDEFINED) { ++ cSubMenuNodes *pMenu = node->GetCurrentMenu(); ++ pMenu->Del(node, true); ++ remove = true; ++ } ++ } ++ if (remove) ++ reloadNodeArray(); ++} ++ ++ ++/** ++* Retrieves the Menutitel of the parent Menu ++*/ ++const char *cSubMenu::GetParentMenuTitel() ++{ ++ const char * result = ""; ++ ++ if (_currentMenuTree != NULL && _currentParentMenuTree != NULL) { ++ cSubMenuNode *node = NULL; ++ for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { ++ if (_currentMenuTree == node->GetSubMenus()) { ++ result = node->GetName(); ++ break; ++ } ++ } ++ } ++ ++ return(result); ++} ++ ++#endif ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/submenu.h vdr-1.7.5-extensions/submenu.h +--- vdr-1.7.5/submenu.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/submenu.h 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,160 @@ ++#ifdef USE_SETUP ++/**************************************************************************** ++ * DESCRIPTION: ++ * Submenu ++ * ++ * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ ++ * ++ * Contact: ranga@teddycats.de ++ * ++ * Copyright (C) 2004, 2005 by Ralf Dotzert ++ * ++ * modified for the VDR Extensions Patch by zulu @vdr-portal ++ ****************************************************************************/ ++ ++#ifndef SUBMENU_H ++#define SUBMENU_H ++ ++#include "thread.h" ++#include "tools.h" ++#include "tinystr.h" ++ ++class cSubMenuNode; ++class cSubMenuNodes; ++class cSubMenu; ++ ++ ++class cSubMenuNodes : public cList<cSubMenuNode> {}; ++ ++// execute cmd thread ++class cExecCmdThread : public cThread { ++private: ++ char *ExecCmd; ++protected: ++ virtual void Action(void) { ++ if (system(ExecCmd) == 0) ++ esyslog("%s - finished", ExecCmd); ++ delete(this); ++ }; ++public: ++ cExecCmdThread(char *cmd) { ++ asprintf(&ExecCmd, "%s", cmd); ++ } ++ cExecCmdThread(const char *cmd) { ++ asprintf(&ExecCmd, "%s", cmd); ++ } ++ ~cExecCmdThread() { ++ free(ExecCmd); ++ }; ++ }; ++ ++//################################################################################ ++//# SubMenuNode ++//################################################################################ ++class cSubMenuNode : public cListObject { ++public: ++ enum Type { UNDEFINED, SYSTEM, COMMAND, THREAD, PLUGIN, MENU }; ++ cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); ++ ~cSubMenuNode(); ++ bool SaveXml(TiXmlElement * root); ++ static cSubMenuNode::Type IsType(const char *name); ++ void SetType(const char *name); ++ void SetType(enum Type type); ++ void SetPlugin(); ++ cSubMenuNode::Type GetType(); ++ const char *GetTypeAsString(); ++ void SetCommand(const char *command); ++ bool CommandConfirm(); ++ void SetCommandConfirm(int val); ++ const char *GetCommand(); ++ void SetCustomTitle(const char *title); ++ const char *GetCustomTitle(); ++ void SetName(const char *name); ++ const char*GetName(); ++ int GetLevel(); ++ void SetLevel(int level); ++ int GetPluginIndex(); ++ void SetPluginIndex(int index); ++ void SetPluginMainMenuEntry(const char *mainMenuEntry); ++ const char *GetPluginMainMenuEntry(); ++ cSubMenuNodes *GetParentMenu(); ++ void SetParentMenu(cSubMenuNodes *parent); ++ cSubMenuNodes *GetCurrentMenu(); ++ void SetCurrentMenu(cSubMenuNodes *current); ++ cSubMenuNodes *GetSubMenus(); ++ bool HasSubMenus(); ++ void Print(int index = 0); ++private: ++ Type _type; ++ int _level; ++ // Plugin Variables ++ int _pluginIndex; ++ const char *_pluginMainMenuEntry; ++ // common ++ const char *_name; ++ const char *_command; ++ bool _commandConfirm; ++ const char *_title; ++ cSubMenuNodes _subMenus; ++ cSubMenuNodes *_parentMenu; ++ cSubMenuNodes *_currentMenu; ++ void init(); ++ }; ++ ++ ++//################################################################################ ++//# SubMenu Class ++//################################################################################ ++class cSubMenu { ++public: ++ cSubMenu(); ++ ~cSubMenu(); ++ enum Where { BEFORE, BEHIND, INTO}; ++ bool LoadXml(char *fname); ++ bool SaveXml(char *fname); ++ bool SaveXml(); ++ cSubMenuNodes *GetMenuTree(); ++ bool Up(int *ParentIndex); ++#ifdef USE_PINPLUGIN ++ bool Down(cSubMenuNode* node, int currentIndex); ++#else ++ bool Down(int index); ++#endif /* PINPLUGIN */ ++ int GetNrOfNodes(); ++ cSubMenuNode* GetAbsNode(int index); ++ cSubMenuNode* GetNode(int index); ++ void PrintMenuTree(); ++ bool IsPluginInMenu(const char *name); ++ void AddPlugin(const char *name); ++ void CreateCommand(int index, const char *name, const char *execute, int confirm); ++ void CreateThread(int index, const char *name, const char *execute, int confirm); ++ const char *ExecuteCommand(const char *command); ++ void MoveMenu(int index, int toindex, enum Where); ++ void CreateMenu(int index, const char *menuTitle); ++ void DeleteMenu(int index); ++ char *GetMenuSuffix() { return _menuSuffix; } ++ void SetMenuSuffix(char *suffix) { if (_menuSuffix) free(_menuSuffix); asprintf(&_menuSuffix, suffix); } ++ bool isTopMenu() { return (_currentParentMenuTree == NULL); } ++ const char *GetParentMenuTitel(); ++private: ++ cSubMenuNodes _menuTree; ++ cSubMenuNodes *_currentMenuTree; ++ cSubMenuNodes *_currentParentMenuTree; ++#ifdef USE_PINPLUGIN ++ int _currentParentIndex; ++#endif /* PINPLUGIN */ ++ char *_fname; ++ char *_commandResult; ++ int _nrNodes; ++ cSubMenuNode **_nodeArray; ++ char *_menuSuffix; ++ int countNodes(cSubMenuNodes *tree); ++ void tree2Array(cSubMenuNodes *tree, int &index); ++ void addMissingPlugins(); ++ void reloadNodeArray(); ++ void removeUndefinedNodes(); ++ }; ++ ++#endif //__SUBMENU_H ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/svdrp.c vdr-1.7.5-extensions/svdrp.c +--- vdr-1.7.5/svdrp.c 2009-01-06 15:35:45.000000000 +0100 ++++ vdr-1.7.5-extensions/svdrp.c 2009-04-12 13:37:59.000000000 +0200 +@@ -39,6 +39,9 @@ + #include "timers.h" + #include "tools.h" + #include "videodir.h" ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ + + // --- cSocket --------------------------------------------------------------- + +@@ -296,6 +299,10 @@ const char *HelpPages[] = { + "REMO [ on | off ]\n" + " Turns the remote control on or off. Without a parameter, the current\n" + " status of the remote control is reported.", ++#ifdef USE_LIEMIEXT ++ "RENR <number> <new name>\n" ++ " Rename recording. Number must be the Number as returned by LSTR command.", ++#endif /* LIEMIEXT */ + "SCAN\n" + " Forces an EPG scan. If this is a single DVB device system, the scan\n" + " will be done on the primary device unless it is currently recording.", +@@ -616,6 +623,9 @@ void cSVDRP::CmdDELC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("channel %s deleted", Option); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(NULL, scDel); ++#endif /* STREAMDEVEXT */ + if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { + if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) + Channels.SwitchTo(CurrentChannel->Number()); +@@ -1135,6 +1145,9 @@ void cSVDRP::CmdMODC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("modifed channel %d %s", channel->Number(), *channel->ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scMod); ++#endif /* STREAMDEVEXT */ + Reply(250, "%d %s", channel->Number(), *channel->ToText()); + } + else +@@ -1221,6 +1234,9 @@ void cSVDRP::CmdMOVC(const char *Option) + else + cDevice::SetCurrentChannel(CurrentChannel); + } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(ToChannel, scMod); ++#endif /* STREAMDEVEXT */ + isyslog("channel %d moved to %d", FromNumber, ToNumber); + Reply(250,"Channel \"%d\" moved to \"%d\"", From, To); + } +@@ -1264,6 +1280,9 @@ void cSVDRP::CmdNEWC(const char *Option) + Channels.ReNumber(); + Channels.SetModified(true); + isyslog("new channel %d %s", channel->Number(), *channel->ToText()); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgChannelChange(channel, scAdd); ++#endif /* STREAMDEVEXT */ + Reply(250, "%d %s", channel->Number(), *channel->ToText()); + } + else +@@ -1466,6 +1485,38 @@ void cSVDRP::CmdSCAN(const char *Option) + Reply(250, "EPG scan triggered"); + } + ++#ifdef USE_LIEMIEXT ++void cSVDRP::CmdRENR(const char *Option) ++{ ++ bool recordings = Recordings.Update(true); ++ if (recordings) { ++ if (*Option) { ++ char *tail; ++ int n = strtol(Option, &tail, 10); ++ cRecording *recording = Recordings.Get(n - 1); ++ if (recording && tail && tail != Option) { ++ char *oldName = strdup(recording->Name()); ++ tail = skipspace(tail); ++ if (recording->Rename(tail)) { ++ Reply(250, "Renamed \"%s\" to \"%s\"", oldName, recording->Name()); ++ Recordings.ChangeState(); ++ Recordings.TouchUpdate(); ++ } ++ else ++ Reply(501, "Renaming \"%s\" to \"%s\" failed", oldName, tail); ++ free(oldName); ++ } ++ else ++ Reply(501, "Recording not found or wrong syntax"); ++ } ++ else ++ Reply(501, "Missing Input settings"); ++ } ++ else ++ Reply(550, "No recordings available"); ++} ++#endif /* LIEMIEXT */ ++ + void cSVDRP::CmdSTAT(const char *Option) + { + if (*Option) { +@@ -1581,6 +1632,9 @@ void cSVDRP::Execute(char *Cmd) + else if (CMD("PLUG")) CmdPLUG(s); + else if (CMD("PUTE")) CmdPUTE(s); + else if (CMD("REMO")) CmdREMO(s); ++#ifdef USE_LIEMIEXT ++ else if (CMD("RENR")) CmdRENR(s); ++#endif /* LIEMIEXT */ + else if (CMD("SCAN")) CmdSCAN(s); + else if (CMD("STAT")) CmdSTAT(s); + else if (CMD("UPDT")) CmdUPDT(s); +diff -ruNp vdr-1.7.5/svdrp.h vdr-1.7.5-extensions/svdrp.h +--- vdr-1.7.5/svdrp.h 2007-04-30 14:28:28.000000000 +0200 ++++ vdr-1.7.5-extensions/svdrp.h 2009-04-12 13:37:59.000000000 +0200 +@@ -79,6 +79,9 @@ private: + void CmdPLUG(const char *Option); + void CmdPUTE(const char *Option); + void CmdREMO(const char *Option); ++#ifdef USE_LIEMIEXT ++ void CmdRENR(const char *Option); ++#endif /* LIEMIEXT */ + void CmdSCAN(const char *Option); + void CmdSTAT(const char *Option); + void CmdUPDT(const char *Option); +diff -ruNp vdr-1.7.5/timers.c vdr-1.7.5-extensions/timers.c +--- vdr-1.7.5/timers.c 2008-04-13 14:41:41.000000000 +0200 ++++ vdr-1.7.5-extensions/timers.c 2009-04-12 13:37:59.000000000 +0200 +@@ -46,6 +46,9 @@ cTimer::cTimer(bool Instant, bool Pause, + stop -= 2400; + priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; + lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + aux = NULL; + event = NULL; +@@ -79,12 +82,18 @@ cTimer::cTimer(const cEvent *Event) + stop -= 2400; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = 0; ++#endif /* PINPLUGIN */ + *file = 0; + const char *Title = Event->Title(); + if (!isempty(Title)) + Utf8Strn0Cpy(file, Event->Title(), sizeof(file)); + aux = NULL; + event = NULL; // let SetEvent() be called to get a log message ++#ifdef USE_PINPLUGIN ++ cStatus::MsgTimerCreation(this, Event); ++#endif /* PINPLUGIN */ + } + + cTimer::cTimer(const cTimer &Timer) +@@ -119,6 +128,9 @@ cTimer& cTimer::operator= (const cTimer + stop = Timer.stop; + priority = Timer.priority; + lifetime = Timer.lifetime; ++#ifdef USE_PINPLUGIN ++ fskProtection = Timer.fskProtection; ++#endif /* PINPLUGIN */ + strncpy(file, Timer.file, sizeof(file)); + free(aux); + aux = Timer.aux ? strdup(Timer.aux) : NULL; +@@ -313,6 +325,9 @@ bool cTimer::Parse(const char *s) + result = false; + } + } ++#ifdef USE_PINPLUGIN ++ fskProtection = aux && strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"); ++#endif /* PINPLUGIN */ + free(channelbuffer); + free(daybuffer); + free(filebuffer); +@@ -559,6 +574,9 @@ void cTimer::SetRecording(bool Recording + SetFlags(tfRecording); + else + ClrFlags(tfRecording); ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(NULL, scAdd); ++#endif /* STREAMDEVEXT */ + isyslog("timer %s %s", *ToDescr(), recording ? "start" : "stop"); + } + +@@ -622,6 +640,35 @@ void cTimer::OnOff(void) + Matches(); // refresh start and end time + } + ++#ifdef USE_PINPLUGIN ++void cTimer::SetFskProtection(int aFlag) ++{ ++ char* p; ++ char* tmp = 0; ++ ++ fskProtection = aFlag; ++ ++ if (fskProtection && (!aux || !strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // add protection info to aux ++ ++ if (aux) { tmp = strdup(aux); free(aux); } ++ asprintf(&aux,"%s<pin-plugin><protected>yes</protected></pin-plugin>", tmp ? tmp : ""); ++ } ++ else if (!fskProtection && aux && (p = strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) ++ { ++ // remove protection info to aux ++ ++ asprintf(&tmp, "%.*s%s", p-aux, aux, p+strlen("<pin-plugin><protected>yes</protected></pin-plugin>")); ++ free(aux); ++ aux = strdup(tmp); ++ } ++ ++ if (tmp) ++ free(tmp); ++} ++#endif /* PINPLUGIN */ ++ + // --- cTimers --------------------------------------------------------------- + + cTimers Timers; +diff -ruNp vdr-1.7.5/timers.h vdr-1.7.5-extensions/timers.h +--- vdr-1.7.5/timers.h 2008-02-16 15:33:23.000000000 +0100 ++++ vdr-1.7.5-extensions/timers.h 2009-04-12 13:37:59.000000000 +0200 +@@ -37,6 +37,9 @@ private: + int start; + int stop; + int priority; ++#ifdef USE_PINPLUGIN ++ int fskProtection; ++#endif /* PINPLUGIN */ + int lifetime; + mutable char file[MaxFileName]; + char *aux; +@@ -58,6 +61,9 @@ public: + int Start(void) const { return start; } + int Stop(void) const { return stop; } + int Priority(void) const { return priority; } ++#ifdef USE_PINPLUGIN ++ int FskProtection(void) const { return fskProtection; } ++#endif /* PINPLUGIN */ + int Lifetime(void) const { return lifetime; } + const char *File(void) const { return file; } + time_t FirstDay(void) const { return weekdays ? day : 0; } +@@ -86,6 +92,9 @@ public: + void SetInVpsMargin(bool InVpsMargin); + void SetPriority(int Priority); + void SetFlags(uint Flags); ++#ifdef USE_PINPLUGIN ++ void SetFskProtection(int aFlag); ++#endif /* PINPLUGIN */ + void ClrFlags(uint Flags); + void InvFlags(uint Flags); + bool HasFlags(uint Flags) const; +diff -ruNp vdr-1.7.5/tinystr.c vdr-1.7.5-extensions/tinystr.c +--- vdr-1.7.5/tinystr.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/tinystr.c 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,301 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++#ifndef TIXML_USE_STL ++ ++ ++#include <stdlib.h> ++#include <string.h> ++#include <ctype.h> ++ ++#include "tinystr.h" ++ ++// TiXmlString constructor, based on a C string ++TiXmlString::TiXmlString (const char* instring) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (!instring) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = strlen (instring) + 1; ++ newstring = new char [newlen]; ++ memcpy (newstring, instring, newlen); ++ // strcpy (newstring, instring); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString copy constructor ++TiXmlString::TiXmlString (const TiXmlString& copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ // Prevent copy to self! ++ if ( © == this ) ++ return; ++ ++ if (! copy . allocated) ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . cstring); ++ memcpy (newstring, copy . cstring, newlen); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// TiXmlString = operator. Safe when assign own content ++void TiXmlString ::operator = (const char * content) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! content) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = strlen (content) + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, content); ++ memcpy (newstring, content, newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++// = operator. Safe when assign own content ++void TiXmlString ::operator = (const TiXmlString & copy) ++{ ++ unsigned newlen; ++ char * newstring; ++ ++ if (! copy . length ()) ++ { ++ empty_it (); ++ return; ++ } ++ newlen = copy . length () + 1; ++ newstring = new char [newlen]; ++ // strcpy (newstring, copy . c_str ()); ++ memcpy (newstring, copy . c_str (), newlen); ++ empty_it (); ++ allocated = newlen; ++ cstring = newstring; ++ current_length = newlen - 1; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char* str, int len ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size, size_suffix; ++ ++ // don't use strlen - it can overrun the len passed in! ++ const char* p = str; ++ size_suffix = 0; ++ ++ while ( *p && size_suffix < (unsigned)len ) ++ { ++ ++p; ++ ++size_suffix; ++ } ++ if ( !size_suffix) ++ return; ++ ++ new_size = length () + size_suffix + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ // strcpy (new_string, cstring); ++ memcpy (new_string, cstring, length ()); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strncat (new_string, str, len); ++ memcpy (new_string + length (), ++ str, ++ size_suffix); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strncat (cstring, str, len); ++ memcpy (cstring + length (), ++ str, ++ size_suffix); ++ } ++ current_length = new_size - 1; ++ cstring [current_length] = 0; ++} ++ ++ ++// append a const char * to an existing TiXmlString ++void TiXmlString::append( const char * suffix ) ++{ ++ char * new_string; ++ unsigned new_alloc, new_size; ++ ++ new_size = length () + strlen (suffix) + 1; ++ // check if we need to expand ++ if (new_size > allocated) ++ { ++ // compute new size ++ new_alloc = assign_new_size (new_size); ++ ++ // allocate new buffer ++ new_string = new char [new_alloc]; ++ new_string [0] = 0; ++ ++ // copy the previous allocated buffer into this one ++ if (allocated && cstring) ++ memcpy (new_string, cstring, 1 + length ()); ++ // strcpy (new_string, cstring); ++ ++ // append the suffix. It does exist, otherwize we wouldn't be expanding ++ // strcat (new_string, suffix); ++ memcpy (new_string + length (), ++ suffix, ++ strlen (suffix) + 1); ++ ++ // return previsously allocated buffer if any ++ if (allocated && cstring) ++ delete [] cstring; ++ ++ // update member variables ++ cstring = new_string; ++ allocated = new_alloc; ++ } ++ else ++ { ++ // we know we can safely append the new string ++ // strcat (cstring, suffix); ++ memcpy (cstring + length (), ++ suffix, ++ strlen (suffix) + 1); ++ } ++ current_length = new_size - 1; ++} ++ ++// Check for TiXmlString equuivalence ++//bool TiXmlString::operator == (const TiXmlString & compare) const ++//{ ++// return (! strcmp (c_str (), compare . c_str ())); ++//} ++ ++//unsigned TiXmlString::length () const ++//{ ++// if (allocated) ++// // return strlen (cstring); ++// return current_length; ++// return 0; ++//} ++ ++ ++unsigned TiXmlString::find (char tofind, unsigned offset) const ++{ ++ char * lookup; ++ ++ if (offset >= length ()) ++ return (unsigned) notfound; ++ for (lookup = cstring + offset; * lookup; lookup++) ++ if (* lookup == tofind) ++ return lookup - cstring; ++ return (unsigned) notfound; ++} ++ ++ ++bool TiXmlString::operator == (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) == 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator < (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) > 0 ); ++ } ++ return false; ++} ++ ++ ++bool TiXmlString::operator > (const TiXmlString & compare) const ++{ ++ if ( allocated && compare.allocated ) ++ { ++ assert( cstring ); ++ assert( compare.cstring ); ++ return ( strcmp( cstring, compare.cstring ) < 0 ); ++ } ++ return false; ++} ++ ++ ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/tinystr.h vdr-1.7.5-extensions/tinystr.h +--- vdr-1.7.5/tinystr.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/tinystr.h 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,244 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original file by Yves Berquin. ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++ ++#ifndef TIXML_USE_STL ++ ++#ifndef TIXML_STRING_INCLUDED ++#define TIXML_STRING_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4786 ) // Debugger truncating names. ++#endif ++ ++#include <assert.h> ++ ++/* ++ TiXmlString is an emulation of the std::string template. ++ Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. ++ Only the member functions relevant to the TinyXML project have been implemented. ++ The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase ++ a string and there's no more room, we allocate a buffer twice as big as we need. ++*/ ++class TiXmlString ++{ ++ public : ++ // TiXmlString constructor, based on a string ++ TiXmlString (const char * instring); ++ ++ // TiXmlString empty constructor ++ TiXmlString () ++ { ++ allocated = 0; ++ cstring = NULL; ++ current_length = 0; ++ } ++ ++ // TiXmlString copy constructor ++ TiXmlString (const TiXmlString& copy); ++ ++ // TiXmlString destructor ++ ~ TiXmlString () ++ { ++ empty_it (); ++ } ++ ++ // Convert a TiXmlString into a classical char * ++ const char * c_str () const ++ { ++ if (allocated) ++ return cstring; ++ return ""; ++ } ++ ++ // Return the length of a TiXmlString ++ unsigned length () const ++ { ++ return ( allocated ) ? current_length : 0; ++ } ++ ++ // TiXmlString = operator ++ void operator = (const char * content); ++ ++ // = operator ++ void operator = (const TiXmlString & copy); ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (const char * suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (char single) ++ { ++ append (single); ++ return *this; ++ } ++ ++ // += operator. Maps to append ++ TiXmlString& operator += (TiXmlString & suffix) ++ { ++ append (suffix); ++ return *this; ++ } ++ bool operator == (const TiXmlString & compare) const; ++ bool operator < (const TiXmlString & compare) const; ++ bool operator > (const TiXmlString & compare) const; ++ ++ // Checks if a TiXmlString is empty ++ bool empty () const ++ { ++ return length () ? false : true; ++ } ++ ++ // single char extraction ++ const char& at (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // find a char in a string. Return TiXmlString::notfound if not found ++ unsigned find (char lookup) const ++ { ++ return find (lookup, 0); ++ } ++ ++ // find a char in a string from an offset. Return TiXmlString::notfound if not found ++ unsigned find (char tofind, unsigned offset) const; ++ ++ /* Function to reserve a big amount of data when we know we'll need it. Be aware that this ++ function clears the content of the TiXmlString if any exists. ++ */ ++ void reserve (unsigned size) ++ { ++ empty_it (); ++ if (size) ++ { ++ allocated = size; ++ cstring = new char [size]; ++ cstring [0] = 0; ++ current_length = 0; ++ } ++ } ++ ++ // [] operator ++ char& operator [] (unsigned index) const ++ { ++ assert( index < length ()); ++ return cstring [index]; ++ } ++ ++ // Error value for find primitive ++ enum { notfound = 0xffffffff, ++ npos = notfound }; ++ ++ void append (const char *str, int len ); ++ ++ protected : ++ ++ // The base string ++ char * cstring; ++ // Number of chars allocated ++ unsigned allocated; ++ // Current string size ++ unsigned current_length; ++ ++ // New size computation. It is simplistic right now : it returns twice the amount ++ // we need ++ unsigned assign_new_size (unsigned minimum_to_allocate) ++ { ++ return minimum_to_allocate * 2; ++ } ++ ++ // Internal function that clears the content of a TiXmlString ++ void empty_it () ++ { ++ if (cstring) ++ delete [] cstring; ++ cstring = NULL; ++ allocated = 0; ++ current_length = 0; ++ } ++ ++ void append (const char *suffix ); ++ ++ // append function for another TiXmlString ++ void append (const TiXmlString & suffix) ++ { ++ append (suffix . c_str ()); ++ } ++ ++ // append for a single char. ++ void append (char single) ++ { ++ if ( cstring && current_length < (allocated-1) ) ++ { ++ cstring[ current_length ] = single; ++ ++current_length; ++ cstring[ current_length ] = 0; ++ } ++ else ++ { ++ char smallstr [2]; ++ smallstr [0] = single; ++ smallstr [1] = 0; ++ append (smallstr); ++ } ++ } ++ ++} ; ++ ++/* ++ TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. ++ Only the operators that we need for TinyXML have been developped. ++*/ ++class TiXmlOutStream : public TiXmlString ++{ ++public : ++ TiXmlOutStream () : TiXmlString () {} ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const char * in) ++ { ++ append (in); ++ return (* this); ++ } ++ ++ // TiXmlOutStream << operator. Maps to TiXmlString::append ++ TiXmlOutStream & operator << (const TiXmlString & in) ++ { ++ append (in . c_str ()); ++ return (* this); ++ } ++} ; ++ ++#endif // TIXML_STRING_INCLUDED ++#endif // TIXML_USE_STL ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/tinyxml.c vdr-1.7.5-extensions/tinyxml.c +--- vdr-1.7.5/tinyxml.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/tinyxml.c 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,1429 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include <ctype.h> ++#include "tinyxml.h" ++ ++#ifdef TIXML_USE_STL ++#include <sstream> ++#endif ++ ++ ++bool TiXmlBase::condenseWhiteSpace = true; ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream ) ++{ ++ TIXML_STRING buffer; ++ PutString( str, &buffer ); ++ (*stream) << buffer; ++} ++ ++void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) ++{ ++ int i=0; ++ ++ while( i<(int)str.length() ) ++ { ++ unsigned char c = (unsigned char) str[i]; ++ ++ if ( c == '&' ++ && i < ( (int)str.length() - 2 ) ++ && str[i+1] == '#' ++ && str[i+2] == 'x' ) ++ { ++ // Hexadecimal character reference. ++ // Pass through unchanged. ++ // © -- copyright symbol, for example. ++ // ++ // The -1 is a bug fix from Rob Laveaux. It keeps ++ // an overflow from happening if there is no ';'. ++ // There are actually 2 ways to exit this loop - ++ // while fails (error case) and break (semicolon found). ++ // However, there is no mechanism (currently) for ++ // this function to return an error. ++ while ( i<(int)str.length()-1 ) ++ { ++ outString->append( str.c_str() + i, 1 ); ++ ++i; ++ if ( str[i] == ';' ) ++ break; ++ } ++ } ++ else if ( c == '&' ) ++ { ++ outString->append( entity[0].str, entity[0].strLength ); ++ ++i; ++ } ++ else if ( c == '<' ) ++ { ++ outString->append( entity[1].str, entity[1].strLength ); ++ ++i; ++ } ++ else if ( c == '>' ) ++ { ++ outString->append( entity[2].str, entity[2].strLength ); ++ ++i; ++ } ++ else if ( c == '\"' ) ++ { ++ outString->append( entity[3].str, entity[3].strLength ); ++ ++i; ++ } ++ else if ( c == '\'' ) ++ { ++ outString->append( entity[4].str, entity[4].strLength ); ++ ++i; ++ } ++ else if ( c < 32 ) ++ { ++ // Easy pass at non-alpha/numeric/symbol ++ // Below 32 is symbolic. ++ char buf[ 32 ]; ++ sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); ++ outString->append( buf, strlen( buf ) ); ++ ++i; ++ } ++ else ++ { ++ //char realc = (char) c; ++ //outString->append( &realc, 1 ); ++ *outString += (char) c; // somewhat more efficient function call. ++ ++i; ++ } ++ } ++} ++ ++ ++// <-- Strange class for a bug fix. Search for STL_STRING_BUG ++TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str ) ++{ ++ buffer = new char[ str.length()+1 ]; ++ if ( buffer ) ++ { ++ strcpy( buffer, str.c_str() ); ++ } ++} ++ ++ ++TiXmlBase::StringToBuffer::~StringToBuffer() ++{ ++ delete [] buffer; ++} ++// End strange bug fix. --> ++ ++ ++TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() ++{ ++ parent = 0; ++ type = _type; ++ firstChild = 0; ++ lastChild = 0; ++ prev = 0; ++ next = 0; ++} ++ ++ ++TiXmlNode::~TiXmlNode() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++} ++ ++ ++void TiXmlNode::CopyTo( TiXmlNode* target ) const ++{ ++ target->SetValue (value.c_str() ); ++ target->userData = userData; ++} ++ ++ ++void TiXmlNode::Clear() ++{ ++ TiXmlNode* node = firstChild; ++ TiXmlNode* temp = 0; ++ ++ while ( node ) ++ { ++ temp = node; ++ node = node->next; ++ delete temp; ++ } ++ ++ firstChild = 0; ++ lastChild = 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) ++{ ++ node->parent = this; ++ ++ node->prev = lastChild; ++ node->next = 0; ++ ++ if ( lastChild ) ++ lastChild->next = node; ++ else ++ firstChild = node; // it was an empty list. ++ ++ lastChild = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) ++{ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ return LinkEndChild( node ); ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) ++{ ++ if ( !beforeThis || beforeThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->next = beforeThis; ++ node->prev = beforeThis->prev; ++ if ( beforeThis->prev ) ++ { ++ beforeThis->prev->next = node; ++ } ++ else ++ { ++ assert( firstChild == beforeThis ); ++ firstChild = node; ++ } ++ beforeThis->prev = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) ++{ ++ if ( !afterThis || afterThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = addThis.Clone(); ++ if ( !node ) ++ return 0; ++ node->parent = this; ++ ++ node->prev = afterThis; ++ node->next = afterThis->next; ++ if ( afterThis->next ) ++ { ++ afterThis->next->prev = node; ++ } ++ else ++ { ++ assert( lastChild == afterThis ); ++ lastChild = node; ++ } ++ afterThis->next = node; ++ return node; ++} ++ ++ ++TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) ++{ ++ if ( replaceThis->parent != this ) ++ return 0; ++ ++ TiXmlNode* node = withThis.Clone(); ++ if ( !node ) ++ return 0; ++ ++ node->next = replaceThis->next; ++ node->prev = replaceThis->prev; ++ ++ if ( replaceThis->next ) ++ replaceThis->next->prev = node; ++ else ++ lastChild = node; ++ ++ if ( replaceThis->prev ) ++ replaceThis->prev->next = node; ++ else ++ firstChild = node; ++ ++ delete replaceThis; ++ node->parent = this; ++ return node; ++} ++ ++ ++bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) ++{ ++ if ( removeThis->parent != this ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ if ( removeThis->next ) ++ removeThis->next->prev = removeThis->prev; ++ else ++ lastChild = removeThis->prev; ++ ++ if ( removeThis->prev ) ++ removeThis->prev->next = removeThis->next; ++ else ++ firstChild = removeThis->next; ++ ++ delete removeThis; ++ return true; ++} ++ ++TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = firstChild; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING( _value )) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::LastChild( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = lastChild; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild(); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling(); ++ } ++} ++ ++TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous ) const ++{ ++ if ( !previous ) ++ { ++ return FirstChild( val ); ++ } ++ else ++ { ++ assert( previous->parent == this ); ++ return previous->NextSibling( val ); ++ } ++} ++ ++TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = next; node; node = node->next ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++ ++TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const ++{ ++ TiXmlNode* node; ++ for ( node = prev; node; node = node->prev ) ++ { ++ if ( node->SValue() == TIXML_STRING (_value)) ++ return node; ++ } ++ return 0; ++} ++ ++void TiXmlElement::RemoveAttribute( const char * name ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = FirstChild( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement* TiXmlNode::NextSiblingElement() const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling(); ++ node; ++ node = node->NextSibling() ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const ++{ ++ TiXmlNode* node; ++ ++ for ( node = NextSibling( _value ); ++ node; ++ node = node->NextSibling( _value ) ) ++ { ++ if ( node->ToElement() ) ++ return node->ToElement(); ++ } ++ return 0; ++} ++ ++ ++ ++TiXmlDocument* TiXmlNode::GetDocument() const ++{ ++ const TiXmlNode* node; ++ ++ for( node = this; node; node = node->parent ) ++ { ++ if ( node->ToDocument() ) ++ return node->ToDocument(); ++ } ++ return 0; ++} ++ ++ ++TiXmlElement::TiXmlElement (const char * _value) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlElement::TiXmlElement( const std::string& _value ) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ value = _value; ++} ++#endif ++ ++ ++TiXmlElement::TiXmlElement( const TiXmlElement& copy) ++ : TiXmlNode( TiXmlNode::ELEMENT ) ++{ ++ firstChild = lastChild = 0; ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlElement::operator=( const TiXmlElement& base ) ++{ ++ ClearThis(); ++ base.CopyTo( this ); ++} ++ ++ ++TiXmlElement::~TiXmlElement() ++{ ++ ClearThis(); ++} ++ ++ ++void TiXmlElement::ClearThis() ++{ ++ Clear(); ++ while( attributeSet.First() ) ++ { ++ TiXmlAttribute* node = attributeSet.First(); ++ attributeSet.Remove( node ); ++ delete node; ++ } ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ ++ if ( node ) ++ return node->Value(); ++ ++ return 0; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, int* i ) const ++{ ++ const char * s = Attribute( name ); ++ if ( i ) ++ { ++ if ( s ) ++ *i = atoi( s ); ++ else ++ *i = 0; ++ } ++ return s; ++} ++ ++ ++const char * TiXmlElement::Attribute( const char * name, double* d ) const ++{ ++ const char * s = Attribute( name ); ++ if ( d ) ++ { ++ if ( s ) ++ *d = atof( s ); ++ else ++ *d = 0; ++ } ++ return s; ++} ++ ++ ++int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryIntValue( ival ); ++} ++ ++ ++int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( !node ) ++ return TIXML_NO_ATTRIBUTE; ++ ++ return node->QueryDoubleValue( dval ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, int val ) ++{ ++ char buf[64]; ++ sprintf( buf, "%d", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetDoubleAttribute( const char * name, double val ) ++{ ++ char buf[128]; ++ sprintf( buf, "%f", val ); ++ SetAttribute( name, buf ); ++} ++ ++ ++void TiXmlElement::SetAttribute( const char * name, const char * _value ) ++{ ++ TiXmlAttribute* node = attributeSet.Find( name ); ++ if ( node ) ++ { ++ node->SetValue( _value ); ++ return; ++ } ++ ++ TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); ++ if ( attrib ) ++ { ++ attributeSet.Add( attrib ); ++ } ++ else ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++} ++ ++void TiXmlElement::Print( FILE* cfile, int depth ) const ++{ ++ int i; ++ for ( i=0; i<depth; i++ ) ++ { ++ fprintf( cfile, " " ); ++ } ++ ++ fprintf( cfile, "<%s", value.c_str() ); ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ fprintf( cfile, " " ); ++ attrib->Print( cfile, depth ); ++ } ++ ++ // There are 3 different formatting approaches: ++ // 1) An element without children is printed as a <foo /> node ++ // 2) An element with only a text child is printed as <foo> text </foo> ++ // 3) An element with children is printed on multiple lines. ++ TiXmlNode* node; ++ if ( !firstChild ) ++ { ++ fprintf( cfile, " />" ); ++ } ++ else if ( firstChild == lastChild && firstChild->ToText() ) ++ { ++ fprintf( cfile, ">" ); ++ firstChild->Print( cfile, depth + 1 ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++ else ++ { ++ fprintf( cfile, ">" ); ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ if ( !node->ToText() ) ++ { ++ fprintf( cfile, "\n" ); ++ } ++ node->Print( cfile, depth+1 ); ++ } ++ fprintf( cfile, "\n" ); ++ for( i=0; i<depth; ++i ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "</%s>", value.c_str() ); ++ } ++} ++ ++void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value; ++ ++ TiXmlAttribute* attrib; ++ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) ++ { ++ (*stream) << " "; ++ attrib->StreamOut( stream ); ++ } ++ ++ // If this node has children, give it a closing tag. Else ++ // make it an empty tag. ++ TiXmlNode* node; ++ if ( firstChild ) ++ { ++ (*stream) << ">"; ++ ++ for ( node = firstChild; node; node=node->NextSibling() ) ++ { ++ node->StreamOut( stream ); ++ } ++ (*stream) << "</" << value << ">"; ++ } ++ else ++ { ++ (*stream) << " />"; ++ } ++} ++ ++ ++void TiXmlElement::CopyTo( TiXmlElement* target ) const ++{ ++ // superclass: ++ TiXmlNode::CopyTo( target ); ++ ++ // Element class: ++ // Clone the attributes, then clone the children. ++ TiXmlAttribute* attribute = 0; ++ for( attribute = attributeSet.First(); ++ attribute; ++ attribute = attribute->Next() ) ++ { ++ target->SetAttribute( attribute->Name(), attribute->Value() ); ++ } ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlElement::Clone() const ++{ ++ TiXmlElement* clone = new TiXmlElement( Value() ); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ ClearError(); ++} ++ ++TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ tabsize = 4; ++ value = documentName; ++ ClearError(); ++} ++#endif ++ ++ ++TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDocument::operator=( const TiXmlDocument& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && LoadFile( buf.buffer, encoding ) ) ++ return true; ++ ++ return false; ++} ++ ++ ++bool TiXmlDocument::SaveFile() const ++{ ++ // See STL_STRING_BUG below. ++ StringToBuffer buf( value ); ++ ++ if ( buf.buffer && SaveFile( buf.buffer ) ) ++ return true; ++ ++ return false; ++} ++ ++bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding ) ++{ ++ // Delete the existing data: ++ Clear(); ++ location.Clear(); ++ ++ // There was a really terrifying little bug here. The code: ++ // value = filename ++ // in the STL case, cause the assignment method of the std::string to ++ // be called. What is strange, is that the std::string had the same ++ // address as it's c_str() method, and so bad things happen. Looks ++ // like a bug in the Microsoft STL implementation. ++ // See STL_STRING_BUG above. ++ // Fixed with the StringToBuffer class. ++ value = filename; ++ ++ FILE* file = fopen( value.c_str (), "r" ); ++ ++ if ( file ) ++ { ++ // Get the file size, so we can pre-allocate the string. HUGE speed impact. ++ long length = 0; ++ fseek( file, 0, SEEK_END ); ++ length = ftell( file ); ++ fseek( file, 0, SEEK_SET ); ++ ++ // Strange case, but good to handle up front. ++ if ( length == 0 ) ++ { ++ fclose( file ); ++ return false; ++ } ++ ++ // If we have a file, assume it is all one big XML file, and read it in. ++ // The document parser may decide the document ends sooner than the entire file, however. ++ TIXML_STRING data; ++ data.reserve( length ); ++ ++ const int BUF_SIZE = 2048; ++ char buf[BUF_SIZE]; ++ ++ while( fgets( buf, BUF_SIZE, file ) ) ++ { ++ data += buf; ++ } ++ fclose( file ); ++ ++ Parse( data.c_str(), 0, encoding ); ++ ++ if ( Error() ) ++ return false; ++ else ++ return true; ++ } ++ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return false; ++} ++ ++bool TiXmlDocument::SaveFile( const char * filename ) const ++{ ++ // The old c stuff lives on... ++ FILE* fp = fopen( filename, "w" ); ++ if ( fp ) ++ { ++ Print( fp, 0 ); ++ fclose( fp ); ++ return true; ++ } ++ return false; ++} ++ ++ ++void TiXmlDocument::CopyTo( TiXmlDocument* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->error = error; ++ target->errorDesc = errorDesc.c_str (); ++ ++ TiXmlNode* node = 0; ++ for ( node = firstChild; node; node = node->NextSibling() ) ++ { ++ target->LinkEndChild( node->Clone() ); ++ } ++} ++ ++ ++TiXmlNode* TiXmlDocument::Clone() const ++{ ++ TiXmlDocument* clone = new TiXmlDocument(); ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlDocument::Print( FILE* cfile, int depth ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->Print( cfile, depth ); ++ fprintf( cfile, "\n" ); ++ } ++} ++ ++void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const ++{ ++ TiXmlNode* node; ++ for ( node=FirstChild(); node; node=node->NextSibling() ) ++ { ++ node->StreamOut( out ); ++ ++ // Special rule for streams: stop after the root element. ++ // The stream in code will only read one element, so don't ++ // write more than one. ++ if ( node->ToElement() ) ++ break; ++ } ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Next() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( next->value.empty() && next->name.empty() ) ++ return 0; ++ return next; ++} ++ ++ ++TiXmlAttribute* TiXmlAttribute::Previous() const ++{ ++ // We are using knowledge of the sentinel. The sentinel ++ // have a value or name. ++ if ( prev->value.empty() && prev->name.empty() ) ++ return 0; ++ return prev; ++} ++ ++ ++void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING n, v; ++ ++ PutString( name, &n ); ++ PutString( value, &v ); ++ ++ if (value.find ('\"') == TIXML_STRING::npos) ++ fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); ++ else ++ fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); ++} ++ ++ ++void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ if (value.find( '\"' ) != TIXML_STRING::npos) ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "'"; ++ PutString( value, stream ); ++ (*stream) << "'"; ++ } ++ else ++ { ++ PutString( name, stream ); ++ (*stream) << "=" << "\""; ++ PutString( value, stream ); ++ (*stream) << "\""; ++ } ++} ++ ++int TiXmlAttribute::QueryIntValue( int* ival ) const ++{ ++ if ( sscanf( value.c_str(), "%d", ival ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++int TiXmlAttribute::QueryDoubleValue( double* dval ) const ++{ ++ if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) ++ return TIXML_SUCCESS; ++ return TIXML_WRONG_TYPE; ++} ++ ++void TiXmlAttribute::SetIntValue( int _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%d", _value); ++ SetValue (buf); ++} ++ ++void TiXmlAttribute::SetDoubleValue( double _value ) ++{ ++ char buf [64]; ++ sprintf (buf, "%lf", _value); ++ SetValue (buf); ++} ++ ++const int TiXmlAttribute::IntValue() const ++{ ++ return atoi (value.c_str ()); ++} ++ ++const double TiXmlAttribute::DoubleValue() const ++{ ++ return atof (value.c_str ()); ++} ++ ++ ++TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::operator=( const TiXmlComment& base ) ++{ ++ Clear(); ++ base.CopyTo( this ); ++} ++ ++ ++void TiXmlComment::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ { ++ fputs( " ", cfile ); ++ } ++ fprintf( cfile, "<!--%s-->", value.c_str() ); ++} ++ ++void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<!--"; ++ //PutString( value, stream ); ++ (*stream) << value; ++ (*stream) << "-->"; ++} ++ ++ ++void TiXmlComment::CopyTo( TiXmlComment* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlComment::Clone() const ++{ ++ TiXmlComment* clone = new TiXmlComment(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ TIXML_STRING buffer; ++ PutString( value, &buffer ); ++ fprintf( cfile, "%s", buffer.c_str() ); ++} ++ ++ ++void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ PutString( value, stream ); ++} ++ ++ ++void TiXmlText::CopyTo( TiXmlText* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlText::Clone() const ++{ ++ TiXmlText* clone = 0; ++ clone = new TiXmlText( "" ); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const char * _version, ++ const char * _encoding, ++ const char * _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ version = _version; ++ encoding = _encoding; ++ standalone = _standalone; ++} ++#endif ++ ++ ++TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) ++ : TiXmlNode( TiXmlNode::DECLARATION ) ++{ ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) ++{ ++ Clear(); ++ copy.CopyTo( this ); ++} ++ ++ ++void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const ++{ ++ fprintf (cfile, "<?xml "); ++ ++ if ( !version.empty() ) ++ fprintf (cfile, "version=\"%s\" ", version.c_str ()); ++ if ( !encoding.empty() ) ++ fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); ++ if ( !standalone.empty() ) ++ fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); ++ fprintf (cfile, "?>"); ++} ++ ++void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<?xml "; ++ ++ if ( !version.empty() ) ++ { ++ (*stream) << "version=\""; ++ PutString( version, stream ); ++ (*stream) << "\" "; ++ } ++ if ( !encoding.empty() ) ++ { ++ (*stream) << "encoding=\""; ++ PutString( encoding, stream ); ++ (*stream ) << "\" "; ++ } ++ if ( !standalone.empty() ) ++ { ++ (*stream) << "standalone=\""; ++ PutString( standalone, stream ); ++ (*stream) << "\" "; ++ } ++ (*stream) << "?>"; ++} ++ ++ ++void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++ ++ target->version = version; ++ target->encoding = encoding; ++ target->standalone = standalone; ++} ++ ++ ++TiXmlNode* TiXmlDeclaration::Clone() const ++{ ++ TiXmlDeclaration* clone = new TiXmlDeclaration(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++void TiXmlUnknown::Print( FILE* cfile, int depth ) const ++{ ++ for ( int i=0; i<depth; i++ ) ++ fprintf( cfile, " " ); ++ fprintf( cfile, "<%s>", value.c_str() ); ++} ++ ++ ++void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const ++{ ++ (*stream) << "<" << value << ">"; // Don't use entities here! It is unknown. ++} ++ ++ ++void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const ++{ ++ TiXmlNode::CopyTo( target ); ++} ++ ++ ++TiXmlNode* TiXmlUnknown::Clone() const ++{ ++ TiXmlUnknown* clone = new TiXmlUnknown(); ++ ++ if ( !clone ) ++ return 0; ++ ++ CopyTo( clone ); ++ return clone; ++} ++ ++ ++TiXmlAttributeSet::TiXmlAttributeSet() ++{ ++ sentinel.next = &sentinel; ++ sentinel.prev = &sentinel; ++} ++ ++ ++TiXmlAttributeSet::~TiXmlAttributeSet() ++{ ++ assert( sentinel.next == &sentinel ); ++ assert( sentinel.prev == &sentinel ); ++} ++ ++ ++void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) ++{ ++ assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. ++ ++ addMe->next = &sentinel; ++ addMe->prev = sentinel.prev; ++ ++ sentinel.prev->next = addMe; ++ sentinel.prev = addMe; ++} ++ ++void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node == removeMe ) ++ { ++ node->prev->next = node->next; ++ node->next->prev = node->prev; ++ node->next = 0; ++ node->prev = 0; ++ return; ++ } ++ } ++ assert( 0 ); // we tried to remove a non-linked attribute. ++} ++ ++TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const ++{ ++ TiXmlAttribute* node; ++ ++ for( node = sentinel.next; node != &sentinel; node = node->next ) ++ { ++ if ( node->name == name ) ++ return node; ++ } ++ return 0; ++} ++ ++ ++#ifdef TIXML_USE_STL ++TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base) ++{ ++ TIXML_STRING tag; ++ tag.reserve( 8 * 1000 ); ++ base.StreamIn( &in, &tag ); ++ ++ base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); ++ return in; ++} ++#endif ++ ++ ++TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base) ++{ ++ base.StreamOut (& out); ++ return out; ++} ++ ++ ++#ifdef TIXML_USE_STL ++std::string & operator<< (std::string& out, const TiXmlNode& base ) ++{ ++ std::ostringstream os_stream( std::ostringstream::out ); ++ base.StreamOut( &os_stream ); ++ ++ out.append( os_stream.str() ); ++ return out; ++} ++#endif ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild() const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlNode* child = node->FirstChild( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement() const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement(); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const ++{ ++ if ( node ) ++ { ++ TiXmlElement* child = node->FirstChildElement( value ); ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlNode* child = node->FirstChild( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSibling( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement(); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement(), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++ ++ ++TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const ++{ ++ if ( node ) ++ { ++ int i; ++ TiXmlElement* child = node->FirstChildElement( value ); ++ for ( i=0; ++ child && i<count; ++ child = child->NextSiblingElement( value ), ++i ) ++ { ++ // nothing ++ } ++ if ( child ) ++ return TiXmlHandle( child ); ++ } ++ return TiXmlHandle( 0 ); ++} ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/tinyxmlerror.c vdr-1.7.5-extensions/tinyxmlerror.c +--- vdr-1.7.5/tinyxmlerror.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/tinyxmlerror.c 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,53 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++ ++// The goal of the seperate error file is to make the first ++// step towards localization. tinyxml (currently) only supports ++// latin-1, but at least the error messages could now be translated. ++// ++// It also cleans up the code a bit. ++// ++ ++const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = ++{ ++ "No error", ++ "Error", ++ "Failed to open file", ++ "Memory allocation failed.", ++ "Error parsing Element.", ++ "Failed to read Element name", ++ "Error reading Element value.", ++ "Error reading Attributes.", ++ "Error: empty tag.", ++ "Error reading end tag.", ++ "Error parsing Unknown.", ++ "Error parsing Comment.", ++ "Error parsing Declaration.", ++ "Error document empty.", ++ "Error null (0) or unexpected EOF found in input stream.", ++}; ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/tinyxml.h vdr-1.7.5-extensions/tinyxml.h +--- vdr-1.7.5/tinyxml.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/tinyxml.h 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,1372 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++ ++#ifndef TINYXML_INCLUDED ++#define TINYXML_INCLUDED ++ ++#ifdef _MSC_VER ++#pragma warning( disable : 4530 ) ++#pragma warning( disable : 4786 ) ++#endif ++ ++#include <ctype.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <assert.h> ++ ++// Help out windows: ++#if defined( _DEBUG ) && !defined( DEBUG ) ++#define DEBUG ++#endif ++ ++#if defined( DEBUG ) && defined( _MSC_VER ) ++#include <windows.h> ++#define TIXML_LOG OutputDebugString ++#else ++#define TIXML_LOG printf ++#endif ++ ++#ifdef TIXML_USE_STL ++ #include <string> ++ #include <iostream> ++ #define TIXML_STRING std::string ++ #define TIXML_ISTREAM std::istream ++ #define TIXML_OSTREAM std::ostream ++#else ++ #include "tinystr.h" ++ #define TIXML_STRING TiXmlString ++ #define TIXML_OSTREAM TiXmlOutStream ++#endif ++ ++class TiXmlDocument; ++class TiXmlElement; ++class TiXmlComment; ++class TiXmlUnknown; ++class TiXmlAttribute; ++class TiXmlText; ++class TiXmlDeclaration; ++class TiXmlParsingData; ++ ++const int TIXML_MAJOR_VERSION = 2; ++const int TIXML_MINOR_VERSION = 3; ++const int TIXML_PATCH_VERSION = 2; ++ ++/* Internal structure for tracking location of items ++ in the XML file. ++*/ ++struct TiXmlCursor ++{ ++ TiXmlCursor() { Clear(); } ++ void Clear() { row = col = -1; } ++ ++ int row; // 0 based. ++ int col; // 0 based. ++}; ++ ++ ++// Only used by Attribute::Query functions ++enum ++{ ++ TIXML_SUCCESS, ++ TIXML_NO_ATTRIBUTE, ++ TIXML_WRONG_TYPE ++}; ++ ++ ++// Used by the parsing routines. ++enum TiXmlEncoding ++{ ++ TIXML_ENCODING_UNKNOWN, ++ TIXML_ENCODING_UTF8, ++ TIXML_ENCODING_LEGACY ++}; ++ ++const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; ++ ++/** TiXmlBase is a base class for every class in TinyXml. ++ It does little except to establish that TinyXml classes ++ can be printed and provide some utility functions. ++ ++ In XML, the document and elements can contain ++ other elements and other types of nodes. ++ ++ @verbatim ++ A Document can contain: Element (container or leaf) ++ Comment (leaf) ++ Unknown (leaf) ++ Declaration( leaf ) ++ ++ An Element can contain: Element (container or leaf) ++ Text (leaf) ++ Attributes (not on tree) ++ Comment (leaf) ++ Unknown (leaf) ++ ++ A Decleration contains: Attributes (not on tree) ++ @endverbatim ++*/ ++class TiXmlBase ++{ ++ friend class TiXmlNode; ++ friend class TiXmlElement; ++ friend class TiXmlDocument; ++ ++public: ++ TiXmlBase() : userData(0) {} ++ virtual ~TiXmlBase() {} ++ ++ /** All TinyXml classes can print themselves to a filestream. ++ This is a formatted print, and will insert tabs and newlines. ++ ++ (For an unformatted stream, use the << operator.) ++ */ ++ virtual void Print( FILE* cfile, int depth ) const = 0; ++ ++ /** The world does not agree on whether white space should be kept or ++ not. In order to make everyone happy, these global, static functions ++ are provided to set whether or not TinyXml will condense all white space ++ into a single space or not. The default is to condense. Note changing this ++ values is not thread safe. ++ */ ++ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } ++ ++ /// Return the current white space setting. ++ static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } ++ ++ /** Return the position, in the original source file, of this node or attribute. ++ The row and column are 1-based. (That is the first row and first column is ++ 1,1). If the returns values are 0 or less, then the parser does not have ++ a row and column value. ++ ++ Generally, the row and column value will be set when the TiXmlDocument::Load(), ++ TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set ++ when the DOM was created from operator>>. ++ ++ The values reflect the initial load. Once the DOM is modified programmatically ++ (by adding or changing nodes and attributes) the new values will NOT update to ++ reflect changes in the document. ++ ++ There is a minor performance cost to computing the row and column. Computation ++ can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. ++ ++ @sa TiXmlDocument::SetTabSize() ++ */ ++ int Row() const { return location.row + 1; } ++ int Column() const { return location.col + 1; } ///< See Row() ++ ++ void SetUserData( void* user ) { userData = user; } ++ void* GetUserData() { return userData; } ++ ++ // Table that returs, for a given lead byte, the total number of bytes ++ // in the UTF-8 sequence. ++ static const int utf8ByteTable[256]; ++ ++ virtual const char* Parse( const char* p, ++ TiXmlParsingData* data, ++ TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; ++ ++protected: ++ ++ // See STL_STRING_BUG ++ // Utility class to overcome a bug. ++ class StringToBuffer ++ { ++ public: ++ StringToBuffer( const TIXML_STRING& str ); ++ ~StringToBuffer(); ++ char* buffer; ++ }; ++ ++ static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); ++ inline static bool IsWhiteSpace( char c ) ++ { ++ return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); ++ } ++ ++ virtual void StreamOut (TIXML_OSTREAM *) const = 0; ++ ++ #ifdef TIXML_USE_STL ++ static bool StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ static bool StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ); ++ #endif ++ ++ /* Reads an XML name into the string provided. Returns ++ a pointer just past the last character of the name, ++ or 0 if the function has an error. ++ */ ++ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); ++ ++ /* Reads text. Returns a pointer past the given end tag. ++ Wickedly complex options, but it keeps the (sensitive) code in one place. ++ */ ++ static const char* ReadText( const char* in, // where to start ++ TIXML_STRING* text, // the string read ++ bool ignoreWhiteSpace, // whether to keep the white space ++ const char* endTag, // what ends this text ++ bool ignoreCase, // whether to ignore case in the end tag ++ TiXmlEncoding encoding ); // the current encoding ++ ++ // If an entity has been found, transform it into a character. ++ static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); ++ ++ // Get a character, while interpreting entities. ++ // The length can be from 0 to 4 bytes. ++ inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) ++ { ++ assert( p ); ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ *length = utf8ByteTable[ *((unsigned char*)p) ]; ++ assert( *length >= 0 && *length < 5 ); ++ } ++ else ++ { ++ *length = 1; ++ } ++ ++ if ( *length == 1 ) ++ { ++ if ( *p == '&' ) ++ return GetEntity( p, _value, length, encoding ); ++ *_value = *p; ++ return p+1; ++ } ++ else if ( *length ) ++ { ++ strncpy( _value, p, *length ); ++ return p + (*length); ++ } ++ else ++ { ++ // Not valid text. ++ return 0; ++ } ++ } ++ ++ // Puts a string to a stream, expanding entities as it goes. ++ // Note this should not contian the '<', '>', etc, or they will be transformed into entities! ++ static void PutString( const TIXML_STRING& str, TIXML_OSTREAM* out ); ++ ++ static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); ++ ++ // Return true if the next characters in the stream are any of the endTag sequences. ++ // Ignore case only works for english, and should only be relied on when comparing ++ // to Engilish words: StringEqual( p, "version", true ) is fine. ++ static bool StringEqual( const char* p, ++ const char* endTag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ); ++ ++ ++ enum ++ { ++ TIXML_NO_ERROR = 0, ++ TIXML_ERROR, ++ TIXML_ERROR_OPENING_FILE, ++ TIXML_ERROR_OUT_OF_MEMORY, ++ TIXML_ERROR_PARSING_ELEMENT, ++ TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, ++ TIXML_ERROR_READING_ELEMENT_VALUE, ++ TIXML_ERROR_READING_ATTRIBUTES, ++ TIXML_ERROR_PARSING_EMPTY, ++ TIXML_ERROR_READING_END_TAG, ++ TIXML_ERROR_PARSING_UNKNOWN, ++ TIXML_ERROR_PARSING_COMMENT, ++ TIXML_ERROR_PARSING_DECLARATION, ++ TIXML_ERROR_DOCUMENT_EMPTY, ++ TIXML_ERROR_EMBEDDED_NULL, ++ ++ TIXML_ERROR_STRING_COUNT ++ }; ++ static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; ++ ++ TiXmlCursor location; ++ ++ /// Field containing a generic user pointer ++ void* userData; ++ ++ // None of these methods are reliable for any language except English. ++ // Good for approximation, not great for accuracy. ++ static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); ++ static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); ++ inline static int ToLower( int v, TiXmlEncoding encoding ) ++ { ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( v < 128 ) return tolower( v ); ++ return v; ++ } ++ else ++ { ++ return tolower( v ); ++ } ++ } ++ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); ++ ++private: ++ TiXmlBase( const TiXmlBase& ); // not implemented. ++ void operator=( const TiXmlBase& base ); // not allowed. ++ ++ struct Entity ++ { ++ const char* str; ++ unsigned int strLength; ++ char chr; ++ }; ++ enum ++ { ++ NUM_ENTITY = 5, ++ MAX_ENTITY_LENGTH = 6 ++ ++ }; ++ static Entity entity[ NUM_ENTITY ]; ++ static bool condenseWhiteSpace; ++}; ++ ++ ++/** The parent class for everything in the Document Object Model. ++ (Except for attributes). ++ Nodes have siblings, a parent, and children. A node can be ++ in a document, or stand on its own. The type of a TiXmlNode ++ can be queried, and it can be cast to its more defined type. ++*/ ++class TiXmlNode : public TiXmlBase ++{ ++ friend class TiXmlDocument; ++ friend class TiXmlElement; ++ ++public: ++ #ifdef TIXML_USE_STL ++ ++ /** An input stream operator, for every class. Tolerant of newlines and ++ formatting, but doesn't expect them. ++ */ ++ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); ++ ++ /** An output stream operator, for every class. Note that this outputs ++ without any newlines or formatting, as opposed to Print(), which ++ includes tabs and new lines. ++ ++ The operator<< and operator>> are not completely symmetric. Writing ++ a node to a stream is very well defined. You'll get a nice stream ++ of output, without any extra whitespace or newlines. ++ ++ But reading is not as well defined. (As it always is.) If you create ++ a TiXmlElement (for example) and read that from an input stream, ++ the text needs to define an element or junk will result. This is ++ true of all input streams, but it's worth keeping in mind. ++ ++ A TiXmlDocument will read nodes until it reads a root element, and ++ all the children of that root element. ++ */ ++ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); ++ ++ /// Appends the XML node or attribute to a std::string. ++ friend std::string& operator<< (std::string& out, const TiXmlNode& base ); ++ ++ #else ++ // Used internally, not part of the public API. ++ friend TIXML_OSTREAM& operator<< (TIXML_OSTREAM& out, const TiXmlNode& base); ++ #endif ++ ++ /** The types of XML nodes supported by TinyXml. (All the ++ unsupported types are picked up by UNKNOWN.) ++ */ ++ enum NodeType ++ { ++ DOCUMENT, ++ ELEMENT, ++ COMMENT, ++ UNKNOWN, ++ TEXT, ++ DECLARATION, ++ TYPECOUNT ++ }; ++ ++ virtual ~TiXmlNode(); ++ ++ /** The meaning of 'value' changes for the specific type of ++ TiXmlNode. ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ ++ The subclasses will wrap this function. ++ */ ++ const char * Value() const { return value.c_str (); } ++ ++ /** Changes the value of the node. Defined as: ++ @verbatim ++ Document: filename of the xml file ++ Element: name of the element ++ Comment: the comment text ++ Unknown: the tag contents ++ Text: the text string ++ @endverbatim ++ */ ++ void SetValue(const char * _value) { value = _value;} ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "" ); ++ } ++ #endif ++ ++ /// Delete all the children of this node. Does not affect 'this'. ++ void Clear(); ++ ++ /// One step up the DOM. ++ TiXmlNode* Parent() const { return parent; } ++ ++ TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. ++ TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. ++ ++ TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. ++ TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** An alternate way to walk the children of a node. ++ One way to iterate over nodes is: ++ @verbatim ++ for( child = parent->FirstChild(); child; child = child->NextSibling() ) ++ @endverbatim ++ ++ IterateChildren does the same thing with the syntax: ++ @verbatim ++ child = 0; ++ while( child = parent->IterateChildren( child ) ) ++ @endverbatim ++ ++ IterateChildren takes the previous child as input and finds ++ the next one. If the previous child is null, it returns the ++ first. IterateChildren will return null when done. ++ */ ++ TiXmlNode* IterateChildren( TiXmlNode* previous ) const; ++ ++ /// This flavor of IterateChildren searches for children with a particular 'value' ++ TiXmlNode* IterateChildren( const char * value, TiXmlNode* previous ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* IterateChildren( const std::string& _value, TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. ++ #endif ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); ++ ++ ++ /** Add a new node related to this. Adds a child past the LastChild. ++ ++ NOTE: the node to be added is passed by pointer, and will be ++ henceforth owned (and deleted) by tinyXml. This method is efficient ++ and avoids an extra copy, but should be used with care as it ++ uses a different memory model than the other insert functions. ++ ++ @sa InsertEndChild ++ */ ++ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); ++ ++ /** Add a new node related to this. Adds a child before the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); ++ ++ /** Add a new node related to this. Adds a child after the specified child. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); ++ ++ /** Replace a child of this node. ++ Returns a pointer to the new object or NULL if an error occured. ++ */ ++ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); ++ ++ /// Delete a child of this node. ++ bool RemoveChild( TiXmlNode* removeThis ); ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling() const { return prev; } ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* PreviousSibling( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. ++ TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Navigate to a sibling node. ++ TiXmlNode* NextSibling() const { return next; } ++ ++ /// Navigate to a sibling node with the given 'value'. ++ TiXmlNode* NextSibling( const char * ) const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement() const; ++ ++ /** Convenience function to get through elements. ++ Calls NextSibling and ToElement. Will skip all non-Element ++ nodes. Returns 0 if there is not another element. ++ */ ++ TiXmlElement* NextSiblingElement( const char * ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement() const; ++ ++ /// Convenience function to get through elements. ++ TiXmlElement* FirstChildElement( const char * value ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ /** Query the type (as an enumerated value, above) of this node. ++ The possible types are: DOCUMENT, ELEMENT, COMMENT, ++ UNKNOWN, TEXT, and DECLARATION. ++ */ ++ virtual int Type() const { return type; } ++ ++ /** Return a pointer to the Document this node lives in. ++ Returns null if not in a document. ++ */ ++ TiXmlDocument* GetDocument() const; ++ ++ /// Returns true if this node has no children. ++ bool NoChildren() const { return !firstChild; } ++ ++ TiXmlDocument* ToDocument() const { return ( this && type == DOCUMENT ) ? (TiXmlDocument*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlElement* ToElement() const { return ( this && type == ELEMENT ) ? (TiXmlElement*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlComment* ToComment() const { return ( this && type == COMMENT ) ? (TiXmlComment*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlUnknown* ToUnknown() const { return ( this && type == UNKNOWN ) ? (TiXmlUnknown*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlText* ToText() const { return ( this && type == TEXT ) ? (TiXmlText*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ TiXmlDeclaration* ToDeclaration() const { return ( this && type == DECLARATION ) ? (TiXmlDeclaration*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ++ ++ /** Create an exact duplicate of this node and return it. The memory must be deleted ++ by the caller. ++ */ ++ virtual TiXmlNode* Clone() const = 0; ++ ++protected: ++ TiXmlNode( NodeType _type ); ++ ++ // Copy to the allocated object. Shared functionality between Clone, Copy constructor, ++ // and the assignment operator. ++ void CopyTo( TiXmlNode* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ // The real work of the input operator. ++ virtual void StreamIn( TIXML_ISTREAM* in, TIXML_STRING* tag ) = 0; ++ #endif ++ ++ // Figure out what is at *p, and parse it. Returns null if it is not an xml node. ++ TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); ++ ++ // Internal Value function returning a TIXML_STRING ++ const TIXML_STRING& SValue() const { return value ; } ++ ++ TiXmlNode* parent; ++ NodeType type; ++ ++ TiXmlNode* firstChild; ++ TiXmlNode* lastChild; ++ ++ TIXML_STRING value; ++ ++ TiXmlNode* prev; ++ TiXmlNode* next; ++ ++private: ++ TiXmlNode( const TiXmlNode& ); // not implemented. ++ void operator=( const TiXmlNode& base ); // not allowed. ++}; ++ ++ ++/** An attribute is a name-value pair. Elements have an arbitrary ++ number of attributes, each with a unique name. ++ ++ @note The attributes are not TiXmlNodes, since they are not ++ part of the tinyXML document object model. There are other ++ suggested ways to look at this problem. ++*/ ++class TiXmlAttribute : public TiXmlBase ++{ ++ friend class TiXmlAttributeSet; ++ ++public: ++ /// Construct an empty attribute. ++ TiXmlAttribute() : TiXmlBase() ++ { ++ document = 0; ++ prev = next = 0; ++ } ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlAttribute( const std::string& _name, const std::string& _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ #endif ++ ++ /// Construct an attribute with a name and value. ++ TiXmlAttribute( const char * _name, const char * _value ) ++ { ++ name = _name; ++ value = _value; ++ document = 0; ++ prev = next = 0; ++ } ++ ++ const char* Name() const { return name.c_str (); } ///< Return the name of this attribute. ++ const char* Value() const { return value.c_str (); } ///< Return the value of this attribute. ++ const int IntValue() const; ///< Return the value of this attribute, converted to an integer. ++ const double DoubleValue() const; ///< Return the value of this attribute, converted to a double. ++ ++ /** QueryIntValue examines the value string. It is an alternative to the ++ IntValue() method with richer error checking. ++ If the value is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. ++ ++ A specialized but useful call. Note that for success it returns 0, ++ which is the opposite of almost all other TinyXml calls. ++ */ ++ int QueryIntValue( int* value ) const; ++ /// QueryDoubleValue examines the value string. See QueryIntValue(). ++ int QueryDoubleValue( double* value ) const; ++ ++ void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. ++ void SetValue( const char* _value ) { value = _value; } ///< Set the value. ++ ++ void SetIntValue( int value ); ///< Set the value from an integer. ++ void SetDoubleValue( double value ); ///< Set the value from a double. ++ ++ #ifdef TIXML_USE_STL ++ /// STL std::string form. ++ void SetName( const std::string& _name ) ++ { ++ StringToBuffer buf( _name ); ++ SetName ( buf.buffer ? buf.buffer : "error" ); ++ } ++ /// STL std::string form. ++ void SetValue( const std::string& _value ) ++ { ++ StringToBuffer buf( _value ); ++ SetValue( buf.buffer ? buf.buffer : "error" ); ++ } ++ #endif ++ ++ /// Get the next sibling attribute in the DOM. Returns null at end. ++ TiXmlAttribute* Next() const; ++ /// Get the previous sibling attribute in the DOM. Returns null at beginning. ++ TiXmlAttribute* Previous() const; ++ ++ bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } ++ bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } ++ bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } ++ ++ /* Attribute parsing starts: first letter of the name ++ returns: the next char after the value end quote ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++ // Prints this Attribute to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ // [internal use] ++ // Set the document pointer so the attribute can report errors. ++ void SetDocument( TiXmlDocument* doc ) { document = doc; } ++ ++private: ++ TiXmlAttribute( const TiXmlAttribute& ); // not implemented. ++ void operator=( const TiXmlAttribute& base ); // not allowed. ++ ++ TiXmlDocument* document; // A pointer back to a document, for error reporting. ++ TIXML_STRING name; ++ TIXML_STRING value; ++ TiXmlAttribute* prev; ++ TiXmlAttribute* next; ++}; ++ ++ ++/* A class used to manage a group of attributes. ++ It is only used internally, both by the ELEMENT and the DECLARATION. ++ ++ The set can be changed transparent to the Element and Declaration ++ classes that use it, but NOT transparent to the Attribute ++ which has to implement a next() and previous() method. Which makes ++ it a bit problematic and prevents the use of STL. ++ ++ This version is implemented with circular lists because: ++ - I like circular lists ++ - it demonstrates some independence from the (typical) doubly linked list. ++*/ ++class TiXmlAttributeSet ++{ ++public: ++ TiXmlAttributeSet(); ++ ~TiXmlAttributeSet(); ++ ++ void Add( TiXmlAttribute* attribute ); ++ void Remove( TiXmlAttribute* attribute ); ++ ++ TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } ++ TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } ++ TiXmlAttribute* Find( const char * name ) const; ++ ++private: ++ TiXmlAttribute sentinel; ++}; ++ ++ ++/** The element is a container class. It has a value, the element name, ++ and can contain other elements, text, comments, and unknowns. ++ Elements also contain an arbitrary number of attributes. ++*/ ++class TiXmlElement : public TiXmlNode ++{ ++public: ++ /// Construct an element. ++ TiXmlElement (const char * in_value); ++ ++ #ifdef TIXML_USE_STL ++ /// std::string constructor. ++ TiXmlElement( const std::string& _value ); ++ #endif ++ ++ TiXmlElement( const TiXmlElement& ); ++ ++ void operator=( const TiXmlElement& base ); ++ ++ virtual ~TiXmlElement(); ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ */ ++ const char* Attribute( const char* name ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an integer, ++ the integer value will be put in the return 'i', if 'i' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, int* i ) const; ++ ++ /** Given an attribute name, Attribute() returns the value ++ for the attribute of that name, or null if none exists. ++ If the attribute exists and can be converted to an double, ++ the double value will be put in the return 'd', if 'd' ++ is non-null. ++ */ ++ const char* Attribute( const char* name, double* d ) const; ++ ++ /** QueryIntAttribute examines the attribute - it is an alternative to the ++ Attribute() method with richer error checking. ++ If the attribute is an integer, it is stored in 'value' and ++ the call returns TIXML_SUCCESS. If it is not ++ an integer, it returns TIXML_WRONG_TYPE. If the attribute ++ does not exist, then TIXML_NO_ATTRIBUTE is returned. ++ */ ++ int QueryIntAttribute( const char* name, int* value ) const; ++ /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). ++ int QueryDoubleAttribute( const char* name, double* value ) const; ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char* name, const char * value ); ++ ++ #ifdef TIXML_USE_STL ++ const char* Attribute( const std::string& name ) const { return Attribute( name.c_str() ); } ++ const char* Attribute( const std::string& name, int* i ) const { return Attribute( name.c_str(), i ); } ++ const char* Attribute( const std::string& name, double* d ) const { return Attribute( name.c_str(), d ); } ++ int QueryIntAttribute( const std::string& name, int* value ) const { return QueryIntAttribute( name.c_str(), value ); } ++ int QueryDoubleAttribute( const std::string& name, double* value ) const { return QueryDoubleAttribute( name.c_str(), value ); } ++ ++ /// STL std::string form. ++ void SetAttribute( const std::string& name, const std::string& _value ) ++ { ++ StringToBuffer n( name ); ++ StringToBuffer v( _value ); ++ if ( n.buffer && v.buffer ) ++ SetAttribute (n.buffer, v.buffer ); ++ } ++ ///< STL std::string form. ++ void SetAttribute( const std::string& name, int _value ) ++ { ++ StringToBuffer n( name ); ++ if ( n.buffer ) ++ SetAttribute (n.buffer, _value); ++ } ++ #endif ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetAttribute( const char * name, int value ); ++ ++ /** Sets an attribute of name to a given value. The attribute ++ will be created if it does not exist, or changed if it does. ++ */ ++ void SetDoubleAttribute( const char * name, double value ); ++ ++ /** Deletes an attribute with the given name. ++ */ ++ void RemoveAttribute( const char * name ); ++ #ifdef TIXML_USE_STL ++ void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. ++ #endif ++ ++ TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. ++ TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. ++ ++ /// Creates a new Element and returns it - the returned element is a copy. ++ virtual TiXmlNode* Clone() const; ++ // Print the Element to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: next char past '<' ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ ++ void CopyTo( TiXmlElement* target ) const; ++ void ClearThis(); // like clear, but initializes 'this' object as well ++ ++ // Used to be public [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++ /* [internal use] ++ Reads the "value" of the element -- another element, or text. ++ This should terminate with the current end tag. ++ */ ++ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++private: ++ ++ TiXmlAttributeSet attributeSet; ++}; ++ ++ ++/** An XML comment. ++*/ ++class TiXmlComment : public TiXmlNode ++{ ++public: ++ /// Constructs an empty comment. ++ TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} ++ TiXmlComment( const TiXmlComment& ); ++ void operator=( const TiXmlComment& base ); ++ ++ virtual ~TiXmlComment() {} ++ ++ /// Returns a copy of this Comment. ++ virtual TiXmlNode* Clone() const; ++ /// Write this Comment to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ /* Attribtue parsing starts: at the ! of the !-- ++ returns: next char past '>' ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlComment* target ) const; ++ ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** XML text. Contained in an element. ++*/ ++class TiXmlText : public TiXmlNode ++{ ++ friend class TiXmlElement; ++public: ++ /// Constructor. ++ TiXmlText (const char * initValue) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ virtual ~TiXmlText() {} ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) ++ { ++ SetValue( initValue ); ++ } ++ #endif ++ ++ TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlText& base ) { base.CopyTo( this ); } ++ ++ /// Write this text object to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected : ++ /// [internal use] Creates a new Element and returns it. ++ virtual TiXmlNode* Clone() const; ++ void CopyTo( TiXmlText* target ) const; ++ ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ bool Blank() const; // returns true if all white space and new lines ++ // [internal use] ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++}; ++ ++ ++/** In correct XML the declaration is the first entry in the file. ++ @verbatim ++ <?xml version="1.0" standalone="yes"?> ++ @endverbatim ++ ++ TinyXml will happily read or write files without a declaration, ++ however. There are 3 possible attributes to the declaration: ++ version, encoding, and standalone. ++ ++ Note: In this version of the code, the attributes are ++ handled as special cases, not generic attributes, simply ++ because there can only be at most 3 and they are always the same. ++*/ ++class TiXmlDeclaration : public TiXmlNode ++{ ++public: ++ /// Construct an empty declaration. ++ TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} ++ ++#ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDeclaration( const std::string& _version, ++ const std::string& _encoding, ++ const std::string& _standalone ); ++#endif ++ ++ /// Construct. ++ TiXmlDeclaration( const char* _version, ++ const char* _encoding, ++ const char* _standalone ); ++ ++ TiXmlDeclaration( const TiXmlDeclaration& copy ); ++ void operator=( const TiXmlDeclaration& copy ); ++ ++ virtual ~TiXmlDeclaration() {} ++ ++ /// Version. Will return an empty string if none was found. ++ const char *Version() const { return version.c_str (); } ++ /// Encoding. Will return an empty string if none was found. ++ const char *Encoding() const { return encoding.c_str (); } ++ /// Is this a standalone document? ++ const char *Standalone() const { return standalone.c_str (); } ++ ++ /// Creates a copy of this Declaration and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this declaration to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlDeclaration* target ) const; ++ // used to be public ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ ++private: ++ ++ TIXML_STRING version; ++ TIXML_STRING encoding; ++ TIXML_STRING standalone; ++}; ++ ++ ++/** Any tag that tinyXml doesn't recognize is saved as an ++ unknown. It is a tag of text, but should not be modified. ++ It will be written back to the XML, unchanged, when the file ++ is saved. ++ ++ DTD tags get thrown into TiXmlUnknowns. ++*/ ++class TiXmlUnknown : public TiXmlNode ++{ ++public: ++ TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} ++ virtual ~TiXmlUnknown() {} ++ ++ TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } ++ void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } ++ ++ /// Creates a copy of this Unknown and returns it. ++ virtual TiXmlNode* Clone() const; ++ /// Print this Unknown to a FILE stream. ++ virtual void Print( FILE* cfile, int depth ) const; ++ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); ++ ++protected: ++ void CopyTo( TiXmlUnknown* target ) const; ++ ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ virtual void StreamOut ( TIXML_OSTREAM * out ) const; ++ ++private: ++ ++}; ++ ++ ++/** Always the top level node. A document binds together all the ++ XML pieces. It can be saved, loaded, and printed to the screen. ++ The 'value' of a document node is the xml file name. ++*/ ++class TiXmlDocument : public TiXmlNode ++{ ++public: ++ /// Create an empty document, that has no name. ++ TiXmlDocument(); ++ /// Create a document with a name. The name of the document is also the filename of the xml. ++ TiXmlDocument( const char * documentName ); ++ ++ #ifdef TIXML_USE_STL ++ /// Constructor. ++ TiXmlDocument( const std::string& documentName ); ++ #endif ++ ++ TiXmlDocument( const TiXmlDocument& copy ); ++ void operator=( const TiXmlDocument& copy ); ++ ++ virtual ~TiXmlDocument() {} ++ ++ /** Load a file using the current document value. ++ Returns true if successful. Will delete any existing ++ document data before loading. ++ */ ++ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the current document value. Returns true if successful. ++ bool SaveFile() const; ++ /// Load a file using the given filename. Returns true if successful. ++ bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ /// Save a file using the given filename. Returns true if successful. ++ bool SaveFile( const char * filename ) const; ++ ++ #ifdef TIXML_USE_STL ++ bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && LoadFile( f.buffer, encoding )); ++ } ++ bool SaveFile( const std::string& filename ) const ///< STL std::string version. ++ { ++ StringToBuffer f( filename ); ++ return ( f.buffer && SaveFile( f.buffer )); ++ } ++ #endif ++ ++ /** Parse the given null terminated block of xml data. Passing in an encoding to this ++ method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml ++ to use that encoding, regardless of what TinyXml might otherwise try to detect. ++ */ ++ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); ++ ++ /** Get the root element -- the only top level element -- of the document. ++ In well formed XML, there should only be one. TinyXml is tolerant of ++ multiple elements at the document level. ++ */ ++ TiXmlElement* RootElement() const { return FirstChildElement(); } ++ ++ /** If an error occurs, Error will be set to true. Also, ++ - The ErrorId() will contain the integer identifier of the error (not generally useful) ++ - The ErrorDesc() method will return the name of the error. (very useful) ++ - The ErrorRow() and ErrorCol() will return the location of the error (if known) ++ */ ++ bool Error() const { return error; } ++ ++ /// Contains a textual (english) description of the error if one occurs. ++ const char * ErrorDesc() const { return errorDesc.c_str (); } ++ ++ /** Generally, you probably want the error string ( ErrorDesc() ). But if you ++ prefer the ErrorId, this function will fetch it. ++ */ ++ const int ErrorId() const { return errorId; } ++ ++ /** Returns the location (if known) of the error. The first column is column 1, ++ and the first row is row 1. A value of 0 means the row and column wasn't applicable ++ (memory errors, for example, have no row/column) or the parser lost the error. (An ++ error in the error reporting, in that case.) ++ ++ @sa SetTabSize, Row, Column ++ */ ++ int ErrorRow() { return errorLocation.row+1; } ++ int ErrorCol() { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() ++ ++ /** By calling this method, with a tab size ++ greater than 0, the row and column of each node and attribute is stored ++ when the file is loaded. Very useful for tracking the DOM back in to ++ the source file. ++ ++ The tab size is required for calculating the location of nodes. If not ++ set, the default of 4 is used. The tabsize is set per document. Setting ++ the tabsize to 0 disables row/column tracking. ++ ++ Note that row and column tracking is not supported when using operator>>. ++ ++ The tab size needs to be enabled before the parse or load. Correct usage: ++ @verbatim ++ TiXmlDocument doc; ++ doc.SetTabSize( 8 ); ++ doc.Load( "myfile.xml" ); ++ @endverbatim ++ ++ @sa Row, Column ++ */ ++ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } ++ ++ int TabSize() const { return tabsize; } ++ ++ /** If you have handled the error, it can be reset with this call. The error ++ state is automatically cleared if you Parse a new XML block. ++ */ ++ void ClearError() { error = false; ++ errorId = 0; ++ errorDesc = ""; ++ errorLocation.row = errorLocation.col = 0; ++ //errorLocation.last = 0; ++ } ++ ++ /** Dump the document to standard out. */ ++ void Print() const { Print( stdout, 0 ); } ++ ++ /// Print this Document to a FILE stream. ++ virtual void Print( FILE* cfile, int depth = 0 ) const; ++ // [internal use] ++ void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); ++ ++protected : ++ virtual void StreamOut ( TIXML_OSTREAM * out) const; ++ // [internal use] ++ virtual TiXmlNode* Clone() const; ++ #ifdef TIXML_USE_STL ++ virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); ++ #endif ++ ++private: ++ void CopyTo( TiXmlDocument* target ) const; ++ ++ bool error; ++ int errorId; ++ TIXML_STRING errorDesc; ++ int tabsize; ++ TiXmlCursor errorLocation; ++}; ++ ++ ++/** ++ A TiXmlHandle is a class that wraps a node pointer with null checks; this is ++ an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml ++ DOM structure. It is a separate utility class. ++ ++ Take an example: ++ @verbatim ++ <Document> ++ <Element attributeA = "valueA"> ++ <Child attributeB = "value1" /> ++ <Child attributeB = "value2" /> ++ </Element> ++ <Document> ++ @endverbatim ++ ++ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very ++ easy to write a *lot* of code that looks like: ++ ++ @verbatim ++ TiXmlElement* root = document.FirstChildElement( "Document" ); ++ if ( root ) ++ { ++ TiXmlElement* element = root->FirstChildElement( "Element" ); ++ if ( element ) ++ { ++ TiXmlElement* child = element->FirstChildElement( "Child" ); ++ if ( child ) ++ { ++ TiXmlElement* child2 = child->NextSiblingElement( "Child" ); ++ if ( child2 ) ++ { ++ // Finally do something useful. ++ @endverbatim ++ ++ And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity ++ of such code. A TiXmlHandle checks for null pointers so it is perfectly safe ++ and correct to use: ++ ++ @verbatim ++ TiXmlHandle docHandle( &document ); ++ TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).Element(); ++ if ( child2 ) ++ { ++ // do something useful ++ @endverbatim ++ ++ Which is MUCH more concise and useful. ++ ++ It is also safe to copy handles - internally they are nothing more than node pointers. ++ @verbatim ++ TiXmlHandle handleCopy = handle; ++ @endverbatim ++ ++ What they should not be used for is iteration: ++ ++ @verbatim ++ int i=0; ++ while ( true ) ++ { ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).Element(); ++ if ( !child ) ++ break; ++ // do something ++ ++i; ++ } ++ @endverbatim ++ ++ It seems reasonable, but it is in fact two embedded while loops. The Child method is ++ a linear walk to find the element, so this code would iterate much more than it needs ++ to. Instead, prefer: ++ ++ @verbatim ++ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).Element(); ++ ++ for( child; child; child=child->NextSiblingElement() ) ++ { ++ // do something ++ } ++ @endverbatim ++*/ ++class TiXmlHandle ++{ ++public: ++ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. ++ TiXmlHandle( TiXmlNode* node ) { this->node = node; } ++ /// Copy constructor ++ TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } ++ TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } ++ ++ /// Return a handle to the first child node. ++ TiXmlHandle FirstChild() const; ++ /// Return a handle to the first child node with the given name. ++ TiXmlHandle FirstChild( const char * value ) const; ++ /// Return a handle to the first child element. ++ TiXmlHandle FirstChildElement() const; ++ /// Return a handle to the first child element with the given name. ++ TiXmlHandle FirstChildElement( const char * value ) const; ++ ++ /** Return a handle to the "index" child with the given name. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( const char* value, int index ) const; ++ /** Return a handle to the "index" child. ++ The first child is 0, the second 1, etc. ++ */ ++ TiXmlHandle Child( int index ) const; ++ /** Return a handle to the "index" child element with the given name. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( const char* value, int index ) const; ++ /** Return a handle to the "index" child element. ++ The first child element is 0, the second 1, etc. Note that only TiXmlElements ++ are indexed: other types are not counted. ++ */ ++ TiXmlHandle ChildElement( int index ) const; ++ ++ #ifdef TIXML_USE_STL ++ TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } ++ TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } ++ ++ TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } ++ TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } ++ #endif ++ ++ /// Return the handle as a TiXmlNode. This may return null. ++ TiXmlNode* Node() const { return node; } ++ /// Return the handle as a TiXmlElement. This may return null. ++ TiXmlElement* Element() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } ++ /// Return the handle as a TiXmlText. This may return null. ++ TiXmlText* Text() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } ++ /// Return the handle as a TiXmlUnknown. This may return null; ++ TiXmlUnknown* Unknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } ++ ++private: ++ TiXmlNode* node; ++}; ++ ++ ++#endif ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/tinyxmlparser.c vdr-1.7.5-extensions/tinyxmlparser.c +--- vdr-1.7.5/tinyxmlparser.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-extensions/tinyxmlparser.c 2009-04-12 13:37:59.000000000 +0200 +@@ -0,0 +1,1494 @@ ++#ifdef USE_SETUP ++/* ++www.sourceforge.net/projects/tinyxml ++Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) ++ ++This software is provided 'as-is', without any express or implied ++warranty. In no event will the authors be held liable for any ++damages arising from the use of this software. ++ ++Permission is granted to anyone to use this software for any ++purpose, including commercial applications, and to alter it and ++redistribute it freely, subject to the following restrictions: ++ ++1. The origin of this software must not be misrepresented; you must ++not claim that you wrote the original software. If you use this ++software in a product, an acknowledgment in the product documentation ++would be appreciated but is not required. ++ ++2. Altered source versions must be plainly marked as such, and ++must not be misrepresented as being the original software. ++ ++3. This notice may not be removed or altered from any source ++distribution. ++*/ ++ ++#include "tinyxml.h" ++#include <ctype.h> ++ ++//#define DEBUG_PARSER ++ ++// Note tha "PutString" hardcodes the same list. This ++// is less flexible than it appears. Changing the entries ++// or order will break putstring. ++TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = ++{ ++ { "&", 5, '&' }, ++ { "<", 4, '<' }, ++ { ">", 4, '>' }, ++ { """, 6, '\"' }, ++ { "'", 6, '\'' } ++}; ++ ++// Bunch of unicode info at: ++// http://www.unicode.org/faq/utf_bom.html ++// Including the basic of this table, which determines the #bytes in the ++// sequence from the lead byte. 1 placed for invalid sequences -- ++// although the result will be junk, pass it through as much as possible. ++// Beware of the non-characters in UTF-8: ++// ef bb bf (Microsoft "lead bytes") ++// ef bf be ++// ef bf bf ++ ++ ++ ++const int TiXmlBase::utf8ByteTable[256] = ++{ ++ // 0 1 2 3 4 5 6 7 8 9 a b c d e f ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 ++ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte ++ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid ++}; ++ ++ ++void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) ++{ ++ const unsigned long BYTE_MASK = 0xBF; ++ const unsigned long BYTE_MARK = 0x80; ++ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; ++ ++ if (input < 0x80) ++ *length = 1; ++ else if ( input < 0x800 ) ++ *length = 2; ++ else if ( input < 0x10000 ) ++ *length = 3; ++ else if ( input < 0x200000 ) ++ *length = 4; ++ else ++ { *length = 0; return; } // This code won't covert this correctly anyway. ++ ++ output += *length; ++ ++ // Scary scary fall throughs. ++ switch (*length) ++ { ++ case 4: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 3: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 2: ++ --output; ++ *output = (char)((input | BYTE_MARK) & BYTE_MASK); ++ input >>= 6; ++ case 1: ++ --output; ++ *output = (char)(input | FIRST_BYTE_MARK[*length]); ++ } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalpha( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalpha( anyByte ); ++// } ++} ++ ++ ++/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ) ++{ ++ // This will only work for low-ascii, everything else is assumed to be a valid ++ // letter. I'm not sure this is the best approach, but it is quite tricky trying ++ // to figure out alhabetical vs. not across encoding. So take a very ++ // conservative approach. ++ ++// if ( encoding == TIXML_ENCODING_UTF8 ) ++// { ++ if ( anyByte < 127 ) ++ return isalnum( anyByte ); ++ else ++ return 1; // What else to do? The unicode set is huge...get the english ones right. ++// } ++// else ++// { ++// return isalnum( anyByte ); ++// } ++} ++ ++ ++class TiXmlParsingData ++{ ++ friend class TiXmlDocument; ++ public: ++ void Stamp( const char* now, TiXmlEncoding encoding ); ++ ++ const TiXmlCursor& Cursor() { return cursor; } ++ ++ private: ++ // Only used by the document! ++ TiXmlParsingData( const char* start, int _tabsize, int row, int col ) ++ { ++ assert( start ); ++ stamp = start; ++ tabsize = _tabsize; ++ cursor.row = row; ++ cursor.col = col; ++ } ++ ++ TiXmlCursor cursor; ++ const char* stamp; ++ int tabsize; ++}; ++ ++ ++void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) ++{ ++ assert( now ); ++ ++ // Do nothing if the tabsize is 0. ++ if ( tabsize < 1 ) ++ { ++ return; ++ } ++ ++ // Get the current row, column. ++ int row = cursor.row; ++ int col = cursor.col; ++ const char* p = stamp; ++ assert( p ); ++ ++ while ( p < now ) ++ { ++ // Code contributed by Fletcher Dunn: (modified by lee) ++ switch (*p) { ++ case 0: ++ // We *should* never get here, but in case we do, don't ++ // advance past the terminating null character, ever ++ return; ++ ++ case '\r': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ // Eat the character ++ ++p; ++ ++ // Check for \r\n sequence, and treat this as a single character ++ if (*p == '\n') { ++ ++p; ++ } ++ break; ++ ++ case '\n': ++ // bump down to the next line ++ ++row; ++ col = 0; ++ ++ // Eat the character ++ ++p; ++ ++ // Check for \n\r sequence, and treat this as a single ++ // character. (Yes, this bizarre thing does occur still ++ // on some arcane platforms...) ++ if (*p == '\r') { ++ ++p; ++ } ++ break; ++ ++ case '\t': ++ // Eat the character ++ ++p; ++ ++ // Skip to next tab stop ++ col = (col / tabsize + 1) * tabsize; ++ break; ++ ++ case (char)(0xef): ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ if ( *(p+1) && *(p+2) ) ++ { ++ // In these cases, don't advance the column. These are ++ // 0-width spaces. ++ if ( *(p+1)==(char)(0xbb) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbe) ) ++ p += 3; ++ else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbf) ) ++ p += 3; ++ else ++ { p +=3; ++col; } // A normal character. ++ } ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ ++ default: ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // Eat the 1 to 4 byte utf8 character. ++ int step = TiXmlBase::utf8ByteTable[*((unsigned char*)p)]; ++ if ( step == 0 ) ++ step = 1; // Error case from bad encoding, but handle gracefully. ++ p += step; ++ ++ // Just advance one column, of course. ++ ++col; ++ } ++ else ++ { ++ ++p; ++ ++col; ++ } ++ break; ++ } ++ } ++ cursor.row = row; ++ cursor.col = col; ++ assert( cursor.row >= -1 ); ++ assert( cursor.col >= -1 ); ++ stamp = p; ++ assert( stamp ); ++} ++ ++ ++const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) ++{ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ while ( *p ) ++ { ++ // Skip the stupid Microsoft UTF-8 Byte order marks ++ if ( *(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbb ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbe ) ++ { ++ p += 3; ++ continue; ++ } ++ else if(*(p+0)==(char) 0xef ++ && *(p+1)==(char) 0xbf ++ && *(p+2)==(char) 0xbf ) ++ { ++ p += 3; ++ continue; ++ } ++ ++ if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. ++ ++p; ++ else ++ break; ++ } ++ } ++ else ++ { ++ while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) ++ ++p; ++ } ++ ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++/*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ for( ;; ) ++ { ++ if ( !in->good() ) return false; ++ ++ int c = in->peek(); ++ // At this scope, we can't get to a document. So fail silently. ++ if ( !IsWhiteSpace( c ) || c <= 0 ) ++ return true; ++ ++ *tag += (char) in->get(); ++ } ++} ++ ++/*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ) ++{ ++ //assert( character > 0 && character < 128 ); // else it won't work in utf-8 ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == character ) ++ return true; ++ if ( c <= 0 ) // Silent failure: can't get document at this scope ++ return false; ++ ++ in->get(); ++ *tag += (char) c; ++ } ++ return false; ++} ++#endif ++ ++const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) ++{ ++ *name = ""; ++ assert( p ); ++ ++ // Names start with letters or underscores. ++ // Of course, in unicode, tinyxml has no idea what a letter *is*. The ++ // algorithm is generous. ++ // ++ // After that, they can be letters, underscores, numbers, ++ // hyphens, or colons. (Colons are valid ony for namespaces, ++ // but tinyxml can't tell namespaces from names.) ++ if ( p && *p ++ && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) ++ { ++ while( p && *p ++ && ( IsAlphaNum( (unsigned char ) *p, encoding ) ++ || *p == '_' ++ || *p == '-' ++ || *p == '.' ++ || *p == ':' ) ) ++ { ++ (*name) += *p; ++ ++p; ++ } ++ return p; ++ } ++ return 0; ++} ++ ++const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) ++{ ++ // Presume an entity, and pull it out. ++ TIXML_STRING ent; ++ int i; ++ *length = 0; ++ ++ if ( *(p+1) && *(p+1) == '#' && *(p+2) ) ++ { ++ unsigned long ucs = 0; ++ unsigned delta = 0; ++ unsigned mult = 1; ++ ++ if ( *(p+2) == 'x' ) ++ { ++ // Hexadecimal. ++ if ( !*(p+3) ) return 0; ++ ++ const char* q = p+3; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != 'x' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else if ( *q >= 'a' && *q <= 'f' ) ++ ucs += mult * (*q - 'a' + 10); ++ else if ( *q >= 'A' && *q <= 'F' ) ++ ucs += mult * (*q - 'A' + 10 ); ++ else ++ return 0; ++ mult *= 16; ++ --q; ++ } ++ } ++ else ++ { ++ // Decimal. ++ if ( !*(p+2) ) return 0; ++ ++ const char* q = p+2; ++ q = strchr( q, ';' ); ++ ++ if ( !q || !*q ) return 0; ++ ++ delta = q-p; ++ --q; ++ ++ while ( *q != '#' ) ++ { ++ if ( *q >= '0' && *q <= '9' ) ++ ucs += mult * (*q - '0'); ++ else ++ return 0; ++ mult *= 10; ++ --q; ++ } ++ } ++ if ( encoding == TIXML_ENCODING_UTF8 ) ++ { ++ // convert the UCS to UTF-8 ++ ConvertUTF32ToUTF8( ucs, value, length ); ++ } ++ else ++ { ++ *value = (char)ucs; ++ *length = 1; ++ } ++ return p + delta + 1; ++ } ++ ++ // Now try to match it. ++ for( i=0; i<NUM_ENTITY; ++i ) ++ { ++ if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) ++ { ++ assert( strlen( entity[i].str ) == entity[i].strLength ); ++ *value = entity[i].chr; ++ *length = 1; ++ return ( p + entity[i].strLength ); ++ } ++ } ++ ++ // So it wasn't an entity, its unrecognized, or something like that. ++ *value = *p; // Don't put back the last one, since we return it! ++ return p+1; ++} ++ ++ ++bool TiXmlBase::StringEqual( const char* p, ++ const char* tag, ++ bool ignoreCase, ++ TiXmlEncoding encoding ) ++{ ++ assert( p ); ++ assert( tag ); ++ if ( !p || !*p ) ++ { ++ assert( 0 ); ++ return false; ++ } ++ ++ const char* q = p; ++ ++ if ( ignoreCase ) ++ { ++ while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) ++ return true; ++ } ++ else ++ { ++ while ( *q && *tag && *q == *tag ) ++ { ++ ++q; ++ ++tag; ++ } ++ ++ if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? ++ return true; ++ } ++ return false; ++} ++ ++const char* TiXmlBase::ReadText( const char* p, ++ TIXML_STRING * text, ++ bool trimWhiteSpace, ++ const char* endTag, ++ bool caseInsensitive, ++ TiXmlEncoding encoding ) ++{ ++ *text = ""; ++ if ( !trimWhiteSpace // certain tags always keep whitespace ++ || !condenseWhiteSpace ) // if true, whitespace is always kept ++ { ++ // Keep all the white space. ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ++ ) ++ { ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ text->append( cArr, len ); ++ } ++ } ++ else ++ { ++ bool whitespace = false; ++ ++ // Remove leading white space: ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ++ && !StringEqual( p, endTag, caseInsensitive, encoding ) ) ++ { ++ if ( *p == '\r' || *p == '\n' ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else if ( IsWhiteSpace( *p ) ) ++ { ++ whitespace = true; ++ ++p; ++ } ++ else ++ { ++ // If we've found whitespace, add it before the ++ // new character. Any whitespace just becomes a space. ++ if ( whitespace ) ++ { ++ (*text) += ' '; ++ whitespace = false; ++ } ++ int len; ++ char cArr[4] = { 0, 0, 0, 0 }; ++ p = GetChar( p, cArr, &len, encoding ); ++ if ( len == 1 ) ++ (*text) += cArr[0]; // more efficient ++ else ++ text->append( cArr, len ); ++ } ++ } ++ } ++ return p + strlen( endTag ); ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ // The basic issue with a document is that we don't know what we're ++ // streaming. Read something presumed to be a tag (and hope), then ++ // identify it, and call the appropriate stream method on the tag. ++ // ++ // This "pre-streaming" will never read the closing ">" so the ++ // sub-tag can orient itself. ++ ++ if ( !StreamTo( in, '<', tag ) ) ++ { ++ SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ while ( in->good() ) ++ { ++ int tagIndex = (int) tag->length(); ++ while ( in->good() && in->peek() != '>' ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ break; ++ } ++ (*tag) += (char) c; ++ } ++ ++ if ( in->good() ) ++ { ++ // We now have something we presume to be a node of ++ // some sort. Identify it, and call the node to ++ // continue streaming. ++ TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); ++ ++ if ( node ) ++ { ++ node->StreamIn( in, tag ); ++ bool isElement = node->ToElement() != 0; ++ delete node; ++ node = 0; ++ ++ // If this is the root element, we're done. Parsing will be ++ // done by the >> operator. ++ if ( isElement ) ++ { ++ return; ++ } ++ } ++ else ++ { ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ } ++ } ++ // We should have returned sooner. ++ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); ++} ++ ++#endif ++ ++const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) ++{ ++ ClearError(); ++ ++ // Parse away, at the document level. Since a document ++ // contains nothing but other tags, most of what happens ++ // here is skipping white space. ++ if ( !p || !*p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ // Note that, for a document, this needs to come ++ // before the while space skip, so that parsing ++ // starts from the pointer we are given. ++ location.Clear(); ++ if ( prevData ) ++ { ++ location.row = prevData->cursor.row; ++ location.col = prevData->cursor.col; ++ } ++ else ++ { ++ location.row = 0; ++ location.col = 0; ++ } ++ TiXmlParsingData data( p, TabSize(), location.row, location.col ); ++ location = data.Cursor(); ++ ++ if ( encoding == TIXML_ENCODING_UNKNOWN ) ++ { ++ // Check for the Microsoft UTF-8 lead bytes. ++ if ( *(p+0) && *(p+0) == (char)(0xef) ++ && *(p+1) && *(p+1) == (char)(0xbb) ++ && *(p+2) && *(p+2) == (char)(0xbf) ) ++ { ++ encoding = TIXML_ENCODING_UTF8; ++ } ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p ) ++ { ++ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return 0; ++ } ++ ++ while ( p && *p ) ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, &data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ break; ++ } ++ ++ // Did we get encoding info? ++ if ( encoding == TIXML_ENCODING_UNKNOWN ++ && node->ToDeclaration() ) ++ { ++ TiXmlDeclaration* dec = node->ToDeclaration(); ++ const char* enc = dec->Encoding(); ++ assert( enc ); ++ ++ if ( *enc == 0 ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; ++ else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) ++ encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice ++ else ++ encoding = TIXML_ENCODING_LEGACY; ++ } ++ ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ // All is well. ++ return p; ++} ++ ++void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ // The first error in a chain is more accurate - don't set again! ++ if ( error ) ++ return; ++ ++ assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); ++ error = true; ++ errorId = err; ++ errorDesc = errorString[ errorId ]; ++ ++ errorLocation.Clear(); ++ if ( pError && data ) ++ { ++ //TiXmlParsingData data( pError, prevData ); ++ data->Stamp( pError, encoding ); ++ errorLocation = data->Cursor(); ++ } ++} ++ ++ ++TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) ++{ ++ TiXmlNode* returnNode = 0; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ if( !p || !*p || *p != '<' ) ++ { ++ return 0; ++ } ++ ++ TiXmlDocument* doc = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ return 0; ++ } ++ ++ // What is this thing? ++ // - Elements start with a letter or underscore, but xml is reserved. ++ // - Comments: <!-- ++ // - Decleration: <?xml ++ // - Everthing else is unknown to tinyxml. ++ // ++ ++ const char* xmlHeader = { "<?xml" }; ++ const char* commentHeader = { "<!--" }; ++ const char* dtdHeader = { "<!" }; ++ ++ if ( StringEqual( p, xmlHeader, true, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Declaration\n" ); ++ #endif ++ returnNode = new TiXmlDeclaration(); ++ } ++ else if ( StringEqual( p, commentHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Comment\n" ); ++ #endif ++ returnNode = new TiXmlComment(); ++ } ++ else if ( StringEqual( p, dtdHeader, false, encoding ) ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(1)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ else if ( IsAlpha( *(p+1), encoding ) ++ || *(p+1) == '_' ) ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Element\n" ); ++ #endif ++ returnNode = new TiXmlElement( "" ); ++ } ++ else ++ { ++ #ifdef DEBUG_PARSER ++ TIXML_LOG( "XML parsing Unknown(2)\n" ); ++ #endif ++ returnNode = new TiXmlUnknown(); ++ } ++ ++ if ( returnNode ) ++ { ++ // Set the parent, so it can report errors ++ returnNode->parent = this; ++ } ++ else ++ { ++ if ( doc ) ++ doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ } ++ return returnNode; ++} ++ ++#ifdef TIXML_USE_STL ++ ++void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag) ++{ ++ // We're called with some amount of pre-parsing. That is, some of "this" ++ // element is in "tag". Go ahead and stream to the closing ">" ++ while( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c ; ++ ++ if ( c == '>' ) ++ break; ++ } ++ ++ if ( tag->length() < 3 ) return; ++ ++ // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. ++ // If not, identify and stream. ++ ++ if ( tag->at( tag->length() - 1 ) == '>' ++ && tag->at( tag->length() - 2 ) == '/' ) ++ { ++ // All good! ++ return; ++ } ++ else if ( tag->at( tag->length() - 1 ) == '>' ) ++ { ++ // There is more. Could be: ++ // text ++ // closing tag ++ // another node. ++ for ( ;; ) ++ { ++ StreamWhiteSpace( in, tag ); ++ ++ // Do we have text? ++ if ( in->good() && in->peek() != '<' ) ++ { ++ // Yep, text. ++ TiXmlText text( "" ); ++ text.StreamIn( in, tag ); ++ ++ // What follows text is a closing tag or another node. ++ // Go around again and figure it out. ++ continue; ++ } ++ ++ // We now have either a closing tag...or another node. ++ // We should be at a "<", regardless. ++ if ( !in->good() ) return; ++ assert( in->peek() == '<' ); ++ int tagIndex = tag->length(); ++ ++ bool closingTag = false; ++ bool firstCharFound = false; ++ ++ for( ;; ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->peek(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ if ( c == '>' ) ++ break; ++ ++ *tag += (char) c; ++ in->get(); ++ ++ if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) ++ { ++ firstCharFound = true; ++ if ( c == '/' ) ++ closingTag = true; ++ } ++ } ++ // If it was a closing tag, then read in the closing '>' to clean up the input stream. ++ // If it was not, the streaming will be done by the tag. ++ if ( closingTag ) ++ { ++ if ( !in->good() ) ++ return; ++ ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ assert( c == '>' ); ++ *tag += (char) c; ++ ++ // We are done, once we've found our closing tag. ++ return; ++ } ++ else ++ { ++ // If not a closing tag, id it, and stream. ++ const char* tagloc = tag->c_str() + tagIndex; ++ TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); ++ if ( !node ) ++ return; ++ node->StreamIn( in, tag ); ++ delete node; ++ node = 0; ++ ++ // No return: go around from the beginning: text, closing tag, or node. ++ } ++ } ++ } ++} ++#endif ++ ++const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ TiXmlDocument* document = GetDocument(); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); ++ return 0; ++ } ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ ++ if ( *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); ++ return 0; ++ } ++ ++ p = SkipWhiteSpace( p+1, encoding ); ++ ++ // Read the name. ++ const char* pErr = p; ++ ++ p = ReadName( p, &value, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); ++ return 0; ++ } ++ ++ TIXML_STRING endTag ("</"); ++ endTag += value; ++ endTag += ">"; ++ ++ // Check for and read attributes. Also look for an empty ++ // tag or an end tag. ++ while ( p && *p ) ++ { ++ pErr = p; ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ if ( *p == '/' ) ++ { ++ ++p; ++ // Empty tag. ++ if ( *p != '>' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); ++ return 0; ++ } ++ return (p+1); ++ } ++ else if ( *p == '>' ) ++ { ++ // Done with attributes (if there were any.) ++ // Read the value -- which can include other ++ // elements -- read the end tag, and return. ++ ++p; ++ p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. ++ if ( !p || !*p ) ++ return 0; ++ ++ // We should find the end tag now ++ if ( StringEqual( p, endTag.c_str(), false, encoding ) ) ++ { ++ p += endTag.length(); ++ return p; ++ } ++ else ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); ++ return 0; ++ } ++ } ++ else ++ { ++ // Try to read an attribute: ++ TiXmlAttribute* attrib = new TiXmlAttribute(); ++ if ( !attrib ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); ++ return 0; ++ } ++ ++ attrib->SetDocument( document ); ++ const char* pErr = p; ++ p = attrib->Parse( p, data, encoding ); ++ ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); ++ delete attrib; ++ return 0; ++ } ++ ++ // Handle the strange case of double attributes: ++ TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); ++ if ( node ) ++ { ++ node->SetValue( attrib->Value() ); ++ delete attrib; ++ return 0; ++ } ++ ++ attributeSet.Add( attrib ); ++ } ++ } ++ return p; ++} ++ ++ ++const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ ++ const char* pWithWhiteSpace = p; ++ // Read in text and elements in any order. ++ p = SkipWhiteSpace( p, encoding ); ++ while ( p && *p ) ++ { ++ if ( *p != '<' ) ++ { ++ // Take what we have, make a text element. ++ TiXmlText* textNode = new TiXmlText( "" ); ++ ++ if ( !textNode ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); ++ return 0; ++ } ++ ++ if ( TiXmlBase::IsWhiteSpaceCondensed() ) ++ { ++ p = textNode->Parse( p, data, encoding ); ++ } ++ else ++ { ++ // Special case: we want to keep the white space ++ // so that leading spaces aren't removed. ++ p = textNode->Parse( pWithWhiteSpace, data, encoding ); ++ } ++ ++ if ( !textNode->Blank() ) ++ LinkEndChild( textNode ); ++ else ++ delete textNode; ++ } ++ else ++ { ++ // We hit a '<' ++ // Have we hit a new element or an end tag? ++ if ( StringEqual( p, "</", false, encoding ) ) ++ { ++ return p; ++ } ++ else ++ { ++ TiXmlNode* node = Identify( p, encoding ); ++ if ( node ) ++ { ++ p = node->Parse( p, data, encoding ); ++ LinkEndChild( node ); ++ } ++ else ++ { ++ return 0; ++ } ++ } ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); ++ } ++ return p; ++} ++ ++ ++#ifdef TIXML_USE_STL ++void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ if ( !p || !*p || *p != '<' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); ++ return 0; ++ } ++ ++p; ++ value = ""; ++ ++ while ( p && *p && *p != '>' ) ++ { ++ value += *p; ++ ++p; ++ } ++ ++ if ( !p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); ++ } ++ if ( *p == '>' ) ++ return p+1; ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ ++ if ( c == '>' ++ && tag->at( tag->length() - 2 ) == '-' ++ && tag->at( tag->length() - 3 ) == '-' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++ ++const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ TiXmlDocument* document = GetDocument(); ++ value = ""; ++ ++ p = SkipWhiteSpace( p, encoding ); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ const char* startTag = "<!--"; ++ const char* endTag = "-->"; ++ ++ if ( !StringEqual( p, startTag, false, encoding ) ) ++ { ++ document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); ++ return 0; ++ } ++ p += strlen( startTag ); ++ p = ReadText( p, &value, false, endTag, false, encoding ); ++ return p; ++} ++ ++ ++const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) return 0; ++ ++ int tabsize = 4; ++ if ( document ) ++ tabsize = document->TabSize(); ++ ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ // Read the name, the '=' and the value. ++ const char* pErr = p; ++ p = ReadName( p, &name, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); ++ return 0; ++ } ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p || *p != '=' ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ ++p; // skip '=' ++ p = SkipWhiteSpace( p, encoding ); ++ if ( !p || !*p ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); ++ return 0; ++ } ++ ++ const char* end; ++ ++ if ( *p == '\'' ) ++ { ++ ++p; ++ end = "\'"; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else if ( *p == '"' ) ++ { ++ ++p; ++ end = "\""; ++ p = ReadText( p, &value, false, end, false, encoding ); ++ } ++ else ++ { ++ // All attribute values should be in single or double quotes. ++ // But this is such a common error that the parser will try ++ // its best, even without them. ++ value = ""; ++ while ( p && *p // existence ++ && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace ++ && *p != '/' && *p != '>' ) // tag end ++ { ++ value += *p; ++ ++p; ++ } ++ } ++ return p; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->peek(); ++ if ( c == '<' ) ++ return; ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ ++ (*tag) += (char) c; ++ in->get(); ++ } ++} ++#endif ++ ++const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) ++{ ++ value = ""; ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, encoding ); ++ location = data->Cursor(); ++ } ++ bool ignoreWhite = true; ++ ++ const char* end = "<"; ++ p = ReadText( p, &value, ignoreWhite, end, false, encoding ); ++ if ( p ) ++ return p-1; // don't truncate the '<' ++ return 0; ++} ++ ++#ifdef TIXML_USE_STL ++void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) ++{ ++ while ( in->good() ) ++ { ++ int c = in->get(); ++ if ( c <= 0 ) ++ { ++ TiXmlDocument* document = GetDocument(); ++ if ( document ) ++ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); ++ return; ++ } ++ (*tag) += (char) c; ++ ++ if ( c == '>' ) ++ { ++ // All is well. ++ return; ++ } ++ } ++} ++#endif ++ ++const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) ++{ ++ p = SkipWhiteSpace( p, _encoding ); ++ // Find the beginning, find the end, and look for ++ // the stuff in-between. ++ TiXmlDocument* document = GetDocument(); ++ if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) ++ { ++ if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); ++ return 0; ++ } ++// TiXmlParsingData data( p, prevData ); ++ if ( data ) ++ { ++ data->Stamp( p, _encoding ); ++ location = data->Cursor(); ++ } ++ p += 5; ++ ++ version = ""; ++ encoding = ""; ++ standalone = ""; ++ ++ while ( p && *p ) ++ { ++ if ( *p == '>' ) ++ { ++ ++p; ++ return p; ++ } ++ ++ p = SkipWhiteSpace( p, _encoding ); ++ if ( StringEqual( p, "version", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ version = attrib.Value(); ++ } ++ else if ( StringEqual( p, "encoding", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ encoding = attrib.Value(); ++ } ++ else if ( StringEqual( p, "standalone", true, _encoding ) ) ++ { ++ TiXmlAttribute attrib; ++ p = attrib.Parse( p, data, _encoding ); ++ standalone = attrib.Value(); ++ } ++ else ++ { ++ // Read over whatever it is. ++ while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++ ++p; ++ } ++ } ++ return 0; ++} ++ ++bool TiXmlText::Blank() const ++{ ++ for ( unsigned i=0; i<value.length(); i++ ) ++ if ( !IsWhiteSpace( value[i] ) ) ++ return false; ++ return true; ++} ++#endif /* SETUP */ +diff -ruNp vdr-1.7.5/vdr.c vdr-1.7.5-extensions/vdr.c +--- vdr-1.7.5/vdr.c 2009-04-05 15:21:46.000000000 +0200 ++++ vdr-1.7.5-extensions/vdr.c 2009-04-12 13:37:59.000000000 +0200 +@@ -139,10 +139,17 @@ static bool SetKeepCaps(bool On) + return true; + } + ++#ifdef USE_SETTIME ++char *SetTime=NULL; ++#endif /* SETTIME */ ++ + static void SignalHandler(int signum) + { + switch (signum) { + case SIGPIPE: ++#ifdef USE_EM84XX ++ case SIGINT: ++#endif /* EM84XX */ + break; + case SIGHUP: + LastSignal = signum; +@@ -163,6 +170,10 @@ static void Watchdog(int signum) + exit(1); + } + ++#ifdef USE_CMDRECCMDI18N ++const char *ConfigDirectory = NULL; ++#endif /* CMDRECCMDI18N */ ++ + int main(int argc, char *argv[]) + { + // Save terminal settings: +@@ -187,8 +198,11 @@ int main(int argc, char *argv[]) + bool UserDump = false; + int SVDRPport = DEFAULTSVDRPPORT; + const char *AudioCommand = NULL; ++#ifndef USE_CMDRECCMDI18N + const char *ConfigDirectory = NULL; ++#endif /* CMDRECCMDI18N */ + const char *EpgDataFileName = DEFAULTEPGDATAFILENAME; ++ bool DisplayExtensions = false; + bool DisplayHelp = false; + bool DisplayVersion = false; + bool DaemonMode = false; +@@ -221,6 +235,7 @@ int main(int argc, char *argv[]) + { "daemon", no_argument, NULL, 'd' }, + { "device", required_argument, NULL, 'D' }, + { "epgfile", required_argument, NULL, 'E' }, ++ { "extensions",no_argument, NULL, 'e' | 0x100 }, + { "grab", required_argument, NULL, 'g' }, + { "help", no_argument, NULL, 'h' }, + { "instance", required_argument, NULL, 'i' }, +@@ -236,6 +251,9 @@ int main(int argc, char *argv[]) + { "record", required_argument, NULL, 'r' }, + { "shutdown", required_argument, NULL, 's' }, + { "terminal", required_argument, NULL, 't' }, ++#ifdef USE_SETTIME ++ { "timeset", required_argument, NULL, 'T' }, ++#endif /* SETTIME */ + { "user", required_argument, NULL, 'u' }, + { "userdump", no_argument, NULL, 'u' | 0x100 }, + { "version", no_argument, NULL, 'V' }, +@@ -246,7 +264,11 @@ int main(int argc, char *argv[]) + }; + + int c; ++#ifdef USE_SETTIME ++ while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hi:l:L:mp:P:r:s:t:T:u:v:Vw:", long_options, NULL)) != -1) { ++#else + while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hi:l:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) { ++#endif /* SETTIME */ + switch (c) { + case 'a': AudioCommand = optarg; + break; +@@ -263,6 +285,9 @@ int main(int argc, char *argv[]) + fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg); + return 2; + break; ++ case 'e' | 0x100: ++ DisplayExtensions = true; ++ break; + case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL); + break; + case 'g': cSVDRP::SetGrabImageDir(*optarg != '-' ? optarg : NULL); +@@ -341,6 +366,10 @@ int main(int argc, char *argv[]) + break; + case 's': ShutdownHandler.SetShutdownCommand(optarg); + break; ++#ifdef USE_SETTIME ++ case 'T': SetTime = strdup(optarg); ++ break; ++#endif /* SETTIME */ + case 't': Terminal = optarg; + if (access(Terminal, R_OK | W_OK) < 0) { + fprintf(stderr, "vdr: can't access terminal: %s\n", Terminal); +@@ -406,6 +435,7 @@ int main(int argc, char *argv[]) + " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" + " there may be several -D options (default: all DVB\n" + " devices will be used)\n" ++ " --extensions print patchlevel and exit\n" + " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n" + " '%s' in the video directory)\n" + " '-E-' disables this\n" +@@ -437,6 +467,9 @@ int main(int argc, char *argv[]) + " -r CMD, --record=CMD call CMD before and after a recording\n" + " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" + " -t TTY, --terminal=TTY controlling tty\n" ++#ifdef USE_SETTIME ++ " -T CMD, --timeset=CMD call CMD to set the system time\n" ++#endif /* SETTIME */ + " -u USER, --user=USER run as user USER; only applicable if started as\n" + " root\n" + " --userdump allow coredumps if -u is given (debugging)\n" +@@ -480,6 +513,197 @@ int main(int argc, char *argv[]) + return 0; + } + ++ if (DisplayExtensions) { ++ printf("VDR %s\n", VDRVERSION); ++ printf("VDREXTENSIONS %d\n", VDREXTENSIONS); ++ ++#ifdef USE_ANALOGTV ++ printf(" ANALOGTV\n"); ++#endif /* ANALOGTV */ ++ ++#ifdef USE_ATSC ++ printf(" ATSC\n"); ++#endif /* ATSC */ ++ ++#ifdef USE_CHANNELSCAN ++ printf(" CHANNELSCAN\n"); ++#endif /* CHANNELSCAN */ ++ ++#ifdef USE_CMDRECCMDI18N ++ printf(" CMDRECCMDI18N\n"); ++#endif /* CMDRECCMDI18N */ ++ ++#ifdef USE_CMDSUBMENU ++ printf(" CMDSUBMENU %d\n", CMDSUBMENUVERSNUM); ++#endif /* CMDSUBMENU */ ++ ++#ifdef USE_CUTTERLIMIT ++ printf(" CUTTERLIMIT\n"); ++#endif /* CUTTERLIMIT */ ++ ++#ifdef USE_CUTTERQUEUE ++ printf(" CUTTERQUEUE\n"); ++#endif /* CUTTERQUEUE */ ++ ++#ifdef USE_CUTTIME ++ printf(" CUTTIME\n"); ++#endif /* CUTTIME */ ++ ++#ifdef USE_DDEPGENTRY ++ printf(" DDEPGENTRY\n"); ++#endif /* DDEPGENTRY */ ++ ++#ifdef USE_DELTIMESHIFTREC ++ printf(" DELTIMESHIFTREC\n"); ++#endif /* DELTIMESHIFTREC */ ++ ++#ifdef USE_DOLBYINREC ++ printf(" DOLBYINREC\n"); ++#endif /* DOLBYINREC */ ++ ++#ifdef USE_DVBSETUP ++ printf(" DVBSETUP\n"); ++#endif /* DVBSETUP */ ++ ++#ifdef USE_DVDARCHIVE ++ printf(" DVDARCHIVE\n"); ++#endif /* DVDARCHIVE */ ++ ++#ifdef USE_DVDCHAPJUMP ++ printf(" DVDCHAPJUMP\n"); ++#endif /* DVDCHAPJUMP */ ++ ++#ifdef USE_DVLRECSCRIPTADDON ++ printf(" DVLRECSCRIPTADDON\n"); ++#endif /* DVLRECSCRIPTADDON */ ++ ++#ifdef USE_DVLVIDPREFER ++ printf(" DVLVIDPREFER\n"); ++#endif /* DVLVIDPREFER */ ++ ++#ifdef USE_DVLFRIENDLYFNAMES ++ printf(" DVLFRIENDLYFNAMES\n"); ++#endif /* DVLFRIENDLYFNAMES */ ++ ++#ifdef USE_EM84XX ++ printf(" EM84XX\n"); ++#endif /* EM84XX */ ++ ++#ifdef USE_GRAPHTFT ++ printf(" GRAPHTFT\n"); ++#endif /* GRAPHTFT */ ++ ++#ifdef USE_HARDLINKCUTTER ++ printf(" HARDLINKCUTTER\n"); ++#endif /* HARDLINKCUTTER */ ++ ++#ifdef USE_JUMPPLAY ++ printf(" JUMPPLAY %d\n", JUMPPLAYVERSNUM); ++#endif /* JUMPPLAY */ ++ ++#ifdef USE_LIEMIEXT ++ printf(" LIEMIEXT %d\n", LIEMIKUUTIO); ++#endif /* LIEMIEXT */ ++ ++#ifdef USE_LIRCSETTINGS ++ printf(" LIRCSETTINGS\n"); ++#endif /* LIRCSETTINGS */ ++ ++#ifdef USE_LNBSHARE ++ printf(" LNBSHARE\n"); ++#endif /* LNBSHARE */ ++ ++#ifdef USE_MAINMENUHOOKS ++ printf(" MAINMENUHOOKS %3.1f\n", MAINMENUHOOKSVERSNUM); ++#endif /* MAINMENUHOOKS */ ++ ++#ifdef USE_MENUORG ++ printf(" MENUORG\n"); ++#endif /* MENUORG */ ++ ++#ifdef USE_NOEPG ++ printf(" NOEPG\n"); ++#endif /* NOEPG */ ++ ++#ifdef USE_OSDMAXITEMS ++ printf(" OSDMAXITEMS\n"); ++#endif /* OSDMAXITEMS */ ++ ++#ifdef USE_PARENTALRATING ++ printf(" PARENTALRATING\n"); ++#endif /* PARENTALRATING */ ++ ++#ifdef USE_PINPLUGIN ++ printf(" PINPLUGIN %d\n", PIN_PLUGIN_PATCH); ++#endif /* PINPLUGIN */ ++ ++#ifdef USE_PLUGINAPI ++ printf(" PLUGINAPI\n"); ++#endif /* PLUGINAPI */ ++ ++#ifdef USE_PLUGINMISSING ++ printf(" PLUGINMISSING\n"); ++#endif /* PLUGINMISSING */ ++ ++#ifdef USE_PLUGINPARAM ++ printf(" PLUGINPARAM %d\n", PLUGINPARAMPATCHVERSNUM); ++#endif /* PLUGINPARAM */ ++ ++#ifdef USE_ROTOR ++ printf(" ROTOR\n"); ++#endif /* ROTOR */ ++ ++#ifdef USE_SETTIME ++ printf(" SETTIME\n"); ++#endif /* SETTIME */ ++ ++#ifdef USE_SETUP ++ printf(" SETUP\n"); ++#endif /* SETUP */ ++ ++#ifdef USE_SOFTOSD ++ printf(" SOFTOSD\n"); ++#endif /* SOFTOSD */ ++ ++#ifdef USE_SOURCECAPS ++ printf(" SOURCECAPS\n"); ++#endif /* SOURCECAPS */ ++ ++#ifdef USE_SORTRECORDS ++ printf(" SORTRECORDS\n"); ++#endif /* SORTRECORDS */ ++ ++#ifdef USE_STREAMDEVEXT ++ printf(" STREAMDEVEXT\n"); ++#endif /* STREAMDEVEXT */ ++ ++#ifdef USE_TIMERCMD ++ printf(" TIMERCMD\n"); ++#endif /* TIMERCMD */ ++ ++#ifdef USE_TIMERINFO ++ printf(" TIMERINFO\n"); ++#endif /* TIMERINFO */ ++ ++#ifdef USE_VALIDINPUT ++ printf(" VALIDINPUT\n"); ++#endif /* VALIDINPUT */ ++ ++#ifdef USE_VOLCTRL ++ printf(" VOLCTRL\n"); ++#endif /* VOLCTRL */ ++ ++#ifdef USE_WAREAGLEICON ++ printf(" WAREAGLEICON\n"); ++#endif /* WAREAGLEICON */ ++ ++#ifdef USE_YAEPG ++ printf(" YAEPG\n"); ++#endif /* YAEPG */ ++ ++ return 0; ++ } ++ + // Log file: + + if (SysLogLevel > 0) +@@ -573,8 +797,20 @@ int main(int argc, char *argv[]) + Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC); + Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true); + Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); ++#ifdef USE_CMDRECCMDI18N ++ LoadCommandsI18n(Commands,AddDirectory(ConfigDirectory, "commands.conf"), true); ++ LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory, "reccmds.conf"), true); ++#else + Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true); + RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true); ++#endif /* CMDRECCMDI18N */ ++#ifdef USE_TIMERCMD ++#ifdef USE_CMDRECCMDI18N ++ LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true); ++#else ++ TimerCommands.Load(AddDirectory(ConfigDirectory, "timercmds.conf"), true); ++#endif /* CMDRECCMDI18N */ ++#endif /* TIMERCMD */ + SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true); + Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")); + KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true); +@@ -735,7 +971,11 @@ int main(int argc, char *argv[]) + // Make sure we have a visible programme in case device usage has changed: + if (!EITScanner.Active() && cDevice::PrimaryDevice()->HasDecoder() && !cDevice::PrimaryDevice()->HasProgramme()) { + static time_t lastTime = 0; ++#ifdef USE_CHANNELSCAN ++ if (!scanning_on_receiving_device && (!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { ++#else + if ((!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { // !Menu to avoid interfering with the CAM if a CAM menu is open ++#endif /* CHANNELSCAN */ + cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel()); + if (Channel && (Channel->Vpid() || Channel->Apid(0))) { + if (!Channels.SwitchTo(cDevice::CurrentChannel()) // try to switch to the original channel... +@@ -910,6 +1150,9 @@ int main(int argc, char *argv[]) + cOsdObject *Interact = Menu ? Menu : cControl::Control(); + eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse()); + if (ISREALKEY(key)) { ++#ifdef USE_PINPLUGIN ++ cStatus::MsgUserAction(key, Interact); ++#endif /* PINPLUGIN */ + EITScanner.Activity(); + // Cancel shutdown countdown: + if (ShutdownHandler.countdown) +@@ -982,10 +1225,16 @@ int main(int argc, char *argv[]) + cControl::Control()->Hide(); + cPlugin *plugin = cPluginManager::GetPlugin(PluginName); + if (plugin) { ++#ifdef USE_PINPLUGIN ++ if (!cStatus::MsgPluginProtected(plugin)) { ++#endif /* PINPLUGIN */ + Menu = plugin->MainMenuAction(); + if (Menu) + Menu->Show(); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + else + esyslog("ERROR: unknown plugin '%s'", PluginName); + } +@@ -1062,8 +1311,15 @@ int main(int argc, char *argv[]) + // Instant recording: + case kRecord: + if (!cControl::Control()) { ++#ifdef USE_STREAMDEVEXT ++ if (cRecordControls::Start()) { ++ Skins.Message(mtInfo, tr("Recording started")); ++ cStatus::MsgRecordingChange(NULL, scAdd); ++ } ++#else + if (cRecordControls::Start()) + Skins.Message(mtInfo, tr("Recording started")); ++#endif /* STREAMDEVEXT */ + key = kNone; // nobody else needs to see this key + } + break; +@@ -1119,8 +1375,15 @@ int main(int argc, char *argv[]) + Skins.Message(mtError, tr("No free DVB device to record!")); + break; + case osRecord: DELETE_MENU; ++#ifdef USE_STREAMDEVEXT ++ if (cRecordControls::Start()) { ++ Skins.Message(mtInfo, tr("Recording started")); ++ cStatus::MsgRecordingChange(NULL, scAdd); ++ } ++#else + if (cRecordControls::Start()) + Skins.Message(mtInfo, tr("Recording started")); ++#endif /* STREAMDEVEXT */ + break; + case osRecordings: + DELETE_MENU; +@@ -1171,13 +1434,26 @@ int main(int argc, char *argv[]) + Channels.SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]); + break; + } ++#ifdef USE_VOLCTRL ++ // Left/Right volume control ++#else + // Direct Channel Select: + case k1 ... k9: + // Left/Right rotates through channel groups: ++#endif /* VOLCTRL */ + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: ++#ifdef USE_VOLCTRL ++ if (Setup.LRVolumeControl && Setup.LRChannelGroups < 2) { ++ cRemote::Put(NORMALKEY(key) == kLeft ? kVolDn : kVolUp, true); ++ break; ++ } ++ // else fall through ++ // Direct Channel Select: ++ case k1 ... k9: ++#endif /* VOLCTRL */ + // Previous/Next rotates through channel groups: + case kPrev|k_Repeat: + case kPrev: +@@ -1195,9 +1471,15 @@ int main(int argc, char *argv[]) + // Instant resume of the last viewed recording: + case kPlay: + if (cReplayControl::LastReplayed()) { ++#ifdef USE_PINPLUGIN ++ if (cStatus::MsgReplayProtected(0, cReplayControl::LastReplayed(), 0, false) == false) { ++#endif /* PINPLUGIN */ + cControl::Shutdown(); + cControl::Launch(new cReplayControl); + } ++#ifdef USE_PINPLUGIN ++ } ++#endif /* PINPLUGIN */ + break; + default: break; + } +diff -ruNp vdr-1.7.5/videodir.c vdr-1.7.5-extensions/videodir.c +--- vdr-1.7.5/videodir.c 2008-02-16 14:00:03.000000000 +0100 ++++ vdr-1.7.5-extensions/videodir.c 2009-04-12 13:37:59.000000000 +0200 +@@ -19,6 +19,13 @@ + #include "recording.h" + #include "tools.h" + ++#ifdef USE_HARDLINKCUTTER ++//#define HARDLINK_TEST_ONLY ++#ifdef USE_STREAMDEVEXT ++#include "status.h" ++#endif /* STREAMDEVEXT */ ++#endif /* HARDLINKCUTTER */ ++ + const char *VideoDirectory = VIDEODIR; + + class cVideoDirectory { +@@ -36,6 +43,11 @@ public: + bool Next(void); + void Store(void); + const char *Adjust(const char *FileName); ++#ifdef USE_DVLVIDPREFER ++ char *GetVidPath(int nVid); ++ bool GetPreferedVideoDir(void); ++ bool IsVidDirOK(int nVid, int *freeMB = NULL); ++#endif /* DVLVIDPREFER */ + }; + + cVideoDirectory::cVideoDirectory(void) +@@ -117,6 +129,9 @@ cUnbufferedFile *OpenVideoFile(const cha + if ((Flags & O_CREAT) != 0) { + cVideoDirectory Dir; + if (Dir.IsDistributed()) { ++#ifdef USE_DVLVIDPREFER ++ if (Setup.UseVidPrefer == 0) { ++#endif /* DVLVIDPREFER */ + // Find the directory with the most free space: + int MaxFree = Dir.FreeMB(); + while (Dir.Next()) { +@@ -126,14 +141,24 @@ cUnbufferedFile *OpenVideoFile(const cha + MaxFree = Free; + } + } ++#ifdef USE_DVLVIDPREFER ++ } ++ else Dir.GetPreferedVideoDir(); ++#endif /* DVLVIDPREFER */ + if (Dir.Stored()) { + ActualFileName = Dir.Adjust(FileName); + if (!MakeDirs(ActualFileName, false)) + return NULL; // errno has been set by MakeDirs() ++#ifdef USE_DVLVIDPREFER ++ if (strcmp(ActualFileName, FileName) != 0) { ++#endif /* DVLVIDPREFER */ + if (symlink(ActualFileName, FileName) < 0) { + LOG_ERROR_STR(FileName); + return NULL; + } ++#ifdef USE_DVLVIDPREFER ++ } ++#endif /* DVLVIDPREFER */ + ActualFileName = strdup(ActualFileName); // must survive Dir! + } + } +@@ -168,6 +193,125 @@ bool RemoveVideoFile(const char *FileNam + return RemoveFileOrDir(FileName, true); + } + ++#ifdef USE_HARDLINKCUTTER ++static bool StatNearestDir(const char *FileName, struct stat *Stat) ++{ ++ cString Name(FileName); ++ char *p; ++ while ((p = strrchr((const char*)Name + 1, '/')) != NULL) { ++ *p = 0; // truncate at last '/' ++ if (stat(Name, Stat) == 0) { ++ isyslog("StatNearestDir: Stating %s", (const char*)Name); ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool HardLinkVideoFile(const char *OldName, const char *NewName) ++{ ++ // Incoming name must be in base video directory: ++ if (strstr(OldName, VideoDirectory) != OldName) { ++ esyslog("ERROR: %s not in %s", OldName, VideoDirectory); ++ return false; ++ } ++ if (strstr(NewName, VideoDirectory) != NewName) { ++ esyslog("ERROR: %s not in %s", NewName, VideoDirectory); ++ return false; ++ } ++ ++ const char *ActualNewName = NewName; ++ cString ActualOldName(ReadLink(OldName), true); ++ ++ // Some safety checks: ++ struct stat StatOldName; ++ if (lstat(ActualOldName, &StatOldName) == 0) { ++ if (S_ISLNK(StatOldName.st_mode)) { ++ esyslog("HardLinkVideoFile: Failed to resolve symbolic link %s", (const char*)ActualOldName); ++ return false; ++ } ++ } ++ else { ++ esyslog("HardLinkVideoFile: lstat failed on %s", (const char*)ActualOldName); ++ return false; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", (const char*)ActualOldName, (int)StatOldName.st_dev); ++ ++ // Find the video directory where ActualOldName is located ++ ++ cVideoDirectory Dir; ++ struct stat StatDir; ++ if (!StatNearestDir(NewName, &StatDir)) { ++ esyslog("HardLinkVideoFile: stat failed on %s", NewName); ++ return false; ++ } ++ ++ isyslog("HardLinkVideoFile: %s is on %i", NewName, (int)StatDir.st_dev); ++ if (StatDir.st_dev != StatOldName.st_dev) { ++ // Not yet found. ++ ++ if (!Dir.IsDistributed()) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Search in video01 and upwards ++ bool found = false; ++ while (Dir.Next()) { ++ Dir.Store(); ++ const char *TmpNewName = Dir.Adjust(NewName); ++ if (StatNearestDir(TmpNewName, &StatDir) && StatDir.st_dev == StatOldName.st_dev) { ++ isyslog("HardLinkVideoFile: %s is on %i (match)", TmpNewName, (int)StatDir.st_dev); ++ ActualNewName = TmpNewName; ++ found = true; ++ break; ++ } ++ isyslog("HardLinkVideoFile: %s is on %i", TmpNewName, (int)StatDir.st_dev); ++ } ++ if (ActualNewName == NewName) { ++ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); ++ return false; ++ } ++ ++ // Looking good, we have a match. Create necessary folders. ++ if (!MakeDirs(ActualNewName, false)) ++ return false; ++ // There's no guarantee that the directory of ActualNewName ++ // is on the same device as the dir that StatNearestDir found. ++ // But worst case is that the link fails. ++ } ++ ++#ifdef HARDLINK_TEST_ONLY ++ // Do the hard link to *.vdr_ for testing only ++ char *name = NULL; ++ asprintf(&name, "%s_",ActualNewName); ++ link(ActualOldName, name); ++ free(name); ++ return false; ++#endif // HARDLINK_TEST_ONLY ++ ++ // Try creating the hard link ++ if (link(ActualOldName, ActualNewName) != 0) { ++ // Failed to hard link. Maybe not allowed on file system. ++ LOG_ERROR_STR(ActualNewName); ++ isyslog("HardLinkVideoFile: failed to hard link from %s to %s", (const char*)ActualOldName, ActualNewName); ++ return false; ++ } ++ ++ if (ActualNewName != NewName) { ++ // video01 and up. Do the remaining symlink ++ if (symlink(ActualNewName, NewName) < 0) { ++ LOG_ERROR_STR(NewName); ++ return false; ++ } ++ } ++#ifdef USE_STREAMDEVEXT ++ cStatus::MsgRecordingChange(Recordings.GetByName(NewName), scMod); ++#endif /* STREAMDEVEXT */ ++ return true; ++} ++#endif /* HARDLINKCUTTER */ ++ + bool VideoFileSpaceAvailable(int SizeMB) + { + cVideoDirectory Dir; +@@ -232,6 +376,129 @@ void RemoveEmptyVideoDirectories(void) + } while (Dir.Next()); + } + ++#ifdef USE_DVLVIDPREFER ++// returns path to nVid'th video directory or NULL if not existing ++char *cVideoDirectory::GetVidPath(int nVid) ++{ ++ char *b = strdup(VideoDirectory); ++ int l = strlen(b), di, n; ++ ++ while (l-- > 0 && isdigit(b[ l ])); ++ ++ l++; ++ di = strlen(b) - l; ++ ++ // di == number of digits ++ n = atoi(&b[ l ]); ++ if (n != 0) ++ return NULL; ++ ++ // add requested number to dir name ++ sprintf(&b[ l ], "%0*d", di, nVid); ++ ++ if (DirectoryOk(b) == true) ++ return b; ++ ++ free(b); ++ return NULL; ++} ++ ++// checks if a video dir is 'valid' ++bool cVideoDirectory::IsVidDirOK(int nVid, int *freeMB) ++{ ++ char *dn; ++ int fMB; ++ ++ if (nVid >= Setup.nVidPrefer) ++ return false; ++ ++ if (Setup.VidPreferSize[ nVid ] == -1) ++ return false; ++ ++ dn = GetVidPath(nVid); ++ if (dn == NULL) ++ return false; ++ ++ fMB = FreeDiskSpaceMB(dn, NULL); ++ if (freeMB != NULL) ++ *freeMB = fMB; ++ ++ free(dn); ++ ++ if (Setup.VidPreferSize[ nVid ] >= fMB) ++ return false; ++ return true; ++} ++ ++ ++// calculates which video dir to use ++bool cVideoDirectory::GetPreferedVideoDir(void) ++{ ++ cVideoDirectory d; ++ int nDirs = 1, ++ vidUse = Setup.nVidPrefer; ++ int i, top, topFree, x; ++ ++ if (name == NULL) ++ return(false); ++ ++ // count available video dirs ++ while (d.Next() == true) ++ nDirs++; ++ ++ if (vidUse > nDirs) ++ vidUse = nDirs; ++ ++ // check for prefered video dir ++ for (i = 0, top = -1, topFree = 0; i < vidUse; i++) { ++ if (IsVidDirOK(i, &x) == true) { ++ if (top == -1) { ++ // nothing set yet, use first 'ok' dir ++ top = i; ++ topFree = x; ++ } ++ else { ++ // check if we got a higher priority ++ if (Setup.VidPreferPrio[ i ] >= Setup.VidPreferPrio[ top ]) { ++ top = i; ++ topFree = x; ++ } ++ // check if we got same priority but more space ++ else if (Setup.VidPreferPrio[ i ] == Setup.VidPreferPrio[ top ] && x >= topFree) { ++ top = i; ++ topFree = x; ++ } ++ } ++ } ++ } ++ ++ if (top == -1) { ++ isyslog("VidPrefer: no prefered video directory could be determined!"); ++ ++ // something went wrong here... ++ // let VDR determine the video directory ++ int MaxFree = FreeMB(); ++ ++ while (Next()) { ++ int Free = FreeDiskSpaceMB(Name()); ++ ++ if (Free > MaxFree) { ++ Store(); ++ MaxFree = Free; ++ } ++ } ++ } ++ else { ++ isyslog("VidPrefer: prefered video directory '%d' set.", top); ++ if (stored != NULL) ++ free(stored); ++ stored = GetVidPath(top); ++ } ++ ++ return true; ++} ++#endif /* DVLVIDPREFER */ ++ + bool IsOnVideoDirectoryFileSystem(const char *FileName) + { + cVideoDirectory Dir; +diff -ruNp vdr-1.7.5/videodir.h vdr-1.7.5-extensions/videodir.h +--- vdr-1.7.5/videodir.h 2008-02-16 13:53:11.000000000 +0100 ++++ vdr-1.7.5-extensions/videodir.h 2009-04-12 13:37:59.000000000 +0200 +@@ -19,6 +19,9 @@ cUnbufferedFile *OpenVideoFile(const cha + int CloseVideoFile(cUnbufferedFile *File); + bool RenameVideoFile(const char *OldName, const char *NewName); + bool RemoveVideoFile(const char *FileName); ++#ifdef USE_HARDLINKCUTTER ++bool HardLinkVideoFile(const char *OldName, const char *NewName); ++#endif /* HARDLINKCUTTER */ + bool VideoFileSpaceAvailable(int SizeMB); + int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent + cString PrefixVideoFileName(const char *FileName, char Prefix); diff --git a/vdr/install-vdr.sh b/vdr/install-vdr.sh new file mode 100644 index 0000000..bcbe098 --- /dev/null +++ b/vdr/install-vdr.sh @@ -0,0 +1,987 @@ +#!/bin/sh + +# x-vdr (Installations-Skript fuer einen VDR mit Debian als Basis) +# von Marc Wernecke - www.zulu-entertainment.de +# 10.04.2009 + +# defaults +VDRVERSION="1.6.0" +MTPATCHES="" # MTPATCHES="1 2 3" +VDROPTIONS="" # hier bitte nur zusaetzliche Optionen eintragen +DIR=$(pwd) + +# config files +[ -f ./patchlevel.conf ] && source ./patchlevel.conf +source ./../x-vdr.conf +source ./../setup.conf +# functions +source ./../functions + +verify_vdrversion "$VDRVERSION" || exit 1 +[ $(( ${VDRVERSION:2:1} % 2 )) -eq 0 ] && VDRWEB="ftp://ftp.cadsoft.de/vdr" || VDRWEB="ftp://ftp.cadsoft.de/vdr/Developer" + +# create error file +error_file="$SOURCEDIR/x-vdr/.error" +echo "install-vdr.sh " > $error_file +log "****************************************" +log "Vorbereitungen fuer den VDR ..." +log "****************************************" + +# check input (on/off) +AUTOSTART=`verify_input "$AUTOSTART"` +INS_USER=`verify_input "$INS_USER"` +USEVFAT=`verify_input "$USEVFAT"` +USELIRC=`verify_input "$USELIRC"` +VDRUPDATE=`verify_input "$VDRUPDATE"` +vdr_plugins=`verify_input "$vdr_plugins"` +analogtv=`verify_input "$analogtv"` +burn=`verify_input "$burn"` +channelblocker=`verify_input "$channelblocker"` +dxr3=`verify_input "$dxr3"` +epgsearch=`verify_input "$epgsearch"` +extrecmenu=`verify_input "$extrecmenu"` +graphtft=`verify_input "$graphtft"` +iptv=`verify_input "$iptv"` +menuorg=`verify_input "$menuorg"` +noepgmenu=`verify_input "$noepgmenu"` +pin=`verify_input "$pin"` +pvrinput=`verify_input "$pvrinput"` +pvrusb2=`verify_input "$pvrusb2"` +reelbox=`verify_input "$reelbox"` +reelchannelscan=`verify_input "$reelchannelscan"` +remoteosd=`verify_input "$remoteosd"` +remotetimers=`verify_input "$remotetimers"` +rotor=`verify_input "$rotor"` +setup=`verify_input "$setup"` +submenu=`verify_input "$submenu"` +subtitles=`verify_input "$subtitles"` +ttxtsubs=`verify_input "$ttxtsubs"` +yaepg=`verify_input "$yaepg"` +verify_patchlevel + +# pre-install +if [ ! -d $SOURCEDIR/DVB ]; then + if [ -d /usr/include/linux/dvb ]; then + if [ ! -f /usr/include/linux/compiler.h ]; then + cd /usr/include/linux + if [ -f /usr/src/linux/include/linux/compiler.h ]; then + ln -s /usr/src/linux/include/linux/compiler.h compiler.h + elif [ -f /usr/src/$(uname -r)/include/linux/compiler.h ]; then + ln -s /usr/src/$(uname -r)/include/linux/compiler.h compiler.h + elif [ -f /usr/src/linux-headers-$(uname -r)/include/linux/compiler.h ]; then + ln -s /usr/src/linux-headers-$(uname -r)/include/linux/compiler.h compiler.h + else + log "***************************************" + log "VDR Fehler! - compiler.h nicht gefunden" + log "***************************************" + echo "- /usr/src/linux/include/linux/compiler.h nicht gefunden." >> $error_file + exit 1 + fi + fi + else + log "****************************************" + log "VDR Fehler! - DVB Treiber nicht gefunden" + log "****************************************" + echo "- dvb-treiber nicht gefunden." >> $error_file + exit 1 + fi +fi + +# DVB_API_VERSION +get_dvbapi + +## VDR-Source +# download VDR-Source +if [ ! -f $FILES/vdr/vdr-$VDRVERSION.tar.bz2 ]; then + log "vdr-$VDRVERSION.tar.bz2 nicht gefunden" + log "Starte download" + wget --tries=2 "$VDRWEB/vdr-$VDRVERSION.tar.bz2" --directory-prefix="$FILES/vdr" +else + log "vdr-$VDRVERSION.tar.bz2 gefunden" +fi + +if [ ! -f "$FILES/vdr/vdr-$VDRVERSION.tar.bz2" ]; then + log "****************************************" + log "VDR Fehler!" + log "vdr-$VDRVERSION.tar.bz2 nicht gefunden" + log "****************************************" + echo "- vdr-$VDRVERSION.tar.bz2 konnte nicht geladen werden" >> $error_file + exit 1 +fi + +# untar VDR-Source +tar xjf "$FILES/vdr/vdr-$VDRVERSION.tar.bz2" -C $SOURCEDIR && log "Extrahiere vdr-$VDRVERSION.tar.bz2" + +# create VDR-Symlink +cd $SOURCEDIR +ln -vnfs vdr-$VDRVERSION VDR + +# create vdruser +[ "$VDRUPDATE" != "on" ] && make_user + +# create Directories +[ "$VDRUPDATE" != "on" ] && make_dirs + +# create VDR make.config +function make_makeconfig() { + MAKECONFIG="$SOURCEDIR/VDR/Make.config" + [ -f $MAKECONFIG ] && mv -f $MAKECONFIG $MAKECONFIG.old + + { + echo "#" + echo "# User defined Makefile options for the Video Disk Recorder" + echo "#" + echo "# Copy this file to 'Make.config' and change the parameters as necessary." + echo "#" + echo "# See the main source file 'vdr.c' for copyright information and" + echo "# how to reach the author." + echo "#" + echo "# \$Id: Make.config.template 1.10 2006/06/15 09:15:25 kls Exp \$" + echo "" + echo "# $(date)" + echo "# modified for x-vdr" + echo "" + echo "### The C compiler and options:" + echo "CC = gcc" + echo "CFLAGS = -g -O2 -Wall" + echo "" + echo "CXX = g++" + echo "CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual" + echo "" + echo "ifdef PLUGIN" + echo "CFLAGS += -fPIC" + echo "CXXFLAGS += -fPIC" + if [ ${VDRVERSION:2:1} -gt 6 -a ${VDRVERSION:4:1} -gt 2 -o ${VDRVERSION:2:1} -gt 7 ]; then + echo "DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE" + fi + echo "endif" + echo "" + echo "DEFINES += -D__KERNEL_STRICT_NAMES" + echo "" + echo "### The directory environment:" + echo "" + if [ -f "$SOURCEDIR/DVB/linux/include/linux/dvb/version.h" ]; then + echo "DVBDIR= $SOURCEDIR/DVB/linux" + else + echo "#DVBDIR= $SOURCEDIR/v4l-dvb/linux" + fi + echo "MANDIR= $VDRMANDIR" + echo "BINDIR= $VDRBINDIR" + echo "" + echo "LOCDIR= $VDRLOCDIR" + echo "PLUGINDIR= ./PLUGINS" + echo "PLUGINLIBDIR= $VDRLIBDIR" + echo "VIDEODIR= $VIDEODIR" + echo "CONFDIR= $VDRCONFDIR" + echo "" + echo "LIBDIR= \$(PLUGINLIBDIR)" + echo "" + echo "### The remote control:" + echo "" + echo "LIRC_DEVICE = /dev/lircd" + echo "RCU_DEVICE = /dev/ttyS1" + echo "" + echo "## Define if you want vdr to not run as root" + echo "#VDR_USER = $VDRUSER" + echo "" + echo "### Extra Options:" + echo "" + + if [ "$USELIRC" = "on" ]; then + echo "REMOTE= LIRC" + else + echo "#REMOTE= LIRC" + fi + + if [ "$USEVFAT" = "on" ]; then + echo "VFAT= 1" + else + echo "#VFAT= 1" + fi + + if [ "$dxr3" = "on" ]; then + echo "EM8300= $SOURCEDIR/em8300/include" + fi + + if [ "$ffmpeg" = "on" ]; then + echo "FFMDIR= $SOURCEDIR/ffmpeg" + else + echo "FFMDIR= /usr/include/ffmpeg" + fi + + if [ "$burn" = "on" ]; then + echo "DVDDEV= $DVDBURNER" + echo "ISODIR= $DVDISODIR" + fi + + if [ "$tvm2vdr" = "on" ]; then + echo "DEFINES += -DTVM2VDR_DATA_DIR=$VDRVARDIR" + else + echo "#DEFINES += -DTVM2VDR_DATA_DIR=$VDRVARDIR" + fi + + if [ "$PATCHLEVEL" = "EXTENSIONS" ]; then + echo "" + echo "### VDR-Extensions:" + echo "# Comment the patches you don't need" + echo "# DVDCHAPJUMP needs DVDARCHIVE enabled" + echo "# DVDARCHIVE needs LIEMIEXT enabled" + echo "# SORTRECORDS needs LIEMIEXT enabled" + echo "# you can only enable one of MENUORG SUBMENU SETUP" + echo "" + + if [ "$ANALOGTV" = "on" ] || [ "$analogtv" = "on" ] || [ "$pvrinput" = "on" ] || [ "$pvrusb2" = "on" ]; then + echo "ANALOGTV = 1" + else + echo "#ANALOGTV = 1" + fi + + if [ "$ATSC" = "on" ]; then + echo "ATSC = 1" + else + echo "#ATSC = 1" + fi + + if [ "$CHANNELSCAN" = "on" ] || [ "$reelchannelscan" = "on" ]; then + echo "CHANNELSCAN = 1" + else + echo "#CHANNELSCAN = 1" + fi + + if [ "$CMDRECCMDI18N" = "on" ]; then + echo "CMDRECCMDI18N = 1" + else + echo "#CMDRECCMDI18N = 1" + fi + + if [ "$CMDSUBMENU" = "on" ]; then + echo "CMDSUBMENU = 1" + else + echo "#CMDSUBMENU = 1" + fi + + if [ "$CUTTERLIMIT" = "on" ]; then + echo "CUTTERLIMIT = 1" + else + echo "#CUTTERLIMIT = 1" + fi + + if [ "$CUTTERQUEUE" = "on" ]; then + echo "CUTTERQUEUE = 1" + else + echo "#CUTTERQUEUE = 1" + fi + + if [ "$CUTTIME" = "on" ]; then + echo "CUTTIME = 1" + else + echo "#CUTTIME = 1" + fi + + if [ "$DELTIMESHIFTREC" = "on" ]; then + echo "DELTIMESHIFTREC = 1" + else + echo "#DELTIMESHIFTREC = 1" + fi + + if [ "$DDEPGENTRY" = "on" ]; then + echo "DDEPGENTRY = 1" + else + echo "#DDEPGENTRY = 1" + fi + + if [ "$DOLBYINREC" = "on" ]; then + echo "DOLBYINREC = 1" + else + echo "#DOLBYINREC = 1" + fi + + if [ "$DVBPLAYER" = "on" ]; then + echo "DVBPLAYER = 1" + else + echo "#DVBPLAYER = 1" + fi + + if [ "$DVBSETUP" = "on" ] || [ "$channelblocker" = "on" ]; then + echo "DVBSETUP = 1" + else + echo "#DVBSETUP = 1" + fi + + if [ "$DVDARCHIVE" = "on" ]; then + echo "DVDARCHIVE = 1" + else + echo "#DVDARCHIVE = 1" + fi + + if [ "$DVDCHAPJUMP" = "on" ]; then + echo "DVDCHAPJUMP = 1" + else + echo "#DVDCHAPJUMP = 1" + fi + + if [ "$DVLFRIENDLYFNAMES" = "on" ]; then + echo "DVLFRIENDLYFNAMES = 1" + else + echo "#DVLFRIENDLYFNAMES = 1" + fi + + if [ "$DVLRECSCRIPTADDON" = "on" ]; then + echo "DVLRECSCRIPTADDON = 1" + else + echo "#DVLRECSCRIPTADDON = 1" + fi + + if [ "$DVLVIDPREFER" = "on" ]; then + echo "DVLVIDPREFER = 1" + else + echo "#DVLVIDPREFER = 1" + fi + + if [ "$EM84XX" = "on" ] || [ "$em84xx" = "on" ]; then + echo "EM84XX = 1" + else + echo "#EM84XX = 1" + fi + + if [ "$GOTOX" = "on" ]; then + echo "GOTOX = 1" + else + echo "#GOTOX = 1" + fi + + if [ "$GRAPHTFT" = "on" ] || [ "$graphtft" = "on" ]; then + echo "GRAPHTFT = 1" + else + echo "#GRAPHTFT = 1" + fi + + if [ "$HARDLINKCUTTER" = "on" ]; then + echo "HARDLINKCUTTER = 1" + else + echo "#HARDLINKCUTTER = 1" + fi + + if [ "$JUMPPLAY" = "on" ]; then + echo "JUMPPLAY = 1" + else + echo "#JUMPPLAY = 1" + fi + + if [ "$LIEMIEXT" = "on" ]; then + echo "LIEMIEXT = 1" + else + echo "#LIEMIEXT = 1" + fi + + if [ "$LIRCSETTINGS" = "on" ]; then # || [ "$USELIRC" = "on" ] + echo "LIRCSETTINGS = 1" + else + echo "#LIRCSETTINGS = 1" + fi + + if [ "$LIVEBUFFER" = "on" ]; then + echo "LIVEBUFFER = 1" + else + echo "#LIVEBUFFER = 1" + fi + + if [ "$LNBSHARE" = "on" ]; then + echo "LNBSHARE = 1" + else + echo "#LNBSHARE = 1" + fi + + if [ "$MAINMENUHOOKS" = "on" ] || [ "$epgsearch" = "on" ] || [ "$extrecmenu" = "on" ] || [ "$remoteosd" = "on" ] || [ "$remotetimers" = "on" ]; then + echo "MAINMENUHOOKS = 1" + else + echo "#MAINMENUHOOKS = 1" + fi + + if [ "$MENUORG" = "on" ] || [ "$menuorg" = "on" ]; then + SETUP="off" + setup="off" + SUBMENU="off" + submenu="off" + echo "MENUORG = 1" + else + echo "#MENUORG = 1" + fi + + if [ "$NOEPG" = "on" ] || [ "$noepgmenu" = "on" ]; then + echo "NOEPG = 1" + else + echo "#NOEPG = 1" + fi + + if [ "$OSDMAXITEMS" = "on" ] || [ "$text2skin" = "on" ]; then + echo "OSDMAXITEMS = 1" + else + echo "#OSDMAXITEMS = 1" + fi + + if [ "$PARENTALRATING" = "on" ]; then + echo "PARENTALRATING = 1" + else + echo "#PARENTALRATING = 1" + fi + + if [ "$PINPLUGIN" = "on" ] || [ "$pin" = "on" ]; then + echo "PINPLUGIN = 1" + else + echo "#PINPLUGIN = 1" + fi + + if [ "$PLUGINAPI" = "on" ]; then + echo "PLUGINAPI = 1" + else + echo "#PLUGINAPI = 1" + fi + + if [ "$PLUGINMISSING" = "on" ]; then + echo "PLUGINMISSING = 1" + else + echo "#PLUGINMISSING = 1" + fi + + if [ "$PLUGINPARAM" = "on" ] || [ "$iptv" = "on" ]; then + echo "PLUGINPARAM = 1" + else + echo "#PLUGINPARAM = 1" + fi + + if [ "$REELPLUGIN" = "on" ] || [ "$reelbox" = "on" ]; then + echo "REELPLUGIN = 1" + else + echo "#REELPLUGIN = 1" + fi + + if [ "$ROTOR" = "on" ] || [ "$rotor" = "on" ]; then + echo "ROTOR = 1" + else + echo "#ROTOR = 1" + fi + + if [ "$SETTIME" = "on" ]; then + echo "SETTIME = 1" + else + echo "#SETTIME = 1" + fi + + if [ "$SETUP" = "on" ] || [ "$setup" = "on" ]; then + echo "SETUP = 1" + SUBMENU="off" + submenu="off" + else + echo "#SETUP = 1" + fi + + if [ "$SOFTOSD" = "on" ]; then + echo "SOFTOSD = 1" + else + echo "#SOFTOSD = 1" + fi + + if [ "$SOURCECAPS" = "on" ]; then + echo "SOURCECAPS = 1" + else + echo "#SOURCECAPS = 1" + fi + + if [ "$SORTRECORDS" = "on" ]; then + echo "SORTRECORDS = 1" + else + echo "#SORTRECORDS = 1" + fi + + if [ "$SUBMENU" = "on" ] || [ "$submenu" = "on" ]; then + echo "SUBMENU = 1" + else + echo "#SUBMENU = 1" + fi + + if [ "$STREAMDEVEXT" = "on" ]; then + echo "STREAMDEVEXT = 1" + else + echo "#STREAMDEVEXT = 1" + fi + + if [ "$SYNCEARLY" = "on" ]; then + echo "SYNCEARLY = 1" + else + echo "#SYNCEARLY = 1" + fi + + if [ "$TIMERCMD" = "on" ]; then + echo "TIMERCMD = 1" + else + echo "#TIMERCMD = 1" + fi + + if [ "$TIMERINFO" = "on" ]; then + echo "TIMERINFO = 1" + else + echo "#TIMERINFO = 1" + fi + + if [ "$TTXTSUBS" = "on" ] || [ "$ttxtsubs" = "on" ]; then + echo "TTXTSUBS = 1" + else + echo "#TTXTSUBS = 1" + fi + + if [ "$VALIDINPUT" = "on" ]; then + echo "VALIDINPUT = 1" + else + echo "#VALIDINPUT = 1" + fi + + if [ "$VOLCTRL" = "on" ]; then + echo "VOLCTRL = 1" + else + echo "#VOLCTRL = 1" + fi + + if [ "$WAREAGLEICON" = "on" ]; then + echo "WAREAGLEICON = 1" + else + echo "#WAREAGLEICON = 1" + fi + + if [ "$YAEPG" = "on" ] || [ "$yaepg" = "on" ]; then + echo "YAEPG = 1" + else + echo "#YAEPG = 1" + fi + fi + echo "" + echo "" + echo "### You don't need to touch the following:" + echo "" + echo "ifdef DVBDIR" + echo "INCLUDES += -I\$(DVBDIR)/include" + echo "endif" + echo "" + if [ "$PATCHLEVEL" = "EXTENSIONS" ]; then + echo "ifdef ANALOGTV" + echo "DEFINES += -DUSE_ANALOGTV" + echo "endif" + echo "" + echo "ifdef ATSC" + echo "DEFINES += -DUSE_ATSC" + echo "endif" + echo "" + echo "ifdef CHANNELSCAN" + echo "DEFINES += -DUSE_CHANNELSCAN" + echo "endif" + echo "" + echo "ifdef CMDRECCMDI18N" + echo "DEFINES += -DUSE_CMDRECCMDI18N" + echo "endif" + echo "" + echo "ifdef CMDSUBMENU" + echo "DEFINES += -DUSE_CMDSUBMENU" + echo "endif" + echo "" + echo "ifdef CUTTERLIMIT" + echo "DEFINES += -DUSE_CUTTERLIMIT" + echo "endif" + echo "" + echo "ifdef CUTTERQUEUE" + echo "DEFINES += -DUSE_CUTTERQUEUE" + echo "endif" + echo "" + echo "ifdef CUTTIME" + echo "DEFINES += -DUSE_CUTTIME" + echo "endif" + echo "" + echo "ifdef DELTIMESHIFTREC" + echo "DEFINES += -DUSE_DELTIMESHIFTREC" + echo "endif" + echo "" + echo "ifdef DDEPGENTRY" + echo "DEFINES += -DUSE_DDEPGENTRY" + echo "endif" + echo "" + echo "ifdef DOLBYINREC" + echo "DEFINES += -DUSE_DOLBYINREC" + echo "endif" + echo "" + echo "ifdef DVBPLAYER" + echo "DEFINES += -DUSE_DVBPLAYER" + echo "endif" + echo "" + echo "ifdef DVBSETUP" + echo "DEFINES += -DUSE_DVBSETUP" + echo "endif" + echo "" + echo "ifdef DVDARCHIVE" + echo "ifdef LIEMIEXT" + echo "DEFINES += -DUSE_DVDARCHIVE" + echo "endif" + echo "endif" + echo "" + echo "ifdef DVLRECSCRIPTADDON" + echo "DEFINES += -DUSE_DVLRECSCRIPTADDON" + echo "endif" + echo "" + echo "ifdef DVLVIDPREFER" + echo "DEFINES += -DUSE_DVLVIDPREFER" + echo "endif" + echo "" + echo "ifdef DVLFRIENDLYFNAMES" + echo "DEFINES += -DUSE_DVLFRIENDLYFNAMES" + echo "endif" + echo "" + echo "ifdef EM84XX" + echo "DEFINES += -DUSE_EM84XX" + echo "endif" + echo "" + echo "ifdef GOTOX" + echo "DEFINES += -DUSE_GOTOX" + echo "endif" + echo "" + echo "ifdef GRAPHTFT" + echo "DEFINES += -DUSE_GRAPHTFT" + echo "endif" + echo "" + echo "ifdef HARDLINKCUTTER" + echo "DEFINES += -DUSE_HARDLINKCUTTER" + echo "endif" + echo "" + echo "ifdef JUMPPLAY" + echo "DEFINES += -DUSE_JUMPPLAY" + echo "endif" + echo "" + echo "ifdef LIEMIEXT" + echo "DEFINES += -DUSE_LIEMIEXT" + echo "endif" + echo "" + echo "ifdef LIRCSETTINGS" + echo "DEFINES += -DUSE_LIRCSETTINGS" + echo "endif" + echo "" + echo "ifdef LIVEBUFFER" + echo "DEFINES += -DUSE_LIVEBUFFER" + echo "endif" + echo "" + echo "ifdef LNBSHARE" + echo "DEFINES += -DUSE_LNBSHARE" + echo "endif" + echo "" + echo "ifdef MAINMENUHOOKS" + echo "DEFINES += -DUSE_MAINMENUHOOKS" + echo "endif" + echo "" + echo "ifdef MENUORG" + echo "DEFINES += -DUSE_MENUORG" + echo "else" + echo "ifdef SETUP" + echo "DEFINES += -DUSE_SETUP" + echo "else" + echo "ifdef SUBMENU" + echo "DEFINES += -DUSE_SUBMENU" + echo "endif" + echo "endif" + echo "endif" + echo "" + echo "ifdef NOEPG" + echo "DEFINES += -DUSE_NOEPG" + echo "endif" + echo "" + echo "ifdef OSDMAXITEMS" + echo "DEFINES += -DUSE_OSDMAXITEMS" + echo "endif" + echo "" + echo "ifdef PARENTALRATING" + echo "DEFINES += -DUSE_PARENTALRATING" + echo "endif" + echo "" + echo "ifdef PINPLUGIN" + echo "DEFINES += -DUSE_PINPLUGIN" + echo "endif" + echo "" + echo "ifdef PLUGINMISSING" + echo "DEFINES += -DUSE_PLUGINMISSING" + echo "endif" + echo "" + echo "ifdef PLUGINPARAM" + echo "DEFINES += -DUSE_PLUGINPARAM" + echo "endif" + echo "" + echo "ifdef REELPLUGIN" + echo "DEFINES += -DUSE_REELPLUGIN" + echo "endif" + echo "" + echo "ifdef ROTOR" + echo "DEFINES += -DUSE_ROTOR" + echo "endif" + echo "" + echo "ifdef SETTIME" + echo "DEFINES += -DUSE_SETTIME" + echo "endif" + echo "" + echo "ifdef SOFTOSD" + echo "DEFINES += -DUSE_SOFTOSD" + echo "endif" + echo "" + echo "ifdef SOURCECAPS" + echo "DEFINES += -DUSE_SOURCECAPS" + echo "endif" + echo "" + echo "ifdef SORTRECORDS" + echo "ifdef LIEMIEXT" + echo "DEFINES += -DUSE_SORTRECORDS" + echo "endif" + echo "endif" + echo "" + echo "ifdef STREAMDEVEXT" + echo "DEFINES += -DUSE_STREAMDEVEXT" + echo "endif" + echo "" + echo "ifdef SYNCEARLY" + echo "DEFINES += -DUSE_SYNCEARLY" + echo "endif" + echo "" + echo "ifdef TIMERCMD" + echo "DEFINES += -DUSE_TIMERCMD" + echo "endif" + echo "" + echo "ifdef TIMERINFO" + echo "DEFINES += -DUSE_TIMERINFO" + echo "endif" + echo "" + echo "ifdef TTXTSUBS" + echo "DEFINES += -DUSE_TTXTSUBS" + echo "endif" + echo "" + echo "ifdef VALIDINPUT" + echo "DEFINES += -DUSE_VALIDINPUT" + echo "endif" + echo "" + echo "ifdef VOLCTRL" + echo "DEFINES += -DUSE_VOLCTRL" + echo "endif" + echo "" + echo "ifdef WAREAGLEICON" + echo "DEFINES += -DUSE_WAREAGLEICON" + echo "endif" + echo "" + echo "ifdef YAEPG" + echo "DEFINES += -DUSE_YAEPG" + echo "endif" + echo "" + else + if [ "$setup" = "on" ] || [ "$SETUP" = "on" ]; then + echo "DEFINES += -DUSE_LIVEBUFFER" + echo "" + fi + fi + } > $MAKECONFIG +} +make_makeconfig + +## patch VDR +cd $SOURCEDIR/VDR + +# download vdr-maintenance patches +if [ -n "$MTPATCHES" ]; then + for n in $MTPATCHES; do + if [ -f $DIR/maintenance/vdr-$VDRVERSION-$n.diff ]; then + log "vdr-$VDRVERSION-$n.diff gefunden" + else + wget -q --tries=1 "$VDRWEB/Developer/vdr-$VDRVERSION-$n.diff" --directory-prefix="$DIR/maintenance" + [ ! -f $DIR/maintenance/vdr-$VDRVERSION-$n.diff ] && break + log "vdr-$VDRVERSION-$n.diff geladen" + fi + done +fi + +# apply vdr-maintenance patches +for i in `ls $DIR/maintenance | grep "vdr-$VDRVERSION-.*.diff$"`; do + log "apply $i" + patch -f -p 1 < $DIR/maintenance/$i +done + +# check if dvb-api-wrapper is needed +if [ ${VDRVERSION:2:1} -gt 6 ] && [ "$PATCHLEVEL" != "PLAIN" ]; then + if [ $DVB_API_VERSION -lt 5 -a ${VDRVERSION:4:1} -gt 1 -o ${VDRVERSION:2:1} -gt 7 ] || + [ $DVB_API_VERSION -eq 3 -a $DVB_API_VERSION_MINOR -lt 3 ]; then + api_wrapper_patch=$(ls -r $DIR | grep -m1 "^vdr-$VDRVERSION.*s2apiwrapper.*.diff$") + [ -n "$api_wrapper_patch" ] || api_wrapper_patch=$(ls -r $DIR | grep -m1 "^vdr-1.7.*s2apiwrapper.*.diff$") + if [ -n "$api_wrapper_patch" ]; then + log "apply $api_wrapper_patch" + patch -f -p 1 < $DIR/$api_wrapper_patch + else + echo "- DVB_API_VERSION < 5 und api_wrapper_patch nicht gefunden." >> $error_file + log "DVB_API_VERSION < 5 und api_wrapper_patch nicht gefunden" + exit 1 + fi + fi +fi + +# apply extensions +if [ "$PATCHLEVEL" = "EXTENSIONS" ]; then + extensions_patch=$(ls -r $DIR/extensions | grep -m1 "^vdr-${VDRVERSION}_extensions.diff$") + [ -n "$extensions_patch" ] || extensions_patch=$(ls -r $DIR/extensions | grep -m1 "^vdr-${VDRVERSION}.*_extensions.diff$") + [ -n "$extensions_patch" ] || extensions_patch=$(ls -r $DIR/extensions | grep -m1 "^vdr-.*_extensions.diff$") + if [ -n "$extensions_patch" ]; then + log "apply $extensions_patch" + patch -f -p 1 < $DIR/extensions/$extensions_patch + # search for more extensions + for i in `ls $DIR/extensions | grep "^vdr-${VDRVERSION}.*-ext.*_.*.diff$"`; do + log "apply $i" + patch -f -p 1 < $DIR/extensions/$i + done + else + echo "- Extensions-Patch nicht gefunden." >> $error_file + log "Extensions-Patch nicht gefunden" + exit 1 + fi +fi + +if [ "$PATCHLEVEL" != "PLAIN" ]; then + # search for *.bz2 + for i in `ls $DIR/patches | grep ".bz2$"`; do + log "apply $i" + bzcat $DIR/patches/$i | patch -f -p 1 + done + # search for *.diff + for i in `ls $DIR/patches | grep ".diff$"`; do + log "apply $i" + patch -f -p 1 < $DIR/patches/$i + done + # search for *.patch + for i in `ls $DIR/patches | grep ".patch$"`; do + log "apply $i" + patch -f -p 1 < $DIR/patches/$i + done +fi + +# remove default plugins +if [ "$vdr_plugins" = "off" ]; then + rm -rf $SOURCEDIR/VDR/PLUGINS/src/hello + rm -rf $SOURCEDIR/VDR/PLUGINS/src/osddemo + rm -rf $SOURCEDIR/VDR/PLUGINS/src/pictures + rm -rf $SOURCEDIR/VDR/PLUGINS/src/servicedemo + rm -rf $SOURCEDIR/VDR/PLUGINS/src/skincurses + rm -rf $SOURCEDIR/VDR/PLUGINS/src/sky + rm -rf $SOURCEDIR/VDR/PLUGINS/src/status + rm -rf $SOURCEDIR/VDR/PLUGINS/src/svdrpdemo +fi + +# make VDR +log "****************************************" +log "Erstellen des VDR ..." +log "****************************************" +cd $SOURCEDIR/VDR +make $VDROPTIONS + +# copy instead of make install +if ! cp -f vdr $VDRPRG ; then + log "****************************************" + log "Fehler! - VDR wurde nicht erstellt." + log "****************************************" + echo "- $VDRPRG konnte nicht erstellt werden." >> $error_file + exit 1 +fi + +# copy locale +if [ -d $SOURCEDIR/VDR/locale ]; then + [ ! -d $VDRLOCDIR ] && mkdir -p $VDRLOCDIR && log "Erstelle $VDRLOCDIR" + cp -fR $SOURCEDIR/VDR/locale/* $VDRLOCDIR +fi + +# stop if VDRUPDATE=on +if [ "$VDRUPDATE" = "on" ]; then + log "****************************************" + log "Aktualisierung des VDR erfolgreich." + log "****************************************" + # delete error file + [ -f $error_file ] && rm -f $error_file + exit 0 +fi + +# copy / create files +function make_files() { + # kopiere man1 und man5 + gzip -c vdr.1 > $VDRMANDIR/man1/vdr.1.gz + gzip -c vdr.5 > $VDRMANDIR/man5/vdr.5.gz + # vdr-config dateien kopieren + cd $SOURCEDIR/VDR + cp -f svdrpsend.pl $VDRBINDIR + cp -f *.conf $VDRCONFDIR + # config dateien erstellen + cd $SOURCEDIR/x-vdr/vdr + ./make-conf.sh + # eigene config dateien kopieren + cd $SOURCEDIR/x-vdr/vdr/conf + cp -f *.conf $VDRCONFDIR + cp -f _xinitrc $VDRCONFDIR/.xinitrc + # Kanallisten kopieren + [ -d $SOURCEDIR/x-vdr/extra/channellists ] && cp -fR $SOURCEDIR/x-vdr/extra/channellists $VDRCONFDIR + # eigene scripte kopieren + cd $SOURCEDIR/x-vdr/vdr/scripts + # runvdr + cp -f runvdr $VDRBINDIR + # dvd-bc + cp -f burn-bc $VDRBINDIR + # vdrplayer + cp -f vdrplayer $VDRBINDIR + # vdr2root + cp -f vdr2root $VDRSCRIPTDIR + # vdrmount + cp -f vdrmount $VDRSCRIPTDIR + # noad + cp -f vdrnoad $VDRSCRIPTDIR + # shutdown + cp -f vdrshutdown $VDRSCRIPTDIR + # reccmds + cp -f vdrreccmds $VDRSCRIPTDIR + # settime + cp -f vdrsettime $VDRSCRIPTDIR + # vdrsetup + cp -f vdrsetup $VDRSCRIPTDIR + # vdrreaddvd + cp -f vdrreaddvd $VDRSCRIPTDIR + # vdrwritedvd + cp -f vdrwritedvd $VDRSCRIPTDIR + # timerrep.sh + cp -f timerrep.sh $VDRSCRIPTDIR + # kopiere vdr init script + cp -f vdr /etc/init.d + + # rechte setzen + chmod 0755 $VDRBINDIR/runvdr + chmod 0755 $VDRBINDIR/burn-bc + chmod 0755 $VDRBINDIR/vdrplayer + chmod 0755 /etc/init.d/vdr + chmod -R 0744 $VDRSCRIPTDIR + + # mkdir DVD-VCD + if [ ! -d $MEDIADIR/DVD-VCD ]; then + mkdir -p $MEDIADIR/DVD-VCD + touch $MEDIADIR/DVD-VCD/DVD $MEDIADIR/DVD-VCD/VCD + chmod 0666 $MEDIADIR/DVD-VCD/DVD $MEDIADIR/DVD-VCD/VCD + fi + + chown -R $VDRUSER:$VDRGROUP $VDRCONFDIR $VDRSCRIPTDIR $VDRVARDIR $VIDEODIR $MUSICDIR $DIVXDIR $DVDISODIR $MEDIADIR $PICTUREDIR +} +make_files + +# autostart VDR +[ "$AUTOSTART" = "on" ] && make_autostart + +cd $SOURCEDIR + +# create /etc/default/vdr +make_default +log "****************************************" +log "VDR Installation erfolgreich." +log "****************************************" + +# delete error file +[ -f $error_file ] && rm -f $error_file + +exit 0 + diff --git a/vdr/make-conf.sh b/vdr/make-conf.sh new file mode 100644 index 0000000..00e4088 --- /dev/null +++ b/vdr/make-conf.sh @@ -0,0 +1,215 @@ +#!/bin/sh + +# x-vdr (Installations-Skript fuer einen VDR mit Debian als Basis) +# von Marc Wernecke - www.zulu-entertainment.de +# 29.07.2008 + +# defaults +source ./../x-vdr.conf +source ./../setup.conf +#VDRSCRIPTDIR="/usr/lib/vdr/scripts" +#VDRCONFDIR="." + + +# Function +function make_config() { +# create commands.conf +{ +echo "# $VDRCONFDIR/commands.conf +# x-vdr `date '+%F %T'` +# + +V D R : echo true +- Aktualisiere Liste der Aufnahmen : sudo $VDRSCRIPTDIR/vdr2root video-update ; echo \"$VDRBINDIR/svdrpsend.pl HITK Red\"|at now +- Loeschen der EPG daten? : echo \"$VDRBINDIR/svdrpsend.pl CLRE\"|at now +- VDR neustarten? : sudo $VDRSCRIPTDIR/vdr2root vdr-restart +- VDR beenden? : sudo $VDRSCRIPTDIR/vdr2root vdr-stop + +S y s t e m : echo true +- Zeige /var/log/messages : sudo $VDRSCRIPTDIR/vdr2root show-log +- Saeubere /var/log/messages : sudo $VDRSCRIPTDIR/vdr2root clean-log +- Belegung der Laufwerke : df -h|awk '/%/ { printf(\"%4.4s : %5.5s : %s\n\",\$5,\$4,\$6) }' +- Starte SSH? : sudo $VDRSCRIPTDIR/vdr2root ssh-start +- SSH ausschalten? : sudo $VDRSCRIPTDIR/vdr2root ssh-stop +- System neustarten? : sudo $VDRSCRIPTDIR/vdr2root reboot +- System ausschalten? : echo \"$VDRBINDIR/svdrpsend.pl HITK Power\"|at now +" + +if [ "$burn" = "on" ]; then +echo " +B u r n - B C : echo true +- Blend Only : echo \"$VDRBINDIR/burn-bc -f draw-storke -w default\"|at now +- Simple Cropping : echo \"$VDRBINDIR/burn-bc -f 'crop resize draw-storke unsharp' -w default\"|at now +- Zoom Center : echo \"$VDRBINDIR/burn-bc -f 'crop zoom-center resize draw-storke unsharp' -w default\"|at now +- Zoom Left : echo \"$VDRBINDIR/burn-bc -f 'crop zoom-left resize draw-storke unsharp' -w default\"|at now +- Zoom Right : echo \"$VDRBINDIR/burn-bc -f 'crop zoom-right resize draw-storke unsharp' -w default\"|at now +- Serial Foto : echo \"$VDRBINDIR/burn-bc -f 'crop zoom-center resize draw-storke serial-foto unsharp' -w default\"|at now +- Serial Movie : echo \"$VDRBINDIR/burn-bc -f 'crop zoom-center resize draw-storke serial-movie unsharp' -w default\"|at now +- Big Serial Movie : echo \"$VDRBINDIR/burn-bc -f 'crop zoom-center resize draw-bigsize serial-movie unsharp' -w default\"|at now +- 16x9 -> 4x3 : echo \"$VDRBINDIR/burn-bc -f 'zoom-center-16x9 resize draw-storke unsharp' -w default\"|at now +" +fi + +if [ -e "$DVDBURNER" ]; then +echo " +eject dvd : eject $DVDBURNER +" +fi + +if [ "$vdrconvert" = "on" ]; then +echo " +V D R C o n v e r t - SVCD : echo true +- Zu SVCD-Liste : ${PREFIX}/bin/ins.sh vdr2svcd +- Aktiviere SVCD-Liste : ${PREFIX}/bin/convstart.sh vdr2svcd +- Entferne von SVCD-Liste? : ${PREFIX}/bin/del.sh vdr2svcd +- Zeige SVCD-Liste : ${PREFIX}/bin/cap.sh vdr2svcd +V D R C o n v e r t - VCD : echo true +- Zu VCD-Liste : ${PREFIX}/bin/ins.sh vdr2vcd +- Aktiviere VCD-Liste : ${PREFIX}/bin/convstart.sh vdr2vcd +- Entferne von VCD-Liste? : ${PREFIX}/bin/del.sh vdr2vcd +- Zeige VCD-Liste : ${PREFIX}/bin/cap.sh vdr2vcd +V D R C o n v e r t - DIVX : echo true +- Zu DivX-Liste : ${PREFIX}/bin/ins.sh vdr2divx +- Aktiviere DivX : ${PREFIX}/bin/convstart.sh vdr2divx +- Entferne von DivX-Liste? : ${PREFIX}/bin/del.sh vdr2divx +- Zeige DivX-Liste : ${PREFIX}/bin/cap.sh vdr2divx +V D R C o n v e r t - Quickmodus : echo true +- Erstelle DivX sofort? : ${PREFIX}/bin/convnow.sh vdr2divx +- Erstelle DVD sofort? : ${PREFIX}/bin/convnow.sh vdr2dvd +- Erstelle Handy sofort? : ${PREFIX}/bin/convnow.sh vdr2handy +- Erstelle PDA sofort? : ${PREFIX}/bin/convnow.sh vdr2pda +- Erstelle SVCD sofort? : ${PREFIX}/bin/convnow.sh vdr2svcd +- Erstelle VCD sofort? : ${PREFIX}/bin/convnow.sh vdr2vcd +- Erstelle Mpeg ( sync )? : ${PREFIX}/bin/convnow.sh vdr2mpg +- Erstelle Mp3? : ${PREFIX}/bin/convnow.sh vdr2mp3 +- Erstelle ogg? : ${PREFIX}/bin/convnow.sh vdr2ogg +- Erstelle AC3? : ${PREFIX}/bin/convnow.sh vdr2ac3 +" +fi + +if [ "$vdrrip" = "on" ]; then +echo " +vdrrip starten : echo \"$VDRSCRIPTDIR/queuehandler.sh $VDRCONFDIR/plugins/queue.vdrrip /tmp\"|at now +" +fi + +echo " +x-vdr setup : echo \"sudo /usr/lib/vdr/scripts/vdrsetup\"|at now +" +} > $VDRCONFDIR/commands.conf + + + +# reccmds.conf +{ +echo "# $VDRCONFDIR/reccmds.conf +# x-vdr `date '+%F %T'` +# +" + +if [ "$pin" = "on" ]; then +echo " +FSK Schutz hinzufuegen : $VDRSCRIPTDIR/fskprotect.sh protect +FSK Schutz entfernen : $VDRSCRIPTDIR/fskprotect.sh unprotect +" +fi + +if [ "$noad" = "on" ]; then +echo " +Werbung markieren : $VDRSCRIPTDIR/vdrnoad -start +M o r e N o a d : echo true +- Run noad : $VDRSCRIPTDIR/vdrnoad -start +- Run noad, all recordings (batch) : $VDRSCRIPTDIR/vdrnoad -batch +- View Cut list : $VDRSCRIPTDIR/vdrnoad -view +- In prozess : $VDRSCRIPTDIR/vdrnoad -count +- Stop noad (killpid) : $VDRSCRIPTDIR/vdrnoad -killpid +- Stop noad (killall)? : $VDRSCRIPTDIR/vdrnoad -killall +- Remove marks : $VDRSCRIPTDIR/vdrnoad -marks +- Remove pid : $VDRSCRIPTDIR/vdrnoad -pid +- Remove all marks : $VDRSCRIPTDIR/vdrnoad -marks.vdr +- Remove all pids : $VDRSCRIPTDIR/vdrnoad -noad.pid +" +fi + +if [ "$vdrconvert" = "on" ]; then +echo " +V D R C o n v e r t : echo true +- Show VDRConvert Status : ${PREFIX}/bin/status.sh +- Import Audio CD : echo 1 > /var/spool/vdrconvert/ripcda +- VDRConvert einschalten : /etc/init.d/vdrconvert start >/dev/null 2>&1 +- VDRConvert ausschalten : /etc/init.d/vdrconvert stop >/dev/null 2>&1 +" +fi +} > $VDRCONFDIR/reccmds.conf + +# timercmds.conf +{ +echo "# $VDRCONFDIR/timercmds.conf +# x-vdr `date '+%F %T'` +# +" + +if [ "$epgsearch" = "on" ]; then +echo " +Suche nach Wiederholungen : $VDRSCRIPTDIR/timerrep.sh 0 +Suche nach Wiederholungen mit Episodentitle : $VDRSCRIPTDIR/timerrep.sh 1 +" +fi +} > $VDRCONFDIR/timercmds.conf + +# setup.conf +{ +echo "OSDHeight = 488 +OSDLanguage = 1 +OSDLeft = 62 +OSDMessageTime = 1 +OSDSkin = EnigmaNG +OSDTheme = default +OSDTop = 40 +OSDWidth = 584 +dvd.AudioLanguage = 1 +dvd.Gain = 4 +dvd.HideMainMenu = 0 +dvd.MenuLanguage = 1 +dvd.PlayerRCE = 2 +dvd.ReadAHead = 0 +dvd.ShowSubtitles = 0 +dvd.SpuLanguage = 1 +dvdselect.DVDOutputDir = $DVDISODIR +dvdselect.DVDReadScript = $VDRSCRIPTDIR/vdrreaddvd +dvdselect.DVDWriteScript = $VDRSCRIPTDIR/vdrwritedvd +dvdselect.ImageDir = $DVDISODIR +dvdselect.NameDevice = /dev/dvd +dvdselect.NameOrgDevice = /dev/hdc +dvdselect.ResetDVDLink = 1 +femon.Skin = 0 +femon.Theme = 4 +mediamvp.dongle_version = 22146 +osdpip.ColorDepth = 3 +osdpip.CropBottom = 5 +osdpip.CropLeft = 5 +osdpip.CropRight = 5 +osdpip.CropTop = 5 +osdpip.FrameDrop = -1 +osdpip.FrameMode = 2 +osdpip.InfoPosition = 2 +osdpip.InfoWidth = 400 +osdpip.ShowInfo = 1 +osdpip.Size = 2 +osdpip.SwapFfmpeg = 1 +osdpip.XPosition = 50 +osdpip.YPosition = 50 +setup.DirectMenu = 1 +setup.EntryPrefix = : +setup.MenuSuffix = +setup.ReturnValue = 1 +ttxtsubs.MainMenuEntry = 3 +" +} > $VDRCONFDIR/setup.conf + +} # Function End + +# Function Call +make_config + + diff --git a/vdr/patchlevel.conf b/vdr/patchlevel.conf new file mode 100644 index 0000000..ee1a848 --- /dev/null +++ b/vdr/patchlevel.conf @@ -0,0 +1,60 @@ +### x-vdr patchlevel.conf +# EXTENSIONS or PLAIN +PATCHLEVEL="EXTENSIONS" + +### VDR-Extensions: +# Plugin patches will be added automaticly if a corresponding plugin is enabled in x-vdr +# Comment the patches you don't need +# DVDCHAPJUMP needs DVDARCHIVE enabled +# DVDARCHIVE needs LIEMIEXT enabled +# SORTRECORDS needs LIEMIEXT enabled +# you can only enable one of MENUORG SUBMENU SETUP + +ANALOGTV="off" +ATSC="off" +CMDRECCMDI18N="off" +CMDSUBMENU="on" +CUTTERLIMIT="off" +CUTTERQUEUE="on" +CUTTIME="on" +DDEPGENTRY="on" +DOLBYINREC="on" +DVBPLAYER="off" +DVBSETUP="on" +DVDARCHIVE="off" +DVDCHAPJUMP="off" +DVLFRIENDLYFNAMES="off" +DVLRECSCRIPTADDON="on" +DVLVIDPREFER="off" +EM84XX="off" +GRAPHTFT="off" +HARDLINKCUTTER="off" +JUMPPLAY="on" +LIEMIEXT="on" +LIRCSETTINGS="off" +LIVEBUFFER="off" +LNBSHARE="off" +MAINMENUHOOKS="off" +MENUORG="off" +NOEPG="off" +OSDMAXITEMS="off" +PARENTALRATING="off" +PINPLUGIN="off" +PLUGINAPI="on" +PLUGINMISSING="on" +PLUGINPARAM="off" +ROTOR="off" +SETTIME="on" +SETUP="off" +SOFTOSD="off" +SOURCECAPS="off" +SORTRECORDS="on" +STREAMDEVEXT="off" +SYNCEARLY="on" +TIMERCMD="off" +TIMERINFO="off" +TTXTSUBS="off" +VALIDINPUT="off" +VOLCTRL="off" +WAREAGLEICON="on" +YAEPG="off" diff --git a/vdr/scripts/README.DE_burn-bc b/vdr/scripts/README.DE_burn-bc new file mode 100644 index 0000000..831f9e1 --- /dev/null +++ b/vdr/scripts/README.DE_burn-bc @@ -0,0 +1,142 @@ +burn-bc (burn background creator 0.0.5) - readme 2007-07-01 +=================================================== +Beschreibung: +================= +burn-bc ist ein Skript zum erstellen von Hintergründen für das burn-plugin des VDR. +Das Skript kann per Terminal, Maus (Xdialog) oder aus dem VDR-Menu bedient werden. +Es können Bilder aus der eigenen Sammlung oder Screenshots der laufenden Sendung bzw. Aufzeichnung verwendet werden. +Die Bilder werden mit auswählbaren Filtern bearbeitet und an die entsprechenden Stellen kopiert. +Textfelder können gezeichnet oder als Template eingeblendet eingebelndet werden. + +================= +Vorraussetzungen: +================= +ImageMagick 6.2.4 +svdrpsend.pl (zum erstellen der Screenshots) +sharutils (zum erstellen der Screenshots) +Xdialog (optional) +at (optional) + +================= +Installation: +================= +Am einfachsten ist es, burn-bc nach /usr/bin zu kopieren und ausführbar zu machen. +# terminal +cp ./burn-bc /usr/bin +chmod 755 /usr/bin/burn-bc + +Das Skript kann aber auch an jeder anderen Stelle abgelegt werden. +Nur muss dann der Pfad beim aufrufen mit angegeben werden. + +Damit burn-bc aus dem VDR-Menu bedienbar ist, muss die commands.conf angepasst werden: +burn-bc : echo "/usr/bin/burn-bc -f 'crop zoom-center resize draw-storke unsharp' -w default"|at now + +Wer auch eigene Bilder verwenden möchte, kann zum aufrufen das image-plugin benutzen und dafür die imagecmds.conf ergänzen: +burn-bc : echo "/usr/bin/burn-bc -f 'draw-storke unsharp' -w default -i %s"|at now + +Weitere Beispiele gibt es weiter unten... + +================= +Filter: +================= +# Optimierung +crop -> Ränder abschneiden + +# Bildausschnitt +zoom-center -> Zoom auf die Mitte des Bildes +zoom-left -> Zoom auf die linke Seite des Bildes +zoom-right -> Zoom auf die rechte Seite des Bildes +zoom-center-16x9 -> Zoom auf die Mitte eines anamorphen 16/9 Bildes +zoom-left-16x9 -> Zoom auf die linke Seite eines anamorphen 16/9 Bildes +zoom-right-16x9 -> Zoom auf die rechte Seite eines anamorphen 16/9 Bildes +letterbox-16x9 -> Erzeugt ein Letterbox Bild aus einem anamorphen 16/9 Bild + +# Optimierung (nach dem Ränder abschneiden oder zoomen notwendig) +resize -> Skaliert das Bild auf 720x576 + +# Textfelder +comp-atop -> Legt ein Template über das Bild +comp-blend -> Blendet ein Template in das Bild +draw-bigsize -> Zeichnet zwei grosse, transparente Textfelder mit Rahmen über das Bild +draw-normal -> Zeichnet zwei transparente Textfelder mit runde Ecken über das Bild +draw-storke -> Zeichnet zwei transparente Textfelder mit runde Ecken und Rahmen über das Bild +draw-user -> Zeichnet die Textfelder über das Bild (zum anpassen gedacht) + +# Fun +serial-foto -> Legt eine Serie von vier bzw fünf (bei 16/9 Filmen) verkleinerten Screenshots über das Bild +serial-movie -> Montiert eine Serie von fünf Screenshots zu einem Filmstreifen und legt diesen über das Bild +tux -> Blendet ein Bild (das als Template "$targetdir/tux.png" vorliegen muss) in den unteren rechten Teil des Textfeldes ein. +watermark -> Blendet einen Schriftzug in den unteren rechten Teil des Textfeldes ein. + +# Optimierung +sharpen -> Leichtes anheben der Bildschärfe +depth -> Reduziert die Farbtiefe auf 24bpp (damit das Bild mit dem Image-Plugin angezeigt werden kann) + +================= +Tipps: +================= +Auf die Reihenfolge der Filter achten und nie mehr als notwendig verwenden. + +================= +Argumente: +================= +burn-bc [-argument wert] +Optionale Argumente sind: +-f | -filter crop +-f | -filter zoom-center|zoom-left|zoom-right|zoom-center-16x9|zoom-left-16x9|zoom-right-16x9|letterbox-16x9 +-f | -filter resize +-f | -filter comp-atop|comp-blend|draw-bigsize|draw-normal|draw-storke|draw-user +-f | -filter serial-foto|serial-movie +-f | -filter tux +-f | -filter sharpen +-f | -filter depth +-i | -image /path/to/image.ext +-o | -osd on|off +-t | -target /path/to/plugins/burn/menu-bg.png +-T | -template /path/to/template.png +-w | -watermark ?|default|"some text" +-W | -width 720|768 +-x | -showfile on|off +-d | -dialog +-h | -help +-v | -version + +Terminal: +================= +burn-bc -w default -f crop -f resize -f draw-storke' +burn-bc -f 'crop zoom-center resize draw-storke unsharp depth' -o off -w default +burn-bc -f draw-normal -w default -i ~/bilder/image.jpg + +Xdialog: +================= +burn-bc +burn-bc -d -w " Dokumentation" +burn-bc -d -w ? + +KDE Kontext-Menu (rechte Maustaste): +burn-bc -d -w ? -i %f + +commands.conf +================= +d v d - b c : echo "sub menu" +- Draw Only : echo "/usr/bin/burn-bc -f draw-storke -w default"|at now +- Simple Cropping : echo "/usr/bin/burn-bc -f 'crop resize draw-storke unsharp' -w default"|at now +- Zoom Center : echo "/usr/bin/burn-bc -f 'crop zoom-center resize draw-storke unsharp' -w default"|at now +- Zoom Left : echo "/usr/bin/burn-bc -f 'crop zoom-left resize draw-storke unsharp' -w default"|at now +- Zoom Right : echo "/usr/bin/burn-bc -f 'crop zoom-right resize draw-storke unsharp' -w default"|at now +- Serial Foto : echo "/usr/bin/burn-bc -f 'crop zoom-center resize draw-storke serial-foto unsharp' -w default"|at now +- Serial Movie : echo "/usr/bin/burn-bc -f 'crop zoom-center resize draw-storke serial-movie unsharp' -w default"|at now + +imagecmds.conf +================= +# ? - Bestätigung anfordern, (optional) +# %s - Platzhalter für Dateinamen (optional) +# burn-bc +Draw Only : echo "/usr/bin/burn-bc -f draw-storke -w default -i %s"|at now +Resize Only : echo "/usr/bin/burn-bc -f 'draw-storke unsharp' -w default -i %s"|at now +Simple Cropping : echo "/usr/bin/burn-bc -f 'crop resize draw-storke unsharp' -w default -i %s"|at now +Zoom Center : echo "/usr/bin/burn-bc -f 'zoom-center resize draw-storke unsharp' -w default -i %s"|at now +Zoom Left : echo "/usr/bin/burn-bc -f 'crop zoom-left resize draw-storke unsharp' -w default -i %s"|at now +Zoom Right : echo "/usr/bin/burn-bc -f 'crop zoom-right resize draw-storke unsharp' -w default -i %s"|at now +Symlink anlegen : echo ln -fs '%s' /var/lib/vdr/plugins/burn/menu-bg.png | sh + diff --git a/vdr/scripts/burn-bc b/vdr/scripts/burn-bc new file mode 100644 index 0000000..750b4d9 --- /dev/null +++ b/vdr/scripts/burn-bc @@ -0,0 +1,838 @@ +#! /bin/bash +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +script="burn-bc" # +version="burn background creator 0.0.5" # +# written by Marc Wernecke # +# date: 2007-07-01 # +# use: script [-argument value] # +# optional arguments are: # +# -f | -filter crop # +# zoom-center|zoom-left|zoom-right| # +# zoom-center-16x9|zoom-left-16x9|zoom-right-16x9|letterbox-16x9 # +# resize # +# comp-atop|comp-blend|draw-bigsize|draw-normal|draw-storke|draw-user # +# serial-foto|serial-movie # +# tux # +# sharpen # +# depth # +# -i | -image /path/to/image.ext # +# -t | -target /path/to/plugins/burn/menu-bg.png # +# -T | -template /path/to/template.png # +# -o | -osd on|off # +# -w | -watermark ?|default|"some text" # +# -W | -width 720|768 # +# -x | -showfile on|off # +# -d | -dialog # +# -h | -help # +# -v | -version # +# # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # +# defaults: # +FILTER="" # filter1 filter2 # +IMAGE="" # /path/file # +INFO="off" # on|off # +OSDMSG="on" # on|off # +TARGET="$HOME/plugins/burn/menu-bg.png" # /path/file.ext # +TEMPLATE="template.png" # /path/file.ext # +WATERMARK="off" # on|off # +WIDTH="768" # 720|768 # +WMTEXT=" powered by VDR" # "some text" # +SHOWFILE="off" # on|off # +TMPDIR="/tmp" # /path # +SVDRPSEND="svdrpsend.pl" # /path/file.ext # +# # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +args="$*" +language="deu" + +# svdrpsend.pl +TEST=$(which $SVDRPSEND) +if [ ! "$TEST" ]; then + SVDRPSEND="$(grep "^VDRBINDIR=" /etc/default/vdr | cut -d "=" -f 2 | sed -e 's/\"//g')/svdrpsend.pl" + if [ ! -x "$SVDRPSEND" ]; then + echo "svdrpsend.pl not found" + exit 2 + fi +fi + +## FUNCTIONS +function start_action() { + # target directory + test "${TARGET:0:1}" = "/" + if [ "x$?" != "x0" ]; then + echo "$script: TARGET must be an absolute path ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: TARGET must be an absolute path" + exit 3 + fi + targetdir="$(dirname $TARGET)" + if [ ! -d "$targetdir/$script" ]; then + mkdir -p "$targetdir/$script" + if [ ! -d "$targetdir/$script" ]; then + echo "$script: Could not create $targetdir/$script ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: Could not create $targetdir/$script" + exit 3 + fi + fi + + # temp directory + test "${TMPDIR:0:1}" = "/" + if [ "x$?" != "x0" ]; then + echo "$script: TMPDIR must be an absolute path ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: TMPDIR must be an absolute path" + exit 4 + fi + if [ ! -d "$TMPDIR" ]; then + echo "$script: $TMPDIR not found ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: $TMPDIR not found" + exit 4 + fi + tmpdir="$TMPDIR/$$$script" + mkdir -p "$tmpdir" + + # image + if [ -f "$IMAGE" ]; then + image=$(basename "$IMAGE") + convert -extent $(identify -format "%wx%h" "$IMAGE") "$IMAGE" "$tmpdir/$image" + else + image="burn-bg_$(date '+%F_%T').jpg" + IMAGE="$image" # this is for logging only + $SVDRPSEND grab - 100 $WIDTH 576 | \ + sed -n -e 's/^216-//p' -e '1ibegin-base64 644 -' -e '$a====' | \ + uudecode -o "$tmpdir/$image" # <- was passiert hier bei sed mit dem image? + BYTES=$(ls -l "$tmpdir/$image" | tr -s " " | cut -d " " -f 5) + if [ "$BYTES" = "0" ]; then + echo "$script: Snapshot is empty ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: Snapshot is empty" + exit 5 + fi + fi + + # check if temp image exists + if [ ! -f "$tmpdir/$image" ]; then + echo "$script: Image not found ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: Image not found" + exit 6 + fi + + # resize temp image to 720x576 if necessary + f_resize +} + +# filter functions +function f_comp() { + # template.png + if [ -f "$TEMPLATE" ]; then + template="$TEMPLATE" + elif [ -f "$targetdir/$TEMPLATE" ]; then + template="$targetdir/$TEMPLATE" + else + template="$targetdir/template.png" + fi + if [ ! -f "$template" ]; then + echo "$script: $template not found ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: $template not found" + exit 7 + fi + + if [ "$WATERMARK" = "on" ]; then + convert -font helvetica -fill black -pointsize 32 -draw "text 250,460 '$WMTEXT'" "$template" "$tmpdir/template.png" + template="$tmpdir/template.png" + fi + + case $1 in + atop) + composite -gravity center -compose atop -quality 100 "$template" "$tmpdir/$image" "$tmpdir/tmp_$image" + ;; + blend) + image_s=$(identify -format "%wx%h" "$template") + composite -gravity center -blend $image_s -quality 100 "$template" "$tmpdir/$image" "$tmpdir/tmp_$image" + ;; + esac + cp -f "$tmpdir/tmp_$image" "$tmpdir/$image" +} + +function f_crop() { + array=($(identify -format "%w %h" "$tmpdir/$image")) + image_w=${array[0]} + image_h=${array[1]} + crop_w=$(($image_w / 36)) + crop_h=$(($image_h / 36)) + new_w=$(($image_w - $crop_w * 2)) + new_h=$(($image_h - $crop_h * 2)) + new_s=$(echo "$new_w x $new_h" | sed -e 's/ //g') + mogrify -crop $new_s+$crop_w+$crop_h "$tmpdir/$image" + mogrify -extent $new_s "$tmpdir/$image" +} + +function f_depth() { + mogrify -depth 8 "$tmpdir/$image" # 8 or 16 +} + +function f_draw() { + template="$tmpdir/template.png" + # create template.png + case $1 in + bigsize) + convert -size 720x576 xc:transparent -fill "#000000" \ + -stroke "#ffffff" -strokewidth 2 \ + -draw 'rectangle 60,35 660,95' \ + -draw 'rectangle 60,105 660,475' "$tmpdir/tmp.png" + tux_align="right" + ;; + normal) + convert -size 720x576 xc:transparent -fill "#000000" \ + -draw 'roundRectangle 70,35 650,95 10,10' \ + -draw 'roundRectangle 70,105 550,475 10,10' "$tmpdir/tmp.png" + ;; + storke) + convert -size 720x576 xc:transparent -fill "#000000" \ + -stroke "#ffffff" -strokewidth 2 \ + -draw 'roundRectangle 70,35 650,95 10,10' \ + -draw 'roundRectangle 70,105 550,475 10,10' "$tmpdir/tmp.png" + ;; + user) + convert -size 720x576 xc:transparent -fill "#000000" \ + -stroke "#303030" -strokewidth 5 \ + -draw 'polygon 70,35 650,35 650,95 550,95 550,475 70,475' "$tmpdir/tmp.png" + ;; + esac + + # reduce alphachannel about 50% and create the watermark + if [ "$WATERMARK" = "on" ]; then + convert -font helvetica -fill "#303030" -pointsize 32 -draw "text 250,460 '$WMTEXT'" -channel Alpha -fx 'u/2.0' "$tmpdir/tmp.png" "$template" + else + convert -channel Alpha -fx 'u/2.0' "$tmpdir/tmp.png" "$template" + fi + # composite + composite -gravity center -compose atop -quality 100 "$template" "$tmpdir/$image" "$tmpdir/tmp_$image" + cp -f "$tmpdir/tmp_$image" "$tmpdir/$image" +} + +function f_resize() { + image_h=$(identify -format "%h" "$tmpdir/$image") + (($image_h != 576)) && mogrify -resize x576 "$tmpdir/$image" + image_w=$(identify -format "%w" "$tmpdir/$image") + if (($image_w > 720)); then + crop_w=$((($image_w - 720) / 2)) + mogrify -crop 720x576+${crop_w}+0 "$tmpdir/$image" + elif (($image_w < 720)); then + mogrify -resize 720 "$tmpdir/$image" + image_h=$(identify -format "%h" "$tmpdir/$image") + crop_h=$((($image_h - 576) / 2)) + (($image_h > 576)) && mogrify -crop 720x576+0+$crop_h "$tmpdir/$image" + fi + mogrify -extent 720x576 "$tmpdir/$image" +} + +function f_serial_foto() { + aspect="4x3" + sec=1 + images="" + x=130 + while [ $sec -le 4 ]; do + sleep 5 + $SVDRPSEND grab - 100 $WIDTH 576 | \ + sed -n -e 's/^216-//p' -e '1ibegin-base64 644 -' -e '$a====' | \ + uudecode -o "$tmpdir/serial-$sec.jpg" + BYTES=$(ls -l "$tmpdir/serial-$sec.jpg" | tr -s " " | cut -d " " -f 5) + if [ "$BYTES" = "0" ]; then + echo "$script: Snapshot is empty ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: Snapshot is empty" + return 1 + fi + [ "$WIDTH" = "768" ] && mogrify -crop 720x576+24+0 "$tmpdir/serial-$sec.jpg" + + # autodetect blackbars + if [ "$aspect" != "16x9" ] && [ ! -f "$tmpdir/blackbar.jpg" ]; then + cp -f "$tmpdir/serial-$sec.jpg" "$tmpdir/blackbar.jpg" + mogrify -crop 720x5+0+566 "$tmpdir/blackbar.jpg" + colors=$(identify -verbose "$tmpdir/blackbar.jpg" | grep Type: | cut -d ":" -f2 | sed -e 's/ //g') + [ "$colors" = "Grayscale" ] && aspect="16x9" + fi + case $aspect in + 4x3) + mogrify -crop 680x544+20+16 "$tmpdir/serial-$sec.jpg" + ;; + 16x9) + mogrify -crop 680x382+20+97 "$tmpdir/serial-$sec.jpg" + ;; + esac + + mogrify -resize 90x "$tmpdir/serial-$sec.jpg" + composite -compose atop -geometry +560+$x -quality 100 "$tmpdir/serial-$sec.jpg" "$tmpdir/$image" "$tmpdir/tmp_$image" + cp -f "$tmpdir/tmp_$image" "$tmpdir/$image" + sec=$(($sec+1)) + ((x=$x+82)) + done + tux_align="center" +} + +function f_serial_movie() { + aspect="4x3" + sec=1 + images="" + while [ $sec -le 5 ]; do + sleep 5 + $SVDRPSEND grab - 100 $WIDTH 576 | \ + sed -n -e 's/^216-//p' -e '1ibegin-base64 644 -' -e '$a====' | \ + uudecode -o "$tmpdir/serial-$sec.jpg" + BYTES=$(ls -l "$tmpdir/serial-$sec.jpg" | tr -s " " | cut -d " " -f 5) + if [ "$BYTES" = "0" ]; then + echo "$script: Snapshot is empty ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: Snapshot is empty" + return 1 + fi + images="$images $tmpdir/serial-$sec.jpg" + [ "$WIDTH" = "768" ] && mogrify -crop 720x576+24+0 "$tmpdir/serial-$sec.jpg" +# mogrify -crop 680x544+20+16 "$tmpdir/serial-$sec.jpg" + # autodetect blackbars + if [ "$aspect" != "16x9" ] && [ ! -f "$tmpdir/blackbar.jpg" ]; then + cp -f "$tmpdir/serial-$sec.jpg" "$tmpdir/blackbar.jpg" + mogrify -crop 720x5+0+566 "$tmpdir/blackbar.jpg" + colors=$(identify -verbose "$tmpdir/blackbar.jpg" | grep Type: | cut -d ":" -f2 | sed -e 's/ //g') + [ "$colors" = "Grayscale" ] && aspect="16x9" + fi + case $aspect in + 4x3) + mogrify -crop 680x544+20+16 "$tmpdir/serial-$sec.jpg" + ;; + 16x9) + mogrify -crop 680x382+20+97 "$tmpdir/serial-$sec.jpg" + ;; + esac + sec=$(($sec+1)) + done + montage -background "#000000" -tile 5x1 -geometry +10+60 -rotate -90 $images "$tmpdir/montage.jpg" + mogrify -fill "#ffffff" \ + -draw 'rectangle 10,10 50,50' \ + -draw 'rectangle 70,10 110,50' \ + -draw 'rectangle 130,10 170,50' \ + -draw 'rectangle 190,10 230,50' \ + -draw 'rectangle 250,10 290,50' \ + -draw 'rectangle 310,10 350,50' \ + -draw 'rectangle 370,10 410,50' \ + -draw 'rectangle 430,10 470,50' \ + -draw 'rectangle 490,10 530,50' \ + -draw 'rectangle 550,10 590,50' \ + -draw 'rectangle 610,10 650,50' \ + -draw 'rectangle 670,10 710,50' \ + -draw 'rectangle 730,10 770,50' \ + -draw 'rectangle 790,10 830,50' \ + -draw 'rectangle 850,10 890,50' \ + -draw 'rectangle 910,10 950,50' \ + -draw 'rectangle 970,10 1010,50' \ + -draw 'rectangle 1030,10 1070,50' \ + -draw 'rectangle 1090,10 1130,50' \ + -draw 'rectangle 1150,10 1190,50' \ + -draw 'rectangle 1210,10 1250,50' \ + -draw 'rectangle 1270,10 1310,50' \ + -draw 'rectangle 1330,10 1370,50' \ + -draw 'rectangle 1390,10 1430,50' \ + -draw 'rectangle 1450,10 1490,50' \ + -draw 'rectangle 1510,10 1550,50' \ + -draw 'rectangle 1570,10 1610,50' \ + -draw 'rectangle 1630,10 1670,50' \ + -draw 'rectangle 1690,10 1730,50' \ + -draw 'rectangle 1750,10 1790,50' \ + -draw 'rectangle 1810,10 1850,50' \ + -draw 'rectangle 1870,10 1910,50' \ + -draw 'rectangle 1930,10 1970,50' \ + -draw 'rectangle 1990,10 2030,50' \ + -draw 'rectangle 2050,10 2090,50' \ + -draw 'rectangle 2110,10 2150,50' \ + -draw 'rectangle 2170,10 2210,50' \ + -draw 'rectangle 2230,10 2270,50' \ + -draw 'rectangle 2290,10 2330,50' \ + -draw 'rectangle 2350,10 2390,50' \ + -draw 'rectangle 2410,10 2450,50' \ + -draw 'rectangle 2470,10 2510,50' \ + -draw 'rectangle 2530,10 2570,50' \ + -draw 'rectangle 2590,10 2630,50' \ + -draw 'rectangle 2650,10 2690,50' \ + -draw 'rectangle 2710,10 2750,50' \ + -draw 'rectangle 2770,10 2810,50' \ + -draw 'rectangle 10,750 50,790' \ + -draw 'rectangle 70,750 110,790' \ + -draw 'rectangle 130,750 170,790' \ + -draw 'rectangle 190,750 230,790' \ + -draw 'rectangle 250,750 290,790' \ + -draw 'rectangle 310,750 350,790' \ + -draw 'rectangle 370,750 410,790' \ + -draw 'rectangle 430,750 470,790' \ + -draw 'rectangle 490,750 530,790' \ + -draw 'rectangle 550,750 590,790' \ + -draw 'rectangle 610,750 650,790' \ + -draw 'rectangle 670,750 710,790' \ + -draw 'rectangle 730,750 770,790' \ + -draw 'rectangle 790,750 830,790' \ + -draw 'rectangle 850,750 890,790' \ + -draw 'rectangle 910,750 950,790' \ + -draw 'rectangle 970,750 1010,790' \ + -draw 'rectangle 1030,750 1070,790' \ + -draw 'rectangle 1090,750 1130,790' \ + -draw 'rectangle 1150,750 1190,790' \ + -draw 'rectangle 1210,750 1250,790' \ + -draw 'rectangle 1270,750 1310,790' \ + -draw 'rectangle 1330,750 1370,790' \ + -draw 'rectangle 1390,750 1430,790' \ + -draw 'rectangle 1450,750 1490,790' \ + -draw 'rectangle 1510,750 1550,790' \ + -draw 'rectangle 1570,750 1610,790' \ + -draw 'rectangle 1630,750 1670,790' \ + -draw 'rectangle 1690,750 1730,790' \ + -draw 'rectangle 1750,750 1790,790' \ + -draw 'rectangle 1810,750 1850,790' \ + -draw 'rectangle 1870,750 1910,790' \ + -draw 'rectangle 1930,750 1970,790' \ + -draw 'rectangle 1990,750 2030,790' \ + -draw 'rectangle 2050,750 2090,790' \ + -draw 'rectangle 2110,750 2150,790' \ + -draw 'rectangle 2170,750 2210,790' \ + -draw 'rectangle 2230,750 2270,790' \ + -draw 'rectangle 2290,750 2330,790' \ + -draw 'rectangle 2350,750 2390,790' \ + -draw 'rectangle 2410,750 2450,790' \ + -draw 'rectangle 2470,750 2510,790' \ + -draw 'rectangle 2530,750 2570,790' \ + -draw 'rectangle 2590,750 2630,790' \ + -draw 'rectangle 2650,750 2690,790' \ + -draw 'rectangle 2710,750 2750,790' \ + -draw 'rectangle 2770,750 2810,790' \ + "$tmpdir/montage.jpg" + mogrify -rotate 90 -resize 90x "$tmpdir/montage.jpg" + composite -compose atop -geometry +560+130 -quality 100 "$tmpdir/montage.jpg" "$tmpdir/$image" "$tmpdir/tmp_$image" + cp -f "$tmpdir/tmp_$image" "$tmpdir/$image" + tux_align="center" +} + +function f_sharpen() { + mogrify -unsharp 0 "$tmpdir/$image" +} + +function f_tux() { + # template + template="$targetdir/tux.png" + if [ ! -f "$template" ]; then + echo "$script: $template not found ..." + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: $template not found" + return 1 + fi + array=($(identify -format "%w %h" "$template")) + image_w=${array[0]} + image_h=${array[1]} + new_w=$((550 - $image_w)) + new_h=$((475 - $image_h)) + [ "$tux_align" = "right" ] && new_w=$((660 - $image_w)) + [ "$WATERMARK" = "on" ] && new_h=$((440 - $image_w)) + tux_align="center" + convert -channel Alpha -fx 'u/4.0' "$template" "$tmpdir/tmp.png" + composite -compose atop -geometry +$new_w+$new_h -quality 100 "$tmpdir/tmp.png" "$tmpdir/$image" "$tmpdir/tmp_$image" + cp -f "$tmpdir/tmp_$image" "$tmpdir/$image" +} + +function f_zoom_center() { + array=($(identify -format "%w %h" "$tmpdir/$image")) + image_w=${array[0]} + image_h=${array[1]} + new_w=$(($image_w * 3 / 4)) + new_h=$(($image_h * 3 / 4)) + crop_w=$((($image_w - $new_w) / 2)) + crop_h=$((($image_h - $new_h) / 2)) + new_s=$(echo "$new_w x $new_h" | sed -e 's/ //g') + mogrify -crop $new_s+$crop_w+$crop_h "$tmpdir/$image" + mogrify -extent $new_s "$tmpdir/$image" +} + +function f_zoom_left() { + array=($(identify -format "%w %h" "$tmpdir/$image")) + image_w=${array[0]} + image_h=${array[1]} + new_w=$(($image_w * 3 / 4)) + new_h=$(($image_h * 3 / 4)) + crop_w=0 + crop_h=$((($image_h - $new_h) / 2)) + new_s=$(echo "$new_w x $new_h" | sed -e 's/ //g') + mogrify -crop $new_s+$crop_w+$crop_h "$tmpdir/$image" + mogrify -extent $new_s "$tmpdir/$image" +} + +function f_zoom_right() { + array=($(identify -format "%w %h" "$tmpdir/$image")) + image_w=${array[0]} + image_h=${array[1]} + new_w=$(($image_w * 3 / 4)) + new_h=$(($image_h * 3 / 4)) + crop_w=$(($image_w - $new_w)) + crop_h=$((($image_h - $new_h) / 2)) + new_s=$(echo "$new_w x $new_h" | sed -e 's/ //g') + mogrify -crop $new_s+$crop_w+$crop_h "$tmpdir/$image" + mogrify -extent $new_s "$tmpdir/$image" +} + +function f_zoom_center_16x9() { + array=($(identify -format "%wx%h %w %h" "$tmpdir/$image")) + image_s=${array[0]} + image_w=${array[1]} + image_h=${array[2]} + new_w=$(($image_h * 16 / 9)) + crop_w=$((($new_w - $image_w) / 2)) + new_s=$(echo "$new_w x $image_h" | sed -e 's/ //g') + mogrify -resize $new_s\! -crop $image_s+$crop_w+0 "$tmpdir/$image" + mogrify -extent $image_s "$tmpdir/$image" +} + +function f_zoom_left_16x9() { + array=($(identify -format "%wx%h %w %h" "$tmpdir/$image")) + image_s=${array[0]} + image_w=${array[1]} + image_h=${array[2]} + new_w=$(($image_h * 16 / 9)) + crop_w=0 + new_s=$(echo "$new_w x $image_h" | sed -e 's/ //g') + mogrify -resize $new_s\! -crop $image_s+$crop_w+0 "$tmpdir/$image" + mogrify -extent $image_s "$tmpdir/$image" +} + +function f_zoom_right_16x9() { + array=($(identify -format "%wx%h %w %h" "$tmpdir/$image")) + image_s=${array[0]} + image_w=${array[1]} + image_h=${array[2]} + new_w=$(($image_h * 16 / 9)) + crop_w=$(($new_w - $image_w)) + new_s=$(echo "$new_w x $image_h" | sed -e 's/ //g') + mogrify -resize $new_s\! -crop $image_s+$crop_w+0 "$tmpdir/$image" + mogrify -extent $image_s "$tmpdir/$image" +} + +function f_letterbox_16x9() { + array=($(identify -format "%wx%h %w %h" "$tmpdir/$image")) + image_s=${array[0]} + image_w=${array[1]} + image_h=${array[2]} + new_w=$(($image_h * 16 / 9)) + new_h=$(($new_w * 4 / 5)) + (( new_h == 819 )) && new_h=820 + bar=$((($new_h - $image_h) / 2)) + new_h1=$(($image_h + $bar)) + new_h2=$(($image_h + $bar + $bar)) + new_s1=$(echo "$image_w x $new_h1" | sed -e 's/ //g') + new_s2=$(echo "$image_w x $new_h2" | sed -e 's/ //g') + mogrify -rotate 180 -extent $new_s1 -rotate 180 -extent $new_s2 -resize $image_s\! "$tmpdir/$image" +} + +function filter_select() { + for f in $FILTER; do + case $f in + comp-atop) + f_comp atop + ;; + comp-blend) + f_comp blend + ;; + crop) + f_crop + ;; + depth) + f_depth + ;; + draw-bigsize) + f_draw bigsize + ;; + draw-normal) + f_draw normal + ;; + draw-storke) + f_draw storke + ;; + draw-user) + f_draw user + ;; + resize) + f_resize + ;; + serial-foto) + f_serial_foto + ;; + serial-movie) + f_serial_movie + ;; + sharpen) + f_sharpen + ;; + tux) + f_tux right + ;; + zoom-center) + f_zoom_center + ;; + zoom-left) + f_zoom_left + ;; + zoom-right) + f_zoom_right + ;; + zoom-center-16x9) + f_zoom_center_16x9 + ;; + zoom-left-16x9) + f_zoom_left_16x9 + ;; + zoom-right-16x9) + f_zoom_right_16x9 + ;; + letterbox-16x9) + f_letterbox_16x9 + ;; + esac + done +} + +function final_action() { + # install the new image + image_name=$(echo "$image" | cut -f1 -d "." - ) + convert -comment "$version" "$tmpdir/$image" "$targetdir/$script/$image_name.png" + ln -fs "$targetdir/$script/$image_name.png" "$TARGET" + + # clean up + rm -rf "$tmpdir" + + # messages + [ "$OSDMSG" = "on" ] && $SVDRPSEND "MESG $script: Image created" + + if [ "$INFO" = "on" ]; then + echo "$script: $(date '+%F %T')" + echo "image: $IMAGE" + echo "filter: $FILTER" + echo -n "target:"; identify -format "%f %wx%h" "$targetdir/$script/$image_name.png" + echo "template: $template" + echo "tmpdir: $tmpdir" + fi + + [ "$SHOWFILE" = "on" ] && display "$targetdir/$script/$image_name.png" & +} + +## PROG +# arguments +for i in $args; do + case $1 in + -showfile|-x) + shift 1 + SHOWFILE="$1" + [ "$SHOWFILE" != "on" ] && SHOWFILE="off" + ;; + -filter|-f) + shift 1 + FILTER="$FILTER $1" + ;; + -image|-i) + shift 1 + IMAGE="$1" + ;; + -target|-t) + shift 1 + TARGET="$1" + ;; + -template|-T) + shift 1 + TEMPLATE="$1" + ;; + -osd|-o) + shift 1 + OSDMSG="$1" + [ "$OSDMSG" != "on" ] && OSDMSG="off" + ;; + -watermark|-w) + shift 1 + [ "$1" != "default" ] && WMTEXT="$1" + WATERMARK="on" + ;; + -width|-W) + shift 1 + if [ "$1" = "768" ]; then + WIDTH="768" + else + WIDTH="720" + fi + ;; + -dialog|-d) + use_dialog="true" + ;; + -help|-h) + echo "$script ($version)" + echo "use: $script [-argument value]" + echo "optional arguments are:" + echo "-f | -filter crop" + echo "-f | -filter zoom-center|zoom-left|zoom-right|zoom-center-16x9|zoom-left-16x9|zoom-right-16x9|letterbox-16x9" + echo "-f | -filter resize" + echo "-f | -filter comp-atop|comp-blend|draw-bigsize|draw-normal|draw-storke|draw-user" + echo "-f | -filter serial-foto|serial-movie" + echo "-f | -filter tux" + echo "-f | -filter unsharp" + echo "-f | -filter depth" + echo "-i | -image /path/to/image.ext" + echo "-o | -osd on|off" + echo "-t | -target /path/to/plugins/burn/menu-bg.png" + echo "-T | -template /path/to/template.png" + echo "-w | -watermark ?|default|\"some text\"" + echo "-W | -width 768|720" + echo "-x | -showfile on|off" + echo "-d | -dialog" + echo "-h | -help" + echo "-v | -version" + echo "" + exit 0 + ;; + -version|-v) + echo "$script ($version)" + echo "" + exit 0 + ;; + esac + shift 1 +done + +# MAIN PROG +if [ ! "$args" ] || [ "$use_dialog" = "true" ]; then # DIALOG + # filter defaults + crop="on" + zoomcenter="off" + zoomleft="off" + zoomright="off" + resize="on" + drawbigsize="off" + drawnormal="off" + drawstorke="off" + drawuser="off" + serialfoto="off" + serialmovie="off" + tux="off" + sharpen="off" + depth="off" + SHOWFILE="on" + OSDMSG="off" + + #WATERMARK="on" + # watermark text input + if [ "$WMTEXT" = "?" ]; then + WMTEXT_DEF=" powered by VDR" + case $language in + deu) menutext="Text fuer das Wasserzeichen" ;; + eng) menutext="Text for the watermark" ;; + fra) menutext="Watermark" ;; + esac + TMP_WMTEXT=`Xdialog --left --wrap --title " $version " --inputbox "$menutext" 0 0 "$WMTEXT_DEF" 3>&1 1>&2 2>&3` + if [ $? = 0 ]; then + WMTEXT="$TMP_WMTEXT" + else + WMTEXT="$WMTEXT_DEF" + fi + fi + + # language + case $language in + deu) + # menutext + menutext="Von den Filtern mit zoom-*, draw-* oder serial-*\nsollte jeweils nur einer ausgewaehlt werden." + # helptext + text_crop="Raender abschneiden" + text_zoomcenter="Zoom auf die Mitte des Bildes" + text_zoomleft="Zoom auf die linke Seite des Bildes" + text_zoomright="Zoom auf die rechte Seite des Bildes" + text_resize="Skaliert das bearbeitete Bild wieder auf 720x576. Dieser Filter muss aktiviert werden, wenn crop oder zoom* benutzt werden" + text_drawbigsize="Zeichnet zwei grosse, transparente Textfelder mit Rahmen ueber das Bild" + text_drawnormal="Zeichnet zwei transparente Textfelder mit runde Ecken ueber das Bild" + text_drawstorke="Zeichnet zwei transparente Textfelder mit runde Ecken und Rahmen ueber das Bild" + text_drawuser="Zeichnet ueber das Bild" + text_watermark="Blendet ein Wasserzeichen in das Textfeld. Text: \"$WMTEXT\"" + text_serialfoto="Legt eine Serie von vier verkleinerten Screenshots ueber das Bild" + text_serialmovie="Montiert eine Serie von fuenf Screenshots zu einem Filmstreifen und legt diesen ueber das Bild" + text_tux="Blendet einen Tux in das Bild" + text_sharpen="Leichtes anheben der Bildschaerfe" + text_depth="Reduziert die Farbtiefe auf 24bpp (damit das Bild mit dem Image-Plugin angezeigt werden kann)" + text_showfile="Fertiges Bild anzeigen" + ;; + eng) + ;; + fra) + ;; + esac + + while true; do + options=`Xdialog --item-help --no-tags --left --wrap --separate-output --cancel-label "Exit" --title " $version " \ + --checklist "$menutext" 0 0 17 \ + "1" "crop" "$crop" "$text_crop" \ + "2" "zoom-center" "$zoomcenter" "$text_zoomcenter" \ + "3" "zoom-left" "$zoomleft" "$text_zoomleft" \ + "4" "zoom-right" "$zoomright" "$text_zoomright" \ + "5" "resize" "$resize" "$text_resize" \ + "6" "draw-bigsize" "$drawbigsize" "$text_drawbigsize" \ + "7" "draw-normal" "$drawnormal" "$text_drawnormal" \ + "8" "draw-storke" "$drawstorke" "$text_drawstorke" \ + "9" "draw-user" "$drawuser" "$text_drawuser" \ + "10" "watermark" "$WATERMARK" "$text_watermark" \ + "11" "serial-foto" "$serialfoto" "$text_serialfoto" \ + "12" "serial-movie" "$serialmovie" "$text_serialmovie" \ + "13" "tux" "$tux" "$text_tux" \ + "14" "sharpen" "$sharpen" "$text_sharpen" \ + "15" "depth" "$depth" "$text_depth" \ + "16" "showfile" "$SHOWFILE" "$text_showfile" 3>&1 1>&2 2>&3` + [ $? != 0 ] && exit 0 + + # settings + FILTER="" + crop="off" + zoomcenter="off" + zoomleft="off" + zoomright="off" + resize="off" + drawbigsize="off" + drawnormal="off" + drawstorke="off" + drawuser="off" + serialfoto="off" + serialmovie="off" + tux="off" + sharpen="off" + depth="off" + SHOWFILE="off" + WATERMARK="off" + + for i in $options; do + case "$i" in + 1) crop="on"; FILTER="$FILTER crop" ;; + 2) zoomcenter="on"; FILTER="$FILTER zoom-center" ;; + 3) zoomleft="on"; FILTER="$FILTER zoom-left" ;; + 4) zoomright="on"; FILTER="$FILTER zoom-right" ;; + 5) resize="on"; FILTER="$FILTER resize" ;; + 6) drawbigsize="on"; FILTER="$FILTER draw-bigsize" ;; + 7) drawnormal="on"; FILTER="$FILTER draw-normal" ;; + 8) drawstorke="on"; FILTER="$FILTER draw-storke" ;; + 9) drawuser="on"; FILTER="$FILTER draw-user" ;; + 10) WATERMARK="on" ;; + 11) serialfoto="on"; FILTER="$FILTER serial-foto" ;; + 12) serialmovie="on"; FILTER="$FILTER serial-movie" ;; + 13) tux="on"; FILTER="$FILTER tux" ;; + 14) sharpen="on"; FILTER="$FILTER sharpen" ;; + 15) depth="on"; FILTER="$FILTER depth" ;; + 16) SHOWFILE="on" ;; + esac + done + # action + start_action + # apply filter + filter_select + # final + final_action + done +else # MAIN PROG + # action + start_action + # apply filter + filter_select + # final + final_action +fi + +exit 0 diff --git a/vdr/scripts/runvdr b/vdr/scripts/runvdr new file mode 100644 index 0000000..36115ea --- /dev/null +++ b/vdr/scripts/runvdr @@ -0,0 +1,247 @@ +#!/bin/sh + +# x-vdr (Installations-Skript fuer einen VDR mit Debian als Basis) +# von Marc Wernecke - www.zulu-entertainment.de +# 24.03.2009 +# runvdr + +VDRLANG="de_DE.iso88591" +VDRCHARSET="ISO-8859-9" +KILL="/usr/bin/killall -q -TERM" +KERNEL=`uname -r` +VDRCONFIG=/etc/default/vdr +LOGGER="logger -s ${0##*/} " + +function VdrSettings() { + # read vdr default configuration + if [ -f "$VDRCONFIG" ]; then + . $VDRCONFIG + else + $LOGGER "exit, because $VDRCONFIG does not exists" + exit 1 + fi + + # read sysconfig generated by setup-plugin + if [ "$setup" = "on" ] && [ -f "$VDRCONFDIR/plugins/setup/sysconfig" ]; then + . "$VDRCONFDIR/plugins/setup/sysconfig" + fi + + # test if vdr exists and is executable + test -x "$VDRPRG" || exit 0 + + # create tmp files + $VDRPRG --help | sed -e '/^$/d' -e 's/^. //' > /tmp/vdr-help.tmp + $VDRPRG --version | sed -e 's/\(^[^ ]*\)\(.*$\)/\1_desc="\1\2"/' -e '/^streamdev/s/-/_/' -e 's/^\[.*//' | sort > /tmp/vdr-desc.cache + + # export vdr language + export LANG=$VDRLANG + export LC_ALL=$VDRLANG + export VDR_CHARSET_OVERRIDE=$VDRCHARSET + + # export HOME + if [ "$VDRUSER" = "root" ]; then + export HOME="/root" + else + export HOME="$VDRCONFDIR" + fi + + # java / projectx for burn and dvdconvert + if [ "$burn" = "on" ] || [ "$dvdconvert" = "on" ]; then + [ -z "$JAVA_HOME" ] && export JAVA_HOME="/usr/lib/jvm/java-6-sun/jre" + [ -z "$PROJECTX_HOME" ] && export PROJECTX_HOME="/usr/bin/ProjectX" + fi + + # set DISPLAY + # - activate automatic login + # - copy x-vdr/extra/xhost to ~/.kde/Autostart and set xhost executable + if [ "$softdevice" = "on" ] || [ "$xineliboutput" = "on" ]; then + [ -z "$DISPLAY" ] && export DISPLAY=:$XV_DISPLAY + fi + + # load nvram + if [ `which nvram-wakeup | wc -l` -gt 0 ] && [ `lsmod | grep -cw 'nvram'` -eq 0 ]; then + modprobe -q nvram + fi + + # load cdfs + if [ `lsmod | grep -cw 'cdfs'` -eq 0 ]; then + modprobe -q cdfs + fi + + # load av7710ir + if [ -e /proc/av7110_ir ] || [ -e /proc/budget_ci_ir ]; then + for FILE in av7110_ir budget_ci_ir; do + if [ -e "/proc/$FILE" ]; then + chown $VDRUSER:$VDRGROUP /proc/$FILE + fi + done + if [ `lsmod | grep -cw 'evdev'` -eq 0 ]; then modprobe -q evdev ; fi + fi + + # load em8300 + if [ "$em8300" = "on" ]; then +# EM8300="/lib/modules/$KERNEL/em8300" +# if [ -f "$EM8300/adv717x.ko" ] && [ -f "$EM8300/bt865.ko" ] && [ -f "$EM8300/em8300.ko" ]; then +# $VDRSCRIPTDIR/rmm +# $VDRSCRIPTDIR/ldm + [ "$dxr3" != "on" ] && em8300setup +# fi + fi + + # load parport + if [ "$graphlcd_base" = "on" ]; then + [ `lsmod | grep -cw 'parport'` -eq 0 ] && modprobe -q parport + [ `lsmod | grep -cw 'parport_pc'` -eq 0 ] && modprobe -q parport_pc + [ `lsmod | grep -cw 'ppdev'` -eq 0 ] && modprobe -q ppdev +# chmod 0666 /dev/parport0 + fi + + # only for mplayer via xine + # - copy x-vdr/extra/xhost to ~/.kde/Autostart and set xhost executable + if [ "$VDRUSER" != "root" ] && [ "$xine" = "on" ] && [ "$mplayer" = "on" ]; then + chmod 666 /dev/rtc +# echo 1024 > /proc/sys/dev/rtc/max-user-freq + fi + + # plugins + PLUGINS="" + ignore_cmd="" + + if [ "$USE_SYSCONFIG" = "on" ]; then # use PLUGINLIST from sysconfig + PLUGINS="$PLUGINLIST" + + else # start creating a temporary pluginlist ... + # plugin api version + plugin_api="$(grep -m1 '^vdr_desc=' /tmp/vdr-desc.cache | sed -e 's/^vdr_desc=//' -e 's/[^)]*$//' -e 's/^[^\/]*//g' -e 's/\///' -e 's/\/*)//')" + [ -n "$plugin_api" ] || plugin_api="$($VDRPRG --version | grep -m1 '^vdr ' | sed -e 's/[^)]*$//' -e 's/^[^\/]*//g' -e 's/\///' -e 's/\/*)//')" + + # put these plugins on top of the pluginlist + if [ -n "$PLUGINS_ON_TOP" ]; then + for p in $PLUGINS_ON_TOP ; do + if [ -f "$VDRLIBDIR/libvdr-${p}.so.${plugin_api}" ]; then + ignore_cmd="$ignore_cmd -I libvdr-${p}.so.${plugin_api}" + plugin=$(echo $p | sed -e "s/-/_/g") # this is for streamdev-... + if [ "${!plugin}" = "on" ]; then + plugin_args="${plugin}_args" + if [ -n "${!plugin_args}" ]; then + PLUGINS="$PLUGINS -P'${p} ${!plugin_args}'" + else + PLUGINS="$PLUGINS -P'${p}'" + fi + fi + fi + done + fi + + # read libdir and continue creating pluginlist + files=$(ls -B $ignore_cmd "$VDRLIBDIR" | grep "^libvdr-" | grep ".so.${plugin_api}$" | sed -e "s/^libvdr-//g" -e "s/.so.${plugin_api}$//g") + if [ -n "$files" ]; then + for p in $files ; do + plugin=$(echo $p | sed -e "s/-/_/g") # this is for streamdev-... + if [ -z "${!plugin}" ] && [ -f "$VDRLIBDIR/libvdr-$(echo $plugin | sed -e "s/_/-/g").so.${plugin_api}" ]; then + echo "" >> $VDRCONFIG + echo "# $p" >> $VDRCONFIG + echo "${plugin}=\"off"\" >> $VDRCONFIG + eval ${plugin}="off" + # plugin args + nl=0; (( nl=$(grep -n "^$p " /tmp/vdr-help.tmp | cut -f 1 -d ":") +1 )) + [ $nl -gt 1 ] && [ $(sed -n "${nl}p" /tmp/vdr-help.tmp | grep -c "^-") -gt 0 ] && echo "${plugin}_args=\"\"" >> $VDRCONFIG + fi + if [ "${!plugin}" = "on" ]; then + plugin_args="${plugin}_args" + if [ -n "${!plugin_args}" ]; then + PLUGINS="$PLUGINS -P'${p} ${!plugin_args}'" + else + PLUGINS="$PLUGINS -P'${p}'" + fi + fi + done + fi + + # special plugin settings + [ "$remote" = "on" ] && chmod 0666 $remote_event + fi + + # scripts + VDRRECCMDS="" + [ -x "$VDRSCRIPTDIR/vdrreccmds" ] && VDRRECCMDS="-r $VDRSCRIPTDIR/vdrreccmds" + VDRSETTIME="" + [ -x "$VDRSCRIPTDIR/vdrsettime" ] && [ $(grep -c "\-T CMD, --timeset=CMD" /tmp/vdr-help.tmp) -gt 0 ] && VDRSETTIME="-T $VDRSCRIPTDIR/vdrsettime" + VDRSHUTDOWN="" + [ -x "$VDRSCRIPTDIR/vdrshutdown" ] && VDRSHUTDOWN="-s $VDRSCRIPTDIR/vdrshutdown" + + # keyboard tty (terminal for vdr) + VDRKEYBTTY="" + if [ "$KEYB_TTY" != "" ]; then + VDRKEYBTTY="-t $KEYB_TTY" + [ "$VDRUSER" != "root" ] && chmod 0666 $KEYB_TTY + fi + + # cmd + VDRCMD="$VDRPRG -w $WATCHDOG -v $VIDEODIR -c $VDRCONFDIR -E $VDRVARDIR/epg.data -L $VDRLIBDIR -u $VDRUSER \ + $VDRRECCMDS $VDRSETTIME $VDRSHUTDOWN $VDRKEYBTTY $PLUGINS $OPTIONS " +} + +# modules +function get_modulenames() { + KVERS=`uname -r | grep -e '2.6'` + if [ -z "$KVERS" ]; then + MODULES=`lsmod | grep 'dvb-core' | cut -d'[' -f2 | cut -d']' -f1` + else + MODULES=`lsmod | grep '^dvb_core' | awk '{print $4;}' | awk '{ gsub(/,/," ", $1); print }'` + fi +} + +get_modulenames + +if [ -z "$MODULES" ]; then # If no DVB-Modules were found, try to load + modprobe -q dvb # the module with the name dvb, this could + get_modulenames # be an alias for the dvb-ttpci-module or +fi # another dvb-module + +MODULES="$MODULES dvb-core" + +if [ `echo $MODULES | grep -cw 'b2c2_flexcop'` -gt 0 ] && [ `echo $MODULES | grep -cw 'b2c2_flexcop_pci'` -eq 0 ]; then + MODULES="b2c2_flexcop_pci $MODULES" +fi + +# clear TTY +if [ "$KEYB_TTY" != "" ]; then + clear > $KEYB_TTY +fi + +# main script +while (true) do + # load vdr settings + VdrSettings + # start X + MSG="Starting Xserver for VDRUSER: '$VDRUSER'" + [ "$XPLAYER" = "on" ] && echo "$MSG" && su "$VDRUSER" -c "startx &" + # start vdr + $LOGGER "Starting Video Disk Recorder at `date`" + eval $VDRCMD >/dev/null 2>&1 + if test $? -eq 0; then + $LOGGER "Video Disk Recorder stopped at `date`" + [ "$XPLAYER" = "on" ] && $KILL Xorg + exit 0 + fi + # stop vdr + $LOGGER "Stopping Video Disk Recorder at `date`" + [ "$XPLAYER" = "on" ] && $KILL Xorg + $KILL $VDRPRG + wait `pidof $VDRPRG` + # unload modules + for MODULE in $MODULES; do + rmmod $MODULE >/dev/null 2>&1 + wait `pidof rmmod` + done + # load modules + for MODULE in $MODULES; do + modprobe $MODULE >/dev/null 2>&1 + done +done + +# clear tty +if [ "$KEYB_TTY" != "" ]; then + clear > $KEYB_TTY +fi diff --git a/vdr/scripts/runvdr-old b/vdr/scripts/runvdr-old new file mode 100644 index 0000000..6e8373a --- /dev/null +++ b/vdr/scripts/runvdr-old @@ -0,0 +1,319 @@ +#!/bin/sh + +# x-vdr (Installations-Skript fuer einen VDR mit Debian als Basis) +# von Marc Wernecke - www.zulu-entertainment.de +# 06.11.2007 +# runvdr + +#export LD_ASSUME_KERNEL=2.4.1 +export LANG=de_DE.iso8859-1 +export LC_ALL=de_DE.iso8859-1 + +KILL="/usr/bin/killall -q -TERM" +KERNEL=`uname -r` + +function vdr_settings() { + # load vdr configuration + if [ -f /etc/default/vdr ]; then + . /etc/default/vdr + else + logger "$0 - error -> /etc/default/vdr does not exists" + exit 1 + fi + + # test if vdr exists and is executable + test -x "$VDRPRG" || exit 0 + + # export HOME + if [ "$VDRUSER" = "root" ]; then + export HOME="/root" + else + export HOME="$VDRCONFDIR" + fi + + # java for burn + if [ "$burn" = "on" ]; then + [ -z "$JAVA_HOME" ] && export JAVA_HOME="/usr/lib/jvm/java-1.5.0-sun/jre" + [ -z "$PROJECTX_HOME" ] && export PROJECTX_HOME="/usr/local/src/ProjectX" + fi + + # set DISPLAY + # - activate automatic login + # - copy x-vdr/extra/xhost to ~/.kde/Autostart and set xhost executable + if [ "$softdevice" = "on" ] || [ "$xineliboutput" = "on" ]; then + [ -z "$DISPLAY" ] && export DISPLAY=:$XV_DISPLAY + fi + + # load nvram + if [ `which nvram-wakeup | wc -l` -gt 0 ] && [ `lsmod | grep -cw 'nvram'` -eq 0 ]; then + modprobe -q nvram + fi + + # load cdfs + if [ `lsmod | grep -cw 'cdfs'` -eq 0 ]; then + modprobe -q cdfs + fi + + # load av7710ir + if [ -e /proc/av7110_ir ] || [ -e /proc/budget_ci_ir ]; then + for FILE in av7110_ir budget_ci_ir; do + if [ -e "/proc/$FILE" ]; then + chown $VDRUSER:$VDRGROUP /proc/$FILE + fi + done + if [ `lsmod | grep -cw 'evdev'` -eq 0 ]; then modprobe -q evdev ; fi + fi + + # load em8300 + if [ "$em8300" = "on" ]; then +# EM8300="/lib/modules/$KERNEL/em8300" +# if [ -f "$EM8300/adv717x.ko" ] && [ -f "$EM8300/bt865.ko" ] && [ -f "$EM8300/em8300.ko" ]; then +# $VDRSCRIPTDIR/rmm +# $VDRSCRIPTDIR/ldm + [ "$dxr3" != "on" ] && em8300setup +# fi + fi + + # load parport + if [ "$graphlcd_base" = "on" ]; then + [ `lsmod | grep -cw 'parport'` -eq 0 ] && modprobe -q parport + [ `lsmod | grep -cw 'parport_pc'` -eq 0 ] && modprobe -q parport_pc + [ `lsmod | grep -cw 'ppdev'` -eq 0 ] && modprobe -q ppdev + # chmod 0666 /dev/parport0 + fi + + # only for mplayer via xine + # - copy x-vdr/extra/xhost to ~/.kde/Autostart and set xhost executable + if [ "$VDRUSER" != "root" ] && [ "$xine" = "on" ] && [ "$mplayer" = "on" ]; then + chmod 666 /dev/rtc + echo 1024 > /proc/sys/dev/rtc/max-user-freq + fi + + + # plugins + PLUGINS="" + # video devices + [ "$dxr3" = "on" ] && PLUGINS="$PLUGINS -P'dxr3'" + [ "$softdevice" = "on" ] && PLUGINS="$PLUGINS -P'softdevice $softdevice_args'" + [ "$vdrtvtime" = "on" ] && PLUGINS="$PLUGINS -P'vdrtvtime $vdrtvtime_args'" + [ "$xine" = "on" ] && PLUGINS="$PLUGINS -P'xine $xine_args'" + [ "$xineliboutput" = "on" ] && PLUGINS="$PLUGINS -P'xineliboutput $xineliboutput_args'" + # other + [ "$admin" = "on" ] && PLUGINS="$PLUGINS -P'admin'" + [ "$adzap" = "on" ] && PLUGINS="$PLUGINS -P'adzap $adzap_args'" + [ "$alcd" = "on" ] && PLUGINS="$PLUGINS -P'alcd $alcd_args'" + [ "$analogradio" = "on" ] && PLUGINS="$PLUGINS -P'analogradio $analogradio_args'" + [ "$arghdirector" = "on" ] && PLUGINS="$PLUGINS -P'arghdirector'" + [ "$atmo" = "on" ] && PLUGINS="$PLUGINS -P'atmo $atmo_args'" + [ "$audiorecorder" = "on" ] && PLUGINS="$PLUGINS -P'audiorecorder $audiorecorder_args'" + [ "$autosort" = "on" ] && PLUGINS="$PLUGINS -P'autosort'" + [ "$autotimeredit" = "on" ] && PLUGINS="$PLUGINS -P'autotimeredit $autotimeredit_args'" + [ "$avards" = "on" ] && PLUGINS="$PLUGINS -P'avards $avards_args'" + [ "$avolctl" = "on" ] && PLUGINS="$PLUGINS -P'avolctl'" + [ "$beep" = "on" ] && PLUGINS="$PLUGINS -P'beep'" + [ "$bitstreamout" = "on" ] && PLUGINS="$PLUGINS -P'bitstreamout $bitstreamout_args'" + [ "$burn" = "on" ] && PLUGINS="$PLUGINS -P'burn $burn_args'" + [ "$calc" = "on" ] && PLUGINS="$PLUGINS -P'calc'" + [ "$cdda" = "on" ] && PLUGINS="$PLUGINS -P'cdda $cdda_args'" + [ "$chanorg" = "on" ] && PLUGINS="$PLUGINS -P'chanorg $chanorg_args'" + [ "$channelswitcher" = "on" ] && PLUGINS="$PLUGINS -P'channelswitcher'" + [ "$cinebars" = "on" ] && PLUGINS="$PLUGINS -P'cinebars'" + [ "$clock" = "on" ] && PLUGINS="$PLUGINS -P'clock'" + [ "$console" = "on" ] && PLUGINS="$PLUGINS -P'console $console_args'" + [ "$control" = "on" ] && PLUGINS="$PLUGINS -P'control $control_args'" + [ "$csf" = "on" ] && PLUGINS="$PLUGINS -P'csf'" + [ "$cutalot" = "on" ] && PLUGINS="$PLUGINS -P'cutalot'" + [ "$decruft" = "on" ] && PLUGINS="$PLUGINS -P'decruft'" + [ "$digicam" = "on" ] && PLUGINS="$PLUGINS -P'digicam'" + [ "$director" = "on" ] && PLUGINS="$PLUGINS -P'director'" + [ "$dummydevice" = "on" ] && PLUGINS="$PLUGINS -P'dummydevice'" + [ "$dvd" = "on" ] && PLUGINS="$PLUGINS -P'dvd $dvd_args'" + [ "$dvdconvert" = "on" ] && PLUGINS="$PLUGINS -P'dvdconvert $dvdconvert_args'" + [ "$dvdselect" = "on" ] && PLUGINS="$PLUGINS -P'dvdselect'" + [ "$dvdswitch" = "on" ] && PLUGINS="$PLUGINS -P'dvdswitch $dvdswitch_args'" + if [ "$epgsearch" = "on" ]; then + PLUGINS="$PLUGINS -P'epgsearch $epgsearch_args'" + [ "$epgsearchonly" = "on" ] && PLUGINS="$PLUGINS -P'epgsearchonly'" + [ "$conflictcheckonly" = "on" ] && PLUGINS="$PLUGINS -P'conflictcheckonly'" + [ "$quickepgsearch" = "on" ] && PLUGINS="$PLUGINS -P'quickepgsearch'" + fi + [ "$epgsync" = "on" ] && PLUGINS="$PLUGINS -P'epgsync'" + [ "$extb" = "on" ] && PLUGINS="$PLUGINS -P'extb $extb_args'" + [ "$extrecmenu" = "on" ] && PLUGINS="$PLUGINS -P'extrecmenu'" + [ "$femon" = "on" ] && PLUGINS="$PLUGINS -P'femon'" + [ "$ffnetdev" = "on" ] && PLUGINS="$PLUGINS -P'ffnetdev $ffnetdev_args'" + [ "$filebrowser" = "on" ] && PLUGINS="$PLUGINS -P'filebrowser'" + [ "$freecell" = "on" ] && PLUGINS="$PLUGINS -P'freecell'" + [ "$fritzbox" = "on" ] && PLUGINS="$PLUGINS -P'fritzbox'" + [ "$games" = "on" ] && PLUGINS="$PLUGINS -P'games'" + [ "$graphlcd" = "on" ] && PLUGINS="$PLUGINS -P'graphlcd $graphlcd_args'" + [ "$graphtft" = "on" ] && PLUGINS="$PLUGINS -P'graphtft $graphtft_args'" + [ "$image" = "on" ] && PLUGINS="$PLUGINS -P'image $image_args'" + [ "$ipod" = "on" ] && PLUGINS="$PLUGINS -P'ipod'" + [ "$iptv" = "on" ] && PLUGINS="$PLUGINS -P'iptv $iptv_args'" + [ "$launcher" = "on" ] && PLUGINS="$PLUGINS -P'launcher'" + [ "$lcdproc" = "on" ] && PLUGINS="$PLUGINS -P'lcdproc $lcdproc_args'" + [ "$lcr" = "on" ] && PLUGINS="$PLUGINS -P'lcr $lcr_args'" + [ "$live" = "on" ] && PLUGINS="$PLUGINS -P'live $live_args'" + [ "$loadepg" = "on" ] && PLUGINS="$PLUGINS -P'loadepg $loadepg_args'" + [ "$mailbox" = "on" ] && PLUGINS="$PLUGINS -P'mailbox $mailbox_args'" + [ "$manual" = "on" ] && PLUGINS="$PLUGINS -P'manual'" + [ "$mediamvp" = "on" ] && PLUGINS="$PLUGINS -P'mediamvp $mediamvp_args'" + [ "$menuorg" = "on" ] && PLUGINS="$PLUGINS -P'menuorg $menuorg_args'" + [ "$mlcd" = "on" ] && PLUGINS="$PLUGINS -P'mlcd'" + [ "$mlist" = "on" ] && PLUGINS="$PLUGINS -P'mlist'" + [ "$mousemate" = "on" ] && PLUGINS="$PLUGINS -P'mousemate $mousemate_args'" + [ "$mp3" = "on" ] && PLUGINS="$PLUGINS -P'mp3 $mp3_args'" + [ "$mplayer" = "on" ] && PLUGINS="$PLUGINS -P'mplayer $mplayer_args'" + [ "$muggle" = "on" ] && PLUGINS="$PLUGINS -P'muggle $muggle_args'" + [ "$music" = "on" ] && PLUGINS="$PLUGINS -P'music $music_args'" + [ "$coverviewer" = "on" ] && PLUGINS="$PLUGINS -P'coverviewer $coverviewer_args'" + [ "$netconfig" = "on" ] && PLUGINS="$PLUGINS -P'netconfig $netconfig_args'" + [ "$newsticker" = "on" ] && PLUGINS="$PLUGINS -P'newsticker'" + [ "$noepgmenu" = "on" ] && PLUGINS="$PLUGINS -P'noepgmenu'" + [ "$nordlichtsepg" = "on" ] && PLUGINS="$PLUGINS -P'nordlichtsepg'" + [ "$osdout" = "on" ] && PLUGINS="$PLUGINS -P'osdout'" + [ "$osdpip" = "on" ] && PLUGINS="$PLUGINS -P'osdpip'" + [ "$osdserver" = "on" ] && PLUGINS="$PLUGINS -P'osdserver'" + [ "$osdteletext" = "on" ] && PLUGINS="$PLUGINS -P'osdteletext $osdteletext_args'" + [ "$picselshow" = "on" ] && PLUGINS="$PLUGINS -P'picselshow $picselshow_args'" + [ "$pilot" = "on" ] && PLUGINS="$PLUGINS -P'pilot'" + [ "$pilotskin" = "on" ] && PLUGINS="$PLUGINS -P'pilotskin'" + [ "$pim" = "on" ] && PLUGINS="$PLUGINS -P'pim'" + [ "$pin" = "on" ] && PLUGINS="$PLUGINS -P'pin'" + [ "$playlist" = "on" ] && PLUGINS="$PLUGINS -P'playlist $playlist_args'" + [ "$podcatcher" = "on" ] && PLUGINS="$PLUGINS -P'podcatcher $podcatcher_args'" + [ "$powermate" = "on" ] && PLUGINS="$PLUGINS -P'powermate $powermate_args'" + [ "$prefermenu" = "on" ] && PLUGINS="$PLUGINS -P'prefermenu'" + [ "$premiereepg" = "on" ] && PLUGINS="$PLUGINS -P'premiereepg'" + [ "$pvrinput" = "on" ] && PLUGINS="$PLUGINS -P'pvrinput'" + [ "$radio" = "on" ] && PLUGINS="$PLUGINS -P'radio $radio_args'" + [ "$recstatus" = "on" ] && PLUGINS="$PLUGINS -P'recstatus'" + [ "$reelchannelscan" = "on" ] && PLUGINS="$PLUGINS -P'reelchannelscan'" + [ "$remote" = "on" ] && PLUGINS="$PLUGINS -P'remote $remote_args'" && chmod 0666 $remote_event + [ "$remoteosd" = "on" ] && PLUGINS="$PLUGINS -P'remoteosd'" + [ "$remotetimers" = "on" ] && PLUGINS="$PLUGINS -P'remotetimers'" + [ "$ripit" = "on" ] && PLUGINS="$PLUGINS -P'ripit'" + [ "$rotor" = "on" ] && PLUGINS="$PLUGINS -P'rotor $rotor_args'" + [ "$rssreader" = "on" ] && PLUGINS="$PLUGINS -P'rssreader'" + [ "$screenshot" = "on" ] && PLUGINS="$PLUGINS -P'screenshot'" + [ "$setup" = "on" ] && PLUGINS="$PLUGINS -P'setup'" + [ "$skinelchi" = "on" ] && PLUGINS="$PLUGINS -P'skinelchi $skinelchi_args'" + [ "$skinenigmang" = "on" ] && PLUGINS="$PLUGINS -P'skinenigmang $skinenigmang_args'" + [ "$skinreel" = "on" ] && PLUGINS="$PLUGINS -P'skinreel'" + [ "$skinsoppalusikka" = "on" ] && PLUGINS="$PLUGINS -P'skinsoppalusikka $skinsoppalusikka_args'" + [ "$sleeptimer" = "on" ] && PLUGINS="$PLUGINS -P'sleeptimer $sleeptimer_args'" + [ "$solitaire" = "on" ] && PLUGINS="$PLUGINS -P'solitaire'" + [ "$span" = "on" ] && PLUGINS="$PLUGINS -P'span'" + [ "$spider" = "on" ] && PLUGINS="$PLUGINS -P'spider'" + [ "$sport" = "on" ] && PLUGINS="$PLUGINS -P'sport $sport_args'" + [ "$streamdev_client" = "on" ] && PLUGINS="$PLUGINS -P'streamdev-client'" + [ "$streamdev_server" = "on" ] && PLUGINS="$PLUGINS -P'streamdev-server $streamdev_server_args'" + [ "$streamplayer" = "on" ] && PLUGINS="$PLUGINS -P'streamplayer'" + [ "$submenu" = "on" ] && PLUGINS="$PLUGINS -P'submenu'" + [ "$subtitles" = "on" ] && PLUGINS="$PLUGINS -P'subtitles'" + [ "$sudoku" = "on" ] && PLUGINS="$PLUGINS -P'sudoku'" + [ "$svdrpext" = "on" ] && PLUGINS="$PLUGINS -P'svdrpext'" + [ "$svdrpservice" = "on" ] && PLUGINS="$PLUGINS -P'svdrpservice'" + [ "$sysinfo" = "on" ] && PLUGINS="$PLUGINS -P'sysinfo'" + [ "$taste" = "on" ] && PLUGINS="$PLUGINS -P'taste'" + [ "$text2skin" = "on" ] && PLUGINS="$PLUGINS -P'text2skin'" + [ "$ttxtsubs" = "on" ] && PLUGINS="$PLUGINS -P'ttxtsubs'" + [ "$timeline" = "on" ] && PLUGINS="$PLUGINS -P'timeline'" + [ "$touchtft" = "on" ] && PLUGINS="$PLUGINS -P'touchtft $touchtft_args'" + [ "$tvonscreen" = "on" ] && PLUGINS="$PLUGINS -P'tvonscreen $tvonscreen_args'" + [ "$tvtv" = "on" ] && PLUGINS="$PLUGINS -P'tvtv'" + [ "$undelete" = "on" ] && PLUGINS="$PLUGINS -P'undelete $undelete_args'" + [ "$vdrcd" = "on" ] && PLUGINS="$PLUGINS -P'vdrcd $vdrcd_args'" + [ "$vdrrip" = "on" ] && PLUGINS="$PLUGINS -P'vdrrip $vdrrip_args'" + [ "$vompserver" = "on" ] && PLUGINS="$PLUGINS -P'vompserver $vompserver_args'" + [ "$wapd" = "on" ] && PLUGINS="$PLUGINS -P'wapd $wapd_args'" + [ "$weatherng" = "on" ] && PLUGINS="$PLUGINS -P'weatherng $weatherng_args'" + [ "$wirbelscan" = "on" ] && PLUGINS="$PLUGINS -P'wirbelscan'" + [ "$xxvautotimer" = "on" ] && PLUGINS="$PLUGINS -P'xxvautotimer $xxvautotimer_args'" + [ "$yaepg" = "on" ] && PLUGINS="$PLUGINS -P'yaepg'" + [ "$zaphistory" = "on" ] && PLUGINS="$PLUGINS -P'zaphistory'" + [ "$default_plugins" = "on" ] && PLUGINS="$PLUGINS -P'hello' -P'osddemo' -P'svccli' -P'svcsvr' -P'sky' -P'status' -P'svdrpdemo'" + + # scripts + VDRRECCMDS="$VDRSCRIPTDIR/vdrreccmds" + VDRSETTIME="$VDRSCRIPTDIR/vdrsettime" + VDRSHUTDOWN="$VDRSCRIPTDIR/vdrshutdown" + + # keyboard tty (terminal for vdr) + VDRKEYBTTY="" + if [ "$KEYB_TTY" != "" ]; then + VDRKEYBTTY="-t $KEYB_TTY" + [ "$VDRUSER" != "root" ] && chmod 0666 $KEYB_TTY + fi + + # cmd + VDRCMD="$VDRPRG -w $WATCHDOG -v $VIDEODIR -c $VDRCONFDIR -E $VDRVARDIR/epg.data -L $VDRLIBDIR \ + -s $VDRSHUTDOWN -T $VDRSETTIME -r $VDRRECCMDS $VDRKEYBTTY -u $VDRUSER $PLUGINS $OPTIONS " +} + +# modules +function get_modulenames() { + KVERS=`uname -r | grep -e '2.6'` + if [ -z "$KVERS" ]; then + MODULES=`lsmod | grep 'dvb-core' | cut -d'[' -f2 | cut -d']' -f1` + else + MODULES=`lsmod | grep '^dvb_core' | awk '{print $4;}' | awk '{ gsub(/,/," ", $1); print }'` + fi +} + +get_modulenames + +if [ -z "$MODULES" ]; then # If no DVB-Modules were found, try to load + modprobe -q dvb # the module with the name dvb, this could + get_modulenames # be an alias for the dvb-ttpci-module or +fi # another dvb-module + +MODULES="$MODULES dvb-core" + +if [ `echo $MODULES | grep -cw 'b2c2_flexcop'` -gt 0 ] && [ `echo $MODULES | grep -cw 'b2c2_flexcop_pci'` -eq 0 ]; then + MODULES="b2c2_flexcop_pci $MODULES" +fi + +# clear TTY +if [ "$KEYB_TTY" != "" ]; then + clear > $KEYB_TTY +fi + +# main script +while (true) do + # load vdr settings + vdr_settings + # start vdr + logger "Starting Video Disk Recorder at `date`" + eval $VDRCMD >/dev/null 2>&1 + if test $? -eq 0; then + logger "Video Disk Recorder stopped at `date`" + exit 0 + fi + # stop vdr + logger "Stopping Video Disk Recorder at `date`" + $KILL $VDRPRG + n=10 + echo -n "Waiting $n seconds ..." + for i in `seq 1 $n`; do + sleep 1 + (( n=$n-1 )) + echo -n " $n" + done + echo "" + # unload modules + for MODULE in $MODULES; do + rmmod $MODULE >/dev/null 2>&1 + wait `pidof rmmod` + done + # load modules + for MODULE in $MODULES; do + modprobe $MODULE >/dev/null 2>&1 + done +done + +# clear tty +if [ "$KEYB_TTY" != "" ]; then + clear > $KEYB_TTY +fi diff --git a/vdr/scripts/timerrep.sh b/vdr/scripts/timerrep.sh new file mode 100644 index 0000000..c3d48bb --- /dev/null +++ b/vdr/scripts/timerrep.sh @@ -0,0 +1,63 @@ +#!/bin/sh +#------------------------------------------------------------------------------ +# this script allows searching for a repeat of timer using epgsearch (>=0.9.3). +# it requires the timercmd patch from Gerhard Steiner, that extends the timers +# menu of VDR with commands like in recordings menu +# +# add the following lines to your timercmds.conf +# +# Search for repeat : /path_of_this_script/timerrep.sh 0 +# Search for repeat (with subtitle): /path_of_this_script/timerrep.sh 1 +# +# Author: Christian Wieninger (cwieninger@gmx.de) +#------------------------------------------------------------------------------ + +source /etc/default/vdr # x-vdr + +# adjust the following lines to your config +# your plugins config dir +PLUGINCONFDIR=${VDRCONFDIR}/plugins/epgsearch +# path to svdrpsend.pl +SVDRPSEND=${VDRBINDIR}/svdrpsend.pl +# if you are using special subfolders for some recordings, please add them here +FOLDERS="" +# the key used to call epgsearch +EPGSEARCHKEY=user2 + +# do not edit below this line +#------------------------------------------------------------------------------ + +cat << EOM >/tmp/cmd.sh + +SEARCHTERM="$6"~"$7"; +#event info not yet present? then extract it from the file name +if test "\$SEARCHTERM" == "~"; then +SEARCHTERM='$8' +#cut leading special folders +i=0; +FOLDERS=$FOLDERS; +while [ "\$LASTWORD" != "\$FOLDERS" ]; +do + LASTWORD=\${FOLDERS%%,*}; + SEARCHTERM=\${SEARCHTERM#*\$LASTWORD~}; + i=\$i+1; + FOLDERS=\${FOLDERS#*,}; +done +#cut trailing dummy subtitle created by epgsearch +SEARCHTERM=\${SEARCHTERM%~???_??.??.????-??:??} +if [ "$1" -eq "0" ]; then + SEARCHTERM=\${SEARCHTERM%~*}; +fi +fi + +RCFILE=$PLUGINCONFDIR/.epgsearchrc; +echo Search=\$SEARCHTERM > \$RCFILE; +echo SearchMode=0 >> \$RCFILE; +echo UseDescr=0 >> \$RCFILE; +$SVDRPSEND HITK $EPGSEARCHKEY; +EOM + +echo ". /tmp/cmd.sh; rm /tmp/cmd.sh" | at now + + + diff --git a/vdr/scripts/vdr b/vdr/scripts/vdr new file mode 100644 index 0000000..c11d0a5 --- /dev/null +++ b/vdr/scripts/vdr @@ -0,0 +1,130 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: vdr +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Linux Video Disk Recorder +### END INIT INFO +# x-vdr (Installations-Skript fuer einen VDR mit Debian als Basis) +# von Marc Wernecke - www.zulu-entertainment.de +# 12.02.2009 +# /etc/init.d/vdr + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DESC="Linux Video Disk Recorder" +NAME="vdr" +LOGGER="logger -s ${0##*/} " + +if [ -f /etc/default/vdr ]; then + . /etc/default/vdr +else + $LOGGER "exit, because /etc/default/vdr does not exists" + exit 1 +fi + +DAEMON=$VDRBINDIR/runvdr +PIDFILE=/var/run/runvdr.pid + +test -x "$DAEMON" || exit 0 +test -x "$VDRPRG" || exit 0 + +function clean_console() { + if [ "$KEYB_TTY" != "" ]; then + tput -Tlinux clear > $KEYB_TTY + fi +} + +function switch_console() { + if [ "$KEYB_TTY" != "" ]; then + clean_console + echo -e "This tty is currently mapped to VDR, keypresses aren't echoed.\r" > $KEYB_TTY + echo -n "For a login prompt switch to another console." > $KEYB_TTY + chvt `echo "$KEYB_TTY" | sed "s/\/dev\/tty//"` + REDIRECT="< $KEYB_TTY" + fi +} + +function get_status() { + if start-stop-daemon --start --startas $DAEMON --test \ + --name $(basename $DAEMON) --pidfile $PIDFILE >/dev/null + then + echo " - is not running." + exit 3 + else + echo " - is running." + exit 0 + fi +} + +function startvdr() { + if [ "$AUTOSTART" != "off" ]; then + # only start vdr if there is no other instance running + if start-stop-daemon --start --startas $DAEMON --test \ + --name $(basename $DAEMON) --pidfile $PIDFILE >/dev/null + then + # stopping dvb-bootsplash (mplayer) + [ -x /etc/init.d/dvb-bootsplash ] && /etc/init.d/dvb-bootsplash stop + # starting LCDd + # uncomment this only if you DONT use the systems init rc +# [ "$LCDproc" = "on" ] && [ -f /etc/init.d/lcdd ] && /etc/init.d/lcdd start & + # starting Video Disk Recorder +# switch_console + start-stop-daemon --start --quiet --startas $DAEMON --background \ + --name $(basename $DAEMON) --pidfile $PIDFILE --make-pidfile -- $REDIRECT + else + echo -n " - seems to be running already" + fi + else + echo -n " - aborted (to enable the daemon, set AUTOSTART=\"on\" in /etc/default/vdr)" + fi +} + +function stopvdr() { + if start-stop-daemon --stop --retry 30 \ + --name $(basename $DAEMON) --pidfile $PIDFILE >/dev/null + then + start-stop-daemon --stop --retry 30 --oknodo --exec $VDRPRG >/dev/null + rm -f $PIDFILE + clean_console + # graphlcd shutdown sequence + [ "$graphlcd_base" = "on" ] && [ -f /etc/init.d/x-lcd ] && /etc/init.d/x-lcd stop + # stopping LCDd + # uncomment this only if you DONT use the systems init rc +# [ "$LCDproc" = "on" ] && [ -f /etc/init.d/lcdd ] && /etc/init.d/lcdd stop + else + echo -n " - seems not to be running" + fi +} + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + startvdr + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + stopvdr + echo "." + ;; + restart|force-reload) + echo -n "Restarting $DESC: $NAME" + stopvdr + sleep 4 + startvdr + echo "." + ;; + status) + echo -n "Getting status of $DESC: $NAME" + get_status + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/vdr/scripts/vdr-no-shutdown b/vdr/scripts/vdr-no-shutdown new file mode 100644 index 0000000..b880f93 --- /dev/null +++ b/vdr/scripts/vdr-no-shutdown @@ -0,0 +1,12 @@ +#!/bin/sh + +while (true) do + date + echo "vdr-no-shutdown" + echo "if this script is running" + echo "vdr can not shutdown the system" + sleep 60 + done + + + diff --git a/vdr/scripts/vdr2root b/vdr/scripts/vdr2root new file mode 100644 index 0000000..e6cea06 --- /dev/null +++ b/vdr/scripts/vdr2root @@ -0,0 +1,244 @@ +#!/bin/sh + +# x-vdr (Installations-Skript fuer einen VDR mit Debian als Basis) +# von Marc Wernecke - www.zulu-entertainment.de +# 24.03.2008 + +# vdr2root + +# Load VDR configuration +GRUB_POWEROFF= +. /etc/default/vdr +LOGGER="logger -s ${0##*/} " + +# Load vdrshutdown configuration +if [ -f "$VDRCONFDIR/shutdown.conf" ]; then + . "$VDRCONFDIR/shutdown.conf" +else + $LOGGER "$VDRCONFDIR/shutdown.conf nonreadable" + $LOGGER "using defaults" +fi + +KILL="/usr/bin/killall -q -TERM" + +if [ $# -eq 0 ]; then + echo "vdr2root -> this script needs a command..." + $0 help + exit 1 +fi + +case $1 in + admin) + $VDRCONFDIR/plugins/admin/setvdr.sh + ;; + clean-log) + cd /var/log ; cat /dev/null > messages ; cat /dev/null > wtmp ; echo "Säubern der Logfiles..." + ;; + show-log) + if test -s /var/log/messages ; then tail -n 500 /var/log/messages|tac ; else echo "(/var/log/messages) nicht gefunden oder leer..." ; fi + ;; + video-update) + touch $VIDEODIR/.update + ;; + ssh-start) + /etc/init.d/ssh start + ;; + ssh-stop) + /etc/init.d/ssh stop + ;; + ssh-restart) + /etc/init.d/ssh restart + ;; + vdr-kill) + killall -9 runvdr + killall -9 vdr + ;; + vdr-start) + /etc/init.d/vdr start + ;; + vdr-stop) + if [ "$AUTOSTART" != "off" ]; then + /etc/init.d/vdr stop + else + killall -9 runvdr + killall -9 vdr + fi + ;; + vdr-restart) + if [ "$AUTOSTART" != "off" ]; then + /etc/init.d/vdr restart + else + killall -9 vdr + fi + ;; + acpi-wakeup) + # $2 = wakeuptime + [ $# -eq 3 ] && echo $2 > $3 + ;; + nvram-wakeup) + # $2 = wakeuptime + [ $# -eq 2 ] && nvram-wakeup $2 + ;; + extb-poweroff) + $VDRSCRIPTDIR/extb-poweroff.pl + ;; + lilo) + lilo -R PowerOff + ;; + grub) + if [ $# -eq 2 ] && [ -n "$GRUB_POWEROFF" ]; then + grub-set-default $GRUB_POWEROFF + else + $LOGGER "stop shutdown, because missing configuration" + fi + ;; + reboot) + shutdown -r now + ;; + shutdown) + shutdown -h now + ;; + poweroff) + poweroff + ;; + settime) + [ $# -eq 2 ] && /bin/date $2 + ;; + readdvd) + # dvdselect and dvdswitch + # $1 = "readdvd" + # $2 = directory for dvd's (see plugin configuration menu) + # $3 = name of dvd + # $4 = original dvd-device + # dvdswitch only + # $5 = mountpoint - default is "(null)" + # $6 = "IMAGE" or "DIR" + LOGFILE="/var/log/vdrreaddvd.log" + echo "vdr2root # `date`" > "$LOGFILE" 2>&1 + echo "vdr2root # $0 $*" >> "$LOGFILE" 2>&1 + if [ ! -e "$DVDBURNER" ]; then + echo "vdr2root # DVDBURNER=\"$DVDBURNER\" does not exists" >> "$LOGFILE" 2>&1 + exit 1 + fi + eject -t $DVDBURNER + [ ! -d "$2" ] && mkdir -p "$2" && echo "vdr2root # Erstelle \"$2\"" >> "$LOGFILE" 2>&1 + case $6 in + IMAGE) + [ -f "$2/$3" ] && rm -f "$2/$3" && echo "vdr2root # Lösche \"$2/$3\"" >> "$LOGFILE" 2>&1 + echo "vdr2root # DVD einlesen gestartet" >> "$LOGFILE" 2>&1 + $VDRBINDIR/svdrpsend.pl -d localhost "MESG DVD einlesen gestartet" + dd if="$4" of="$2/$3" >> "$LOGFILE" 2>&1 + ;; + DIR) + cd "$2" + [ -d "$3" ] && rm -rf "$3" && echo "vdr2root # Lösche \"$2/$3\"" >> "$LOGFILE" 2>&1 + echo "vdr2root # DVD einlesen gestartet" >> "$LOGFILE" 2>&1 + $VDRBINDIR/svdrpsend.pl -d localhost "MESG DVD einlesen gestartet" + vobcopy -i $DVDBURNER -o "$2" -t "$3" -m >> "$LOGFILE" 2>&1 + ;; + esac + eject $DVDBURNER + echo "vdr2root # DVD einlesen fertig" >> "$LOGFILE" 2>&1 + chown $VDRUSER.$VDRGROUP "$2/$3" && echo "vdr2root # chown $VDRUSER.$VDRGROUP \"$2/$3\"" >> "$LOGFILE" 2>&1 + $VDRBINDIR/svdrpsend.pl -d localhost "MESG DVD einlesen fertig" + ;; + writedvd) + # dvdselect and dvdswitch + # $1 = writedvd + # $2 = filename + LOGFILE="/var/log/vdrwritedvd.log" + echo "vdr2root # `date`" > "$LOGFILE" 2>&1 + echo "vdr2root # $0 $1 \"$2\"" >> "$LOGFILE" 2>&1 + if [ ! -e "$DVDBURNER" ]; then + echo "vdr2root # DVDBURNER=\"$DVDBURNER\" does not exists" >> "$LOGFILE" 2>&1 + exit 1 + fi + BURN_SPEED=0 + SPEED="" + [ $BURN_SPEED -gt 0 ] && SPEED="-speed=$BURN_SPEED" + unset SUDO_COMMAND + eject -t $DVDBURNER + echo "vdr2root # DVD brennen gestartet" >> "$LOGFILE" 2>&1 + $VDRBINDIR/svdrpsend.pl -d localhost "MESG DVD brennen gestartet" + if [ -f "$2" ]; then + growisofs -use-the-force-luke=tty -dvd-compat $SPEED -Z $DVDBURNER="$2" >> "$LOGFILE" 2>&1 + elif [ -d "$2" ]; then + DVDNAME=`basename "$2"` + growisofs -use-the-force-luke=tty -dvd-compat $SPEED -Z $DVDBURNER -dvd-video -V "$DVDNAME" "$2" >> "$LOGFILE" 2>&1 + fi + eject $DVDBURNER + echo "vdr2root # DVD brennen fertig" >> "$LOGFILE" 2>&1 + $VDRBINDIR/svdrpsend.pl -d localhost "MESG DVD brennen fertig" + ;; + automount) + wakeonlan 00:00:00:00:00:00 + echo "wake on..." + sleep 10 + [ ! -d /mnt/vdrserver ] && mkdir -p /mnt/vdrserver + if [ ! -d $VIDEODIR/vdrserver ]; then + cd $VIDEODIR + ln -vnfs /mnt/vdrserver vdrserver + fi + echo "...waiting" + sleep 10 + echo "waiting..." + sleep 10 + echo "...waiting" + sleep 10 + echo "waiting..." + sleep 10 + echo "...mounting" + mount -t smbfs -o password= //vdrserver/video /mnt/vdrserver + echo "erneues einlesen der Aufnahmen..." + touch $VIDEODIR/.update + ;; + wakeonlan) + wakeonlan 00:00:00:00:00:00 + ;; + mount) + if [ ! -d /mnt/vdrserver ] ; then mkdir -p /mnt/vdrserver ; fi + if [ ! -d $VIDEODIR/vdrserver ] ; then + cd $VIDEODIR + ln -vnfs /mnt/vdrserver vdrserver + fi + mount -t smbfs -o password= //vdrserver/video /mnt/vdrserver + touch $VIDEODIR/.update + ;; + umount) + umount -t smbfs /mnt/vdrserver +# exec umount -t smbfs /mnt/vdrserver + touch $VIDEODIR/.update + ;; + * | help) + [ "$1" != "help" ] && echo "vdr2root -> # $0 $* <- command not found" + echo "vdr2root -> possible commands are..." + echo "$0 acpi-wakeup \$2" + echo "$0 admin" + echo "$0 automount" + echo "$0 clean-log" + echo "$0 help" + echo "$0 lilo" + echo "$0 mount" + echo "$0 nvram-wakeup \$2" + echo "$0 poweroff" + echo "$0 readdvd \$2 \$3 \$4" + echo "$0 reboot" + echo "$0 settime \$2" + echo "$0 show-log" + echo "$0 shutdown" + echo "$0 ssh-start" + echo "$0 ssh-stop" + echo "$0 umount" + echo "$0 vdr-start" + echo "$0 vdr-stop" + echo "$0 vdr-restart" + echo "$0 video-update" + echo "$0 wakeonlan" + echo "$0 writedvd \$2" + ;; +esac + +exit 0 + + + diff --git a/vdr/scripts/vdrmount b/vdr/scripts/vdrmount new file mode 100644 index 0000000..0be7b02 --- /dev/null +++ b/vdr/scripts/vdrmount @@ -0,0 +1,35 @@ +#!/bin/bash +# +# This script is called from VDR to mount/unmount/eject +# the sources for MP3 play. +# +# argument 1: wanted action, one of mount,unmount,eject,status +# argument 2: mountpoint to act on +# +# mount,unmount,eject must return 0 if succeeded, 1 if failed +# status must return 0 if device is mounted, 1 if not +# + +action="$1" +path="$2" + +case "$action" in + mount) + if [ -z "$(echo $path | grep "usb")" ]; then + eject -t "$path" || exit 1 # close the tray + fi + mount "$path" || exit 1 # mount it + ;; + unmount) + umount "$path" || exit 1 # unmount it + ;; + eject) + eject "$path" || exit 1 # eject disk + ;; + status) + cat /proc/mounts | grep -q "$path" # check if mounted + [ $? -ne 0 ] && exit 1 # not mounted ... + ;; +esac + +exit 0 diff --git a/vdr/scripts/vdrnoad b/vdr/scripts/vdrnoad new file mode 100644 index 0000000..39ba8af --- /dev/null +++ b/vdr/scripts/vdrnoad @@ -0,0 +1,99 @@ +#!/bin/bash +# +# vdrnoad +# +# Required: noad, at +# +# add this lines to your reccmds.conf: +# folgende zeilen in die reccmds.conf eintragen: +# +# Run noad : /usr/lib/vdr/scripts/vdrnoad -start +# Run noad, all recordings (batch) : /usr/lib/vdr/scripts/vdrnoad -batch +# View Cut list : /usr/lib/vdr/scripts/vdrnoad -view +# In prozess : /usr/lib/vdr/scripts/vdrnoad -count +# Stop noad (killpid) : /usr/lib/vdr/scripts/vdrnoad -killpid +# Stop noad (killall)? : /usr/lib/vdr/scripts/vdrnoad -killall +# Remove marks : /usr/lib/vdr/scripts/vdrnoad -marks +# Remove pid : /usr/lib/vdr/scripts/vdrnoad -pid +# Remove all marks : /usr/lib/vdr/scripts/vdrnoad -marks.vdr +# Remove all pids : /usr/lib/vdr/scripts/vdrnoad -noad.pid + +# CONFIG START + NOADOPTS="nice --background --ac3 --asd --overlap --jumplogo --comments --OSD --statisticfile=/var/log/noadstat" + #VIDEODIR="/video" + source /etc/default/vdr +# CONFIG END + +#PATH=/usr/local/bin:$PATH + +case "$1" in + -start) + echo "recording: " + echo + echo "$2" + echo + if [ -e "$2/noad.pid" ] ; then + echo "noad is already active..." + else + echo "noad $NOADOPTS \"$2\" >/dev/null 2>&1" | at now + echo "noad startet..." + fi + ;; + -batch) + while read i ; do + if [ ! -e "$i/marks.vdr" -a ! -e "$i/noad.pid" ] ; then + echo "noad $NOADOPTS \"$i\" >/dev/null 2>&1" | batch + fi + done < <(find "$VIDEODIR" -follow -name "*.rec") + ;; + -view) + echo "recording: " + echo + echo "$2" + echo + if [ -e "$2/noad.pid" ] ; then + echo "noad is still active..." + echo + fi + if [ -e "$2/marks.vdr" ] ; then + cat "$2/marks.vdr" + else + echo "cut list not found..." + fi + ;; + -count) + echo "all noad processes:" + echo + pidof noad | wc -w | tr -d ' ' + ;; + -killpid) + echo "recording: " + echo + echo "$2" + echo + if [ -e "$2/noad.pid" ] ; then + kill `cat "$2/noad.pid"` + echo "noad stopped..." + else + echo "noad is not active..." + fi + ;; + -killall) + PID=`pidof noad` + eval ${PID:+kill $PID} + ;; + -marks) + rm -f "$2/marks.vdr" + ;; + -pid) + rm -f "$2/noad.pid" + ;; + -marks.vdr|-noad.pid) + find "$VIDEODIR" -follow -type f -name "${1/-}" -exec rm -f '{}' ';' & + ;; + *) + echo "unrecognized option: $1" + exit 1 + ;; +esac + diff --git a/vdr/scripts/vdrplayer b/vdr/scripts/vdrplayer new file mode 100644 index 0000000..ce6b8b5 --- /dev/null +++ b/vdr/scripts/vdrplayer @@ -0,0 +1,279 @@ +#!/bin/bash + +# vdrplayer 0.0.5 (start-script for shmclient, tvtime, vdrtvtime, vdr-sxfe, xine or xineliboutput) +# by Marc Wernecke - www.zulu-entertainment.de +# 10.02.2009 + +### Config #################################################################################### +NONROOT="true" # true or false +STARTX="true" # allways, true or false +VDRIP= # 127.0.0.1 for localhost or any other ip for a vdr-server in your local-network +VDRPLAYER= # shmclient, tvtime, vdr-sxfe, xine, xineliboutput or xine-network + +[ "$HOME" = "/" ] && HOME=/etc +[ -r $HOME/vdrplayer.conf ] && . $HOME/vdrplayer.conf + +### Arguments ################################################################################# +EXIT="false" +KILLALL="false" +VERSION="vdrplayer 0.0.4" + +for i in $* ; do + case $1 in + --exit|-e) + EXIT="true" + ;; + --help|-h) + echo "$VERSION" + echo "--exit|-e Kill all active player and exit" + echo "--help|-h Shows the help text and exit" + echo "--killall|-k Kill all active player, the X server and exit" + echo "--nonroot|-n Sets NONROOT flag" + echo "--reset|-r Remove the configuration file (\$HOME/vdrplayer.conf)" + echo "--startx|-s [allways|true|false]" + echo "--ip|-i [ip] 127.0.0.1 for localhost or any other ip for a vdr-server in your local-network" + echo "--player|-p [shmclient|tvtime|vdr-sxfe|xine|xineliboutput|xine-network]" + echo "--version|-v Shows the script version and exit" + exit 0 + ;; + --killall|-k) + KILLALL="true" + ;; + --nonroot|-n) + NONROOT="true" + ;; + --reset|-r) + if [ -f $HOME/vdrplayer.conf ]; then + rm -f $HOME/vdrplayer.conf + VDRIP= + VDRPLAYER= + fi + ;; + --startx|-s) + shift 1 + STARTX="$1" + ;; + --ip|-i) + shift 1 + VDRIP="$1" + ;; + --player|-p) + shift 1 + VDRPLAYER="$1" + ;; + --version|-v) + echo "$VERSION" + exit 0 + ;; + esac + shift 1 +done + +if [ -n "`ps x --user root | grep "/usr/.*bin/X.*:0" | grep -v grep`" ]; then # X is running + DIALOG="Xdialog" +else + DIALOG="dialog" +fi + +### Functions ################################################################################# +function _exit() { + case $1 in + 0) exit 0 + ;; + 1) exit 1 + ;; + 2) exit 2 + ;; + esac + exit 0 +} + +function _vdr() { + # Max waiting time in Seconds + n=10 + # Check if VDR is running + if [ `ps -C vdr | grep -cw "vdr"` -eq 0 ]; then + echo "vdr is not running" + echo -n "Waiting $n seconds ..." + # test if vdr is running + while [ `ps -C vdr | grep -cw "vdr"` -eq 0 ] && [ $n -gt 0 ]; do + sleep 1 + (( n=$n-1 )) + echo -n " $n" + if [ $n -eq 0 ]; then + echo " exit" + return 1 + fi + done + echo "" + echo "vdr is online" + fi + return 0 +} + +function _vdrip() { + VDRIP=`$DIALOG --inputbox "VDR Server IP" 10 50 "127.0.0.1" 3>&1 1>&2 2>&3` + [ $? != 0 ] && return 1 + [ "$VDRIP" = "" ] && return 1 + echo "VDRIP=$VDRIP" >> $HOME/vdrplayer.conf + return 0 +} + +function _x() { + case $STARTX in + allways) STARTX="allways";; + true) STARTX="true";; + *) STARTX="false"; return 0 ;; + esac + VT=vt7 + + # if no X is running and user=root, start it + if [ -n "`ps x --user root | grep "/usr/.*bin/X.*:1" | grep -v "grep"`" ]; then + # X:1 is running + export DISPLAY=:1 + return 0 + elif [ -n "`ps x --user root | grep "/usr/.*bin/X" | grep -v "grep"`" ]; then + # X:0 is running + if [ "$STARTX" = "allways" ]; then + if [ "$NONROOT" = "false" ]; then + [ "`id -u`" = "0" ] || return 1 + fi + export DISPLAY=:1 + VT=vt9 + else + export DISPLAY=:0 + return 0 + fi + else + if [ "$NONROOT" = "false" ]; then + [ "`id -u`" = "0" ] || return 1 + fi + export DISPLAY=:0 + fi + + # start X + echo "Starting the X server..." + /usr/bin/X -ac -dpi 100 $DISPLAY $VT & sleep 4 +# xhost local:localhost + return 0 +} + +function _shmclient() { + _x || return 1 + CMD="--fullscreen" + ShmClient $CMD & + return 0 +} + +function _tvtime() { +# chmod 666 /dev/rtc +# echo 1024 > /proc/sys/dev/rtc/max-user-freq + _x || return 1 + CMD="--fullscreen --display=$DISPLAY" + tvtime $CMD & + sleep 2 + tvtime-command MENU_EXIT + return 0 +} + +function _vdrtvtime() { +# chmod 666 /dev/rtc +# echo 1024 > /proc/sys/dev/rtc/max-user-freq + _x || return 1 + svdrpsend.pl PLUG vdrtvtime start & + return 0 +} + +function _vdrsxfe() { + [ -n "$VDRIP" ] || _vdrip || return 1 + _x || return 1 + CMD="--video=xv --fullscreen --post tvtime:method=LinearBlend,cheap_mode=1,pulldown=0,use_progressive_frame_flag=1" + MRL="xvdr+tcp://$VDRIP" + vdr-sxfe $CMD $MRL & + return 0 +} + +function _xineliboutput() { + [ -n "$VDRIP" ] || _vdrip || return 1 + _x || return 1 + CMD="--fullscreen --hide-gui" + MRL="xvdr+tcp://$VDRIP#nocache;demux:mpeg_block" + xine $CMD "$MRL" & + return 0 +} + +function _xine() { + _x || return 1 + CMD="--fullscreen --hide-gui --post vdr --post vdr_audio" + MRL="vdr:/tmp/vdr-xine/stream#demux:mpeg_pes" + xine $CMD "$MRL" & + return 0 +} + +function _xinenetwork() { + [ -n "$VDRIP" ] || _vdrip || return 1 + _x || return 1 + CMD="--fullscreen --hide-gui --post vdr --post vdr_audio" + MRL="netvdr://$VDRIP#demux:mpeg_pes" + xine $CMD "$MRL" & + return 0 +} + +### Main Script ############################################################################### + +_vdr || exit 1 # Check if VDR is running + +[ -n "`ps x | grep ShmClient`" ] && killall -q -9 ShmClient # If ShmClient is running, stop it +[ -n "`ps x | grep tvtime`" ] && killall -q -9 tvtime # If tvtime is running, stop it +[ -n "`ps x | grep vdr-sxfe`" ] && killall -q -9 vdr-sxfe # If vdr-sxfe is running, stop it +[ -n "`ps cx | grep xine`" ] && killall -q -9 xine # If xine is running, stop it +[ "$VDRPLAYER" = "vdrtvtime" ] && svdrpsend.pl PLUG vdrtvtime stop + +if [ "$EXIT" = "true" ]; then # Exit + exit 0 +fi + +if [ "$KILLALL" = "true" ]; then # Stop X and Exit + [ -n "`ps x --user root | grep "/usr/.*bin/X" | grep -v "grep"`" ] && killall -q -9 Xorg + exit 0 +fi + +# Player +if [ -n "$VDRPLAYER" ]; then + case $VDRPLAYER in + shmclient) _shmclient ;; + tvtime) _tvtime ;; + vdrtvtime) _vdrtvtime ;; + vdr-sxfe) _vdrsxfe ;; + xineliboutput) _xineliboutput ;; + xine) _xine ;; + xine-network) _xinenetwork ;; + *) VDRPLAYER="" ;; + esac +fi + +# Dialog +if [ -z "$VDRPLAYER" ]; then + option=`$DIALOG --menu \ + 'Aktiviere den Player, den du nutzen moechtest.' 0 0 8 \ + '1' 'ShmClient (Softdevice)' \ + '2' 'Tvtime (FF-Karte)' \ + '3' 'vdrtvtime (tvtime als Plugin, FF-Karte)' \ + '4' 'vdr-sxfe (Xineliboutput)' \ + '5' 'Xine' \ + '6' 'Xine (Xineliboutput)' \ + '7' 'Xine-Network' 3>&1 1>&2 2>&3` + [ $? != 0 ] && exit 1 + VDRIP= + case $option in + 1) echo "VDRPLAYER=\"shmclient\"" > $HOME/vdrplayer.conf && _shmclient ;; + 2) echo "VDRPLAYER=\"tvtime\"" > $HOME/vdrplayer.conf && _tvtime ;; + 3) echo "VDRPLAYER=\"vdrtvtime\"" > $HOME/vdrplayer.conf && _vdrtvtime ;; + 4) echo "VDRPLAYER=\"vdr-sxfe\"" > $HOME/vdrplayer.conf && _vdrsxfe ;; + 5) echo "VDRPLAYER=\"xine\"" > $HOME/vdrplayer.conf && _xine ;; + 6) echo "VDRPLAYER=\"xineliboutput\"" > $HOME/vdrplayer.conf && _xineliboutput ;; + 7) echo "VDRPLAYER=\"xine-network\"" > $HOME/vdrplayer.conf && _xinenetwork ;; + esac +fi + +exit 0
\ No newline at end of file diff --git a/vdr/scripts/vdrreaddvd b/vdr/scripts/vdrreaddvd new file mode 100644 index 0000000..ff1a84d --- /dev/null +++ b/vdr/scripts/vdrreaddvd @@ -0,0 +1,31 @@ +#!/bin/sh +# +# vdrreaddvd - x-vdr version +# +# This script will be called by the vdr-plugins dvdselect and dvdswitch to copy a DVD to the local drive. +# +# It gets the following parameters: +# +# dvdselect and dvdswitch +# $1 = directory for dvd's (see plugin configuration menu) +# $2 = name of dvd +# $3 = original dvd-device +# dvdswitch only +# $4 = mountpoint - default is "(none)" +# $5 = "IMAGE" or "DIR" + +# Load VDR configuration +. /etc/default/vdr + +# vdr2root +if [ $# -eq 3 ]; then + # dvdselect + echo "sudo $VDRSCRIPTDIR/vdr2root readdvd \"$1\" \"$2\" \"$3.iso\" (none) IMAGE" | at now +elif [ $# -eq 5 ]; then + # dvdswitch + echo "sudo $VDRSCRIPTDIR/vdr2root readdvd \"$1\" \"$2\" \"$3\" \"$4\" \"$5\"" | at now +else + exit 1 +fi + +exit 0 diff --git a/vdr/scripts/vdrreccmds b/vdr/scripts/vdrreccmds new file mode 100644 index 0000000..5259b43 --- /dev/null +++ b/vdr/scripts/vdrreccmds @@ -0,0 +1,32 @@ +#!/bin/sh +# 24.06.2007 + +# Load VDR configuration +. /etc/default/vdr + +function NoadExclude() { + Channel="$*" + [ -r $VDRCONFDIR/noad-exclude-channels.conf ] || return 1 + cat $VDRCONFDIR/noad-exclude-channels.conf | while read NewLine; do + [ -n "`echo "$Channel" | grep "D\ .*\ -"`" ] && Channel="`echo "$Channel" | cut -c1,2,3`" + [ "$NewLine" = "$Channel" ] && killall -9 $(basename $0) + done +} + +case "$1" in + before) + echo "Start recording $2" + ;; + after) + echo "Finished recording $2" + [ "$noad" = "on" ] || exit + [ $# -ge 3 ] && NoadExclude "$3" + $VDRSCRIPTDIR/vdrnoad -start $2 + ;; + edited) + echo "Edited recording $2" + ;; + *) + echo "ERROR: unknown state: $1" + ;; +esac
\ No newline at end of file diff --git a/vdr/scripts/vdrsettime b/vdr/scripts/vdrsettime new file mode 100644 index 0000000..6bd83bb --- /dev/null +++ b/vdr/scripts/vdrsettime @@ -0,0 +1,8 @@ +#!/bin/bash + +# Load VDR configuration +. /etc/default/vdr + +sudo $VDRSCRIPTDIR/vdr2root settime "$1" + + diff --git a/vdr/scripts/vdrsetup b/vdr/scripts/vdrsetup new file mode 100644 index 0000000..e45e39f --- /dev/null +++ b/vdr/scripts/vdrsetup @@ -0,0 +1,1896 @@ +#!/bin/bash +# +# (x-)vdrsetup 0.0.8 - script for OSDServer on localhost +# by Marc Wernecke - www.zulu-entertainment.de +# 12.02.2009 + +script="$0" + +# convenient return values +true=0 +false=1 + + +# Some generic stuff for handling a connection + +function error() { + # Fatal error. Send quit command, close FIFO and terminate netcat + DoLog "fatal error, disconnecting..." + [ "${reply2xx[0]}" != 202 ] && SendCmd Quit + + exec 3>&- + exec 4>&- + + kill $pid + + exit 1 +} + +function ConnectServer() { + # Connect to the OSDServer + DoLog "connecting to the OSDServer..." + # Set up temporary fifo and open as file descriptor 3 and 4 + mkfifo --mode=700 /tmp/pipe-in$$ /tmp/pipe-out$$ + exec 3<> /tmp/pipe-in$$ + exec 4<> /tmp/pipe-out$$ + rm /tmp/pipe-in$$ /tmp/pipe-out$$ + + # Connect to server using the fifo + { + netcat $1 $2 + + # In case of connection loss: + echo 499 disconnected + echo 202 Good Bye. + } <&3 >&4 & + pid=$! + + # Sending to the server: use >&3 + # Receive from the server: use <&4 +} + + +function ReadReply() { + # Read a complete server reply until 2xx return code, + # and store replies in each category by number + reply2xx=() + reply3xx=() + reply4xx=() + reply5xx=() + reply6xx=() + + while read -r code line <&4 ; do + echo "< $code $line" + # screen echo + + # vdrsetup debug + if [ "$vdrsetup_use_debug" = "on" ]; then + [ "$vdrsetup_use_log" = "on" ] && echo "< $code $line" >> "$vdrsetup_log" + [ "$vdrsetup_use_syslog" = "on" ] && $LOGGER "< $code $line" + fi + + case $code in + 2*) IFS=$' \t\n\r' reply2xx=($code "$line") + ;; + 3*) IFS=$' \t\n\r' reply3xx=($code $line) + ;; + 4*) IFS=$' \t\n\r' reply4xx=($code "$line") + ;; + 5*) IFS=$' \t\n\r' reply5xx=($code "$line") + ;; + 6*) IFS=$' \t\n\r' reply6xx=($code "$line") + ;; + esac + [ -n "${reply2xx[0]}" ] && break + done + + [ -n "${reply4xx[0]}" ] && return $false + return $true +} + +function SendCmd() { + # Send a command and read the reply + + echo "> $*" + # screen echo + + echo "$*" >&3 + # network send + + # vdrsetup debug + if [ "$vdrsetup_use_debug" = "on" ]; then + [ "$vdrsetup_use_log" = "on" ] && echo "> $*" >> "$vdrsetup_log" + [ "$vdrsetup_use_syslog" = "on" ] && $LOGGER "> $*" + fi + + ReadReply +} + +function IsEvent() { + # Helper to check reply for a certain event + + [ "${reply3xx[0]}" != 300 ] && return $false + [ "${reply3xx[1]}" != "$1" ] && return $false + [ "${reply3xx[2]}" != "$2" ] && return $false + + return $true +} + + +function QuoteString() { + # Quote arbitrary string for use in '' and "" + local str="${!1}" + + str="${str//'\'/\\\\}" + str="${str//'\\'/\\\\}" + # work around bash bug: double quoted '\' + + str="${str//\'/$'\\\''}" + # This is bogus, anyone knows something better to replace ' by \' ? + + str="${str//\"/\\\"}" + str="${str//$'\r'/\\r}" + str="${str//$'\n'/\\n}" + str="${str//$'\t'/\\t}" + + eval "$1=\$str" +} + +function UnquoteString() { + # Unquote string + local str="${!1}" + + str="${str//\\r/$'\r'}" + str="${str//\\n/$'\n'}" + str="${str//\\t/$'\t'}" + str="${str//\\\"/\"}" + str="${str//\\\'/\'}" + str="${str//\\\\/\\}" + + eval "$1=\$str" +} + + +############## +# vdrsetup # +############## +vdrsetup_ok_ends="on" +vdrsetup_key_timeout=1000 +# logging +LOGGER="logger -- ${0##*/} - " +vdrsetup_use_screen="on" # echo setup changings to the screen +vdrsetup_use_log="off" # echo setup changings to $vdrsetup_log +vdrsetup_log="/tmp/vdrsetup.log" # log file +vdrsetup_use_syslog="on" # echo setup changings (with LOGGER) to syslog +vdrsetup_use_debug="off" # enable comunications log + +# vdr configuration +config=/etc/default/vdr # path to vdr configuration +. $config # load vdr configuration +[ -f "$VDRCONFDIR/plugins/vdrsetup.conf" ] && . "$VDRCONFDIR/plugins/vdrsetup.conf" + +# x-vdr +have_xvdr="on" +[ ! -f /usr/local/src/x-vdr/setup.conf ] && have_xvdr="off" + +# /tmp/vdr-help.tmp +[ ! -f /tmp/vdr-help.tmp ] && $VDRPRG --help | sed -e '/^$/d' -e 's/^. //' > /tmp/vdr-help.tmp + +# vdr-desc.cache +[ ! -f /tmp/vdr-desc.cache ] && $VDRPRG --version | sed -e 's/\(^[^ ]*\)\(.*$\)/\1_desc="\1\2"/' -e '/^streamdev/s/-/_/' -e 's/^\[.*//' | sort > /tmp/vdr-desc.cache +. /tmp/vdr-desc.cache +vdr_version=$(echo $vdr_desc | sed -e 's/[^)]*$//') +plugin_api=$(echo $vdr_desc | sed -e 's/[^)]*$//' -e 's/^[^\/]*//g' -e 's/\///' -e 's/\/*)//') + +# reset logfile +[ "$vdrsetup_use_log" = "on" ] && echo "$0" > "$vdrsetup_log" + +# helper functions => +function DoLog() { + [ "$vdrsetup_use_log" = "on" ] && echo "$*" >> "$vdrsetup_log" + [ "$vdrsetup_use_screen" = "on" ] && echo ">> $*" + [ "$vdrsetup_use_syslog" = "on" ] && $LOGGER "$*" +} + +function CreateDir() { + directory="$*" + if [ ! -d "$directory" ]; then + SendCmd "Message -seconds 10 'Create $directory?'" || return $false + if IsEvent Message keyOk ; then + mkdir -p "$directory" + chown -R $VDRUSER:$VDRGROUP "$directory" + [ -d "$directory" ] && DoLog "creating \"$directory\"" + fi + else + DoLog "directory \"$directory\" already exist" + fi +} + +# Menu functions => + +##### Script-Setup Menu ##### +function ScriptSetup() { + # Menu ---------------------------------------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu 'Skript Intern'" || return $false + SendCmd "menu.SetColorKeyText -blue 'Help'" || return $false + SendCmd "menu.SetColumns 24" || return $false + SendCmd "menu.EnableEvent keyOk keyBlue close" || return $false + # List ---------------------------------------------------------------------------------------------------------------------------------> + SendCmd "menu.AddNew OsdItem -unselectable '--- Einstellungen ---'" || return $false + SendCmd "opt1=menu.AddNew EditListItem -selectname '$vdrsetup_ok_ends' 'Beim Speichern beenden' on off" || return $false + SendCmd "opt2=menu.AddNew EditIntItem 'Tasten Timeout (ms)' '$vdrsetup_key_timeout'" || return $false + SendCmd "menu.AddNew OsdItem -unselectable ''" || return $false + SendCmd "menu.AddNew OsdItem -unselectable '--- Logging ---'" || return $false + SendCmd "opt3=menu.AddNew EditListItem -selectname '$vdrsetup_use_log' 'Benutze Log Datei' on off" || return $false + SendCmd "opt4=menu.AddNew EditStrItem 'Log Datei' $vdrsetup_log'" || return $false + SendCmd "opt5=menu.AddNew EditListItem -selectname '$vdrsetup_use_syslog' 'Syslog benutzen' on off" || return $false + SendCmd "opt6=menu.AddNew EditListItem -selectname '$vdrsetup_use_debug' 'Debug Nachrichten' on off" || return $false + SendCmd "menu.AddNew OsdItem -unselectable ''" || return $false + SendCmd "menu.AddNew OsdItem -unselectable '--- Befehle ---'" || return $false + SendCmd "opt7=menu.AddNew OsdItem 'Cache neu erstellen'" || return $false + SendCmd "opt7.EnableEvent keyRed focus blur" || return $false + # <--------------------------------------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.show" || return $false + # <--------------------------------------------------------------------------------------------------------------------------------- Menu + + while true; do + SendCmd "menu.SleepEvent" || return $false + # keyOk + if IsEvent menu keyOk ; then + echo "# $script" > "$VDRCONFDIR/plugins/vdrsetup.conf" + # vdrsetup_ok_ends + SendCmd "opt1.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + vdrsetup_ok_ends="${reply6xx[1]}" + echo "vdrsetup_ok_ends=\"$vdrsetup_ok_ends\"" >> "$VDRCONFDIR/plugins/vdrsetup.conf" + # key_timeout + SendCmd "opt2.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + vdrsetup_key_timeout="${reply6xx[1]}" + echo "vdrsetup_key_timeout=\"$vdrsetup_key_timeout\"" >> "$VDRCONFDIR/plugins/vdrsetup.conf" + # vdrsetup_use_log + SendCmd "opt3.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + vdrsetup_use_log="${reply6xx[1]}" + echo "vdrsetup_use_log=\"$vdrsetup_use_log\"" >> "$VDRCONFDIR/plugins/vdrsetup.conf" + # vdrsetup_log + SendCmd "opt4.GetValue -quoted" || return $false + if [ "${reply5xx[0]}" = 500 ]; then + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + [ -d "$(dirname "$value")" ] && vdrsetup_log="$value" + fi + echo "vdrsetup_log=\"$vdrsetup_log\"" >> "$VDRCONFDIR/plugins/vdrsetup.conf" + # vdrsetup_use_syslog + SendCmd "opt5.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + vdrsetup_use_syslog="${reply6xx[1]}" + echo "vdrsetup_use_syslog=\"$vdrsetup_use_syslog\"" >> "$VDRCONFDIR/plugins/vdrsetup.conf" + # vdrsetup_use_debug + SendCmd "opt6.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + vdrsetup_use_debug="${reply6xx[1]}" + echo "vdrsetup_use_debug=\"$vdrsetup_use_debug\"" >> "$VDRCONFDIR/plugins/vdrsetup.conf" + # close the submenu + if [ "$vdrsetup_ok_ends" = "on" ]; then + SendCmd "menu.SendState osBack" || return $false +# SendCmd "delete menu" || return $false +# SendCmd "leavelocal" || return $false +# return $true + fi + fi + if IsEvent opt7 focus ; then + SendCmd "menu.SetColorKeyText -red Create" || return $false + SendCmd "menu.Show" || return $false + fi + if IsEvent opt7 blur ; then + SendCmd "menu.SetColorKeyText -red ''" || return $false + SendCmd "menu.Show" || return $false + fi + if IsEvent opt7 keyRed ; then + SendCmd "Message -seconds 10 '/tmp/vdr-desc.cache erstellen?'" || return $false + if IsEvent Message keyOk ; then + $VDRPRG --version | sed -e 's/\(^[^ ]*\)\(.*$\)/\1_desc="\1\2"/' -e '/^streamdev/s/-/_/' -e 's/^\[.*//' | sort > /tmp/vdr-desc.cache + . /tmp/vdr-desc.cache + fi + fi + # keyBlue (Help) + if IsEvent menu keyBlue ; then + SendCmd "Message -seconds 5 'Auswahl mit Links und Rechts, speichern mit Ok'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + +##### System-Start Menu ##### +function SystemStart() { + Gdm="$(find /etc/rc*d/S*gdm)" + if [ -n "$Gdm" ]; then + DESKTOP_MANGER="gdm" + [ -f /etc/rc2.d/S30gdm ] && echo warning + [ -f /etc/rc3.d/S30gdm ] && DESKTOP="on" + fi + + RUNLEVEL_STR="$(cat /etc/inittab | grep -m1 ^id:)" + RUNLEVEL=$(echo $RUNLEVEL_STR | cut -f2 -d":") + if [ $RUNLEVEL -eq 5 ] || [ "$DESKTOP_MANGER" ="gdm" -a $RUNLEVEL -gt 2 ]; then + DESKTOP="on" + else + DESKTOP="off" + fi + + # Menu -------------------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu 'Systemstart'" || return $false + SendCmd "menu.SetColorKeyText -blue 'Help'" || return $false + SendCmd "menu.SetColumns 24" || return $false + SendCmd "menu.EnableEvent keyOk close" || return $false + # List -------------------------------------------------------------------------------------------------------------> + SendCmd "menu.AddNew OsdItem -unselectable '--- Programme ---'" || return $false + SendCmd "opt1=menu.AddNew EditListItem -selectname '$AUTOSTART' 'VDR' on off" || return $false + SendCmd "opt1.EnableEvent keyBlue" || return $false + SendCmd "opt2=menu.AddNew EditListItem -selectname '$XPLAYER' 'Xserver und Player' on off" || return $false + SendCmd "opt2.EnableEvent keyBlue" || return $false + SendCmd "opt3=menu.AddNew EditListItem -selectname '$DESKTOP' 'Desktop-Manager' on off" || return $false + SendCmd "opt3.EnableEvent keyBlue" || return $false + SendCmd "opt4=menu.AddNew EditListItem -selectname '$vdradmin' 'VDR-Admin' on off" || return $false + SendCmd "opt4.EnableEvent keyBlue" || return $false + SendCmd "menu.AddNew OsdItem -unselectable ''" || return $false + SendCmd "menu.AddNew OsdItem -unselectable '--- Module ---'" || return $false + SendCmd "optA=menu.AddNew EditListItem -selectname '$em8300' 'DXR3' on off" || return $false + SendCmd "optA.EnableEvent keyBlue" || return $false + SendCmd "optB=menu.AddNew EditListItem -selectname '$graphlcd_base' 'GraphLCD' on off" || return $false + SendCmd "optB.EnableEvent keyBlue" || return $false + SendCmd "optC=menu.AddNew EditListItem -selectname '$LCDproc' 'LCDproc' on off" || return $false + SendCmd "optC.EnableEvent keyBlue" || return $false + SendCmd "optD=menu.AddNew EditListItem -selectname '$lirc' 'Lirc' on off" || return $false + SendCmd "optD.EnableEvent keyBlue" || return $false + SendCmd "optE=menu.AddNew EditIntItem -min 1 -max 2 'Lirc Port' '$lirc_port'" || return $false + SendCmd "optE.EnableEvent keyBlue" || return $false + # <------------------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.show" || return $false + # <------------------------------------------------------------------------------------------------------------- Menu + + while true; do + SendCmd "menu.SleepEvent" || return $false + # keyOk + if IsEvent menu keyOk ; then + # AUTOSTART + SendCmd "opt1.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$AUTOSTART" != "${reply6xx[1]}" ]; then + DoLog "changing AUTOSTART to ${reply6xx[1]}" + sed -i $config -e "/^AUTOSTART=/s/$AUTOSTART/${reply6xx[1]}/" + AUTOSTART=${reply6xx[1]} + fi + # Xserver and Player + SendCmd "opt2.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$XPLAYER" != "${reply6xx[1]}" ]; then + DoLog "changing XPLAYER to ${reply6xx[1]}" + sed -i $config -e "/^XPLAYER=/s/$XPLAYER/${reply6xx[1]}/" + XPLAYER=${reply6xx[1]} + fi + # Desktop-Manager + SendCmd "opt3.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$DESKTOP" != "${reply6xx[1]}" ] || [ "$DESKTOP" = "$XPLAYER" ]; then + DESKTOP=${reply6xx[1]} + [ "$XPLAYER" = "on" ] && DESKTOP="off" + DoLog "changing Desktop-Manager to $DESKTOP" + # runlevel + if [ $RUNLEVEL -eq 5 -a "$DESKTOP" = "off" ]; then + sed -i /etc/inittab -e "s/$RUNLEVEL_STR/id:3:initdefault:/" + elif [ $RUNLEVEL -ne 5 -a "$DESKTOP" = "on" ]; then + sed -i /etc/inittab -e "s/$RUNLEVEL_STR/id:5:initdefault:/" + fi + XWRAPPER_STR="$(cat /etc/X11/Xwrapper.config | grep -m1 ^allowed_users)" + XWRAPPER=$(echo $XWRAPPER_STR | cut -f2 -d"=") + if [ "$DESKTOP" != "on" -a "$XWRAPPER" != "anybody" ]; then + log "Setting 'allowed_users' to 'anybody' in /etc/X11/Xwrapper.config" + sed -i /etc/X11/Xwrapper.config -e "s/$XWRAPPER_STR/allowed_users=anybody/g" + fi + fi + # vdradmin + SendCmd "opt4.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$vdradmin" != "${reply6xx[1]}" ]; then + DoLog "changing vdradmin to ${reply6xx[1]}" + sed -i $config -e "/^vdradmin=/s/$vdradmin/${reply6xx[1]}/" + vdradmin=${reply6xx[1]} + fi + # dxr3 + SendCmd "optA.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$em8300" != "${reply6xx[1]}" ]; then + DoLog "changing em8300 to ${reply6xx[1]}" + sed -i $config -e "/^em8300=/s/$em8300/${reply6xx[1]}/" + em8300=${reply6xx[1]} + fi + # graphlcd_base + SendCmd "optB.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$graphlcd_base" != "${reply6xx[1]}" ]; then + DoLog "changing graphlcd_base to ${reply6xx[1]}" + sed -i $config -e "/^graphlcd_base=/s/$graphlcd_base/${reply6xx[1]}/" + graphlcd_base=${reply6xx[1]} + fi + # LCDproc + SendCmd "optC.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$LCDproc" != "${reply6xx[1]}" ]; then + DoLog "changing LCDproc to ${reply6xx[1]}" + sed -i $config -e "/^LCDproc=/s/$LCDproc/${reply6xx[1]}/" + LCDproc=${reply6xx[1]} + fi + # lirc + SendCmd "optD.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$lirc" != "${reply6xx[1]}" ]; then + DoLog "changing lirc to ${reply6xx[1]}" + sed -i $config -e "/^lirc=/s/$lirc/${reply6xx[1]}/" + lirc=${reply6xx[1]} + fi + # lirc_port + SendCmd "optE.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$lirc_port" != "${reply6xx[1]}" ]; then + DoLog "changing lirc_port to ${reply6xx[1]}" + sed -i $config -e "/^lirc_port=/s/$lirc_port/${reply6xx[1]}/" + lirc_port=${reply6xx[1]} + fi + # close the submenu + if [ "$vdrsetup_ok_ends" = "on" ]; then + SendCmd "menu.SendState osBack" || return $false +# SendCmd "delete menu" || return $false +# SendCmd "leavelocal" || return $false +# return $true + fi + fi + + # keyBlue (Help) + if IsEvent opt1 keyBlue ; then + SendCmd "Message -seconds 5 'VDR automatisch starten on/off'" || return $false + fi + if IsEvent opt2 keyBlue ; then + SendCmd "Message -seconds 5 'Xserver und Player automatisch starten on/off'" || return $false + fi + if IsEvent opt3 keyBlue ; then + SendCmd "Message -seconds 5 'Desktop-Manager automatisch starten on/off'" || return $false + fi + if IsEvent opt4 keyBlue ; then + SendCmd "Message -seconds 5 'VDRAdmin automatisch starten on/off'" || return $false + fi + + if IsEvent optA keyBlue ; then + SendCmd "Message -seconds 5 'Modul automatisch laden on/off'" || return $false + fi + if IsEvent optB keyBlue ; then + SendCmd "Message -seconds 5 'Modul automatisch laden on/off'" || return $false + fi + if IsEvent optC keyBlue ; then + SendCmd "Message -seconds 5 'Modul automatisch laden on/off'" || return $false + fi + if IsEvent optD keyBlue ; then + SendCmd "Message -seconds 5 'Modul automatisch laden on/off'" || return $false + fi + if IsEvent optE keyBlue ; then + SendCmd "Message -seconds 5 'Lirc-Port 1/2'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + +##### VDR-Setup Menu ##### +function VdrSetup() { + # directorys + videodir=$( grep "^VIDEODIR=" $config | tail -n1 | sed -e "s/^VIDEODIR=//" -e 's/"//g' -e 's/#.*//') + musicdir=$( grep "^MUSICDIR=" $config | tail -n1 | sed -e "s/^MUSICDIR=//" -e 's/"//g' -e 's/#.*//') + dvdisodir=$( grep "^DVDISODIR=" $config | tail -n1 | sed -e "s/^DVDISODIR=//" -e 's/"//g' -e 's/#.*//') + picturedir=$(grep "^PICTUREDIR=" $config | tail -n1 | sed -e "s/^PICTUREDIR=//" -e 's/"//g' -e 's/#.*//') + divxdir=$( grep "^DIVXDIR=" $config | tail -n1 | sed -e "s/^DIVXDIR=//" -e 's/"//g' -e 's/#.*//') + vdrvardir=$( grep "^VDRVARDIR=" $config | tail -n1 | sed -e "s/^VDRVARDIR=//" -e 's/"//g' -e 's/#.*//') + dvdburner=$( grep "^DVDBURNER=" $config | tail -n1 | sed -e "s/^DVDBURNER=//" -e 's/"//g' -e 's/#.*//') + + ls_dev=$(ls -r /dev/*) + + # cd / dvd + all_dvd=$(echo "$ls_dev" | grep "^/dev/[c,d][d,v][r,d]" | sort -r) + if [ -n "$all_dvd" ] && [ $(echo $all_dvd | grep -cw "$dvdburner") -eq 0 ]; then + dvdburner_old="$dvdburner" + dvdburner=$(echo $all_dvd | cut -f 1 -d " ") + sed -i $config -e "/^DVDBURNER=/s?$dvdburner_old?$dvdburner?" + SendCmd "Message -seconds 5 \"Resetting DVDBURNER to $dvdburner\"" || return $false + fi + + # vdr keyb tty + all_tty=$(echo "$ls_dev" | grep "^/dev/tty[0-9]$") + if [ $(echo $all_tty | grep -cw "$KEYB_TTY") -eq 0 ]; then + KEYB_TTY_OLD="$KEYB_TTY" + KEYB_TTY="" + sed -i $config -e "/^KEYB_TTY=/s/$KEYB_TTY_OLD/$KEYB_TTY/" + SendCmd "Message -seconds 5 \"Resetting KEYB_TTY to $KEYB_TTY\"" || return $false + fi + + # vdr language + all_lang=$(locale -a | grep "_") + if [ $(echo $all_lang | grep -cw "$VDRLANG") -eq 0 ]; then + VDRLANG_OLD="$VDRLANG" + VDRLANG=$(echo $VDRLANG | cut -f 1 -d ".") + [ $(echo $all_lang | grep -cw "$VDRLANG") -eq 0 ] && VDRLANG=$(echo $all_lang | cut -f 1 -d " ") + sed -i $config -e "/^VDRLANG=/s/$VDRLANG_OLD/$VDRLANG/" + SendCmd "Message -seconds 5 \"Resetting VDRLANG to $VDRLANG\"" || return $false + fi + + # Menu --------------------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu '$vdr_version'" || return $false + SendCmd "menu.SetColorKeyText -blue 'Help'" || return $false + SendCmd "menu.SetColumns 24" || return $false + SendCmd "menu.EnableEvent keyOk keyBlue close" || return $false + # List --------------------------------------------------------------------------------------------------------------> + SendCmd "menu.AddNew OsdItem -unselectable '--- Einstellungen ---'" || return $false + SendCmd "opt1=menu.AddNew EditListItem -selectname '$noad' 'Schnittmarken erkennen' on off" || return $false + SendCmd "opt2=menu.AddNew EditListItem -selectname '$KEYB_TTY' 'KEYB TTY' \"\" $(echo $all_tty)" || return $false + SendCmd "opt3=menu.AddNew EditListItem -selectname '$VDRLANG' 'Sprache (LANG)' $(echo $all_lang)" || return $false + SendCmd "opt4=menu.AddNew EditIntItem 'Watchdog Timeout (sec)' '$WATCHDOG'" || return $false + SendCmd "opt5=menu.AddNew EditIntItem 'XV Display' '$XV_DISPLAY'" || return $false + SendCmd "menu.AddNew OsdItem -unselectable '--- Laufwerke & Verzeichnisse ---'" || return $false + SendCmd "optA=menu.AddNew EditStrItem 'Video' '$videodir'" || return $false + SendCmd "optB=menu.AddNew EditStrItem 'Musik' '$musicdir'" || return $false + SendCmd "optC=menu.AddNew EditStrItem 'DVD-Isos' '$dvdisodir'" || return $false + SendCmd "optD=menu.AddNew EditStrItem 'Bilder und Fotos' '$picturedir'" || return $false + SendCmd "optE=menu.AddNew EditStrItem 'DivX und Co' '$divxdir'" || return $false + SendCmd "optF=menu.AddNew EditStrItem 'EPG Daten' '$vdrvardir'" || return $false + SendCmd "optG=menu.AddNew EditListItem -selectname '$dvdburner' 'DVD Brenner' \"\" $(echo $all_dvd)" || return $false + # <-------------------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.show" || return $false + # <-------------------------------------------------------------------------------------------------------------- Menu + + while true; do + SendCmd "menu.SleepEvent" || return $false + # keyOk + if IsEvent menu keyOk ; then + # noad + SendCmd "opt1.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + value="${reply6xx[1]}" + if [ "$noad" != "$value" ]; then + DoLog "changing noad to $value" + sed -i $config -e "/^noad=/s/$noad/$value/" + noad="$value" + fi + # KEYB_TTY + SendCmd "opt2.GetValue -name" || return $false + if [ "${reply6xx[0]}" = 600 ]; then + value="${reply6xx[1]}" + elif [ "${reply2xx[0]}" = 200 ]; then + value="" + else + return $false + fi + if [ "$KEYB_TTY" != "$value" ]; then + DoLog "changing KEYB_TTY to \"$value\"" + sed -i $config -e "/^KEYB_TTY=/s/\"//g" -e "s?^KEYB_TTY=$KEYB_TTY?KEYB_TTY=\"$value\"?" + KEYB_TTY="$value" + fi + + # VDRLANG + SendCmd "opt3.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + value="${reply6xx[1]}" + if [ "$VDRLANG" != "$value" ]; then + DoLog "changing VDRLANG to $value" + sed -i $config -e "/^VDRLANG=/s/$VDRLANG/$value/" + VDRLANG="$value" + fi + + # WATCHDOG + SendCmd "opt4.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + value="${reply6xx[1]}" + if [ "$WATCHDOG" != "$value" ]; then + DoLog "changing WATCHDOG to $value" + sed -i $config -e "/^WATCHDOG=/s/$WATCHDOG/$value/" + WATCHDOG="$value" + fi + # XV_DISPLAY + SendCmd "opt5.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + value="${reply6xx[1]}" + if [ "$XV_DISPLAY" != "$value" ]; then + DoLog "changing XV_DISPLAY to $value" + sed -i $config -e "/^XV_DISPLAY=/s/$XV_DISPLAY/$value/" + XV_DISPLAY="$value" + fi + # VIDEODIR + SendCmd "optA.GetValue -quoted" || return $false + [ "${reply5xx[0]}" != 500 ] && return $false + value="${reply5xx[1]}" + if [ "$videodir" != "$value" ]; then + [ ! -d "$value" ] && CreateDir "$value" + if [ -d "$value" ]; then + DoLog "changing VIDEODIR to $value" + sed -i $config -e "/^VIDEODIR=/s?$videodir?$value?" + else + DoLog "error: directory \"$value\" does not exists" + fi + fi + # MUSICDIR + SendCmd "optB.GetValue -quoted" || return $false + [ "${reply5xx[0]}" != 500 ] && return $false + value="${reply5xx[1]}" + if [ "$musicdir" != "$value" ]; then + [ ! -d "$value" ] && CreateDir "$value" + if [ -d "$value" ]; then + DoLog "changing MUSICDIR to $value" + sed -i $config -e "/^MUSICDIR=/s?$musicdir?$value?" + else + DoLog "error: directory \"$value\" does not exists" + fi + fi + # DVDISODIR + SendCmd "optC.GetValue -quoted" || return $false + [ "${reply5xx[0]}" != 500 ] && return $false + value="${reply5xx[1]}" + if [ "$dvdisodir" != "$value" ]; then + [ ! -d "$value" ] && CreateDir "$value" + if [ -d "$value" ]; then + DoLog "changing DVDISODIR to $value" + sed -i $config -e "/^DVDISODIR=/s?$dvdisodir?$value?" + else + DoLog "error: directory \"$value\" does not exists" + fi + fi + # PICTUREDIR + SendCmd "optD.GetValue -quoted" || return $false + [ "${reply5xx[0]}" != 500 ] && return $false + value="${reply5xx[1]}" + if [ "$picturedir" != "$value" ]; then + [ ! -d "$value" ] && CreateDir "$value" + if [ -d "$value" ]; then + DoLog "changing PICTUREDIR to $value" + sed -i $config -e "/^PICTUREDIR=/s?$picturedir?$value?" + else + DoLog "error: directory \"$value\" does not exists" + fi + fi + # DIVXDIR + SendCmd "optE.GetValue -quoted" || return $false + [ "${reply5xx[0]}" != 500 ] && return $false + value="${reply5xx[1]}" + if [ "$divxdir" != "$value" ]; then + [ ! -d "$value" ] && CreateDir "$value" + if [ -d "$value" ]; then + DoLog "changing DIVXDIR to $value" + sed -i $config -e "/^DIVXDIR=/s?$divxdir?$value?" + else + DoLog "error: directory \"$value\" does not exists" + fi + fi + # VDRVARDIR + SendCmd "optF.GetValue -quoted" || return $false + [ "${reply5xx[0]}" != 500 ] && return $false + value="${reply5xx[1]}" + if [ "$vdrvardir" != "$value" ]; then + [ ! -d "$value" ] && CreateDir "$value" + if [ -d "$value" ]; then + DoLog "changing VDRVARDIR to $value" + sed -i $config -e "/^VDRVARDIR=/s?$vdrvardir?$value?" + else + DoLog "error: directory \"$value\" does not exists" + fi + fi + # DVDBURNER + SendCmd "optG.GetValue -name" || return $false + if [ "${reply6xx[0]}" = 600 ]; then + value="${reply6xx[1]}" + elif [ "${reply2xx[0]}" = 200 ]; then + value="" + else + return $false + fi + if [ "$dvdburner" != "$value" ]; then + DoLog "changing DVDBURNER to \"$value\"" + [ ! -e "$value" ] && DoLog "warning: \"$value\" is no valid" +# sed -i $config -e "/^DVDBURNER=/s?$dvdburner?$value?" + sed -i $config -e "/^DVDBURNER=/s/\"//g" -e "s?^DVDBURNER=$dvdburner?DVDBURNER=\"$value\"?" + fi + # close the submenu + if [ "$vdrsetup_ok_ends" = "on" ]; then + SendCmd "menu.SendState osBack" || return $false +# SendCmd "delete menu" || return $false +# SendCmd "leavelocal" || return $false +# return $true + fi + fi + # keyBlue (Help) + if IsEvent menu keyBlue ; then + SendCmd "Message -seconds 5 'Speichern mit Ok oder Menue verlassen mit Exit'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + +##### Plugin Menus ##### +function PluginSetup() { + plugin=$1 + plugin_have_args=$(grep "^${plugin}_args=" $config | tail -n1) + plugin_version=$(grep "^${plugin}_desc=" /tmp/vdr-desc.cache | tail -n1 | sed -e "s/^${plugin}_desc=//" -e 's/[^)]*$//' -e 's/"//g' -e 's/#.*//') + [ -n "$plugin_version" ] || plugin_version="$plugin" + # Menu --------------------------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu '$plugin_version'" || return $false + SendCmd "menu.SetColorKeyText -green 'About' -blue 'Help'" || return $false + SendCmd "menu.SetColumns 14" || return $false + SendCmd "menu.EnableEvent keyOk keyGreen keyBlue close" || return $false + # List --------------------------------------------------------------------------------------------------------------------> + SendCmd "opt1=menu.AddNew EditListItem -selectname '${!plugin}' 'Status' on off" || return $false + if [ "$plugin" = "remote" ]; then + SendCmd "optA=menu.AddNew EditStrItem 'Remote Event' '$remote_event'" || return $false + fi + if [ -n "$plugin_have_args" ]; then + plugin_args=$(echo "$plugin_have_args" | sed -e "s/^${plugin}_args=//" -e 's/"//g' -e 's/#.*//') + SendCmd "opt2=menu.AddNew EditStrItem 'Argumente' '$plugin_args'" || return $false + else + SendCmd "menu.AddNew OsdItem -unselectable 'Argumente:\tPlugin kennt keine Argumente'" || return $false + fi + # <-------------------------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.show" || return $false + # <-------------------------------------------------------------------------------------------------------------------- Menu + + while true; do + SendCmd "menu.SleepEvent" || return $false + # keyOk + if IsEvent menu keyOk ; then + # plugin status + SendCmd "opt1.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + value="${reply6xx[1]}" + if [ "${!plugin}" != "$value" ]; then + DoLog "changing $plugin to $value" + sed -i $config -e "/^$plugin=/s/${!plugin}/$value/" + eval $plugin="$value" + fi + # plugin arguments + if [ -n "$plugin_have_args" ]; then + SendCmd "opt2.GetValue -quoted" || return $false + if [ "${reply5xx[0]}" = 500 ] || [ "${reply2xx[0]}" = 200 ]; then + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + if [ "$plugin_args" != "$value" ]; then + DoLog "changing arguments for $plugin to $value" + sed -i $config -e "/^${plugin}_args=/s/\"//g" -e "s?^${plugin}_args=$plugin_args?${plugin}_args=\"$value\"?" + fi + fi + fi + # remote_event for remote plugin + if [ "$plugin" = "remote" ]; then + SendCmd "optA.GetValue -quoted" || return $false + [ "${reply5xx[0]}" = 500 ] || return $false + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + if [ "$remote_event" != "$value" ]; then + DoLog "changing arguments for remote_event to $value" + sed -i $config -e "/^remote_event=/s?$remote_event?$value?" + fi + fi + # close the submenu + if [ "$vdrsetup_ok_ends" = "on" ]; then + SendCmd "menu.SendState osBack" || return $false +# SendCmd "delete menu" || return $false +# SendCmd "leavelocal" || return $false +# return $true + fi + fi + # keyGreen (About) + if IsEvent menu keyGreen ; then + desc=$(grep "^${plugin}_desc=" /tmp/vdr-desc.cache | tail -n1 | sed -e "s/^${plugin}_desc=\"${plugin} ([^)]*) - //" -e 's/"//g' -e 's/#.*//') + SendCmd "Message -seconds 5 \"$desc\"" || return $false + fi + # keyBlue (Help) + if IsEvent menu keyBlue ; then + SendCmd "Message -seconds 5 'Auswahl mit Links und Rechts, speichern mit Ok'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + +function PluginStatusList() { + # Menu ----------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu 'Plugin Status Liste'" || return $false + SendCmd "menu.SetColorKeyText -green 'About' -blue 'Help'" || return $false # -red 'Edit' + SendCmd "menu.SetColumns 24" || return $false + SendCmd "menu.EnableEvent keyOk keyGreen keyBlue close" || return $false # keyRed + # List ----------------------------------------------------------------------------------------------------> + SendCmd "Message -status 'Menu wird aufgebaut ...'" || return $false + files=$(ls "$VDRLIBDIR" | grep "^libvdr-" | grep "${plugin_api}$" | sed -e "s/^libvdr-//g" -e "s/.so.${plugin_api}$//g") + if [ -n "$files" ]; then + for p in $files ; do + plugin=$(echo $p | sed -e "s/-/_/g") # this is for streamdev-server ... + if [ -z "${!plugin}" ]; then + DoLog "creating $plugin=\"off\"" + echo "" >> $config + echo "# $plugin" >> $config + echo "${plugin}=\"off\"" >> $config + eval ${plugin}="off" + # plugin args + nl=0; (( nl=$(grep -n "^$p " /tmp/vdr-help.tmp | cut -f 1 -d ":") +1 )) + [ $nl -gt 1 ] && [ $(sed -n "${nl}p" /tmp/vdr-help.tmp | grep -c "^-") -gt 0 ] && echo "${plugin}_args=\"\"" >> $config + fi + SendCmd "$plugin=menu.AddNew EditListItem -selectname \"${!plugin}\" \"$p\" on off" || return $false + done + fi + SendCmd "Message -statusclear" || return $false + # <---------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "menu.Show" || return $false + # <---------------------------------------------------------------------------------------------------- Menu + + while true ; do + SendCmd "menu.SleepEvent" || return $false + # keyOk (save settings and clsoe the submenu) + if IsEvent menu keyOk ; then + if [ -n "$files" ]; then + SendCmd "Message 'Einstellungen werden gespeichert'" || return $false + for p in $files ; do + plugin=$(echo $p | sed -e "s/-/_/g") # this is for streamdev-server ... + SendCmd "${plugin}.GetValue -name" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "${!plugin}" != "${reply6xx[1]}" ]; then + DoLog "changing $plugin to ${reply6xx[1]}" + sed -i $config -e "/^${plugin}=/s/${!plugin}/${reply6xx[1]}/" + eval ${plugin}="${reply6xx[1]}" + fi + done + fi + # close the submenu + if [ "$vdrsetup_ok_ends" = "on" ]; then + SendCmd "menu.SendState osBack" || return $false +# SendCmd "delete menu" || return $false +# SendCmd "leavelocal" || return $false +# return $true + fi + fi + # keyRed (Edit) !!! Bug Inside !!! + if IsEvent menu keyRed ; then + SendCmd "menu.GetCurrent" + [ "${reply3xx[0]}" != 302 ] && return $false + PluginSetup "${reply3xx[2]}" || return $false + SendCmd "menu.Show" || return $false + fi + # keyGreen (About) + if IsEvent menu keyGreen ; then + SendCmd "menu.GetCurrent" + [ "${reply3xx[0]}" != 302 ] && return $false + desc=$(grep "^${reply3xx[2]}_desc=" /tmp/vdr-desc.cache | tail -n1 | sed -e "s/^${reply3xx[2]}_desc=\"${reply3xx[2]} ([^)]*) - //" -e 's/"//g' -e 's/#.*//') + SendCmd "Message -seconds 5 \"$desc\"" || return $false + fi + # keyBlue (Help) + if IsEvent menu keyBlue ; then + SendCmd "Message -seconds 5 'Auswahl mit Links und Rechts, speichern mit Ok'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + +function ListPlugins() { + # Menu ------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu 'Installierte Plugins'" || return $false + SendCmd "menu.SetColorKeyText -red 'Edit' -green 'Status' -blue 'Help'" || return $false + SendCmd "menu.SetColumns 4" || return $false + SendCmd "menu.EnableEvent keyOk keyRed keyGreen keyBlue close" || return $false + SendCmd "menu.EnableEvent key1 key2 key3 key4 key5 key6 key7 key8 key9 key0" || return $false + # List-------------------------------------------------------------------------------------------> + SendCmd "Message -status 'Menu wird aufgebaut ...'" || return $false + files=$(ls "$VDRLIBDIR" | grep "^libvdr-" | grep "${plugin_api}$" | sed -e "s/^libvdr-//g" -e "s/.so.${plugin_api}$//g") + if [ -n "$files" ]; then + n=0 + for p in $files ; do + ((n=n+1)) + plugin=$(echo $p | sed -e "s/-/_/g") # this is for streamdev-server ... + if [ -z "${!plugin}" ]; then + DoLog "creating $plugin=\"off\"" + echo "" >> $config + echo "# $plugin" >> $config + echo "${plugin}=\"off\"" >> $config + eval ${plugin}="off" + # plugin args + nl=0; (( nl=$(grep -n "^$p " /tmp/vdr-help.tmp | cut -f 1 -d ":") +1 )) + [ $nl -gt 1 ] && [ $(sed -n "${nl}p" /tmp/vdr-help.tmp | grep -c "^-") -gt 0 ] && echo "${plugin}_args=\"\"" >> $config + fi + plugin_desc="${plugin}_desc" + desc="${!plugin_desc}" + [ -n "$(echo $n | grep "^[0-9][0-9][0-9]$")" ] && N="$n" + [ -n "$(echo $n | grep "^[0-9][0-9]$")" ] && N=" $n" + [ -n "$(echo $n | grep "^[0-9]$")" ] && N=" $n" + SendCmd "$plugin=menu.AddNew OsdItem \"$N \t$desc\"" || return $false + done + fi + SendCmd "Message -statusclear" || return $false + # <------------------------------------------------------------------------------------------ List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "menu.Show" || return $false + # <------------------------------------------------------------------------------------------ Menu + + while true ; do + SendCmd "menu.SleepEvent" || return $false + # keyOk and keyRed + if IsEvent menu keyOk || IsEvent menu keyRed; then + SendCmd "menu.GetCurrent" + [ "${reply3xx[0]}" != 302 ] && return $false + PluginSetup "${reply3xx[2]}" || return $false + SendCmd "menu.Show" || return $false + fi + # keyGreen (Status) + if IsEvent menu keyGreen ; then + SendCmd "menu.GetCurrent" + [ "${reply3xx[0]}" != 302 ] && return $false + plugin="${reply3xx[2]}" + SendCmd "Message -seconds 5 'Status: ${!plugin}'" || return $false + fi + # keyBlue (Help) + if IsEvent menu keyBlue ; then + SendCmd "Message -seconds 5 'Auswahl mit OK oder Menue verlassen mit Exit'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + # keyNr + if [ $n -gt 0 ]; then + mykey=; + k1=; + for k1 in 0 1 2 3 4 5 6 7 8 9 ; do + if IsEvent menu key$k1 ; then + mykey=$k1 + [ $n -gt 9 ] || break + SendCmd "menu.SleepEvent -timeoutms $vdrsetup_key_timeout" || return $false + if IsEvent menu keyOk ; then break; fi + k2=; + for k2 in 0 1 2 3 4 5 6 7 8 9 ; do + if IsEvent menu key$k2 ; then + mykey=${k1}${k2} + [ $n -gt 99 ] || break + SendCmd "menu.SleepEvent -timeoutms $vdrsetup_key_timeout" || return $false + if IsEvent menu keyOk ; then break; fi + k3=; + for k3 in 0 1 2 3 4 5 6 7 8 9 ; do + if IsEvent menu key$k3 ; then + mykey=${k1}${k2}${k3} + break + fi + done + break + fi + done + break + fi + done + + if [ -n "$mykey" ]; then + [ $mykey -gt $n ] && mykey=$n + ((mykey=mykey-1)) # we do this, because 0 is the first item + [ $mykey -lt 0 ] && mykey=0 + SendCmd "menu.SetCurrent $mykey" || return $false +# SendCmd "menu.GetCurrent" +# [ "${reply3xx[0]}" != 302 ] && return $false +# PluginSetup "${reply3xx[2]}" || return $false + SendCmd "menu.Show" || return $false + fi + fi + done +} + +##### Wakeup Menu ##### +function Wakeup() { + shutdown="$VDRCONFDIR/shutdown.conf" + . $shutdown + + # settings +# WAKEUP_MODE=$(grep "^WAKEUP_MODE=" $shutdown | tail -n1 | sed -e "s/^WAKEUP_MODE=//" -e 's/"//g' -e 's/#.*//') + (( WAKEUP_MODE_T = $WAKEUP_MODE + 1 )) +# NVRAM_CONFIG=$(grep "^NVRAM_CONFIG=" $shutdown | tail -n1 | sed -e "s/^NVRAM_CONFIG=//" -e 's/"//g' -e 's/#.*//') +# NVRAM_IWNAME=$(grep "^NVRAM_IWNAME=" $shutdown | tail -n1 | sed -e "s/^NVRAM_IWNAME=//" -e 's/"//g' -e 's/#.*//') +# NVRAM_OPT=$(grep "^NVRAM_OPT=" $shutdown | tail -n1 | sed -e "s/^NVRAM_OPT=//" -e 's/"//g' -e 's/#.*//') +# NEED_REBOOT=$(grep "^NEED_REBOOT=" $shutdown | tail -n1 | sed -e "s/^NEED_REBOOT=//" -e 's/"//g' -e 's/#.*//') + (( NEED_REBOOT_T = $NEED_REBOOT + 1 )) +# LILO=$(grep "^LILO=" $shutdown | tail -n1 | sed -e "s/^LILO=//" -e 's/"//g' -e 's/#.*//') + (( LILO_T = $LILO + 1 )) + +# WAKEUP_BEFORE=$(grep "^WAKEUP_BEFORE=" $shutdown | tail -n1 | sed -e "s/^WAKEUP_BEFORE=//" -e 's/"//g' -e 's/#.*//') +# MAX_POWEROFF_TIME=$(grep "^MAX_POWEROFF_TIME=" $shutdown | tail -n1 | sed -e "s/^MAX_POWEROFF_TIME=//" -e 's/"//g' -e 's/#.*//') +# INTERVAL=$(grep "^INTERVAL=" $shutdown | tail -n1 | sed -e "s/^INTERVAL=//" -e 's/"//g' -e 's/#.*//') +# DREAMTIME=$(grep "^DREAMTIME=" $shutdown | tail -n1 | sed -e "s/^DREAMTIME=//" -e 's/"//g' -e 's/#.*//') +# MIN_WAKEUP_VAR=$(grep "^MIN_WAKEUP_VAR=" $shutdown | tail -n1 | sed -e "s/^MIN_WAKEUP_VAR=//" -e 's/"//g' -e 's/#.*//') +# WAITING_PERIOD=$(grep "^WAITING_PERIOD=" $shutdown | tail -n1 | sed -e "s/^WAITING_PERIOD=//" -e 's/"//g' -e 's/#.*//') + + # Menu ---------------------------------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu 'Wakeup'" || return $false + SendCmd "menu.SetColorKeyText -blue Help" || return $false + SendCmd "menu.SetColumns 24" || return $false + SendCmd "menu.EnableEvent keyOk close" || return $false + # List ---------------------------------------------------------------------------------------------------------------------------> + SendCmd "menu.AddNew OsdItem -unselectable '--- System ---'" || return $false + SendCmd "opt1=menu.AddNew EditListItem -select '$WAKEUP_MODE_T' 'Aufwach Methode' keine acpi nvram extension-board" || return $false + SendCmd "opt1.EnableEvent keyBlue" || return $false + SendCmd "opt2=menu.AddNew EditListItem -select '$NEED_REBOOT_T' 'Neustart erforderlich' nein ja immer" || return $false + SendCmd "opt2.EnableEvent keyBlue" || return $false + SendCmd "opt3=menu.AddNew EditListItem -select '$LILO_T' 'Bootmanger' grub lilo" || return $false + SendCmd "opt3.EnableEvent keyBlue" || return $false + SendCmd "menu.AddNew OsdItem -unselectable '--- Nvram ---'" || return $false + SendCmd "opt4=menu.AddNew EditStrItem 'Konfiguration' '$NVRAM_CONFIG'" || return $false + SendCmd "opt4.EnableEvent keyBlue" || return $false + SendCmd "opt5=menu.AddNew EditStrItem 'IW Name' '$NVRAM_IWNAME'" || return $false + SendCmd "opt5.EnableEvent keyBlue" || return $false + SendCmd "opt6=menu.AddNew EditStrItem 'Optionen' '$NVRAM_OPT'" || return $false + SendCmd "opt6.EnableEvent keyBlue" || return $false + SendCmd "menu.AddNew OsdItem -unselectable '--- Nur fuer Experten ---'" || return $false + SendCmd "optA=menu.AddNew EditIntItem 'Vorlauf in Minuten' '$WAKEUP_BEFORE'" || return $false + SendCmd "optA.EnableEvent keyBlue" || return $false + SendCmd "optB=menu.AddNew EditStrItem 'Maximale Auszeit' '$MAX_POWEROFF_TIME'" || return $false + SendCmd "optB.EnableEvent keyBlue" || return $false + SendCmd "optC=menu.AddNew EditIntItem -max 31 'Interval in Tagen' '$INTERVAL'" || return $false + SendCmd "optC.EnableEvent keyBlue" || return $false + SendCmd "optD=menu.AddNew EditStrItem 'Wunsch Aufwachzeit' '$DREAMTIME'" || return $false + SendCmd "optD.EnableEvent keyBlue" || return $false + SendCmd "optE=menu.AddNew EditIntItem -max 3 'Aktion' '$MIN_WAKEUP_VAR'" || return $false + SendCmd "optE.EnableEvent keyBlue" || return $false + SendCmd "optF=menu.AddNew EditIntItem 'Warte Zeit' '$WAITING_PERIOD'" || return $false + SendCmd "optF.EnableEvent keyBlue" || return $false + # <---------------------------------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.show" || return $false + # <---------------------------------------------------------------------------------------------------------------------------- Menu + + while true; do + SendCmd "menu.SleepEvent" || return $false + # keyOk + if IsEvent menu keyOk ; then + # WAKEUP_MODE + SendCmd "opt1.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$WAKEUP_MODE_T" != "${reply6xx[1]}" ]; then + (( WAKEUP_MODE_N = ${reply6xx[1]} - 1 )) + (( WAKEUP_MODE = $WAKEUP_MODE_T - 1 )) + DoLog "changing WAKEUP_MODE to $WAKEUP_MODE_N" + sed -i $shutdown -e "/^WAKEUP_MODE=/s/$WAKEUP_MODE/$WAKEUP_MODE_N/" + fi + # NEED_REBOOT + SendCmd "opt2.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$NEED_REBOOT_T" != "${reply6xx[1]}" ]; then + (( NEED_REBOOT_N = ${reply6xx[1]} - 1 )) + (( NEED_REBOOT = $NEED_REBOOT_T - 1 )) + DoLog "changing NEED_REBOOT to $NEED_REBOOT_N" + sed -i $shutdown -e "/^NEED_REBOOT=/s/$NEED_REBOOT/$NEED_REBOOT_N/" + fi + # LILO + SendCmd "opt3.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$LILO_T" != "${reply6xx[1]}" ]; then + (( LILO_N = ${reply6xx[1]} - 1 )) + (( LILO = $LILO_T - 1 )) + DoLog "changing LILO to $LILO_N" + sed -i $shutdown -e "/^LILO=/s/$LILO/$LILO_N/" + fi + # NVRAM_CONFIG + SendCmd "opt4.GetValue -quoted" || return $false + if [ "${reply5xx[0]}" = 500 ] || [ "${reply2xx[0]}" = 200 ]; then + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + if [ "$NVRAM_CONFIG" != "$value" ]; then + if [ -f "$value" ]; then + DoLog "changing NVRAM_CONFIG to $value" + sed -i $shutdown -e "/^NVRAM_CONFIG=/s/\"//g" -e "s?^NVRAM_CONFIG=$NVRAM_CONFIG?NVRAM_CONFIG=\"$value\"?" + else + DoLog "error: file \"$value\" for NVRAM_CONFIG does not exist" + fi + fi + fi + # NVRAM_IWNAME + SendCmd "opt5.GetValue -quoted" || return $false + if [ "${reply5xx[0]}" = 500 ] || [ "${reply2xx[0]}" = 200 ]; then + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + if [ "$NVRAM_IWNAME" != "$value" ]; then + DoLog "changing NVRAM_IWNAME to $value" + sed -i $shutdown -e "/^NVRAM_IWNAME=/s/\"//g" -e "s?^NVRAM_IWNAME=$NVRAM_IWNAME?NVRAM_IWNAME=\"$value\"?" + fi + fi + # NVRAM_OPT + SendCmd "opt6.GetValue -quoted" || return $false + if [ "${reply5xx[0]}" = 500 ] || [ "${reply2xx[0]}" = 200 ]; then + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + if [ "$NVRAM_OPT" != "$value" ]; then + DoLog "changing NVRAM_OPT to $value" + sed -i $shutdown -e "/^NVRAM_OPT=/s/\"//g" -e "s?^NVRAM_OPT=$NVRAM_OPT?NVRAM_OPT=\"$value\"?" + fi + fi + # WAKEUP_BEFORE + SendCmd "optA.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$WAKEUP_BEFORE" != "${reply6xx[1]}" ]; then + DoLog "changing WAKEUP_BEFORE to ${reply6xx[1]}" + sed -i $shutdown -e "/^WAKEUP_BEFORE=/s/$WAKEUP_BEFORE/${reply6xx[1]}/" + fi + # MAX_POWEROFF_TIME + SendCmd "optB.GetValue -quoted" || return $false + if [ "${reply5xx[0]}" = 500 ] || [ "${reply2xx[0]}" = 200 ]; then + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + if [ "$MAX_POWEROFF_TIME" != "$value" ]; then + DoLog "changing MAX_POWEROFF_TIME to $value" + sed -i $shutdown -e "/^MAX_POWEROFF_TIME=/s/\"//g" -e "s?^MAX_POWEROFF_TIME=$MAX_POWEROFF_TIME?MAX_POWEROFF_TIME=\"$value\"?" + fi + fi + # INTERVAL + SendCmd "optC.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$INTERVAL" != "${reply6xx[1]}" ]; then + DoLog "changing INTERVAL to ${reply6xx[1]}" + sed -i $shutdown -e "/^INTERVAL=/s/$INTERVAL/${reply6xx[1]}/" + fi + # DREAMTIME + SendCmd "optD.GetValue -quoted" || return $false + if [ "${reply5xx[0]}" = 500 ] || [ "${reply2xx[0]}" = 200 ]; then + value=$(echo " ${reply5xx[1]}" | sed -e 's/^ //g' -e 's/\\r//g') + if [ "$DREAMTIME" != "$value" ]; then + [ -n "$(echo $value | grep '^[0-9]:[0-9][0-9]$')" ] && value="0${value}" + if [ -n "$(echo $value | grep '^[0-9][0-9]:[0-9][0-9]$')" ]; then + DoLog "changing DREAMTIME to $value" + sed -i $shutdown -e "/^DREAMTIME=/s/\"//g" -e "s?^DREAMTIME=$DREAMTIME?DREAMTIME=\"$value\"?" + else + DoLog "error: value \"$value\" for DREAMTIME has bad format" + fi + fi + fi + # MIN_WAKEUP_VAR + SendCmd "optE.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$MIN_WAKEUP_VAR" != "${reply6xx[1]}" ]; then + DoLog "changing MIN_WAKEUP_VAR to ${reply6xx[1]}" + sed -i $shutdown -e "/^MIN_WAKEUP_VAR=/s/$MIN_WAKEUP_VAR/${reply6xx[1]}/" + fi + # WAITING_PERIOD + SendCmd "optF.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "$WAITING_PERIOD" != "${reply6xx[1]}" ]; then + DoLog "changing WAITING_PERIOD to ${reply6xx[1]}" + sed -i $shutdown -e "/^WAITING_PERIOD=/s/$WAITING_PERIOD/${reply6xx[1]}/" + fi + # close the submenu + if [ "$vdrsetup_ok_ends" = "on" ]; then + SendCmd "menu.SendState osBack" || return $false +# SendCmd "delete menu" || return $false +# SendCmd "leavelocal" || return $false +# return $true + fi + fi + # keyBlue (Help) + if IsEvent opt1 keyBlue ; then + SendCmd "Message -seconds 5 'Optionen: keine, acpi, nvram, extension-board'" || return $false + fi + if IsEvent opt2 keyBlue ; then + SendCmd "Message -seconds 5 'Optionen: nein, ja, immer'" || return $false + fi + if IsEvent opt3 keyBlue ; then + SendCmd "Message -seconds 5 'Optionen: grub, lilo'" || return $false + fi + if IsEvent opt4 keyBlue ; then + SendCmd "Message -seconds 5 'Pfad zur nvram-wakeup Konfiguration'" || return $false + fi + if IsEvent opt5 keyBlue ; then + SendCmd "Message -seconds 5 'Specify the iw (infowriter) name (e.g: gigabyte_5aa)'" || return $false + fi + if IsEvent opt6 keyBlue ; then + SendCmd "Message -seconds 5 'Versuche \"nvram-wakeup --help\" auf einem Terminal'" || return $false + fi + if IsEvent optA keyBlue ; then + SendCmd "Message -seconds 5 'Optionen: 0, MAXIMAL, INTERVAL oder Zeit in Minuten'" || return $false + fi + if IsEvent optB keyBlue ; then + SendCmd "Message -seconds 5 'Gebe den Interval in Tagen an'" || return $false + fi + if IsEvent optC keyBlue ; then + SendCmd "Message -seconds 5 'Aufwachzeit in Stunden:Minuten zB 03:00'" || return $false + fi + if IsEvent optD keyBlue ; then + SendCmd "Message -seconds 5 'Aktion wenn \$MIN_WAKEUPTIME -gt \$WAKEUPTIME'" || return $false + fi + if IsEvent optE keyBlue ; then + SendCmd "Message -seconds 5 'Wartezeit bis zum erneuten Shutdown in Minuten'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + +##### DVB-Modul Menu ##### +function DVBModul() { + # dvb_ttpci parameter description + debug_desc="debug level (bitmask, default 0)" + vidmode_desc="analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC" + pids_off_desc="clear video/audio/PCR PID filters when demux is closed" + adac_desc="audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)" + hw_sections_desc="0 use software section filter, 1 use hardware" + rgb_on_desc="For Siemens DVB-C cards only: Enable RGB control signal on SCART pin 16 to switch SCART video mode from CVBS to RGB" + volume_desc="initial volume: default 255 (range 0-255)" + budgetpatch_desc="use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)" + wss_cfg_4_3_desc="WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data" + wss_cfg_16_9_desc="WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data" + tv_standard_desc="TV standard: 0 PAL (default), 1 NTSC" + + +# { 0x7, "16:9" }, +# { 0x8, "4:3" }, +# { 0x1, "L14:9" }, +# { 0xb, "L16:9" }, +# { 0xd, "L>16:9" } + + + TT_PARAMETERS="options dvb_ttpci" + if [ -d /sys/module/dvb_ttpci/parameters ]; then + for p in $(ls /sys/module/dvb_ttpci/parameters); do + eval ${p}=`cat /sys/module/dvb_ttpci/parameters/${p}` + done + fi + + # defaults and some tests + vidmode=$(echo $vidmode | grep '^[0,1,2,3]$') + [ -n "$vidmode" ] || vidmode=1 + [ "$vidmode" = "0" ] && vidmode=4 + tv_standard=$(echo $tv_standard | grep '^[0,1]$') + [ -n "$tv_standard" ] || tv_standard=0 + (( tv_standard = $tv_standard + 1 )) + wss_cfg_16_9=$(echo $wss_cfg_16_9 | grep '^[[:digit:]]*$') + [ -n "$wss_cfg_16_9" ] || wss_cfg_16_9=7 + wss_cfg_4_3=$(echo $wss_cfg_4_3 | grep '^[[:digit:]]*$') + [ -n "$wss_cfg_4_3" ] || wss_cfg_4_3=16392 + debug=$(echo $debug | grep '^[[:digit:]]*$') + [ -n "$debug" ] || debug=0 + ir_inversion=$(echo $ir_inversion | cut -f1 -d ',' | grep '^[0,1]$') + [ -n "$ir_inversion" ] || ir_inversion=0 + (( ir_inversion = $ir_inversion + 1 )) + volume=$(echo $volume | grep '^[[:digit:]]*$') + [ -n "$volume" ] || volume=255 + + + SendCmd "enterlocal" || return $false # Preserve global variable space, so we can re-use 'menu' + SendCmd "menu=New Menu 'DVB Module'" || return $false + SendCmd "menu.SetColorKeyText -blue Help" || return $false + SendCmd "menu.SetColumns 24" || return $false + SendCmd "menu.EnableEvent keyOk close" || return $false + # List -> + SendCmd "menu.AddNew OsdItem -unselectable '--- Video ---'" || return $false + SendCmd "opt1=menu.AddNew EditListItem -select '$vidmode' 'Video Ausgang' RGB/Composite S-Video/Composite S-Video off" || return $false + SendCmd "opt1.EnableEvent keyBlue" || return $false + SendCmd "opt2=menu.AddNew EditListItem -select '$tv_standard' 'TV Standard' PAL NTSC" || return $false + SendCmd "opt2.EnableEvent keyBlue" || return $false + SendCmd "opt3=menu.AddNew EditIntItem 'WSS 16:9' '$wss_cfg_16_9'" || return $false +# SendCmd "opt3=menu.AddNew EditListItem -select '$wss_cfg_16_9' 'WSS 16:9' 16:9 1 2 " || return $false + SendCmd "opt3.EnableEvent keyBlue" || return $false + SendCmd "opt4=menu.AddNew EditIntItem 'WSS 4:3' '$wss_cfg_4_3'" || return $false + SendCmd "opt4.EnableEvent keyBlue" || return $false + SendCmd "menu.AddNew OsdItem -unselectable ''" || return $false + SendCmd "menu.AddNew OsdItem -unselectable '--- Sonstiges ---'" || return $false + SendCmd "opt5=menu.AddNew EditIntItem 'Debug Level' '$debug'" || return $false + SendCmd "opt5.EnableEvent keyBlue" || return $false + SendCmd "opt6=menu.AddNew EditListItem -select '$ir_inversion' 'IR invertieren' off on" || return $false + SendCmd "opt6.EnableEvent keyBlue" || return $false + SendCmd "opt7=menu.AddNew EditIntItem -max 255 'Lautstaerke' '$volume'" || return $false + SendCmd "opt7.EnableEvent keyBlue" || return $false + # <- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.show" || return $false + + while true; do + SendCmd "menu.SleepEvent" || return $false + # keyOk + if IsEvent menu keyOk ; then + # vidmode + SendCmd "opt1.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "1" != "${reply6xx[1]}" ]; then + vidmode="${reply6xx[1]}" + [ "$vidmode" = "4" ] && vidmode=0 + DoLog "adding vidmode=${reply6xx[1]} to TT_PARAMETERS" + TT_PARAMETERS="$TT_PARAMETERS vidmode=${reply6xx[1]}" + fi + # tv_standard + SendCmd "opt2.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "1" != "${reply6xx[1]}" ]; then + (( tv_standard = ${reply6xx[1]} - 1 )) + DoLog "adding tv_standard=$tv_standard to TT_PARAMETERS" + TT_PARAMETERS="$TT_PARAMETERS tv_standard=$tv_standard" + fi + # wss_cfg_16_9 + SendCmd "opt3.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "7" != "${reply6xx[1]}" ]; then + DoLog "adding wss_cfg_16_9=${reply6xx[1]} to TT_PARAMETERS" + TT_PARAMETERS="$TT_PARAMETERS wss_cfg_16_9=${reply6xx[1]}" + fi + # wss_cfg_4_3 + SendCmd "opt4.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "16392" != "${reply6xx[1]}" ]; then + DoLog "adding wss_cfg_4_3=${reply6xx[1]} to TT_PARAMETERS" + TT_PARAMETERS="$TT_PARAMETERS wss_cfg_4_3=${reply6xx[1]}" + fi + # debug + SendCmd "opt5.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "0" != "${reply6xx[1]}" ]; then + DoLog "adding debug=${reply6xx[1]} to TT_PARAMETERS" + TT_PARAMETERS="$TT_PARAMETERS debug=${reply6xx[1]}" + fi + # ir_inversion + SendCmd "opt6.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "1" != "${reply6xx[1]}" ]; then + (( ir_inversion = ${reply6xx[1]} - 1 )) + DoLog "adding tv_standard=$ir_inversion to TT_PARAMETERS" + TT_PARAMETERS="$TT_PARAMETERS tv_standard=$ir_inversion" + fi + # volume + SendCmd "opt7.GetValue" || return $false + [ "${reply6xx[0]}" != 600 ] && return $false + if [ "255" != "${reply6xx[1]}" ]; then + DoLog "adding volume=${reply6xx[1]} to TT_PARAMETERS" + TT_PARAMETERS="$TT_PARAMETERS volume=${reply6xx[1]}" + fi + + # write config to /etc/modprobe.d/dvb + echo $TT_PARAMETERS > /etc/modprobe.d/dvb + + # close the submenu + if [ "$vdrsetup_ok_ends" = "on" ]; then + SendCmd "menu.SendState osBack" || return $false +# SendCmd "delete menu" || return $false +# SendCmd "leavelocal" || return $false +# return $true + fi + fi + # keyBlue (Help) + if IsEvent opt1 keyBlue ; then + SendCmd "Message -seconds 5 'Video Modus des J2 - default RGB'" || return $false + fi + if IsEvent opt2 keyBlue ; then + SendCmd "Message -seconds 5 'TV Standard - default Pal'" || return $false + fi + if IsEvent opt3 keyBlue ; then + SendCmd "Message -seconds 5 'WSS 16/9 - default 7'" || return $false + fi + if IsEvent opt4 keyBlue ; then + SendCmd "Message -seconds 5 'WSS 4/3 - default 16392'" || return $false + fi + if IsEvent opt5 keyBlue ; then + SendCmd "Message -seconds 5 'Debug Level - default 0'" || return $false + fi + if IsEvent opt6 keyBlue ; then + SendCmd "Message -seconds 5 'IR-Signal invertieren - default off'" || return $false + fi + if IsEvent opt7 keyBlue ; then + SendCmd "Message -seconds 5 'Start Lautstaerke von 0-255 - default 255'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + + +##### x-vdr ############# +function InstallPlugins { + [ "$have_xvdr" = "on" ] || return $false + xdir=/usr/local/src/x-vdr + cmd=$1 + # Menu --------------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + if [ "$cmd" = "installed" ]; then + SendCmd "menu=New Menu 'Installierte Plugins'" || return $false + SendCmd "menu.SetColorKeyText -red 'Edit' -green 'Reinstall' -yellow 'Remove' -blue 'Help'" || return $false + SendCmd "menu.SetColumns 4" || return $false + elif [ "$cmd" = "standby" ]; then + SendCmd "menu=New Menu 'Installierbare Plugins'" || return $false + SendCmd "menu.SetColorKeyText -red 'Edit' -green 'Install' -blue 'Help'" || return $false + SendCmd "menu.SetColumns 4 16" || return $false + else + SendCmd "menu=New Menu 'Alle Plugins'" || return $false + SendCmd "menu.SetColorKeyText -red 'Edit' -green 'Install' -yellow 'Remove' -blue 'Help'" || return $false + SendCmd "menu.SetColumns 4 16" || return $false + fi + + SendCmd "menu.EnableEvent keyOk keyRed keyGreen keyYellow keyBlue close" || return $false + SendCmd "menu.EnableEvent key1 key2 key3 key4 key5 key6 key7 key8 key9 key0" || return $false + # List---------------------------------------------------------------------------------------------------------> + SendCmd "Message -status 'Menu wird aufgebaut ...'" || return $false + plugs=$(ls -B "$xdir/plugins") + if [ -n "$plugs" ]; then + n=0 + for plug in $plugs ; do +# eval local $(grep -r -m1 "^${plug}=" $xdir/setup.conf) # status +# if [ "x${!plug}" = "xon" ] || [ "x${!plug}" = "xoff" ]; then +# fi + ins_status="nicht installiert" + if [ "$plug" = "streamdev" ]; then + [ -f "${VDRLIBDIR}/libvdr-streamdev-server.so.${plugin_api}" ] && ins_status="installiert" + [ -f "${VDRLIBDIR}/libvdr-streamdev-client.so.${plugin_api}" ] && ins_status="installiert" + plugin_desc="streamdev_server_desc" + desc="${!plugin_desc}" + [ -n "$desc" ] || { + plugin_desc="streamdev_client_desc" + desc="${!plugin_desc}" + } + [ -n "$desc" ] || desc="$plug" + else + [ -f "${VDRLIBDIR}/libvdr-${plug}.so.${plugin_api}" ] && ins_status="installiert" + plugin_desc="${plug}_desc" + desc="${!plugin_desc}" + [ -n "$desc" ] || desc="$plug" + fi + if [ "$cmd" = "installed" ]; then + if [ "$ins_status" = "installiert" ]; then + ((n=n+1)) + [ -n "$(echo $n | grep "^[0-9][0-9][0-9]$")" ] && N="$n" + [ -n "$(echo $n | grep "^[0-9][0-9]$")" ] && N=" $n" + [ -n "$(echo $n | grep "^[0-9]$")" ] && N=" $n" + SendCmd "$plug=menu.AddNew OsdItem '$N \t$desc'" || return $false + fi + elif [ "$cmd" = "standby" ]; then + if [ "$ins_status" != "installiert" ]; then + ((n=n+1)) + [ -n "$(echo $n | grep "^[0-9][0-9][0-9]$")" ] && N="$n" + [ -n "$(echo $n | grep "^[0-9][0-9]$")" ] && N=" $n" + [ -n "$(echo $n | grep "^[0-9]$")" ] && N=" $n" + SendCmd "$plug=menu.AddNew OsdItem '$N \t$plug \t$ins_status'" || return $false + fi + else # all + ((n=n+1)) + [ -n "$(echo $n | grep "^[0-9][0-9][0-9]$")" ] && N="$n" + [ -n "$(echo $n | grep "^[0-9][0-9]$")" ] && N=" $n" + [ -n "$(echo $n | grep "^[0-9]$")" ] && N=" $n" + SendCmd "$plug=menu.AddNew OsdItem '$N \t$plug \t$ins_status'" || return $false + fi + done + fi + SendCmd "Message -statusclear" || return $false + # <-------------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "menu.Show" || return $false + # <-------------------------------------------------------------------------------------------------------- Menu + + while true ; do + SendCmd "menu.SleepEvent" || return $false + # keyOk and keyRed + # if IsEvent menu keyOk || IsEvent menu keyRed; then + # keyRed (Edit) + if IsEvent menu keyRed; then + SendCmd "menu.GetCurrent" + [ "${reply3xx[0]}" != 302 ] && return $false + PluginSetup "${reply3xx[2]}" || return $false + SendCmd "menu.Show" || return $false + fi + # keyGreen (Install) + if IsEvent menu keyGreen ; then + SendCmd "menu.GetCurrent" + [ "${reply3xx[0]}" != 302 ] && return $false + n="${reply3xx[1]}"; N=; + [ -n "$(echo $n | grep "^[0-9][0-9][0-9]$")" ] && N="$n" + [ -n "$(echo $n | grep "^[0-9][0-9]$")" ] && N=" $n" + [ -n "$(echo $n | grep "^[0-9]$")" ] && N=" $n" + plugin="${reply3xx[2]}" + if [ "$cmd" = "installed" ]; then + SendCmd "Message -warn -seconds 10 '$plugin neu installieren?'" || return $false + else + SendCmd "Message -warn -seconds 10 '$plugin installieren?'" || return $false + fi + if IsEvent Message keyOk ; then + SendCmd "Message -status 'Installiere $plugin ...'" || return $false + cd $xdir/plugins/$plugin + plugin_status=$(./plugin.sh -s) + case $plugin_status in + 0 ) ./plugin.sh -m && { + $VDRPRG --version | sed -e 's/\(^[^ ]*\)\(.*$\)/\1_desc="\1\2"/' -e '/^streamdev/s/-/_/' -e 's/^\[.*//' | sort > /tmp/vdr-desc.cache + . /tmp/vdr-desc.cache + } ;; + * ) ./plugin.sh -r ;; + esac + SendCmd "Message -statusclear" || return $false + SendCmd "$plugin.SETTEXT '$N \t$plugin \tinstalliert'" + SendCmd "menu.Show" || return $false + fi + fi + # keyYellow (Remove) + if [ "$cmd" != "standby" ]; then + if IsEvent menu keyYellow ; then + SendCmd "menu.GetCurrent" + [ "${reply3xx[0]}" != 302 ] && return $false + n="${reply3xx[1]}"; N=; + [ -n "$(echo $n | grep "^[0-9][0-9][0-9]$")" ] && N="$n" + [ -n "$(echo $n | grep "^[0-9][0-9]$")" ] && N=" $n" + [ -n "$(echo $n | grep "^[0-9]$")" ] && N=" $n" + plugin="${reply3xx[2]}" + cd $xdir/plugins/$plugin + plugin_status=$(./plugin.sh -s) + case $plugin_status in + 0 ) SendCmd "Message -seconds 5 '$plugin ist nicht installiert'" || return $false ;; + * ) SendCmd "Message -warn -seconds 10 'Soll $plugin entfernt werden?'" || return $false + if IsEvent Message keyOk ; then + SendCmd "Message -status 'Entferne $plugin ...'" || return $false + ./plugin.sh -c + SendCmd "Message -statusclear" || return $false + SendCmd "$plugin.SETTEXT '$N \t$plugin'" + SendCmd "menu.Show" || return $false + fi ;; + esac + fi + fi + # keyBlue (Help) + if IsEvent menu keyBlue ; then + SendCmd "Message -seconds 5 'Auswahl mit Farbtasten oder Menue verlassen mit Exit'" || return $false + fi + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + # keyNr + if [ $n -gt 0 ]; then + mykey=; + k1=; + for k1 in 0 1 2 3 4 5 6 7 8 9 ; do + if IsEvent menu key$k1 ; then + mykey=$k1 + [ $n -gt 9 ] || break + SendCmd "menu.SleepEvent -timeoutms $vdrsetup_key_timeout" || return $false + if IsEvent menu keyOk ; then break; fi + k2=; + for k2 in 0 1 2 3 4 5 6 7 8 9 ; do + if IsEvent menu key$k2 ; then + mykey=${k1}${k2} + [ $n -gt 99 ] || break + SendCmd "menu.SleepEvent -timeoutms $vdrsetup_key_timeout" || return $false + if IsEvent menu keyOk ; then break; fi + k3=; + for k3 in 0 1 2 3 4 5 6 7 8 9 ; do + if IsEvent menu key$k3 ; then + mykey=${k1}${k2}${k3} + break + fi + done + break + fi + done + break + fi + done + + if [ -n "$mykey" ]; then + [ $mykey -gt $n ] && mykey=$n + ((mykey=mykey-1)) # we do this, because 0 is the first item + [ $mykey -lt 0 ] && mykey=0 + SendCmd "menu.SetCurrent $mykey" || return $false +# SendCmd "menu.GetCurrent" +# [ "${reply3xx[0]}" != 302 ] && return $false +# PluginSetup "${reply3xx[2]}" || return $false + SendCmd "menu.Show" || return $false + fi + fi + done +} + +function BackupVdrConf() { + [ "$have_xvdr" = "on" ] || return $false + xdir=/usr/local/src/x-vdr + SendCmd "Message -status 'Backup wird erstellt ...'" || return $false + BACKUPDIR="/tmp/vdr-backup" + BACKUPPATH="$xdir/backup" + [ ! -d $BACKUPPATH ] && mkdir -p $BACKUPPATH + [ -d $BACKUPDIR ] && rm -rf $BACKUPDIR + mkdir -p $BACKUPDIR + cp -pfR --parents $VDRCONFDIR $BACKUPDIR + cp -pfR --parents $VDRSCRIPTDIR $BACKUPDIR + cp -pf --parents $VDRBINDIR/runvdr $BACKUPDIR + cp -pf --parents /etc/default/vdr $BACKUPDIR + cp -pf --parents /etc/init.d/vdr $BACKUPDIR + BACKUPFILE=$BACKUPPATH/`date +%y%m%d-%H%M`-vdr-conf.tar.gz + cd $BACKUPDIR + tar -zcf $BACKUPFILE * && SendCmd "Message -seconds 5 'Backup erstellt'" || return $false + cd .. + rm -rf $BACKUPDIR + SendCmd "Message -statusclear" || return $false +} + +function Xvdr() { + [ "$have_xvdr" = "on" ] || return $false + xdir=/usr/local/src/x-vdr + # Menu ---------------------------------------------------------------------------------------------------------------> + SendCmd "enterlocal" || return $false + SendCmd "menu=New Menu 'x-vdr'" || return $false + SendCmd "menu.SetColorKeyText -red 'Reboot' -green 'Shutdown' -yellow 'VDR Restart' -blue 'Help'" || return $false + SendCmd "menu.SetColumns 1 2" || return $false + SendCmd "menu.EnableEvent keyRed keyGreen keyYellow close" || return $false + SendCmd "menu.EnableEvent key1 key2 key3 key4 key5 key6 key7 key8 key9 key0" || return $false + # List ---------------------------------------------------------------------------------------------------------------> + SendCmd "menu.AddNew OsdItem -unselectable '--- Plugins ---'" || return $false + SendCmd "optP1=menu.AddNew OsdItem '\t1\tAlle Plugins'" || return $false + SendCmd "optP1.EnableEvent keyOk keyBlue" || return $false + SendCmd "optP2=menu.AddNew OsdItem '\t2\tInstallierte Plugins'" || return $false + SendCmd "optP2.EnableEvent keyOk keyBlue" || return $false + SendCmd "optP3=menu.AddNew OsdItem '\t3\tInstallierbare Plugins'" || return $false + SendCmd "optP3.EnableEvent keyOk keyBlue" + + SendCmd "menu.AddNew OsdItem -unselectable '--- Backup ---'" || return $false + SendCmd "optB1=menu.AddNew OsdItem '\t3\tKonfiguration und Skripte'" || return $false + SendCmd "optB1.EnableEvent keyOk keyBlue" || return $false + # <--------------------------------------------------------------------------------------------------------------- List + SendCmd "_focus.addsubmenu menu" || return $false + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.show" || return $false + # <--------------------------------------------------------------------------------------------------------------- Menu + + while true; do + SendCmd "menu.SleepEvent" || return $false + # keyOk (SubMenu InstallPlugins) + if IsEvent optP1 keyOk || IsEvent menu key1 ; then + InstallPlugins all || return $false + SendCmd "menu.Show" || return $false + fi + if IsEvent optP2 keyOk || IsEvent menu key2 ; then + InstallPlugins installed || return $false + SendCmd "menu.Show" || return $false + fi + if IsEvent optP3 keyOk || IsEvent menu key2 ; then + InstallPlugins standby || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (Backup) + if IsEvent optB1 keyOk || IsEvent menu key3 ; then + BackupVdrConf || return $false + SendCmd "menu.Show" || return $false + fi + # keyRed (Reboot) + if IsEvent menu keyRed ; then + SendCmd "Message -warn -seconds 10 'System jetzt neustarten?'" || return $false + if IsEvent Message keyOk ; then + SendCmd "Message 'System wird neugestartet...'" || return $false + SendCmd "menu.SendState osEnd" || return $false + shutdown -r now + fi + fi + # keyGreen (Shutdown) + if IsEvent menu keyGreen ; then + SendCmd "Message -warn -seconds 10 'System jetzt ausschalten?'" || return $false + if IsEvent Message keyOk ; then +# SendCmd "Message 'System wird ausgeschaltet...'" || return $false + SendCmd "menu.SendState osEnd" || return $false +# shutdown -h now + /usr/bin/svdrpsend.pl HITK Power + return $true + fi + fi + # keyYellow (Restart) + if IsEvent menu keyYellow ; then + SendCmd "Message -warn -seconds 10 'VDR jetzt neustarten?'" || return $false + if IsEvent Message keyOk ; then + SendCmd "Message 'VDR wird neugestartet...'" || return $false + SendCmd "menu.SendState osEnd" || return $false + sleep 1 + killall -9 vdr + fi + fi + # keyBlue (Help) + if IsEvent optP1 keyBlue ; then + SendCmd "Message -seconds 5 'Zeigt alle verfuegbaren Plugins'" || return $false + fi + if IsEvent optP2 keyBlue ; then + SendCmd "Message -seconds 5 'Zeigt nur die installierten Plugins'" || return $false + fi + if IsEvent optP3 keyBlue ; then + SendCmd "Message -seconds 5 'Zeigt nur die nicht installierten Plugins'" || return $false + fi + if IsEvent optB1 keyBlue ; then + SendCmd "Message -seconds 5 'Erstellt ein Backup von Konfiguration und Skripten'" || return $false + fi + + # close the submenu + if IsEvent menu close ; then + SendCmd "delete menu" || return $false + SendCmd "leavelocal" || return $false + return $true + fi + done +} + + +##### Main Menu ##### +function MainMenu() { + # Menu ---------------------------------------------------------------------------------------------------------------> + SendCmd "menu=New Menu 'vdrsetup'" || return $false + SendCmd "menu.SetColorKeyText -red 'Reboot' -green 'Shutdown' -yellow 'VDR Restart' -blue 'Help'" || return $false + SendCmd "menu.SetColumns 1 2" || return $false + SendCmd "menu.EnableEvent keyRed keyGreen keyYellow keyBlue close" || return $false + SendCmd "menu.EnableEvent key1 key2 key3 key4 key5 key6 key7 key8 key9 key0" || return $false + # List ---------------------------------------------------------------------------------------------------------------> + SendCmd "opt1=menu.AddNew OsdItem '\t1\tVDR Einstellungen'" || return $false + SendCmd "opt1.EnableEvent keyOk" || return $false + SendCmd "opt2=menu.AddNew OsdItem '\t2\tInstallierte Plugins'" || return $false + SendCmd "opt2.EnableEvent keyOk" || return $false + SendCmd "opt3=menu.AddNew OsdItem '\t3\tPlugin Status Liste'" || return $false + SendCmd "opt3.EnableEvent keyOk" || return $false + SendCmd "opt4=menu.AddNew OsdItem '\t4\tSystemstart'" || return $false + SendCmd "opt4.EnableEvent keyOk" || return $false + SendCmd "opt5=menu.AddNew OsdItem '\t5\tWakeup'" || return $false + SendCmd "opt5.EnableEvent keyOk" || return $false + SendCmd "opt6=menu.AddNew OsdItem '\t6\tSkript Intern'" || return $false + SendCmd "opt6.EnableEvent keyOk" || return $false + SendCmd "opt7=menu.AddNew OsdItem '\t7\tDVB Modul'" || return $false + SendCmd "opt7.EnableEvent keyOk" || return $false + if [ "$have_xvdr" = "on" ]; then + SendCmd "opt8=menu.AddNew OsdItem '\t8\tX-VDR'" || return $false + SendCmd "opt8.EnableEvent keyOk" || return $false + fi + # <--------------------------------------------------------------------------------------------------------------- List + SendCmd "opt1.SetCurrent" || return $false + SendCmd "menu.Show" || return $false + # <--------------------------------------------------------------------------------------------------------------- Menu + + while true ; do + SendCmd "menu.SleepEvent" || return $false + # keyOk (SubMenu VdrSetup) + if IsEvent opt1 keyOk || IsEvent menu key1 ; then + VdrSetup || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (SubMenu ListPlugins) + if IsEvent opt2 keyOk || IsEvent menu key2 ; then + ListPlugins || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (SubMenu PluginStatusList) + if IsEvent opt3 keyOk || IsEvent menu key3 ; then + PluginStatusList || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (SubMenu SystemStart) + if IsEvent opt4 keyOk || IsEvent menu key4 ; then + SystemStart || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (SubMenu Wakeup) + if IsEvent opt5 keyOk || IsEvent menu key5 ; then + Wakeup || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (SubMenu ScriptSetup) + if IsEvent opt6 keyOk || IsEvent menu key6 ; then +# SendCmd "Message -seconds 5 'Einstellungen gelten nur fuer diese Sitzung'" || return $false + ScriptSetup || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (SubMenu DVB) + if IsEvent opt7 keyOk || IsEvent menu key7 ; then + DVBModul || return $false + SendCmd "menu.Show" || return $false + fi + # keyOk (SubMenu Xvdr) + if [ "$have_xvdr" = "on" ]; then + if IsEvent opt8 keyOk || IsEvent menu key8 ; then + Xvdr || return $false + SendCmd "menu.Show" || return $false + fi + fi + # keyRed (Reboot) + if IsEvent menu keyRed ; then + SendCmd "Message -warn -seconds 10 'System jetzt neustarten?'" || return $false + if IsEvent Message keyOk ; then + SendCmd "Message 'System wird neugestartet...'" || return $false + SendCmd "menu.SendState osEnd" || return $false + shutdown -r now + fi + fi + # keyGreen (Shutdown) + if IsEvent menu keyGreen ; then + SendCmd "Message -warn -seconds 10 'System jetzt ausschalten?'" || return $false + if IsEvent Message keyOk ; then +# SendCmd "Message 'System wird ausgeschaltet...'" || return $false + SendCmd "menu.SendState osEnd" || return $false +# shutdown -h now + /usr/bin/svdrpsend.pl HITK Power + return $true + fi + fi + # keyYellow (Restart) + if IsEvent menu keyYellow ; then + SendCmd "Message -warn -seconds 10 'VDR jetzt neustarten?'" || return $false + if IsEvent Message keyOk ; then + SendCmd "Message 'VDR wird neugestartet...'" || return $false + SendCmd "menu.SendState osEnd" || return $false + sleep 1 + killall -9 vdr + fi + fi + # keyBlue (Help) + if IsEvent menu keyBlue ; then + SendCmd "Message -seconds 5 'Auswahl mit OK oder Menue verlassen mit Exit'" || return $false + fi + # close the menu + if IsEvent menu close ; then + SendCmd "menu.SendState osEnd" || return $false + return $true + fi + done +} + + +############### +# Main Code # +############### + + +ConnectServer localhost 2010 +# Connect to the server process + +ReadReply || error +# Read server welcome + +SendCmd "Version 0.1" || error +# Identify to server with protocol version + +MainMenu || error +# Do vdrsetup + +SendCmd Quit +DoLog "disconnecting from OSDServer" +# ... and good bye + +exec 3>&- +exec 4>&- +# close FIFOs + diff --git a/vdr/scripts/vdrshutdown b/vdr/scripts/vdrshutdown new file mode 100644 index 0000000..bda6766 --- /dev/null +++ b/vdr/scripts/vdrshutdown @@ -0,0 +1,214 @@ +#!/bin/bash + +# x-vdr (Installations-Skript fuer einen VDR mit Debian als Basis) +# von Marc Wernecke - www.zulu-entertainment.de +# 26.01.2009 + +# vdrshutdown: shutdown script for x-vdr + +# no arguments, no action +[ $# -gt 0 ] || exit 1 + +# defaults +DEBUG=0 +LOGGER="logger -s ${0##*/} " +WAKEUPTIME=0 + +# load VDR configuration +if [ -f /etc/default/vdr ]; then + . /etc/default/vdr +else + $LOGGER "exit, because /etc/default/vdr does not exists" + exit 1 +fi + +# load Shutdown configuration +if [ -f "$VDRCONFDIR/shutdown.conf" ]; then + . "$VDRCONFDIR/shutdown.conf" +else + $LOGGER "exit, because $VDRCONFDIR/shutdown.conf does not exists" + exit 1 +fi + +# check acpi +if [ "$WAKEUP_MODE" = "1" ]; then + if [ -f /sys/class/rtc/rtc0/wakealarm ]; then + ACPI="/sys/class/rtc/rtc0/wakealarm" + elif [ -f /proc/acpi/alarm ]; then + ACPI="/proc/acpi/alarm" + else + $LOGGER "acpi-wakeup is not supported by your kernel, exit" + echo "$VDRBINDIR/svdrpsend.pl MESG 'acpi-wakeup is not supported by your kernel, exit'"| at now + exit 1 + fi +fi + +# check procs +while read i; do + CMD=$(eval $i 2>/dev/null) + if [ $? -eq 0 ] && [ -n "$CMD" ]; then + $LOGGER "stop shutdown, because $CMD..." + $LOGGER "waiting period $WAITING_PERIOD minutes up to the next shutdown..." + echo "$VDRBINDIR/svdrpsend.pl MESG 'Shutdown abgebrochen, weil $CMD'"| at now + sleep 1 + echo "$VDRBINDIR/svdrpsend.pl MESG 'Erneuter Shutdown Versuch in $WAITING_PERIOD Minuten.'"| at now + sleep 1 + echo "$VDRBINDIR/svdrpsend.pl HITK Power"| at now +$WAITING_PERIOD minutes + exit 1 + fi +done < <(echo "$CHECK_PROCS" | sed '/^[ ]*$/d') + +# no wakeup-mode +if [ "$WAKEUP_MODE" = "0" ]; then + echo "$VDRBINDIR/svdrpsend.pl MESG 'Shutdown now!'"| at now + sudo $VDRSCRIPTDIR/vdr2root shutdown + exit 0 +fi + +# extension-board +if [ "$WAKEUP_MODE" = "3" ]; then + echo "$VDRBINDIR/svdrpsend.pl MESG 'Shutdown now!'"| at now + sudo $VDRSCRIPTDIR/vdr2root extb-poweroff + exit 0 +fi + +# check MAX_POWEROFF_TIME for special commands and set the value +if [ "$MAX_POWEROFF_TIME" = "MAXIMAL" ]; then # calculate the maximal wakeup-time + MONTH_NOW=`date +%-m` # if this month has no 31th, set the wakeup to the 31th of the next month + if [ $MONTH_NOW==2 ] || [ $MONTH_NOW==4 ] || [ $MONTH_NOW==6 ] || [ $MONTH_NOW==9 ] || [ $MONTH_NOW==11 ]; then + YEAR_NOW=`date +%Y` + NEXT_WAKEUP=`date -d "$YEAR_NOW-$(($MONTH_NOW+1))-31 23:59:59" +%s` + MAX_POWEROFF_TIME=$((($NEXT_WAKEUP-`date +%s`) / 60)) + else # sleep exactly one month + MAX_POWEROFF_TIME=44640 + fi + WAKEUPTIME=$((`date +%s` + $MAX_POWEROFF_TIME * 60)) +elif [ "$MAX_POWEROFF_TIME" = "INTERVAL" ]; then # calculate the next wakeup-time for housekeeping + DAY_IN_YEAR=`date +%j` + DREAMDAY=0 + while [ $DREAMDAY -le $DAY_IN_YEAR ]; do + DREAMDAY=$(($DREAMDAY + $INTERVAL)) + done + YEAR_NOW=`date +%Y` + if [ $DREAMDAY -gt 365 ]; then + DREAMDAY=$(($DREAMDAY - 365)) + YEAR_NOW=$(($YEAR_NOW + 1)) + fi + WAKEUPTIME=$((`date -d "$YEAR_NOW-01-01 $DREAMTIME:00" +%s` + $DREAMDAY * 3600 * 24)) +elif [ -n "$MAX_POWEROFF_TIME" ] && (($MAX_POWEROFF_TIME > 0)); then # calculate, at what time the machine should be powered on + WAKEUPTIME=$((`date +%s` + $MAX_POWEROFF_TIME * 60)) +else + WAKEUPTIME=$1 +fi + +# final test +if [ $WAKEUPTIME -gt $1 ] && [ $1 -gt 0 ]; then + WAKEUPTIME=$1 +fi + +# wakeupbefore - minutes before the programmed wakeuptime the computer should wake up +[ -z "$WAKEUP_BEFORE" ] && WAKEUP_BEFORE=0 +WAKEUPTIME=$(($WAKEUPTIME - $WAKEUP_BEFORE * 60)) + +# wakeup-time is greater then zero +if [ $WAKEUPTIME -gt 0 ]; then + # calculate the minimal wakeup-time + MinEventTimeout=`grep -m1 "MinEventTimeout" $VDRCONFDIR/setup.conf | cut -f 2 -d "=" | sed -e 's/^ //g' -e 's/ $//g'` + [ $MinEventTimeout -lt 10 ] && MinEventTimeout=10 + MIN_WAKEUPTIME=$(($NOW + $MinEventTimeout * 60 + 1)) + if [ $MIN_WAKEUPTIME -gt $WAKEUPTIME ]; then + case "$MIN_WAKEUP_VAR" in + 0) VAR=`date -d "1970-01-01 UTC $MIN_WAKEUPTIME seconds" +"%Y-%m-%d %R:%S"` + echo "$VDRBINDIR/svdrpsend.pl MESG 'Timer wird auf $VAR gestellt.'"| at now + sleep 2 + ;; + 1) WAKEUPTIME=$(($WAKEUPTIME - $MinEventTimeout * 60 + 600)) + [ $WAKEUPTIME -lt $(($NOW + 600)) ] && WAKEUPTIME=$(($NOW + 600)) + VAR=`date -d "1970-01-01 UTC $WAKEUPTIME seconds" +"%Y-%m-%d %R:%S"` + echo "$VDRBINDIR/svdrpsend.pl MESG 'Timer wird auf $VAR gestellt.'"| at now + sleep 2 + ;; + 2) echo "$VDRBINDIR/svdrpsend.pl MESG 'Es werden keine Timer gestellt.'"| at now + sleep 2 + [ "$WAKEUP_MODE" = "1" ] && sudo $VDRSCRIPTDIR/vdr2root poweroff && exit 0 + sudo $VDRSCRIPTDIR/vdr2root shutdown && exit 0 + ;; + 3) echo "$VDRBINDIR/svdrpsend.pl MESG 'Shutdown abgebrochen.'"| at now + sleep 2 + exit 0 + ;; + esac + fi + + # debug + if [ "$DEBUG" = "1" ]; then + echo `date '+%F %T'` > /tmp/wakeuptime.txt + echo "Next Wakeup Time:" >> /tmp/wakeuptime.txt + echo "ACPI -> `date -d "1970-01-01 UTC $WAKEUPTIME seconds" +"%Y-%m-%d %R:%S"` > $ACPI" >> /tmp/wakeuptime.txt + echo "NVRAM -> $WAKEUPTIME" >> /tmp/wakeuptime.txt + fi + + # acpi-wakeup + if [ "$WAKEUP_MODE" = "1" ]; then + echo "$VDRBINDIR/svdrpsend.pl MESG 'Shutdown now!'"| at now + if [ "$ACPI" = "/sys/class/rtc/rtc0/wakealarm" ]; then + VAR="$WAKEUPTIME" + sudo $VDRSCRIPTDIR/vdr2root acpi-wakeup "0" "$ACPI" + else + VAR=`date -d "1970-01-01 UTC $WAKEUPTIME seconds" +"%Y-%m-%d %R:%S"` + sudo $VDRSCRIPTDIR/vdr2root acpi-wakeup "$VAR" "$ACPI" + fi + sudo $VDRSCRIPTDIR/vdr2root acpi-wakeup "$VAR" "$ACPI" + sleep 1 + sudo $VDRSCRIPTDIR/vdr2root poweroff + exit 0 + fi + + # nvram-wakeup + if [ "$WAKEUP_MODE" = "2" ]; then + echo "$VDRBINDIR/svdrpsend.pl MESG 'Shutdown now!'"| at now + VAR="-s $WAKEUPTIME $NVRAM_OPT ${NVRAM_CONFIG:+-C $NVRAM_CONFIG} ${NVRAM_IWNAME:+-I $NVRAM_IWNAME}" +# VAR="-s $WAKEUPTIME $NVRAM_OPT -w 0 ${NVRAM_CONFIG:+-C $NVRAM_CONFIG} ${NVRAM_IWNAME:+-I $NVRAM_IWNAME}" +# sudo $VDRSCRIPTDIR/vdr2root nvram-wakeup -d + sudo $VDRSCRIPTDIR/vdr2root nvram-wakeup "$VAR" + sleep 1 + if [ "$NEED_REBOOT" = "0" ]; then + sudo $VDRSCRIPTDIR/vdr2root shutdown + else + if [ "$LILO" = "1" ]; then + sudo $VDRSCRIPTDIR/vdr2root lilo + else + sudo $VDRSCRIPTDIR/vdr2root grub $GRUB_POWEROFF + fi + sudo $VDRSCRIPTDIR/vdr2root reboot + fi + exit 0 + fi + +else # wakeup-time is equal to zero + if [ "$WAKEUP_MODE" = "2" ]; then + # disable nvram-wakeup + sudo $VDRSCRIPTDIR/vdr2root nvram-wakeup -d + sleep 1 + # if wakeup-lan works only with a shutdown via poweroff-kernel + if [ "$NEED_REBOOT" = "2" ]; then + if [ "$LILO" = "1" ]; then + sudo $VDRSCRIPTDIR/vdr2root lilo + else + sudo $VDRSCRIPTDIR/vdr2root grub $GRUB_POWEROFF + fi + sudo $VDRSCRIPTDIR/vdr2root reboot + exit 0 + fi + fi +fi + +# wakeuptime is equal to zero, shutdown +echo "$VDRBINDIR/svdrpsend.pl MESG 'Shutdown now!'"| at now +if [ "$WAKEUP_MODE" = "1" ]; then + sudo $VDRSCRIPTDIR/vdr2root poweroff +else + sudo $VDRSCRIPTDIR/vdr2root shutdown +fi + +exit 0 diff --git a/vdr/scripts/vdrwritedvd b/vdr/scripts/vdrwritedvd new file mode 100644 index 0000000..2c4ad1c --- /dev/null +++ b/vdr/scripts/vdrwritedvd @@ -0,0 +1,17 @@ +#!/bin/sh +# +# vdrwritedvd - x-vdr version +# +# This script will be called by the vdr-plugins dvdselect and dvdswitch to write a dvd. +# +# It gets the following parameter: +# +# $1 = filename + +# Load VDR configuration +. /etc/default/vdr + +# vdr2root +echo "sudo $VDRSCRIPTDIR/vdr2root writedvd \"$1\"" | at now + +exit 0 diff --git a/vdr/scripts/x-lcd b/vdr/scripts/x-lcd new file mode 100644 index 0000000..ef28a7c --- /dev/null +++ b/vdr/scripts/x-lcd @@ -0,0 +1,26 @@ +#! /bin/sh +# /etc/init.d/x-lcd + +# Load VDR configuration +. /etc/default/vdr + +STARTLOGO=$VDRCONFDIR/plugins/graphlcd/splash/start +STOPLOGO=$VDRCONFDIR/plugins/graphlcd/splash/stop + +case "$1" in + start) + echo "Displaying Startlogo" + /usr/bin/showpic -c /etc/graphlcd.conf -d ks0108 -s 200 $(ls $STARTLOGO/*.glcd) & + ;; + stop) + echo "Displaying Shutdownlogo" + /usr/bin/showpic -c /etc/graphlcd.conf -d ks0108 -s 200 $(ls $STOPLOGO/*.glcd) & + ;; + *) + echo "Usage: /etc/init.d/x-lcd {start|stop}" + exit 1 + ;; +esac + +exit 0 + diff --git a/vdr/vdr-1.7.5-ext_s2apiwrapper-0.5.diff b/vdr/vdr-1.7.5-ext_s2apiwrapper-0.5.diff new file mode 100644 index 0000000..b10be7a --- /dev/null +++ b/vdr/vdr-1.7.5-ext_s2apiwrapper-0.5.diff @@ -0,0 +1,475 @@ +diff -ruNp vdr-1.7.5-extensions/channels.c vdr-1.7.5-ext-s2apiwrapper/channels.c +--- vdr-1.7.5-extensions/channels.c 2009-04-12 13:37:59.000000000 +0200 ++++ vdr-1.7.5-ext-s2apiwrapper/channels.c 2009-04-13 21:06:29.000000000 +0200 +@@ -11,6 +11,7 @@ + #include <linux/dvb/frontend.h> + #include <ctype.h> + #include "device.h" ++#include "s2apiwrapper.h" + #include "epg.h" + #include "timers.h" + #ifdef USE_STREAMDEVEXT +diff -ruNp vdr-1.7.5-extensions/dvbdevice.c vdr-1.7.5-ext-s2apiwrapper/dvbdevice.c +--- vdr-1.7.5-extensions/dvbdevice.c 2009-04-12 13:37:59.000000000 +0200 ++++ vdr-1.7.5-ext-s2apiwrapper/dvbdevice.c 2009-04-13 21:06:29.000000000 +0200 +@@ -230,7 +230,7 @@ bool cDvbTuner::SetFrontend(void) + memset(&CmdSeq, 0, sizeof(CmdSeq)); + CmdSeq.props = Frontend; + SETCMD(DTV_CLEAR, 0); +- if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { ++ if (S2API_ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { + esyslog("ERROR: frontend %d: %m", cardIndex); + return false; + } +@@ -364,7 +364,7 @@ bool cDvbTuner::SetFrontend(void) + return false; + } + SETCMD(DTV_TUNE, 0); +- if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { ++ if (S2API_ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { + esyslog("ERROR: frontend %d: %m", cardIndex); + return false; + } +@@ -1428,12 +1428,14 @@ int cDvbDevice::PlayAudio(const uchar *D + + int cDvbDevice::PlayTsVideo(const uchar *Data, int Length) + { +- return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); ++ //return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); ++ return cDevice::PlayTsVideo(Data, Length); + } + + int cDvbDevice::PlayTsAudio(const uchar *Data, int Length) + { +- return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); ++ //return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); ++ return cDevice::PlayTsAudio(Data, Length); + } + + bool cDvbDevice::OpenDvr(void) +diff -ruNp vdr-1.7.5-extensions/dvbdevice.h vdr-1.7.5-ext-s2apiwrapper/dvbdevice.h +--- vdr-1.7.5-extensions/dvbdevice.h 2009-04-12 13:37:59.000000000 +0200 ++++ vdr-1.7.5-ext-s2apiwrapper/dvbdevice.h 2009-04-13 21:06:29.000000000 +0200 +@@ -14,9 +14,10 @@ + #include <linux/dvb/version.h> + #include "device.h" + #include "dvbspu.h" +- +-#if DVB_API_VERSION != 5 || DVB_API_VERSION_MINOR != 0 +-#error VDR requires Linux DVB driver API version 5.0! ++#include "s2apiwrapper.h" ++ ++#if DVB_API_VERSION != 3 ++#error VDR requires Linux DVB driver API version 3! + #endif + + #define MAXDVBDEVICES 8 +diff -ruNp vdr-1.7.5-extensions/Makefile vdr-1.7.5-ext-s2apiwrapper/Makefile +--- vdr-1.7.5-extensions/Makefile 2009-04-12 13:37:59.000000000 +0200 ++++ vdr-1.7.5-ext-s2apiwrapper/Makefile 2009-04-13 21:06:29.000000000 +0200 +@@ -36,7 +36,7 @@ DOXYFILE = Doxyfile + + SILIB = $(LSIDIR)/libsi.a + +-OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbci.o dvbosd.o\ ++OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o s2apiwrapper.o dvbdevice.o dvbci.o dvbosd.o\ + dvbplayer.o dvbspu.o dvbsubtitle.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\ + lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\ + receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\ +diff -ruNp vdr-1.7.5-extensions/nit.c vdr-1.7.5-ext-s2apiwrapper/nit.c +--- vdr-1.7.5-extensions/nit.c 2008-12-20 11:57:50.000000000 +0100 ++++ vdr-1.7.5-ext-s2apiwrapper/nit.c 2009-04-13 21:06:29.000000000 +0200 +@@ -10,6 +10,7 @@ + #include "nit.h" + #include <linux/dvb/frontend.h> + #include "channels.h" ++#include "s2apiwrapper.h" + #include "eitscan.h" + #include "libsi/section.h" + #include "libsi/descriptor.h" +diff -ruNp vdr-1.7.5-extensions/s2apiwrapper.c vdr-1.7.5-ext-s2apiwrapper/s2apiwrapper.c +--- vdr-1.7.5-extensions/s2apiwrapper.c 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-ext-s2apiwrapper/s2apiwrapper.c 2009-04-13 21:06:29.000000000 +0200 +@@ -0,0 +1,165 @@ ++/* ++ * s2apiwrapper.c: ++ * Wrapper to translate DVB S2API to DVB 3.0 API calls ++ * ++ * See the main source file 'vdr.c' for copyright information and ++ * how to reach the author. ++ * ++ * $Id: $ ++ */ ++ ++#include "s2apiwrapper.h" ++#include <string.h> ++#include <errno.h> ++ ++#ifdef DVB_S2API_WRAPPER ++ ++static int ioctl_FE_SET_PROPERTY(int d, dtv_properties *properties) { ++ int result = 0; ++ fe_delivery_system Delivery = SYS_UNDEFINED; ++ dvb_frontend_parameters Frontend; ++ memset(&Frontend, 0, sizeof(Frontend)); ++ ++ for (__u32 i=0; i<properties->num; i++) { ++ __u32 cmd = properties->props[i].cmd; ++ __u32 data = properties->props[i].u.data; ++ ++ switch (cmd) { ++ case DTV_CLEAR: ++ memset(&Frontend, 0, sizeof(Frontend)); ++ continue; ++ ++ case DTV_DELIVERY_SYSTEM: ++ Delivery = fe_delivery_system(data); ++ continue; ++ ++ case DTV_FREQUENCY: ++ Frontend.frequency = data; ++ continue; ++ ++ case DTV_INVERSION: ++ Frontend.inversion = fe_spectral_inversion(data); ++ continue; ++ ++ case DTV_TUNE: ++ result = ioctl(d, FE_SET_FRONTEND, &Frontend); ++ if (result < 0) ++ return result; ++ continue; ++ } ++ ++ if (Delivery == SYS_DVBS) { ++ switch (cmd) { ++ case DTV_MODULATION: ++ if (data != FE_QPSK) { ++ errno = EINVAL; ++ return -1; ++ } ++ break; ++ ++ case DTV_SYMBOL_RATE: ++ Frontend.u.qpsk.symbol_rate = data; ++ break; ++ ++ case DTV_INNER_FEC: ++ Frontend.u.qpsk.fec_inner = fe_code_rate(data); ++ break; ++ ++ case DTV_ROLLOFF: ++ if (data != ROLLOFF_35) { ++ errno = EINVAL; ++ return -1; ++ } ++ break; ++ default: ++ errno = EINVAL; ++ return -1; ++ } ++ } ++ else if (Delivery == SYS_DVBC_ANNEX_AC && result >= 0) { ++ switch (cmd) { ++ case DTV_MODULATION: ++ Frontend.u.qam.modulation = fe_modulation(data); ++ break; ++ ++ case DTV_SYMBOL_RATE: ++ Frontend.u.qam.symbol_rate = data; ++ break; ++ ++ case DTV_INNER_FEC: ++ Frontend.u.qam.fec_inner = fe_code_rate(data); ++ break; ++ default: ++ errno = EINVAL; ++ return -1; ++ } ++ } ++ else if (Delivery == SYS_DVBT && result >= 0) { ++ switch (cmd) { ++ case DTV_MODULATION: ++ Frontend.u.ofdm.constellation = fe_modulation(data); ++ break; ++ ++ case DTV_BANDWIDTH_HZ: ++ Frontend.u.ofdm.bandwidth = fe_bandwidth(data); ++ break; ++ ++ case DTV_CODE_RATE_HP: ++ Frontend.u.ofdm.code_rate_HP = fe_code_rate(data); ++ break; ++ ++ case DTV_CODE_RATE_LP: ++ Frontend.u.ofdm.code_rate_LP = fe_code_rate(data); ++ break; ++ ++ case DTV_TRANSMISSION_MODE: ++ Frontend.u.ofdm.transmission_mode = fe_transmit_mode(data); ++ break; ++ ++ case DTV_GUARD_INTERVAL: ++ Frontend.u.ofdm.guard_interval = fe_guard_interval(data); ++ break; ++ ++ case DTV_HIERARCHY: ++ Frontend.u.ofdm.hierarchy_information = fe_hierarchy(data); ++ break; ++ ++ default: ++ errno = EINVAL; ++ return -1; ++ } ++ } ++ } // for ++ return result; ++} ++ ++static int ioctl_FE_GET_PROPERTY(int d, dtv_properties *properties) { ++ errno = EINVAL; ++ return -1; ++} ++ ++#ifdef DVB_S2API_RUNTIME ++static bool S2APITested = false; ++static bool HasS2APIResult; ++ ++static bool HasS2API(int d) { ++ if (!S2APITested) { ++ // TODO: Test for S2API availability ++ HasS2APIResult = false; ++ S2APITested = true; ++ } ++ return HasS2APIResult; ++} ++#else ++static bool HasS2API(int d) { return false; } ++#endif // ifdef DVB_S2API_RUNTIME ++ ++int S2API_ioctl(int d, int request, void *data) { ++ if (request == (int)FE_SET_PROPERTY && !HasS2API(d)) ++ return ioctl_FE_SET_PROPERTY(d, (dtv_properties*)data); ++ if (request == (int)FE_GET_PROPERTY && !HasS2API(d)) ++ return ioctl_FE_GET_PROPERTY(d, (dtv_properties*)data); ++ return ioctl(d, request, data); ++} ++ ++#endif // ifdef DVB_S2API_WRAPPER +diff -ruNp vdr-1.7.5-extensions/s2apiwrapper.h vdr-1.7.5-ext-s2apiwrapper/s2apiwrapper.h +--- vdr-1.7.5-extensions/s2apiwrapper.h 1970-01-01 01:00:00.000000000 +0100 ++++ vdr-1.7.5-ext-s2apiwrapper/s2apiwrapper.h 2009-04-13 21:06:29.000000000 +0200 +@@ -0,0 +1,213 @@ ++/* ++ * s2apiwrapper.h: ++ * Wrapper to translate DVB S2API to DVB 3.0 API calls ++ * ++ * See the main source file 'vdr.c' for copyright information and ++ * how to reach the author. ++ * ++ * $Id: $ ++ */ ++ ++#ifndef __S2API_WRAPPER_H ++#define __S2API_WRAPPER_H ++ ++#include <linux/dvb/frontend.h> ++#include <linux/dvb/version.h> ++#include <sys/ioctl.h> ++ ++#if DVB_API_VERSION != 3 ++#error VDR requires Linux DVB driver API version 3! ++#endif ++ ++#if !defined(DVB_S2API_RUNTIME) ++#define DVB_S2API_RUNTIME 1 ++#endif ++ ++#if DVB_S2API_RUNTIME == 0 ++#undef DVB_S2API_RUNTIME ++#endif ++ ++#if !defined(DVB_S2API_WRAPPER) \ ++ && (DVB_API_VERSION_MINOR < 3 || defined(DVB_S2API_RUNTIME)) ++#define DVB_S2API_WRAPPER 1 ++#endif ++ ++#if defined(DVB_S2API_WRAPPER) && DVB_S2API_WRAPPER == 0 ++#undef DVB_S2API_WRAPPER ++#endif ++ ++#if DVB_API_VERSION_MINOR < 3 ++ ++// DVB API is missing S2API structs, so we declare them. ++// The following is based on frontend.h from s2api DVB driver ++ ++ ++enum fe_s2caps { ++ FE_HAS_EXTENDED_CAPS = 0x800000, // We need more bitspace for newer APIs, indicate this. ++ FE_CAN_2G_MODULATION = 0x10000000, // frontend supports "2nd generation modulation" (DVB-S2) ++}; ++ ++enum fe_s2code_rate { ++ FEC_3_5 = FEC_AUTO + 1, ++ FEC_9_10, ++}; ++ ++enum fe_s2modulation { ++ PSK_8 = VSB_16 + 1, ++ APSK_16, ++ APSK_32, ++ DQPSK, ++}; ++ ++ ++/* S2API Commands */ ++#define DTV_UNDEFINED 0 ++#define DTV_TUNE 1 ++#define DTV_CLEAR 2 ++#define DTV_FREQUENCY 3 ++#define DTV_MODULATION 4 ++#define DTV_BANDWIDTH_HZ 5 ++#define DTV_INVERSION 6 ++#define DTV_DISEQC_MASTER 7 ++#define DTV_SYMBOL_RATE 8 ++#define DTV_INNER_FEC 9 ++#define DTV_VOLTAGE 10 ++#define DTV_TONE 11 ++#define DTV_PILOT 12 ++#define DTV_ROLLOFF 13 ++#define DTV_DISEQC_SLAVE_REPLY 14 ++ ++/* Basic enumeration set for querying unlimited capabilities */ ++#define DTV_FE_CAPABILITY_COUNT 15 ++#define DTV_FE_CAPABILITY 16 ++#define DTV_DELIVERY_SYSTEM 17 ++ ++#if 0 ++/* ISDB */ ++/* maybe a dup of DTV_ISDB_SOUND_BROADCASTING_SUBCHANNEL_ID ??? */ ++#define DTV_ISDB_SEGMENT_IDX 18 ++/* 1, 3 or 13 ??? */ ++#define DTV_ISDB_SEGMENT_WIDTH 19 ++ ++/* the central segment can be received independently or 1/3 seg in SB-mode */ ++#define DTV_ISDB_PARTIAL_RECEPTION 20 ++/* sound broadcasting is used 0 = 13segment, 1 = 1 or 3 see DTV_ISDB_PARTIAL_RECEPTION */ ++#define DTV_ISDB_SOUND_BROADCASTING 21 ++ ++/* only used in SB */ ++/* determines the initial PRBS of the segment (to match with 13seg channel) */ ++#define DTV_ISDB_SOUND_BROADCASTING_SUBCHANNEL_ID 22 ++ ++#define DTV_ISDB_LAYERA_FEC 23 ++#define DTV_ISDB_LAYERA_MODULATION 24 ++#define DTV_ISDB_LAYERA_SEGMENT_WIDTH 25 ++#define DTV_ISDB_LAYERA_TIME_INTERLEAVER 26 ++ ++#define DTV_ISDB_LAYERB_FEC 27 ++#define DTV_ISDB_LAYERB_MODULATION 28 ++#define DTV_ISDB_LAYERB_SEGMENT_WIDTH 29 ++#define DTV_ISDB_LAYERB_TIME_INTERLEAVING 30 ++ ++#define DTV_ISDB_LAYERC_FEC 31 ++#define DTV_ISDB_LAYERC_MODULATION 32 ++#define DTV_ISDB_LAYERC_SEGMENT_WIDTH 33 ++#define DTV_ISDB_LAYERC_TIME_INTERLEAVING 34 ++#endif ++#define DTV_API_VERSION 35 ++#define DTV_API_VERSION 35 ++#define DTV_CODE_RATE_HP 36 ++#define DTV_CODE_RATE_LP 37 ++#define DTV_GUARD_INTERVAL 38 ++#define DTV_TRANSMISSION_MODE 39 ++#define DTV_HIERARCHY 40 ++ ++#define DTV_MAX_COMMAND DTV_HIERARCHY ++ ++typedef enum fe_pilot { ++ PILOT_ON, ++ PILOT_OFF, ++ PILOT_AUTO, ++} fe_pilot_t; ++ ++typedef enum fe_rolloff { ++ ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */ ++ ROLLOFF_20, ++ ROLLOFF_25, ++ ROLLOFF_AUTO, ++} fe_rolloff_t; ++ ++typedef enum fe_delivery_system { ++ SYS_UNDEFINED, ++ SYS_DVBC_ANNEX_AC, ++ SYS_DVBC_ANNEX_B, ++ SYS_DVBT, ++ SYS_DSS, ++ SYS_DVBS, ++ SYS_DVBS2, ++ SYS_DVBH, ++ SYS_ISDBT, ++ SYS_ISDBS, ++ SYS_ISDBC, ++ SYS_ATSC, ++ SYS_ATSCMH, ++ SYS_DMBTH, ++ SYS_CMMB, ++ SYS_DAB, ++} fe_delivery_system_t; ++ ++struct dtv_cmds_h { ++ char *name; /* A display name for debugging purposes */ ++ ++ __u32 cmd; /* A unique ID */ ++ ++ /* Flags */ ++ __u32 set:1; /* Either a set or get property */ ++ __u32 buffer:1; /* Does this property use the buffer? */ ++ __u32 reserved:30; /* Align */ ++}; ++ ++struct dtv_property { ++ __u32 cmd; ++ __u32 reserved[3]; ++ union { ++ __u32 data; ++ struct { ++ __u8 data[32]; ++ __u32 len; ++ __u32 reserved1[3]; ++ void *reserved2; ++ } buffer; ++ } u; ++ int result; ++} __attribute__ ((packed)); ++ ++/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */ ++#define DTV_IOCTL_MAX_MSGS 64 ++ ++struct dtv_properties { ++ __u32 num; ++ struct dtv_property *props; ++}; ++ ++#define FE_SET_PROPERTY _IOW('o', 82, struct dtv_properties) ++#define FE_GET_PROPERTY _IOR('o', 83, struct dtv_properties) ++ ++// End of copied section of frontend.h ++ ++#endif // DVB_API_VERSION_MINOR < 3 ++ ++ ++ ++#ifdef DVB_S2API_WRAPPER ++ ++// Wrapper for S2API ioctl calls: ++int S2API_ioctl(int d, int request, void *data); ++ ++#else // ifdef DVB_S2API_WRAPPER ++ ++// Null wrapper for s2api ioctl calls: ++inline int S2API_ioctl(int d, int request, void *data) { return ioctl(d, request, data); } ++ ++#endif // ifdef DVB_S2API_WRAPPER ++ ++#endif // ifndef __S2API_WRAPPER_H |
