Version 1.7.18 vdr-1.7.18
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>
Sun, 17 Apr 2011 14:50:00 +0000 (16:50 +0200)
committerKlaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de>
Sun, 17 Apr 2011 15:09:00 +0000 (17:09 +0200)
- Changed -O2 to -O3 in Make.config.template (reported by Matti Lehtimäki).
- Added a missing 'default' case in cPixmapMemory::DrawEllipse().
- Fixed some direct comparisons of double values.
- Fixed detecting frames on channels that broadcast with separate "fields" instead
  of complete frames.
- Made updating the editing marks during replay react faster in case the marks
  file has just been written (with a patch from Udo Richter).
- Fixed horizontal scaling of subtitles (reported by Reinhard Nissl).
- Stripped the note "The data returned by this function is only used for informational
  purposes (if any)" from the description of cDevice::GetVideoSize(). The VideoAspect
  is now used to properly scale subtitles.
- Fixed cUnbufferedFile::Seek() in case it is compiled without USE_FADVISE (thanks
  to Juergen Lock).
- Fixed the Language header of the Serbian translation file (thanks to Ville Skyttä).
- Added anti-aliasing when upscaling bitmaps, which improves the display of SD subtitles
  when replayed on an HD OSD (thanks to Reinhard Nissl for his help in debugging).
- Renamed cBitmap::Scale() to Scaled(), because it doesn't modify the bitmap itself,
  but rather returns a scaled copy.
- Fixed the description of cReceiver in PLUGINS.html, regarding detaching a receiver
  from its device before deleting it (reported by Winfried Köhler). This change in
  behavior was introduced in version 1.5.7.
- Fixed scaling subtitles in case the OSD size is exactly the same as the display
  size of the subtitles.
- Added a missing initialization to sDvbSpuRect (reported by Sergiu Dotenco).
- Replaced "%lld" and "%llX" print format specifiers with "PRId64" and "PRIX64" to
  avoid compiler warnings with gcc 4.5.2 (thanks to Sergiu Dotenco).
  On a personal note: I find it a step in the totally wrong direction that there
  have been macros introduced to work around this problem in the first place. There
  should have been "real" format specifiers defined that address this. These macros
  are nothing but an ugly workaround.
- Added Cancel(3) to ~cTrueColorDemo() in the "osddemo" plugin (thanks to Reinhard Nissl).
- Added a missing font deletion in cTrueColorDemo::Action() in the "osddemo" plugin
  (thanks to Reinhard Nissl).
- Fixed a buffer overflow in cFont::Bidi() (thanks to Reinhard Nissl).
- Added HD stream content identifiers to vdr.5 (thanks to Christoph Haubrich).
- Made cRecordingInfo::Read(FILE *f) private to avoid calls to it from outside
  cRecordingInfo or cRecording (reported by Mika Laitio).
- The dvbhddevice plugin is now part of the VDR distribution archive (thanks to
  Andreas Regel).
- Removed an obsolete local variable in dvbsdffosd.c (thanks to Paul Menzel).
- Fixed a possible NULL pointer dereference in osddemo.c (reported by Paul Menzel).
- Now using pkg-config to get fribidi, freetype and fontconfig cflags and libs (thanks
  to Ville Skyttä).
- The Makefile now also installs the include files (thanks to Ville Skyttä).
- Added handling of "ANSI/SCTE 57" descriptors (thanks too Rolf Ahrenberg).
- Avoiding an unecessary call to Recordings.ResetResume() (thanks to Reinhard
  Nissl).

44 files changed:
CONTRIBUTORS
HISTORY
Make.config.template
Makefile
PLUGINS.html
PLUGINS/src/dvbhddevice/COPYING [new file with mode: 0644]
PLUGINS/src/dvbhddevice/HISTORY [new file with mode: 0644]
PLUGINS/src/dvbhddevice/Makefile [new file with mode: 0644]
PLUGINS/src/dvbhddevice/README [new file with mode: 0644]
PLUGINS/src/dvbhddevice/bitbuffer.c [new file with mode: 0644]
PLUGINS/src/dvbhddevice/bitbuffer.h [new file with mode: 0644]
PLUGINS/src/dvbhddevice/dvbhddevice.c [new file with mode: 0644]
PLUGINS/src/dvbhddevice/dvbhdffdevice.c [new file with mode: 0644]
PLUGINS/src/dvbhddevice/dvbhdffdevice.h [new file with mode: 0644]
PLUGINS/src/dvbhddevice/hdffcmd.c [new file with mode: 0644]
PLUGINS/src/dvbhddevice/hdffcmd.h [new file with mode: 0644]
PLUGINS/src/dvbhddevice/hdffmsgdef.h [new file with mode: 0644]
PLUGINS/src/dvbhddevice/hdffosd.c [new file with mode: 0644]
PLUGINS/src/dvbhddevice/hdffosd.h [new file with mode: 0644]
PLUGINS/src/dvbhddevice/setup.c [new file with mode: 0644]
PLUGINS/src/dvbhddevice/setup.h [new file with mode: 0644]
PLUGINS/src/dvbsddevice/HISTORY
PLUGINS/src/dvbsddevice/dvbsddevice.c
PLUGINS/src/dvbsddevice/dvbsdffosd.c
PLUGINS/src/osddemo/HISTORY
PLUGINS/src/osddemo/osddemo.c
config.h
device.h
dvbspu.h
dvbsubtitle.c
dvbsubtitle.h
font.c
osd.c
osd.h
pat.c
po/sr_SR.po
recording.c
recording.h
remote.c
remux.c
remux.h
runvdr.template
tools.c
vdr.5

index 74090c2..f6ba82c 100644 (file)
@@ -1103,6 +1103,7 @@ Rolf Ahrenberg <rahrenbe@cc.hut.fi>
  for fixing the array size of Atypes in cPatFilter::Process()
  for adding support for "registration descriptor" to 'libsi' and using it in pat.c
  for adding an include of VDR's 'Make.global' to libsi's Makefile
+ for adding handling of "ANSI/SCTE 57" descriptors
 
 Ralf Klueber <ralf.klueber@vodafone.com>
  for reporting a bug in cutting a recording if there is only a single editing mark
@@ -1264,6 +1265,10 @@ Reinhard Nissl <rnissl@gmx.de>
  for some valuable input during development of the TrueColor OSD, help with
  debugging, and an implementation of the AlphaBlend() function.
  for storing the original display size when handling DVB subtitles
+ for reporting a problem with horizontal scaling of subtitles
+ for fixing a buffer overflow in cFont::Bidi()
+ for avoiding an unecessary call to Recordings.ResetResume()
+ for debugging a problem in handling the bitmap color depth for scaled subtitles
 
 Richard Robson <richard_robson@beeb.net>
  for reporting freezing replay if a timer starts while in Transfer Mode from the
@@ -1392,6 +1397,7 @@ Andreas Regel <andreas.regel@gmx.de>
  for adding some missing 'const' statements to cBitmap
  for making cDevice::AddPid() store the stream type of the given pid
  for adding cFont::FontName() and cFont::Size()
+ for writing the dvbhddevice plugin
 
 Thomas Bergwinkl <Thomas.Bergwinkl@vr-web.de>
  for fixing the validity check for channel IDs, because some providers use TIDs
@@ -1688,6 +1694,8 @@ Udo Richter <udo_richter@gmx.de>
  for reporting missing defines for large files in the 'newplugin' script
  for pointing out that the full timer file name should be displayed if it ends with
  "TITLE" or "EPISODE"
+ for a patch to "Made updating the editing marks during replay react faster in case
+ the marks file has just been written"
 
 Sven Kreiensen <svenk@kammer.uni-hannover.de>
  for his help in keeping 'channels.conf.terr' up to date
@@ -1886,6 +1894,9 @@ Ville Skytt
  for adding passing package name and version to xgettext
  for making 'dist' target dependent on up to date *.po
  for adding Language and fixing Language-Team header of *.po
+ for fixing the Language header of the Serbian translation file
+ for using pkg-config to get fribidi, freetype and fontconfig cflags and libs
+ for making the Makefile also install the include files
 
 Steffen Beyer <cpunk@reactor.de>
  for fixing setting the colored button help after deleting a recording in case the next
@@ -2205,6 +2216,7 @@ Christoph Haubrich <christoph1.haubrich@arcor.de>
  for reporting unused 'synced' member in cTsToPes
  for suggesting to add a note to cTsToPes about all TS packets having to belong to
  the same PID
+ for adding HD stream content identifiers to vdr.5
 
 Pekka Mauno <pekka.mauno@iki.fi>
  for fixing cSchedule::GetFollowingEvent() in case there is currently no present
@@ -2522,6 +2534,8 @@ Winfried K
  for fixing wrong value for TableIdBAT in libsi/si.h
  for making several code modifications to avoid compiler warnings
  for improving the description of the transponder parameters in vdr.5
+ for reporting a necessary fix in the description of cReceiver in PLUGINS.html,
+ regarding detaching a receiver from its device before deleting it
 
 Igor M. Liplianin <liplianin@tut.by>
  for a patch that was used to convert VDR to the S2API driver API
@@ -2601,6 +2615,7 @@ Francesco Saverio Schiavarelli <fschiava@libero.it>
 
 Matti Lehtimäki <matti.lehtimaki@gmail.com>
  for implementing the setup option "Miscellaneous/Channels wrap"
+ for reporting a missing change from -O2 to -O3 in Make.config.template
 
 Stephan Austermühle <au@hcsd.de>
  for suggesting to flush the file in cSafeFile::Close()
@@ -2622,6 +2637,8 @@ Paul Menzel <paulepanter@users.sourceforge.net>
  for making include paths not be overwritten in the Makefile
  for adding LDFLAGS to the linker calls in the Makefiles
  for reporting a possible memory leak in the "pictures" plugin
+ for removing an obsolete local variable in dvbsdffosd.c
+ for reporting a possible NULL pointer dereference in osddemo.c
 
 Radek Stastny <dedkus@gmail.com>
  for translating OSD texts to the Czech language
@@ -2670,3 +2687,13 @@ Frank Neumann <frank.neumann@hp.com>
 Gerald Dachs <vdr@dachsweb.de>
  for reporting a problem with checking for minimum line length of 21 characters in
  the LIRC receiver code
+
+Juergen Lock <vdr-l@jelal.kn-bremen.de>
+ for fixing cUnbufferedFile::Seek() in case it is compiled without USE_FADVISE
+
+Sergiu Dotenco <sergiu.dotenco@googlemail.com>
+ for reporting a missing initialization in sDvbSpuRect
+ for replacing "%lld" and "%llX" print format specifiers with "PRId64" and "PRIX64"
+
+Mika Laitio <lamikr@pilppa.org>
+ for reporting a case where cRecordingInfo::Read(FILE *f) was called with a NULL pointer
diff --git a/HISTORY b/HISTORY
index f73f5cf..c4e22fd 100644 (file)
--- a/HISTORY
+++ b/HISTORY
@@ -6556,3 +6556,53 @@ Video Disk Recorder Revision History
   Reinhard Nissl).
 - The original display size of subtitles is now used to scale them properly when
   displaying them on an HD OSD.
+
+2011-04-17: Version 1.7.18
+
+- Changed -O2 to -O3 in Make.config.template (reported by Matti Lehtimäki).
+- Added a missing 'default' case in cPixmapMemory::DrawEllipse().
+- Fixed some direct comparisons of double values.
+- Fixed detecting frames on channels that broadcast with separate "fields" instead
+  of complete frames.
+- Made updating the editing marks during replay react faster in case the marks
+  file has just been written (with a patch from Udo Richter).
+- Fixed horizontal scaling of subtitles (reported by Reinhard Nissl).
+- Stripped the note "The data returned by this function is only used for informational
+  purposes (if any)" from the description of cDevice::GetVideoSize(). The VideoAspect
+  is now used to properly scale subtitles.
+- Fixed cUnbufferedFile::Seek() in case it is compiled without USE_FADVISE (thanks
+  to Juergen Lock).
+- Fixed the Language header of the Serbian translation file (thanks to Ville Skyttä).
+- Added anti-aliasing when upscaling bitmaps, which improves the display of SD subtitles
+  when replayed on an HD OSD (thanks to Reinhard Nissl for his help in debugging).
+- Renamed cBitmap::Scale() to Scaled(), because it doesn't modify the bitmap itself,
+  but rather returns a scaled copy.
+- Fixed the description of cReceiver in PLUGINS.html, regarding detaching a receiver
+  from its device before deleting it (reported by Winfried Köhler). This change in
+  behavior was introduced in version 1.5.7.
+- Fixed scaling subtitles in case the OSD size is exactly the same as the display
+  size of the subtitles.
+- Added a missing initialization to sDvbSpuRect (reported by Sergiu Dotenco).
+- Replaced "%lld" and "%llX" print format specifiers with "PRId64" and "PRIX64" to
+  avoid compiler warnings with gcc 4.5.2 (thanks to Sergiu Dotenco).
+  On a personal note: I find it a step in the totally wrong direction that there
+  have been macros introduced to work around this problem in the first place. There
+  should have been "real" format specifiers defined that address this. These macros
+  are nothing but an ugly workaround.
+- Added Cancel(3) to ~cTrueColorDemo() in the "osddemo" plugin (thanks to Reinhard Nissl).
+- Added a missing font deletion in cTrueColorDemo::Action() in the "osddemo" plugin
+  (thanks to Reinhard Nissl).
+- Fixed a buffer overflow in cFont::Bidi() (thanks to Reinhard Nissl).
+- Added HD stream content identifiers to vdr.5 (thanks to Christoph Haubrich).
+- Made cRecordingInfo::Read(FILE *f) private to avoid calls to it from outside
+  cRecordingInfo or cRecording (reported by Mika Laitio).
+- The dvbhddevice plugin is now part of the VDR distribution archive (thanks to
+  Andreas Regel).
+- Removed an obsolete local variable in dvbsdffosd.c (thanks to Paul Menzel).
+- Fixed a possible NULL pointer dereference in osddemo.c (reported by Paul Menzel).
+- Now using pkg-config to get fribidi, freetype and fontconfig cflags and libs (thanks
+  to Ville Skyttä).
+- The Makefile now also installs the include files (thanks to Ville Skyttä).
+- Added handling of "ANSI/SCTE 57" descriptors (thanks too Rolf Ahrenberg).
+- Avoiding an unecessary call to Recordings.ResetResume() (thanks to Reinhard
+  Nissl).
index 3abb724..1fc8227 100644 (file)
@@ -6,15 +6,15 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Make.config.template 2.2 2010/02/06 14:50:03 kls Exp $
+# $Id: Make.config.template 2.3 2011/03/13 13:41:12 kls Exp $
 
 ### The C compiler and options:
 
 CC       = gcc
-CFLAGS   = -g -O2 -Wall
+CFLAGS   = -g -O3 -Wall
 
 CXX      = g++
-CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
+CXXFLAGS = -g -O3 -Wall -Woverloaded-virtual -Wno-parentheses
 
 ifdef PLUGIN
 CFLAGS   += -fPIC
index e84849b..9317839 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Makefile 2.14 2011/02/27 09:59:11 kls Exp $
+# $Id: Makefile 2.17 2011/04/17 13:35:53 kls Exp $
 
 .DELETE_ON_ERROR:
 
@@ -19,9 +19,10 @@ DESTDIR ?=
 PREFIX  ?= /usr/local
 MANDIR   = $(PREFIX)/share/man
 BINDIR   = $(PREFIX)/bin
+INCDIR   = $(PREFIX)/include
 LOCDIR   = ./locale
-LIBS     = -ljpeg -lpthread -ldl -lcap -lrt -lfreetype -lfontconfig
-INCLUDES ?= $(shell pkg-config --cflags freetype2)
+LIBS     = -ljpeg -lpthread -ldl -lcap -lrt $(shell pkg-config --libs freetype2 fontconfig)
+INCLUDES ?= $(shell pkg-config --cflags freetype2 fontconfig)
 
 PLUGINDIR= ./PLUGINS
 PLUGINLIBDIR= $(PLUGINDIR)/lib
@@ -54,9 +55,9 @@ ifdef VDR_USER
 DEFINES += -DVDR_USER=\"$(VDR_USER)\"
 endif
 ifdef BIDI
-INCLUDES += -I/usr/include/fribidi
+INCLUDES += $(shell pkg-config --cflags fribidi)
 DEFINES += -DBIDI
-LIBS += -lfribidi
+LIBS += $(shell pkg-config --libs fribidi)
 endif
 
 LIRC_DEVICE ?= /dev/lircd
@@ -162,7 +163,7 @@ clean-plugins:
 
 # Install the files:
 
-install: install-bin install-conf install-doc install-plugins install-i18n
+install: install-bin install-conf install-doc install-plugins install-i18n install-includes
 
 # VDR binary:
 
@@ -193,6 +194,12 @@ install-plugins: plugins
        @mkdir -p $(DESTDIR)$(PLUGINLIBDIR)
        @cp --remove-destination $(PLUGINDIR)/lib/lib*-*.so.$(APIVERSION) $(DESTDIR)$(PLUGINLIBDIR)
 
+# Includes:
+
+install-includes: include-dir
+       @mkdir -p $(DESTDIR)$(INCDIR)
+       @cp -pLR include/vdr include/libsi $(DESTDIR)$(INCDIR)
+
 # Source documentation:
 
 srcdoc:
index 05fb7ed..3859918 100644 (file)
@@ -1523,8 +1523,9 @@ the receiver is attached to the device that actually receives the current live
 video stream (this may be different from the primary device in case of <i>Transfer
 Mode</i>).
 <p>
-If the <tt>cReceiver</tt> isn't needed any more, it may simply be <i>deleted</i>
-and will automatically detach itself from the <tt>cDevice</tt>.
+<div class="modified">
+The <tt>cReceiver</tt> must be detached from its device before it is deleted.
+</div modified>
 
 <hr><h2><a name="Filters">Filters</a></h2>
 
