diff -ruN vdr-1.7.17/CONTRIBUTORS vdr-1.7.18/CONTRIBUTORS
--- vdr-1.7.17/CONTRIBUTORS	2011-03-12 14:09:30.000000000 +0100
+++ vdr-1.7.18/CONTRIBUTORS	2011-04-17 16:40:58.000000000 +0200
@@ -1103,6 +1103,7 @@
  for fixing the array size of Atypes in cPatFilter::Process()
  for adding support for "registration descriptor" to 'libsi' and using it in pat.c
  for adding an include of VDR's 'Make.global' to libsi's Makefile
+ for adding handling of "ANSI/SCTE 57" descriptors
 
 Ralf Klueber <ralf.klueber@vodafone.com>
  for reporting a bug in cutting a recording if there is only a single editing mark
@@ -1264,6 +1265,10 @@
  for some valuable input during development of the TrueColor OSD, help with
  debugging, and an implementation of the AlphaBlend() function.
  for storing the original display size when handling DVB subtitles
+ for reporting a problem with horizontal scaling of subtitles
+ for fixing a buffer overflow in cFont::Bidi()
+ for avoiding an unecessary call to Recordings.ResetResume()
+ for debugging a problem in handling the bitmap color depth for scaled subtitles
 
 Richard Robson <richard_robson@beeb.net>
  for reporting freezing replay if a timer starts while in Transfer Mode from the
@@ -1392,6 +1397,7 @@
  for adding some missing 'const' statements to cBitmap
  for making cDevice::AddPid() store the stream type of the given pid
  for adding cFont::FontName() and cFont::Size()
+ for writing the dvbhddevice plugin
 
 Thomas Bergwinkl <Thomas.Bergwinkl@vr-web.de>
  for fixing the validity check for channel IDs, because some providers use TIDs
@@ -1688,6 +1694,8 @@
  for reporting missing defines for large files in the 'newplugin' script
  for pointing out that the full timer file name should be displayed if it ends with
  "TITLE" or "EPISODE"
+ for a patch to "Made updating the editing marks during replay react faster in case
+ the marks file has just been written"
 
 Sven Kreiensen <svenk@kammer.uni-hannover.de>
  for his help in keeping 'channels.conf.terr' up to date
@@ -1886,6 +1894,9 @@
  for adding passing package name and version to xgettext
  for making 'dist' target dependent on up to date *.po
  for adding Language and fixing Language-Team header of *.po
+ 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
 
 Steffen Beyer <cpunk@reactor.de>
  for fixing setting the colored button help after deleting a recording in case the next
@@ -2205,6 +2216,7 @@
  for reporting unused 'synced' member in cTsToPes
  for suggesting to add a note to cTsToPes about all TS packets having to belong to
  the same PID
+ for adding HD stream content identifiers to vdr.5
 
 Pekka Mauno <pekka.mauno@iki.fi>
  for fixing cSchedule::GetFollowingEvent() in case there is currently no present
@@ -2522,6 +2534,8 @@
  for fixing wrong value for TableIdBAT in libsi/si.h
  for making several code modifications to avoid compiler warnings
  for improving the description of the transponder parameters in vdr.5
+ for reporting a necessary fix in the description of cReceiver in PLUGINS.html,
+ regarding detaching a receiver from its device before deleting it
 
 Igor M. Liplianin <liplianin@tut.by>
  for a patch that was used to convert VDR to the S2API driver API
@@ -2601,6 +2615,7 @@
 
 Matti Lehtimäki <matti.lehtimaki@gmail.com>
  for implementing the setup option "Miscellaneous/Channels wrap"
+ for reporting a missing change from -O2 to -O3 in Make.config.template
 
 Stephan Austermühle <au@hcsd.de>
  for suggesting to flush the file in cSafeFile::Close()
@@ -2622,6 +2637,8 @@
  for making include paths not be overwritten in the Makefile
  for adding LDFLAGS to the linker calls in the Makefiles
  for reporting a possible memory leak in the "pictures" plugin
+ for removing an obsolete local variable in dvbsdffosd.c
+ for reporting a possible NULL pointer dereference in osddemo.c
 
 Radek Stastny <dedkus@gmail.com>
  for translating OSD texts to the Czech language
@@ -2670,3 +2687,13 @@
 Gerald Dachs <vdr@dachsweb.de>
  for reporting a problem with checking for minimum line length of 21 characters in
  the LIRC receiver code
+
+Juergen Lock <vdr-l@jelal.kn-bremen.de>
+ for fixing cUnbufferedFile::Seek() in case it is compiled without USE_FADVISE
+
+Sergiu Dotenco <sergiu.dotenco@googlemail.com>
+ for reporting a missing initialization in sDvbSpuRect
+ for replacing "%lld" and "%llX" print format specifiers with "PRId64" and "PRIX64"
+
+Mika Laitio <lamikr@pilppa.org>
+ for reporting a case where cRecordingInfo::Read(FILE *f) was called with a NULL pointer
diff -ruN vdr-1.7.17/HISTORY vdr-1.7.18/HISTORY
--- vdr-1.7.17/HISTORY	2011-03-12 17:08:08.000000000 +0100
+++ vdr-1.7.18/HISTORY	2011-04-17 16:40:31.000000000 +0200
@@ -6556,3 +6556,53 @@
   Reinhard Nissl).
 - The original display size of subtitles is now used to scale them properly when
   displaying them on an HD OSD.
+
+2011-04-17: Version 1.7.18
+
+- Changed -O2 to -O3 in Make.config.template (reported by Matti Lehtimäki).
+- Added a missing 'default' case in cPixmapMemory::DrawEllipse().
+- Fixed some direct comparisons of double values.
+- Fixed detecting frames on channels that broadcast with separate "fields" instead
+  of complete frames.
+- Made updating the editing marks during replay react faster in case the marks
+  file has just been written (with a patch from Udo Richter).
+- Fixed horizontal scaling of subtitles (reported by Reinhard Nissl).
+- Stripped the note "The data returned by this function is only used for informational
+  purposes (if any)" from the description of cDevice::GetVideoSize(). The VideoAspect
+  is now used to properly scale subtitles.
+- Fixed cUnbufferedFile::Seek() in case it is compiled without USE_FADVISE (thanks
+  to Juergen Lock).
+- Fixed the Language header of the Serbian translation file (thanks to Ville Skyttä).
+- Added anti-aliasing when upscaling bitmaps, which improves the display of SD subtitles
+  when replayed on an HD OSD (thanks to Reinhard Nissl for his help in debugging).
+- Renamed cBitmap::Scale() to Scaled(), because it doesn't modify the bitmap itself,
+  but rather returns a scaled copy.
+- Fixed the description of cReceiver in PLUGINS.html, regarding detaching a receiver
+  from its device before deleting it (reported by Winfried Köhler). This change in
+  behavior was introduced in version 1.5.7.
+- Fixed scaling subtitles in case the OSD size is exactly the same as the display
+  size of the subtitles.
+- Added a missing initialization to sDvbSpuRect (reported by Sergiu Dotenco).
+- Replaced "%lld" and "%llX" print format specifiers with "PRId64" and "PRIX64" to
+  avoid compiler warnings with gcc 4.5.2 (thanks to Sergiu Dotenco).
+  On a personal note: I find it a step in the totally wrong direction that there
+  have been macros introduced to work around this problem in the first place. There
+  should have been "real" format specifiers defined that address this. These macros
+  are nothing but an ugly workaround.
+- Added Cancel(3) to ~cTrueColorDemo() in the "osddemo" plugin (thanks to Reinhard Nissl).
+- Added a missing font deletion in cTrueColorDemo::Action() in the "osddemo" plugin
+  (thanks to Reinhard Nissl).
+- Fixed a buffer overflow in cFont::Bidi() (thanks to Reinhard Nissl).
+- Added HD stream content identifiers to vdr.5 (thanks to Christoph Haubrich).
+- Made cRecordingInfo::Read(FILE *f) private to avoid calls to it from outside
+  cRecordingInfo or cRecording (reported by Mika Laitio).
+- The dvbhddevice plugin is now part of the VDR distribution archive (thanks to
+  Andreas Regel).
+- Removed an obsolete local variable in dvbsdffosd.c (thanks to Paul Menzel).
+- Fixed a possible NULL pointer dereference in osddemo.c (reported by Paul Menzel).
+- Now using pkg-config to get fribidi, freetype and fontconfig cflags and libs (thanks
+  to Ville Skyttä).
+- The Makefile now also installs the include files (thanks to Ville Skyttä).
+- Added handling of "ANSI/SCTE 57" descriptors (thanks too Rolf Ahrenberg).
+- Avoiding an unecessary call to Recordings.ResetResume() (thanks to Reinhard
+  Nissl).
diff -ruN vdr-1.7.17/Make.config.template vdr-1.7.18/Make.config.template
--- vdr-1.7.17/Make.config.template	2010-02-06 15:50:03.000000000 +0100
+++ vdr-1.7.18/Make.config.template	2011-03-13 14:41:12.000000000 +0100
@@ -6,15 +6,15 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Make.config.template 2.2 2010/02/06 14:50:03 kls Exp $
+# $Id: Make.config.template 2.3 2011/03/13 13:41:12 kls Exp $
 
 ### The C compiler and options:
 
 CC       = gcc
-CFLAGS   = -g -O2 -Wall
+CFLAGS   = -g -O3 -Wall
 
 CXX      = g++
-CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
+CXXFLAGS = -g -O3 -Wall -Woverloaded-virtual -Wno-parentheses
 
 ifdef PLUGIN
 CFLAGS   += -fPIC
diff -ruN vdr-1.7.17/Makefile vdr-1.7.18/Makefile
--- vdr-1.7.17/Makefile	2011-02-27 10:59:11.000000000 +0100
+++ vdr-1.7.18/Makefile	2011-04-17 15:35:53.000000000 +0200
@@ -4,7 +4,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Makefile 2.14 2011/02/27 09:59:11 kls Exp $
+# $Id: Makefile 2.17 2011/04/17 13:35:53 kls Exp $
 
 .DELETE_ON_ERROR:
 
@@ -19,9 +19,10 @@
 PREFIX  ?= /usr/local
 MANDIR   = $(PREFIX)/share/man
 BINDIR   = $(PREFIX)/bin
+INCDIR   = $(PREFIX)/include
 LOCDIR   = ./locale
-LIBS     = -ljpeg -lpthread -ldl -lcap -lrt -lfreetype -lfontconfig
-INCLUDES ?= $(shell pkg-config --cflags freetype2)
+LIBS     = -ljpeg -lpthread -ldl -lcap -lrt $(shell pkg-config --libs freetype2 fontconfig)
+INCLUDES ?= $(shell pkg-config --cflags freetype2 fontconfig)
 
 PLUGINDIR= ./PLUGINS
 PLUGINLIBDIR= $(PLUGINDIR)/lib
@@ -54,9 +55,9 @@
 DEFINES += -DVDR_USER=\"$(VDR_USER)\"
 endif
 ifdef BIDI
-INCLUDES += -I/usr/include/fribidi
+INCLUDES += $(shell pkg-config --cflags fribidi)
 DEFINES += -DBIDI
-LIBS += -lfribidi
+LIBS += $(shell pkg-config --libs fribidi)
 endif
 
 LIRC_DEVICE ?= /dev/lircd
@@ -162,7 +163,7 @@
 
 # Install the files:
 
-install: install-bin install-conf install-doc install-plugins install-i18n
+install: install-bin install-conf install-doc install-plugins install-i18n install-includes
 
 # VDR binary:
 
@@ -193,6 +194,12 @@
 	@mkdir -p $(DESTDIR)$(PLUGINLIBDIR)
 	@cp --remove-destination $(PLUGINDIR)/lib/lib*-*.so.$(APIVERSION) $(DESTDIR)$(PLUGINLIBDIR)
 
