diff -ruN vdr-1.7.21/CONTRIBUTORS vdr-1.7.22/CONTRIBUTORS
--- vdr-1.7.21/CONTRIBUTORS	2011-08-27 16:27:22.000000000 +0200
+++ vdr-1.7.22/CONTRIBUTORS	2011-12-04 15:53:41.000000000 +0100
@@ -1117,6 +1117,9 @@
  for making the Audio and Subtitles options available through the Green and Yellow
  keys in the Setup/DVB menu
  for making the Recordings menu display the length (in hours:minutes) of each recording
+ for fixing handling DVB subtitles and implementing decoding textual DVB subtitles
+ for adding file name and line number to LOG_ERROR_STR()
+ for replacing all calls to sleep() with cCondWait::SleepMs()
 
 Ralf Klueber <ralf.klueber@vodafone.com>
  for reporting a bug in cutting a recording if there is only a single editing mark
@@ -1632,6 +1635,7 @@
  for reporting problems with CAMs when checking the CAM status too frequently
  for reporting references to old *.vdr file names in MANUAL
  for reporting that the video stream type was set to 2 even if the vpid was 0
+ for updates to 'sources.conf'
 
 Milos Kapoun <m.kapoun@cra.cz>
  for suggesting to skip code table info in SI data
@@ -1868,6 +1872,8 @@
  "repeat" keypresses very fast
  for reporting a broken entry 'A111.1W' in sources.conf
  for translating OSD texts to the Spanish and Catalan language
+ for fixing scaling subtitles in case the primary device's GetVideoSize() function
+ doesn't return actual values
 
 Mikko Salo <mikko.salo@ppe.inet.fi>
  for suggesting to make the setup option "DVB/Video display format" available only
@@ -1918,6 +1924,11 @@
  for fixing the Language header of the Serbian translation file
  for using pkg-config to get fribidi, freetype and fontconfig cflags and libs
  for making the Makefile also install the include files
+ for fixing a crash when deleting a recording while cutting it
+ for fixing several spelling errors
+ for adding generating a pkg-config file to the Makefile
+ for removing the '.pl' suffix from all scripts (thanks to Ville Skytt�).
+ for changing the default location for the LIRC socket to /var/run/lirc/lircd
 
 Steffen Beyer <cpunk@reactor.de>
  for fixing setting the colored button help after deleting a recording in case the next
@@ -2244,6 +2255,7 @@
  for reporting that Setup.InitialChannel was dereferenced without checking for NULL
  for suggesting to implement a function to determine the length of a recording's
  index file
+ for fixing setting the start time of an edited recording
 
 Pekka Mauno <pekka.mauno@iki.fi>
  for fixing cSchedule::GetFollowingEvent() in case there is currently no present
@@ -2659,6 +2671,8 @@
 
 Lars Hanisch <dvb@flensrocker.de>
  for suggesting to assign the source character 'V' to "Analog Video"
+ for a patch that was used to implement SCR (Satellite Channel Routing)
+ for implementing the SVDRP command 'UPDR'
 
 Alex Lasnier <alex@fepg.org>
  for adding tuning support for ATSC devices
@@ -2774,3 +2788,7 @@
 
 Chris Mayo <aklhfex@gmail.com>
  for reporting a problem with detecting frames on radio channels
+
+Dominic Evans <oldmanuk@gmail.com>
+ for making the SVDRP command LSTC accepts channel IDs
+ for adding cap_net_raw to the capabilities that are not dropped
diff -ruN vdr-1.7.21/HISTORY vdr-1.7.22/HISTORY
--- vdr-1.7.21/HISTORY	2011-09-04 15:07:04.000000000 +0200
+++ vdr-1.7.22/HISTORY	2011-12-04 16:09:45.000000000 +0100
@@ -6742,3 +6742,41 @@
   Detecting frames in case the Picture Start Code or Access Unit Delimiter
   extends over TS packet boundaries is now done by locally skipping TS packets
   in cFrameDetector.
+
+2011-12-04: Version 1.7.22
+
+- Fixed scaling subtitles in case the primary device's GetVideoSize() function doesn't
+  return actual values (thanks to Luca Olivetti).
+- The DiSEqC codes are now copied in the call to cDiseqc::Execute().
+- VDR now supports "Satellite Channel Routing" (SCR) according to EN50494 (based on
+  the "unicable" patch from Lars Hanisch).
+  Since "Unicable" is a registered trademark and stands for only one of many
+  implementations of SCR, the following changes have been made compared to the patch,
+  which need to be taken into account by people who have set up their system using
+  the patch:
+  - The 'U' parameter in the diseqc.conf file has been changed to 'S' ("Scr").
+  - The configuration file name has been changed from "unicable.conf" to "scr.conf".
+- Updated sources.conf (thanks to Arthur Konovalov).
+- The SVDRP command LSTC now also accepts channel IDs (thanks to Dominic Evans).
+- Fixed handling DVB subtitles and implemented decoding textual DVB subtitles (thanks
+  to Rolf Ahrenberg).
+- Added cap_net_raw to the capabilities that are not dropped (thanks to Dominic Evans).
+- Fixed setting the start time of an edited recording (thanks to Christoph Haubrich).
+- Temporarily switching free devices to transponders in order to have their running
+  status updated is now done by marking the devices as "occupied" for a certain
+  amount of time.
+- The new setup options "LNB/Device n connected to sat cable" can be used to define
+  which DVB-S devices are connected to the same sat cable and are therefore "bonded".
+  This obsoletes the LNBSHARE patch. Users of the LNBSHARE patch will need to newly
+  set up their sat devices with the above options.
+- Fixed a crash when deleting a recording while cutting it (thanks to Ville Skytt�).
+- Fixed several spelling errors (thanks to Ville Skytt�).
+- The new SVDRP command UPDR can be used to trigger an update of the list of
+  recordings (thanks to Lars Hanisch).
+- Added generating a pkg-config file to the Makefile (thanks to Ville Skytt�).
+- Removed the '.pl' suffix from all scripts (thanks to Ville Skytt�).
+- Changed the default location for the LIRC socket to /var/run/lirc/lircd (thanks
+  to Ville Skytt�).
+- Added file name and line number to LOG_ERROR_STR() (thanks to Rolf Ahrenberg).
+- Replaced all calls to sleep() with cCondWait::SleepMs() (thanks to Rolf Ahrenberg).
+- Fixed a crash with malformed SI data (patch from vdr-portal).
diff -ruN vdr-1.7.21/INSTALL vdr-1.7.22/INSTALL
--- vdr-1.7.21/INSTALL	2010-09-19 14:29:26.000000000 +0200
+++ vdr-1.7.22/INSTALL	2011-11-27 11:37:54.000000000 +0100
@@ -386,6 +386,23 @@
 parameter to "on". You also need to set up the file 'diseqc.conf' to properly
 access your DiSEqC equipment (see man vdr(5) for details).
 
+A special form of DiSEqC is used to connect several receivers to one signal
+source using only a single cable. This method, known as "Satellite Channel Routing"
+according to EN50494 (aka "Unicable(TM)", "OLT(TM)", "SatCR", "Single Cable
+Distribution", "Channel Stacking System" or "Single Cable Interface") uses
+the file "scr.conf" to specify which SCR channels use which user band frequency.
+
+If DVB-S devices need to be connected to the same satellite cable, but no
+"Satellite Channel Routing" is available, they can be set to be "bonded" in
+the Setup/LNB menu. Bonded devices can only be tuned to the same polarization
+and frequency band, which reduces the number of potentially receivable channels.
+
+Note that it doesn't make sense to use "Satellite Channel Routing" and
+"Device Bonding" at the same time with the same devices. If you use either
+of these methods, it is necessary that your devices are always created in the
+same sequence when the drivers are loaded. You may need to configure some
+proper "udev" rules to make sure this happens.
+
 Running VDR with DVB-C (cable) or DVB-T (terrestrial):
 ------------------------------------------------------
 
diff -ruN vdr-1.7.21/MANUAL vdr-1.7.22/MANUAL
--- vdr-1.7.21/MANUAL	2011-08-15 12:46:20.000000000 +0200
+++ vdr-1.7.22/MANUAL	2011-12-03 16:31:50.000000000 +0100
@@ -732,12 +732,18 @@
 
   LNB:
 
+  Use DiSEqC = no        Generally turns DiSEqC support on or off.
+
   SLOF               = 11700  The switching frequency (in MHz) between low and
                               high LOF
   Low LNB frequency  =  9750  The LNB's low and high local oscillator frequencies
   High LNB frequency = 10600  (in MHz, these have no meaning for DVB-C receivers)
 
-  Use DiSEqC = no        Generally turns DiSEqC support on or off.
+  Device n connected to sat cable = own
+                         Defines whether DVB-S device n has its own satellite cable,
+                         or is "bonded" with another device. All DVB-S devices that
+                         are connected to the same sat cable must be set to the same
+                         number here.
 
   CAM:
 
diff -ruN vdr-1.7.21/Make.config.template vdr-1.7.22/Make.config.template
--- vdr-1.7.21/Make.config.template	2011-03-13 14:41:12.000000000 +0100
+++ vdr-1.7.22/Make.config.template	2011-12-04 15:41:00.000000000 +0100
@@ -6,7 +6,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Make.config.template 2.3 2011/03/13 13:41:12 kls Exp $
+# $Id: Make.config.template 2.4 2011/12/04 14:41:00 kls Exp $
 
 ### The C compiler and options:
 
@@ -35,7 +35,7 @@
 
 ### The remote control:
 
-LIRC_DEVICE = /dev/lircd
+LIRC_DEVICE = /var/run/lirc/lircd
 RCU_DEVICE  = /dev/ttyS1
 
 ## Define if you want vdr to not run as root
diff -ruN vdr-1.7.21/Makefile vdr-1.7.22/Makefile
--- vdr-1.7.21/Makefile	2011-05-21 14:21:40.000000000 +0200
+++ vdr-1.7.22/Makefile	2011-12-04 15:41:00.000000000 +0100
@@ -4,7 +4,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Makefile 2.18 2011/05/21 12:21:40 kls Exp $
+# $Id: Makefile 2.22 2011/12/04 14:41:00 kls Exp $
 
 .DELETE_ON_ERROR:
 
@@ -33,6 +33,8 @@
 DOXYGEN  = /usr/bin/doxygen
 DOXYFILE = Doxyfile
 
+PCDIR   ?= $(firstword $(subst :, , ${PKG_CONFIG_PATH}:$(shell pkg-config --variable=pc_path pkg-config):$(PREFIX)/lib/pkgconfig))
+
 include Make.global
 -include Make.config
 
@@ -60,7 +62,7 @@
 LIBS += $(shell pkg-config --libs fribidi)
 endif
 
-LIRC_DEVICE ?= /dev/lircd
+LIRC_DEVICE ?= /var/run/lirc/lircd
 RCU_DEVICE  ?= /dev/ttyS1
 
 DEFINES += -DLIRC_DEVICE=\"$(LIRC_DEVICE)\" -DRCU_DEVICE=\"$(RCU_DEVICE)\"
@@ -77,7 +79,7 @@
 VDRVERSION = $(shell sed -ne '/define VDRVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h)
 APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h)
 
-all: vdr i18n
+all: vdr i18n vdr.pc
 
 # Implicit rules:
 
@@ -103,6 +105,25 @@
 $(SILIB):
 	$(MAKE) -C $(LSIDIR) all
 
+# pkg-config file:
+
+vdr.pc: Makefile Make.global
+	@echo "bindir=$(BINDIR)" > $@
+	@echo "includedir=$(INCDIR)" >> $@
+	@echo "configdir=$(CONFDIR)" >> $@
+	@echo "videodir=$(VIDEODIR)" >> $@
+	@echo "plugindir=$(PLUGINLIBDIR)" >> $@
+	@echo "localedir=$(LOCDIR)" >> $@
+	@echo "apiversion=$(APIVERSION)" >> $@
+	@echo "cflags=$(CXXFLAGS) $(DEFINES) -I\$${includedir}" >> $@
+	@echo "plugincflags=\$${cflags} -fPIC" >> $@
+	@echo "" >> $@
+	@echo "Name: VDR" >> $@
+	@echo "Description: Video Disk Recorder" >> $@
+	@echo "URL: http://www.tvdr.de/" >> $@
+	@echo "Version: $(VDRVERSION)" >> $@
+	@echo "Cflags: \$${cflags}" >> $@
+
 # Internationalization (I18N):
 
 PODIR     = po
@@ -163,13 +184,13 @@
 
 # Install the files:
 
-install: install-bin install-conf install-doc install-plugins install-i18n install-includes
+install: install-bin install-conf install-doc install-plugins install-i18n install-includes install-pc
 
 # VDR binary:
 
 install-bin: vdr
 	@mkdir -p $(DESTDIR)$(BINDIR)
-	@cp --remove-destination vdr svdrpsend.pl $(DESTDIR)$(BINDIR)
+	@cp --remove-destination vdr svdrpsend $(DESTDIR)$(BINDIR)
 
 # Configuration files:
 
@@ -200,6 +221,14 @@
 	@mkdir -p $(DESTDIR)$(INCDIR)
 	@cp -pLR include/vdr include/libsi $(DESTDIR)$(INCDIR)
 
+# pkg-config file:
+
+install-pc: vdr.pc
+	if [ -n "$(PCDIR)" ] ; then \
+	    mkdir -p $(DESTDIR)$(PCDIR) ; \
+	    cp vdr.pc $(DESTDIR)$(PCDIR) ; \
+	    fi
+
 # Source documentation:
 
 srcdoc:
@@ -212,7 +241,7 @@
 
 clean:
 	$(MAKE) -C $(LSIDIR) clean
-	-rm -f $(OBJS) $(DEPFILE) vdr core* *~
+	-rm -f $(OBJS) $(DEPFILE) vdr vdr.pc core* *~
 	-rm -rf $(LOCALEDIR) $(PODIR)/*.mo $(PODIR)/*.pot
 	-rm -rf include
 	-rm -rf srcdoc
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/Makefile vdr-1.7.22/PLUGINS/src/dvbhddevice/Makefile
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/Makefile	2011-05-21 14:25:33.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/Makefile	2011-12-04 16:30:21.000000000 +0100
@@ -1,7 +1,7 @@
 #
 # Makefile for a Video Disk Recorder plugin
 #
-# $Id: Makefile 1.8 2011/05/21 12:25:33 kls Exp $
+# $Id: Makefile 1.9 2011/12/04 15:30:21 kls Exp $
 
 # The official name of this plugin.
 # This name will be used in the '-P...' option of VDR to load the plugin.
@@ -98,8 +98,9 @@
 
 ### Targets:
 
-libvdr-$(PLUGIN).so: $(OBJS)
-	$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+libvdr-$(PLUGIN).so: $(OBJS) libhdffcmd
+	$(MAKE) -C libhdffcmd all
+	$(CXX) $(CXXFLAGS) -shared $(OBJS) libhdffcmd/libhdffcmd.a -o $@
 	@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
 
 dist: $(I18Npo) clean
@@ -112,3 +113,4 @@
 
 clean:
 	@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
+	$(MAKE) -C libhdffcmd clean
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/dvbhdffdevice.c vdr-1.7.22/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/dvbhdffdevice.c	2011-08-27 11:32:18.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/dvbhdffdevice.c	2011-12-04 16:30:42.000000000 +0100
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: dvbhdffdevice.c 1.33 2011/08/27 09:32:18 kls Exp $
+ * $Id: dvbhdffdevice.c 1.35 2011/12/04 15:30:42 kls Exp $
  */
 
 #include "dvbhdffdevice.h"
@@ -47,18 +47,18 @@
      isHdffPrimary = true;
      mHdffCmdIf = new HDFF::cHdffCmdIf(fd_osd);
      mHdffCmdIf->CmdAvSetAudioDelay(gHdffSetup.AudioDelay);
-     mHdffCmdIf->CmdAvSetAudioDownmix((HDFF::eDownmixMode) gHdffSetup.AudioDownmix);
-     mHdffCmdIf->CmdMuxSetVideoOut((HDFF::eVideoOut) gHdffSetup.AnalogueVideo);
+     mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) gHdffSetup.AudioDownmix);
+     mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) gHdffSetup.AnalogueVideo);
      mHdffCmdIf->CmdHdmiSetVideoMode(gHdffSetup.GetVideoMode());
-     HDFF::tHdmiConfig hdmiConfig;
+     HdffHdmiConfig_t hdmiConfig;
      hdmiConfig.TransmitAudio = true;
      hdmiConfig.ForceDviMode = false;
      hdmiConfig.CecEnabled = gHdffSetup.CecEnabled;
-     hdmiConfig.VideoModeAdaption = (HDFF::eVideoModeAdaption) gHdffSetup.VideoModeAdaption;
+     hdmiConfig.VideoModeAdaption = (HdffVideoModeAdaption_t) gHdffSetup.VideoModeAdaption;
      mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
      if (gHdffSetup.CecEnabled)
-        mHdffCmdIf->CmdHdmiSendCecCommand(HDFF::cecCommandTvOn);
-     mHdffCmdIf->CmdRemoteSetProtocol((HDFF::eRemoteProtocol) gHdffSetup.RemoteProtocol);
+        mHdffCmdIf->CmdHdmiSendCecCommand(HDFF_CEC_COMMAND_TV_ON);
+     mHdffCmdIf->CmdRemoteSetProtocol((HdffRemoteProtocol_t) gHdffSetup.RemoteProtocol);
      mHdffCmdIf->CmdRemoteSetAddressFilter(gHdffSetup.RemoteAddress >= 0, gHdffSetup.RemoteAddress);
      }
 
@@ -109,11 +109,11 @@
 
 void cDvbHdFfDevice::SetVideoFormat(bool VideoFormat16_9)
 {
-  HDFF::tVideoFormat videoFormat;
+  HdffVideoFormat_t videoFormat;
   videoFormat.AutomaticEnabled = true;
   videoFormat.AfdEnabled = true;
-  videoFormat.TvFormat = (HDFF::eTvFormat) gHdffSetup.TvFormat;
-  videoFormat.VideoConversion = (HDFF::eVideoConversion) gHdffSetup.VideoConversion;
+  videoFormat.TvFormat = (HdffTvFormat_t) gHdffSetup.TvFormat;
+  videoFormat.VideoConversion = (HdffVideoConversion_t) gHdffSetup.VideoConversion;
   mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
 }
 
@@ -184,14 +184,14 @@
            mHdffCmdIf->CmdAvSetPcrPid(0, Handle->pid);
         else if (Type == ptVideo) {
            if (Handle->streamType == 0x1B)
-              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF::videoStreamH264);
+              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_H264);
            else
-              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF::videoStreamMpeg2);
+              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_MPEG2);
            }
         else if (Type == ptAudio)
-           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF::audioStreamMpeg1);
+           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1);
         else if (Type == ptDolby)
-           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF::audioStreamAc3);
+           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AC3);
         if (!(Type <= ptDolby && Handle->used <= 1)) {
            pesFilterParams.pid     = Handle->pid;
            pesFilterParams.input   = DMX_IN_FRONTEND;
@@ -209,11 +209,11 @@
         if (Type == ptPcr)
            mHdffCmdIf->CmdAvSetPcrPid(0, 0);
         else if (Type == ptVideo)
-           mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg2);
+           mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
         else if (Type == ptAudio)
-           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
         else if (Type == ptDolby)
-           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamAc3);
+           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_AC3);
         //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid()
         close(Handle->handle);
         Handle->handle = -1;
@@ -351,10 +351,13 @@
 bool cDvbHdFfDevice::SetPlayMode(ePlayMode PlayMode)
 {
   if (PlayMode == pmNone) {
+     mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+     mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
+
      mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
      mHdffCmdIf->CmdAvSetPcrPid(0, 0);
-     mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg2);
-     mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+     mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
+     mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
 
      ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
      mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
@@ -374,6 +377,8 @@
      playAudioPid = -1;
      audioCounter = 0;
      videoCounter = 0;
+     freezed = false;
+     trickMode = false;
 
      mHdffCmdIf->CmdAvSetDecoderInput(0, 2);
      ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
@@ -405,18 +410,20 @@
 
 void cDvbHdFfDevice::TrickSpeed(int Speed)
 {
+  freezed = false;
   mHdffCmdIf->CmdAvEnableSync(0, false);
-  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
   playAudioPid = -1;
   if (Speed > 0)
      mHdffCmdIf->CmdAvSetVideoSpeed(0, 100 / Speed);
+  trickMode = true;
 }
 
 void cDvbHdFfDevice::Clear(void)
 {
   CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
-  mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg1);
-  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+  mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
   playVideoPid = -1;
   playAudioPid = -1;
   cDevice::Clear();
@@ -424,6 +431,8 @@
 
 void cDvbHdFfDevice::Play(void)
 {
+  freezed = false;
+  trickMode = false;
   mHdffCmdIf->CmdAvEnableSync(0, true);
   mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
   mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
@@ -432,6 +441,7 @@
 
 void cDvbHdFfDevice::Freeze(void)
 {
+  freezed = true;
   mHdffCmdIf->CmdAvSetVideoSpeed(0, 0);
   mHdffCmdIf->CmdAvSetAudioSpeed(0, 0);
   cDevice::Freeze();
@@ -443,13 +453,13 @@
   cDevice::Mute();
 }
 
-static HDFF::eVideoStreamType MapVideoStreamTypes(int Vtype)
+static HdffVideoStreamType_t MapVideoStreamTypes(int Vtype)
 {
   switch (Vtype) {
-    case 0x01: return HDFF::videoStreamMpeg1;
-    case 0x02: return HDFF::videoStreamMpeg2;
-    case 0x1B: return HDFF::videoStreamH264;
-    default: return HDFF::videoStreamMpeg2; // fallback to MPEG2
+    case 0x01: return HDFF_VIDEO_STREAM_MPEG1;
+    case 0x02: return HDFF_VIDEO_STREAM_MPEG2;
+    case 0x1B: return HDFF_VIDEO_STREAM_H264;
+    default: return HDFF_VIDEO_STREAM_MPEG2; // fallback to MPEG2
     }
 }
 
@@ -594,6 +604,8 @@
 
 int cDvbHdFfDevice::PlayVideo(const uchar *Data, int Length)
 {
+    if (freezed)
+        return -1;
     //TODO: support greater Length
     uint8_t tsBuffer[188 * 16];
     uint32_t tsLength;
@@ -603,7 +615,7 @@
 
     if (pid != playVideoPid) {
         playVideoPid = pid;
-        mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, HDFF::videoStreamMpeg2, true);
+        mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, HDFF_VIDEO_STREAM_MPEG2, true);
     }
     if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
         Length = 0;
@@ -612,39 +624,43 @@
 
 int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
 {
+    if (freezed)
+        return -1;
+    if (trickMode)
+        return Length;
     uint8_t streamId;
     uint8_t tsBuffer[188 * 16];
     uint32_t tsLength;
-    HDFF::eAudioStreamType streamType = HDFF::audioStreamMpeg1;
-    HDFF::eAVContainerType containerType = HDFF::avContainerPes;
+    HdffAudioStreamType_t streamType = HDFF_AUDIO_STREAM_MPEG1;
+    HdffAvContainerType_t containerType = HDFF_AV_CONTAINER_PES;
     int pid;
 
     streamId = Data[3];
     if (streamId >= 0xC0 && streamId <= 0xDF)
     {
-        streamType = HDFF::audioStreamMpeg1;
+        streamType = HDFF_AUDIO_STREAM_MPEG1;
     }
     else if (streamId == 0xBD)
     {
         const uint8_t * payload = Data + 9 + Data[8];
         if ((payload[0] & 0xF8) == 0xA0)
         {
-            containerType = HDFF::avContainerPesDvd;
-            streamType = HDFF::audioStreamPcm;
+            containerType = HDFF_AV_CONTAINER_PES_DVD;
+            streamType = HDFF_AUDIO_STREAM_PCM;
         }
         else if ((payload[0] & 0xF8) == 0x88)
         {
-            containerType = HDFF::avContainerPesDvd;
-            streamType = HDFF::audioStreamDts;
+            containerType = HDFF_AV_CONTAINER_PES_DVD;
+            streamType = HDFF_AUDIO_STREAM_DTS;
         }
         else if ((payload[0] & 0xF8) == 0x80)
         {
-            containerType = HDFF::avContainerPesDvd;
-            streamType = HDFF::audioStreamAc3;
+            containerType = HDFF_AV_CONTAINER_PES_DVD;
+            streamType = HDFF_AUDIO_STREAM_AC3;
         }
         else
         {
-            streamType = HDFF::audioStreamAc3;
+            streamType = HDFF_AUDIO_STREAM_AC3;
         }
     }
     pid = 200 + (int) streamType;
@@ -661,6 +677,8 @@
 
 int cDvbHdFfDevice::PlayTsVideo(const uchar *Data, int Length)
 {
+  if (freezed)
+    return -1;
   int pid = TsPid(Data);
   if (pid != playVideoPid) {
      PatPmtParser();
@@ -672,21 +690,25 @@
   return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
 }
 
-static HDFF::eAudioStreamType MapAudioStreamTypes(int Atype)
+static HdffAudioStreamType_t MapAudioStreamTypes(int Atype)
 {
   switch (Atype) {
-    case 0x03: return HDFF::audioStreamMpeg1;
-    case 0x04: return HDFF::audioStreamMpeg2;
-    case SI::AC3DescriptorTag: return HDFF::audioStreamAc3;
-    case SI::EnhancedAC3DescriptorTag: return HDFF::audioStreamEAc3;
-    case 0x0F: return HDFF::audioStreamAac;
-    case 0x11: return HDFF::audioStreamHeAac;
-    default: return HDFF::audioStreamMaxValue; // there is no HDFF::audioStreamNone
+    case 0x03: return HDFF_AUDIO_STREAM_MPEG1;
+    case 0x04: return HDFF_AUDIO_STREAM_MPEG2;
+    case SI::AC3DescriptorTag: return HDFF_AUDIO_STREAM_AC3;
+    case SI::EnhancedAC3DescriptorTag: return HDFF_AUDIO_STREAM_EAC3;
+    case 0x0F: return HDFF_AUDIO_STREAM_AAC;
+    case 0x11: return HDFF_AUDIO_STREAM_HE_AAC;
+    default: return HDFF_AUDIO_STREAM_MPEG1;
     }
 }
 
 int cDvbHdFfDevice::PlayTsAudio(const uchar *Data, int Length)
 {
+  if (freezed)
+    return -1;
+  if (trickMode)
+    return Length;
   int pid = TsPid(Data);
   if (pid != playAudioPid) {
      playAudioPid = pid;
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/dvbhdffdevice.h vdr-1.7.22/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/dvbhdffdevice.h	2010-03-13 12:18:13.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/dvbhdffdevice.h	2011-09-10 12:17:32.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: dvbhdffdevice.h 1.6 2010/03/13 11:18:13 kls Exp $
+ * $Id: dvbhdffdevice.h 1.7 2011/09/10 10:17:32 kls Exp $
  */
 
 #ifndef __DVBHDFFDEVICE_H
@@ -79,6 +79,8 @@
 private:
   int playVideoPid;
   int playAudioPid;
+  bool freezed;
+  bool trickMode;
 
   // Pes2Ts conversion stuff
   uint8_t videoCounter;
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/hdffcmd.c vdr-1.7.22/PLUGINS/src/dvbhddevice/hdffcmd.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/hdffcmd.c	2011-08-27 11:34:18.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/hdffcmd.c	2011-12-04 16:31:03.000000000 +0100
@@ -3,34 +3,15 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: hdffcmd.c 1.21 2011/08/27 09:34:18 kls Exp $
+ * $Id: hdffcmd.c 1.22 2011/12/04 15:31:03 kls Exp $
  */
 
 #include "hdffcmd.h"
-#include <linux/dvb/osd.h>
+#include "libhdffcmd/hdffcmd.h"
 #include <stdio.h>
 #include <string.h>
-#include <sys/ioctl.h>
 #include <vdr/tools.h>
 
-#if !defined OSD_RAW_CMD
-typedef struct osd_raw_cmd_s {
-    const void *cmd_data;
-    int cmd_len;
-    void *result_data;
-    int result_len;
-} osd_raw_cmd_t;
-
-typedef struct osd_raw_data_s {
-    const void *data_buffer;
-    int data_length;
-    int data_handle;
-} osd_raw_data_t;
-
-#define OSD_RAW_CMD            _IOWR('o', 162, osd_raw_cmd_t)
-#define OSD_RAW_DATA           _IOWR('o', 163, osd_raw_data_t)
-#endif
-
 
 namespace HDFF
 {
@@ -48,1093 +29,347 @@
 {
 }
 
-void cHdffCmdIf::CmdBuildHeader(cBitBuffer & MsgBuf, eMessageType MsgType, eMessageGroup MsgGroup, eMessageId MsgId)
-{
-    MsgBuf.SetBits(16, 0); // length field will be set later
-    MsgBuf.SetBits(6, 0); // reserved
-    MsgBuf.SetBits(2, MsgType);
-    MsgBuf.SetBits(8, MsgGroup);
-    MsgBuf.SetBits(16, MsgId);
-}
-
-uint32_t cHdffCmdIf::CmdSetLength(cBitBuffer & MsgBuf)
-{
-    uint32_t length;
-
-    length = MsgBuf.GetByteLength() - 2;
-    MsgBuf.SetDataByte(0, (uint8_t) (length >> 8));
-    MsgBuf.SetDataByte(1, (uint8_t) length);
-
-    return length + 2;
-}
-
 
 uint32_t cHdffCmdIf::CmdGetFirmwareVersion(char * pString, uint32_t MaxLength)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    cBitBuffer resBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    osd_cmd.result_data = resBuf.GetData();
-    osd_cmd.result_len = resBuf.GetMaxLength();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupGeneric, msgGenGetFirmwareVersion);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-    if (osd_cmd.result_len > 0)
-    {
-        uint8_t * result = resBuf.GetData();
-        uint8_t textLength = result[9];
-        if (textLength >= MaxLength)
-            textLength = MaxLength - 1;
-        memcpy(pString, &result[10], textLength);
-        pString[textLength] = 0;
-        return (result[6] << 16) | (result[7] << 8) | result[8];
-    }
+    uint32_t version;
+    int err;
+
+    err = HdffCmdGetFirmwareVersion(mOsdDev, &version, pString, MaxLength);
+    if (err == 0)
+        return version;
     return 0;
 }
 
 uint32_t cHdffCmdIf::CmdGetInterfaceVersion(char * pString, uint32_t MaxLength)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    cBitBuffer resBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    osd_cmd.result_data = resBuf.GetData();
-    osd_cmd.result_len = resBuf.GetMaxLength();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupGeneric, msgGenGetInterfaceVersion);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-    if (osd_cmd.result_len > 0)
-    {
-        uint8_t * result = resBuf.GetData();
-        uint8_t textLength = result[9];
-        if (textLength >= MaxLength)
-            textLength = MaxLength - 1;
-        memcpy(pString, &result[10], textLength);
-        pString[textLength] = 0;
-        return (result[6] << 16) | (result[7] << 8) | result[8];
-    }
+    uint32_t version;
+    int err;
+
+    err = HdffCmdGetInterfaceVersion(mOsdDev, &version, pString, MaxLength);
+    if (err == 0)
+        return version;
     return 0;
 }
 
 uint32_t cHdffCmdIf::CmdGetCopyrights(uint8_t Index, char * pString, uint32_t MaxLength)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    cBitBuffer resBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    osd_cmd.result_data = resBuf.GetData();
-    osd_cmd.result_len = resBuf.GetMaxLength();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupGeneric, msgGenGetCopyrights);
-    cmdBuf.SetBits(8, Index);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-    if (osd_cmd.result_len > 0)
-    {
-        uint8_t * result = resBuf.GetData();
-        uint8_t index = result[6];
-        uint8_t textLen = result[7];
-        if (index == Index && textLen > 0)
-        {
-            if (textLen >= MaxLength)
-            {
-                textLen = MaxLength - 1;
-            }
-            memcpy(pString, result + 8, textLen);
-            pString[textLen] = 0;
-            return textLen;
-        }
-    }
+    int err;
+
+    err = HdffCmdGetCopyrights(mOsdDev, Index, pString, MaxLength);
+    if (err == 0)
+        return strlen(pString);
     return 0;
 }
 
 
 void cHdffCmdIf::CmdAvSetPlayMode(uint8_t PlayMode, bool Realtime)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetPlayMode);
-    cmdBuf.SetBits(1, Realtime ? 1 : 0);
-    cmdBuf.SetBits(7, PlayMode);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetPlayMode(mOsdDev, PlayMode, Realtime);
 }
 
-void cHdffCmdIf::CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, eVideoStreamType StreamType, bool PlaybackMode)
+void cHdffCmdIf::CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, HdffVideoStreamType_t StreamType, bool PlaybackMode)
 {
     //printf("SetVideoPid %d %d\n", VideoPid, StreamType);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoPid);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, StreamType);
-    cmdBuf.SetBits(1, PlaybackMode ? 1 : 0);
-    cmdBuf.SetBits(15, VideoPid);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetVideoPid(mOsdDev, DecoderIndex, VideoPid, StreamType);
 }
 
-void cHdffCmdIf::CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, eAudioStreamType StreamType, eAVContainerType ContainerType)
+void cHdffCmdIf::CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, HdffAudioStreamType_t StreamType, HdffAvContainerType_t ContainerType)
 {
     //printf("SetAudioPid %d %d %d\n", AudioPid, StreamType, ContainerType);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioPid);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, StreamType);
-    cmdBuf.SetBits(2, 0); // reserved
-    cmdBuf.SetBits(1, ContainerType);
-    cmdBuf.SetBits(13, AudioPid);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetAudioPid(mOsdDev, DecoderIndex, AudioPid, StreamType,
+                         ContainerType);
 }
 
 void cHdffCmdIf::CmdAvSetPcrPid(uint8_t DecoderIndex, uint16_t PcrPid)
 {
     //printf("SetPcrPid %d\n", PcrPid);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetPcrPid);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, 0); // reserved
-    cmdBuf.SetBits(16, PcrPid);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetPcrPid(mOsdDev, DecoderIndex, PcrPid);
 }
 
 void cHdffCmdIf::CmdAvSetTeletextPid(uint8_t DecoderIndex, uint16_t TeletextPid)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetTeletextPid);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, 0); // reserved
-    cmdBuf.SetBits(16, TeletextPid);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetTeletextPid(mOsdDev, DecoderIndex, TeletextPid);
 }
 
 void cHdffCmdIf::CmdAvSetVideoWindow(uint8_t DecoderIndex, bool Enable, uint16_t X, uint16_t Y, uint16_t Width, uint16_t Height)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
+    HdffCmdAvSetVideoWindow(mOsdDev, DecoderIndex, Enable, X, Y, Width, Height);
+}
 
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoWindow);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(3, 0); // reserved
-    if (Enable)
-        cmdBuf.SetBits(1, 1);
-    else
-        cmdBuf.SetBits(1, 0);
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(16, Width);
-    cmdBuf.SetBits(16, Height);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-}
-
-void cHdffCmdIf::CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, eVideoStreamType StreamType)
-{
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-    osd_raw_data_t osd_data;
-
-    memset(&osd_data, 0, sizeof(osd_raw_data_t));
-    osd_data.data_buffer = (void *) pStillImage;
-    osd_data.data_length = Size;
-    ioctl(mOsdDev, OSD_RAW_DATA, &osd_data);
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvShowStillImage);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, StreamType);
-    cmdBuf.SetBits(16, osd_data.data_handle);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+void cHdffCmdIf::CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, HdffVideoStreamType_t StreamType)
+{
+    HdffCmdAvShowStillImage(mOsdDev, DecoderIndex, pStillImage, Size,
+                            StreamType);
 }
 
 void cHdffCmdIf::CmdAvSetDecoderInput(uint8_t DecoderIndex, uint8_t DemultiplexerIndex)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetDecoderInput);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, DemultiplexerIndex);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetDecoderInput(mOsdDev, DecoderIndex, DemultiplexerIndex);
 }
 
 void cHdffCmdIf::CmdAvSetDemultiplexerInput(uint8_t DemultiplexerIndex, uint8_t TsInputIndex)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
+    HdffCmdAvSetDemultiplexerInput(mOsdDev, DemultiplexerIndex, TsInputIndex);
+}
 
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetDemultiplexerInput);
-    cmdBuf.SetBits(4, DemultiplexerIndex);
-    cmdBuf.SetBits(4, TsInputIndex);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-}
-
-void cHdffCmdIf::CmdAvSetVideoFormat(uint8_t DecoderIndex, const tVideoFormat * pVideoFormat)
-{
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoFormat);
-    cmdBuf.SetBits(4, DecoderIndex);
-    if (pVideoFormat->AutomaticEnabled)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    if (pVideoFormat->AfdEnabled)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    cmdBuf.SetBits(2, pVideoFormat->TvFormat);
-    cmdBuf.SetBits(8, pVideoFormat->VideoConversion);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-}
-
-void cHdffCmdIf::CmdAvSetVideoOutputMode(uint8_t DecoderIndex, eVideoOutputMode OutputMode)
-{
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoOutputMode);
-    cmdBuf.SetBits(8, OutputMode);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+void cHdffCmdIf::CmdAvSetVideoFormat(uint8_t DecoderIndex, const HdffVideoFormat_t * pVideoFormat)
+{
+    HdffCmdAvSetVideoFormat(mOsdDev, DecoderIndex, pVideoFormat);
 }
 
-void cHdffCmdIf::CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc)
+void cHdffCmdIf::CmdAvSetVideoOutputMode(uint8_t DecoderIndex, HdffVideoOutputMode_t OutputMode)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
+    HdffCmdAvSetVideoOutputMode(mOsdDev, DecoderIndex, OutputMode);
+}
 
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetStc);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(3, 0); // reserved
-    cmdBuf.SetBits(1, (uint32_t) (Stc >> 32));
-    cmdBuf.SetBits(32, (uint32_t) Stc);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+void cHdffCmdIf::CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc)
+{
+    HdffCmdAvSetStc(mOsdDev, DecoderIndex, Stc);
 }
 
 void cHdffCmdIf::CmdAvFlushBuffer(uint8_t DecoderIndex, bool FlushAudio, bool FlushVideo)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvFlushBuffer);
-    cmdBuf.SetBits(4, DecoderIndex);
-    if (FlushAudio)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    if (FlushVideo)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvFlushBuffer(mOsdDev, DecoderIndex, FlushAudio, FlushVideo);
 }
 
 void cHdffCmdIf::CmdAvEnableSync(uint8_t DecoderIndex, bool EnableSync)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvEnableSync);
-    cmdBuf.SetBits(4, DecoderIndex);
-    if (EnableSync)
-    {
-        cmdBuf.SetBits(1, 1);
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-        cmdBuf.SetBits(1, 0);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvEnableSync(mOsdDev, DecoderIndex, EnableSync, EnableSync);
 }
 
 void cHdffCmdIf::CmdAvSetVideoSpeed(uint8_t DecoderIndex, int32_t Speed)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoSpeed);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, 0);
-    cmdBuf.SetBits(32, Speed);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetVideoSpeed(mOsdDev, DecoderIndex, Speed);
 }
 
 void cHdffCmdIf::CmdAvSetAudioSpeed(uint8_t DecoderIndex, int32_t Speed)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioSpeed);
-    cmdBuf.SetBits(4, DecoderIndex);
-    cmdBuf.SetBits(4, 0);
-    cmdBuf.SetBits(32, Speed);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetAudioSpeed(mOsdDev, DecoderIndex, Speed);
 }
 
 void cHdffCmdIf::CmdAvEnableVideoAfterStop(uint8_t DecoderIndex, bool EnableVideoAfterStop)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvEnableVideoAfterStop);
-    cmdBuf.SetBits(4, DecoderIndex);
-    if (EnableVideoAfterStop)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvEnableVideoAfterStop(mOsdDev, DecoderIndex, EnableVideoAfterStop);
 }
 
 void cHdffCmdIf::CmdAvSetAudioDelay(int16_t Delay)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
+    HdffCmdAvSetAudioDelay(mOsdDev, Delay);
+}
 
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioDelay);
-    cmdBuf.SetBits(16, Delay);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-}
-
-void cHdffCmdIf::CmdAvSetAudioDownmix(eDownmixMode DownmixMode)
-{
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioDownmix);
-    cmdBuf.SetBits(8, DownmixMode);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+void cHdffCmdIf::CmdAvSetAudioDownmix(HdffAudioDownmixMode_t DownmixMode)
+{
+    HdffCmdAvSetAudioDownmix(mOsdDev, DownmixMode);
 }
 
 void cHdffCmdIf::CmdAvSetAudioChannel(uint8_t AudioChannel)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioChannel);
-    cmdBuf.SetBits(8, AudioChannel);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdAvSetAudioChannel(mOsdDev, AudioChannel);
 }
 
 
-void cHdffCmdIf::CmdOsdConfigure(const tOsdConfig * pConfig)
+void cHdffCmdIf::CmdOsdConfigure(const HdffOsdConfig_t * pConfig)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdConfigure);
-    if (pConfig->FontAntialiasing)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    if (pConfig->FontKerning)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdConfigure(mOsdDev, pConfig);
 }
 
 void cHdffCmdIf::CmdOsdReset(void)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdReset);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdReset(mOsdDev);
 }
 
-uint32_t cHdffCmdIf::CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, eColorType ColorType)
+uint32_t cHdffCmdIf::CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, HdffColorType_t ColorType)
 {
     //printf("CreateDisplay %d %d %d\n", Width, Height, ColorType);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    cBitBuffer resBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    osd_cmd.result_data = resBuf.GetData();
-    osd_cmd.result_len = resBuf.GetMaxLength();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreateDisplay);
-    cmdBuf.SetBits(16, Width);
-    cmdBuf.SetBits(16, Height);
-    cmdBuf.SetBits(8, ColorType);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-    if (osd_cmd.result_len > 0)
-    {
-        uint8_t * result = resBuf.GetData();
-        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
-    }
-    return InvalidHandle;
+    uint32_t newDisplay;
+
+    if (HdffCmdOsdCreateDisplay(mOsdDev, Width, Height, ColorType, &newDisplay) == 0)
+        return newDisplay;
+    return HDFF_INVALID_HANDLE;
 }
 
 void cHdffCmdIf::CmdOsdDeleteDisplay(uint32_t hDisplay)
 {
     //printf("DeleteDisplay\n");
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeleteDisplay);
-    cmdBuf.SetBits(32, hDisplay);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDeleteDisplay(mOsdDev, hDisplay);
 }
 
 void cHdffCmdIf::CmdOsdEnableDisplay(uint32_t hDisplay, bool Enable)
 {
     //printf("EnableDisplay\n");
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdEnableDisplay);
-    cmdBuf.SetBits(32, hDisplay);
-    if (Enable)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    cmdBuf.SetBits(7, 0); // reserved
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdEnableDisplay(mOsdDev, hDisplay, Enable);
 }
 
 void cHdffCmdIf::CmdOsdSetDisplayOutputRectangle(uint32_t hDisplay, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height)
 {
     //printf("SetOutputRect %d %d %d %d %d\n", hDisplay, X, Y, Width, Height);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetDisplayOutputRectangle);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(16, Width);
-    cmdBuf.SetBits(16, Height);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdSetDisplayOutputRectangle(mOsdDev, hDisplay, X, Y, Width, Height);
 }
 
 void cHdffCmdIf::CmdOsdSetDisplayClippingArea(uint32_t hDisplay, bool Enable, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height)
 {
     //printf("SetClippingArea %d %d %d %d %d %d\n", hDisplay, Enable, X, Y, Width, Height);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetDisplayClippingArea);
-    cmdBuf.SetBits(32, hDisplay);
-    if (Enable)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    cmdBuf.SetBits(7, 0); // reserved
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(16, Width);
-    cmdBuf.SetBits(16, Height);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdSetDisplayClippingArea(mOsdDev, hDisplay, Enable, X, Y, Width, Height);
 }
 
 void cHdffCmdIf::CmdOsdRenderDisplay(uint32_t hDisplay)
 {
     //printf("Render\n");
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdRenderDisplay);
-    cmdBuf.SetBits(32, hDisplay);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdRenderDisplay(mOsdDev, hDisplay);
 }
 
-uint32_t cHdffCmdIf::CmdOsdCreatePalette(eColorType ColorType, eColorFormat ColorFormat,
+uint32_t cHdffCmdIf::CmdOsdCreatePalette(HdffColorType_t ColorType, HdffColorFormat_t ColorFormat,
                                          uint32_t NumColors, const uint32_t * pColors)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    cBitBuffer resBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-    uint32_t i;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    osd_cmd.result_data = resBuf.GetData();
-    osd_cmd.result_len = resBuf.GetMaxLength();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreatePalette);
-    cmdBuf.SetBits(8, ColorType);
-    cmdBuf.SetBits(8, ColorFormat);
-    if (NumColors > 256)
-        NumColors = 256;
-    cmdBuf.SetBits(8, NumColors == 256 ? 0 : NumColors);
-    for (i = 0; i < NumColors; i++)
-    {
-        cmdBuf.SetBits(32, pColors[i]);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-    if (osd_cmd.result_len > 0)
-    {
-        uint8_t * result = resBuf.GetData();
-        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
-    }
-    return InvalidHandle;
+    uint32_t newPalette;
+    int err;
+
+    err = HdffCmdOsdCreatePalette(mOsdDev, ColorType, ColorFormat, NumColors,
+                                  pColors, &newPalette);
+    if (err == 0)
+        return newPalette;
+    return HDFF_INVALID_HANDLE;
 }
 
 void cHdffCmdIf::CmdOsdDeletePalette(uint32_t hPalette)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeletePalette);
-    cmdBuf.SetBits(32, hPalette);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDeletePalette(mOsdDev, hPalette);
 }
 
 void cHdffCmdIf::CmdOsdSetDisplayPalette(uint32_t hDisplay, uint32_t hPalette)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetDisplayPalette);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(32, hPalette);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdSetDisplayPalette(mOsdDev, hDisplay, hPalette);
 }
 
-void cHdffCmdIf::CmdOsdSetPaletteColors(uint32_t hPalette, eColorFormat ColorFormat,
+void cHdffCmdIf::CmdOsdSetPaletteColors(uint32_t hPalette, HdffColorFormat_t ColorFormat,
                                         uint8_t StartColor, uint32_t NumColors, const uint32_t * pColors)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-    uint32_t i;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetPaletteColors);
-    cmdBuf.SetBits(32, hPalette);
-    cmdBuf.SetBits(8, ColorFormat);
-    cmdBuf.SetBits(8, StartColor);
-    if (NumColors > 256)
-        NumColors = 256;
-    cmdBuf.SetBits(8, NumColors == 256 ? 0 : NumColors);
-    for (i = 0; i < NumColors; i++)
-    {
-        cmdBuf.SetBits(32, pColors[i]);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdSetPaletteColors(mOsdDev, hPalette, ColorFormat, StartColor,
+                               NumColors, pColors);
 }
 
 uint32_t cHdffCmdIf::CmdOsdCreateFontFace(const uint8_t * pFontData, uint32_t DataSize)
 {
     //printf("CreateFontFace %d\n", DataSize);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    cBitBuffer resBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-    osd_raw_data_t osd_data;
-
-    memset(&osd_data, 0, sizeof(osd_raw_data_t));
-    osd_data.data_buffer = pFontData;
-    osd_data.data_length = DataSize;
-    ioctl(mOsdDev, OSD_RAW_DATA, &osd_data);
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    osd_cmd.result_data = resBuf.GetData();
-    osd_cmd.result_len = resBuf.GetMaxLength();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreateFontFace);
-    cmdBuf.SetBits(16, osd_data.data_handle);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-    if (osd_cmd.result_len > 0)
-    {
-        uint8_t * result = resBuf.GetData();
-        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
-    }
-    return InvalidHandle;
+    uint32_t newFontFace;
+    int err;
+
+    err = HdffCmdOsdCreateFontFace(mOsdDev, pFontData, DataSize, &newFontFace);
+    if (err == 0)
+        return newFontFace;
+    return HDFF_INVALID_HANDLE;
 }
 
 void cHdffCmdIf::CmdOsdDeleteFontFace(uint32_t hFontFace)
 {
     //printf("DeleteFontFace %08X\n", hFontFace);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeleteFontFace);
-    cmdBuf.SetBits(32, hFontFace);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDeleteFontFace(mOsdDev, hFontFace);
 }
 
 uint32_t cHdffCmdIf::CmdOsdCreateFont(uint32_t hFontFace, uint32_t Size)
 {
     //printf("CreateFont %d\n", Size);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    cBitBuffer resBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    osd_cmd.result_data = resBuf.GetData();
-    osd_cmd.result_len = resBuf.GetMaxLength();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreateFont);
-    cmdBuf.SetBits(32, hFontFace);
-    cmdBuf.SetBits(32, Size);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-    if (osd_cmd.result_len > 0)
-    {
-        uint8_t * result = resBuf.GetData();
-        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
-    }
-    return InvalidHandle;
+    uint32_t newFont;
+    int err;
+
+    err = HdffCmdOsdCreateFont(mOsdDev, hFontFace, Size, &newFont);
+    if (err == 0)
+        return newFont;
+    return HDFF_INVALID_HANDLE;
 }
 
 void cHdffCmdIf::CmdOsdDeleteFont(uint32_t hFont)
 {
     //printf("DeleteFont %08X\n", hFont);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeleteFont);
-    cmdBuf.SetBits(32, hFont);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDeleteFont(mOsdDev, hFont);
 }
 
 void cHdffCmdIf::CmdOsdDrawRectangle(uint32_t hDisplay, int X, int Y, int Width, int Height, uint32_t Color)
 {
     //printf("Rect (%d,%d) %d x %d, %08X\n", X, Y, Width, Height, Color);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawRectangle);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(16, Width);
-    cmdBuf.SetBits(16, Height);
-    cmdBuf.SetBits(32, Color);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDrawRectangle(mOsdDev, hDisplay, X, Y, Width, Height, Color);
 }
 
 void cHdffCmdIf::CmdOsdDrawEllipse(uint32_t hDisplay, int CX, int CY, int RadiusX, int RadiusY,
                                  uint32_t Color, uint32_t Flags)
 {
     //printf("Ellipse (%d,%d) %d x %d, %08X, %d\n", CX, CY, RadiusX, RadiusY, Color, Flags);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawEllipse);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(16, CX);
-    cmdBuf.SetBits(16, CY);
-    cmdBuf.SetBits(16, RadiusX);
-    cmdBuf.SetBits(16, RadiusY);
-    cmdBuf.SetBits(32, Color);
-    cmdBuf.SetBits(32, Flags);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDrawEllipse(mOsdDev, hDisplay, CX, CY, RadiusX, RadiusY, Color, Flags);
 }
 
 void cHdffCmdIf::CmdOsdDrawText(uint32_t hDisplay, uint32_t hFont, int X, int Y, const char * pText, uint32_t Color)
 {
     //printf("Text %08X (%d,%d), %s, %08X\n", hFont, X, Y, pText, Color);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-    int i;
-    int length;
-
-    length = 0;
-    while (pText[length])
-    {
-        length++;
-    }
-    if (length > 980)
-        length = 980;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawText);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(32, hFont);
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(32, Color);
-    cmdBuf.SetBits(16, length);
-    for (i = 0; i < length; i++)
-    {
-        cmdBuf.SetBits(8, pText[i]);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDrawText(mOsdDev, hDisplay, hFont, X, Y, pText, Color);
 }
 
 void cHdffCmdIf::CmdOsdDrawTextW(uint32_t hDisplay, uint32_t hFont, int X, int Y, const uint16_t * pText, uint32_t Color)
 {
     //printf("TextW %08X (%d,%d), %08X\n", hFont, X, Y, Color);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-    int i;
-    int length;
-
-    length = 0;
-    while (pText[length])
-    {
-        length++;
-    }
-    if (length > 480)
-        length = 480;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawTextW);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(32, hFont);
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(32, Color);
-    cmdBuf.SetBits(16, length);
-    for (i = 0; i < length; i++)
-    {
-        cmdBuf.SetBits(16, pText[i]);
-    }
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDrawWideText(mOsdDev, hDisplay, hFont, X, Y, pText, Color);
 }
 
 void cHdffCmdIf::CmdOsdDrawBitmap(uint32_t hDisplay, int X, int Y, const uint8_t * pBitmap,
                                   int BmpWidth, int BmpHeight, int BmpSize,
-                                  eColorType ColorType, uint32_t hPalette)
+                                  HdffColorType_t ColorType, uint32_t hPalette)
 {
     //printf("Bitmap (%d,%d) %d x %d\n", X, Y, BmpWidth, BmpHeight);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-    osd_raw_data_t osd_data;
-
-    memset(&osd_data, 0, sizeof(osd_raw_data_t));
-    osd_data.data_buffer = pBitmap;
-    osd_data.data_length = BmpSize;
-    ioctl(mOsdDev, OSD_RAW_DATA, &osd_data);
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawBitmap);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(16, BmpWidth);
-    cmdBuf.SetBits(16, BmpHeight);
-    cmdBuf.SetBits(8, ColorType);
-    cmdBuf.SetBits(6, 0); // reserved
-    cmdBuf.SetBits(2, 0); // uncompressed
-    cmdBuf.SetBits(32, hPalette);
-    cmdBuf.SetBits(16, osd_data.data_handle);
-    cmdBuf.SetBits(32, 0);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdDrawBitmap(mOsdDev, hDisplay, X, Y, pBitmap, BmpWidth, BmpHeight,
+                         BmpSize, ColorType, hPalette);
 }
 
 void cHdffCmdIf::CmdOsdSaveRegion(uint32_t hDisplay, int X, int Y, int Width, int Height)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSaveRegion);
-    cmdBuf.SetBits(32, hDisplay);
-    cmdBuf.SetBits(16, X);
-    cmdBuf.SetBits(16, Y);
-    cmdBuf.SetBits(16, Width);
-    cmdBuf.SetBits(16, Height);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdOsdSaveRegion(mOsdDev, hDisplay, X, Y, Width, Height);
 }
 
 void cHdffCmdIf::CmdOsdRestoreRegion(uint32_t hDisplay)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
+    HdffCmdOsdRestoreRegion(mOsdDev, hDisplay);
+}
 
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdRestoreRegion);
-    cmdBuf.SetBits(32, hDisplay);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-}
-
-void cHdffCmdIf::CmdMuxSetVideoOut(eVideoOut VideoOut)
-{
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvMux, msgMuxSetVideoOut);
-    cmdBuf.SetBits(4, VideoOut);
-    cmdBuf.SetBits(4, 0); // reserved
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+void cHdffCmdIf::CmdMuxSetVideoOut(HdffVideoOut_t VideoOut)
+{
+    HdffCmdMuxSetVideoOut(mOsdDev, VideoOut);
 }
 
 void cHdffCmdIf::CmdMuxSetVolume(uint8_t Volume)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvMux, msgMuxSetVolume);
-    cmdBuf.SetBits(8, Volume);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdMuxSetVolume(mOsdDev, Volume);
 }
 
 void cHdffCmdIf::CmdMuxMuteAudio(bool Mute)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvMux, msgMuxSetAudioMute);
-    cmdBuf.SetBits(1, Mute);
-    cmdBuf.SetBits(7, 0); // reserved
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdMuxMuteAudio(mOsdDev, Mute);
 }
 
-void cHdffCmdIf::CmdHdmiSetVideoMode(eHdmiVideoMode VideoMode)
+void cHdffCmdIf::CmdHdmiSetVideoMode(HdffVideoMode_t VideoMode)
 {
     //printf("HdmiSetVideoMode %d\n", VideoMode);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupHdmi, msgHdmiSetVideoMode);
-    cmdBuf.SetBits(8, VideoMode);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
-}
-
-void cHdffCmdIf::CmdHdmiConfigure(const tHdmiConfig * pConfig)
-{
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupHdmi, msgHdmiConfigure);
-    if (pConfig->TransmitAudio)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    if (pConfig->ForceDviMode)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    if (pConfig->CecEnabled)
-    {
-        cmdBuf.SetBits(1, 1);
-    }
-    else
-    {
-        cmdBuf.SetBits(1, 0);
-    }
-    cmdBuf.SetBits(3, (uint32_t) pConfig->VideoModeAdaption);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdHdmiSetVideoMode(mOsdDev, VideoMode);
 }
 
-void cHdffCmdIf::CmdHdmiSendCecCommand(eCecCommand Command)
+void cHdffCmdIf::CmdHdmiConfigure(const HdffHdmiConfig_t * pConfig)
 {
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
+    HdffCmdHdmiConfigure(mOsdDev, pConfig);
+}
 
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupHdmi, msgHdmiSendCecCommand);
-    cmdBuf.SetBits(8, Command);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+void cHdffCmdIf::CmdHdmiSendCecCommand(HdffCecCommand_t Command)
+{
+    HdffCmdHdmiSendCecCommand(mOsdDev, Command);
 }
 
-void cHdffCmdIf::CmdRemoteSetProtocol(eRemoteProtocol Protocol)
+void cHdffCmdIf::CmdRemoteSetProtocol(HdffRemoteProtocol_t Protocol)
 {
     //printf("%s %d\n", __func__, Protocol);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupRemoteControl, msgRemoteSetProtocol);
-    cmdBuf.SetBits(8, Protocol);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdRemoteSetProtocol(mOsdDev, Protocol);
 }
 
 void cHdffCmdIf::CmdRemoteSetAddressFilter(bool Enable, uint32_t Address)
 {
     //printf("%s %d %d\n", __func__, Enable, Address);
-    cBitBuffer cmdBuf(MAX_CMD_LEN);
-    osd_raw_cmd_t osd_cmd;
-
-    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
-    osd_cmd.cmd_data = cmdBuf.GetData();
-    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupRemoteControl, msgRemoteSetAddressFilter);
-    cmdBuf.SetBits(1, Enable);
-    cmdBuf.SetBits(7, 0); // reserved
-    cmdBuf.SetBits(32, Address);
-    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
-    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    HdffCmdRemoteSetAddressFilter(mOsdDev, Enable, Address);
 }
 
 } // end of namespace
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/hdffcmd.h vdr-1.7.22/PLUGINS/src/dvbhddevice/hdffcmd.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/hdffcmd.h	2011-04-17 13:20:22.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/hdffcmd.h	2011-12-04 16:31:23.000000000 +0100
@@ -3,14 +3,14 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: hdffcmd.h 1.17 2011/04/17 11:20:22 kls Exp $
+ * $Id: hdffcmd.h 1.18 2011/12/04 15:31:23 kls Exp $
  */
 
 #ifndef _HDFF_CMD_H_
 #define _HDFF_CMD_H_
 
 #include "bitbuffer.h"
-#include "hdffmsgdef.h"
+#include "libhdffcmd/hdffcmd.h"
 
 namespace HDFF
 {
@@ -20,9 +20,6 @@
 private:
     int mOsdDev;
 
-    void CmdBuildHeader(cBitBuffer & MsgBuf, eMessageType MsgType, eMessageGroup MsgGroup, eMessageId MsgId);
-    uint32_t CmdSetLength(cBitBuffer & MsgBuf);
-
 public:
     cHdffCmdIf(int OsdDev);
     ~cHdffCmdIf(void);
@@ -32,16 +29,16 @@
     uint32_t CmdGetCopyrights(uint8_t Index, char * pString, uint32_t MaxLength);
 
     void CmdAvSetPlayMode(uint8_t PlayMode, bool Realtime);
-    void CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, eVideoStreamType StreamType, bool PlaybackMode = false);
-    void CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, eAudioStreamType StreamType, eAVContainerType ContainerType = avContainerPes);
+    void CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, HdffVideoStreamType_t StreamType, bool PlaybackMode = false);
+    void CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, HdffAudioStreamType_t StreamType, HdffAvContainerType_t ContainerType = HDFF_AV_CONTAINER_PES);
     void CmdAvSetPcrPid(uint8_t DecoderIndex, uint16_t PcrPid);
     void CmdAvSetTeletextPid(uint8_t DecoderIndex, uint16_t TeletextPid);
     void CmdAvSetVideoWindow(uint8_t DecoderIndex, bool Enable, uint16_t X, uint16_t Y, uint16_t Width, uint16_t Height);
-    void CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, eVideoStreamType StreamType);
+    void CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, HdffVideoStreamType_t StreamType);
     void CmdAvSetDecoderInput(uint8_t DecoderIndex, uint8_t DemultiplexerIndex);
     void CmdAvSetDemultiplexerInput(uint8_t DemultiplexerIndex, uint8_t TsInputIndex);
-    void CmdAvSetVideoFormat(uint8_t DecoderIndex, const tVideoFormat * pVideoFormat);
-    void CmdAvSetVideoOutputMode(uint8_t DecoderIndex, eVideoOutputMode OutputMode);
+    void CmdAvSetVideoFormat(uint8_t DecoderIndex, const HdffVideoFormat_t * pVideoFormat);
+    void CmdAvSetVideoOutputMode(uint8_t DecoderIndex, HdffVideoOutputMode_t OutputMode);
     void CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc);
     void CmdAvFlushBuffer(uint8_t DecoderIndex, bool FlushAudio, bool FlushVideo);
     void CmdAvEnableSync(uint8_t DecoderIndex, bool EnableSync);
@@ -49,24 +46,24 @@
     void CmdAvSetAudioSpeed(uint8_t DecoderIndex, int32_t Speed);
     void CmdAvEnableVideoAfterStop(uint8_t DecoderIndex, bool EnableVideoAfterStop);
     void CmdAvSetAudioDelay(int16_t Delay);
-    void CmdAvSetAudioDownmix(eDownmixMode DownmixMode);
+    void CmdAvSetAudioDownmix(HdffAudioDownmixMode_t DownmixMode);
     void CmdAvSetAudioChannel(uint8_t AudioChannel);
 
-    void CmdOsdConfigure(const tOsdConfig * pConfig);
+    void CmdOsdConfigure(const HdffOsdConfig_t * pConfig);
     void CmdOsdReset(void);
 
-    uint32_t CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, eColorType ColorType);
+    uint32_t CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, HdffColorType_t ColorType);
     void CmdOsdDeleteDisplay(uint32_t hDisplay);
     void CmdOsdEnableDisplay(uint32_t hDisplay, bool Enable);
     void CmdOsdSetDisplayOutputRectangle(uint32_t hDisplay, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height);
     void CmdOsdSetDisplayClippingArea(uint32_t hDisplay, bool Enable, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height);
     void CmdOsdRenderDisplay(uint32_t hDisplay);
 
-    uint32_t CmdOsdCreatePalette(eColorType ColorType, eColorFormat ColorFormat,
+    uint32_t CmdOsdCreatePalette(HdffColorType_t ColorType, HdffColorFormat_t ColorFormat,
                                  uint32_t NumColors, const uint32_t * pColors);
     void CmdOsdDeletePalette(uint32_t hPalette);
     void CmdOsdSetDisplayPalette(uint32_t hDisplay, uint32_t hPalette);
-    void CmdOsdSetPaletteColors(uint32_t hPalette, eColorFormat ColorFormat,
+    void CmdOsdSetPaletteColors(uint32_t hPalette, HdffColorFormat_t ColorFormat,
                                 uint8_t StartColor, uint32_t NumColors, const uint32_t * pColors);
 
     uint32_t CmdOsdCreateFontFace(const uint8_t * pFontData, uint32_t DataSize);
@@ -81,19 +78,19 @@
     void CmdOsdDrawTextW(uint32_t hDisplay, uint32_t hFont, int X, int Y, const uint16_t * pText, uint32_t Color);
     void CmdOsdDrawBitmap(uint32_t hDisplay, int X, int Y, const uint8_t * pBitmap,
                           int BmpWidth, int BmpHeight, int BmpSize,
-                          eColorType ColorType, uint32_t hPalette);
+                          HdffColorType_t ColorType, uint32_t hPalette);
     void CmdOsdSaveRegion(uint32_t hDisplay, int X, int Y, int Width, int Height);
     void CmdOsdRestoreRegion(uint32_t hDisplay);
 
-    void CmdMuxSetVideoOut(eVideoOut VideoOut);
+    void CmdMuxSetVideoOut(HdffVideoOut_t VideoOut);
     void CmdMuxSetVolume(uint8_t Volume);
     void CmdMuxMuteAudio(bool Mute);
 
-    void CmdHdmiSetVideoMode(eHdmiVideoMode VideoMode);
-    void CmdHdmiConfigure(const tHdmiConfig * pConfig);
-    void CmdHdmiSendCecCommand(eCecCommand Command);
+    void CmdHdmiSetVideoMode(HdffVideoMode_t VideoMode);
+    void CmdHdmiConfigure(const HdffHdmiConfig_t * pConfig);
+    void CmdHdmiSendCecCommand(HdffCecCommand_t Command);
 
-    void CmdRemoteSetProtocol(eRemoteProtocol Protocol);
+    void CmdRemoteSetProtocol(HdffRemoteProtocol_t Protocol);
     void CmdRemoteSetAddressFilter(bool Enable, uint32_t Address);
 };
 
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/hdffosd.c vdr-1.7.22/PLUGINS/src/dvbhddevice/hdffosd.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/hdffosd.c	2011-05-15 16:47:29.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/hdffosd.c	2011-12-04 16:31:41.000000000 +0100
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: hdffosd.c 1.10 2011/05/15 14:47:29 kls Exp $
+ * $Id: hdffosd.c 1.12 2011/12/04 15:31:41 kls Exp $
  */
 
 #include "hdffosd.h"
@@ -71,7 +71,7 @@
 :   cOsd(Left, Top, Level)
 {
     double pixelAspect;
-    HDFF::tOsdConfig config;
+    HdffOsdConfig_t config;
 
     //printf("cHdffOsd %d, %d, %d\n", Left, Top, Level);
     mHdffCmdIf = pHdffCmdIf;
@@ -80,24 +80,24 @@
     shown = false;
     mChanged = false;
     mBitmapModified = false;
-    mBitmapPalette = InvalidHandle;
+    mBitmapPalette = HDFF_INVALID_HANDLE;
     config.FontKerning = false;
     config.FontAntialiasing = Setup.AntiAlias ? true : false;
     mHdffCmdIf->CmdOsdConfigure(&config);
 
     gHdffSetup.GetOsdSize(mDispWidth, mDispHeight, pixelAspect);
-    mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF::colorTypeARGB8888);
-    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, SizeFullScreen, SizeFullScreen);
+    mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF_COLOR_TYPE_ARGB8888);
+    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, HDFF_SIZE_FULL_SCREEN, HDFF_SIZE_FULL_SCREEN);
     for (int i = 0; i < MAX_NUM_FONTFACES; i++)
     {
         mFontFaces[i].Name = "";
-        mFontFaces[i].Handle = InvalidHandle;
+        mFontFaces[i].Handle = HDFF_INVALID_HANDLE;
     }
     for (int i = 0; i < MAX_NUM_FONTS; i++)
     {
-        mFonts[i].hFontFace = InvalidHandle;
+        mFonts[i].hFontFace = HDFF_INVALID_HANDLE;
         mFonts[i].Size = 0;
-        mFonts[i].Handle = InvalidHandle;
+        mFonts[i].Handle = HDFF_INVALID_HANDLE;
     }
 }
 
@@ -108,18 +108,18 @@
 
     for (int i = 0; i < MAX_NUM_FONTS; i++)
     {
-        if (mFonts[i].Handle == InvalidHandle)
+        if (mFonts[i].Handle == HDFF_INVALID_HANDLE)
             break;
         mHdffCmdIf->CmdOsdDeleteFont(mFonts[i].Handle);
     }
     for (int i = 0; i < MAX_NUM_FONTFACES; i++)
     {
-        if (mFontFaces[i].Handle == InvalidHandle)
+        if (mFontFaces[i].Handle == HDFF_INVALID_HANDLE)
             break;
         mHdffCmdIf->CmdOsdDeleteFontFace(mFontFaces[i].Handle);
     }
 
-    if (mBitmapPalette != InvalidHandle)
+    if (mBitmapPalette != HDFF_INVALID_HANDLE)
         mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
     mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
     mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
@@ -220,19 +220,19 @@
                 mBitmapColors[i] = ColorFg;
         }
     }
-    if (mBitmapPalette == InvalidHandle)
+    if (mBitmapPalette == HDFF_INVALID_HANDLE)
     {
-        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF::colorTypeClut8,
-                HDFF::colorFormatARGB, numColors, mBitmapColors);
+        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF_COLOR_TYPE_CLUT8,
+                HDFF_COLOR_FORMAT_ARGB, numColors, mBitmapColors);
     }
     else
     {
         mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
-                HDFF::colorFormatARGB, 0, numColors, mBitmapColors);
+                HDFF_COLOR_FORMAT_ARGB, 0, numColors, mBitmapColors);
     }
     mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y,
         (uint8_t *) Bitmap.Data(0, 0), Bitmap.Width(), Bitmap.Height(),
-        Bitmap.Width() * Bitmap.Height(), HDFF::colorTypeClut8, mBitmapPalette);
+        Bitmap.Width() * Bitmap.Height(), HDFF_COLOR_TYPE_CLUT8, mBitmapPalette);
 #if 0
     uint32_t * tmpBitmap = new uint32_t[Bitmap.Width() * Bitmap.Height()];
     for (int ix = 0; ix < Bitmap.Width(); ix++)
@@ -284,7 +284,7 @@
     pFontFace = NULL;
     for (i = 0; i < MAX_NUM_FONTFACES; i++)
     {
-        if (mFontFaces[i].Handle == InvalidHandle)
+        if (mFontFaces[i].Handle == HDFF_INVALID_HANDLE)
             break;
 
         if (strcmp(mFontFaces[i].Name, Font->FontName()) == 0)
@@ -312,7 +312,7 @@
                         if (fread(buffer, fileSize, 1, fp) == 1)
                         {
                             mFontFaces[i].Handle = mHdffCmdIf->CmdOsdCreateFontFace(buffer, fileSize);
-                            if (mFontFaces[i].Handle != InvalidHandle)
+                            if (mFontFaces[i].Handle != HDFF_INVALID_HANDLE)
                             {
                                 mFontFaces[i].Name = Font->FontName();
                                 pFontFace = &mFontFaces[i];
@@ -331,7 +331,7 @@
     pFont = NULL;
     for (i = 0; i < MAX_NUM_FONTS; i++)
     {
-        if (mFonts[i].Handle == InvalidHandle)
+        if (mFonts[i].Handle == HDFF_INVALID_HANDLE)
             break;
 
         if (mFonts[i].hFontFace == pFontFace->Handle
@@ -346,7 +346,7 @@
         if (i < MAX_NUM_FONTS)
         {
             mFonts[i].Handle = mHdffCmdIf->CmdOsdCreateFont(pFontFace->Handle, size);
-            if (mFonts[i].Handle != InvalidHandle)
+            if (mFonts[i].Handle != HDFF_INVALID_HANDLE)
             {
                 mFonts[i].hFontFace = pFontFace->Handle;
                 mFonts[i].Size = size;
@@ -435,9 +435,9 @@
     {
         case 1:
             if (Quadrants > 0)
-                flags = HDFF::drawQuarterTopRight;
+                flags = HDFF_DRAW_QUARTER_TOP_RIGHT;
             else
-                flags = HDFF::drawQuarterTopRightInverted;
+                flags = HDFF_DRAW_QUARTER_TOP_RIGHT_INVERTED;
             cx = x1;
             cy = y2;
             rx = x2 - x1;
@@ -445,9 +445,9 @@
             break;
         case 2:
             if (Quadrants > 0)
-                flags = HDFF::drawQuarterTopLeft;
+                flags = HDFF_DRAW_QUARTER_TOP_LEFT;
             else
-                flags = HDFF::drawQuarterTopLeftInverted;
+                flags = HDFF_DRAW_QUARTER_TOP_LEFT_INVERTED;
             cx = x2;
             cy = y2;
             rx = x2 - x1;
@@ -455,9 +455,9 @@
             break;
         case 3:
             if (Quadrants > 0)
-                flags = HDFF::drawQuarterBottomLeft;
+                flags = HDFF_DRAW_QUARTER_BOTTOM_LEFT;
             else
-                flags = HDFF::drawQuarterBottomLeftInverted;
+                flags = HDFF_DRAW_QUARTER_BOTTOM_LEFT_INVERTED;
             cx = x2;
             cy = y1;
             rx = x2 - x1;
@@ -465,44 +465,44 @@
             break;
         case 4:
             if (Quadrants > 0)
-                flags = HDFF::drawQuarterBottomRight;
+                flags = HDFF_DRAW_QUARTER_BOTTOM_RIGHT;
             else
-                flags = HDFF::drawQuarterBottomRightInverted;
+                flags = HDFF_DRAW_QUARTER_BOTTOM_RIGHT_INVERTED;
             cx = x1;
             cy = y1;
             rx = x2 - x1;
             ry = y2 - y1;
             break;
         case 5:
-            flags = HDFF::drawHalfRight;
+            flags = HDFF_DRAW_HALF_RIGHT;
             cx = x1;
             cy = (y1 + y2) / 2;
             rx = x2 - x1;
             ry = (y2 - y1) / 2;
             break;
         case 6:
-            flags = HDFF::drawHalfTop;
+            flags = HDFF_DRAW_HALF_TOP;
             cx = (x1 + x2) / 2;
             cy = y2;
             rx = (x2 - x1) / 2;
             ry = y2 - y1;
             break;
         case 7:
-            flags = HDFF::drawHalfLeft;
+            flags = HDFF_DRAW_HALF_LEFT;
             cx = x2;
             cy = (y1 + y2) / 2;
             rx = x2 - x1;
             ry = (y2 - y1) / 2;
             break;
         case 8:
-            flags = HDFF::drawHalfBottom;
+            flags = HDFF_DRAW_HALF_BOTTOM;
             cx = (x1 + x2) / 2;
             cy = y1;
             rx = (x2 - x1) / 2;
             ry = y2 - y1;
             break;
         default:
-            flags = HDFF::drawFull;
+            flags = HDFF_DRAW_FULL;
             cx = (x1 + x2) / 2;
             cy = (y1 + y2) / 2;
             rx = (x2 - x1) / 2;
@@ -552,7 +552,7 @@
     HDFF::cHdffCmdIf * mHdffCmdIf;
     int mDispWidth;
     int mDispHeight;
-    bool shown;
+    bool refresh;
     uint32_t mDisplay;
     uint32_t mBitmapPalette;
     uint32_t mBitmapColors[256];
@@ -575,24 +575,27 @@
 
     //printf("cHdffOsdRaw %d, %d, %d\n", Left, Top, Level);
     mHdffCmdIf = pHdffCmdIf;
-    shown = false;
-    mBitmapPalette = InvalidHandle;
+    refresh = true;
+    mBitmapPalette = HDFF_INVALID_HANDLE;
+    mDisplay = HDFF_INVALID_HANDLE;
 
     gHdffSetup.GetOsdSize(mDispWidth, mDispHeight, pixelAspect);
-    mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF::colorTypeARGB8888);
-    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, SizeFullScreen, SizeFullScreen);
 }
 
 cHdffOsdRaw::~cHdffOsdRaw()
 {
     //printf("~cHdffOsdRaw %d %d\n", Left(), Top());
-    SetActive(false);
-
-    if (mBitmapPalette != InvalidHandle)
+    if (mDisplay != HDFF_INVALID_HANDLE)
+    {
+        mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    }
+    if (mBitmapPalette != HDFF_INVALID_HANDLE)
         mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
-    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
-    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
-    mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+    mBitmapPalette = HDFF_INVALID_HANDLE;
+    if (mDisplay != HDFF_INVALID_HANDLE)
+       mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+    mDisplay = HDFF_INVALID_HANDLE;
 }
 
 void cHdffOsdRaw::SetActive(bool On)
@@ -602,14 +605,29 @@
         cOsd::SetActive(On);
         if (On)
         {
+            if (mDisplay == HDFF_INVALID_HANDLE)
+            {
+                mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF_COLOR_TYPE_ARGB8888);
+                if (mDisplay != HDFF_INVALID_HANDLE)
+                    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, HDFF_SIZE_FULL_SCREEN, HDFF_SIZE_FULL_SCREEN);
+            }
+            refresh = true;
             if (GetBitmap(0)) // only flush here if there are already bitmaps
                 Flush();
         }
-        else if (shown)
+        else
         {
-            mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
-            mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
-            shown = false;
+            if (mDisplay != HDFF_INVALID_HANDLE)
+            {
+                mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+                mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+            }
+            if (mBitmapPalette != HDFF_INVALID_HANDLE)
+                mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+            mBitmapPalette = HDFF_INVALID_HANDLE;
+            if (mDisplay != HDFF_INVALID_HANDLE)
+                mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+            mDisplay = HDFF_INVALID_HANDLE;
         }
     }
 }
@@ -635,18 +653,18 @@
     {
         //printf("SetAreas %d: %d %d %d %d %d\n", i, Areas[i].x1, Areas[i].y1, Areas[i].x2, Areas[i].y2, Areas[i].bpp);
     }
-    if (shown)
+    if (mDisplay != HDFF_INVALID_HANDLE)
     {
         mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
         mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
-        shown = false;
+        refresh = true;
     }
     return cOsd::SetAreas(Areas, NumAreas);
 }
 
 void cHdffOsdRaw::Flush(void)
 {
-    if (!Active())
+    if (!Active() || (mDisplay == HDFF_INVALID_HANDLE))
         return;
     //struct timeval start;
     //struct timeval end;
@@ -673,7 +691,7 @@
                  mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
                      Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y() + y,
                      pm->Data() + y * d, w, hc, hc * d,
-                     HDFF::colorTypeARGB8888, InvalidHandle);
+                     HDFF_COLOR_TYPE_ARGB8888, HDFF_INVALID_HANDLE);
             }
             delete pm;
             render = true;
@@ -688,9 +706,9 @@
         for (int i = 0; (bitmap = GetBitmap(i)) != NULL; i++)
         {
             int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
-            if (!shown || bitmap->Dirty(x1, y1, x2, y2))
+            if (refresh || bitmap->Dirty(x1, y1, x2, y2))
             {
-                if (!shown)
+                if (refresh)
                 {
                     x2 = bitmap->Width() - 1;
                     y2 = bitmap->Height() - 1;
@@ -702,15 +720,15 @@
                 {
                     for (int c = 0; c < numColors; c++)
                         mBitmapColors[c] = colors[c];
-                    if (mBitmapPalette == InvalidHandle)
+                    if (mBitmapPalette == HDFF_INVALID_HANDLE)
                     {
-                        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF::colorTypeClut8,
-                            HDFF::colorFormatARGB, numColors, mBitmapColors);
+                        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF_COLOR_TYPE_CLUT8,
+                            HDFF_COLOR_FORMAT_ARGB, numColors, mBitmapColors);
                     }
                     else
                     {
                         mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
-                            HDFF::colorFormatARGB, 0, numColors, mBitmapColors);
+                            HDFF_COLOR_FORMAT_ARGB, 0, numColors, mBitmapColors);
                     }
                 }
                 // commit modified data:
@@ -729,7 +747,7 @@
                     mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
                         Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1 + y,
                         buffer, width, hc, hc * width,
-                        HDFF::colorTypeClut8, mBitmapPalette);
+                        HDFF_COLOR_TYPE_CLUT8, mBitmapPalette);
                 }
                 render = true;
             }
@@ -745,7 +763,7 @@
         //timeNeeded += (end.tv_sec - start.tv_sec) * 1000000;
         //printf("time = %d\n", timeNeeded);
     }
-    shown = true;
+    refresh = false;
 }
 
 
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,75 @@
+#
+# Makefile for the HDFF firmware command interface library
+#
+
+VERSION = 0.1.0
+
+ifndef $(INSTALL_PATH)
+    INSTALL_PATH=/usr/local
+endif
+
+ifndef $(INSTALL_LIB_PATH)
+    INSTALL_LIB_PATH=$(INSTALL_PATH)/lib
+endif
+
+ifndef $(INSTALL_INCLUDE_PATH)
+    INSTALL_INCLUDE_PATH=$(INSTALL_PATH)/include
+endif
+
+LIB_NAME = libhdffcmd
+
+LIB_OBJS = bitbuffer.o hdffcmd_av.o hdffcmd_base.o hdffcmd_generic.o \
+           hdffcmd_hdmi.o hdffcmd_mux.o hdffcmd_osd.o hdffcmd_remote.o
+
+LIB_HEADERS = hdffcmd.h hdffcmd_av.h hdffcmd_generic.h hdffcmd_hdmi.h \
+              hdffcmd_mux.h hdffcmd_osd.h hdffcmd_remote.h
+
+LIB_STATIC = $(LIB_NAME).a
+LIB_SHARED = $(LIB_NAME)-$(VERSION).so
+
+CC     = gcc
+CFLAGS = -g -O2 -fPIC -Wall
+AR     = ar -r
+
+### Implicit rules:
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = $(CC) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+	@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: $(LIB_STATIC) $(LIB_SHARED)
+
+$(LIB_STATIC): $(LIB_OBJS)
+	$(AR) $(LIB_STATIC) $(LIB_OBJS)
+
+$(LIB_SHARED): $(LIB_OBJS)
+	$(CC) -fPIC -shared -o $(LIB_SHARED) $(LIB_OBJS)
+	ln -sf $(LIB_SHARED) $(LIB_NAME).so
+
+clean:
+	rm -f $(LIB_OBJS) $(DEPFILE) $(LIB_STATIC) $(LIB_NAME)*.so
+
+install: $(LIB_SHARED)
+	chown root $(LIB_SHARED)
+	chgrp root $(LIB_SHARED)
+	chmod 0755 $(LIB_SHARED)
+	cp -f $(LIB_SHARED) $(INSTALL_LIB_PATH)/
+	ln -sf $(LIB_SHARED) $(INSTALL_LIB_PATH)/$(LIB_NAME).so
+	mkdir -p  $(INSTALL_INCLUDE_PATH)/libhdffcmd
+	list='$(LIB_HEADERS)'; \
+	for headerfile in $$list; do \
+	  cp -f $$headerfile $(INSTALL_INCLUDE_PATH)/libhdffcmd/ ; \
+	  chown root $(INSTALL_INCLUDE_PATH)/libhdffcmd/$$headerfile ; \
+	  chgrp root $(INSTALL_INCLUDE_PATH)/libhdffcmd/$$headerfile ; \
+	  chmod 0644 $(INSTALL_INCLUDE_PATH)/libhdffcmd/$$headerfile ; \
+	done
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,79 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <string.h>
+
+#include "bitbuffer.h"
+
+void BitBuffer_Init(BitBuffer_t * BitBuffer,
+                    uint8_t * Data, uint32_t MaxLength)
+{
+    memset(Data, 0, MaxLength);
+    BitBuffer->Data = Data;
+    BitBuffer->MaxLength = MaxLength * 8;
+    BitBuffer->BitPos = 0;
+}
+
+void BitBuffer_SetBits(BitBuffer_t * BitBuffer, int NumBits, uint32_t Data)
+{
+    uint32_t nextBitPos;
+    uint32_t bytePos;
+    uint32_t bitsInByte;
+    int shift;
+
+    if (NumBits <= 0 || NumBits > 32)
+        return;
+
+    nextBitPos = BitBuffer->BitPos + NumBits;
+
+    if (nextBitPos > BitBuffer->MaxLength)
+        return;
+
+    bytePos = BitBuffer->BitPos / 8;
+    bitsInByte = BitBuffer->BitPos % 8;
+
+    BitBuffer->Data[bytePos] &= (uint8_t) (0xFF << (8 - bitsInByte));
+    shift = NumBits - (8 - bitsInByte);
+    if (shift > 0)
+        BitBuffer->Data[bytePos] |= (uint8_t) (Data >> shift);
+    else
+        BitBuffer->Data[bytePos] |= (uint8_t) (Data << (-shift));
+    NumBits -= 8 - bitsInByte;
+    bytePos++;
+    while (NumBits > 0)
+    {
+        shift = NumBits - 8;
+        if (shift > 0)
+            BitBuffer->Data[bytePos] = (uint8_t) (Data >> shift);
+        else
+            BitBuffer->Data[bytePos] = (uint8_t) (Data << (-shift));
+        NumBits -= 8;
+        bytePos++;
+    }
+    BitBuffer->BitPos = nextBitPos;
+}
+
+uint32_t BitBuffer_GetByteLength(BitBuffer_t * BitBuffer)
+{
+    return (BitBuffer->BitPos + 7) / 8;
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/bitbuffer.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,43 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef BITBUFFER_H
+#define BITBUFFER_H
+
+#include <stdint.h>
+
+typedef struct BitBuffer_t
+{
+    uint8_t * Data;
+    uint32_t MaxLength;
+    uint32_t BitPos;
+} BitBuffer_t;
+
+void BitBuffer_Init(BitBuffer_t * BitBuffer,
+                    uint8_t * Data, uint32_t MaxLength);
+
+void BitBuffer_SetBits(BitBuffer_t * BitBuffer, int NumBits, uint32_t Data);
+
+uint32_t BitBuffer_GetByteLength(BitBuffer_t * BitBuffer);
+
+#endif /* BITBUFFER_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,42 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_H
+#define HDFFCMD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hdffcmd_av.h"
+#include "hdffcmd_generic.h"
+#include "hdffcmd_hdmi.h"
+#include "hdffcmd_mux.h"
+#include "hdffcmd_osd.h"
+#include "hdffcmd_remote.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HDFFCMD_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,451 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdAvSetPlayMode(int OsdDevice, uint8_t PlayMode, int Realtime)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_PLAY_MODE);
+    BitBuffer_SetBits(&cmdBuf, 1, Realtime ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 7, PlayMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffVideoStreamType_t StreamType)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, StreamType);
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffAudioStreamType_t StreamType,
+                         HdffAvContainerType_t ContainerType)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, StreamType);
+    BitBuffer_SetBits(&cmdBuf, 2, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 1, ContainerType);
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetPcrPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_PCR_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetTeletextPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_TELETEXT_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoWindow(int OsdDevice, uint8_t DecoderIndex, int Enable,
+                            uint16_t X, uint16_t Y, uint16_t Width,
+                            uint16_t Height)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_WINDOW);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    if (Enable)
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    else
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvShowStillImage(int OsdDevice, uint8_t DecoderIndex,
+                            const uint8_t * StillImage, int Size,
+                            HdffVideoStreamType_t StreamType)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+    int err;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = StillImage;
+    osd_data.data_length = Size;
+    err = ioctl(OsdDevice, OSD_RAW_DATA, &osd_data);
+    if (err != 0)
+        return err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SHOW_STILL_IMAGE);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, StreamType);
+    BitBuffer_SetBits(&cmdBuf, 16, osd_data.data_handle);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetDecoderInput(int OsdDevice, uint8_t DecoderIndex,
+                             uint8_t DemultiplexerIndex)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_DECODER_INPUT);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, DemultiplexerIndex);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetDemultiplexerInput(int OsdDevice, uint8_t DemultiplexerIndex,
+                                   uint8_t TsInputIndex)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_DEMULTIPLEXER_INPUT);
+    BitBuffer_SetBits(&cmdBuf, 4, DemultiplexerIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, TsInputIndex);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoFormat(int OsdDevice, uint8_t DecoderIndex,
+                            const HdffVideoFormat_t * VideoFormat)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_FORMAT);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, VideoFormat->AutomaticEnabled ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, VideoFormat->AfdEnabled ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 2, VideoFormat->TvFormat);
+    BitBuffer_SetBits(&cmdBuf, 8, VideoFormat->VideoConversion);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoOutputMode(int OsdDevice, uint8_t DecoderIndex,
+                                HdffVideoOutputMode_t OutputMode)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_OUTPUT_MODE);
+    BitBuffer_SetBits(&cmdBuf, 8, OutputMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetStc(int OsdDevice, uint8_t DecoderIndex, uint64_t Stc)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_STC);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 1, (uint32_t) (Stc >> 32));
+    BitBuffer_SetBits(&cmdBuf, 32, (uint32_t) Stc);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvFlushBuffer(int OsdDevice, uint8_t DecoderIndex, int FlushAudio,
+                         int FlushVideo)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_FLUSH_BUFFER);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    if (FlushAudio)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    if (FlushVideo)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvEnableSync(int OsdDevice, uint8_t DecoderIndex, int SyncAudio,
+                        int SyncVideo)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_ENABLE_SYNC);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, SyncAudio ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, SyncVideo ? 1 : 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_SPEED);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0);
+    BitBuffer_SetBits(&cmdBuf, 32, Speed);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_SPEED);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0);
+    BitBuffer_SetBits(&cmdBuf, 32, Speed);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvEnableVideoAfterStop(int OsdDevice, uint8_t DecoderIndex,
+                                  int EnableVideoAfterStop)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_ENABLE_VIDEO_AFTER_STOP);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, EnableVideoAfterStop ? 1 : 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioDelay(int OsdDevice, int16_t Delay)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_DELAY);
+    BitBuffer_SetBits(&cmdBuf, 16, Delay);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioDownmix(int OsdDevice, HdffAudioDownmixMode_t DownmixMode)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_DOWNMIX);
+    BitBuffer_SetBits(&cmdBuf, 8, DownmixMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioChannel(int OsdDevice, uint8_t AudioChannel)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_CHANNEL);
+    BitBuffer_SetBits(&cmdBuf, 8, AudioChannel);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,151 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_AV_H
+#define HDFFCMD_AV_H
+
+typedef enum HdffAvContainerType_t
+{
+    HDFF_AV_CONTAINER_PES,
+    HDFF_AV_CONTAINER_PES_DVD
+} HdffAvContainerType_t;
+
+typedef enum HdffAudioStreamType_t
+{
+    HDFF_AUDIO_STREAM_INVALID = -1,
+    HDFF_AUDIO_STREAM_MPEG1 = 0,
+    HDFF_AUDIO_STREAM_MPEG2,
+    HDFF_AUDIO_STREAM_AC3,
+    HDFF_AUDIO_STREAM_AAC,
+    HDFF_AUDIO_STREAM_HE_AAC,
+    HDFF_AUDIO_STREAM_PCM,
+    HDFF_AUDIO_STREAM_EAC3,
+    HDFF_AUDIO_STREAM_DTS
+} HdffAudioStreamType_t;
+
+typedef enum HdffVideoStreamType_t
+{
+    HDFF_VIDEO_STREAM_INVALID = -1,
+    HDFF_VIDEO_STREAM_MPEG1 = 0,
+    HDFF_VIDEO_STREAM_MPEG2,
+    HDFF_VIDEO_STREAM_H264,
+    HDFF_VIDEO_STREAM_MPEG4_ASP,
+    HDFF_VIDEO_STREAM_VC1
+} HdffVideoStreamType_t;
+
+typedef enum HdffTvFormat_t
+{
+    HDFF_TV_FORMAT_4_BY_3,
+    HDFF_TV_FORMAT_16_BY_9
+} HdffTvFormat_t;
+
+typedef enum HdffVideoConversion_t
+{
+    HDFF_VIDEO_CONVERSION_AUTOMATIC,
+    HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9,
+    HDFF_VIDEO_CONVERSION_LETTERBOX_14_BY_9,
+    HDFF_VIDEO_CONVERSION_PILLARBOX,
+    HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT,
+    HDFF_VIDEO_CONVERSION_ALWAYS_16_BY_9
+} HdffVideoConversion_t;
+
+typedef struct HdffVideoFormat_t
+{
+    int AutomaticEnabled;
+    int AfdEnabled;
+    HdffTvFormat_t TvFormat;
+    HdffVideoConversion_t VideoConversion;
+} HdffVideoFormat_t;
+
+typedef enum HdffVideoOutputMode_t
+{
+    HDFF_VIDEO_OUTPUT_CLONE,
+    HDFF_VIDEO_OUTPUT_HD_ONLY
+} HdffVideoOutputMode_t;
+
+typedef enum HdffAudioDownmixMode_t
+{
+    HDFF_AUDIO_DOWNMIX_OFF,
+    HDFF_AUDIO_DOWNMIX_ANALOG,
+    HDFF_AUDIO_DOWNMIX_ALWAYS,
+    HDFF_AUDIO_DOWNMIX_AUTOMATIC,
+    HDFF_AUDIO_DOWNMIX_HDMI_ONLY
+} HdffAudioDownmixMode_t;
+
+
+int HdffCmdAvSetPlayMode(int OsdDevice, uint8_t PlayMode, int Realtime);
+
+int HdffCmdAvSetVideoPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffVideoStreamType_t StreamType);
+
+int HdffCmdAvSetAudioPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffAudioStreamType_t StreamType,
+                         HdffAvContainerType_t ContainerType);
+
+int HdffCmdAvSetPcrPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid);
+
+int HdffCmdAvSetTeletextPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid);
+
+int HdffCmdAvSetVideoWindow(int OsdDevice, uint8_t DecoderIndex, int Enable,
+                            uint16_t X, uint16_t Y, uint16_t Width,
+                            uint16_t Height);
+
+int HdffCmdAvShowStillImage(int OsdDevice, uint8_t DecoderIndex,
+                            const uint8_t * StillImage, int Size,
+                            HdffVideoStreamType_t StreamType);
+
+int HdffCmdAvSetDecoderInput(int OsdDevice, uint8_t DecoderIndex,
+                             uint8_t DemultiplexerIndex);
+
+int HdffCmdAvSetDemultiplexerInput(int OsdDevice, uint8_t DemultiplexerIndex,
+                                   uint8_t TsInputIndex);
+
+int HdffCmdAvSetVideoFormat(int OsdDevice, uint8_t DecoderIndex,
+                            const HdffVideoFormat_t * VideoFormat);
+
+int HdffCmdAvSetVideoOutputMode(int OsdDevice, uint8_t DecoderIndex,
+                                HdffVideoOutputMode_t OutputMode);
+
+int HdffCmdAvSetStc(int OsdDevice, uint8_t DecoderIndex, uint64_t Stc);
+
+int HdffCmdAvFlushBuffer(int OsdDevice, uint8_t DecoderIndex, int FlushAudio,
+                         int FlushVideo);
+
+int HdffCmdAvEnableSync(int OsdDevice, uint8_t DecoderIndex, int SyncAudio,
+                        int SyncVideo);
+
+int HdffCmdAvSetVideoSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed);
+
+int HdffCmdAvSetAudioSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed);
+
+int HdffCmdAvEnableVideoAfterStop(int OsdDevice, uint8_t DecoderIndex,
+                                  int EnableVideoAfterStop);
+
+int HdffCmdAvSetAudioDelay(int OsdDevice, int16_t Delay);
+
+int HdffCmdAvSetAudioDownmix(int OsdDevice,
+                             HdffAudioDownmixMode_t DownmixMode);
+
+int HdffCmdAvSetAudioChannel(int OsdDevice, uint8_t AudioChannel);
+
+#endif /* HDFFCMD_AV_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "hdffcmd_base.h"
+
+void HdffCmdBuildHeader(BitBuffer_t * MsgBuf, HdffMessageType_t MsgType,
+                        HdffMessageGroup_t MsgGroup, HdffMessageId_t MsgId)
+{
+    BitBuffer_SetBits(MsgBuf, 16, 0); // length field will be set later
+    BitBuffer_SetBits(MsgBuf, 6, 0); // reserved
+    BitBuffer_SetBits(MsgBuf, 2, MsgType);
+    BitBuffer_SetBits(MsgBuf, 8, MsgGroup);
+    BitBuffer_SetBits(MsgBuf, 16, MsgId);
+}
+
+uint32_t HdffCmdSetLength(BitBuffer_t * MsgBuf)
+{
+    uint32_t length;
+
+    length = BitBuffer_GetByteLength(MsgBuf) - 2;
+    MsgBuf->Data[0] = (uint8_t) (length >> 8);
+    MsgBuf->Data[1] = (uint8_t) length;
+
+    return length + 2;
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,55 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_BASE_H
+#define HDFFCMD_BASE_H
+
+#include <linux/dvb/osd.h>
+
+#if !defined OSD_RAW_CMD
+typedef struct osd_raw_cmd_s {
+    const void *cmd_data;
+    int cmd_len;
+    void *result_data;
+    int result_len;
+} osd_raw_cmd_t;
+
+typedef struct osd_raw_data_s {
+    const void *data_buffer;
+    int data_length;
+    int data_handle;
+} osd_raw_data_t;
+
+#define OSD_RAW_CMD            _IOWR('o', 162, osd_raw_cmd_t)
+#define OSD_RAW_DATA           _IOWR('o', 163, osd_raw_data_t)
+#endif
+
+#include "bitbuffer.h"
+#include "hdffcmd_defs.h"
+
+void HdffCmdBuildHeader(BitBuffer_t * MsgBuf, HdffMessageType_t MsgType,
+                        HdffMessageGroup_t MsgGroup, HdffMessageId_t MsgId);
+
+uint32_t HdffCmdSetLength(BitBuffer_t * MsgBuf);
+
+#endif /* HDFFCMD_BASE_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,120 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_DEFS_H
+#define HDFFCMD_DEFS_H
+
+typedef enum HdffMessageType_t
+{
+    HDFF_MSG_TYPE_COMMAND,
+    HDFF_MSG_TYPE_ANSWER,
+    HDFF_MSG_TYPE_RESULT,
+    HDFF_MSG_TYPE_EVENT
+} HdffMessageType_t;
+
+typedef enum HdffMessageGroup_t
+{
+    HDFF_MSG_GROUP_GENERIC,
+    HDFF_MSG_GROUP_AV_DECODER,
+    HDFF_MSG_GROUP_AV_MUX,
+    HDFF_MSG_GROUP_FRONTEND,
+    HDFF_MSG_GROUP_OSD,
+    HDFF_MSG_GROUP_HDMI,
+    HDFF_MSG_GROUP_REMOTE_CONTROL
+} HdffMessageGroup_t;
+
+typedef enum HdffMessageId_t
+{
+    HDFF_MSG_GEN_GET_FIRMWARE_VERSION = 0,
+    HDFF_MSG_GEN_GET_INTERFACE_VERSION,
+    HDFF_MSG_GEN_GET_COPYRIGHTS,
+
+    HDFF_MSG_AV_SET_AUDIO_PID = 0,
+    HDFF_MSG_AV_SET_VIDEO_PID,
+    HDFF_MSG_AV_SET_PCR_PID,
+    HDFF_MSG_AV_SET_TELETEXT_PID,
+    HDFF_MSG_AV_SHOW_STILL_IMAGE,
+    HDFF_MSG_AV_SET_VIDEO_WINDOW,
+    HDFF_MSG_AV_SET_DECODER_INPUT,
+    HDFF_MSG_AV_SET_DEMULTIPLEXER_INPUT,
+    HDFF_MSG_AV_SET_VIDEO_FORMAT,
+    HDFF_MSG_AV_SET_VIDEO_OUTPUT_MODE,
+    HDFF_MSG_AV_SET_STC,
+    HDFF_MSG_AV_FLUSH_BUFFER,
+    HDFF_MSG_AV_ENABLE_SYNC,
+    HDFF_MSG_AV_SET_VIDEO_SPEED,
+    HDFF_MSG_AV_SET_AUDIO_SPEED,
+    HDFF_MSG_AV_ENABLE_VIDEO_AFTER_STOP,
+    HDFF_MSG_AV_GET_VIDEO_FORMAT_INFO,
+    HDFF_MSG_AV_SET_AUDIO_DELAY,
+    HDFF_MSG_AV_SET_AUDIO_DOWNMIX,
+    HDFF_MSG_AV_SET_AUDIO_CHANNEL,
+    HDFF_MSG_AV_SET_PLAY_MODE,
+
+    HDFF_MSG_MUX_SET_VIDEO_OUT = 0,
+    HDFF_MSG_MUX_SET_SLOW_BLANK,
+    HDFF_MSG_MUX_SET_FAST_BLANK,
+    HDFF_MSG_MUX_SET_VOLUME,
+    HDFF_MSG_MUX_SET_AUDIO_MUTE,
+
+    HDFF_MSG_OSD_CONFIGURE = 0,
+    HDFF_MSG_OSD_RESET,
+    HDFF_MSG_OSD_CREATE_DISPLAY = 10,
+    HDFF_MSG_OSD_DELETE_DISPLAY,
+    HDFF_MSG_OSD_ENABLE_DISPLAY,
+    HDFF_MSG_OSD_SET_DISPLAY_OUTPUT_RECTANGLE,
+    HDFF_MSG_OSD_SET_DISPLAY_CLIPPLING_AREA,
+    HDFF_MSG_OSD_RENDER_DISPLAY,
+    HDFF_MSG_OSD_SAVE_REGION,
+    HDFF_MSG_OSD_RESTORE_REGION,
+    HDFF_MSG_OSD_CREATE_PALETTE = 30,
+    HDFF_MSG_OSD_DELETE_PALETTE,
+    HDFF_MSG_OSD_SET_DISPLAY_PALETTE,
+    HDFF_MSG_OSD_SET_PALETTE_COLORS,
+    HDFF_MSG_OSD_CREATE_FONT_FACE = 50,
+    HDFF_MSG_OSD_DELETE_FONT_FACE,
+    HDFF_MSG_OSD_CREATE_FONT,
+    HDFF_MSG_OSD_DELETE_FONT,
+    HDFF_MSG_OSD_DRAW_PIXEL = 70,
+    HDFF_MSG_OSD_DRAW_RECTANGLE,
+    HDFF_MSG_OSD_DRAW_CIRCLE,
+    HDFF_MSG_OSD_DRAW_ELLIPSE,
+    HDFF_MSG_OSD_DRAW_SLOPE,
+    HDFF_MSG_OSD_DRAW_TEXT,
+    HDFF_MSG_OSD_DRAW_WIDE_TEXT,
+    HDFF_MSG_OSD_DRAW_BITMAP,
+
+    HDFF_MSG_HDMI_ENABLE_OUTPUT = 0,
+    HDFF_MSG_HDMI_SET_VIDEO_MODE,
+    HDFF_MSG_HDMI_CONFIGURE,
+    HDFF_MSG_HDMI_IS_DISPLAY_CONNECTED,
+    HDFF_MSG_HDMI_GET_DISPLAY_INFO,
+    HDFF_MSG_HDMI_GET_VIDEO_MODE,
+    HDFF_MSG_HDMI_SEND_CEC_COMMAND,
+
+    HDFF_MSG_REMOTE_SET_PROTOCOL = 0,
+    HDFF_MSG_REMOTE_SET_ADDRESS_FILTER,
+    HDFF_MSG_REMOTE_KEY_EVENT
+} HdffMessageId_t;
+
+#endif /* HDFFCMD_DEFS_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,147 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+int HdffCmdGetFirmwareVersion(int OsdDevice, uint32_t * Version, char * String,
+                              uint32_t MaxLength)
+{
+    uint8_t cmdData[8];
+    uint8_t resultData[64];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    *Version = 0;
+    String[0] = 0;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_GENERIC,
+                       HDFF_MSG_GEN_GET_FIRMWARE_VERSION);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            uint8_t textLength = resultData[9];
+            if (textLength >= MaxLength)
+                textLength = MaxLength - 1;
+            memcpy(String, &resultData[10], textLength);
+            String[textLength] = 0;
+            *Version = (resultData[6] << 16)
+                     | (resultData[7] << 8)
+                     | resultData[8];
+        }
+    }
+    return err;
+}
+
+int HdffCmdGetInterfaceVersion(int OsdDevice, uint32_t * Version, char * String,
+                               uint32_t MaxLength)
+{
+    uint8_t cmdData[8];
+    uint8_t resultData[64];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    *Version = 0;
+    String[0] = 0;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_GENERIC,
+                       HDFF_MSG_GEN_GET_INTERFACE_VERSION);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            uint8_t textLength = resultData[9];
+            if (textLength >= MaxLength)
+                textLength = MaxLength - 1;
+            memcpy(String, &resultData[10], textLength);
+            String[textLength] = 0;
+            *Version = (resultData[6] << 16)
+                     | (resultData[7] << 8)
+                     | resultData[8];
+        }
+    }
+    return err;
+}
+
+int HdffCmdGetCopyrights(int OsdDevice, uint8_t Index, char * String,
+                         uint32_t MaxLength)
+{
+    uint8_t cmdData[8];
+    uint8_t resultData[280];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    String[0] = 0;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_GENERIC,
+                       HDFF_MSG_GEN_GET_COPYRIGHTS);
+    BitBuffer_SetBits(&cmdBuf, 8, Index);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            uint8_t index = resultData[6];
+            uint8_t textLen = resultData[7];
+            if (index == Index && textLen > 0)
+            {
+                if (textLen >= MaxLength)
+                {
+                    textLen = MaxLength - 1;
+                }
+                memcpy(String, resultData + 8, textLen);
+                String[textLen] = 0;
+            }
+        }
+    }
+    return err;
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_generic.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,36 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_GENERIC_H
+#define HDFFCMD_GENERIC_H
+
+int HdffCmdGetFirmwareVersion(int OsdDevice, uint32_t * Version, char * String,
+                              uint32_t MaxLength);
+
+int HdffCmdGetInterfaceVersion(int OsdDevice, uint32_t * Version, char * String,
+                               uint32_t MaxLength);
+
+int HdffCmdGetCopyrights(int OsdDevice, uint8_t Index, char * String,
+                         uint32_t MaxLength);
+
+#endif /* HDFFCMD_GENERIC_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,82 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdHdmiSetVideoMode(int OsdDevice, HdffVideoMode_t VideoMode)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_HDMI,
+                       HDFF_MSG_HDMI_SET_VIDEO_MODE);
+    BitBuffer_SetBits(&cmdBuf, 8, VideoMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdHdmiConfigure(int OsdDevice, const HdffHdmiConfig_t * Config)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_HDMI,
+                       HDFF_MSG_HDMI_CONFIGURE);
+    BitBuffer_SetBits(&cmdBuf, 1, Config->TransmitAudio ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, Config->ForceDviMode ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, Config->CecEnabled ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 3, Config->VideoModeAdaption);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdHdmiSendCecCommand(int OsdDevice, HdffCecCommand_t Command)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_HDMI,
+                       HDFF_MSG_HDMI_SEND_CEC_COMMAND);
+    BitBuffer_SetBits(&cmdBuf, 8, Command);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_hdmi.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,67 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_HDMI_H
+#define HDFFCMD_HDMI_H
+
+
+typedef enum HdffVideoMode_t
+{
+    HDFF_VIDEO_MODE_576P50 = 18,
+    HDFF_VIDEO_MODE_720P50 = 19,
+    HDFF_VIDEO_MODE_1080I50 = 20,
+    HDFF_VIDEO_MODE_576I50 = 22
+} HdffVideoMode_t;
+
+typedef enum HdffVideoModeAdaption_t
+{
+    HDFF_VIDEO_MODE_ADAPT_OFF,
+    HDFF_VIDEO_MODE_ADAPT_FRAME_RATE,
+    HDFF_VIDEO_MODE_ADAPT_ONLY_FOR_HD,
+    HDFF_VIDEO_MODE_ADAPT_ALWAYS
+} HdffVideoModeAdaption_t;
+
+typedef struct HdffHdmiConfig_t
+{
+    int TransmitAudio;
+    int ForceDviMode;
+    int CecEnabled;
+    HdffVideoModeAdaption_t VideoModeAdaption;
+} HdffHdmiConfig_t;
+
+typedef enum HdffCecCommand_t
+{
+    HDFF_CEC_COMMAND_TV_ON,
+    HDFF_CEC_COMMAND_TV_OFF,
+    HDFF_CEC_COMMAND_TV_ACTIVE_SOURCE,
+    HDFF_CEC_COMMAND_TV_INACTIVE_SOURCE
+} HdffCecCommand_t;
+
+
+int HdffCmdHdmiSetVideoMode(int OsdDevice, HdffVideoMode_t VideoMode);
+
+int HdffCmdHdmiConfigure(int OsdDevice, const HdffHdmiConfig_t * Config);
+
+int HdffCmdHdmiSendCecCommand(int OsdDevice, HdffCecCommand_t Command);
+
+#endif /* HDFFCMD_HDMI_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,81 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdMuxSetVideoOut(int OsdDevice, HdffVideoOut_t VideoOut)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_AV_MUX,
+                       HDFF_MSG_MUX_SET_VIDEO_OUT);
+    BitBuffer_SetBits(&cmdBuf, 4, VideoOut);
+    BitBuffer_SetBits(&cmdBuf, 4, 0); // reserved
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdMuxSetVolume(int OsdDevice, uint8_t Volume)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_AV_MUX,
+                       HDFF_MSG_MUX_SET_VOLUME);
+    BitBuffer_SetBits(&cmdBuf, 8, Volume);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdMuxMuteAudio(int OsdDevice, int Mute)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_AV_MUX,
+                       HDFF_MSG_MUX_SET_AUDIO_MUTE);
+    BitBuffer_SetBits(&cmdBuf, 1, Mute);
+    BitBuffer_SetBits(&cmdBuf, 7, 0); // reserved
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_mux.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,56 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_MUX_H
+#define HDFFCMD_MUX_H
+
+
+typedef enum HdffVideoOut_t
+{
+    HDFF_VIDEO_OUT_DISABLED,
+    HDFF_VIDEO_OUT_CVBS_RGB,
+    HDFF_VIDEO_OUT_CVBS_YUV,
+    HDFF_VIDEO_OUT_YC
+} HdffVideoOut_t;
+
+typedef enum HdffSlowBlank_t
+{
+    HDFF_SLOW_BLANK_OFF,
+    HDFF_SLOW_BLANK_16_BY_9,
+    HDFF_SLOW_BLANK_4_BY_3
+} HdffSlowBlank_t;
+
+typedef enum HdffFastBlank_t
+{
+    HDFF_FAST_BLANK_CVBS,
+    HDFF_FAST_BLANK_RGB
+} HdffFastBlank_t;
+
+
+int HdffCmdMuxSetVideoOut(int OsdDevice, HdffVideoOut_t VideoOut);
+
+int HdffCmdMuxSetVolume(int OsdDevice, uint8_t Volume);
+
+int HdffCmdMuxMuteAudio(int OsdDevice, int Mute);
+
+#endif /* HDFFCMD_MUX_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,637 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdOsdConfigure(int OsdDevice, const HdffOsdConfig_t * Config)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CONFIGURE);
+    if (Config->FontAntialiasing)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    if (Config->FontKerning)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdReset(int OsdDevice)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_RESET);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+
+int HdffCmdOsdCreateDisplay(int OsdDevice, uint16_t Width, uint16_t Height,
+                            HdffColorType_t ColorType, uint32_t * NewDisplay)
+{
+    uint8_t cmdData[16];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorType);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    *NewDisplay = HDFF_INVALID_HANDLE;
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            *NewDisplay = (resultData[6] << 24)
+                        | (resultData[7] << 16)
+                        | (resultData[8] << 8)
+                        | resultData[9];
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeleteDisplay(int OsdDevice, uint32_t Display)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdEnableDisplay(int OsdDevice, uint32_t Display, int Enable)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_ENABLE_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    if (Enable)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetDisplayOutputRectangle(int OsdDevice, uint32_t Display,
+                                        uint16_t X, uint16_t Y,
+                                        uint16_t Width, uint16_t Height)
+{
+    uint8_t cmdData[20];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_DISPLAY_OUTPUT_RECTANGLE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetDisplayClippingArea(int OsdDevice, uint32_t Display,
+                                     int Enable, uint16_t X, uint16_t Y,
+                                     uint16_t Width, uint16_t Height)
+{
+    uint8_t cmdData[20];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_DISPLAY_CLIPPLING_AREA);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    if (Enable)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    BitBuffer_SetBits(&cmdBuf, 7, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdRenderDisplay(int OsdDevice, uint32_t Display)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_RENDER_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSaveRegion(int OsdDevice, uint32_t Display,
+                         uint16_t X, uint16_t Y,
+                         uint16_t Width, uint16_t Height)
+{
+    uint8_t cmdData[20];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SAVE_REGION);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdRestoreRegion(int OsdDevice, uint32_t Display)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_RESTORE_REGION);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+
+int HdffCmdOsdCreatePalette(int OsdDevice, HdffColorType_t ColorType,
+                            HdffColorFormat_t ColorFormat,
+                            uint32_t NumColors, const uint32_t * Colors,
+                            uint32_t * NewPalette)
+{
+    uint8_t cmdData[1060];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_PALETTE);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorType);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorFormat);
+    if (NumColors > 256)
+        NumColors = 256;
+    BitBuffer_SetBits(&cmdBuf, 8, NumColors == 256 ? 0 : NumColors);
+    for (i = 0; i < NumColors; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 32, Colors[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    *NewPalette = HDFF_INVALID_HANDLE;
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            *NewPalette = (resultData[6] << 24)
+                        | (resultData[7] << 16)
+                        | (resultData[8] << 8)
+                        | resultData[9];
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeletePalette(int OsdDevice, uint32_t Palette)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_PALETTE);
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetDisplayPalette(int OsdDevice, uint32_t Display,
+                                uint32_t Palette)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_DISPLAY_PALETTE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetPaletteColors(int OsdDevice, uint32_t Palette,
+                               HdffColorFormat_t ColorFormat,
+                               uint8_t StartColor, uint32_t NumColors,
+                               const uint32_t * Colors)
+{
+    uint8_t cmdData[1060];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_PALETTE_COLORS);
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorFormat);
+    BitBuffer_SetBits(&cmdBuf, 8, StartColor);
+    if (NumColors > 256)
+        NumColors = 256;
+    BitBuffer_SetBits(&cmdBuf, 8, NumColors == 256 ? 0 : NumColors);
+    for (i = 0; i < NumColors; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 32, Colors[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdCreateFontFace(int OsdDevice, const uint8_t * FontData,
+                             uint32_t DataSize, uint32_t * NewFontFace)
+{
+    uint8_t cmdData[16];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+    int err;
+
+    *NewFontFace = HDFF_INVALID_HANDLE;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = FontData;
+    osd_data.data_length = DataSize;
+    err = ioctl(OsdDevice, OSD_RAW_DATA, &osd_data);
+    if (err != 0)
+        return err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_FONT_FACE);
+    BitBuffer_SetBits(&cmdBuf, 16, osd_data.data_handle);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            *NewFontFace = (resultData[6] << 24)
+                         | (resultData[7] << 16)
+                         | (resultData[8] << 8)
+                         | resultData[9];
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeleteFontFace(int OsdDevice, uint32_t FontFace)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_FONT_FACE);
+    BitBuffer_SetBits(&cmdBuf, 32, FontFace);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdCreateFont(int OsdDevice, uint32_t FontFace, uint32_t Size,
+                         uint32_t * NewFont)
+{
+    uint8_t cmdData[16];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    *NewFont = HDFF_INVALID_HANDLE;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_FONT);
+    BitBuffer_SetBits(&cmdBuf, 32, FontFace);
+    BitBuffer_SetBits(&cmdBuf, 32, Size);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            *NewFont = (resultData[6] << 24)
+                     | (resultData[7] << 16)
+                     | (resultData[8] << 8)
+                     | resultData[9];
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeleteFont(int OsdDevice, uint32_t Font)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_FONT);
+    BitBuffer_SetBits(&cmdBuf, 32, Font);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+
+int HdffCmdOsdDrawRectangle(int OsdDevice, uint32_t Display, uint16_t X,
+                            uint16_t Y, uint16_t Width, uint16_t Height,
+                            uint32_t Color)
+{
+    uint8_t cmdData[24];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_RECTANGLE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawEllipse(int OsdDevice, uint32_t Display, uint16_t CX,
+                          uint16_t CY, uint16_t RadiusX, uint16_t RadiusY,
+                          uint32_t Color, uint32_t Flags)
+{
+    uint8_t cmdData[28];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_ELLIPSE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, CX);
+    BitBuffer_SetBits(&cmdBuf, 16, CY);
+    BitBuffer_SetBits(&cmdBuf, 16, RadiusX);
+    BitBuffer_SetBits(&cmdBuf, 16, RadiusY);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 32, Flags);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawText(int OsdDevice, uint32_t Display, uint32_t Font,
+                       uint16_t X, uint16_t Y, const char * Text,
+                       uint32_t Color)
+{
+    uint8_t cmdData[1060];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int length;
+
+    length = 0;
+    while (Text[length])
+    {
+        length++;
+    }
+    if (length > 980)
+        length = 980;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_TEXT);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 32, Font);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 16, length);
+    for (i = 0; i < length; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 8, Text[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawWideText(int OsdDevice, uint32_t Display, uint32_t Font,
+                           uint16_t X, uint16_t Y, const uint16_t * Text,
+                           uint32_t Color)
+{
+    uint8_t cmdData[1060];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int length;
+
+    length = 0;
+    while (Text[length])
+    {
+        length++;
+    }
+    if (length > 480)
+        length = 480;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_WIDE_TEXT);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 32, Font);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 16, length);
+    for (i = 0; i < length; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 16, Text[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawBitmap(int OsdDevice, uint32_t Display, uint16_t X,
+                         uint16_t Y, const uint8_t * Bitmap, uint16_t BmpWidth,
+                         uint16_t BmpHeight, uint32_t BmpSize,
+                         HdffColorType_t ColorType, uint32_t Palette)
+{
+    uint8_t cmdData[32];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+    int err;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = Bitmap;
+    osd_data.data_length = BmpSize;
+    err = ioctl(OsdDevice, OSD_RAW_DATA, &osd_data);
+    if (err != 0)
+        return err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_BITMAP);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, BmpWidth);
+    BitBuffer_SetBits(&cmdBuf, 16, BmpHeight);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorType);
+    BitBuffer_SetBits(&cmdBuf, 6, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 2, 0); // uncompressed
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    BitBuffer_SetBits(&cmdBuf, 16, osd_data.data_handle);
+    BitBuffer_SetBits(&cmdBuf, 32, 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_osd.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,161 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_OSD_H
+#define HDFFCMD_OSD_H
+
+
+#define HDFF_INVALID_HANDLE             0xFFFFFFFF
+#define HDFF_SCREEN_DISPLAY_HANDLE      0xFFFFFFFE
+
+#define HDFF_POSITION_SCREEN_CENTERED   0xFFFF
+
+#define HDFF_SIZE_FULL_SCREEN           0xFFFF
+#define HDFF_SIZE_SAME_AS_SOURCE        0xFFFE
+
+#define HDFF_FONT_FACE_TIRESIAS         0x00000000
+
+
+typedef struct HdffOsdConfig_t
+{
+    int FontAntialiasing;
+    int FontKerning;
+} HdffOsdConfig_t;
+
+typedef enum HdffColorType_t
+{
+    HDFF_COLOR_TYPE_CLUT1,
+    HDFF_COLOR_TYPE_CLUT2,
+    HDFF_COLOR_TYPE_CLUT4,
+    HDFF_COLOR_TYPE_CLUT8,
+    HDFF_COLOR_TYPE_ARGB8888,
+    HDFF_COLOR_TYPE_ARGB8565,
+    HDFF_COLOR_TYPE_ARGB4444,
+    HDFF_COLOR_TYPE_ARGB1555,
+    HDFF_COLOR_TYPE_RGB888,
+    HDFF_COLOR_TYPE_RGB565
+} HdffColorType_t;
+
+typedef enum HdffColorFormat_t
+{
+    HDFF_COLOR_FORMAT_ARGB,
+    HDFF_COLOR_FORMAT_ACBYCR
+} HdffColorFormat_t;
+
+typedef enum HdffDrawingFlags_t
+{
+    HDFF_DRAW_FULL,
+    HDFF_DRAW_HALF_TOP,
+    HDFF_DRAW_HALF_LEFT,
+    HDFF_DRAW_HALF_BOTTOM,
+    HDFF_DRAW_HALF_RIGHT,
+    HDFF_DRAW_QUARTER_TOP_LEFT,
+    HDFF_DRAW_QUARTER_TOP_RIGHT,
+    HDFF_DRAW_QUARTER_BOTTOM_LEFT,
+    HDFF_DRAW_QUARTER_BOTTOM_RIGHT,
+    HDFF_DRAW_QUARTER_TOP_LEFT_INVERTED,
+    HDFF_DRAW_QUARTER_TOP_RIGHT_INVERTED,
+    HDFF_DRAW_QUARTER_BOTTOM_LEFT_INVERTED,
+    HDFF_DRAW_QUARTER_BOTTOM_RIGHT_INVERTED
+} HdffDrawingFlags_t;
+
+
+int HdffCmdOsdConfigure(int OsdDevice, const HdffOsdConfig_t * Config);
+
+int HdffCmdOsdReset(int OsdDevice);
+
+
+int HdffCmdOsdCreateDisplay(int OsdDevice, uint16_t Width, uint16_t Height,
+                            HdffColorType_t ColorType, uint32_t * NewDisplay);
+
+int HdffCmdOsdDeleteDisplay(int OsdDevice, uint32_t Display);
+
+int HdffCmdOsdEnableDisplay(int OsdDevice, uint32_t Display, int Enable);
+
+int HdffCmdOsdSetDisplayOutputRectangle(int OsdDevice, uint32_t Display,
+                                        uint16_t X, uint16_t Y,
+                                        uint16_t Width, uint16_t Height);
+
+int HdffCmdOsdSetDisplayClippingArea(int OsdDevice, uint32_t Display,
+                                     int Enable, uint16_t X, uint16_t Y,
+                                     uint16_t Width, uint16_t Height);
+
+int HdffCmdOsdRenderDisplay(int OsdDevice, uint32_t Display);
+
+int HdffCmdOsdSaveRegion(int OsdDevice, uint32_t Display,
+                         uint16_t X, uint16_t Y,
+                         uint16_t Width, uint16_t Height);
+
+int HdffCmdOsdRestoreRegion(int OsdDevice, uint32_t Display);
+
+
+int HdffCmdOsdCreatePalette(int OsdDevice, HdffColorType_t ColorType,
+                            HdffColorFormat_t ColorFormat,
+                            uint32_t NumColors, const uint32_t * Colors,
+                            uint32_t * NewPalette);
+
+int HdffCmdOsdDeletePalette(int OsdDevice, uint32_t Palette);
+
+int HdffCmdOsdSetDisplayPalette(int OsdDevice, uint32_t Display,
+                                uint32_t Palette);
+
+int HdffCmdOsdSetPaletteColors(int OsdDevice, uint32_t Palette,
+                               HdffColorFormat_t ColorFormat,
+                               uint8_t StartColor, uint32_t NumColors,
+                               const uint32_t * Colors);
+
+
+int HdffCmdOsdCreateFontFace(int OsdDevice, const uint8_t * FontData,
+                             uint32_t DataSize, uint32_t * NewFontFace);
+
+int HdffCmdOsdDeleteFontFace(int OsdDevice, uint32_t FontFace);
+
+int HdffCmdOsdCreateFont(int OsdDevice, uint32_t FontFace, uint32_t Size,
+                         uint32_t * NewFont);
+
+int HdffCmdOsdDeleteFont(int OsdDevice, uint32_t Font);
+
+
+int HdffCmdOsdDrawRectangle(int OsdDevice, uint32_t Display, uint16_t X,
+                            uint16_t Y, uint16_t Width, uint16_t Height,
+                            uint32_t Color);
+
+int HdffCmdOsdDrawEllipse(int OsdDevice, uint32_t Display, uint16_t CX,
+                          uint16_t CY, uint16_t RadiusX, uint16_t RadiusY,
+                          uint32_t Color, uint32_t Flags);
+
+int HdffCmdOsdDrawText(int OsdDevice, uint32_t Display, uint32_t Font,
+                       uint16_t X, uint16_t Y, const char * Text,
+                       uint32_t Color);
+
+int HdffCmdOsdDrawWideText(int OsdDevice, uint32_t Display, uint32_t Font,
+                           uint16_t X, uint16_t Y, const uint16_t * Text,
+                           uint32_t Color);
+
+int HdffCmdOsdDrawBitmap(int OsdDevice, uint32_t Display, uint16_t X,
+                         uint16_t Y, const uint8_t * Bitmap, uint16_t BmpWidth,
+                         uint16_t BmpHeight, uint32_t BmpSize,
+                         HdffColorType_t ColorType, uint32_t Palette);
+
+
+#endif /* HDFFCMD_OSD_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.c vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.c	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,67 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdRemoteSetProtocol(int OsdDevice, HdffRemoteProtocol_t Protocol)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_REMOTE_CONTROL,
+                       HDFF_MSG_REMOTE_SET_PROTOCOL);
+    BitBuffer_SetBits(&cmdBuf, 8, Protocol);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdRemoteSetAddressFilter(int OsdDevice, int Enable, uint32_t Address)
+{
+    uint8_t cmdData[12];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_REMOTE_CONTROL,
+                       HDFF_MSG_REMOTE_SET_ADDRESS_FILTER);
+    BitBuffer_SetBits(&cmdBuf, 1, Enable);
+    BitBuffer_SetBits(&cmdBuf, 7, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 32, Address);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.h vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_remote.h	2011-10-16 17:12:49.000000000 +0200
@@ -0,0 +1,39 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_REMOTE_H
+#define HDFFCMD_REMOTE_H
+
+typedef enum HdffRemoteProtocol_t
+{
+    HDFF_REMOTE_PROTOCOL_NONE,
+    HDFF_REMOTE_PROTOCOL_RC5,
+    HDFF_REMOTE_PROTOCOL_RC6
+} HdffRemoteProtocol_t;
+
+
+int HdffCmdRemoteSetProtocol(int OsdDevice, HdffRemoteProtocol_t Protocol);
+
+int HdffCmdRemoteSetAddressFilter(int OsdDevice, int Enable, uint32_t Address);
+
+#endif /* HDFFCMD_REMOTE_H */
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/po/fi_FI.po vdr-1.7.22/PLUGINS/src/dvbhddevice/po/fi_FI.po
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/po/fi_FI.po	2011-08-27 11:37:09.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/po/fi_FI.po	2011-09-10 12:20:35.000000000 +0200
@@ -20,13 +20,13 @@
 msgstr "DVB-laite HD-ulostulolla"
 
 msgid "Off"
-msgstr ""
+msgstr "ei"
 
 msgid "Frame rate"
-msgstr ""
+msgstr "kuvataajuuden mukaan"
 
 msgid "HD Only"
-msgstr ""
+msgstr "vain HD-resoluutiolla"
 
 msgid "Always"
 msgstr "aina"
@@ -68,7 +68,7 @@
 msgstr "Kuvaresoluutio"
 
 msgid "Video Mode Adaption"
-msgstr ""
+msgstr "Sovita näyttömoodi"
 
 msgid "TV format"
 msgstr "Näytön kuvasuhde"
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/setup.c vdr-1.7.22/PLUGINS/src/dvbhddevice/setup.c
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/setup.c	2011-08-27 11:35:35.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/setup.c	2011-12-04 16:31:58.000000000 +0100
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: setup.c 1.13 2011/08/27 09:35:35 kls Exp $
+ * $Id: setup.c 1.14 2011/12/04 15:31:58 kls Exp $
  */
 
 #include "setup.h"
@@ -20,12 +20,12 @@
 cHdffSetup::cHdffSetup(void)
 {
     Resolution = kResolution1080i;
-    VideoModeAdaption = HDFF::videoModeAdaptOff;
-    TvFormat = HDFF::tvFormat16by9;
-    VideoConversion = HDFF::videoConversionPillarbox;
-    AnalogueVideo = HDFF::videoOutCvbsYuv;
+    VideoModeAdaption = HDFF_VIDEO_MODE_ADAPT_OFF;
+    TvFormat = HDFF_TV_FORMAT_16_BY_9;
+    VideoConversion = HDFF_VIDEO_CONVERSION_PILLARBOX;
+    AnalogueVideo = HDFF_VIDEO_OUT_CVBS_YUV;
     AudioDelay = 0;
-    AudioDownmix = HDFF::downmixAutomatic;
+    AudioDownmix = HDFF_AUDIO_DOWNMIX_AUTOMATIC;
     OsdSize = 0;
     CecEnabled = 1;
     RemoteProtocol = 1;
@@ -68,7 +68,7 @@
             Width = 720;
             Height = 576;
         }
-        if (TvFormat == HDFF::tvFormat16by9)
+        if (TvFormat == HDFF_TV_FORMAT_16_BY_9)
             PixelAspect = 16.0 / 9.0;
         else
             PixelAspect = 4.0 / 3.0;
@@ -96,19 +96,19 @@
     PixelAspect /= double(Width) / Height;
 }
 
-HDFF::eHdmiVideoMode cHdffSetup::GetVideoMode(void)
+HdffVideoMode_t cHdffSetup::GetVideoMode(void)
 {
     switch (Resolution)
     {
         case kResolution1080i:
         default:
-            return HDFF::videoMode1080i50;
+            return HDFF_VIDEO_MODE_1080I50;
         case kResolution720p:
-            return HDFF::videoMode720p50;
+            return HDFF_VIDEO_MODE_720P50;
         case kResolution576p:
-            return HDFF::videoMode576p50;
+            return HDFF_VIDEO_MODE_576P50;
         case kResolution576i:
-            return HDFF::videoMode576i50;
+            return HDFF_VIDEO_MODE_576I50;
     }
 }
 
@@ -233,27 +233,27 @@
         {
             mHdffCmdIf->CmdHdmiSetVideoMode(mNewHdffSetup.GetVideoMode());
         }
-        HDFF::tVideoFormat videoFormat;
-        HDFF::tHdmiConfig hdmiConfig;
+        HdffVideoFormat_t videoFormat;
+        HdffHdmiConfig_t hdmiConfig;
 
         videoFormat.AutomaticEnabled = true;
         videoFormat.AfdEnabled = true;
-        videoFormat.TvFormat = (HDFF::eTvFormat) mNewHdffSetup.TvFormat;
-        videoFormat.VideoConversion = (HDFF::eVideoConversion) mNewHdffSetup.VideoConversion;
+        videoFormat.TvFormat = (HdffTvFormat_t) mNewHdffSetup.TvFormat;
+        videoFormat.VideoConversion = (HdffVideoConversion_t) mNewHdffSetup.VideoConversion;
         mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
 
         mHdffCmdIf->CmdAvSetAudioDelay(mNewHdffSetup.AudioDelay);
-        mHdffCmdIf->CmdAvSetAudioDownmix((HDFF::eDownmixMode) mNewHdffSetup.AudioDownmix);
+        mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) mNewHdffSetup.AudioDownmix);
 
-        mHdffCmdIf->CmdMuxSetVideoOut((HDFF::eVideoOut) mNewHdffSetup.AnalogueVideo);
+        mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) mNewHdffSetup.AnalogueVideo);
 
         hdmiConfig.TransmitAudio = true;
         hdmiConfig.ForceDviMode = false;
         hdmiConfig.CecEnabled = mNewHdffSetup.CecEnabled;
-        hdmiConfig.VideoModeAdaption = (HDFF::eVideoModeAdaption) mNewHdffSetup.VideoModeAdaption;
+        hdmiConfig.VideoModeAdaption = (HdffVideoModeAdaption_t) mNewHdffSetup.VideoModeAdaption;
         mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
 
-        mHdffCmdIf->CmdRemoteSetProtocol((HDFF::eRemoteProtocol) mNewHdffSetup.RemoteProtocol);
+        mHdffCmdIf->CmdRemoteSetProtocol((HdffRemoteProtocol_t) mNewHdffSetup.RemoteProtocol);
         mHdffCmdIf->CmdRemoteSetAddressFilter(mNewHdffSetup.RemoteAddress >= 0, mNewHdffSetup.RemoteAddress);
     }
 
diff -ruN vdr-1.7.21/PLUGINS/src/dvbhddevice/setup.h vdr-1.7.22/PLUGINS/src/dvbhddevice/setup.h
--- vdr-1.7.21/PLUGINS/src/dvbhddevice/setup.h	2011-08-27 11:36:02.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/dvbhddevice/setup.h	2011-12-04 16:32:13.000000000 +0100
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: setup.h 1.9 2011/08/27 09:36:02 kls Exp $
+ * $Id: setup.h 1.10 2011/12/04 15:32:13 kls Exp $
  */
 
 #ifndef _HDFF_SETUP_H_
@@ -17,7 +17,7 @@
     cHdffSetup(void);
     bool SetupParse(const char * Name, const char * Value);
     void GetOsdSize(int &Width, int &Height, double &PixelAspect);
-    HDFF::eHdmiVideoMode GetVideoMode(void);
+    HdffVideoMode_t GetVideoMode(void);
 
     int Resolution;
     int VideoModeAdaption;
diff -ruN vdr-1.7.21/PLUGINS/src/pictures/HISTORY vdr-1.7.22/PLUGINS/src/pictures/HISTORY
--- vdr-1.7.21/PLUGINS/src/pictures/HISTORY	2011-08-14 15:46:39.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/pictures/HISTORY	2011-11-02 21:58:22.000000000 +0100
@@ -55,3 +55,7 @@
 - The pic2mpg script now generates HD images (thanks to Andre Weidemann for his
   support in using convert/ffmpeg). The old SD version is still available as
   pic2mpg-sd.
+
+2011-11-02:
+
+- Fixed handling images that are rotated by 180 degrees in pic2mpg.
diff -ruN vdr-1.7.21/PLUGINS/src/pictures/pic2mpg vdr-1.7.22/PLUGINS/src/pictures/pic2mpg
--- vdr-1.7.21/PLUGINS/src/pictures/pic2mpg	2011-08-14 15:34:15.000000000 +0200
+++ vdr-1.7.22/PLUGINS/src/pictures/pic2mpg	2011-11-02 18:20:37.000000000 +0100
@@ -7,7 +7,7 @@
 #
 # See the README file for copyright information and how to reach the author.
 #
-# $Id: pic2mpg 2.2 2011/08/14 13:34:15 kls Exp $
+# $Id: pic2mpg 2.3 2011/11/02 17:20:37 kls Exp $
 
 use File::Path;
 use File::Spec;
@@ -124,7 +124,7 @@
   return if (!defined $PICTYPES{$Type});
   my $Exif = ImageInfo($Pict);
   my $Orientation = $$Exif{"Orientation"};
-  my ($Degrees) = $Orientation =~ /Rotate ([0-9]+) /; 
+  my ($Degrees) = $Orientation =~ /Rotate ([0-9]+)/; 
   my $Rotate = $Degrees ? "-rotate $Degrees" : "";
   print "orientation = '$Orientation' -> rotation = $Rotate\n" if ($Detailed);
   $Pict = EscapeMeta($Pict);
diff -ruN vdr-1.7.21/ci.h vdr-1.7.22/ci.h
--- vdr-1.7.21/ci.h	2007-01-03 13:49:10.000000000 +0100
+++ vdr-1.7.22/ci.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: ci.h 2.0 2007/01/03 12:49:10 kls Exp $
+ * $Id: ci.h 2.1 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __CI_H
@@ -220,7 +220,7 @@
        ///< CAM is currently not decrypting anything. If there is already a
        ///< channel being decrypted, a call to CanDecrypt() checks whether the
        ///< CAM can also decrypt the given channel. Only CAMs that have replied
-       ///< to the inital QUERY will perform this check at all. CAMs that never
+       ///< to the initial QUERY will perform this check at all. CAMs that never
        ///< replied to the initial QUERY are assumed not to be able to handle
        ///< more than one channel at a time.
   void StartDecrypting(void);
diff -ruN vdr-1.7.21/config.c vdr-1.7.22/config.c
--- vdr-1.7.21/config.c	2011-08-20 11:12:05.000000000 +0200
+++ vdr-1.7.22/config.c	2011-12-03 16:21:30.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.c 2.15 2011/08/20 09:12:05 kls Exp $
+ * $Id: config.c 2.16 2011/12/03 15:21:30 kls Exp $
  */
 
 #include "config.h"
@@ -63,6 +63,69 @@
   return (Address & mask) == (addr.s_addr & mask);
 }
 
+// --- cSatCableNumbers ------------------------------------------------------
+
+cSatCableNumbers::cSatCableNumbers(int Size, const char *s)
+{
+  size = Size;
+  array = MALLOC(int, size);
+  memset(array, size * sizeof(int), 0);
+  FromString(s);
+}
+
+cSatCableNumbers::~cSatCableNumbers()
+{
+  free(array);
+}
+
+bool cSatCableNumbers::FromString(const char *s)
+{
+  char *t;
+  int i = 0;
+  const char *p = s;
+  while (p && *p) {
+        int n = strtol(p, &t, 10);
+        if (t != p) {
+           if (i < size)
+              array[i++] = n;
+           else {
+              esyslog("ERROR: too many sat cable numbers in '%s'", s);
+              return false;
+              }
+           }
+        else {
+           esyslog("ERROR: invalid sat cable number in '%s'", s);
+           return false;
+           }
+        p = skipspace(t);
+        }
+  for ( ; i < size; i++)
+      array[i] = 0;
+  return true;
+}
+
+cString cSatCableNumbers::ToString(void)
+{
+  cString s("");
+  for (int i = 0; i < size; i++) {
+      s = cString::sprintf("%s%d ", *s, array[i]);
+      }
+  return s;
+}
+
+int cSatCableNumbers::FirstDeviceIndex(int DeviceIndex) const
+{
+  if (0 <= DeviceIndex && DeviceIndex < size) {
+     if (int CableNr = array[DeviceIndex]) {
+        for (int i = 0; i < size; i++) {
+            if (i < DeviceIndex && array[i] == CableNr)
+               return i;
+            }
+        }
+     }
+  return -1;
+}
+
 // --- cNestedItem -----------------------------------------------------------
 
 cNestedItem::cNestedItem(const char *Text, bool WithSubItems)
@@ -396,6 +459,7 @@
   CurrentVolume = MAXVOLUME;
   CurrentDolby = 0;
   InitialChannel = "";
+  DeviceBondings = "";
   InitialVolume = -1;
   ChannelsWrap = 0;
   EmergencyExit = 1;
@@ -405,6 +469,7 @@
 {
   memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__);
   InitialChannel = s.InitialChannel;
+  DeviceBondings = s.DeviceBondings;
   return *this;
 }
 
@@ -589,6 +654,7 @@
   else if (!strcasecmp(Name, "CurrentDolby"))        CurrentDolby       = atoi(Value);
   else if (!strcasecmp(Name, "InitialChannel"))      InitialChannel     = Value;
   else if (!strcasecmp(Name, "InitialVolume"))       InitialVolume      = atoi(Value);
+  else if (!strcasecmp(Name, "DeviceBondings"))      DeviceBondings     = Value;
   else if (!strcasecmp(Name, "ChannelsWrap"))        ChannelsWrap       = atoi(Value);
   else if (!strcasecmp(Name, "EmergencyExit"))       EmergencyExit      = atoi(Value);
   else
@@ -685,6 +751,7 @@
   Store("CurrentDolby",       CurrentDolby);
   Store("InitialChannel",     InitialChannel);
   Store("InitialVolume",      InitialVolume);
+  Store("DeviceBondings",     DeviceBondings);
   Store("ChannelsWrap",       ChannelsWrap);
   Store("EmergencyExit",      EmergencyExit);
 
diff -ruN vdr-1.7.21/config.h vdr-1.7.22/config.h
--- vdr-1.7.21/config.h	2011-08-20 10:51:47.000000000 +0200
+++ vdr-1.7.22/config.h	2011-12-03 15:19:52.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.h 2.34 2011/08/20 08:51:47 kls Exp $
+ * $Id: config.h 2.36 2011/12/03 14:19:52 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -22,13 +22,13 @@
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.7.21"
-#define VDRVERSNUM   10721  // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION  "1.7.22"
+#define VDRVERSNUM   10722  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
 
-#define APIVERSION  "1.7.21"
-#define APIVERSNUM   10721  // Version * 10000 + Major * 100 + Minor
+#define APIVERSION  "1.7.22"
+#define APIVERSNUM   10722  // Version * 10000 + Major * 100 + Minor
 
 // When loading plugins, VDR searches them by their APIVERSION, which
 // may be smaller than VDRVERSION in case there have been no changes to
@@ -61,6 +61,25 @@
   bool Accepts(in_addr_t Address);
   };
 
+class cSatCableNumbers {
+private:
+  int size;
+  int *array;
+public:
+  cSatCableNumbers(int Size, const char *s = NULL);
+  ~cSatCableNumbers();
+  int Size(void) const { return size; }
+  int *Array(void) { return array; }
+  bool FromString(const char *s);
+  cString ToString(void);
+  int FirstDeviceIndex(int DeviceIndex) const;
+      ///< Returns the first device index (starting at 0) that uses the same
+      ///< sat cable number as the device with the given DeviceIndex.
+      ///< If the given device does not use the same sat cable as any other device,
+      ///< or if the resulting value would be the same as DeviceIndex,
+      ///< or if DeviceIndex is out of range, -1 is returned.
+  };
+
 template<class T> class cConfig : public cList<T> {
 private:
   char *fileName;
@@ -292,6 +311,7 @@
   int EmergencyExit;
   int __EndData__;
   cString InitialChannel;
+  cString DeviceBondings;
   cSetup(void);
   cSetup& operator= (const cSetup &s);
   bool Load(const char *FileName);
diff -ruN vdr-1.7.21/cutter.c vdr-1.7.22/cutter.c
--- vdr-1.7.21/cutter.c	2011-08-21 13:08:08.000000000 +0200
+++ vdr-1.7.22/cutter.c	2011-12-04 13:55:53.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: cutter.c 2.8 2011/08/21 11:08:08 kls Exp $
+ * $Id: cutter.c 2.10 2011/12/04 12:55:53 kls Exp $
  */
 
 #include "cutter.h"
@@ -100,7 +100,8 @@
            if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
               if (FileNumber != CurrentFileNumber) {
                  fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
-                 fromFile->SetReadAhead(MEGABYTE(20));
+                 if (fromFile)
+                    fromFile->SetReadAhead(MEGABYTE(20));
                  CurrentFileNumber = FileNumber;
                  }
               if (fromFile) {
@@ -210,7 +211,7 @@
      cRecording Recording(FileName);
 
      cMarks FromMarks;
-     FromMarks.Load(FileName);
+     FromMarks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
      if (cMark *First = FromMarks.First())
         Recording.SetStartTime(Recording.Start() + (int(First->Position() / Recording.FramesPerSecond() + 30) / 60) * 60);
 
diff -ruN vdr-1.7.21/device.c vdr-1.7.22/device.c
--- vdr-1.7.21/device.c	2011-08-26 14:56:00.000000000 +0200
+++ vdr-1.7.22/device.c	2011-10-16 16:36:43.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.c 2.42 2011/08/26 12:56:00 kls Exp $
+ * $Id: device.c 2.44 2011/10/16 14:36:43 kls Exp $
  */
 
 #include "device.h"
@@ -95,6 +95,8 @@
   camSlot = NULL;
   startScrambleDetection = 0;
 
+  occupiedTimeout = 0;
+
   player = NULL;
   isPlayingVideo = false;
   ClrAvailableTracks();
@@ -638,14 +640,14 @@
   return NULL;
 }
 
-bool cDevice::IsTunedToTransponder(const cChannel *Channel)
+bool cDevice::IsTunedToTransponder(const cChannel *Channel) const
 {
   return false;
 }
 
-bool cDevice::MaySwitchTransponder(void)
+bool cDevice::MaySwitchTransponder(const cChannel *Channel) const
 {
-  return !Receiving(true) && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid);
+  return time(NULL) > occupiedTimeout && !Receiving(true) && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid);
 }
 
 bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
@@ -786,6 +788,18 @@
      }
 }
 
+int cDevice::Occupied(void) const
+{
+  int Seconds = occupiedTimeout - time(NULL);
+  return Seconds > 0 ? Seconds : 0;
+}
+
+void cDevice::SetOccupied(int Seconds)
+{
+  if (Seconds >= 0)
+     occupiedTimeout = time(NULL) + min(Seconds, MAXOCCUPIEDTIMEOUT);
+}
+
 bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 {
   return false;
@@ -1474,6 +1488,7 @@
 int cDevice::Priority(void) const
 {
   int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY;
+  cMutexLock MutexLock(&mutexReceiver);
   for (int i = 0; i < MAXRECEIVERS; i++) {
       if (receiver[i])
          priority = max(receiver[i]->priority, priority);
@@ -1488,6 +1503,7 @@
 
 bool cDevice::Receiving(bool CheckAny) const
 {
+  cMutexLock MutexLock(&mutexReceiver);
   for (int i = 0; i < MAXRECEIVERS; i++) {
       if (receiver[i] && (CheckAny || receiver[i]->priority >= 0)) // cReceiver with priority < 0 doesn't count
          return true;
diff -ruN vdr-1.7.21/device.h vdr-1.7.22/device.h
--- vdr-1.7.21/device.h	2011-08-26 14:52:29.000000000 +0200
+++ vdr-1.7.22/device.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.h 2.27 2011/08/26 12:52:29 kls Exp $
+ * $Id: device.h 2.30 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __DEVICE_H
@@ -30,6 +30,7 @@
 #define MAXRECEIVERS       16 // the maximum number of receivers per device
 #define MAXVOLUME         255
 #define VOLUMEDELTA         5 // used to increase/decrease the volume
+#define MAXOCCUPIEDTIMEOUT 99 // max. time (in seconds) a device may be occupied
 
 enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed };
 
@@ -220,6 +221,8 @@
 
 // Channel facilities
 
+private:
+  time_t occupiedTimeout;
 protected:
   static int currentChannel;
 public:
@@ -272,12 +275,14 @@
          ///< This is not one of the channels in the global cChannels list, but rather
          ///< a local copy. The result may be NULL if the device is not tuned to any
          ///< transponder.
-  virtual bool IsTunedToTransponder(const cChannel *Channel);
+  virtual bool IsTunedToTransponder(const cChannel *Channel) const;
          ///< Returns true if this device is currently tuned to the given Channel's
          ///< transponder.
-  virtual bool MaySwitchTransponder(void);
-         ///< Returns true if it is ok to switch the transponder on this device,
-         ///< without disturbing any other activities.
+  virtual bool MaySwitchTransponder(const cChannel *Channel) const;
+         ///< Returns true if it is ok to switch to the Channel's transponder on this
+         ///< device, without disturbing any other activities. If an occupied timeout
+         ///< has been set for this device, and that timeout has not yet expired,
+         ///< this function returns false,
   bool SwitchChannel(const cChannel *Channel, bool LiveView);
          ///< Switches the device to the given Channel, initiating transfer mode
          ///< if necessary.
@@ -300,6 +305,16 @@
          ///< channel number while replaying.
   void ForceTransferMode(void);
          ///< Forces the device into transfermode for the current channel.
+  int Occupied(void) const;
+         ///< Returns the number of seconds this device is still occupied for.
+  void SetOccupied(int Seconds);
+         ///< Sets the occupied timeout for this device to the given number of
+         ///< Seconds, This can be used to tune a device to a particular transponder
+         ///< and make sure it will stay there for a certain amount of time, for
+         ///< instance to collect EPG data. This function shall only be called
+         ///< after the device has been successfully tuned to the requested transponder.
+         ///< Seconds will be silently limited to MAXOCCUPIEDTIMEOUT. Values less than
+         ///< 0 will be silently ignored.
   virtual bool HasLock(int TimeoutMs = 0);
          ///< Returns true if the device has a lock on the requested transponder.
          ///< Default is true, a specific device implementation may return false
@@ -457,7 +472,7 @@
        ///< Sets the current subtitle track to the given value.
 public:
   void ClrAvailableTracks(bool DescriptionsOnly = false, bool IdsOnly = false);
-       ///< Clears the list of currently availabe tracks. If DescriptionsOnly
+       ///< Clears the list of currently available tracks. If DescriptionsOnly
        ///< is true, only the track descriptions will be cleared. With IdsOnly
        ///< set to true only the ids will be cleared. IdsOnly is only taken
        ///< into account if DescriptionsOnly is false.
@@ -650,10 +665,10 @@
        ///< Returns true if the device itself or any of the file handles in
        ///< Poller is ready for further action.
        ///< If TimeoutMs is not zero, the device will wait up to the given number
-       ///< of milleseconds before returning in case it can't accept any data.
+       ///< of milliseconds before returning in case it can't accept any data.
   virtual bool Flush(int TimeoutMs = 0);
        ///< Returns true if the device's output buffers are empty, i. e. any
-       ///< data which was bufferd so far has been processed.
+       ///< data which was buffered so far has been processed.
        ///< If TimeoutMs is not zero, the device will wait up to the given
        ///< number of milliseconds before returning in case there is still
        ///< data in the buffers.
@@ -697,7 +712,7 @@
 // Receiver facilities
 
 private:
-  cMutex mutexReceiver;
+  mutable cMutex mutexReceiver;
   cReceiver *receiver[MAXRECEIVERS];
 public:
   int Priority(void) const;
@@ -726,7 +741,7 @@
        ///< Detaches the given receiver from this device.
   void DetachAll(int Pid);
        ///< Detaches all receivers from this device for this pid.
-  void DetachAllReceivers(void);
+  virtual void DetachAllReceivers(void);
        ///< Detaches all receivers from this device.
   };
 
diff -ruN vdr-1.7.21/diseqc.c vdr-1.7.22/diseqc.c
--- vdr-1.7.21/diseqc.c	2011-08-06 12:32:18.000000000 +0200
+++ vdr-1.7.22/diseqc.c	2011-09-17 16:13:31.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: diseqc.c 2.5 2011/08/06 10:32:18 kls Exp $
+ * $Id: diseqc.c 2.9 2011/09/17 14:13:31 kls Exp $
  */
 
 #include "diseqc.h"
@@ -12,6 +12,81 @@
 #include "sources.h"
 #include "thread.h"
 
+static bool ParseDeviceNumbers(const char *s, int &Devices)
+{
+  if (*s && s[strlen(s) - 1] == ':') {
+     const char *p = s;
+     while (*p && *p != ':') {
+           char *t = NULL;
+           int d = strtol(p, &t, 10);
+           p = t;
+           if (0 < d && d < 31)
+              Devices |= (1 << d - 1);
+           else {
+              esyslog("ERROR: invalid device number %d in '%s'", d, s);
+              return false;
+              }
+           }
+     }
+  return true;
+}
+
+// --- cScr ------------------------------------------------------------------
+
+cScr::cScr(void)
+{
+  devices = 0;
+  channel = -1;
+  userBand = 0;
+  pin = -1;
+  used = false;
+}
+
+bool cScr::Parse(const char *s)
+{
+  if (!ParseDeviceNumbers(s, devices))
+     return false;
+  if (devices)
+     return true;
+  bool result = false;
+  int fields = sscanf(s, "%d %u %d", &channel, &userBand, &pin);
+  if (fields == 2 || fields == 3) {
+     if (channel >= 0 && channel < 8) {
+        result = true;
+        if (fields == 3 && (pin < 0 || pin > 255)) {
+           esyslog("Error: invalid SCR pin '%d'", pin);
+           result = false;
+           }
+        }
+     else
+        esyslog("Error: invalid SCR channel '%d'", channel);
+     }
+  return result;
+}
+
+// --- cScrs -----------------------------------------------------------------
+
+cScrs Scrs;
+
+cScr *cScrs::GetUnused(int Device)
+{
+  cMutexLock MutexLock(&mutex);
+  int Devices = 0;
+  for (cScr *p = First(); p; p = Next(p)) {
+      if (p->Devices()) {
+         Devices = p->Devices();
+         continue;
+         }
+      if (Devices && !(Devices & (1 << Device - 1)))
+         continue;
+      if (!p->Used()) {
+        p->SetUsed(true);
+        return p;
+        }
+      }
+  return NULL;
+}
+
 // --- cDiseqc ---------------------------------------------------------------
 
 cDiseqc::cDiseqc(void)
@@ -21,9 +96,9 @@
   slof = 0;
   polarization = 0;
   lof = 0;
+  scrBank = -1;
   commands = NULL;
   parsing = false;
-  numCodes = 0;
 }
 
 cDiseqc::~cDiseqc()
@@ -33,23 +108,12 @@
 
 bool cDiseqc::Parse(const char *s)
 {
+  if (!ParseDeviceNumbers(s, devices))
+     return false;
+  if (devices)
+     return true;
   bool result = false;
   char *sourcebuf = NULL;
-  if (*s && s[strlen(s) - 1] == ':') {
-     const char *p = s;
-     while (*p && *p != ':') {
-           char *t = NULL;
-           int d = strtol(p, &t, 10);
-           p = t;
-           if (0 < d && d < 32)
-              devices |= (1 << d - 1);
-           else {
-              esyslog("ERROR: invalid device number %d in '%s'", d, s);
-              return false;
-              }
-           }
-     return true;
-     }
   int fields = sscanf(s, "%a[^ ] %d %c %d %a[^\n]", &sourcebuf, &slof, &polarization, &lof, &commands);
   if (fields == 4)
      commands = NULL; //XXX Apparently sscanf() doesn't work correctly if the last %a argument results in an empty string
@@ -60,7 +124,7 @@
         if (polarization == 'V' || polarization == 'H' || polarization == 'L' || polarization == 'R') {
            parsing = true;
            const char *CurrentAction = NULL;
-           while (Execute(&CurrentAction) != daNone)
+           while (Execute(&CurrentAction, NULL, NULL, NULL, NULL) != daNone)
                  ;
            parsing = false;
            result = !commands || !*CurrentAction;
@@ -75,6 +139,31 @@
   return result;
 }
 
+uint cDiseqc::SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const
+{
+  uint t = SatFrequency == 0 ? 0 : (SatFrequency + Scr->UserBand() + 2) / 4 - 350; // '+ 2' together with '/ 4' results in rounding!
+  if (t < 1024 && Scr->Channel() >= 0 && Scr->Channel() < 8) {
+     Codes[3] = t >> 8 | (t == 0 ? 0 : scrBank << 2) | Scr->Channel() << 5;
+     Codes[4] = t;
+     if (t)
+        return (t + 350) * 4 - SatFrequency;
+     }
+  return 0;
+}
+
+int cDiseqc::SetScrPin(const cScr *Scr, uint8_t *Codes) const
+{
+  if (Scr->Pin() >= 0 && Scr->Pin() <= 255) {
+     Codes[2] = 0x5C;
+     Codes[5] = Scr->Pin();
+     return 6;
+     }
+  else {
+     Codes[2] = 0x5A;
+     return 5;
+     }
+}
+
 const char *cDiseqc::Wait(const char *s) const
 {
   char *p = NULL;
@@ -89,7 +178,25 @@
   return NULL;
 }
 
-const char *cDiseqc::Codes(const char *s) const
+const char *cDiseqc::GetScrBank(const char *s) const
+{
+  char *p = NULL;
+  errno = 0;
+  int n = strtol(s, &p, 10);
+  if (!errno && p != s && n >= 0 && n < 8) {
+     if (parsing) {
+        if (scrBank < 0)
+           scrBank = n;
+        else
+           esyslog("ERROR: more than one scr bank in '%s'", s - 1);
+        }
+     return p;
+     }
+  esyslog("ERROR: more than one scr bank in '%s'", s - 1);
+  return NULL;
+}
+
+const char *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) const
 {
   const char *e = strchr(s, ']');
   if (e) {
@@ -101,9 +208,13 @@
               char *p;
               int n = strtol(t, &p, 16);
               if (!errno && p != t && 0 <= n && n <= 255) {
-                 if (!parsing) {
-                    codes[NumCodes++] = uchar(n);
-                    numCodes = NumCodes;
+                 if (Codes) {
+                    if (NumCodes < *MaxCodes)
+                       Codes[NumCodes++] = uchar(n);
+                    else {
+                       esyslog("ERROR: too many codes in code sequence '%s'", s - 1);
+                       return NULL;
+                       }
                     }
                  t = skipspace(p);
                  }
@@ -117,6 +228,8 @@
               return NULL;
               }
            }
+     if (MaxCodes)
+        *MaxCodes = NumCodes;
      return e + 1;
      }
   else
@@ -124,7 +237,7 @@
   return NULL;
 }
 
-cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction) const
+cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const
 {
   if (!*CurrentAction)
      *CurrentAction = commands;
@@ -138,7 +251,16 @@
           case 'A': return daMiniA;
           case 'B': return daMiniB;
           case 'W': *CurrentAction = Wait(*CurrentAction); break;
-          case '[': *CurrentAction = Codes(*CurrentAction); return *CurrentAction ? daCodes : daNone;
+          case 'S': *CurrentAction = GetScrBank(*CurrentAction); break;
+          case '[': *CurrentAction = GetCodes(*CurrentAction, Codes, MaxCodes);
+                    if (*CurrentAction) {
+                       if (Scr && Frequency) {
+                          *Frequency = SetScrFrequency(*Frequency, Scr, Codes);
+                          *MaxCodes = SetScrPin(Scr, Codes);
+                          }
+                       return daCodes;
+                       }
+                    break;
           default: return daNone;
           }
         }
@@ -149,7 +271,7 @@
 
 cDiseqcs Diseqcs;
 
-const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization) const
+const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const
 {
   int Devices = 0;
   for (const cDiseqc *p = First(); p; p = Next(p)) {
@@ -159,8 +281,16 @@
          }
       if (Devices && !(Devices & (1 << Device - 1)))
          continue;
-      if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization))
+      if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization)) {
+         if (p->IsScr() && Scr && !*Scr) {
+            *Scr = Scrs.GetUnused(Device);
+            if (*Scr)
+               dsyslog("SCR %d assigned to device %d", (*Scr)->Channel(), Device);
+            else
+               esyslog("ERROR: no free SCR entry available for device %d", Device);
+            }
          return p;
+         }
       }
   return NULL;
 }
diff -ruN vdr-1.7.21/diseqc.conf vdr-1.7.22/diseqc.conf
--- vdr-1.7.21/diseqc.conf	2010-02-06 16:54:04.000000000 +0100
+++ vdr-1.7.22/diseqc.conf	2011-09-10 14:41:58.000000000 +0200
@@ -18,6 +18,7 @@
 #   V         voltage high (18V)
 #   A         mini A
 #   B         mini B
+#   Sn        Satellite channel routing code sequence for bank n follows
 #   Wnn       wait nn milliseconds (nn may be any positive integer number)
 #   [xx ...]  hex code sequence (max. 6)
 #
@@ -75,3 +76,15 @@
 # S19.2E  99999 H 10560 t v
 # S19.2E  12110 V 11080 t v
 # S19.2E  99999 V 10720 t v
+#
+# SCR (Satellite Channel Routing):
+#
+# S19.2E  11700 V  9750  t V W10 S0 [E0 10 5A 00 00] W10 v
+# S19.2E  99999 V 10600  t V W10 S1 [E0 10 5A 00 00] W10 v
+# S19.2E  11700 H  9750  t V W10 S2 [E0 10 5A 00 00] W10 v
+# S19.2E  99999 H 10600  t V W10 S3 [E0 10 5A 00 00] W10 v
+#
+# S13.0E  11700 V  9750  t V W10 S4 [E0 10 5A 00 00] W10 v
+# S13.0E  99999 V 10600  t V W10 S5 [E0 10 5A 00 00] W10 v
+# S13.0E  11700 H  9750  t V W10 S6 [E0 10 5A 00 00] W10 v
+# S13.0E  99999 H 10600  t V W10 S7 [E0 10 5A 00 00] W10 v
diff -ruN vdr-1.7.21/diseqc.h vdr-1.7.22/diseqc.h
--- vdr-1.7.21/diseqc.h	2011-05-22 12:35:38.000000000 +0200
+++ vdr-1.7.22/diseqc.h	2011-09-17 15:15:17.000000000 +0200
@@ -4,13 +4,41 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: diseqc.h 2.2 2011/05/22 10:35:38 kls Exp $
+ * $Id: diseqc.h 2.5 2011/09/17 13:15:17 kls Exp $
  */
 
 #ifndef __DISEQC_H
 #define __DISEQC_H
 
 #include "config.h"
+#include "thread.h"
+
+class cScr : public cListObject {
+private:
+  int devices;
+  int channel;
+  uint userBand;
+  int pin;
+  bool used;
+public:
+  cScr(void);
+  bool Parse(const char *s);
+  int Devices(void) const { return devices; }
+  int Channel(void) const { return channel; }
+  uint UserBand(void) const { return userBand; }
+  int Pin(void) const { return pin; }
+  bool Used(void) const { return used; }
+  void SetUsed(bool Used) { used = Used; }
+  };
+
+class cScrs : public cConfig<cScr> {
+private:
+  cMutex mutex;
+public:
+  cScr *GetUnused(int Device);
+  };
+
+extern cScrs Scrs;
 
 class cDiseqc : public cListObject {
 public:
@@ -22,6 +50,7 @@
     daVoltage18,
     daMiniA,
     daMiniB,
+    daScr,
     daCodes,
     };
   enum { MaxDiseqcCodes = 6 };
@@ -31,36 +60,53 @@
   int slof;
   char polarization;
   int lof;
+  mutable int scrBank;
   char *commands;
   bool parsing;
-  mutable uchar codes[MaxDiseqcCodes];
-  mutable int numCodes;
+  uint SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const;
+  int SetScrPin(const cScr *Scr, uint8_t *Codes) const;
   const char *Wait(const char *s) const;
-  const char *Codes(const char *s) const;
+  const char *GetScrBank(const char *s) const;
+  const char *GetCodes(const char *s, uchar *Codes = NULL, uint8_t *MaxCodes = NULL) const;
 public:
   cDiseqc(void);
   ~cDiseqc();
   bool Parse(const char *s);
-  eDiseqcActions Execute(const char **CurrentAction) const;
-      // Parses the DiSEqC commands and returns the appropriate action code
-      // with every call. CurrentAction must be the address of a character pointer,
-      // which is initialized to NULL. This pointer is used internally while parsing
-      // the commands and shall not be modified once Execute() has been called with
-      // it. Call Execute() repeatedly (always providing the same CurrentAction pointer)
-      // until it returns daNone. After a successful execution of all commands
-      // *CurrentAction points to the value 0x00.
+  eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const;
+      ///< Parses the DiSEqC commands and returns the appropriate action code
+      ///< with every call. CurrentAction must be the address of a character pointer,
+      ///< which is initialized to NULL. This pointer is used internally while parsing
+      ///< the commands and shall not be modified once Execute() has been called with
+      ///< it. Call Execute() repeatedly (always providing the same CurrentAction pointer)
+      ///< until it returns daNone. After a successful execution of all commands
+      ///< *CurrentAction points to the value 0x00.
+      ///< If the current action consists of sending code bytes to the device, those
+      ///< bytes will be copied into Codes. MaxCodes must be initialized to the maximum
+      ///< number of bytes Codes can handle, and will be set to the actual number of
+      ///< bytes copied to Codes upon return.
+      ///< If this DiSEqC entry requires SCR, the given Scr will be used. This must
+      ///< be a pointer returned from a previous call to cDiseqcs::Get().
+      ///< Frequency must be the frequency the tuner will be tuned to, and will be
+      ///< set to the proper SCR frequency upon return (if SCR is used).
   int Devices(void) const { return devices; }
   int Source(void) const { return source; }
   int Slof(void) const { return slof; }
   char Polarization(void) const { return polarization; }
   int Lof(void) const { return lof; }
+  bool IsScr() const { return scrBank >= 0; }
   const char *Commands(void) const { return commands; }
-  const uchar *Codes(int &NumCodes) const { NumCodes = numCodes; return numCodes ? codes : NULL; }
   };
 
 class cDiseqcs : public cConfig<cDiseqc> {
 public:
-  const cDiseqc *Get(int Device, int Source, int Frequency, char Polarization) const;
+  const cDiseqc *Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const;
+      ///< Selects a DiSEqC entry suitable for the given Device and tuning parameters.
+      ///< If this DiSEqC entry requires SCR and the given *Scr is NULL
+      ///< a free one will be selected from the Scrs and a pointer to that will
+      ///< be returned in Scr. The caller shall memorize that pointer and reuse it in
+      ///< subsequent calls.
+      ///< Scr may be NULL for checking whether there is any DiSEqC entry for the
+      ///< given transponder.
   };
 
 extern cDiseqcs Diseqcs;
diff -ruN vdr-1.7.21/dvbdevice.c vdr-1.7.22/dvbdevice.c
--- vdr-1.7.21/dvbdevice.c	2011-08-26 14:57:34.000000000 +0200
+++ vdr-1.7.22/dvbdevice.c	2011-12-03 16:24:27.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbdevice.c 2.43 2011/08/26 12:57:34 kls Exp $
+ * $Id: dvbdevice.c 2.48 2011/12/03 15:24:27 kls Exp $
  */
 
 #include "dvbdevice.h"
@@ -32,6 +32,8 @@
 #define ATSC_TUNE_TIMEOUT  9000 //ms
 #define ATSC_LOCK_TIMEOUT  2000 //ms
 
+#define SCR_RANDOM_TIMEOUT  500 // ms (add random value up to this when tuning SCR device to avoid lockups)
+
 // --- DVB Parameter Maps ----------------------------------------------------
 
 const tDvbParameterMap InversionValues[] = {
@@ -257,8 +259,9 @@
 
 class cDvbTuner : public cThread {
 private:
+  static cMutex bondMutex;
   enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
-  int device;
+  const cDvbDevice *device;
   int fd_frontend;
   int adapter, frontend;
   uint32_t subsystemId;
@@ -267,28 +270,41 @@
   time_t lastTimeoutReport;
   fe_delivery_system frontendType;
   cChannel channel;
-  const char *diseqcCommands;
+  const cDiseqc *lastDiseqc;
+  const cScr *scr;
   eTunerStatus tunerStatus;
   cMutex mutex;
   cCondVar locked;
   cCondVar newSet;
+  cDvbTuner *bondedTuner;
+  bool bondedMaster;
+  bool bondedMasterFailed;
+  cString GetBondingParams(const cChannel *Channel = NULL) const;
   void ClearEventQueue(void) const;
   bool GetFrontendStatus(fe_status_t &Status) const;
+  void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency);
+  void ResetToneAndVoltage(void);
   bool SetFrontend(void);
   virtual void Action(void);
 public:
-  cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType);
+  cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType);
   virtual ~cDvbTuner();
+  bool Bond(cDvbTuner *Tuner);
+  void UnBond(void);
+  bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
+  cDvbTuner *GetBondedMaster(void);
   const cChannel *GetTransponder(void) const { return &channel; }
   uint32_t SubsystemId(void) const { return subsystemId; }
   bool IsTunedTo(const cChannel *Channel) const;
-  void Set(const cChannel *Channel);
+  void SetChannel(const cChannel *Channel);
   bool Locked(int TimeoutMs = 0);
   int GetSignalStrength(void) const;
   int GetSignalQuality(void) const;
   };
 
-cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType)
+cMutex cDvbTuner::bondMutex;
+
+cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType)
 {
   device = Device;
   fd_frontend = Fd_Frontend;
@@ -299,10 +315,14 @@
   tuneTimeout = 0;
   lockTimeout = 0;
   lastTimeoutReport = 0;
-  diseqcCommands = NULL;
+  lastDiseqc = NULL;
+  scr = NULL;
   tunerStatus = tsIdle;
+  bondedTuner = NULL;
+  bondedMaster = false;
+  bondedMasterFailed = false;
   if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)
-     CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
+     ResetToneAndVoltage(); // must explicitly turn on LNB power
   SetDescription("tuner on frontend %d/%d", adapter, frontend);
   Start();
 }
@@ -313,6 +333,116 @@
   newSet.Broadcast();
   locked.Broadcast();
   Cancel(3);
+  UnBond();
+  /* looks like this irritates the SCR switch, so let's leave it out for now
+  if (lastDiseqc && lastDiseqc->IsScr()) {
+     unsigned int Frequency = 0;
+     ExecuteDiseqc(lastDiseqc, &Frequency);
+     }
+  */
+}
+
+bool cDvbTuner::Bond(cDvbTuner *Tuner)
+{
+  cMutexLock MutexLock(&bondMutex);
+  if (!bondedTuner) {
+     if ((frontendType == SYS_DVBS || frontendType == SYS_DVBS2) && (Tuner->frontendType == SYS_DVBS || Tuner->frontendType == SYS_DVBS2)) {
+        ResetToneAndVoltage();
+        bondedMaster = false; // makes sure we don't disturb an existing master
+        bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner;
+        Tuner->bondedTuner = this;
+        dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
+        return true;
+        }
+     else
+        esyslog("ERROR: can't bond tuner %d/%d with tuner %d/%d (only DVB-S(2) tuners can be bonded)", adapter, frontend, Tuner->adapter, Tuner->frontend);
+     }
+  else
+     esyslog("ERROR: tuner %d/%d already bonded with tuner %d/%d, can't bond with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend, Tuner->adapter, Tuner->frontend);
+  return false;
+}
+
+void cDvbTuner::UnBond(void)
+{
+  cMutexLock MutexLock(&bondMutex);
+  if (cDvbTuner *t = bondedTuner) {
+     dsyslog("tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
+     while (t->bondedTuner != this)
+           t = t->bondedTuner;
+     if (t == bondedTuner)
+        t->bondedTuner = NULL;
+     else
+        t->bondedTuner = bondedTuner;
+     bondedMaster = false; // another one will automatically become master whenever necessary
+     bondedTuner = NULL;
+     }
+}
+
+cString cDvbTuner::GetBondingParams(const cChannel *Channel) const
+{
+  if (!Channel)
+     Channel = &channel;
+  cDvbTransponderParameters dtp(Channel->Parameters());
+  if (Setup.DiSEqC) {
+     if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL))
+        return diseqc->Commands();
+     }
+  else {
+     bool ToneOff = Channel->Frequency() < (unsigned int)Setup.LnbSLOF;
+     bool VoltOff = dtp.Polarization() == 'V' || dtp.Polarization() == 'R';
+     return cString::sprintf("%c %c", ToneOff ? 't' : 'T', VoltOff ? 'v' : 'V');
+     }
+  return "";
+}
+
+bool cDvbTuner::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
+{
+  cMutexLock MutexLock(&bondMutex);
+  if (cDvbTuner *t = bondedTuner) {
+     cString BondingParams = GetBondingParams(Channel);
+     do {
+        if (t->device->Receiving() || t->tunerStatus != tsIdle && (t->device == cDevice::ActualDevice() || ConsiderOccupied && t->device->Occupied())) {
+           if (strcmp(BondingParams, t->GetBondingParams()) != 0)
+              return false;
+           }
+        t = t->bondedTuner;
+        } while (t != bondedTuner);
+     }
+  return true;
+}
+
+cDvbTuner *cDvbTuner::GetBondedMaster(void)
+{
+  if (!bondedTuner)
+     return this; // an unbonded tuner is always "master"
+  cMutexLock MutexLock(&bondMutex);
+  if (bondedMaster) {
+     if (!bondedMasterFailed)
+        return this;
+     else
+        bondedMaster = false;
+     }
+  // This tuner is bonded, but it's not the master, so let's see if there is a master at all:
+  if (cDvbTuner *t = bondedTuner) {
+     while (t != this) {
+           if (t->bondedMaster)
+              return t;
+           t = t->bondedTuner;
+           }
+     }
+  // None of the other bonded tuners is master, so make this one the master:
+  cDvbTuner *t = this;
+  if (bondedMasterFailed) {
+     // This one has failed, so switch to the next one:
+     t = bondedTuner;
+     t->bondedMasterFailed = false;
+     cMutexLock MutexLock(&t->mutex);
+     t->channel = channel;
+     t->tunerStatus = tsSet;
+     }
+  t->bondedMaster = true;
+  dsyslog("tuner %d/%d is now bonded master", t->adapter, t->frontend);
+  return t;
 }
 
 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
@@ -325,14 +455,34 @@
   return strcmp(channel.Parameters(), Channel->Parameters()) == 0;
 }
 
-void cDvbTuner::Set(const cChannel *Channel)
+void cDvbTuner::SetChannel(const cChannel *Channel)
 {
-  cMutexLock MutexLock(&mutex);
-  if (!IsTunedTo(Channel))
-     tunerStatus = tsSet;
-  channel = *Channel;
-  lastTimeoutReport = 0;
-  newSet.Broadcast();
+  if (Channel) {
+     if (bondedTuner) {
+        cMutexLock MutexLock(&bondMutex);
+        cDvbTuner *BondedMaster = GetBondedMaster();
+        if (BondedMaster == this) {
+           if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
+              // switching to a completely different band, so set all others to idle:
+              for (cDvbTuner *t = bondedTuner; t && t != this; t = t->bondedTuner)
+                  t->SetChannel(NULL);
+              }
+           }
+        else if (!BondedMaster->device->Receiving())
+           BondedMaster->SetChannel(Channel);
+        }
+     cMutexLock MutexLock(&mutex);
+     if (!IsTunedTo(Channel))
+        tunerStatus = tsSet;
+     channel = *Channel;
+     lastTimeoutReport = 0;
+     newSet.Broadcast();
+     }
+  else {
+     cMutexLock MutexLock(&mutex);
+     tunerStatus = tsIdle;
+     ResetToneAndVoltage();
+     }
 }
 
 bool cDvbTuner::Locked(int TimeoutMs)
@@ -482,6 +632,36 @@
   return f;
 }
 
+void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency)
+{
+  struct dvb_diseqc_master_cmd cmd;
+  const char *CurrentAction = NULL;
+  for (;;) {
+      cmd.msg_len = sizeof(cmd.msg);
+      cDiseqc::eDiseqcActions da = Diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len, scr, Frequency);
+      if (da == cDiseqc::daNone)
+         break;
+      switch (da) {
+        case cDiseqc::daToneOff:   CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
+        case cDiseqc::daToneOn:    CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
+        case cDiseqc::daVoltage13: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
+        case cDiseqc::daVoltage18: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
+        case cDiseqc::daMiniA:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
+        case cDiseqc::daMiniB:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
+        case cDiseqc::daCodes:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); break;
+        default: esyslog("ERROR: unknown diseqc command %d", da);
+        }
+      }
+  if (scr)
+     ResetToneAndVoltage(); // makes sure we don't block the bus!
+}
+
+void cDvbTuner::ResetToneAndVoltage(void)
+{
+  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13));
+  CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
+}
+
 bool cDvbTuner::SetFrontend(void)
 {
 #define MAXFRONTENDCMDS 16
@@ -509,36 +689,18 @@
   if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
      unsigned int frequency = channel.Frequency();
      if (Setup.DiSEqC) {
-        const cDiseqc *diseqc = Diseqcs.Get(device, channel.Source(), channel.Frequency(), dtp.Polarization());
-        if (diseqc) {
-           if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) {
-              cDiseqc::eDiseqcActions da;
-              for (const char *CurrentAction = NULL; (da = diseqc->Execute(&CurrentAction)) != cDiseqc::daNone; ) {
-                  switch (da) {
-                    case cDiseqc::daNone:      break;
-                    case cDiseqc::daToneOff:   CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
-                    case cDiseqc::daToneOn:    CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
-                    case cDiseqc::daVoltage13: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
-                    case cDiseqc::daVoltage18: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
-                    case cDiseqc::daMiniA:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
-                    case cDiseqc::daMiniB:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
-                    case cDiseqc::daCodes: {
-                         int n = 0;
-                         const uchar *codes = diseqc->Codes(n);
-                         if (codes) {
-                            struct dvb_diseqc_master_cmd cmd;
-                            cmd.msg_len = min(n, int(sizeof(cmd.msg)));
-                            memcpy(cmd.msg, codes, cmd.msg_len);
-                            CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd));
-                            }
-                         }
-                         break;
-                    default: esyslog("ERROR: unknown diseqc command %d", da);
-                    }
-                  }
-              diseqcCommands = diseqc->Commands();
-              }
+        if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
            frequency -= diseqc->Lof();
+           if (diseqc != lastDiseqc || diseqc->IsScr()) {
+              if (GetBondedMaster() == this) {
+                 ExecuteDiseqc(diseqc, &frequency);
+                 if (frequency == 0)
+                    return false;
+                 }
+              else
+                 ResetToneAndVoltage();
+              lastDiseqc = diseqc;
+              }
            }
         else {
            esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number());
@@ -555,7 +717,11 @@
            frequency -= Setup.LnbFrequHi;
            tone = SEC_TONE_ON;
            }
-        int volt = (dtp.Polarization() == 'v' || dtp.Polarization() == 'V' || dtp.Polarization() == 'r' || dtp.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
+        int volt = (dtp.Polarization() == 'V' || dtp.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
+        if (GetBondedMaster() != this) {
+           tone = SEC_TONE_OFF;
+           volt = SEC_VOLTAGE_13;
+           }
         CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
         CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
         }
@@ -652,22 +818,25 @@
                break;
           case tsSet:
                tunerStatus = SetFrontend() ? tsTuned : tsIdle;
-               Timer.Set(tuneTimeout);
+               Timer.Set(tuneTimeout + (scr ? rand() % SCR_RANDOM_TIMEOUT : 0));
                continue;
           case tsTuned:
                if (Timer.TimedOut()) {
                   tunerStatus = tsSet;
-                  diseqcCommands = NULL;
+                  lastDiseqc = NULL;
                   if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
                      isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder());
                      lastTimeoutReport = time(NULL);
                      }
+                  cMutexLock MutexLock(&bondMutex);
+                  if (bondedTuner && bondedMaster)
+                     bondedMasterFailed = true; // give an other tuner a chance in case the sat cable was disconnected
                   continue;
                   }
           case tsLocked:
                if (Status & FE_REINIT) {
                   tunerStatus = tsSet;
-                  diseqcCommands = NULL;
+                  lastDiseqc = NULL;
                   isyslog("frontend %d/%d was reinitialized", adapter, frontend);
                   lastTimeoutReport = 0;
                   continue;
@@ -757,6 +926,7 @@
 // --- cDvbDevice ------------------------------------------------------------
 
 int cDvbDevice::setTransferModeForDolbyDigital = 1;
+cMutex cDvbDevice::bondMutex;
 
 const char *DeliverySystems[] = {
   "UNDEFINED",
@@ -786,6 +956,8 @@
   dvbTuner = NULL;
   frontendType = SYS_UNDEFINED;
   numProvidedSystems = 0;
+  bondedDevice = NULL;
+  needsDetachBondedReceivers = false;
 
   // Devices that are present on all card types:
 
@@ -835,7 +1007,7 @@
         else
            p = (char *)"unknown modulations";
         isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, DeliverySystems[frontendType], p, frontendInfo.name);
-        dvbTuner = new cDvbTuner(CardIndex() + 1, fd_frontend, adapter, frontend, frontendType);
+        dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend, frontendType);
         }
      }
   else
@@ -849,6 +1021,7 @@
   StopSectionHandler();
   delete dvbTuner;
   delete ciAdapter;
+  UnBond();
   // We're not explicitly closing any device files here, since this sometimes
   // caused segfaults. Besides, the program is about to terminate anyway...
 }
@@ -940,6 +1113,104 @@
   return true;
 }
 
+bool cDvbDevice::BondDevices(const char *Bondings)
+{
+  UnBondDevices();
+  if (Bondings) {
+     cSatCableNumbers SatCableNumbers(MAXDEVICES, Bondings);
+     for (int i = 0; i < cDevice::NumDevices(); i++) {
+         int d = SatCableNumbers.FirstDeviceIndex(i);
+         if (d >= 0) {
+            int ErrorDevice = 0;
+            if (cDevice *Device1 = cDevice::GetDevice(i)) {
+               if (cDevice *Device2 = cDevice::GetDevice(d)) {
+                  if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
+                     if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
+                        if (!DvbDevice2->Bond(DvbDevice1))
+                           return false; // Bond() has already logged the error
+                        }
+                     else
+                        ErrorDevice = d + 1;
+                     }
+                  else
+                     ErrorDevice = i + 1;
+                  if (ErrorDevice) {
+                     esyslog("ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
+                     return false;
+                     }
+                  }
+               else
+                  ErrorDevice = d + 1;
+               }
+            else
+               ErrorDevice = i + 1;
+            if (ErrorDevice) {
+               esyslog("ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
+               return false;
+               }
+            }
+         }
+     }
+  return true;
+}
+
+void cDvbDevice::UnBondDevices(void)
+{
+  for (int i = 0; i < cDevice::NumDevices(); i++) {
+      if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(cDevice::GetDevice(i)))
+         d->UnBond();
+      }
+}
+
+bool cDvbDevice::Bond(cDvbDevice *Device)
+{
+  cMutexLock MutexLock(&bondMutex);
+  if (!bondedDevice) {
+     if (Device != this) {
+        if ((frontendType == SYS_DVBS || frontendType == SYS_DVBS2) && (Device->frontendType == SYS_DVBS || Device->frontendType == SYS_DVBS2)) {
+           if (dvbTuner && Device->dvbTuner && dvbTuner->Bond(Device->dvbTuner)) {
+              bondedDevice = Device->bondedDevice ? Device->bondedDevice : Device;
+              Device->bondedDevice = this;
+              dsyslog("device %d bonded with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
+              return true;
+              }
+           }
+        else
+           esyslog("ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", CardIndex() + 1, Device->CardIndex() + 1);
+        }
+     else
+        esyslog("ERROR: can't bond device %d with itself", CardIndex() + 1);
+     }
+  else
+     esyslog("ERROR: device %d already bonded with device %d, can't bond with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->CardIndex() + 1);
+  return false;
+}
+
+void cDvbDevice::UnBond(void)
+{
+  cMutexLock MutexLock(&bondMutex);
+  if (cDvbDevice *d = bondedDevice) {
+     if (dvbTuner)
+        dvbTuner->UnBond();
+     dsyslog("device %d unbonded from device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
+     while (d->bondedDevice != this)
+           d = d->bondedDevice;
+     if (d == bondedDevice)
+        d->bondedDevice = NULL;
+     else
+        d->bondedDevice = bondedDevice;
+     bondedDevice = NULL;
+     }
+}
+
+bool cDvbDevice::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
+{
+  cMutexLock MutexLock(&bondMutex);
+  if (bondedDevice)
+     return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
+  return true;
+}
+
 bool cDvbDevice::HasCi(void)
 {
   return ciAdapter;
@@ -1042,7 +1313,7 @@
      dtp.Modulation() == PSK_8    && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to determine this condition
      return false; // requires modulation system which frontend doesn't provide
   if (!cSource::IsSat(Channel->Source()) ||
-     !Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization()))
+     (!Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL)))
      return DeviceHooksProvidesTransponder(Channel);
   return false;
 }
@@ -1052,28 +1323,44 @@
   bool result = false;
   bool hasPriority = Priority < 0 || Priority > this->Priority();
   bool needsDetachReceivers = false;
+  needsDetachBondedReceivers = false;
 
   if (dvbTuner && ProvidesTransponder(Channel)) {
      result = hasPriority;
-     if (Priority >= 0 && Receiving(true)) {
-        if (dvbTuner->IsTunedTo(Channel)) {
-           if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
-              if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN) {
-                 if (CamSlot()->CanDecrypt(Channel))
+     if (Priority >= 0) {
+        if (Receiving(true)) {
+           if (dvbTuner->IsTunedTo(Channel)) {
+              if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
+                 if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN) {
+                    if (CamSlot()->CanDecrypt(Channel))
+                       result = true;
+                    else
+                       needsDetachReceivers = true;
+                    }
+                 else if (!IsPrimaryDevice())
                     result = true;
                  else
-                    needsDetachReceivers = true;
+                    result = Priority >= Setup.PrimaryLimit;
                  }
-              else if (!IsPrimaryDevice())
-                 result = true;
               else
-                 result = Priority >= Setup.PrimaryLimit;
+                 result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit;
               }
            else
-              result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit;
+              needsDetachReceivers = true;
+           }
+        if (result) {
+           if (!BondingOk(Channel)) {
+              // This device is bonded, so we need to check the priorities of the others:
+              for (cDvbDevice *d = bondedDevice; d && d != this; d = d->bondedDevice) {
+                  if (d->Priority() >= Priority) {
+                     result = false;
+                     break;
+                     }
+                  }
+              needsDetachBondedReceivers = true;
+              needsDetachReceivers = true;
+              }
            }
-        else
-           needsDetachReceivers = true;
         }
      }
   if (NeedsDetachReceivers)
@@ -1106,15 +1393,20 @@
   return dvbTuner ? dvbTuner->GetTransponder() : NULL;
 }
 
-bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel)
+bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel) const
 {
   return dvbTuner ? dvbTuner->IsTunedTo(Channel) : false;
 }
 
+bool cDvbDevice::MaySwitchTransponder(const cChannel *Channel) const
+{
+  return BondingOk(Channel, true) && cDevice::MaySwitchTransponder(Channel);
+}
+
 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 {
   if (dvbTuner)
-     dvbTuner->Set(Channel);
+     dvbTuner->SetChannel(Channel);
   return true;
 }
 
@@ -1156,6 +1448,17 @@
   return false;
 }
 
+void cDvbDevice::DetachAllReceivers(void)
+{
+  cMutexLock MutexLock(&bondMutex);
+  cDvbDevice *d = this;
+  do {
+     d->cDevice::DetachAllReceivers();
+     d = d->bondedDevice;
+     } while (d && d != this && needsDetachBondedReceivers);
+  needsDetachBondedReceivers = false;
+}
+
 // --- cDvbDeviceProbe -------------------------------------------------------
 
 cList<cDvbDeviceProbe> DvbDeviceProbes;
diff -ruN vdr-1.7.21/dvbdevice.h vdr-1.7.22/dvbdevice.h
--- vdr-1.7.21/dvbdevice.h	2011-08-26 14:55:45.000000000 +0200
+++ vdr-1.7.22/dvbdevice.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbdevice.h 2.16 2011/08/26 12:55:45 kls Exp $
+ * $Id: dvbdevice.h 2.18 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __DVBDEVICE_H
@@ -122,10 +122,40 @@
   int numProvidedSystems;
   fe_delivery_system frontendType;
   int fd_dvr, fd_ca;
+  static cMutex bondMutex;
+  cDvbDevice *bondedDevice;
+  mutable bool needsDetachBondedReceivers;
 public:
   cDvbDevice(int Adapter, int Frontend);
   virtual ~cDvbDevice();
   virtual bool Ready(void);
+  static bool BondDevices(const char *Bondings);
+       ///< Bonds the devices as defined in the given Bondings string.
+       ///< A bonding is a sequence of device numbers (starting at 1),
+       ///< separated by '+' characters. Several bondings are separated by
+       ///< commas, as in "1+2,3+4+5".
+       ///< Returns false if an error occurred.
+  static void UnBondDevices(void);
+       ///< Unbonds all devices.
+  bool Bond(cDvbDevice *Device);
+       ///< Bonds this device with the given Device, making both of them use
+       ///< the same satellite cable and LNB. Only DVB-S(2) devices can be
+       ///< bonded. When this function is called, the calling device must
+       ///< not be bonded to any other device. The given Device, however,
+       ///< may already be bonded to an other device. That way several devices
+       ///< can be bonded together.
+       ///< Returns true if the bonding was successful.
+  void UnBond(void);
+       ///< Removes this device from any bonding it might have with other
+       ///< devices. If this device is not bonded with any other device,
+       ///< nothing happens.
+  bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
+       ///< Returns true if this device is either not bonded to any other
+       ///< device, or the given Channel is on the same satellite, polarization
+       ///< and band as those the bonded devices are tuned to (if any).
+       ///< If ConsiderOccupied is true, any bonded devices that are currently
+       ///< occupied but not otherwise receiving will cause this function to
+       ///< return false.
 
 // Common Interface facilities:
 
@@ -145,7 +175,8 @@
   virtual int SignalStrength(void) const;
   virtual int SignalQuality(void) const;
   virtual const cChannel *GetCurrentlyTunedTransponder(void) const;
-  virtual bool IsTunedToTransponder(const cChannel *Channel);
+  virtual bool IsTunedToTransponder(const cChannel *Channel) const;
+  virtual bool MaySwitchTransponder(const cChannel *Channel) const;
 protected:
   virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
 public:
@@ -172,7 +203,7 @@
 protected:
   static int setTransferModeForDolbyDigital;
 public:
-  static void SetTransferModeForDolbyDigital(int Mode); // needs to be here for backwards compatibilty
+  static void SetTransferModeForDolbyDigital(int Mode); // needs to be here for backwards compatibility
          ///< Controls how the DVB device handles Transfer Mode when replaying
          ///< Dolby Digital audio.
          ///< 0 = don't set "audio bypass" in driver/firmware, don't force Transfer Mode
@@ -187,6 +218,7 @@
   virtual bool OpenDvr(void);
   virtual void CloseDvr(void);
   virtual bool GetTSPacket(uchar *&Data);
+  virtual void DetachAllReceivers(void);
   };
 
 // A plugin that implements a DVB device derived from cDvbDevice needs to create
diff -ruN vdr-1.7.21/dvbsubtitle.c vdr-1.7.22/dvbsubtitle.c
--- vdr-1.7.21/dvbsubtitle.c	2011-08-13 15:33:00.000000000 +0200
+++ vdr-1.7.22/dvbsubtitle.c	2011-09-18 13:23:15.000000000 +0200
@@ -7,7 +7,7 @@
  * Original author: Marco Schl��ler <marco@lordzodiac.de>
  * With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
  *
- * $Id: dvbsubtitle.c 2.18 2011/08/13 13:33:00 kls Exp $
+ * $Id: dvbsubtitle.c 2.20 2011/09/18 11:23:15 kls Exp $
  */
 
 
@@ -15,13 +15,18 @@
 #define __STDC_FORMAT_MACROS // Required for format specifiers
 #include <inttypes.h>
 #include "device.h"
+#include "libsi/si.h"
 
-#define PAGE_COMPOSITION_SEGMENT   0x10
-#define REGION_COMPOSITION_SEGMENT 0x11
-#define CLUT_DEFINITION_SEGMENT    0x12
-#define OBJECT_DATA_SEGMENT        0x13
-#define DISPLAY_DEFINITION_SEGMENT 0x14
-#define END_OF_DISPLAY_SET_SEGMENT 0x80
+//#define FINISHPAGE_HACK
+
+#define PAGE_COMPOSITION_SEGMENT    0x10
+#define REGION_COMPOSITION_SEGMENT  0x11
+#define CLUT_DEFINITION_SEGMENT     0x12
+#define OBJECT_DATA_SEGMENT         0x13
+#define DISPLAY_DEFINITION_SEGMENT  0x14
+#define DISPARITY_SIGNALING_SEGMENT 0x15 // DVB BlueBook A156
+#define END_OF_DISPLAY_SET_SEGMENT  0x80
+#define STUFFING_SEGMENT            0xFF
 
 // Set these to 'true' for debug output:
 static bool DebugConverter = false;
@@ -61,8 +66,68 @@
 ,palette4(4)
 ,palette8(8)
 {
+  int a = 0, r = 0, g = 0, b = 0;
   clutId = ClutId;
   version = -1;
+  // ETSI EN 300 743 10.3: 4-entry CLUT default contents
+  palette2.SetColor(0, ArgbToColor(  0,   0,   0,   0));
+  palette2.SetColor(1, ArgbToColor(255, 255, 255, 255));
+  palette2.SetColor(2, ArgbToColor(255,   0,   0,   0));
+  palette2.SetColor(3, ArgbToColor(255, 127, 127, 127));
+  // ETSI EN 300 743 10.2: 16-entry CLUT default contents
+  palette4.SetColor(0, ArgbToColor(0, 0, 0, 0));
+  for (int i = 1; i < 16; ++i) {
+      if (i < 8) {
+         r = (i & 1) ? 255 : 0;
+         g = (i & 2) ? 255 : 0;
+         b = (i & 4) ? 255 : 0;
+         }
+      else {
+         r = (i & 1) ? 127 : 0;
+         g = (i & 2) ? 127 : 0;
+         b = (i & 4) ? 127 : 0;
+         }
+      palette4.SetColor(i, ArgbToColor(255, r, g, b));
+      }
+  // ETSI EN 300 743 10.1: 256-entry CLUT default contents
+  palette8.SetColor(0, ArgbToColor(0, 0, 0, 0));
+  for (int i = 1; i < 256; ++i) {
+      if (i < 8) {
+         r = (i & 1) ? 255 : 0;
+         g = (i & 2) ? 255 : 0;
+         b = (i & 4) ? 255 : 0;
+         a = 63;
+         }
+      else {
+         switch (i & 0x88) {
+           case 0x00:
+                r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
+                g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
+                b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
+                a = 255;
+                break;
+           case 0x08:
+                r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
+                g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
+                b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
+                a = 127;
+                break;
+           case 0x80:
+                r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
+                g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
+                b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
+                a = 255;
+                break;
+           case 0x88:
+                r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
+                g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
+                b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
+                a = 255;
+                break;
+            }
+         }
+      palette8.SetColor(i, ArgbToColor(a, r, g, b));
+      }
 }
 
 void cSubtitleClut::SetColor(int Bpp, int Index, tColor Color)
@@ -94,29 +159,33 @@
   int version;
   int codingMethod;
   bool nonModifyingColorFlag;
-  int nibblePos;
-  uchar backgroundColor;
-  uchar foregroundColor;
+  uchar backgroundPixelCode;
+  uchar foregroundPixelCode;
   int providerFlag;
   int px;
   int py;
   cBitmap *bitmap;
+  char textData[Utf8BufSize(256)]; // number of character codes is an 8-bit field
   void DrawLine(int x, int y, tIndex Index, int Length);
-  uchar Get2Bits(const uchar *Data, int &Index);
-  uchar Get4Bits(const uchar *Data, int &Index);
-  bool Decode2BppCodeString(const uchar *Data, int &Index, int&x, int y);
-  bool Decode4BppCodeString(const uchar *Data, int &Index, int&x, int y);
-  bool Decode8BppCodeString(const uchar *Data, int &Index, int&x, int y);
+  bool Decode2BppCodeString(cBitStream *bs, int&x, int y, const uint8_t *MapTable);
+  bool Decode4BppCodeString(cBitStream *bs, int&x, int y, const uint8_t *MapTable);
+  bool Decode8BppCodeString(cBitStream *bs, int&x, int y);
 public:
   cSubtitleObject(int ObjectId, cBitmap *Bitmap);
   int ObjectId(void) { return objectId; }
   int Version(void) { return version; }
   int CodingMethod(void) { return codingMethod; }
+  uchar BackgroundPixelCode(void) { return backgroundPixelCode; }
+  uchar ForegroundPixelCode(void) { return foregroundPixelCode; }
+  const char *TextData(void) { return &textData[0]; }
+  int X(void) { return px; }
+  int Y(void) { return py; }
   bool NonModifyingColorFlag(void) { return nonModifyingColorFlag; }
+  void DecodeCharacterString(const uchar *Data, int NumberOfCodes);
   void DecodeSubBlock(const uchar *Data, int Length, bool Even);
   void SetVersion(int Version) { version = Version; }
-  void SetBackgroundColor(uchar BackgroundColor) { backgroundColor = BackgroundColor; }
-  void SetForegroundColor(uchar ForegroundColor) { foregroundColor = ForegroundColor; }
+  void SetBackgroundPixelCode(uchar BackgroundPixelCode) { backgroundPixelCode = BackgroundPixelCode; }
+  void SetForegroundPixelCode(uchar ForegroundPixelCode) { foregroundPixelCode = ForegroundPixelCode; }
   void SetNonModifyingColorFlag(bool NonModifyingColorFlag) { nonModifyingColorFlag = NonModifyingColorFlag; }
   void SetCodingMethod(int CodingMethod) { codingMethod = CodingMethod; }
   void SetPosition(int x, int y) { px = x; py = y; }
@@ -129,59 +198,105 @@
   version = -1;
   codingMethod = -1;
   nonModifyingColorFlag = false;
-  nibblePos = 0;
-  backgroundColor = 0;
-  foregroundColor = 0;
+  backgroundPixelCode = 0;
+  foregroundPixelCode = 0;
   providerFlag = -1;
   px = py = 0;
   bitmap = Bitmap;
+  memset(textData, 0, sizeof(textData));
+}
+
+void cSubtitleObject::DecodeCharacterString(const uchar *Data, int NumberOfCodes)
+{
+  if (NumberOfCodes > 0) {
+     bool singleByte;
+     const uchar *from = &Data[1];
+     int len = NumberOfCodes * 2 - 1;
+     cCharSetConv conv(SI::getCharacterTable(from, len, &singleByte));
+     if (singleByte) {
+        char txt[NumberOfCodes + 1];
+        char *p = txt;
+        for (int i = 2; i < NumberOfCodes; ++i) {
+            char c = Data[i * 2 + 1] & 0xFF;
+            if (c == 0)
+               break;
+            if (' ' <= c && c <= '~' || c == '\n' || 0xA0 <= c)
+               *(p++) = c;
+            else if (c == 0x8A)
+               *(p++) = '\n';
+            }
+        *p = 0;
+        const char *s = conv.Convert(txt);
+        Utf8Strn0Cpy(textData, s, Utf8StrLen(s));
+        }
+     else {
+        // TODO: add proper multibyte support for "UTF-16", "EUC-KR", "GB2312", "GBK", "UTF-8"
+        }
+     }
 }
 
 void cSubtitleObject::DecodeSubBlock(const uchar *Data, int Length, bool Even)
 {
   int x = 0;
   int y = Even ? 0 : 1;
-  for (int index = 0; index < Length; ) {
-      switch (Data[index++]) {
-        case 0x10: {
-             nibblePos = 8;
-             while (Decode2BppCodeString(Data, index, x, y) && index < Length)
-                   ;
-             if (!nibblePos)
-                index++;
-             break;
-             }
-        case 0x11: {
-             nibblePos = 4;
-             while (Decode4BppCodeString(Data, index, x, y) && index < Length)
-                   ;
-             if (!nibblePos)
-                index++;
-             break;
-             }
-        case 0x12:
-             while (Decode8BppCodeString(Data, index, x, y) && index < Length)
-                   ;
-             break;
-        case 0x20: //TODO
-             dbgobjects("sub block 2 to 4 map\n");
-             index += 4;
-             break;
-        case 0x21: //TODO
-             dbgobjects("sub block 2 to 8 map\n");
-             index += 4;
-             break;
-        case 0x22: //TODO
-             dbgobjects("sub block 4 to 8 map\n");
-             index += 16;
-             break;
-        case 0xF0:
-             x = 0;
-             y += 2;
-             break;
-        default: dbgobjects("unknown sub block %s %d\n", __FUNCTION__, __LINE__);
+  uint8_t map2to4[ 4] = { 0x00, 0x07, 0x08, 0x0F };
+  uint8_t map2to8[ 4] = { 0x00, 0x77, 0x88, 0xFF };
+  uint8_t map4to8[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
+  const uint8_t *mapTable = NULL;
+  cBitStream bs(Data, Length * 8);
+  while (!bs.IsEOF()) {
+        switch (bs.GetBits(8)) {
+          case 0x10:
+               dbgobjects("2-bit / pixel code string\n");
+               switch (bitmap->Bpp()) {
+                 case 8:  mapTable = map2to8; break;
+                 case 4:  mapTable = map2to4; break;
+                 default: mapTable = NULL;    break;
+                 }
+               while (Decode2BppCodeString(&bs, x, y, mapTable) && !bs.IsEOF())
+                     ;
+               bs.ByteAlign();
+               break;
+          case 0x11:
+               dbgobjects("4-bit / pixel code string\n");
+               switch (bitmap->Bpp()) {
+                 case 8:  mapTable = map4to8; break;
+                 default: mapTable = NULL;    break;
+                 }
+               while (Decode4BppCodeString(&bs, x, y, mapTable) && !bs.IsEOF())
+                     ;
+               bs.ByteAlign();
+               break;
+          case 0x12:
+               dbgobjects("8-bit / pixel code string\n");
+               while (Decode8BppCodeString(&bs, x, y) && !bs.IsEOF())
+                     ;
+               break;
+          case 0x20:
+               dbgobjects("sub block 2 to 4 map\n");
+               map2to4[0] = bs.GetBits(4);
+               map2to4[1] = bs.GetBits(4);
+               map2to4[2] = bs.GetBits(4);
+               map2to4[3] = bs.GetBits(4);
+               break;
+          case 0x21:
+               dbgobjects("sub block 2 to 8 map\n");
+               for (int i = 0; i < 4; ++i)
+                   map2to8[i] = bs.GetBits(8);
+               break;
+          case 0x22:
+               dbgobjects("sub block 4 to 8 map\n");
+               for (int i = 0; i < 16; ++i)
+                   map4to8[i] = bs.GetBits(8);
+               break;
+          case 0xF0:
+               dbgobjects("end of object line\n");
+               x = 0;
+               y += 2;
+               break;
+          default: dbgobjects("unknown sub block %s %d\n", __FUNCTION__, __LINE__);
+          }
         }
-      }
 }
 
 void cSubtitleObject::DrawLine(int x, int y, tIndex Index, int Length)
@@ -194,136 +309,110 @@
       bitmap->SetIndex(pos, y, Index);
 }
 
-uchar cSubtitleObject::Get2Bits(const uchar *Data, int &Index)
-{
-  uchar result = Data[Index];
-  if (!nibblePos) {
-     Index++;
-     nibblePos = 8;
-     }
-  nibblePos -= 2;
-  return (result >> nibblePos) & 0x03;
-}
-
-uchar cSubtitleObject::Get4Bits(const uchar *Data, int &Index)
-{
-  uchar result = Data[Index];
-  if (!nibblePos) {
-     Index++;
-     nibblePos = 4;
-     }
-  else {
-     result >>= 4;
-     nibblePos -= 4;
-     }
-  return result & 0x0F;
-}
-
-bool cSubtitleObject::Decode2BppCodeString(const uchar *Data, int &Index, int &x, int y)
+bool cSubtitleObject::Decode2BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
 {
   int rl = 0;
   int color = 0;
-  uchar code = Get2Bits(Data, Index);
+  uchar code = bs->GetBits(2);
   if (code) {
      color = code;
      rl = 1;
      }
+  else if (bs->GetBit()) { // switch_1
+     rl = bs->GetBits(3) + 3;
+     color = bs->GetBits(2);
+     }
+  else if (bs->GetBit()) // switch_2
+     rl = 1; //color 0
   else {
-     code = Get2Bits(Data, Index);
-     if (code & 2) { // switch_1
-        rl = ((code & 1) << 2) + Get2Bits(Data, Index) + 3;
-        color = Get2Bits(Data, Index);
-        }
-     else if (code & 1)
-        rl = 1; //color 0
-     else {
-        code = Get2Bits(Data, Index);
-        switch (code & 3) { //switch_3
-          case 0:
-               return false;
-          case 1:
-               rl = 2; //color 0
-               break;
-          case 2:
-               rl = (Get2Bits(Data, Index) << 2) + Get2Bits(Data, Index) + 12;
-               color = Get2Bits(Data, Index);
-               break;
-          case 3:
-               rl = (Get2Bits(Data, Index) << 6) + (Get2Bits(Data, Index) << 4) + (Get2Bits(Data, Index) << 2) + Get2Bits(Data, Index) + 29;
-               color = Get2Bits(Data, Index);
-               break;
-          default: ;
-          }
-        }
+     switch (bs->GetBits(2)) { // switch_3
+       case 0:
+            return false;
+       case 1:
+            rl = 2; //color 0
+            break;
+       case 2:
+            rl = bs->GetBits(4) + 12;
+            color = bs->GetBits(2);
+            break;
+       case 3:
+            rl = bs->GetBits(8) + 29;
+            color = bs->GetBits(2);
+            break;
+       default: ;
+       }
      }
+  if (MapTable)
+     color = MapTable[color];
   DrawLine(x, y, color, rl);
   x += rl;
   return true;
 }
 
-bool cSubtitleObject::Decode4BppCodeString(const uchar *Data, int &Index, int &x, int y)
+bool cSubtitleObject::Decode4BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
 {
   int rl = 0;
   int color = 0;
-  uchar code = Get4Bits(Data, Index);
+  uchar code = bs->GetBits(4);
   if (code) {
      color = code;
      rl = 1;
      }
+  else if (bs->GetBit() == 0) { // switch_1
+     code = bs->GetBits(3);
+     if (code)
+        rl = code + 2; //color 0
+     else
+        return false;
+     }
+  else if (bs->GetBit() == 0) { // switch_2
+     rl = bs->GetBits(2) + 4;
+     color = bs->GetBits(4);
+     }
   else {
-     code = Get4Bits(Data, Index);
-     if (code & 8) { // switch_1
-        if (code & 4) { //switch_2
-           switch (code & 3) { //switch_3
-             case 0: // color 0
-                  rl = 1;
-                  break;
-             case 1: // color 0
-                  rl = 2;
-                  break;
-             case 2:
-                  rl = Get4Bits(Data, Index) + 9;
-                  color = Get4Bits(Data, Index);
-                  break;
-             case 3:
-                  rl = (Get4Bits(Data, Index) << 4) + Get4Bits(Data, Index) + 25;
-                  color = Get4Bits(Data, Index);
-                  break;
-             default: ;
-             }
-           }
-        else {
-           rl = (code & 3) + 4;
-           color = Get4Bits(Data, Index);
-           }
-        }
-     else { // color 0
-        if (!code)
-           return false;
-        rl = code + 2;
-        }
+     switch (bs->GetBits(2)) { // switch_3
+       case 0: // color 0
+            rl = 1;
+            break;
+       case 1: // color 0
+            rl = 2;
+            break;
+       case 2:
+            rl = bs->GetBits(4) + 9;
+            color = bs->GetBits(4);
+            break;
+       case 3:
+            rl = bs->GetBits(8) + 25;
+            color = bs->GetBits(4);
+            break;
+       }
      }
+  if (MapTable)
+     color = MapTable[color];
   DrawLine(x, y, color, rl);
   x += rl;
   return true;
 }
 
-bool cSubtitleObject::Decode8BppCodeString(const uchar *Data, int &Index, int &x, int y)
+bool cSubtitleObject::Decode8BppCodeString(cBitStream *bs, int &x, int y)
 {
   int rl = 0;
   int color = 0;
-  uchar code = Data[Index++];
+  uchar code = bs->GetBits(8);
   if (code) {
      color = code;
      rl = 1;
      }
+  else if (bs->GetBit()) {
+     rl = bs->GetBits(7);
+     color = bs->GetBits(8);
+     }
   else {
-     code = Data[Index++];
-     rl = code & 0x63;
-     if (code & 0x80)
-        color = Data[Index++];
-     else if (!rl)
-        return false; //else color 0
+     code = bs->GetBits(7);
+     if (code)
+        rl = code; // color 0
+     else
+        return false;
      }
   DrawLine(x, y, color, rl);
   x += rl;
@@ -340,6 +429,7 @@
   int horizontalAddress;
   int verticalAddress;
   int level;
+  int lineHeight;
   cList<cSubtitleObject> objects;
 public:
   cSubtitleRegion(int RegionId);
@@ -358,6 +448,7 @@
   void SetDepth(int Depth);
   void SetHorizontalAddress(int HorizontalAddress) { horizontalAddress = HorizontalAddress; }
   void SetVerticalAddress(int VerticalAddress) { verticalAddress = VerticalAddress; }
+  void UpdateTextData(cSubtitleClut *Clut);
   };
 
 cSubtitleRegion::cSubtitleRegion(int RegionId)
@@ -369,6 +460,7 @@
   horizontalAddress = 0;
   verticalAddress = 0;
   level = 0;
+  lineHeight = 26; // configurable subtitling font size
 }
 
 void cSubtitleRegion::FillRegion(tIndex Index)
@@ -394,6 +486,22 @@
   return result;
 }
 
+void cSubtitleRegion::UpdateTextData(cSubtitleClut *Clut)
+{
+  const cPalette *palette = Clut ? Clut->GetPalette(Depth()) : NULL;
+  for (cSubtitleObject *so = objects.First(); so && palette; so = objects.Next(so)) {
+      if (Utf8StrLen(so->TextData()) > 0) {
+         const cFont *font = cFont::GetFont(fontOsd);
+         cBitmap *tmp = new cBitmap(font->Width(so->TextData()), font->Height(), Depth());
+         double factor = (double)lineHeight / font->Height();
+         tmp->DrawText(0, 0, so->TextData(), palette->Color(so->ForegroundPixelCode()), palette->Color(so->BackgroundPixelCode()), font);
+         tmp = tmp->Scaled(factor, factor, true);
+         DrawBitmap(so->X(), so->Y(), *tmp);
+         DELETENULL(tmp);
+         }
+      }
+}
+
 void cSubtitleRegion::SetLevel(int Level)
 {
   if (Level > 0 && Level < 4)
@@ -887,7 +995,7 @@
   double VideoAspect;
   cDevice::PrimaryDevice()->GetOsdSize(OsdWidth, OsdHeight, OsdAspect);
   cDevice::PrimaryDevice()->GetVideoSize(VideoWidth, VideoHeight, VideoAspect);
-  if (OsdWidth == displayWidth && OsdHeight == displayHeight) {
+  if (OsdWidth == displayWidth && OsdHeight == displayHeight || VideoWidth == 0) {
      osdFactorX = osdFactorY = 1.0;
      osdDeltaX = osdDeltaY = 0;
      }
@@ -907,12 +1015,15 @@
 
 int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t Pts)
 {
-  if (Length > 5 && Data[0] == 0x0F) {
-     int segmentLength = (Data[4] << 8) + Data[5] + 6;
-     if (segmentLength > Length)
+  cBitStream bs(Data, Length * 8);
+  if (Length > 5 && bs.GetBits(8) == 0x0F) { // sync byte
+     int segmentType = bs.GetBits(8);
+     if (segmentType == STUFFING_SEGMENT)
+        return -1;
+     int pageId = bs.GetBits(16);
+     int segmentLength = bs.GetBits(16);
+     if (!bs.SetLength(bs.Index() + segmentLength * 8))
         return -1;
-     int segmentType = Data[1];
-     int pageId = (Data[2] << 8) + Data[3];
      cDvbSubtitlePage *page = NULL;
      LOCK_THREAD;
      for (cDvbSubtitlePage *sp = pages->First(); sp; sp = pages->Next(sp)) {
@@ -931,154 +1042,170 @@
      switch (segmentType) {
        case PAGE_COMPOSITION_SEGMENT: {
             dbgsegments("PAGE_COMPOSITION_SEGMENT\n");
-            int pageVersion = (Data[6 + 1] & 0xF0) >> 4;
+            int pageTimeout = bs.GetBits(8);
+            int pageVersion = bs.GetBits(4);
             if (pageVersion == page->Version())
                break; // no update
             page->SetVersion(pageVersion);
-            page->SetTimeout(Data[6]);
-            page->SetState((Data[6 + 1] & 0x0C) >> 2);
+            page->SetTimeout(pageTimeout);
+            page->SetState(bs.GetBits(2));
             page->regions.Clear();
+            bs.SkipBits(2); // reserved
             dbgpages("Update page id %d version %d pts %"PRId64" timeout %d state %d\n", pageId, page->Version(), page->Pts(), page->Timeout(), page->State());
-            for (int i = 6 + 2; i < segmentLength; i += 6) {
-                cSubtitleRegion *region = page->GetRegionById(Data[i], true);
-                region->SetHorizontalAddress((Data[i + 2] << 8) + Data[i + 3]);
-                region->SetVerticalAddress((Data[i + 4] << 8) + Data[i + 5]);
-                }
+            while (!bs.IsEOF()) {
+                  cSubtitleRegion *region = page->GetRegionById(bs.GetBits(8), true);
+                  bs.SkipBits(8); // reserved
+                  region->SetHorizontalAddress(bs.GetBits(16));
+                  region->SetVerticalAddress(bs.GetBits(16));
+                  }
             break;
             }
        case REGION_COMPOSITION_SEGMENT: {
             dbgsegments("REGION_COMPOSITION_SEGMENT\n");
-            cSubtitleRegion *region = page->GetRegionById(Data[6]);
+            cSubtitleRegion *region = page->GetRegionById(bs.GetBits(8));
             if (!region)
                break;
-            int regionVersion = (Data[6 + 1] & 0xF0) >> 4;
+            int regionVersion = bs.GetBits(4);
             if (regionVersion == region->Version())
                break; // no update
             region->SetVersion(regionVersion);
-            bool regionFillFlag = (Data[6 + 1] & 0x08) >> 3;
-            int regionWidth = (Data[6 + 2] << 8) | Data[6 + 3];
+            bool regionFillFlag = bs.GetBit();
+            bs.SkipBits(3); // reserved
+            int regionWidth = bs.GetBits(16);
             if (regionWidth < 1)
                regionWidth = 1;
-            int regionHeight = (Data[6 + 4] << 8) | Data[6 + 5];
+            int regionHeight = bs.GetBits(16);
             if (regionHeight < 1)
                regionHeight = 1;
             region->SetSize(regionWidth, regionHeight);
-            region->SetLevel((Data[6 + 6] & 0xE0) >> 5);
-            region->SetDepth((Data[6 + 6] & 0x1C) >> 2);
-            region->SetClutId(Data[6 + 7]);
+            region->SetLevel(bs.GetBits(3));
+            region->SetDepth(bs.GetBits(3));
+            bs.SkipBits(2); // reserved
+            region->SetClutId(bs.GetBits(8));
             dbgregions("Region pageId %d id %d version %d fill %d width %d height %d level %d depth %d clutId %d\n", pageId, region->RegionId(), region->Version(), regionFillFlag, regionWidth, regionHeight, region->Level(), region->Depth(), region->ClutId());
+            int region8bitPixelCode = bs.GetBits(8);
+            int region4bitPixelCode = bs.GetBits(4);
+            int region2bitPixelCode = bs.GetBits(2);
+            bs.SkipBits(2); // reserved
             if (regionFillFlag) {
                switch (region->Bpp()) {
-                 case 2: region->FillRegion((Data[6 + 9] & 0x0C) >> 2); break;
-                 case 4: region->FillRegion((Data[6 + 9] & 0xF0) >> 4); break;
-                 case 8: region->FillRegion(Data[6 + 8]); break;
+                 case 2: region->FillRegion(region8bitPixelCode); break;
+                 case 4: region->FillRegion(region4bitPixelCode); break;
+                 case 8: region->FillRegion(region2bitPixelCode); break;
                  default: dbgregions("unknown bpp %d (%s %d)\n", region->Bpp(), __FUNCTION__, __LINE__);
                  }
                }
-            for (int i = 6 + 10; i < segmentLength; i += 6) {
-                cSubtitleObject *object = region->GetObjectById((Data[i] << 8) | Data[i + 1], true);
-                int objectType = (Data[i + 2] & 0xC0) >> 6;
-                object->SetCodingMethod(objectType);
-                object->SetProviderFlag((Data[i + 2] & 0x30) >> 4);
-                int objectHorizontalPosition = ((Data[i + 2] & 0x0F) << 8) | Data[i + 3];
-                int objectVerticalPosition = ((Data[i + 4] & 0x0F) << 8) | Data[i + 5];
-                object->SetPosition(objectHorizontalPosition, objectVerticalPosition);
-                if (objectType == 0x01 || objectType == 0x02) {
-                   object->SetForegroundColor(Data[i + 6]);
-                   object->SetBackgroundColor(Data[i + 7]);
-                   i += 2;
-                   }
-                }
+            while (!bs.IsEOF()) {
+                  cSubtitleObject *object = region->GetObjectById(bs.GetBits(16), true);
+                  int objectType = bs.GetBits(2);
+                  object->SetCodingMethod(objectType);
+                  object->SetProviderFlag(bs.GetBits(2));
+                  int objectHorizontalPosition = bs.GetBits(12);
+                  bs.SkipBits(4); // reserved
+                  int objectVerticalPosition = bs.GetBits(12);
+                  object->SetPosition(objectHorizontalPosition, objectVerticalPosition);
+                  if (objectType == 0x01 || objectType == 0x02) {
+                     object->SetForegroundPixelCode(bs.GetBits(8));
+                     object->SetBackgroundPixelCode(bs.GetBits(8));
+                     }
+                  }
             break;
             }
        case CLUT_DEFINITION_SEGMENT: {
             dbgsegments("CLUT_DEFINITION_SEGMENT\n");
-            cSubtitleClut *clut =  page->GetClutById(Data[6], true);
-            int clutVersion = (Data[6 + 1] & 0xF0) >> 4;
+            cSubtitleClut *clut =  page->GetClutById(bs.GetBits(8), true);
+            int clutVersion = bs.GetBits(4);
             if (clutVersion == clut->Version())
                break; // no update
             clut->SetVersion(clutVersion);
+            bs.SkipBits(4); // reserved
             dbgcluts("Clut pageId %d id %d version %d\n", pageId, clut->ClutId(), clut->Version());
-            for (int i = 6 + 2; i < segmentLength; i += 2) {
-                uchar clutEntryId = Data[i];
-                bool fullRangeFlag = Data[i + 1] & 1;
-                uchar yval;
-                uchar crval;
-                uchar cbval;
-                uchar tval;
-                if (fullRangeFlag) {
-                   yval  = Data[i + 2];
-                   crval = Data[i + 3];
-                   cbval = Data[i + 4];
-                   tval  = Data[i + 5];
-                   }
-                else {
-                   yval   =   Data[i + 2] & 0xFC;
-                   crval  =  (Data[i + 2] & 0x03) << 6;
-                   crval |=  (Data[i + 3] & 0xC0) >> 2;
-                   cbval  =  (Data[i + 3] & 0x3C) << 2;
-                   tval   =  (Data[i + 3] & 0x03) << 6;
-                   }
-                tColor value = 0;
-                if (yval) {
-                   value = yuv2rgb(yval, cbval, crval);
-                   value |= ((10 - (clutEntryId ? Setup.SubtitleFgTransparency : Setup.SubtitleBgTransparency)) * (255 - tval) / 10) << 24;
-                   }
-                int EntryFlags = Data[i + 1];
-                dbgcluts("%2d %d %d %d %08X\n", clutEntryId, (EntryFlags & 0x80) ? 2 : 0, (EntryFlags & 0x40) ? 4 : 0, (EntryFlags & 0x20) ? 8 : 0, value);
-                if ((EntryFlags & 0x80) != 0)
-                   clut->SetColor(2, clutEntryId, value);
-                if ((EntryFlags & 0x40) != 0)
-                   clut->SetColor(4, clutEntryId, value);
-                if ((EntryFlags & 0x20) != 0)
-                   clut->SetColor(8, clutEntryId, value);
-                i += fullRangeFlag ? 4 : 2;
-                }
+            while (!bs.IsEOF()) {
+                  uchar clutEntryId = bs.GetBits(8);
+                  bool entryClut2Flag = bs.GetBit();
+                  bool entryClut4Flag = bs.GetBit();
+                  bool entryClut8Flag = bs.GetBit();
+                  bs.SkipBits(4); // reserved
+                  uchar yval;
+                  uchar crval;
+                  uchar cbval;
+                  uchar tval;
+                  if (bs.GetBit()) { // full_range_flag
+                     yval  = bs.GetBits(8);
+                     crval = bs.GetBits(8);
+                     cbval = bs.GetBits(8);
+                     tval  = bs.GetBits(8);
+                     }
+                  else {
+                     yval  = bs.GetBits(6) << 2;
+                     crval = bs.GetBits(4) << 4;
+                     cbval = bs.GetBits(4) << 4;
+                     tval  = bs.GetBits(2) << 6;
+                     }
+                  tColor value = 0;
+                  if (yval) {
+                     value = yuv2rgb(yval, cbval, crval);
+                     value |= ((10 - (clutEntryId ? Setup.SubtitleFgTransparency : Setup.SubtitleBgTransparency)) * (255 - tval) / 10) << 24;
+                     }
+                  dbgcluts("%2d %d %d %d %08X\n", clutEntryId, entryClut2Flag ? 2 : 0, entryClut4Flag ? 4 : 0, entryClut8Flag ? 8 : 0, value);
+                  if (entryClut2Flag)
+                     clut->SetColor(2, clutEntryId, value);
+                  if (entryClut4Flag)
+                     clut->SetColor(4, clutEntryId, value);
+                  if (entryClut8Flag)
+                     clut->SetColor(8, clutEntryId, value);
+                  }
             dbgcluts("\n");
             page->UpdateRegionPalette(clut);
             break;
             }
        case OBJECT_DATA_SEGMENT: {
             dbgsegments("OBJECT_DATA_SEGMENT\n");
-            cSubtitleObject *object = page->GetObjectById((Data[6] << 8) | Data[6 + 1]);
+            cSubtitleObject *object = page->GetObjectById(bs.GetBits(16));
             if (!object)
                break;
-            int objectVersion = (Data[6 + 2] & 0xF0) >> 4;
+            int objectVersion = bs.GetBits(4);
             if (objectVersion == object->Version())
                break; // no update
             object->SetVersion(objectVersion);
-            int codingMethod = (Data[6 + 2] & 0x0C) >> 2;
-            object->SetNonModifyingColorFlag(Data[6 + 2] & 0x01);
+            int codingMethod = bs.GetBits(2);
+            object->SetNonModifyingColorFlag(bs.GetBit());
+            bs.SkipBit(); // reserved
             dbgobjects("Object pageId %d id %d version %d method %d modify %d\n", pageId, object->ObjectId(), object->Version(), object->CodingMethod(), object->NonModifyingColorFlag());
             if (codingMethod == 0) { // coding of pixels
-               int i = 6 + 3;
-               int topFieldLength = (Data[i] << 8) | Data[i + 1];
-               int bottomFieldLength = (Data[i + 2] << 8) | Data[i + 3];
-               object->DecodeSubBlock(Data + i + 4, topFieldLength, true);
+               int topFieldLength = bs.GetBits(16);
+               int bottomFieldLength = bs.GetBits(16);
+               object->DecodeSubBlock(bs.GetData(), topFieldLength, true);
                if (bottomFieldLength)
-                  object->DecodeSubBlock(Data + i + 4 + topFieldLength, bottomFieldLength, false);
+                  object->DecodeSubBlock(bs.GetData() + topFieldLength, bottomFieldLength, false);
                else
-                  object->DecodeSubBlock(Data + i + 4, topFieldLength, false);
+                  object->DecodeSubBlock(bs.GetData(), topFieldLength, false);
+               bs.WordAlign();
                }
             else if (codingMethod == 1) { // coded as a string of characters
-               //TODO implement textual subtitles
+               int numberOfCodes = bs.GetBits(8);
+               object->DecodeCharacterString(bs.GetData(), numberOfCodes);
                }
+#ifdef FINISHPAGE_HACK
+            FinishPage(page); // flush to OSD right away
+#endif
             break;
             }
        case DISPLAY_DEFINITION_SEGMENT: {
             dbgsegments("DISPLAY_DEFINITION_SEGMENT\n");
-            int version = (Data[6] & 0xF0) >> 4;
+            int version = bs.GetBits(4);
             if (version != ddsVersionNumber) {
-               int displayWindowFlag   = (Data[6] & 0x08) >> 3;
+               bool displayWindowFlag = bs.GetBit();
                windowHorizontalOffset = 0;
                windowVerticalOffset   = 0;
-               displayWidth = windowWidth   = ((Data[7] << 8) | Data[8]) + 1;
-               displayHeight = windowHeight = ((Data[9] << 8) | Data[10]) + 1;
-               if (displayWindowFlag) { 
-                  windowHorizontalOffset = (Data[11] << 8) | Data[12];                                // displayWindowHorizontalPositionMinimum
-                  windowWidth            = ((Data[13] << 8) | Data[14]) - windowHorizontalOffset + 1; // displayWindowHorizontalPositionMaximum
-                  windowVerticalOffset   = (Data[15] << 8) | Data[16];                                // displayWindowVerticalPositionMinimum
-                  windowHeight           = ((Data[17] << 8) | Data[18]) - windowVerticalOffset + 1;   // displayWindowVerticalPositionMaximum
+               bs.SkipBits(3); // reserved
+               displayWidth  = windowWidth  = bs.GetBits(16) + 1;
+               displayHeight = windowHeight = bs.GetBits(16) + 1;
+               if (displayWindowFlag) {
+                  windowHorizontalOffset = bs.GetBits(16);                              // displayWindowHorizontalPositionMinimum
+                  windowWidth            = bs.GetBits(16) - windowHorizontalOffset + 1; // displayWindowHorizontalPositionMaximum
+                  windowVerticalOffset   = bs.GetBits(16);                              // displayWindowVerticalPositionMinimum
+                  windowHeight           = bs.GetBits(16) - windowVerticalOffset + 1;   // displayWindowVerticalPositionMaximum
                   }
                SetOsdData();
                SetupChanged();
@@ -1086,15 +1213,56 @@
                }
             break;
             }
+       case DISPARITY_SIGNALING_SEGMENT: {
+            dbgsegments("DISPARITY_SIGNALING_SEGMENT\n");
+            bs.SkipBits(4); // dss_version_number
+            bool disparity_shift_update_sequence_page_flag = bs.GetBit();
+            bs.SkipBits(3); // reserved
+            bs.SkipBits(8); // page_default_disparity_shift
+            if (disparity_shift_update_sequence_page_flag) {
+               bs.SkipBits(8); // disparity_shift_update_sequence_length
+               bs.SkipBits(24); // interval_duration[23..0]
+               int division_period_count = bs.GetBits(8);
+               for (int i = 0; i < division_period_count; ++i) {
+                   bs.SkipBits(8); // interval_count
+                   bs.SkipBits(8); // disparity_shift_update_integer_part
+                   }
+               }
+            while (!bs.IsEOF()) {
+                  bs.SkipBits(8); // region_id
+                  bool disparity_shift_update_sequence_region_flag = bs.GetBit();
+                  bs.SkipBits(5); // reserved
+                  int number_of_subregions_minus_1 = bs.GetBits(2);
+                  for (int i = 0; i <= number_of_subregions_minus_1; ++i) {
+                      if (number_of_subregions_minus_1 > 0) {
+                         bs.SkipBits(16); // subregion_horizontal_position
+                         bs.SkipBits(16); // subregion_width
+                         }
+                      bs.SkipBits(8); // subregion_disparity_shift_integer_part
+                      bs.SkipBits(4); // subregion_disparity_shift_fractional_part
+                      bs.SkipBits(4); // reserved
+                      if (disparity_shift_update_sequence_region_flag) {
+                         bs.SkipBits(8); // disparity_shift_update_sequence_length
+                         bs.SkipBits(24); // interval_duration[23..0]
+                         int division_period_count = bs.GetBits(8);
+                         for (int i = 0; i < division_period_count; ++i) {
+                             bs.SkipBits(8); // interval_count
+                             bs.SkipBits(8); // disparity_shift_update_integer_part
+                             }
+                         }
+                      }
+                  }
+            break;
+            }
        case END_OF_DISPLAY_SET_SEGMENT: {
             dbgsegments("END_OF_DISPLAY_SET_SEGMENT\n");
             FinishPage(page);
-            }
             break;
+            }
        default:
             dbgsegments("*** unknown segment type: %02X\n", segmentType);
        }
-     return segmentLength;
+     return bs.Length() / 8;
      }
   return -1;
 }
@@ -1143,6 +1311,7 @@
   cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas, osdFactorX, osdFactorY);
   bitmaps->Add(Bitmaps);
   for (cSubtitleRegion *sr = Page->regions.First(); sr; sr = Page->regions.Next(sr)) {
+      sr->UpdateTextData(Page->GetClutById(sr->ClutId()));
       int posX = sr->HorizontalAddress();
       int posY = sr->VerticalAddress();
       if (sr->Width() > 0 && sr->Height() > 0) {
diff -ruN vdr-1.7.21/eitscan.c vdr-1.7.22/eitscan.c
--- vdr-1.7.21/eitscan.c	2011-08-26 18:16:46.000000000 +0200
+++ vdr-1.7.22/eitscan.c	2011-09-25 16:58:55.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: eitscan.c 2.4 2011/08/26 16:16:46 kls Exp $
+ * $Id: eitscan.c 2.5 2011/09/25 14:58:55 kls Exp $
  */
 
 #include "eitscan.h"
@@ -150,7 +150,7 @@
                          if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
                             if (Device->ProvidesTransponder(Channel)) {
                                if (!Device->Receiving()) {
-                                  bool MaySwitchTransponder = Device->MaySwitchTransponder();
+                                  bool MaySwitchTransponder = Device->MaySwitchTransponder(Channel);
                                   if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) {
                                      if (!MaySwitchTransponder) {
                                         if (Device == cDevice::ActualDevice() && !currentChannel) {
diff -ruN vdr-1.7.21/epg2html vdr-1.7.22/epg2html
--- vdr-1.7.21/epg2html	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/epg2html	2011-12-04 15:17:35.000000000 +0100
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+
+# A simple EPG to HTML converter
+#
+# Converts the EPG data written by 'vdr' into the file /video/epg.data
+# into a simple HTML programme listing, consisting of one file per channel
+# plus an 'index.htm' file. All output files are written into the current
+# directory.
+#
+# Usage: epg2html < /video/epg.data
+#
+# See the main source file 'vdr.c' for copyright information and
+# how to reach the author.
+#
+# $Id: epg2html 2.1 2011/12/04 14:17:35 kls Exp $
+
+@Index = ();
+
+sub GetDay
+{
+  return substr(localtime(shift), 0, 10);
+}
+
+sub GetTime
+{
+  return substr(localtime(shift), 11, 5);
+}
+
+sub Tags
+{
+  my $s = shift;
+  $s =~ s/\&/&amp;/g;
+  $s =~ s/</&lt;/g;
+  $s =~ s/>/&gt;/g;
+  return $s;
+}
+
+while (<>) {
+      chomp;
+      if (/^C ([^ ]+) *(.*)/) {
+         my $Channel = $2;
+         (my $Page = $Channel) =~ y/\/ /-_/;
+         $Page .= ".htm";
+         $Channel = Tags($Channel);
+         push(@Index, qq{<a href="$Page">$Channel</a><br>\n});
+         my %Events = ();
+         while (<>) {
+               if (/^E (.*?) (.*?) ([^ ]*)/) {
+                  (my $Time, $Duration) = ($2, $3);
+                  my $Title = "", $Subtitle = "", $Description = "", $Vps = 0;
+                  while (<>) {
+                        if    (/^T (.*)/) { $Title       = Tags($1); }
+                        elsif (/^S (.*)/) { $Subtitle    = Tags($1); }
+                        elsif (/^D (.*)/) { $Description = Tags($1); $Description =~ s/\|/<br>/g; }
+                        elsif (/^V (.*)/) { $Vps         = $1; }
+                        elsif (/^e/) {
+                           $Events{$Time} = [($Duration, $Title, $Subtitle, $Description, $Vps)];
+                           last;
+                           }
+                        }
+                  }
+               elsif (/^c/) {
+                  my @Schedule = ();
+                  my $Day = "";
+                  for $t (sort keys %Events) {
+                      (my $Duration, $Title, $Subtitle, $Description, $Vps) = @{$Events{$t}};
+                      my $d = GetDay($t);
+                      if ($d ne $Day) {
+                         push(@Schedule, "</table>\n") if ($Day && @Schedule);
+                         push(@Schedule, "<h2>$d</h2>\n");
+                         push(@Schedule, "<table cellspacing=2>\n");
+                         $Day = $d;
+                         }
+                      my $Entry = $Title;
+                      $Entry .= "<br><i>$Subtitle</i>" if $Subtitle;
+                      $Entry .= "<br>$Description" if $Description;
+                      $Entry .= "<br>(VPS = " . scalar localtime($Vps) . ")" if $Vps && $Vps != $t;
+                      push(@Schedule, "<tr><td valign=top>" . GetTime($t) . "</td><td>$Entry</td></tr>\n");
+                      }
+                  push(@Schedule, "</table>\n") if (@Schedule);
+                  open(PAGE, ">$Page") or die "$Page: $!\n";
+                  print PAGE "<html>\n<head><title>$Channel</title><head>\n<body>\n";
+                  print PAGE "<h1>$Channel</h1>\n";
+                  print PAGE @Schedule;
+                  print PAGE "</body>\n</html>\n";
+                  close(PAGE);
+                  last;
+                  }
+               }
+         }
+      }
+
+open(INDEX, ">index.htm") or die "index.htm: $!\n";
+print INDEX "<html>\n<head><title>EPG Index</title><head>\n<body>\n";
+print INDEX sort { lc($a) cmp lc($b) } @Index;
+print INDEX "</body>\n</html>\n";
+close(INDEX);
diff -ruN vdr-1.7.21/epg2html.pl vdr-1.7.22/epg2html.pl
--- vdr-1.7.21/epg2html.pl	2006-04-17 14:19:08.000000000 +0200
+++ vdr-1.7.22/epg2html.pl	1970-01-01 01:00:00.000000000 +0100
@@ -1,97 +0,0 @@
-#!/usr/bin/perl
-
-# A simple EPG to HTML converter
-#
-# Converts the EPG data written by 'vdr' into the file /video/epg.data
-# into a simple HTML programme listing, consisting of one file per channel
-# plus an 'index.htm' file. All output files are written into the current
-# directory.
-#
-# Usage: epg2html.pl < /video/epg.data
-#
-# See the main source file 'vdr.c' for copyright information and
-# how to reach the author.
-#
-# $Id: epg2html.pl 2.0 2006/04/17 12:19:08 kls Exp $
-
-@Index = ();
-
-sub GetDay
-{
-  return substr(localtime(shift), 0, 10);
-}
-
-sub GetTime
-{
-  return substr(localtime(shift), 11, 5);
-}
-
-sub Tags
-{
-  my $s = shift;
-  $s =~ s/\&/&amp;/g;
-  $s =~ s/</&lt;/g;
-  $s =~ s/>/&gt;/g;
-  return $s;
-}
-
-while (<>) {
-      chomp;
-      if (/^C ([^ ]+) *(.*)/) {
-         my $Channel = $2;
-         (my $Page = $Channel) =~ y/\/ /-_/;
-         $Page .= ".htm";
-         $Channel = Tags($Channel);
-         push(@Index, qq{<a href="$Page">$Channel</a><br>\n});
-         my %Events = ();
-         while (<>) {
-               if (/^E (.*?) (.*?) ([^ ]*)/) {
-                  (my $Time, $Duration) = ($2, $3);
-                  my $Title = "", $Subtitle = "", $Description = "", $Vps = 0;
-                  while (<>) {
-                        if    (/^T (.*)/) { $Title       = Tags($1); }
-                        elsif (/^S (.*)/) { $Subtitle    = Tags($1); }
-                        elsif (/^D (.*)/) { $Description = Tags($1); $Description =~ s/\|/<br>/g; }
-                        elsif (/^V (.*)/) { $Vps         = $1; }
-                        elsif (/^e/) {
-                           $Events{$Time} = [($Duration, $Title, $Subtitle, $Description, $Vps)];
-                           last;
-                           }
-                        }
-                  }
-               elsif (/^c/) {
-                  my @Schedule = ();
-                  my $Day = "";
-                  for $t (sort keys %Events) {
-                      (my $Duration, $Title, $Subtitle, $Description, $Vps) = @{$Events{$t}};
-                      my $d = GetDay($t);
-                      if ($d ne $Day) {
-                         push(@Schedule, "</table>\n") if ($Day && @Schedule);
-                         push(@Schedule, "<h2>$d</h2>\n");
-                         push(@Schedule, "<table cellspacing=2>\n");
-                         $Day = $d;
-                         }
-                      my $Entry = $Title;
-                      $Entry .= "<br><i>$Subtitle</i>" if $Subtitle;
-                      $Entry .= "<br>$Description" if $Description;
-                      $Entry .= "<br>(VPS = " . scalar localtime($Vps) . ")" if $Vps && $Vps != $t;
-                      push(@Schedule, "<tr><td valign=top>" . GetTime($t) . "</td><td>$Entry</td></tr>\n");
-                      }
-                  push(@Schedule, "</table>\n") if (@Schedule);
-                  open(PAGE, ">$Page") or die "$Page: $!\n";
-                  print PAGE "<html>\n<head><title>$Channel</title><head>\n<body>\n";
-                  print PAGE "<h1>$Channel</h1>\n";
-                  print PAGE @Schedule;
-                  print PAGE "</body>\n</html>\n";
-                  close(PAGE);
-                  last;
-                  }
-               }
-         }
-      }
-
-open(INDEX, ">index.htm") or die "index.htm: $!\n";
-print INDEX "<html>\n<head><title>EPG Index</title><head>\n<body>\n";
-print INDEX sort { lc($a) cmp lc($b) } @Index;
-print INDEX "</body>\n</html>\n";
-close(INDEX);
diff -ruN vdr-1.7.21/font.h vdr-1.7.22/font.h
--- vdr-1.7.21/font.h	2011-01-14 17:22:03.000000000 +0100
+++ vdr-1.7.22/font.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: font.h 2.5 2011/01/14 16:22:03 kls Exp $
+ * $Id: font.h 2.6 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __FONT_H
@@ -51,7 +51,7 @@
   virtual int Height(void) const = 0;
           ///< Returns the height of this font in pixel (all characters have the same height).
   int Height(const char *s) const { return Height(); }
-          ///< Returns the height of this font in pixel (obsolete, just for backwards compatibilty).
+          ///< Returns the height of this font in pixel (obsolete, just for backwards compatibility).
   virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const = 0;
           ///< Draws the given text into the Bitmap at position (x, y) with the given colors.
           ///< The text will not exceed the given Width (if > 0), and will end with a complete character.
diff -ruN vdr-1.7.21/i18n-to-gettext vdr-1.7.22/i18n-to-gettext
--- vdr-1.7.21/i18n-to-gettext	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/i18n-to-gettext	2011-12-04 15:17:35.000000000 +0100
@@ -0,0 +1,347 @@
+#!/usr/bin/perl -w
+
+# Convert i18n texts to gettext
+#
+# Extracts all texts from the file i18n.c and creates language
+# specific *.po files.
+#
+# Usage: i18n-to-gettext
+#
+# See the main source file 'vdr.c' for copyright information and
+# how to reach the author.
+#
+# $Id: i18n-to-gettext 2.2 2011/12/04 14:17:35 kls Exp $
+
+# How to convert an actual plugin:
+#
+# - If your code contains something like
+#
+#   const char *Text = "Some text";
+#   ...
+#   Function(tr(Text));
+#
+#   you need to enclose the text constant in trNOOP(...), as in
+#
+#   const char *Text = trNOOP("Some text");
+#
+#   The actual usage of the tr() macro remains unchanged.
+#
+# - If you have comments following the texts in your i18n.c file
+#   that should be seen by the translators, move them from the
+#   i18n.c file into the file where the text is actually used,
+#   and mark them with the TRANSLATORS keyword, as in
+#
+#   // TRANSLATORS: note the plural!
+#   Add(new cMenuEditIntItem( tr("Setup.EPG$Preferred languages"), ...
+#
+# - Fill in your email address in the line
+#   $MSGIDBUGS = "" ...
+#   below, so that users can reach you in case there is a problem
+#   with a message id.
+#
+# - Run this Perl script from within your plugin's source directory.
+#   This script will run 'xgettext' to extract all of your texts
+#   into a file named <pluginname>.pot. After that it will extract
+#   your existing i18n texts from the file i18n.c (or wherever you
+#   have defined them) and generate *.po files for all languages
+#   currently known by VDR.
+#
+# - Your Makefile will be automatically adjusted to allow for
+#   building the *.mo files necessary for supporting gettext().
+#   Please check carefully whether the automatic adjustments have
+#   succeeded, though. The modified Makefile will be written to
+#   Makefile.new, so you can call this script any numer of times
+#   in case you need to do some fine tuning of your texts (especially
+#   adding some trNOOP() in case the script reports "missing phrases".
+#   Once you're done converting your plugin source to using gettext,
+#   rename Makefile.new to Makefile.
+#
+# - You may want to remove the old internationalized texts from your
+#   source. Usually this means removing the files i18n.[hc], stripping
+#   i18n.o from the OBJS variable in the Makefile and removing all
+#   '#include "i18n.h"' lines from the rest of your source files.
+#   These steps are not done automatically.
+
+# Check for the existence of a Makefile:
+
+die "Makefile not found!" unless (-f "Makefile");
+
+# Determine the plugin name:
+
+$PLUGIN = `grep '^PLUGIN *=' Makefile | head -1` || die "can't find plugin name!";
+$PLUGIN =~ s/.*= *(.*)\n/$1/;
+die "can't find plugin name!" unless ($PLUGIN);
+
+# Locate the file containing the texts:
+
+$I18NFILE = "";
+for ("i18n.c", "i18n.h", `ls *.c`) { # try i18n.[ch] explicitly first
+    chomp($f = $_);
+    if (-f $f && `grep tI18nPhrase $f`) {
+       $I18NFILE = $f;
+       last;
+       }
+    }
+die "can't find internationalized texts!" unless ($I18NFILE);
+
+# Plugin specific information:
+
+$TITLE = "VDR plugin language source file";
+$COPYRIGHT = "2007 Klaus Schmidinger <kls\@tvdr.de>";
+$PACKAGE = "VDR";
+$VERSION = "1.5.7";
+$MSGIDBUGS = "" || die "enter your email address here"; # escape the '@', as in "user\@domain.tld"
+$LANGUAGETEAM = "<vdr\@linuxtv.org>";
+
+# Gettext environment:
+
+$XGETTEXT = "xgettext -C -cTRANSLATORS --no-wrap -F -k -ktr -ktrNOOP --msgid-bugs-address='$MSGIDBUGS'";
+$PODIR = "po";
+$POTFILE = "$PODIR/$PLUGIN.pot";
+
+# Languages as known by VDR 1.5.6:
+
+@LANGS = (
+  "en_US",
+  "de_DE",
+  "sl_SI",
+  "it_IT",
+  "nl_NL",
+  "pt_PT",
+  "fr_FR",
+  "nn_NO",
+  "fi_FI",
+  "pl_PL",
+  "es_ES",
+  "el_GR",
+  "sv_SE",
+  "ro_RO",
+  "hu_HU",
+  "ca_ES",
+  "ru_RU",
+  "hr_HR",
+  "et_EE",
+  "da_DK",
+  "cs_CZ",
+  "tr_TR"
+  );
+
+@CHARSETS = (
+  "ISO-8859-15",
+  "ISO-8859-15",
+  "ISO-8859-2",
+  "ISO-8859-15",
+  "ISO-8859-15",
+  "ISO-8859-1",
+  "ISO-8859-1",
+  "ISO-8859-1",
+  "ISO-8859-15",
+  "ISO-8859-2",
+  "ISO-8859-15",
+  "ISO-8859-7",
+  "ISO-8859-1",
+  "ISO-8859-2",
+  "ISO-8859-2",
+  "ISO-8859-1",
+  "ISO-8859-5",
+  "ISO-8859-2",
+  "ISO-8859-13",
+  "ISO-8859-15",
+  "ISO-8859-2",
+  "ISO-8859-9",
+  );
+
+@TRANSLATORS = (
+  "Klaus Schmidinger <kls\@tvdr.de>, 2000",
+  "Klaus Schmidinger <kls\@tvdr.de>, 2000",
+  "Miha Setina <mihasetina\@softhome.net>, 2000; Matjaz Thaler <matjaz.thaler\@guest.arnes.si>, 2003",
+  "Alberto Carraro <bertocar\@tin.it>, 2001; Antonio Ospite <ospite\@studenti.unina.it>, 2003; Sean Carlos <seanc\@libero.it>, 2005",
+  "Arnold Niessen <niessen\@iae.nl> <arnold.niessen\@philips.com>, 2001; Hans Dingemans <hans.dingemans\@tacticalops.nl>, 2003; Maarten Wisse <Maarten.Wisse\@urz.uni-hd.de>, 2005",
+  "Paulo Lopes <pmml\@netvita.pt>, 2001",
+  "Jean-Claude Repetto <jc\@repetto.org>, 2001; Olivier Jacques <jacquesolivier\@hotmail.com>, 2003; Gregoire Favre <greg\@magma.unil.ch>, 2003; Nicolas Huillard <nhuillard\@e-dition.fr>, 2005",
+  "J�rgen Tvedt <pjtvedt\@online.no>, 2001; Truls Slevigen <truls\@slevigen.no>, 2002",
+  "Hannu Savolainen <hannu\@opensound.com>, 2002; Jaakko Hyv�tti <jaakko\@hyvatti.iki.fi>, 2002; Niko Tarnanen <niko.tarnanen\@hut.fi>, 2003; Rolf Ahrenberg <rahrenbe\@cc.hut.fi>, 2003",
+  "Michael Rakowski <mrak\@gmx.de>, 2002",
+  "Ruben Nunez Francisco <ruben.nunez\@tang-it.com>, 2002",
+  "Dimitrios Dimitrakos <mail\@dimitrios.de>, 2002",
+  "Tomas Prybil <tomas\@prybil.se>, 2002; Jan Ekholm <chakie\@infa.abo.fi>, 2003",
+  "Paul Lacatus <paul\@campina.iiruc.ro>, 2002; Lucian Muresan <lucianm\@users.sourceforge.net>, 2004",
+  "Istvan Koenigsberger <istvnko\@hotmail.com>, 2002; Guido Josten <guido.josten\@t-online.de>, 2002",
+  "Marc Rovira Vall <tm05462\@salleURL.edu>, 2003; Ramon Roca <ramon.roca\@xcombo.com>, 2003; Jordi Vil� <jvila\@tinet.org>, 2003",
+  "Vyacheslav Dikonov <sdiconov\@mail.ru>, 2004",
+  "Drazen Dupor <drazen.dupor\@dupor.com>, 2004; Dino Ravnic <dino.ravnic\@fer.hr>, 2004",
+  "Arthur Konovalov <kasjas\@hot.ee>, 2004",
+  "Mogens Elneff <mogens\@elneff.dk>, 2004",
+  "Vladim�r B�rta <vladimir.barta\@k2atmitec.cz>, 2006",
+  "Oktay Yolge�en <oktay_73\@yahoo.de>, 2007"
+  );
+
+@LASTTRANSLATOR = (
+  "Klaus Schmidinger <kls\@tvdr.de>",
+  "Klaus Schmidinger <kls\@tvdr.de>",
+  "Matjaz Thaler <matjaz.thaler\@guest.arnes.si>",
+  "Sean Carlos <seanc\@libero.it>",
+  "Maarten Wisse <Maarten.Wisse\@urz.uni-hd.de>",
+  "Paulo Lopes <pmml\@netvita.pt>",
+  "Nicolas Huillard <nhuillard\@e-dition.fr>",
+  "Truls Slevigen <truls\@slevigen.no>",
+  "Rolf Ahrenberg <rahrenbe\@cc.hut.fi>",
+  "Michael Rakowski <mrak\@gmx.de>",
+  "Ruben Nunez Francisco <ruben.nunez\@tang-it.com>",
+  "Dimitrios Dimitrakos <mail\@dimitrios.de>",
+  "Tomas Prybil <tomas\@prybil.se>",
+  "Lucian Muresan <lucianm\@users.sourceforge.net>",
+  "Istvan Koenigsberger <istvnko\@hotmail.com>, Guido Josten <guido.josten\@t-online.de>",
+  "Jordi Vil� <jvila\@tinet.org>",
+  "Vyacheslav Dikonov <sdiconov\@mail.ru>",
+  "Drazen Dupor <drazen.dupor\@dupor.com>",
+  "Arthur Konovalov <kasjas\@hot.ee>",
+  "Mogens Elneff <mogens\@elneff.dk>",
+  "Vladim�r B�rta <vladimir.barta\@k2atmitec.cz>",
+  "Oktay Yolge�en <oktay_73\@yahoo.de>"
+  );
+
+# Collect all translated texts:
+
+open(F, $I18NFILE) || die "$I18NFILE: $!\n";
+$InComment = 0;
+while (<F>) {
+      chomp;
+      s/\t/ /g; # get rid of tabs
+      s/  *$//; # get rid of trailing blanks
+      s/^ *\/\/.*//; # remove comment lines
+      s/ *\/\/.*//; # strip trailing comments
+      s/\/\*.*\*\///g; # strip c comments
+      if (/\/\*/) {
+         $InComment = 1;
+         s/\/\*.*$//; # remove start of comment
+         }
+      elsif (/\*\//) {
+         $InComment = 0;
+         s/^.*\*\///; # remove end of comment
+         }
+      elsif ($InComment) {
+         next;
+         }
+      next if (/^ *$/); # skip empty lines
+      next if (/#if/);
+      next if (/#endif/);
+      next unless ($found or $found = /const *tI18nPhrase .*{/); # sync on phrases
+      next if (/const *tI18nPhrase .*{/); # skip sync line
+      last if (/{ *NULL *}/); # stop after last phrase
+      if (/{ *(.*),/) {
+         $Original = $1;
+         $Index = 0;
+         }
+      elsif (/}/) {
+         }
+      else {
+         $Translated = $_;
+         $Translated =~ s/ *(.*),/$1/;
+         $Index++;
+         $Map{$Original}[$Index] = $Translated;
+         }
+      }
+close(F);
+
+# Generate the .pot file:
+
+(mkdir($PODIR) || die "$PODIR: $!\n") unless -d $PODIR;
+
+system("$XGETTEXT -o $POTFILE *.c");
+
+# Generate .po files for all languages:
+
+open(POT, $POTFILE) || die "$POTFILE: $!\n";
+@POT = <POT>;
+close(POT);
+
+for ($Index = 1; $LANGS[$Index]; $Index++) {
+
+    $Authors = "# " . join("\n# ", split(/; */, $TRANSLATORS[$Index])) . "\n";
+
+    $POFILE = "$PODIR/$LANGS[$Index].po";
+    open(PO, ">$POFILE") || die "$POFILE: $!\n";
+    $msgid = "";
+    for (@POT) {
+        next if (/^#, fuzzy$/); # skip the 'fuzzy' keyword
+        $msgid = $1 if (/^msgid (".+")/);
+        $date = $1 if (/POT-Creation-Date: (.*)\\n/);
+        $s = $_;
+        if (!$msgid) {
+           $s =~ s/SOME DESCRIPTIVE TITLE/$TITLE/;
+           $s =~ s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/$COPYRIGHT/;
+           $s =~ s/PACKAGE/$PACKAGE/;
+           $s =~ s/VERSION/$VERSION/;
+           $s = $Authors if (/FIRST AUTHOR/);
+           $s =~ s/YEAR-MO-DA HO:MI\+ZONE/$date/;
+           $s =~ s/FULL NAME <EMAIL\@ADDRESS>/$LASTTRANSLATOR[$Index]/;
+           $s =~ s/LANGUAGE <LL\@li\.org>/$LANGUAGETEAM/;
+           $s =~ s/CHARSET/$CHARSETS[$Index]/;
+           }
+        else {
+           $s =~ s/""/$Map{$msgid}[$Index]/ if ($msgid && /^msgstr ""/ && defined $Map{$msgid}[$Index]);
+           $Used{$msgid} = 1;
+           }
+        print PO $s;
+        }
+    close(PO);
+    }
+
+# Report missing phrases:
+
+for (keys %Map) {
+    push(@Missing, "$_\n") unless $Used{$_};
+    }
+
+if (@Missing) {
+   print "Missing phrases (may need to use trNOOP):\n\n";
+   print sort(@Missing);
+   }
+
+# Adjust the Makefile:
+
+$MAKEI18N = q{### Internationalization (I18N):
+
+PODIR     = po
+LOCALEDIR = $(VDRDIR)/locale
+I18Npo    = $(wildcard $(PODIR)/*.po)
+I18Nmsgs  = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot   = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+	msgfmt -c -o $@ $<
+
+$(I18Npot): $(wildcard *.c)
+	xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<} . $MSGIDBUGS . q{>' -o $@ $^
+
+%.po: $(I18Npot)
+	msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
+	@touch $@
+
+$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+	@mkdir -p $(dir $@)
+	cp $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmsgs)
+
+};
+
+open(OLD, "Makefile") || die "Makefile: $!";
+open(NEW, ">Makefile.new") || die "Makefile.new: $!";
+while (<OLD>) {
+      chomp;
+      if (/Targets:/) {
+         print NEW $MAKEI18N;
+         }
+      elsif (/^all:/) {
+         $_ .= " i18n";
+         }
+      elsif (/^clean:/) {
+         $_ .= "\n\t\@-rm -f \$(PODIR)/*.mo \$(PODIR)/*.pot";
+         }
+      print NEW "$_\n";
+      }
+close(NEW);
+close(OLD);
diff -ruN vdr-1.7.21/i18n-to-gettext.pl vdr-1.7.22/i18n-to-gettext.pl
--- vdr-1.7.21/i18n-to-gettext.pl	2009-10-18 16:07:49.000000000 +0200
+++ vdr-1.7.22/i18n-to-gettext.pl	1970-01-01 01:00:00.000000000 +0100
@@ -1,347 +0,0 @@
-#!/usr/bin/perl -w
-
-# Convert i18n texts to gettext
-#
-# Extracts all texts from the file i18n.c and creates language
-# specific *.po files.
-#
-# Usage: i18n-to-gettext.pl
-#
-# See the main source file 'vdr.c' for copyright information and
-# how to reach the author.
-#
-# $Id: i18n-to-gettext.pl 2.1 2009/10/18 14:07:49 kls Exp $
-
-# How to convert an actual plugin:
-#
-# - If your code contains something like
-#
-#   const char *Text = "Some text";
-#   ...
-#   Function(tr(Text));
-#
-#   you need to enclose the text constant in trNOOP(...), as in
-#
-#   const char *Text = trNOOP("Some text");
-#
-#   The actual usage of the tr() macro remains unchanged.
-#
-# - If you have comments following the texts in your i18n.c file
-#   that should be seen by the translators, move them from the
-#   i18n.c file into the file where the text is actually used,
-#   and mark them with the TRANSLATORS keyword, as in
-#
-#   // TRANSLATORS: note the plural!
-#   Add(new cMenuEditIntItem( tr("Setup.EPG$Preferred languages"), ...
-#
-# - Fill in your email address in the line
-#   $MSGIDBUGS = "" ...
-#   below, so that users can reach you in case there is a problem
-#   with a message id.
-#
-# - Run this Perl script from within your plugin's source directory.
-#   This script will run 'xgettext' to extract all of your texts
-#   into a file named <pluginname>.pot. After that it will extract
-#   your existing i18n texts from the file i18n.c (or wherever you
-#   have defined them) and generate *.po files for all languages
-#   currently known by VDR.
-#
-# - Your Makefile will be automatically adjusted to allow for
-#   building the *.mo files necessary for supporting gettext().
-#   Please check carefully whether the automatic adjustments have
-#   succeeded, though. The modified Makefile will be written to
-#   Makefile.new, so you can call this script any numer of times
-#   in case you need to do some fine tuning of your texts (especially
-#   adding some trNOOP() in case the script reports "missing phrases".
-#   Once you're done converting your plugin source to using gettext,
-#   rename Makefile.new to Makefile.
-#
-# - You may want to remove the old internationalized texts from your
-#   source. Usually this means removing the files i18n.[hc], stripping
-#   i18n.o from the OBJS variable in the Makefile and removing all
-#   '#include "i18n.h"' lines from the rest of your source files.
-#   These steps are not done automatically.
-
-# Check for the existence of a Makefile:
-
-die "Makefile not found!" unless (-f "Makefile");
-
-# Determine the plugin name:
-
-$PLUGIN = `grep '^PLUGIN *=' Makefile | head -1` || die "can't find plugin name!";
-$PLUGIN =~ s/.*= *(.*)\n/$1/;
-die "can't find plugin name!" unless ($PLUGIN);
-
-# Locate the file containing the texts:
-
-$I18NFILE = "";
-for ("i18n.c", "i18n.h", `ls *.c`) { # try i18n.[ch] explicitly first
-    chomp($f = $_);
-    if (-f $f && `grep tI18nPhrase $f`) {
-       $I18NFILE = $f;
-       last;
-       }
-    }
-die "can't find internationalized texts!" unless ($I18NFILE);
-
-# Plugin specific information:
-
-$TITLE = "VDR plugin language source file";
-$COPYRIGHT = "2007 Klaus Schmidinger <kls\@tvdr.de>";
-$PACKAGE = "VDR";
-$VERSION = "1.5.7";
-$MSGIDBUGS = "" || die "enter your email address here"; # escape the '@', as in "user\@domain.tld"
-$LANGUAGETEAM = "<vdr\@linuxtv.org>";
-
-# Gettext environment:
-
-$XGETTEXT = "xgettext -C -cTRANSLATORS --no-wrap -F -k -ktr -ktrNOOP --msgid-bugs-address='$MSGIDBUGS'";
-$PODIR = "po";
-$POTFILE = "$PODIR/$PLUGIN.pot";
-
-# Languages as known by VDR 1.5.6:
-
-@LANGS = (
-  "en_US",
-  "de_DE",
-  "sl_SI",
-  "it_IT",
-  "nl_NL",
-  "pt_PT",
-  "fr_FR",
-  "nn_NO",
-  "fi_FI",
-  "pl_PL",
-  "es_ES",
-  "el_GR",
-  "sv_SE",
-  "ro_RO",
-  "hu_HU",
-  "ca_ES",
-  "ru_RU",
-  "hr_HR",
-  "et_EE",
-  "da_DK",
-  "cs_CZ",
-  "tr_TR"
-  );
-
-@CHARSETS = (
-  "ISO-8859-15",
-  "ISO-8859-15",
-  "ISO-8859-2",
-  "ISO-8859-15",
-  "ISO-8859-15",
-  "ISO-8859-1",
-  "ISO-8859-1",
-  "ISO-8859-1",
-  "ISO-8859-15",
-  "ISO-8859-2",
-  "ISO-8859-15",
-  "ISO-8859-7",
-  "ISO-8859-1",
-  "ISO-8859-2",
-  "ISO-8859-2",
-  "ISO-8859-1",
-  "ISO-8859-5",
-  "ISO-8859-2",
-  "ISO-8859-13",
-  "ISO-8859-15",
-  "ISO-8859-2",
-  "ISO-8859-9",
-  );
-
-@TRANSLATORS = (
-  "Klaus Schmidinger <kls\@tvdr.de>, 2000",
-  "Klaus Schmidinger <kls\@tvdr.de>, 2000",
-  "Miha Setina <mihasetina\@softhome.net>, 2000; Matjaz Thaler <matjaz.thaler\@guest.arnes.si>, 2003",
-  "Alberto Carraro <bertocar\@tin.it>, 2001; Antonio Ospite <ospite\@studenti.unina.it>, 2003; Sean Carlos <seanc\@libero.it>, 2005",
-  "Arnold Niessen <niessen\@iae.nl> <arnold.niessen\@philips.com>, 2001; Hans Dingemans <hans.dingemans\@tacticalops.nl>, 2003; Maarten Wisse <Maarten.Wisse\@urz.uni-hd.de>, 2005",
-  "Paulo Lopes <pmml\@netvita.pt>, 2001",
-  "Jean-Claude Repetto <jc\@repetto.org>, 2001; Olivier Jacques <jacquesolivier\@hotmail.com>, 2003; Gregoire Favre <greg\@magma.unil.ch>, 2003; Nicolas Huillard <nhuillard\@e-dition.fr>, 2005",
-  "J�rgen Tvedt <pjtvedt\@online.no>, 2001; Truls Slevigen <truls\@slevigen.no>, 2002",
-  "Hannu Savolainen <hannu\@opensound.com>, 2002; Jaakko Hyv�tti <jaakko\@hyvatti.iki.fi>, 2002; Niko Tarnanen <niko.tarnanen\@hut.fi>, 2003; Rolf Ahrenberg <rahrenbe\@cc.hut.fi>, 2003",
-  "Michael Rakowski <mrak\@gmx.de>, 2002",
-  "Ruben Nunez Francisco <ruben.nunez\@tang-it.com>, 2002",
-  "Dimitrios Dimitrakos <mail\@dimitrios.de>, 2002",
-  "Tomas Prybil <tomas\@prybil.se>, 2002; Jan Ekholm <chakie\@infa.abo.fi>, 2003",
-  "Paul Lacatus <paul\@campina.iiruc.ro>, 2002; Lucian Muresan <lucianm\@users.sourceforge.net>, 2004",
-  "Istvan Koenigsberger <istvnko\@hotmail.com>, 2002; Guido Josten <guido.josten\@t-online.de>, 2002",
-  "Marc Rovira Vall <tm05462\@salleURL.edu>, 2003; Ramon Roca <ramon.roca\@xcombo.com>, 2003; Jordi Vil� <jvila\@tinet.org>, 2003",
-  "Vyacheslav Dikonov <sdiconov\@mail.ru>, 2004",
-  "Drazen Dupor <drazen.dupor\@dupor.com>, 2004; Dino Ravnic <dino.ravnic\@fer.hr>, 2004",
-  "Arthur Konovalov <kasjas\@hot.ee>, 2004",
-  "Mogens Elneff <mogens\@elneff.dk>, 2004",
-  "Vladim�r B�rta <vladimir.barta\@k2atmitec.cz>, 2006",
-  "Oktay Yolge�en <oktay_73\@yahoo.de>, 2007"
-  );
-
-@LASTTRANSLATOR = (
-  "Klaus Schmidinger <kls\@tvdr.de>",
-  "Klaus Schmidinger <kls\@tvdr.de>",
-  "Matjaz Thaler <matjaz.thaler\@guest.arnes.si>",
-  "Sean Carlos <seanc\@libero.it>",
-  "Maarten Wisse <Maarten.Wisse\@urz.uni-hd.de>",
-  "Paulo Lopes <pmml\@netvita.pt>",
-  "Nicolas Huillard <nhuillard\@e-dition.fr>",
-  "Truls Slevigen <truls\@slevigen.no>",
-  "Rolf Ahrenberg <rahrenbe\@cc.hut.fi>",
-  "Michael Rakowski <mrak\@gmx.de>",
-  "Ruben Nunez Francisco <ruben.nunez\@tang-it.com>",
-  "Dimitrios Dimitrakos <mail\@dimitrios.de>",
-  "Tomas Prybil <tomas\@prybil.se>",
-  "Lucian Muresan <lucianm\@users.sourceforge.net>",
-  "Istvan Koenigsberger <istvnko\@hotmail.com>, Guido Josten <guido.josten\@t-online.de>",
-  "Jordi Vil� <jvila\@tinet.org>",
-  "Vyacheslav Dikonov <sdiconov\@mail.ru>",
-  "Drazen Dupor <drazen.dupor\@dupor.com>",
-  "Arthur Konovalov <kasjas\@hot.ee>",
-  "Mogens Elneff <mogens\@elneff.dk>",
-  "Vladim�r B�rta <vladimir.barta\@k2atmitec.cz>",
-  "Oktay Yolge�en <oktay_73\@yahoo.de>"
-  );
-
-# Collect all translated texts:
-
-open(F, $I18NFILE) || die "$I18NFILE: $!\n";
-$InComment = 0;
-while (<F>) {
-      chomp;
-      s/\t/ /g; # get rid of tabs
-      s/  *$//; # get rid of trailing blanks
-      s/^ *\/\/.*//; # remove comment lines
-      s/ *\/\/.*//; # strip trailing comments
-      s/\/\*.*\*\///g; # strip c comments
-      if (/\/\*/) {
-         $InComment = 1;
-         s/\/\*.*$//; # remove start of comment
-         }
-      elsif (/\*\//) {
-         $InComment = 0;
-         s/^.*\*\///; # remove end of comment
-         }
-      elsif ($InComment) {
-         next;
-         }
-      next if (/^ *$/); # skip empty lines
-      next if (/#if/);
-      next if (/#endif/);
-      next unless ($found or $found = /const *tI18nPhrase .*{/); # sync on phrases
-      next if (/const *tI18nPhrase .*{/); # skip sync line
-      last if (/{ *NULL *}/); # stop after last phrase
-      if (/{ *(.*),/) {
-         $Original = $1;
-         $Index = 0;
-         }
-      elsif (/}/) {
-         }
-      else {
-         $Translated = $_;
-         $Translated =~ s/ *(.*),/$1/;
-         $Index++;
-         $Map{$Original}[$Index] = $Translated;
-         }
-      }
-close(F);
-
-# Generate the .pot file:
-
-(mkdir($PODIR) || die "$PODIR: $!\n") unless -d $PODIR;
-
-system("$XGETTEXT -o $POTFILE *.c");
-
-# Generate .po files for all languages:
-
-open(POT, $POTFILE) || die "$POTFILE: $!\n";
-@POT = <POT>;
-close(POT);
-
-for ($Index = 1; $LANGS[$Index]; $Index++) {
-
-    $Authors = "# " . join("\n# ", split(/; */, $TRANSLATORS[$Index])) . "\n";
-
-    $POFILE = "$PODIR/$LANGS[$Index].po";
-    open(PO, ">$POFILE") || die "$POFILE: $!\n";
-    $msgid = "";
-    for (@POT) {
-        next if (/^#, fuzzy$/); # skip the 'fuzzy' keyword
-        $msgid = $1 if (/^msgid (".+")/);
-        $date = $1 if (/POT-Creation-Date: (.*)\\n/);
-        $s = $_;
-        if (!$msgid) {
-           $s =~ s/SOME DESCRIPTIVE TITLE/$TITLE/;
-           $s =~ s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/$COPYRIGHT/;
-           $s =~ s/PACKAGE/$PACKAGE/;
-           $s =~ s/VERSION/$VERSION/;
-           $s = $Authors if (/FIRST AUTHOR/);
-           $s =~ s/YEAR-MO-DA HO:MI\+ZONE/$date/;
-           $s =~ s/FULL NAME <EMAIL\@ADDRESS>/$LASTTRANSLATOR[$Index]/;
-           $s =~ s/LANGUAGE <LL\@li\.org>/$LANGUAGETEAM/;
-           $s =~ s/CHARSET/$CHARSETS[$Index]/;
-           }
-        else {
-           $s =~ s/""/$Map{$msgid}[$Index]/ if ($msgid && /^msgstr ""/ && defined $Map{$msgid}[$Index]);
-           $Used{$msgid} = 1;
-           }
-        print PO $s;
-        }
-    close(PO);
-    }
-
-# Report missing phrases:
-
-for (keys %Map) {
-    push(@Missing, "$_\n") unless $Used{$_};
-    }
-
-if (@Missing) {
-   print "Missing phrases (may need to use trNOOP):\n\n";
-   print sort(@Missing);
-   }
-
-# Adjust the Makefile:
-
-$MAKEI18N = q{### Internationalization (I18N):
-
-PODIR     = po
-LOCALEDIR = $(VDRDIR)/locale
-I18Npo    = $(wildcard $(PODIR)/*.po)
-I18Nmsgs  = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
-I18Npot   = $(PODIR)/$(PLUGIN).pot
-
-%.mo: %.po
-	msgfmt -c -o $@ $<
-
-$(I18Npot): $(wildcard *.c)
-	xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<} . $MSGIDBUGS . q{>' -o $@ $^
-
-%.po: $(I18Npot)
-	msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
-	@touch $@
-
-$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
-	@mkdir -p $(dir $@)
-	cp $< $@
-
-.PHONY: i18n
-i18n: $(I18Nmsgs)
-
-};
-
-open(OLD, "Makefile") || die "Makefile: $!";
-open(NEW, ">Makefile.new") || die "Makefile.new: $!";
-while (<OLD>) {
-      chomp;
-      if (/Targets:/) {
-         print NEW $MAKEI18N;
-         }
-      elsif (/^all:/) {
-         $_ .= " i18n";
-         }
-      elsif (/^clean:/) {
-         $_ .= "\n\t\@-rm -f \$(PODIR)/*.mo \$(PODIR)/*.pot";
-         }
-      print NEW "$_\n";
-      }
-close(NEW);
-close(OLD);
diff -ruN vdr-1.7.21/interface.c vdr-1.7.22/interface.c
--- vdr-1.7.21/interface.c	2008-02-10 16:49:15.000000000 +0100
+++ vdr-1.7.22/interface.c	2011-12-04 15:52:38.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: interface.c 2.0 2008/02/10 15:49:15 kls Exp $
+ * $Id: interface.c 2.1 2011/12/04 14:52:38 kls Exp $
  */
 
 #include "interface.h"
@@ -79,7 +79,7 @@
      DisplayMenu->SetItem(tr("RC code detected!"), 4, false, false);
      DisplayMenu->SetItem(tr("Do not press any key..."), 5, false, false);
      DisplayMenu->Flush();
-     sleep(3);
+     cCondWait::SleepMs(3000);
      DisplayMenu->SetItem("", 4, false, false);
      DisplayMenu->SetItem("", 5, false, false);
 
diff -ruN vdr-1.7.21/libsi/Makefile vdr-1.7.22/libsi/Makefile
--- vdr-1.7.21/libsi/Makefile	2010-11-07 14:31:05.000000000 +0100
+++ vdr-1.7.22/libsi/Makefile	2011-12-04 15:18:38.000000000 +0100
@@ -1,7 +1,7 @@
 #
 # Makefile for a libsi
 #
-# $Id: Makefile 2.1 2010/11/07 13:31:05 kls Exp $
+# $Id: Makefile 2.2 2011/12/04 14:18:38 kls Exp $
 
 ### The C++ compiler and options:
 
@@ -52,4 +52,4 @@
 
 dist:
 	tar cvzf libsi.tar.gz -C .. libsi/util.c libsi/si.c libsi/section.c libsi/descriptor.c \
-   libsi/util.h libsi/si.h libsi/section.h libsi/descriptor.h libsi/headers.h libsi/Makefile libsi/gendescr.pl
+   libsi/util.h libsi/si.h libsi/section.h libsi/descriptor.h libsi/headers.h libsi/Makefile libsi/gendescr
diff -ruN vdr-1.7.21/libsi/gendescr vdr-1.7.22/libsi/gendescr
--- vdr-1.7.21/libsi/gendescr	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/libsi/gendescr	2003-12-13 11:40:53.000000000 +0100
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+# $Id: gendescr 2.0 2003/12/13 10:40:53 kls Exp $
+
+print "Name (ohne ...Descriptor):";
+$name=<STDIN>;
+$name =~ s/\n$//;
+$inner = ($name =~ s/�$//);
+$name .= "Descriptor" unless ($inner);
+
+print "Struct:";
+$struct=<STDIN>;
+$struct =~ s/\n$//;
+
+mm:
+$index=0;
+$which=1;
+print "Variablen:";
+while ( <STDIN> ) {
+   if (/�/) {
+      goto vv;
+   } elsif (/�/) {
+      $which=1;
+      next;
+   }
+   $eingabe=$_;
+   $eingabe =~ s/(.{75,120} )/\1\n/g;
+   $eingabe =~ s/\n$//;
+   if ($which) {
+      $members[$index]=$eingabe;
+   } else {
+      $members_comments[$index]=$eingabe;
+      $index++;
+      print "Jep!\n";
+   }
+   $which= (! $which);
+}
+
+vv:
+$filename_h="tempdescr.h";
+$filename_c="tempdescr.c";
+schreib();
+
+sub schreib {
+   print "Danke.\n";
+   open(OUTPUT_H, ">>".$filename_h) or die "Could not open file!!";
+   open(OUTPUT_C, ">>".$filename_c) or die "Could not open file!!";
+
+   if ($inner) {
+      $offset="   ";
+   } else {
+      $offset="";
+   }
+   print(OUTPUT_H $offset."class ".$name);
+   if ($inner) {
+      print(OUTPUT_H " : public LoopElement {\n".$offset."public:");
+   } else {
+      print(OUTPUT_H " : public Descriptor {\n".$offset."public:");
+   }
+   #for ($i=0; $i<=$#vars;$i++) {
+   #   print (OUTPUT "/*\n".$vars_comments[$i]." */\n".$vars[$i].";\n\n\n");
+   #}
+   for ($i=0; $i<=$#members;$i++) {
+      print (OUTPUT_H "\n".$offset."   int get".$members[$i]."() const;");
+   }
+   print(OUTPUT_H "\n".$offset."virtual int getLength() { return sizeof(".$struct."); }") if ($inner);
+
+   print(OUTPUT_H "\n".$offset."protected:\n".$offset."   virtual void Parse();");
+   print(OUTPUT_H "\n".$offset."private:\n".$offset."   const ".$struct." *s;") if ($struct ne "");
+   print(OUTPUT_H "\n".$offset."};\n\n");
+   for ($i=0; $i<=$#members_comments;$i++) {
+      print (OUTPUT_C "int ".$name."::get".$members[$i]."() const {\n");
+      if ($members_comments[$i] =~ /^(.+)_hi$/) {
+         $varbase=$1;
+         print (OUTPUT_C "   return HILO(s->".$varbase.");\n}\n\n");
+      } else {
+         print (OUTPUT_C "   return s->".$members_comments[$i].";\n}\n\n");
+      }
+   }
+   print (OUTPUT_C "void ".$name."::Parse() {\n}\n\n");
+   print (OUTPUT_C "\n\n\n");
+   exit;
+}
diff -ruN vdr-1.7.21/libsi/gendescr.pl vdr-1.7.22/libsi/gendescr.pl
--- vdr-1.7.21/libsi/gendescr.pl	2003-12-13 11:40:53.000000000 +0100
+++ vdr-1.7.22/libsi/gendescr.pl	1970-01-01 01:00:00.000000000 +0100
@@ -1,83 +0,0 @@
-#!/usr/bin/perl
-
-# $Id: gendescr.pl 2.0 2003/12/13 10:40:53 kls Exp $
-
-print "Name (ohne ...Descriptor):";
-$name=<STDIN>;
-$name =~ s/\n$//;
-$inner = ($name =~ s/�$//);
-$name .= "Descriptor" unless ($inner);
-
-print "Struct:";
-$struct=<STDIN>;
-$struct =~ s/\n$//;
-
-mm:
-$index=0;
-$which=1;
-print "Variablen:";
-while ( <STDIN> ) {
-   if (/�/) {
-      goto vv;
-   } elsif (/�/) {
-      $which=1;
-      next;
-   }
-   $eingabe=$_;
-   $eingabe =~ s/(.{75,120} )/\1\n/g;
-   $eingabe =~ s/\n$//;
-   if ($which) {
-      $members[$index]=$eingabe;
-   } else {
-      $members_comments[$index]=$eingabe;
-      $index++;
-      print "Jep!\n";
-   }
-   $which= (! $which);
-}
-
-vv:
-$filename_h="tempdescr.h";
-$filename_c="tempdescr.c";
-schreib();
-
-sub schreib {
-   print "Danke.\n";
-   open(OUTPUT_H, ">>".$filename_h) or die "Could not open file!!";
-   open(OUTPUT_C, ">>".$filename_c) or die "Could not open file!!";
-
-   if ($inner) {
-      $offset="   ";
-   } else {
-      $offset="";
-   }
-   print(OUTPUT_H $offset."class ".$name);
-   if ($inner) {
-      print(OUTPUT_H " : public LoopElement {\n".$offset."public:");
-   } else {
-      print(OUTPUT_H " : public Descriptor {\n".$offset."public:");
-   }
-   #for ($i=0; $i<=$#vars;$i++) {
-   #   print (OUTPUT "/*\n".$vars_comments[$i]." */\n".$vars[$i].";\n\n\n");
-   #}
-   for ($i=0; $i<=$#members;$i++) {
-      print (OUTPUT_H "\n".$offset."   int get".$members[$i]."() const;");
-   }
-   print(OUTPUT_H "\n".$offset."virtual int getLength() { return sizeof(".$struct."); }") if ($inner);
-
-   print(OUTPUT_H "\n".$offset."protected:\n".$offset."   virtual void Parse();");
-   print(OUTPUT_H "\n".$offset."private:\n".$offset."   const ".$struct." *s;") if ($struct ne "");
-   print(OUTPUT_H "\n".$offset."};\n\n");
-   for ($i=0; $i<=$#members_comments;$i++) {
-      print (OUTPUT_C "int ".$name."::get".$members[$i]."() const {\n");
-      if ($members_comments[$i] =~ /^(.+)_hi$/) {
-         $varbase=$1;
-         print (OUTPUT_C "   return HILO(s->".$varbase.");\n}\n\n");
-      } else {
-         print (OUTPUT_C "   return s->".$members_comments[$i].";\n}\n\n");
-      }
-   }
-   print (OUTPUT_C "void ".$name."::Parse() {\n}\n\n");
-   print (OUTPUT_C "\n\n\n");
-   exit;
-}
diff -ruN vdr-1.7.21/libsi/si.c vdr-1.7.22/libsi/si.c
--- vdr-1.7.21/libsi/si.c	2011-06-15 23:26:00.000000000 +0200
+++ vdr-1.7.22/libsi/si.c	2011-12-04 16:06:18.000000000 +0100
@@ -6,7 +6,7 @@
  *   the Free Software Foundation; either version 2 of the License, or     *
  *   (at your option) any later version.                                   *
  *                                                                         *
- *   $Id: si.c 2.4 2011/06/15 21:26:00 kls Exp $
+ *   $Id: si.c 2.5 2011/12/04 15:06:18 kls Exp $
  *                                                                         *
  ***************************************************************************/
 
@@ -206,6 +206,8 @@
          array[i]=0;
    } else if (length != d->getLastDescriptorNumber()+1)
       return; //avoid crash in case of misuse
+   if (length <= d->getDescriptorNumber())
+      return; // see http://www.vdr-portal.de/board60-linux/board14-betriebssystem/board69-c-t-vdr/p1025777-segfault-mit-vdr-1-7-21/#post1025777
    array[d->getDescriptorNumber()]=d;
 }
 
diff -ruN vdr-1.7.21/menu.c vdr-1.7.22/menu.c
--- vdr-1.7.21/menu.c	2011-08-27 13:05:33.000000000 +0200
+++ vdr-1.7.22/menu.c	2011-12-04 15:52:38.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menu.c 2.32 2011/08/27 11:05:33 kls Exp $
+ * $Id: menu.c 2.34 2011/12/04 14:52:38 kls Exp $
  */
 
 #include "menu.h"
@@ -2885,6 +2885,7 @@
 
 class cMenuSetupLNB : public cMenuSetupBase {
 private:
+  cSatCableNumbers satCableNumbers;
   void Setup(void);
 public:
   cMenuSetupLNB(void);
@@ -2892,7 +2893,9 @@
   };
 
 cMenuSetupLNB::cMenuSetupLNB(void)
+:satCableNumbers(MAXDEVICES)
 {
+  satCableNumbers.FromString(data.DeviceBondings);
   SetSection(tr("LNB"));
   Setup();
 }
@@ -2910,6 +2913,18 @@
      Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
      }
 
+  int NumSatDevices = 0;
+  for (int i = 0; i < cDevice::NumDevices(); i++) {
+      if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat))
+         NumSatDevices++;
+      }
+  if (NumSatDevices > 1) {
+     for (int i = 0; i < cDevice::NumDevices(); i++) {
+         if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat))
+            Add(new cMenuEditIntItem(cString::sprintf(tr("Setup.LNB$Device %d connected to sat cable"), i + 1), &satCableNumbers.Array()[i], 0, NumSatDevices, tr("Setup.LNB$own")));
+         }
+     }
+
   SetCurrent(Get(current));
   Display();
 }
@@ -2917,10 +2932,18 @@
 eOSState cMenuSetupLNB::ProcessKey(eKeys Key)
 {
   int oldDiSEqC = data.DiSEqC;
+  bool DeviceBondingsChanged = false;
+  if (Key == kOk) {
+     cString NewDeviceBondings = satCableNumbers.ToString();
+     DeviceBondingsChanged = strcmp(data.DeviceBondings, NewDeviceBondings) != 0;
+     data.DeviceBondings = NewDeviceBondings;
+     }
   eOSState state = cMenuSetupBase::ProcessKey(Key);
 
   if (Key != kNone && data.DiSEqC != oldDiSEqC)
      Setup();
+  else if (DeviceBondingsChanged)
+     cDvbDevice::BondDevices(data.DeviceBondings);
   return state;
 }
 
@@ -4185,7 +4208,7 @@
       }
       if (seconds == 0)
          dsyslog("waiting for EPG info...");
-      sleep(1);
+      cCondWait::SleepMs(1000);
       }
   dsyslog("no EPG info available");
   return false;
@@ -4295,11 +4318,11 @@
   Skins.Message(mtStatus, tr("Pausing live video..."));
   cReplayControl::SetRecording(NULL, NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
   if (Start(NULL, true)) {
-     sleep(2); // allow recorded file to fill up enough to start replaying
+     cCondWait::SleepMs(2000); // allow recorded file to fill up enough to start replaying
      cReplayControl *rc = new cReplayControl;
      cControl::Launch(rc);
      cControl::Attach();
-     sleep(1); // allow device to replay some frames, so we have a picture
+     cCondWait::SleepMs(1000); // allow device to replay some frames, so we have a picture
      Skins.Message(mtStatus, NULL);
      rc->ProcessKey(kPause); // pause, allowing replay mode display
      return true;
diff -ruN vdr-1.7.21/osd.h vdr-1.7.22/osd.h
--- vdr-1.7.21/osd.h	2011-08-15 11:22:50.000000000 +0200
+++ vdr-1.7.22/osd.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.h 2.14 2011/08/15 09:22:50 kls Exp $
+ * $Id: osd.h 2.15 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __OSD_H
@@ -496,7 +496,7 @@
        ///< In order to allow devices that can handle only a limited number of layers,
        ///< the Layer parameter must be less than 8 (MAXPIXMAPLAYERS).
        ///< ViewPort defines the rectangle in which this pixmap will be rendered on
-       ///< the OSD. If no DrawPort ist given, it defaults to the same size as the
+       ///< the OSD. If no DrawPort is given, it defaults to the same size as the
        ///< ViewPort, with its upper left corner set to (0, 0).
        ///< All drawing operations will be executed relative to the origin of the
        ///< DrawPort rectangle, and will be clipped to the size of this rectangle.
@@ -566,7 +566,7 @@
        ///< Sets the pixmap's draw port to the given Point.
        ///< Only the origin point of the draw port can be modified, its size is fixed.
        ///< By default, setting a new draw port point results in marking the relevant
-       ///< part of the view port as "drity". If Dirty is set to false, the view port
+       ///< part of the view port as "dirty". If Dirty is set to false, the view port
        ///< will not be marked as dirty. This is mainly used to implement the Pan()
        ///< function.
        ///< If a derived class reimplements this function, it needs to call the base
@@ -701,7 +701,7 @@
 /// reimplement all necessary cPixmap functions and do the rendering
 /// itself ("high level mode").
 /// If an OSD provides a "high level mode", it shall also provide a "raw mode"
-/// in order to verify proper operation. The plugin that impements the OSD
+/// in order to verify proper operation. The plugin that implements the OSD
 /// shall offer a configuration switch in its setup.
 
 class cOsd {
diff -ruN vdr-1.7.21/pat.h vdr-1.7.22/pat.h
--- vdr-1.7.21/pat.h	2009-06-14 13:14:00.000000000 +0200
+++ vdr-1.7.22/pat.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: pat.h 2.1 2009/06/14 11:14:00 kls Exp $
+ * $Id: pat.h 2.2 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __PAT_H
@@ -39,7 +39,7 @@
          ///< are copied that match one of the given CA system IDs.
          ///< \return Returns the number of bytes copied into Data (0 if no CA descriptors are
          ///< available), or -1 if BufSize was too small to hold all CA descriptors.
-         ///< The return value in StreamFlag tells whether these CA descriptors are to be used
+         ///< The return value tells whether these CA descriptors are to be used
          ///< for the individual streams.
 
 #endif //__PAT_H
diff -ruN vdr-1.7.21/po/ar.po vdr-1.7.22/po/ar.po
--- vdr-1.7.21/po/ar.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/ar.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-10-16 11:16-0400\n"
 "Last-Translator: Osama Alrawab <alrawab@hotmail.com>\n"
 "Language-Team: Arabic <ar@li.org>\n"
@@ -983,6 +983,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "التردد المرتفع للاقط م هرتز"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "اعادة تشغيل الكامة"
 
diff -ruN vdr-1.7.21/po/ca_ES.po vdr-1.7.22/po/ca_ES.po
--- vdr-1.7.21/po/ca_ES.po	2011-08-27 11:55:33.000000000 +0200
+++ vdr-1.7.22/po/ca_ES.po	2011-12-03 16:35:33.000000000 +0100
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-03-02 19:02+0100\n"
 "Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
 "Language-Team: Catalan <vdr@linuxtv.org>\n"
@@ -965,6 +965,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Freq��ncia LNB alta (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Reiniciar CAM"
 
diff -ruN vdr-1.7.21/po/cs_CZ.po vdr-1.7.22/po/cs_CZ.po
--- vdr-1.7.21/po/cs_CZ.po	2011-08-27 11:55:33.000000000 +0200
+++ vdr-1.7.22/po/cs_CZ.po	2011-12-03 16:35:33.000000000 +0100
@@ -9,7 +9,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.14\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2010-05-06 11:00+0200\n"
 "Last-Translator: Radek Šťastný <dedkus@gmail.com>\n"
 "Language-Team: Czech <vdr@linuxtv.org>\n"
@@ -964,6 +964,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Horní frekvence LNB (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Reset CAMu"
 
diff -ruN vdr-1.7.21/po/da_DK.po vdr-1.7.22/po/da_DK.po
--- vdr-1.7.21/po/da_DK.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/da_DK.po	2011-12-03 16:35:33.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Mogens Elneff <mogens@elneff.dk>\n"
 "Language-Team: Danish <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "�vre LNB frekvens (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM nulstil"
 
diff -ruN vdr-1.7.21/po/de_DE.po vdr-1.7.22/po/de_DE.po
--- vdr-1.7.21/po/de_DE.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/de_DE.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2010-01-16 16:46+0100\n"
 "Last-Translator: Klaus Schmidinger <kls@tvdr.de>\n"
 "Language-Team: German <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Obere LNB-Frequenz (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr "Device %d angeschlossen an Sat-Kabel"
+
+msgid "Setup.LNB$own"
+msgstr "eigenes"
+
 msgid "CAM reset"
 msgstr "CAM zur�ckgesetzt"
 
diff -ruN vdr-1.7.21/po/el_GR.po vdr-1.7.22/po/el_GR.po
--- vdr-1.7.21/po/el_GR.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/el_GR.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Dimitrios Dimitrakos <mail@dimitrios.de>\n"
 "Language-Team: Greek <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "��� LNB-��������� (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr ""
 
diff -ruN vdr-1.7.21/po/es_ES.po vdr-1.7.22/po/es_ES.po
--- vdr-1.7.21/po/es_ES.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/es_ES.po	2011-12-03 16:35:33.000000000 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-03-02 19:02+0100\n"
 "Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
 "Language-Team: Spanish <vdr@linuxtv.org>\n"
@@ -963,6 +963,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Frecuencia superior del LNB (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Reset CAM"
 
diff -ruN vdr-1.7.21/po/et_EE.po vdr-1.7.22/po/et_EE.po
--- vdr-1.7.21/po/et_EE.po	2011-08-27 11:55:33.000000000 +0200
+++ vdr-1.7.22/po/et_EE.po	2011-12-03 16:35:33.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Arthur Konovalov <artlov@gmail.com>\n"
 "Language-Team: Estonian <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "HI LNB sagedus (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM taask�ivitamine"
 
diff -ruN vdr-1.7.21/po/fi_FI.po vdr-1.7.22/po/fi_FI.po
--- vdr-1.7.21/po/fi_FI.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/fi_FI.po	2011-12-03 16:35:33.000000000 +0100
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2007-08-15 15:52+0200\n"
 "Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
 "Language-Team: Finnish <vdr@linuxtv.org>\n"
@@ -965,6 +965,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "LNB-ylätaajuus (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM nollaus"
 
diff -ruN vdr-1.7.21/po/fr_FR.po vdr-1.7.22/po/fr_FR.po
--- vdr-1.7.21/po/fr_FR.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/fr_FR.po	2011-12-03 16:35:34.000000000 +0100
@@ -13,7 +13,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-02-27 18:14+0100\n"
 "Last-Translator: Jean-Claude Repetto <jc@repetto.org>\n"
 "Language-Team: French <vdr@linuxtv.org>\n"
@@ -968,6 +968,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Fr�quence haute LNB (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM remis � z�ro"
 
diff -ruN vdr-1.7.21/po/hr_HR.po vdr-1.7.22/po/hr_HR.po
--- vdr-1.7.21/po/hr_HR.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/hr_HR.po	2011-12-03 16:35:34.000000000 +0100
@@ -9,7 +9,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-03-17 19:00+0100\n"
 "Last-Translator: Adrian Caval <anrxc@sysphere.org>\n"
 "Language-Team: Croatian <vdr@linuxtv.org>\n"
@@ -964,6 +964,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Gornja LNB frekv. (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Ponovno pokreni CAM"
 
diff -ruN vdr-1.7.21/po/hu_HU.po vdr-1.7.22/po/hu_HU.po
--- vdr-1.7.21/po/hu_HU.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/hu_HU.po	2011-12-03 16:35:33.000000000 +0100
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+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 <vdr@linuxtv.org>\n"
@@ -965,6 +965,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Fels� LNB-frekvencia (MHZ)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM �jraind�t�s"
 
diff -ruN vdr-1.7.21/po/it_IT.po vdr-1.7.22/po/it_IT.po
--- vdr-1.7.21/po/it_IT.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/it_IT.po	2011-12-03 16:35:34.000000000 +0100
@@ -11,7 +11,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2010-06-13 00:30+0100\n"
 "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
 "Language-Team: Italian <vdr@linuxtv.org>\n"
@@ -969,6 +969,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Freq HI LNB (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Reimposta la CAM"
 
diff -ruN vdr-1.7.21/po/lt_LT.po vdr-1.7.22/po/lt_LT.po
--- vdr-1.7.21/po/lt_LT.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/lt_LT.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.16\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2010-10-30 11:55+0200\n"
 "Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
 "Language-Team: Lithuanian <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Aukštasis LNB dažnis (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Dekodavimo modulis (CAM) perkrautas"
 
diff -ruN vdr-1.7.21/po/mk_MK.po vdr-1.7.22/po/mk_MK.po
--- vdr-1.7.21/po/mk_MK.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/mk_MK.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR-1.7.14\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2010-03-11 00:54+0100\n"
 "Last-Translator: Dimitar Petrovski <dimeptr@gmail.com>\n"
 "Language-Team: Macedonian <en@li.org>\n"
@@ -963,6 +963,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Форна LNB фрекфенција (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Рестартирај CAM"
 
diff -ruN vdr-1.7.21/po/nl_NL.po vdr-1.7.22/po/nl_NL.po
--- vdr-1.7.21/po/nl_NL.po	2011-08-27 11:55:33.000000000 +0200
+++ vdr-1.7.22/po/nl_NL.po	2011-12-03 16:35:33.000000000 +0100
@@ -11,7 +11,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-02-26 17:20+0100\n"
 "Last-Translator: Johan Schuring <johan.schuring@vetteblei.nl>\n"
 "Language-Team: Dutch <vdr@linuxtv.org>\n"
@@ -966,6 +966,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Hoogste LNB frequentie (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM herstarten"
 
diff -ruN vdr-1.7.21/po/nn_NO.po vdr-1.7.22/po/nn_NO.po
--- vdr-1.7.21/po/nn_NO.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/nn_NO.po	2011-12-03 16:35:34.000000000 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2007-08-12 14:17+0200\n"
 "Last-Translator: Truls Slevigen <truls@slevigen.no>\n"
 "Language-Team: Norwegian Nynorsk <vdr@linuxtv.org>\n"
@@ -963,6 +963,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "LO-frekvens i h�yb�ndet (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr ""
 
diff -ruN vdr-1.7.21/po/pl_PL.po vdr-1.7.22/po/pl_PL.po
--- vdr-1.7.21/po/pl_PL.po	2011-08-27 11:55:33.000000000 +0200
+++ vdr-1.7.22/po/pl_PL.po	2011-12-03 16:35:33.000000000 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-03-09 12:59+0100\n"
 "Last-Translator: Michael Rakowski <mrak@gmx.de>\n"
 "Language-Team: Polish <vdr@linuxtv.org>\n"
@@ -963,6 +963,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "G�rna cz�stotliwo�� LNB (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM zresetowany"
 
diff -ruN vdr-1.7.21/po/pt_PT.po vdr-1.7.22/po/pt_PT.po
--- vdr-1.7.21/po/pt_PT.po	2011-08-27 11:55:17.000000000 +0200
+++ vdr-1.7.22/po/pt_PT.po	2011-12-03 16:35:33.000000000 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.15\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2010-03-28 22:49+0100\n"
 "Last-Translator: Cris Silva <hudokkow@gmail.com>\n"
 "Language-Team: Portuguese <vdr@linuxtv.org>\n"
@@ -963,6 +963,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Frequ�ncia alta do LNB (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Reiniciar CAM"
 
diff -ruN vdr-1.7.21/po/ro_RO.po vdr-1.7.22/po/ro_RO.po
--- vdr-1.7.21/po/ro_RO.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/ro_RO.po	2011-12-03 16:35:33.000000000 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.12\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2011-03-10 23:52+0100\n"
 "Last-Translator: Lucian Muresan <lucianm@users.sourceforge.net>\n"
 "Language-Team: Romanian <vdr@linuxtv.org>\n"
@@ -965,6 +965,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Frecvn�� LNB superioar� (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Resetare CAM"
 
diff -ruN vdr-1.7.21/po/ru_RU.po vdr-1.7.22/po/ru_RU.po
--- vdr-1.7.21/po/ru_RU.po	2011-08-27 11:55:33.000000000 +0200
+++ vdr-1.7.22/po/ru_RU.po	2011-12-03 16:35:34.000000000 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-12-15 14:37+0100\n"
 "Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
 "Language-Team: Russian <vdr@linuxtv.org>\n"
@@ -963,6 +963,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "������� ������� ���������� (���)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM ����������"
 
diff -ruN vdr-1.7.21/po/sk_SK.po vdr-1.7.22/po/sk_SK.po
--- vdr-1.7.21/po/sk_SK.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/sk_SK.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.16\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2011-02-15 16:29+0100\n"
 "Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
 "Language-Team: Slovak <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Horn� frekvencia LNB (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Resetnutie CAMu"
 
diff -ruN vdr-1.7.21/po/sl_SI.po vdr-1.7.22/po/sl_SI.po
--- vdr-1.7.21/po/sl_SI.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/sl_SI.po	2011-12-03 16:35:34.000000000 +0100
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+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 <vdr@linuxtv.org>\n"
@@ -963,6 +963,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Zgornja LNB-frek. (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Reset CAM-a"
 
diff -ruN vdr-1.7.21/po/sr_SR.po vdr-1.7.22/po/sr_SR.po
--- vdr-1.7.21/po/sr_SR.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/sr_SR.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.1\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2011-01-09 15:57+0100\n"
 "Last-Translator: Milan Cvijanovi� <elcom_cvijo@hotmail.com>\n"
 "Language-Team: Serbian <vdr@linuxtv.org>\n"
@@ -981,6 +981,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Gornja LNB frekv. (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Ponovno pokreni CAM"
 
diff -ruN vdr-1.7.21/po/sv_SE.po vdr-1.7.22/po/sv_SE.po
--- vdr-1.7.21/po/sv_SE.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/sv_SE.po	2011-12-03 16:35:34.000000000 +0100
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2008-03-12 18:25+0100\n"
 "Last-Translator: Magnus Andersson <svankan@bahnhof.se>\n"
 "Language-Team: Swedish <vdr@linuxtv.org>\n"
@@ -965,6 +965,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "�vre LNB frekvens (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM omstart"
 
diff -ruN vdr-1.7.21/po/tr_TR.po vdr-1.7.22/po/tr_TR.po
--- vdr-1.7.21/po/tr_TR.po	2011-08-27 11:55:34.000000000 +0200
+++ vdr-1.7.22/po/tr_TR.po	2011-12-03 16:35:33.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+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 <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "�st LNB frekans� (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM s�f�rland�"
 
diff -ruN vdr-1.7.21/po/uk_UA.po vdr-1.7.22/po/uk_UA.po
--- vdr-1.7.21/po/uk_UA.po	2011-08-27 11:55:35.000000000 +0200
+++ vdr-1.7.22/po/uk_UA.po	2011-12-03 16:35:34.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.7.7\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2010-04-25 16:35+0200\n"
 "Last-Translator: Yarema aka Knedlyk <yupadmin@gmail.com>\n"
 "Language-Team: Ukrainian <vdr@linuxtv.org>\n"
@@ -962,6 +962,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "Верхня частота конвертера (МГц)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "Перезавантаження CAM"
 
diff -ruN vdr-1.7.21/po/zh_CN.po vdr-1.7.22/po/zh_CN.po
--- vdr-1.7.21/po/zh_CN.po	2011-08-27 11:55:33.000000000 +0200
+++ vdr-1.7.22/po/zh_CN.po	2011-12-03 16:35:33.000000000 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: VDR 1.6.0\n"
 "Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2011-08-27 11:54+0200\n"
+"POT-Creation-Date: 2011-12-03 16:25+0100\n"
 "PO-Revision-Date: 2009-09-23 23:50+0800\n"
 "Last-Translator: Nan Feng <nfgx@21cn.com>\n"
 "Language-Team: Chinese (simplified) <vdr@linuxtv.org>\n"
@@ -965,6 +965,13 @@
 msgid "Setup.LNB$High LNB frequency (MHz)"
 msgstr "高本振频率 (MHz)"
 
+#, c-format
+msgid "Setup.LNB$Device %d connected to sat cable"
+msgstr ""
+
+msgid "Setup.LNB$own"
+msgstr ""
+
 msgid "CAM reset"
 msgstr "CAM重置"
 
diff -ruN vdr-1.7.21/receiver.h vdr-1.7.22/receiver.h
--- vdr-1.7.21/receiver.h	2010-01-30 11:25:19.000000000 +0100
+++ vdr-1.7.22/receiver.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: receiver.h 2.1 2010/01/30 10:25:19 kls Exp $
+ * $Id: receiver.h 2.2 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __RECEIVER_H
@@ -56,7 +56,7 @@
   bool AddPid(int Pid);
                ///< Adds the given Pid to the list of PIDs of this receiver.
   bool AddPids(const int *Pids);
-               ///< Adds the given izero terminated list of Pids to the list of PIDs of this
+               ///< Adds the given zero terminated list of Pids to the list of PIDs of this
                ///< receiver.
   bool AddPids(int Pid1, int Pid2, int Pid3 = 0, int Pid4 = 0, int Pid5 = 0, int Pid6 = 0, int Pid7 = 0, int Pid8 = 0, int Pid9 = 0);
                ///< Adds the given Pids to the list of PIDs of this receiver.
diff -ruN vdr-1.7.21/recording.c vdr-1.7.22/recording.c
--- vdr-1.7.21/recording.c	2011-09-04 11:32:25.000000000 +0200
+++ vdr-1.7.22/recording.c	2011-12-04 14:51:44.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.c 2.38 2011/09/04 09:32:25 kls Exp $
+ * $Id: recording.c 2.39 2011/12/04 13:51:44 kls Exp $
  */
 
 #include "recording.h"
@@ -1162,7 +1162,7 @@
   bool needsUpdate = NeedsUpdate();
   TouchFile(UpdateFileName());
   if (!needsUpdate)
-     lastUpdate = time(NULL); // make sure we don't tigger ourselves
+     lastUpdate = time(NULL); // make sure we don't trigger ourselves
 }
 
 bool cRecordings::NeedsUpdate(void)
diff -ruN vdr-1.7.21/recording.h vdr-1.7.22/recording.h
--- vdr-1.7.21/recording.h	2011-08-21 15:10:39.000000000 +0200
+++ vdr-1.7.22/recording.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.h 2.25 2011/08/21 13:10:39 kls Exp $
+ * $Id: recording.h 2.26 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __RECORDING_H
@@ -176,7 +176,7 @@
        ///< Triggers an update of the list of recordings, which will run
        ///< as a separate thread if Wait is false. If Wait is true, the
        ///< function returns only after the update has completed.
-       ///< Returns true if Wait is true and there is anyting in the list
+       ///< Returns true if Wait is true and there is anything in the list
        ///< of recordings, false otherwise.
   void TouchUpdate(void);
        ///< Touches the '.update' file in the video directory, so that other
@@ -292,7 +292,7 @@
   bool IsStillRecording(void);
   void Delete(void);
   static int GetLength(const char *FileName, bool IsPesRecording = false);
-       ///< Calculates the recording length (numer of frames) without actually reading the index file.
+       ///< Calculates the recording length (number of frames) without actually reading the index file.
        ///< Returns -1 in case of error.
   };
 
diff -ruN vdr-1.7.21/ringbuffer.h vdr-1.7.22/ringbuffer.h
--- vdr-1.7.21/ringbuffer.h	2009-11-08 12:52:25.000000000 +0100
+++ vdr-1.7.22/ringbuffer.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: ringbuffer.h 2.2 2009/11/08 11:52:25 kls Exp $
+ * $Id: ringbuffer.h 2.3 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __RINGBUFFER_H
@@ -85,7 +85,7 @@
     ///< \return Returns the number of bytes actually read and stored, or
     ///< an error value from the actual read() call.
   int Read(cUnbufferedFile *File, int Max = 0);
-    ///< Like Read(int FileHandle, int Max), but reads fom a cUnbufferedFile).
+    ///< Like Read(int FileHandle, int Max), but reads from a cUnbufferedFile).
   int Put(const uchar *Data, int Count);
     ///< Puts at most Count bytes of Data into the ring buffer.
     ///< \return Returns the number of bytes actually stored.
diff -ruN vdr-1.7.21/scr.conf vdr-1.7.22/scr.conf
--- vdr-1.7.21/scr.conf	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/scr.conf	2011-09-17 14:58:39.000000000 +0200
@@ -0,0 +1,24 @@
+# SCR (Satellite Channel Routing) configuration for VDR
+#
+# Format:
+#
+# channel frequency [pin]
+#
+# channel:        SCR channel index (0-7)
+# frequency:      frequency of the SCR channel ("user band")
+# pin:            optional pin of the SCR channel (0-255)
+#
+# A line containing space separated integer numbers, terminated with a ':',
+# defines that any following lines apply only to the given list
+# of device numbers.
+#
+# Examples:
+
+# 0 1284
+# 1 1400
+# 2 1516
+# 3 1632
+# 4 1748
+# 5 1864
+# 6 1980
+# 7 2096
diff -ruN vdr-1.7.21/skins.h vdr-1.7.22/skins.h
--- vdr-1.7.21/skins.h	2008-02-17 12:30:56.000000000 +0100
+++ vdr-1.7.22/skins.h	2011-12-04 14:38:17.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: skins.h 2.0 2008/02/17 11:30:56 kls Exp $
+ * $Id: skins.h 2.1 2011/12/04 13:38:17 kls Exp $
  */
 
 #ifndef __SKINS_H
@@ -148,7 +148,7 @@
        ///< Sets the Total number of items in the currently displayed list, and the
        ///< Offset of the first item that is currently displayed (the skin knows how
        ///< many items it can display at once, see MaxItems()). This can be used to
-       ///< display a scollbar.
+       ///< display a scrollbar.
   virtual void SetEvent(const cEvent *Event) = 0;
        ///< Sets the Event that shall be displayed, using the entire central area
        ///< of the menu. The Event's 'description' shall be displayed using a
diff -ruN vdr-1.7.21/sources.conf vdr-1.7.22/sources.conf
--- vdr-1.7.21/sources.conf	2010-03-06 12:07:05.000000000 +0100
+++ vdr-1.7.22/sources.conf	2011-09-11 16:26:16.000000000 +0200
@@ -19,174 +19,165 @@
 
 # Europe
 
-S3E     Telecom 2C
-S4E     Eurobird 4
-S4.8E   Sirius 4
+S3E     Eutelsat 3A & Rascom 1R
+S4E     Eurobird 4A
+S4.8E   Astra 4A
 S7E     Eutelsat W3A
-S9E     Eurobird 9
-S10E    Eutelsat W1
-S13E    Hotbird 6/7A/8
-S16E    Eutelsat W2
-S19.2E  Astra F/G/H/KR/L
-S21.0E  Afristar 1
+S9E     Eurobird 9A
+S10E    Eutelsat W2A
+S13E    Hotbird 6/8/9
+S16E    Eutelsat W2M & Eurobird 16A
+S19.2E  Astra 1H/1KR/1L/1M/2C
 S21.6E  Eutelsat W6
-S23.5E  Astra 1E/3A
+S23.5E  Astra 3A/3B
 S25.5E  Eurobird 2
-S26E    Badr 3/4/6
-S28.2E  Astra 2D/A/B
-S28.5E  Eurobird 1 & Astra 2A/B/C/D
-S30.5E  Arabsat 2B
-S31.5E  Astra 1D/5A
-S33E    Eurobird 3 & Intelsat 802
-S36E    Eutelsat W4 & Sesat
+S26E    Badr 4/5/6
+S28.2E  Astra 2A/2B/2D
+S28.5E  Eurobird 1
+S30.5E  Arabsat 5A
+S31.5E  Astra 1G
+S33E    Eurobird 3 & Intelsat New Dawn
+S36E    Eutelsat W4/W7
 S38E    Paksat 1
 S39E    Hellas Sat 2
 S40E    Express AM1
 S42E    Turksat 2A/3A
 S45E    Intelsat 12
 S49E    Yamal 202
-S53E    Express AM 22
-S55E    Insat 3E 
+S53E    Express AM22
+S55E    Insat 3E
 S56E    Bonum 1
-S57E    NSS 703
+S57E    NSS 12
 S60E    Intelsat 904
 S62E    Intelsat 902
 S64E    Intelsat 906
-S66E    Intelsat 704
+S66E    Intelsat 17
 S68.5E  Intelsat 7/10
 S70.5E  Eutelsat W5
-S72E    Intelsat 4
+S72E    Intelsat 709
 
 # Asia
 
-S74E    Insat 3C/4CR & Edusat
-S75E    ABS 1
-S76.5E  Telstar 10
-S78.5E  Thaicom 2/5
-S80E    Express AM2
-S83E    Insat 2E/3B/4A
-S85.2E  Intelsat 709
-S87.5E  Chinastar 1
-S88E    ST 1
+S74E    Insat 3C/4CR
+S75E    ABS 1A
+S76.5E  Apstar 2R
+S78.5E  Thaicom 5
+S80E    Express AM2/MD1
+S83E    Insat 2E/4A
+S85.2E  Intelsat 15
+S87.5E  Chinasat 5A
+S88E    ST 1/2
 S90E    Yamal 201
-S91.5E  Measat 1
+S91.5E  Measat 3/3A
 S92.2E  Chinasat 9
 S93.5E  Insat 3A/4B
 S95E    NSS 6
-S96.5E  Express AM 33
-S98.5E  Protostar 1
-S100.5E Asiasat 2
+S96.5E  Express AM33
+S100.5E Asiasat 5
 S103E   Express A2
-S105E   Asiastar
 S105.5E Asiasat 3S
-S107.7E Cakrawarta 1
-S108E   Telkom 1 & NSS 11
-S110E   N-Sat 110 & BSAT 1A/2A
-S110.5E Sinosat 1
-S113E   Palapa C2 & Koreasat 2
-S116E   Koreasat 3
+S108.2E Telkom 1 & NSS 11 & SES 7
+S110E   N-Sat 110 & BSAT 2C/3A
+S110.5E Chinasat 10
+S113E   Palapa D & Koreasat 5
+S116E   Koreasat 6
 S118E   Telkom 2
-S120E   Thaicom 1A
 S122.2E Asiasat 4
-S124E   JCSAT 4a
-S125E   Sinosat 3
-S128E   JCSAT 3
-S132E   Vinasat 1 & JCSAT5a
+S124E   JCSAT 4A
+S125E   Chinasat 6A
+S128E   JCSAT RA
+S132E   Vinasat 1 & JCSAT5A
 S134E   Apstar 6
 S138E   Telstar 18
-S140E   Express AM 3
-S144E   Superbird C
-S146E   Agila 2
-S148E   Measat 2
-S150E   JCSAT R
+S140E   Express AM3
+S144E   Superbird C2
+S146E   ABS 5
+S150E   JCSAT 1B
 S152E   Optus D2
 S154E   JCSAT 2A
-S156E   Optus C1
-S158E   Superbird A
+S156E   Optus C1/D3
 S160E   Optus D1
 S162E   Superbird B2
 S164E   Optus B3
 S166E   Intelsat 8
-S169E   Intelsat 2
+S169E   Intelsat 5
 S172E   GE 23
 S180E   Intelsat 701
-S177W   NSS 5
+S177W   NSS 9
 
 # Atlantic
 
-S1W     Thor 3/5 & Intelsat 10-02
-S4W     Amos 1/2/3
+S1W     Thor 5/6 & Intelsat 10-02
+S4W     Amos 2/3
 S5W     Atlantic Bird 3
-S7W     Nilesat 101/102 & Atlantic Bird 4
+S7W     Nilesat 101/102/201 & Atlantic Bird 4A
 S8W     Telecom 2D & Atlantic Bird 2
-S11W    Express A3
+S11W    Express AM44
 S12.5W  Atlantic Bird 1
 S14W    Express A4
 S15W    Telstar 12
 S18W    Intelsat 901
-S20W    Intelsat 603
+S20W    NSS 5
 S22W    NSS 7
 S24.5W  Intelsat 905
 S27.5W  Intelsat 907
-S30W    Hispasat 1C/1D
-S31.5W  Intelsat 801
+S30W    Hispasat 1C/1D/1E
+S31.5W  Intelsat 25
 S34.5W  Intelsat 903
-S37.5W  NSS 10
+S37.5W  NSS 10 & Telstar 11N
 S40.5W  NSS 806
-S43W    Intelsat 3R/11
-S45W    Intelsat 1R
-S50W    Intelsat 705
+S43W    Intelsat 11
+S45W    Intelsat 14
+S50W    Intelsat 1R
 S53W    Intelsat 707
 S55.5W  Intelsat 805
-S58W    Intelsat 9
-S61W    Amazonas
+S58W    Intelsat 9/16
+S61W    Amazonas 1/2
 
 # America
 
-S61.5W  Echostar 3 & Rainbow 1
-S63W    Estrelo de Sul 1
+S61.5W  Echostar 12/15
+S63W    Telstar 14R
 S65W    Star One C1
 S70W    Star One C2
-S72W    Nahuel 1 & AMC 6
-S72.5W  DirecTV 1R & Echostar 6
+S72W    AMC 6
+S72.5W  DirecTV 1R & Nimiq 5
 S74W    Horizons 2
-S77W    Echostar 4 & Galaxy 4R
-S79W    AMC5
-S82W    Nimiq 2
+S77W    Echostar 1/8
+S79W    AMC 2/5
+S82W    Nimiq 4
 S83W    AMC 9
-S84W    Brasilsat B3/4
+S84W    Brasilsat B4
 S85W    AMC 16
 S85.1W  XM 3
-S87W    AMC3
+S87W    AMC 3
 S89W    Galaxy 28
-S91W    Galaxy 11/17 & Nimiq 1
-S92W    Brasilsat B2
-S93W    Galaxy 26
+S91W    Galaxy 17 & Nimiq 1
+S93W    Galaxy 25
 S95W    Galaxy 3C
-S97W    Galaxy 25
+S97W    Galaxy 19
 S99W    Galaxy 16
 S99.2W  Spaceway 2 & DirecTV 11
-S101W   DirecTV 4S/8 & AMC 2/4
-S103W   AMC1
-S105W   AMC15/18
+S101W   DirecTV 4S/8 & SES 1
+S103W   AMC 1
+S105W   AMC 15/18
 S107.3W Anik F1/F1R
-S110W   DirecTV 5 & Echostar 8/10
+S110W   DirecTV 5 & Echostar 10/11
 S111.1W Anik F2
 S113W   SatMex 6
 S116.8W SatMex 5
 S118.8W Anik F3
-S119W   Echostar 7 & DirecTV 7S
-S121W   Echostar 9 & Galaxy 23
+S119W   Echostar 14 & DirecTV 7S
+S121W   Echostar 9/Galaxy 23
 S123W   Galaxy 18
-S125W   Galaxy 14
+S125W   Galaxy 14 & AMC 21
 S127W   Galaxy 13/Horizons 1
-S129W   Ciel 2 & Galaxy 27
+S129W   Ciel 2
 S131W   AMC 11
-S133W   Galaxy15
+S133W   Galaxy 13/15
 S135W   AMC 10
 S137W   AMC 7
 S139W   AMC 8
-S148W   Echostar 1/2
 
 # Cable
 
diff -ruN vdr-1.7.21/summary2info vdr-1.7.22/summary2info
--- vdr-1.7.21/summary2info	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.22/summary2info	2011-12-04 15:17:35.000000000 +0100
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+# Convert 'summary.vdr' files to 'info.vdr'
+#
+# Converts all 'summary.vdr' files in the video directory to the
+# 'info.vdr' format as used from VDR version 1.3.25 upward.
+#
+# Usage: summary2info /video
+#
+# See the main source file 'vdr.c' for copyright information and
+# how to reach the author.
+#
+# $Id: summary2info 2.1 2011/12/04 14:17:35 kls Exp $
+
+$VideoDir = $ARGV[0] || die "please provide the name of the video directory\n";
+
+@SummaryFiles = `find "$VideoDir" -name summary.vdr`;
+
+for $SummaryFile (@SummaryFiles) {
+    chomp($SummaryFile);
+    print STDERR "converting $SummaryFile...";
+    open(F, $SummaryFile) || die "$SummaryFile: $!\n";
+    $line = 0;
+    @data = ();
+    while (<F>) {
+          chomp;
+          if ($_ || $line > 1) {
+             $data[$line] .= '|' if ($data[$line]);
+             $data[$line] .= $_;
+             }
+          else {
+             $line++;
+             }
+          }
+    close(F);
+    if (!$data[2]) {
+       $data[2] = $data[1];
+       $data[1] = "";
+       }
+    elsif ($data[1] && $data[2]) {
+       # if line 1 is too long, it can't be the short text,
+       # so assume the short text is missing and concatenate
+       # line 1 and line 2 to be the long text:
+       if (length($data[1]) > 80) {
+          $data[2] = $data[1] . "|" . $data[2];
+          $data[1] = "";
+          }
+       }
+    ($InfoFile = $SummaryFile) =~ s/summary\.vdr$/info.vdr/;
+    open(F, ">$InfoFile") || die "$InfoFile: $!\n";
+    print F "T $data[0]\n" if ($data[0]);
+    print F "S $data[1]\n" if ($data[1]);
+    print F "D $data[2]\n" if ($data[2]);
+    close(F);
+    print STDERR "done.\n";
+    }
diff -ruN vdr-1.7.21/summary2info.pl vdr-1.7.22/summary2info.pl
--- vdr-1.7.21/summary2info.pl	2006-04-17 14:19:24.000000000 +0200
+++ vdr-1.7.22/summary2info.pl	1970-01-01 01:00:00.000000000 +0100
@@ -1,56 +0,0 @@
-#!/usr/bin/perl
-
-# Convert 'summary.vdr' files to 'info.vdr'
-#
-# Converts all 'summary.vdr' files in the video directory to the
-# 'info.vdr' format as used from VDR version 1.3.25 upward.
-#
-# Usage: summary2info.pl /video
-#
-# See the main source file 'vdr.c' for copyright information and
-# how to reach the author.
-#
-# $Id: summary2info.pl 2.0 2006/04/17 12:19:24 kls Exp $
-
-$VideoDir = $ARGV[0] || die "please provide the name of the video directory\n";
-
-@SummaryFiles = `find "$VideoDir" -name summary.vdr`;
-
-for $SummaryFile (@SummaryFiles) {
-    chomp($SummaryFile);
-    print STDERR "converting $SummaryFile...";
-    open(F, $SummaryFile) || die "$SummaryFile: $!\n";
-    $line = 0;
-    @data = ();
-    while (<F>) {
-          chomp;
-          if ($_ || $line > 1) {
-             $data[$line] .= '|' if ($data[$line]);
-             $data[$line] .= $_;
-             }
-          else {
-             $line++;
-             }
-          }
-    close(F);
-    if (!$data[2]) {
-       $data[2] = $data[1];
-       $data[1] = "";
-       }
-    elsif ($data[1] && $data[2]) {
-       # if line 1 is too long, it can't be the short text,
-       # so assume the short text is missing and concatenate
-       # line 1 and line 2 to be the long text:
-       if (length($data[1]) > 80) {
-          $data[2] = $data[1] . "|" . $data[2];
-          $data[1] = "";
-          }
-       }
-    ($InfoFile = $SummaryFile) =~ s/summary\.vdr$/info.vdr/;
-    open(F, ">$InfoFile") || die "$InfoFile: $!\n";
-    print F "T $data[0]\n" if ($data[0]);
-    print F "S $data[1]\n" if ($data[1]);
-    print F "D $data[2]\n" if ($data[2]);
-    close(F);
-    print STDERR "done.\n";
-    }
diff -ruN vdr-1.7.21/svdrp.c vdr-1.7.22/svdrp.c
--- vdr-1.7.21/svdrp.c	2011-08-27 12:43:18.000000000 +0200
+++ vdr-1.7.22/svdrp.c	2011-12-04 14:58:33.000000000 +0100
@@ -10,7 +10,7 @@
  * and interact with the Video Disk Recorder - or write a full featured
  * graphical interface that sits on top of an SVDRP connection.
  *
- * $Id: svdrp.c 2.10 2011/08/27 10:43:18 kls Exp $
+ * $Id: svdrp.c 2.12 2011/12/04 13:58:33 kls Exp $
  */
 
 #include "svdrp.h"
@@ -224,7 +224,7 @@
   "    valid key names is given. If more than one key is given, they are\n"
   "    entered into the remote control queue in the given sequence. There\n"
   "    can be up to 31 keys.",
-  "LSTC [ :groups | <number> | <name> ]\n"
+  "LSTC [ :groups | <number> | <name> | <id> ]\n"
   "    List channels. Without option, all channels are listed. Otherwise\n"
   "    only the given channel is listed. If a name is given, all channels\n"
   "    containing the given string as part of their name are listed.\n"
@@ -315,6 +315,9 @@
   "    Updates a timer. Settings must be in the same format as returned\n"
   "    by the LSTT command. If a timer with the same channel, day, start\n"
   "    and stop time does not yet exists, it will be created.",
+  "UPDR\n"
+  "    Initiates a re-read of the recordings directory, which is the SVDRP\n"
+  "    equivalent to 'touch .update'.",
   "VOLU [ <number> | + | - | mute ]\n"
   "    Set the audio volume to the given number (which is limited to the range\n"
   "    0...255). If the special options '+' or '-' are given, the volume will\n"
@@ -948,16 +951,18 @@
            Reply(501, "Channel \"%s\" not defined", Option);
         }
      else {
-        cChannel *next = NULL;
-        for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
-            if (!channel->GroupSep()) {
-               if (strcasestr(channel->Name(), Option)) {
-                  if (next)
-                     Reply(-250, "%d %s", next->Number(), *next->ToText());
-                  next = channel;
-                  }
-               }
-            }
+        cChannel *next = Channels.GetByChannelID(tChannelID::FromString(Option));
+        if (!next) {
+           for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
+              if (!channel->GroupSep()) {
+                 if (strcasestr(channel->Name(), Option)) {
+                    if (next)
+                       Reply(-250, "%d %s", next->Number(), *next->ToText());
+                    next = channel;
+                    }
+                 }
+              }
+           }
         if (next)
            Reply(250, "%d %s", next->Number(), *next->ToText());
         else
@@ -1557,6 +1562,12 @@
      Reply(501, "Missing timer settings");
 }
 
+void cSVDRP::CmdUPDR(const char *Option)
+{
+  Recordings.Update(false);
+  Reply(250, "Re-read of recordings directory triggered");
+}
+
 void cSVDRP::CmdVOLU(const char *Option)
 {
   if (*Option) {
@@ -1627,6 +1638,7 @@
   else if (CMD("REMO"))  CmdREMO(s);
   else if (CMD("SCAN"))  CmdSCAN(s);
   else if (CMD("STAT"))  CmdSTAT(s);
+  else if (CMD("UPDR"))  CmdUPDR(s);
   else if (CMD("UPDT"))  CmdUPDT(s);
   else if (CMD("VOLU"))  CmdVOLU(s);
   else if (CMD("QUIT"))  Close(true);
diff -ruN vdr-1.7.21/svdrp.h vdr-1.7.22/svdrp.h
--- vdr-1.7.21/svdrp.h	2007-04-30 14:28:28.000000000 +0200
+++ vdr-1.7.22/svdrp.h	2011-12-04 14:51:44.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: svdrp.h 2.0 2007/04/30 12:28:28 kls Exp $
+ * $Id: svdrp.h 2.1 2011/12/04 13:51:44 kls Exp $
  */
 
 #ifndef __SVDRP_H
@@ -82,6 +82,7 @@
   void CmdSCAN(const char *Option);
   void CmdSTAT(const char *Option);
   void CmdUPDT(const char *Option);
+  void CmdUPDR(const char *Option);
   void CmdVOLU(const char *Option);
   void Execute(char *Cmd);
 public:
diff -ruN vdr-1.7.21/tools.c vdr-1.7.22/tools.c
--- vdr-1.7.21/tools.c	2011-08-15 15:35:23.000000000 +0200
+++ vdr-1.7.22/tools.c	2011-12-04 15:52:38.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.c 2.17 2011/08/15 13:35:23 kls Exp $
+ * $Id: tools.c 2.19 2011/12/04 14:52:38 kls Exp $
  */
 
 #include "tools.h"
@@ -1196,6 +1196,47 @@
   return NULL;
 }
 
+// --- cBitStream ------------------------------------------------------------
+
+int cBitStream::GetBit(void)
+{
+  if (index >= length)
+     return 1;
+  int r = (data[index >> 3] >> (7 - (index & 7))) & 1;
+  ++index;
+  return r;
+}
+
+uint32_t cBitStream::GetBits(int n)
+{
+  uint32_t r = 0;
+  while (n--)
+        r |= GetBit() << n;
+  return r;
+}
+
+void cBitStream::ByteAlign(void)
+{
+  int n = index % 8;
+  if (n > 0)
+     SkipBits(8 - n);
+}
+
+void cBitStream::WordAlign(void)
+{
+  int n = index % 16;
+  if (n > 0)
+     SkipBits(16 - n);
+}
+
+bool cBitStream::SetLength(int Length)
+{
+  if (Length > length)
+     return false;
+  length = Length;
+  return true;
+}
+
 // --- cReadLine -------------------------------------------------------------
 
 cReadLine::cReadLine(void)
@@ -1748,7 +1789,7 @@
               break;
               }
            if (WaitSeconds)
-              sleep(1);
+              cCondWait::SleepMs(1000);
            }
         } while (f < 0 && time(NULL) < Timeout);
      }
diff -ruN vdr-1.7.21/tools.h vdr-1.7.22/tools.h
--- vdr-1.7.21/tools.h	2011-08-15 16:13:42.000000000 +0200
+++ vdr-1.7.22/tools.h	2011-12-04 15:48:03.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.h 2.11 2011/08/15 14:13:42 kls Exp $
+ * $Id: tools.h 2.14 2011/12/04 14:48:03 kls Exp $
  */
 
 #ifndef __TOOLS_H
@@ -36,7 +36,7 @@
 #define dsyslog(a...) void( (SysLogLevel > 2) ? syslog_with_tid(LOG_ERR, a) : void() )
 
 #define LOG_ERROR         esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__)
-#define LOG_ERROR_STR(s)  esyslog("ERROR: %s: %m", s)
+#define LOG_ERROR_STR(s)  esyslog("ERROR (%s,%d): %s: %m", __FILE__, __LINE__, s)
 
 #define SECSINDAY  86400
 
@@ -108,7 +108,7 @@
     ///< Returns the number of UTF-8 symbols formed by the given string of
     ///< character bytes.
 char *Utf8Strn0Cpy(char *Dest, const char *Src, int n);
-    ///< Copies at most n character bytes from Src to Dst, making sure that the
+    ///< Copies at most n character bytes from Src to Dest, making sure that the
     ///< resulting copy ends with a complete UTF-8 symbol. The copy is guaranteed
     ///< to be zero terminated.
     ///< Returns a pointer to Dest.
@@ -210,7 +210,7 @@
     ///< The numerical part of the string may be followed by one of the letters
     ///< K, M, G or T to abbreviate Kilo-, Mega-, Giga- or Terabyte, respectively
     ///< (based on 1024). Everything after the first non-numeric character is
-    ///< silently ignored, as are any characters other than the ones mentionend here.
+    ///< silently ignored, as are any characters other than the ones mentioned here.
 cString itoa(int n);
 cString AddDirectory(const char *DirName, const char *FileName);
 bool EntriesOnSameFileSystem(const char *File1, const char *File2);
@@ -266,6 +266,28 @@
       ///< is called, or until the object is destroyed.
   };
 
+class cBitStream {
+private:
+  const uint8_t *data;
+  int length; // in bits
+  int index; // in bits
+public:
+  cBitStream(const uint8_t *Data, int Length) : data(Data), length(Length), index(0) {}
+  ~cBitStream() {}
+  int GetBit(void);
+  uint32_t GetBits(int n);
+  void ByteAlign(void);
+  void WordAlign(void);
+  bool SetLength(int Length);
+  void SkipBits(int n) { index += n; }
+  void SkipBit(void) { SkipBits(1); }
+  bool IsEOF(void) const { return index >= length; }
+  void Reset(void) { index = 0; }
+  int Length(void) const { return length; }
+  int Index(void) const { return (IsEOF() ? length : index); }
+  const uint8_t *GetData(void) const { return (IsEOF() ? NULL : data + (index / 8)); }
+  };
+
 class cTimeMs {
 private:
   uint64_t begin;
diff -ruN vdr-1.7.21/vdr.1 vdr-1.7.22/vdr.1
--- vdr-1.7.21/vdr.1	2011-08-15 14:28:54.000000000 +0200
+++ vdr-1.7.22/vdr.1	2011-12-04 15:41:00.000000000 +0100
@@ -8,7 +8,7 @@
 .\" License as specified in the file COPYING that comes with the
 .\" vdr distribution.
 .\"
-.\" $Id: vdr.1 2.6 2011/08/15 12:28:54 kls Exp $
+.\" $Id: vdr.1 2.7 2011/12/04 14:41:00 kls Exp $
 .\"
 .TH vdr 1 "10 Feb 2008" "1.6" "Video Disk Recorder"
 .SH NAME
@@ -120,7 +120,7 @@
 .TP
 .BI \-\-lirc[= path ]
 Use a LIRC remote control device.
-If \fIpath\fR is omitted, vdr uses \fI/dev/lircd\fR.
+If \fIpath\fR is omitted, vdr uses \fI/var/run/lirc/lircd\fR.
 .TP
 .BI \-\-localedir= dir
 Search for locale files in \fIdir\fR (default is ./locale).
diff -ruN vdr-1.7.21/vdr.5 vdr-1.7.22/vdr.5
--- vdr-1.7.21/vdr.5	2011-08-21 16:06:50.000000000 +0200
+++ vdr-1.7.22/vdr.5	2011-09-25 15:51:34.000000000 +0200
@@ -8,7 +8,7 @@
 .\" License as specified in the file COPYING that comes with the
 .\" vdr distribution.
 .\"
-.\" $Id: vdr.5 2.23 2011/08/21 14:06:50 kls Exp $
+.\" $Id: vdr.5 2.26 2011/09/25 13:51:34 kls Exp $
 .\"
 .TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
 .SH NAME
@@ -450,7 +450,8 @@
 which covers the upper frequency range.
 
 The third parameter defines the polarization to which this entry applies. It can
-be either \fBH\fR for horizontal or \fBV\fR for vertical.
+be either \fBH\fR for horizontal, \fBV\fR for vertical, \fBL\fR for circular left
+or \fBR\fR for circular right.
 
 The fourth parameter specifies the "local oscillator frequency" (lof) of the LNB
 to use for the given frequency range. This number will be subtracted from the
@@ -467,6 +468,7 @@
 \fBV\fR@voltage high (18V)
 \fBA\fR@mini A
 \fBB\fR@mini B
+\fBSn\fR@Satellite channel routing code sequence for bank n follows
 \fBWnn\fR@wait nn milliseconds (nn may be any positive integer number)
 \fB[xx ...]\fR@hex code sequence (max. 6)
 .TE
@@ -484,6 +486,46 @@
 1, 2 and 4 would be able to receive any satellites following this line and up
 to the next such line, or the end of the file. Devices may be listed more than
 once.
+.SS SATELLITE CHANNEL ROUTING (SCR)
+The file \fIscr.conf\fR contains the channel definitions of the SCR device in use.
+The format is
+
+channel frequency [pin]
+
+where channel is the SCR device's channel index (0-7), frequency is the user band
+frequency of the given channel, and pin is an optional pin number (0-255). The
+actual values are device specific and can be found in the SCR device's manual.
+
+Examples:
+
+0 1284
+.br
+1 1400
+.br
+2 1516
+.br
+3 1632
+.br
+4 1748
+.br
+5 1864
+.br
+6 1980
+.br
+7 2096
+
+By default it is assumed that the SCR configurations apply to all devices, and
+each device will pick one. If you have several SCR sat cables connected to one
+VDR machine, or if you want to explicitly assign the SCR channels to your devices,
+lines of the form
+
+\fB1 2 4:\fR
+
+may be inserted in the \fIscr.conf\fR file, defining the devices that are allowed
+to use the SCR channels thereafter. In this case, only the devices
+1, 2 and 4 would be allowed to use the SCR channels following this line and up
+to the next such line, or the end of the file. If a device is listed more than
+once, only its first appearance counts.
 .SS REMOTE CONTROL KEYS
 The file \fIremote.conf\fR contains the key assignments for all remote control
 units. Each line consists of one key assignment in the following format:
diff -ruN vdr-1.7.21/vdr.c vdr-1.7.22/vdr.c
--- vdr-1.7.21/vdr.c	2011-08-15 14:42:39.000000000 +0200
+++ vdr-1.7.22/vdr.c	2011-12-03 16:35:09.000000000 +0100
@@ -22,7 +22,7 @@
  *
  * The project's page is at http://www.tvdr.de
  *
- * $Id: vdr.c 2.23 2011/08/15 12:42:39 kls Exp $
+ * $Id: vdr.c 2.27 2011/12/03 15:35:09 kls Exp $
  */
 
 #include <getopt.h>
@@ -116,7 +116,7 @@
 static bool DropCaps(void)
 {
   // drop all capabilities except selected ones
-  cap_t caps = cap_from_text("= cap_sys_nice,cap_sys_time=ep");
+  cap_t caps = cap_from_text("= cap_sys_nice,cap_sys_time,cap_net_raw=ep");
   if (!caps) {
      fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
      return false;
@@ -598,6 +598,7 @@
   Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
   Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true);
   Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
+  Scrs.Load(AddDirectory(ConfigDirectory, "scr.conf"), true);
   Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
   Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
   Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
@@ -638,6 +639,7 @@
   // DVB interfaces:
 
   cDvbDevice::Initialize();
+  cDvbDevice::BondDevices(Setup.DeviceBondings);
 
   // Initialize plugins:
 
@@ -859,7 +861,6 @@
            static time_t LastTimerCheck = 0;
            if (Now - LastTimerCheck > TIMERCHECKDELTA) { // don't do this too often
               InhibitEpgScan = false;
-              static time_t DeviceUsed[MAXDEVICES] = { 0 };
               for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) {
                   bool InVpsMargin = false;
                   bool NeedsTransponder = false;
@@ -899,19 +900,17 @@
                                Device = d;
                                break;
                                }
-                            bool timeout = Now - DeviceUsed[d->DeviceNumber()] > TIMERDEVICETIMEOUT; // only check other devices if they have been left alone for a while
-                            if (d->MaySwitchTransponder()) {
+                            if (d->MaySwitchTransponder(Timer->Channel())) {
                                DeviceAvailable = true; // avoids using the actual device below
-                               if (timeout)
-                                  Device = d; // only check other devices if they have been left alone for a while
+                               Device = d;
                                }
-                            else if (timeout && !Device && InVpsMargin && !d->Receiving() && d->ProvidesTransponderExclusively(Timer->Channel()))
+                            else if (!d->Occupied() && !Device && InVpsMargin && !d->Receiving() && d->ProvidesTransponderExclusively(Timer->Channel()))
                                Device = d; // use this one only if no other with less impact can be found
                             }
                          }
                      if (!Device && InVpsMargin && !DeviceAvailable) {
                         cDevice *d = cDevice::ActualDevice();
-                        if (!d->Receiving() && d->ProvidesTransponder(Timer->Channel()) && Now - DeviceUsed[d->DeviceNumber()] > TIMERDEVICETIMEOUT)
+                        if (!d->Receiving() && d->ProvidesTransponder(Timer->Channel()) && !d->Occupied())
                            Device = d; // use the actual device as a last resort
                         }
                      // Switch the device to the transponder:
@@ -920,8 +919,8 @@
                            if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice())
                               cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
                            dsyslog("switching device %d to channel %d", Device->DeviceNumber() + 1, Timer->Channel()->Number());
-                           Device->SwitchChannel(Timer->Channel(), false);
-                           DeviceUsed[Device->DeviceNumber()] = Now;
+                           if (Device->SwitchChannel(Timer->Channel(), false))
+                              Device->SetOccupied(TIMERDEVICETIMEOUT);
                            }
                         if (cDevice::PrimaryDevice()->HasDecoder() && !cDevice::PrimaryDevice()->HasProgramme()) {
                            // the previous SwitchChannel() has switched away the current live channel