diff --git a/PLUGINS/src/dvbhddevice/COPYING b/PLUGINS/src/dvbhddevice/COPYING
new file mode 100644 (file)
index 0000000..f90922e
--- /dev/null
@@ -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/PLUGINS/src/dvbhddevice/HISTORY b/PLUGINS/src/dvbhddevice/HISTORY
new file mode 100644 (file)
index 0000000..aa788fd
--- /dev/null
@@ -0,0 +1,16 @@
+VDR Plugin 'dvbhddevice' Revision History
+-----------------------------------------
+
+2009-12-29: Version 0.0.1
+
+- Initial revision.
+
+2010-01-04: Version 0.0.2
+
+- Calling the MakePrimaryDevice() function of the base class to allow
+  the cDevice to stop displaying subtitles.
+- Added support for DVB cards with multiple frontends.
+
+2011-04-17: Version 0.0.3
+
+- Added support for TrueColor OSD.
diff --git a/PLUGINS/src/dvbhddevice/Makefile b/PLUGINS/src/dvbhddevice/Makefile
new file mode 100644 (file)
index 0000000..ea1b9d1
--- /dev/null
@@ -0,0 +1,114 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id: Makefile 1.7 2011/04/17 11:40:55 kls Exp $
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+# IMPORTANT: the presence of this macro is important for the Make.config
+# file. So it must be defined, even if it is not used here!
+#
+PLUGIN = dvbhddevice
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX      ?= g++
+CXXFLAGS ?= -g -O3 -Wall -Woverloaded-virtual -Wno-parentheses
+
+### The directory environment:
+
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Make sure that necessary options are included:
+
+include $(VDRDIR)/Make.global
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR's plugin API (taken from VDR's "config.h"):
+
+APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o bitbuffer.o dvbhdffdevice.o hdffcmd.o hdffosd.o setup.o
+
+### The main target:
+
+all: libvdr-$(PLUGIN).so i18n
+
+### Implicit rules:
+
+%.o: %.c
+       $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+       @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR     = po
+LOCALEDIR = $(VDRDIR)/locale
+I18Npo    = $(wildcard $(PODIR)/*.po)
+I18Nmsgs  = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot   = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+       msgfmt -c -o $@ $<
+
+$(I18Npot): $(wildcard *.c)
+       xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=VDR --package-version=$(VDRVERSION) --msgid-bugs-address='<see README>' -o $@ $^
+
+%.po: $(I18Npot)
+       msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
+       @touch $@
+
+$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+       @mkdir -p $(dir $@)
+       cp $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmsgs) $(I18Npot)
+
+### Targets:
+
+libvdr-$(PLUGIN).so: $(OBJS)
+       $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+       @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
+
+dist: $(I18Npo) clean
+       @-rm -rf $(TMPDIR)/$(ARCHIVE)
+       @mkdir $(TMPDIR)/$(ARCHIVE)
+       @cp -a * $(TMPDIR)/$(ARCHIVE)
+       @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+       @-rm -rf $(TMPDIR)/$(ARCHIVE)
+       @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+       @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
diff --git a/PLUGINS/src/dvbhddevice/README b/PLUGINS/src/dvbhddevice/README
new file mode 100644 (file)
index 0000000..5697dea
--- /dev/null
@@ -0,0 +1,18 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by:                  Andreas Regel <andreas.regel@gmx.de>
+
+Project's homepage:          http://powarman.dyndns.org/hg/dvbhddevice
+
+Latest version available at: http://powarman.dyndns.org/hg/dvbhddevice
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+See the file COPYING for more information.
+
+Description:
+
+The 'dvbhddevice' plugin implements the output device for the
+"Full Featured TechnoTrend S2-6400" DVB cards.
diff --git a/PLUGINS/src/dvbhddevice/bitbuffer.c b/PLUGINS/src/dvbhddevice/bitbuffer.c
new file mode 100644 (file)
index 0000000..244b85e
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * bitbuffer.c: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: bitbuffer.c 1.1 2009/12/29 14:29:20 kls Exp $
+ */
+
+#include "bitbuffer.h"
+#include <stdlib.h>
+
+cBitBuffer::cBitBuffer(uint32_t MaxLength)
+{
+    mData = NULL;
+    mMaxLength = 0;
+    mBitPos = 0;
+
+    if (MaxLength <= 0x10000)
+    {
+        mData = new uint8_t[MaxLength];
+        if (mData)
+        {
+            mMaxLength = MaxLength * 8;
+        }
+    }
+}
+
+cBitBuffer::~cBitBuffer(void)
+{
+    if (mData)
+        delete[] mData;
+}
+
+uint8_t * cBitBuffer::GetData(void)
+{
+    return mData;
+}
+
+uint32_t cBitBuffer::GetMaxLength(void)
+{
+    return mMaxLength / 8;
+}
+
+uint32_t cBitBuffer::GetBits(int NumBits)
+{
+    return 0;
+}
+
+void cBitBuffer::SetBits(int NumBits, uint32_t Data)
+{
+    uint32_t nextBitPos;
+    uint32_t bytePos;
+    uint32_t bitsInByte;
+    int shift;
+
+    if (NumBits <= 0 || NumBits > 32)
+        return;
+
+    nextBitPos = mBitPos + NumBits;
+
+    if (nextBitPos > mMaxLength)
+        return;
+
+    bytePos = mBitPos / 8;
+    bitsInByte = mBitPos % 8;
+
+    mData[bytePos] &= (uint8_t) (0xFF << (8 - bitsInByte));
+    shift = NumBits - (8 - bitsInByte);
+    if (shift > 0)
+        mData[bytePos] |= (uint8_t) (Data >> shift);
+    else
+        mData[bytePos] |= (uint8_t) (Data << (-shift));
+    NumBits -= 8 - bitsInByte;
+    bytePos++;
+    while (NumBits > 0)
+    {
+        shift = NumBits - 8;
+        if (shift > 0)
+            mData[bytePos] = (uint8_t) (Data >> shift);
+        else
+            mData[bytePos] = (uint8_t) (Data << (-shift));
+        NumBits -= 8;
+        bytePos++;
+    }
+    mBitPos = nextBitPos;
+}
+
+uint32_t cBitBuffer::GetByteLength(void)
+{
+    return (mBitPos + 7) / 8;
+}
+
+void cBitBuffer::SetDataByte(uint32_t Position, uint8_t Data)
+{
+    if (Position < mMaxLength)
+        mData[Position] = Data;
+}
diff --git a/PLUGINS/src/dvbhddevice/bitbuffer.h b/PLUGINS/src/dvbhddevice/bitbuffer.h
new file mode 100644 (file)
index 0000000..e7b3650
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * bitbuffer.h: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: bitbuffer.h 1.1 2009/12/29 14:27:03 kls Exp $
+ */
+
+#ifndef _HDFF_BITBUFFER_H_
+#define _HDFF_BITBUFFER_H_
+
+#include <stdint.h>
+
+class cBitBuffer
+{
+private:
+    uint8_t * mData;
+    uint32_t mMaxLength;
+    uint32_t mBitPos;
+public:
+    cBitBuffer(uint32_t MaxLength);
+    ~cBitBuffer(void);
+    uint8_t * GetData(void);
+    uint32_t GetMaxLength(void);
+    uint32_t GetBits(int NumBits);
+    void SetBits(int NumBits, uint32_t Data);
+    uint32_t GetByteLength(void);
+    void SetDataByte(uint32_t Position, uint8_t Data);
+};
+
+#endif
diff --git a/PLUGINS/src/dvbhddevice/dvbhddevice.c b/PLUGINS/src/dvbhddevice/dvbhddevice.c
new file mode 100644 (file)
index 0000000..d639922
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * dvbhddevice.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: dvbhddevice.c 1.12 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include <vdr/plugin.h>
+#include "dvbhdffdevice.h"
+#include "setup.h"
+
+static const char *VERSION        = "0.0.3";
+static const char *DESCRIPTION    = "HD Full Featured DVB device";
+
+class cPluginDvbhddevice : public cPlugin {
+private:
+  cDvbHdFfDeviceProbe *probe;
+public:
+  cPluginDvbhddevice(void);
+  virtual ~cPluginDvbhddevice();
+  virtual const char *Version(void) { return VERSION; }
+  virtual const char *Description(void) { return DESCRIPTION; }
+  virtual cMenuSetupPage *SetupMenu(void);
+  virtual bool SetupParse(const char *Name, const char *Value);
+  };
+
+cPluginDvbhddevice::cPluginDvbhddevice(void)
+{
+  probe = new cDvbHdFfDeviceProbe;
+}
+
+cPluginDvbhddevice::~cPluginDvbhddevice()
+{
+  delete probe;
+}
+
+cMenuSetupPage *cPluginDvbhddevice::SetupMenu(void)
+{
+  return new cHdffSetupPage(cDvbHdFfDevice::GetHdffCmdHandler());
+}
+
+bool cPluginDvbhddevice::SetupParse(const char *Name, const char *Value)
+{
+  return gHdffSetup.SetupParse(Name, Value);
+}
+
+VDRPLUGINCREATOR(cPluginDvbhddevice); // Don't touch this!
diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.c b/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
new file mode 100644 (file)
index 0000000..9263009
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * dvbhdffdevice.c: The DVB HD Full Featured device interface
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: dvbhdffdevice.c 1.29 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include "dvbhdffdevice.h"
+#include <errno.h>
+#include <limits.h>
+#include <libsi/si.h>
+#include <linux/videodev2.h>
+#include <linux/dvb/audio.h>
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/video.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <vdr/eitscan.h>
+#include <vdr/transfer.h>
+#include "hdffosd.h"
+#include "setup.h"
+
+// --- cDvbHdFfDevice ----------------------------------------------------------
+
+int cDvbHdFfDevice::devHdffOffset = -1;
+
+cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend)
+:cDvbDevice(Adapter, Frontend)
+{
+  spuDecoder = NULL;
+  audioChannel = 0;
+  playMode = pmNone;
+  mHdffCmdIf = NULL;
+
+  // Devices that are only present on cards with decoders:
+
+  fd_osd      = DvbOpen(DEV_DVB_OSD,    adapter, frontend, O_RDWR);
+  fd_video    = DvbOpen(DEV_DVB_VIDEO,  adapter, frontend, O_RDWR | O_NONBLOCK);
+  fd_audio    = DvbOpen(DEV_DVB_AUDIO,  adapter, frontend, O_RDWR | O_NONBLOCK);
+
+  //TODO missing /dev/video offset calculation
+
+  isHdffPrimary = false;
+  if (devHdffOffset < 0) {
+     devHdffOffset = adapter;
+     isHdffPrimary = true;
+     mHdffCmdIf = new HDFF::cHdffCmdIf(fd_osd);
+     mHdffCmdIf->CmdAvSetAudioDelay(gHdffSetup.AudioDelay);
+     mHdffCmdIf->CmdAvSetAudioDownmix((HDFF::eDownmixMode) gHdffSetup.AudioDownmix);
+     mHdffCmdIf->CmdMuxSetVideoOut((HDFF::eVideoOut) gHdffSetup.AnalogueVideo);
+     mHdffCmdIf->CmdHdmiSetVideoMode(gHdffSetup.GetVideoMode());
+     HDFF::tHdmiConfig hdmiConfig;
+     hdmiConfig.TransmitAudio = true;
+     hdmiConfig.ForceDviMode = false;
+     hdmiConfig.CecEnabled = gHdffSetup.CecEnabled;
+     mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
+     if (gHdffSetup.CecEnabled)
+        mHdffCmdIf->CmdHdmiSendCecCommand(HDFF::cecCommandTvOn);
+     mHdffCmdIf->CmdRemoteSetProtocol((HDFF::eRemoteProtocol) gHdffSetup.RemoteProtocol);
+     mHdffCmdIf->CmdRemoteSetAddressFilter(gHdffSetup.RemoteAddress >= 0, gHdffSetup.RemoteAddress);
+     }
+
+  // Video format:
+
+  SetVideoFormat(Setup.VideoFormat);
+}
+
+cDvbHdFfDevice::~cDvbHdFfDevice()
+{
+  delete spuDecoder;
+  if (isHdffPrimary)
+     delete mHdffCmdIf;
+  // We're not explicitly closing any device files here, since this sometimes
+  // caused segfaults. Besides, the program is about to terminate anyway...
+}
+
+void cDvbHdFfDevice::MakePrimaryDevice(bool On)
+{
+  if (On)
+     new cHdffOsdProvider(mHdffCmdIf);
+  cDvbDevice::MakePrimaryDevice(On);
+}
+
+bool cDvbHdFfDevice::HasDecoder(void) const
+{
+  return isHdffPrimary;
+}
+
+cSpuDecoder *cDvbHdFfDevice::GetSpuDecoder(void)
+{
+  if (!spuDecoder && IsPrimaryDevice())
+     spuDecoder = new cDvbSpuDecoder();
+  return spuDecoder;
+}
+
+uchar *cDvbHdFfDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
+{
+  //TODO
+  return NULL;
+}
+
+void cDvbHdFfDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
+{
+  //TODO???
+  cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
+}
+
+void cDvbHdFfDevice::SetVideoFormat(bool VideoFormat16_9)
+{
+  HDFF::tVideoFormat videoFormat;
+  videoFormat.AutomaticEnabled = true;
+  videoFormat.AfdEnabled = true;
+  videoFormat.TvFormat = (HDFF::eTvFormat) gHdffSetup.TvFormat;
+  videoFormat.VideoConversion = (HDFF::eVideoConversion) gHdffSetup.VideoConversion;
+  mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
+}
+
+eVideoSystem cDvbHdFfDevice::GetVideoSystem(void)
+{
+  eVideoSystem VideoSystem = vsPAL;
+  if (fd_video >= 0) {
+     video_size_t vs;
+     if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
+        if (vs.h == 480 || vs.h == 240)
+           VideoSystem = vsNTSC;
+        }
+     else
+        LOG_ERROR;
+     }
+  return VideoSystem;
+}
+
+void cDvbHdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
+{
+  if (fd_video >= 0) {
+     video_size_t vs;
+     if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
+        Width = vs.w;
+        Height = vs.h;
+        switch (vs.aspect_ratio) {
+          default:
+          case VIDEO_FORMAT_4_3:   VideoAspect =  4.0 / 3.0; break;
+          case VIDEO_FORMAT_16_9:  VideoAspect = 16.0 / 9.0; break;
+          case VIDEO_FORMAT_221_1: VideoAspect =       2.21; break;
+          }
+        return;
+        }
+     else
+        LOG_ERROR;
+     }
+  cDevice::GetVideoSize(Width, Height, VideoAspect);
+}
+
+void cDvbHdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
+{
+  gHdffSetup.GetOsdSize(Width, Height, PixelAspect);
+}
+
+/*TODO obsolete?
+bool cDvbHdFfDevice::SetAudioBypass(bool On)
+{
+  if (setTransferModeForDolbyDigital != 1)
+     return false;
+  return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
+}
+TODO*/
+
+bool cDvbHdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On)
+{
+  if (Handle->pid) {
+     dmx_pes_filter_params pesFilterParams;
+     memset(&pesFilterParams, 0, sizeof(pesFilterParams));
+     if (On) {
+        if (Handle->handle < 0) {
+           Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
+           if (Handle->handle < 0) {
+              LOG_ERROR;
+              return false;
+              }
+           }
+        if (Type == ptPcr)
+           mHdffCmdIf->CmdAvSetPcrPid(0, Handle->pid);
+        else if (Type == ptVideo) {
+           if (Handle->streamType == 0x1B)
+              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF::videoStreamH264);
+           else
+              mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF::videoStreamMpeg2);
+           }
+        else if (Type == ptAudio)
+           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF::audioStreamMpeg1);
+        else if (Type == ptDolby)
+           mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF::audioStreamAc3);
+        if (!(Type <= ptDolby && Handle->used <= 1)) {
+           pesFilterParams.pid     = Handle->pid;
+           pesFilterParams.input   = DMX_IN_FRONTEND;
+           pesFilterParams.output  = DMX_OUT_TS_TAP;
+           pesFilterParams.pes_type= DMX_PES_OTHER;
+           pesFilterParams.flags   = DMX_IMMEDIATE_START;
+           if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+              LOG_ERROR;
+              return false;
+              }
+           }
+        }
+     else if (!Handle->used) {
+        CHECK(ioctl(Handle->handle, DMX_STOP));
+        if (Type == ptPcr)
+           mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+        else if (Type == ptVideo)
+           mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg2);
+        else if (Type == ptAudio)
+           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+        else if (Type == ptDolby)
+           mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamAc3);
+        //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid()
+        close(Handle->handle);
+        Handle->handle = -1;
+        }
+     }
+  return true;
+}
+
+void cDvbHdFfDevice::TurnOffLiveMode(bool LiveView)
+{
+  // Turn off live PIDs:
+
+  DetachAll(pidHandles[ptAudio].pid);
+  DetachAll(pidHandles[ptVideo].pid);
+  DetachAll(pidHandles[ptPcr].pid);
+  DetachAll(pidHandles[ptTeletext].pid);
+  DelPid(pidHandles[ptAudio].pid);
+  DelPid(pidHandles[ptVideo].pid);
+  DelPid(pidHandles[ptPcr].pid, ptPcr);
+  DelPid(pidHandles[ptTeletext].pid);
+  DelPid(pidHandles[ptDolby].pid);
+}
+
+bool cDvbHdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
+{
+  int apid = Channel->Apid(0);
+  int vpid = Channel->Vpid();
+  int dpid = Channel->Dpid(0);
+
+  bool DoTune = !IsTunedToTransponder(Channel);
+
+  bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid;
+  bool pidHandlesAudio = pidHandles[ptAudio].pid == apid;
+
+  bool TurnOffLivePIDs = DoTune
+                         || !IsPrimaryDevice()
+                         || LiveView // for a new live view the old PIDs need to be turned off
+                         || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
+                         ;
+
+  bool StartTransferMode = IsPrimaryDevice() && !DoTune
+                           && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER
+                              || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
+                              );
+  if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber()))
+     StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN;
+
+  bool TurnOnLivePIDs = !StartTransferMode && LiveView;
+
+  // Turn off live PIDs if necessary:
+
+  if (TurnOffLivePIDs)
+     TurnOffLiveMode(LiveView);
+
+  // Set the tuner:
+
+  if (!cDvbDevice::SetChannelDevice(Channel, LiveView))
+     return false;
+
+  // If this channel switch was requested by the EITScanner we don't wait for
+  // a lock and don't set any live PIDs (the EITScanner will wait for the lock
+  // by itself before setting any filters):
+
+  if (EITScanner.UsesDevice(this)) //XXX
+     return true;
+
+  // PID settings:
+
+  if (TurnOnLivePIDs) {
+     //SetAudioBypass(false);//TODO obsolete?
+     if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid, ptAudio))) {
+        esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
+        return false;
+        }
+     if (IsPrimaryDevice())
+        AddPid(Channel->Tpid(), ptTeletext);//TODO obsolete?
+     }
+  else if (StartTransferMode)
+     cControl::Launch(new cTransferControl(this, Channel));
+
+  return true;
+}
+
+int cDvbHdFfDevice::GetAudioChannelDevice(void)
+{
+  return audioChannel;
+}
+
+void cDvbHdFfDevice::SetAudioChannelDevice(int AudioChannel)
+{
+  mHdffCmdIf->CmdAvSetAudioChannel(AudioChannel);
+  audioChannel = AudioChannel;
+}
+
+void cDvbHdFfDevice::SetVolumeDevice(int Volume)
+{
+  mHdffCmdIf->CmdMuxSetVolume(Volume * 100 / 255);
+}
+
+void cDvbHdFfDevice::SetDigitalAudioDevice(bool On)
+{
+  // not needed
+}
+
+void cDvbHdFfDevice::SetAudioTrackDevice(eTrackType Type)
+{
+  //printf("SetAudioTrackDevice %d\n", Type);
+  const tTrackId *TrackId = GetTrack(Type);
+  if (TrackId && TrackId->id) {
+     if (IS_AUDIO_TRACK(Type)) {
+        if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) {
+           DetachAll(pidHandles[ptAudio].pid);
+           if (CamSlot())
+              CamSlot()->SetPid(pidHandles[ptAudio].pid, false);
+           pidHandles[ptAudio].pid = TrackId->id;
+           SetPid(&pidHandles[ptAudio], ptAudio, true);
+           if (CamSlot()) {
+              CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
+              CamSlot()->StartDecrypting();
+              }
+           }
+       }
+     else if (IS_DOLBY_TRACK(Type)) {
+        pidHandles[ptDolby].pid = TrackId->id;
+        SetPid(&pidHandles[ptDolby], ptDolby, true);
+        }
+     }
+}
+
+bool cDvbHdFfDevice::CanReplay(void) const
+{
+  return cDevice::CanReplay();
+}
+
+bool cDvbHdFfDevice::SetPlayMode(ePlayMode PlayMode)
+{
+  if (PlayMode == pmNone) {
+     mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
+     mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+     mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg2);
+     mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+
+     ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
+     mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
+     mHdffCmdIf->CmdAvEnableSync(0, true);
+     mHdffCmdIf->CmdAvSetPlayMode(0, true);
+     }
+  else {
+     if (playMode == pmNone)
+        TurnOffLiveMode(true);
+
+     mHdffCmdIf->CmdAvSetPlayMode(1, Transferring());
+     mHdffCmdIf->CmdAvSetStc(0, 100000);
+     mHdffCmdIf->CmdAvEnableSync(0, true);
+     mHdffCmdIf->CmdAvEnableVideoAfterStop(0, true);
+
+     playVideoPid = -1;
+     playAudioPid = -1;
+     audioCounter = 0;
+     videoCounter = 0;
+
+     mHdffCmdIf->CmdAvSetDecoderInput(0, 2);
+     ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
+     }
+  playMode = PlayMode;
+  return true;
+}
+
+int64_t cDvbHdFfDevice::GetSTC(void)
+{
+  if (fd_video >= 0) {
+     uint64_t pts;
+     if (ioctl(fd_video, VIDEO_GET_PTS, &pts) == -1) {
+        esyslog("ERROR: pts %d: %m", CardIndex() + 1);
+        return -1;
+        }
+     return pts;
+     }
+  if (fd_audio >= 0) {
+     uint64_t pts;
+     if (ioctl(fd_audio, AUDIO_GET_PTS, &pts) == -1) {
+        esyslog("ERROR: pts %d: %m", CardIndex() + 1);
+        return -1;
+        }
+     return pts;
+     }
+  return -1;
+}
+
+void cDvbHdFfDevice::TrickSpeed(int Speed)
+{
+  mHdffCmdIf->CmdAvEnableSync(0, false);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+  playAudioPid = -1;
+  if (Speed > 0)
+     mHdffCmdIf->CmdAvSetVideoSpeed(0, 100 / Speed);
+}
+
+void cDvbHdFfDevice::Clear(void)
+{
+  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
+  mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF::videoStreamMpeg1);
+  mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF::audioStreamMpeg1);
+  playVideoPid = -1;
+  playAudioPid = -1;
+  cDevice::Clear();
+}
+
+void cDvbHdFfDevice::Play(void)
+{
+  mHdffCmdIf->CmdAvEnableSync(0, true);
+  mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+  mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
+  cDevice::Play();
+}
+
+void cDvbHdFfDevice::Freeze(void)
+{
+  mHdffCmdIf->CmdAvSetVideoSpeed(0, 0);
+  mHdffCmdIf->CmdAvSetAudioSpeed(0, 0);
+  cDevice::Freeze();
+}
+
+void cDvbHdFfDevice::Mute(void)
+{
+  //TODO???
+  cDevice::Mute();
+}
+
+static HDFF::eVideoStreamType MapVideoStreamTypes(int Vtype)
+{
+  switch (Vtype) {
+    case 0x01: return HDFF::videoStreamMpeg1;
+    case 0x02: return HDFF::videoStreamMpeg2;
+    case 0x1B: return HDFF::videoStreamH264;
+    default: return HDFF::videoStreamMpeg2; // fallback to MPEG2
+    }
+}
+
+void cDvbHdFfDevice::StillPicture(const uchar *Data, int Length)
+{
+  if (!Data || Length < TS_SIZE)
+     return;
+  if (Data[0] == 0x47) {
+     // TS data
+     cDevice::StillPicture(Data, Length);
+     }
+  else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) {
+     // PES data
+     char *buf = MALLOC(char, Length);
+     if (!buf)
+        return;
+     int i = 0;
+     int blen = 0;
+     while (i < Length - 6) {
+           if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
+              int len = Data[i + 4] * 256 + Data[i + 5];
+              if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet
+                 // skip PES header
+                 int offs = i + 6;
+                 // skip header extension
+                 if ((Data[i + 6] & 0xC0) == 0x80) {
+                    // MPEG-2 PES header
+                    if (Data[i + 8] >= Length)
+                       break;
+                    offs += 3;
+                    offs += Data[i + 8];
+                    len -= 3;
+                    len -= Data[i + 8];
+                    if (len < 0 || offs + len > Length)
+                       break;
+                    }
+                 else {
+                    // MPEG-1 PES header
+                    while (offs < Length && len > 0 && Data[offs] == 0xFF) {
+                          offs++;
+                          len--;
+                          }
+                    if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) {
+                       offs += 2;
+                       len -= 2;
+                       }
+                    if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) {
+                       offs += 5;
+                       len -= 5;
+                       }
+                    else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) {
+                       offs += 10;
+                       len -= 10;
+                       }
+                    else if (offs < Length && len > 0) {
+                       offs++;
+                       len--;
+                       }
+                    }
+                 if (blen + len > Length) // invalid PES length field
+                    break;
+                 memcpy(&buf[blen], &Data[offs], len);
+                 i = offs + len;
+                 blen += len;
+                 }
+              else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets
+                 i += len + 6;
+              else
+                 i++;
+              }
+           else
+              i++;
+           }
+     mHdffCmdIf->CmdAvShowStillImage(0, (uint8_t *)buf, blen, MapVideoStreamTypes(PatPmtParser()->Vtype()));
+     free(buf);
+     }
+  else {
+     // non-PES data
+     mHdffCmdIf->CmdAvShowStillImage(0, Data, Length, MapVideoStreamTypes(PatPmtParser()->Vtype()));
+     }
+}
+
+bool cDvbHdFfDevice::Poll(cPoller &Poller, int TimeoutMs)
+{
+  Poller.Add(fd_video, true);
+  return Poller.Poll(TimeoutMs);
+}
+
+bool cDvbHdFfDevice::Flush(int TimeoutMs)
+{
+  //TODO actually this function should wait until all buffered data has been processed by the card, but how?
+  return true;
+}
+
+void cDvbHdFfDevice::BuildTsPacket(uint8_t * TsBuffer, bool PusiSet, uint16_t Pid, uint8_t Counter, const uint8_t * Data, uint32_t Length)
+{
+    TsBuffer[0] = 0x47;
+    TsBuffer[1] = PusiSet ? 0x40 : 0x00;
+    TsBuffer[1] |= Pid >> 8;
+    TsBuffer[2] = Pid & 0xFF;
+    if (Length >= 184)
+    {
+        TsBuffer[3] = 0x10 | Counter;
+        memcpy(TsBuffer + 4, Data, 184);
+    }
+    else
+    {
+        uint8_t adaptationLength;
+
+        TsBuffer[3] = 0x30 | Counter;
+        adaptationLength = 183 - Length;
+        TsBuffer[4] = adaptationLength;
+        if (adaptationLength > 0)
+        {
+            TsBuffer[5] = 0x00;
+            memset(TsBuffer + 6, 0xFF, adaptationLength - 1);
+        }
+        memcpy(TsBuffer + 5 + adaptationLength, Data, Length);
+    }
+}
+
+uint32_t cDvbHdFfDevice::PesToTs(uint8_t * TsBuffer, uint16_t Pid, uint8_t & Counter, const uint8_t * Data, uint32_t Length)
+{
+    uint32_t tsOffset;
+    uint32_t i;
+
+    tsOffset = 0;
+    i = 0;
+    while (Length > 0)
+    {
+        BuildTsPacket(TsBuffer + tsOffset, i == 0, Pid, Counter, Data + i * 184, Length);
+        if (Length >= 184)
+            Length -= 184;
+        else
+            Length = 0;
+        Counter = (Counter + 1) & 15;
+        tsOffset += 188;
+        i++;
+    }
+    return tsOffset;
+}
+
+int cDvbHdFfDevice::PlayVideo(const uchar *Data, int Length)
+{
+    //TODO: support greater Length
+    uint8_t tsBuffer[188 * 16];
+    uint32_t tsLength;
+    int pid = 100;
+
+    tsLength = PesToTs(tsBuffer, pid, videoCounter, Data, Length);
+
+    if (pid != playVideoPid) {
+        playVideoPid = pid;
+        mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, HDFF::videoStreamMpeg2, true);
+    }
+    if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
+        Length = 0;
+    return Length;
+}
+
+int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
+{
+    uint8_t streamId;
+    uint8_t tsBuffer[188 * 16];
+    uint32_t tsLength;
+    HDFF::eAudioStreamType streamType = HDFF::audioStreamMpeg1;
+    HDFF::eAVContainerType containerType = HDFF::avContainerPes;
+    int pid;
+
+    streamId = Data[3];
+    if (streamId >= 0xC0 && streamId <= 0xDF)
+    {
+        streamType = HDFF::audioStreamMpeg1;
+    }
+    else if (streamId == 0xBD)
+    {
+        const uint8_t * payload = Data + 9 + Data[8];
+        if ((payload[0] & 0xF8) == 0xA0)
+        {
+            containerType = HDFF::avContainerPesDvd;
+            streamType = HDFF::audioStreamPcm;
+        }
+        else if ((payload[0] & 0xF8) == 0x88)
+        {
+            containerType = HDFF::avContainerPesDvd;
+            streamType = HDFF::audioStreamDts;
+        }
+        else if ((payload[0] & 0xF8) == 0x80)
+        {
+            containerType = HDFF::avContainerPesDvd;
+            streamType = HDFF::audioStreamAc3;
+        }
+        else
+        {
+            streamType = HDFF::audioStreamAc3;
+        }
+    }
+    pid = 200 + (int) streamType;
+    tsLength = PesToTs(tsBuffer, pid, audioCounter, Data, Length);
+
+    if (pid != playAudioPid) {
+        playAudioPid = pid;
+        mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, streamType, containerType);
+    }
+    if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
+        Length = 0;
+    return Length;
+}
+
+int cDvbHdFfDevice::PlayTsVideo(const uchar *Data, int Length)
+{
+  int pid = TsPid(Data);
+  if (pid != playVideoPid) {
+     PatPmtParser();
+     if (pid == PatPmtParser()->Vpid()) {
+        playVideoPid = pid;
+        mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, MapVideoStreamTypes(PatPmtParser()->Vtype()), true);
+        }
+     }
+  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
+}
+
+static HDFF::eAudioStreamType MapAudioStreamTypes(int Atype)
+{
+  switch (Atype) {
+    case 0x03: return HDFF::audioStreamMpeg1;
+    case 0x04: return HDFF::audioStreamMpeg2;
+    case SI::AC3DescriptorTag: return HDFF::audioStreamAc3;
+    case SI::EnhancedAC3DescriptorTag: return HDFF::audioStreamEAc3;
+    case 0x0F: return HDFF::audioStreamAac;
+    case 0x11: return HDFF::audioStreamHeAac;
+    default: return HDFF::audioStreamMaxValue; // there is no HDFF::audioStreamNone
+    }
+}
+
+int cDvbHdFfDevice::PlayTsAudio(const uchar *Data, int Length)
+{
+  int pid = TsPid(Data);
+  if (pid != playAudioPid) {
+     playAudioPid = pid;
+     int AudioStreamType = -1;
+     for (int i = 0; PatPmtParser()->Apid(i); i++) {
+         if (playAudioPid == PatPmtParser()->Apid(i)) {
+            AudioStreamType = PatPmtParser()->Atype(i);
+            break;
+            }
+         }
+     if (AudioStreamType < 0) {
+        for (int i = 0; PatPmtParser()->Dpid(i); i++) {
+            if (playAudioPid == PatPmtParser()->Dpid(i)) {
+               AudioStreamType = PatPmtParser()->Dtype(i);
+               break;
+               }
+            }
+        }
+     mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, MapAudioStreamTypes(AudioStreamType));
+     }
+  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
+}
+
+HDFF::cHdffCmdIf *cDvbHdFfDevice::GetHdffCmdHandler(void)
+{
+  //TODO why not just keep a pointer?
+  if (devHdffOffset >= 0) {
+     cDvbHdFfDevice *device = (cDvbHdFfDevice *)GetDevice(devHdffOffset);
+     if (device)
+        return device->mHdffCmdIf;
+     }
+  return NULL;
+}
+
+// --- cDvbHdFfDeviceProbe ---------------------------------------------------
+
+bool cDvbHdFfDeviceProbe::Probe(int Adapter, int Frontend)
+{
+  static uint32_t SubsystemIds[] = {
+    0x13C23009, // Technotrend S2-6400 HDFF
+    0x00000000
+    };
+  cString FileName;
+  cReadLine ReadLine;
+  FILE *f = NULL;
+  uint32_t SubsystemId = 0;
+  FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend);
+  if ((f = fopen(FileName, "r")) != NULL) {
+     if (char *s = ReadLine.Read(f))
+        SubsystemId = strtoul(s, NULL, 0) << 16;
+     fclose(f);
+     }
+  FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend);
+  if ((f = fopen(FileName, "r")) != NULL) {
+     if (char *s = ReadLine.Read(f))
+        SubsystemId |= strtoul(s, NULL, 0);
+     fclose(f);
+     }
+  for (uint32_t *sid = SubsystemIds; *sid; sid++) {
+      if (*sid == SubsystemId) {
+         FileName = cString::sprintf("/dev/dvb/adapter%d/osd0", Adapter);
+         int fd = open(FileName, O_RDWR);
+         if (fd != -1) { //TODO treat the second path of the S2-6400 as a budget device
+            close(fd);
+            dsyslog("creating cDvbHdFfDevice");
+            new cDvbHdFfDevice(Adapter, Frontend);
+            return true;
+            }
+         }
+      }
+  return false;
+}
diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.h b/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
new file mode 100644 (file)
index 0000000..4dcfb6a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * dvbhdffdevice.h: The DVB HD Full Featured device interface
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: dvbhdffdevice.h 1.6 2010/03/13 11:18:13 kls Exp $
+ */
+
+#ifndef __DVBHDFFDEVICE_H
+#define __DVBHDFFDEVICE_H
+
+#include "hdffcmd.h"
+#include "vdr/dvbdevice.h"
+#include "vdr/dvbspu.h"
+
+/// The cDvbHdFfDevice implements a DVB device which can be accessed through the Linux DVB driver API.
+
+class cDvbHdFfDevice : public cDvbDevice {
+private:
+  int fd_osd, fd_audio, fd_video;
+protected:
+  virtual void MakePrimaryDevice(bool On);
+public:
+  static bool Probe(int Adapter, int Frontend);
+  cDvbHdFfDevice(int Adapter, int Frontend);
+  virtual ~cDvbHdFfDevice();
+  virtual bool HasDecoder(void) const;
+
+// SPU facilities
+
+private:
+  cDvbSpuDecoder *spuDecoder;
+public:
+  virtual cSpuDecoder *GetSpuDecoder(void);
+
+// Channel facilities
+
+private:
+  void TurnOffLiveMode(bool LiveView);
+protected:
+  virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
+
+// PID handle facilities
+
+protected:
+  virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
+
+// Image Grab facilities
+
+public:
+  virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
+
+// Video format facilities
+
+public:
+  virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat);
+  virtual void SetVideoFormat(bool VideoFormat16_9);
+  virtual eVideoSystem GetVideoSystem(void);
+  virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect);
+  virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect);
+
+// Track facilities
+
+protected:
+  virtual void SetAudioTrackDevice(eTrackType Type);
+
+// Audio facilities
+
+private:
+  int audioChannel;
+protected:
+  virtual int GetAudioChannelDevice(void);
+  virtual void SetAudioChannelDevice(int AudioChannel);
+  virtual void SetVolumeDevice(int Volume);
+  virtual void SetDigitalAudioDevice(bool On);
+
+// Player facilities
+
+private:
+  int playVideoPid;
+  int playAudioPid;
+
+  // Pes2Ts conversion stuff
+  uint8_t videoCounter;
+  uint8_t audioCounter;
+  void BuildTsPacket(uint8_t * TsBuffer, bool PusiSet, uint16_t Pid, uint8_t Counter, const uint8_t * Data, uint32_t Length);
+  uint32_t PesToTs(uint8_t * TsBuffer, uint16_t Pid, uint8_t & Counter, const uint8_t * Data, uint32_t Length);
+
+protected:
+  ePlayMode playMode;
+  virtual bool CanReplay(void) const;
+  virtual bool SetPlayMode(ePlayMode PlayMode);
+  virtual int PlayVideo(const uchar *Data, int Length);
+  virtual int PlayAudio(const uchar *Data, int Length, uchar Id);
+  virtual int PlayTsVideo(const uchar *Data, int Length);
+  virtual int PlayTsAudio(const uchar *Data, int Length);
+public:
+  virtual int64_t GetSTC(void);
+  virtual void TrickSpeed(int Speed);
+  virtual void Clear(void);
+  virtual void Play(void);
+  virtual void Freeze(void);
+  virtual void Mute(void);
+  virtual void StillPicture(const uchar *Data, int Length);
+  virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
+  virtual bool Flush(int TimeoutMs = 0);
+
+// HDFF specific things
+
+public:
+  static HDFF::cHdffCmdIf *GetHdffCmdHandler(void);
+private:
+  static int devHdffOffset;//TODO
+  bool isHdffPrimary;//TODO implicit!
+  HDFF::cHdffCmdIf *mHdffCmdIf;
+};
+
+class cDvbHdFfDeviceProbe : public cDvbDeviceProbe {
+public:
+  virtual bool Probe(int Adapter, int Frontend);
+  };
+
+#endif //__DVBHDFFDEVICE_H
diff --git a/PLUGINS/src/dvbhddevice/hdffcmd.c b/PLUGINS/src/dvbhddevice/hdffcmd.c
new file mode 100644 (file)
index 0000000..ecd26ed
--- /dev/null
@@ -0,0 +1,1120 @@
+/*
+ * hdffcmd.c: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffcmd.c 1.19 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include "hdffcmd.h"
+#include <linux/dvb/osd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <vdr/tools.h>
+
+namespace HDFF
+{
+
+cHdffCmdIf::cHdffCmdIf(int OsdDev)
+{
+    mOsdDev = OsdDev;
+    if (mOsdDev < 0)
+    {
+        //printf("ERROR: invalid OSD device handle (%d)!\n", mOsdDev);
+    }
+}
+
+cHdffCmdIf::~cHdffCmdIf(void)
+{
+}
+
+void cHdffCmdIf::CmdBuildHeader(cBitBuffer & MsgBuf, eMessageType MsgType, eMessageGroup MsgGroup, eMessageId MsgId)
+{
+    MsgBuf.SetBits(16, 0); // length field will be set later
+    MsgBuf.SetBits(6, 0); // reserved
+    MsgBuf.SetBits(2, MsgType);
+    MsgBuf.SetBits(8, MsgGroup);
+    MsgBuf.SetBits(16, MsgId);
+}
+
+uint32_t cHdffCmdIf::CmdSetLength(cBitBuffer & MsgBuf)
+{
+    uint32_t length;
+
+    length = MsgBuf.GetByteLength() - 2;
+    MsgBuf.SetDataByte(0, (uint8_t) (length >> 8));
+    MsgBuf.SetDataByte(1, (uint8_t) length);
+
+    return length + 2;
+}
+
+
+uint32_t cHdffCmdIf::CmdGetFirmwareVersion(char * pString, uint32_t MaxLength)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    cBitBuffer resBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    osd_cmd.result_data = resBuf.GetData();
+    osd_cmd.result_len = resBuf.GetMaxLength();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupGeneric, msgGenGetFirmwareVersion);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    if (osd_cmd.result_len > 0)
+    {
+        uint8_t * result = resBuf.GetData();
+        uint8_t textLength = result[9];
+        if (textLength >= MaxLength)
+            textLength = MaxLength - 1;
+        memcpy(pString, &result[10], textLength);
+        pString[textLength] = 0;
+        return (result[6] << 16) | (result[7] << 8) | result[8];
+    }
+    return 0;
+}
+
+uint32_t cHdffCmdIf::CmdGetInterfaceVersion(char * pString, uint32_t MaxLength)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    cBitBuffer resBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    osd_cmd.result_data = resBuf.GetData();
+    osd_cmd.result_len = resBuf.GetMaxLength();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupGeneric, msgGenGetInterfaceVersion);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    if (osd_cmd.result_len > 0)
+    {
+        uint8_t * result = resBuf.GetData();
+        uint8_t textLength = result[9];
+        if (textLength >= MaxLength)
+            textLength = MaxLength - 1;
+        memcpy(pString, &result[10], textLength);
+        pString[textLength] = 0;
+        return (result[6] << 16) | (result[7] << 8) | result[8];
+    }
+    return 0;
+}
+
+uint32_t cHdffCmdIf::CmdGetCopyrights(uint8_t Index, char * pString, uint32_t MaxLength)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    cBitBuffer resBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    osd_cmd.result_data = resBuf.GetData();
+    osd_cmd.result_len = resBuf.GetMaxLength();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupGeneric, msgGenGetCopyrights);
+    cmdBuf.SetBits(8, Index);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    if (osd_cmd.result_len > 0)
+    {
+        uint8_t * result = resBuf.GetData();
+        uint8_t index = result[6];
+        uint8_t textLen = result[7];
+        if (index == Index && textLen > 0)
+        {
+            if (textLen >= MaxLength)
+            {
+                textLen = MaxLength - 1;
+            }
+            memcpy(pString, result + 8, textLen);
+            pString[textLen] = 0;
+            return textLen;
+        }
+    }
+    return 0;
+}
+
+
+void cHdffCmdIf::CmdAvSetPlayMode(uint8_t PlayMode, bool Realtime)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetPlayMode);
+    cmdBuf.SetBits(1, Realtime ? 1 : 0);
+    cmdBuf.SetBits(7, PlayMode);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, eVideoStreamType StreamType, bool PlaybackMode)
+{
+    //printf("SetVideoPid %d %d\n", VideoPid, StreamType);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoPid);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, StreamType);
+    cmdBuf.SetBits(1, PlaybackMode ? 1 : 0);
+    cmdBuf.SetBits(15, VideoPid);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, eAudioStreamType StreamType, eAVContainerType ContainerType)
+{
+    //printf("SetAudioPid %d %d %d\n", AudioPid, StreamType, ContainerType);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioPid);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, StreamType);
+    cmdBuf.SetBits(2, 0); // reserved
+    cmdBuf.SetBits(1, ContainerType);
+    cmdBuf.SetBits(13, AudioPid);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetPcrPid(uint8_t DecoderIndex, uint16_t PcrPid)
+{
+    //printf("SetPcrPid %d\n", PcrPid);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetPcrPid);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, 0); // reserved
+    cmdBuf.SetBits(16, PcrPid);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetTeletextPid(uint8_t DecoderIndex, uint16_t TeletextPid)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetTeletextPid);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, 0); // reserved
+    cmdBuf.SetBits(16, TeletextPid);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetVideoWindow(uint8_t DecoderIndex, bool Enable, uint16_t X, uint16_t Y, uint16_t Width, uint16_t Height)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoWindow);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(3, 0); // reserved
+    if (Enable)
+        cmdBuf.SetBits(1, 1);
+    else
+        cmdBuf.SetBits(1, 0);
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(16, Width);
+    cmdBuf.SetBits(16, Height);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, eVideoStreamType StreamType)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = (void *) pStillImage;
+    osd_data.data_length = Size;
+    ioctl(mOsdDev, OSD_RAW_DATA, &osd_data);
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvShowStillImage);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, StreamType);
+    cmdBuf.SetBits(16, osd_data.data_handle);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetDecoderInput(uint8_t DecoderIndex, uint8_t DemultiplexerIndex)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetDecoderInput);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, DemultiplexerIndex);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetDemultiplexerInput(uint8_t DemultiplexerIndex, uint8_t TsInputIndex)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetDemultiplexerInput);
+    cmdBuf.SetBits(4, DemultiplexerIndex);
+    cmdBuf.SetBits(4, TsInputIndex);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetVideoFormat(uint8_t DecoderIndex, const tVideoFormat * pVideoFormat)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoFormat);
+    cmdBuf.SetBits(4, DecoderIndex);
+    if (pVideoFormat->AutomaticEnabled)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    if (pVideoFormat->AfdEnabled)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    cmdBuf.SetBits(2, pVideoFormat->TvFormat);
+    cmdBuf.SetBits(8, pVideoFormat->VideoConversion);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetVideoOutputMode(uint8_t DecoderIndex, eVideoOutputMode OutputMode)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoOutputMode);
+    cmdBuf.SetBits(8, OutputMode);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetStc);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(3, 0); // reserved
+    cmdBuf.SetBits(1, (uint32_t) (Stc >> 32));
+    cmdBuf.SetBits(32, (uint32_t) Stc);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvFlushBuffer(uint8_t DecoderIndex, bool FlushAudio, bool FlushVideo)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvFlushBuffer);
+    cmdBuf.SetBits(4, DecoderIndex);
+    if (FlushAudio)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    if (FlushVideo)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvEnableSync(uint8_t DecoderIndex, bool EnableSync)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvEnableSync);
+    cmdBuf.SetBits(4, DecoderIndex);
+    if (EnableSync)
+    {
+        cmdBuf.SetBits(1, 1);
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+        cmdBuf.SetBits(1, 0);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetVideoSpeed(uint8_t DecoderIndex, int32_t Speed)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetVideoSpeed);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, 0);
+    cmdBuf.SetBits(32, Speed);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetAudioSpeed(uint8_t DecoderIndex, int32_t Speed)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioSpeed);
+    cmdBuf.SetBits(4, DecoderIndex);
+    cmdBuf.SetBits(4, 0);
+    cmdBuf.SetBits(32, Speed);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvEnableVideoAfterStop(uint8_t DecoderIndex, bool EnableVideoAfterStop)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvEnableVideoAfterStop);
+    cmdBuf.SetBits(4, DecoderIndex);
+    if (EnableVideoAfterStop)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetAudioDelay(int16_t Delay)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioDelay);
+    cmdBuf.SetBits(16, Delay);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetAudioDownmix(eDownmixMode DownmixMode)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioDownmix);
+    cmdBuf.SetBits(8, DownmixMode);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdAvSetAudioChannel(uint8_t AudioChannel)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvDec, msgAvSetAudioChannel);
+    cmdBuf.SetBits(8, AudioChannel);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+
+void cHdffCmdIf::CmdOsdConfigure(const tOsdConfig * pConfig)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdConfigure);
+    if (pConfig->FontAntialiasing)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    if (pConfig->FontKerning)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdReset(void)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdReset);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, eColorType ColorType)
+{
+    //printf("CreateDisplay %d %d %d\n", Width, Height, ColorType);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    cBitBuffer resBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    osd_cmd.result_data = resBuf.GetData();
+    osd_cmd.result_len = resBuf.GetMaxLength();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreateDisplay);
+    cmdBuf.SetBits(16, Width);
+    cmdBuf.SetBits(16, Height);
+    cmdBuf.SetBits(8, ColorType);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    if (osd_cmd.result_len > 0)
+    {
+        uint8_t * result = resBuf.GetData();
+        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
+    }
+    return InvalidHandle;
+}
+
+void cHdffCmdIf::CmdOsdDeleteDisplay(uint32_t hDisplay)
+{
+    //printf("DeleteDisplay\n");
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeleteDisplay);
+    cmdBuf.SetBits(32, hDisplay);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdEnableDisplay(uint32_t hDisplay, bool Enable)
+{
+    //printf("EnableDisplay\n");
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdEnableDisplay);
+    cmdBuf.SetBits(32, hDisplay);
+    if (Enable)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    cmdBuf.SetBits(7, 0); // reserved
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdSetDisplayOutputRectangle(uint32_t hDisplay, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height)
+{
+    //printf("SetOutputRect %d %d %d %d %d\n", hDisplay, X, Y, Width, Height);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetDisplayOutputRectangle);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(16, Width);
+    cmdBuf.SetBits(16, Height);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdSetDisplayClippingArea(uint32_t hDisplay, bool Enable, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height)
+{
+    //printf("SetClippingArea %d %d %d %d %d %d\n", hDisplay, Enable, X, Y, Width, Height);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetDisplayClippingArea);
+    cmdBuf.SetBits(32, hDisplay);
+    if (Enable)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    cmdBuf.SetBits(7, 0); // reserved
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(16, Width);
+    cmdBuf.SetBits(16, Height);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdRenderDisplay(uint32_t hDisplay)
+{
+    //printf("Render\n");
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdRenderDisplay);
+    cmdBuf.SetBits(32, hDisplay);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreatePalette(eColorType ColorType, eColorFormat ColorFormat,
+                                         uint32_t NumColors, const uint32_t * pColors)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    cBitBuffer resBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+    uint32_t i;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    osd_cmd.result_data = resBuf.GetData();
+    osd_cmd.result_len = resBuf.GetMaxLength();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreatePalette);
+    cmdBuf.SetBits(8, ColorType);
+    cmdBuf.SetBits(8, ColorFormat);
+    if (NumColors > 256)
+        NumColors = 256;
+    cmdBuf.SetBits(8, NumColors == 256 ? 0 : NumColors);
+    for (i = 0; i < NumColors; i++)
+    {
+        cmdBuf.SetBits(32, pColors[i]);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    if (osd_cmd.result_len > 0)
+    {
+        uint8_t * result = resBuf.GetData();
+        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
+    }
+    return InvalidHandle;
+}
+
+void cHdffCmdIf::CmdOsdDeletePalette(uint32_t hPalette)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeletePalette);
+    cmdBuf.SetBits(32, hPalette);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdSetDisplayPalette(uint32_t hDisplay, uint32_t hPalette)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetDisplayPalette);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(32, hPalette);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdSetPaletteColors(uint32_t hPalette, eColorFormat ColorFormat,
+                                        uint8_t StartColor, uint32_t NumColors, const uint32_t * pColors)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+    uint32_t i;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSetPaletteColors);
+    cmdBuf.SetBits(32, hPalette);
+    cmdBuf.SetBits(8, ColorFormat);
+    cmdBuf.SetBits(8, StartColor);
+    if (NumColors > 256)
+        NumColors = 256;
+    cmdBuf.SetBits(8, NumColors == 256 ? 0 : NumColors);
+    for (i = 0; i < NumColors; i++)
+    {
+        cmdBuf.SetBits(32, pColors[i]);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreateFontFace(const uint8_t * pFontData, uint32_t DataSize)
+{
+    //printf("CreateFontFace %d\n", DataSize);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    cBitBuffer resBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = pFontData;
+    osd_data.data_length = DataSize;
+    ioctl(mOsdDev, OSD_RAW_DATA, &osd_data);
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    osd_cmd.result_data = resBuf.GetData();
+    osd_cmd.result_len = resBuf.GetMaxLength();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreateFontFace);
+    cmdBuf.SetBits(16, osd_data.data_handle);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    if (osd_cmd.result_len > 0)
+    {
+        uint8_t * result = resBuf.GetData();
+        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
+    }
+    return InvalidHandle;
+}
+
+void cHdffCmdIf::CmdOsdDeleteFontFace(uint32_t hFontFace)
+{
+    //printf("DeleteFontFace %08X\n", hFontFace);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeleteFontFace);
+    cmdBuf.SetBits(32, hFontFace);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+uint32_t cHdffCmdIf::CmdOsdCreateFont(uint32_t hFontFace, uint32_t Size)
+{
+    //printf("CreateFont %d\n", Size);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    cBitBuffer resBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    osd_cmd.result_data = resBuf.GetData();
+    osd_cmd.result_len = resBuf.GetMaxLength();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdCreateFont);
+    cmdBuf.SetBits(32, hFontFace);
+    cmdBuf.SetBits(32, Size);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+    if (osd_cmd.result_len > 0)
+    {
+        uint8_t * result = resBuf.GetData();
+        return (result[6] << 24) | (result[7] << 16) | (result[8] << 8) | result[9];
+    }
+    return InvalidHandle;
+}
+
+void cHdffCmdIf::CmdOsdDeleteFont(uint32_t hFont)
+{
+    //printf("DeleteFont %08X\n", hFont);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDeleteFont);
+    cmdBuf.SetBits(32, hFont);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdDrawRectangle(uint32_t hDisplay, int X, int Y, int Width, int Height, uint32_t Color)
+{
+    //printf("Rect (%d,%d) %d x %d, %08X\n", X, Y, Width, Height, Color);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawRectangle);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(16, Width);
+    cmdBuf.SetBits(16, Height);
+    cmdBuf.SetBits(32, Color);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdDrawEllipse(uint32_t hDisplay, int CX, int CY, int RadiusX, int RadiusY,
+                                 uint32_t Color, uint32_t Flags)
+{
+    //printf("Ellipse (%d,%d) %d x %d, %08X, %d\n", CX, CY, RadiusX, RadiusY, Color, Flags);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawEllipse);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(16, CX);
+    cmdBuf.SetBits(16, CY);
+    cmdBuf.SetBits(16, RadiusX);
+    cmdBuf.SetBits(16, RadiusY);
+    cmdBuf.SetBits(32, Color);
+    cmdBuf.SetBits(32, Flags);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdDrawText(uint32_t hDisplay, uint32_t hFont, int X, int Y, const char * pText, uint32_t Color)
+{
+    //printf("Text %08X (%d,%d), %s, %08X\n", hFont, X, Y, pText, Color);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int length;
+
+    length = 0;
+    while (pText[length])
+    {
+        length++;
+    }
+    if (length > 980)
+        length = 980;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawText);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(32, hFont);
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(32, Color);
+    cmdBuf.SetBits(16, length);
+    for (i = 0; i < length; i++)
+    {
+        cmdBuf.SetBits(8, pText[i]);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdDrawTextW(uint32_t hDisplay, uint32_t hFont, int X, int Y, const uint16_t * pText, uint32_t Color)
+{
+    //printf("TextW %08X (%d,%d), %08X\n", hFont, X, Y, Color);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+    int i;
+    int length;
+
+    length = 0;
+    while (pText[length])
+    {
+        length++;
+    }
+    if (length > 480)
+        length = 480;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawTextW);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(32, hFont);
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(32, Color);
+    cmdBuf.SetBits(16, length);
+    for (i = 0; i < length; i++)
+    {
+        cmdBuf.SetBits(16, pText[i]);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdDrawBitmap(uint32_t hDisplay, int X, int Y, const uint8_t * pBitmap,
+                                  int BmpWidth, int BmpHeight, int BmpSize,
+                                  eColorType ColorType, uint32_t hPalette)
+{
+    //printf("Bitmap (%d,%d) %d x %d\n", X, Y, BmpWidth, BmpHeight);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+    osd_raw_data_t osd_data;
+
+    memset(&osd_data, 0, sizeof(osd_raw_data_t));
+    osd_data.data_buffer = pBitmap;
+    osd_data.data_length = BmpSize;
+    ioctl(mOsdDev, OSD_RAW_DATA, &osd_data);
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdDrawBitmap);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(16, BmpWidth);
+    cmdBuf.SetBits(16, BmpHeight);
+    cmdBuf.SetBits(8, ColorType);
+    cmdBuf.SetBits(6, 0); // reserved
+    cmdBuf.SetBits(2, 0); // uncompressed
+    cmdBuf.SetBits(32, hPalette);
+    cmdBuf.SetBits(16, osd_data.data_handle);
+    cmdBuf.SetBits(32, 0);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdSaveRegion(uint32_t hDisplay, int X, int Y, int Width, int Height)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdSaveRegion);
+    cmdBuf.SetBits(32, hDisplay);
+    cmdBuf.SetBits(16, X);
+    cmdBuf.SetBits(16, Y);
+    cmdBuf.SetBits(16, Width);
+    cmdBuf.SetBits(16, Height);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdOsdRestoreRegion(uint32_t hDisplay)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupOsd, msgOsdRestoreRegion);
+    cmdBuf.SetBits(32, hDisplay);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdMuxSetVideoOut(eVideoOut VideoOut)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvMux, msgMuxSetVideoOut);
+    cmdBuf.SetBits(4, VideoOut);
+    cmdBuf.SetBits(4, 0); // reserved
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdMuxSetVolume(uint8_t Volume)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvMux, msgMuxSetVolume);
+    cmdBuf.SetBits(8, Volume);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdMuxMuteAudio(bool Mute)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupAvMux, msgMuxSetAudioMute);
+    cmdBuf.SetBits(1, Mute);
+    cmdBuf.SetBits(7, 0); // reserved
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdHdmiSetVideoMode(eHdmiVideoMode VideoMode)
+{
+    //printf("HdmiSetVideoMode %d\n", VideoMode);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupHdmi, msgHdmiSetVideoMode);
+    cmdBuf.SetBits(8, VideoMode);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdHdmiConfigure(const tHdmiConfig * pConfig)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupHdmi, msgHdmiConfigure);
+    if (pConfig->TransmitAudio)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    if (pConfig->ForceDviMode)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    if (pConfig->CecEnabled)
+    {
+        cmdBuf.SetBits(1, 1);
+    }
+    else
+    {
+        cmdBuf.SetBits(1, 0);
+    }
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdHdmiSendCecCommand(eCecCommand Command)
+{
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupHdmi, msgHdmiSendCecCommand);
+    cmdBuf.SetBits(8, Command);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdRemoteSetProtocol(eRemoteProtocol Protocol)
+{
+    //printf("%s %d\n", __func__, Protocol);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupRemoteControl, msgRemoteSetProtocol);
+    cmdBuf.SetBits(8, Protocol);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+void cHdffCmdIf::CmdRemoteSetAddressFilter(bool Enable, uint32_t Address)
+{
+    //printf("%s %d %d\n", __func__, Enable, Address);
+    cBitBuffer cmdBuf(MAX_CMD_LEN);
+    osd_raw_cmd_t osd_cmd;
+
+    memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+    osd_cmd.cmd_data = cmdBuf.GetData();
+    CmdBuildHeader(cmdBuf, msgTypeCommand, msgGroupRemoteControl, msgRemoteSetAddressFilter);
+    cmdBuf.SetBits(1, Enable);
+    cmdBuf.SetBits(7, 0); // reserved
+    cmdBuf.SetBits(32, Address);
+    osd_cmd.cmd_len = CmdSetLength(cmdBuf);
+    ioctl(mOsdDev, OSD_RAW_CMD, &osd_cmd);
+}
+
+} // end of namespace
diff --git a/PLUGINS/src/dvbhddevice/hdffcmd.h b/PLUGINS/src/dvbhddevice/hdffcmd.h
new file mode 100644 (file)
index 0000000..cd641eb
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * hdffcmd.h: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffcmd.h 1.17 2011/04/17 11:20:22 kls Exp $
+ */
+
+#ifndef _HDFF_CMD_H_
+#define _HDFF_CMD_H_
+
+#include "bitbuffer.h"
+#include "hdffmsgdef.h"
+
+namespace HDFF
+{
+
+class cHdffCmdIf
+{
+private:
+    int mOsdDev;
+
+    void CmdBuildHeader(cBitBuffer & MsgBuf, eMessageType MsgType, eMessageGroup MsgGroup, eMessageId MsgId);
+    uint32_t CmdSetLength(cBitBuffer & MsgBuf);
+
+public:
+    cHdffCmdIf(int OsdDev);
+    ~cHdffCmdIf(void);
+
+    uint32_t CmdGetFirmwareVersion(char * pString, uint32_t MaxLength);
+    uint32_t CmdGetInterfaceVersion(char * pString, uint32_t MaxLength);
+    uint32_t CmdGetCopyrights(uint8_t Index, char * pString, uint32_t MaxLength);
+
+    void CmdAvSetPlayMode(uint8_t PlayMode, bool Realtime);
+    void CmdAvSetVideoPid(uint8_t DecoderIndex, uint16_t VideoPid, eVideoStreamType StreamType, bool PlaybackMode = false);
+    void CmdAvSetAudioPid(uint8_t DecoderIndex, uint16_t AudioPid, eAudioStreamType StreamType, eAVContainerType ContainerType = avContainerPes);
+    void CmdAvSetPcrPid(uint8_t DecoderIndex, uint16_t PcrPid);
+    void CmdAvSetTeletextPid(uint8_t DecoderIndex, uint16_t TeletextPid);
+    void CmdAvSetVideoWindow(uint8_t DecoderIndex, bool Enable, uint16_t X, uint16_t Y, uint16_t Width, uint16_t Height);
+    void CmdAvShowStillImage(uint8_t DecoderIndex, const uint8_t * pStillImage, int Size, eVideoStreamType StreamType);
+    void CmdAvSetDecoderInput(uint8_t DecoderIndex, uint8_t DemultiplexerIndex);
+    void CmdAvSetDemultiplexerInput(uint8_t DemultiplexerIndex, uint8_t TsInputIndex);
+    void CmdAvSetVideoFormat(uint8_t DecoderIndex, const tVideoFormat * pVideoFormat);
+    void CmdAvSetVideoOutputMode(uint8_t DecoderIndex, eVideoOutputMode OutputMode);
+    void CmdAvSetStc(uint8_t DecoderIndex, uint64_t Stc);
+    void CmdAvFlushBuffer(uint8_t DecoderIndex, bool FlushAudio, bool FlushVideo);
+    void CmdAvEnableSync(uint8_t DecoderIndex, bool EnableSync);
+    void CmdAvSetVideoSpeed(uint8_t DecoderIndex, int32_t Speed);
+    void CmdAvSetAudioSpeed(uint8_t DecoderIndex, int32_t Speed);
+    void CmdAvEnableVideoAfterStop(uint8_t DecoderIndex, bool EnableVideoAfterStop);
+    void CmdAvSetAudioDelay(int16_t Delay);
+    void CmdAvSetAudioDownmix(eDownmixMode DownmixMode);
+    void CmdAvSetAudioChannel(uint8_t AudioChannel);
+
+    void CmdOsdConfigure(const tOsdConfig * pConfig);
+    void CmdOsdReset(void);
+
+    uint32_t CmdOsdCreateDisplay(uint32_t Width, uint32_t Height, eColorType ColorType);
+    void CmdOsdDeleteDisplay(uint32_t hDisplay);
+    void CmdOsdEnableDisplay(uint32_t hDisplay, bool Enable);
+    void CmdOsdSetDisplayOutputRectangle(uint32_t hDisplay, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height);
+    void CmdOsdSetDisplayClippingArea(uint32_t hDisplay, bool Enable, uint32_t X, uint32_t Y, uint32_t Width, uint32_t Height);
+    void CmdOsdRenderDisplay(uint32_t hDisplay);
+
+    uint32_t CmdOsdCreatePalette(eColorType ColorType, eColorFormat ColorFormat,
+                                 uint32_t NumColors, const uint32_t * pColors);
+    void CmdOsdDeletePalette(uint32_t hPalette);
+    void CmdOsdSetDisplayPalette(uint32_t hDisplay, uint32_t hPalette);
+    void CmdOsdSetPaletteColors(uint32_t hPalette, eColorFormat ColorFormat,
+                                uint8_t StartColor, uint32_t NumColors, const uint32_t * pColors);
+
+    uint32_t CmdOsdCreateFontFace(const uint8_t * pFontData, uint32_t DataSize);
+    void CmdOsdDeleteFontFace(uint32_t hFontFace);
+    uint32_t CmdOsdCreateFont(uint32_t hFontFace, uint32_t Size);
+    void CmdOsdDeleteFont(uint32_t hFont);
+
+    void CmdOsdDrawRectangle(uint32_t hDisplay, int X, int Y, int Width, int Height, uint32_t Color);
+    void CmdOsdDrawEllipse(uint32_t hDisplay, int CX, int CY, int RadiusX, int RadiusY,
+                           uint32_t Color, uint32_t Flags);
+    void CmdOsdDrawText(uint32_t hDisplay, uint32_t hFont, int X, int Y, const char * pText, uint32_t Color);
+    void CmdOsdDrawTextW(uint32_t hDisplay, uint32_t hFont, int X, int Y, const uint16_t * pText, uint32_t Color);
+    void CmdOsdDrawBitmap(uint32_t hDisplay, int X, int Y, const uint8_t * pBitmap,
+                          int BmpWidth, int BmpHeight, int BmpSize,
+                          eColorType ColorType, uint32_t hPalette);
+    void CmdOsdSaveRegion(uint32_t hDisplay, int X, int Y, int Width, int Height);
+    void CmdOsdRestoreRegion(uint32_t hDisplay);
+
+    void CmdMuxSetVideoOut(eVideoOut VideoOut);
+    void CmdMuxSetVolume(uint8_t Volume);
+    void CmdMuxMuteAudio(bool Mute);
+
+    void CmdHdmiSetVideoMode(eHdmiVideoMode VideoMode);
+    void CmdHdmiConfigure(const tHdmiConfig * pConfig);
+    void CmdHdmiSendCecCommand(eCecCommand Command);
+
+    void CmdRemoteSetProtocol(eRemoteProtocol Protocol);
+    void CmdRemoteSetAddressFilter(bool Enable, uint32_t Address);
+};
+
+} // end of namespace
+
+#endif
diff --git a/PLUGINS/src/dvbhddevice/hdffmsgdef.h b/PLUGINS/src/dvbhddevice/hdffmsgdef.h
new file mode 100644 (file)
index 0000000..a6c3f4b
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * hdffmsgdef.h: TODO(short description)
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffmsgdef.h 1.12 2011/04/17 11:20:22 kls Exp $
+ */
+
+#ifndef _HDFF_MSGDEF_H_
+#define _HDFF_MSGDEF_H_
+
+#define MAX_CMD_LEN 1536
+
+namespace HDFF
+{
+
+typedef enum _eMessageType
+{
+    msgTypeCommand,
+    msgTypeAnswer,
+    msgTypeResult,
+    msgTypeEvent
+} eMessageType;
+
+typedef enum _eMessageGroup
+{
+    msgGroupGeneric,
+    msgGroupAvDec,
+    msgGroupAvMux,
+    msgGroupFrontend,
+    msgGroupOsd,
+    msgGroupHdmi,
+    msgGroupRemoteControl
+} eMessageGroup;
+
+typedef enum _eMessageId
+{
+    msgGenGetFirmwareVersion = 0,
+    msgGenGetInterfaceVersion,
+    msgGenGetCopyrights,
+
+    msgAvSetAudioPid = 0,
+    msgAvSetVideoPid,
+    msgAvSetPcrPid,
+    msgAvSetTeletextPid,
+    msgAvShowStillImage,
+    msgAvSetVideoWindow,
+    msgAvSetDecoderInput,
+    msgAvSetDemultiplexerInput,
+    msgAvSetVideoFormat,
+    msgAvSetVideoOutputMode,
+    msgAvSetStc,
+    msgAvFlushBuffer,
+    msgAvEnableSync,
+    msgAvSetVideoSpeed,
+    msgAvSetAudioSpeed,
+    msgAvEnableVideoAfterStop,
+    msgAvGetVideoFormatInfo,
+    msgAvSetAudioDelay,
+    msgAvSetAudioDownmix,
+    msgAvSetAudioChannel,
+    msgAvSetPlayMode,
+
+    msgMuxSetVideoOut = 0,
+    msgMuxSetSlowBlank,
+    msgMuxSetFastBlank,
+    msgMuxSetVolume,
+    msgMuxSetAudioMute,
+
+    msgOsdConfigure = 0,
+    msgOsdReset,
+    msgOsdCreateDisplay = 10,
+    msgOsdDeleteDisplay,
+    msgOsdEnableDisplay,
+    msgOsdSetDisplayOutputRectangle,
+    msgOsdSetDisplayClippingArea,
+    msgOsdRenderDisplay,
+    msgOsdSaveRegion,
+    msgOsdRestoreRegion,
+    msgOsdCreatePalette = 30,
+    msgOsdDeletePalette,
+    msgOsdSetDisplayPalette,
+    msgOsdSetPaletteColors,
+    msgOsdCreateFontFace = 50,
+    msgOsdDeleteFontFace,
+    msgOsdCreateFont,
+    msgOsdDeleteFont,
+    msgOsdDrawPixel = 70,
+    msgOsdDrawRectangle,
+    msgOsdDrawCircle,
+    msgOsdDrawEllipse,
+    msgOsdDrawSlope,
+    msgOsdDrawText,
+    msgOsdDrawTextW,
+    msgOsdDrawBitmap,
+
+    msgHdmiEnableOutput = 0,
+    msgHdmiSetVideoMode,
+    msgHdmiConfigure,
+    msgHdmiIsDisplayConnected,
+    msgHdmiGetDisplayInfo,
+    msgHdmiGetVideoMode,
+    msgHdmiSendCecCommand,
+
+    msgRemoteSetProtocol = 0,
+    msgRemoteSetAddressFilter,
+    msgRemoteKeyEvent
+} eMessageId;
+
+
+// AvDec definitions
+
+typedef enum _eAVContainerType
+{
+    avContainerPes,
+    avContainerPesDvd,
+    avContainerMaxValue
+} eAVContainerType;
+
+typedef enum _eAudioStreamType
+{
+    audioStreamMpeg1,
+    audioStreamMpeg2,
+    audioStreamAc3,
+    audioStreamAac,
+    audioStreamHeAac,
+    audioStreamPcm,
+    audioStreamEAc3,
+    audioStreamDts,
+    audioStreamMaxValue
+} eAudioStreamType;
+
+typedef enum _eVideoStreamType
+{
+    videoStreamMpeg1,
+    videoStreamMpeg2,
+    videoStreamH264,
+    videoStreamMpeg4Asp,
+    videoStreamVc1,
+    videoStreamMaxValue
+} eVideoStreamType;
+
+
+typedef enum _eTvFormat
+{
+    tvFormat4by3,
+    tvFormat16by9,
+    tvFormatMaxValue
+} eTvFormat;
+
+typedef enum _eVideoConversion
+{
+    videoConversionAutomatic,
+    videoConversionLetterbox16by9,
+    videoConversionLetterbox14by9,
+    videoConversionPillarbox,
+    videoConversionCentreCutOut,
+    videoConversionAlways16by9,
+    videoConversionMaxValue
+} eVideoConversion;
+
+typedef struct _tVideoFormat
+{
+    bool AutomaticEnabled;
+    bool AfdEnabled;
+    eTvFormat TvFormat;
+    eVideoConversion VideoConversion;
+} tVideoFormat;
+
+typedef enum _eVideoOutputMode
+{
+    videoOutputClone,
+    videoOutputDualView,
+    videoOutputMaxValue
+} eVideoOutputMode;
+
+typedef enum _eDownmixMode
+{
+    downmixOff,
+    downmixAnalog,
+    downmixAlways,
+    downmixAutomatic,
+    downmixHdmi
+} eDownmixMode;
+
+// AvMux definitions
+
+typedef enum _eVideoOut
+{
+    videoOutDisabled,
+    videoOutRgb,
+    videoOutCvbsYuv,
+    videoOutYc,
+    videoOutMaxValue
+} eVideoOut;
+
+typedef enum _eSlowBlank
+{
+    slowBlankOff,
+    slowBlank16by9,
+    slowBlank4by3,
+    slowBlankMaxValue
+} eSlowBlank;
+
+typedef enum _eFastBlank
+{
+    fastBlankCvbs,
+    fastBlankRgb,
+    fastBlankMaxValue
+} eFastBlank;
+
+
+// OSD definitions
+
+#define InvalidHandle           0xFFFFFFFF
+#define ScreenDisplayHandle     0xFFFFFFFE
+
+#define PositionScreenCentered  0xFFFF
+
+#define SizeFullScreen    0xFFFF
+#define SizeSameAsSource  0xFFFE
+
+#define FontFaceTiresias  0x00000000
+
+typedef enum _eColorType
+{
+    colorTypeClut1,
+    colorTypeClut2,
+    colorTypeClut4,
+    colorTypeClut8,
+    colorTypeARGB8888,
+    colorTypeARGB8565,
+    colorTypeARGB4444,
+    colorTypeARGB1555,
+} eColorType;
+
+typedef enum _eColorFormat
+{
+    colorFormatARGB,
+    colorFormatACbYCr,
+} eColorFormat;
+
+typedef enum _eDrawingFlags
+{
+    drawFull,
+    drawHalfTop,
+    drawHalfLeft,
+    drawHalfBottom,
+    drawHalfRight,
+    drawQuarterTopLeft,
+    drawQuarterTopRight,
+    drawQuarterBottomLeft,
+    drawQuarterBottomRight,
+    drawQuarterTopLeftInverted,
+    drawQuarterTopRightInverted,
+    drawQuarterBottomLeftInverted,
+    drawQuarterBottomRightInverted
+} eDrawingFlags;
+
+typedef struct _tOsdConfig
+{
+    bool FontAntialiasing;
+    bool FontKerning;
+} tOsdConfig;
+
+// HDMI definitions
+
+typedef enum _eHdmiVideoMode
+{
+    videoMode576p50 = 18,
+    videoMode720p50 = 19,
+    videoMode1080i50 = 20,
+    videoMode576i50 = 22,
+    videoModeMaxValue
+} eHdmiVideoMode;
+
+typedef enum _eCecCommand
+{
+    cecCommandTvOn,
+    cecCommandTvOff,
+    cecCommandActiveSource,
+    cecCommandInactiveSource
+} eCecCommand;
+
+typedef struct _tHdmiConfig
+{
+    bool TransmitAudio;
+    bool ForceDviMode;
+    bool CecEnabled;
+} tHdmiConfig;
+
+// Remote control definitions
+
+typedef enum _eRemoteProtocol
+{
+    remoteProtocolNone,
+    remoteProtocolRc5,
+    remoteProtocolRc6,
+    remoteProtocolMaxValue
+} eRemoteProtocol;
+
+} // end of namespace
+
+#endif
diff --git a/PLUGINS/src/dvbhddevice/hdffosd.c b/PLUGINS/src/dvbhddevice/hdffosd.c
new file mode 100644 (file)
index 0000000..254f2af
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * hdffosd.c: Implementation of the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffosd.c 1.9 2011/04/17 11:20:22 kls Exp $
+ */
+
+#include "hdffosd.h"
+#include <linux/dvb/osd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include "hdffcmd.h"
+#include "setup.h"
+
+#define MAX_NUM_FONTFACES   8
+#define MAX_NUM_FONTS       8
+#define MAX_BITMAP_SIZE     (1024*1024)
+
+typedef struct _tFontFace
+{
+    cString Name;
+    uint32_t Handle;
+} tFontFace;
+
+typedef struct _tFont
+{
+    uint32_t hFontFace;
+    int Size;
+    uint32_t Handle;
+} tFont;
+
+class cHdffOsd : public cOsd
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    int mLeft;
+    int mTop;
+    int mDispWidth;
+    int mDispHeight;
+    bool shown;
+    bool mChanged;
+    bool mBitmapModified;
+    uint32_t mDisplay;
+    tFontFace mFontFaces[MAX_NUM_FONTFACES];
+    tFont mFonts[MAX_NUM_FONTS];
+    uint32_t mBitmapPalette;
+    uint32_t mBitmapColors[256];
+    uint32_t mBitmapNumColors;
+
+protected:
+    virtual void SetActive(bool On);
+public:
+    cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
+    virtual ~cHdffOsd();
+    cBitmap *GetBitmap(int Area);
+    virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
+    virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
+    virtual void SaveRegion(int x1, int y1, int x2, int y2);
+    virtual void RestoreRegion(void);
+    virtual void DrawPixel(int x, int y, tColor Color);
+    virtual void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool ReplacePalette = false, bool Overlay = false);
+    virtual void DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width = 0, int Height = 0, int Alignment = taDefault);
+    virtual void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color);
+    virtual void DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants = 0);
+    virtual void DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type);
+    virtual void Flush(void);
+};
+
+cHdffOsd::cHdffOsd(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level)
+:   cOsd(Left, Top, Level)
+{
+    double pixelAspect;
+    HDFF::tOsdConfig config;
+
+    //printf("cHdffOsd %d, %d, %d\n", Left, Top, Level);
+    mHdffCmdIf = pHdffCmdIf;
+    mLeft = Left;
+    mTop = Top;
+    shown = false;
+    mChanged = false;
+    mBitmapModified = false;
+    mBitmapPalette = InvalidHandle;
+    config.FontKerning = false;
+    config.FontAntialiasing = Setup.AntiAlias ? true : false;
+    mHdffCmdIf->CmdOsdConfigure(&config);
+
+    gHdffSetup.GetOsdSize(mDispWidth, mDispHeight, pixelAspect);
+    mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF::colorTypeARGB8888);
+    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, SizeFullScreen, SizeFullScreen);
+    for (int i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        mFontFaces[i].Name = "";
+        mFontFaces[i].Handle = InvalidHandle;
+    }
+    for (int i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        mFonts[i].hFontFace = InvalidHandle;
+        mFonts[i].Size = 0;
+        mFonts[i].Handle = InvalidHandle;
+    }
+}
+
+cHdffOsd::~cHdffOsd()
+{
+    //printf("~cHdffOsd %d %d\n", mLeft, mTop);
+    SetActive(false);
+
+    for (int i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        if (mFonts[i].Handle == InvalidHandle)
+            break;
+        mHdffCmdIf->CmdOsdDeleteFont(mFonts[i].Handle);
+    }
+    for (int i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        if (mFontFaces[i].Handle == InvalidHandle)
+            break;
+        mHdffCmdIf->CmdOsdDeleteFontFace(mFontFaces[i].Handle);
+    }
+
+    if (mBitmapPalette != InvalidHandle)
+        mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+}
+
+cBitmap * cHdffOsd::GetBitmap(int Area)
+{
+    //printf("GetBitmap %d\n", Area);
+    mChanged = true;
+    mBitmapModified = true;
+    return cOsd::GetBitmap(Area);
+}
+
+eOsdError cHdffOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
+{
+    eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
+    if (Result == oeOk)
+    {
+        for (int i = 0; i < NumAreas; i++)
+        {
+            if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8)
+                return oeBppNotSupported;
+        }
+    }
+    return Result;
+}
+
+eOsdError cHdffOsd::SetAreas(const tArea *Areas, int NumAreas)
+{
+    for (int i = 0; i < NumAreas; i++)
+    {
+        //printf("SetAreas %d: %d %d %d %d %d\n", i, Areas[i].x1, Areas[i].y1, Areas[i].x2, Areas[i].y2, Areas[i].bpp);
+    }
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    return cOsd::SetAreas(Areas, NumAreas);
+}
+
+void cHdffOsd::SetActive(bool On)
+{
+    if (On != Active())
+    {
+        cOsd::SetActive(On);
+        if (On)
+        {
+        }
+        else if (shown)
+        {
+            shown = false;
+        }
+    }
+}
+
+void cHdffOsd::SaveRegion(int x1, int y1, int x2, int y2)
+{
+    mHdffCmdIf->CmdOsdSaveRegion(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::RestoreRegion(void)
+{
+    mHdffCmdIf->CmdOsdRestoreRegion(mDisplay);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawPixel(int x, int y, tColor Color)
+{
+    //printf("DrawPixel\n");
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
+{
+    //printf("DrawBitmap %d %d %d\n", x, y, Overlay);
+    int i;
+    int numColors;
+    const tColor * colors = Bitmap.Colors(numColors);
+
+    for (i = 0; i < numColors; i++)
+    {
+        mBitmapColors[i] = colors[i];
+        if (ColorFg || ColorBg)
+        {
+            if (i == 0)
+                mBitmapColors[i] = ColorBg;
+            else if (i == 1)
+                mBitmapColors[i] = ColorFg;
+        }
+    }
+    if (mBitmapPalette == InvalidHandle)
+    {
+        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF::colorTypeClut8,
+                HDFF::colorFormatARGB, numColors, mBitmapColors);
+    }
+    else
+    {
+        mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
+                HDFF::colorFormatARGB, 0, numColors, mBitmapColors);
+    }
+    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y,
+        (uint8_t *) Bitmap.Data(0, 0), Bitmap.Width(), Bitmap.Height(),
+        Bitmap.Width() * Bitmap.Height(), HDFF::colorTypeClut8, mBitmapPalette);
+#if 0
+    uint32_t * tmpBitmap = new uint32_t[Bitmap.Width() * Bitmap.Height()];
+    for (int ix = 0; ix < Bitmap.Width(); ix++)
+    {
+        for (int iy = 0; iy < Bitmap.Height(); iy++)
+        {
+            const tIndex * pixel = Bitmap.Data(ix, iy);
+            tColor color = Bitmap.Color(*pixel);
+            if (!Overlay || *pixel != 0)
+            {
+                if (ColorFg || ColorBg)
+                {
+                    if (*pixel == 0)
+                        color = ColorBg;
+                    else if (*pixel == 1)
+                        color = ColorFg;
+                }
+                tmpBitmap[Bitmap.Width() * iy + ix] = color;
+            }
+        }
+    }
+    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay, mLeft + x, mTop + y,
+        (uint8_t *) tmpBitmap, Bitmap.Width(), Bitmap.Height(),
+        Bitmap.Width() * Bitmap.Height() * 4, HDFF::colorTypeARGB8888, InvalidHandle);
+    delete[] tmpBitmap;
+#endif
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
+{
+    int w = Font->Width(s);
+    int h = Font->Height();
+    int limit = 0;
+    int cw = Width ? Width : w;
+    int ch = Height ? Height : h;
+    int i;
+    int size = Font->Size();
+    tFontFace * pFontFace;
+    tFont * pFont;
+
+    if (ColorBg != clrTransparent)
+        mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, mLeft + x, mTop + y, cw, ch, ColorBg);
+
+    if (s == NULL)
+        return;
+
+    pFontFace = NULL;
+    for (i = 0; i < MAX_NUM_FONTFACES; i++)
+    {
+        if (mFontFaces[i].Handle == InvalidHandle)
+            break;
+
+        if (strcmp(mFontFaces[i].Name, Font->FontName()) == 0)
+        {
+            pFontFace = &mFontFaces[i];
+            break;
+        }
+    }
+    if (pFontFace == NULL)
+    {
+        if (i < MAX_NUM_FONTFACES)
+        {
+            cString fontFileName = Font->FontName();
+            FILE * fp = fopen(fontFileName, "rb");
+            if (fp)
+            {
+                fseek(fp, 0, SEEK_END);
+                long fileSize = ftell(fp);
+                fseek(fp, 0, SEEK_SET);
+                if (fileSize > 0)
+                {
+                    uint8_t * buffer = new uint8_t[fileSize];
+                    if (buffer)
+                    {
+                        if (fread(buffer, fileSize, 1, fp) == 1)
+                        {
+                            mFontFaces[i].Handle = mHdffCmdIf->CmdOsdCreateFontFace(buffer, fileSize);
+                            if (mFontFaces[i].Handle != InvalidHandle)
+                            {
+                                mFontFaces[i].Name = Font->FontName();
+                                pFontFace = &mFontFaces[i];
+                            }
+                        }
+                        delete[] buffer;
+                    }
+                }
+                fclose(fp);
+            }
+        }
+    }
+    if (pFontFace == NULL)
+        return;
+
+    pFont = NULL;
+    for (i = 0; i < MAX_NUM_FONTS; i++)
+    {
+        if (mFonts[i].Handle == InvalidHandle)
+            break;
+
+        if (mFonts[i].hFontFace == pFontFace->Handle
+          && mFonts[i].Size == size)
+        {
+            pFont = &mFonts[i];
+            break;
+        }
+    }
+    if (pFont == NULL)
+    {
+        if (i < MAX_NUM_FONTS)
+        {
+            mFonts[i].Handle = mHdffCmdIf->CmdOsdCreateFont(pFontFace->Handle, size);
+            if (mFonts[i].Handle != InvalidHandle)
+            {
+                mFonts[i].hFontFace = pFontFace->Handle;
+                mFonts[i].Size = size;
+                pFont = &mFonts[i];
+            }
+        }
+    }
+    if (pFont == NULL)
+        return;
+
+    mHdffCmdIf->CmdOsdSetDisplayClippingArea(mDisplay, true, mLeft + x, mTop + y, cw, ch);
+
+    if (Width || Height)
+    {
+        limit = x + cw;// - mLeft;
+        if (Width)
+        {
+            if ((Alignment & taLeft) != 0)
+                ;
+            else if ((Alignment & taRight) != 0)
+            {
+                if (w < Width)
+                    x += Width - w;
+            }
+            else
+            { // taCentered
+                if (w < Width)
+                    x += (Width - w) / 2;
+            }
+        }
+        if (Height)
+        {
+            if ((Alignment & taTop) != 0)
+                ;
+            else if ((Alignment & taBottom) != 0)
+            {
+                if (h < Height)
+                    y += Height - h;
+            }
+            else
+            { // taCentered
+                if (h < Height)
+                    y += (Height - h) / 2;
+            }
+        }
+    }
+    //x -= mLeft;
+    //y -= mTop;
+    {
+        uint16_t tmp[1000];
+        uint16_t len = 0;
+        while (*s && (len < (sizeof(tmp) - 1)))
+        {
+            int sl = Utf8CharLen(s);
+            uint sym = Utf8CharGet(s, sl);
+            s += sl;
+            tmp[len] = sym;
+            len++;
+        }
+        tmp[len] = 0;
+        mHdffCmdIf->CmdOsdDrawTextW(mDisplay, pFont->Handle, x + mLeft, y + mTop + h, tmp, ColorFg);
+    }
+    //mHdffCmdIf->CmdOsdDrawText(mDisplay, pFont->Handle, x + mLeft, y + mTop + h - 7, s, ColorFg);
+    mHdffCmdIf->CmdOsdSetDisplayClippingArea(mDisplay, false, 0, 0, 0, 0);
+    //Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
+{
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, mLeft + x1, mTop + y1, x2 - x1 + 1, y2 - y1 + 1, Color);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
+{
+    uint32_t flags;
+    int cx;
+    int cy;
+    int rx;
+    int ry;
+
+    switch (abs(Quadrants))
+    {
+        case 1:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterTopRight;
+            else
+                flags = HDFF::drawQuarterTopRightInverted;
+            cx = x1;
+            cy = y2;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 2:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterTopLeft;
+            else
+                flags = HDFF::drawQuarterTopLeftInverted;
+            cx = x2;
+            cy = y2;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 3:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterBottomLeft;
+            else
+                flags = HDFF::drawQuarterBottomLeftInverted;
+            cx = x2;
+            cy = y1;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 4:
+            if (Quadrants > 0)
+                flags = HDFF::drawQuarterBottomRight;
+            else
+                flags = HDFF::drawQuarterBottomRightInverted;
+            cx = x1;
+            cy = y1;
+            rx = x2 - x1;
+            ry = y2 - y1;
+            break;
+        case 5:
+            flags = HDFF::drawHalfRight;
+            cx = x1;
+            cy = (y1 + y2) / 2;
+            rx = x2 - x1;
+            ry = (y2 - y1) / 2;
+            break;
+        case 6:
+            flags = HDFF::drawHalfTop;
+            cx = (x1 + x2) / 2;
+            cy = y2;
+            rx = (x2 - x1) / 2;
+            ry = y2 - y1;
+            break;
+        case 7:
+            flags = HDFF::drawHalfLeft;
+            cx = x2;
+            cy = (y1 + y2) / 2;
+            rx = x2 - x1;
+            ry = (y2 - y1) / 2;
+            break;
+        case 8:
+            flags = HDFF::drawHalfBottom;
+            cx = (x1 + x2) / 2;
+            cy = y1;
+            rx = (x2 - x1) / 2;
+            ry = y2 - y1;
+            break;
+        default:
+            flags = HDFF::drawFull;
+            cx = (x1 + x2) / 2;
+            cy = (y1 + y2) / 2;
+            rx = (x2 - x1) / 2;
+            ry = (y2 - y1) / 2;
+            break;
+    }
+    mHdffCmdIf->CmdOsdDrawEllipse(mDisplay, mLeft + cx, mTop + cy, rx, ry, Color, flags);
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
+{
+    //printf("DrawSlope\n");
+    mChanged = true;
+    mBitmapModified = false;
+}
+
+void cHdffOsd::Flush(void)
+{
+    if (!Active())
+        return;
+
+    if (!mChanged)
+        return;
+
+    //printf("Flush\n");
+    if (mBitmapModified)
+    {
+        cBitmap *Bitmap;
+        for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++)
+        {
+            DrawBitmap(0, 0, *Bitmap);
+        }
+    }
+
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+
+    mChanged = false;
+    mBitmapModified = false;
+}
+
+
+class cHdffOsdRaw : public cOsd
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    int mDispWidth;
+    int mDispHeight;
+    bool shown;
+    uint32_t mDisplay;
+    uint32_t mBitmapPalette;
+    uint32_t mBitmapColors[256];
+    uint32_t mBitmapNumColors;
+
+protected:
+    virtual void SetActive(bool On);
+public:
+    cHdffOsdRaw(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level);
+    virtual ~cHdffOsdRaw();
+    virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
+    virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
+    virtual void Flush(void);
+};
+
+cHdffOsdRaw::cHdffOsdRaw(int Left, int Top, HDFF::cHdffCmdIf * pHdffCmdIf, uint Level)
+:   cOsd(Left, Top, Level)
+{
+    double pixelAspect;
+
+    //printf("cHdffOsdRaw %d, %d, %d\n", Left, Top, Level);
+    mHdffCmdIf = pHdffCmdIf;
+    shown = false;
+    mBitmapPalette = InvalidHandle;
+
+    gHdffSetup.GetOsdSize(mDispWidth, mDispHeight, pixelAspect);
+    mDisplay = mHdffCmdIf->CmdOsdCreateDisplay(mDispWidth, mDispHeight, HDFF::colorTypeARGB8888);
+    mHdffCmdIf->CmdOsdSetDisplayOutputRectangle(mDisplay, 0, 0, SizeFullScreen, SizeFullScreen);
+}
+
+cHdffOsdRaw::~cHdffOsdRaw()
+{
+    //printf("~cHdffOsdRaw %d %d\n", Left(), Top());
+    SetActive(false);
+
+    if (mBitmapPalette != InvalidHandle)
+        mHdffCmdIf->CmdOsdDeletePalette(mBitmapPalette);
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    mHdffCmdIf->CmdOsdDeleteDisplay(mDisplay);
+}
+
+void cHdffOsdRaw::SetActive(bool On)
+{
+    if (On != Active())
+    {
+        cOsd::SetActive(On);
+        if (On)
+        {
+        }
+        else if (shown)
+        {
+            shown = false;
+        }
+    }
+}
+
+eOsdError cHdffOsdRaw::CanHandleAreas(const tArea *Areas, int NumAreas)
+{
+    eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
+    if (Result == oeOk)
+    {
+        for (int i = 0; i < NumAreas; i++)
+        {
+            if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8
+                && (Areas[i].bpp != 32 || !gHdffSetup.TrueColorOsd))
+                return oeBppNotSupported;
+        }
+    }
+    return Result;
+}
+
+eOsdError cHdffOsdRaw::SetAreas(const tArea *Areas, int NumAreas)
+{
+    for (int i = 0; i < NumAreas; i++)
+    {
+        //printf("SetAreas %d: %d %d %d %d %d\n", i, Areas[i].x1, Areas[i].y1, Areas[i].x2, Areas[i].y2, Areas[i].bpp);
+    }
+    mHdffCmdIf->CmdOsdDrawRectangle(mDisplay, 0, 0, mDispWidth, mDispHeight, 0);
+    mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+    return cOsd::SetAreas(Areas, NumAreas);
+}
+
+void cHdffOsdRaw::Flush(void)
+{
+    if (!Active())
+        return;
+    //struct timeval start;
+    //struct timeval end;
+    //struct timezone timeZone;
+    //gettimeofday(&start, &timeZone);
+
+    bool render = false;
+    if (IsTrueColor())
+    {
+        LOCK_PIXMAPS;
+        while (cPixmapMemory *pm = RenderPixmaps())
+        {
+            int w = pm->ViewPort().Width();
+            int h = pm->ViewPort().Height();
+            int d = w * sizeof(tColor);
+            int Chunk = MAX_BITMAP_SIZE / w / sizeof(tColor);
+            if (Chunk > h)
+                Chunk = h;
+            for (int y = 0; y < h; y += Chunk)
+            {
+                 int hc = Chunk;
+                 if (y + hc > h)
+                     hc = h - y;
+                 mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
+                     Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y() + y,
+                     pm->Data() + y * d, w, hc, hc * d,
+                     HDFF::colorTypeARGB8888, InvalidHandle);
+            }
+            delete pm;
+            render = true;
+        }
+    }
+    else
+    {
+        uint8_t * buffer = new uint8_t[MAX_BITMAP_SIZE];
+        if (!buffer)
+            return;
+        cBitmap * bitmap;
+        for (int i = 0; (bitmap = GetBitmap(i)) != NULL; i++)
+        {
+            int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+            if (!shown || bitmap->Dirty(x1, y1, x2, y2))
+            {
+                if (!shown)
+                {
+                    x2 = bitmap->Width() - 1;
+                    y2 = bitmap->Height() - 1;
+                }
+                // commit colors:
+                int numColors;
+                const tColor * colors = bitmap->Colors(numColors);
+                if (colors)
+                {
+                    for (int c = 0; c < numColors; c++)
+                        mBitmapColors[c] = colors[c];
+                    if (mBitmapPalette == InvalidHandle)
+                    {
+                        mBitmapPalette = mHdffCmdIf->CmdOsdCreatePalette(HDFF::colorTypeClut8,
+                            HDFF::colorFormatARGB, numColors, mBitmapColors);
+                    }
+                    else
+                    {
+                        mHdffCmdIf->CmdOsdSetPaletteColors(mBitmapPalette,
+                            HDFF::colorFormatARGB, 0, numColors, mBitmapColors);
+                    }
+                }
+                // commit modified data:
+                int width = x2 - x1 + 1;
+                int height = y2 - y1 + 1;
+                int chunk = MAX_BITMAP_SIZE / width;
+                if (chunk > height)
+                    chunk = height;
+                for (int y = 0; y < height; y += chunk)
+                {
+                    int hc = chunk;
+                    if (y + hc > height)
+                        hc = height - y;
+                    for (int r = 0; r < hc; r++)
+                        memcpy(buffer + r * width, bitmap->Data(x1, y1 + y + r), width);
+                    mHdffCmdIf->CmdOsdDrawBitmap(mDisplay,
+                        Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1 + y,
+                        buffer, width, hc, hc * width,
+                        HDFF::colorTypeClut8, mBitmapPalette);
+                }
+                render = true;
+            }
+            bitmap->Clean();
+        }
+        delete[] buffer;
+    }
+    if (render)
+    {
+        mHdffCmdIf->CmdOsdRenderDisplay(mDisplay);
+        //gettimeofday(&end, &timeZone);
+        //int timeNeeded = end.tv_usec - start.tv_usec;
+        //timeNeeded += (end.tv_sec - start.tv_sec) * 1000000;
+        //printf("time = %d\n", timeNeeded);
+    }
+    shown = true;
+}
+
+
+
+
+cHdffOsdProvider::cHdffOsdProvider(HDFF::cHdffCmdIf * HdffCmdIf)
+{
+    mHdffCmdIf = HdffCmdIf;
+}
+
+cOsd *cHdffOsdProvider::CreateOsd(int Left, int Top, uint Level)
+{
+    //printf("CreateOsd %d %d %d\n", Left, Top, Level);
+    if (gHdffSetup.HighLevelOsd)
+        return new cHdffOsd(Left, Top, mHdffCmdIf, Level);
+    else
+        return new cHdffOsdRaw(Left, Top, mHdffCmdIf, Level);
+}
+
+bool cHdffOsdProvider::ProvidesTrueColor(void)
+{
+    return gHdffSetup.TrueColorOsd && !gHdffSetup.HighLevelOsd;
+}
diff --git a/PLUGINS/src/dvbhddevice/hdffosd.h b/PLUGINS/src/dvbhddevice/hdffosd.h
new file mode 100644 (file)
index 0000000..533897e
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * hdffosd.h: Implementation of the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hdffosd.h 1.2 2011/01/30 15:27:48 kls Exp $
+ */
+
+#ifndef _HDFF_OSD_H_
+#define _HDFF_OSD_H_
+
+#include <vdr/osd.h>
+
+#include "hdffcmd.h"
+
+class cHdffOsdProvider : public cOsdProvider
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+public:
+    cHdffOsdProvider(HDFF::cHdffCmdIf * pHdffCmdIf);
+    virtual cOsd *CreateOsd(int Left, int Top, uint Level);
+    virtual bool ProvidesTrueColor(void);
+};
+
+#endif
diff --git a/PLUGINS/src/dvbhddevice/setup.c b/PLUGINS/src/dvbhddevice/setup.c
new file mode 100644 (file)
index 0000000..3cb69b1
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * setup.c: Setup for the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: setup.c 1.11 2011/04/17 11:45:17 kls Exp $
+ */
+
+#include "setup.h"
+#include "hdffcmd.h"
+
+const int kResolutions = 4;
+const int kTvFormats = 2;
+const int kVideoConversions = 6;
+const int kAnalogueVideos = 4;
+const int kAudioDownmixes = 5;
+const int kOsdSizes = 5;
+const int kRemoteProtocols = 3;
+
+const int kResolution1080i = 0;
+const int kResolution720p = 1;
+const int kResolution576p = 2;
+const int kResolution576i = 3;
+
+static const char * ResolutionItems[] =
+{
+    "1080i",
+    "720p",
+    "576p",
+    "576i",
+    NULL
+};
+
+static const char * TvFormatItems[] =
+{
+    "4/3",
+    "16/9",
+    NULL
+};
+
+static const char * VideoConversionItems[] =
+{
+    "Automatic",
+    "Letterbox 16/9",
+    "Letterbox 14/9",
+    "Pillarbox",
+    "CentreCutOut",
+    "Always 16/9",
+    NULL
+};
+
+static const char * AnalogueVideoItems[] =
+{
+    "Disabled",
+    "RGB",
+    "CVBS + YUV",
+    "YC (S-Video)",
+    NULL
+};
+
+static const char * AudioDownmixItems[] =
+{
+    "Disabled",
+    "Analogue only",
+    "Always",
+    "Automatic",
+    "HDMI only",
+    NULL
+};
+
+static const char * OsdSizeItems[] =
+{
+    "Follow resolution",
+    "1920x1080",
+    "1280x720",
+    "1024x576",
+    "720x576",
+    NULL
+};
+
+static const char * RemoteProtocolItems[] =
+{
+    "none",
+    "RC5",
+    "RC6",
+    NULL
+};
+
+cHdffSetup gHdffSetup;
+
+cHdffSetup::cHdffSetup(void)
+{
+    Resolution = kResolution1080i;
+    TvFormat = HDFF::tvFormat16by9;
+    VideoConversion = HDFF::videoConversionPillarbox;
+    AnalogueVideo = HDFF::videoOutCvbsYuv;
+    AudioDelay = 0;
+    AudioDownmix = HDFF::downmixAutomatic;
+    OsdSize = 0;
+    CecEnabled = 1;
+    RemoteProtocol = 1;
+    RemoteAddress = -1;
+    HighLevelOsd = 1;
+    TrueColorOsd = 1;
+}
+
+bool cHdffSetup::SetupParse(const char *Name, const char *Value)
+{
+    if      (strcmp(Name, "Resolution")      == 0) Resolution      = atoi(Value);
+    else if (strcmp(Name, "TvFormat")        == 0) TvFormat        = atoi(Value);
+    else if (strcmp(Name, "VideoConversion") == 0) VideoConversion = atoi(Value);
+    else if (strcmp(Name, "AnalogueVideo")   == 0) AnalogueVideo   = atoi(Value);
+    else if (strcmp(Name, "AudioDelay")      == 0) AudioDelay      = atoi(Value);
+    else if (strcmp(Name, "AudioDownmix")    == 0) AudioDownmix    = atoi(Value);
+    else if (strcmp(Name, "OsdSize")         == 0) OsdSize         = atoi(Value);
+    else if (strcmp(Name, "CecEnabled")      == 0) CecEnabled      = atoi(Value);
+    else if (strcmp(Name, "RemoteProtocol")  == 0) RemoteProtocol  = atoi(Value);
+    else if (strcmp(Name, "RemoteAddress")   == 0) RemoteAddress   = atoi(Value);
+    else if (strcmp(Name, "HighLevelOsd")    == 0) HighLevelOsd    = atoi(Value);
+    else if (strcmp(Name, "TrueColorOsd")    == 0) TrueColorOsd    = atoi(Value);
+    else return false;
+    return true;
+}
+
+void cHdffSetup::GetOsdSize(int &Width, int &Height, double &PixelAspect)
+{
+    if (OsdSize == 0) {
+        if (Resolution == kResolution1080i) {
+            Width = 1920;
+            Height = 1080;
+        }
+        else if (Resolution == kResolution720p) {
+            Width = 1280;
+            Height = 720;
+        }
+        else {
+            Width = 720;
+            Height = 576;
+        }
+        if (TvFormat == HDFF::tvFormat16by9)
+            PixelAspect = 16.0 / 9.0;
+        else
+            PixelAspect = 4.0 / 3.0;
+    }
+    else if (OsdSize == 1) {
+        Width = 1920;
+        Height = 1080;
+        PixelAspect = 16.0 / 9.0;
+    }
+    else if (OsdSize == 2) {
+        Width = 1280;
+        Height = 720;
+        PixelAspect = 16.0 / 9.0;
+    }
+    else if (OsdSize == 3) {
+        Width = 1024;
+        Height = 576;
+        PixelAspect = 16.0 / 9.0;
+    }
+    else {
+        Width = 720;
+        Height = 576;
+        PixelAspect = 4.0 / 3.0;
+    }
+  PixelAspect /= double(Width) / Height;
+}
+
+HDFF::eHdmiVideoMode cHdffSetup::GetVideoMode(void)
+{
+    switch (Resolution)
+    {
+        case kResolution1080i:
+        default:
+            return HDFF::videoMode1080i50;
+        case kResolution720p:
+            return HDFF::videoMode720p50;
+        case kResolution576p:
+            return HDFF::videoMode576p50;
+        case kResolution576i:
+            return HDFF::videoMode576i50;
+    }
+}
+
+cHdffSetupPage::cHdffSetupPage(HDFF::cHdffCmdIf * pHdffCmdIf)
+{
+    mHdffCmdIf = pHdffCmdIf;
+    mNewHdffSetup = gHdffSetup;
+
+    Add(new cMenuEditStraItem("Resolution", &mNewHdffSetup.Resolution, kResolutions, ResolutionItems));
+    Add(new cMenuEditStraItem("TV format", &mNewHdffSetup.TvFormat, kTvFormats, TvFormatItems));
+    Add(new cMenuEditStraItem("Video Conversion", &mNewHdffSetup.VideoConversion, kVideoConversions, VideoConversionItems));
+    Add(new cMenuEditStraItem("Analogue Video", &mNewHdffSetup.AnalogueVideo, kAnalogueVideos, AnalogueVideoItems));
+    Add(new cMenuEditIntItem("Audio Delay (ms)", &mNewHdffSetup.AudioDelay, 0, 500));
+    Add(new cMenuEditStraItem("Audio Downmix", &mNewHdffSetup.AudioDownmix, kAudioDownmixes, AudioDownmixItems));
+    Add(new cMenuEditStraItem("Osd Size", &mNewHdffSetup.OsdSize, kOsdSizes, OsdSizeItems));
+    Add(new cMenuEditBoolItem("HDMI CEC", &mNewHdffSetup.CecEnabled));
+    Add(new cMenuEditStraItem("Remote Control Protocol", &mNewHdffSetup.RemoteProtocol, kRemoteProtocols, RemoteProtocolItems));
+    Add(new cMenuEditIntItem("Remote Control Address", &mNewHdffSetup.RemoteAddress, -1, 31));
+    Add(new cMenuEditBoolItem("High Level OSD", &mNewHdffSetup.HighLevelOsd));
+    Add(new cMenuEditBoolItem("Allow True Color OSD", &mNewHdffSetup.TrueColorOsd));
+}
+
+cHdffSetupPage::~cHdffSetupPage(void)
+{
+}
+
+void cHdffSetupPage::Store(void)
+{
+    SetupStore("Resolution", mNewHdffSetup.Resolution);
+    SetupStore("TvFormat", mNewHdffSetup.TvFormat);
+    SetupStore("VideoConversion", mNewHdffSetup.VideoConversion);
+    SetupStore("AnalogueVideo", mNewHdffSetup.AnalogueVideo);
+    SetupStore("AudioDelay", mNewHdffSetup.AudioDelay);
+    SetupStore("AudioDownmix", mNewHdffSetup.AudioDownmix);
+    SetupStore("OsdSize", mNewHdffSetup.OsdSize);
+    SetupStore("CecEnabled", mNewHdffSetup.CecEnabled);
+    SetupStore("RemoteProtocol", mNewHdffSetup.RemoteProtocol);
+    SetupStore("RemoteAddress", mNewHdffSetup.RemoteAddress);
+    SetupStore("HighLevelOsd", mNewHdffSetup.HighLevelOsd);
+    SetupStore("TrueColorOsd", mNewHdffSetup.TrueColorOsd);
+
+    if (mHdffCmdIf)
+    {
+        if (mNewHdffSetup.Resolution != gHdffSetup.Resolution)
+        {
+            mHdffCmdIf->CmdHdmiSetVideoMode(mNewHdffSetup.GetVideoMode());
+        }
+        HDFF::tVideoFormat videoFormat;
+        HDFF::tHdmiConfig hdmiConfig;
+
+        videoFormat.AutomaticEnabled = true;
+        videoFormat.AfdEnabled = true;
+        videoFormat.TvFormat = (HDFF::eTvFormat) mNewHdffSetup.TvFormat;
+        videoFormat.VideoConversion = (HDFF::eVideoConversion) mNewHdffSetup.VideoConversion;
+        mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
+
+        mHdffCmdIf->CmdAvSetAudioDelay(mNewHdffSetup.AudioDelay);
+        mHdffCmdIf->CmdAvSetAudioDownmix((HDFF::eDownmixMode) mNewHdffSetup.AudioDownmix);
+
+        mHdffCmdIf->CmdMuxSetVideoOut((HDFF::eVideoOut) mNewHdffSetup.AnalogueVideo);
+
+        hdmiConfig.TransmitAudio = true;
+        hdmiConfig.ForceDviMode = false;
+        hdmiConfig.CecEnabled = mNewHdffSetup.CecEnabled;
+        mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
+
+        mHdffCmdIf->CmdRemoteSetProtocol((HDFF::eRemoteProtocol) mNewHdffSetup.RemoteProtocol);
+        mHdffCmdIf->CmdRemoteSetAddressFilter(mNewHdffSetup.RemoteAddress >= 0, mNewHdffSetup.RemoteAddress);
+    }
+
+    gHdffSetup = mNewHdffSetup;
+}
diff --git a/PLUGINS/src/dvbhddevice/setup.h b/PLUGINS/src/dvbhddevice/setup.h
new file mode 100644 (file)
index 0000000..07c9d1a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * setup.h: Setup for the DVB HD Full Featured On Screen Display
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: setup.h 1.8 2011/04/17 11:20:22 kls Exp $
+ */
+
+#ifndef _HDFF_SETUP_H_
+#define _HDFF_SETUP_H_
+
+#include <vdr/plugin.h>
+#include "hdffcmd.h"
+
+struct cHdffSetup
+{
+    cHdffSetup(void);
+    bool SetupParse(const char * Name, const char * Value);
+    void GetOsdSize(int &Width, int &Height, double &PixelAspect);
+    HDFF::eHdmiVideoMode GetVideoMode(void);
+
+    int Resolution;
+    int TvFormat;
+    int VideoConversion;
+    int AnalogueVideo;
+    int AudioDelay;
+    int AudioDownmix;
+    int OsdSize;
+    int CecEnabled;
+    int RemoteProtocol;
+    int RemoteAddress;
+
+    int HighLevelOsd;
+    int TrueColorOsd;
+};
+
+extern cHdffSetup gHdffSetup;
+
+class cHdffSetupPage : public cMenuSetupPage
+{
+private:
+    HDFF::cHdffCmdIf * mHdffCmdIf;
+    cHdffSetup mNewHdffSetup;
+
+protected:
+    virtual void Store(void);
+
+public:
+    cHdffSetupPage(HDFF::cHdffCmdIf * pHdffCmdIf);
+    virtual ~cHdffSetupPage(void);
+};
+
+#endif
index 0d1047b..9672f6f 100644 (file)
@@ -15,3 +15,7 @@ VDR Plugin 'dvbsddevice' Revision History
 
 - The PCR pid is now recorded for channels where this is different from the
   video PID.