+# Includes:
+
+install-includes: include-dir
+	@mkdir -p $(DESTDIR)$(INCDIR)
+	@cp -pLR include/vdr include/libsi $(DESTDIR)$(INCDIR)
+
 # Source documentation:
 
 srcdoc:
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/COPYING vdr-1.7.18/PLUGINS/src/dvbhddevice/COPYING
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/COPYING	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/COPYING	2009-12-29 14:36:48.000000000 +0100
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/HISTORY vdr-1.7.18/PLUGINS/src/dvbhddevice/HISTORY
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/HISTORY	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/HISTORY	2011-04-17 13:38:20.000000000 +0200
@@ -0,0 +1,16 @@
+VDR Plugin 'dvbhddevice' Revision History
+-----------------------------------------
+
+2009-12-29: Version 0.0.1
+
+- Initial revision.
+
+2010-01-04: Version 0.0.2
+
+- Calling the MakePrimaryDevice() function of the base class to allow
+  the cDevice to stop displaying subtitles.
+- Added support for DVB cards with multiple frontends.
+
+2011-04-17: Version 0.0.3
+
+- Added support for TrueColor OSD.
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/Makefile vdr-1.7.18/PLUGINS/src/dvbhddevice/Makefile
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/Makefile	2011-04-17 13:40:55.000000000 +0200
@@ -0,0 +1,114 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id: Makefile 1.7 2011/04/17 11:40:55 kls Exp $
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+# IMPORTANT: the presence of this macro is important for the Make.config
+# file. So it must be defined, even if it is not used here!
+#
+PLUGIN = dvbhddevice
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX      ?= g++
+CXXFLAGS ?= -g -O3 -Wall -Woverloaded-virtual -Wno-parentheses
+
+### The directory environment:
+
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Make sure that necessary options are included:
+
+include $(VDRDIR)/Make.global
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR's plugin API (taken from VDR's "config.h"):
+
+APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o bitbuffer.o dvbhdffdevice.o hdffcmd.o hdffosd.o setup.o
+
+### The main target:
+
+all: libvdr-$(PLUGIN).so i18n
+
+### Implicit rules:
+
+%.o: %.c
+	$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+	@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### 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 --package-name=VDR --package-version=$(VDRVERSION) --msgid-bugs-address='<see README>' -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) $(I18Npot)
+
+### Targets:
+
+libvdr-$(PLUGIN).so: $(OBJS)
+	$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+	@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
+
+dist: $(I18Npo) clean
+	@-rm -rf $(TMPDIR)/$(ARCHIVE)
+	@mkdir $(TMPDIR)/$(ARCHIVE)
+	@cp -a * $(TMPDIR)/$(ARCHIVE)
+	@tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+	@-rm -rf $(TMPDIR)/$(ARCHIVE)
+	@echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+	@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/README vdr-1.7.18/PLUGINS/src/dvbhddevice/README
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/README	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/README	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,18 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by:                  Andreas Regel <andreas.regel@gmx.de>
+
+Project's homepage:          http://powarman.dyndns.org/hg/dvbhddevice
+
+Latest version available at: http://powarman.dyndns.org/hg/dvbhddevice
+
+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.
+See the file COPYING for more information.
+
+Description:
+
+The 'dvbhddevice' plugin implements the output device for the
+"Full Featured TechnoTrend S2-6400" DVB cards.
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/bitbuffer.c vdr-1.7.18/PLUGINS/src/dvbhddevice/bitbuffer.c
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/bitbuffer.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/bitbuffer.c	2009-12-29 15:29:20.000000000 +0100
@@ -0,0 +1,97 @@
+/*
+ * bitbuffer.c: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: bitbuffer.c 1.1 2009/12/29 14:29:20 kls Exp $
+ */
+
+#include "bitbuffer.h"
+#include <stdlib.h>
+
+cBitBuffer::cBitBuffer(uint32_t MaxLength)
+{
+    mData = NULL;
+    mMaxLength = 0;
+    mBitPos = 0;
+
+    if (MaxLength <= 0x10000)
+    {
+        mData = new uint8_t[MaxLength];
+        if (mData)
+        {
+            mMaxLength = MaxLength * 8;
+        }
+    }
+}
+
+cBitBuffer::~cBitBuffer(void)
+{
+    if (mData)
+        delete[] mData;
+}
+
+uint8_t * cBitBuffer::GetData(void)
+{
+    return mData;
+}
+
+uint32_t cBitBuffer::GetMaxLength(void)
+{
+    return mMaxLength / 8;
+}
+
+uint32_t cBitBuffer::GetBits(int NumBits)
+{
+    return 0;
+}
+
+void cBitBuffer::SetBits(int NumBits, uint32_t Data)
+{
+    uint32_t nextBitPos;
+    uint32_t bytePos;
+    uint32_t bitsInByte;
+    int shift;
+
+    if (NumBits <= 0 || NumBits > 32)
+        return;
+
+    nextBitPos = mBitPos + NumBits;
+
+    if (nextBitPos > mMaxLength)
+        return;
+
+    bytePos = mBitPos / 8;
+    bitsInByte = mBitPos % 8;
+
+    mData[bytePos] &= (uint8_t) (0xFF << (8 - bitsInByte));
+    shift = NumBits - (8 - bitsInByte);
+    if (shift > 0)
+        mData[bytePos] |= (uint8_t) (Data >> shift);
+    else
+        mData[bytePos] |= (uint8_t) (Data << (-shift));
+    NumBits -= 8 - bitsInByte;
+    bytePos++;
+    while (NumBits > 0)
+    {
+        shift = NumBits - 8;
+        if (shift > 0)
+            mData[bytePos] = (uint8_t) (Data >> shift);
+        else
+            mData[bytePos] = (uint8_t) (Data << (-shift));
+        NumBits -= 8;
+        bytePos++;
+    }
+    mBitPos = nextBitPos;
+}
+
+uint32_t cBitBuffer::GetByteLength(void)
+{
+    return (mBitPos + 7) / 8;
+}
+
+void cBitBuffer::SetDataByte(uint32_t Position, uint8_t Data)
+{
+    if (Position < mMaxLength)
+        mData[Position] = Data;
+}
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/bitbuffer.h vdr-1.7.18/PLUGINS/src/dvbhddevice/bitbuffer.h
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/bitbuffer.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/bitbuffer.h	2009-12-29 15:27:03.000000000 +0100
@@ -0,0 +1,31 @@
+/*
+ * bitbuffer.h: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: bitbuffer.h 1.1 2009/12/29 14:27:03 kls Exp $
+ */
+
+#ifndef _HDFF_BITBUFFER_H_
+#define _HDFF_BITBUFFER_H_
+
+#include <stdint.h>
+
+class cBitBuffer
+{
+private:
+    uint8_t * mData;
+    uint32_t mMaxLength;
+    uint32_t mBitPos;
+public:
+    cBitBuffer(uint32_t MaxLength);
+    ~cBitBuffer(void);
+    uint8_t * GetData(void);
+    uint32_t GetMaxLength(void);
+    uint32_t GetBits(int NumBits);
+    void SetBits(int NumBits, uint32_t Data);
+    uint32_t GetByteLength(void);
+    void SetDataByte(uint32_t Position, uint8_t Data);
+};
+
+#endif
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/dvbhddevice.c vdr-1.7.18/PLUGINS/src/dvbhddevice/dvbhddevice.c
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/dvbhddevice.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/dvbhddevice.c	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,48 @@
+/*
+ * dvbhddevice.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: dvbhddevice.c 1.12 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include <vdr/plugin.h>
+#include "dvbhdffdevice.h"
+#include "setup.h"
+
+static const char *VERSION        = "0.0.3";
+static const char *DESCRIPTION    = "HD Full Featured DVB device";
+
+class cPluginDvbhddevice : public cPlugin {
+private:
+  cDvbHdFfDeviceProbe *probe;
+public:
+  cPluginDvbhddevice(void);
+  virtual ~cPluginDvbhddevice();
+  virtual const char *Version(void) { return VERSION; }
+  virtual const char *Description(void) { return DESCRIPTION; }
+  virtual cMenuSetupPage *SetupMenu(void);
+  virtual bool SetupParse(const char *Name, const char *Value);
+  };
+
+cPluginDvbhddevice::cPluginDvbhddevice(void)
+{
+  probe = new cDvbHdFfDeviceProbe;
+}
+
+cPluginDvbhddevice::~cPluginDvbhddevice()
+{
+  delete probe;
+}
+
+cMenuSetupPage *cPluginDvbhddevice::SetupMenu(void)
+{
+  return new cHdffSetupPage(cDvbHdFfDevice::GetHdffCmdHandler());
+}
+
+bool cPluginDvbhddevice::SetupParse(const char *Name, const char *Value)
+{
+  return gHdffSetup.SetupParse(Name, Value);
+}
+
+VDRPLUGINCREATOR(cPluginDvbhddevice); // Don't touch this!
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/dvbhdffdevice.c vdr-1.7.18/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/dvbhdffdevice.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/dvbhdffdevice.c	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,760 @@
+/*
+ * dvbhdffdevice.c: The DVB HD Full Featured device interface
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: dvbhdffdevice.c 1.29 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include "dvbhdffdevice.h"
+#include <errno.h>
+#include <limits.h>
+#include <libsi/si.h>
+#include <linux/videodev2.h>
+#include <linux/dvb/audio.h>
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/video.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <vdr/eitscan.h>
+#include <vdr/transfer.h>
+#include "hdffosd.h"
+#include "setup.h"
+
+// --- cDvbHdFfDevice ----------------------------------------------------------
+
+int cDvbHdFfDevice::devHdffOffset = -1;
+
+cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend)
+:cDvbDevice(Adapter, Frontend)
+{
+  spuDecoder = NULL;
+  audioChannel = 0;
+  playMode = pmNone;
+  mHdffCmdIf = NULL;
+
+  // Devices that are only present on cards with decoders:
+
+  fd_osd      = DvbOpen(DEV_DVB_OSD,    adapter, frontend, O_RDWR);
+  fd_video    = DvbOpen(DEV_DVB_VIDEO,  adapter, frontend, O_RDWR | O_NONBLOCK);
+  fd_audio    = DvbOpen(DEV_DVB_AUDIO,  adapter, frontend, O_RDWR | O_NONBLOCK);
+
+  //TODO missing /dev/video offset calculation
+
+  isHdffPrimary = false;
+  if (devHdffOffset < 0) {
+     devHdffOffset = adapter;
+     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->CmdHdmiSetVideoMode(gHdffSetup.GetVideoMode());
+     HDFF::tHdmiConfig hdmiConfig;
+     hdmiConfig.TransmitAudio = true;
+     hdmiConfig.ForceDviMode = false;
+     hdmiConfig.CecEnabled = gHdffSetup.CecEnabled;
+     mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
+     if (gHdffSetup.CecEnabled)
+        mHdffCmdIf->CmdHdmiSendCecCommand(HDFF::cecCommandTvOn);
+     mHdffCmdIf->CmdRemoteSetProtocol((HDFF::eRemoteProtocol) gHdffSetup.RemoteProtocol);
+     mHdffCmdIf->CmdRemoteSetAddressFilter(gHdffSetup.RemoteAddress >= 0, gHdffSetup.RemoteAddress);
+     }
+
+  // Video format:
+
+  SetVideoFormat(Setup.VideoFormat);
+}
+
+cDvbHdFfDevice::~cDvbHdFfDevice()
+{
+  delete spuDecoder;
+  if (isHdffPrimary)
+     delete mHdffCmdIf;
+  // We're not explicitly closing any device files here, since this sometimes
+  // caused segfaults. Besides, the program is about to terminate anyway...
+}
+
+void cDvbHdFfDevice::MakePrimaryDevice(bool On)
+{
+  if (On)
+     new cHdffOsdProvider(mHdffCmdIf);
+  cDvbDevice::MakePrimaryDevice(On);
+}
+
+bool cDvbHdFfDevice::HasDecoder(void) const
+{
+  return isHdffPrimary;
+}
+
+cSpuDecoder *cDvbHdFfDevice::GetSpuDecoder(void)
+{
+  if (!spuDecoder && IsPrimaryDevice())
+     spuDecoder = new cDvbSpuDecoder();
+  return spuDecoder;
+}
+
+uchar *cDvbHdFfDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
+{
+  //TODO
+  return NULL;
+}
+
+void cDvbHdFfDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
+{
+  //TODO???
+  cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
+}
+
+void cDvbHdFfDevice::SetVideoFormat(bool VideoFormat16_9)
+{
+  HDFF::tVideoFormat videoFormat;
+  videoFormat.AutomaticEnabled = true;
+  videoFormat.AfdEnabled = true;
+  videoFormat.TvFormat = (HDFF::eTvFormat) gHdffSetup.TvFormat;
+  videoFormat.VideoConversion = (HDFF::eVideoConversion) gHdffSetup.VideoConversion;
+  mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
+}
+
+eVideoSystem cDvbHdFfDevice::GetVideoSystem(void)
+{
+  eVideoSystem VideoSystem = vsPAL;
+  if (fd_video >= 0) {
+     video_size_t vs;
+     if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
+        if (vs.h == 480 || vs.h == 240)
+           VideoSystem = vsNTSC;
+        }
+     else
+        LOG_ERROR;
+     }
+  return VideoSystem;
+}
+
+void cDvbHdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
+{
+  if (fd_video >= 0) {
+     video_size_t vs;
+     if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
+        Width = vs.w;
+        Height = vs.h;
+        switch (vs.aspect_ratio) {
+          default:
+          case VIDEO_FORMAT_4_3:   VideoAspect =  4.0 / 3.0; break;
+          case VIDEO_FORMAT_16_9:  VideoAspect = 16.0 / 9.0; break;
+          case VIDEO_FORMAT_221_1: VideoAspect =       2.21; break;
+          }
+        return;
+        }
+     else
+        LOG_ERROR;
+     }
+  cDevice::GetVideoSize(Width, Height, VideoAspect);
+}
+
+void cDvbHdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
+{
+  gHdffSetup.GetOsdSize(Width, Height, PixelAspect);
+}
+
+/*TODO obsolete?
+bool cDvbHdFfDevice::SetAudioBypass(bool On)
+{
+  if (setTransferModeForDolbyDigital != 1)
+     return false;
+  return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
+}
+TODO*/
+
+bool cDvbHdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On)
+{
+  if (Handle->pid) {
+     dmx_pes_filter_params pesFilterParams;
+     memset(&pesFilterParams, 0, sizeof(pesFilterParams));
+     if (On) {
+        if (Handle->handle < 0) {
+           Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
+           if (Handle->handle < 0) {
+              LOG_ERROR;
+              return false;
+              }
+           }
+        if (Type == ptPcr)
+           mHdffCmdIf->CmdAvSetPcrPid(0, Handle->pid);
+        else if (Type == ptVideo) {
+           if (Handle->streamType == 0x1B)
+              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF::videoStreamH264);
+           else
+              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF::videoStreamMpeg2);
+           }
+        else if (Type == ptAudio)
+           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF::audioStreamMpeg1);
+        else if (Type == ptDolby)
+           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF::audioStreamAc3);
+        if (!(Type <= ptDolby && Handle->used <= 1)) {
+           pesFilterParams.pid     = Handle->pid;
+           pesFilterParams.input   = DMX_IN_FRONTEND;
+           pesFilterParams.output  = DMX_OUT_TS_TAP;
+           pesFilterParams.pes_type= DMX_PES_OTHER;
+           pesFilterParams.flags   = DMX_IMMEDIATE_START;
+           if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+              LOG_ERROR;
+              return false;
+              }
+           }
+        }
+     else if (!Handle->used) {
+        CHECK(ioctl(Handle->handle, DMX_STOP));
+        if (Type == ptPcr)
+           mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+        else if (Type == ptVideo)
+           mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg2);
+        else if (Type == ptAudio)
+           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+        else if (Type == ptDolby)
+           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamAc3);
+        //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid()
+        close(Handle->handle);
+        Handle->handle = -1;
+        }
+     }
+  return true;
+}
+
+void cDvbHdFfDevice::TurnOffLiveMode(bool LiveView)
+{
+  // Turn off live PIDs:
+
+  DetachAll(pidHandles[ptAudio].pid);
+  DetachAll(pidHandles[ptVideo].pid);
+  DetachAll(pidHandles[ptPcr].pid);
+  DetachAll(pidHandles[ptTeletext].pid);
+  DelPid(pidHandles[ptAudio].pid);
+  DelPid(pidHandles[ptVideo].pid);
+  DelPid(pidHandles[ptPcr].pid, ptPcr);
+  DelPid(pidHandles[ptTeletext].pid);
+  DelPid(pidHandles[ptDolby].pid);
+}
+
+bool cDvbHdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
+{
+  int apid = Channel->Apid(0);
+  int vpid = Channel->Vpid();
+  int dpid = Channel->Dpid(0);
+
+  bool DoTune = !IsTunedToTransponder(Channel);
+
+  bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid;
+  bool pidHandlesAudio = pidHandles[ptAudio].pid == apid;
+
+  bool TurnOffLivePIDs = DoTune
+                         || !IsPrimaryDevice()
+                         || LiveView // for a new live view the old PIDs need to be turned off
+                         || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
+                         ;
+
+  bool StartTransferMode = IsPrimaryDevice() && !DoTune
+                           && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER
+                              || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
+                              );
+  if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber()))
+     StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN;
+
+  bool TurnOnLivePIDs = !StartTransferMode && LiveView;
+
+  // Turn off live PIDs if necessary:
+
+  if (TurnOffLivePIDs)
+     TurnOffLiveMode(LiveView);
+
+  // Set the tuner:
+
+  if (!cDvbDevice::SetChannelDevice(Channel, LiveView))
+     return false;
+
+  // If this channel switch was requested by the EITScanner we don't wait for
+  // a lock and don't set any live PIDs (the EITScanner will wait for the lock
+  // by itself before setting any filters):
+
+  if (EITScanner.UsesDevice(this)) //XXX
+     return true;
+
+  // PID settings:
+
+  if (TurnOnLivePIDs) {
+     //SetAudioBypass(false);//TODO obsolete?
+     if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid, ptAudio))) {
+        esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
+        return false;
+        }
+     if (IsPrimaryDevice())
+        AddPid(Channel->Tpid(), ptTeletext);//TODO obsolete?
+     }
+  else if (StartTransferMode)
+     cControl::Launch(new cTransferControl(this, Channel));
+
+  return true;
+}
+
+int cDvbHdFfDevice::GetAudioChannelDevice(void)
+{
+  return audioChannel;
+}
+
+void cDvbHdFfDevice::SetAudioChannelDevice(int AudioChannel)
+{
+  mHdffCmdIf->CmdAvSetAudioChannel(AudioChannel);
+  audioChannel = AudioChannel;
+}
+
+void cDvbHdFfDevice::SetVolumeDevice(int Volume)
+{
+  mHdffCmdIf->CmdMuxSetVolume(Volume * 100 / 255);
+}
+
+void cDvbHdFfDevice::SetDigitalAudioDevice(bool On)
+{
+  // not needed
+}
+
+void cDvbHdFfDevice::SetAudioTrackDevice(eTrackType Type)
+{
+  //printf("SetAudioTrackDevice %d\n", Type);
+  const tTrackId *TrackId = GetTrack(Type);
+  if (TrackId && TrackId->id) {
+     if (IS_AUDIO_TRACK(Type)) {
+        if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) {
+           DetachAll(pidHandles[ptAudio].pid);
+           if (CamSlot())
+              CamSlot()->SetPid(pidHandles[ptAudio].pid, false);
+           pidHandles[ptAudio].pid = TrackId->id;
+           SetPid(&pidHandles[ptAudio], ptAudio, true);
+           if (CamSlot()) {
+              CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
+              CamSlot()->StartDecrypting();
+              }
+           }
+	}
+     else if (IS_DOLBY_TRACK(Type)) {
+        pidHandles[ptDolby].pid = TrackId->id;
+        SetPid(&pidHandles[ptDolby], ptDolby, true);
+        }
+     }
+}
+
+bool cDvbHdFfDevice::CanReplay(void) const
+{
+  return cDevice::CanReplay();
+}
+
+bool cDvbHdFfDevice::SetPlayMode(ePlayMode PlayMode)
+{
+  if (PlayMode == pmNone) {
+     mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
+     mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+     mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg2);
+     mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+
+     ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
+     mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
+     mHdffCmdIf->CmdAvEnableSync(0, true);
+     mHdffCmdIf->CmdAvSetPlayMode(0, true);
+     }
+  else {
+     if (playMode == pmNone)
+        TurnOffLiveMode(true);
+
+     mHdffCmdIf->CmdAvSetPlayMode(1, Transferring());
+     mHdffCmdIf->CmdAvSetStc(0, 100000);
+     mHdffCmdIf->CmdAvEnableSync(0, true);
+     mHdffCmdIf->CmdAvEnableVideoAfterStop(0, true);
+
+     playVideoPid = -1;
+     playAudioPid = -1;
+     audioCounter = 0;
+     videoCounter = 0;
+
+     mHdffCmdIf->CmdAvSetDecoderInput(0, 2);
+     ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
+     }
+  playMode = PlayMode;
+  return true;
+}
+
+int64_t cDvbHdFfDevice::GetSTC(void)
+{
+  if (fd_video >= 0) {
+     uint64_t pts;
+     if (ioctl(fd_video, VIDEO_GET_PTS, &pts) == -1) {
+        esyslog("ERROR: pts %d: %m", CardIndex() + 1);
+        return -1;
+        }
+     return pts;
+     }
+  if (fd_audio >= 0) {
+     uint64_t pts;
+     if (ioctl(fd_audio, AUDIO_GET_PTS, &pts) == -1) {
+        esyslog("ERROR: pts %d: %m", CardIndex() + 1);
+        return -1;
+        }
+     return pts;
+     }
+  return -1;
+}
+
+void cDvbHdFfDevice::TrickSpeed(int Speed)
+{
+  mHdffCmdIf->CmdAvEnableSync(0, false);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+  playAudioPid = -1;
+  if (Speed > 0)
+     mHdffCmdIf->CmdAvSetVideoSpeed(0, 100 / Speed);
+}
+
+void cDvbHdFfDevice::Clear(void)
+{
+  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
+  mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg1);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+  playVideoPid = -1;
+  playAudioPid = -1;
+  cDevice::Clear();
+}
+
+void cDvbHdFfDevice::Play(void)
+{
+  mHdffCmdIf->CmdAvEnableSync(0, true);
+  mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+  mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
+  cDevice::Play();
+}
+
+void cDvbHdFfDevice::Freeze(void)
+{
+  mHdffCmdIf->CmdAvSetVideoSpeed(0, 0);
+  mHdffCmdIf->CmdAvSetAudioSpeed(0, 0);
+  cDevice::Freeze();
+}
+
+void cDvbHdFfDevice::Mute(void)
+{
+  //TODO???
+  cDevice::Mute();
+}
+
+static HDFF::eVideoStreamType 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
+    }
+}
+
+void cDvbHdFfDevice::StillPicture(const uchar *Data, int Length)
+{
+  if (!Data || Length < TS_SIZE)
+     return;
+  if (Data[0] == 0x47) {
+     // TS data
+     cDevice::StillPicture(Data, Length);
+     }
+  else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) {
+     // PES data
+     char *buf = MALLOC(char, Length);
+     if (!buf)
+        return;
+     int i = 0;
+     int blen = 0;
+     while (i < Length - 6) {
+           if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
+              int len = Data[i + 4] * 256 + Data[i + 5];
+              if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet
+                 // skip PES header
+                 int offs = i + 6;
+                 // skip header extension
+                 if ((Data[i + 6] & 0xC0) == 0x80) {
+                    // MPEG-2 PES header
+                    if (Data[i + 8] >= Length)
+                       break;
+                    offs += 3;
+                    offs += Data[i + 8];
+                    len -= 3;
+                    len -= Data[i + 8];
+                    if (len < 0 || offs + len > Length)
+                       break;
+                    }
+                 else {
+                    // MPEG-1 PES header
+                    while (offs < Length && len > 0 && Data[offs] == 0xFF) {
+                          offs++;
+                          len--;
+                          }
+                    if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) {
+                       offs += 2;
+                       len -= 2;
+                       }
+                    if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) {
+                       offs += 5;
+                       len -= 5;
+                       }
+                    else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) {
+                       offs += 10;
+                       len -= 10;
+                       }
+                    else if (offs < Length && len > 0) {
+                       offs++;
+                       len--;
+                       }
+                    }
+                 if (blen + len > Length) // invalid PES length field
+                    break;
+                 memcpy(&buf[blen], &Data[offs], len);
+                 i = offs + len;
+                 blen += len;
+                 }
+              else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets
+                 i += len + 6;
+              else
+                 i++;
+              }
+           else
+              i++;
+           }
+     mHdffCmdIf->CmdAvShowStillImage(0, (uint8_t *)buf, blen, MapVideoStreamTypes(PatPmtParser()->Vtype()));
+     free(buf);
+     }
+  else {
+     // non-PES data
+     mHdffCmdIf->CmdAvShowStillImage(0, Data, Length, MapVideoStreamTypes(PatPmtParser()->Vtype()));
+     }
+}
+
+bool cDvbHdFfDevice::Poll(cPoller &Poller, int TimeoutMs)
+{
+  Poller.Add(fd_video, true);
+  return Poller.Poll(TimeoutMs);
+}
+
+bool cDvbHdFfDevice::Flush(int TimeoutMs)
+{
+  //TODO actually this function should wait until all buffered data has been processed by the card, but how?
+  return true;
+}
+
+void cDvbHdFfDevice::BuildTsPacket(uint8_t * TsBuffer, bool PusiSet, uint16_t Pid, uint8_t Counter, const uint8_t * Data, uint32_t Length)
+{
+    TsBuffer[0] = 0x47;
+    TsBuffer[1] = PusiSet ? 0x40 : 0x00;
+    TsBuffer[1] |= Pid >> 8;
+    TsBuffer[2] = Pid & 0xFF;
+    if (Length >= 184)
+    {
+        TsBuffer[3] = 0x10 | Counter;
+        memcpy(TsBuffer + 4, Data, 184);
+    }
+    else
+    {
+        uint8_t adaptationLength;
+
+        TsBuffer[3] = 0x30 | Counter;
+        adaptationLength = 183 - Length;
+        TsBuffer[4] = adaptationLength;
+        if (adaptationLength > 0)
+        {
+            TsBuffer[5] = 0x00;
+            memset(TsBuffer + 6, 0xFF, adaptationLength - 1);
+        }
+        memcpy(TsBuffer + 5 + adaptationLength, Data, Length);
+    }
+}
+
+uint32_t cDvbHdFfDevice::PesToTs(uint8_t * TsBuffer, uint16_t Pid, uint8_t & Counter, const uint8_t * Data, uint32_t Length)
+{
+    uint32_t tsOffset;
+    uint32_t i;
+
+    tsOffset = 0;
+    i = 0;
+    while (Length > 0)
+    {
+        BuildTsPacket(TsBuffer + tsOffset, i == 0, Pid, Counter, Data + i * 184, Length);
+        if (Length >= 184)
+            Length -= 184;
+        else
+            Length = 0;
+        Counter = (Counter + 1) & 15;
+        tsOffset += 188;
+        i++;
+    }
+    return tsOffset;
+}
+
+int cDvbHdFfDevice::PlayVideo(const uchar *Data, int Length)
+{
+    //TODO: support greater Length
+    uint8_t tsBuffer[188 * 16];
+    uint32_t tsLength;
+    int pid = 100;
+
+    tsLength = PesToTs(tsBuffer, pid, videoCounter, Data, Length);
+
+    if (pid != playVideoPid) {
+        playVideoPid = pid;
+        mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, HDFF::videoStreamMpeg2, true);
+    }
+    if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
+        Length = 0;
+    return Length;
+}
+
+int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
+{
+    uint8_t streamId;
+    uint8_t tsBuffer[188 * 16];
+    uint32_t tsLength;
+    HDFF::eAudioStreamType streamType = HDFF::audioStreamMpeg1;
+    HDFF::eAVContainerType containerType = HDFF::avContainerPes;
+    int pid;
+
+    streamId = Data[3];
+    if (streamId >= 0xC0 && streamId <= 0xDF)
+    {
+        streamType = HDFF::audioStreamMpeg1;
+    }
+    else if (streamId == 0xBD)
+    {
+        const uint8_t * payload = Data + 9 + Data[8];
+        if ((payload[0] & 0xF8) == 0xA0)
+        {
+            containerType = HDFF::avContainerPesDvd;
+            streamType = HDFF::audioStreamPcm;
+        }
+        else if ((payload[0] & 0xF8) == 0x88)
+        {
+            containerType = HDFF::avContainerPesDvd;
+            streamType = HDFF::audioStreamDts;
+        }
+        else if ((payload[0] & 0xF8) == 0x80)
+        {
+            containerType = HDFF::avContainerPesDvd;
+            streamType = HDFF::audioStreamAc3;
+        }
+        else
+        {
+            streamType = HDFF::audioStreamAc3;
+        }
+    }
+    pid = 200 + (int) streamType;
+    tsLength = PesToTs(tsBuffer, pid, audioCounter, Data, Length);
+
+    if (pid != playAudioPid) {
+        playAudioPid = pid;
+        mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, streamType, containerType);
+    }
+    if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
+        Length = 0;
+    return Length;
+}
+
+int cDvbHdFfDevice::PlayTsVideo(const uchar *Data, int Length)
+{
+  int pid = TsPid(Data);
+  if (pid != playVideoPid) {
+     PatPmtParser();
+     if (pid == PatPmtParser()->Vpid()) {
+        playVideoPid = pid;
+        mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, MapVideoStreamTypes(PatPmtParser()->Vtype()), true);
+        }
+     }
+  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
+}
+
+static HDFF::eAudioStreamType 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
+    }
+}
+
+int cDvbHdFfDevice::PlayTsAudio(const uchar *Data, int Length)
+{
+  int pid = TsPid(Data);
+  if (pid != playAudioPid) {
+     playAudioPid = pid;
+     int AudioStreamType = -1;
+     for (int i = 0; PatPmtParser()->Apid(i); i++) {
+         if (playAudioPid == PatPmtParser()->Apid(i)) {
+            AudioStreamType = PatPmtParser()->Atype(i);
+            break;
+            }
+         }
+     if (AudioStreamType < 0) {
+        for (int i = 0; PatPmtParser()->Dpid(i); i++) {
+            if (playAudioPid == PatPmtParser()->Dpid(i)) {
+               AudioStreamType = PatPmtParser()->Dtype(i);
+               break;
+               }
+            }
+        }
+     mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, MapAudioStreamTypes(AudioStreamType));
+     }
+  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
+}
+
+HDFF::cHdffCmdIf *cDvbHdFfDevice::GetHdffCmdHandler(void)
+{
+  //TODO why not just keep a pointer?
+  if (devHdffOffset >= 0) {
+     cDvbHdFfDevice *device = (cDvbHdFfDevice *)GetDevice(devHdffOffset);
+     if (device)
+        return device->mHdffCmdIf;
+     }
+  return NULL;
+}
+
+// --- cDvbHdFfDeviceProbe ---------------------------------------------------
+
+bool cDvbHdFfDeviceProbe::Probe(int Adapter, int Frontend)
+{
+  static uint32_t SubsystemIds[] = {
+    0x13C23009, // Technotrend S2-6400 HDFF
+    0x00000000
+    };
+  cString FileName;
+  cReadLine ReadLine;
+  FILE *f = NULL;
+  uint32_t SubsystemId = 0;
+  FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend);
+  if ((f = fopen(FileName, "r")) != NULL) {
+     if (char *s = ReadLine.Read(f))
+        SubsystemId = strtoul(s, NULL, 0) << 16;
+     fclose(f);
+     }
+  FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend);
+  if ((f = fopen(FileName, "r")) != NULL) {
+     if (char *s = ReadLine.Read(f))
+        SubsystemId |= strtoul(s, NULL, 0);
+     fclose(f);
+     }
+  for (uint32_t *sid = SubsystemIds; *sid; sid++) {
+      if (*sid == SubsystemId) {
+         FileName = cString::sprintf("/dev/dvb/adapter%d/osd0", Adapter);
+         int fd = open(FileName, O_RDWR);
+         if (fd != -1) { //TODO treat the second path of the S2-6400 as a budget device
+            close(fd);
+            dsyslog("creating cDvbHdFfDevice");
+            new cDvbHdFfDevice(Adapter, Frontend);
+            return true;
+            }
+         }
+      }
+  return false;
+}
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/dvbhdffdevice.h vdr-1.7.18/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/dvbhdffdevice.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/dvbhdffdevice.h	2010-03-13 12:18:13.000000000 +0100
@@ -0,0 +1,123 @@
+/*
+ * dvbhdffdevice.h: The DVB HD Full Featured device interface
+ *
+ * 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 $
+ */
+
+#ifndef __DVBHDFFDEVICE_H
+#define __DVBHDFFDEVICE_H
+
+#include "hdffcmd.h"
+#include "vdr/dvbdevice.h"
+#include "vdr/dvbspu.h"
+
+/// The cDvbHdFfDevice implements a DVB device which can be accessed through the Linux DVB driver API.
+
+class cDvbHdFfDevice : public cDvbDevice {
+private:
+  int fd_osd, fd_audio, fd_video;
+protected:
+  virtual void MakePrimaryDevice(bool On);
+public:
+  static bool Probe(int Adapter, int Frontend);
+  cDvbHdFfDevice(int Adapter, int Frontend);
+  virtual ~cDvbHdFfDevice();
+  virtual bool HasDecoder(void) const;
+
+// SPU facilities
+
+private:
+  cDvbSpuDecoder *spuDecoder;
+public:
+  virtual cSpuDecoder *GetSpuDecoder(void);
+
+// Channel facilities
+
+private:
+  void TurnOffLiveMode(bool LiveView);
+protected:
+  virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
+
+// PID handle facilities
+
+protected:
+  virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
+
+// Image Grab facilities
+
+public:
+  virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
+
+// Video format facilities
+
+public:
+  virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat);
+  virtual void SetVideoFormat(bool VideoFormat16_9);
+  virtual eVideoSystem GetVideoSystem(void);
+  virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect);
+  virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect);
+
+// Track facilities
+
+protected:
+  virtual void SetAudioTrackDevice(eTrackType Type);
+
+// Audio facilities
+
+private:
+  int audioChannel;
+protected:
+  virtual int GetAudioChannelDevice(void);
+  virtual void SetAudioChannelDevice(int AudioChannel);
+  virtual void SetVolumeDevice(int Volume);
+  virtual void SetDigitalAudioDevice(bool On);
+
+// Player facilities
+
+private:
+  int playVideoPid;
+  int playAudioPid;
+
+  // Pes2Ts conversion stuff
+  uint8_t videoCounter;
+  uint8_t audioCounter;
+  void BuildTsPacket(uint8_t * TsBuffer, bool PusiSet, uint16_t Pid, uint8_t Counter, const uint8_t * Data, uint32_t Length);
+  uint32_t PesToTs(uint8_t * TsBuffer, uint16_t Pid, uint8_t & Counter, const uint8_t * Data, uint32_t Length);
+
+protected:
+  ePlayMode playMode;
+  virtual bool CanReplay(void) const;
+  virtual bool SetPlayMode(ePlayMode PlayMode);
+  virtual int PlayVideo(const uchar *Data, int Length);
+  virtual int PlayAudio(const uchar *Data, int Length, uchar Id);
+  virtual int PlayTsVideo(const uchar *Data, int Length);
+  virtual int PlayTsAudio(const uchar *Data, int Length);
+public:
+  virtual int64_t GetSTC(void);
+  virtual void TrickSpeed(int Speed);
+  virtual void Clear(void);
+  virtual void Play(void);
+  virtual void Freeze(void);
+  virtual void Mute(void);
+  virtual void StillPicture(const uchar *Data, int Length);
+  virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
+  virtual bool Flush(int TimeoutMs = 0);
+
+// HDFF specific things
+
+public:
+  static HDFF::cHdffCmdIf *GetHdffCmdHandler(void);
+private:
+  static int devHdffOffset;//TODO
+  bool isHdffPrimary;//TODO implicit!
+  HDFF::cHdffCmdIf *mHdffCmdIf;
+};
+
+class cDvbHdFfDeviceProbe : public cDvbDeviceProbe {
+public:
+  virtual bool Probe(int Adapter, int Frontend);
+  };
+
+#endif //__DVBHDFFDEVICE_H
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffcmd.c vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffcmd.c
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffcmd.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffcmd.c	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,1120 @@
+/*
+ * hdffcmd.c: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffcmd.c 1.19 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include "hdffcmd.h"
+#include <linux/dvb/osd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <vdr/tools.h>
+
+namespace HDFF
+{
+
+cHdffCmdIf::cHdffCmdIf(int OsdDev)
+{
+    mOsdDev = OsdDev;
+    if (mOsdDev < 0)
+    {
+        //printf("ERROR: invalid OSD device handle (%d)!\n", mOsdDev);
+    }
+}
+
+cHdffCmdIf::~cHdffCmdIf(void)
+{
+}
+
+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];
+    }
+    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];
+    }
+    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;
+        }
+    }
+    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);
+}
+
+void cHdffCmdIf::CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, eVideoStreamType 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);
+}
+
+void cHdffCmdIf::CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, eAudioStreamType StreamType, eAVContainerType 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);
+}
+
+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);
+}
+
+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);
+}
+
+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;
+
+    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::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);
+}
+
+void cHdffCmdIf::CmdAvSetDemultiplexerInput(uint8_t DemultiplexerIndex, uint8_t TsInputIndex)
+{
+    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, 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::CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc)
+{
+    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, 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::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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+void cHdffCmdIf::CmdAvSetAudioDelay(int16_t Delay)
+{
+    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, 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::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);
+}
+
+
+void cHdffCmdIf::CmdOsdConfigure(const tOsdConfig * 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);
+}
+
+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);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, eColorType 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;
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreatePalette(eColorType ColorType, eColorFormat 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;
+}
+
+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);
+}
+
+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);
+}
+
+void cHdffCmdIf::CmdOsdSetPaletteColors(uint32_t hPalette, eColorFormat 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);
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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)
+{
+    //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);
+}
+
+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);
+}
+
+void cHdffCmdIf::CmdOsdRestoreRegion(uint32_t hDisplay)
+{
+    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, 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::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);
+}
+
+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);
+}
+
+void cHdffCmdIf::CmdHdmiSetVideoMode(eHdmiVideoMode 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);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdHdmiSendCecCommand(eCecCommand Command)
+{
+    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, msgHdmiSendCecCommand);
+    cmdBuf.SetBits(8, Command);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdRemoteSetProtocol(eRemoteProtocol 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);
+}
+
+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);
+}
+
+} // end of namespace
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffcmd.h vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffcmd.h
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffcmd.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffcmd.h	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,102 @@
+/*
+ * hdffcmd.h: TODO(short description)
+ *
+ * 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 $
+ */
+
+#ifndef _HDFF_CMD_H_
+#define _HDFF_CMD_H_
+
+#include "bitbuffer.h"
+#include "hdffmsgdef.h"
+
+namespace HDFF
+{
+
+class cHdffCmdIf
+{
+private:
+    int mOsdDev;
+
+    void CmdBuildHeader(cBitBuffer & MsgBuf, eMessageType MsgType, eMessageGroup MsgGroup, eMessageId MsgId);
+    uint32_t CmdSetLength(cBitBuffer & MsgBuf);
+
+public:
+    cHdffCmdIf(int OsdDev);
+    ~cHdffCmdIf(void);
+
+    uint32_t CmdGetFirmwareVersion(char * pString, uint32_t MaxLength);
+    uint32_t CmdGetInterfaceVersion(char * pString, uint32_t MaxLength);
+    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 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 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 CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc);
+    void CmdAvFlushBuffer(uint8_t DecoderIndex, bool FlushAudio, bool FlushVideo);
+    void CmdAvEnableSync(uint8_t DecoderIndex, bool EnableSync);
+    void CmdAvSetVideoSpeed(uint8_t DecoderIndex, int32_t Speed);
+    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 CmdAvSetAudioChannel(uint8_t AudioChannel);
+
+    void CmdOsdConfigure(const tOsdConfig * pConfig);
+    void CmdOsdReset(void);
+
+    uint32_t CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, eColorType 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 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,
+                                uint8_t StartColor, uint32_t NumColors, const uint32_t * pColors);
+
+    uint32_t CmdOsdCreateFontFace(const uint8_t * pFontData, uint32_t DataSize);
+    void CmdOsdDeleteFontFace(uint32_t hFontFace);
+    uint32_t CmdOsdCreateFont(uint32_t hFontFace, uint32_t Size);
+    void CmdOsdDeleteFont(uint32_t hFont);
+
+    void CmdOsdDrawRectangle(uint32_t hDisplay, int X, int Y, int Width, int Height, uint32_t Color);
+    void CmdOsdDrawEllipse(uint32_t hDisplay, int CX, int CY, int RadiusX, int RadiusY,
+                           uint32_t Color, uint32_t Flags);
+    void CmdOsdDrawText(uint32_t hDisplay, uint32_t hFont, int X, int Y, const char * pText, uint32_t Color);
+    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);
+    void CmdOsdSaveRegion(uint32_t hDisplay, int X, int Y, int Width, int Height);
+    void CmdOsdRestoreRegion(uint32_t hDisplay);
+
+    void CmdMuxSetVideoOut(eVideoOut VideoOut);
+    void CmdMuxSetVolume(uint8_t Volume);
+    void CmdMuxMuteAudio(bool Mute);
+
+    void CmdHdmiSetVideoMode(eHdmiVideoMode VideoMode);
+    void CmdHdmiConfigure(const tHdmiConfig * pConfig);
+    void CmdHdmiSendCecCommand(eCecCommand Command);
+
+    void CmdRemoteSetProtocol(eRemoteProtocol Protocol);
+    void CmdRemoteSetAddressFilter(bool Enable, uint32_t Address);
+};
+
+} // end of namespace
+
+#endif
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffmsgdef.h vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffmsgdef.h
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffmsgdef.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffmsgdef.h	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,304 @@
+/*
+ * hdffmsgdef.h: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffmsgdef.h 1.12 2011/04/17 11:20:22 kls Exp $
+ */
+
+#ifndef _HDFF_MSGDEF_H_
+#define _HDFF_MSGDEF_H_
+
+#define MAX_CMD_LEN 1536
+
+namespace HDFF
+{
+
+typedef enum _eMessageType
+{
+    msgTypeCommand,
+    msgTypeAnswer,
+    msgTypeResult,
+    msgTypeEvent
+} eMessageType;
+
+typedef enum _eMessageGroup
+{
+    msgGroupGeneric,
+    msgGroupAvDec,
+    msgGroupAvMux,
+    msgGroupFrontend,
+    msgGroupOsd,
+    msgGroupHdmi,
+    msgGroupRemoteControl
+} eMessageGroup;
+
+typedef enum _eMessageId
+{
+    msgGenGetFirmwareVersion = 0,
+    msgGenGetInterfaceVersion,
+    msgGenGetCopyrights,
+
+    msgAvSetAudioPid = 0,
+    msgAvSetVideoPid,
+    msgAvSetPcrPid,
+    msgAvSetTeletextPid,
+    msgAvShowStillImage,
+    msgAvSetVideoWindow,
+    msgAvSetDecoderInput,
+    msgAvSetDemultiplexerInput,
+    msgAvSetVideoFormat,
+    msgAvSetVideoOutputMode,
+    msgAvSetStc,
+    msgAvFlushBuffer,
+    msgAvEnableSync,
+    msgAvSetVideoSpeed,
+    msgAvSetAudioSpeed,
+    msgAvEnableVideoAfterStop,
+    msgAvGetVideoFormatInfo,
+    msgAvSetAudioDelay,
+    msgAvSetAudioDownmix,
+    msgAvSetAudioChannel,
+    msgAvSetPlayMode,
+
+    msgMuxSetVideoOut = 0,
+    msgMuxSetSlowBlank,
+    msgMuxSetFastBlank,
+    msgMuxSetVolume,
+    msgMuxSetAudioMute,
+
+    msgOsdConfigure = 0,
+    msgOsdReset,
+    msgOsdCreateDisplay = 10,
+    msgOsdDeleteDisplay,
+    msgOsdEnableDisplay,
+    msgOsdSetDisplayOutputRectangle,
+    msgOsdSetDisplayClippingArea,
+    msgOsdRenderDisplay,
+    msgOsdSaveRegion,
+    msgOsdRestoreRegion,
+    msgOsdCreatePalette = 30,
+    msgOsdDeletePalette,
+    msgOsdSetDisplayPalette,
+    msgOsdSetPaletteColors,
+    msgOsdCreateFontFace = 50,
+    msgOsdDeleteFontFace,
+    msgOsdCreateFont,
+    msgOsdDeleteFont,
+    msgOsdDrawPixel = 70,
+    msgOsdDrawRectangle,
+    msgOsdDrawCircle,
+    msgOsdDrawEllipse,
+    msgOsdDrawSlope,
+    msgOsdDrawText,
+    msgOsdDrawTextW,
+    msgOsdDrawBitmap,
+
+    msgHdmiEnableOutput = 0,
+    msgHdmiSetVideoMode,
+    msgHdmiConfigure,
+    msgHdmiIsDisplayConnected,
+    msgHdmiGetDisplayInfo,
+    msgHdmiGetVideoMode,
+    msgHdmiSendCecCommand,
+
+    msgRemoteSetProtocol = 0,
+    msgRemoteSetAddressFilter,
+    msgRemoteKeyEvent
+} eMessageId;
+
+
+// AvDec definitions
+
+typedef enum _eAVContainerType
+{
+    avContainerPes,
+    avContainerPesDvd,
+    avContainerMaxValue
+} eAVContainerType;
+
+typedef enum _eAudioStreamType
+{
+    audioStreamMpeg1,
+    audioStreamMpeg2,
+    audioStreamAc3,
+    audioStreamAac,
+    audioStreamHeAac,
+    audioStreamPcm,
+    audioStreamEAc3,
+    audioStreamDts,
+    audioStreamMaxValue
+} eAudioStreamType;
+
+typedef enum _eVideoStreamType
+{
+    videoStreamMpeg1,
+    videoStreamMpeg2,
+    videoStreamH264,
+    videoStreamMpeg4Asp,
+    videoStreamVc1,
+    videoStreamMaxValue
+} eVideoStreamType;
+
+
+typedef enum _eTvFormat
+{
+    tvFormat4by3,
+    tvFormat16by9,
+    tvFormatMaxValue
+} eTvFormat;
+
+typedef enum _eVideoConversion
+{
+    videoConversionAutomatic,
+    videoConversionLetterbox16by9,
+    videoConversionLetterbox14by9,
+    videoConversionPillarbox,
+    videoConversionCentreCutOut,
+    videoConversionAlways16by9,
+    videoConversionMaxValue
+} eVideoConversion;
+
+typedef struct _tVideoFormat
+{
+    bool AutomaticEnabled;
+    bool AfdEnabled;
+    eTvFormat TvFormat;
+    eVideoConversion VideoConversion;
+} tVideoFormat;
+
+typedef enum _eVideoOutputMode
+{
+    videoOutputClone,
+    videoOutputDualView,
+    videoOutputMaxValue
+} eVideoOutputMode;
+
+typedef enum _eDownmixMode
+{
+    downmixOff,
+    downmixAnalog,
+    downmixAlways,
+    downmixAutomatic,
+    downmixHdmi
+} eDownmixMode;
+
+// AvMux definitions
+
+typedef enum _eVideoOut
+{
+    videoOutDisabled,
+    videoOutRgb,
+    videoOutCvbsYuv,
+    videoOutYc,
+    videoOutMaxValue
+} eVideoOut;
+
+typedef enum _eSlowBlank
+{
+    slowBlankOff,
+    slowBlank16by9,
+    slowBlank4by3,
+    slowBlankMaxValue
+} eSlowBlank;
+
+typedef enum _eFastBlank
+{
+    fastBlankCvbs,
+    fastBlankRgb,
+    fastBlankMaxValue
+} eFastBlank;
+
+
+// OSD definitions
+
+#define InvalidHandle           0xFFFFFFFF
+#define ScreenDisplayHandle     0xFFFFFFFE
+
+#define PositionScreenCentered  0xFFFF
+
+#define SizeFullScreen    0xFFFF
+#define SizeSameAsSource  0xFFFE
+
+#define FontFaceTiresias  0x00000000
+
+typedef enum _eColorType
+{
+    colorTypeClut1,
+    colorTypeClut2,
+    colorTypeClut4,
+    colorTypeClut8,
+    colorTypeARGB8888,
+    colorTypeARGB8565,
+    colorTypeARGB4444,
+    colorTypeARGB1555,
+} eColorType;
+
+typedef enum _eColorFormat
+{
+    colorFormatARGB,
+    colorFormatACbYCr,
+} eColorFormat;
+
+typedef enum _eDrawingFlags
+{
+    drawFull,
+    drawHalfTop,
+    drawHalfLeft,
+    drawHalfBottom,
+    drawHalfRight,
+    drawQuarterTopLeft,
+    drawQuarterTopRight,
+    drawQuarterBottomLeft,
+    drawQuarterBottomRight,
+    drawQuarterTopLeftInverted,
+    drawQuarterTopRightInverted,
+    drawQuarterBottomLeftInverted,
+    drawQuarterBottomRightInverted
+} eDrawingFlags;
+
+typedef struct _tOsdConfig
+{
+    bool FontAntialiasing;
+    bool FontKerning;
+} tOsdConfig;
+
+// HDMI definitions
+
+typedef enum _eHdmiVideoMode
+{
+    videoMode576p50 = 18,
+    videoMode720p50 = 19,
+    videoMode1080i50 = 20,
+    videoMode576i50 = 22,
+    videoModeMaxValue
+} eHdmiVideoMode;
+
+typedef enum _eCecCommand
+{
+    cecCommandTvOn,
+    cecCommandTvOff,
+    cecCommandActiveSource,
+    cecCommandInactiveSource
+} eCecCommand;
+
+typedef struct _tHdmiConfig
+{
+    bool TransmitAudio;
+    bool ForceDviMode;
+    bool CecEnabled;
+} tHdmiConfig;
+
+// Remote control definitions
+
+typedef enum _eRemoteProtocol
+{
+    remoteProtocolNone,
+    remoteProtocolRc5,
+    remoteProtocolRc6,
+    remoteProtocolMaxValue
+} eRemoteProtocol;
+
+} // end of namespace
+
+#endif
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffosd.c vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffosd.c
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffosd.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffosd.c	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,755 @@
+/*
+ * hdffosd.c: Implementation of the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffosd.c 1.9 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include "hdffosd.h"
+#include <linux/dvb/osd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include "hdffcmd.h"
+#include "setup.h"
+
+#define MAX_NUM_FONTFACES   8
+#define MAX_NUM_FONTS       8
+#define MAX_BITMAP_SIZE     (1024*1024)
+
+typedef struct _tFontFace
+{
+    cString Name;
+    uint32_t Handle;
+} tFontFace;
+
+typedef struct _tFont
+{
+    uint32_t hFontFace;
+    int Size;
+    uint32_t Handle;
+} tFont;
+
+class cHdffOsd : public cOsd
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    int mLeft;
+    int mTop;
+    int mDispWidth;
+    int mDispHeight;
+    bool shown;
+    bool mChanged;
+    bool mBitmapModified;
+    uint32_t mDisplay;
+    tFontFace mFontFaces[MAX_NUM_FONTFACES];
+    tFont mFonts[MAX_NUM_FONTS];
+    uint32_t mBitmapPalette;
+    uint32_t mBitmapColors[256];
+    uint32_t mBitmapNumColors;
+
+protected:
+    virtual void SetActive(bool On);
+public:
+    cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
+    virtual ~cHdffOsd();
+    cBitmap *GetBitmap(int Area);
+    virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
+    virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
+    virtual void SaveRegion(int x1, int y1, int x2, int y2);
+    virtual void RestoreRegion(void);
+    virtual void DrawPixel(int x, int y, tColor Color);
+    virtual void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool ReplacePalette = false, bool Overlay = false);
+    virtual void DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width = 0, int Height = 0, int Alignment = taDefault);
+    virtual void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color);
+    virtual void DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants = 0);
+    virtual void DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type);
+    virtual void Flush(void);
+};
+
+cHdffOsd::cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level)
+:   cOsd(Left, Top, Level)
+{
+    double pixelAspect;
+    HDFF::tOsdConfig config;
+
+    //printf("cHdffOsd %d, %d, %d\n", Left, Top, Level);
+    mHdffCmdIf = pHdffCmdIf;
+    mLeft = Left;
+    mTop = Top;
+    shown = false;
+    mChanged = false;
+    mBitmapModified = false;
+    mBitmapPalette = InvalidHandle;
+    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);
+    for (int i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        mFontFaces[i].Name = "";
+        mFontFaces[i].Handle = InvalidHandle;
+    }
+    for (int i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        mFonts[i].hFontFace = InvalidHandle;
+        mFonts[i].Size = 0;
+        mFonts[i].Handle = InvalidHandle;
+    }
+}
+
+cHdffOsd::~cHdffOsd()
+{
+    //printf("~cHdffOsd %d %d\n", mLeft, mTop);
+    SetActive(false);
+
+    for (int i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        if (mFonts[i].Handle == InvalidHandle)
+            break;
+        mHdffCmdIf->CmdOsdDeleteFont(mFonts[i].Handle);
+    }
+    for (int i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        if (mFontFaces[i].Handle == InvalidHandle)
+            break;
+        mHdffCmdIf->CmdOsdDeleteFontFace(mFontFaces[i].Handle);
+    }
+
+    if (mBitmapPalette != InvalidHandle)
+        mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+}
+
+cBitmap * cHdffOsd::GetBitmap(int Area)
+{
+    //printf("GetBitmap %d\n", Area);
+    mChanged = true;
+    mBitmapModified = true;
+    return cOsd::GetBitmap(Area);
+}
+
+eOsdError cHdffOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
+{
+    eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
+    if (Result == oeOk)
+    {
+        for (int i = 0; i < NumAreas; i++)
+        {
+            if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8)
+                return oeBppNotSupported;
+        }
+    }
+    return Result;
+}
+
+eOsdError cHdffOsd::SetAreas(const tArea *Areas, int NumAreas)
+{
+    for (int i = 0; i < NumAreas; i++)
+    {
+        //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);
+    }
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    return cOsd::SetAreas(Areas, NumAreas);
+}
+
+void cHdffOsd::SetActive(bool On)
+{
+    if (On != Active())
+    {
+        cOsd::SetActive(On);
+        if (On)
+        {
+        }
+        else if (shown)
+        {
+            shown = false;
+        }
+    }
+}
+
+void cHdffOsd::SaveRegion(int x1, int y1, int x2, int y2)
+{
+    mHdffCmdIf->CmdOsdSaveRegion(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::RestoreRegion(void)
+{
+    mHdffCmdIf->CmdOsdRestoreRegion(mDisplay);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawPixel(int x, int y, tColor Color)
+{
+    //printf("DrawPixel\n");
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
+{
+    //printf("DrawBitmap %d %d %d\n", x, y, Overlay);
+    int i;
+    int numColors;
+    const tColor * colors = Bitmap.Colors(numColors);
+
+    for (i = 0; i < numColors; i++)
+    {
+        mBitmapColors[i] = colors[i];
+        if (ColorFg || ColorBg)
+        {
+            if (i == 0)
+                mBitmapColors[i] = ColorBg;
+            else if (i == 1)
+                mBitmapColors[i] = ColorFg;
+        }
+    }
+    if (mBitmapPalette == InvalidHandle)
+    {
+        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF::colorTypeClut8,
+                HDFF::colorFormatARGB, numColors, mBitmapColors);
+    }
+    else
+    {
+        mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
+                HDFF::colorFormatARGB, 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);
+#if 0
+    uint32_t * tmpBitmap = new uint32_t[Bitmap.Width() * Bitmap.Height()];
+    for (int ix = 0; ix < Bitmap.Width(); ix++)
+    {
+        for (int iy = 0; iy < Bitmap.Height(); iy++)
+        {
+            const tIndex * pixel = Bitmap.Data(ix, iy);
+            tColor color = Bitmap.Color(*pixel);
+            if (!Overlay || *pixel != 0)
+            {
+                if (ColorFg || ColorBg)
+                {
+                    if (*pixel == 0)
+                        color = ColorBg;
+                    else if (*pixel == 1)
+                        color = ColorFg;
+                }
+                tmpBitmap[Bitmap.Width() * iy + ix] = color;
+            }
+        }
+    }
+    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y,
+        (uint8_t *) tmpBitmap, Bitmap.Width(), Bitmap.Height(),
+        Bitmap.Width() * Bitmap.Height() * 4, HDFF::colorTypeARGB8888, InvalidHandle);
+    delete[] tmpBitmap;
+#endif
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
+{
+    int w = Font->Width(s);
+    int h = Font->Height();
+    int limit = 0;
+    int cw = Width ? Width : w;
+    int ch = Height ? Height : h;
+    int i;
+    int size = Font->Size();
+    tFontFace * pFontFace;
+    tFont * pFont;
+
+    if (ColorBg != clrTransparent)
+        mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, mLeft + x, mTop + y, cw, ch, ColorBg);
+
+    if (s == NULL)
+        return;
+
+    pFontFace = NULL;
+    for (i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        if (mFontFaces[i].Handle == InvalidHandle)
+            break;
+
+        if (strcmp(mFontFaces[i].Name, Font->FontName()) == 0)
+        {
+            pFontFace = &mFontFaces[i];
+            break;
+        }
+    }
+    if (pFontFace == NULL)
+    {
+        if (i < MAX_NUM_FONTFACES)
+        {
+            cString fontFileName = Font->FontName();
+            FILE * fp = fopen(fontFileName, "rb");
+            if (fp)
+            {
+                fseek(fp, 0, SEEK_END);
+                long fileSize = ftell(fp);
+                fseek(fp, 0, SEEK_SET);
+                if (fileSize > 0)
+                {
+                    uint8_t * buffer = new uint8_t[fileSize];
+                    if (buffer)
+                    {
+                        if (fread(buffer, fileSize, 1, fp) == 1)
+                        {
+                            mFontFaces[i].Handle = mHdffCmdIf->CmdOsdCreateFontFace(buffer, fileSize);
+                            if (mFontFaces[i].Handle != InvalidHandle)
+                            {
+                                mFontFaces[i].Name = Font->FontName();
+                                pFontFace = &mFontFaces[i];
+                            }
+                        }
+                        delete[] buffer;
+                    }
+                }
+                fclose(fp);
+            }
+        }
+    }
+    if (pFontFace == NULL)
+        return;
+
+    pFont = NULL;
+    for (i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        if (mFonts[i].Handle == InvalidHandle)
+            break;
+
+        if (mFonts[i].hFontFace == pFontFace->Handle
+          && mFonts[i].Size == size)
+        {
+            pFont = &mFonts[i];
+            break;
+        }
+    }
+    if (pFont == NULL)
+    {
+        if (i < MAX_NUM_FONTS)
+        {
+            mFonts[i].Handle = mHdffCmdIf->CmdOsdCreateFont(pFontFace->Handle, size);
+            if (mFonts[i].Handle != InvalidHandle)
+            {
+                mFonts[i].hFontFace = pFontFace->Handle;
+                mFonts[i].Size = size;
+                pFont = &mFonts[i];
+            }
+        }
+    }
+    if (pFont == NULL)
+        return;
+
+    mHdffCmdIf->CmdOsdSetDisplayClippingArea(mDisplay, true, mLeft + x, mTop + y, cw, ch);
+
+    if (Width || Height)
+    {
+        limit = x + cw;// - mLeft;
+        if (Width)
+        {
+            if ((Alignment & taLeft) != 0)
+                ;
+            else if ((Alignment & taRight) != 0)
+            {
+                if (w < Width)
+                    x += Width - w;
+            }
+            else
+            { // taCentered
+                if (w < Width)
+                    x += (Width - w) / 2;
+            }
+        }
+        if (Height)
+        {
+            if ((Alignment & taTop) != 0)
+                ;
+            else if ((Alignment & taBottom) != 0)
+            {
+                if (h < Height)
+                    y += Height - h;
+            }
+            else
+            { // taCentered
+                if (h < Height)
+                    y += (Height - h) / 2;
+            }
+        }
+    }
+    //x -= mLeft;
+    //y -= mTop;
+    {
+        uint16_t tmp[1000];
+        uint16_t len = 0;
+        while (*s && (len < (sizeof(tmp) - 1)))
+        {
+            int sl = Utf8CharLen(s);
+            uint sym = Utf8CharGet(s, sl);
+            s += sl;
+            tmp[len] = sym;
+            len++;
+        }
+        tmp[len] = 0;
+        mHdffCmdIf->CmdOsdDrawTextW(mDisplay, pFont->Handle, x + mLeft, y + mTop + h, tmp, ColorFg);
+    }
+    //mHdffCmdIf->CmdOsdDrawText(mDisplay, pFont->Handle, x + mLeft, y + mTop + h - 7, s, ColorFg);
+    mHdffCmdIf->CmdOsdSetDisplayClippingArea(mDisplay, false, 0, 0, 0, 0);
+    //Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
+{
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1, Color);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
+{
+    uint32_t flags;
+    int cx;
+    int cy;
+    int rx;
+    int ry;
+
+    switch (abs(Quadrants))
+    {
+        case 1:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterTopRight;
+            else
+                flags = HDFF::drawQuarterTopRightInverted;
+            cx = x1;
+            cy = y2;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 2:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterTopLeft;
+            else
+                flags = HDFF::drawQuarterTopLeftInverted;
+            cx = x2;
+            cy = y2;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 3:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterBottomLeft;
+            else
+                flags = HDFF::drawQuarterBottomLeftInverted;
+            cx = x2;
+            cy = y1;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 4:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterBottomRight;
+            else
+                flags = HDFF::drawQuarterBottomRightInverted;
+            cx = x1;
+            cy = y1;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 5:
+            flags = HDFF::drawHalfRight;
+            cx = x1;
+            cy = (y1 + y2) / 2;
+            rx = x2 - x1;
+            ry = (y2 - y1) / 2;
+            break;
+        case 6:
+            flags = HDFF::drawHalfTop;
+            cx = (x1 + x2) / 2;
+            cy = y2;
+            rx = (x2 - x1) / 2;
+            ry = y2 - y1;
+            break;
+        case 7:
+            flags = HDFF::drawHalfLeft;
+            cx = x2;
+            cy = (y1 + y2) / 2;
+            rx = x2 - x1;
+            ry = (y2 - y1) / 2;
+            break;
+        case 8:
+            flags = HDFF::drawHalfBottom;
+            cx = (x1 + x2) / 2;
+            cy = y1;
+            rx = (x2 - x1) / 2;
+            ry = y2 - y1;
+            break;
+        default:
+            flags = HDFF::drawFull;
+            cx = (x1 + x2) / 2;
+            cy = (y1 + y2) / 2;
+            rx = (x2 - x1) / 2;
+            ry = (y2 - y1) / 2;
+            break;
+    }
+    mHdffCmdIf->CmdOsdDrawEllipse(mDisplay, mLeft + cx, mTop + cy, rx, ry, Color, flags);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
+{
+    //printf("DrawSlope\n");
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::Flush(void)
+{
+    if (!Active())
+        return;
+
+    if (!mChanged)
+        return;
+
+    //printf("Flush\n");
+    if (mBitmapModified)
+    {
+        cBitmap *Bitmap;
+        for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++)
+        {
+            DrawBitmap(0, 0, *Bitmap);
+        }
+    }
+
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+
+    mChanged = false;
+    mBitmapModified = false;
+}
+
+
+class cHdffOsdRaw : public cOsd
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    int mDispWidth;
+    int mDispHeight;
+    bool shown;
+    uint32_t mDisplay;
+    uint32_t mBitmapPalette;
+    uint32_t mBitmapColors[256];
+    uint32_t mBitmapNumColors;
+
+protected:
+    virtual void SetActive(bool On);
+public:
+    cHdffOsdRaw(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
+    virtual ~cHdffOsdRaw();
+    virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
+    virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
+    virtual void Flush(void);
+};
+
+cHdffOsdRaw::cHdffOsdRaw(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level)
+:   cOsd(Left, Top, Level)
+{
+    double pixelAspect;
+
+    //printf("cHdffOsdRaw %d, %d, %d\n", Left, Top, Level);
+    mHdffCmdIf = pHdffCmdIf;
+    shown = false;
+    mBitmapPalette = InvalidHandle;
+
+    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)
+        mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+}
+
+void cHdffOsdRaw::SetActive(bool On)
+{
+    if (On != Active())
+    {
+        cOsd::SetActive(On);
+        if (On)
+        {
+        }
+        else if (shown)
+        {
+            shown = false;
+        }
+    }
+}
+
+eOsdError cHdffOsdRaw::CanHandleAreas(const tArea *Areas, int NumAreas)
+{
+    eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
+    if (Result == oeOk)
+    {
+        for (int i = 0; i < NumAreas; i++)
+        {
+            if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8
+                && (Areas[i].bpp != 32 || !gHdffSetup.TrueColorOsd))
+                return oeBppNotSupported;
+        }
+    }
+    return Result;
+}
+
+eOsdError cHdffOsdRaw::SetAreas(const tArea *Areas, int NumAreas)
+{
+    for (int i = 0; i < NumAreas; i++)
+    {
+        //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);
+    }
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    return cOsd::SetAreas(Areas, NumAreas);
+}
+
+void cHdffOsdRaw::Flush(void)
+{
+    if (!Active())
+        return;
+    //struct timeval start;
+    //struct timeval end;
+    //struct timezone timeZone;
+    //gettimeofday(&start, &timeZone);
+
+    bool render = false;
+    if (IsTrueColor())
+    {
+        LOCK_PIXMAPS;
+        while (cPixmapMemory *pm = RenderPixmaps())
+        {
+            int w = pm->ViewPort().Width();
+            int h = pm->ViewPort().Height();
+            int d = w * sizeof(tColor);
+            int Chunk = MAX_BITMAP_SIZE / w / sizeof(tColor);
+            if (Chunk > h)
+                Chunk = h;
+            for (int y = 0; y < h; y += Chunk)
+            {
+                 int hc = Chunk;
+                 if (y + hc > h)
+                     hc = h - y;
+                 mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
+                     Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y() + y,
+                     pm->Data() + y * d, w, hc, hc * d,
+                     HDFF::colorTypeARGB8888, InvalidHandle);
+            }
+            delete pm;
+            render = true;
+        }
+    }
+    else
+    {
+        uint8_t * buffer = new uint8_t[MAX_BITMAP_SIZE];
+        if (!buffer)
+            return;
+        cBitmap * bitmap;
+        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 (!shown)
+                {
+                    x2 = bitmap->Width() - 1;
+                    y2 = bitmap->Height() - 1;
+                }
+                // commit colors:
+                int numColors;
+                const tColor * colors = bitmap->Colors(numColors);
+                if (colors)
+                {
+                    for (int c = 0; c < numColors; c++)
+                        mBitmapColors[c] = colors[c];
+                    if (mBitmapPalette == InvalidHandle)
+                    {
+                        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF::colorTypeClut8,
+                            HDFF::colorFormatARGB, numColors, mBitmapColors);
+                    }
+                    else
+                    {
+                        mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
+                            HDFF::colorFormatARGB, 0, numColors, mBitmapColors);
+                    }
+                }
+                // commit modified data:
+                int width = x2 - x1 + 1;
+                int height = y2 - y1 + 1;
+                int chunk = MAX_BITMAP_SIZE / width;
+                if (chunk > height)
+                    chunk = height;
+                for (int y = 0; y < height; y += chunk)
+                {
+                    int hc = chunk;
+                    if (y + hc > height)
+                        hc = height - y;
+                    for (int r = 0; r < hc; r++)
+                        memcpy(buffer + r * width, bitmap->Data(x1, y1 + y + r), width);
+                    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
+                        Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1 + y,
+                        buffer, width, hc, hc * width,
+                        HDFF::colorTypeClut8, mBitmapPalette);
+                }
+                render = true;
+            }
+            bitmap->Clean();
+        }
+        delete[] buffer;
+    }
+    if (render)
+    {
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+        //gettimeofday(&end, &timeZone);
+        //int timeNeeded = end.tv_usec - start.tv_usec;
+        //timeNeeded += (end.tv_sec - start.tv_sec) * 1000000;
+        //printf("time = %d\n", timeNeeded);
+    }
+    shown = true;
+}
+
+
+
+
+cHdffOsdProvider::cHdffOsdProvider(HDFF::cHdffCmdIf * HdffCmdIf)
+{
+    mHdffCmdIf = HdffCmdIf;
+}
+
+cOsd *cHdffOsdProvider::CreateOsd(int Left, int Top, uint Level)
+{
+    //printf("CreateOsd %d %d %d\n", Left, Top, Level);
+    if (gHdffSetup.HighLevelOsd)
+        return new cHdffOsd(Left, Top, mHdffCmdIf, Level);
+    else
+        return new cHdffOsdRaw(Left, Top, mHdffCmdIf, Level);
+}
+
+bool cHdffOsdProvider::ProvidesTrueColor(void)
+{
+    return gHdffSetup.TrueColorOsd && !gHdffSetup.HighLevelOsd;
+}
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffosd.h vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffosd.h
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/hdffosd.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/hdffosd.h	2011-01-30 16:27:48.000000000 +0100
@@ -0,0 +1,26 @@
+/*
+ * hdffosd.h: Implementation of the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffosd.h 1.2 2011/01/30 15:27:48 kls Exp $
+ */
+
+#ifndef _HDFF_OSD_H_
+#define _HDFF_OSD_H_
+
+#include <vdr/osd.h>
+
+#include "hdffcmd.h"
+
+class cHdffOsdProvider : public cOsdProvider
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+public:
+    cHdffOsdProvider(HDFF::cHdffCmdIf * pHdffCmdIf);
+    virtual cOsd *CreateOsd(int Left, int Top, uint Level);
+    virtual bool ProvidesTrueColor(void);
+};
+
+#endif
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/setup.c vdr-1.7.18/PLUGINS/src/dvbhddevice/setup.c
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/setup.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/setup.c	2011-04-17 13:45:17.000000000 +0200
@@ -0,0 +1,252 @@
+/*
+ * setup.c: Setup for the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: setup.c 1.11 2011/04/17 11:45:17 kls Exp $
+ */
+
+#include "setup.h"
+#include "hdffcmd.h"
+
+const int kResolutions = 4;
+const int kTvFormats = 2;
+const int kVideoConversions = 6;
+const int kAnalogueVideos = 4;
+const int kAudioDownmixes = 5;
+const int kOsdSizes = 5;
+const int kRemoteProtocols = 3;
+
+const int kResolution1080i = 0;
+const int kResolution720p = 1;
+const int kResolution576p = 2;
+const int kResolution576i = 3;
+
+static const char * ResolutionItems[] =
+{
+    "1080i",
+    "720p",
+    "576p",
+    "576i",
+    NULL
+};
+
+static const char * TvFormatItems[] =
+{
+    "4/3",
+    "16/9",
+    NULL
+};
+
+static const char * VideoConversionItems[] =
+{
+    "Automatic",
+    "Letterbox 16/9",
+    "Letterbox 14/9",
+    "Pillarbox",
+    "CentreCutOut",
+    "Always 16/9",
+    NULL
+};
+
+static const char * AnalogueVideoItems[] =
+{
+    "Disabled",
+    "RGB",
+    "CVBS + YUV",
+    "YC (S-Video)",
+    NULL
+};
+
+static const char * AudioDownmixItems[] =
+{
+    "Disabled",
+    "Analogue only",
+    "Always",
+    "Automatic",
+    "HDMI only",
+    NULL
+};
+
+static const char * OsdSizeItems[] =
+{
+    "Follow resolution",
+    "1920x1080",
+    "1280x720",
+    "1024x576",
+    "720x576",
+    NULL
+};
+
+static const char * RemoteProtocolItems[] =
+{
+    "none",
+    "RC5",
+    "RC6",
+    NULL
+};
+
+cHdffSetup gHdffSetup;
+
+cHdffSetup::cHdffSetup(void)
+{
+    Resolution = kResolution1080i;
+    TvFormat = HDFF::tvFormat16by9;
+    VideoConversion = HDFF::videoConversionPillarbox;
+    AnalogueVideo = HDFF::videoOutCvbsYuv;
+    AudioDelay = 0;
+    AudioDownmix = HDFF::downmixAutomatic;
+    OsdSize = 0;
+    CecEnabled = 1;
+    RemoteProtocol = 1;
+    RemoteAddress = -1;
+    HighLevelOsd = 1;
+    TrueColorOsd = 1;
+}
+
+bool cHdffSetup::SetupParse(const char *Name, const char *Value)
+{
+    if      (strcmp(Name, "Resolution")      == 0) Resolution      = atoi(Value);
+    else if (strcmp(Name, "TvFormat")        == 0) TvFormat        = atoi(Value);
+    else if (strcmp(Name, "VideoConversion") == 0) VideoConversion = atoi(Value);
+    else if (strcmp(Name, "AnalogueVideo")   == 0) AnalogueVideo   = atoi(Value);
+    else if (strcmp(Name, "AudioDelay")      == 0) AudioDelay      = atoi(Value);
+    else if (strcmp(Name, "AudioDownmix")    == 0) AudioDownmix    = atoi(Value);
+    else if (strcmp(Name, "OsdSize")         == 0) OsdSize         = atoi(Value);
+    else if (strcmp(Name, "CecEnabled")      == 0) CecEnabled      = atoi(Value);
+    else if (strcmp(Name, "RemoteProtocol")  == 0) RemoteProtocol  = atoi(Value);
+    else if (strcmp(Name, "RemoteAddress")   == 0) RemoteAddress   = atoi(Value);
+    else if (strcmp(Name, "HighLevelOsd")    == 0) HighLevelOsd    = atoi(Value);
+    else if (strcmp(Name, "TrueColorOsd")    == 0) TrueColorOsd    = atoi(Value);
+    else return false;
+    return true;
+}
+
+void cHdffSetup::GetOsdSize(int &Width, int &Height, double &PixelAspect)
+{
+    if (OsdSize == 0) {
+        if (Resolution == kResolution1080i) {
+            Width = 1920;
+            Height = 1080;
+        }
+        else if (Resolution == kResolution720p) {
+            Width = 1280;
+            Height = 720;
+        }
+        else {
+            Width = 720;
+            Height = 576;
+        }
+        if (TvFormat == HDFF::tvFormat16by9)
+            PixelAspect = 16.0 / 9.0;
+        else
+            PixelAspect = 4.0 / 3.0;
+    }
+    else if (OsdSize == 1) {
+        Width = 1920;
+        Height = 1080;
+        PixelAspect = 16.0 / 9.0;
+    }
+    else if (OsdSize == 2) {
+        Width = 1280;
+        Height = 720;
+        PixelAspect = 16.0 / 9.0;
+    }
+    else if (OsdSize == 3) {
+        Width = 1024;
+        Height = 576;
+        PixelAspect = 16.0 / 9.0;
+    }
+    else {
+        Width = 720;
+        Height = 576;
+        PixelAspect = 4.0 / 3.0;
+    }
+  PixelAspect /= double(Width) / Height;
+}
+
+HDFF::eHdmiVideoMode cHdffSetup::GetVideoMode(void)
+{
+    switch (Resolution)
+    {
+        case kResolution1080i:
+        default:
+            return HDFF::videoMode1080i50;
+        case kResolution720p:
+            return HDFF::videoMode720p50;
+        case kResolution576p:
+            return HDFF::videoMode576p50;
+        case kResolution576i:
+            return HDFF::videoMode576i50;
+    }
+}
+
+cHdffSetupPage::cHdffSetupPage(HDFF::cHdffCmdIf * pHdffCmdIf)
+{
+    mHdffCmdIf = pHdffCmdIf;
+    mNewHdffSetup = gHdffSetup;
+
+    Add(new cMenuEditStraItem("Resolution", &mNewHdffSetup.Resolution, kResolutions, ResolutionItems));
+    Add(new cMenuEditStraItem("TV format", &mNewHdffSetup.TvFormat, kTvFormats, TvFormatItems));
+    Add(new cMenuEditStraItem("Video Conversion", &mNewHdffSetup.VideoConversion, kVideoConversions, VideoConversionItems));
+    Add(new cMenuEditStraItem("Analogue Video", &mNewHdffSetup.AnalogueVideo, kAnalogueVideos, AnalogueVideoItems));
+    Add(new cMenuEditIntItem("Audio Delay (ms)", &mNewHdffSetup.AudioDelay, 0, 500));
+    Add(new cMenuEditStraItem("Audio Downmix", &mNewHdffSetup.AudioDownmix, kAudioDownmixes, AudioDownmixItems));
+    Add(new cMenuEditStraItem("Osd Size", &mNewHdffSetup.OsdSize, kOsdSizes, OsdSizeItems));
+    Add(new cMenuEditBoolItem("HDMI CEC", &mNewHdffSetup.CecEnabled));
+    Add(new cMenuEditStraItem("Remote Control Protocol", &mNewHdffSetup.RemoteProtocol, kRemoteProtocols, RemoteProtocolItems));
+    Add(new cMenuEditIntItem("Remote Control Address", &mNewHdffSetup.RemoteAddress, -1, 31));
+    Add(new cMenuEditBoolItem("High Level OSD", &mNewHdffSetup.HighLevelOsd));
+    Add(new cMenuEditBoolItem("Allow True Color OSD", &mNewHdffSetup.TrueColorOsd));
+}
+
+cHdffSetupPage::~cHdffSetupPage(void)
+{
+}
+
+void cHdffSetupPage::Store(void)
+{
+    SetupStore("Resolution", mNewHdffSetup.Resolution);
+    SetupStore("TvFormat", mNewHdffSetup.TvFormat);
+    SetupStore("VideoConversion", mNewHdffSetup.VideoConversion);
+    SetupStore("AnalogueVideo", mNewHdffSetup.AnalogueVideo);
+    SetupStore("AudioDelay", mNewHdffSetup.AudioDelay);
+    SetupStore("AudioDownmix", mNewHdffSetup.AudioDownmix);
+    SetupStore("OsdSize", mNewHdffSetup.OsdSize);
+    SetupStore("CecEnabled", mNewHdffSetup.CecEnabled);
+    SetupStore("RemoteProtocol", mNewHdffSetup.RemoteProtocol);
+    SetupStore("RemoteAddress", mNewHdffSetup.RemoteAddress);
+    SetupStore("HighLevelOsd", mNewHdffSetup.HighLevelOsd);
+    SetupStore("TrueColorOsd", mNewHdffSetup.TrueColorOsd);
+
+    if (mHdffCmdIf)
+    {
+        if (mNewHdffSetup.Resolution != gHdffSetup.Resolution)
+        {
+            mHdffCmdIf->CmdHdmiSetVideoMode(mNewHdffSetup.GetVideoMode());
+        }
+        HDFF::tVideoFormat videoFormat;
+        HDFF::tHdmiConfig hdmiConfig;
+
+        videoFormat.AutomaticEnabled = true;
+        videoFormat.AfdEnabled = true;
+        videoFormat.TvFormat = (HDFF::eTvFormat) mNewHdffSetup.TvFormat;
+        videoFormat.VideoConversion = (HDFF::eVideoConversion) mNewHdffSetup.VideoConversion;
+        mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
+
+        mHdffCmdIf->CmdAvSetAudioDelay(mNewHdffSetup.AudioDelay);
+        mHdffCmdIf->CmdAvSetAudioDownmix((HDFF::eDownmixMode) mNewHdffSetup.AudioDownmix);
+
+        mHdffCmdIf->CmdMuxSetVideoOut((HDFF::eVideoOut) mNewHdffSetup.AnalogueVideo);
+
+        hdmiConfig.TransmitAudio = true;
+        hdmiConfig.ForceDviMode = false;
+        hdmiConfig.CecEnabled = mNewHdffSetup.CecEnabled;
+        mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
+
+        mHdffCmdIf->CmdRemoteSetProtocol((HDFF::eRemoteProtocol) mNewHdffSetup.RemoteProtocol);
+        mHdffCmdIf->CmdRemoteSetAddressFilter(mNewHdffSetup.RemoteAddress >= 0, mNewHdffSetup.RemoteAddress);
+    }
+
+    gHdffSetup = mNewHdffSetup;
+}
diff -ruN vdr-1.7.17/PLUGINS/src/dvbhddevice/setup.h vdr-1.7.18/PLUGINS/src/dvbhddevice/setup.h
--- vdr-1.7.17/PLUGINS/src/dvbhddevice/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbhddevice/setup.h	2011-04-17 13:20:22.000000000 +0200
@@ -0,0 +1,53 @@
+/*
+ * setup.h: Setup for the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: setup.h 1.8 2011/04/17 11:20:22 kls Exp $
+ */
+
+#ifndef _HDFF_SETUP_H_
+#define _HDFF_SETUP_H_
+
+#include <vdr/plugin.h>
+#include "hdffcmd.h"
+
+struct cHdffSetup
+{
+    cHdffSetup(void);
+    bool SetupParse(const char * Name, const char * Value);
+    void GetOsdSize(int &Width, int &Height, double &PixelAspect);
+    HDFF::eHdmiVideoMode GetVideoMode(void);
+
+    int Resolution;
+    int TvFormat;
+    int VideoConversion;
+    int AnalogueVideo;
+    int AudioDelay;
+    int AudioDownmix;
+    int OsdSize;
+    int CecEnabled;
+    int RemoteProtocol;
+    int RemoteAddress;
+
+    int HighLevelOsd;
+    int TrueColorOsd;
+};
+
+extern cHdffSetup gHdffSetup;
+
+class cHdffSetupPage : public cMenuSetupPage
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    cHdffSetup mNewHdffSetup;
+
+protected:
+    virtual void Store(void);
+
+public:
+    cHdffSetupPage(HDFF::cHdffCmdIf * pHdffCmdIf);
+    virtual ~cHdffSetupPage(void);
+};
+
+#endif
diff -ruN vdr-1.7.17/PLUGINS/src/dvbsddevice/HISTORY vdr-1.7.18/PLUGINS/src/dvbsddevice/HISTORY
--- vdr-1.7.17/PLUGINS/src/dvbsddevice/HISTORY	2010-01-30 12:03:08.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbsddevice/HISTORY	2011-04-17 14:57:29.000000000 +0200
@@ -15,3 +15,7 @@
 
 - The PCR pid is now recorded for channels where this is different from the
   video PID.
