[vdr-plugin-dvbhddevice] 01/02: Import Upstream version 2.2.0

Tobias Grimm tiber-guest at moszumanska.debian.org
Sat Jan 7 20:05:19 UTC 2017


This is an automated email from the git hooks/post-receive script.

tiber-guest pushed a commit to branch master
in repository vdr-plugin-dvbhddevice.

commit 457391b6c0a66a463f0a0948ecee7eec6fa81d08
Author: Tobias Grimm <git at e-tobi.net>
Date:   Sat Jan 7 20:10:35 2017 +0100

    Import Upstream version 2.2.0
---
 COPYING                      |  340 +++++++++++++
 HISTORY                      |  108 ++++
 Makefile                     |  123 +++++
 README                       |   18 +
 dvbhddevice.c                |  123 +++++
 dvbhdffdevice.c              | 1133 ++++++++++++++++++++++++++++++++++++++++++
 dvbhdffdevice.h              |  138 +++++
 hdffcmd.c                    |  401 +++++++++++++++
 hdffcmd.h                    |  100 ++++
 hdffosd.c                    |  844 +++++++++++++++++++++++++++++++
 hdffosd.h                    |   24 +
 libhdffcmd/Makefile          |   68 +++
 libhdffcmd/bitbuffer.c       |   79 +++
 libhdffcmd/bitbuffer.h       |   43 ++
 libhdffcmd/hdffcmd.h         |   42 ++
 libhdffcmd/hdffcmd_av.c      |  506 +++++++++++++++++++
 libhdffcmd/hdffcmd_av.h      |  159 ++++++
 libhdffcmd/hdffcmd_base.c    |   45 ++
 libhdffcmd/hdffcmd_base.h    |   55 ++
 libhdffcmd/hdffcmd_defs.h    |  125 +++++
 libhdffcmd/hdffcmd_generic.c |  165 ++++++
 libhdffcmd/hdffcmd_generic.h |   36 ++
 libhdffcmd/hdffcmd_hdmi.c    |  120 +++++
 libhdffcmd/hdffcmd_hdmi.h    |   72 +++
 libhdffcmd/hdffcmd_mux.c     |   81 +++
 libhdffcmd/hdffcmd_mux.h     |   56 +++
 libhdffcmd/hdffcmd_osd.c     |  720 +++++++++++++++++++++++++++
 libhdffcmd/hdffcmd_osd.h     |  170 +++++++
 libhdffcmd/hdffcmd_remote.c  |   67 +++
 libhdffcmd/hdffcmd_remote.h  |   39 ++
 menu.c                       |   65 +++
 menu.h                       |   29 ++
 po/de_DE.po                  |  128 +++++
 po/et_EE.po                  |  128 +++++
 po/fi_FI.po                  |  128 +++++
 po/it_IT.po                  |  131 +++++
 po/uk_UA.po                  |  129 +++++
 setup.c                      |  476 ++++++++++++++++++
 setup.h                      |   66 +++
 39 files changed, 7280 insertions(+)

diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f90922e
--- /dev/null
+++ b/COPYING
@@ -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 --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..532b5e9
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,108 @@
+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
+
+- Improved trickmodes
+- No transfer mode needed for dolby digital
+- Clear audio and video PID when Clear() ist called to stop audio decoding when jumping to cutting marks
+- Support still frames in H264 format
+- Remote control setup
+- Added analogue video setting, support volume control.
+- Support setting of audio delay.
+- Support setting of audio channel (Stereo, Left, Right)
+- Support setting of audio downmix mode.
+- Playback of PES data is working now.
+- Fall back to MPEG2 stream type when no PMT is available.
+- Added support for PES PCM playback
+- Support HDMI-CEC. (One-Touch Play)
+- Added low level OSD implementation.
+- Added option to select between high level and low level OSD.
+- high level OSD: Implement SaveRegion and RestoreRegion.
+- Fix not working video playback when PCR PID is different from video PID.
+- Fix not working pause when playing H.264 video
+- Improvements in transfer mode, fix audio dropouts or no audio at all
+- Add implementation of CanHandleAreas method to support VDR 1.7.17
+- in cHdffOsdRaw::Flush fix reusing of loop variable i in subloop that lead to OSD update problems
+- Specify container format when starting audio decoding to support PES-DVD containers
+- Added support for True Color OSD
+- Allow to disable true color OSD support via setup option
+
+2011-04-xx: Version 0.0.4
+
+- locally define DVB OSD API extensions to support compiling with original DVB headers
+- Return correct pixel aspect ratio in GetOsdSize
+- Adapt Makefile to changes introduced in recent VDR versions
+
+2012-12-27: Version 0.0.5
+
+- Adapted Makefile to changes introduced in recent VDR versions.
+
+2013-01-12: Version 0.0.6
+
+- Adapted Makefile to changes introduced in recent VDR versions.
+
+2013-01-24: Version 0.0.7
+
+- Fixed cHdffOsd::SetAreas() (didn't clear the OSD).
+
+2013-02-16: Version 0.0.8
+
+- Added missing $(LDFLAGS) to the Makefile (thanks to Ville Skytt�).
+
+2013-02-24: Version 0.0.9
+
+- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
+- Updated the Italian OSD texts (thanks to Diego Pierotto).
+- Fixed flashing OSD in "high level OSD" mode in case a menu is open while subtitles
+  are being displayed.
+- Fixed immediately disappearing subtitle track menu when selecting "No subtitles".
+
+2013-03-31: Version 2.0.0
+
+- Official release.
+
+2013-04-11: Version 2.0.1
+
+- Fixed aspect ratio and position of scaled video.
+
+2013-08-23: Version 2.1.1
+
+- Fixed aspect ratio and position of scaled video.
+- Added yellow button in main menu to send CEC TV-Off command.
+
+2013-08-26: Version 2.1.2
+
+- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
+
+2014-01-01: Version 2.1.3
+
+- Avoiding unnecessary pkg-config warnings in plugin Makefiles.
+- cDevice::TrickSpeed() now has an additional parameter named Forward.
+
+2014-01-17: Version 2.1.4
+
+- Using PCR based clock recovery in transfer mode.
+
+2014-03-15: Version 2.1.6
+
+- The function cDevice::GetVideoSystem() has been deprecated.
+- Removed old-style video format setting functions.
+
+2015-02-11: Version 2.1.7
+
+- Adapted to the new return value of cOsd::RenderPixmaps().
+
+2015-02-19: Version 2.2.0
+
+- Official release.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a994e2e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,123 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+
+# 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.
+
+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 directory environment:
+
+# Use package data if installed...otherwise assume we're under the VDR source directory:
+PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell PKG_CONFIG_PATH="$$PKG_CONFIG_PATH:../../.." pkg-config --variable=$(1) vdr))
+LIBDIR = $(call PKGCFG,libdir)
+LOCDIR = $(call PKGCFG,locdir)
+PLGCFG = $(call PKGCFG,plgcfg)
+#
+TMPDIR ?= /tmp
+
+### The compiler options:
+
+export CFLAGS   = $(call PKGCFG,cflags)
+export CXXFLAGS = $(call PKGCFG,cxxflags)
+
+### The version number of VDR's plugin API:
+
+APIVERSION = $(call PKGCFG,apiversion)
+
+### Allow user defined options to overwrite defaults:
+
+-include $(PLGCFG)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### The name of the shared object file:
+
+SOFILE = libvdr-$(PLUGIN).so
+
+### Includes and Defines (add further entries here):
+
+INCLUDES +=
+
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o dvbhdffdevice.o hdffcmd.o hdffosd.o menu.o setup.o
+
+### The main target:
+
+all: $(SOFILE) i18n
+
+### Implicit rules:
+
+%.o: %.c
+	$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+	@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR     = po
+I18Npo    = $(wildcard $(PODIR)/*.po)
+I18Nmo    = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
+I18Nmsgs  = $(addprefix $(DESTDIR)$(LOCDIR)/, $(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-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+
+%.po: $(I18Npot)
+	msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+	@touch $@
+
+$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+	install -D -m644 $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmo) $(I18Npot)
+
+install-i18n: $(I18Nmsgs)
+
+### Targets:
+
+$(SOFILE): $(OBJS) libhdffcmd
+	@$(MAKE) --no-print-directory -C libhdffcmd all
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) libhdffcmd/libhdffcmd.a -o $@
+
+install-lib: $(SOFILE)
+	install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
+
+install: install-lib install-i18n
+
+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 $(PODIR)/*.mo $(PODIR)/*.pot
+	@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
+	@-$(MAKE) --no-print-directory -C libhdffcmd clean
diff --git a/README b/README
new file mode 100644
index 0000000..5697dea
--- /dev/null
+++ b/README
@@ -0,0 +1,18 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by:                  Andreas Regel <andreas.regel at 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 --git a/dvbhddevice.c b/dvbhddevice.c
new file mode 100644
index 0000000..84902b1
--- /dev/null
+++ b/dvbhddevice.c
@@ -0,0 +1,123 @@
+/*
+ * dvbhddevice.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#include <getopt.h>
+#include <vdr/plugin.h>
+#include <vdr/shutdown.h>
+#include "dvbhdffdevice.h"
+#include "menu.h"
+#include "setup.h"
+
+static const char *VERSION        = "2.2.0";
+static const char *DESCRIPTION    = trNOOP("HD Full Featured DVB device");
+static const char *MAINMENUENTRY  = "dvbhddevice";
+
+class cPluginDvbhddevice : public cPlugin {
+private:
+  cDvbHdFfDeviceProbe *probe;
+  bool mIsUserInactive;
+public:
+  cPluginDvbhddevice(void);
+  virtual ~cPluginDvbhddevice();
+  virtual const char *Version(void) { return VERSION; }
+  virtual const char *Description(void) { return tr(DESCRIPTION); }
+  virtual void MainThreadHook(void);
+  virtual void Stop(void);
+  virtual const char *MainMenuEntry(void);
+  virtual cOsdObject *MainMenuAction(void);
+  virtual cMenuSetupPage *SetupMenu(void);
+  virtual bool SetupParse(const char *Name, const char *Value);
+  virtual const char *CommandLineHelp(void);
+  virtual bool ProcessArgs(int argc, char *argv[]);
+  };
+
+cPluginDvbhddevice::cPluginDvbhddevice(void)
+:   mIsUserInactive(true)
+{
+  probe = new cDvbHdFfDeviceProbe;
+}
+
+cPluginDvbhddevice::~cPluginDvbhddevice()
+{
+  delete probe;
+}
+
+const char *cPluginDvbhddevice::CommandLineHelp(void)
+{
+  return "  -o        --outputonly   do not receive, just use as output device\n";
+}
+
+bool cPluginDvbhddevice::ProcessArgs(int argc, char *argv[])
+{
+  static struct option long_options[] = {
+       { "outputonly", no_argument, NULL, 'o' },
+       { NULL,         no_argument, NULL,  0  }
+     };
+
+  int c;
+  while ((c = getopt_long(argc, argv, "o", long_options, NULL)) != -1) {
+        switch (c) {
+          case 'o': probe->SetOutputOnly(true);
+                    break;
+          default:  return false;
+          }
+        }
+  return true;
+}
+
+void cPluginDvbhddevice::MainThreadHook(void)
+{
+    bool isUserInactive = ShutdownHandler.IsUserInactive();
+    if (isUserInactive != mIsUserInactive)
+    {
+        mIsUserInactive = isUserInactive;
+        if (gHdffSetup.CecEnabled && gHdffSetup.CecTvOn)
+        {
+            HDFF::cHdffCmdIf * hdffCmdIf = cDvbHdFfDevice::GetHdffCmdHandler();
+            if (hdffCmdIf && !mIsUserInactive)
+            {
+                hdffCmdIf->CmdHdmiSendCecCommand(HDFF_CEC_COMMAND_TV_ON);
+            }
+        }
+    }
+}
+
+void cPluginDvbhddevice::Stop(void)
+{
+    if (gHdffSetup.CecEnabled && gHdffSetup.CecTvOff)
+    {
+        HDFF::cHdffCmdIf * hdffCmdIf = cDvbHdFfDevice::GetHdffCmdHandler();
+        if (hdffCmdIf)
+        {
+            hdffCmdIf->CmdHdmiSendCecCommand(HDFF_CEC_COMMAND_TV_OFF);
+            isyslog("HDFF_CEC_COMMAND_TV_OFF");
+        }
+    }
+}
+
+const char *cPluginDvbhddevice::MainMenuEntry(void)
+{
+  return gHdffSetup.HideMainMenu ? NULL : MAINMENUENTRY;
+}
+
+cOsdObject *cPluginDvbhddevice::MainMenuAction(void)
+{
+  HDFF::cHdffCmdIf * hdffCmdIf = cDvbHdFfDevice::GetHdffCmdHandler();
+  return hdffCmdIf ? new cHdffMenu(hdffCmdIf) : NULL;
+}
+
+cMenuSetupPage *cPluginDvbhddevice::SetupMenu(void)
+{
+  HDFF::cHdffCmdIf * hdffCmdIf = cDvbHdFfDevice::GetHdffCmdHandler();
+  return hdffCmdIf ? new cHdffSetupPage(hdffCmdIf) : NULL;
+}
+
+bool cPluginDvbhddevice::SetupParse(const char *Name, const char *Value)
+{
+  return gHdffSetup.SetupParse(Name, Value);
+}
+
+VDRPLUGINCREATOR(cPluginDvbhddevice); // Don't touch this!
diff --git a/dvbhdffdevice.c b/dvbhdffdevice.c
new file mode 100644
index 0000000..60decb7
--- /dev/null
+++ b/dvbhdffdevice.c
@@ -0,0 +1,1133 @@
+/*
+ * dvbhdffdevice.c: The DVB HD Full Featured device interface
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#include <stdint.h>
+
+#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"
+
+
+static uchar *YuvToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality);
+
+
+// --- cDvbHdFfDevice --------------------------------------------------------
+
+int cDvbHdFfDevice::devHdffOffset = -1;
+
+cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend, bool OutputOnly)
+:cDvbDevice(Adapter, Frontend)
+{
+  spuDecoder = NULL;
+  audioChannel = 0;
+  playMode = pmNone;
+  mHdffCmdIf = NULL;
+  outputOnly = OutputOnly;
+
+  if (outputOnly) {
+     StopSectionHandler();
+     // cannot close fd_tuner, fd_ca and delete ciAdapter, dvbTuner here - are cDvbDevice private
+  }
+
+  // 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);
+
+     uint32_t firmwareVersion = mHdffCmdIf->CmdGetFirmwareVersion(NULL, 0);
+     if (firmwareVersion < 0x401)
+        supportsPcrInTransferMode = false;
+     else
+        supportsPcrInTransferMode = true;
+
+     /* reset some stuff in case the VDR was killed before and had no chance
+        to clean up. */
+     mHdffCmdIf->CmdOsdReset();
+
+     mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+     mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
+
+     mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
+     mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+     mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
+     mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
+
+     ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
+     mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
+     mHdffCmdIf->CmdAvEnableSync(0, true);
+     mHdffCmdIf->CmdAvSetPlayMode(0, true);
+     /* reset done */
+
+     mHdffCmdIf->CmdAvSetAudioDelay(gHdffSetup.AudioDelay);
+     mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) gHdffSetup.AudioDownmix);
+     mHdffCmdIf->CmdAvSetSyncShift(gHdffSetup.AvSyncShift);
+     mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) gHdffSetup.AnalogueVideo);
+     mHdffCmdIf->CmdHdmiSetVideoMode(gHdffSetup.GetVideoMode());
+
+     HdffHdmiConfig_t hdmiConfig;
+     memset(&hdmiConfig, 0, sizeof(hdmiConfig));
+     hdmiConfig.TransmitAudio = true;
+     hdmiConfig.ForceDviMode = false;
+     hdmiConfig.CecEnabled = gHdffSetup.CecEnabled;
+     strcpy(hdmiConfig.CecDeviceName, "VDR");
+     hdmiConfig.VideoModeAdaption = (HdffVideoModeAdaption_t) gHdffSetup.VideoModeAdaption;
+     mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
+
+     mHdffCmdIf->CmdRemoteSetProtocol((HdffRemoteProtocol_t) gHdffSetup.RemoteProtocol);
+     mHdffCmdIf->CmdRemoteSetAddressFilter(gHdffSetup.RemoteAddress >= 0, gHdffSetup.RemoteAddress);
+     }
+}
+
+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);
+
+        gHdffSetup.SetVideoFormat(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)
+{
+    #define BUFFER_SIZE  (sizeof(struct v4l2_pix_format) + 1920 * 1080 * 2)
+    int fd;
+    uint8_t * buffer;
+    uint8_t * result = NULL;
+
+    fd = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDONLY);
+    if (fd < 0) {
+        esyslog("GrabImage: failed open DVB video device");
+        return NULL;
+    }
+
+    buffer = (uint8_t *) malloc(BUFFER_SIZE);
+    if (buffer)
+    {
+        int readBytes;
+
+        readBytes = read(fd, buffer, BUFFER_SIZE);
+        if (readBytes < (int) sizeof(struct v4l2_pix_format))
+            esyslog("GrabImage: failed reading from DVB video device");
+        else {
+            struct v4l2_pix_format * pixfmt;
+            int dataSize;
+
+            pixfmt = (struct v4l2_pix_format *) buffer;
+            dsyslog("GrabImage: Read image of size %d x %d",
+                    pixfmt->width, pixfmt->height);
+            dataSize = readBytes - sizeof(struct v4l2_pix_format);
+            if (dataSize < (int) pixfmt->sizeimage)
+                esyslog("GrabImage: image is not complete");
+            else {
+                if (Jpeg) {
+                    uint8_t * temp;
+                    temp = (uint8_t *) malloc(pixfmt->width * 3 * pixfmt->height);
+                    if (temp) {
+                        int numPixels = pixfmt->width * pixfmt->height;
+                        uint8_t * destData = temp;
+                        uint8_t * srcData = buffer + sizeof(struct v4l2_pix_format);
+                        while (numPixels > 0)
+                        {
+                            destData[0] = srcData[1];
+                            destData[1] = srcData[0];
+                            destData[2] = srcData[2];
+                            destData[3] = srcData[3];
+                            destData[4] = srcData[0];
+                            destData[5] = srcData[2];
+                            srcData += 4;
+                            destData += 6;
+                            numPixels -= 2;
+                        }
+                        if (Quality < 0)
+                            Quality = 100;
+                        result = YuvToJpeg(temp, pixfmt->width, pixfmt->height, Size, Quality);
+                        free(temp);
+                    }
+                }
+                else {
+                    // convert to PNM:
+                    char buf[32];
+                    snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n",
+                             pixfmt->width, pixfmt->height);
+                    int l = strlen(buf);
+                    Size = l + pixfmt->width * 3 * pixfmt->height;
+                    result = (uint8_t *) malloc(Size);
+                    if (result)
+                    {
+                        memcpy(result, buf, l);
+                        uint8_t * destData = result + l;
+                        uint8_t * srcData = buffer + sizeof(struct v4l2_pix_format);
+                        int numPixels = pixfmt->width * pixfmt->height;
+                        while (numPixels > 0)
+                        {
+                            int cb = srcData[0] - 128;
+                            int y1 = srcData[1];
+                            int cr = srcData[2] - 128;
+                            int y2 = srcData[3];
+                            int r;
+                            int g;
+                            int b;
+
+                            r = y1 + (int) (1.402f * cr);
+                            g = y1 - (int) (0.344f * cb + 0.714f * cr);
+                            b = y1 + (int) (1.772f * cb);
+                            destData[0] = r > 255 ? 255 : r < 0 ? 0 : r;
+                            destData[1] = g > 255 ? 255 : g < 0 ? 0 : g;
+                            destData[2] = b > 255 ? 255 : b < 0 ? 0 : b;
+                            r = y2 + (int) (1.402f * cr);
+                            g = y2 - (int) (0.344f * cb + 0.714f * cr);
+                            b = y2 + (int) (1.772f * cb);
+                            destData[3] = r > 255 ? 255 : r < 0 ? 0 : r;
+                            destData[4] = g > 255 ? 255 : g < 0 ? 0 : g;
+                            destData[5] = b > 255 ? 255 : b < 0 ? 0 : b;
+
+                            srcData += 4;
+                            destData += 6;
+                            numPixels -= 2;
+                        }
+                    }
+                }
+            }
+        }
+        free(buffer);
+    }
+
+    close(fd);
+
+    return result;
+}
+
+void cDvbHdFfDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
+{
+    if (gHdffSetup.TvFormat == HDFF_TV_FORMAT_4_BY_3)
+    {
+        switch (VideoDisplayFormat)
+        {
+            case vdfPanAndScan:
+            case vdfCenterCutOut:
+                gHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT;
+                break;
+
+            case vdfLetterBox:
+                gHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9;
+                break;
+        }
+        gHdffSetup.SetVideoFormat(mHdffCmdIf);
+    }
+    cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
+}
+
+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);
+}
+
+bool cDvbHdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On)
+{
+    //printf("SetPid Type %d, On %d, PID %5d, streamtype %d, handle %d, used %d\n", Type, On, Handle->pid, Handle->streamType, Handle->handle, Handle->used);
+    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_VIDEO_STREAM_H264);
+                else
+                    mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_MPEG2);
+            }
+            else if (Type == ptAudio) {
+                if (Handle->streamType == 0x03)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1);
+                else if (Handle->streamType == 0x04)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG2);
+                else if (Handle->streamType == SI::AC3DescriptorTag)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AC3);
+                else if (Handle->streamType == SI::EnhancedAC3DescriptorTag)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_EAC3);
+                else if (Handle->streamType == 0x0F)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AAC);
+                else if (Handle->streamType == 0x11)
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_HE_AAC);
+                else
+                    mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1);
+            }
+            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_VIDEO_STREAM_MPEG1);
+            else if (Type == ptAudio)
+                mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
+            else if (Type == ptDolby)
+                mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_AC3);
+            //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid()
+            close(Handle->handle);
+            Handle->handle = -1;
+        }
+    }
+    return true;
+}
+
+bool cDvbHdFfDevice::ProvidesSource(int Source) const
+{
+  if (outputOnly)
+     return false;
+  return cDvbDevice::ProvidesSource(Source);
+}
+
+int cDvbHdFfDevice::NumProvidedSystems(void) const
+{
+  if (outputOnly)
+     return 0;
+  return cDvbDevice::NumProvidedSystems();
+}
+
+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 = vpid && pidHandles[ptVideo].pid == vpid;
+  bool pidHandlesAudio = apid && 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;
+
+  //printf("SetChannelDevice Transfer %d, Live %d\n", StartTransferMode, LiveView);
+
+  bool TurnOnLivePIDs = !StartTransferMode && LiveView;
+
+  // Turn off live PIDs if necessary:
+
+  if (TurnOffLivePIDs)
+     TurnOffLiveMode(LiveView);
+
+  // Set the tuner:
+
+  if (!cDvbDevice::SetChannelDevice(Channel, LiveView))
+     return false;
+
+  // PID settings:
+
+  if (TurnOnLivePIDs) {
+     if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid ? apid : dpid, ptAudio, apid ? 0 : Channel->Dtype(0)))) {
+        esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
+        return false;
+        }
+     }
+  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::SetAudioTrackDevice(eTrackType Type)
+{
+    //printf("SetAudioTrackDevice %d\n", Type);
+    const tTrackId *TrackId = GetTrack(Type);
+    if (TrackId && TrackId->id) {
+        int streamType = 0;
+        cChannel * channel = Channels.GetByNumber(CurrentChannel());
+        if (channel) {
+            if (IS_AUDIO_TRACK(Type))
+                streamType = channel->Atype(Type - ttAudioFirst);
+            else if (IS_DOLBY_TRACK(Type))
+                streamType = channel->Dtype(Type - ttDolbyFirst);
+        }
+        //printf("SetAudioTrackDevice new %d %d, current %d\n", TrackId->id, streamType, pidHandles[ptAudio].pid);
+        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;
+            pidHandles[ptAudio].streamType = streamType;
+            SetPid(&pidHandles[ptAudio], ptAudio, true);
+            if (CamSlot()) {
+                CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
+                CamSlot()->StartDecrypting();
+            }
+        }
+    }
+}
+
+bool cDvbHdFfDevice::CanReplay(void) const
+{
+  return cDevice::CanReplay();
+}
+
+bool cDvbHdFfDevice::SetPlayMode(ePlayMode PlayMode)
+{
+    if (PlayMode == pmNone) {
+        if (fd_video == -1)
+            fd_video = DvbOpen(DEV_DVB_VIDEO,  adapter, frontend, O_RDWR | O_NONBLOCK);
+        if (fd_audio == -1)
+            fd_audio = DvbOpen(DEV_DVB_AUDIO,  adapter, frontend, O_RDWR | O_NONBLOCK);
+
+        mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+        mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
+
+        mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
+        mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+        mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
+        mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
+
+        ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
+        mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
+        mHdffCmdIf->CmdAvEnableSync(0, true);
+        mHdffCmdIf->CmdAvSetPlayMode(0, true);
+        mHdffCmdIf->CmdAvMuteAudio(0, false);
+    }
+    else {
+        if (playMode == pmNone)
+            TurnOffLiveMode(true);
+
+        if (PlayMode == pmExtern_THIS_SHOULD_BE_AVOIDED)
+        {
+            close(fd_video);
+            fd_video = -1;
+            close(fd_audio);
+            fd_audio = -1;
+        }
+        else
+        {
+            isTransferMode = Transferring() || (cTransferControl::ReceiverDevice() == this);
+            mHdffCmdIf->CmdAvSetPlayMode(1, isTransferMode);
+            mHdffCmdIf->CmdAvSetStc(0, 100000);
+            mHdffCmdIf->CmdAvEnableSync(0, false);
+            mHdffCmdIf->CmdAvEnableVideoAfterStop(0, true);
+
+            playVideoPid = -1;
+            playAudioPid = -1;
+            playPcrPid = -1;
+            audioCounter = 0;
+            videoCounter = 0;
+            freezed = false;
+            trickMode = false;
+            isPlayingVideo = false;
+
+            mHdffCmdIf->CmdAvSetDecoderInput(0, 2);
+            ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
+        }
+    }
+    playMode = PlayMode;
+    return true;
+}
+
+int64_t cDvbHdFfDevice::GetSTC(void)
+{
+    if (isPlayingVideo)
+    {
+        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;
+            }
+            //printf("video PTS %lld\n", pts);
+            return pts;
+        }
+    }
+    else
+    {
+        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;
+            }
+            //printf("audio PTS %lld\n", pts);
+            return pts;
+        }
+    }
+    return -1;
+}
+
+cRect cDvbHdFfDevice::CanScaleVideo(const cRect &Rect, int Alignment)
+{
+    return Rect;
+}
+
+void cDvbHdFfDevice::ScaleVideo(const cRect &Rect)
+{
+    if (Rect == cRect::Null)
+    {
+        mHdffCmdIf->CmdAvSetVideoWindow(0, false, 0, 0, 0, 0);
+    }
+    else
+    {
+        //printf("ScaleVideo: Rect = %d %d %d %d\n", Rect.X(), Rect.Y(), Rect.Width(), Rect.Height());
+
+        int osdWidth;
+        int osdHeight;
+        double osdPixelAspect;
+
+        GetOsdSize(osdWidth, osdHeight, osdPixelAspect);
+        //printf("ScaleVideo: OsdSize = %d %d %g\n", osdWidth, osdHeight, osdPixelAspect);
+
+        // Convert the video window coordinates in 1/10 percent of the display
+        // resolution.
+        int x = (Rect.X() * 1000 + osdWidth / 2) / osdWidth;
+        int y = (Rect.Y() * 1000 + osdHeight / 2) / osdHeight;
+        int w = (Rect.Width() * 1000 + osdWidth / 2) / osdWidth;
+        int h = (Rect.Height() * 1000 + osdHeight / 2) / osdHeight;
+        //printf("ScaleVideo: Win1 = %d %d %d %d\n", x, y, w, h);
+
+        // fix aspect ratio, reposition video
+        if (w > h) {
+            x += (w - h) / 2;
+            w = h;
+        }
+        else if (w < h) {
+            y += (h - w) / 2;
+            h = w;
+        }
+
+        //printf("ScaleVideo: Win2 = %d %d %d %d\n", x, y, w, h);
+        mHdffCmdIf->CmdAvSetVideoWindow(0, true, x, y, w, h);
+    }
+}
+
+#if (APIVERSNUM >= 20103)
+void cDvbHdFfDevice::TrickSpeed(int Speed, bool Forward)
+#else
+void cDvbHdFfDevice::TrickSpeed(int Speed)
+#endif
+{
+  freezed = false;
+  mHdffCmdIf->CmdAvEnableSync(0, false);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
+  playAudioPid = -1;
+  if (Speed > 0)
+     mHdffCmdIf->CmdAvSetVideoSpeed(0, 100 / Speed);
+  trickMode = true;
+}
+
+void cDvbHdFfDevice::Clear(void)
+{
+  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
+  mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
+  playVideoPid = -1;
+  playAudioPid = -1;
+  cDevice::Clear();
+}
+
+void cDvbHdFfDevice::Play(void)
+{
+    freezed = false;
+    trickMode = false;
+    if (isPlayingVideo)
+        mHdffCmdIf->CmdAvEnableSync(0, true);
+    mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+    mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
+    mHdffCmdIf->CmdAvMuteAudio(0, false);
+    cDevice::Play();
+}
+
+void cDvbHdFfDevice::Freeze(void)
+{
+  freezed = true;
+  mHdffCmdIf->CmdAvSetVideoSpeed(0, 0);
+  mHdffCmdIf->CmdAvSetAudioSpeed(0, 0);
+  cDevice::Freeze();
+}
+
+void cDvbHdFfDevice::Mute(void)
+{
+    mHdffCmdIf->CmdAvMuteAudio(0, true);
+    cDevice::Mute();
+}
+
+static HdffVideoStreamType_t MapVideoStreamTypes(int Vtype)
+{
+  switch (Vtype) {
+    case 0x01: return HDFF_VIDEO_STREAM_MPEG1;
+    case 0x02: return HDFF_VIDEO_STREAM_MPEG2;
+    case 0x1B: return HDFF_VIDEO_STREAM_H264;
+    default: return HDFF_VIDEO_STREAM_MPEG2; // fallback to MPEG2
+    }
+}
+
+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)
+{
+    if (freezed)
+        return -1;
+    if (!isPlayingVideo)
+    {
+        mHdffCmdIf->CmdAvEnableSync(0, true);
+        isPlayingVideo = true;
+    }
+
+    // ignore padding PES packets
+    if (Data[3] == 0xBE)
+        return 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_VIDEO_STREAM_MPEG2, true);
+    }
+    if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
+        Length = 0;
+    return Length;
+}
+
+int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
+{
+    if (freezed)
+        return -1;
+    uint8_t streamId;
+    uint8_t tsBuffer[188 * 16];
+    uint32_t tsLength;
+    HdffAudioStreamType_t streamType = HDFF_AUDIO_STREAM_MPEG1;
+    HdffAvContainerType_t containerType = HDFF_AV_CONTAINER_PES;
+    int pid;
+
+    streamId = Data[3];
+    if (streamId >= 0xC0 && streamId <= 0xDF)
+    {
+        streamType = HDFF_AUDIO_STREAM_MPEG1;
+    }
+    else if (streamId == 0xBD)
+    {
+        const uint8_t * payload = Data + 9 + Data[8];
+        if ((payload[0] & 0xF8) == 0xA0)
+        {
+            containerType = HDFF_AV_CONTAINER_PES_DVD;
+            streamType = HDFF_AUDIO_STREAM_PCM;
+        }
+        else if ((payload[0] & 0xF8) == 0x88)
+        {
+            containerType = HDFF_AV_CONTAINER_PES_DVD;
+            streamType = HDFF_AUDIO_STREAM_DTS;
+        }
+        else if ((payload[0] & 0xF8) == 0x80)
+        {
+            containerType = HDFF_AV_CONTAINER_PES_DVD;
+            streamType = HDFF_AUDIO_STREAM_AC3;
+        }
+        else
+        {
+            streamType = HDFF_AUDIO_STREAM_AC3;
+        }
+    }
+    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)
+{
+    if (freezed)
+        return -1;
+    if (!isPlayingVideo)
+    {
+        mHdffCmdIf->CmdAvEnableSync(0, true);
+        isPlayingVideo = true;
+    }
+
+    int pid = TsPid(Data);
+    if (pid != playVideoPid) {
+        PatPmtParser();
+        if (pid == PatPmtParser()->Vpid()) {
+            playVideoPid = pid;
+            mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, MapVideoStreamTypes(PatPmtParser()->Vtype()), true);
+        }
+    }
+    if (isTransferMode && supportsPcrInTransferMode) {
+        if (pid != playPcrPid) {
+            if (pid == PatPmtParser()->Ppid()) {
+                playPcrPid = pid;
+                mHdffCmdIf->CmdAvSetPcrPid(0, playPcrPid);
+            }
+        }
+    }
+    return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
+}
+
+static HdffAudioStreamType_t MapAudioStreamTypes(int Atype)
+{
+  switch (Atype) {
+    case 0x03: return HDFF_AUDIO_STREAM_MPEG1;
+    case 0x04: return HDFF_AUDIO_STREAM_MPEG2;
+    case SI::AC3DescriptorTag: return HDFF_AUDIO_STREAM_AC3;
+    case SI::EnhancedAC3DescriptorTag: return HDFF_AUDIO_STREAM_EAC3;
+    case 0x0F: return HDFF_AUDIO_STREAM_AAC;
+    case 0x11: return HDFF_AUDIO_STREAM_HE_AAC;
+    default: return HDFF_AUDIO_STREAM_MPEG1;
+    }
+}
+
+int cDvbHdFfDevice::PlayTsAudio(const uchar *Data, int Length)
+{
+  if (freezed)
+    return -1;
+  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 ---------------------------------------------------
+
+cDvbHdFfDeviceProbe::cDvbHdFfDeviceProbe(void)
+{
+  outputOnly = false;
+}
+
+bool cDvbHdFfDeviceProbe::Probe(int Adapter, int Frontend)
+{
+  static uint32_t SubsystemIds[] = {
+    0x13C23009, // Technotrend S2-6400 HDFF development samples
+    0x13C2300A, // Technotrend S2-6400 HDFF production version
+    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%s", outputOnly ? " (output only)" : "");
+            new cDvbHdFfDevice(Adapter, Frontend, outputOnly);
+            return true;
+            }
+         else if (outputOnly) {
+            dsyslog("cDvbHdFfDevice 2nd tuner disabled (outputonly)");
+            return true;
+            }
+         }
+      }
+  return false;
+}
+
+
+// --- YuvToJpeg -------------------------------------------------------------
+
+#include <jpeglib.h>
+
+#define JPEGCOMPRESSMEM 4000000
+
+struct tJpegCompressData {
+  int size;
+  uchar *mem;
+  };
+
+static void JpegCompressInitDestination(j_compress_ptr cinfo)
+{
+  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
+  if (jcd) {
+     cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM;
+     cinfo->dest->next_output_byte = jcd->mem = MALLOC(uchar, jcd->size);
+     }
+}
+
+static boolean JpegCompressEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
+  if (jcd) {
+     int Used = jcd->size;
+     int NewSize = jcd->size + JPEGCOMPRESSMEM;
+     if (uchar *NewBuffer = (uchar *)realloc(jcd->mem, NewSize)) {
+        jcd->size = NewSize;
+        jcd->mem = NewBuffer;
+        }
+     else {
+        esyslog("ERROR: out of memory");
+        return false;
+        }
+     if (jcd->mem) {
+        cinfo->dest->next_output_byte = jcd->mem + Used;
+        cinfo->dest->free_in_buffer = jcd->size - Used;
+        return true;
+        }
+     }
+  return false;
+}
+
+static void JpegCompressTermDestination(j_compress_ptr cinfo)
+{
+  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
+  if (jcd) {
+     int Used = cinfo->dest->next_output_byte - jcd->mem;
+     if (Used < jcd->size) {
+        if (uchar *NewBuffer = (uchar *)realloc(jcd->mem, Used)) {
+           jcd->size = Used;
+           jcd->mem = NewBuffer;
+           }
+        else
+           esyslog("ERROR: out of memory");
+        }
+     }
+}
+
+static uchar *YuvToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality)
+{
+  if (Quality < 0)
+     Quality = 0;
+  else if (Quality > 100)
+     Quality = 100;
+
+  jpeg_destination_mgr jdm;
+
+  jdm.init_destination = JpegCompressInitDestination;
+  jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer;
+  jdm.term_destination = JpegCompressTermDestination;
+
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_compress(&cinfo);
+  cinfo.dest = &jdm;
+  tJpegCompressData jcd;
+  cinfo.client_data = &jcd;
+  cinfo.image_width = Width;
+  cinfo.image_height = Height;
+  cinfo.input_components = 3;
+  cinfo.in_color_space = JCS_YCbCr;
+
+  jpeg_set_defaults(&cinfo);
+  jpeg_set_quality(&cinfo, Quality, true);
+  jpeg_start_compress(&cinfo, true);
+
+  int rs = Width * 3;
+  JSAMPROW rp[Height];
+  for (int k = 0; k < Height; k++)
+      rp[k] = &Mem[rs * k];
+  jpeg_write_scanlines(&cinfo, rp, Height);
+  jpeg_finish_compress(&cinfo);
+  jpeg_destroy_compress(&cinfo);
+
+  Size = jcd.size;
+  return jcd.mem;
+}
diff --git a/dvbhdffdevice.h b/dvbhdffdevice.h
new file mode 100644
index 0000000..68b7933
--- /dev/null
+++ b/dvbhdffdevice.h
@@ -0,0 +1,138 @@
+/*
+ * dvbhdffdevice.h: The DVB HD Full Featured device interface
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#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;
+  bool outputOnly;
+protected:
+  virtual void MakePrimaryDevice(bool On);
+public:
+  static bool Probe(int Adapter, int Frontend);
+  cDvbHdFfDevice(int Adapter, int Frontend, bool OutputOnly);
+  virtual ~cDvbHdFfDevice();
+  virtual bool HasDecoder(void) const;
+
+// SPU facilities
+
+private:
+  cDvbSpuDecoder *spuDecoder;
+public:
+  virtual cSpuDecoder *GetSpuDecoder(void);
+
+// Channel facilities
+
+public:
+  virtual bool ProvidesSource(int Source) const;
+  virtual int NumProvidedSystems(void) const;
+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 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);
+
+// Player facilities
+
+private:
+  int playVideoPid;
+  int playAudioPid;
+  int playPcrPid;
+  bool freezed;
+  bool trickMode;
+  bool isPlayingVideo;
+  bool isTransferMode;
+  bool supportsPcrInTransferMode;
+
+  // 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 cRect CanScaleVideo(const cRect &Rect, int Alignment = taCenter);
+  virtual void ScaleVideo(const cRect &Rect = cRect::Null);
+#if (APIVERSNUM >= 20103)
+  virtual void TrickSpeed(int Speed, bool Forward);
+#else
+  virtual void TrickSpeed(int Speed);
+#endif
+  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 {
+private:
+  bool outputOnly;
+public:
+  cDvbHdFfDeviceProbe(void);
+  virtual bool Probe(int Adapter, int Frontend);
+  void SetOutputOnly(bool On) { outputOnly = On; }
+  };
+
+#endif //__DVBHDFFDEVICE_H
diff --git a/hdffcmd.c b/hdffcmd.c
new file mode 100644
index 0000000..fd2d598
--- /dev/null
+++ b/hdffcmd.c
@@ -0,0 +1,401 @@
+/*
+ * hdffcmd.c: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#include <stdint.h>
+
+#include "hdffcmd.h"
+#include "libhdffcmd/hdffcmd.h"
+#include <stdio.h>
+#include <string.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)
+{
+}
+
+
+uint32_t cHdffCmdIf::CmdGetFirmwareVersion(char * pString, uint32_t MaxLength)
+{
+    uint32_t version;
+    int err;
+
+    err = HdffCmdGetFirmwareVersion(mOsdDev, &version, pString, MaxLength);
+    if (err == 0)
+        return version;
+    return 0;
+}
+
+uint32_t cHdffCmdIf::CmdGetInterfaceVersion(char * pString, uint32_t MaxLength)
+{
+    uint32_t version;
+    int err;
+
+    err = HdffCmdGetInterfaceVersion(mOsdDev, &version, pString, MaxLength);
+    if (err == 0)
+        return version;
+    return 0;
+}
+
+uint32_t cHdffCmdIf::CmdGetCopyrights(uint8_t Index, char * pString, uint32_t MaxLength)
+{
+    int err;
+
+    err = HdffCmdGetCopyrights(mOsdDev, Index, pString, MaxLength);
+    if (err == 0)
+        return strlen(pString);
+    return 0;
+}
+
+
+void cHdffCmdIf::CmdAvSetPlayMode(uint8_t PlayMode, bool Realtime)
+{
+    HdffCmdAvSetPlayMode(mOsdDev, PlayMode, Realtime);
+}
+
+void cHdffCmdIf::CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, HdffVideoStreamType_t StreamType, bool PlaybackMode)
+{
+    //printf("SetVideoPid %d %d\n", VideoPid, StreamType);
+    HdffCmdAvSetVideoPid(mOsdDev, DecoderIndex, VideoPid, StreamType);
+}
+
+void cHdffCmdIf::CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, HdffAudioStreamType_t StreamType, HdffAvContainerType_t ContainerType)
+{
+    //printf("SetAudioPid %d %d %d\n", AudioPid, StreamType, ContainerType);
+    HdffCmdAvSetAudioPid(mOsdDev, DecoderIndex, AudioPid, StreamType,
+                         ContainerType);
+}
+
+void cHdffCmdIf::CmdAvSetPcrPid(uint8_t DecoderIndex, uint16_t PcrPid)
+{
+    //printf("SetPcrPid %d\n", PcrPid);
+    HdffCmdAvSetPcrPid(mOsdDev, DecoderIndex, PcrPid);
+}
+
+void cHdffCmdIf::CmdAvSetTeletextPid(uint8_t DecoderIndex, uint16_t TeletextPid)
+{
+    HdffCmdAvSetTeletextPid(mOsdDev, DecoderIndex, TeletextPid);
+}
+
+void cHdffCmdIf::CmdAvSetVideoWindow(uint8_t DecoderIndex, bool Enable, uint16_t X, uint16_t Y, uint16_t Width, uint16_t Height)
+{
+    HdffCmdAvSetVideoWindow(mOsdDev, DecoderIndex, Enable, X, Y, Width, Height);
+}
+
+void cHdffCmdIf::CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, HdffVideoStreamType_t StreamType)
+{
+    HdffCmdAvShowStillImage(mOsdDev, DecoderIndex, pStillImage, Size,
+                            StreamType);
+}
+
+void cHdffCmdIf::CmdAvSetDecoderInput(uint8_t DecoderIndex, uint8_t DemultiplexerIndex)
+{
+    HdffCmdAvSetDecoderInput(mOsdDev, DecoderIndex, DemultiplexerIndex);
+}
+
+void cHdffCmdIf::CmdAvSetDemultiplexerInput(uint8_t DemultiplexerIndex, uint8_t TsInputIndex)
+{
+    HdffCmdAvSetDemultiplexerInput(mOsdDev, DemultiplexerIndex, TsInputIndex);
+}
+
+void cHdffCmdIf::CmdAvSetVideoFormat(uint8_t DecoderIndex, const HdffVideoFormat_t * pVideoFormat)
+{
+    HdffCmdAvSetVideoFormat(mOsdDev, DecoderIndex, pVideoFormat);
+}
+
+void cHdffCmdIf::CmdAvSetVideoOutputMode(uint8_t DecoderIndex, HdffVideoOutputMode_t OutputMode)
+{
+    HdffCmdAvSetVideoOutputMode(mOsdDev, DecoderIndex, OutputMode);
+}
+
+void cHdffCmdIf::CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc)
+{
+    HdffCmdAvSetStc(mOsdDev, DecoderIndex, Stc);
+}
+
+void cHdffCmdIf::CmdAvFlushBuffer(uint8_t DecoderIndex, bool FlushAudio, bool FlushVideo)
+{
+    HdffCmdAvFlushBuffer(mOsdDev, DecoderIndex, FlushAudio, FlushVideo);
+}
+
+void cHdffCmdIf::CmdAvEnableSync(uint8_t DecoderIndex, bool EnableSync)
+{
+    HdffCmdAvEnableSync(mOsdDev, DecoderIndex, EnableSync, EnableSync);
+}
+
+void cHdffCmdIf::CmdAvSetVideoSpeed(uint8_t DecoderIndex, int32_t Speed)
+{
+    HdffCmdAvSetVideoSpeed(mOsdDev, DecoderIndex, Speed);
+}
+
+void cHdffCmdIf::CmdAvSetAudioSpeed(uint8_t DecoderIndex, int32_t Speed)
+{
+    HdffCmdAvSetAudioSpeed(mOsdDev, DecoderIndex, Speed);
+}
+
+void cHdffCmdIf::CmdAvEnableVideoAfterStop(uint8_t DecoderIndex, bool EnableVideoAfterStop)
+{
+    HdffCmdAvEnableVideoAfterStop(mOsdDev, DecoderIndex, EnableVideoAfterStop);
+}
+
+void cHdffCmdIf::CmdAvSetAudioDelay(int16_t Delay)
+{
+    HdffCmdAvSetAudioDelay(mOsdDev, Delay);
+}
+
+void cHdffCmdIf::CmdAvSetAudioDownmix(HdffAudioDownmixMode_t DownmixMode)
+{
+    HdffCmdAvSetAudioDownmix(mOsdDev, DownmixMode);
+}
+
+void cHdffCmdIf::CmdAvSetAudioChannel(uint8_t AudioChannel)
+{
+    HdffCmdAvSetAudioChannel(mOsdDev, AudioChannel);
+}
+
+void cHdffCmdIf::CmdAvSetSyncShift(int16_t SyncShift)
+{
+    HdffCmdAvSetSyncShift(mOsdDev, SyncShift);
+}
+
+void cHdffCmdIf::CmdAvMuteAudio(uint8_t DecoderIndex, bool Mute)
+{
+    HdffCmdAvMuteAudio(mOsdDev, DecoderIndex, Mute);
+}
+
+void cHdffCmdIf::CmdOsdConfigure(const HdffOsdConfig_t * pConfig)
+{
+    HdffCmdOsdConfigure(mOsdDev, pConfig);
+}
+
+void cHdffCmdIf::CmdOsdReset(void)
+{
+    HdffCmdOsdReset(mOsdDev);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, HdffColorType_t ColorType)
+{
+    //printf("CreateDisplay %d %d %d\n", Width, Height, ColorType);
+    uint32_t newDisplay;
+
+    if (HdffCmdOsdCreateDisplay(mOsdDev, Width, Height, ColorType, &newDisplay) == 0)
+        return newDisplay;
+    LOG_ERROR_STR("Error creating display");
+    return HDFF_INVALID_HANDLE;
+}
+
+void cHdffCmdIf::CmdOsdDeleteDisplay(uint32_t hDisplay)
+{
+    //printf("DeleteDisplay\n");
+    HdffCmdOsdDeleteDisplay(mOsdDev, hDisplay);
+}
+
+void cHdffCmdIf::CmdOsdEnableDisplay(uint32_t hDisplay, bool Enable)
+{
+    //printf("EnableDisplay\n");
+    HdffCmdOsdEnableDisplay(mOsdDev, hDisplay, Enable);
+}
+
+void cHdffCmdIf::CmdOsdSetDisplayOutputRectangle(uint32_t hDisplay, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height)
+{
+    //printf("SetOutputRect %d %d %d %d %d\n", hDisplay, X, Y, Width, Height);
+    HdffCmdOsdSetDisplayOutputRectangle(mOsdDev, hDisplay, X, Y, Width, Height);
+}
+
+void cHdffCmdIf::CmdOsdSetDisplayClippingArea(uint32_t hDisplay, bool Enable, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height)
+{
+    //printf("SetClippingArea %d %d %d %d %d %d\n", hDisplay, Enable, X, Y, Width, Height);
+    HdffCmdOsdSetDisplayClippingArea(mOsdDev, hDisplay, Enable, X, Y, Width, Height);
+}
+
+void cHdffCmdIf::CmdOsdRenderDisplay(uint32_t hDisplay)
+{
+    //printf("Render %08X\n", hDisplay);
+    HdffCmdOsdRenderDisplay(mOsdDev, hDisplay);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreatePalette(HdffColorType_t ColorType, HdffColorFormat_t ColorFormat,
+                                         uint32_t NumColors, const uint32_t * pColors)
+{
+    uint32_t newPalette;
+    int err;
+
+    err = HdffCmdOsdCreatePalette(mOsdDev, ColorType, ColorFormat, NumColors,
+                                  pColors, &newPalette);
+    if (err == 0)
+        return newPalette;
+    LOG_ERROR_STR("Error creating palette");
+    return HDFF_INVALID_HANDLE;
+}
+
+void cHdffCmdIf::CmdOsdDeletePalette(uint32_t hPalette)
+{
+    HdffCmdOsdDeletePalette(mOsdDev, hPalette);
+}
+
+void cHdffCmdIf::CmdOsdSetDisplayPalette(uint32_t hDisplay, uint32_t hPalette)
+{
+    HdffCmdOsdSetDisplayPalette(mOsdDev, hDisplay, hPalette);
+}
+
+void cHdffCmdIf::CmdOsdSetPaletteColors(uint32_t hPalette, HdffColorFormat_t ColorFormat,
+                                        uint8_t StartColor, uint32_t NumColors, const uint32_t * pColors)
+{
+    HdffCmdOsdSetPaletteColors(mOsdDev, hPalette, ColorFormat, StartColor,
+                               NumColors, pColors);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreateFontFace(const uint8_t * pFontData, uint32_t DataSize)
+{
+    //printf("CreateFontFace %d\n", DataSize);
+    uint32_t newFontFace;
+    int err;
+
+    err = HdffCmdOsdCreateFontFace(mOsdDev, pFontData, DataSize, &newFontFace);
+    if (err == 0)
+        return newFontFace;
+    LOG_ERROR_STR("Error creating font face");
+    return HDFF_INVALID_HANDLE;
+}
+
+void cHdffCmdIf::CmdOsdDeleteFontFace(uint32_t hFontFace)
+{
+    //printf("DeleteFontFace %08X\n", hFontFace);
+    HdffCmdOsdDeleteFontFace(mOsdDev, hFontFace);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreateFont(uint32_t hFontFace, uint32_t Size)
+{
+    //printf("CreateFont %d\n", Size);
+    uint32_t newFont;
+    int err;
+
+    err = HdffCmdOsdCreateFont(mOsdDev, hFontFace, Size, &newFont);
+    if (err == 0)
+        return newFont;
+    LOG_ERROR_STR("Error creating font");
+    return HDFF_INVALID_HANDLE;
+}
+
+void cHdffCmdIf::CmdOsdDeleteFont(uint32_t hFont)
+{
+    //printf("DeleteFont %08X\n", hFont);
+    HdffCmdOsdDeleteFont(mOsdDev, hFont);
+}
+
+void cHdffCmdIf::CmdOsdDrawRectangle(uint32_t hDisplay, int X, int Y, int Width, int Height, uint32_t Color)
+{
+    //printf("Rect (%d,%d) %d x %d, %08X\n", X, Y, Width, Height, Color);
+    HdffCmdOsdDrawRectangle(mOsdDev, hDisplay, X, Y, Width, Height, Color);
+}
+
+void cHdffCmdIf::CmdOsdDrawEllipse(uint32_t hDisplay, int CX, int CY, int RadiusX, int RadiusY,
+                                 uint32_t Color, uint32_t Flags)
+{
+    //printf("Ellipse (%d,%d) %d x %d, %08X, %d\n", CX, CY, RadiusX, RadiusY, Color, Flags);
+    HdffCmdOsdDrawEllipse(mOsdDev, hDisplay, CX, CY, RadiusX, RadiusY, Color, Flags);
+}
+
+void cHdffCmdIf::CmdOsdDrawSlope(uint32_t hDisplay, int X, int Y, int Width, int Height,
+                                 uint32_t Color, uint32_t Type)
+{
+    //printf("Slope (%d,%d) %d x %d, %08X, %X\n", X, Y, Width, Height, Color, Type);
+    HdffCmdOsdDrawSlope(mOsdDev, hDisplay, X, Y, Width, Height, Color, Type);
+}
+
+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);
+    HdffCmdOsdDrawText(mOsdDev, hDisplay, hFont, X, Y, pText, Color);
+}
+
+void cHdffCmdIf::CmdOsdDrawUtf8Text(uint32_t hDisplay, uint32_t hFont, int X, int Y, const char * pText, uint32_t Color)
+{
+    //printf("Text(UTF8) %08X (%d,%d), %s, %08X\n", hFont, X, Y, pText, Color);
+    HdffCmdOsdDrawUtf8Text(mOsdDev, hDisplay, hFont, X, Y, pText, Color);
+}
+
+void cHdffCmdIf::CmdOsdDrawTextW(uint32_t hDisplay, uint32_t hFont, int X, int Y, const uint16_t * pText, uint32_t Color)
+{
+    //printf("TextW %08X (%d,%d), %08X\n", hFont, X, Y, Color);
+    HdffCmdOsdDrawWideText(mOsdDev, hDisplay, hFont, X, Y, pText, Color);
+}
+
+void cHdffCmdIf::CmdOsdDrawBitmap(uint32_t hDisplay, int X, int Y, const uint8_t * pBitmap,
+                                  int BmpWidth, int BmpHeight, int BmpSize,
+                                  HdffColorType_t ColorType, uint32_t hPalette)
+{
+    //printf("Bitmap %08X (%d,%d) %d x %d, %08X\n", hDisplay, X, Y, BmpWidth, BmpHeight, hPalette);
+    HdffCmdOsdDrawBitmap(mOsdDev, hDisplay, X, Y, pBitmap, BmpWidth, BmpHeight,
+                         BmpSize, ColorType, hPalette);
+}
+
+void cHdffCmdIf::CmdOsdSaveRegion(uint32_t hDisplay, int X, int Y, int Width, int Height)
+{
+    HdffCmdOsdSaveRegion(mOsdDev, hDisplay, X, Y, Width, Height);
+}
+
+void cHdffCmdIf::CmdOsdRestoreRegion(uint32_t hDisplay)
+{
+    HdffCmdOsdRestoreRegion(mOsdDev, hDisplay);
+}
+
+void cHdffCmdIf::CmdMuxSetVideoOut(HdffVideoOut_t VideoOut)
+{
+    HdffCmdMuxSetVideoOut(mOsdDev, VideoOut);
+}
+
+void cHdffCmdIf::CmdMuxSetVolume(uint8_t Volume)
+{
+    HdffCmdMuxSetVolume(mOsdDev, Volume);
+}
+
+void cHdffCmdIf::CmdMuxMuteAudio(bool Mute)
+{
+    HdffCmdMuxMuteAudio(mOsdDev, Mute);
+}
+
+void cHdffCmdIf::CmdHdmiSetVideoMode(HdffVideoMode_t VideoMode)
+{
+    //printf("HdmiSetVideoMode %d\n", VideoMode);
+    HdffCmdHdmiSetVideoMode(mOsdDev, VideoMode);
+}
+
+void cHdffCmdIf::CmdHdmiConfigure(const HdffHdmiConfig_t * pConfig)
+{
+    HdffCmdHdmiConfigure(mOsdDev, pConfig);
+}
+
+void cHdffCmdIf::CmdHdmiSendCecCommand(HdffCecCommand_t Command)
+{
+    HdffCmdHdmiSendCecCommand(mOsdDev, Command);
+}
+
+void cHdffCmdIf::CmdRemoteSetProtocol(HdffRemoteProtocol_t Protocol)
+{
+    //printf("%s %d\n", __func__, Protocol);
+    HdffCmdRemoteSetProtocol(mOsdDev, Protocol);
+}
+
+void cHdffCmdIf::CmdRemoteSetAddressFilter(bool Enable, uint32_t Address)
+{
+    //printf("%s %d %d\n", __func__, Enable, Address);
+    HdffCmdRemoteSetAddressFilter(mOsdDev, Enable, Address);
+}
+
+} // end of namespace
diff --git a/hdffcmd.h b/hdffcmd.h
new file mode 100644
index 0000000..891bc7e
--- /dev/null
+++ b/hdffcmd.h
@@ -0,0 +1,100 @@
+/*
+ * hdffcmd.h: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#ifndef _HDFF_CMD_H_
+#define _HDFF_CMD_H_
+
+#include "libhdffcmd/hdffcmd.h"
+
+namespace HDFF
+{
+
+class cHdffCmdIf
+{
+private:
+    int mOsdDev;
+
+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, HdffVideoStreamType_t StreamType, bool PlaybackMode = false);
+    void CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, HdffAudioStreamType_t StreamType, HdffAvContainerType_t ContainerType = HDFF_AV_CONTAINER_PES);
+    void CmdAvSetPcrPid(uint8_t DecoderIndex, uint16_t PcrPid);
+    void CmdAvSetTeletextPid(uint8_t DecoderIndex, uint16_t TeletextPid);
+    void CmdAvSetVideoWindow(uint8_t DecoderIndex, bool Enable, uint16_t X, uint16_t Y, uint16_t Width, uint16_t Height);
+    void CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, HdffVideoStreamType_t StreamType);
+    void CmdAvSetDecoderInput(uint8_t DecoderIndex, uint8_t DemultiplexerIndex);
+    void CmdAvSetDemultiplexerInput(uint8_t DemultiplexerIndex, uint8_t TsInputIndex);
+    void CmdAvSetVideoFormat(uint8_t DecoderIndex, const HdffVideoFormat_t * pVideoFormat);
+    void CmdAvSetVideoOutputMode(uint8_t DecoderIndex, HdffVideoOutputMode_t OutputMode);
+    void CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc);
+    void CmdAvFlushBuffer(uint8_t DecoderIndex, bool FlushAudio, bool FlushVideo);
+    void CmdAvEnableSync(uint8_t DecoderIndex, bool EnableSync);
+    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(HdffAudioDownmixMode_t DownmixMode);
+    void CmdAvSetAudioChannel(uint8_t AudioChannel);
+    void CmdAvSetSyncShift(int16_t SyncShift);
+    void CmdAvMuteAudio(uint8_t DecoderIndex, bool Mute);
+
+    void CmdOsdConfigure(const HdffOsdConfig_t * pConfig);
+    void CmdOsdReset(void);
+
+    uint32_t CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, HdffColorType_t ColorType);
+    void CmdOsdDeleteDisplay(uint32_t hDisplay);
+    void CmdOsdEnableDisplay(uint32_t hDisplay, bool Enable);
+    void CmdOsdSetDisplayOutputRectangle(uint32_t hDisplay, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height);
+    void CmdOsdSetDisplayClippingArea(uint32_t hDisplay, bool Enable, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height);
+    void CmdOsdRenderDisplay(uint32_t hDisplay);
+
+    uint32_t CmdOsdCreatePalette(HdffColorType_t ColorType, HdffColorFormat_t ColorFormat,
+                                 uint32_t NumColors, const uint32_t * pColors);
+    void CmdOsdDeletePalette(uint32_t hPalette);
+    void CmdOsdSetDisplayPalette(uint32_t hDisplay, uint32_t hPalette);
+    void CmdOsdSetPaletteColors(uint32_t hPalette, HdffColorFormat_t 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 CmdOsdDrawSlope(uint32_t hDisplay, int X, int Y, int Width, int Height, uint32_t Color, uint32_t Type);
+    void CmdOsdDrawText(uint32_t hDisplay, uint32_t hFont, int X, int Y, const char * pText, uint32_t Color);
+    void CmdOsdDrawUtf8Text(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,
+                          HdffColorType_t ColorType, uint32_t hPalette);
+    void CmdOsdSaveRegion(uint32_t hDisplay, int X, int Y, int Width, int Height);
+    void CmdOsdRestoreRegion(uint32_t hDisplay);
+
+    void CmdMuxSetVideoOut(HdffVideoOut_t VideoOut);
+    void CmdMuxSetVolume(uint8_t Volume);
+    void CmdMuxMuteAudio(bool Mute);
+
+    void CmdHdmiSetVideoMode(HdffVideoMode_t VideoMode);
+    void CmdHdmiConfigure(const HdffHdmiConfig_t * pConfig);
+    void CmdHdmiSendCecCommand(HdffCecCommand_t Command);
+
+    void CmdRemoteSetProtocol(HdffRemoteProtocol_t Protocol);
+    void CmdRemoteSetAddressFilter(bool Enable, uint32_t Address);
+};
+
+} // end of namespace
+
+#endif
diff --git a/hdffosd.c b/hdffosd.c
new file mode 100644
index 0000000..089ffe7
--- /dev/null
+++ b/hdffosd.c
@@ -0,0 +1,844 @@
+/*
+ * 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.
+ */
+
+#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 mChanged;
+    uint32_t mDisplay;
+    tFontFace mFontFaces[MAX_NUM_FONTFACES];
+    tFont mFonts[MAX_NUM_FONTS];
+    uint32_t mBitmapPalette;
+    uint32_t mBitmapColors[256];
+
+    bool mSupportsUtf8Text;
+
+protected:
+    virtual void SetActive(bool On);
+public:
+    cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
+    virtual ~cHdffOsd();
+    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;
+    HdffOsdConfig_t config;
+
+    //printf("cHdffOsd %d, %d, %d\n", Left, Top, Level);
+    mHdffCmdIf = pHdffCmdIf;
+    mLeft = Left;
+    mTop = Top;
+    mChanged = false;
+    mBitmapPalette = HDFF_INVALID_HANDLE;
+
+    mSupportsUtf8Text = false;
+    if (mHdffCmdIf->CmdGetFirmwareVersion(NULL, 0) >= 0x309)
+        mSupportsUtf8Text = true;
+
+    memset(&config, 0, sizeof(config));
+    config.FontKerning = true;
+    config.FontAntialiasing = Setup.AntiAlias ? true : false;
+    mHdffCmdIf->CmdOsdConfigure(&config);
+
+    gHdffSetup.GetOsdSize(mDispWidth, mDispHeight, pixelAspect);
+    mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF_COLOR_TYPE_ARGB8888);
+    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, HDFF_SIZE_FULL_SCREEN, HDFF_SIZE_FULL_SCREEN);
+    for (int i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        mFontFaces[i].Name = "";
+        mFontFaces[i].Handle = HDFF_INVALID_HANDLE;
+    }
+    for (int i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        mFonts[i].hFontFace = HDFF_INVALID_HANDLE;
+        mFonts[i].Size = 0;
+        mFonts[i].Handle = HDFF_INVALID_HANDLE;
+    }
+}
+
+cHdffOsd::~cHdffOsd()
+{
+    //printf("~cHdffOsd %d %d\n", mLeft, mTop);
+    if (Active()) {
+        mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    }
+    SetActive(false);
+
+    for (int i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        if (mFonts[i].Handle == HDFF_INVALID_HANDLE)
+            break;
+        mHdffCmdIf->CmdOsdDeleteFont(mFonts[i].Handle);
+    }
+    for (int i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        if (mFontFaces[i].Handle == HDFF_INVALID_HANDLE)
+            break;
+        mHdffCmdIf->CmdOsdDeleteFontFace(mFontFaces[i].Handle);
+    }
+
+    if (mBitmapPalette != HDFF_INVALID_HANDLE)
+        mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+    mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+}
+
+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)
+{
+    eOsdError error;
+    cBitmap * bitmap;
+
+    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);
+    }
+    if (Active() && mDisplay != HDFF_INVALID_HANDLE)
+    {
+        mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    }
+    error = cOsd::SetAreas(Areas, NumAreas);
+
+    for (int i = 0; (bitmap = GetBitmap(i)) != NULL; i++)
+    {
+        bitmap->Clean();
+    }
+
+    return error;
+}
+
+void cHdffOsd::SetActive(bool On)
+{
+    if (On != Active())
+    {
+        cOsd::SetActive(On);
+        if (On)
+        {
+            if (GetBitmap(0)) // only flush here if there are already bitmaps
+                Flush();
+        }
+        else if (mDisplay != HDFF_INVALID_HANDLE)
+        {
+            mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+            mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+        }
+    }
+}
+
+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;
+}
+
+void cHdffOsd::RestoreRegion(void)
+{
+    mHdffCmdIf->CmdOsdRestoreRegion(mDisplay);
+    mChanged = true;
+}
+
+void cHdffOsd::DrawPixel(int x, int y, tColor Color)
+{
+    //printf("DrawPixel\n");
+}
+
+void cHdffOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
+{
+    //printf("DrawBitmap %d %d %d x %d\n", x, y, Bitmap.Width(), Bitmap.Height());
+    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 == HDFF_INVALID_HANDLE)
+    {
+        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF_COLOR_TYPE_CLUT8,
+                HDFF_COLOR_FORMAT_ARGB, numColors, mBitmapColors);
+    }
+    else
+    {
+        mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
+                HDFF_COLOR_FORMAT_ARGB, 0, numColors, mBitmapColors);
+    }
+    int width = Bitmap.Width();
+    int height = Bitmap.Height();
+    int chunk = MAX_BITMAP_SIZE / width;
+    if (chunk > height)
+        chunk = height;
+    for (int yc = 0; yc < height; yc += chunk)
+    {
+        int hc = chunk;
+        if (yc + hc > height)
+            hc = height - yc;
+        mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y + yc,
+            (uint8_t *) Bitmap.Data(0, yc), width, hc,
+            width * hc, HDFF_COLOR_TYPE_CLUT8, mBitmapPalette);
+    }
+    mChanged = true;
+}
+
+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 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 == HDFF_INVALID_HANDLE)
+            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 != HDFF_INVALID_HANDLE)
+                            {
+                                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 == HDFF_INVALID_HANDLE)
+            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 != HDFF_INVALID_HANDLE)
+            {
+                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)
+    {
+        if (Width)
+        {
+            if ((Alignment & taLeft) != 0)
+            {
+#if (APIVERSNUM >= 10728)
+                if ((Alignment & taBorder) != 0)
+                    x += max(h / TEXT_ALIGN_BORDER, 1);
+#endif
+            }
+            else if ((Alignment & taRight) != 0)
+            {
+                if (w < Width)
+                    x += Width - w;
+#if (APIVERSNUM >= 10728)
+                if ((Alignment & taBorder) != 0)
+                    x -= max(h / TEXT_ALIGN_BORDER, 1);
+#endif
+            }
+            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;
+            }
+        }
+    }
+#if 0
+    if (mSupportsUtf8Text)
+    {
+        mHdffCmdIf->CmdOsdDrawUtf8Text(mDisplay, pFont->Handle, x + mLeft, y + mTop + h, s, ColorFg);
+    }
+    else
+#endif
+    {
+        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->CmdOsdSetDisplayClippingArea(mDisplay, false, 0, 0, 0, 0);
+    mChanged = true;
+}
+
+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;
+}
+
+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_DRAW_QUARTER_TOP_RIGHT;
+            else
+                flags = HDFF_DRAW_QUARTER_TOP_RIGHT_INVERTED;
+            cx = x1;
+            cy = y2;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 2:
+            if (Quadrants > 0)
+                flags = HDFF_DRAW_QUARTER_TOP_LEFT;
+            else
+                flags = HDFF_DRAW_QUARTER_TOP_LEFT_INVERTED;
+            cx = x2;
+            cy = y2;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 3:
+            if (Quadrants > 0)
+                flags = HDFF_DRAW_QUARTER_BOTTOM_LEFT;
+            else
+                flags = HDFF_DRAW_QUARTER_BOTTOM_LEFT_INVERTED;
+            cx = x2;
+            cy = y1;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 4:
+            if (Quadrants > 0)
+                flags = HDFF_DRAW_QUARTER_BOTTOM_RIGHT;
+            else
+                flags = HDFF_DRAW_QUARTER_BOTTOM_RIGHT_INVERTED;
+            cx = x1;
+            cy = y1;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 5:
+            flags = HDFF_DRAW_HALF_RIGHT;
+            cx = x1;
+            cy = (y1 + y2) / 2;
+            rx = x2 - x1;
+            ry = (y2 - y1) / 2;
+            break;
+        case 6:
+            flags = HDFF_DRAW_HALF_TOP;
+            cx = (x1 + x2) / 2;
+            cy = y2;
+            rx = (x2 - x1) / 2;
+            ry = y2 - y1;
+            break;
+        case 7:
+            flags = HDFF_DRAW_HALF_LEFT;
+            cx = x2;
+            cy = (y1 + y2) / 2;
+            rx = x2 - x1;
+            ry = (y2 - y1) / 2;
+            break;
+        case 8:
+            flags = HDFF_DRAW_HALF_BOTTOM;
+            cx = (x1 + x2) / 2;
+            cy = y1;
+            rx = (x2 - x1) / 2;
+            ry = y2 - y1;
+            break;
+        default:
+            flags = HDFF_DRAW_FULL;
+            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;
+}
+
+void cHdffOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
+{
+    //printf("DrawSlope\n");
+    mHdffCmdIf->CmdOsdDrawSlope(mDisplay, mLeft + x1, mTop + y1,
+                                x2 - x1 + 1, y2 - y1 + 1, Color, Type);
+    mChanged = true;
+}
+
+void cHdffOsd::Flush(void)
+{
+    if (!Active())
+        return;
+
+    //printf("Flush\n");
+    cBitmap * Bitmap;
+
+    for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++)
+    {
+        int x1;
+        int y1;
+        int x2;
+        int y2;
+
+        if (Bitmap->Dirty(x1, y1, x2, y2))
+        {
+            //printf("dirty %d %d, %d %d\n", x1, y1, x2, y2);
+            DrawBitmap(0, 0, *Bitmap);
+            Bitmap->Clean();
+        }
+    }
+
+    if (!mChanged)
+        return;
+
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+
+    mChanged = false;
+}
+
+
+class cHdffOsdRaw : public cOsd
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    int mDispWidth;
+    int mDispHeight;
+    bool refresh;
+    uint32_t mDisplay;
+    uint32_t mBitmapPalette;
+    uint32_t mBitmapColors[256];
+
+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;
+    refresh = true;
+    mBitmapPalette = HDFF_INVALID_HANDLE;
+    mDisplay = HDFF_INVALID_HANDLE;
+
+    gHdffSetup.GetOsdSize(mDispWidth, mDispHeight, pixelAspect);
+}
+
+cHdffOsdRaw::~cHdffOsdRaw()
+{
+    //printf("~cHdffOsdRaw %d %d\n", Left(), Top());
+    if (mDisplay != HDFF_INVALID_HANDLE)
+    {
+        mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    }
+    if (mBitmapPalette != HDFF_INVALID_HANDLE)
+        mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+    mBitmapPalette = HDFF_INVALID_HANDLE;
+    if (mDisplay != HDFF_INVALID_HANDLE)
+       mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+    mDisplay = HDFF_INVALID_HANDLE;
+}
+
+void cHdffOsdRaw::SetActive(bool On)
+{
+    if (On != Active())
+    {
+        cOsd::SetActive(On);
+        if (On)
+        {
+            if (mDisplay == HDFF_INVALID_HANDLE)
+            {
+                mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF_COLOR_TYPE_ARGB8888);
+                if (mDisplay != HDFF_INVALID_HANDLE)
+                    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, HDFF_SIZE_FULL_SCREEN, HDFF_SIZE_FULL_SCREEN);
+            }
+            refresh = true;
+            if (GetBitmap(0)) // only flush here if there are already bitmaps
+                Flush();
+        }
+        else
+        {
+            if (mDisplay != HDFF_INVALID_HANDLE)
+            {
+                mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+                mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+            }
+            if (mBitmapPalette != HDFF_INVALID_HANDLE)
+                mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+            mBitmapPalette = HDFF_INVALID_HANDLE;
+            if (mDisplay != HDFF_INVALID_HANDLE)
+                mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+            mDisplay = HDFF_INVALID_HANDLE;
+        }
+    }
+}
+
+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);
+    }
+    if (mDisplay != HDFF_INVALID_HANDLE)
+    {
+        mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+        refresh = true;
+    }
+    return cOsd::SetAreas(Areas, NumAreas);
+}
+
+void cHdffOsdRaw::Flush(void)
+{
+    if (!Active() || (mDisplay == HDFF_INVALID_HANDLE))
+        return;
+#ifdef MEASURE_OSD_TIME
+    struct timeval start;
+    struct timeval end;
+    struct timezone timeZone;
+    gettimeofday(&start, &timeZone);
+#endif
+
+    bool render = false;
+    if (IsTrueColor())
+    {
+        uint8_t * buffer = 0;
+        if (gHdffSetup.TrueColorFormat != 0)
+        {
+            buffer = new uint8_t[MAX_BITMAP_SIZE];
+            if (!buffer)
+                return;
+        }
+        LOCK_PIXMAPS;
+#if (APIVERSNUM >= 20110)
+        while (cPixmapMemory *pm = dynamic_cast<cPixmapMemory *>(RenderPixmaps()))
+#else
+        while (cPixmapMemory *pm = RenderPixmaps())
+#endif
+        {
+            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;
+                if (gHdffSetup.TrueColorFormat == 0) // ARGB8888 (32 bit)
+                {
+                    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
+                        Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y() + y,
+                        pm->Data() + y * d, w, hc, hc * d,
+                        HDFF_COLOR_TYPE_ARGB8888, HDFF_INVALID_HANDLE);
+                }
+                else if (gHdffSetup.TrueColorFormat == 1) // ARGB8565 (24 bit)
+                {
+                    const tColor * pixmapData = (const tColor *) (pm->Data() + y * d);
+                    uint8_t * bitmapData = buffer;
+                    for (int i = 0; i < hc * w; i++)
+                    {
+                        bitmapData[2] =  (pixmapData[i] & 0xFF000000) >> 24;
+                        bitmapData[1] = ((pixmapData[i] & 0x00F80000) >> 16)
+                                      | ((pixmapData[i] & 0x0000E000) >> 13);
+                        bitmapData[0] = ((pixmapData[i] & 0x00001C00) >> 5)
+                                      | ((pixmapData[i] & 0x000000F8) >> 3);
+                        bitmapData += 3;
+                    }
+                    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
+                        Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y() + y,
+                        buffer, w, hc, hc * w * 3,
+                        HDFF_COLOR_TYPE_ARGB8565, HDFF_INVALID_HANDLE);
+                }
+                else if (gHdffSetup.TrueColorFormat == 2) // ARGB4444 (16 bit)
+                {
+                    const tColor * pixmapData = (const tColor *) (pm->Data() + y * d);
+                    uint16_t * bitmapData = (uint16_t *) buffer;
+                    for (int i = 0; i < hc * w; i++)
+                    {
+                        bitmapData[i] = ((pixmapData[i] & 0xF0000000) >> 16)
+                                      | ((pixmapData[i] & 0x00F00000) >> 12)
+                                      | ((pixmapData[i] & 0x0000F000) >> 8)
+                                      | ((pixmapData[i] & 0x000000F0) >> 4);
+                    }
+                    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
+                        Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y() + y,
+                        buffer, w, hc, hc * w * 2,
+                        HDFF_COLOR_TYPE_ARGB4444, HDFF_INVALID_HANDLE);
+                }
+            }
+#if (APIVERSNUM >= 20110)
+            DestroyPixmap(pm);
+#else
+            delete pm;
+#endif
+            render = true;
+        }
+        if (buffer)
+            delete[] buffer;
+    }
+    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 (refresh || bitmap->Dirty(x1, y1, x2, y2))
+            {
+                if (refresh)
+                {
+                    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 == HDFF_INVALID_HANDLE)
+                    {
+                        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF_COLOR_TYPE_CLUT8,
+                            HDFF_COLOR_FORMAT_ARGB, numColors, mBitmapColors);
+                    }
+                    else
+                    {
+                        mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
+                            HDFF_COLOR_FORMAT_ARGB, 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_COLOR_TYPE_CLUT8, mBitmapPalette);
+                }
+                render = true;
+            }
+            bitmap->Clean();
+        }
+        delete[] buffer;
+    }
+    if (render)
+    {
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+#ifdef MEASURE_OSD_TIME
+        gettimeofday(&end, &timeZone);
+        int timeNeeded = end.tv_usec - start.tv_usec;
+        timeNeeded += (end.tv_sec - start.tv_sec) * 1000000;
+        printf("time = %d\n", timeNeeded);
+#endif
+    }
+    refresh = false;
+}
+
+
+
+
+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 --git a/hdffosd.h b/hdffosd.h
new file mode 100644
index 0000000..c8eaf46
--- /dev/null
+++ b/hdffosd.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#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 --git a/libhdffcmd/Makefile b/libhdffcmd/Makefile
new file mode 100644
index 0000000..216cdba
--- /dev/null
+++ b/libhdffcmd/Makefile
@@ -0,0 +1,68 @@
+#
+# Makefile for the HDFF firmware command interface library
+#
+
+VERSION = 0.1.0
+
+INSTALL_PATH         ?= /usr/local
+INSTALL_LIB_PATH     ?= $(INSTALL_PATH)/lib
+INSTALL_INCLUDE_PATH ?= $(INSTALL_PATH)/include
+
+LIB_NAME = libhdffcmd
+
+LIB_OBJS = bitbuffer.o hdffcmd_av.o hdffcmd_base.o hdffcmd_generic.o \
+           hdffcmd_hdmi.o hdffcmd_mux.o hdffcmd_osd.o hdffcmd_remote.o
+
+LIB_HEADERS = hdffcmd.h hdffcmd_av.h hdffcmd_generic.h hdffcmd_hdmi.h \
+              hdffcmd_mux.h hdffcmd_osd.h hdffcmd_remote.h
+
+LIB_STATIC = $(LIB_NAME).a
+LIB_SHARED = $(LIB_NAME)-$(VERSION).so
+
+CC      ?= gcc
+CFLAGS  ?= -g -O2 -fPIC -Wall
+AR      ?= ar
+ARFLAGS ?= r
+
+### Implicit rules:
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+### Dependencies:
+
+MAKEDEP = $(CC) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+	@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(LIB_OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: $(LIB_STATIC) $(LIB_SHARED)
+
+$(LIB_STATIC): $(LIB_OBJS)
+	$(AR) $(ARFLAGS) $(LIB_STATIC) $(LIB_OBJS)
+
+$(LIB_SHARED): $(LIB_OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -fPIC -shared -o $(LIB_SHARED) $(LIB_OBJS)
+	ln -sf $(LIB_SHARED) $(LIB_NAME).so
+
+clean:
+	@-rm -f $(LIB_OBJS) $(DEPFILE) $(LIB_STATIC) $(LIB_NAME)*.so
+
+install: $(LIB_SHARED)
+	chown root $(LIB_SHARED)
+	chgrp root $(LIB_SHARED)
+	chmod 0755 $(LIB_SHARED)
+	cp -f $(LIB_SHARED) $(INSTALL_LIB_PATH)/
+	ln -sf $(LIB_SHARED) $(INSTALL_LIB_PATH)/$(LIB_NAME).so
+	mkdir -p  $(INSTALL_INCLUDE_PATH)/libhdffcmd
+	list='$(LIB_HEADERS)'; \
+	for headerfile in $$list; do \
+	  cp -f $$headerfile $(INSTALL_INCLUDE_PATH)/libhdffcmd/ ; \
+	  chown root $(INSTALL_INCLUDE_PATH)/libhdffcmd/$$headerfile ; \
+	  chgrp root $(INSTALL_INCLUDE_PATH)/libhdffcmd/$$headerfile ; \
+	  chmod 0644 $(INSTALL_INCLUDE_PATH)/libhdffcmd/$$headerfile ; \
+	done
diff --git a/libhdffcmd/bitbuffer.c b/libhdffcmd/bitbuffer.c
new file mode 100644
index 0000000..b85990d
--- /dev/null
+++ b/libhdffcmd/bitbuffer.c
@@ -0,0 +1,79 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include <string.h>
+
+#include "bitbuffer.h"
+
+void BitBuffer_Init(BitBuffer_t * BitBuffer,
+                    uint8_t * Data, uint32_t MaxLength)
+{
+    memset(Data, 0, MaxLength);
+    BitBuffer->Data = Data;
+    BitBuffer->MaxLength = MaxLength * 8;
+    BitBuffer->BitPos = 0;
+}
+
+void BitBuffer_SetBits(BitBuffer_t * BitBuffer, int NumBits, uint32_t Data)
+{
+    uint32_t nextBitPos;
+    uint32_t bytePos;
+    uint32_t bitsInByte;
+    int shift;
+
+    if (NumBits <= 0 || NumBits > 32)
+        return;
+
+    nextBitPos = BitBuffer->BitPos + NumBits;
+
+    if (nextBitPos > BitBuffer->MaxLength)
+        return;
+
+    bytePos = BitBuffer->BitPos / 8;
+    bitsInByte = BitBuffer->BitPos % 8;
+
+    BitBuffer->Data[bytePos] &= (uint8_t) (0xFF << (8 - bitsInByte));
+    shift = NumBits - (8 - bitsInByte);
+    if (shift > 0)
+        BitBuffer->Data[bytePos] |= (uint8_t) (Data >> shift);
+    else
+        BitBuffer->Data[bytePos] |= (uint8_t) (Data << (-shift));
+    NumBits -= 8 - bitsInByte;
+    bytePos++;
+    while (NumBits > 0)
+    {
+        shift = NumBits - 8;
+        if (shift > 0)
+            BitBuffer->Data[bytePos] = (uint8_t) (Data >> shift);
+        else
+            BitBuffer->Data[bytePos] = (uint8_t) (Data << (-shift));
+        NumBits -= 8;
+        bytePos++;
+    }
+    BitBuffer->BitPos = nextBitPos;
+}
+
+uint32_t BitBuffer_GetByteLength(BitBuffer_t * BitBuffer)
+{
+    return (BitBuffer->BitPos + 7) / 8;
+}
diff --git a/libhdffcmd/bitbuffer.h b/libhdffcmd/bitbuffer.h
new file mode 100644
index 0000000..5bdc23b
--- /dev/null
+++ b/libhdffcmd/bitbuffer.h
@@ -0,0 +1,43 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef BITBUFFER_H
+#define BITBUFFER_H
+
+#include <stdint.h>
+
+typedef struct BitBuffer_t
+{
+    uint8_t * Data;
+    uint32_t MaxLength;
+    uint32_t BitPos;
+} BitBuffer_t;
+
+void BitBuffer_Init(BitBuffer_t * BitBuffer,
+                    uint8_t * Data, uint32_t MaxLength);
+
+void BitBuffer_SetBits(BitBuffer_t * BitBuffer, int NumBits, uint32_t Data);
+
+uint32_t BitBuffer_GetByteLength(BitBuffer_t * BitBuffer);
+
+#endif /* BITBUFFER_H */
diff --git a/libhdffcmd/hdffcmd.h b/libhdffcmd/hdffcmd.h
new file mode 100644
index 0000000..8d05782
--- /dev/null
+++ b/libhdffcmd/hdffcmd.h
@@ -0,0 +1,42 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_H
+#define HDFFCMD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hdffcmd_av.h"
+#include "hdffcmd_generic.h"
+#include "hdffcmd_hdmi.h"
+#include "hdffcmd_mux.h"
+#include "hdffcmd_osd.h"
+#include "hdffcmd_remote.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HDFFCMD_H */
diff --git a/libhdffcmd/hdffcmd_av.c b/libhdffcmd/hdffcmd_av.c
new file mode 100644
index 0000000..ea17ceb
--- /dev/null
+++ b/libhdffcmd/hdffcmd_av.c
@@ -0,0 +1,506 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdAvSetPlayMode(int OsdDevice, uint8_t PlayMode, int Realtime)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_PLAY_MODE);
+    BitBuffer_SetBits(&cmdBuf, 1, Realtime ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 7, PlayMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffVideoStreamType_t StreamType)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, StreamType);
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffAudioStreamType_t StreamType,
+                         HdffAvContainerType_t ContainerType)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, StreamType);
+    BitBuffer_SetBits(&cmdBuf, 2, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 1, ContainerType);
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetPcrPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_PCR_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetTeletextPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_TELETEXT_PID);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 13, Pid);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoWindow(int OsdDevice, uint8_t DecoderIndex, int Enable,
+                            uint16_t X, uint16_t Y, uint16_t Width,
+                            uint16_t Height)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_WINDOW);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    if (Enable)
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    else
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvShowStillImage(int OsdDevice, uint8_t DecoderIndex,
+                            const uint8_t * StillImage, int Size,
+                            HdffVideoStreamType_t StreamType)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+    int err;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = StillImage;
+    osd_data.data_length = Size;
+    err = ioctl(OsdDevice, OSD_RAW_DATA, &osd_data);
+    if (err != 0)
+        return err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SHOW_STILL_IMAGE);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, StreamType);
+    BitBuffer_SetBits(&cmdBuf, 16, osd_data.data_handle);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetDecoderInput(int OsdDevice, uint8_t DecoderIndex,
+                             uint8_t DemultiplexerIndex)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_DECODER_INPUT);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, DemultiplexerIndex);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetDemultiplexerInput(int OsdDevice, uint8_t DemultiplexerIndex,
+                                   uint8_t TsInputIndex)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_DEMULTIPLEXER_INPUT);
+    BitBuffer_SetBits(&cmdBuf, 4, DemultiplexerIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, TsInputIndex);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoFormat(int OsdDevice, uint8_t DecoderIndex,
+                            const HdffVideoFormat_t * VideoFormat)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_FORMAT);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, VideoFormat->AutomaticEnabled ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, VideoFormat->AfdEnabled ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 2, VideoFormat->TvFormat);
+    BitBuffer_SetBits(&cmdBuf, 8, VideoFormat->VideoConversion);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoOutputMode(int OsdDevice, uint8_t DecoderIndex,
+                                HdffVideoOutputMode_t OutputMode)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_OUTPUT_MODE);
+    BitBuffer_SetBits(&cmdBuf, 8, OutputMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetStc(int OsdDevice, uint8_t DecoderIndex, uint64_t Stc)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_STC);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 3, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 1, (uint32_t) (Stc >> 32));
+    BitBuffer_SetBits(&cmdBuf, 32, (uint32_t) Stc);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvFlushBuffer(int OsdDevice, uint8_t DecoderIndex, int FlushAudio,
+                         int FlushVideo)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_FLUSH_BUFFER);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    if (FlushAudio)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    if (FlushVideo)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvEnableSync(int OsdDevice, uint8_t DecoderIndex, int SyncAudio,
+                        int SyncVideo)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_ENABLE_SYNC);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, SyncAudio ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, SyncVideo ? 1 : 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetVideoSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_VIDEO_SPEED);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0);
+    BitBuffer_SetBits(&cmdBuf, 32, Speed);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_SPEED);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 4, 0);
+    BitBuffer_SetBits(&cmdBuf, 32, Speed);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvEnableVideoAfterStop(int OsdDevice, uint8_t DecoderIndex,
+                                  int EnableVideoAfterStop)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_ENABLE_VIDEO_AFTER_STOP);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, EnableVideoAfterStop ? 1 : 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioDelay(int OsdDevice, int16_t Delay)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_DELAY);
+    BitBuffer_SetBits(&cmdBuf, 16, Delay);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioDownmix(int OsdDevice, HdffAudioDownmixMode_t DownmixMode)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_DOWNMIX);
+    BitBuffer_SetBits(&cmdBuf, 8, DownmixMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetAudioChannel(int OsdDevice, uint8_t AudioChannel)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_AUDIO_CHANNEL);
+    BitBuffer_SetBits(&cmdBuf, 8, AudioChannel);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvSetSyncShift(int OsdDevice, int16_t SyncShift)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_SET_OPTIONS);
+    BitBuffer_SetBits(&cmdBuf, 1, 1);
+    BitBuffer_SetBits(&cmdBuf, 31, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 16, SyncShift);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvMuteAudio(int OsdDevice, uint8_t DecoderIndex, int Mute)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_MUTE_AUDIO);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, Mute ? 1 : 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdAvMuteVideo(int OsdDevice, uint8_t DecoderIndex, int Mute)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_AV_DECODER,
+                       HDFF_MSG_AV_MUTE_VIDEO);
+    BitBuffer_SetBits(&cmdBuf, 4, DecoderIndex);
+    BitBuffer_SetBits(&cmdBuf, 1, Mute ? 1 : 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff --git a/libhdffcmd/hdffcmd_av.h b/libhdffcmd/hdffcmd_av.h
new file mode 100644
index 0000000..3638141
--- /dev/null
+++ b/libhdffcmd/hdffcmd_av.h
@@ -0,0 +1,159 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_AV_H
+#define HDFFCMD_AV_H
+
+typedef enum HdffAvContainerType_t
+{
+    HDFF_AV_CONTAINER_PES,
+    HDFF_AV_CONTAINER_PES_DVD
+} HdffAvContainerType_t;
+
+typedef enum HdffAudioStreamType_t
+{
+    HDFF_AUDIO_STREAM_INVALID = -1,
+    HDFF_AUDIO_STREAM_MPEG1 = 0,
+    HDFF_AUDIO_STREAM_MPEG2,
+    HDFF_AUDIO_STREAM_AC3,
+    HDFF_AUDIO_STREAM_AAC,
+    HDFF_AUDIO_STREAM_HE_AAC,
+    HDFF_AUDIO_STREAM_PCM,
+    HDFF_AUDIO_STREAM_EAC3,
+    HDFF_AUDIO_STREAM_DTS
+} HdffAudioStreamType_t;
+
+typedef enum HdffVideoStreamType_t
+{
+    HDFF_VIDEO_STREAM_INVALID = -1,
+    HDFF_VIDEO_STREAM_MPEG1 = 0,
+    HDFF_VIDEO_STREAM_MPEG2,
+    HDFF_VIDEO_STREAM_H264,
+    HDFF_VIDEO_STREAM_MPEG4_ASP,
+    HDFF_VIDEO_STREAM_VC1
+} HdffVideoStreamType_t;
+
+typedef enum HdffTvFormat_t
+{
+    HDFF_TV_FORMAT_4_BY_3,
+    HDFF_TV_FORMAT_16_BY_9
+} HdffTvFormat_t;
+
+typedef enum HdffVideoConversion_t
+{
+    HDFF_VIDEO_CONVERSION_AUTOMATIC,
+    HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9,
+    HDFF_VIDEO_CONVERSION_LETTERBOX_14_BY_9,
+    HDFF_VIDEO_CONVERSION_PILLARBOX,
+    HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT,
+    HDFF_VIDEO_CONVERSION_ALWAYS_16_BY_9,
+    HDFF_VIDEO_CONVERSION_ZOOM_16_BY_9
+} HdffVideoConversion_t;
+
+typedef struct HdffVideoFormat_t
+{
+    int AutomaticEnabled;
+    int AfdEnabled;
+    HdffTvFormat_t TvFormat;
+    HdffVideoConversion_t VideoConversion;
+} HdffVideoFormat_t;
+
+typedef enum HdffVideoOutputMode_t
+{
+    HDFF_VIDEO_OUTPUT_CLONE,
+    HDFF_VIDEO_OUTPUT_HD_ONLY
+} HdffVideoOutputMode_t;
+
+typedef enum HdffAudioDownmixMode_t
+{
+    HDFF_AUDIO_DOWNMIX_OFF,
+    HDFF_AUDIO_DOWNMIX_ANALOG,
+    HDFF_AUDIO_DOWNMIX_ALWAYS,
+    HDFF_AUDIO_DOWNMIX_AUTOMATIC,
+    HDFF_AUDIO_DOWNMIX_HDMI_ONLY
+} HdffAudioDownmixMode_t;
+
+
+int HdffCmdAvSetPlayMode(int OsdDevice, uint8_t PlayMode, int Realtime);
+
+int HdffCmdAvSetVideoPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffVideoStreamType_t StreamType);
+
+int HdffCmdAvSetAudioPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid,
+                         HdffAudioStreamType_t StreamType,
+                         HdffAvContainerType_t ContainerType);
+
+int HdffCmdAvSetPcrPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid);
+
+int HdffCmdAvSetTeletextPid(int OsdDevice, uint8_t DecoderIndex, uint16_t Pid);
+
+int HdffCmdAvSetVideoWindow(int OsdDevice, uint8_t DecoderIndex, int Enable,
+                            uint16_t X, uint16_t Y, uint16_t Width,
+                            uint16_t Height);
+
+int HdffCmdAvShowStillImage(int OsdDevice, uint8_t DecoderIndex,
+                            const uint8_t * StillImage, int Size,
+                            HdffVideoStreamType_t StreamType);
+
+int HdffCmdAvSetDecoderInput(int OsdDevice, uint8_t DecoderIndex,
+                             uint8_t DemultiplexerIndex);
+
+int HdffCmdAvSetDemultiplexerInput(int OsdDevice, uint8_t DemultiplexerIndex,
+                                   uint8_t TsInputIndex);
+
+int HdffCmdAvSetVideoFormat(int OsdDevice, uint8_t DecoderIndex,
+                            const HdffVideoFormat_t * VideoFormat);
+
+int HdffCmdAvSetVideoOutputMode(int OsdDevice, uint8_t DecoderIndex,
+                                HdffVideoOutputMode_t OutputMode);
+
+int HdffCmdAvSetStc(int OsdDevice, uint8_t DecoderIndex, uint64_t Stc);
+
+int HdffCmdAvFlushBuffer(int OsdDevice, uint8_t DecoderIndex, int FlushAudio,
+                         int FlushVideo);
+
+int HdffCmdAvEnableSync(int OsdDevice, uint8_t DecoderIndex, int SyncAudio,
+                        int SyncVideo);
+
+int HdffCmdAvSetVideoSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed);
+
+int HdffCmdAvSetAudioSpeed(int OsdDevice, uint8_t DecoderIndex, int32_t Speed);
+
+int HdffCmdAvEnableVideoAfterStop(int OsdDevice, uint8_t DecoderIndex,
+                                  int EnableVideoAfterStop);
+
+int HdffCmdAvSetAudioDelay(int OsdDevice, int16_t Delay);
+
+int HdffCmdAvSetAudioDownmix(int OsdDevice,
+                             HdffAudioDownmixMode_t DownmixMode);
+
+int HdffCmdAvSetAudioChannel(int OsdDevice, uint8_t AudioChannel);
+
+int HdffCmdAvSetSyncShift(int OsdDevice, int16_t SyncShift);
+
+int HdffCmdAvMuteAudio(int OsdDevice, uint8_t DecoderIndex, int Mute);
+
+int HdffCmdAvMuteVideo(int OsdDevice, uint8_t DecoderIndex, int Mute);
+
+
+#endif /* HDFFCMD_AV_H */
diff --git a/libhdffcmd/hdffcmd_base.c b/libhdffcmd/hdffcmd_base.c
new file mode 100644
index 0000000..ac1ab7e
--- /dev/null
+++ b/libhdffcmd/hdffcmd_base.c
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include "hdffcmd_base.h"
+
+void HdffCmdBuildHeader(BitBuffer_t * MsgBuf, HdffMessageType_t MsgType,
+                        HdffMessageGroup_t MsgGroup, HdffMessageId_t MsgId)
+{
+    BitBuffer_SetBits(MsgBuf, 16, 0); // length field will be set later
+    BitBuffer_SetBits(MsgBuf, 6, 0); // reserved
+    BitBuffer_SetBits(MsgBuf, 2, MsgType);
+    BitBuffer_SetBits(MsgBuf, 8, MsgGroup);
+    BitBuffer_SetBits(MsgBuf, 16, MsgId);
+}
+
+uint32_t HdffCmdSetLength(BitBuffer_t * MsgBuf)
+{
+    uint32_t length;
+
+    length = BitBuffer_GetByteLength(MsgBuf) - 2;
+    MsgBuf->Data[0] = (uint8_t) (length >> 8);
+    MsgBuf->Data[1] = (uint8_t) length;
+
+    return length + 2;
+}
diff --git a/libhdffcmd/hdffcmd_base.h b/libhdffcmd/hdffcmd_base.h
new file mode 100644
index 0000000..b6856aa
--- /dev/null
+++ b/libhdffcmd/hdffcmd_base.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_BASE_H
+#define HDFFCMD_BASE_H
+
+#include <linux/dvb/osd.h>
+
+#if !defined OSD_RAW_CMD
+typedef struct osd_raw_cmd_s {
+    const void *cmd_data;
+    int cmd_len;
+    void *result_data;
+    int result_len;
+} osd_raw_cmd_t;
+
+typedef struct osd_raw_data_s {
+    const void *data_buffer;
+    int data_length;
+    int data_handle;
+} osd_raw_data_t;
+
+#define OSD_RAW_CMD            _IOWR('o', 162, osd_raw_cmd_t)
+#define OSD_RAW_DATA           _IOWR('o', 163, osd_raw_data_t)
+#endif
+
+#include "bitbuffer.h"
+#include "hdffcmd_defs.h"
+
+void HdffCmdBuildHeader(BitBuffer_t * MsgBuf, HdffMessageType_t MsgType,
+                        HdffMessageGroup_t MsgGroup, HdffMessageId_t MsgId);
+
+uint32_t HdffCmdSetLength(BitBuffer_t * MsgBuf);
+
+#endif /* HDFFCMD_BASE_H */
diff --git a/libhdffcmd/hdffcmd_defs.h b/libhdffcmd/hdffcmd_defs.h
new file mode 100644
index 0000000..cae2097
--- /dev/null
+++ b/libhdffcmd/hdffcmd_defs.h
@@ -0,0 +1,125 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_DEFS_H
+#define HDFFCMD_DEFS_H
+
+typedef enum HdffMessageType_t
+{
+    HDFF_MSG_TYPE_COMMAND,
+    HDFF_MSG_TYPE_ANSWER,
+    HDFF_MSG_TYPE_RESULT,
+    HDFF_MSG_TYPE_EVENT
+} HdffMessageType_t;
+
+typedef enum HdffMessageGroup_t
+{
+    HDFF_MSG_GROUP_GENERIC,
+    HDFF_MSG_GROUP_AV_DECODER,
+    HDFF_MSG_GROUP_AV_MUX,
+    HDFF_MSG_GROUP_FRONTEND,
+    HDFF_MSG_GROUP_OSD,
+    HDFF_MSG_GROUP_HDMI,
+    HDFF_MSG_GROUP_REMOTE_CONTROL
+} HdffMessageGroup_t;
+
+typedef enum HdffMessageId_t
+{
+    HDFF_MSG_GEN_GET_FIRMWARE_VERSION = 0,
+    HDFF_MSG_GEN_GET_INTERFACE_VERSION,
+    HDFF_MSG_GEN_GET_COPYRIGHTS,
+
+    HDFF_MSG_AV_SET_AUDIO_PID = 0,
+    HDFF_MSG_AV_SET_VIDEO_PID,
+    HDFF_MSG_AV_SET_PCR_PID,
+    HDFF_MSG_AV_SET_TELETEXT_PID,
+    HDFF_MSG_AV_SHOW_STILL_IMAGE,
+    HDFF_MSG_AV_SET_VIDEO_WINDOW,
+    HDFF_MSG_AV_SET_DECODER_INPUT,
+    HDFF_MSG_AV_SET_DEMULTIPLEXER_INPUT,
+    HDFF_MSG_AV_SET_VIDEO_FORMAT,
+    HDFF_MSG_AV_SET_VIDEO_OUTPUT_MODE,
+    HDFF_MSG_AV_SET_STC,
+    HDFF_MSG_AV_FLUSH_BUFFER,
+    HDFF_MSG_AV_ENABLE_SYNC,
+    HDFF_MSG_AV_SET_VIDEO_SPEED,
+    HDFF_MSG_AV_SET_AUDIO_SPEED,
+    HDFF_MSG_AV_ENABLE_VIDEO_AFTER_STOP,
+    HDFF_MSG_AV_GET_VIDEO_FORMAT_INFO,
+    HDFF_MSG_AV_SET_AUDIO_DELAY,
+    HDFF_MSG_AV_SET_AUDIO_DOWNMIX,
+    HDFF_MSG_AV_SET_AUDIO_CHANNEL,
+    HDFF_MSG_AV_SET_PLAY_MODE,
+    HDFF_MSG_AV_SET_OPTIONS,
+    HDFF_MSG_AV_MUTE_AUDIO,
+    HDFF_MSG_AV_MUTE_VIDEO,
+
+    HDFF_MSG_MUX_SET_VIDEO_OUT = 0,
+    HDFF_MSG_MUX_SET_SLOW_BLANK,
+    HDFF_MSG_MUX_SET_FAST_BLANK,
+    HDFF_MSG_MUX_SET_VOLUME,
+    HDFF_MSG_MUX_SET_AUDIO_MUTE,
+
+    HDFF_MSG_OSD_CONFIGURE = 0,
+    HDFF_MSG_OSD_RESET,
+    HDFF_MSG_OSD_CREATE_DISPLAY = 10,
+    HDFF_MSG_OSD_DELETE_DISPLAY,
+    HDFF_MSG_OSD_ENABLE_DISPLAY,
+    HDFF_MSG_OSD_SET_DISPLAY_OUTPUT_RECTANGLE,
+    HDFF_MSG_OSD_SET_DISPLAY_CLIPPLING_AREA,
+    HDFF_MSG_OSD_RENDER_DISPLAY,
+    HDFF_MSG_OSD_SAVE_REGION,
+    HDFF_MSG_OSD_RESTORE_REGION,
+    HDFF_MSG_OSD_CREATE_PALETTE = 30,
+    HDFF_MSG_OSD_DELETE_PALETTE,
+    HDFF_MSG_OSD_SET_DISPLAY_PALETTE,
+    HDFF_MSG_OSD_SET_PALETTE_COLORS,
+    HDFF_MSG_OSD_CREATE_FONT_FACE = 50,
+    HDFF_MSG_OSD_DELETE_FONT_FACE,
+    HDFF_MSG_OSD_CREATE_FONT,
+    HDFF_MSG_OSD_DELETE_FONT,
+    HDFF_MSG_OSD_DRAW_PIXEL = 70,
+    HDFF_MSG_OSD_DRAW_RECTANGLE,
+    HDFF_MSG_OSD_DRAW_CIRCLE,
+    HDFF_MSG_OSD_DRAW_ELLIPSE,
+    HDFF_MSG_OSD_DRAW_SLOPE,
+    HDFF_MSG_OSD_DRAW_TEXT,
+    HDFF_MSG_OSD_DRAW_WIDE_TEXT,
+    HDFF_MSG_OSD_DRAW_BITMAP,
+    HDFF_MSG_OSD_DRAW_UTF8_TEXT,
+
+    HDFF_MSG_HDMI_ENABLE_OUTPUT = 0,
+    HDFF_MSG_HDMI_SET_VIDEO_MODE,
+    HDFF_MSG_HDMI_CONFIGURE,
+    HDFF_MSG_HDMI_IS_DISPLAY_CONNECTED,
+    HDFF_MSG_HDMI_GET_DISPLAY_INFO,
+    HDFF_MSG_HDMI_GET_VIDEO_MODE,
+    HDFF_MSG_HDMI_SEND_CEC_COMMAND,
+    HDFF_MSG_HDMI_SEND_RAW_CEC_COMMAND,
+
+    HDFF_MSG_REMOTE_SET_PROTOCOL = 0,
+    HDFF_MSG_REMOTE_SET_ADDRESS_FILTER,
+    HDFF_MSG_REMOTE_KEY_EVENT
+} HdffMessageId_t;
+
+#endif /* HDFFCMD_DEFS_H */
diff --git a/libhdffcmd/hdffcmd_generic.c b/libhdffcmd/hdffcmd_generic.c
new file mode 100644
index 0000000..797abe8
--- /dev/null
+++ b/libhdffcmd/hdffcmd_generic.c
@@ -0,0 +1,165 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+int HdffCmdGetFirmwareVersion(int OsdDevice, uint32_t * Version, char * String,
+                              uint32_t MaxLength)
+{
+    uint8_t cmdData[8];
+    uint8_t resultData[64];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    if (Version == NULL)
+        return -EINVAL;
+
+    *Version = 0;
+    if (String)
+        String[0] = 0;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_GENERIC,
+                       HDFF_MSG_GEN_GET_FIRMWARE_VERSION);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            if (String)
+            {
+                uint8_t textLength = resultData[9];
+                if (textLength >= MaxLength)
+                    textLength = MaxLength - 1;
+                memcpy(String, &resultData[10], textLength);
+                String[textLength] = 0;
+            }
+            *Version = (resultData[6] << 16)
+                     | (resultData[7] << 8)
+                     | resultData[8];
+        }
+    }
+    return err;
+}
+
+int HdffCmdGetInterfaceVersion(int OsdDevice, uint32_t * Version, char * String,
+                               uint32_t MaxLength)
+{
+    uint8_t cmdData[8];
+    uint8_t resultData[64];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    if (Version == NULL)
+        return -EINVAL;
+
+    *Version = 0;
+    if (String)
+        String[0] = 0;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_GENERIC,
+                       HDFF_MSG_GEN_GET_INTERFACE_VERSION);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            if (String)
+            {
+                uint8_t textLength = resultData[9];
+                if (textLength >= MaxLength)
+                    textLength = MaxLength - 1;
+                memcpy(String, &resultData[10], textLength);
+                String[textLength] = 0;
+            }
+            *Version = (resultData[6] << 16)
+                     | (resultData[7] << 8)
+                     | resultData[8];
+        }
+    }
+    return err;
+}
+
+int HdffCmdGetCopyrights(int OsdDevice, uint8_t Index, char * String,
+                         uint32_t MaxLength)
+{
+    uint8_t cmdData[8];
+    uint8_t resultData[280];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    if (String == NULL)
+        return -EINVAL;
+
+    String[0] = 0;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_GENERIC,
+                       HDFF_MSG_GEN_GET_COPYRIGHTS);
+    BitBuffer_SetBits(&cmdBuf, 8, Index);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            uint8_t index = resultData[6];
+            uint8_t textLen = resultData[7];
+            if (index == Index && textLen > 0)
+            {
+                if (textLen >= MaxLength)
+                {
+                    textLen = MaxLength - 1;
+                }
+                memcpy(String, resultData + 8, textLen);
+                String[textLen] = 0;
+            }
+        }
+    }
+    return err;
+}
diff --git a/libhdffcmd/hdffcmd_generic.h b/libhdffcmd/hdffcmd_generic.h
new file mode 100644
index 0000000..c12b296
--- /dev/null
+++ b/libhdffcmd/hdffcmd_generic.h
@@ -0,0 +1,36 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_GENERIC_H
+#define HDFFCMD_GENERIC_H
+
+int HdffCmdGetFirmwareVersion(int OsdDevice, uint32_t * Version, char * String,
+                              uint32_t MaxLength);
+
+int HdffCmdGetInterfaceVersion(int OsdDevice, uint32_t * Version, char * String,
+                               uint32_t MaxLength);
+
+int HdffCmdGetCopyrights(int OsdDevice, uint8_t Index, char * String,
+                         uint32_t MaxLength);
+
+#endif /* HDFFCMD_GENERIC_H */
diff --git a/libhdffcmd/hdffcmd_hdmi.c b/libhdffcmd/hdffcmd_hdmi.c
new file mode 100644
index 0000000..de315f8
--- /dev/null
+++ b/libhdffcmd/hdffcmd_hdmi.c
@@ -0,0 +1,120 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdHdmiSetVideoMode(int OsdDevice, HdffVideoMode_t VideoMode)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_HDMI,
+                       HDFF_MSG_HDMI_SET_VIDEO_MODE);
+    BitBuffer_SetBits(&cmdBuf, 8, VideoMode);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdHdmiConfigure(int OsdDevice, const HdffHdmiConfig_t * Config)
+{
+    uint8_t cmdData[24];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    size_t nameLen;
+    int i;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_HDMI,
+                       HDFF_MSG_HDMI_CONFIGURE);
+    BitBuffer_SetBits(&cmdBuf, 1, Config->TransmitAudio ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, Config->ForceDviMode ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 1, Config->CecEnabled ? 1 : 0);
+    BitBuffer_SetBits(&cmdBuf, 3, Config->VideoModeAdaption);
+    BitBuffer_SetBits(&cmdBuf, 6, 0); // reserved
+    nameLen = strlen(Config->CecDeviceName);
+    if (nameLen > 13)
+        nameLen = 13;
+    BitBuffer_SetBits(&cmdBuf, 4, nameLen);
+    for (i = 0; i < nameLen; i++)
+        BitBuffer_SetBits(&cmdBuf, 8, Config->CecDeviceName[i]);
+
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdHdmiSendCecCommand(int OsdDevice, HdffCecCommand_t Command)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_HDMI,
+                       HDFF_MSG_HDMI_SEND_CEC_COMMAND);
+    BitBuffer_SetBits(&cmdBuf, 8, Command);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdHdmiSendRawCecCommand(int OsdDevice, uint8_t Destination,
+                                 uint8_t Opcode, const uint8_t * Operand,
+                                 uint8_t OperandLength)
+{
+    uint8_t cmdData[24];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+
+    if (OperandLength > 14)
+        OperandLength = 14;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_HDMI,
+                       HDFF_MSG_HDMI_SEND_RAW_CEC_COMMAND);
+    BitBuffer_SetBits(&cmdBuf, 4, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 4, Destination);
+    BitBuffer_SetBits(&cmdBuf, 8, Opcode);
+    BitBuffer_SetBits(&cmdBuf, 8, OperandLength);
+    for (i = 0; i < OperandLength; i++)
+        BitBuffer_SetBits(&cmdBuf, 8, Operand[i]);
+
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff --git a/libhdffcmd/hdffcmd_hdmi.h b/libhdffcmd/hdffcmd_hdmi.h
new file mode 100644
index 0000000..fc79bd9
--- /dev/null
+++ b/libhdffcmd/hdffcmd_hdmi.h
@@ -0,0 +1,72 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_HDMI_H
+#define HDFFCMD_HDMI_H
+
+
+typedef enum HdffVideoMode_t
+{
+    HDFF_VIDEO_MODE_576P50 = 18,
+    HDFF_VIDEO_MODE_720P50 = 19,
+    HDFF_VIDEO_MODE_1080I50 = 20,
+    HDFF_VIDEO_MODE_576I50 = 22
+} HdffVideoMode_t;
+
+typedef enum HdffVideoModeAdaption_t
+{
+    HDFF_VIDEO_MODE_ADAPT_OFF,
+    HDFF_VIDEO_MODE_ADAPT_FRAME_RATE,
+    HDFF_VIDEO_MODE_ADAPT_ONLY_FOR_HD,
+    HDFF_VIDEO_MODE_ADAPT_ALWAYS
+} HdffVideoModeAdaption_t;
+
+typedef struct HdffHdmiConfig_t
+{
+    int TransmitAudio;
+    int ForceDviMode;
+    int CecEnabled;
+    HdffVideoModeAdaption_t VideoModeAdaption;
+    char CecDeviceName[14];
+} HdffHdmiConfig_t;
+
+typedef enum HdffCecCommand_t
+{
+    HDFF_CEC_COMMAND_TV_ON,
+    HDFF_CEC_COMMAND_TV_OFF,
+    HDFF_CEC_COMMAND_ACTIVE_SOURCE,
+    HDFF_CEC_COMMAND_INACTIVE_SOURCE
+} HdffCecCommand_t;
+
+
+int HdffCmdHdmiSetVideoMode(int OsdDevice, HdffVideoMode_t VideoMode);
+
+int HdffCmdHdmiConfigure(int OsdDevice, const HdffHdmiConfig_t * Config);
+
+int HdffCmdHdmiSendCecCommand(int OsdDevice, HdffCecCommand_t Command);
+
+int HdffCmdHdmiSendRawCecCommand(int OsdDevice, uint8_t Destination,
+                                 uint8_t Opcode, const uint8_t * Operand,
+                                 uint8_t OperandLength);
+
+#endif /* HDFFCMD_HDMI_H */
diff --git a/libhdffcmd/hdffcmd_mux.c b/libhdffcmd/hdffcmd_mux.c
new file mode 100644
index 0000000..3698b56
--- /dev/null
+++ b/libhdffcmd/hdffcmd_mux.c
@@ -0,0 +1,81 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdMuxSetVideoOut(int OsdDevice, HdffVideoOut_t VideoOut)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_AV_MUX,
+                       HDFF_MSG_MUX_SET_VIDEO_OUT);
+    BitBuffer_SetBits(&cmdBuf, 4, VideoOut);
+    BitBuffer_SetBits(&cmdBuf, 4, 0); // reserved
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdMuxSetVolume(int OsdDevice, uint8_t Volume)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_AV_MUX,
+                       HDFF_MSG_MUX_SET_VOLUME);
+    BitBuffer_SetBits(&cmdBuf, 8, Volume);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdMuxMuteAudio(int OsdDevice, int Mute)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_AV_MUX,
+                       HDFF_MSG_MUX_SET_AUDIO_MUTE);
+    BitBuffer_SetBits(&cmdBuf, 1, Mute);
+    BitBuffer_SetBits(&cmdBuf, 7, 0); // reserved
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff --git a/libhdffcmd/hdffcmd_mux.h b/libhdffcmd/hdffcmd_mux.h
new file mode 100644
index 0000000..8821d5f
--- /dev/null
+++ b/libhdffcmd/hdffcmd_mux.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_MUX_H
+#define HDFFCMD_MUX_H
+
+
+typedef enum HdffVideoOut_t
+{
+    HDFF_VIDEO_OUT_DISABLED,
+    HDFF_VIDEO_OUT_CVBS_RGB,
+    HDFF_VIDEO_OUT_CVBS_YUV,
+    HDFF_VIDEO_OUT_YC
+} HdffVideoOut_t;
+
+typedef enum HdffSlowBlank_t
+{
+    HDFF_SLOW_BLANK_OFF,
+    HDFF_SLOW_BLANK_16_BY_9,
+    HDFF_SLOW_BLANK_4_BY_3
+} HdffSlowBlank_t;
+
+typedef enum HdffFastBlank_t
+{
+    HDFF_FAST_BLANK_CVBS,
+    HDFF_FAST_BLANK_RGB
+} HdffFastBlank_t;
+
+
+int HdffCmdMuxSetVideoOut(int OsdDevice, HdffVideoOut_t VideoOut);
+
+int HdffCmdMuxSetVolume(int OsdDevice, uint8_t Volume);
+
+int HdffCmdMuxMuteAudio(int OsdDevice, int Mute);
+
+#endif /* HDFFCMD_MUX_H */
diff --git a/libhdffcmd/hdffcmd_osd.c b/libhdffcmd/hdffcmd_osd.c
new file mode 100644
index 0000000..cf714a8
--- /dev/null
+++ b/libhdffcmd/hdffcmd_osd.c
@@ -0,0 +1,720 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdOsdConfigure(int OsdDevice, const HdffOsdConfig_t * Config)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CONFIGURE);
+    if (Config->FontAntialiasing)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    if (Config->FontKerning)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    BitBuffer_SetBits(&cmdBuf, 6, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 16, Config->FontDpi);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdReset(int OsdDevice)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_RESET);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+
+int HdffCmdOsdCreateDisplay(int OsdDevice, uint16_t Width, uint16_t Height,
+                            HdffColorType_t ColorType, uint32_t * NewDisplay)
+{
+    uint8_t cmdData[16];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorType);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    *NewDisplay = HDFF_INVALID_HANDLE;
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            if (resultData[2] == HDFF_MSG_TYPE_ANSWER)
+            {
+                *NewDisplay = (resultData[6] << 24)
+                            | (resultData[7] << 16)
+                            | (resultData[8] << 8)
+                            | resultData[9];
+            }
+            else
+                err = -1;
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeleteDisplay(int OsdDevice, uint32_t Display)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdEnableDisplay(int OsdDevice, uint32_t Display, int Enable)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_ENABLE_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    if (Enable)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetDisplayOutputRectangle(int OsdDevice, uint32_t Display,
+                                        uint16_t X, uint16_t Y,
+                                        uint16_t Width, uint16_t Height)
+{
+    uint8_t cmdData[20];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_DISPLAY_OUTPUT_RECTANGLE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetDisplayClippingArea(int OsdDevice, uint32_t Display,
+                                     int Enable, uint16_t X, uint16_t Y,
+                                     uint16_t Width, uint16_t Height)
+{
+    uint8_t cmdData[20];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_DISPLAY_CLIPPLING_AREA);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    if (Enable)
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 1);
+    }
+    else
+    {
+        BitBuffer_SetBits(&cmdBuf, 1, 0);
+    }
+    BitBuffer_SetBits(&cmdBuf, 7, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdRenderDisplay(int OsdDevice, uint32_t Display)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_RENDER_DISPLAY);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSaveRegion(int OsdDevice, uint32_t Display,
+                         uint16_t X, uint16_t Y,
+                         uint16_t Width, uint16_t Height)
+{
+    uint8_t cmdData[20];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SAVE_REGION);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdRestoreRegion(int OsdDevice, uint32_t Display)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_RESTORE_REGION);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+
+int HdffCmdOsdCreatePalette(int OsdDevice, HdffColorType_t ColorType,
+                            HdffColorFormat_t ColorFormat,
+                            uint32_t NumColors, const uint32_t * Colors,
+                            uint32_t * NewPalette)
+{
+    uint8_t cmdData[1060];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_PALETTE);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorType);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorFormat);
+    if (NumColors > 256)
+        NumColors = 256;
+    BitBuffer_SetBits(&cmdBuf, 8, NumColors == 256 ? 0 : NumColors);
+    for (i = 0; i < NumColors; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 32, Colors[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    *NewPalette = HDFF_INVALID_HANDLE;
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            if (resultData[2] == HDFF_MSG_TYPE_ANSWER)
+            {
+                *NewPalette = (resultData[6] << 24)
+                            | (resultData[7] << 16)
+                            | (resultData[8] << 8)
+                            | resultData[9];
+            }
+            else
+                err = -1;
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeletePalette(int OsdDevice, uint32_t Palette)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_PALETTE);
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetDisplayPalette(int OsdDevice, uint32_t Display,
+                                uint32_t Palette)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_DISPLAY_PALETTE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdSetPaletteColors(int OsdDevice, uint32_t Palette,
+                               HdffColorFormat_t ColorFormat,
+                               uint8_t StartColor, uint32_t NumColors,
+                               const uint32_t * Colors)
+{
+    uint8_t cmdData[1060];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_SET_PALETTE_COLORS);
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorFormat);
+    BitBuffer_SetBits(&cmdBuf, 8, StartColor);
+    if (NumColors > 256)
+        NumColors = 256;
+    BitBuffer_SetBits(&cmdBuf, 8, NumColors == 256 ? 0 : NumColors);
+    for (i = 0; i < NumColors; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 32, Colors[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdCreateFontFace(int OsdDevice, const uint8_t * FontData,
+                             uint32_t DataSize, uint32_t * NewFontFace)
+{
+    uint8_t cmdData[16];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+    int err;
+
+    *NewFontFace = HDFF_INVALID_HANDLE;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = FontData;
+    osd_data.data_length = DataSize;
+    err = ioctl(OsdDevice, OSD_RAW_DATA, &osd_data);
+    if (err != 0)
+        return err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_FONT_FACE);
+    BitBuffer_SetBits(&cmdBuf, 16, osd_data.data_handle);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            if (resultData[2] == HDFF_MSG_TYPE_ANSWER)
+            {
+                *NewFontFace = (resultData[6] << 24)
+                             | (resultData[7] << 16)
+                             | (resultData[8] << 8)
+                             | resultData[9];
+            }
+            else
+                err = -1;
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeleteFontFace(int OsdDevice, uint32_t FontFace)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_FONT_FACE);
+    BitBuffer_SetBits(&cmdBuf, 32, FontFace);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdCreateFont(int OsdDevice, uint32_t FontFace, uint32_t Size,
+                         uint32_t * NewFont)
+{
+    uint8_t cmdData[16];
+    uint8_t resultData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int err;
+
+    *NewFont = HDFF_INVALID_HANDLE;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    osd_cmd.result_data = resultData;
+    osd_cmd.result_len = sizeof(resultData);
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_CREATE_FONT);
+    BitBuffer_SetBits(&cmdBuf, 32, FontFace);
+    BitBuffer_SetBits(&cmdBuf, 32, Size);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    err = ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+    if (err == 0)
+    {
+        if (osd_cmd.result_len > 0)
+        {
+            if (resultData[2] == HDFF_MSG_TYPE_ANSWER)
+            {
+                *NewFont = (resultData[6] << 24)
+                         | (resultData[7] << 16)
+                         | (resultData[8] << 8)
+                         | resultData[9];
+            }
+            else
+                err = -1;
+        }
+    }
+    return err;
+}
+
+int HdffCmdOsdDeleteFont(int OsdDevice, uint32_t Font)
+{
+    uint8_t cmdData[16];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DELETE_FONT);
+    BitBuffer_SetBits(&cmdBuf, 32, Font);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+
+int HdffCmdOsdDrawRectangle(int OsdDevice, uint32_t Display, uint16_t X,
+                            uint16_t Y, uint16_t Width, uint16_t Height,
+                            uint32_t Color)
+{
+    uint8_t cmdData[24];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_RECTANGLE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawEllipse(int OsdDevice, uint32_t Display, uint16_t CX,
+                          uint16_t CY, uint16_t RadiusX, uint16_t RadiusY,
+                          uint32_t Color, uint32_t Flags)
+{
+    uint8_t cmdData[28];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_ELLIPSE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, CX);
+    BitBuffer_SetBits(&cmdBuf, 16, CY);
+    BitBuffer_SetBits(&cmdBuf, 16, RadiusX);
+    BitBuffer_SetBits(&cmdBuf, 16, RadiusY);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 32, Flags);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawSlope(int OsdDevice, uint32_t Display, uint16_t X,
+                        uint16_t Y, uint16_t Width, uint16_t Height,
+                        uint32_t Color, uint32_t Type)
+{
+    uint8_t cmdData[28];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_SLOPE);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, Width);
+    BitBuffer_SetBits(&cmdBuf, 16, Height);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 32, Type);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawText(int OsdDevice, uint32_t Display, uint32_t Font,
+                       uint16_t X, uint16_t Y, const char * Text,
+                       uint32_t Color)
+{
+    uint8_t cmdData[1060];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int length;
+
+    length = 0;
+    while (Text[length])
+    {
+        length++;
+    }
+    if (length > 980)
+        length = 980;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_TEXT);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 32, Font);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 16, length);
+    for (i = 0; i < length; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 8, Text[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawUtf8Text(int OsdDevice, uint32_t Display, uint32_t Font,
+                           uint16_t X, uint16_t Y, const char * Text,
+                           uint32_t Color)
+{
+    uint8_t cmdData[1060];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int length;
+
+    length = 0;
+    while (Text[length])
+    {
+        length++;
+    }
+    if (length > 980)
+        length = 980;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_UTF8_TEXT);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 32, Font);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 16, length);
+    for (i = 0; i < length; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 8, Text[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawWideText(int OsdDevice, uint32_t Display, uint32_t Font,
+                           uint16_t X, uint16_t Y, const uint16_t * Text,
+                           uint32_t Color)
+{
+    uint8_t cmdData[1060];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int length;
+
+    length = 0;
+    while (Text[length])
+    {
+        length++;
+    }
+    if (length > 480)
+        length = 480;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_WIDE_TEXT);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 32, Font);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 32, Color);
+    BitBuffer_SetBits(&cmdBuf, 16, length);
+    for (i = 0; i < length; i++)
+    {
+        BitBuffer_SetBits(&cmdBuf, 16, Text[i]);
+    }
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdOsdDrawBitmap(int OsdDevice, uint32_t Display, uint16_t X,
+                         uint16_t Y, const uint8_t * Bitmap, uint16_t BmpWidth,
+                         uint16_t BmpHeight, uint32_t BmpSize,
+                         HdffColorType_t ColorType, uint32_t Palette)
+{
+    uint8_t cmdData[32];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+    int err;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = Bitmap;
+    osd_data.data_length = BmpSize;
+    err = ioctl(OsdDevice, OSD_RAW_DATA, &osd_data);
+    if (err != 0)
+        return err;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND, HDFF_MSG_GROUP_OSD,
+                       HDFF_MSG_OSD_DRAW_BITMAP);
+    BitBuffer_SetBits(&cmdBuf, 32, Display);
+    BitBuffer_SetBits(&cmdBuf, 16, X);
+    BitBuffer_SetBits(&cmdBuf, 16, Y);
+    BitBuffer_SetBits(&cmdBuf, 16, BmpWidth);
+    BitBuffer_SetBits(&cmdBuf, 16, BmpHeight);
+    BitBuffer_SetBits(&cmdBuf, 8, ColorType);
+    BitBuffer_SetBits(&cmdBuf, 6, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 2, 0); // uncompressed
+    BitBuffer_SetBits(&cmdBuf, 32, Palette);
+    BitBuffer_SetBits(&cmdBuf, 16, osd_data.data_handle);
+    BitBuffer_SetBits(&cmdBuf, 32, 0);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff --git a/libhdffcmd/hdffcmd_osd.h b/libhdffcmd/hdffcmd_osd.h
new file mode 100644
index 0000000..079b754
--- /dev/null
+++ b/libhdffcmd/hdffcmd_osd.h
@@ -0,0 +1,170 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_OSD_H
+#define HDFFCMD_OSD_H
+
+
+#define HDFF_INVALID_HANDLE             0xFFFFFFFF
+#define HDFF_SCREEN_DISPLAY_HANDLE      0xFFFFFFFE
+
+#define HDFF_POSITION_SCREEN_CENTERED   0xFFFF
+
+#define HDFF_SIZE_FULL_SCREEN           0xFFFF
+#define HDFF_SIZE_SAME_AS_SOURCE        0xFFFE
+
+#define HDFF_FONT_FACE_TIRESIAS         0x00000000
+
+
+typedef struct HdffOsdConfig_t
+{
+    int FontAntialiasing;
+    int FontKerning;
+    uint16_t FontDpi;
+} HdffOsdConfig_t;
+
+typedef enum HdffColorType_t
+{
+    HDFF_COLOR_TYPE_CLUT1,
+    HDFF_COLOR_TYPE_CLUT2,
+    HDFF_COLOR_TYPE_CLUT4,
+    HDFF_COLOR_TYPE_CLUT8,
+    HDFF_COLOR_TYPE_ARGB8888,
+    HDFF_COLOR_TYPE_ARGB8565,
+    HDFF_COLOR_TYPE_ARGB4444,
+    HDFF_COLOR_TYPE_ARGB1555,
+    HDFF_COLOR_TYPE_RGB888,
+    HDFF_COLOR_TYPE_RGB565
+} HdffColorType_t;
+
+typedef enum HdffColorFormat_t
+{
+    HDFF_COLOR_FORMAT_ARGB,
+    HDFF_COLOR_FORMAT_ACBYCR
+} HdffColorFormat_t;
+
+typedef enum HdffDrawingFlags_t
+{
+    HDFF_DRAW_FULL,
+    HDFF_DRAW_HALF_TOP,
+    HDFF_DRAW_HALF_LEFT,
+    HDFF_DRAW_HALF_BOTTOM,
+    HDFF_DRAW_HALF_RIGHT,
+    HDFF_DRAW_QUARTER_TOP_LEFT,
+    HDFF_DRAW_QUARTER_TOP_RIGHT,
+    HDFF_DRAW_QUARTER_BOTTOM_LEFT,
+    HDFF_DRAW_QUARTER_BOTTOM_RIGHT,
+    HDFF_DRAW_QUARTER_TOP_LEFT_INVERTED,
+    HDFF_DRAW_QUARTER_TOP_RIGHT_INVERTED,
+    HDFF_DRAW_QUARTER_BOTTOM_LEFT_INVERTED,
+    HDFF_DRAW_QUARTER_BOTTOM_RIGHT_INVERTED
+} HdffDrawingFlags_t;
+
+
+int HdffCmdOsdConfigure(int OsdDevice, const HdffOsdConfig_t * Config);
+
+int HdffCmdOsdReset(int OsdDevice);
+
+
+int HdffCmdOsdCreateDisplay(int OsdDevice, uint16_t Width, uint16_t Height,
+                            HdffColorType_t ColorType, uint32_t * NewDisplay);
+
+int HdffCmdOsdDeleteDisplay(int OsdDevice, uint32_t Display);
+
+int HdffCmdOsdEnableDisplay(int OsdDevice, uint32_t Display, int Enable);
+
+int HdffCmdOsdSetDisplayOutputRectangle(int OsdDevice, uint32_t Display,
+                                        uint16_t X, uint16_t Y,
+                                        uint16_t Width, uint16_t Height);
+
+int HdffCmdOsdSetDisplayClippingArea(int OsdDevice, uint32_t Display,
+                                     int Enable, uint16_t X, uint16_t Y,
+                                     uint16_t Width, uint16_t Height);
+
+int HdffCmdOsdRenderDisplay(int OsdDevice, uint32_t Display);
+
+int HdffCmdOsdSaveRegion(int OsdDevice, uint32_t Display,
+                         uint16_t X, uint16_t Y,
+                         uint16_t Width, uint16_t Height);
+
+int HdffCmdOsdRestoreRegion(int OsdDevice, uint32_t Display);
+
+
+int HdffCmdOsdCreatePalette(int OsdDevice, HdffColorType_t ColorType,
+                            HdffColorFormat_t ColorFormat,
+                            uint32_t NumColors, const uint32_t * Colors,
+                            uint32_t * NewPalette);
+
+int HdffCmdOsdDeletePalette(int OsdDevice, uint32_t Palette);
+
+int HdffCmdOsdSetDisplayPalette(int OsdDevice, uint32_t Display,
+                                uint32_t Palette);
+
+int HdffCmdOsdSetPaletteColors(int OsdDevice, uint32_t Palette,
+                               HdffColorFormat_t ColorFormat,
+                               uint8_t StartColor, uint32_t NumColors,
+                               const uint32_t * Colors);
+
+
+int HdffCmdOsdCreateFontFace(int OsdDevice, const uint8_t * FontData,
+                             uint32_t DataSize, uint32_t * NewFontFace);
+
+int HdffCmdOsdDeleteFontFace(int OsdDevice, uint32_t FontFace);
+
+int HdffCmdOsdCreateFont(int OsdDevice, uint32_t FontFace, uint32_t Size,
+                         uint32_t * NewFont);
+
+int HdffCmdOsdDeleteFont(int OsdDevice, uint32_t Font);
+
+
+int HdffCmdOsdDrawRectangle(int OsdDevice, uint32_t Display, uint16_t X,
+                            uint16_t Y, uint16_t Width, uint16_t Height,
+                            uint32_t Color);
+
+int HdffCmdOsdDrawEllipse(int OsdDevice, uint32_t Display, uint16_t CX,
+                          uint16_t CY, uint16_t RadiusX, uint16_t RadiusY,
+                          uint32_t Color, uint32_t Flags);
+
+int HdffCmdOsdDrawSlope(int OsdDevice, uint32_t Display, uint16_t X,
+                        uint16_t Y, uint16_t Width, uint16_t Height,
+                        uint32_t Color, uint32_t Type);
+
+int HdffCmdOsdDrawText(int OsdDevice, uint32_t Display, uint32_t Font,
+                       uint16_t X, uint16_t Y, const char * Text,
+                       uint32_t Color);
+
+int HdffCmdOsdDrawUtf8Text(int OsdDevice, uint32_t Display, uint32_t Font,
+                           uint16_t X, uint16_t Y, const char * Text,
+                           uint32_t Color);
+
+int HdffCmdOsdDrawWideText(int OsdDevice, uint32_t Display, uint32_t Font,
+                           uint16_t X, uint16_t Y, const uint16_t * Text,
+                           uint32_t Color);
+
+int HdffCmdOsdDrawBitmap(int OsdDevice, uint32_t Display, uint16_t X,
+                         uint16_t Y, const uint8_t * Bitmap, uint16_t BmpWidth,
+                         uint16_t BmpHeight, uint32_t BmpSize,
+                         HdffColorType_t ColorType, uint32_t Palette);
+
+
+#endif /* HDFFCMD_OSD_H */
diff --git a/libhdffcmd/hdffcmd_remote.c b/libhdffcmd/hdffcmd_remote.c
new file mode 100644
index 0000000..d9bbe45
--- /dev/null
+++ b/libhdffcmd/hdffcmd_remote.c
@@ -0,0 +1,67 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "hdffcmd.h"
+#include "hdffcmd_base.h"
+#include "hdffcmd_defs.h"
+
+
+int HdffCmdRemoteSetProtocol(int OsdDevice, HdffRemoteProtocol_t Protocol)
+{
+    uint8_t cmdData[8];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_REMOTE_CONTROL,
+                       HDFF_MSG_REMOTE_SET_PROTOCOL);
+    BitBuffer_SetBits(&cmdBuf, 8, Protocol);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
+
+int HdffCmdRemoteSetAddressFilter(int OsdDevice, int Enable, uint32_t Address)
+{
+    uint8_t cmdData[12];
+    BitBuffer_t cmdBuf;
+    osd_raw_cmd_t osd_cmd;
+
+    BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdData;
+    HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+                       HDFF_MSG_GROUP_REMOTE_CONTROL,
+                       HDFF_MSG_REMOTE_SET_ADDRESS_FILTER);
+    BitBuffer_SetBits(&cmdBuf, 1, Enable);
+    BitBuffer_SetBits(&cmdBuf, 7, 0); // reserved
+    BitBuffer_SetBits(&cmdBuf, 32, Address);
+    osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+    return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff --git a/libhdffcmd/hdffcmd_remote.h b/libhdffcmd/hdffcmd_remote.h
new file mode 100644
index 0000000..f2e6b8a
--- /dev/null
+++ b/libhdffcmd/hdffcmd_remote.h
@@ -0,0 +1,39 @@
+/**********************************************************************
+ *
+ * HDFF firmware command interface library
+ *
+ * Copyright (C) 2011  Andreas Regel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *********************************************************************/
+
+#ifndef HDFFCMD_REMOTE_H
+#define HDFFCMD_REMOTE_H
+
+typedef enum HdffRemoteProtocol_t
+{
+    HDFF_REMOTE_PROTOCOL_NONE,
+    HDFF_REMOTE_PROTOCOL_RC5,
+    HDFF_REMOTE_PROTOCOL_RC6
+} HdffRemoteProtocol_t;
+
+
+int HdffCmdRemoteSetProtocol(int OsdDevice, HdffRemoteProtocol_t Protocol);
+
+int HdffCmdRemoteSetAddressFilter(int OsdDevice, int Enable, uint32_t Address);
+
+#endif /* HDFFCMD_REMOTE_H */
diff --git a/menu.c b/menu.c
new file mode 100644
index 0000000..fa953fb
--- /dev/null
+++ b/menu.c
@@ -0,0 +1,65 @@
+/*
+ * menu.c: The DVB HD Full Featured device main menu
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#include "menu.h"
+#include "setup.h"
+
+cHdffMenu::cHdffMenu(HDFF::cHdffCmdIf * pHdffCmdIf)
+:   cOsdMenu("dvbhddevice"),
+    mHdffCmdIf(pHdffCmdIf)
+{
+    mVideoConversionItem = new cOsdItem("", osUnknown, false);
+    Add(mVideoConversionItem);
+    SetHelp(tr("Video Conversion"), tr("TV on"), tr("TV off"));
+    SetVideoConversion();
+}
+
+cHdffMenu::~cHdffMenu()
+{
+}
+
+eOSState cHdffMenu::ProcessKey(eKeys key)
+{
+    eOSState state = cOsdMenu::ProcessKey(key);
+    if (state == osUnknown)
+    {
+        switch (key)
+        {
+            case kRed:
+                gHdffSetup.SetNextVideoConversion();
+                SetVideoConversion();
+                break;
+
+            case kGreen:
+                mHdffCmdIf->CmdHdmiSendCecCommand(HDFF_CEC_COMMAND_TV_ON);
+                state = osEnd;
+                break;
+
+            case kYellow:
+                mHdffCmdIf->CmdHdmiSendCecCommand(HDFF_CEC_COMMAND_TV_OFF);
+                state = osEnd;
+                break;
+
+            case kOk:
+                state = osEnd;
+                break;
+
+            default:
+                break;
+        }
+    }
+    return state;
+}
+
+void cHdffMenu::SetVideoConversion(void)
+{
+    gHdffSetup.SetVideoFormat(mHdffCmdIf);
+
+    char str[128];
+    sprintf(str, "%s: %s", tr("Video Conversion"), gHdffSetup.GetVideoConversionString());
+    mVideoConversionItem->SetText(str);
+    Display();
+}
diff --git a/menu.h b/menu.h
new file mode 100644
index 0000000..18b3d99
--- /dev/null
+++ b/menu.h
@@ -0,0 +1,29 @@
+/*
+ * menu.h: The DVB HD Full Featured device main menu
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#ifndef _HDFF_MENU_H_
+#define _HDFF_MENU_H_
+
+#include <vdr/osd.h>
+#include <vdr/plugin.h>
+
+#include "hdffcmd.h"
+
+class cHdffMenu : public cOsdMenu
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+
+    cOsdItem * mVideoConversionItem;
+
+    void SetVideoConversion(void);
+public:
+    cHdffMenu(HDFF::cHdffCmdIf * pHdffCmdIf);
+    virtual ~cHdffMenu();
+    virtual eOSState ProcessKey(eKeys Key);
+};
+
+#endif
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..2bee15e
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,128 @@
+# VDR plugin language source file
+# Copyright (C) 2015 Andreas Regel
+# This file is distributed under the same license as the dvbhddevice package.
+# Christoph Haubrich <christoph1.haubrich at arcor.de>, 2011
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-dvbhddevice 2.2.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2014-09-21 14:01+0200\n"
+"PO-Revision-Date: 2011-04-25 21:44+0200\n"
+"Last-Translator: Christoph Haubrich\n"
+"Language-Team: <see README>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "HD Full Featured DVB device"
+msgstr "HD Full Featured DVB device"
+
+msgid "Video Conversion"
+msgstr "Bildanpassung"
+
+msgid "TV on"
+msgstr "TV ein"
+
+msgid "TV off"
+msgstr "TV aus"
+
+msgid "Automatic"
+msgstr "automatisch"
+
+msgid "Letterbox 16/9"
+msgstr "Letterbox 16:9"
+
+msgid "Letterbox 14/9"
+msgstr "Letterbox 14:9"
+
+msgid "Pillarbox"
+msgstr "Pillarbox"
+
+msgid "CentreCutOut"
+msgstr "CentreCutOut"
+
+msgid "Always 16/9"
+msgstr "immer 16:9"
+
+msgid "Zoom 16/9"
+msgstr "Zoome 16:9"
+
+msgid "Off"
+msgstr "aus"
+
+msgid "Frame rate"
+msgstr "passende Framerate"
+
+msgid "HD Only"
+msgstr "nur bei HD"
+
+msgid "Always"
+msgstr "immer"
+
+msgid "Disabled"
+msgstr "abgeschaltet"
+
+msgid "Analogue only"
+msgstr "nur analoge Ausgänge"
+
+msgid "HDMI only"
+msgstr "nur HDMI"
+
+msgid "Follow resolution"
+msgstr "folge Auflösung"
+
+msgid "none"
+msgstr "keins"
+
+msgid "Resolution"
+msgstr "Auflösung"
+
+msgid "Video Mode Adaption"
+msgstr "Auflösungsanpassung"
+
+msgid "TV format"
+msgstr "TV-Format"
+
+msgid "Analogue Video"
+msgstr "Analoges Video"
+
+msgid "Audio Delay (ms)"
+msgstr "Audio Verzögerung (ms)"
+
+msgid "Audio Downmix"
+msgstr "Audio Downmix"
+
+msgid "A/V Sync Shift (ms)"
+msgstr "A/V-Sync Verschiebung (ms)"
+
+msgid "OSD Size"
+msgstr "OSD Größe"
+
+msgid "HDMI CEC"
+msgstr "HDMI CEC"
+
+msgid "CEC: Switch TV on"
+msgstr "CEC: TV einschalten"
+
+msgid "CEC: Switch TV off"
+msgstr "CEC: TV ausschalten"
+
+msgid "Remote Control Protocol"
+msgstr "Fernbedienungsprotokoll"
+
+msgid "Remote Control Address"
+msgstr "Fernbedienungsadresse"
+
+msgid "High Level OSD"
+msgstr "High Level OSD"
+
+msgid "Allow True Color OSD"
+msgstr "Erlaube True Color OSD"
+
+msgid "True Color format"
+msgstr "True Color Format"
+
+msgid "Hide mainmenu entry"
+msgstr "Hauptmenüeintrag verstecken"
diff --git a/po/et_EE.po b/po/et_EE.po
new file mode 100644
index 0000000..b483cfe
--- /dev/null
+++ b/po/et_EE.po
@@ -0,0 +1,128 @@
+# VDR plugin language source file
+# Copyright (C) 2015 Andreas Regel
+# This file is distributed under the same license as the dvbhddevice package.
+# Arthur Konovalov <artlov at gmail.com>, 2015
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-dvbhddevice 2.2.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2014-09-21 14:01+0200\n"
+"PO-Revision-Date: 2011-04-25 21:44+0200\n"
+"Last-Translator: Arthur Konovalov <artlov at gmail.com>\n"
+"Language-Team: Estonian <vdr at linuxtv.org>\n"
+"Language: et\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "HD Full Featured DVB device"
+msgstr "Täisfunktsionaalne HD DVB seade"
+
+msgid "Video Conversion"
+msgstr "Video konverteerimine"
+
+msgid "TV on"
+msgstr "TV sisse"
+
+msgid "TV off"
+msgstr "TV välja"
+
+msgid "Automatic"
+msgstr "automaatne"
+
+msgid "Letterbox 16/9"
+msgstr "letterbox 16:9"
+
+msgid "Letterbox 14/9"
+msgstr "letterbox 14:9"
+
+msgid "Pillarbox"
+msgstr "pillarbox"
+
+msgid "CentreCutOut"
+msgstr "center cut out"
+
+msgid "Always 16/9"
+msgstr "alati 16:9"
+
+msgid "Zoom 16/9"
+msgstr "suum 16/9"
+
+msgid "Off"
+msgstr "väljas"
+
+msgid "Frame rate"
+msgstr "kaadrisagedus"
+
+msgid "HD Only"
+msgstr "ainult HD-resolutsioon"
+
+msgid "Always"
+msgstr "alati"
+
+msgid "Disabled"
+msgstr "keelatud"
+
+msgid "Analogue only"
+msgstr "ainult analoog"
+
+msgid "HDMI only"
+msgstr "ainult HDMI"
+
+msgid "Follow resolution"
+msgstr "vastavalt resolutsioonile"
+
+msgid "none"
+msgstr "ei"
+
+msgid "Resolution"
+msgstr "Resolutsioon"
+
+msgid "Video Mode Adaption"
+msgstr "Videorežiimi sobitus"
+
+msgid "TV format"
+msgstr "TV külgsuhe"
+
+msgid "Analogue Video"
+msgstr "Analoogvideo"
+
+msgid "Audio Delay (ms)"
+msgstr "Heli viide (ms)"
+
+msgid "Audio Downmix"
+msgstr "Heli downmix"
+
+msgid "A/V Sync Shift (ms)"
+msgstr "A/V-sünkro nihe (ms)"
+
+msgid "OSD Size"
+msgstr "Ekraanimenüü suurus"
+
+msgid "HDMI CEC"
+msgstr "HDMI CEC"
+
+msgid "CEC: Switch TV on"
+msgstr "CEC: TV sisselülitus"
+
+msgid "CEC: Switch TV off"
+msgstr "CEC: TV väljalülitus"
+
+msgid "Remote Control Protocol"
+msgstr "Kaugjuhtimispuldi protokoll"
+
+msgid "Remote Control Address"
+msgstr "Kaugjuhtimispuldi aadress"
+
+msgid "High Level OSD"
+msgstr "Kõrgema taseme ekraanimenüü"
+
+msgid "Allow True Color OSD"
+msgstr "True Color ekraanimenüü"
+
+msgid "True Color format"
+msgstr "True Color formaat"
+
+msgid "Hide mainmenu entry"
+msgstr "Peita peamenüü valikus"
diff --git a/po/fi_FI.po b/po/fi_FI.po
new file mode 100644
index 0000000..c97827f
--- /dev/null
+++ b/po/fi_FI.po
@@ -0,0 +1,128 @@
+# VDR plugin language source file
+# Copyright (C) 2015 Andreas Regel
+# This file is distributed under the same license as the dvbhddevice package.
+# Christoph Haubrich <christoph1.haubrich at arcor.de>, 2011
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-dvbhddevice 2.2.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2014-09-21 14:01+0200\n"
+"PO-Revision-Date: 2011-04-25 21:44+0200\n"
+"Last-Translator: Rolf Ahrenberg\n"
+"Language-Team: Finnish <vdr at linuxtv.org>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "HD Full Featured DVB device"
+msgstr "DVB-laite HD-ulostulolla"
+
+msgid "Video Conversion"
+msgstr "Näyttömuoto"
+
+msgid "TV on"
+msgstr "TV päälle"
+
+msgid "TV off"
+msgstr "TV kiinni"
+
+msgid "Automatic"
+msgstr "automaattinen"
+
+msgid "Letterbox 16/9"
+msgstr "letterbox 16:9"
+
+msgid "Letterbox 14/9"
+msgstr "letterbox 14:9"
+
+msgid "Pillarbox"
+msgstr "pillarbox"
+
+msgid "CentreCutOut"
+msgstr "center cut out"
+
+msgid "Always 16/9"
+msgstr "aina 16:9"
+
+msgid "Zoom 16/9"
+msgstr "zoom 16/9"
+
+msgid "Off"
+msgstr "ei"
+
+msgid "Frame rate"
+msgstr "kuvataajuuden mukaan"
+
+msgid "HD Only"
+msgstr "vain HD-resoluutiolla"
+
+msgid "Always"
+msgstr "aina"
+
+msgid "Disabled"
+msgstr "ei käytössä"
+
+msgid "Analogue only"
+msgstr "vain analoginen"
+
+msgid "HDMI only"
+msgstr "vain HDMI"
+
+msgid "Follow resolution"
+msgstr "resoluution mukaan"
+
+msgid "none"
+msgstr "ei"
+
+msgid "Resolution"
+msgstr "Kuvaresoluutio"
+
+msgid "Video Mode Adaption"
+msgstr "Sovita näyttömoodi"
+
+msgid "TV format"
+msgstr "Näytön kuvasuhde"
+
+msgid "Analogue Video"
+msgstr "Analoginen kuvalähtö"
+
+msgid "Audio Delay (ms)"
+msgstr "Äänen viive (ms)"
+
+msgid "Audio Downmix"
+msgstr "Äänen alasmiksaus"
+
+msgid "A/V Sync Shift (ms)"
+msgstr "A/V-synkronointi (ms)"
+
+msgid "OSD Size"
+msgstr "Kuvaruutunäytön koko"
+
+msgid "HDMI CEC"
+msgstr "Käytä HDMI CEC-toimintoa"
+
+msgid "CEC: Switch TV on"
+msgstr "CEC: Laita TV päälle"
+
+msgid "CEC: Switch TV off"
+msgstr "CEC: Sammuta TV"
+
+msgid "Remote Control Protocol"
+msgstr "Kaukosäätimen protokolla"
+
+msgid "Remote Control Address"
+msgstr "Kaukosäätimen osoite"
+
+msgid "High Level OSD"
+msgstr "Käytä korkean tason kuvaruutunäyttöä"
+
+msgid "Allow True Color OSD"
+msgstr "Salli tosivärit kuvaruutunäytölle"
+
+msgid "True Color format"
+msgstr "Näytä tosivärit muodossa"
+
+msgid "Hide mainmenu entry"
+msgstr "Piilota valinta päävalikosta"
diff --git a/po/it_IT.po b/po/it_IT.po
new file mode 100644
index 0000000..16752a8
--- /dev/null
+++ b/po/it_IT.po
@@ -0,0 +1,131 @@
+# VDR plugin language source file
+# Copyright (C) 2015 Andreas Regel
+# This file is distributed under the same license as the dvbhddevice package.
+# Christoph Haubrich <christoph1.haubrich at arcor.de>, 2011
+# Diego Pierotto <vdr-italian at tiscali.it>, 2013
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-dvbhddevice 2.2.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2014-09-21 14:01+0200\n"
+"PO-Revision-Date: 2015-02-08 19:48+0100\n"
+"Last-Translator: Diego Pierotto <vdr-italian at tiscali.it>\n"
+"Language-Team:  <see README>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-SourceCharset: utf-8\n"
+"X-Generator: Poedit 1.5.4\n"
+
+msgid "HD Full Featured DVB device"
+msgstr "Scheda DVB HD Full Featured"
+
+msgid "Video Conversion"
+msgstr "Conversione video"
+
+msgid "TV on"
+msgstr "TV accesa"
+
+msgid "TV off"
+msgstr "TV spenta"
+
+msgid "Automatic"
+msgstr "Automatica"
+
+msgid "Letterbox 16/9"
+msgstr "Letterbox 16:9"
+
+msgid "Letterbox 14/9"
+msgstr "Letterbox 14:9"
+
+msgid "Pillarbox"
+msgstr "Pillarbox"
+
+msgid "CentreCutOut"
+msgstr "CentreCutOut"
+
+msgid "Always 16/9"
+msgstr "Sempre 16:9"
+
+msgid "Zoom 16/9"
+msgstr "Ingrandimento 16/9"
+
+msgid "Off"
+msgstr "Spento"
+
+msgid "Frame rate"
+msgstr "Frame rate"
+
+msgid "HD Only"
+msgstr "Solo HD"
+
+msgid "Always"
+msgstr "Sempre"
+
+msgid "Disabled"
+msgstr "Disabilitata"
+
+msgid "Analogue only"
+msgstr "Solo analogica"
+
+msgid "HDMI only"
+msgstr "Solo HDMI"
+
+msgid "Follow resolution"
+msgstr "Risoluzione seguente"
+
+msgid "none"
+msgstr "nessuna"
+
+msgid "Resolution"
+msgstr "Risoluzione"
+
+msgid "Video Mode Adaption"
+msgstr "Adattamento modalità video"
+
+msgid "TV format"
+msgstr "Formato TV"
+
+msgid "Analogue Video"
+msgstr "Video analogico"
+
+msgid "Audio Delay (ms)"
+msgstr "Ritardo audio (ms)"
+
+msgid "Audio Downmix"
+msgstr "Scala Audio"
+
+msgid "A/V Sync Shift (ms)"
+msgstr "Alterna sincro A/V (ms)"
+
+msgid "OSD Size"
+msgstr "Dimensione OSD"
+
+msgid "HDMI CEC"
+msgstr "HDMI CEC"
+
+msgid "CEC: Switch TV on"
+msgstr "CEC: Passa a TV accesa"
+
+msgid "CEC: Switch TV off"
+msgstr "CEC: Passa a TV spenta"
+
+msgid "Remote Control Protocol"
+msgstr "Protocollo controllo remoto"
+
+msgid "Remote Control Address"
+msgstr "Indirizzo controllo remoto"
+
+msgid "High Level OSD"
+msgstr "OSD alto livello"
+
+msgid "Allow True Color OSD"
+msgstr "Permetti OSD True Color"
+
+msgid "True Color format"
+msgstr "Formato True Color"
+
+msgid "Hide mainmenu entry"
+msgstr "Nascondi voce menu principale"
diff --git a/po/uk_UA.po b/po/uk_UA.po
new file mode 100644
index 0000000..7d43819
--- /dev/null
+++ b/po/uk_UA.po
@@ -0,0 +1,129 @@
+# VDR plugin language source file.
+# Copyright (C) 2015 Andreas Regel
+# This file is distributed under the same license as the dvbhddevice package.
+# Yarema Aka Knedlyk <yupadmin at gmail.com>, 2015
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-dvbhddevice 2.2.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2015-02-03 13:28+0100\n"
+"PO-Revision-Date: 2015-02-01 23:31+0100\n"
+"Last-Translator: Yarema aka Knedlyk <yupadmin at gmail.com>\n"
+"Language-Team: Ukrainian <vdr at linuxtv.org>\n"
+"Language: uk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.7.3\n"
+
+msgid "HD Full Featured DVB device"
+msgstr "HD Full Featured DVB device"
+
+msgid "Video Conversion"
+msgstr "Конвертація відео"
+
+msgid "TV on"
+msgstr "Вкл ТБ"
+
+msgid "TV off"
+msgstr "Викл ТБ"
+
+msgid "Automatic"
+msgstr "Автоматично"
+
+msgid "Letterbox 16/9"
+msgstr "Конверт 16:9"
+
+msgid "Letterbox 14/9"
+msgstr "Конверт 14:9"
+
+msgid "Pillarbox"
+msgstr "Pillarbox"
+
+msgid "CentreCutOut"
+msgstr "Вірізання від центру"
+
+msgid "Always 16/9"
+msgstr "Завжди 16:9"
+
+msgid "Zoom 16/9"
+msgstr "Допасувати до 16:9"
+
+msgid "Off"
+msgstr "Викл"
+
+msgid "Frame rate"
+msgstr "Частота кадрів"
+
+msgid "HD Only"
+msgstr "Тільки HD"
+
+msgid "Always"
+msgstr "Завжди"
+
+msgid "Disabled"
+msgstr "Відключено"
+
+msgid "Analogue only"
+msgstr "Тільки аналоговий"
+
+msgid "HDMI only"
+msgstr "Тільки HDMI"
+
+msgid "Follow resolution"
+msgstr "Відносно розд. здатн."
+
+msgid "none"
+msgstr "немає"
+
+msgid "Resolution"
+msgstr "Розд. здатність"
+
+msgid "Video Mode Adaption"
+msgstr "Адаптація відео режиму"
+
+msgid "TV format"
+msgstr "Формат ТБ"
+
+msgid "Analogue Video"
+msgstr "Аналогове відео"
+
+msgid "Audio Delay (ms)"
+msgstr "Затримка аудіо (мс)"
+
+msgid "Audio Downmix"
+msgstr "Міксування аудіо"
+
+msgid "A/V Sync Shift (ms)"
+msgstr "А/В зсув синхронізації (мс)"
+
+msgid "OSD Size"
+msgstr "Розмір OSD"
+
+msgid "HDMI CEC"
+msgstr "HDMI CEC"
+
+msgid "CEC: Switch TV on"
+msgstr "CEC: включити ТБ"
+
+msgid "CEC: Switch TV off"
+msgstr "CEC: виключити ТБ"
+
+msgid "Remote Control Protocol"
+msgstr "Протокол пульта"
+
+msgid "Remote Control Address"
+msgstr "Адрес пульта"
+
+msgid "High Level OSD"
+msgstr "High Level OSD"
+
+msgid "Allow True Color OSD"
+msgstr "Включити True Color OSD"
+
+msgid "True Color format"
+msgstr "Формат True Color"
+
+msgid "Hide mainmenu entry"
+msgstr "Приховати в головному меню"
diff --git a/setup.c b/setup.c
new file mode 100644
index 0000000..fd16a48
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,476 @@
+/*
+ * 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.
+ */
+
+#include "setup.h"
+#include "hdffcmd.h"
+
+const int kResolution1080i = 0;
+const int kResolution720p = 1;
+const int kResolution576p = 2;
+const int kResolution576i = 3;
+
+
+cHdffSetup gHdffSetup;
+
+cHdffSetup::cHdffSetup(void)
+{
+    Resolution = kResolution1080i;
+    VideoModeAdaption = HDFF_VIDEO_MODE_ADAPT_OFF;
+    TvFormat = HDFF_TV_FORMAT_16_BY_9;
+    VideoConversion = HDFF_VIDEO_CONVERSION_PILLARBOX;
+    AnalogueVideo = HDFF_VIDEO_OUT_CVBS_YUV;
+    AudioDelay = 0;
+    AudioDownmix = HDFF_AUDIO_DOWNMIX_AUTOMATIC;
+    AvSyncShift = 0;
+    OsdSize = 0;
+    CecEnabled = 1;
+    CecTvOn = 1;
+    CecTvOff = 0;
+    RemoteProtocol = 1;
+    RemoteAddress = -1;
+    HighLevelOsd = 1;
+    TrueColorOsd = 1;
+    TrueColorFormat = 0;
+    HideMainMenu = 0;
+}
+
+bool cHdffSetup::SetupParse(const char *Name, const char *Value)
+{
+    if      (strcmp(Name, "Resolution")        == 0) Resolution        = atoi(Value);
+    else if (strcmp(Name, "VideoModeAdaption") == 0) VideoModeAdaption = 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, "AvSyncShift")       == 0) AvSyncShift       = atoi(Value);
+    else if (strcmp(Name, "OsdSize")           == 0) OsdSize           = atoi(Value);
+    else if (strcmp(Name, "CecEnabled")        == 0) CecEnabled        = atoi(Value);
+    else if (strcmp(Name, "CecTvOn")           == 0) CecTvOn           = atoi(Value);
+    else if (strcmp(Name, "CecTvOff")          == 0) CecTvOff          = 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 if (strcmp(Name, "TrueColorFormat")   == 0) TrueColorFormat   = atoi(Value);
+    else if (strcmp(Name, "HideMainMenu")      == 0) HideMainMenu      = 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_TV_FORMAT_16_BY_9)
+            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;
+}
+
+HdffVideoMode_t cHdffSetup::GetVideoMode(void)
+{
+    switch (Resolution)
+    {
+        case kResolution1080i:
+        default:
+            return HDFF_VIDEO_MODE_1080I50;
+        case kResolution720p:
+            return HDFF_VIDEO_MODE_720P50;
+        case kResolution576p:
+            return HDFF_VIDEO_MODE_576P50;
+        case kResolution576i:
+            return HDFF_VIDEO_MODE_576I50;
+    }
+}
+
+void cHdffSetup::SetNextVideoConversion(void)
+{
+    int nextVideoConversion = HDFF_VIDEO_CONVERSION_AUTOMATIC;
+
+    if (TvFormat == HDFF_TV_FORMAT_16_BY_9)
+    {
+        switch (VideoConversion)
+        {
+            case HDFF_VIDEO_CONVERSION_PILLARBOX:
+                nextVideoConversion = HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT;
+                break;
+            case HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT:
+                nextVideoConversion = HDFF_VIDEO_CONVERSION_ALWAYS_16_BY_9;
+                break;
+            case HDFF_VIDEO_CONVERSION_ALWAYS_16_BY_9:
+                nextVideoConversion = HDFF_VIDEO_CONVERSION_ZOOM_16_BY_9;
+                break;
+            case HDFF_VIDEO_CONVERSION_ZOOM_16_BY_9:
+                nextVideoConversion = HDFF_VIDEO_CONVERSION_PILLARBOX;
+                break;
+        }
+    }
+    else
+    {
+        switch (VideoConversion)
+        {
+            case HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9:
+                nextVideoConversion = HDFF_VIDEO_CONVERSION_LETTERBOX_14_BY_9;
+                break;
+            case HDFF_VIDEO_CONVERSION_LETTERBOX_14_BY_9:
+                nextVideoConversion = HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT;
+                break;
+            case HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT:
+                nextVideoConversion = HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9;
+                break;
+        }
+    }
+    VideoConversion = nextVideoConversion;
+}
+
+const char * cHdffSetup::GetVideoConversionString(void)
+{
+    switch (VideoConversion)
+    {
+        case HDFF_VIDEO_CONVERSION_AUTOMATIC:
+        default:
+            return tr("Automatic");
+        case HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9:
+            return tr("Letterbox 16/9");
+        case HDFF_VIDEO_CONVERSION_LETTERBOX_14_BY_9:
+            return tr("Letterbox 14/9");
+        case HDFF_VIDEO_CONVERSION_PILLARBOX:
+            return tr("Pillarbox");
+        case HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT:
+            return tr("CentreCutOut");
+        case HDFF_VIDEO_CONVERSION_ALWAYS_16_BY_9:
+            return tr("Always 16/9");
+        case HDFF_VIDEO_CONVERSION_ZOOM_16_BY_9:
+            return tr("Zoom 16/9");
+    }
+}
+
+void cHdffSetup::SetVideoFormat(HDFF::cHdffCmdIf * HdffCmdIf)
+{
+    HdffVideoFormat_t videoFormat;
+
+    videoFormat.AutomaticEnabled = true;
+    videoFormat.AfdEnabled = false;
+    videoFormat.TvFormat = (HdffTvFormat_t) TvFormat;
+    videoFormat.VideoConversion = (HdffVideoConversion_t) VideoConversion;
+    HdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
+}
+
+cHdffSetupPage::cHdffSetupPage(HDFF::cHdffCmdIf * pHdffCmdIf)
+{
+    const int kResolutions = 4;
+    const int kVideoModeAdaptions = 4;
+    const int kTvFormats = 2;
+    const int kAnalogueVideos = 4;
+    const int kAudioDownmixes = 5;
+    const int kOsdSizes = 5;
+    const int kRemoteProtocols = 3;
+    const int kTrueColorFormats = 3;
+
+    static const char * ResolutionItems[kResolutions] =
+    {
+        "1080i",
+        "720p",
+        "576p",
+        "576i",
+    };
+
+    static const char * VideoModeAdaptionItems[kVideoModeAdaptions] =
+    {
+        tr("Off"),
+        tr("Frame rate"),
+        tr("HD Only"),
+        tr("Always")
+    };
+
+    static const char * TvFormatItems[kTvFormats] =
+    {
+        "4/3",
+        "16/9",
+    };
+
+    static const char * AnalogueVideoItems[kAnalogueVideos] =
+    {
+        tr("Disabled"),
+        "RGB",
+        "CVBS + YUV",
+        "YC (S-Video)",
+    };
+
+    static const char * AudioDownmixItems[kAudioDownmixes] =
+    {
+        tr("Disabled"),
+        tr("Analogue only"),
+        tr("Always"),
+        tr("Automatic"),
+        tr("HDMI only"),
+    };
+
+    static const char * OsdSizeItems[kOsdSizes] =
+    {
+        tr("Follow resolution"),
+        "1920x1080",
+        "1280x720",
+        "1024x576",
+        "720x576",
+    };
+
+    static const char * RemoteProtocolItems[] =
+    {
+        tr("none"),
+        "RC5",
+        "RC6",
+    };
+
+    static const char * TrueColorFormatItems[kTrueColorFormats] =
+    {
+        "ARGB8888",
+        "ARGB8565",
+        "ARGB4444",
+    };
+
+    mHdffCmdIf = pHdffCmdIf;
+    mNewHdffSetup = gHdffSetup;
+
+    Add(new cMenuEditStraItem(tr("Resolution"), &mNewHdffSetup.Resolution, kResolutions, ResolutionItems));
+    Add(new cMenuEditStraItem(tr("Video Mode Adaption"), &mNewHdffSetup.VideoModeAdaption, kVideoModeAdaptions, VideoModeAdaptionItems));
+    mTvFormatItem = new cMenuEditStraItem(tr("TV format"), &mNewHdffSetup.TvFormat, kTvFormats, TvFormatItems);
+    Add(mTvFormatItem);
+    Add(new cMenuEditStraItem(tr("Analogue Video"), &mNewHdffSetup.AnalogueVideo, kAnalogueVideos, AnalogueVideoItems));
+    Add(new cMenuEditIntItem(tr("Audio Delay (ms)"), &mNewHdffSetup.AudioDelay, 0, 500));
+    Add(new cMenuEditStraItem(tr("Audio Downmix"), &mNewHdffSetup.AudioDownmix, kAudioDownmixes, AudioDownmixItems));
+    Add(new cMenuEditIntItem(tr("A/V Sync Shift (ms)"), &mNewHdffSetup.AvSyncShift, -500, 500));
+    Add(new cMenuEditStraItem(tr("OSD Size"), &mNewHdffSetup.OsdSize, kOsdSizes, OsdSizeItems));
+    Add(new cMenuEditBoolItem(tr("HDMI CEC"), &mNewHdffSetup.CecEnabled));
+    Add(new cMenuEditBoolItem(tr("CEC: Switch TV on"), &mNewHdffSetup.CecTvOn));
+    Add(new cMenuEditBoolItem(tr("CEC: Switch TV off"), &mNewHdffSetup.CecTvOff));
+    Add(new cMenuEditStraItem(tr("Remote Control Protocol"), &mNewHdffSetup.RemoteProtocol, kRemoteProtocols, RemoteProtocolItems));
+    Add(new cMenuEditIntItem(tr("Remote Control Address"), &mNewHdffSetup.RemoteAddress, -1, 31));
+    Add(new cMenuEditBoolItem(tr("High Level OSD"), &mNewHdffSetup.HighLevelOsd));
+    Add(new cMenuEditBoolItem(tr("Allow True Color OSD"), &mNewHdffSetup.TrueColorOsd));
+    Add(new cMenuEditStraItem(tr("True Color format"), &mNewHdffSetup.TrueColorFormat, kTrueColorFormats, TrueColorFormatItems));
+    Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &mNewHdffSetup.HideMainMenu));
+
+    mVideoConversion = 0;
+    if (mNewHdffSetup.TvFormat == HDFF_TV_FORMAT_16_BY_9)
+    {
+        switch (mNewHdffSetup.VideoConversion)
+        {
+            case HDFF_VIDEO_CONVERSION_PILLARBOX:
+                mVideoConversion = 0;
+                break;
+            case HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT:
+                mVideoConversion = 1;
+                break;
+            case HDFF_VIDEO_CONVERSION_ALWAYS_16_BY_9:
+                mVideoConversion = 2;
+                break;
+            case HDFF_VIDEO_CONVERSION_ZOOM_16_BY_9:
+                mVideoConversion = 3;
+                break;
+        }
+    }
+    else
+    {
+        switch (mNewHdffSetup.VideoConversion)
+        {
+            case HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9:
+                mVideoConversion = 0;
+                break;
+            case HDFF_VIDEO_CONVERSION_LETTERBOX_14_BY_9:
+                mVideoConversion = 1;
+                break;
+            case HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT:
+                mVideoConversion = 2;
+                break;
+        }
+    }
+    BuildVideoConversionItem();
+}
+
+cHdffSetupPage::~cHdffSetupPage(void)
+{
+}
+
+void cHdffSetupPage::BuildVideoConversionItem(void)
+{
+    const int kVideoConversions4by3 = 3;
+    const int kVideoConversions16by9 = 4;
+
+    static const char * VideoConversionItems4by3[kVideoConversions4by3] =
+    {
+        tr("Letterbox 16/9"),
+        tr("Letterbox 14/9"),
+        tr("CentreCutOut")
+    };
+
+    static const char * VideoConversionItems16by9[kVideoConversions16by9] =
+    {
+        tr("Pillarbox"),
+        tr("CentreCutOut"),
+        tr("Always 16/9"),
+        tr("Zoom 16/9")
+    };
+
+    cOsdItem * item;
+
+    cList<cOsdItem>::Del(mTvFormatItem->Next());
+    if (mNewHdffSetup.TvFormat == HDFF_TV_FORMAT_16_BY_9)
+    {
+        item = new cMenuEditStraItem(tr("Video Conversion"), &mVideoConversion,
+                kVideoConversions16by9, VideoConversionItems16by9);
+    }
+    else
+    {
+        item = new cMenuEditStraItem(tr("Video Conversion"), &mVideoConversion,
+                kVideoConversions4by3, VideoConversionItems4by3);
+    }
+    Add(item, false, mTvFormatItem);
+}
+
+void cHdffSetupPage::Store(void)
+{
+    if (mNewHdffSetup.TvFormat == HDFF_TV_FORMAT_16_BY_9)
+    {
+        switch (mVideoConversion)
+        {
+            case 0:
+                mNewHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_PILLARBOX;
+                break;
+            case 1:
+                mNewHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT;
+                break;
+            case 2:
+                mNewHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_ALWAYS_16_BY_9;
+                break;
+            case 3:
+                mNewHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_ZOOM_16_BY_9;
+                break;
+        }
+    }
+    else
+    {
+        switch (mVideoConversion)
+        {
+            case 0:
+                mNewHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_LETTERBOX_16_BY_9;
+                break;
+            case 1:
+                mNewHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_LETTERBOX_14_BY_9;
+                break;
+            case 2:
+                mNewHdffSetup.VideoConversion = HDFF_VIDEO_CONVERSION_CENTRE_CUT_OUT;
+                break;
+        }
+    }
+    SetupStore("Resolution", mNewHdffSetup.Resolution);
+    SetupStore("VideoModeAdaption", mNewHdffSetup.VideoModeAdaption);
+    SetupStore("TvFormat", mNewHdffSetup.TvFormat);
+    SetupStore("VideoConversion", mNewHdffSetup.VideoConversion);
+    SetupStore("AnalogueVideo", mNewHdffSetup.AnalogueVideo);
+    SetupStore("AudioDelay", mNewHdffSetup.AudioDelay);
+    SetupStore("AudioDownmix", mNewHdffSetup.AudioDownmix);
+    SetupStore("AvSyncShift", mNewHdffSetup.AvSyncShift);
+    SetupStore("OsdSize", mNewHdffSetup.OsdSize);
+    SetupStore("CecEnabled", mNewHdffSetup.CecEnabled);
+    SetupStore("CecTvOn", mNewHdffSetup.CecTvOn);
+    SetupStore("CecTvOff", mNewHdffSetup.CecTvOff);
+    SetupStore("RemoteProtocol", mNewHdffSetup.RemoteProtocol);
+    SetupStore("RemoteAddress", mNewHdffSetup.RemoteAddress);
+    SetupStore("HighLevelOsd", mNewHdffSetup.HighLevelOsd);
+    SetupStore("TrueColorOsd", mNewHdffSetup.TrueColorOsd);
+    SetupStore("TrueColorFormat", mNewHdffSetup.TrueColorFormat);
+    SetupStore("HideMainMenu", mNewHdffSetup.HideMainMenu);
+
+    if (mHdffCmdIf)
+    {
+        if (mNewHdffSetup.Resolution != gHdffSetup.Resolution)
+        {
+            mHdffCmdIf->CmdHdmiSetVideoMode(mNewHdffSetup.GetVideoMode());
+        }
+        HdffHdmiConfig_t hdmiConfig;
+
+        mNewHdffSetup.SetVideoFormat(mHdffCmdIf);
+
+        mHdffCmdIf->CmdAvSetAudioDelay(mNewHdffSetup.AudioDelay);
+        mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) mNewHdffSetup.AudioDownmix);
+        mHdffCmdIf->CmdAvSetSyncShift(mNewHdffSetup.AvSyncShift);
+
+        mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) mNewHdffSetup.AnalogueVideo);
+
+        memset(&hdmiConfig, 0, sizeof(hdmiConfig));
+        hdmiConfig.TransmitAudio = true;
+        hdmiConfig.ForceDviMode = false;
+        hdmiConfig.CecEnabled = mNewHdffSetup.CecEnabled;
+        hdmiConfig.VideoModeAdaption = (HdffVideoModeAdaption_t) mNewHdffSetup.VideoModeAdaption;
+        mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
+
+        mHdffCmdIf->CmdRemoteSetProtocol((HdffRemoteProtocol_t) mNewHdffSetup.RemoteProtocol);
+        mHdffCmdIf->CmdRemoteSetAddressFilter(mNewHdffSetup.RemoteAddress >= 0, mNewHdffSetup.RemoteAddress);
+    }
+
+    gHdffSetup = mNewHdffSetup;
+}
+
+eOSState cHdffSetupPage::ProcessKey(eKeys key)
+{
+    eOSState state = cMenuSetupPage::ProcessKey(key);
+
+    if (state == osContinue)
+    {
+        cOsdItem * item;
+        switch (key)
+        {
+            case kLeft:
+            case kRight:
+                item = Get(Current());
+                if (item == mTvFormatItem)
+                {
+                    mVideoConversion = 0;
+                    BuildVideoConversionItem();
+                    Display();
+                }
+                break;
+            default:
+                break;
+        }
+    }
+    return state;
+}
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..582ee76
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#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);
+    HdffVideoMode_t GetVideoMode(void);
+    void SetNextVideoConversion(void);
+    const char * GetVideoConversionString(void);
+    void SetVideoFormat(HDFF::cHdffCmdIf * HdffCmdIf);
+
+    int Resolution;
+    int VideoModeAdaption;
+    int TvFormat;
+    int VideoConversion;
+    int AnalogueVideo;
+    int AudioDelay;
+    int AudioDownmix;
+    int AvSyncShift;
+    int OsdSize;
+    int CecEnabled;
+    int CecTvOn;
+    int CecTvOff;
+    int RemoteProtocol;
+    int RemoteAddress;
+
+    int HighLevelOsd;
+    int TrueColorOsd;
+    int TrueColorFormat;
+
+    int HideMainMenu;
+};
+
+extern cHdffSetup gHdffSetup;
+
+class cHdffSetupPage : public cMenuSetupPage
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    cHdffSetup mNewHdffSetup;
+    cOsdItem * mTvFormatItem;
+    int mVideoConversion;
+
+    void BuildVideoConversionItem(void);
+
+protected:
+    virtual void Store(void);
+
+public:
+    cHdffSetupPage(HDFF::cHdffCmdIf * pHdffCmdIf);
+    virtual ~cHdffSetupPage(void);
+    virtual eOSState ProcessKey(eKeys Key);
+};
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-dvbhddevice.git



More information about the pkg-vdr-dvb-changes mailing list