+
+2011-04-17: Version 0.0.4
+
+- Removed an obsolete local variable in dvbsdffosd.c (thanks to Paul Menzel).
index cc48b28..6f042d8 100644 (file)
@@ -3,13 +3,13 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: dvbsddevice.c 1.3 2010/01/30 10:05:42 kls Exp $
+ * $Id: dvbsddevice.c 1.4 2011/04/17 12:55:43 kls Exp $
  */
 
 #include <vdr/plugin.h>
 #include "dvbsdffdevice.h"
 
-static const char *VERSION        = "0.0.3";
+static const char *VERSION        = "0.0.4";
 static const char *DESCRIPTION    = "SD Full Featured DVB device";
 
 class cPluginDvbsddevice : public cPlugin {
index 4b60ef5..46c65e0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: dvbsdffosd.c 2.2 2010/09/19 12:43:45 kls Exp $
+ * $Id: dvbsdffosd.c 2.3 2011/04/17 12:55:09 kls Exp $
  */
 
 #include "dvbsdffosd.h"
@@ -73,8 +73,7 @@ void cDvbSdFfOsd::SetActive(bool On)
            Flush();
         }
      else if (shown) {
-        cBitmap *Bitmap;
-        for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
+        for (int i = 0; GetBitmap(i); i++) {
             Cmd(OSD_SetWindow, 0, i + 1);
             Cmd(OSD_Close);
             }
@@ -108,8 +107,7 @@ eOsdError cDvbSdFfOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
 eOsdError cDvbSdFfOsd::SetAreas(const tArea *Areas, int NumAreas)
 {
   if (shown) {
-     cBitmap *Bitmap;
-     for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
+     for (int i = 0; GetBitmap(i); i++) {
          Cmd(OSD_SetWindow, 0, i + 1);
          Cmd(OSD_Close);
          }
index 1270fbf..ac386b0 100644 (file)
@@ -25,3 +25,12 @@ VDR Plugin 'osddemo' Revision History
 2011-02-20: Version 0.2.0
 
 - Added support for TrueColor OSD.
+
+2011-03-28: Version 0.2.1
+
+- Added Cancel(3) to ~cTrueColorDemo() (thanks to Reinhard Nissl).
+- Added a missing font deletion in cTrueColorDemo::Action() (thanks to Reinhard Nissl).
+
+2011-04-17: Version 0.2.2
+
+- Fixed a possible NULL pointer dereference in osddemo.c (reported by Paul Menzel).
index 2e6a33b..9ad9df7 100644 (file)
@@ -3,13 +3,13 @@
  *
  * See the README file for copyright information and how to reach the author.
  *
- * $Id: osddemo.c 2.3 2011/02/26 12:08:13 kls Exp $
+ * $Id: osddemo.c 2.5 2011/04/17 13:05:13 kls Exp $
  */
 
 #include <vdr/osd.h>
 #include <vdr/plugin.h>
 
-static const char *VERSION        = "0.2.0";
+static const char *VERSION        = "0.2.2";
 static const char *DESCRIPTION    = "Demo of arbitrary OSD setup";
 static const char *MAINMENUENTRY  = "Osd Demo";
 
@@ -103,6 +103,7 @@ cTrueColorDemo::cTrueColorDemo(void)
 
 cTrueColorDemo::~cTrueColorDemo()
 {
+  Cancel(3);
   delete osd;
 }
 
@@ -262,12 +263,13 @@ void cTrueColorDemo::Action(void)
              case 3: {
                        if (cFont *Font = cFont::CreateFont(DefaultFontOsd, osd->Height() / 10)) {
                           NextPixmap = CreateTextPixmap("Millions of colors", Line, 1, clrYellow, clrTransparent, Font);
+                          delete Font;
                           if (NextPixmap) {
                              FadeInPixmap = NextPixmap;
+                             Start = cTimeMs::Now();
+                             StartLine = Line;
+                             Line += NextPixmap->DrawPort().Height();
                              }
-                          Start = cTimeMs::Now();
-                          StartLine = Line;
-                          Line += NextPixmap->DrawPort().Height();
                           }
                        State++;
                      }
index c9aeb5e..e4ac2f2 100644 (file)
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.h 2.29 2010/10/24 11:22:35 kls Exp $
+ * $Id: config.h 2.30 2011/03/13 12:02:31 kls Exp $
  */
 
 #ifndef __CONFIG_H
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.7.17"
-#define VDRVERSNUM   10717  // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION  "1.7.18"
+#define VDRVERSNUM   10718  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
 
-#define APIVERSION  "1.7.17"
-#define APIVERSNUM   10717  // Version * 10000 + Major * 100 + Minor
+#define APIVERSION  "1.7.18"
+#define APIVERSNUM   10718  // Version * 10000 + Major * 100 + Minor
 
 // When loading plugins, VDR searches them by their APIVERSION, which
 // may be smaller than VDRVERSION in case there have been no changes to
index 1598af2..a383dac 100644 (file)
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.h 2.23 2010/10/24 12:11:16 kls Exp $
+ * $Id: device.h 2.24 2011/03/21 17:58:41 kls Exp $
  */
 
 #ifndef __DEVICE_H
@@ -405,10 +405,9 @@ public:
          ///< (default is PAL).
   virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect);
          ///< Returns the With, Height and VideoAspect ratio of the currently
-         ///< displayed video material. The data returned by this function is
-         ///< only used for informational purposes (if any). Width and
-         ///< Height are given in pixel (e.g. 720x576) and VideoAspect is
-         ///< e.g. 1.33333 for a 4:3 broadcast, or 1.77778 for 16:9.
+         ///< displayed video material. Width and Height are given in pixel
+         ///< (e.g. 720x576) and VideoAspect is e.g. 1.33333 for a 4:3 broadcast,
+         ///< or 1.77778 for 16:9.
          ///< The default implementation returns 0 for Width and Height
          ///< and 1.0 for VideoAspect.
   virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect);
index 9e33e45..863e446 100644 (file)
--- a/dvbspu.h
+++ b/dvbspu.h
@@ -8,7 +8,7 @@
  *
  * parts of this file are derived from the OMS program.
  *
- * $Id: dvbspu.h 2.4 2009/12/13 12:07:00 kls Exp $
+ * $Id: dvbspu.h 2.5 2011/03/27 14:50:48 kls Exp $
  */
 
 #ifndef __DVBSPU_H
@@ -32,6 +32,9 @@ typedef struct sDvbSpuRect {
     int x1, y1;
     int x2, y2;
 
+    sDvbSpuRect(void) {
+        x1 = y1 = x2 = y2 = 0;
+    };
     int width() const {
         return x2 - x1 + 1;
     };
index c1a0a0c..de1cd1c 100644 (file)
@@ -7,10 +7,13 @@
  * Original author: Marco Schlüßler <marco@lordzodiac.de>
  * With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
  *
- * $Id: dvbsubtitle.c 2.11 2011/03/12 15:13:03 kls Exp $
+ * $Id: dvbsubtitle.c 2.17 2011/04/17 14:34:05 kls Exp $
  */
 
+
 #include "dvbsubtitle.h"
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
 #include "device.h"
 
 #define PAGE_COMPOSITION_SEGMENT   0x10
@@ -420,7 +423,7 @@ public:
   int PageId(void) { return pageId; }
   int Version(void) { return version; }
   int State(void) { return state; }
-  tArea *GetAreas(double Factor);
+  tArea *GetAreas(double FactorX, double FactorY);
   cSubtitleClut *GetClutById(int ClutId, bool New = false);
   cSubtitleObject *GetObjectById(int ObjectId);
   cSubtitleRegion *GetRegionById(int RegionId, bool New = false);
@@ -446,16 +449,16 @@ cDvbSubtitlePage::~cDvbSubtitlePage()
 {
 }
 
-tArea *cDvbSubtitlePage::GetAreas(double Factor)
+tArea *cDvbSubtitlePage::GetAreas(double FactorX, double FactorY)
 {
   if (regions.Count() > 0) {
      tArea *Areas = new tArea[regions.Count()];
      tArea *a = Areas;
      for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) {
-         a->x1 = int(round(Factor * sr->HorizontalAddress()));
-         a->y1 = int(round(Factor * sr->VerticalAddress()));
-         a->x2 = int(round(Factor * (sr->HorizontalAddress() + sr->Width() - 1)));
-         a->y2 = int(round(Factor * (sr->VerticalAddress() + sr->Height() - 1)));
+         a->x1 = int(round(FactorX * sr->HorizontalAddress()));
+         a->y1 = int(round(FactorY * sr->VerticalAddress()));
+         a->x2 = int(round(FactorX * (sr->HorizontalAddress() + sr->Width() - 1)));
+         a->y2 = int(round(FactorY * (sr->VerticalAddress() + sr->Height() - 1)));
          a->bpp = sr->Bpp();
          while ((a->Width() & 3) != 0)
                a->x2++; // aligns width to a multiple of 4, so 2, 4 and 8 bpp will work
@@ -616,10 +619,11 @@ private:
   int timeout;
   tArea *areas;
   int numAreas;
-  double osdFactor;
+  double osdFactorX;
+  double osdFactorY;
   cVector<cBitmap *> bitmaps;
 public:
-  cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactor);
+  cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY);
   ~cDvbSubtitleBitmaps();
   int64_t Pts(void) { return pts; }
   int Timeout(void) { return timeout; }
@@ -627,13 +631,14 @@ public:
   void Draw(cOsd *Osd);
   };
 
-cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactor)
+cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas, double OsdFactorX, double OsdFactorY)
 {
   pts = Pts;
   timeout = Timeout;
   areas = Areas;
   numAreas = NumAreas;
-  osdFactor = OsdFactor;
+  osdFactorX = OsdFactorX;
+  osdFactorY = OsdFactorY;
 }
 
 cDvbSubtitleBitmaps::~cDvbSubtitleBitmaps()