+
+2011-04-17: Version 0.0.4
+
+- Removed an obsolete local variable in dvbsdffosd.c (thanks to Paul Menzel).
diff -ruN vdr-1.7.17/PLUGINS/src/dvbsddevice/dvbsddevice.c vdr-1.7.18/PLUGINS/src/dvbsddevice/dvbsddevice.c
--- vdr-1.7.17/PLUGINS/src/dvbsddevice/dvbsddevice.c	2010-01-30 11:05:42.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/dvbsddevice/dvbsddevice.c	2011-04-17 14:55:43.000000000 +0200
@@ -3,13 +3,13 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: dvbsddevice.c 1.3 2010/01/30 10:05:42 kls Exp $
+ * $Id: dvbsddevice.c 1.4 2011/04/17 12:55:43 kls Exp $
  */
 
 #include <vdr/plugin.h>
 #include "dvbsdffdevice.h"
 
-static const char *VERSION        = "0.0.3";
+static const char *VERSION        = "0.0.4";
 static const char *DESCRIPTION    = "SD Full Featured DVB device";
 
 class cPluginDvbsddevice : public cPlugin {
diff -ruN vdr-1.7.17/PLUGINS/src/dvbsddevice/dvbsdffosd.c vdr-1.7.18/PLUGINS/src/dvbsddevice/dvbsdffosd.c
--- vdr-1.7.17/PLUGINS/src/dvbsddevice/dvbsdffosd.c	2010-09-19 14:43:45.000000000 +0200
+++ vdr-1.7.18/PLUGINS/src/dvbsddevice/dvbsdffosd.c	2011-04-17 14:55:09.000000000 +0200
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: dvbsdffosd.c 2.2 2010/09/19 12:43:45 kls Exp $
+ * $Id: dvbsdffosd.c 2.3 2011/04/17 12:55:09 kls Exp $
  */
 
 #include "dvbsdffosd.h"
@@ -73,8 +73,7 @@
            Flush();
         }
      else if (shown) {
-        cBitmap *Bitmap;
-        for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
+        for (int i = 0; GetBitmap(i); i++) {
             Cmd(OSD_SetWindow, 0, i + 1);
             Cmd(OSD_Close);
             }
@@ -108,8 +107,7 @@
 eOsdError cDvbSdFfOsd::SetAreas(const tArea *Areas, int NumAreas)
 {
   if (shown) {
-     cBitmap *Bitmap;
-     for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
+     for (int i = 0; GetBitmap(i); i++) {
          Cmd(OSD_SetWindow, 0, i + 1);
          Cmd(OSD_Close);
          }
diff -ruN vdr-1.7.17/PLUGINS/src/osddemo/HISTORY vdr-1.7.18/PLUGINS/src/osddemo/HISTORY
--- vdr-1.7.17/PLUGINS/src/osddemo/HISTORY	2011-02-20 16:06:52.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/osddemo/HISTORY	2011-04-17 15:05:01.000000000 +0200
@@ -25,3 +25,12 @@
 2011-02-20: Version 0.2.0
 
 - Added support for TrueColor OSD.
+
+2011-03-28: Version 0.2.1
+
+- Added Cancel(3) to ~cTrueColorDemo() (thanks to Reinhard Nissl).
+- Added a missing font deletion in cTrueColorDemo::Action() (thanks to Reinhard Nissl).
+
+2011-04-17: Version 0.2.2
+
+- Fixed a possible NULL pointer dereference in osddemo.c (reported by Paul Menzel).
diff -ruN vdr-1.7.17/PLUGINS/src/osddemo/osddemo.c vdr-1.7.18/PLUGINS/src/osddemo/osddemo.c
--- vdr-1.7.17/PLUGINS/src/osddemo/osddemo.c	2011-02-26 13:08:13.000000000 +0100
+++ vdr-1.7.18/PLUGINS/src/osddemo/osddemo.c	2011-04-17 15:05:13.000000000 +0200
@@ -3,13 +3,13 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: osddemo.c 2.3 2011/02/26 12:08:13 kls Exp $
+ * $Id: osddemo.c 2.5 2011/04/17 13:05:13 kls Exp $
  */
 
 #include <vdr/osd.h>
 #include <vdr/plugin.h>
 
-static const char *VERSION        = "0.2.0";
+static const char *VERSION        = "0.2.2";
 static const char *DESCRIPTION    = "Demo of arbitrary OSD setup";
 static const char *MAINMENUENTRY  = "Osd Demo";
 
@@ -103,6 +103,7 @@
 
 cTrueColorDemo::~cTrueColorDemo()
 {
+  Cancel(3);
   delete osd;
 }
 
@@ -262,12 +263,13 @@
              case 3: {
                        if (cFont *Font = cFont::CreateFont(DefaultFontOsd, osd->Height() / 10)) {
                           NextPixmap = CreateTextPixmap("Millions of colors", Line, 1, clrYellow, clrTransparent, Font);
+                          delete Font;
                           if (NextPixmap) {
                              FadeInPixmap = NextPixmap;
+                             Start = cTimeMs::Now();
+                             StartLine = Line;
+                             Line += NextPixmap->DrawPort().Height();
                              }
-                          Start = cTimeMs::Now();
-                          StartLine = Line;
-                          Line += NextPixmap->DrawPort().Height();
                           }
                        State++;
                      }
diff -ruN vdr-1.7.17/PLUGINS.html vdr-1.7.18/PLUGINS.html
--- vdr-1.7.17/PLUGINS.html	2010-02-06 15:20:36.000000000 +0100
+++ vdr-1.7.18/PLUGINS.html	2011-03-27 15:06:31.000000000 +0200
@@ -1523,8 +1523,9 @@
 video stream (this may be different from the primary device in case of <i>Transfer
 Mode</i>).
 <p>
-If the <tt>cReceiver</tt> isn't needed any more, it may simply be <i>deleted</i>
-and will automatically detach itself from the <tt>cDevice</tt>.
+<div class="modified">
+The <tt>cReceiver</tt> must be detached from its device before it is deleted.
+</div modified>
 
 <hr><h2><a name="Filters">Filters</a></h2>
 
diff -ruN vdr-1.7.17/config.h vdr-1.7.18/config.h
--- vdr-1.7.17/config.h	2010-10-24 13:22:35.000000000 +0200
+++ vdr-1.7.18/config.h	2011-03-13 13:02:31.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.29 2010/10/24 11:22:35 kls Exp $
+ * $Id: config.h 2.30 2011/03/13 12:02:31 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -22,13 +22,13 @@
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.7.17"
-#define VDRVERSNUM   10717  // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION  "1.7.18"
+#define VDRVERSNUM   10718  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
 
-#define APIVERSION  "1.7.17"
-#define APIVERSNUM   10717  // Version * 10000 + Major * 100 + Minor
+#define APIVERSION  "1.7.18"
+#define APIVERSNUM   10718  // Version * 10000 + Major * 100 + Minor
 
 // When loading plugins, VDR searches them by their APIVERSION, which
 // may be smaller than VDRVERSION in case there have been no changes to
diff -ruN vdr-1.7.17/device.h vdr-1.7.18/device.h
--- vdr-1.7.17/device.h	2010-10-24 14:11:16.000000000 +0200
+++ vdr-1.7.18/device.h	2011-03-21 18:58:41.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.23 2010/10/24 12:11:16 kls Exp $
+ * $Id: device.h 2.24 2011/03/21 17:58:41 kls Exp $
  */
 
 #ifndef __DEVICE_H
@@ -405,10 +405,9 @@
          ///< (default is PAL).
   virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect);
          ///< Returns the With, Height and VideoAspect ratio of the currently
-         ///< displayed video material. The data returned by this function is
-         ///< only used for informational purposes (if any). Width and
-         ///< Height are given in pixel (e.g. 720x576) and VideoAspect is
-         ///< e.g. 1.33333 for a 4:3 broadcast, or 1.77778 for 16:9.
+         ///< displayed video material. Width and Height are given in pixel
+         ///< (e.g. 720x576) and VideoAspect is e.g. 1.33333 for a 4:3 broadcast,
+         ///< or 1.77778 for 16:9.
          ///< The default implementation returns 0 for Width and Height
          ///< and 1.0 for VideoAspect.
   virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect);
diff -ruN vdr-1.7.17/dvbspu.h vdr-1.7.18/dvbspu.h
--- vdr-1.7.17/dvbspu.h	2009-12-13 13:07:00.000000000 +0100
+++ vdr-1.7.18/dvbspu.h	2011-03-27 16:50:48.000000000 +0200
@@ -8,7 +8,7 @@
  *
  * parts of this file are derived from the OMS program.
  *
- * $Id: dvbspu.h 2.4 2009/12/13 12:07:00 kls Exp $
+ * $Id: dvbspu.h 2.5 2011/03/27 14:50:48 kls Exp $
  */
 
 #ifndef __DVBSPU_H
@@ -32,6 +32,9 @@
     int x1, y1;
     int x2, y2;
 
+    sDvbSpuRect(void) {
+        x1 = y1 = x2 = y2 = 0;
+    };
     int width() const {
         return x2 - x1 + 1;
     };
diff -ruN vdr-1.7.17/dvbsubtitle.c vdr-1.7.18/dvbsubtitle.c
--- vdr-1.7.17/dvbsubtitle.c	2011-03-12 16:13:03.000000000 +0100
+++ vdr-1.7.18/dvbsubtitle.c	2011-04-17 16:34:05.000000000 +0200
@@ -7,10 +7,13 @@
  * 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.11 2011/03/12 15:13:03 kls Exp $
+ * $Id: dvbsubtitle.c 2.17 2011/04/17 14:34:05 kls Exp $
  */
 
+
 #include "dvbsubtitle.h"
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
 #include "device.h"
 
 #define PAGE_COMPOSITION_SEGMENT   0x10
@@ -420,7 +423,7 @@
   int PageId(void) { return pageId; }
   int Version(void) { return version; }
   int State(void) { return state; }
-  tArea *GetAreas(double Factor);
+  tArea *GetAreas(double FactorX, double FactorY);
   cSubtitleClut *GetClutById(int ClutId, bool New = false);
   cSubtitleObject *GetObjectById(int ObjectId);
   cSubtitleRegion *GetRegionById(int RegionId, bool New = false);
@@ -446,16 +449,16 @@
 {
 }
 
-tArea *cDvbSubtitlePage::GetAreas(double Factor)
+tArea *cDvbSubtitlePage::GetAreas(double FactorX, double FactorY)
 {
   if (regions.Count() > 0) {
      tArea *Areas = new tArea[regions.Count()];
      tArea *a = Areas;
      for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) {
-         a->x1 = int(round(Factor * sr->HorizontalAddress()));
-         a->y1 = int(round(Factor * sr->VerticalAddress()));
-         a->x2 = int(round(Factor * (sr->HorizontalAddress() + sr->Width() - 1)));
-         a->y2 = int(round(Factor * (sr->VerticalAddress() + sr->Height() - 1)));
+         a->x1 = int(round(FactorX * sr->HorizontalAddress()));
+         a->y1 = int(round(FactorY * sr->VerticalAddress()));
+         a->x2 = int(round(FactorX * (sr->HorizontalAddress() + sr->Width() - 1)));
+         a->y2 = int(round(FactorY * (sr->VerticalAddress() + sr->Height() - 1)));
          a->bpp = sr->Bpp();
          while ((a->Width() & 3) != 0)
                a->x2++; // aligns width to a multiple of 4, so 2, 4 and 8 bpp will work
@@ -616,10 +619,11 @@
   int timeout;
   tArea *areas;
   int numAreas;
-  double osdFactor;
+  double osdFactorX;
+  double osdFactorY;
   cVector<cBitmap *> bitmaps;
 public:
-  cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactor);
+  cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY);
   ~cDvbSubtitleBitmaps();
   int64_t Pts(void) { return pts; }
   int Timeout(void) { return timeout; }
@@ -627,13 +631,14 @@
   void Draw(cOsd *Osd);
   };
 
-cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactor)
+cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY)
 {
   pts = Pts;
   timeout = Timeout;
   areas = Areas;
   numAreas = NumAreas;
-  osdFactor = OsdFactor;
+  osdFactorX = OsdFactorX;
+  osdFactorY = OsdFactorY;
 }
 
 cDvbSubtitleBitmaps::~cDvbSubtitleBitmaps()
@@ -650,12 +655,27 @@
 
 void cDvbSubtitleBitmaps::Draw(cOsd *Osd)
 {
+  bool Scale = !(DoubleEqual(osdFactorX, 1.0) && DoubleEqual(osdFactorY, 1.0));
+  bool AntiAlias = true;
+  if (Scale && osdFactorX > 1.0 || osdFactorY > 1.0) {
+     // Upscaling requires 8bpp:
+     int Bpp[MAXOSDAREAS];
+     for (int i = 0; i < numAreas; i++) {
+         Bpp[i] = areas[i].bpp;
+         areas[i].bpp = 8;
+         }
+     if (Osd->CanHandleAreas(areas, numAreas) != oeOk) {
+        for (int i = 0; i < numAreas; i++)
+            Bpp[i] = areas[i].bpp = Bpp[i];
+        AntiAlias = false;
+        }
+     }
   if (Osd->SetAreas(areas, numAreas) == oeOk) {
      for (int i = 0; i < bitmaps.Size(); i++) {
          cBitmap *b = bitmaps[i];
-         if (osdFactor != 1.0)
-            b = b->Scale(osdFactor, osdFactor);
-         Osd->DrawBitmap(int(round(b->X0() * osdFactor)), int(round(b->Y0() * osdFactor)), *b);
+         if (Scale)
+            b = b->Scaled(osdFactorX, osdFactorY, AntiAlias);
+         Osd->DrawBitmap(int(round(b->X0() * osdFactorX)), int(round(b->Y0() * osdFactorY)), *b);
          if (b != bitmaps[i])
             delete b;
          }
@@ -733,7 +753,7 @@
      if (Length > PayloadOffset + SubstreamHeaderLength) {
         int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
         if (pts)
-           dbgconverter("Converter PTS: %lld\n", pts);
+           dbgconverter("Converter PTS: %"PRId64"\n", pts);
         const uchar *data = Data + PayloadOffset + SubstreamHeaderLength; // skip substream header
         int length = Length - PayloadOffset - SubstreamHeaderLength; // skip substream header
         if (ResetSubtitleAssembler)
@@ -769,7 +789,7 @@
      if (Length > PayloadOffset) {
         int64_t pts = PesGetPts(Data);
         if (pts)
-           dbgconverter("Converter PTS: %lld\n", pts);
+           dbgconverter("Converter PTS: %"PRId64"\n", pts);
         const uchar *data = Data + PayloadOffset;
         int length = Length - PayloadOffset;
         if (length > 3) {
@@ -828,7 +848,7 @@
                     if (AssertOsd()) {
                        sb->Draw(osd);
                        Timeout.Set(sb->Timeout() * 1000);
-                       dbgconverter("PTS: %lld  STC: %lld (%lld) timeout: %d\n", sb->Pts(), cDevice::PrimaryDevice()->GetSTC(), Delta, sb->Timeout());
+                       dbgconverter("PTS: %"PRId64"  STC: %"PRId64" (%"PRId64") timeout: %d\n", sb->Pts(), cDevice::PrimaryDevice()->GetSTC(), Delta, sb->Timeout());
                        }
                     bitmaps->Del(sb);
                     }
@@ -862,27 +882,27 @@
 
 void cDvbSubtitleConverter::SetOsdData(void)
 {
-  int OsdWidth;
-  int OsdHeight;
+  int OsdWidth, OsdHeight;
   double OsdAspect;
+  int VideoWidth, VideoHeight;
+  double VideoAspect;
   cDevice::PrimaryDevice()->GetOsdSize(OsdWidth, OsdHeight, OsdAspect);
-  osdDeltaX = osdDeltaY = 0;
-  osdFactor = 1.0;
-  double fw = double(OsdWidth) / displayWidth;
-  double fh = double(OsdHeight) / displayHeight;
-  if (fw >= fh) {
-     osdFactor = fh;
-     osdDeltaX = (OsdWidth - displayWidth * osdFactor) / 2;
+  cDevice::PrimaryDevice()->GetVideoSize(VideoWidth, VideoHeight, VideoAspect);
+  if (OsdWidth == displayWidth && OsdHeight == displayHeight) {
+     osdFactorX = osdFactorY = 1.0;
+     osdDeltaX = osdDeltaY = 0;
      }
   else {
-     osdFactor = fw;
-     osdDeltaY = (OsdHeight - displayHeight * osdFactor) / 2;
+     osdFactorX = VideoAspect * OsdHeight / displayWidth;
+     osdFactorY = double(OsdHeight) / displayHeight;
+     osdDeltaX = (OsdWidth - displayWidth * osdFactorX) / 2;
+     osdDeltaY = (OsdHeight - displayHeight * osdFactorY) / 2;
      }
 }
 
 bool cDvbSubtitleConverter::AssertOsd(void)
 {
-  return osd || (osd = cOsdProvider::NewOsd(int(round(osdFactor * windowHorizontalOffset + osdDeltaX)), int(round(osdFactor * windowVerticalOffset + osdDeltaY)) + Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES));
+  return osd || (osd = cOsdProvider::NewOsd(int(round(osdFactorX * windowHorizontalOffset + osdDeltaX)), int(round(osdFactorY * windowVerticalOffset + osdDeltaY)) + Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES));
 }
 
 int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t Pts)
@@ -918,7 +938,7 @@
             page->SetTimeout(Data[6]);
             page->SetState((Data[6 + 1] & 0x0C) >> 2);
             page->regions.Clear();
-            dbgpages("Update page id %d version %d pts %lld timeout %d state %d\n", pageId, page->Version(), page->Pts(), page->Timeout(), page->State());
+            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]);
@@ -1079,7 +1099,7 @@
 {
   if (!AssertOsd())
      return;
-  tArea *Areas = Page->GetAreas(osdFactor);
+  tArea *Areas = Page->GetAreas(osdFactorX, osdFactorY);
   int NumAreas = Page->regions.Count();
   int Bpp = 8;
   bool Reduced = false;
@@ -1116,7 +1136,7 @@
             }
          }
      }
-  cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas, osdFactor);
+  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)) {
       int posX = sr->HorizontalAddress();
diff -ruN vdr-1.7.17/dvbsubtitle.h vdr-1.7.18/dvbsubtitle.h
--- vdr-1.7.17/dvbsubtitle.h	2011-03-12 15:03:42.000000000 +0100
+++ vdr-1.7.18/dvbsubtitle.h	2011-03-20 14:34:23.000000000 +0100
@@ -6,7 +6,7 @@
  *
  * Original author: Marco Schlüßler <marco@lordzodiac.de>
  *
- * $Id: dvbsubtitle.h 2.5 2011/03/12 14:03:42 kls Exp $
+ * $Id: dvbsubtitle.h 2.6 2011/03/20 13:34:23 kls Exp $
  */
 
 #ifndef __DVBSUBTITLE_H
@@ -35,7 +35,8 @@
   int windowHeight;
   int osdDeltaX;
   int osdDeltaY;
-  double osdFactor;
+  double osdFactorX;
+  double osdFactorY;
   cList<cDvbSubtitlePage> *pages;
   cList<cDvbSubtitleBitmaps> *bitmaps;
   tColor yuv2rgb(int Y, int Cb, int Cr);
diff -ruN vdr-1.7.17/font.c vdr-1.7.18/font.c
--- vdr-1.7.17/font.c	2011-02-26 13:09:18.000000000 +0100
+++ vdr-1.7.18/font.c	2011-03-28 18:29:51.000000000 +0200
@@ -6,7 +6,7 @@
  *
  * BiDi support by Osama Alrawab <alrawab@hotmail.com> @2008 Tripoli-Libya.
  *
- * $Id: font.c 2.7 2011/02/26 12:09:18 kls Exp $
+ * $Id: font.c 2.8 2011/03/28 16:29:51 kls Exp $
  */
 
 #include "font.h"
@@ -520,7 +520,7 @@
   bool ok = fribidi_log2vis(Logical, RtlLen, &Base, Visual, NULL, NULL, NULL);
   if (ok) {
      fribidi_remove_bidi_marks(Visual, RtlLen, NULL, NULL, NULL);
-     Rtl = MALLOC(char, RtlLen * 4);
+     Rtl = MALLOC(char, RtlLen * 4 + 1);
      fribidi_unicode_to_charset(fribidiCharset, Visual, RtlLen, Rtl);
      }
   free(Logical);
diff -ruN vdr-1.7.17/osd.c vdr-1.7.18/osd.c
--- vdr-1.7.17/osd.c	2011-03-12 16:32:33.000000000 +0100
+++ vdr-1.7.18/osd.c	2011-04-17 16:25:07.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.c 2.17 2011/03/12 15:32:33 kls Exp $
+ * $Id: osd.c 2.21 2011/04/17 14:25:07 kls Exp $
  */
 
 #include "osd.h"
@@ -503,8 +503,7 @@
 {
   x -= x0;
   y -= y0;
-  if (0 <= x && x < width && 0 <= y && y < height)
-     SetIndex(x, y, Index(Color));
+  SetIndex(x, y, Index(Color));
 }
 
 void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
@@ -807,7 +806,7 @@
      }
 }
 