@@ -650,12 +655,27 @@ void cDvbSubtitleBitmaps::AddBitmap(cBitmap *Bitmap)
 
 void cDvbSubtitleBitmaps::Draw(cOsd *Osd)
 {
+  bool Scale = !(DoubleEqual(osdFactorX, 1.0) && DoubleEqual(osdFactorY, 1.0));
+  bool AntiAlias = true;
+  if (Scale && osdFactorX > 1.0 || osdFactorY > 1.0) {
+     // Upscaling requires 8bpp:
+     int Bpp[MAXOSDAREAS];
+     for (int i = 0; i < numAreas; i++) {
+         Bpp[i] = areas[i].bpp;
+         areas[i].bpp = 8;
+         }
+     if (Osd->CanHandleAreas(areas, numAreas) != oeOk) {
+        for (int i = 0; i < numAreas; i++)
+            Bpp[i] = areas[i].bpp = Bpp[i];
+        AntiAlias = false;
+        }
+     }
   if (Osd->SetAreas(areas, numAreas) == oeOk) {
      for (int i = 0; i < bitmaps.Size(); i++) {
          cBitmap *b = bitmaps[i];
-         if (osdFactor != 1.0)
-            b = b->Scale(osdFactor, osdFactor);
-         Osd->DrawBitmap(int(round(b->X0() * osdFactor)), int(round(b->Y0() * osdFactor)), *b);
+         if (Scale)
+            b = b->Scaled(osdFactorX, osdFactorY, AntiAlias);
+         Osd->DrawBitmap(int(round(b->X0() * osdFactorX)), int(round(b->Y0() * osdFactorY)), *b);
          if (b != bitmaps[i])
             delete b;
          }
@@ -733,7 +753,7 @@ int cDvbSubtitleConverter::ConvertFragments(const uchar *Data, int Length)
      if (Length > PayloadOffset + SubstreamHeaderLength) {
         int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
         if (pts)
-           dbgconverter("Converter PTS: %lld\n", pts);
+           dbgconverter("Converter PTS: %"PRId64"\n", pts);
         const uchar *data = Data + PayloadOffset + SubstreamHeaderLength; // skip substream header
         int length = Length - PayloadOffset - SubstreamHeaderLength; // skip substream header
         if (ResetSubtitleAssembler)
@@ -769,7 +789,7 @@ int cDvbSubtitleConverter::Convert(const uchar *Data, int Length)
      if (Length > PayloadOffset) {
         int64_t pts = PesGetPts(Data);
         if (pts)
-           dbgconverter("Converter PTS: %lld\n", pts);
+           dbgconverter("Converter PTS: %"PRId64"\n", pts);
         const uchar *data = Data + PayloadOffset;
         int length = Length - PayloadOffset;
         if (length > 3) {
@@ -828,7 +848,7 @@ void cDvbSubtitleConverter::Action(void)
                     if (AssertOsd()) {
                        sb->Draw(osd);
                        Timeout.Set(sb->Timeout() * 1000);
-                       dbgconverter("PTS: %lld  STC: %lld (%lld) timeout: %d\n", sb->Pts(), cDevice::PrimaryDevice()->GetSTC(), Delta, sb->Timeout());
+                       dbgconverter("PTS: %"PRId64"  STC: %"PRId64" (%"PRId64") timeout: %d\n", sb->Pts(), cDevice::PrimaryDevice()->GetSTC(), Delta, sb->Timeout());
                        }
                     bitmaps->Del(sb);
                     }
@@ -862,27 +882,27 @@ tColor cDvbSubtitleConverter::yuv2rgb(int Y, int Cb, int Cr)
 
 void cDvbSubtitleConverter::SetOsdData(void)
 {
-  int OsdWidth;
-  int OsdHeight;
+  int OsdWidth, OsdHeight;
   double OsdAspect;
+  int VideoWidth, VideoHeight;
+  double VideoAspect;
   cDevice::PrimaryDevice()->GetOsdSize(OsdWidth, OsdHeight, OsdAspect);
-  osdDeltaX = osdDeltaY = 0;
-  osdFactor = 1.0;
-  double fw = double(OsdWidth) / displayWidth;
-  double fh = double(OsdHeight) / displayHeight;
-  if (fw >= fh) {
-     osdFactor = fh;
-     osdDeltaX = (OsdWidth - displayWidth * osdFactor) / 2;
+  cDevice::PrimaryDevice()->GetVideoSize(VideoWidth, VideoHeight, VideoAspect);
+  if (OsdWidth == displayWidth && OsdHeight == displayHeight) {
+     osdFactorX = osdFactorY = 1.0;
+     osdDeltaX = osdDeltaY = 0;
      }
   else {
-     osdFactor = fw;
-     osdDeltaY = (OsdHeight - displayHeight * osdFactor) / 2;
+     osdFactorX = VideoAspect * OsdHeight / displayWidth;
+     osdFactorY = double(OsdHeight) / displayHeight;
+     osdDeltaX = (OsdWidth - displayWidth * osdFactorX) / 2;
+     osdDeltaY = (OsdHeight - displayHeight * osdFactorY) / 2;
      }
 }
 
 bool cDvbSubtitleConverter::AssertOsd(void)
 {
-  return osd || (osd = cOsdProvider::NewOsd(int(round(osdFactor * windowHorizontalOffset + osdDeltaX)), int(round(osdFactor * windowVerticalOffset + osdDeltaY)) + Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES));
+  return osd || (osd = cOsdProvider::NewOsd(int(round(osdFactorX * windowHorizontalOffset + osdDeltaX)), int(round(osdFactorY * windowVerticalOffset + osdDeltaY)) + Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES));
 }
 
 int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t Pts)
@@ -918,7 +938,7 @@ int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t
             page->SetTimeout(Data[6]);
             page->SetState((Data[6 + 1] & 0x0C) >> 2);
             page->regions.Clear();
-            dbgpages("Update page id %d version %d pts %lld timeout %d state %d\n", pageId, page->Version(), page->Pts(), page->Timeout(), page->State());
+            dbgpages("Update page id %d version %d pts %"PRId64" timeout %d state %d\n", pageId, page->Version(), page->Pts(), page->Timeout(), page->State());
             for (int i = 6 + 2; i < segmentLength; i += 6) {
                 cSubtitleRegion *region = page->GetRegionById(Data[i], true);
                 region->SetHorizontalAddress((Data[i + 2] << 8) + Data[i + 3]);
@@ -1079,7 +1099,7 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page)
 {
   if (!AssertOsd())
      return;
-  tArea *Areas = Page->GetAreas(osdFactor);
+  tArea *Areas = Page->GetAreas(osdFactorX, osdFactorY);
   int NumAreas = Page->regions.Count();
   int Bpp = 8;
   bool Reduced = false;
@@ -1116,7 +1136,7 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page)
             }
          }
      }
-  cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas, osdFactor);
+  cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas, osdFactorX, osdFactorY);
   bitmaps->Add(Bitmaps);
   for (cSubtitleRegion *sr = Page->regions.First(); sr; sr = Page->regions.Next(sr)) {
       int posX = sr->HorizontalAddress();
index 6e71765..a9f453e 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Original author: Marco Schlüßler <marco@lordzodiac.de>
  *
- * $Id: dvbsubtitle.h 2.5 2011/03/12 14:03:42 kls Exp $
+ * $Id: dvbsubtitle.h 2.6 2011/03/20 13:34:23 kls Exp $
  */
 
 #ifndef __DVBSUBTITLE_H
@@ -35,7 +35,8 @@ private:
   int windowHeight;
   int osdDeltaX;
   int osdDeltaY;
-  double osdFactor;
+  double osdFactorX;
+  double osdFactorY;
   cList<cDvbSubtitlePage> *pages;
   cList<cDvbSubtitleBitmaps> *bitmaps;
   tColor yuv2rgb(int Y, int Cb, int Cr);
diff --git a/font.c b/font.c
index db1bd89..16d1013 100644 (file)
--- a/font.c
+++ b/font.c
@@ -6,7 +6,7 @@
  *
  * BiDi support by Osama Alrawab <alrawab@hotmail.com> @2008 Tripoli-Libya.
  *
- * $Id: font.c 2.7 2011/02/26 12:09:18 kls Exp $
+ * $Id: font.c 2.8 2011/03/28 16:29:51 kls Exp $
  */
 
 #include "font.h"
@@ -520,7 +520,7 @@ cString cFont::Bidi(const char *Ltr)
   bool ok = fribidi_log2vis(Logical, RtlLen, &Base, Visual, NULL, NULL, NULL);
   if (ok) {
      fribidi_remove_bidi_marks(Visual, RtlLen, NULL, NULL, NULL);
-     Rtl = MALLOC(char, RtlLen * 4);
+     Rtl = MALLOC(char, RtlLen * 4 + 1);
      fribidi_unicode_to_charset(fribidiCharset, Visual, RtlLen, Rtl);
      }
   free(Logical);
diff --git a/osd.c b/osd.c
index 3a53556..d4e095a 100644 (file)
--- a/osd.c
+++ b/osd.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.c 2.17 2011/03/12 15:32:33 kls Exp $
+ * $Id: osd.c 2.21 2011/04/17 14:25:07 kls Exp $
  */
 
 #include "osd.h"
@@ -503,8 +503,7 @@ void cBitmap::DrawPixel(int x, int y, tColor Color)
 {
   x -= x0;
   y -= y0;
-  if (0 <= x && x < width && 0 <= y && y < height)
-     SetIndex(x, y, Index(Color));
+  SetIndex(x, y, Index(Color));
 }
 
 void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
@@ -807,7 +806,7 @@ void cBitmap::ShrinkBpp(int NewBpp)
      }
 }
 
-cBitmap *cBitmap::Scale(double FactorX, double FactorY)
+cBitmap *cBitmap::Scaled(double FactorX, double FactorY, bool AntiAlias)
 {
   // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf
   // by deltener@mindtremors.com
@@ -815,19 +814,42 @@ cBitmap *cBitmap::Scale(double FactorX, double FactorY)
   b->Replace(*this); // copy palette
   int RatioX = (Width() << 16) / b->Width();
   int RatioY = (Height() << 16) / b->Height();
-  tIndex *DestRow = b->bitmap;
-  int SourceY = 0;
-  for (int y = 0; y < b->Height(); y++) {
-      int SourceX = 0;
-      tIndex *SourceRow = bitmap + (SourceY >> 16) * Width();
-      tIndex *Dest = DestRow;
-      for (int x = 0; x < b->Width(); x++) {
-          *Dest++ = SourceRow[SourceX >> 16];
-          SourceX += RatioX;
-          }
-      SourceY += RatioY;
-      DestRow += b->Width();
-      }
+  if (!AntiAlias || FactorX <= 1.0 && FactorY <= 1.0) {
+     // Downscaling - no anti-aliasing:
+     tIndex *DestRow = b->bitmap;
+     int SourceY = 0;
+     for (int y = 0; y < b->Height(); y++) {
+         int SourceX = 0;
+         tIndex *SourceRow = bitmap + (SourceY >> 16) * Width();
+         tIndex *Dest = DestRow;
+         for (int x = 0; x < b->Width(); x++) {
+             *Dest++ = SourceRow[SourceX >> 16];
+             SourceX += RatioX;
+             }
+         SourceY += RatioY;
+         DestRow += b->Width();
+         }
+     }
+  else {
+     // Upscaling - anti-aliasing:
+     b->SetBpp(8);
+     int SourceY = 0;
+     for (int y = 0; y < b->Height() - 1; y++) {
+         int SourceX = 0;
+         int sy = SourceY >> 16;
+         uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF);
+         for (int x = 0; x < b->Width() - 1; x++) {
+             int sx = SourceX >> 16;
+             uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF);
+             tColor c1 = b->Blend(GetColor(sx, sy),     GetColor(sx + 1, sy),     BlendX);
+             tColor c2 = b->Blend(GetColor(sx, sy + 1), GetColor(sx + 1, sy + 1), BlendX);
+             tColor c3 = b->Blend(c1, c2, BlendY);
+             b->DrawPixel(x + X0(), y + Y0(), c3);
+             SourceX += RatioX;
+             }
+         SourceY += RatioY;
+         }
+     }
   return b;
 }
 