-cBitmap *cBitmap::Scale(double FactorX, double FactorY)
+cBitmap *cBitmap::Scaled(double FactorX, double FactorY, bool AntiAlias)
 {
   // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf
   // by deltener@mindtremors.com
@@ -815,19 +814,42 @@
   b->Replace(*this); // copy palette
   int RatioX = (Width() << 16) / b->Width();
   int RatioY = (Height() << 16) / b->Height();
-  tIndex *DestRow = b->bitmap;
-  int SourceY = 0;
-  for (int y = 0; y < b->Height(); y++) {
-      int SourceX = 0;
-      tIndex *SourceRow = bitmap + (SourceY >> 16) * Width();
-      tIndex *Dest = DestRow;
-      for (int x = 0; x < b->Width(); x++) {
-          *Dest++ = SourceRow[SourceX >> 16];
-          SourceX += RatioX;
-          }
-      SourceY += RatioY;
-      DestRow += b->Width();
-      }
+  if (!AntiAlias || FactorX <= 1.0 && FactorY <= 1.0) {
+     // Downscaling - no anti-aliasing:
+     tIndex *DestRow = b->bitmap;
+     int SourceY = 0;
+     for (int y = 0; y < b->Height(); y++) {
+         int SourceX = 0;
+         tIndex *SourceRow = bitmap + (SourceY >> 16) * Width();
+         tIndex *Dest = DestRow;
+         for (int x = 0; x < b->Width(); x++) {
+             *Dest++ = SourceRow[SourceX >> 16];
+             SourceX += RatioX;
+             }
+         SourceY += RatioY;
+         DestRow += b->Width();
+         }
+     }
+  else {
+     // Upscaling - anti-aliasing:
+     b->SetBpp(8);
+     int SourceY = 0;
+     for (int y = 0; y < b->Height() - 1; y++) {
+         int SourceX = 0;
+         int sy = SourceY >> 16;
+         uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF);
+         for (int x = 0; x < b->Width() - 1; x++) {
+             int sx = SourceX >> 16;
+             uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF);
+             tColor c1 = b->Blend(GetColor(sx, sy),     GetColor(sx + 1, sy),     BlendX);
+             tColor c2 = b->Blend(GetColor(sx, sy + 1), GetColor(sx + 1, sy + 1), BlendX);
+             tColor c3 = b->Blend(c1, c2, BlendY);
+             b->DrawPixel(x + X0(), y + Y0(), c3);
+             SourceX += RatioX;
+             }
+         SourceY += RatioY;
+         }
+     }
   return b;
 }
 