@@ -1394,6 +1416,7 @@ void cPixmapMemory::DrawEllipse(const cRect &Rect, tColor Color, int Quadrants)
           case -2: DrawRectangle(cRect(x1,     cy - y, cx - x - x1 + 1, 1), Color); break;
           case -3: DrawRectangle(cRect(x1,     cy + y, cx - x - x1 + 1, 1), Color); break;
           case -4: DrawRectangle(cRect(cx + x, cy + y, x2 - x + 1,      1), Color); break;
+          default: ;
           }
         x++;
         StoppingX += TwoBSquare;
diff --git a/osd.h b/osd.h
index ebd2797..b56853a 100644 (file)
--- a/osd.h
+++ b/osd.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.h 2.11 2011/03/12 16:06:48 kls Exp $
+ * $Id: osd.h 2.13 2011/04/17 14:24:32 kls Exp $
  */
 
 #ifndef __OSD_H
@@ -273,8 +273,11 @@ public:
        ///< the 2^NewBpp most frequently used colors as defined in the current palette.
        ///< If NewBpp is not smaller than the bitmap's current color depth,
        ///< or if it is not one of 4bpp or 2bpp, nothing happens.
-  cBitmap *Scale(double FactorX, double FactorY);
+  cBitmap *Scaled(double FactorX, double FactorY, bool AntiAlias = false);
        ///< Creates a copy of this bitmap, scaled by the given factors.