@@ -1394,6 +1416,7 @@
           case -2: DrawRectangle(cRect(x1,     cy - y, cx - x - x1 + 1, 1), Color); break;
           case -3: DrawRectangle(cRect(x1,     cy + y, cx - x - x1 + 1, 1), Color); break;
           case -4: DrawRectangle(cRect(cx + x, cy + y, x2 - x + 1,      1), Color); break;
+          default: ;
           }
         x++;
         StoppingX += TwoBSquare;
diff -ruN vdr-1.7.17/osd.h vdr-1.7.18/osd.h
--- vdr-1.7.17/osd.h	2011-03-12 17:06:48.000000000 +0100
+++ vdr-1.7.18/osd.h	2011-04-17 16:24:32.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.h 2.11 2011/03/12 16:06:48 kls Exp $
+ * $Id: osd.h 2.13 2011/04/17 14:24:32 kls Exp $
  */
 
 #ifndef __OSD_H
@@ -273,8 +273,11 @@
        ///< the 2^NewBpp most frequently used colors as defined in the current palette.
        ///< If NewBpp is not smaller than the bitmap's current color depth,
        ///< or if it is not one of 4bpp or 2bpp, nothing happens.
-  cBitmap *Scale(double FactorX, double FactorY);
+  cBitmap *Scaled(double FactorX, double FactorY, bool AntiAlias = false);
        ///< Creates a copy of this bitmap, scaled by the given factors.
+       ///< If AntiAlias is true and either of the factors is greater than 1.0,
+       ///< anti-aliasing is applied. This will also set the color depth of the
+       ///< returned bitmap to 8bpp.
        ///< The caller must delete the returned bitmap once it is no longer used.
   };
 
diff -ruN vdr-1.7.17/pat.c vdr-1.7.18/pat.c
--- vdr-1.7.17/pat.c	2010-11-07 14:47:16.000000000 +0100
+++ vdr-1.7.18/pat.c	2011-04-17 15:45:25.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: pat.c 2.15 2010/11/07 13:47:16 kls Exp $
+ * $Id: pat.c 2.16 2011/04/17 13:45:25 kls Exp $
  */
 
 #include "pat.h"
@@ -456,7 +456,37 @@
                          }
                       }
                       break;