+       ///< If AntiAlias is true and either of the factors is greater than 1.0,
+       ///< anti-aliasing is applied. This will also set the color depth of the
+       ///< returned bitmap to 8bpp.
        ///< The caller must delete the returned bitmap once it is no longer used.
   };
 
diff --git a/pat.c b/pat.c
index 862bf46..b7493ec 100644 (file)
--- a/pat.c
+++ b/pat.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: pat.c 2.15 2010/11/07 13:47:16 kls Exp $
+ * $Id: pat.c 2.16 2011/04/17 13:45:25 kls Exp $
  */
 
 #include "pat.h"
@@ -456,7 +456,37 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
                          }
                       }
                       break;
-              case 0x80 ... 0xFF: // STREAMTYPE_USER_PRIVATE
+              case 0x80: // STREAMTYPE_USER_PRIVATE - DigiCipher II VIDEO (ANSI/SCTE 57)
+                      Vpid = esPid;
+                      Ppid = pmt.getPCRPid();
+                      Vtype = 0x02; // compression based upon MPEG-2
+                      ProcessCaDescriptors = true;
+                      break;
+              case 0x81: // STREAMTYPE_USER_PRIVATE - ATSC A/53 AUDIO (ANSI/SCTE 57)
+                      {
+                      char lang[MAXLANGCODE1] = { 0 };
+                      SI::Descriptor *d;
+                      for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+                          switch (d->getDescriptorTag()) {
+                            case SI::ISO639LanguageDescriptorTag: {
+                                 SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
+                                 strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
+                                 }
+                                 break;
+                            default: ;
+                            }
+                         delete d;
+                         }
+                      if (NumDpids < MAXDPIDS) {
+                         Dpids[NumDpids] = esPid;
+                         Dtypes[NumDpids] = SI::AC3DescriptorTag;
+                         strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
+                         NumDpids++;
+                         }
+                      ProcessCaDescriptors = true;
+                      }
+                      break;
+              case 0x82 ... 0xFF: // STREAMTYPE_USER_PRIVATE
                       {
                       char lang[MAXLANGCODE1] = { 0 };
                       bool IsAc3 = false;
@@ -467,17 +497,11 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
                                  SI::RegistrationDescriptor *rd = (SI::RegistrationDescriptor *)d;
                                  // http://www.smpte-ra.org/mpegreg/mpegreg.html
                                  switch (rd->getFormatIdentifier()) {
-                                   case 0x44434949: // 'DCII' aka. DigiCipher II
-                                        Vpid = esPid;
-                                        Ppid = pmt.getPCRPid();
-                                        Vtype = 0x02; // DCII compression is based upon MPEG-2
-                                        ProcessCaDescriptors = true;
-                                        break;
                                    case 0x41432D33: // 'AC-3'
                                         IsAc3 = true;
                                         break;
                                    default:
-                                        //printf("Format identifier: 0x08X\n", rd->getFormatIdentifier());
+                                        //printf("Format identifier: 0x%08X (pid: %d)\n", rd->getFormatIdentifier(), esPid);
                                         break;
                                    }
                                  }
@@ -493,11 +517,11 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
                          }
                       if (IsAc3) {
                          if (NumDpids < MAXDPIDS) {
-                           Dpids[NumDpids] = esPid;
-                           Dtypes[NumDpids] = SI::AC3DescriptorTag;
-                           strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
-                           NumDpids++;
-                           }
+                            Dpids[NumDpids] = esPid;
+                            Dtypes[NumDpids] = SI::AC3DescriptorTag;
+                            strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
+                            NumDpids++;
+                            }
                          ProcessCaDescriptors = true;
                          }
                       }
index 0900cbc..9a20687 100644 (file)
@@ -14,7 +14,7 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=ISO-8859-2\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Language: Serbian-latin\n"
+"Language: sr\n"
 
 msgid "*** Invalid Channel ***"
 msgstr "*** Neispravan Kanal ***"
index 02a6e61..d4cf9c3 100644 (file)
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.c 2.26 2011/02/27 13:35:20 kls Exp $
+ * $Id: recording.c 2.30 2011/04/17 13:53:11 kls Exp $
  */
 
 #include "recording.h"
@@ -12,6 +12,8 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
@@ -301,9 +303,10 @@ bool cResumeFile::Save(int Index)
 void cResumeFile::Delete(void)
 {
   if (fileName) {
-     if (remove(fileName) < 0 && errno != ENOENT)
+     if (remove(fileName) == 0)
+        Recordings.ResetResume(fileName);
+     else if (errno != ENOENT)
         LOG_ERROR_STR(fileName);
-     Recordings.ResetResume(fileName);
      }
 }
 
@@ -1270,19 +1273,31 @@ bool cMarks::Load(const char *RecordingFileName, double FramesPerSecond, bool Is
 {
   fileName = AddDirectory(RecordingFileName, IsPesRecording ? MARKSFILESUFFIX ".vdr" : MARKSFILESUFFIX);
   framesPerSecond = FramesPerSecond;
-  lastUpdate = 0;
+  nextUpdate = 0;
   lastFileTime = -1; // the first call to Load() must take place!
+  lastChange = 0;
   return Update();
 }
 
 bool cMarks::Update(void)
 {
   time_t t = time(NULL);
-  if (t - lastUpdate > MARKSUPDATEDELTA) {
-     lastUpdate = t;
-     t = LastModifiedTime(fileName);
-     if (t > lastFileTime) {
-        lastFileTime = t;
+  if (t > nextUpdate) {
+     time_t LastModified = LastModifiedTime(fileName);
+     if (LastModified != lastFileTime) // change detected, or first run
+        lastChange = LastModified > 0 ? LastModified : t;
+     int d = t - lastChange;
+     if (d < 60)
+        d = 1; // check frequently if the file has just been modified
+     else if (d < 3600)
+        d = 10; // older files are checked less frequently
+     else
+        d /= 360; // phase out checking for very old files
+     nextUpdate = t + d;
+     if (LastModified != lastFileTime) { // change detected, or first run
+        lastFileTime = LastModified;
+        if (lastFileTime == t)
+           lastFileTime--; // make sure we don't miss updates in the remaining second
         cMutexLock MutexLock(&MutexMarkFramesPerSecond);
         MarkFramesPerSecond = framesPerSecond;
         if (cConfig<cMark>::Load(fileName)) {
@@ -1550,7 +1565,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record, bool IsPesRecording)
               delta = int(buf.st_size % sizeof(tIndexTs));
               if (delta) {
                  delta = sizeof(tIndexTs) - delta;
-                 esyslog("ERROR: invalid file size (%lld) in '%s'", buf.st_size, fileName);
+                 esyslog("ERROR: invalid file size (%"PRId64") in '%s'", buf.st_size, fileName);
                  }
               last = int((buf.st_size + delta) / sizeof(tIndexTs) - 1);
               if (!Record && last >= 0) {
index 93b5a9c..8ec7f49 100644 (file)
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.h 2.16 2011/02/27 12:48:21 kls Exp $
+ * $Id: recording.h 2.19 2011/04/17 13:18:04 kls Exp $
  */
 
 #ifndef __RECORDING_H
@@ -57,6 +57,7 @@ private:
   int lifetime;
   char *fileName;
   cRecordingInfo(const cChannel *Channel = NULL, const cEvent *Event = NULL);
+  bool Read(FILE *f);
   void SetData(const char *Title, const char *ShortText, const char *Description);
   void SetAux(const char *Aux);
 public:
@@ -72,7 +73,6 @@ public:
   const char *Aux(void) const { return aux; }
   double FramesPerSecond(void) const { return framesPerSecond; }
   void SetFramesPerSecond(double FramesPerSecond);
-  bool Read(FILE *f);
   bool Write(FILE *f, const char *Prefix = "") const;
   bool Read(void);
   bool Write(void) const;
@@ -192,8 +192,9 @@ class cMarks : public cConfig<cMark> {
 private:
   cString fileName;
   double framesPerSecond;
-  time_t lastUpdate;
+  time_t nextUpdate;
   time_t lastFileTime;
+  time_t lastChange;
 public:
   bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false);
   bool Update(void);
index 048b98c..cd3a758 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -4,11 +4,13 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remote.c 2.2 2010/12/24 15:26:05 kls Exp $
+ * $Id: remote.c 2.3 2011/03/27 15:03:36 kls Exp $
  */
 
 #include "remote.h"
 #include <fcntl.h>
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
 #include <netinet/in.h>
 #include <string.h>
 #include <sys/types.h>
@@ -122,7 +124,7 @@ bool cRemote::PutMacro(eKeys Key)
 bool cRemote::Put(uint64_t Code, bool Repeat, bool Release)
 {
   char buffer[32];
-  snprintf(buffer, sizeof(buffer), "%016llX", Code);
+  snprintf(buffer, sizeof(buffer), "%016"PRIX64, Code);
   return Put(buffer, Repeat, Release);
 }
 
diff --git a/remux.c b/remux.c
index f7ad86d..f7ef87a 100644 (file)
--- a/remux.c
+++ b/remux.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remux.c 2.51 2011/02/26 15:51:04 kls Exp $
+ * $Id: remux.c 2.53 2011/03/20 10:21:14 kls Exp $
  */
 
 #include "remux.h"
@@ -783,9 +783,11 @@ cFrameDetector::cFrameDetector(int Pid, int Type)
   synced = false;
   newFrame = independentFrame = false;
   numPtsValues = 0;
+  numFrames = 0;
   numIFrames = 0;
   framesPerSecond = 0;
   framesInPayloadUnit = framesPerPayloadUnit = 0;
+  payloadUnitOfFrame = 0;
   scanning = false;
   scanner = EMPTY_SCANNER;
 }
@@ -807,6 +809,7 @@ void cFrameDetector::SetPid(int Pid, int Type)
 void cFrameDetector::Reset(void)
 {
   newFrame = independentFrame = false;
+  payloadUnitOfFrame = 0;
   scanning = false;
   scanner = EMPTY_SCANNER;
 }
@@ -833,7 +836,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                     return Processed;
                  if (Length < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE)
                     return Processed; // need more data, in case the frame type is not stored in the first TS packet
-                 if (!framesPerSecond) {
+                 if (framesPerSecond <= 0.0) {
                     // frame rate unknown, so collect a sequence of PTS values:
                     if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
                        const uchar *Pes = Data + TsPayloadOffset(Data);
@@ -844,6 +847,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                              dbgframes("#");
                              numPtsValues = 0;
                              numIFrames = 0;
+                             numFrames = 0;
                              }
                           else
                              numPtsValues++;
@@ -863,10 +867,23 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                              framesPerSecond = 25.0;
                           else if (Delta % 3003 == 0)
                              framesPerSecond = 30.0 / 1.001;
-                          else if (abs(Delta - 1800) <= 1)
-                             framesPerSecond = 50.0;
+                          else if (abs(Delta - 1800) <= 1) {
+                             if (numFrames > 50) {
+                                // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
+                                framesPerSecond = 25.0;
+                                framesPerPayloadUnit = -2;
+                                }
+                             else
+                                framesPerSecond = 50.0;
+                             }
                           else if (Delta == 1501)
-                             framesPerSecond = 60.0 / 1.001;
+                             if (numFrames > 50) {
+                                // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
+                                framesPerSecond = 30.0 / 1.001;
+                                framesPerPayloadUnit = -2;
+                                }
+                             else
+                                framesPerSecond = 60.0 / 1.001;
                           else {
                              framesPerSecond = 25.0;
                              dsyslog("unknown frame delta (%d), assuming 25 fps", Delta);
@@ -874,7 +891,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                           }
                        else // audio
                           framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing
-                       dbgframes("\nDelta = %d  FPS = %5.2f  FPPU = %d\n", Delta, framesPerSecond, framesPerPayloadUnit);
+                       dbgframes("\nDelta = %d  FPS = %5.2f  FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numFrames);
                        }
                     }
                  scanner = EMPTY_SCANNER;
@@ -909,6 +926,8 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                                   framesInPayloadUnit++;
                                   if (independentFrame)
                                      numIFrames++;
+                                  if (numIFrames == 1)
+                                     numFrames++;
                                   dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
                                   }
                                if (synced)
@@ -923,6 +942,13 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                                newFrame = true;
                                independentFrame = Data[i + 1] == 0x10;
                                if (synced) {
+                                  if (framesPerPayloadUnit < 0) {
+                                     payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
+                                     if (payloadUnitOfFrame != 0 && independentFrame)
+                                        payloadUnitOfFrame = 0;
+                                     if (payloadUnitOfFrame)
+                                        newFrame = false;
+                                     }
                                   if (framesPerPayloadUnit <= 1)
                                      scanning = false;
                                   }
@@ -930,6 +956,8 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                                   framesInPayloadUnit++;
                                   if (independentFrame)
                                      numIFrames++;
+                                  if (numIFrames == 1)
+                                     numFrames++;
                                   dbgframes("%02X ", Data[i + 1]);
                                   }
                                if (synced)
@@ -953,9 +981,9 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
                                 pid = 0; // let's just ignore any further data
                        }
                      }
-                 if (!synced && framesPerSecond && independentFrame) {
+                 if (!synced && framesPerSecond > 0.0 && independentFrame) {
                     synced = true;
-                    dbgframes("*");
+                    dbgframes("*\n");
                     Reset();
                     return Processed + TS_SIZE;
                     }
diff --git a/remux.h b/remux.h
index 7140aaf..60a9a57 100644 (file)
--- a/remux.h
+++ b/remux.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remux.h 2.27 2010/11/01 11:24:20 kls Exp $
+ * $Id: remux.h 2.28 2011/03/19 16:52:46 kls Exp $
  */
 
 #ifndef __REMUX_H
@@ -345,12 +345,15 @@ private:
   bool independentFrame;
   uint32_t ptsValues[MaxPtsValues]; // 32 bit is enough - we only need the delta
   int numPtsValues;
+  int numFrames;
   int numIFrames;
   bool isVideo;
   double framesPerSecond;
   int framesInPayloadUnit;
   int framesPerPayloadUnit; // Some broadcasters send one frame per payload unit (== 1),
-                            // while others put an entire GOP into one payload unit (> 1).
+                            // some put an entire GOP into one payload unit (> 1), and
+                            // some spread a single frame over several payload units (< 0).
+  int payloadUnitOfFrame;
   bool scanning;
   uint32_t scanner;
 public:
index ebc2f04..2f6fd87 100755 (executable)
@@ -20,7 +20,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: runvdr.template 2.1 2010/01/17 12:39:27 kls Exp $
+# $Id: runvdr.template 2.2 2011/04/17 12:34:30 kls Exp $
 
 VDRPRG="./vdr"
 
@@ -30,8 +30,12 @@ VDROPTIONS="-w 60"
 VDRPLUGINS=""
 # You will need to select your output device plugin if you want
 # to use VDR to watch video. For instance, for a "Full Featured"
-# DVB card that would be
+# SD DVB card that would be
 # VDRPLUGINS="-P dvbsddevice"
+# For a "Full Featured" HD DVB card you could use
+# VDRPLUGINS="-P dvbhddevice"
+# There are also other output device plugins available, see
+# http://www.vdr-wiki.de/wiki/index.php/Plugins.
 
 VDRCMD="$VDRPRG $VDROPTIONS $VDRPLUGINS $*"
 
diff --git a/tools.c b/tools.c
index d03595e..ab7fe96 100644 (file)
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.c 2.12 2011/02/25 14:58:31 kls Exp $
+ * $Id: tools.c 2.13 2011/03/20 12:07:18 kls Exp $
  */
 
 #include "tools.h"
@@ -1575,9 +1575,9 @@ ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
      cachedstart = min(cachedstart, curpos);
 #endif
      ssize_t bytesRead = safe_read(fd, Data, Size);
-#ifdef USE_FADVISE
      if (bytesRead > 0) {
         curpos += bytesRead;
+#ifdef USE_FADVISE
         cachedend = max(cachedend, curpos);
 
         // Read ahead:
@@ -1597,8 +1597,9 @@ ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
            }
         else
            ahead = curpos; // jumped -> we really don't want any readahead, otherwise e.g. fast-rewind gets in trouble.
+#endif
         }
-
+#ifdef USE_FADVISE
      if (cachedstart < cachedend) {
         if (curpos - cachedstart > READCHUNK * 2) {
            // current position has moved forward enough, shrink tail window.
diff --git a/vdr.5 b/vdr.5
index ce15215..6274c1a 100644 (file)
--- a/vdr.5
+++ b/vdr.5
@@ -8,7 +8,7 @@
 .\" License as specified in the file COPYING that comes with the
 .\" vdr distribution.
 .\"
-.\" $Id: vdr.5 2.21 2010/12/24 15:19:21 kls Exp $
+.\" $Id: vdr.5 2.22 2011/04/03 10:21:36 kls Exp $
 .\"
 .TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
 .SH NAME
@@ -807,7 +807,7 @@ l l.
 <description>  @is the description of the event (any '|' characters will be interpreted as newlines)
 <genre>        @is a two digit hex code, as defined in  ETSI EN 300 468, table 28 (up to 4 genre codes are supported)
 <parental rating>@is the minimum age of the intended audience
-<stream>       @is the stream content (1 = video, 2 = audio, 3 = subtitles, 4 = AC3)
+<stream>       @is the stream content (1 = MPEG2 video, 2 = MP2 audio, 3 = subtitles, 4 = AC3 audio, 5 = H.264 video, 6 = HEAAC audio)
 <type>         @is the stream type according to ETSI EN 300 468
 <language>     @is the three letter language code (optionally two codes, separated by '+')
 <descr>        @is the description of this stream component