-              case 0x80 ... 0xFF: // STREAMTYPE_USER_PRIVATE
+              case 0x80: // STREAMTYPE_USER_PRIVATE - DigiCipher II VIDEO (ANSI/SCTE 57)
+                      Vpid = esPid;
+                      Ppid = pmt.getPCRPid();
+                      Vtype = 0x02; // compression based upon MPEG-2
+                      ProcessCaDescriptors = true;
+                      break;
+              case 0x81: // STREAMTYPE_USER_PRIVATE - ATSC A/53 AUDIO (ANSI/SCTE 57)
+                      {
+                      char lang[MAXLANGCODE1] = { 0 };
+                      SI::Descriptor *d;
+                      for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+                          switch (d->getDescriptorTag()) {
+                            case SI::ISO639LanguageDescriptorTag: {
+                                 SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
+                                 strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
+                                 }
+                                 break;
+                            default: ;
+                            }
+                         delete d;
+                         }
+                      if (NumDpids < MAXDPIDS) {
+                         Dpids[NumDpids] = esPid;
+                         Dtypes[NumDpids] = SI::AC3DescriptorTag;
+                         strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
+                         NumDpids++;
+                         }
+                      ProcessCaDescriptors = true;
+                      }
+                      break;
+              case 0x82 ... 0xFF: // STREAMTYPE_USER_PRIVATE
                       {
                       char lang[MAXLANGCODE1] = { 0 };
                       bool IsAc3 = false;
@@ -467,17 +497,11 @@
                                  SI::RegistrationDescriptor *rd = (SI::RegistrationDescriptor *)d;
                                  // http://www.smpte-ra.org/mpegreg/mpegreg.html
                                  switch (rd->getFormatIdentifier()) {
-                                   case 0x44434949: // 'DCII' aka. DigiCipher II
-                                        Vpid = esPid;
-                                        Ppid = pmt.getPCRPid();
-                                        Vtype = 0x02; // DCII compression is based upon MPEG-2
-                                        ProcessCaDescriptors = true;
-                                        break;
                                    case 0x41432D33: // 'AC-3'
                                         IsAc3 = true;
                                         break;
                                    default:
-                                        //printf("Format identifier: 0x08X\n", rd->getFormatIdentifier());
+                                        //printf("Format identifier: 0x%08X (pid: %d)\n", rd->getFormatIdentifier(), esPid);
                                         break;
                                    }
                                  }
@@ -493,11 +517,11 @@
                          }
                       if (IsAc3) {
                          if (NumDpids < MAXDPIDS) {
-                           Dpids[NumDpids] = esPid;
-                           Dtypes[NumDpids] = SI::AC3DescriptorTag;
-                           strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
-                           NumDpids++;
-                           }
+                            Dpids[NumDpids] = esPid;
+                            Dtypes[NumDpids] = SI::AC3DescriptorTag;
+                            strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
+                            NumDpids++;
+                            }
                          ProcessCaDescriptors = true;
                          }
                       }
diff -ruN vdr-1.7.17/po/sr_SR.po vdr-1.7.18/po/sr_SR.po
--- vdr-1.7.17/po/sr_SR.po	2011-02-20 19:03:05.000000000 +0100
+++ vdr-1.7.18/po/sr_SR.po	2011-03-21 18:40:53.000000000 +0100
@@ -14,7 +14,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=ISO-8859-2\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Language: Serbian-latin\n"
+"Language: sr\n"
 
 msgid "*** Invalid Channel ***"
 msgstr "*** Neispravan Kanal ***"
diff -ruN vdr-1.7.17/recording.c vdr-1.7.18/recording.c
--- vdr-1.7.17/recording.c	2011-02-27 14:35:20.000000000 +0100
+++ vdr-1.7.18/recording.c	2011-04-17 15:53:11.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.c 2.26 2011/02/27 13:35:20 kls Exp $
+ * $Id: recording.c 2.30 2011/04/17 13:53:11 kls Exp $
  */
 
 #include "recording.h"
@@ -12,6 +12,8 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
@@ -301,9 +303,10 @@
 void cResumeFile::Delete(void)
 {
   if (fileName) {
-     if (remove(fileName) < 0 && errno != ENOENT)
+     if (remove(fileName) == 0)
+        Recordings.ResetResume(fileName);
+     else if (errno != ENOENT)
         LOG_ERROR_STR(fileName);
-     Recordings.ResetResume(fileName);
      }
 }
 
@@ -1270,19 +1273,31 @@
 {
   fileName = AddDirectory(RecordingFileName, IsPesRecording ? MARKSFILESUFFIX ".vdr" : MARKSFILESUFFIX);
   framesPerSecond = FramesPerSecond;
-  lastUpdate = 0;
+  nextUpdate = 0;
   lastFileTime = -1; // the first call to Load() must take place!
+  lastChange = 0;
   return Update();
 }
 
 bool cMarks::Update(void)
 {
   time_t t = time(NULL);
-  if (t - lastUpdate > MARKSUPDATEDELTA) {
-     lastUpdate = t;
-     t = LastModifiedTime(fileName);
-     if (t > lastFileTime) {
-        lastFileTime = t;
+  if (t > nextUpdate) {
+     time_t LastModified = LastModifiedTime(fileName);
+     if (LastModified != lastFileTime) // change detected, or first run
+        lastChange = LastModified > 0 ? LastModified : t;
+     int d = t - lastChange;
+     if (d < 60)
+        d = 1; // check frequently if the file has just been modified
+     else if (d < 3600)
+        d = 10; // older files are checked less frequently
+     else
+        d /= 360; // phase out checking for very old files
+     nextUpdate = t + d;
+     if (LastModified != lastFileTime) { // change detected, or first run
+        lastFileTime = LastModified;
+        if (lastFileTime == t)
+           lastFileTime--; // make sure we don't miss updates in the remaining second
         cMutexLock MutexLock(&MutexMarkFramesPerSecond);
         MarkFramesPerSecond = framesPerSecond;
         if (cConfig<cMark>::Load(fileName)) {
@@ -1550,7 +1565,7 @@
               delta = int(buf.st_size % sizeof(tIndexTs));
               if (delta) {
                  delta = sizeof(tIndexTs) - delta;
-                 esyslog("ERROR: invalid file size (%lld) in '%s'", buf.st_size, fileName);
+                 esyslog("ERROR: invalid file size (%"PRId64") in '%s'", buf.st_size, fileName);
                  }
               last = int((buf.st_size + delta) / sizeof(tIndexTs) - 1);
               if (!Record && last >= 0) {
diff -ruN vdr-1.7.17/recording.h vdr-1.7.18/recording.h
--- vdr-1.7.17/recording.h	2011-02-27 13:48:21.000000000 +0100
+++ vdr-1.7.18/recording.h	2011-04-17 15:18:04.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.h 2.16 2011/02/27 12:48:21 kls Exp $
+ * $Id: recording.h 2.19 2011/04/17 13:18:04 kls Exp $
  */
 
 #ifndef __RECORDING_H
@@ -57,6 +57,7 @@
   int lifetime;
   char *fileName;
   cRecordingInfo(const cChannel *Channel = NULL, const cEvent *Event = NULL);
+  bool Read(FILE *f);
   void SetData(const char *Title, const char *ShortText, const char *Description);
   void SetAux(const char *Aux);
 public:
@@ -72,7 +73,6 @@
   const char *Aux(void) const { return aux; }
   double FramesPerSecond(void) const { return framesPerSecond; }
   void SetFramesPerSecond(double FramesPerSecond);
-  bool Read(FILE *f);
   bool Write(FILE *f, const char *Prefix = "") const;
   bool Read(void);
   bool Write(void) const;
@@ -192,8 +192,9 @@
 private:
   cString fileName;
   double framesPerSecond;
-  time_t lastUpdate;
+  time_t nextUpdate;
   time_t lastFileTime;
+  time_t lastChange;
 public:
   bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false);
   bool Update(void);
diff -ruN vdr-1.7.17/remote.c vdr-1.7.18/remote.c
--- vdr-1.7.17/remote.c	2010-12-24 16:26:05.000000000 +0100
+++ vdr-1.7.18/remote.c	2011-03-27 17:03:36.000000000 +0200
@@ -4,11 +4,13 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remote.c 2.2 2010/12/24 15:26:05 kls Exp $
+ * $Id: remote.c 2.3 2011/03/27 15:03:36 kls Exp $
  */
 
 #include "remote.h"
 #include <fcntl.h>
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
 #include <netinet/in.h>
 #include <string.h>
 #include <sys/types.h>
@@ -122,7 +124,7 @@
 bool cRemote::Put(uint64_t Code, bool Repeat, bool Release)
 {
   char buffer[32];
-  snprintf(buffer, sizeof(buffer), "%016llX", Code);
+  snprintf(buffer, sizeof(buffer), "%016"PRIX64, Code);
   return Put(buffer, Repeat, Release);
 }
 
diff -ruN vdr-1.7.17/remux.c vdr-1.7.18/remux.c
--- vdr-1.7.17/remux.c	2011-02-26 16:51:04.000000000 +0100
+++ vdr-1.7.18/remux.c	2011-03-20 11:21:14.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remux.c 2.51 2011/02/26 15:51:04 kls Exp $
+ * $Id: remux.c 2.53 2011/03/20 10:21:14 kls Exp $
  */
 
 #include "remux.h"
@@ -783,9 +783,11 @@
   synced = false;
   newFrame = independentFrame = false;
   numPtsValues = 0;
+  numFrames = 0;
   numIFrames = 0;
   framesPerSecond = 0;
   framesInPayloadUnit = framesPerPayloadUnit = 0;
+  payloadUnitOfFrame = 0;
   scanning = false;
   scanner = EMPTY_SCANNER;
 }
@@ -807,6 +809,7 @@
 void cFrameDetector::Reset(void)
 {
   newFrame = independentFrame = false;
+  payloadUnitOfFrame = 0;
   scanning = false;
   scanner = EMPTY_SCANNER;
 }
@@ -833,7 +836,7 @@
                     return Processed;
                  if (Length < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE)
                     return Processed; // need more data, in case the frame type is not stored in the first TS packet
-                 if (!framesPerSecond) {
+                 if (framesPerSecond <= 0.0) {
                     // frame rate unknown, so collect a sequence of PTS values:
                     if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
                        const uchar *Pes = Data + TsPayloadOffset(Data);
@@ -844,6 +847,7 @@
                              dbgframes("#");
                              numPtsValues = 0;
                              numIFrames = 0;
+                             numFrames = 0;
                              }
                           else
                              numPtsValues++;
@@ -863,10 +867,23 @@
                              framesPerSecond = 25.0;
                           else if (Delta % 3003 == 0)
                              framesPerSecond = 30.0 / 1.001;
-                          else if (abs(Delta - 1800) <= 1)
-                             framesPerSecond = 50.0;
+                          else if (abs(Delta - 1800) <= 1) {
+                             if (numFrames > 50) {
+                                // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
+                                framesPerSecond = 25.0;
+                                framesPerPayloadUnit = -2;
+                                }
+                             else
+                                framesPerSecond = 50.0;
+                             }
                           else if (Delta == 1501)
-                             framesPerSecond = 60.0 / 1.001;
+                             if (numFrames > 50) {
+                                // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
+                                framesPerSecond = 30.0 / 1.001;
+                                framesPerPayloadUnit = -2;
+                                }
+                             else
+                                framesPerSecond = 60.0 / 1.001;
                           else {
                              framesPerSecond = 25.0;
                              dsyslog("unknown frame delta (%d), assuming 25 fps", Delta);
@@ -874,7 +891,7 @@
                           }
                        else // audio
                           framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing
-                       dbgframes("\nDelta = %d  FPS = %5.2f  FPPU = %d\n", Delta, framesPerSecond, framesPerPayloadUnit);
+                       dbgframes("\nDelta = %d  FPS = %5.2f  FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numFrames);
                        }
                     }
                  scanner = EMPTY_SCANNER;
@@ -909,6 +926,8 @@
                                   framesInPayloadUnit++;
                                   if (independentFrame)
                                      numIFrames++;
+                                  if (numIFrames == 1)
+                                     numFrames++;
                                   dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
                                   }
                                if (synced)
@@ -923,6 +942,13 @@
                                newFrame = true;
                                independentFrame = Data[i + 1] == 0x10;
                                if (synced) {
+                                  if (framesPerPayloadUnit < 0) {
+                                     payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
+                                     if (payloadUnitOfFrame != 0 && independentFrame)
+                                        payloadUnitOfFrame = 0;
+                                     if (payloadUnitOfFrame)
+                                        newFrame = false;
+                                     }
                                   if (framesPerPayloadUnit <= 1)
                                      scanning = false;
                                   }
@@ -930,6 +956,8 @@
                                   framesInPayloadUnit++;
                                   if (independentFrame)
                                      numIFrames++;
+                                  if (numIFrames == 1)
+                                     numFrames++;
                                   dbgframes("%02X ", Data[i + 1]);
                                   }
                                if (synced)
@@ -953,9 +981,9 @@
                                 pid = 0; // let's just ignore any further data
                        }
                      }
-                 if (!synced && framesPerSecond && independentFrame) {
+                 if (!synced && framesPerSecond > 0.0 && independentFrame) {
                     synced = true;
-                    dbgframes("*");
+                    dbgframes("*\n");
                     Reset();
                     return Processed + TS_SIZE;
                     }
diff -ruN vdr-1.7.17/remux.h vdr-1.7.18/remux.h
--- vdr-1.7.17/remux.h	2010-11-01 12:24:20.000000000 +0100
+++ vdr-1.7.18/remux.h	2011-03-19 17:52:46.000000000 +0100
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remux.h 2.27 2010/11/01 11:24:20 kls Exp $
+ * $Id: remux.h 2.28 2011/03/19 16:52:46 kls Exp $
  */
 
 #ifndef __REMUX_H
@@ -345,12 +345,15 @@
   bool independentFrame;
   uint32_t ptsValues[MaxPtsValues]; // 32 bit is enough - we only need the delta
   int numPtsValues;
+  int numFrames;
   int numIFrames;
   bool isVideo;
   double framesPerSecond;
   int framesInPayloadUnit;
   int framesPerPayloadUnit; // Some broadcasters send one frame per payload unit (== 1),
-                            // while others put an entire GOP into one payload unit (> 1).
+                            // some put an entire GOP into one payload unit (> 1), and
+                            // some spread a single frame over several payload units (< 0).
+  int payloadUnitOfFrame;
   bool scanning;
   uint32_t scanner;
 public:
diff -ruN vdr-1.7.17/runvdr.template vdr-1.7.18/runvdr.template
--- vdr-1.7.17/runvdr.template	2010-01-17 13:39:27.000000000 +0100
+++ vdr-1.7.18/runvdr.template	2011-04-17 14:34:30.000000000 +0200
@@ -20,7 +20,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: runvdr.template 2.1 2010/01/17 12:39:27 kls Exp $
+# $Id: runvdr.template 2.2 2011/04/17 12:34:30 kls Exp $
 
 VDRPRG="./vdr"
 
@@ -30,8 +30,12 @@
 VDRPLUGINS=""
 # You will need to select your output device plugin if you want
 # to use VDR to watch video. For instance, for a "Full Featured"
-# DVB card that would be
+# SD DVB card that would be
 # VDRPLUGINS="-P dvbsddevice"
+# For a "Full Featured" HD DVB card you could use
+# VDRPLUGINS="-P dvbhddevice"
+# There are also other output device plugins available, see
+# http://www.vdr-wiki.de/wiki/index.php/Plugins.
 
 VDRCMD="$VDRPRG $VDROPTIONS $VDRPLUGINS $*"
 
diff -ruN vdr-1.7.17/tools.c vdr-1.7.18/tools.c
--- vdr-1.7.17/tools.c	2011-02-25 15:58:31.000000000 +0100
+++ vdr-1.7.18/tools.c	2011-03-20 13:07:18.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.12 2011/02/25 14:58:31 kls Exp $
+ * $Id: tools.c 2.13 2011/03/20 12:07:18 kls Exp $
  */
 
 #include "tools.h"
@@ -1575,9 +1575,9 @@
      cachedstart = min(cachedstart, curpos);
 #endif
      ssize_t bytesRead = safe_read(fd, Data, Size);
-#ifdef USE_FADVISE
      if (bytesRead > 0) {
         curpos += bytesRead;
+#ifdef USE_FADVISE
         cachedend = max(cachedend, curpos);
 
         // Read ahead:
@@ -1597,8 +1597,9 @@
            }
         else
            ahead = curpos; // jumped -> we really don't want any readahead, otherwise e.g. fast-rewind gets in trouble.
+#endif
         }
-
+#ifdef USE_FADVISE
      if (cachedstart < cachedend) {
         if (curpos - cachedstart > READCHUNK * 2) {
            // current position has moved forward enough, shrink tail window.
diff -ruN vdr-1.7.17/vdr.5 vdr-1.7.18/vdr.5
--- vdr-1.7.17/vdr.5	2010-12-24 16:19:21.000000000 +0100
+++ vdr-1.7.18/vdr.5	2011-04-03 12:21:36.000000000 +0200
@@ -8,7 +8,7 @@
 .\" License as specified in the file COPYING that comes with the
 .\" vdr distribution.
 .\"
-.\" $Id: vdr.5 2.21 2010/12/24 15:19:21 kls Exp $
+.\" $Id: vdr.5 2.22 2011/04/03 10:21:36 kls Exp $
 .\"
 .TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
 .SH NAME
@@ -807,7 +807,7 @@
 <description>  @is the description of the event (any '|' characters will be interpreted as newlines)
 <genre>        @is a two digit hex code, as defined in  ETSI EN 300 468, table 28 (up to 4 genre codes are supported)
 <parental rating>@is the minimum age of the intended audience
-<stream>       @is the stream content (1 = video, 2 = audio, 3 = subtitles, 4 = AC3)
+<stream>       @is the stream content (1 = MPEG2 video, 2 = MP2 audio, 3 = subtitles, 4 = AC3 audio, 5 = H.264 video, 6 = HEAAC audio)
 <type>         @is the stream type according to ETSI EN 300 468
 <language>     @is the three letter language code (optionally two codes, separated by '+')
 <descr>        @is the description of this stream component
