added new vdr-plugin-vnsiserver - uploaded2-3-vdr-stable-PPA
authormango <mango@mail.com>
Fri, 7 Dec 2018 14:33:15 +0000 (15:33 +0100)
committermango <mango@mail.com>
Fri, 7 Dec 2018 14:33:15 +0000 (15:33 +0100)
93 files changed:
v/vdr-plugin-vnsiserver-1.8.0/.gitignore [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/.pc/.quilt_patches [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/.pc/.quilt_series [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/.pc/.version [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/.pc/applied-patches [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/.pc/extend_allowed_hosts.conf/vnsiserver/allowed_hosts.conf [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/COPYING [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/HISTORY [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/Makefile [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/README [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/bitstream.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/bitstream.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/channelfilter.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/channelfilter.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/channelscancontrol.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/channelscancontrol.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/config.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/config.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/cxsocket.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/cxsocket.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/changelog [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/compat [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/control [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/copyright [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/dirs [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/docs [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/install [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/links [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/patches/extend_allowed_hosts.conf [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/patches/series [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/plugin.vnsiserver.conf [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/postinst [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/rules [new file with mode: 0755]
v/vdr-plugin-vnsiserver-1.8.0/debian/source/format [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/debian/source/options [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/demuxer.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/demuxer.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/hash.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/hash.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_AAC.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_AAC.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_AC3.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_AC3.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_DTS.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_DTS.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGAudio.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGAudio.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGVideo.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGVideo.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_Subtitle.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_Subtitle.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_Teletext.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_Teletext.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_h264.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_h264.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_hevc.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/parser_hevc.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/po/de_DE.po [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/po/lt_LT.po [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/recordingscache.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/recordingscache.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/recplayer.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/recplayer.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/requestpacket.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/requestpacket.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/responsepacket.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/responsepacket.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/setup.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/setup.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/status.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/status.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/streamer.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/streamer.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/videobuffer.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/videobuffer.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/videoinput.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/videoinput.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsi.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsi.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsiclient.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsiclient.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsicommand.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsiosd.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsiosd.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsiserver.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsiserver.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsiserver/allowed_hosts.conf [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsitimer.c [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/vnsitimer.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver-1.8.0/wirbelscan_services.h [new file with mode: 0644]
v/vdr-plugin-vnsiserver_1.8.0.orig.tar.xz [new file with mode: 0644]

diff --git a/v/vdr-plugin-vnsiserver-1.8.0/.gitignore b/v/vdr-plugin-vnsiserver-1.8.0/.gitignore
new file mode 100644 (file)
index 0000000..d6cbfea
--- /dev/null
@@ -0,0 +1,12 @@
+.dependencies
+*.o
+*.so
+*~
+po/*.pot
+po/*.mo
+.kdev4/
+
+# Don't add patch files
+*.diff
+*.patch
+*.orig
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/.pc/.quilt_patches b/v/vdr-plugin-vnsiserver-1.8.0/.pc/.quilt_patches
new file mode 100644 (file)
index 0000000..6857a8d
--- /dev/null
@@ -0,0 +1 @@
+debian/patches
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/.pc/.quilt_series b/v/vdr-plugin-vnsiserver-1.8.0/.pc/.quilt_series
new file mode 100644 (file)
index 0000000..c206706
--- /dev/null
@@ -0,0 +1 @@
+series
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/.pc/.version b/v/vdr-plugin-vnsiserver-1.8.0/.pc/.version
new file mode 100644 (file)
index 0000000..0cfbf08
--- /dev/null
@@ -0,0 +1 @@
+2
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/.pc/applied-patches b/v/vdr-plugin-vnsiserver-1.8.0/.pc/applied-patches
new file mode 100644 (file)
index 0000000..8e39e3a
--- /dev/null
@@ -0,0 +1,2 @@
+extend_allowed_hosts.conf
+fix-encoding.patch
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/.pc/extend_allowed_hosts.conf/vnsiserver/allowed_hosts.conf b/v/vdr-plugin-vnsiserver-1.8.0/.pc/extend_allowed_hosts.conf/vnsiserver/allowed_hosts.conf
new file mode 100644 (file)
index 0000000..07a7c49
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# allowed_hosts.conf  This file describes a number of host addresses that
+#                     are allowed to connect to the streamdev server running 
+#                     with the Video Disk Recorder (VDR) on this system.
+# Syntax:
+#
+# IP-Address[/Netmask]
+#
+
+127.0.0.1             # always accept localhost
+192.168.0.0/24        # any host on the local net
+#204.152.189.113      # a specific host
+#0.0.0.0/0            # any host on any net (USE THIS WITH CARE!)
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/COPYING b/v/vdr-plugin-vnsiserver-1.8.0/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    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/v/vdr-plugin-vnsiserver-1.8.0/HISTORY b/v/vdr-plugin-vnsiserver-1.8.0/HISTORY
new file mode 100644 (file)
index 0000000..eb1c5fe
--- /dev/null
@@ -0,0 +1,100 @@
+VDR Plugin 'vnsiserver' Revision History
+----------------------------------------
+
+2018-10-19: Version 1.8.0
+
+- see gibhub history
+
+2018-05-01: Version 1.6.0
+
+- protocol 12 with stream times for timeshift
+- EDL: choose between scenes, comskips and cuts
+- Signal info: use DVB5 API if possible
+- see github history
+
+2017-01-14: Version 1.5.2
+
+- group recordings
+- fixes for epg updates
+- fixes for searchtimers
+- see github history
+
+2016-09-25: Version 1.5.1
+
+- see github history for fixes
+- added new setup parameter DisableCamBlacklist:
+  avoids a VDR hard-coded 15 seconds timeout if tuning failed due to hard-coded scramble timeout
+
+2016-08-01: Version 1.5.0
+
+- support for vdr 2.3.1
+- add epg search timers
+- support for h265 (hevc)
+- fix PID change
+- fixes and improvements for handling of CAMs
+- see github history for other fixes
+
+2015-09-18: Version 1.3.0
+
+- add support for undelete recordings
+- add support for rds data if present on dvb radio and send to addon if supported there
+- Update support for wirbelscan plugin
+- Rework Licence files to use KODI
+- Improved README
+- Fix possible seq fault in void cRecPlayer::reScan()
+- fix picons for western 
+- make avoid EPG scan while streaming default
+- see github history for other fixes
+
+2015-01-25: Version 1.2.1
+
+- add cmd line switch for setting tcp port
+- fix potential segfault on stop streaming
+- stop triggering epg updates if client does not fetch epg
+
+2014-09-03: Version 1.2.0
+
+- add cmd line switch "-d". if set, vnsi creates a dummy dvb device which makes femon work 
+  on all channels
+- add setup parameter AvoidEPGScan. if set to 1, vnsi disables EPG scan while streaming.
+  EPG scan during streaming can lead to artifacs on some dual tuner cards.
+- fix div by zero on AAC audio, thanks to Jakob Sloth Jepsen
+
+2014-03-20: Version 1.1.0
+
+- add support for picons
+- add setup paramter to select if current recording should start when tuning to a channel
+- only activate AAC mux workaround if environment variable VNSI_AAC_MUXMODE is set
+- bump max timshift buffer RAM to 8 gig
+
+2014-03-20: Version 1.0.0
+
+- release 1.0
+- various fixes
+- remove suffix from plugin name vnsiserver5 -> vnsiserver
+
+2014-01-08: Version 0.9.4
+
+- update length of recorings in progress
+  while playing
+
+2013-12-04: Version 0.9.3
+
+- add support for EDL (marks)
+- add channel filter
+- send buffer times for timeshift
+- bump protocol to XBMC to 5
+- suffix plugin with version of protocol: vnsiserver5
+- this version is compatible with XBMC 13
+
+2013-02-03: Version 0.9.1
+
+- most parts of the plugin rewritten
+- revised parsers
+- proper handling of PMT changes
+- suffix plugin with version of protocol: vnsiserver3
+- this version is compatible with XBMC 12.0
+
+2010-03-23: Version 0.0.1
+
+- Initial revision.
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/Makefile b/v/vdr-plugin-vnsiserver-1.8.0/Makefile
new file mode 100644 (file)
index 0000000..660df05
--- /dev/null
@@ -0,0 +1,145 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id$
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+
+PLUGIN = vnsiserver
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' vnsi.h | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The directory environment:
+
+# Use package data if installed...otherwise assume we're under the VDR source directory:
+PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
+LIBDIR ?= $(call PKGCFG,libdir)
+LOCDIR = $(call PKGCFG,locdir)
+PLGCFG = $(call PKGCFG,plgcfg)
+#
+TMPDIR ?= /tmp
+
+### The compiler options:
+
+export CFLAGS   = $(call PKGCFG,cflags)
+export CXXFLAGS = $(call PKGCFG,cxxflags)
+
+### The version number of VDR's plugin API:
+
+APIVERSION = $(call PKGCFG,apiversion)
+ifeq ($(strip $(APIVERSION)),)
+APIVERSION = $(shell grep 'define APIVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+NOCONFIG := 1
+endif
+
+### Allow user defined options to overwrite defaults:
+
+-include $(PLGCFG)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### The name of the shared object file:
+
+SOFILE = libvdr-$(PLUGIN).so
+
+### Includes and Defines (add further entries here):
+
+ifdef API1733
+INCLUDES += -I$(VDRSRC)/include
+endif
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DVNSI_SERVER_VERSION='"$(VERSION)"'
+CXXFLAGS += -std=c++11
+export CXXFLAGS
+
+ifeq ($(DEBUG),1)
+DEFINES += -DDEBUG
+endif
+
+### The object files (add further files here):
+
+OBJS = vnsi.o bitstream.o vnsiclient.o channelscancontrol.o config.o cxsocket.o parser.o parser_AAC.o \
+       parser_AC3.o parser_DTS.o parser_h264.o parser_hevc.o parser_MPEGAudio.o parser_MPEGVideo.o \
+       parser_Subtitle.o parser_Teletext.o streamer.o recplayer.o requestpacket.o responsepacket.o \
+       vnsiserver.o hash.o recordingscache.o setup.o vnsiosd.o demuxer.o videobuffer.o \
+       videoinput.o channelfilter.o status.o vnsitimer.o
+
+### The main target:
+
+ifdef API1733
+all: install-lib
+else
+all: $(SOFILE)
+endif
+#
+
+### Implicit rules:
+
+%.o: %.c
+       $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+       @$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR     = po
+I18Npo    = $(wildcard $(PODIR)/*.po)
+I18Nmo    = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
+I18Nmsgs  = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot   = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+       msgfmt -c -o $@ $<
+
+$(I18Npot): $(wildcard *.c)
+       xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+
+%.po: $(I18Npot)
+       msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+       @touch $@
+
+$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+       install -D -m644 $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmo) $(I18Npot)
+
+install-i18n: $(I18Nmsgs)
+
+### Targets:
+
+$(SOFILE): $(OBJS)
+       $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+
+install-lib: $(SOFILE)
+       install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
+
+install: install-lib install-i18n
+
+dist: $(I18Npo) clean
+       @-rm -rf $(TMPDIR)/$(ARCHIVE)
+       @mkdir $(TMPDIR)/$(ARCHIVE)
+       @cp -a * $(TMPDIR)/$(ARCHIVE)
+       @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+       @-rm -rf $(TMPDIR)/$(ARCHIVE)
+       @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+       @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot
+       @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
+
+compile: $(SOFILE)
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/README b/v/vdr-plugin-vnsiserver-1.8.0/README
new file mode 100644 (file)
index 0000000..d8155a9
--- /dev/null
@@ -0,0 +1,47 @@
+
+-----------------------------------------------------------------------------
+1. Introduction
+-----------------------------------------------------------------------------
+
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+VDR plugin to handle KODI clients.
+The vdr-plugin-vnsiserver is able to handle serveral KODI clients connecting
+via the VNSI addon.
+
+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.
+
+Latest version available at: 
+https://github.com/FernetMenta/vdr-plugin-vnsiserver
+
+-----------------------------------------------------------------------------
+2. Compile in VDR's source tree
+-----------------------------------------------------------------------------
+
+Get VDR sources.
+
+   $ cd <path to vdr>/PLUGINS/src
+   $ git clone https://github.com/FernetMenta/vdr-plugin-vnsiserver
+   $ ln -s vdr-plugin-vnsiserver vnsiserver
+
+On newer VDR Versions (2.2.0) plugin can be build and installed alone, use:
+
+   $ git clone https://github.com/FernetMenta/vdr-plugin-vnsiserver
+   $ cd vdr-plugin-vnsiserver
+   $ make
+   $ sudo make install
+
+If you want to fix install dir you can use this, where the end define the VDR
+library folder:
+
+   $ sudo make install LIBDIR=/usr/lib/vdr
+
+-----------------------------------------------------------------------------
+3. Help and Suppport
+-----------------------------------------------------------------------------
+
+http://forum.kodi.tv/forumdisplay.php?fid=169
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/bitstream.c b/v/vdr-plugin-vnsiserver-1.8.0/bitstream.c
new file mode 100644 (file)
index 0000000..60ee244
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "bitstream.h"
+
+void cBitstream::skipBits(unsigned int num)
+{
+  if (m_doEP3)
+  {
+    register unsigned int tmp;
+
+    while (num)
+    {
+      tmp = m_offset >> 3;
+      if (!(m_offset & 7) && (m_data[tmp--] == 3) && (m_data[tmp--] == 0) && (m_data[tmp] == 0))
+        m_offset += 8;   // skip EP3 byte
+
+      if (!(m_offset & 7) && (num >= 8)) // byte boundary, speed up things a little bit
+      {
+        m_offset += 8;
+        num -= 8;
+      }
+      else if ((tmp = 8-(m_offset & 7)) <= num) // jump to byte boundary
+      {
+        m_offset += tmp;
+        num -= tmp;
+      }
+      else
+      {
+        m_offset += num;
+         num = 0;
+      }
+
+      if (m_offset >= m_len)
+      {
+        m_error = true;
+        break;
+      }
+    }
+
+    return;
+  }
+
+  m_offset += num;
+}
+
+unsigned int cBitstream::readBits(int num)
+{
+  unsigned int r = 0;
+
+  while(num > 0)
+  {
+    if (m_doEP3)
+    {
+      size_t tmp = m_offset >> 3;
+      if (!(m_offset & 7) && (m_data[tmp--] == 3) && (m_data[tmp--] == 0) && (m_data[tmp] == 0))
+        m_offset += 8;   // skip EP3 byte
+    }
+
+    if(m_offset >= m_len)
+    {
+      m_error = true;
+      return 0;
+    }
+
+    num--;
+
+    if(m_data[m_offset / 8] & (1 << (7 - (m_offset & 7))))
+      r |= 1 << num;
+
+    m_offset++;
+  }
+  return r;
+}
+
+unsigned int cBitstream::showBits(int num)
+{
+  unsigned int r = 0;
+  size_t offs = m_offset;
+
+  while(num > 0)
+  {
+    if(offs >= m_len)
+    {
+      m_error = true;
+      return 0;
+    }
+
+    num--;
+
+    if(m_data[offs / 8] & (1 << (7 - (offs & 7))))
+      r |= 1 << num;
+
+    offs++;
+  }
+  return r;
+}
+
+unsigned int cBitstream::readGolombUE(int maxbits)
+{
+  int lzb = -1;
+  int bits = 0;
+
+  for(int b = 0; !b; lzb++, bits++)
+  {
+    if (bits > maxbits)
+      return 0;
+    b = readBits1();
+  }
+
+  return (1 << lzb) - 1 + readBits(lzb);
+}
+
+signed int cBitstream::readGolombSE()
+{
+  int v, pos;
+  v = readGolombUE();
+  if(v == 0)
+    return 0;
+
+  pos = (v & 1);
+  v = (v + 1) >> 1;
+  return pos ? v : -v;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/bitstream.h b/v/vdr-plugin-vnsiserver-1.8.0/bitstream.h
new file mode 100644 (file)
index 0000000..c589654
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_BITSTREAM_H
+#define VNSI_BITSTREAM_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+class cBitstream
+{
+private:
+  uint8_t *const m_data;
+  size_t   m_offset = 0;
+  const size_t m_len;
+  bool     m_error = false;
+  const bool m_doEP3 = false;
+
+public:
+  constexpr cBitstream(uint8_t *data, size_t bits)
+    :m_data(data), m_len(bits)
+  {
+  }
+
+  // this is a bitstream that has embedded emulation_prevention_three_byte
+  // sequences that need to be removed as used in HECV.
+  // Data must start at byte 2
+  constexpr cBitstream(uint8_t *data, size_t bits, bool doEP3)
+    :m_data(data),
+     m_offset(16), // skip header and use as sentinel for EP3 detection
+     m_len(bits),
+     m_doEP3(true)
+  {
+  }
+
+  void skipBits(unsigned int num);
+  unsigned int readBits(int num);
+  unsigned int showBits(int num);
+  unsigned int readBits1() { return readBits(1); }
+  unsigned int readGolombUE(int maxbits = 32);
+  signed int readGolombSE();
+  constexpr size_t length() const { return m_len; }
+  constexpr bool isError() const { return m_error; }
+};
+
+#endif // VNSI_BITSTREAM_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/channelfilter.c b/v/vdr-plugin-vnsiserver-1.8.0/channelfilter.c
new file mode 100644 (file)
index 0000000..2cd2901
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2013 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "channelfilter.h"
+#include "config.h"
+#include "hash.h"
+#include <string>
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <vdr/tools.h>
+
+cVNSIProvider::cVNSIProvider()
+  :m_caid(0)
+{
+
+}
+
+cVNSIProvider::cVNSIProvider(const cVNSIProvider &provider)
+  :m_name(provider.m_name), m_caid(provider.m_caid)
+{
+}
+
+cVNSIProvider::cVNSIProvider(std::string name, int caid)
+  :m_name(name), m_caid(caid)
+{
+};
+
+bool cVNSIProvider::operator==(const cVNSIProvider &rhs) const
+{
+  if (rhs.m_caid != m_caid)
+    return false;
+  if (m_name.empty())
+    return false;
+  if (rhs.m_name.compare(m_name) != 0)
+    return false;
+  return true;
+}
+
+
+bool cVNSIChannelFilter::IsRadio(const cChannel* channel)
+{
+  bool isRadio = false;
+
+  // assume channels without VPID & APID are video channels
+  if (channel->Vpid() == 0 && channel->Apid(0) == 0)
+    isRadio = false;
+  // channels without VPID are radio channels (channels with VPID 1 are encrypted radio channels)
+  else if (channel->Vpid() == 0 || channel->Vpid() == 1 || channel->Rid() == 1)
+    isRadio = true;
+
+  return isRadio;
+}
+
+void cVNSIChannelFilter::Load()
+{
+  cMutexLock lock(&m_Mutex);
+
+  cString filename;
+  std::string line;
+  std::ifstream rfile;
+
+  filename = cString::sprintf("%s/videowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+  m_providersVideo.clear();
+  rfile.open(filename);
+  if (rfile.is_open())
+  {
+    while(std::getline(rfile,line))
+    {
+      cVNSIProvider provider;
+      size_t pos = line.find("|");
+      if(pos == line.npos)
+      {
+        provider.m_name = line;
+      }
+      else
+      {
+        provider.m_name.assign(line, 0, pos);
+        provider.m_caid = strtol(line.c_str() + pos + 1, nullptr, 10);
+      }
+      auto p_it = std::find(m_providersVideo.begin(), m_providersVideo.end(), provider);
+      if(p_it == m_providersVideo.end())
+      {
+        m_providersVideo.emplace_back(std::move(provider));
+      }
+    }
+    rfile.close();
+  }
+
+  filename = cString::sprintf("%s/radiowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+  rfile.open(filename);
+  m_providersRadio.clear();
+  if (rfile.is_open())
+  {
+    while(std::getline(rfile,line))
+    {
+      cVNSIProvider provider;
+      auto pos = line.find("|");
+      if(pos == line.npos)
+      {
+        provider.m_name = line;
+      }
+      else
+      {
+        provider.m_name.assign(line, 0, pos);
+        provider.m_caid = strtol(line.c_str() + pos + 1, nullptr, 10);
+      }
+      auto p_it = std::find(m_providersRadio.begin(), m_providersRadio.end(), provider);
+      if(p_it == m_providersRadio.end())
+      {
+        m_providersRadio.emplace_back(std::move(provider));
+      }
+    }
+    rfile.close();
+  }
+
+  filename = cString::sprintf("%s/videoblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+  rfile.open(filename);
+  m_channelsVideo.clear();
+  if (rfile.is_open())
+  {
+    while(getline(rfile,line))
+    {
+      int id = strtol(line.c_str(), nullptr, 10);
+      m_channelsVideo.insert(id);
+    }
+    rfile.close();
+  }
+
+  filename = cString::sprintf("%s/radioblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+  rfile.open(filename);
+  m_channelsRadio.clear();
+  if (rfile.is_open())
+  {
+    while(getline(rfile,line))
+    {
+      int id = strtol(line.c_str(), nullptr, 10);
+      m_channelsRadio.insert(id);
+    }
+    rfile.close();
+  }
+}
+
+void cVNSIChannelFilter::StoreWhitelist(bool radio)
+{
+  {
+    cMutexLock lock(&m_Mutex);
+
+    cString filename;
+    std::ofstream wfile;
+    std::vector<cVNSIProvider> *whitelist;
+
+    if (radio)
+    {
+      filename = cString::sprintf("%s/radiowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+      whitelist = &m_providersRadio;
+    }
+    else
+    {
+      filename = cString::sprintf("%s/videowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+      whitelist = &m_providersVideo;
+    }
+
+    wfile.open(filename);
+    if(wfile.is_open())
+    {
+      for (const auto i : *whitelist)
+      {
+        wfile << i.m_name << '|' << i.m_caid << '\n';
+      }
+      wfile.close();
+    }
+  }
+
+  SortChannels();
+}
+
+void cVNSIChannelFilter::StoreBlacklist(bool radio)
+{
+  {
+    cMutexLock lock(&m_Mutex);
+
+    cString filename;
+    std::ofstream wfile;
+    std::set<int> *blacklist;
+
+    if (radio)
+    {
+      filename = cString::sprintf("%s/radioblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+      blacklist = &m_channelsRadio;
+    }
+    else
+    {
+      filename = cString::sprintf("%s/videoblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+      blacklist = &m_channelsVideo;
+    }
+
+    wfile.open(filename);
+    if(wfile.is_open())
+    {
+      for (const auto i : *blacklist)
+      {
+        wfile << i << '\n';
+      }
+      wfile.close();
+    }
+  }
+
+  SortChannels();
+}
+
+bool cVNSIChannelFilter::IsWhitelist(const cChannel &channel)
+{
+  cVNSIProvider provider;
+  std::vector<cVNSIProvider> *providers;
+  provider.m_name = channel.Provider();
+
+  if (IsRadio(&channel))
+    providers = &m_providersRadio;
+  else
+    providers = &m_providersVideo;
+
+  if(providers->empty())
+    return true;
+
+  if (channel.Ca(0) == 0)
+  {
+    provider.m_caid = 0;
+    auto p_it = std::find(providers->begin(), providers->end(), provider);
+    if(p_it!=providers->end())
+      return true;
+    else
+      return false;
+  }
+
+  int caid;
+  int idx = 0;
+  while((caid = channel.Ca(idx)) != 0)
+  {
+    provider.m_caid = caid;
+    auto p_it = std::find(providers->begin(), providers->end(), provider);
+    if(p_it!=providers->end())
+      return true;
+
+    idx++;
+  }
+  return false;
+}
+
+bool cVNSIChannelFilter::PassFilter(const cChannel &channel)
+{
+  cMutexLock lock(&m_Mutex);
+
+  if(channel.GroupSep())
+    return true;
+
+  if (!IsWhitelist(channel))
+    return false;
+
+  if (IsRadio(&channel))
+  {
+    auto it = std::find(m_channelsRadio.begin(), m_channelsRadio.end(), CreateChannelUID(&channel));
+    if(it!=m_channelsRadio.end())
+      return false;
+  }
+  else
+  {
+    auto it = std::find(m_channelsVideo.begin(), m_channelsVideo.end(), CreateChannelUID(&channel));
+    if(it!=m_channelsVideo.end())
+      return false;
+  }
+
+  return true;
+}
+
+void cVNSIChannelFilter::SortChannels()
+{
+#if VDRVERSNUM >= 20301
+  LOCK_CHANNELS_WRITE;
+  for (cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
+#else
+  Channels.IncBeingEdited();
+  Channels.Lock(true);
+  for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+#endif
+  {
+    if(!PassFilter(*channel))
+    {
+#if VDRVERSNUM >= 20301
+      for (cChannel *whitechan = Channels->Next(channel); whitechan; whitechan = Channels->Next(whitechan))
+#else
+      for (cChannel *whitechan = Channels.Next(channel); whitechan; whitechan = Channels.Next(whitechan))
+#endif
+      {
+        if(PassFilter(*whitechan))
+        {
+#if VDRVERSNUM >= 20301
+          Channels->Move(whitechan, channel);
+#else
+          Channels.Move(whitechan, channel);
+#endif
+          channel = whitechan;
+          break;
+        }
+      }
+    }
+  }
+
+#if VDRVERSNUM >= 20301
+  Channels->SetModifiedByUser();
+#else
+  Channels.SetModified(true);
+  Channels.Unlock();
+  Channels.DecBeingEdited();
+#endif
+}
+
+cVNSIChannelFilter VNSIChannelFilter;
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/channelfilter.h b/v/vdr-plugin-vnsiserver-1.8.0/channelfilter.h
new file mode 100644 (file)
index 0000000..3d9dd28
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2013 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <set>
+#include <vdr/thread.h>
+#include <vdr/channels.h>
+
+class cVNSIProvider
+{
+public:
+  cVNSIProvider();
+  cVNSIProvider(std::string name, int caid);
+  cVNSIProvider(const cVNSIProvider &provider);
+  bool operator==(const cVNSIProvider &rhs) const;
+  std::string m_name;
+  int m_caid;
+};
+
+class cVNSIChannelFilter
+{
+public:
+  void Load();
+  void StoreWhitelist(bool radio);
+  void StoreBlacklist(bool radio);
+  bool IsWhitelist(const cChannel &channel);
+  bool PassFilter(const cChannel &channel);
+  void SortChannels();
+  static bool IsRadio(const cChannel* channel);
+  std::vector<cVNSIProvider> m_providersVideo;
+  std::vector<cVNSIProvider> m_providersRadio;
+  std::set<int> m_channelsVideo;
+  std::set<int> m_channelsRadio;
+  cMutex m_Mutex;
+};
+
+extern cVNSIChannelFilter VNSIChannelFilter;
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/channelscancontrol.c b/v/vdr-plugin-vnsiserver-1.8.0/channelscancontrol.c
new file mode 100644 (file)
index 0000000..7ca2d4c
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2010,2015 Alwin Esch (Team KODI)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "channelscancontrol.h"
+#include "vnsiclient.h"
+
+#include <vdr/menu.h>
+#include <vdr/status.h>
+
+using namespace WIRBELSCAN_SERVICE;
+
+/*!
+ * versions definitions
+ */
+#define MIN_CMDVERSION     1    // command api 0001
+#define MIN_STATUSVERSION  1    // query status
+#define MIN_SETUPVERSION   1    // get/put setup, GetSetup#XXXX/SetSetup#XXXX
+#define MIN_COUNTRYVERSION 1    // get list of country IDs and Names
+#define MIN_SATVERSION     1    // get list of sat IDs and Names
+#define MIN_USERVERSION    1    // scan user defined transponder
+
+#define SCAN_TV        ( 1 << 0 )
+#define SCAN_RADIO     ( 1 << 1 )
+#define SCAN_FTA       ( 1 << 2 )
+#define SCAN_SCRAMBLED ( 1 << 3 )
+#define SCAN_HD        ( 1 << 4 )
+
+/*!
+ * macro definitions
+ */
+#define SETSCAN  0
+#define SCANNING 1
+#define SCANDONE 2
+#define CHECKVERSION(a,b,c) p=strchr((char *) m_scanInformation->a,'#') + 1; sscanf(p,"%d ",&version); if (version < b) c = true;
+#define CHECKLIMITS(a,v,_min,_max,_def) a=v; if ((a<_min) || (a>_max)) a=_def;
+
+CScanControl::CScanControl(cVNSIClient *client)
+  : m_client(client),
+    m_isChecked(false),
+    m_isNotSupported(true),
+    m_channelScanPlugin(NULL),
+    m_singleScan(0),
+    m_cbuf(NULL),
+    m_sbuf(NULL),
+    m_scanInformation(NULL)
+{
+}
+
+CScanControl::~CScanControl()
+{
+  delete m_scanInformation;
+  free(m_cbuf);
+  free(m_sbuf);
+}
+
+bool CScanControl::IsSupported()
+{
+  if (!m_isChecked)
+    LoadScanner();
+
+  return !m_isNotSupported;
+}
+
+bool CScanControl::LoadScanner()
+{
+  /*!
+   * Plugin present?
+   */
+  m_channelScanPlugin = cPluginManager::GetPlugin("wirbelscan");
+  if (m_channelScanPlugin == NULL)
+    return false;
+
+  /*!
+   * This plugin version compatibel to wirbelscan?
+   */
+  char *p;
+  m_scanInformation = new cWirbelscanInfo;
+  if (asprintf(&p, "%s%s", SPlugin, SInfo) < 0 ||
+      !m_channelScanPlugin->Service("wirbelscan_GetVersion", m_scanInformation))
+  {
+    m_client->OsdStatusMessage(*cString::sprintf("%s", tr("Your scanner version doesnt support services - Please upgrade.")));
+    free(p);
+    return false;
+  }
+  free(p);
+
+  int version = 0;
+  m_isNotSupported = false;
+  CHECKVERSION(CommandVersion,MIN_CMDVERSION,     m_isNotSupported);
+  CHECKVERSION(StatusVersion, MIN_STATUSVERSION,  m_isNotSupported);
+  CHECKVERSION(SetupVersion,  MIN_SETUPVERSION,   m_isNotSupported);
+  CHECKVERSION(CountryVersion,MIN_COUNTRYVERSION, m_isNotSupported);
+  CHECKVERSION(SatVersion,    MIN_SATVERSION,     m_isNotSupported);
+  CHECKVERSION(UserVersion,   MIN_USERVERSION,    m_isNotSupported);
+  if (m_isNotSupported)
+  {
+    m_client->OsdStatusMessage(*cString::sprintf("%s", tr("Your scanner version is to old - Please upgrade." )));
+    return false;
+  }
+
+  /*!
+   * Check which receivers are present
+   */
+  int cardnr = 0;
+  cDevice *device;
+  memset(&m_receiverSystems, 0, sizeof(m_receiverSystems));
+  while ((device = cDevice::GetDevice(cardnr++)))
+  {
+    if (device->ProvidesSource(cSource::stTerr))
+      m_receiverSystems[RECEIVER_SYSTEM_DVB_T] = true;
+    if (device->ProvidesSource(cSource::stCable))
+      m_receiverSystems[RECEIVER_SYSTEM_DVB_C] = true;
+    if (device->ProvidesSource(cSource::stSat))
+      m_receiverSystems[RECEIVER_SYSTEM_DVB_S] = true;
+    if (device->ProvidesSource(cSource::stAtsc))
+      m_receiverSystems[RECEIVER_SYSTEM_ATSC] = true;
+  }
+
+  if (cPluginManager::GetPlugin("pvrinput"))
+  {
+    m_receiverSystems[RECEIVER_SYSTEM_ANALOG_TV]    = true;
+    m_receiverSystems[RECEIVER_SYSTEM_ANALOG_RADIO] = true;
+  }
+
+  m_countryBuffer.size = 0;
+  m_countryBuffer.count = 0;
+  m_countryBuffer.buffer = NULL;
+  if (asprintf(&p, "%sGet%s", SPlugin, SCountry) < 0)
+    return false;
+  m_channelScanPlugin->Service(p, &m_countryBuffer);                      // query buffer size.
+  m_cbuf = (SListItem*) malloc(m_countryBuffer.size * sizeof(SListItem)); // now, allocate memory.
+  m_countryBuffer.buffer = m_cbuf;                                        // assign buffer
+  m_channelScanPlugin->Service(p, &m_countryBuffer);                      // fill buffer with values.
+  free(p);
+
+  m_satBuffer.size = 0;
+  m_satBuffer.count = 0;
+  m_satBuffer.buffer = NULL;
+  if (asprintf(&p, "%sGet%s", SPlugin, SSat) < 0)
+    return false;
+  m_channelScanPlugin->Service(p, &m_satBuffer);                          // query buffer size.
+  m_sbuf = (SListItem*) malloc(m_satBuffer.size * sizeof(SListItem));     // now, allocate memory.
+  m_satBuffer.buffer = m_sbuf;                                            // assign buffer
+  m_channelScanPlugin->Service(p, &m_satBuffer);                          // fill buffer with values.
+  free(p);
+
+  if (asprintf(&p, "%sGet%s", SPlugin, SSetup) < 0)
+    return false;
+  m_channelScanPlugin->Service(p, &m_setup);
+  free(p);
+
+  return true;
+}
+
+bool CScanControl::StartScan(sScanServiceData &data)
+{
+  if (m_isNotSupported)
+    return false;
+
+  m_finishReported = false;
+
+  CHECKLIMITS(m_setup.SatId           , data.SatIndex        , 0 , 0xFFFF, 0);
+  CHECKLIMITS(m_setup.CountryId       , data.CountryIndex    , 0 , 0xFFFF, 0);
+  CHECKLIMITS(m_setup.DVB_Type        , data.type            , 0 , 5     , 0);
+  CHECKLIMITS(m_setup.DVBT_Inversion  , data.DVBT_Inversion  , 0 , 1     , 0);
+  CHECKLIMITS(m_setup.DVBC_Inversion  , data.DVBC_Inversion  , 0 , 1     , 0);
+  CHECKLIMITS(m_setup.DVBC_Symbolrate , data.DVBC_Symbolrate , 0 , 16    , 0);
+  CHECKLIMITS(m_setup.DVBC_QAM        , data.DVBC_QAM        , 0 , 4     , 0);
+  CHECKLIMITS(m_setup.ATSC_type       , data.ATSC_Type       , 0 , 1     , 0);
+
+  m_setup.scanflags  = data.scan_tv        ? SCAN_TV        : 0;
+  m_setup.scanflags |= data.scan_radio     ? SCAN_RADIO     : 0;
+  m_setup.scanflags |= data.scan_scrambled ? SCAN_SCRAMBLED : 0;
+  m_setup.scanflags |= data.scan_fta       ? SCAN_FTA       : 0;
+  m_setup.scanflags |= data.scan_hd        ? SCAN_HD        : 0;
+
+#if VDRVERSNUM >= 20301
+  {
+    LOCK_CHANNELS_READ;
+    m_lastChannelCount = Channels->Count();
+  }
+#else
+  m_lastChannelCount = Channels.Count();
+#endif
+
+  char *s;
+  if (asprintf(&s, "%sSet%s", SPlugin, SSetup) < 0)
+    return false;
+  m_channelScanPlugin->Service(s, &m_setup);
+  free(s);
+
+  PutCommand(CmdStartScan);
+  Start();// start polling thread
+  return true;
+}
+
+bool CScanControl::StopScan()
+{
+  if (m_isNotSupported)
+    return false;
+
+  PutCommand(CmdStopScan);
+  cCondWait::SleepMs(500);
+  Cancel(2);
+  if (!m_finishReported)
+  {
+    if (m_scanStatus.status != StatusStopped)
+    {
+      m_scanStatus.status = StatusStopped;
+      m_client->processSCAN_SetStatus(m_scanStatus.status);
+      INFOLOG("Stopping scan plugin not reported back and stop maybe not complete confirmed");
+    }
+    m_client->processSCAN_IsFinished();
+  }
+
+  return true;
+}
+
+bool CScanControl::GetCountries(scannerEntryList &list)
+{
+  for (uint32_t i = 0; i < m_countryBuffer.count; i++)
+  {
+    scannerEntry entry;
+    entry.index    = m_countryBuffer.buffer[i].id;
+    entry.name     = m_countryBuffer.buffer[i].short_name;
+    entry.longName = m_countryBuffer.buffer[i].full_name;
+    list.push_back(entry);
+  }
+
+  return !list.empty();
+}
+
+bool CScanControl::GetSatellites(scannerEntryList &list)
+{
+  for (uint32_t i = 0; i < m_satBuffer.count; i++)
+  {
+    scannerEntry entry;
+    entry.index    = m_satBuffer.buffer[i].id;
+    entry.name     = m_satBuffer.buffer[i].short_name;
+    entry.longName = m_satBuffer.buffer[i].full_name;
+    list.push_back(entry);
+  }
+
+  return !list.empty();
+}
+
+void CScanControl::PutCommand(WIRBELSCAN_SERVICE::s_cmd command)
+{
+  cWirbelscanCmd cmd;
+  char * request;
+  if (asprintf(&request, "%s%s", SPlugin, SCommand) < 0)
+    return;
+
+  cmd.cmd = command;
+  m_channelScanPlugin->Service(request, &cmd);
+  free(request);
+}
+
+void CScanControl::Action(void)
+{
+  while (Running())
+  {
+    cCondWait::SleepMs(1000);
+
+    char * s;
+    if (asprintf(&s, "%sGet%s", SPlugin, SStatus) < 0)
+      return;
+    m_channelScanPlugin->Service(s, &m_scanStatus);
+    free(s);
+
+    m_client->processSCAN_SetStatus(m_scanStatus.status);
+    m_client->processSCAN_SetPercentage(m_scanStatus.progress);
+    m_client->processSCAN_SetSignalStrength(m_scanStatus.strength, false);
+    m_client->processSCAN_SetDeviceInfo(m_scanStatus.curr_device);
+    m_client->processSCAN_SetTransponder(m_scanStatus.transponder);
+
+
+    int noOfChannels;
+#if VDRVERSNUM >= 20301
+    {
+      LOCK_CHANNELS_READ;
+      noOfChannels = Channels->Count();
+    }
+#else
+    noOfChannels = Channels.Count();
+#endif
+
+    for (int i = 0; i < noOfChannels-m_lastChannelCount; i++)
+    {
+#if VDRVERSNUM >= 20301
+      LOCK_CHANNELS_READ;
+      const cChannel *channel = Channels->GetByNumber(Channels->Count()-i);
+#else
+      cChannel *channel = Channels.GetByNumber(Channels.Count()-i);
+#endif
+      m_client->processSCAN_NewChannel(channel->Name(), channel->Vpid() == 0, channel->Ca() > 0, channel->Vtype() > 2);
+    }
+
+#if VDRVERSNUM >= 20301
+  {
+    LOCK_CHANNELS_READ;
+    m_lastChannelCount = Channels->Count();
+  }
+#else
+  m_lastChannelCount = Channels.Count();
+#endif
+
+    if (m_scanStatus.status == StatusStopped)
+    {
+      m_client->processSCAN_IsFinished();
+      m_finishReported = true;
+      break;
+    }
+  }
+  Cancel(0);
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/channelscancontrol.h b/v/vdr-plugin-vnsiserver-1.8.0/channelscancontrol.h
new file mode 100644 (file)
index 0000000..4bb0819
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2010,2015 Alwin Esch (Team KODI)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __CHANNELSCAN_CONTROL__
+#define __CHANNELSCAN_CONTROL__
+
+#include <vector>
+#include <vdr/plugin.h>
+#include "wirbelscan_services.h"
+
+#define RECEIVER_SYSTEM_DVB_T         0
+#define RECEIVER_SYSTEM_DVB_C         1
+#define RECEIVER_SYSTEM_DVB_S         2
+#define RECEIVER_SYSTEM_ATSC          3
+#define RECEIVER_SYSTEM_ANALOG_TV     4
+#define RECEIVER_SYSTEM_ANALOG_RADIO  5
+
+typedef enum scantype
+{
+  DVB_TERR    = 0,
+  DVB_CABLE   = 1,
+  DVB_SAT     = 2,
+  PVRINPUT    = 3,
+  PVRINPUT_FM = 4,
+  DVB_ATSC    = 5,
+} scantype_t;
+
+struct sScanServiceData
+{
+  int    type;
+
+  bool        scan_tv;
+  bool        scan_radio;
+  bool        scan_fta;
+  bool        scan_scrambled;
+  bool        scan_hd;
+
+  int         CountryIndex;
+
+  int         DVBC_Inversion;
+  int         DVBC_Symbolrate;
+  int         DVBC_QAM;
+
+  int         DVBT_Inversion;
+
+  int         SatIndex;
+
+  int         ATSC_Type;
+};
+
+struct scannerEntry
+{
+  int index;
+  const char *name;
+  const char *longName;
+};
+
+typedef std::vector<scannerEntry> scannerEntryList;
+
+class cVNSIClient;
+
+class CScanControl : public cThread
+{
+public:
+  CScanControl(cVNSIClient *client);
+  ~CScanControl();
+
+  bool IsSupported();
+  bool StartScan(sScanServiceData &data);
+  bool StopScan();
+  bool GetCountries(scannerEntryList &list);
+  bool GetSatellites(scannerEntryList &list);
+
+  bool SupportsDVB_T() { return m_receiverSystems[RECEIVER_SYSTEM_DVB_T]; }
+  bool SupportsDVB_C() { return m_receiverSystems[RECEIVER_SYSTEM_DVB_C]; }
+  bool SupportsDVB_S() { return m_receiverSystems[RECEIVER_SYSTEM_DVB_S]; }
+  bool SupportsAnalogTV() { return m_receiverSystems[RECEIVER_SYSTEM_ANALOG_TV]; }
+  bool SupportsAnalogRadio() { return m_receiverSystems[RECEIVER_SYSTEM_ANALOG_RADIO]; }
+  bool SupportsATSC() { return m_receiverSystems[RECEIVER_SYSTEM_ATSC]; }
+
+  virtual void Action();
+
+private:
+  bool LoadScanner();
+  void PutCommand(WIRBELSCAN_SERVICE::s_cmd command);
+
+  cVNSIClient       *m_client;
+  bool               m_isChecked;
+  bool               m_isNotSupported;
+  bool               m_isNotTpSupported;
+  bool               m_receiverSystems[6];
+  cPlugin           *m_channelScanPlugin;
+  bool               m_singleScan;
+  bool               m_finishReported;
+  WIRBELSCAN_SERVICE::SListItem         *m_cbuf;
+  WIRBELSCAN_SERVICE::SListItem         *m_sbuf;
+  WIRBELSCAN_SERVICE::cPreAllocBuffer    m_countryBuffer;
+  WIRBELSCAN_SERVICE::cPreAllocBuffer    m_satBuffer;
+  WIRBELSCAN_SERVICE::cWirbelscanInfo   *m_scanInformation;
+  WIRBELSCAN_SERVICE::cWirbelscanStatus  m_scanStatus;
+  WIRBELSCAN_SERVICE::cWirbelscanScanSetup m_setup;
+  int                m_lastChannelCount;
+};
+
+#endif // __CHANNELSCAN_CONTROL__
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/config.c b/v/vdr-plugin-vnsiserver-1.8.0/config.c
new file mode 100644 (file)
index 0000000..29a1909
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <vdr/plugin.h>
+
+#include "config.h"
+
+cVNSIServerConfig::cVNSIServerConfig()
+{
+  listen_port         = LISTEN_PORT;
+  ConfigDirectory     = NULL;
+  stream_timeout      = 10;
+  device              = false;
+  pDevice             = NULL;
+  testStreamActive    = false;
+}
+
+/* Global instance */
+cVNSIServerConfig VNSIServerConfig;
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/config.h b/v/vdr-plugin-vnsiserver-1.8.0/config.h
new file mode 100644 (file)
index 0000000..2148767
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_CONFIG_H
+#define VNSI_CONFIG_H
+
+#include <string.h>
+#include <stdint.h>
+
+#include <vdr/config.h>
+
+// log output configuration
+
+#ifdef CONSOLEDEBUG
+#define INFOLOG(x...) printf("VNSI: " x)
+#define ERRORLOG(x...) printf("VNSI-Error: " x)
+#define DEBUGLOG(x...) printf("VNSI-Debug: " x)
+#else
+#define INFOLOG(x...) isyslog("VNSI: " x)
+#define ERRORLOG(x...) esyslog("VNSI-Error: " x)
+#define DEBUGLOG(x...) (SysLogLevel > 3) ? dsyslog("VNSI-Debug: " x) : void()
+#endif
+
+// default settings
+
+#define ALLOWED_HOSTS_FILE  "allowed_hosts.conf"
+#define FRONTEND_DEVICE     "/dev/dvb/adapter%d/frontend%d"
+
+#define LISTEN_PORT       34890
+#define LISTEN_PORT_S    "34890"
+#define DISCOVERY_PORT    34890
+
+// backward compatibility
+
+#if APIVERSNUM < 10701
+#define FOLDERDELIMCHAR '~'
+#endif
+
+// Error flags
+#define ERROR_PES_GENERAL   0x01
+#define ERROR_PES_SCRAMBLE  0x02
+#define ERROR_PES_STARTCODE 0x04
+#define ERROR_TS_SCRAMBLE   0x08
+#define ERROR_DEMUX_NODATA  0x10
+#define ERROR_CAM_ERROR     0x20
+
+
+class cVNSIServerConfig
+{
+public:
+  cVNSIServerConfig();
+
+  // Remote server settings
+  cString ConfigDirectory;      // config directory path
+  uint16_t listen_port;         // Port of remote server
+  uint16_t stream_timeout;      // timeout in seconds for stream data
+  bool device;                  // true if vnsi should act as dummy device
+  void *pDevice;                // pointer to cDvbVnsiDevice
+  cString testStreamFile;       // TS file to simulate channel
+  bool testStreamActive;        // true if test mode is enabled
+};
+
+// Global instance
+extern cVNSIServerConfig VNSIServerConfig;
+
+#endif // VNSI_CONFIG_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/cxsocket.c b/v/vdr-plugin-vnsiserver-1.8.0/cxsocket.c
new file mode 100644 (file)
index 0000000..5ef9fe4
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2003-2006 Petri Hintukainen
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * Socket wrapper classes
+ *
+ * Code is taken from xineliboutput plugin.
+ *
+ */
+
+#include "cxsocket.h"
+#include "config.h"
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+
+#include <vdr/config.h>
+#include <vdr/tools.h>
+
+#ifndef MSG_MORE
+#define MSG_MORE 0
+#endif
+
+cxSocket::cxSocket(int h)
+  :m_fd(h), m_pollerRead(m_fd), m_pollerWrite(m_fd, true)
+{
+}
+
+cxSocket::~cxSocket()
+{
+  if (m_fd >= 0)
+    close(m_fd);
+}
+
+void cxSocket::Shutdown()
+{
+  if (m_fd >= 0)
+    ::shutdown(m_fd, SHUT_RD);
+}
+
+void cxSocket::LockWrite()
+{
+  m_MutexWrite.Lock();
+}
+
+void cxSocket::UnlockWrite()
+{
+  m_MutexWrite.Unlock();
+}
+
+int cxSocket::GetHandle()
+{
+  return m_fd;
+}
+
+void cxSocket::Invalidate()
+{
+  m_fd = -1;
+}
+
+ssize_t cxSocket::write(const void *buffer, size_t size, int timeout_ms, bool more_data)
+{
+  cMutexLock CmdLock(&m_MutexWrite);
+
+  if (m_fd < 0)
+    return 0;
+
+  ssize_t written = (ssize_t)size;
+  const unsigned char *ptr = (const unsigned char *)buffer;
+
+  while (size > 0)
+  {
+    if (!m_pollerWrite.Poll(timeout_ms))
+    {
+      ERRORLOG("cxSocket::write(fd=%d): poll() failed", m_fd);
+      return written-size;
+    }
+
+    ssize_t p = ::send(m_fd, ptr, size, (more_data ? MSG_MORE : 0));
+
+    if (p <= 0)
+    {
+      if (errno == EINTR || errno == EAGAIN)
+      {
+        DEBUGLOG("cxSocket::write(fd=%d): EINTR during write(), retrying", m_fd);
+        continue;
+      }
+      else if (errno != EPIPE)
+        ERRORLOG("cxSocket::write(fd=%d): write() error", m_fd);
+      return p;
+    }
+
+    ptr  += p;
+    size -= p;
+  }
+
+  return written;
+}
+
+ssize_t cxSocket::read(void *buffer, size_t size, int timeout_ms)
+{
+  if (m_fd < 0)
+    return 0;
+
+  int retryCounter = 0;
+
+  ssize_t missing = (ssize_t)size;
+  unsigned char *ptr = (unsigned char *)buffer;
+
+  while (missing > 0)
+  {
+    if(!m_pollerRead.Poll(timeout_ms))
+    {
+      ERRORLOG("cxSocket::read(fd=%d): poll() failed at %d/%d", m_fd, (int)(size-missing), (int)size);
+      return size-missing;
+    }
+
+    ssize_t p = ::read(m_fd, ptr, missing);
+
+    if (p < 0)
+    {
+      if (retryCounter < 10 && (errno == EINTR || errno == EAGAIN))
+      {
+        DEBUGLOG("cxSocket::read(fd=%d): EINTR/EAGAIN during read(), retrying", m_fd);
+        retryCounter++;
+        continue;
+      }
+      ERRORLOG("cxSocket::read(fd=%d): read() error at %d/%d", m_fd, (int)(size-missing), (int)size);
+      return 0;
+    }
+    else if (p == 0)
+    {
+      INFOLOG("cxSocket::read(fd=%d): eof, connection closed", m_fd);
+      return 0;
+    }
+
+    retryCounter = 0;
+    ptr  += p;
+    missing -= p;
+  }
+
+  return size;
+}
+
+char *cxSocket::ip2txt(uint32_t ip, unsigned int port, char *str)
+{
+  // inet_ntoa is not thread-safe (?)
+  if (str)
+  {
+    unsigned int iph =(unsigned int)ntohl(ip);
+    unsigned int porth =(unsigned int)ntohs(port);
+    if (!porth)
+    {
+      sprintf(str, "%d.%d.%d.%d",
+             ((iph>>24)&0xff), ((iph>>16)&0xff),
+             ((iph>>8)&0xff), ((iph)&0xff));
+    }
+    else
+    {
+      sprintf(str, "%u.%u.%u.%u:%u",
+             ((iph>>24)&0xff), ((iph>>16)&0xff),
+             ((iph>>8)&0xff), ((iph)&0xff),
+             porth);
+    }
+  }
+  return str;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/cxsocket.h b/v/vdr-plugin-vnsiserver-1.8.0/cxsocket.h
new file mode 100644 (file)
index 0000000..54413b8
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2003-2006 Petri Hintukainen
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#ifdef __FreeBSD__
+#include <netinet/in.h>
+#endif
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <vdr/thread.h>
+#include <vdr/tools.h>
+
+class cxSocket
+{
+  int m_fd;
+  cMutex m_MutexWrite;
+  cPoller m_pollerRead;
+  cPoller m_pollerWrite;
+
+ public:
+  cxSocket(int h);
+  virtual ~cxSocket();
+
+  cxSocket(const cxSocket &) = delete;
+  cxSocket &operator=(const cxSocket &) = delete;
+
+  void Shutdown(void);
+  void LockWrite();
+  void UnlockWrite();
+  int GetHandle();
+  void Invalidate();
+  ssize_t read(void *buffer, size_t size, int timeout_ms = -1);
+  ssize_t write(const void *buffer, size_t size, int timeout_ms = -1, bool more_data = false);
+  static char *ip2txt(uint32_t ip, unsigned int port, char *str);
+};
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/changelog b/v/vdr-plugin-vnsiserver-1.8.0/debian/changelog
new file mode 100644 (file)
index 0000000..ddacd25
--- /dev/null
@@ -0,0 +1,689 @@
+vdr-plugin-vnsiserver (2:1.8.0-0easyVDR0~trusty) trusty; urgency=high
+
+  * new release 1.8.0
+  * commit:49003f0 -  Merge pull request #117 from FernetMenta/FernetMenta-patch-1
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 05 Dec 2018 15:11:08 +0100
+
+vdr-plugin-vnsiserver (2:1.7.0~git20180809-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:2ed5d19 - fix compilation against vdr 2.2.0
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Thu, 09 Aug 2018 15:32:22 +0200
+
+vdr-plugin-vnsiserver (2:1.6.0~git20180626-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:0b44ed8 - Merge pull request #109 from mglae/recordings_update
+                   - Speed up larger recording updates
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 26 Jun 2018 12:25:27 +0200
+
+vdr-plugin-vnsiserver (2:1.5.2~git20180311-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:0c84792 - fix deadlock caused by vdr status callback while holding locks
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Sun, 11 Mar 2018 15:52:54 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20180220-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:31c8f71 - drop setting current channel on device - obsolete cam (activation) hack
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 20 Feb 2018 21:27:14 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20180123-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:d73b847 - fix deadlock when saving channel filters
+                   - improve signal strenght display (dvbapi 5 or 3)
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 24 Jan 2018 00:01:25 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20171219-0easyVDR1~trusty) trusty; urgency=high
+
+  * rebuild for vdr-2.3.8
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 20 Dec 2017 22:08:12 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20171219-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:02f1631 - fix timeshift max/mintime
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 20 Dec 2017 22:03:47 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20171022-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:63d8151 - fix retune if we have no videoInput
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Sun, 22 Oct 2017 16:57:35 +0200
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170908-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:1fd5aee - protocol 12, report length in msec for recordings
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Fri, 08 Sep 2017 17:26:17 +0200
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170815-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:cca2047 - SignalInfo: correct returned CardIndex
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 15 Aug 2017 19:27:28 +0200
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170807-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:dad54ed - check schedule for nullptr
+  * commit:b1b961a - protocol 11, improve report of playing times
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Mon, 07 Aug 2017 16:44:10 +0200
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170616-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:2c42df3 - fix invalid locking sequence
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Fri, 16 Jun 2017 02:33:09 +0200
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170513-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:a710278 - Added Messgae "Low disk space!" to list of ignored messages
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Sat, 13 May 2017 15:16:10 +0200
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170306-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:615a077 - fix segfault if recording has no title
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Mon, 06 Mar 2017 23:02:25 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170228-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:4bc0eff - fix typo
+  * commit:aef3380 - make grouping of series recordings configurable
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 28 Feb 2017 22:12:37 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170214-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:56ad368 - Fix building against musl C library
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 14 Feb 2017 21:17:09 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170115-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:41e62a5 - update history
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Sun, 15 Jan 2017 20:27:39 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20170104-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:d6847c3 - fix backwards compatibility to protocol 9
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Fri, 06 Jan 2017 20:05:31 +0100
+
+vdr-plugin-vnsiserver (2:1.5.2~git20161224-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:f649006 - fixes for search timers
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Sat, 24 Dec 2016 22:21:58 +0100
+
+vdr-plugin-vnsiserver (2:1.5.1~git20161206-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:2c1f90b - add copy contructor for cVNSIProvider
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 06 Dec 2016 22:36:58 +0100
+
+vdr-plugin-vnsiserver (2:1.5.1~git20161115-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:d47c0bb - fixes for epg update
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 15 Nov 2016 22:19:40 +0100
+
+vdr-plugin-vnsiserver (2:1.5.1~git20160928.9b19e98-0easyVDR2~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Fri, 14 Oct 2016 22:04:04 +0200
+
+vdr-plugin-vnsiserver (2:1.5.1~git20160928.9b19e98-0easyVDR1~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 05 Oct 2016 21:50:00 +0200
+
+vdr-plugin-vnsiserver (2:1.5.1~git20160928.9b19e98-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:9b19e98 - Some cVideoInput cleanup
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 28 Sep 2016 21:05:21 +0200
+
+vdr-plugin-vnsiserver (2:1.5.1~git20160926.15b8d86-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:15b8d86 - Update History for 1.5.1
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Mon, 26 Sep 2016 23:51:31 +0200
+
+vdr-plugin-vnsiserver (2:1.5.0~git20160924.39721f9-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:39721f9 - fixes for searchtimer, some comments to cam handling hacks
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Sun, 25 Sep 2016 00:57:34 +0200
+
+vdr-plugin-vnsiserver (2:1.5.0~git20160824.abd24d5-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:abd24d5 - Avoid division by zero on BBC-SATBACK channels (27.5W)
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 24 Aug 2016 19:59:30 +0200
+
+vdr-plugin-vnsiserver (2:1.5.0~git20160817.1b96c6a-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:1b96c6a - fix resetting cam
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 17 Aug 2016 20:35:38 +0200
+
+vdr-plugin-vnsiserver (2:1.5.0~git20160801-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:5f956c0 - update history for 1.5.0
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Mon, 01 Aug 2016 20:59:47 +0200
+
+vdr-plugin-vnsiserver (2:1.5.0~git20160713-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:87b14f7 - Fix rangeles's Fix
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Wed, 13 Jul 2016 17:59:05 +0200
+
+vdr-plugin-vnsiserver (2:1.5.0~git20160707-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:80799f1 - demuxer: fix SetChannelStreams
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Thu, 07 Jul 2016 17:25:13 +0200
+
+vdr-plugin-vnsiserver (2:1.5.0~git20160606-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:51a0882 - reset parsers if stream is scrambled
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Mon, 06 Jun 2016 23:45:33 +0200
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160405-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:c63d8e8 - add proto9 method for timer types
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Fri, 15 Apr 2016 21:19:52 +0200
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160226-2easyVDR3) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sat, 09 Apr 2016 01:02:57 +0200
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160226-2easyVDR2~trustyubuntu1) trusty; urgency=high
+
+  * remove auto allowed_hosts.conf
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Fri, 11 Mar 2016 19:26:35 +0100
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160226-2easyVDR1~trusty) trusty; urgency=high
+
+  * added fix-encoding patch
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Fri, 04 Mar 2016 17:12:23 +0100
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160226-2easyVDR0~trusty) trusty; urgency=high
+
+  * added new postinst
+  * added new extend_allowed_hosts.conf patch  
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Tue, 01 Mar 2016 22:46:01 +0100
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160226-1easyVDR0~trusty) trusty; urgency=high
+
+  * added set_network_range.patch
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Mon, 29 Feb 2016 23:32:10 +0100
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160226-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:7497fe3 - More informative logging and thread names
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sat, 27 Feb 2016 19:06:53 +0100
+
+vdr-plugin-vnsiserver (2:1.3.1+git20160215-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit:00b5779 - Don't send "Shutting down in ..." to OSD over and over 
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Mon, 15 Feb 2016 18:34:08 +0100
+
+vdr-plugin-vnsiserver (2:1.3.1+git20151204-0easyVDR1~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Fri, 25 Dec 2015 15:55:24 +0100
+
+vdr-plugin-vnsiserver (2:1.3.1+git20151204-0easyVDR0~trusty) trusty; urgency=high
+
+  * rebuild for easyVDR
+  * commit:3f42c55 - Code cleanup, sync with pvr.vdr.vnsi
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sun, 06 Dec 2015 01:35:33 +0100
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150813-2easyVDR0~trusty) trusty; urgency=high
+
+  * added depends kodi-pvr-vdr-vnsi
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sun, 06 Dec 2015 01:17:20 +0100
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150813-1easyVDR0~trusty) trusty; urgency=high
+
+  * rebuild for easyVDR
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Wed, 18 Nov 2015 23:03:57 +0100
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150813-0mangoVDR2~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Tue, 25 Aug 2015 21:34:26 +0200
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150813-0mangoVDR1~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Thu, 20 Aug 2015 22:26:20 +0200
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150813-0mangoVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * [eab5d83] fix duration for h264 frames in case of timestamps jumping back
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Thu, 13 Aug 2015 22:41:38 +0200
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150720-0easyVDR2~trusty) trusty; urgency=high
+
+  * rebuild for VDR-2.2.0
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sat, 25 Jul 2015 00:56:18 +0200
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150720-0easyVDR1~trusty) trusty; urgency=high
+
+  * rebuild
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Mon, 20 Jul 2015 23:58:38 +0200
+
+vdr-plugin-vnsiserver (2:1.3.0+git20150720-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * commit 1c63a8a: fix memleak caused by duplicate new of osd provider
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Mon, 20 Jul 2015 23:52:30 +0200
+
+vdr-plugin-vnsiserver (2:1.2.1~git20150208-0easyVDR3~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Thu, 02 Apr 2015 01:31:09 +0200
+
+vdr-plugin-vnsiserver (2:1.2.1~git20150208-0easyVDR2~trusty) trusty; urgency=high
+
+  * rebuild
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Tue, 31 Mar 2015 12:44:19 +0200
+
+vdr-plugin-vnsiserver (2:1.2.1~git20150208-0easyVDR1~trusty) trusty; urgency=high
+
+  * automatic rebuild for 2.2-vdr-testing PPA
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Tue, 24 Mar 2015 04:38:36 +0100
+
+vdr-plugin-vnsiserver (2:1.2.1~git20150208-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream release:
+    - add cmd line switch for setting tcp port
+    - fix potential segfault on stop streaming
+    - stop triggering epg updates if client does not fetch epg
+  * increase version   
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Sun, 22 Mar 2015 00:11:36 +0100
+
+vdr-plugin-vnsiserver (2:1.1.0~git20140518-7d4aa813cc-1easyVDR6~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- Wolfgang Mangold <vdr@gmx.de>  Thu, 19 Mar 2015 01:26:29 +0100
+
+vdr-plugin-vnsiserver (2:1.1.0~git20140518-7d4aa813cc-1easyVDR5~trusty) trusty; urgency=high
+
+  * automatic rebuild for vdr-2.2.0 Happy B'day
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Fri, 20 Feb 2015 01:34:11 +0100
+
+vdr-plugin-vnsiserver (2:1.1.0~git20140518-7d4aa813cc-1easyVDR4~trusty) trusty; urgency=high
+
+  * automatic rebuild for vdr-2.0.7
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sun, 25 Jan 2015 23:00:11 +0100
+
+vdr-plugin-vnsiserver (2:1.1.0~git20140518-7d4aa813cc-1easyVDR3~trusty) trusty; urgency=high
+
+  * remove vnsiserver5 dummy-packages
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sun, 14 Sep 2014 02:36:31 +0200
+
+vdr-plugin-vnsiserver (2:1.1.0~git20140518-7d4aa813cc-0easyVDR3~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Fri, 29 Aug 2014 22:18:46 +0200
+
+vdr-plugin-vnsiserver (2:1.1.0~git20140518-7d4aa813cc-0easyVDR2~trusty) trusty; urgency=high
+
+  * automatic rebuild
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Tue, 26 Aug 2014 23:20:07 +0200
+
+vdr-plugin-vnsiserver (2:1.1.0~git20140518-7d4aa813cc-0easyVDR1~trusty) trusty; urgency=high
+
+  * increase version
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sat, 28 Jun 2014 02:54:16 +0200
+
+vdr-plugin-vnsiserver (1:1.1.0~git20140518-7d4aa813cc-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Fri, 27 Jun 2014 23:44:39 +0200
+
+vdr-plugin-vnsiserver5 (1:0.9.4+git20140504-0easyVDR0~trusty) trusty; urgency=high
+
+  * new upstream snapshot
+  * add depends pvr-vdr-vnsi
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Tue, 06 May 2014 00:16:53 +0200
+
+vdr-plugin-vnsiserver5 (1:0.9.4+git20140304-0easyVDR0~trusty) trusty; urgency=high
+
+  * rebuild for easyVDR
+  * add depends pvr-vdr-vnsi  
+
+ -- easyVDR-Developer <easyvdr-dev@easy-vdr.de>  Sun, 09 Mar 2014 22:33:20 +0100
+
+vdr-plugin-vnsiserver5 (1:0.9.4+git20140304-0yavdr0~trusty) trusty; urgency=medium
+
+  * new upstream snapshot 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Wed, 05 Mar 2014 22:58:47 +0100
+
+vdr-plugin-vnsiserver5 (0.9.6+git20140205-0yavdr0~trusty) trusty; urgency=medium
+
+  * new upstream snapshot 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Wed, 05 Feb 2014 12:25:52 +0100
+
+vdr-plugin-vnsiserver5 (0.9.5+git20131217-0yavdr0~precise) precise; urgency=medium
+
+  * increase version number 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Tue, 31 Dec 2013 10:29:09 +0100
+
+vdr-plugin-vnsiserver5 (0.9.2+git20131217-0yavdr0~precise) precise; urgency=medium
+
+  * new upstream snapshot for vnsiserver5 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Tue, 31 Dec 2013 10:04:57 +0100
+
+vdr-plugin-vnsiserver3 (2:0.9.1+git20131213.1417-e1c3fb1-6yavdr0~precise) precise; urgency=medium
+
+  * fix build path 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 23:34:37 +0100
+
+vdr-plugin-vnsiserver3 (2:0.9.1+git20131213.1417-e1c3fb1-5yavdr0~precise) precise; urgency=medium
+
+  * increase version number for yavdr ppa 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 14:58:10 +0100
+
+vdr-plugin-vnsiserver3 (0.9.1+git20131213.1417-e1c3fb1-4yavdr0~precise) precise; urgency=medium
+
+  * move config file 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 14:36:47 +0100
+
+vdr-plugin-vnsiserver3 (0.9.1+git20131213.1417-e1c3fb1-3yavdr0~precise) precise; urgency=medium
+
+  * fix control file 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 14:20:35 +0100
+
+vdr-plugin-vnsiserver3 (0.9.1+git20131213.1417-e1c3fb1-2yavdr0~precise) precise; urgency=medium
+
+  * fix install file 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 14:13:50 +0100
+
+vdr-plugin-vnsiserver3 (0.9.1+git20131213.1417-e1c3fb1-1yavdr0~precise) precise; urgency=medium
+
+  * rebuild 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 14:04:23 +0100
+
+vdr-plugin-vnsiserver3 (0.9.1+git20131213.1417-e1c3fb1-yavdr0~precise) precise; urgency=medium
+
+  * reupload 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 13:58:12 +0100
+
+vdr-plugin-vnsiserver3 (0.9.1+git20131213.1417-e1c3fb1-0yavdr0~precise) precise; urgency=medium
+
+  * rename package 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 30 Dec 2013 13:44:41 +0100
+
+vdr-plugin-vnsiserver (1:0.9.2~git20130714.1106-5b20fa5-0yavdr3~precise) precise; urgency=medium
+
+  * automatic rebuild
+
+ -- yavdr package builder <release@yavdr.org>  Sun, 27 Oct 2013 09:16:49 +0100
+
+vdr-plugin-vnsiserver (1:0.9.2~git20130714.1106-5b20fa5-0yavdr3~precise) precise; urgency=medium
+
+  * automatic rebuild
+
+ -- yavdr package builder <release@yavdr.org>  Sat, 26 Oct 2013 19:06:26 +0200
+
+vdr-plugin-vnsiserver (1:0.9.2~git20130714.1106-5b20fa5-0yavdr2~precise) precise; urgency=medium
+
+  * changed config file dir from vnsiserver3 to vnsiserver4
+
+ -- Gerald Dachs <gda@dachsweb.de>  Tue, 17 Sep 2013 19:50:56 +0200
+
+vdr-plugin-vnsiserver (1:0.9.2~git20130714.1106-5b20fa5-0yavdr1~precise) precise; urgency=medium
+
+  * changed config file dir from vnsiserver3 to vnsiserver4
+
+ -- Gerald Dachs <gda@dachsweb.de>  Mon, 16 Sep 2013 23:27:40 +0200
+
+vdr-plugin-vnsiserver (1:0.9.2~git20130714.1106-5b20fa5-0yavdr0~precise) precise; urgency=medium
+
+  * new upstream version
+
+ -- Gerald Dachs <gda@dachsweb.de>  Mon, 16 Sep 2013 23:21:43 +0200
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130714.1106-5b20fa5~0yavdr0~precise) precise; urgency=medium
+
+  * new upstream version
+  * added override_dh_gencontrol
+
+ -- Gerald Dachs <gda@dachsweb.de>  Mon, 16 Sep 2013 00:08:02 +0200
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-5yavdr3~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Lars Hanisch <dvb@flensrocker.de>  Thu, 12 Sep 2013 13:16:16 +0200
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-5yavdr2~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Lars Hanisch <dvb@flensrocker.de>  Fri, 12 Jul 2013 01:10:06 +0200
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-5yavdr1~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Lars Hanisch <dvb@flensrocker.de>  Sun, 23 Jun 2013 10:34:44 +0200
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-5yavdr0~precise) precise; urgency=medium
+
+  * fix NFS recording NOATIME
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Sun, 07 Apr 2013 16:14:12 +0200
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-4yavdr2~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Lars Hanisch <dvb@flensrocker.de>  Tue, 02 Apr 2013 19:59:21 +0200
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-4yavdr1~precise) precise; urgency=medium
+
+  * change connfiles 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Fri, 29 Mar 2013 19:56:36 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-4yavdr0~precise) precise; urgency=medium
+
+  * rename 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Thu, 21 Mar 2013 21:51:35 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-1yavdr2~precise) precise; urgency=medium
+
+  * fix typo 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Thu, 21 Mar 2013 21:48:19 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-1yavdr0~precise) precise; urgency=medium
+
+  * fix config dir 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Thu, 21 Mar 2013 21:30:49 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130320-0yavdr0~precise) precise; urgency=medium
+
+  * new upstream release
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Wed, 20 Mar 2013 18:23:30 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130214-1yavdr5~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Lars Hanisch <dvb@flensrocker.de>  Sun, 17 Mar 2013 16:00:27 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130214-1yavdr4~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Lars Hanisch <dvb@flensrocker.de>  Thu, 14 Mar 2013 01:10:55 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130214-1yavdr2~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Lars Hanisch <dvb@flensrocker.de>  Wed, 13 Mar 2013 22:01:30 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130214-1yavdr1~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 11 Mar 2013 00:16:06 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130214-1yavdr0~precise) precise; urgency=medium
+
+  * rebuild, add pkg-config
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Thu, 14 Feb 2013 11:12:02 +0100
+
+vdr-plugin-vnsiserver (1:0.9.1.git20130214-0yavdr0~precise) precise; urgency=medium
+
+  * new upstream snapshot, new Makefile system 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Thu, 14 Feb 2013 11:01:51 +0100
+
+vdr-plugin-vnsiserver (0.9.9.git20121119-0yavdr1~precise) precise; urgency=medium
+
+  * update 
+
+ -- Alexander Grothe <seahawk1986@gmx.de>  Mon, 19 Nov 2012 11:47:36 +0100
+
+vdr-plugin-vnsiserver (0.9.0.git20120606-0yavdr1~precise) precise; urgency=medium
+
+  * rebuild
+
+ -- Holger Schvestka <hotzenplotz5@gmx.de>  Thu, 11 Oct 2012 11:23:18 +0200
+
+vdr-plugin-vnsiserver (0.9.0.git20120606-0yavdr0~precise) precise; urgency=medium
+
+  * New Upstream Snapshot
+
+ -- Holger Schvestka <hotzenplotz5@gmx.de>  Wed, 06 Jun 2012 11:22:48 +0100
+
+vdr-plugin-vnsiserver (0.9.0.git20110526-0yavdr0~natty) natty; urgency=low
+
+  * New Upstream Snapshot
+
+ -- Holger Schvestka <hotzenplotz5@gmx.de>  Sun, 12 Jun 2011 23:47:24 +0200
+
+vdr-plugin-vnsiserver (0.0.2+svn20110425.2354-1yavdr1~natty) natty; urgency=low
+
+  * New Upstream Snapshot
+
+ -- Holger Schvestka <hotzenplotz5@gmx.de>  Mon, 25 Apr 2011 16:37:11 +0200
+
+vdr-plugin-vnsiserver (0.0.2+svn20110415.2353-0yavdr0~natty) natty; urgency=low
+
+  * New Upstream Snapshot https://github.com/pipelka/xbmc/commits/master
+
+ -- Gerald Dachs <gda@dachsweb.de>  Sat, 16 Apr 2011 00:30:59 +0200
+
+vdr-plugin-vnsiserver (0.0.2+svn20110325.2320-0yavdr0~natty) natty; urgency=low
+
+  * New Upstream Snapshot https://github.com/pipelka/xbmc/commits/master
+
+ -- Holger Schvestka <hotzenplotz5@gmx.de>  Fri, 25 Mar 2011 23:20:01 +0200
+
+vdr-plugin-vnsiserver (0.0.2+svn20100409-1yavdr1) lucid; urgency=low
+
+  * Initial release for yaVDR, thanks aelo for packaging
+
+ -- Holger Schvestka <hotzenplotz5@gmx.de>  Mon, 05 Apr 2010 22:27:56 +0200
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/compat b/v/vdr-plugin-vnsiserver-1.8.0/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/control b/v/vdr-plugin-vnsiserver-1.8.0/debian/control
new file mode 100644 (file)
index 0000000..38bc586
--- /dev/null
@@ -0,0 +1,24 @@
+Source: vdr-plugin-vnsiserver
+Section: video
+Priority: extra
+Maintainer: Alexander Grothe <seahawk1986@hotmail.com>
+Uploaders: Wolfgang Mangold <vdr@gmx.de>
+Build-Depends: debhelper (>= 7.0.50~), vdr-dev (>= 1.7.17), gettext, pkg-config
+Standards-Version: 3.9.1
+Homepage: https://github.com/FernetMenta/vdr-plugin-vnsiserver
+
+Package: vdr-plugin-vnsiserver
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${vdr:Depends}, kodi-pvr-vdr-vnsi
+Description: VDR-Network-Streaming-Interface
+ VDR-Network-Streaming-Interface
+
+Package: vdr-plugin-vnsiserver-dbg
+Architecture: any
+Section: debug
+Priority: extra
+Depends: vdr-plugin-vnsiserver (= ${binary:Version}), ${misc:Depends}
+Description: debugging symbols for vdr-plugin-vnsiserver
+ .
+ This package contains only the debugging symbols for vdr-plugin-vnsiserver
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/copyright b/v/vdr-plugin-vnsiserver-1.8.0/debian/copyright
new file mode 100644 (file)
index 0000000..5cd7943
--- /dev/null
@@ -0,0 +1,46 @@
+Upstream Homepage:
+    <fill in http/ftp site>
+
+Upstream Author(s):
+    <put author(s) name and email here>
+
+Debian Maintainer(s):
+    root <root@unknown>
+
+Copyright:
+    <put the year(s) of the copyright, and the names of the copyright
+     holder(s) here>
+
+Copyright (Debian packaging):
+    (C) 2010 root
+
+License:
+    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.
+
+    The complete text of the GNU General Public License can be found
+    in /usr/share/common-licenses/GPL-2 on most Debian systems.
+
+License (Debian packaging):
+    The Debian packaging is licensed under the GPL, version 2 or any
+    later version, see /usr/share/common-licenses/GPL-2.
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them in this file.
+#
+# Check if the upstream sources explicitly state which licenses apply to
+# which action. If this is not the case, ask the upstream author to add such a
+# license disclaimer to all source files or at least to the README. For the
+# GPL2 or GPL3 the small license disclaimer mentioned at the end of the full license
+# text in "How to Apply These Terms to Your New Programs" should be sufficient.
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/dirs b/v/vdr-plugin-vnsiserver-1.8.0/debian/dirs
new file mode 100644 (file)
index 0000000..4f477cb
--- /dev/null
@@ -0,0 +1 @@
+var/lib/vdr/plugins/vnsiserver
\ No newline at end of file
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/docs b/v/vdr-plugin-vnsiserver-1.8.0/debian/docs
new file mode 100644 (file)
index 0000000..e845566
--- /dev/null
@@ -0,0 +1 @@
+README
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/install b/v/vdr-plugin-vnsiserver-1.8.0/debian/install
new file mode 100644 (file)
index 0000000..9bbe06b
--- /dev/null
@@ -0,0 +1,2 @@
+vnsiserver/allowed_hosts.conf  etc/vdr/plugins/vnsiserver/
+debian/plugin.vnsiserver.conf  etc/vdr/plugins/
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/links b/v/vdr-plugin-vnsiserver-1.8.0/debian/links
new file mode 100644 (file)
index 0000000..d5a597b
--- /dev/null
@@ -0,0 +1 @@
+etc/vdr/plugins/vnsiserver/allowed_hosts.conf  var/lib/vdr/plugins/vnsiserver/allowed_hosts.conf
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/patches/extend_allowed_hosts.conf b/v/vdr-plugin-vnsiserver-1.8.0/debian/patches/extend_allowed_hosts.conf
new file mode 100644 (file)
index 0000000..77ab09b
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/vnsiserver/allowed_hosts.conf
++++ b/vnsiserver/allowed_hosts.conf
+@@ -8,6 +8,6 @@
+ #
+ 127.0.0.1             # always accept localhost
+-192.168.0.0/24        # any host on the local net
++#192.168.0.0/24      # any host on the local net
+ #204.152.189.113      # a specific host
+ #0.0.0.0/0            # any host on any net (USE THIS WITH CARE!)
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/patches/series b/v/vdr-plugin-vnsiserver-1.8.0/debian/patches/series
new file mode 100644 (file)
index 0000000..8e39e3a
--- /dev/null
@@ -0,0 +1,2 @@
+extend_allowed_hosts.conf
+fix-encoding.patch
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/plugin.vnsiserver.conf b/v/vdr-plugin-vnsiserver-1.8.0/debian/plugin.vnsiserver.conf
new file mode 100644 (file)
index 0000000..f942799
--- /dev/null
@@ -0,0 +1 @@
+-t 10
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/postinst b/v/vdr-plugin-vnsiserver-1.8.0/debian/postinst
new file mode 100644 (file)
index 0000000..bb7ed56
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/sh
+# postinst script for vdr-plugin-vnsiserver
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    configure)
+        PLUG_CNF="/etc/vdr/plugins/vnsiserver/allowed_hosts.conf"
+        SVDRP_CNF="/etc/vdr/svdrphosts.conf"
+        EASY_MARK="#inserted by easyvdr"
+        AddLine=$(cat $SVDRP_CNF | grep "$EASY_MARK")
+        sed -i '/'"$EASY_MARK"'/d' $PLUG_CNF; echo "$AddLine" >> $PLUG_CNF    
+        chown -R vdr:vdr /var/lib/vdr/plugins/vnsiserver
+        
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/rules b/v/vdr-plugin-vnsiserver-1.8.0/debian/rules
new file mode 100755 (executable)
index 0000000..976041c
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/make -f
+
+#DH_VERBOSE=1
+
+.PHONY: override_dh_strip override_dh_auto_install
+
+override_dh_strip:
+       dh_strip --dbg-package=vdr-plugin-vnsiserver-dbg
+
+override_dh_auto_install:
+       dh_auto_install --destdir=debian/vdr-plugin-vnsiserver
+
+override_dh_gencontrol:
+       sh /usr/share/vdr-dev/dependencies.sh
+       dh_gencontrol
+
+%:
+       dh $@
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/source/format b/v/vdr-plugin-vnsiserver-1.8.0/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/debian/source/options b/v/vdr-plugin-vnsiserver-1.8.0/debian/source/options
new file mode 100644 (file)
index 0000000..b7bc1f2
--- /dev/null
@@ -0,0 +1 @@
+compression = "xz"
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/demuxer.c b/v/vdr-plugin-vnsiserver-1.8.0/demuxer.c
new file mode 100644 (file)
index 0000000..d744612
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "config.h"
+#include "demuxer.h"
+#include "parser.h"
+#include "videobuffer.h"
+
+#include <vdr/channels.h>
+#include <libsi/si.h>
+
+cStreamInfo::cStreamInfo()
+{
+
+}
+
+cStreamInfo::cStreamInfo(const cStreamInfo& info)
+{
+  pID = info.pID;
+  type = info.type;
+  content = info.content;
+  subtitlingType = info.subtitlingType;
+  compositionPageId = info.compositionPageId;
+  ancillaryPageId = info.ancillaryPageId;
+  handleRDS = info.handleRDS;
+  SetLanguage(info.language);
+}
+
+void cStreamInfo::SetLanguage(const char* lang)
+{
+  language[0] = lang[0];
+  language[1] = lang[1];
+  language[2] = lang[2];
+  language[3] = 0;
+}
+
+cVNSIDemuxer::cVNSIDemuxer(bool bAllowRDS)
+ : m_bAllowRDS(bAllowRDS)
+{
+}
+
+cVNSIDemuxer::~cVNSIDemuxer()
+{
+
+}
+
+void cVNSIDemuxer::Open(const cChannel &channel, cVideoBuffer *videoBuffer)
+{
+  cMutexLock lock(&m_Mutex);
+
+  m_CurrentChannel = channel;
+  m_VideoBuffer = videoBuffer;
+
+  if (m_CurrentChannel.Vpid())
+    m_WaitIFrame = true;
+  else
+    m_WaitIFrame = false;
+
+  m_PtsWrap.m_Wrap = false;
+  m_PtsWrap.m_NoOfWraps = 0;
+  m_PtsWrap.m_ConfirmCount = 0;
+  m_MuxPacketSerial = 0;
+  m_Error = ERROR_DEMUX_NODATA;
+  m_SetRefTime = true;
+  m_seenFirstPacket = false;
+}
+
+void cVNSIDemuxer::Close()
+{
+  cMutexLock lock(&m_Mutex);
+
+  for (auto *i : m_Streams)
+  {
+    DEBUGLOG("Deleting stream parser for pid=%i and type=%i", i->GetPID(), i->Type());
+    delete i;
+  }
+  m_Streams.clear();
+  m_StreamInfos.clear();
+}
+
+int cVNSIDemuxer::Read(sStreamPacket *packet, sStreamPacket *packet_side_data)
+{
+  uint8_t *buf;
+  int len;
+  cTSStream *stream;
+
+  cMutexLock lock(&m_Mutex);
+
+  if (!m_CurrentChannel.Vpid())
+    m_WaitIFrame = false;
+
+  // clear packet
+  if (!packet)
+    return -1;
+  packet->data = NULL;
+  packet->streamChange = false;
+  packet->pmtChange = false;
+
+  // read TS Packet from buffer
+  len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime);
+  // eof
+  if (len == -2)
+    return -2;
+  else if (len != TS_SIZE)
+    return -1;
+
+  m_Error &= ~ERROR_DEMUX_NODATA;
+
+  int ts_pid = TsPid(buf);
+
+  // parse PAT/PMT
+  if (ts_pid == PATPID)
+  {
+    m_PatPmtParser.ParsePat(buf, TS_SIZE);
+  }
+#if APIVERSNUM >= 10733
+  else if (m_PatPmtParser.IsPmtPid(ts_pid))
+#else
+  else if (ts_pid == m_PatPmtParser.PmtPid())
+#endif
+  {
+    int patVersion, pmtVersion;
+    m_PatPmtParser.ParsePmt(buf, TS_SIZE);
+    if (m_PatPmtParser.GetVersions(patVersion, pmtVersion))
+    {
+      cChannel pmtChannel(m_CurrentChannel);
+      SetChannelPids(&pmtChannel, &m_PatPmtParser);
+      SetChannelStreamInfos(&pmtChannel);
+      m_PatPmtParser.Reset();
+      if (EnsureParsers())
+      {
+        packet->pmtChange = true;
+        return 1;
+      }
+    }
+  }
+  else if (stream = FindStream(ts_pid))
+  {
+    int error = stream->ProcessTSPacket(buf, packet, packet_side_data, m_WaitIFrame);
+    if (error == 0)
+    {
+      m_WaitIFrame = false;
+      m_seenFirstPacket = true;
+
+      packet->serial = m_MuxPacketSerial;
+      if (m_SetRefTime)
+      {
+        m_refTime = m_VideoBuffer->GetRefTime();
+        packet->reftime = m_refTime;
+        m_SetRefTime = false;
+      }
+      return 1;
+    }
+    else if (error < 0)
+    {
+      m_Error |= abs(error);
+      if (m_Error & (ERROR_PES_SCRAMBLE | ERROR_TS_SCRAMBLE))
+      {
+        if (m_seenFirstPacket)
+        {
+          ResetParsers();
+          m_Error |= ERROR_CAM_ERROR;
+          m_WaitIFrame = true;
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+bool cVNSIDemuxer::SeekTime(int64_t time)
+{
+  off_t pos, pos_min, pos_max, pos_limit, start_pos;
+  int64_t ts, ts_min, ts_max, last_ts;
+  int no_change;
+
+  if (!m_VideoBuffer->HasBuffer())
+    return false;
+
+  cMutexLock lock(&m_Mutex);
+
+//  INFOLOG("----- seek to time: %ld", time);
+
+  // rescale to 90khz
+  time = cTSStream::Rescale(time, 90000, DVD_TIME_BASE);
+
+  m_VideoBuffer->GetPositions(&pos, &pos_min, &pos_max);
+
+//  INFOLOG("----- seek to time: %ld", time);
+//  INFOLOG("------pos: %ld, pos min: %ld, pos max: %ld", pos, pos_min, pos_max);
+
+  if (!GetTimeAtPos(&pos_min, &ts_min))
+  {
+    ResetParsers();
+    m_WaitIFrame = true;
+    return false;
+  }
+
+//  INFOLOG("----time at min: %ld", ts_min);
+
+  if (ts_min >= time)
+  {
+    m_VideoBuffer->SetPos(pos_min);
+    ResetParsers();
+    m_WaitIFrame = true;
+    m_MuxPacketSerial++;
+    return true;
+  }
+
+  int64_t timecur;
+  GetTimeAtPos(&pos, &timecur);
+
+  // get time at end of buffer
+  unsigned int step= 1024;
+  bool gotTime;
+  do
+  {
+    pos_max -= step;
+    gotTime = GetTimeAtPos(&pos_max, &ts_max);
+    step += step;
+  } while (!gotTime && pos_max >= step);
+
+  if (!gotTime)
+  {
+    ResetParsers();
+    m_WaitIFrame = true;
+    return false;
+  }
+
+  if (ts_max <= time)
+  {
+    ResetParsers();
+    m_WaitIFrame = true;
+    m_MuxPacketSerial++;
+    return true;
+  }
+
+//  INFOLOG(" - time in buffer: %ld", cTSStream::Rescale(ts_max-ts_min, DVD_TIME_BASE, 90000)/1000000);
+
+  // bisect seek
+  if(ts_min > ts_max)
+  {
+    ResetParsers();
+    m_WaitIFrame = true;
+    return false;
+  }
+  else if (ts_min == ts_max)
+  {
+    pos_limit = pos_min;
+  }
+  else
+    pos_limit = pos_max;
+
+  no_change = 0;
+  ts = time;
+  last_ts = 0;
+  while (pos_min < pos_limit)
+  {
+    if (no_change==0)
+    {
+      // interpolate position
+      pos = cTSStream::Rescale(time - ts_min, pos_max - pos_min, ts_max - ts_min)
+          + pos_min - (pos_max - pos_limit);
+    }
+    else if (no_change==1)
+    {
+      // bisection, if interpolation failed to change min or max pos last time
+      pos = (pos_min + pos_limit) >> 1;
+    }
+    else
+    {
+      // linear search if bisection failed
+      pos = pos_min;
+    }
+
+    // clamp calculated pos into boundaries
+    if( pos <= pos_min)
+      pos = pos_min + 1;
+    else if (pos > pos_limit)
+      pos = pos_limit;
+    start_pos = pos;
+
+    // get time stamp at pos
+    if (!GetTimeAtPos(&pos, &ts))
+    {
+      ResetParsers();
+      m_WaitIFrame = true;
+      return false;
+    }
+    pos = m_VideoBuffer->GetPosCur();
+
+    // determine method for next calculation of pos
+    if ((last_ts == ts) || (pos >= pos_max))
+      no_change++;
+    else
+      no_change=0;
+
+//    INFOLOG("--- pos: %ld, \t time: %ld, diff time: %ld", pos, ts, time-ts);
+
+    // 0.4 sec is close enough
+    if (abs(time - ts) <= 36000)
+    {
+      break;
+    }
+    // target is to the left
+    else if (time <= ts)
+    {
+      pos_limit = start_pos - 1;
+      pos_max = pos;
+      ts_max = ts;
+    }
+    // target is to the right
+    if (time >= ts)
+    {
+      pos_min = pos;
+      ts_min = ts;
+    }
+    last_ts = ts;
+  }
+
+//  INFOLOG("----pos found: %ld", pos);
+//  INFOLOG("----time at pos: %ld, diff time: %ld", ts, cTSStream::Rescale(timecur-ts, DVD_TIME_BASE, 90000));
+
+  m_VideoBuffer->SetPos(pos);
+
+  ResetParsers();
+  m_WaitIFrame = true;
+  m_MuxPacketSerial++;
+  return true;
+}
+
+void cVNSIDemuxer::BufferStatus(bool &timeshift, uint32_t &start, uint32_t &end)
+{
+  cMutexLock lock(&m_Mutex);
+
+  timeshift = m_VideoBuffer->HasBuffer();
+
+  if (timeshift)
+  {
+    m_VideoBuffer->GetBufferTime(m_endTime, m_wrapTime);
+    if (!m_wrapTime)
+    {
+      start = m_refTime;
+    }
+    else
+    {
+      start = m_endTime - (m_wrapTime - m_refTime);
+    }
+    end = m_endTime;
+  }
+  else
+  {
+    start = 0;
+    end = 0;
+  }
+}
+
+cTSStream *cVNSIDemuxer::GetFirstStream()
+{
+  m_StreamsIterator = m_Streams.begin();
+  if (m_StreamsIterator != m_Streams.end())
+    return *m_StreamsIterator;
+  else
+    return NULL;
+}
+
+cTSStream *cVNSIDemuxer::GetNextStream()
+{
+  ++m_StreamsIterator;
+  if (m_StreamsIterator != m_Streams.end())
+    return *m_StreamsIterator;
+  else
+    return NULL;
+}
+
+cTSStream *cVNSIDemuxer::FindStream(int Pid)
+{
+  for (auto *i : m_Streams)
+  {
+    if (Pid == i->GetPID())
+      return i;
+  }
+  return NULL;
+}
+
+void cVNSIDemuxer::ResetParsers()
+{
+  for (auto *i : m_Streams)
+  {
+    i->ResetParser();
+  }
+  m_seenFirstPacket = false;
+}
+
+static bool Contains(const std::list<cStreamInfo> &list, int pID, eStreamType type)
+{
+  for (const auto &i : list)
+    if (i.pID == pID && i.type == type)
+      return true;
+
+  return false;
+}
+
+bool cVNSIDemuxer::EnsureParsers()
+{
+  bool streamChange = false;
+
+  auto it = m_Streams.begin();
+  while (it != m_Streams.end())
+  {
+    if (!Contains(m_StreamInfos, (*it)->GetPID(), (*it)->Type()))
+    {
+      INFOLOG("Deleting stream for pid=%i and type=%i", (*it)->GetPID(), (*it)->Type());
+      it = m_Streams.erase(it);
+      streamChange = true;
+    }
+    else
+      ++it;
+  }
+
+  for (const auto &i : m_StreamInfos)
+  {
+    cTSStream *stream = FindStream(i.pID);
+    if (stream)
+    {
+      // TODO: check for change in lang
+      stream->SetLanguage(i.language);
+      continue;
+    }
+
+    if (i.type == stH264)
+    {
+      stream = new cTSStream(stH264, i.pID, &m_PtsWrap);
+    }
+    else if (i.type == stHEVC)
+    {
+      stream = new cTSStream(stHEVC, i.pID, &m_PtsWrap);
+    }
+    else if (i.type == stMPEG2VIDEO)
+    {
+      stream = new cTSStream(stMPEG2VIDEO, i.pID, &m_PtsWrap);
+    }
+    else if (i.type == stMPEG2AUDIO)
+    {
+      stream = new cTSStream(stMPEG2AUDIO, i.pID, &m_PtsWrap, i.handleRDS);
+      stream->SetLanguage(i.language);
+    }
+    else if (i.type == stAACADTS)
+    {
+      stream = new cTSStream(stAACADTS, i.pID, &m_PtsWrap);
+      stream->SetLanguage(i.language);
+    }
+    else if (i.type == stAACLATM)
+    {
+      stream = new cTSStream(stAACLATM, i.pID, &m_PtsWrap);
+      stream->SetLanguage(i.language);
+    }
+    else if (i.type == stAC3)
+    {
+      stream = new cTSStream(stAC3, i.pID, &m_PtsWrap);
+      stream->SetLanguage(i.language);
+    }
+    else if (i.type == stEAC3)
+    {
+      stream = new cTSStream(stEAC3, i.pID, &m_PtsWrap);
+      stream->SetLanguage(i.language);
+    }
+    else if (i.type == stDVBSUB)
+    {
+      stream = new cTSStream(stDVBSUB, i.pID, &m_PtsWrap);
+      stream->SetLanguage(i.language);
+#if APIVERSNUM >= 10709
+      stream->SetSubtitlingDescriptor(i.subtitlingType, i.compositionPageId, i.ancillaryPageId);
+#endif
+    }
+    else if (i.type == stTELETEXT)
+    {
+      stream = new cTSStream(stTELETEXT, i.pID, &m_PtsWrap);
+    }
+    else
+      continue;
+
+    m_Streams.push_back(stream);
+    INFOLOG("Created stream for pid=%i and type=%i", stream->GetPID(), stream->Type());
+    streamChange = true;
+  }
+  m_StreamInfos.clear();
+
+  return streamChange;
+}
+
+void cVNSIDemuxer::SetChannelStreamInfos(const cChannel *channel)
+{
+  m_StreamInfos.clear();
+
+  cStreamInfo newStream;
+  bool containsVideo = false;
+  int index = 0;
+  if (channel->Vpid())
+  {
+    newStream.pID = channel->Vpid();
+#if APIVERSNUM >= 10701
+    if (channel->Vtype() == 0x1B)
+      newStream.type = stH264;
+    else if (channel->Vtype() == 0x24)
+      newStream.type = stHEVC;
+    else
+#endif
+      newStream.type = stMPEG2VIDEO;
+
+    m_StreamInfos.push_back(newStream);
+    containsVideo = true;
+  }
+
+  const int *DPids = channel->Dpids();
+  index = 0;
+  for ( ; *DPids; DPids++)
+  {
+    newStream.pID = *DPids;
+    newStream.type = stAC3;
+    if (channel->Dtype(index) == SI::EnhancedAC3DescriptorTag)
+      newStream.type = stEAC3;
+    newStream.SetLanguage(channel->Dlang(index));
+    m_StreamInfos.push_back(newStream);
+    index++;
+  }
+
+  const int *APids = channel->Apids();
+  index = 0;
+  for ( ; *APids; APids++)
+  {
+    newStream.pID = *APids;
+    newStream.type = stMPEG2AUDIO;
+    if (channel->Atype(index) == 0x0F)
+      newStream.type = stAACADTS;
+    else if (channel->Atype(index) == 0x11)
+      newStream.type = stAACLATM;
+    newStream.handleRDS = m_bAllowRDS && newStream.type == stMPEG2AUDIO && !containsVideo ? true : false; // Relevant for RDS, if present only on mpeg 2 audio, use only if RDS is allowed
+    newStream.SetLanguage(channel->Alang(index));
+    m_StreamInfos.push_back(newStream);
+    index++;
+  }
+
+  const int *SPids = channel->Spids();
+  if (SPids)
+  {
+    index = 0;
+    for ( ; *SPids; SPids++)
+    {
+      newStream.pID = *SPids;
+      newStream.type = stDVBSUB;
+      newStream.SetLanguage(channel->Slang(index));
+      newStream.subtitlingType = channel->SubtitlingType(index);
+      newStream.compositionPageId = channel->CompositionPageId(index);
+      newStream.ancillaryPageId = channel->AncillaryPageId(index);
+      m_StreamInfos.push_back(newStream);
+    }
+    index++;
+  }
+
+  if (channel->Tpid())
+  {
+    newStream.pID = channel->Tpid();
+    newStream.type = stTELETEXT;
+    m_StreamInfos.push_back(newStream);
+  }
+}
+
+void cVNSIDemuxer::SetChannelPids(cChannel *channel, cPatPmtParser *patPmtParser)
+{
+  int Apids[MAXAPIDS + 1] = { 0 };
+  int Atypes[MAXAPIDS + 1] = { 0 };
+  int Dpids[MAXDPIDS + 1] = { 0 };
+  int Dtypes[MAXDPIDS + 1] = { 0 };
+  int Spids[MAXSPIDS + 1] = { 0 };
+  char ALangs[MAXAPIDS][MAXLANGCODE2] = { 0 };
+  char DLangs[MAXDPIDS][MAXLANGCODE2] = { 0 };
+  char SLangs[MAXSPIDS][MAXLANGCODE2] = { 0 };
+  int index = 0;
+
+  const int *aPids = patPmtParser->Apids();
+  index = 0;
+  for ( ; *aPids; aPids++)
+  {
+    Apids[index] = patPmtParser->Apid(index);
+    Atypes[index] = patPmtParser->Atype(index);
+    strn0cpy(ALangs[index], patPmtParser->Alang(index), MAXLANGCODE2);
+    index++;
+  }
+
+  const int *dPids = patPmtParser->Dpids();
+  index = 0;
+  for ( ; *dPids; dPids++)
+  {
+    Dpids[index] = patPmtParser->Dpid(index);
+    Dtypes[index] = patPmtParser->Dtype(index);
+    strn0cpy(DLangs[index], patPmtParser->Dlang(index), MAXLANGCODE2);
+    index++;
+  }
+
+  const int *sPids = patPmtParser->Spids();
+  index = 0;
+  for ( ; *sPids; sPids++)
+  {
+    Spids[index] = patPmtParser->Spid(index);
+    strn0cpy(SLangs[index], patPmtParser->Slang(index), MAXLANGCODE2);
+    index++;
+  }
+
+  int Vpid = patPmtParser->Vpid();
+  int Ppid = patPmtParser->Ppid();
+  int VType = patPmtParser->Vtype();
+  int Tpid = m_CurrentChannel.Tpid();
+  channel->SetPids(Vpid, Ppid, VType,
+                   Apids, Atypes, ALangs,
+                   Dpids, Dtypes, DLangs,
+                   Spids, SLangs,
+                   Tpid);
+}
+
+bool cVNSIDemuxer::GetTimeAtPos(off_t *pos, int64_t *time)
+{
+  uint8_t *buf;
+  int len;
+  cTSStream *stream;
+  int ts_pid;
+
+  m_VideoBuffer->SetPos(*pos);
+  ResetParsers();
+  while ((len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime)) == TS_SIZE)
+  {
+    ts_pid = TsPid(buf);
+    if (stream = FindStream(ts_pid))
+    {
+      // only consider video or audio streams
+      if ((stream->Content() == scVIDEO || stream->Content() == scAUDIO) &&
+          stream->ReadTime(buf, time))
+      {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+uint16_t cVNSIDemuxer::GetError()
+{
+  uint16_t ret = m_Error;
+  m_Error = ERROR_DEMUX_NODATA;
+  return ret;
+}
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/demuxer.h b/v/vdr-plugin-vnsiserver-1.8.0/demuxer.h
new file mode 100644 (file)
index 0000000..8fa758b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+
+#include "parser.h"
+
+#include <list>
+#include <vdr/channels.h>
+#include <vdr/remux.h>
+
+struct sStreamPacket;
+class cTSStream;
+class cChannel;
+class cVideoBuffer;
+
+class cStreamInfo
+{
+public:
+  cStreamInfo();
+  cStreamInfo(const cStreamInfo& info);
+  cStreamInfo& operator=(const cStreamInfo& info) = delete;
+  void SetLanguage(const char* lang);
+
+  int pID = 0;
+  eStreamType type = eStreamType::stNone;
+  eStreamContent content;
+  char language[MAXLANGCODE2] = { 0 };
+  int subtitlingType;
+  int compositionPageId;
+  int ancillaryPageId;
+  bool handleRDS = false;
+};
+
+class cVNSIDemuxer
+{
+public:
+  cVNSIDemuxer(bool bAllowRDS);
+  virtual ~cVNSIDemuxer();
+
+  cVNSIDemuxer(const cVNSIDemuxer &) = delete;
+  cVNSIDemuxer &operator=(const cVNSIDemuxer &) = delete;
+
+  int Read(sStreamPacket *packet, sStreamPacket *packet_side_data);
+  cTSStream *GetFirstStream();
+  cTSStream *GetNextStream();
+  void Open(const cChannel &channel, cVideoBuffer *videoBuffer);
+  void Close();
+  bool SeekTime(int64_t time);
+  uint32_t GetSerial() { return m_MuxPacketSerial; }
+  void SetSerial(uint32_t serial) { m_MuxPacketSerial = serial; }
+  void BufferStatus(bool &timeshift, uint32_t &start, uint32_t &end);
+  uint16_t GetError();
+
+protected:
+  bool EnsureParsers();
+  void ResetParsers();
+  void SetChannelStreamInfos(const cChannel *channel);
+  void SetChannelPids(cChannel *channel, cPatPmtParser *patPmtParser);
+  cTSStream *FindStream(int Pid);
+  bool GetTimeAtPos(off_t *pos, int64_t *time);
+  std::list<cTSStream*> m_Streams;
+  std::list<cTSStream*>::iterator m_StreamsIterator;
+  std::list<cStreamInfo> m_StreamInfos;
+  cChannel m_CurrentChannel;
+  cPatPmtParser m_PatPmtParser;
+  bool m_WaitIFrame;
+  cVideoBuffer *m_VideoBuffer;
+  cMutex m_Mutex;
+  uint32_t m_MuxPacketSerial;
+  sPtsWrap m_PtsWrap;
+  uint16_t m_Error;
+  bool m_SetRefTime;
+  time_t m_refTime, m_endTime, m_wrapTime;
+  bool m_bAllowRDS;
+  bool m_seenFirstPacket;
+};
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/hash.c b/v/vdr-plugin-vnsiserver-1.8.0/hash.c
new file mode 100644 (file)
index 0000000..5c6ca21
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 1986 Gary S. Brown (CRC32 code)
+ *      Copyright (C) 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hash.h"
+
+#include <vdr/tools.h>
+#include <vdr/channels.h>
+
+static uint32_t crc32_tab[] = {
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+       0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+       0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+       0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+       0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+       0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+       0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+       0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+       0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+       0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+       0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+       0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+       0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+       0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+       0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+       0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+       0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+       0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+uint32_t crc32(const unsigned char *buf, size_t size)
+{
+       uint32_t crc = 0xFFFFFFFF;
+       const uint8_t *p = (uint8_t*)buf;
+
+       while (size--)
+               crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+       return (crc ^ ~0U) & 0x7FFFFFFF; // channeluid is signed
+}
+
+uint32_t CreateStringHash(const cString& string) {
+  const char* p = string;
+  int len = strlen(p);
+
+  return crc32((const unsigned char*)p, len);
+}
+
+uint32_t CreateChannelUID(const cChannel* channel) {
+  cString channelid = channel->GetChannelID().ToString();
+  return CreateStringHash(channelid);
+}
+
+const cChannel* FindChannelByUID(uint32_t channelUID) {
+  const cChannel* result = NULL;
+
+#if VDRVERSNUM >= 20301
+  LOCK_CHANNELS_READ;
+  // maybe we need to use a lookup table
+  for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel)) {
+    cString channelid = channel->GetChannelID().ToString();
+    if(channelUID == CreateStringHash(channelid)) {
+      result = channel;
+      break;
+    }
+  }
+#else
+  // maybe we need to use a lookup table
+  Channels.Lock(false);
+  for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
+    cString channelid = channel->GetChannelID().ToString();
+    if(channelUID == CreateStringHash(channelid)) {
+      result = channel;
+      break;
+    }
+  }
+  Channels.Unlock();
+#endif
+
+  return result;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/hash.h b/v/vdr-plugin-vnsiserver-1.8.0/hash.h
new file mode 100644 (file)
index 0000000..05e5fff
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 1986 Gary S. Brown (CRC32 code)
+ *      Copyright (C) 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_HASH_H
+#define VNSI_HASH_H
+
+#include <stdint.h>
+#include <vdr/channels.h>
+
+class cChannel;
+
+uint32_t CreateChannelUID(const cChannel* channel);
+const cChannel* FindChannelByUID(uint32_t channelUID);
+
+uint32_t CreateStringHash(const cString& string);
+
+#endif // VNSI_HASH_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser.c b/v/vdr-plugin-vnsiserver-1.8.0/parser.c
new file mode 100644 (file)
index 0000000..6639f06
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include <vdr/remux.h>
+#include <vdr/channels.h>
+#include "config.h"
+#include "parser.h"
+#include "parser_AAC.h"
+#include "parser_AC3.h"
+#include "parser_DTS.h"
+#include "parser_h264.h"
+#include "parser_hevc.h"
+#include "parser_MPEGAudio.h"
+#include "parser_MPEGVideo.h"
+#include "parser_Subtitle.h"
+#include "parser_Teletext.h"
+
+#define PTS_MASK 0x1ffffffffLL
+
+#ifndef INT64_MIN
+#define INT64_MIN       (-0x7fffffffffffffffLL-1)
+#endif
+
+// --- cParser -------------------------------------------------
+
+cParser::cParser(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : m_pID(pID), m_PtsWrap(ptsWrap), m_ObservePtsWraps(observePtsWraps)
+{
+  m_PesBuffer = NULL;
+  m_Stream = stream;
+  m_IsVideo = false;
+  m_PesBufferInitialSize = 1024;
+  Reset();
+}
+
+cParser::~cParser()
+{
+  free(m_PesBuffer);
+}
+
+void cParser::Reset()
+{
+  m_curPTS = DVD_NOPTS_VALUE;
+  m_curDTS = DVD_NOPTS_VALUE;
+  m_prevDTS = DVD_NOPTS_VALUE;
+  m_PesBufferPtr = 0;
+  m_PesParserPtr = 0;
+  m_PesNextFramePtr = 0;
+  m_FoundFrame = false;
+  m_FrameValid = false;
+  m_PesPacketLength = 0;
+  m_PesHeaderPtr = 0;
+  m_Error = ERROR_PES_GENERAL;
+  m_scrambleCounter = 0;
+}
+/*
+ * Extract DTS and PTS and update current values in stream
+ */
+int cParser::ParsePESHeader(uint8_t *buf, size_t len)
+{
+  m_PesPacketLength = buf[4] << 8 | buf[5];
+
+  if (!PesIsVideoPacket(buf) && !PesIsAudioPacket(buf))
+    return 6;
+
+  unsigned int hdr_len = PesHeaderLength(buf);
+
+  if (m_PesPacketLength > 0)
+    m_PesPacketLength -= (hdr_len-6);
+
+  // scrambled
+  if ((buf[6] & 0x30) != 0)
+    return hdr_len;
+
+  // parse PTS
+  if ((hdr_len >= 13) &&
+      ((((buf[7] & 0xC0) == 0x80) && ((buf[9] & 0xF0) == 0x20)) ||
+        ((buf[7] & 0xC0) == 0xC0) && ((buf[9] & 0xF0) == 0x30)))
+  {
+    int64_t pts;
+    pts  = ((int64_t)(buf[ 9] & 0x0E)) << 29 ;
+    pts |= ((int64_t) buf[10])         << 22 ;
+    pts |= ((int64_t)(buf[11] & 0xFE)) << 14 ;
+    pts |= ((int64_t) buf[12])         <<  7 ;
+    pts |= ((int64_t)(buf[13] & 0xFE)) >>  1 ;
+
+    int64_t bit32and31 = pts >> 31;
+    if (m_ObservePtsWraps)
+    {
+      if ((bit32and31 == 3) && !m_PtsWrap->m_Wrap)
+      {
+        m_PtsWrap->m_ConfirmCount++;
+        if (m_PtsWrap->m_ConfirmCount >= 2)
+        {
+          m_PtsWrap->m_Wrap = true;
+        }
+      }
+      else if ((bit32and31 == 1) && m_PtsWrap->m_Wrap)
+      {
+        m_PtsWrap->m_ConfirmCount++;
+        if (m_PtsWrap->m_ConfirmCount >= 2)
+        {
+          m_PtsWrap->m_Wrap = false;
+          m_PtsWrap->m_NoOfWraps++;
+        }
+      }
+      else
+        m_PtsWrap->m_ConfirmCount = 0;
+    }
+
+    m_prevPTS = m_curPTS;
+    m_curPTS = pts;
+    m_PesTimePos = m_PesBufferPtr;
+    if (m_PtsWrap->m_Wrap && !(bit32and31))
+    {
+      m_curPTS += 1LL<<33;
+    }
+    if (m_PtsWrap->m_NoOfWraps)
+    {
+      m_curPTS += ((int64_t)m_PtsWrap->m_NoOfWraps<<33);
+    }
+  }
+  else
+    return hdr_len;
+
+  m_prevDTS = m_curDTS;
+
+  // parse DTS
+  if ((hdr_len >= 18) &&
+      ((buf[7] & 0xC0) == 0xC0) && ((buf[14] & 0xF0) == 0x10))
+  {
+    int64_t dts;
+    dts  = ((int64_t)( buf[14] & 0x0E)) << 29 ;
+    dts |=  (int64_t)( buf[15]          << 22 );
+    dts |=  (int64_t)((buf[16] & 0xFE)  << 14 );
+    dts |=  (int64_t)( buf[17]          <<  7 );
+    dts |=  (int64_t)((buf[18] & 0xFE)  >>  1 );
+    m_curDTS = dts;
+    if (m_PtsWrap->m_Wrap && !(m_curDTS >> 31))
+    {
+      m_curDTS += 1LL<<33;
+    }
+    if (m_PtsWrap->m_NoOfWraps)
+    {
+      m_curDTS += ((int64_t)m_PtsWrap->m_NoOfWraps<<33);
+    }
+  }
+  else
+    m_curDTS = m_curPTS;
+
+  return hdr_len;
+}
+
+int cParser::ParsePacketHeader(uint8_t *data)
+{
+  if (TsIsScrambled(data))
+  {
+    if (m_scrambleCounter > 100)
+      m_Error = ERROR_TS_SCRAMBLE;
+    else
+      m_scrambleCounter++;
+    return -1;
+  }
+
+  if (TsPayloadStart(data))
+  {
+    m_IsPusi = true;
+    m_Error = 0;
+    m_scrambleCounter = 0;
+  }
+
+  int  bytes = TS_SIZE - TsPayloadOffset(data);
+
+  if (bytes < 0 || bytes > TS_SIZE)
+  {
+    m_Error = ERROR_PES_GENERAL;
+    return -1;
+  }
+
+  if (TsError(data))
+  {
+    m_Error = ERROR_PES_GENERAL;
+    return -1;
+  }
+
+  if (!TsHasPayload(data))
+  {
+    DEBUGLOG("no payload, size %d", bytes);
+    return 0;
+  }
+
+  // drop broken PES packets
+  if (m_Error)
+  {
+    return -1;
+  }
+
+  return bytes;
+}
+
+bool cParser::AddPESPacket(uint8_t *data, int size)
+{
+  // check for beginning of a PES packet
+  if (m_IsPusi && m_IsVideo && !IsValidStartCode(data, 4))
+  {
+    m_IsPusi = false;
+  }
+  if (m_IsPusi)
+  {
+    int hdr_len = 6;
+    if (m_PesHeaderPtr + size < hdr_len)
+    {
+      memcpy(m_PesHeader+m_PesHeaderPtr, data, size);
+      m_PesHeaderPtr += size;
+      return false;
+    }
+    else if (m_PesHeaderPtr)
+    {
+      int bytesNeeded = hdr_len-m_PesHeaderPtr;
+      if (bytesNeeded > 0)
+      {
+        memcpy(m_PesHeader+m_PesHeaderPtr, data, bytesNeeded);
+        m_PesHeaderPtr += bytesNeeded;
+        data += bytesNeeded;
+        size -= bytesNeeded;
+      }
+      if (!IsValidStartCode(m_PesHeader, hdr_len))
+      {
+        Reset();
+        m_Error |= ERROR_PES_STARTCODE;
+        return false;
+      }
+      if (PesIsVideoPacket(m_PesHeader) || PesIsAudioPacket(m_PesHeader))
+      {
+        hdr_len = 9;
+        bytesNeeded = hdr_len-m_PesHeaderPtr;
+        if (size < bytesNeeded)
+        {
+          memcpy(m_PesHeader+m_PesHeaderPtr, data, size);
+          m_PesHeaderPtr += size;
+          return false;
+        }
+        else if (bytesNeeded > 0)
+        {
+          memcpy(m_PesHeader+m_PesHeaderPtr, data, bytesNeeded);
+          m_PesHeaderPtr += bytesNeeded;
+          data += bytesNeeded;
+          size -= bytesNeeded;
+        }
+        if ((m_PesHeader[6] & 0x30))
+        {
+          Reset();
+          m_Error |= ERROR_PES_SCRAMBLE;
+          return false;
+        }
+        hdr_len = PesHeaderLength(m_PesHeader);
+        if (hdr_len > PES_HEADER_LENGTH)
+        {
+          Reset();
+          return false;
+        }
+      }
+      bytesNeeded = hdr_len-m_PesHeaderPtr;
+      if (size < bytesNeeded)
+      {
+        memcpy(m_PesHeader+m_PesHeaderPtr, data, size);
+        m_PesHeaderPtr += size;
+        return false;
+      }
+      else if (bytesNeeded > 0)
+      {
+        memcpy(m_PesHeader+m_PesHeaderPtr, data, bytesNeeded);
+        m_PesHeaderPtr += bytesNeeded;
+        data += bytesNeeded;
+        size -= bytesNeeded;
+      }
+      if (ParsePESHeader(m_PesHeader, hdr_len) < 0)
+      {
+        INFOLOG("error parsing pes packet error ");
+        Reset();
+        return false;
+      }
+      m_PesHeaderPtr = 0;
+      m_IsPusi = false;
+    }
+    else if (!IsValidStartCode(data, size))
+    {
+      Reset();
+      m_Error |= ERROR_PES_STARTCODE;
+      return false;
+    }
+    else
+    {
+      if (PesIsVideoPacket(data) || PesIsAudioPacket(data))
+      {
+        if (size < 9)
+        {
+          memcpy(m_PesHeader+m_PesHeaderPtr, data, size);
+          m_PesHeaderPtr += size;
+          return false;
+        }
+        if ((data[6] & 0x30))
+        {
+          Reset();
+          m_Error |= ERROR_PES_STARTCODE;
+          return false;
+        }
+        hdr_len = PesHeaderLength(data);
+        if (hdr_len > PES_HEADER_LENGTH)
+        {
+          Reset();
+          return false;
+        }
+      }
+      if (size < hdr_len)
+      {
+        memcpy(m_PesHeader+m_PesHeaderPtr, data, size);
+        m_PesHeaderPtr += size;
+        return false;
+      }
+      if (ParsePESHeader(data, hdr_len) < 0)
+      {
+        INFOLOG("error parsing pes packet error 2");
+        Reset();
+        return false;
+      }
+      data += hdr_len;
+      size -= hdr_len;
+      m_IsPusi = false;
+    }
+  }
+
+  if (m_PesBuffer == NULL)
+  {
+    m_PesBufferSize = m_PesBufferInitialSize;
+    m_PesBuffer = (uint8_t*)malloc(m_PesBufferSize);
+    if (m_PesBuffer == NULL)
+    {
+      ERRORLOG("cParser::AddPESPacket - malloc failed");
+      Reset();
+      return false;
+    }
+  }
+
+  if (m_PesBufferPtr + size >= m_PesBufferSize)
+  {
+    if (m_PesBufferPtr + size >= 1000000)
+    {
+      ERRORLOG("cParser::AddPESPacket - max buffer size reached, pid: %d", m_pID);
+      Reset();
+      return false;
+    }
+    m_PesBufferSize += m_PesBufferInitialSize / 10;
+    uint8_t *new_buffer = (uint8_t*)realloc(m_PesBuffer, m_PesBufferSize);
+    if (new_buffer == NULL)
+    {
+      ERRORLOG("cParser::AddPESPacket - realloc failed");
+      Reset();
+      return false;
+    }
+
+    m_PesBuffer = new_buffer;
+  }
+
+  // copy first packet of new frame to front
+  if (m_PesNextFramePtr)
+  {
+    memmove(m_PesBuffer, m_PesBuffer+m_PesNextFramePtr, m_PesBufferPtr-m_PesNextFramePtr);
+    m_PesBufferPtr = m_PesBufferPtr-m_PesNextFramePtr;
+    m_PesTimePos -= m_PesNextFramePtr;
+    m_PesNextFramePtr = 0;
+  }
+
+  // copy payload
+  memcpy(m_PesBuffer+m_PesBufferPtr, data, size);
+  m_PesBufferPtr += size;
+
+  return true;
+}
+
+inline bool cParser::IsValidStartCode(uint8_t *buf, int size)
+{
+  if (size < 4)
+    return false;
+
+  uint32_t startcode = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+  if (m_Stream->Type() == stH264 || m_Stream->Type() == stHEVC ||m_Stream->Type() == stMPEG2VIDEO)
+  {
+    if (startcode >= 0x000001e0 && startcode <= 0x000001ef)
+      return true;
+  }
+  else if (m_Stream->Type() == stAC3 ||
+      m_Stream->Type() == stEAC3)
+  {
+    if (PesIsPS1Packet(buf))
+      return true;
+  }
+  else if (m_Stream->Type() == stMPEG2AUDIO ||
+      m_Stream->Type() == stAACADTS ||
+      m_Stream->Type() == stAACLATM ||
+      m_Stream->Type() == stDTS)
+  {
+    if (startcode >= 0x000001c0 && startcode <= 0x000001df)
+      return true;
+  }
+  else if (m_Stream->Type() == stTELETEXT)
+  {
+    if (PesIsPS1Packet(buf))
+      return true;
+  }
+  else if (m_Stream->Type() == stDVBSUB ||
+      m_Stream->Type() == stTEXTSUB)
+  {
+    if (startcode == 0x000001bd ||
+        startcode == 0x000001bf ||
+        (startcode >= 0x000001f0 && startcode <= 0x000001f9))
+      return true;
+  }
+  return false;
+}
+
+// --- cTSStream ----------------------------------------------------
+
+uint32_t cTSStream::m_UniqueSideDataIDs = 0;
+
+cTSStream::cTSStream(eStreamType type, int pid, sPtsWrap *ptsWrap, bool handleSideData)
+  : m_streamType(type)
+  , m_pID(pid)
+{
+  m_pesParser       = NULL;
+  m_language[0]     = 0;
+  m_FpsScale        = 0;
+  m_FpsRate         = 0;
+  m_Height          = 0;
+  m_Width           = 0;
+  m_Aspect          = 0.0f;
+  m_Channels        = 0;
+  m_SampleRate      = 0;
+  m_BitRate         = 0;
+  m_BitsPerSample   = 0;
+  m_BlockAlign      = 0;
+  m_IsStreamChange  = false;
+
+  if (m_streamType == stMPEG2VIDEO)
+  {
+    m_pesParser = new cParserMPEG2Video(m_pID, this, ptsWrap, true);
+    m_streamContent = scVIDEO;
+  }
+  else if (m_streamType == stH264)
+  {
+    m_pesParser = new cParserH264(m_pID, this, ptsWrap, true);
+    m_streamContent = scVIDEO;
+  }
+  else if (m_streamType == stHEVC)
+  {
+    m_pesParser = new cParserHEVC(m_pID, this, ptsWrap, true);
+    m_streamContent = scVIDEO;
+  }
+  else if (m_streamType == stMPEG2AUDIO)
+  {
+    m_pesParser = new cParserMPEG2Audio(m_pID, this, ptsWrap, true, handleSideData);
+    m_streamContent = scAUDIO;
+  }
+  else if (m_streamType == stAACADTS)
+  {
+    m_pesParser = new cParserAAC(m_pID, this, ptsWrap, true);
+    m_streamContent = scAUDIO;
+  }
+  else if (m_streamType == stAACLATM)
+  {
+    m_pesParser = new cParserAAC(m_pID, this, ptsWrap, true);
+    m_streamContent = scAUDIO;
+  }
+  else if (m_streamType == stAC3)
+  {
+    m_pesParser = new cParserAC3(m_pID, this, ptsWrap, true);
+    m_streamContent = scAUDIO;
+  }
+  else if (m_streamType == stEAC3)
+  {
+    m_pesParser = new cParserAC3(m_pID, this, ptsWrap, true);
+    m_streamContent = scAUDIO;
+  }
+  else if (m_streamType == stDTS)
+  {
+    m_pesParser = new cParserDTS(m_pID, this, ptsWrap, true);
+    m_streamContent = scAUDIO;
+  }
+  else if (m_streamType == stTELETEXT)
+  {
+    m_pesParser = new cParserTeletext(m_pID, this, ptsWrap, false);
+    m_streamContent = scTELETEXT;
+  }
+  else if (m_streamType == stDVBSUB)
+  {
+    m_pesParser = new cParserSubtitle(m_pID, this, ptsWrap, false);
+    m_streamContent = scSUBTITLE;
+  }
+  else
+  {
+    ERRORLOG("Unrecognised type %i inside stream %i", m_streamType, m_pID);
+    return;
+  }
+}
+
+cTSStream::~cTSStream()
+{
+  if (m_pesParser)
+  {
+    delete m_pesParser;
+    m_pesParser = NULL;
+  }
+}
+
+int cTSStream::ProcessTSPacket(uint8_t *data, sStreamPacket *pkt, sStreamPacket *pkt_side_data, bool iframe)
+{
+  int ret = 1;
+  int lastError = m_pesParser->GetError();
+
+  if (!data)
+    return ret;
+
+  if (!m_pesParser)
+    return ret;
+
+  int payloadSize = m_pesParser->ParsePacketHeader(data);
+  if (payloadSize == 0)
+  {
+    return ret;
+  }
+  else if (payloadSize < 0)
+  {
+    if (lastError)
+      return 1;
+    else
+      return -m_pesParser->GetError();
+  }
+
+  if (!m_pesParser->AddPESPacket(data+TS_SIZE-payloadSize, payloadSize))
+  {
+    return -m_pesParser->GetError();
+  }
+
+  m_pesParser->Parse(pkt, pkt_side_data);
+  if (iframe && !m_pesParser->IsVideo())
+    return ret;
+
+  if (pkt->data)
+  {
+    int64_t dts = pkt->dts;
+    int64_t pts = pkt->pts;
+
+    // Rescale for KODI
+    if (pkt->dts != DVD_NOPTS_VALUE)
+      pkt->dts      = Rescale(dts, DVD_TIME_BASE, 90000);
+    if (pkt->pts != DVD_NOPTS_VALUE)
+      pkt->pts      = Rescale(pts, DVD_TIME_BASE, 90000);
+    pkt->duration = Rescale(pkt->duration, DVD_TIME_BASE, 90000);
+
+    ret = 0;
+  }
+
+  if (pkt_side_data && pkt_side_data->data)
+  {
+    int64_t dts = pkt_side_data->dts;
+    int64_t pts = pkt_side_data->pts;
+
+    // Rescale for KODI
+    if (pkt_side_data->dts != DVD_NOPTS_VALUE)
+      pkt_side_data->dts      = Rescale(dts, DVD_TIME_BASE, 90000);
+    if (pkt_side_data->pts != DVD_NOPTS_VALUE)
+      pkt_side_data->pts      = Rescale(pts, DVD_TIME_BASE, 90000);
+    pkt_side_data->duration = Rescale(pkt_side_data->duration, DVD_TIME_BASE, 90000);
+
+    ret = 0;
+  }
+
+  return ret;
+}
+
+bool cTSStream::ReadTime(uint8_t *data, int64_t *dts)
+{
+  if (!data)
+    return false;
+
+  if (!m_pesParser)
+    return false;
+
+  int payloadSize = m_pesParser->ParsePacketHeader(data);
+  if (payloadSize < 0)
+    return false;
+
+  if (m_pesParser->m_IsPusi)
+  {
+    data += TS_SIZE-payloadSize;
+    if (payloadSize >= 6 && m_pesParser->IsValidStartCode(data, payloadSize))
+    {
+      m_pesParser->m_curPTS = DVD_NOPTS_VALUE;
+      m_pesParser->m_curDTS = DVD_NOPTS_VALUE;
+      m_pesParser->ParsePESHeader(data, payloadSize);
+      if (m_pesParser->m_curDTS != DVD_NOPTS_VALUE)
+      {
+        *dts = m_pesParser->m_curDTS;
+        return true;
+      }
+      else if (m_pesParser->m_curPTS != DVD_NOPTS_VALUE)
+      {
+        *dts = m_pesParser->m_curPTS;
+        return true;
+      }
+    }
+    m_pesParser->m_IsPusi = false;
+  }
+  return false;
+}
+
+void cTSStream::ResetParser()
+{
+  if (m_pesParser)
+    m_pesParser->Reset();
+}
+
+int64_t cTSStream::Rescale(int64_t a, int64_t b, int64_t c)
+{
+  uint64_t r = c/2;
+
+  if (b<=INT_MAX && c<=INT_MAX)
+  {
+    if (a<=INT_MAX)
+      return (a * b + r)/c;
+    else
+      return a/c*b + (a%c*b + r)/c;
+  }
+  else
+  {
+    uint64_t a0= a&0xFFFFFFFF;
+    uint64_t a1= a>>32;
+    uint64_t b0= b&0xFFFFFFFF;
+    uint64_t b1= b>>32;
+    uint64_t t1= a0*b1 + a1*b0;
+    uint64_t t1a= t1<<32;
+
+    a0 = a0*b0 + t1a;
+    a1 = a1*b1 + (t1>>32) + (a0<t1a);
+    a0 += r;
+    a1 += a0<r;
+
+    for (int i=63; i>=0; i--)
+    {
+      a1+= a1 + ((a0>>i)&1);
+      t1+=t1;
+      if (c <= (int64_t)a1)
+      {
+        a1 -= c;
+        t1++;
+      }
+    }
+    return t1;
+  }
+}
+
+uint32_t cTSStream::AddSideDataType(eStreamContent content)
+{
+  m_UniqueSideDataIDs++;
+  if (m_UniqueSideDataIDs == 0)
+    m_UniqueSideDataIDs++;
+
+  uint32_t sidePid = m_UniqueSideDataIDs << 16;
+
+  m_SideDataTypes.push_back(std::make_pair(sidePid, content));
+
+  return sidePid;
+}
+
+void cTSStream::SetLanguage(const char *language)
+{
+  m_language[0] = language[0];
+  m_language[1] = language[1];
+  m_language[2] = language[2];
+  m_language[3] = 0;
+}
+
+bool cTSStream::SetVideoInformation(int FpsScale, int FpsRate, int Height, int Width, float Aspect)
+{
+  if ((m_FpsScale != FpsScale) ||
+      (m_FpsRate != FpsRate) ||
+      (m_Height != Height) ||
+      (m_Width != Width) ||
+      (m_Aspect != Aspect))
+  {
+    INFOLOG("Video stream change, pid: %d, width: %d, height: %d, aspect: %f", m_pID, Width, Height, Aspect);
+    m_IsStreamChange = true;
+  }
+
+  m_FpsScale        = FpsScale;
+  m_FpsRate         = FpsRate;
+  m_Height          = Height;
+  m_Width           = Width;
+  m_Aspect          = Aspect;
+
+  return m_IsStreamChange;
+}
+
+void cTSStream::GetVideoInformation(uint32_t &FpsScale, uint32_t &FpsRate, uint32_t &Height, uint32_t &Width, double &Aspect)
+{
+  FpsScale = m_FpsScale;
+  FpsRate = m_FpsRate;
+  Height = m_Height;
+  Width = m_Width;
+  Aspect = m_Aspect;
+
+  m_IsStreamChange = false;
+}
+
+bool cTSStream::SetAudioInformation(int Channels, int SampleRate, int BitRate, int BitsPerSample, int BlockAlign)
+{
+  if ((m_Channels != Channels) ||
+      (m_SampleRate != SampleRate) ||
+      (m_BlockAlign != BlockAlign) ||
+      (m_BitRate != BitRate) ||
+      (m_BitsPerSample != BitsPerSample))
+  {
+    INFOLOG("Audio stream change, pid: %d, channels: %d, samplerate: %d", m_pID, Channels, SampleRate);
+    m_IsStreamChange = true;
+  }
+
+  m_Channels        = Channels;
+  m_SampleRate      = SampleRate;
+  m_BlockAlign      = BlockAlign;
+  m_BitRate         = BitRate;
+  m_BitsPerSample   = BitsPerSample;
+
+  return m_IsStreamChange;
+}
+
+void cTSStream::GetAudioInformation(uint32_t &Channels, uint32_t &SampleRate, uint32_t &BitRate, uint32_t &BitsPerSample, uint32_t &BlockAlign)
+{
+  Channels = m_Channels;
+  SampleRate = m_SampleRate;
+  BlockAlign = m_BlockAlign;
+  BitRate = m_BitRate;
+  BitsPerSample = m_BitsPerSample;
+
+  m_IsStreamChange = false;
+}
+
+void cTSStream::SetSubtitlingDescriptor(unsigned char SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
+{
+  m_subtitlingType    = SubtitlingType;
+  m_compositionPageId = CompositionPageId;
+  m_ancillaryPageId   = AncillaryPageId;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser.h b/v/vdr-plugin-vnsiserver-1.8.0/parser.h
new file mode 100644 (file)
index 0000000..405f600
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <vector>
+#include <cstddef>
+#include <stdint.h>
+
+#define DVD_TIME_BASE 1000000
+#define DVD_NOPTS_VALUE    (-1LL<<52) // should be possible to represent in both double and __int64
+
+/* PES PIDs */
+#define PRIVATE_STREAM1   0xBD
+#define PADDING_STREAM    0xBE
+#define PRIVATE_STREAM2   0xBF
+#define PRIVATE_STREAM3   0xFD
+#define AUDIO_STREAM_S    0xC0      /* 1100 0000 */
+#define AUDIO_STREAM_E    0xDF      /* 1101 1111 */
+#define VIDEO_STREAM_S    0xE0      /* 1110 0000 */
+#define VIDEO_STREAM_E    0xEF      /* 1110 1111 */
+
+#define AUDIO_STREAM_MASK 0x1F  /* 0001 1111 */
+#define VIDEO_STREAM_MASK 0x0F  /* 0000 1111 */
+#define AUDIO_STREAM      0xC0  /* 1100 0000 */
+#define VIDEO_STREAM      0xE0  /* 1110 0000 */
+
+#define ECM_STREAM        0xF0
+#define EMM_STREAM        0xF1
+#define DSM_CC_STREAM     0xF2
+#define ISO13522_STREAM   0xF3
+#define PROG_STREAM_DIR   0xFF
+
+inline bool PesIsHeader(const unsigned char *p)
+{
+  return !(p)[0] && !(p)[1] && (p)[2] == 1;
+}
+
+inline int PesHeaderLength(const unsigned char *p)
+{
+  return 8 + (p)[8] + 1;
+}
+
+inline bool PesIsVideoPacket(const unsigned char *p)
+{
+  return (((p)[3] & ~VIDEO_STREAM_MASK) == VIDEO_STREAM);
+}
+
+inline bool PesIsMPEGAudioPacket(const unsigned char *p)
+{
+  return (((p)[3] & ~AUDIO_STREAM_MASK) == AUDIO_STREAM);
+}
+
+inline bool PesIsPS1Packet(const unsigned char *p)
+{
+  return ((p)[3] == PRIVATE_STREAM1 || (p)[3] == PRIVATE_STREAM3 );
+}
+
+inline bool PesIsAudioPacket(const unsigned char *p)
+{
+  return (PesIsMPEGAudioPacket(p) || PesIsPS1Packet(p));
+}
+
+enum eStreamContent
+{
+  scVIDEO,
+  scAUDIO,
+  scSUBTITLE,
+  scTELETEXT,
+  scPROGRAMM,
+  scRDS
+};
+
+enum eStreamType
+{
+  stNone,
+  stAC3,
+  stMPEG2AUDIO,
+  stEAC3,
+  stAACADTS,
+  stAACLATM,
+  stDTS,
+  stMPEG2VIDEO,
+  stH264,
+  stHEVC,
+  stDVBSUB,
+  stTEXTSUB,
+  stTELETEXT,
+};
+
+#define PKT_I_FRAME 1
+#define PKT_P_FRAME 2
+#define PKT_B_FRAME 3
+#define PKT_NTYPES  4
+struct sStreamPacket
+{
+  int64_t   id;
+  int64_t   dts;
+  int64_t   pts;
+  int       duration;
+
+  uint8_t   commercial;
+  uint8_t   componentindex;
+
+  uint8_t  *data;
+  int       size;
+  bool      streamChange;
+  bool      pmtChange;
+  uint32_t  serial;
+  uint32_t  reftime;
+};
+
+struct sPtsWrap
+{
+  bool m_Wrap;
+  int m_NoOfWraps;
+  int m_ConfirmCount;
+};
+
+class cTSStream;
+
+#define PES_HEADER_LENGTH 128
+
+class cParser
+{
+friend class cTSStream;
+public:
+  cParser(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParser();
+
+  cParser(const cParser &) = delete;
+  cParser &operator=(const cParser &) = delete;
+
+  bool AddPESPacket(uint8_t *data, int size);
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data) = 0;
+  int ParsePacketHeader(uint8_t *data);
+  int ParsePESHeader(uint8_t *buf, size_t len);
+  virtual void Reset();
+  bool IsVideo() {return m_IsVideo; }
+  uint16_t GetError() { return m_Error; }
+
+protected:
+  virtual bool IsValidStartCode(uint8_t *buf, int size);
+
+  uint8_t     m_PesHeader[PES_HEADER_LENGTH];
+  int         m_PesHeaderPtr;
+  int         m_PesPacketLength;
+  uint8_t    *m_PesBuffer;
+  int         m_PesBufferSize;
+  int         m_PesBufferPtr;
+  size_t      m_PesBufferInitialSize;
+  size_t      m_PesParserPtr;
+  size_t      m_PesNextFramePtr;
+  int         m_PesTimePos;
+
+  bool        m_FoundFrame;
+  bool        m_FrameValid;
+
+  int         m_pID;
+  int64_t     m_curPTS;
+  int64_t     m_curDTS;
+  int64_t     m_prevPTS;
+  int64_t     m_prevDTS;
+
+  bool m_IsPusi;
+  uint16_t m_Error;
+  int m_scrambleCounter = 0;
+
+  cTSStream *m_Stream;
+  bool m_IsVideo;
+  sPtsWrap *m_PtsWrap;
+  bool m_ObservePtsWraps;
+};
+
+
+class cTSStream
+{
+private:
+  eStreamType           m_streamType;
+  const int             m_pID;
+  eStreamContent        m_streamContent;
+  bool                  m_IsStreamChange;
+
+  cParser              *m_pesParser;
+
+  char                  m_language[4];  // ISO 639 3-letter language code (empty string if undefined)
+
+  int                   m_FpsScale;     // scale of 1000 and a rate of 29970 will result in 29.97 fps
+  int                   m_FpsRate;
+  int                   m_Height;       // height of the stream reported by the demuxer
+  int                   m_Width;        // width of the stream reported by the demuxer
+  float                 m_Aspect;       // display aspect of stream
+
+  int                   m_Channels;
+  int                   m_SampleRate;
+  int                   m_BitRate;
+  int                   m_BitsPerSample;
+  int                   m_BlockAlign;
+
+  std::vector< std::pair<uint32_t, eStreamContent> >  m_SideDataTypes;
+  static uint32_t       m_UniqueSideDataIDs;
+
+  unsigned char         m_subtitlingType;
+  uint16_t              m_compositionPageId;
+  uint16_t              m_ancillaryPageId;
+
+public:
+  cTSStream(eStreamType type, int pid, sPtsWrap *ptsWrap, bool handleSideData = false);
+  virtual ~cTSStream();
+
+  cTSStream(const cTSStream &) = delete;
+  cTSStream &operator=(const cTSStream &) = delete;
+
+  int ProcessTSPacket(uint8_t *data, sStreamPacket *pkt, sStreamPacket *pkt_side_data, bool iframe);
+  bool ReadTime(uint8_t *data, int64_t *dts);
+  void ResetParser();
+
+  void SetLanguage(const char *language);
+  const char *GetLanguage() { return m_language; }
+  eStreamContent Content() const { return m_streamContent; }
+  eStreamType Type() const { return m_streamType; }
+  void SetType(eStreamType type) { m_streamType = type; }
+  int GetPID() const { return m_pID; }
+
+  uint32_t AddSideDataType(eStreamContent content);
+  const std::vector< std::pair<uint32_t, eStreamContent> > &GetSideDataTypes() const { return m_SideDataTypes; }
+
+  /* Video Stream Information */
+  bool SetVideoInformation(int FpsScale, int FpsRate, int Height, int Width, float Aspect);
+  void GetVideoInformation(uint32_t &FpsScale, uint32_t &FpsRate, uint32_t &Height, uint32_t &Width, double &Aspect);
+
+  /* Audio Stream Information */
+  bool SetAudioInformation(int Channels, int SampleRate, int BitRate, int BitsPerSample, int BlockAlign);
+  void GetAudioInformation(uint32_t &Channels, uint32_t &SampleRate, uint32_t &BitRate, uint32_t &BitsPerSample, uint32_t &BlockAlign);
+
+  /* Subtitle related stream information */
+  void SetSubtitlingDescriptor(unsigned char SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId);
+  unsigned char SubtitlingType() const { return m_subtitlingType; }
+  uint16_t CompositionPageId() const { return m_compositionPageId; }
+  uint16_t AncillaryPageId() const { return m_ancillaryPageId; }
+
+  static int64_t Rescale(int64_t a, int64_t b, int64_t c);
+};
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_AAC.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_AAC.c
new file mode 100644 (file)
index 0000000..9fec5ce
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_AAC.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+static int aac_sample_rates[16] =
+{
+  96000, 88200, 64000, 48000, 44100, 32000,
+  24000, 22050, 16000, 12000, 11025, 8000, 7350
+};
+
+
+cParserAAC::cParserAAC(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_Configured                = false;
+  m_FrameLengthType           = 0;
+  m_PTS                       = 0;
+  m_DTS                       = 0;
+  m_FrameSize                 = 0;
+  m_SampleRate                = 0;
+  m_Channels                  = 0;
+  m_BitRate                   = 0;
+  m_PesBufferInitialSize      = 1920*2;
+  m_DetectMuxMode             = false;
+
+  char *detectEnv = getenv("VNSI_AAC_MUXMODE");
+  if (detectEnv)
+  {
+    m_DetectMuxMode = true;
+    INFOLOG("cParserAAC - detect muxing mode while parsing");
+  }
+}
+
+cParserAAC::~cParserAAC()
+{
+
+}
+
+void cParserAAC::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  int p = m_PesParserPtr;
+  int l;
+  while ((l = m_PesBufferPtr - p) > 8)
+  {
+    if (FindHeaders(m_PesBuffer + p, l) < 0)
+      break;
+    p++;
+  }
+  m_PesParserPtr = p;
+
+  if (m_FoundFrame && l >= m_FrameSize)
+  {
+    bool streamChange = m_Stream->SetAudioInformation(m_Channels, m_SampleRate, m_BitRate, 0, 0);
+    pkt->id       = m_pID;
+    pkt->data     = &m_PesBuffer[p];
+    pkt->size     = m_FrameSize;
+    if(!m_SampleRate)
+      m_SampleRate = aac_sample_rates[4];
+    pkt->duration = 1024 * 90000 / m_SampleRate;
+    pkt->dts      = m_DTS;
+    pkt->pts      = m_PTS;
+    pkt->streamChange = streamChange;
+
+    m_PesNextFramePtr = p + m_FrameSize;
+    m_PesParserPtr = 0;
+    m_FoundFrame = false;
+  }
+}
+
+int cParserAAC::FindHeaders(uint8_t *buf, int buf_size)
+{
+  if (m_FoundFrame)
+    return -1;
+
+  uint8_t *buf_ptr = buf;
+
+  if (m_Stream->Type() == stAACLATM)
+  {
+    if ((buf_ptr[0] == 0x56 && (buf_ptr[1] & 0xE0) == 0xE0))
+    {
+      // TODO
+      if (buf_size < 16)
+        return -1;
+
+      cBitstream bs(buf_ptr, 16 * 8);
+      bs.skipBits(11);
+      m_FrameSize = bs.readBits(13) + 3;
+      if (!ParseLATMAudioMuxElement(&bs))
+        return 0;
+
+      m_FoundFrame = true;
+      m_DTS = m_curPTS;
+      m_PTS = m_curPTS;
+      if(!m_SampleRate)
+       m_SampleRate = aac_sample_rates[4];
+      m_curPTS += 90000 * 1024 / m_SampleRate;
+      return -1;
+    }
+    else if (m_DetectMuxMode && buf_ptr[0] == 0xFF && (buf_ptr[1] & 0xF0) == 0xF0)
+    {
+      m_Stream->SetType(stAACADTS);
+      INFOLOG("cParserAAC::FindHeaders - detected ADTS muxing mode");
+      return -1;
+    }
+  }
+  else if (m_Stream->Type() == stAACADTS)
+  {
+    if(buf_ptr[0] == 0xFF && (buf_ptr[1] & 0xF0) == 0xF0)
+    {
+      // need at least 7 bytes for header
+      if (buf_size < 7)
+        return -1;
+
+      cBitstream bs(buf_ptr, 9 * 8);
+      bs.skipBits(15);
+
+      // check if CRC is present, means header is 9 byte long
+      int noCrc = bs.readBits(1);
+      if (!noCrc && (buf_size < 9))
+        return -1;
+
+      bs.skipBits(2); // profile
+      int SampleRateIndex = bs.readBits(4);
+      bs.skipBits(1); // private
+      m_Channels = bs.readBits(3);
+      bs.skipBits(4);
+
+      m_FrameSize = bs.readBits(13);
+      m_SampleRate    = aac_sample_rates[SampleRateIndex & 0x0E];
+
+      if (!m_SampleRate)
+        m_SampleRate = aac_sample_rates[4];
+
+      m_FoundFrame = true;
+      m_DTS = m_curPTS;
+      m_PTS = m_curPTS;
+      m_curPTS += 90000 * 1024 / m_SampleRate;
+      return -1;
+    }
+    else if (m_DetectMuxMode && buf_ptr[0] == 0x56 && (buf_ptr[1] & 0xE0) == 0xE0)
+    {
+      m_Stream->SetType(stAACLATM);
+      INFOLOG("cParserAAC::FindHeaders - detected LATM muxing mode");
+      return -1;
+    }
+  }
+  return 0;
+}
+
+bool cParserAAC::ParseLATMAudioMuxElement(cBitstream *bs)
+{
+  if (!bs->readBits1())
+    ReadStreamMuxConfig(bs);
+
+  if (!m_Configured)
+    return false;
+
+  return true;
+}
+
+void cParserAAC::ReadStreamMuxConfig(cBitstream *bs)
+{
+  int AudioMuxVersion = bs->readBits(1);
+  m_AudioMuxVersion_A = 0;
+  if (AudioMuxVersion)                       // audioMuxVersion
+    m_AudioMuxVersion_A = bs->readBits(1);
+
+  if(m_AudioMuxVersion_A)
+    return;
+
+  if (AudioMuxVersion)
+    LATMGetValue(bs);                      // taraFullness
+
+  bs->skipBits(1);                         // allStreamSameTimeFraming = 1
+  bs->skipBits(6);                         // numSubFrames = 0
+  bs->skipBits(4);                         // numPrograms = 0
+
+  // for each program (which there is only on in DVB)
+  bs->skipBits(3);                         // numLayer = 0
+
+  // for each layer (which there is only on in DVB)
+  if (!AudioMuxVersion)
+    ReadAudioSpecificConfig(bs);
+  else
+    return;
+
+  // these are not needed... perhaps
+  m_FrameLengthType = bs->readBits(3);
+  switch (m_FrameLengthType)
+  {
+    case 0:
+      bs->readBits(8);
+      break;
+    case 1:
+      bs->readBits(9);
+      break;
+    case 3:
+    case 4:
+    case 5:
+      bs->readBits(6);                 // celp_table_index
+      break;
+    case 6:
+    case 7:
+      bs->readBits(1);                 // hvxc_table_index
+      break;
+  }
+
+  if (bs->readBits(1))
+  {                   // other data?
+    if (AudioMuxVersion == 1)
+    {
+      LATMGetValue(bs);              // other_data_bits
+    }
+    else
+    {
+      int esc;
+      do
+      {
+        esc = bs->readBits(1);
+        bs->skipBits(8);
+      } while (esc);
+    }
+  }
+
+  if (bs->readBits(1))                   // crc present?
+    bs->skipBits(8);                     // config_crc
+  m_Configured = true;
+}
+
+void cParserAAC::ReadAudioSpecificConfig(cBitstream *bs)
+{
+  int aot = bs->readBits(5);
+  if (aot == 31)
+    aot = 32 + bs->readBits(6);
+
+  int SampleRateIndex = bs->readBits(4);
+
+  if (SampleRateIndex == 0xf)
+    m_SampleRate = bs->readBits(24);
+  else
+    m_SampleRate = aac_sample_rates[SampleRateIndex & 0xf];
+
+  m_Channels = bs->readBits(4);
+
+  if (aot == 5) { // AOT_SBR
+    if (bs->readBits(4) == 0xf) { // extensionSamplingFrequencyIndex
+      bs->skipBits(24);
+    }
+    aot = bs->readBits(5); // this is the main object type (i.e. non-extended)
+    if (aot == 31)
+      aot = 32 + bs->readBits(6);
+  }
+
+  if(aot != 2)
+    return;
+
+  bs->skipBits(1);      //framelen_flag
+  if (bs->readBits1())  // depends_on_coder
+    bs->skipBits(14);
+
+  if (bs->readBits(1))  // ext_flag
+    bs->skipBits(1);    // ext3_flag
+}
+
+void cParserAAC::Reset()
+{
+  cParser::Reset();
+  m_Configured = false;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_AAC.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_AAC.h
new file mode 100644 (file)
index 0000000..d898626
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_AAC_H
+#define VNSI_DEMUXER_AAC_H
+
+#include "parser.h"
+#include "bitstream.h"
+
+// --- cParserAAC -------------------------------------------------
+
+class cParserAAC : public cParser
+{
+private:
+  int         m_SampleRate;
+  int         m_Channels;
+  int         m_BitRate;
+  int         m_FrameSize;
+
+  int64_t     m_PTS;                /* pts of the current frame */
+  int64_t     m_DTS;                /* dts of the current frame */
+
+  bool        m_Configured;
+  int         m_AudioMuxVersion_A;
+  int         m_FrameLengthType;
+  bool        m_DetectMuxMode;
+
+  int FindHeaders(uint8_t *buf, int buf_size);
+  bool ParseLATMAudioMuxElement(cBitstream *bs);
+  void ReadStreamMuxConfig(cBitstream *bs);
+  void ReadAudioSpecificConfig(cBitstream *bs);
+  uint32_t LATMGetValue(cBitstream *bs) { return bs->readBits(bs->readBits(2) * 8); }
+
+public:
+  cParserAAC(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserAAC();
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+  virtual void Reset();
+};
+
+#endif // VNSI_DEMUXER_AAC_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_AC3.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_AC3.c
new file mode 100644 (file)
index 0000000..94b13e5
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_AC3.h"
+#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define AC3_HEADER_SIZE 7
+
+/** Channel mode (audio coding mode) */
+typedef enum
+{
+  AC3_CHMODE_DUALMONO = 0,
+  AC3_CHMODE_MONO,
+  AC3_CHMODE_STEREO,
+  AC3_CHMODE_3F,
+  AC3_CHMODE_2F1R,
+  AC3_CHMODE_3F1R,
+  AC3_CHMODE_2F2R,
+  AC3_CHMODE_3F2R
+} AC3ChannelMode;
+
+/* possible frequencies */
+const uint16_t AC3SampleRateTable[3] = { 48000, 44100, 32000 };
+
+/* possible bitrates */
+const uint16_t AC3BitrateTable[19] = {
+    32, 40, 48, 56, 64, 80, 96, 112, 128,
+    160, 192, 224, 256, 320, 384, 448, 512, 576, 640
+};
+
+const uint8_t AC3ChannelsTable[8] = {
+    2, 1, 2, 3, 3, 4, 4, 5
+};
+
+const uint16_t AC3FrameSizeTable[38][3] = {
+    { 64,   69,   96   },
+    { 64,   70,   96   },
+    { 80,   87,   120  },
+    { 80,   88,   120  },
+    { 96,   104,  144  },
+    { 96,   105,  144  },
+    { 112,  121,  168  },
+    { 112,  122,  168  },
+    { 128,  139,  192  },
+    { 128,  140,  192  },
+    { 160,  174,  240  },
+    { 160,  175,  240  },
+    { 192,  208,  288  },
+    { 192,  209,  288  },
+    { 224,  243,  336  },
+    { 224,  244,  336  },
+    { 256,  278,  384  },
+    { 256,  279,  384  },
+    { 320,  348,  480  },
+    { 320,  349,  480  },
+    { 384,  417,  576  },
+    { 384,  418,  576  },
+    { 448,  487,  672  },
+    { 448,  488,  672  },
+    { 512,  557,  768  },
+    { 512,  558,  768  },
+    { 640,  696,  960  },
+    { 640,  697,  960  },
+    { 768,  835,  1152 },
+    { 768,  836,  1152 },
+    { 896,  975,  1344 },
+    { 896,  976,  1344 },
+    { 1024, 1114, 1536 },
+    { 1024, 1115, 1536 },
+    { 1152, 1253, 1728 },
+    { 1152, 1254, 1728 },
+    { 1280, 1393, 1920 },
+    { 1280, 1394, 1920 },
+};
+
+const uint8_t EAC3Blocks[4] = {
+  1, 2, 3, 6
+};
+
+typedef enum {
+  EAC3_FRAME_TYPE_INDEPENDENT = 0,
+  EAC3_FRAME_TYPE_DEPENDENT,
+  EAC3_FRAME_TYPE_AC3_CONVERT,
+  EAC3_FRAME_TYPE_RESERVED
+} EAC3FrameType;
+
+cParserAC3::cParserAC3(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_PTS                       = 0;
+  m_DTS                       = 0;
+  m_FrameSize                 = 0;
+  m_SampleRate                = 0;
+  m_Channels                  = 0;
+  m_BitRate                   = 0;
+  m_PesBufferInitialSize      = 1920*2;
+}
+
+cParserAC3::~cParserAC3()
+{
+}
+
+void cParserAC3::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  int p = m_PesParserPtr;
+  int l;
+  while ((l = m_PesBufferPtr - p) > 8)
+  {
+    if (FindHeaders(m_PesBuffer + p, l) < 0)
+      break;
+    p++;
+  }
+  m_PesParserPtr = p;
+
+  if (m_FoundFrame && l >= m_FrameSize)
+  {
+    bool streamChange = m_Stream->SetAudioInformation(m_Channels, m_SampleRate, m_BitRate, 0, 0);
+    pkt->id       = m_pID;
+    pkt->data     = &m_PesBuffer[p];
+    pkt->size     = m_FrameSize;
+    pkt->duration = 90000 * 1536 / m_SampleRate;
+    pkt->dts      = m_DTS;
+    pkt->pts      = m_PTS;
+    pkt->streamChange = streamChange;
+
+    m_PesNextFramePtr = p + m_FrameSize;
+    m_PesParserPtr = 0;
+    m_FoundFrame = false;
+  }
+}
+
+int cParserAC3::FindHeaders(uint8_t *buf, int buf_size)
+{
+  if (m_FoundFrame)
+    return -1;
+
+  if (buf_size < 9)
+    return -1;
+
+  uint8_t *buf_ptr = buf;
+
+  if ((buf_ptr[0] == 0x0b && buf_ptr[1] == 0x77))
+  {
+    cBitstream bs(buf_ptr + 2, AC3_HEADER_SIZE * 8);
+
+    // read ahead to bsid to distinguish between AC-3 and E-AC-3
+    int bsid = bs.showBits(29) & 0x1F;
+    if (bsid > 16)
+      return 0;
+
+    if (bsid <= 10)
+    {
+      // Normal AC-3
+      bs.skipBits(16);
+      int fscod       = bs.readBits(2);
+      int frmsizecod  = bs.readBits(6);
+      bs.skipBits(5); // skip bsid, already got it
+      bs.skipBits(3); // skip bitstream mode
+      int acmod       = bs.readBits(3);
+
+      if (fscod == 3 || frmsizecod > 37)
+        return 0;
+
+      if (acmod == AC3_CHMODE_STEREO)
+      {
+        bs.skipBits(2); // skip dsurmod
+      }
+      else
+      {
+        if ((acmod & 1) && acmod != AC3_CHMODE_MONO)
+          bs.skipBits(2);
+        if (acmod & 4)
+          bs.skipBits(2);
+      }
+      int lfeon = bs.readBits(1);
+
+      int srShift   = std::max(bsid, 8) - 8;
+      m_SampleRate  = AC3SampleRateTable[fscod] >> srShift;
+      m_BitRate     = (AC3BitrateTable[frmsizecod>>1] * 1000) >> srShift;
+      m_Channels    = AC3ChannelsTable[acmod] + lfeon;
+      m_FrameSize   = AC3FrameSizeTable[frmsizecod][fscod] * 2;
+    }
+    else
+    {
+      // Enhanced AC-3
+      int frametype = bs.readBits(2);
+      if (frametype == EAC3_FRAME_TYPE_RESERVED)
+        return 0;
+
+       bs.readBits(3); // int substreamid
+
+      m_FrameSize = (bs.readBits(11) + 1) << 1;
+      if (m_FrameSize < AC3_HEADER_SIZE)
+        return 0;
+
+      int numBlocks = 6;
+      int sr_code = bs.readBits(2);
+      if (sr_code == 3)
+      {
+        int sr_code2 = bs.readBits(2);
+        if (sr_code2 == 3)
+          return 0;
+        m_SampleRate = AC3SampleRateTable[sr_code2] / 2;
+      }
+      else
+      {
+        numBlocks = EAC3Blocks[bs.readBits(2)];
+        m_SampleRate = AC3SampleRateTable[sr_code];
+      }
+
+      int channelMode = bs.readBits(3);
+      int lfeon = bs.readBits(1);
+
+      m_BitRate  = (uint32_t)(8.0 * m_FrameSize * m_SampleRate / (numBlocks * 256.0));
+      m_Channels = AC3ChannelsTable[channelMode] + lfeon;
+    }
+    m_FoundFrame = true;
+    m_DTS = m_curPTS;
+    m_PTS = m_curPTS;
+    m_curPTS += 90000 * 1536 / m_SampleRate;
+    return -1;
+  }
+  return 0;
+}
+
+void cParserAC3::Reset()
+{
+  cParser::Reset();
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_AC3.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_AC3.h
new file mode 100644 (file)
index 0000000..a70d177
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_AC3_H
+#define VNSI_DEMUXER_AC3_H
+
+#include "parser.h"
+
+// --- cParserAC3 -------------------------------------------------
+
+class cParserAC3 : public cParser
+{
+private:
+  int         m_SampleRate;
+  int         m_Channels;
+  int         m_BitRate;
+  int         m_FrameSize;
+
+  int64_t     m_PTS;                /* pts of the current frame */
+  int64_t     m_DTS;                /* dts of the current frame */
+
+  int FindHeaders(uint8_t *buf, int buf_size);
+
+public:
+  cParserAC3(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserAC3();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+  virtual void Reset();
+};
+
+
+#endif // VNSI_DEMUXER_AC3_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_DTS.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_DTS.c
new file mode 100644 (file)
index 0000000..5395c3b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_DTS.h"
+#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+cParserDTS::cParserDTS(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+}
+
+cParserDTS::~cParserDTS()
+{
+}
+
+void cParserDTS::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_DTS.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_DTS.h
new file mode 100644 (file)
index 0000000..11bd91e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_DTS_H
+#define VNSI_DEMUXER_DTS_H
+
+#include "parser.h"
+
+// --- cParserDTS -------------------------------------------------
+
+class cParserDTS : public cParser
+{
+private:
+
+public:
+  cParserDTS(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserDTS();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+};
+
+
+#endif // VNSI_DEMUXER_DTS_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGAudio.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGAudio.c
new file mode 100644 (file)
index 0000000..2b1ec67
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_MPEGAudio.h"
+#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define MAX_RDS_BUFFER_SIZE 100000
+
+const uint16_t FrequencyTable[3] = { 44100, 48000, 32000 };
+const uint16_t BitrateTable[2][3][15] =
+{
+  {
+    {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 },
+    {0, 32, 48, 56, 64,  80,  96,  112, 128, 160, 192, 224, 256, 320, 384 },
+    {0, 32, 40, 48, 56,  64,  80,  96,  112, 128, 160, 192, 224, 256, 320 }
+  },
+  {
+    {0, 32, 48, 56, 64,  80,  96,  112, 128, 144, 160, 176, 192, 224, 256},
+    {0, 8,  16, 24, 32,  40,  48,  56,  64,  80,  96,  112, 128, 144, 160},
+    {0, 8,  16, 24, 32,  40,  48,  56,  64,  80,  96,  112, 128, 144, 160}
+  }
+};
+
+cParserMPEG2Audio::cParserMPEG2Audio(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps, bool enableRDS)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_PTS                       = 0;
+  m_DTS                       = 0;
+  m_FrameSize                 = 0;
+  m_SampleRate                = 0;
+  m_Channels                  = 0;
+  m_BitRate                   = 0;
+  m_PesBufferInitialSize      = 2048;
+  m_RDSEnabled                = enableRDS;
+  m_RDSBufferInitialSize      = 384;
+  m_RDSBuffer                 = NULL;
+  m_RDSBufferSize             = 0;
+  m_RDSExtPID                 = 0;
+}
+
+cParserMPEG2Audio::~cParserMPEG2Audio()
+{
+  free(m_RDSBuffer);
+}
+
+void cParserMPEG2Audio::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  int p = m_PesParserPtr;
+  int l;
+  while ((l = m_PesBufferPtr - p) > 3)
+  {
+    if (FindHeaders(m_PesBuffer + p, l) < 0)
+      break;
+    p++;
+  }
+  m_PesParserPtr = p;
+
+  if (m_FoundFrame && l >= m_FrameSize)
+  {
+    bool streamChange = m_Stream->SetAudioInformation(m_Channels, m_SampleRate, m_BitRate, 0, 0);
+    pkt->id       = m_pID;
+    pkt->data     = &m_PesBuffer[p];
+    pkt->size     = m_FrameSize;
+    pkt->duration = 90000 * 1152 / m_SampleRate;
+    pkt->dts      = m_DTS;
+    pkt->pts      = m_PTS;
+    pkt->streamChange = streamChange;
+
+    m_PesNextFramePtr = p + m_FrameSize;
+    m_PesParserPtr = 0;
+    m_FoundFrame = false;
+
+    if (m_RDSEnabled)
+    {
+      /*
+       * Reading of RDS Universal Encoder Communication Protocol
+       * If present it starts on end of a mpeg audio stream and goes
+       * backwards.
+       * See ETSI TS 101 154 - C.4.2.18 for details.
+       */
+      int rdsl = m_PesBuffer[p+m_FrameSize-2];                  // RDS DataFieldLength
+      if (m_PesBuffer[p+m_FrameSize-1] == 0xfd && rdsl > 0)     // RDS DataSync = 0xfd @ end
+      {
+        if (m_RDSBuffer == NULL)
+        {
+          m_RDSBufferSize = m_RDSBufferInitialSize;
+          m_RDSBuffer = (uint8_t*)malloc(m_RDSBufferSize);
+
+          if (m_RDSBuffer == NULL)
+          {
+            ERRORLOG("PVR Parser MPEG2-Audio - %s - malloc failed for RDS data", __FUNCTION__);
+            m_RDSEnabled = false;
+            return;
+          }
+
+          m_RDSExtPID = m_Stream->AddSideDataType(scRDS);
+          if (!m_RDSExtPID)
+          {
+            ERRORLOG("PVR Parser MPEG2-Audio - %s - failed to add RDS data stream", __FUNCTION__);
+            m_RDSEnabled = false;
+            return;
+          }
+        }
+
+        if (rdsl >= m_RDSBufferSize)
+        {
+          if (rdsl >= MAX_RDS_BUFFER_SIZE)
+          {
+            ERRORLOG("PVR Parser MPEG2-Audio - %s - max buffer size (%i kB) for RDS data reached, pid: %d", __FUNCTION__, MAX_RDS_BUFFER_SIZE/1024, m_pID);
+            m_RDSEnabled = false;
+            return;
+          }
+          m_RDSBufferSize += m_RDSBufferInitialSize / 10;
+          uint8_t *new_buffer = (uint8_t *)realloc(m_RDSBuffer, m_RDSBufferSize);
+          if (new_buffer == NULL)
+          {
+            ERRORLOG("PVR Parser MPEG2-Audio - %s - realloc for RDS data failed", __FUNCTION__);
+            m_RDSEnabled = false;
+            return;
+          }
+
+          m_RDSBuffer = new_buffer;
+      }
+
+        int pes_buffer_ptr = 0;
+        for (int i = m_FrameSize-3; i > m_FrameSize-3-rdsl; i--)    // <-- data reverse, from end to start
+          m_RDSBuffer[pes_buffer_ptr++] = m_PesBuffer[p+i];
+
+        pkt_side_data->id       = m_RDSExtPID;
+        pkt_side_data->data     = m_RDSBuffer;
+        pkt_side_data->size     = pes_buffer_ptr;
+        pkt_side_data->duration = 0;
+        pkt_side_data->dts      = m_curDTS;
+        pkt_side_data->pts      = m_curPTS;
+        pkt_side_data->streamChange = false;
+      }
+    }
+  }
+}
+
+
+int cParserMPEG2Audio::FindHeaders(uint8_t *buf, int buf_size)
+{
+  if (m_FoundFrame)
+    return -1;
+
+  if (buf_size < 4)
+    return -1;
+
+  uint8_t *buf_ptr = buf;
+
+  if ((buf_ptr[0] == 0xFF && (buf_ptr[1] & 0xE0) == 0xE0))
+  {
+    cBitstream bs(buf_ptr, 4 * 8);
+    bs.skipBits(11); // syncword
+
+    int audioVersion = bs.readBits(2);
+    if (audioVersion == 1)
+      return 0;
+    int mpeg2 = !(audioVersion & 1);
+    int mpeg25 = !(audioVersion & 3);
+
+    int layer = bs.readBits(2);
+    if (layer == 0)
+      return 0;
+    layer = 4 - layer;
+
+    bs.skipBits(1); // protetion bit
+    int bitrate_index = bs.readBits(4);
+    if (bitrate_index == 15 || bitrate_index == 0)
+      return 0;
+    m_BitRate  = BitrateTable[mpeg2][layer - 1][bitrate_index] * 1000;
+
+    int sample_rate_index = bs.readBits(2);
+    if (sample_rate_index == 3)
+      return 0;
+    m_SampleRate = FrequencyTable[sample_rate_index] >> (mpeg2 + mpeg25);
+
+    int padding = bs.readBits1();
+    bs.skipBits(1); // private bit
+    int channel_mode = bs.readBits(2);
+
+    if (channel_mode == 11)
+      m_Channels = 1;
+    else
+      m_Channels = 2;
+
+    if (layer == 1)
+      m_FrameSize = (12 * m_BitRate / m_SampleRate + padding) * 4;
+    else
+      m_FrameSize = 144 * m_BitRate / m_SampleRate + padding;
+
+    m_FoundFrame = true;
+    m_DTS = m_curPTS;
+    m_PTS = m_curPTS;
+    m_curPTS += 90000 * 1152 / m_SampleRate;
+    return -1;
+  }
+  return 0;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGAudio.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGAudio.h
new file mode 100644 (file)
index 0000000..e2f25b1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_MPEGAUDIO_H
+#define VNSI_DEMUXER_MPEGAUDIO_H
+
+#include "parser.h"
+
+// --- cParserMPEG2Audio -------------------------------------------------
+
+class cParserMPEG2Audio : public cParser
+{
+private:
+  int         m_SampleRate;
+  int         m_Channels;
+  int         m_BitRate;
+  int         m_FrameSize;
+
+  int64_t     m_PTS;
+  int64_t     m_DTS;
+
+  bool        m_RDSEnabled;
+  uint32_t    m_RDSExtPID;
+  uint8_t    *m_RDSBuffer;
+  int         m_RDSBufferSize;
+  int         m_RDSBufferPtr;
+  size_t      m_RDSBufferInitialSize;
+
+  int FindHeaders(uint8_t *buf, int buf_size);
+
+public:
+  cParserMPEG2Audio(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps, bool enableRDS);
+  virtual ~cParserMPEG2Audio();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+};
+
+
+#endif // VNSI_DEMUXER_MPEGAUDIO_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGVideo.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGVideo.c
new file mode 100644 (file)
index 0000000..b27dd1b
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_MPEGVideo.h"
+#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+using namespace std;
+
+#define MPEG_PICTURE_START      0x00000100
+#define MPEG_SEQUENCE_START     0x000001b3
+#define MPEG_SEQUENCE_EXTENSION 0x000001b5
+#define MPEG_SLICE_S            0x00000101
+#define MPEG_SLICE_E            0x000001af
+
+/**
+ * MPEG2VIDEO frame duration table (in 90kHz clock domain)
+ */
+const unsigned int mpeg2video_framedurations[16] = {
+  0,
+  3753,
+  3750,
+  3600,
+  3003,
+  3000,
+  1800,
+  1501,
+  1500,
+};
+
+cParserMPEG2Video::cParserMPEG2Video(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_FrameDuration     = 0;
+  m_vbvDelay          = -1;
+  m_vbvSize           = 0;
+  m_Height            = 0;
+  m_Width             = 0;
+  m_Dar               = 0.0;
+  m_FpsScale          = 0;
+  m_PesBufferInitialSize  = 80000;
+  m_IsVideo = true;
+  Reset();
+}
+
+cParserMPEG2Video::~cParserMPEG2Video()
+{
+}
+
+void cParserMPEG2Video::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  if (m_PesBufferPtr < 4)
+    return;
+
+  int p = m_PesParserPtr;
+  uint32_t startcode = m_StartCode;
+  bool frameComplete = false;
+  int l;
+  while ((l = m_PesBufferPtr - p) > 3)
+  {
+    if ((startcode & 0xffffff00) == 0x00000100)
+    {
+      if (Parse_MPEG2Video(startcode, p, frameComplete) < 0)
+      {
+        break;
+      }
+    }
+    startcode = startcode << 8 | m_PesBuffer[p++];
+  }
+  m_PesParserPtr = p;
+  m_StartCode = startcode;
+
+  if (frameComplete)
+  {
+    if (!m_NeedSPS && !m_NeedIFrame && m_FrameValid)
+    {
+      if (m_FpsScale == 0)
+      {
+        if (m_FrameDuration != DVD_NOPTS_VALUE)
+          m_FpsScale = m_Stream->Rescale(m_FrameDuration, DVD_TIME_BASE, 90000);
+        else
+          m_FpsScale = 40000;
+      }
+      bool streamChange = m_Stream->SetVideoInformation(m_FpsScale, DVD_TIME_BASE, m_Height, m_Width, m_Dar);
+
+      pkt->id       = m_pID;
+      pkt->size     = m_PesNextFramePtr;
+      pkt->data     = m_PesBuffer;
+      pkt->dts      = m_DTS;
+      pkt->pts      = m_PTS;
+      pkt->duration = m_FrameDuration;
+      pkt->streamChange = streamChange;
+    }
+    m_StartCode = 0xffffffff;
+    m_PesParserPtr = 0;
+    m_FoundFrame = false;
+    m_FrameValid = true;
+  }
+}
+
+void cParserMPEG2Video::Reset()
+{
+  cParser::Reset();
+  m_StartCode = 0xffffffff;
+  m_NeedIFrame = true;
+  m_NeedSPS = true;
+}
+
+int cParserMPEG2Video::Parse_MPEG2Video(uint32_t startcode, int buf_ptr, bool &complete)
+{
+  int len = m_PesBufferPtr - buf_ptr;
+  uint8_t *buf = m_PesBuffer + buf_ptr;
+
+  switch (startcode & 0xFF)
+  {
+  case 0: // picture start
+  {
+    if (m_NeedSPS)
+    {
+      m_FoundFrame = true;
+      return 0;
+    }
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+    if (len < 4)
+      return -1;
+    if (!Parse_MPEG2Video_PicStart(buf))
+      return 0;
+
+    if (!m_FoundFrame)
+    {
+      m_AuPrevDTS = m_AuDTS;
+      if (buf_ptr - 4 >= m_PesTimePos)
+      {
+        m_AuDTS = m_curDTS != DVD_NOPTS_VALUE ? m_curDTS : m_curPTS;
+        m_AuPTS = m_curPTS;
+      }
+      else
+      {
+        m_AuDTS = m_prevDTS != DVD_NOPTS_VALUE ? m_prevDTS : m_prevPTS;;
+        m_AuPTS = m_prevPTS;
+      }
+    }
+    if (m_AuPrevDTS == m_AuDTS)
+    {
+      m_DTS = m_AuDTS + m_PicNumber*m_FrameDuration;
+      m_PTS = m_AuPTS + (m_TemporalReference-m_TrLastTime)*m_FrameDuration;
+    }
+    else
+    {
+      m_PTS = m_AuPTS;
+      m_DTS = m_AuDTS;
+      m_PicNumber = 0;
+      m_TrLastTime = m_TemporalReference;
+    }
+
+    m_PicNumber++;
+    m_FoundFrame = true;
+    break;
+  }
+
+  case 0xb3: // Sequence start code
+  {
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+    if (len < 8)
+      return -1;
+    if (!Parse_MPEG2Video_SeqStart(buf))
+      return 0;
+
+    break;
+  }
+
+  case 0xb7: // sequence end
+  {
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr;
+      return -1;
+    }
+    break;
+  }
+
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+bool cParserMPEG2Video::Parse_MPEG2Video_SeqStart(uint8_t *buf)
+{
+  cBitstream bs(buf, 8 * 8);
+
+  m_Width         = bs.readBits(12);
+  m_Height        = bs.readBits(12);
+
+  // figure out Display Aspect Ratio
+  uint8_t aspect = bs.readBits(4);
+
+  switch(aspect)
+  {
+    case 1:
+      m_Dar = 1.0;
+      break;
+    case 2:
+      m_Dar = 4.0/3.0;
+      break;
+    case 3:
+      m_Dar = 16.0/9.0;
+      break;
+    case 4:
+      m_Dar = 2.21;
+      break;
+    default:
+      ERRORLOG("invalid / forbidden DAR in sequence header !");
+      return false;
+  }
+
+  m_FrameDuration = mpeg2video_framedurations[bs.readBits(4)];
+  bs.skipBits(18);
+  bs.skipBits(1);
+
+  m_vbvSize = bs.readBits(10) * 16 * 1024 / 8;
+  m_NeedSPS = false;
+
+  return true;
+}
+
+bool cParserMPEG2Video::Parse_MPEG2Video_PicStart(uint8_t *buf)
+{
+  cBitstream bs(buf, 4 * 8);
+
+  m_TemporalReference = bs.readBits(10); /* temporal reference */
+
+  int pct = bs.readBits(3);
+  if (pct < PKT_I_FRAME || pct > PKT_B_FRAME)
+    return true; /* Illegal picture_coding_type */
+
+  if (pct == PKT_I_FRAME)
+    m_NeedIFrame = false;
+
+  int vbvDelay = bs.readBits(16); /* vbv_delay */
+  if (vbvDelay  == 0xffff)
+    m_vbvDelay = -1;
+  else
+    m_vbvDelay = vbvDelay;
+
+  return true;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGVideo.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_MPEGVideo.h
new file mode 100644 (file)
index 0000000..a463469
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_MPEGVIDEO_H
+#define VNSI_DEMUXER_MPEGVIDEO_H
+
+#include <deque>
+#include "parser.h"
+
+class cBitstream;
+
+// --- cParserMPEG2Video -------------------------------------------------
+
+class cParserMPEG2Video : public cParser
+{
+private:
+  uint32_t        m_StartCode;
+  bool            m_NeedIFrame;
+  bool            m_NeedSPS;
+  int64_t         m_FrameDuration;
+  int             m_vbvDelay;       /* -1 if CBR */
+  int             m_vbvSize;        /* Video buffer size (in bytes) */
+  int             m_Width;
+  int             m_Height;
+  float           m_Dar;
+  int64_t         m_DTS;
+  int64_t         m_PTS;
+  int64_t         m_AuDTS, m_AuPTS, m_AuPrevDTS;
+  int             m_TemporalReference;
+  int             m_TrLastTime;
+  int             m_PicNumber;
+  int             m_FpsScale;
+
+  int Parse_MPEG2Video(uint32_t startcode, int buf_ptr, bool &complete);
+  bool Parse_MPEG2Video_SeqStart(uint8_t *buf);
+  bool Parse_MPEG2Video_PicStart(uint8_t *buf);
+
+public:
+  cParserMPEG2Video(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserMPEG2Video();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+  virtual void Reset();
+};
+
+#endif // VNSI_DEMUXER_MPEGVIDEO_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_Subtitle.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_Subtitle.c
new file mode 100644 (file)
index 0000000..032ec88
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_Subtitle.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+cParserSubtitle::cParserSubtitle(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_PesBufferInitialSize = 4000;
+}
+
+cParserSubtitle::~cParserSubtitle()
+{
+
+}
+
+void cParserSubtitle::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  int l = m_PesBufferPtr;
+
+  if (l >= m_PesPacketLength)
+  {
+    if (l < 2 || m_PesBuffer[0] != 0x20 || m_PesBuffer[1] != 0x00)
+    {
+      Reset();
+      return;
+    }
+
+    if(m_PesBuffer[m_PesPacketLength-1] == 0xff)
+    {
+      pkt->id       = m_pID;
+      pkt->data     = m_PesBuffer+2;
+      pkt->size     = m_PesPacketLength-3;
+      pkt->duration = 0;
+      pkt->dts      = m_curDTS;
+      pkt->pts      = m_curPTS;
+    }
+
+    m_PesBufferPtr = 0;
+  }
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_Subtitle.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_Subtitle.h
new file mode 100644 (file)
index 0000000..fa949ef
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_SUBTITLE_H
+#define VNSI_DEMUXER_SUBTITLE_H
+
+#include "parser.h"
+
+// --- cParserSubtitle -------------------------------------------------
+
+class cParserSubtitle : public cParser
+{
+public:
+  cParserSubtitle(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserSubtitle();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+};
+
+
+#endif // VNSI_DEMUXER_SUBTITLE_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_Teletext.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_Teletext.c
new file mode 100644 (file)
index 0000000..8e32dce
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_Teletext.h"
+#include "config.h"
+
+#include <stdlib.h>
+
+cParserTeletext::cParserTeletext(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_PesBufferInitialSize      = 4000;
+}
+
+cParserTeletext::~cParserTeletext()
+{
+}
+
+void cParserTeletext::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  int l = m_PesBufferPtr;
+  if (l < 1)
+    return;
+
+  if (m_PesBuffer[0] < 0x10 || m_PesBuffer[0] > 0x1F)
+  {
+    Reset();
+    return;
+  }
+
+  if (l >= m_PesPacketLength)
+  {
+    pkt->id       = m_pID;
+    pkt->data     = m_PesBuffer;
+    pkt->size     = m_PesPacketLength;
+    pkt->duration = 0;
+    pkt->dts      = m_curDTS;
+    pkt->pts      = m_curPTS;
+
+    m_PesBufferPtr = 0;
+  }
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_Teletext.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_Teletext.h
new file mode 100644 (file)
index 0000000..a26306e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_TELETEXT_H
+#define VNSI_DEMUXER_TELETEXT_H
+
+#include "parser.h"
+
+// --- cParserTeletext -------------------------------------------------
+
+class cParserTeletext : public cParser
+{
+private:
+  int64_t     m_lastDTS;
+  int64_t     m_lastPTS;
+
+public:
+  cParserTeletext(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserTeletext();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+};
+
+#endif // VNSI_DEMUXER_TELETEXT_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_h264.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_h264.c
new file mode 100644 (file)
index 0000000..ced5d88
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "parser_h264.h"
+#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+static const int h264_lev2cpbsize[][2] =
+{
+  {10, 175},
+  {11, 500},
+  {12, 1000},
+  {13, 2000},
+  {20, 2000},
+  {21, 4000},
+  {22, 4000},
+  {30, 10000},
+  {31, 14000},
+  {32, 20000},
+  {40, 25000},
+  {41, 62500},
+  {42, 62500},
+  {50, 135000},
+  {51, 240000},
+  {-1, -1},
+};
+
+cParserH264::cParserH264(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_Height            = 0;
+  m_Width             = 0;
+  m_FPS               = 25;
+  m_FpsScale          = 0;
+  m_FrameDuration     = 0;
+  m_vbvDelay          = -1;
+  m_vbvSize           = 0;
+  m_PixelAspect.den   = 1;
+  m_PixelAspect.num   = 0;
+  memset(&m_streamData, 0, sizeof(m_streamData));
+  m_PesBufferInitialSize      = 240000;
+
+  m_IsVideo = true;
+  Reset();
+}
+
+cParserH264::~cParserH264()
+{
+}
+
+void cParserH264::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  if (m_PesBufferPtr < 4)
+    return;
+
+  int p = m_PesParserPtr;
+  uint32_t startcode = m_StartCode;
+  bool frameComplete = false;
+  int l;
+  while ((l = m_PesBufferPtr - p) > 3)
+  {
+    if ((startcode & 0xffffff00) == 0x00000100)
+    {
+      if (Parse_H264(startcode, p, frameComplete) < 0)
+      {
+        break;
+      }
+    }
+    startcode = startcode << 8 | m_PesBuffer[p++];
+  }
+  m_PesParserPtr = p;
+  m_StartCode = startcode;
+
+  if (frameComplete)
+  {
+    if (!m_NeedSPS && !m_NeedIFrame && m_FrameValid)
+    {
+      double PAR = (double)m_PixelAspect.num/(double)m_PixelAspect.den;
+      double DAR = (PAR * m_Width) / m_Height;
+      DEBUGLOG("H.264 SPS: PAR %i:%i", m_PixelAspect.num, m_PixelAspect.den);
+      DEBUGLOG("H.264 SPS: DAR %.2f", DAR);
+
+      int duration;
+      if (m_curDTS != DVD_NOPTS_VALUE && m_prevDTS != DVD_NOPTS_VALUE && m_curDTS > m_prevDTS)
+        duration = m_curDTS - m_prevDTS;
+      else
+        duration = m_Stream->Rescale(20000, 90000, DVD_TIME_BASE);
+
+      if (m_FpsScale == 0)
+      {
+        m_FpsScale = m_Stream->Rescale(duration, DVD_TIME_BASE, 90000);
+      }
+
+      bool streamChange = m_Stream->SetVideoInformation(m_FpsScale, DVD_TIME_BASE, m_Height, m_Width, DAR);
+
+      pkt->id       = m_pID;
+      pkt->size     = m_PesNextFramePtr;
+      pkt->data     = m_PesBuffer;
+      pkt->dts      = m_DTS;
+      pkt->pts      = m_PTS;
+      pkt->duration = duration;
+      pkt->streamChange = streamChange;
+    }
+    m_StartCode = 0xffffffff;
+    m_PesParserPtr = 0;
+    m_FoundFrame = false;
+    m_FrameValid = true;
+  }
+}
+
+void cParserH264::Reset()
+{
+  cParser::Reset();
+  m_StartCode = 0xffffffff;
+  m_NeedIFrame = true;
+  m_NeedSPS = true;
+  m_NeedPPS = true;
+  memset(&m_streamData, 0, sizeof(m_streamData));
+}
+
+int cParserH264::Parse_H264(uint32_t startcode, int buf_ptr, bool &complete)
+{
+  int len = m_PesBufferPtr - buf_ptr;
+  uint8_t *buf = m_PesBuffer + buf_ptr;
+
+  switch(startcode & 0x9f)
+  {
+  case 1 ... 5:
+  {
+    if (m_NeedSPS || m_NeedPPS)
+    {
+      m_FoundFrame = true;
+      return 0;
+    }
+    // need at least 32 bytes for parsing nal
+    if (len < 32)
+      return -1;
+    h264_private::VCL_NAL vcl;
+    memset(&vcl, 0, sizeof(h264_private::VCL_NAL));
+    vcl.nal_ref_idc = startcode & 0x60;
+    vcl.nal_unit_type = startcode & 0x1F;
+    if (!Parse_SLH(buf, len, vcl))
+      return 0;
+
+    // check for the beginning of a new access unit
+    if (m_FoundFrame && IsFirstVclNal(vcl))
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+
+    if (!m_FoundFrame)
+    {
+      if (buf_ptr - 4 >= m_PesTimePos)
+      {
+        m_DTS = m_curDTS;
+        m_PTS = m_curPTS;
+      }
+      else
+      {
+        m_DTS = m_prevDTS;
+        m_PTS = m_prevPTS;
+      }
+    }
+
+    m_streamData.vcl_nal = vcl;
+    m_FoundFrame = true;
+    break;
+  }
+
+  case NAL_SEI:
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+    break;
+
+  case NAL_SPS:
+  {
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+    // TODO: how big is SPS?
+    if (len < 256)
+      return -1;
+    if (!Parse_SPS(buf, len))
+      return 0;
+
+    m_NeedSPS = false;
+    break;
+  }
+
+  case NAL_PPS:
+  {
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+    // TODO: how big is PPS
+    if (len < 64)
+      return -1;
+    if (!Parse_PPS(buf, len))
+      return 0;
+    m_NeedPPS = false;
+    break;
+  }
+
+  case NAL_AUD:
+    if (m_FoundFrame && (m_prevPTS != DVD_NOPTS_VALUE))
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+    break;
+
+  case NAL_END_SEQ:
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr;
+      return -1;
+    }
+    break;
+
+  case 13 ... 18:
+    if (m_FoundFrame)
+    {
+      complete = true;
+      m_PesNextFramePtr = buf_ptr - 4;
+      return -1;
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+bool cParserH264::Parse_PPS(uint8_t *buf, int len)
+{
+  cBitstream bs(buf, len*8);
+
+  int pps_id = bs.readGolombUE();
+  int sps_id = bs.readGolombUE();
+  m_streamData.pps[pps_id].sps = sps_id;
+  bs.readBits1();
+  m_streamData.pps[pps_id].pic_order_present_flag = bs.readBits1();
+  return true;
+}
+
+bool cParserH264::Parse_SLH(uint8_t *buf, int len, h264_private::VCL_NAL &vcl)
+{
+  cBitstream bs(buf, len*8);
+
+  bs.readGolombUE(); /* first_mb_in_slice */
+  int slice_type = bs.readGolombUE();
+
+  if (slice_type > 4)
+    slice_type -= 5;  /* Fixed slice type per frame */
+
+  switch (slice_type)
+  {
+  case 0:
+    break;
+  case 1:
+    break;
+  case 2:
+    m_NeedIFrame = false;
+    break;
+  default:
+    return false;
+  }
+
+  int pps_id = bs.readGolombUE();
+  int sps_id = m_streamData.pps[pps_id].sps;
+  if (m_streamData.sps[sps_id].cbpsize == 0)
+    return false;
+
+  m_vbvSize = m_streamData.sps[sps_id].cbpsize;
+  m_vbvDelay = -1;
+
+  vcl.pic_parameter_set_id = pps_id;
+  vcl.frame_num = bs.readBits(m_streamData.sps[sps_id].log2_max_frame_num);
+  if (!m_streamData.sps[sps_id].frame_mbs_only_flag)
+  {
+    vcl.field_pic_flag = bs.readBits1();
+    // interlaced
+//    if (vcl.field_pic_flag)
+//      m_FPS *= 2;
+  }
+  if (vcl.field_pic_flag)
+    vcl.bottom_field_flag = bs.readBits1();
+
+  if (vcl.nal_unit_type == 5)
+    vcl.idr_pic_id = bs.readGolombUE();
+  if (m_streamData.sps[sps_id].pic_order_cnt_type == 0)
+  {
+    vcl.pic_order_cnt_lsb = bs.readBits(m_streamData.sps[sps_id].log2_max_pic_order_cnt_lsb);
+    if(m_streamData.pps[pps_id].pic_order_present_flag && !vcl.field_pic_flag)
+      vcl.delta_pic_order_cnt_bottom = bs.readGolombSE();
+  }
+  if(m_streamData.sps[sps_id].pic_order_cnt_type == 1 &&
+      !m_streamData.sps[sps_id].delta_pic_order_always_zero_flag )
+  {
+    vcl.delta_pic_order_cnt_0 = bs.readGolombSE();
+    if(m_streamData.pps[pps_id].pic_order_present_flag && !vcl.field_pic_flag )
+      vcl.delta_pic_order_cnt_1 = bs.readGolombSE();
+  }
+
+  vcl.pic_order_cnt_type = m_streamData.sps[sps_id].pic_order_cnt_type;
+
+  return true;
+}
+
+bool cParserH264::Parse_SPS(uint8_t *buf, int len)
+{
+  cBitstream bs(buf, len*8);
+  unsigned int tmp, frame_mbs_only;
+  int cbpsize = -1;
+
+  int profile_idc = bs.readBits(8);
+  /* constraint_set0_flag = bs.readBits1();    */
+  /* constraint_set1_flag = bs.readBits1();    */
+  /* constraint_set2_flag = bs.readBits1();    */
+  /* constraint_set3_flag = bs.readBits1();    */
+  /* reserved             = bs.readBits(4);    */
+  bs.skipBits(8);
+  int level_idc = bs.readBits(8);
+  unsigned int seq_parameter_set_id = bs.readGolombUE(9);
+
+  unsigned int i = 0;
+  while (h264_lev2cpbsize[i][0] != -1)
+  {
+    if (h264_lev2cpbsize[i][0] >= level_idc)
+    {
+      cbpsize = h264_lev2cpbsize[i][1];
+      break;
+    }
+    i++;
+  }
+  if (cbpsize < 0)
+    return false;
+
+  memset(&m_streamData.sps[seq_parameter_set_id], 0, sizeof(h264_private::SPS));
+  m_streamData.sps[seq_parameter_set_id].cbpsize = cbpsize * 125; /* Convert from kbit to bytes */
+
+  if( profile_idc == 100 || profile_idc == 110 ||
+      profile_idc == 122 || profile_idc == 244 || profile_idc == 44 ||
+      profile_idc == 83 || profile_idc == 86 || profile_idc == 118 ||
+      profile_idc == 128 )
+  {
+    int chroma_format_idc = bs.readGolombUE(9); /* chroma_format_idc              */
+    if(chroma_format_idc == 3)
+      bs.skipBits(1);           /* residual_colour_transform_flag */
+    bs.readGolombUE();          /* bit_depth_luma - 8             */
+    bs.readGolombUE();          /* bit_depth_chroma - 8           */
+    bs.skipBits(1);             /* transform_bypass               */
+    if (bs.readBits1())         /* seq_scaling_matrix_present     */
+    {
+      for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++)
+      {
+        if (bs.readBits1())     /* seq_scaling_list_present       */
+        {
+          int last = 8, next = 8, size = (i<6) ? 16 : 64;
+          for (int j = 0; j < size; j++)
+          {
+            if (next)
+              next = (last + bs.readGolombSE()) & 0xff;
+            last = !next ? last: next;
+          }
+        }
+      }
+    }
+  }
+
+  int log2_max_frame_num_minus4 = bs.readGolombUE();           /* log2_max_frame_num - 4 */
+  m_streamData.sps[seq_parameter_set_id].log2_max_frame_num = log2_max_frame_num_minus4 + 4;
+  int pic_order_cnt_type = bs.readGolombUE(9);
+  m_streamData.sps[seq_parameter_set_id].pic_order_cnt_type = pic_order_cnt_type;
+  if (pic_order_cnt_type == 0)
+  {
+    int log2_max_pic_order_cnt_lsb_minus4 = bs.readGolombUE();         /* log2_max_poc_lsb - 4 */
+    m_streamData.sps[seq_parameter_set_id].log2_max_pic_order_cnt_lsb = log2_max_pic_order_cnt_lsb_minus4 + 4;
+  }
+  else if (pic_order_cnt_type == 1)
+  {
+    m_streamData.sps[seq_parameter_set_id].delta_pic_order_always_zero_flag = bs.readBits1();
+    bs.readGolombSE();         /* offset_for_non_ref_pic          */
+    bs.readGolombSE();         /* offset_for_top_to_bottom_field  */
+    tmp = bs.readGolombUE();   /* num_ref_frames_in_pic_order_cnt_cycle */
+    for (unsigned int i = 0; i < tmp; i++)
+      bs.readGolombSE();       /* offset_for_ref_frame[i]         */
+  }
+  else if(pic_order_cnt_type != 2)
+  {
+    /* Illegal poc */
+    return false;
+  }
+
+  bs.readGolombUE(9);          /* ref_frames                      */
+  bs.skipBits(1);             /* gaps_in_frame_num_allowed       */
+  m_Width  /* mbs */ = bs.readGolombUE() + 1;
+  m_Height /* mbs */ = bs.readGolombUE() + 1;
+  frame_mbs_only     = bs.readBits1();
+  m_streamData.sps[seq_parameter_set_id].frame_mbs_only_flag = frame_mbs_only;
+  DEBUGLOG("H.264 SPS: pic_width:  %u mbs", (unsigned) m_Width);
+  DEBUGLOG("H.264 SPS: pic_height: %u mbs", (unsigned) m_Height);
+  DEBUGLOG("H.264 SPS: frame only flag: %d", frame_mbs_only);
+
+  m_Width  *= 16;
+  m_Height *= 16 * (2-frame_mbs_only);
+
+  if (!frame_mbs_only)
+  {
+    if (bs.readBits1())     /* mb_adaptive_frame_field_flag */
+      DEBUGLOG("H.264 SPS: MBAFF");
+  }
+  bs.skipBits(1);           /* direct_8x8_inference_flag    */
+  if (bs.readBits1())       /* frame_cropping_flag */
+  {
+    uint32_t crop_left   = bs.readGolombUE();
+    uint32_t crop_right  = bs.readGolombUE();
+    uint32_t crop_top    = bs.readGolombUE();
+    uint32_t crop_bottom = bs.readGolombUE();
+    DEBUGLOG("H.264 SPS: cropping %d %d %d %d", crop_left, crop_top, crop_right, crop_bottom);
+
+    m_Width -= 2*(crop_left + crop_right);
+    if (frame_mbs_only)
+      m_Height -= 2*(crop_top + crop_bottom);
+    else
+      m_Height -= 4*(crop_top + crop_bottom);
+  }
+
+  /* VUI parameters */
+  m_PixelAspect.num = 0;
+  if (bs.readBits1())    /* vui_parameters_present flag */
+  {
+    if (bs.readBits1())  /* aspect_ratio_info_present */
+    {
+      uint32_t aspect_ratio_idc = bs.readBits(8);
+      DEBUGLOG("H.264 SPS: aspect_ratio_idc %d", aspect_ratio_idc);
+
+      if (aspect_ratio_idc == 255 /* Extended_SAR */)
+      {
+        m_PixelAspect.num = bs.readBits(16); /* sar_width */
+        m_PixelAspect.den = bs.readBits(16); /* sar_height */
+        DEBUGLOG("H.264 SPS: -> sar %dx%d", m_PixelAspect.num, m_PixelAspect.den);
+      }
+      else
+      {
+        static const mpeg_rational_t aspect_ratios[] =
+        { /* page 213: */
+          /* 0: unknown */
+          {0, 1},
+          /* 1...16: */
+          { 1,  1}, {12, 11}, {10, 11}, {16, 11}, { 40, 33}, {24, 11}, {20, 11}, {32, 11},
+          {80, 33}, {18, 11}, {15, 11}, {64, 33}, {160, 99}, { 4,  3}, { 3,  2}, { 2,  1}
+        };
+
+        if (aspect_ratio_idc < sizeof(aspect_ratios)/sizeof(aspect_ratios[0]))
+        {
+          memcpy(&m_PixelAspect, &aspect_ratios[aspect_ratio_idc], sizeof(mpeg_rational_t));
+          DEBUGLOG("H.264 SPS: PAR %d / %d", m_PixelAspect.num, m_PixelAspect.den);
+        }
+        else
+        {
+          DEBUGLOG("H.264 SPS: aspect_ratio_idc out of range !");
+        }
+      }
+    }
+    if (bs.readBits1()) // overscan
+    {
+      bs.readBits1(); // overscan_appropriate_flag
+    }
+    if (bs.readBits1()) // video_signal_type_present_flag
+    {
+      bs.readBits(3); // video_format
+      bs.readBits1(); // video_full_range_flag
+      if (bs.readBits1()) // colour_description_present_flag
+      {
+        bs.readBits(8); // colour_primaries
+        bs.readBits(8); // transfer_characteristics
+        bs.readBits(8); // matrix_coefficients
+      }
+    }
+
+    if (bs.readBits1()) // chroma_loc_info_present_flag
+    {
+      bs.readGolombUE(); // chroma_sample_loc_type_top_field
+      bs.readGolombUE(); // chroma_sample_loc_type_bottom_field
+    }
+
+    if (bs.readBits1()) // timing_info_present_flag
+    {
+//      uint32_t num_units_in_tick = bs.readBits(32);
+//      uint32_t time_scale = bs.readBits(32);
+//      int fixed_frame_rate = bs.readBits1();
+//      if (num_units_in_tick > 0)
+//        m_FPS = time_scale / (num_units_in_tick * 2);
+    }
+  }
+
+  DEBUGLOG("H.264 SPS: -> video size %dx%d, aspect %d:%d", m_Width, m_Height, m_PixelAspect.num, m_PixelAspect.den);
+  return true;
+}
+
+bool cParserH264::IsFirstVclNal(h264_private::VCL_NAL &vcl)
+{
+  if (m_streamData.vcl_nal.frame_num != vcl.frame_num)
+    return true;
+
+  if (m_streamData.vcl_nal.pic_parameter_set_id != vcl.pic_parameter_set_id)
+    return true;
+
+  if (m_streamData.vcl_nal.field_pic_flag != vcl.field_pic_flag)
+    return true;
+
+  if (m_streamData.vcl_nal.field_pic_flag && vcl.field_pic_flag)
+  {
+    if (m_streamData.vcl_nal.bottom_field_flag != vcl.bottom_field_flag)
+      return true;
+  }
+
+  if (m_streamData.vcl_nal.nal_ref_idc == 0 || vcl.nal_ref_idc == 0)
+  {
+    if (m_streamData.vcl_nal.nal_ref_idc != vcl.nal_ref_idc)
+      return true;
+  }
+
+  if (m_streamData.vcl_nal.pic_order_cnt_type == 0 && vcl.pic_order_cnt_type == 0)
+  {
+    if (m_streamData.vcl_nal.pic_order_cnt_lsb != vcl.pic_order_cnt_lsb)
+      return true;
+    if (m_streamData.vcl_nal.delta_pic_order_cnt_bottom != vcl.delta_pic_order_cnt_bottom)
+      return true;
+  }
+
+  if (m_streamData.vcl_nal.pic_order_cnt_type == 1 && vcl.pic_order_cnt_type == 1)
+  {
+    if (m_streamData.vcl_nal.delta_pic_order_cnt_0 != vcl.delta_pic_order_cnt_0)
+      return true;
+    if (m_streamData.vcl_nal.delta_pic_order_cnt_1 != vcl.delta_pic_order_cnt_1)
+      return true;
+  }
+
+  if (m_streamData.vcl_nal.nal_unit_type == 5 || vcl.nal_unit_type == 5)
+  {
+    if (m_streamData.vcl_nal.nal_unit_type != vcl.nal_unit_type)
+      return true;
+  }
+
+  if (m_streamData.vcl_nal.nal_unit_type == 5 && vcl.nal_unit_type == 5)
+  {
+    if (m_streamData.vcl_nal.idr_pic_id != vcl.idr_pic_id)
+      return true;
+  }
+  return false;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_h264.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_h264.h
new file mode 100644 (file)
index 0000000..3167ba9
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_H264_H
+#define VNSI_DEMUXER_H264_H
+
+#include "parser.h"
+
+class cBitstream;
+
+// --- cParserH264 -------------------------------------------------
+
+class cParserH264 : public cParser
+{
+private:
+  typedef struct h264_private
+  {
+    struct SPS
+    {
+      int frame_duration;
+      int cbpsize;
+      int pic_order_cnt_type;
+      int frame_mbs_only_flag;
+      int log2_max_frame_num;
+      int log2_max_pic_order_cnt_lsb;
+      int delta_pic_order_always_zero_flag;
+    } sps[256];
+
+    struct PPS
+    {
+      int sps;
+      int pic_order_present_flag;
+    } pps[256];
+
+    struct VCL_NAL
+    {
+      int frame_num; // slice
+      int pic_parameter_set_id; // slice
+      int field_pic_flag; // slice
+      int bottom_field_flag; // slice
+      int delta_pic_order_cnt_bottom; // slice
+      int delta_pic_order_cnt_0; // slice
+      int delta_pic_order_cnt_1; // slice
+      int pic_order_cnt_lsb; // slice
+      int idr_pic_id; // slice
+      int nal_unit_type;
+      int nal_ref_idc; // start code
+      int pic_order_cnt_type; // sps
+    } vcl_nal;
+
+  } h264_private_t;
+
+  typedef struct mpeg_rational_s {
+    int num;
+    int den;
+  } mpeg_rational_t;
+
+  enum
+  {
+    NAL_SLH     = 0x01, // Slice Header
+    NAL_SEI     = 0x06, // Supplemental Enhancement Information
+    NAL_SPS     = 0x07, // Sequence Parameter Set
+    NAL_PPS     = 0x08, // Picture Parameter Set
+    NAL_AUD     = 0x09, // Access Unit Delimiter
+    NAL_END_SEQ = 0x0A  // End of Sequence
+  };
+
+  uint32_t        m_StartCode;
+  bool            m_NeedIFrame;
+  bool            m_NeedSPS;
+  bool            m_NeedPPS;
+  int             m_Width;
+  int             m_Height;
+  int             m_FPS;
+  int             m_FpsScale;
+  mpeg_rational_t m_PixelAspect;
+  int             m_FrameDuration;
+  h264_private    m_streamData;
+  int             m_vbvDelay;       /* -1 if CBR */
+  int             m_vbvSize;        /* Video buffer size (in bytes) */
+  int64_t         m_DTS;
+  int64_t         m_PTS;
+
+  int Parse_H264(uint32_t startcode, int buf_ptr, bool &complete);
+  bool Parse_PPS(uint8_t *buf, int len);
+  bool Parse_SLH(uint8_t *buf, int len, h264_private::VCL_NAL &vcl);
+  bool Parse_SPS(uint8_t *buf, int len);
+  bool IsFirstVclNal(h264_private::VCL_NAL &vcl);
+
+public:
+  cParserH264(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserH264();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+  virtual void Reset();
+};
+
+
+#endif // VNSI_DEMUXER_H264_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_hevc.c b/v/vdr-plugin-vnsiserver-1.8.0/parser_hevc.c
new file mode 100644 (file)
index 0000000..34b5901
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// Warning: This is an unfinished port from H.264 to HEVC in alpha state
+// Tested with German DVB-T2 HD channels
+
+#include "parser_hevc.h"
+#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+
+cParserHEVC::cParserHEVC(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+  m_Height            = 0;
+  m_Width             = 0;
+  m_FpsScale          = 0;
+  m_PixelAspect.den   = 1;
+  m_PixelAspect.num   = 0;
+  memset(&m_streamData, 0, sizeof(m_streamData));
+  m_PesBufferInitialSize = 240000;
+
+  m_IsVideo = true;
+  Reset();
+}
+
+cParserHEVC::~cParserHEVC()
+{
+}
+
+void cParserHEVC::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+  if (m_PesBufferPtr < 10) // 2*startcode + header + trail bits
+    return;
+
+  int p = m_PesParserPtr;
+  uint32_t startcode = m_StartCode;
+  bool frameComplete = false;
+
+  while (m_PesBufferPtr - p)
+  {
+    startcode = startcode << 8 | m_PesBuffer[p++];
+    if ((startcode & 0x00ffffff) == 0x00000001)
+    {
+      if (m_LastStartPos != -1)
+         Parse_HEVC(m_LastStartPos, p-m_LastStartPos, &frameComplete);
+      m_LastStartPos = p;
+      if (frameComplete)
+        break;
+    }
+  }
+  m_PesParserPtr = p;
+  m_StartCode = startcode;
+
+  if (frameComplete)
+  {
+    if (!m_NeedSPS && m_FrameValid)
+    {
+      double PAR = (double)m_PixelAspect.num/(double)m_PixelAspect.den;
+      double DAR = (PAR * m_Width) / m_Height;
+      DEBUGLOG("HEVC SPS: PAR %i:%i", m_PixelAspect.num, m_PixelAspect.den);
+      DEBUGLOG("HEVC SPS: DAR %.2f", DAR);
+
+      int duration;
+      if (m_curDTS != DVD_NOPTS_VALUE && m_prevDTS != DVD_NOPTS_VALUE && m_curDTS > m_prevDTS)
+        duration = m_curDTS - m_prevDTS;
+      else
+        duration = m_Stream->Rescale(20000, 90000, DVD_TIME_BASE);
+
+      if (m_FpsScale == 0)
+        m_FpsScale = m_Stream->Rescale(duration, DVD_TIME_BASE, 90000);
+
+      bool streamChange = m_Stream->SetVideoInformation(m_FpsScale, DVD_TIME_BASE, m_Height, m_Width, DAR);
+
+      pkt->id       = m_pID;
+      pkt->size     = m_PesNextFramePtr;
+      pkt->data     = m_PesBuffer;
+      pkt->dts      = m_DTS;
+      pkt->pts      = m_PTS;
+      pkt->duration = duration;
+      pkt->streamChange = streamChange;
+
+    }
+    m_StartCode = 0xffffffff;
+    m_LastStartPos = -1;
+    m_PesParserPtr = 0;
+    m_FoundFrame = false;
+    m_FrameValid = true;
+  }
+}
+
+void cParserHEVC::Reset()
+{
+  cParser::Reset();
+  m_StartCode = 0xffffffff;
+  m_LastStartPos = -1;
+  m_NeedSPS = true;
+  m_NeedPPS = true;
+  memset(&m_streamData, 0, sizeof(m_streamData));
+}
+
+
+void cParserHEVC::Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool *complete)
+{
+  uint8_t *buf = m_PesBuffer + buf_ptr;
+  uint16_t header;
+  HDR_NAL hdr;
+
+  // nal_unit_header
+  header = (buf[0] << 8) | buf[1];
+  if (header & 0x8000) // ignore forbidden_bit == 1
+    return;
+  hdr.nal_unit_type   = (header & 0x7e00) >> 9;
+  hdr.nuh_layer_id    = (header &  0x1f8) >> 3;
+  hdr.nuh_temporal_id = (header &    0x7) - 1;
+
+  switch (hdr.nal_unit_type)
+  {
+  case NAL_TRAIL_N ... NAL_RASL_R:
+  case NAL_BLA_W_LP ... NAL_CRA_NUT:
+  {
+    if (m_NeedSPS || m_NeedPPS)
+    {
+      m_FoundFrame = true;
+      return;
+    }
+    hevc_private::VCL_NAL vcl;
+    memset(&vcl, 0, sizeof(hevc_private::VCL_NAL));
+    Parse_SLH(buf, NumBytesInNalUnit, hdr, vcl);
+    // check for the beginning of a new access unit
+    if (m_FoundFrame && IsFirstVclNal(vcl))
+    {
+      *complete = true;
+      m_PesNextFramePtr = buf_ptr - 3;
+      return;
+    }
+
+    if (!m_FoundFrame)
+    {
+      if (buf_ptr - 3 >= m_PesTimePos)
+      {
+        m_DTS = m_curDTS;
+        m_PTS = m_curPTS;
+      }
+      else
+      {
+        m_DTS = m_prevDTS;
+        m_PTS = m_prevPTS;
+      }
+    }
+
+    m_streamData.vcl_nal = vcl;
+    m_FoundFrame = true;
+    break;
+  }
+
+  case NAL_PFX_SEI_NUT:
+    if (m_FoundFrame)
+    {
+      *complete = true;
+      m_PesNextFramePtr = buf_ptr - 3;
+    }
+    break;
+
+  case NAL_VPS_NUT:
+     break;
+
+  case NAL_SPS_NUT:
+  {
+    if (m_FoundFrame)
+    {
+      *complete = true;
+      m_PesNextFramePtr = buf_ptr - 3;
+      return;
+    }
+    Parse_SPS(buf, NumBytesInNalUnit, hdr);
+    m_NeedSPS = false;
+    break;
+  }
+
+  case NAL_PPS_NUT:
+  {
+    if (m_FoundFrame)
+    {
+      *complete = true;
+      m_PesNextFramePtr = buf_ptr - 3;
+      return;
+    }
+    Parse_PPS(buf, NumBytesInNalUnit);
+    m_NeedPPS = false;
+    break;
+  }
+
+  case NAL_AUD_NUT:
+    if (m_FoundFrame && (m_prevPTS != DVD_NOPTS_VALUE))
+    {
+      *complete = true;
+      m_PesNextFramePtr = buf_ptr - 3;
+    }
+    break;
+
+  case NAL_EOS_NUT:
+    if (m_FoundFrame)
+    {
+      *complete = true;
+      m_PesNextFramePtr = buf_ptr + 2;
+    }
+    break;
+
+  case NAL_FD_NUT:
+  case NAL_SFX_SEI_NUT:
+     break;
+
+  default:
+    INFOLOG("HEVC fixme: nal unknown %i", hdr.nal_unit_type);
+    break;
+  }
+}
+
+void cParserHEVC::Parse_PPS(uint8_t *buf, int len)
+{
+  cBitstream bs(buf, len*8, true);
+
+  int pps_id = bs.readGolombUE();
+  int sps_id = bs.readGolombUE();
+  m_streamData.pps[pps_id].sps = sps_id;
+  m_streamData.pps[pps_id].dependent_slice_segments_enabled_flag = bs.readBits(1);
+}
+
+void cParserHEVC::Parse_SLH(uint8_t *buf, int len, HDR_NAL hdr, hevc_private::VCL_NAL &vcl)
+{
+  cBitstream bs(buf, len*8, true);
+
+  vcl.nal_unit_type = hdr.nal_unit_type;
+
+  vcl.first_slice_segment_in_pic_flag = bs.readBits(1);
+
+  if ((hdr.nal_unit_type >= NAL_BLA_W_LP) && (hdr.nal_unit_type <= NAL_RSV_IRAP_VCL23))
+    bs.skipBits(1); // no_output_of_prior_pics_flag
+
+  vcl.pic_parameter_set_id = bs.readGolombUE();
+}
+
+// 7.3.2.2.1 General sequence parameter set RBSP syntax
+void cParserHEVC::Parse_SPS(uint8_t *buf, int len, HDR_NAL hdr)
+{
+  cBitstream bs(buf, len*8, true);
+  unsigned int i;
+  int sub_layer_profile_present_flag[8], sub_layer_level_present_flag[8];
+
+  bs.skipBits(4); // sps_video_parameter_set_id
+
+  unsigned int sps_max_sub_layers_minus1 = bs.readBits(3);
+  bs.skipBits(1); // sps_temporal_id_nesting_flag
+
+  // skip over profile_tier_level
+  bs.skipBits(8 + 32 + 4 + 43 + 1 +8);
+  for (i=0; i<sps_max_sub_layers_minus1; i++)
+  {
+    sub_layer_profile_present_flag[i] = bs.readBits(1);
+    sub_layer_level_present_flag[i] = bs.readBits(1);
+  }
+  if (sps_max_sub_layers_minus1 > 0)
+  {
+    for (i=sps_max_sub_layers_minus1; i<8; i++)
+      bs.skipBits(2);
+  }
+  for (i=0; i<sps_max_sub_layers_minus1; i++)
+  {
+    if (sub_layer_profile_present_flag[i])
+      bs.skipBits(8 + 32 + 4 + 43 + 1);
+    if (sub_layer_level_present_flag[i])
+      bs.skipBits(8);
+  }
+  // end skip over profile_tier_level
+
+  bs.readGolombUE(); // sps_seq_parameter_set_id
+  unsigned int chroma_format_idc = bs.readGolombUE();
+  if (chroma_format_idc == 3)
+    bs.skipBits(1); // separate_colour_plane_flag
+
+  m_Width  = bs.readGolombUE();
+  m_Height = bs.readGolombUE();
+  m_PixelAspect.num = 1;
+}
+
+bool cParserHEVC::IsFirstVclNal(hevc_private::VCL_NAL &vcl)
+{
+  if (m_streamData.vcl_nal.pic_parameter_set_id != vcl.pic_parameter_set_id)
+    return true;
+
+  if (vcl.first_slice_segment_in_pic_flag)
+    return true;
+
+  return false;
+}
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/parser_hevc.h b/v/vdr-plugin-vnsiserver-1.8.0/parser_hevc.h
new file mode 100644 (file)
index 0000000..77c5869
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "parser.h"
+
+class cBitstream;
+
+// --- cParserHEVC -------------------------------------------------
+
+class cParserHEVC : public cParser
+{
+private:
+  typedef struct hevc_private
+  {
+    struct PPS
+    {
+      int sps;
+      int dependent_slice_segments_enabled_flag;
+    } pps[64];
+
+    struct VCL_NAL
+    {
+      int pic_parameter_set_id; // slice
+      unsigned int first_slice_segment_in_pic_flag;
+      unsigned int nal_unit_type;
+    } vcl_nal;
+
+  } hevc_private_t;
+
+  typedef struct HDR_NAL_t
+  {
+     unsigned int nal_unit_type;
+     unsigned int nuh_layer_id;
+     unsigned int nuh_temporal_id;
+  } HDR_NAL;
+
+  typedef struct mpeg_rational_s {
+    int num;
+    int den;
+  } mpeg_rational_t;
+
+  enum
+  {
+    NAL_TRAIL_N  = 0x00, // Coded slice segment of trailing picture
+    NAL_TRAIL_R  = 0x01, // Coded slice segment of trailing picture
+    NAL_TSA_N    = 0x02, // Coded slice segment of TSA picture
+    NAL_TSA_R    = 0x03, // Coded slice segment of TSA picture
+    NAL_STSA_N   = 0x04, // Coded slice segment of STSA picture
+    NAL_STSA_R   = 0x05, // Coded slice segment of STSA picture
+    NAL_RADL_N   = 0x06, // Coded slice segment of RADL picture
+    NAL_RADL_R   = 0x07, // Coded slice segment of RADL picture
+    NAL_RASL_N   = 0x08, // Coded slice segment of RASL picture
+    NAL_RASL_R   = 0x09, // Coded slice segment of RASL picture
+
+    NAL_BLA_W_LP = 0x10, // Coded slice segment of a BLA picture
+    NAL_CRA_NUT  = 0x15, // Coded slice segment of a CRA picture
+    NAL_RSV_IRAP_VCL22 = 0x16, // Reserved IRAP VCL NAL unit types
+    NAL_RSV_IRAP_VCL23 = 0x17, // Reserved IRAP VCL NAL unit types
+
+    NAL_VPS_NUT  = 0x20, // Video Parameter SET
+    NAL_SPS_NUT  = 0x21, // Sequence Parameter Set
+    NAL_PPS_NUT  = 0x22, // Picture Parameter Set
+    NAL_AUD_NUT  = 0x23, // Access Unit Delimiter
+    NAL_EOS_NUT  = 0x24, // End of Sequence
+    NAL_EOB_NUT  = 0x25, // End of Bitstream
+    NAL_FD_NUT   = 0x26, // Filler Data
+    NAL_PFX_SEI_NUT  = 0x27, // Supplemental Enhancement Information 
+    NAL_SFX_SEI_NUT  = 0x28, // Supplemental Enhancement Information
+
+  };
+
+  uint32_t        m_StartCode;
+  int             m_LastStartPos;
+  bool            m_NeedSPS;
+  bool            m_NeedPPS;
+  int             m_Width;
+  int             m_Height;
+  int             m_FpsScale;
+  mpeg_rational_t m_PixelAspect;
+  hevc_private    m_streamData;
+  int64_t         m_DTS;
+  int64_t         m_PTS;
+
+  void Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool *complete);
+  void Parse_PPS(uint8_t *buf, int len);
+  void Parse_SLH(uint8_t *buf, int len, HDR_NAL hdr, hevc_private::VCL_NAL &vcl);
+  void Parse_SPS(uint8_t *buf, int len, HDR_NAL hdr);
+  bool IsFirstVclNal(hevc_private::VCL_NAL &vcl);
+
+public:
+  cParserHEVC(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+  virtual ~cParserHEVC();
+
+  virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+  virtual void Reset();
+};
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/po/de_DE.po b/v/vdr-plugin-vnsiserver-1.8.0/po/de_DE.po
new file mode 100644 (file)
index 0000000..29c6df8
--- /dev/null
@@ -0,0 +1,88 @@
+# VDR VNSI plugin language source file.
+# Copyright (C) 2015 Alwin Esch
+# This file is distributed under the same license as the VDR package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VNSI-Server 1.0.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2017-08-12 00:35+0200\n"
+"PO-Revision-Date: 2015-01-23 21:46+0100\n"
+"Last-Translator: Alwin Esch\n"
+"Language-Team: German\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Your scanner version doesnt support services - Please upgrade."
+msgstr ""
+
+msgid "Your scanner version is to old - Please upgrade."
+msgstr ""
+
+msgid "Off"
+msgstr "Aus"
+
+msgid "RAM"
+msgstr "RAM"
+
+msgid "File"
+msgstr "Datei"
+
+msgid "Time Shift Mode"
+msgstr "Time Shift Modus"
+
+msgid "TS Buffersize (RAM) (1-80) x 100MB"
+msgstr "TS Puffergröße (RAM) (1-80) x 100MB"
+
+msgid "TS Buffersize (File) (1-10) x 1GB"
+msgstr "TS Puffergröße (Datei) (1-10) x 1GB"
+
+msgid "TS Buffer Directory"
+msgstr "TS-Puffer-Verzeichnis"
+
+msgid "Play Recording instead of live"
+msgstr "Wiedergeben als Aufzeichnung statt Live"
+
+msgid "Group series recordings"
+msgstr ""
+
+msgid "Avoid EPG scan while streaming"
+msgstr "Keine EPG suche während der Wiedergabe durchführen"
+
+msgid "Disable scramble timeout"
+msgstr ""
+
+msgid "Disable cam blacklist"
+msgstr ""
+
+msgid "scene"
+msgstr ""
+
+msgid "comskip"
+msgstr ""
+
+msgid "cut"
+msgstr ""
+
+msgid "EDL Mode"
+msgstr ""
+
+msgid "Recording with the same name exists"
+msgstr "Aufnahme mit der selben größe existiert"
+
+msgid "Error while read last filenumber"
+msgstr "Fehler beim lesen der letzen Dateinummer"
+
+msgid "Error while accessing vdrfile"
+msgstr "Fehler beim zugriff auf VDR-Datei"
+
+msgid "Error while accessing indexfile"
+msgstr "Fehler beim Zugriff der Indexdatei"
+
+msgid "Deleted recording vanished"
+msgstr "Gelöschte Aufnahme verschwunden"
+
+#~ msgid "PMT Timeout (0-10)"
+#~ msgstr "PMT Auszeit (0-10)"
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/po/lt_LT.po b/v/vdr-plugin-vnsiserver-1.8.0/po/lt_LT.po
new file mode 100644 (file)
index 0000000..630e167
--- /dev/null
@@ -0,0 +1,88 @@
+# VDR VNSI plugin language source file.
+# Copyright (C) 2015 Alwin Esch
+# This file is distributed under the same license as the VDR package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VNSI-Server 1.0.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2017-08-12 00:35+0200\n"
+"PO-Revision-Date: 2015-02-11 22:30+0200\n"
+"Last-Translator: Valdemaras Pipiras\n"
+"Language-Team: Lithuanian\n"
+"Language: lt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Your scanner version doesnt support services - Please upgrade."
+msgstr ""
+
+msgid "Your scanner version is to old - Please upgrade."
+msgstr ""
+
+msgid "Off"
+msgstr "Išjungta"
+
+msgid "RAM"
+msgstr "RAM"
+
+msgid "File"
+msgstr "Failas"
+
+msgid "Time Shift Mode"
+msgstr "Atidėto žiūrėjimo (TS) būsena"
+
+msgid "TS Buffersize (RAM) (1-80) x 100MB"
+msgstr "TS buferio dydis (RAM) (1-80) x 100MB"
+
+msgid "TS Buffersize (File) (1-10) x 1GB"
+msgstr "TS buferio dydis (Failas) (1-10) x 1GB"
+
+msgid "TS Buffer Directory"
+msgstr "TS katalogas buferiavimui"
+
+msgid "Play Recording instead of live"
+msgstr "Groti įrašą vietoj gyvos transliacijos"
+
+msgid "Group series recordings"
+msgstr ""
+
+msgid "Avoid EPG scan while streaming"
+msgstr "Vengti EPG skanavimo kol vyksta transliacija"
+
+msgid "Disable scramble timeout"
+msgstr ""
+
+msgid "Disable cam blacklist"
+msgstr ""
+
+msgid "scene"
+msgstr ""
+
+msgid "comskip"
+msgstr ""
+
+msgid "cut"
+msgstr ""
+
+msgid "EDL Mode"
+msgstr ""
+
+msgid "Recording with the same name exists"
+msgstr "Jau yra įrašų tokiu pat pavadinimu"
+
+msgid "Error while read last filenumber"
+msgstr "Klaida nuskaitant paskutinių failų skaičių"
+
+msgid "Error while accessing vdrfile"
+msgstr "Klaida bandant atidaryti VDR failą"
+
+msgid "Error while accessing indexfile"
+msgstr "Klaida bandant atidaryti index failą"
+
+msgid "Deleted recording vanished"
+msgstr "Ištrintas įrašas galutinai išvalytas"
+
+#~ msgid "PMT Timeout (0-10)"
+#~ msgstr "PMT  (0-10)"
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/recordingscache.c b/v/vdr-plugin-vnsiserver-1.8.0/recordingscache.c
new file mode 100644 (file)
index 0000000..1c4ff6e
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "recordingscache.h"
+#include "config.h"
+#include "vnsiclient.h"
+#include "hash.h"
+
+cRecordingsCache::cRecordingsCache() {
+}
+
+cRecordingsCache::~cRecordingsCache() {
+}
+
+cRecordingsCache& cRecordingsCache::GetInstance() {
+  static cRecordingsCache singleton;
+  return singleton;
+}
+
+uint32_t cRecordingsCache::Register(const cRecording* recording, bool deleted) {
+  cString filename = recording->FileName();
+  uint32_t uid = CreateStringHash(filename);
+
+  m_mutex.Lock();
+  if(m_recordings.find(uid) == m_recordings.end())
+  {
+    DEBUGLOG("%s - uid: %08x '%s'", __FUNCTION__, uid, (const char*)filename);
+    m_recordings[uid].filename = filename;
+    m_recordings[uid].isDeleted = deleted;
+  }
+  m_mutex.Unlock();
+
+  return uid;
+}
+
+const cRecording* cRecordingsCache::Lookup(uint32_t uid) {
+  DEBUGLOG("%s - lookup uid: %08x", __FUNCTION__, uid);
+
+  if(m_recordings.find(uid) == m_recordings.end()) {
+    DEBUGLOG("%s - not found !", __FUNCTION__);
+    return NULL;
+  }
+
+  m_mutex.Lock();
+  cString filename = m_recordings[uid].filename;
+  DEBUGLOG("%s - filename: %s", __FUNCTION__, (const char*)filename);
+
+  const cRecording* r;
+  if (!m_recordings[uid].isDeleted)
+  {
+#if VDRVERSNUM >= 20301
+    LOCK_RECORDINGS_READ;
+    r = Recordings->GetByName(filename);
+#else
+    r = Recordings.GetByName(filename);
+#endif
+  }
+  else
+  {
+#if VDRVERSNUM >= 20301
+    LOCK_DELETEDRECORDINGS_READ;
+    r = DeletedRecordings->GetByName(filename);
+#else
+    r = DeletedRecordings.GetByName(filename);
+#endif
+  }
+
+  DEBUGLOG("%s - recording %s", __FUNCTION__, (r == NULL) ? "not found !" : "found");
+  m_mutex.Unlock();
+
+  return r;
+}
+
+cRecording* cRecordingsCache::LookupWrite(uint32_t uid)
+{
+  DEBUGLOG("%s - lookup uid: %08x", __FUNCTION__, uid);
+
+  if(m_recordings.find(uid) == m_recordings.end())
+  {
+    DEBUGLOG("%s - not found !", __FUNCTION__);
+    return NULL;
+  }
+
+  m_mutex.Lock();
+  cString filename = m_recordings[uid].filename;
+  DEBUGLOG("%s - filename: %s", __FUNCTION__, (const char*)filename);
+
+  cRecording* r;
+  if (!m_recordings[uid].isDeleted)
+  {
+#if VDRVERSNUM >= 20301
+    LOCK_RECORDINGS_WRITE;
+    r = Recordings->GetByName(filename);
+#else
+    r = Recordings.GetByName(filename);
+#endif
+  }
+  else
+  {
+#if VDRVERSNUM >= 20301
+    LOCK_DELETEDRECORDINGS_WRITE;
+    r = DeletedRecordings->GetByName(filename);
+#else
+    r = DeletedRecordings.GetByName(filename);
+#endif
+  }
+
+  DEBUGLOG("%s - recording %s", __FUNCTION__, (r == NULL) ? "not found !" : "found");
+  m_mutex.Unlock();
+
+  return r;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/recordingscache.h b/v/vdr-plugin-vnsiserver-1.8.0/recordingscache.h
new file mode 100644 (file)
index 0000000..2dac71d
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_RECORDINGSCACHE_H
+#define VNSI_RECORDINGSCACHE_H
+
+#include <stdint.h>
+#include <map>
+#include <vdr/thread.h>
+#include <vdr/tools.h>
+#include <vdr/recording.h>
+
+class cRecordingsCache
+{
+protected:
+
+  cRecordingsCache();
+
+  virtual ~cRecordingsCache();
+
+public:
+
+  static cRecordingsCache& GetInstance();
+
+  uint32_t Register(const cRecording* recording, bool deleted = false);
+
+  const cRecording* Lookup(uint32_t uid);
+  cRecording* LookupWrite(uint32_t uid);
+
+private:
+  struct RecordingsInfo
+  {
+    cString filename;
+    bool isDeleted;
+  };
+  std::map<uint32_t, RecordingsInfo> m_recordings;
+
+  cMutex m_mutex;
+};
+
+
+#endif // VNSI_RECORDINGSCACHE_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/recplayer.c b/v/vdr-plugin-vnsiserver-1.8.0/recplayer.c
new file mode 100644 (file)
index 0000000..051c549
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2004-2005 Chris Tallon
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This code is taken from VOMP for VDR plugin.
+ */
+
+#include "recplayer.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef O_NOATIME
+#define O_NOATIME 0
+#endif
+
+cRecPlayer::cRecPlayer(const cRecording* rec, bool inProgress)
+  :m_inProgress(inProgress),
+   m_recordingFilename(rec->FileName()),
+   m_pesrecording(rec->IsPesRecording()),
+   m_indexFile(m_recordingFilename.c_str(), false, m_pesrecording),
+   m_file(-1), m_fileOpen(-1)
+{
+  // FIXME find out max file path / name lengths
+
+  if(m_pesrecording)
+    INFOLOG("recording '%s' is a PES recording", m_recordingFilename.c_str());
+
+  m_fps = rec->FramesPerSecond();
+
+  scan();
+}
+
+void cRecPlayer::cleanup() {
+  m_segments.clear();
+}
+
+void cRecPlayer::scan()
+{
+  struct stat s;
+
+  closeFile();
+
+  m_totalLength = 0;
+  m_fileOpen    = -1;
+  m_totalFrames = 0;
+
+  cleanup();
+
+  for(int i = 0; ; i++) // i think we only need one possible loop
+  {
+    fileNameFromIndex(i);
+
+    if(stat(m_fileName, &s) == -1) {
+      break;
+    }
+
+    cSegment segment;
+    segment.start = m_totalLength;
+    segment.end = segment.start + s.st_size;
+
+    m_segments.push_back(segment);
+
+    m_totalLength += s.st_size;
+    INFOLOG("File %i found, size: %lu, totalLength now %lu", i, s.st_size, m_totalLength);
+  }
+
+  m_totalFrames = m_indexFile.Last();
+  INFOLOG("total frames: %u", m_totalFrames);
+}
+
+void cRecPlayer::reScan()
+{
+  struct stat s;
+
+  m_totalLength = 0;
+
+  for(size_t i = 0; ; i++) // i think we only need one possible loop
+  {
+    fileNameFromIndex(i);
+
+    if(stat(m_fileName, &s) == -1) {
+      break;
+    }
+
+    cSegment* segment;
+    if (m_segments.size() < i+1)
+    {
+      m_segments.push_back(cSegment());
+      segment = &m_segments.back();
+      segment->start = m_totalLength;
+    }
+    else
+      segment = &m_segments[i];
+
+    segment->end = segment->start + s.st_size;
+
+    m_totalLength += s.st_size;
+  }
+
+  m_totalFrames = m_indexFile.Last();
+}
+
+
+cRecPlayer::~cRecPlayer()
+{
+  cleanup();
+  closeFile();
+}
+
+char* cRecPlayer::fileNameFromIndex(int index) {
+  if (m_pesrecording)
+    snprintf(m_fileName, sizeof(m_fileName), "%s/%03i.vdr", m_recordingFilename.c_str(), index+1);
+  else
+    snprintf(m_fileName, sizeof(m_fileName), "%s/%05i.ts", m_recordingFilename.c_str(), index+1);
+
+  return m_fileName;
+}
+
+bool cRecPlayer::openFile(int index)
+{
+  if (index == m_fileOpen) return true;
+  closeFile();
+
+  fileNameFromIndex(index);
+  INFOLOG("openFile called for index %i string:%s", index, m_fileName);
+
+  m_file = open(m_fileName, O_RDONLY);
+  if (m_file == -1)
+  {
+    INFOLOG("file failed to open");
+    m_fileOpen = -1;
+    return false;
+  }
+  m_fileOpen = index;
+  return true;
+}
+
+void cRecPlayer::closeFile()
+{
+  if(m_file == -1) {
+    return;
+  }
+
+  INFOLOG("file closed");
+  close(m_file);
+
+  m_file = -1;
+  m_fileOpen = -1;
+}
+
+uint64_t cRecPlayer::getLengthBytes()
+{
+  return m_totalLength;
+}
+
+uint32_t cRecPlayer::getLengthFrames()
+{
+  return m_totalFrames;
+}
+
+double cRecPlayer::getFPS()
+{
+  return m_fps;
+}
+
+int cRecPlayer::getBlock(unsigned char* buffer, uint64_t position, int amount)
+{
+  // dont let the block be larger than 256 kb
+  if (amount > 512*1024)
+    amount = 512*1024;
+
+  if ((uint64_t)amount > m_totalLength)
+    amount = m_totalLength;
+
+  if (position >= m_totalLength)
+  {
+    reScan();
+    if (position >= m_totalLength)
+    {
+      return 0;
+    }
+  }
+
+  if ((position + amount) > m_totalLength)
+    amount = m_totalLength - position;
+
+  // work out what block "position" is in
+  std::vector<cSegment>::iterator begin = m_segments.begin(),
+    end = m_segments.end(), segmentIterator = end;
+  for (std::vector<cSegment>::iterator i = begin; i != end; ++i) {
+    if ((position >= i->start) && (position < i->end)) {
+      segmentIterator = i;
+      break;
+    }
+  }
+
+  // segment not found / invalid position
+  if (segmentIterator == end)
+    return 0;
+
+  // open file (if not already open)
+  if (!openFile(std::distance(begin, segmentIterator)))
+    return 0;
+
+  // work out position in current file
+  uint64_t filePosition = position - segmentIterator->start;
+
+  // seek to position
+  if(lseek(m_file, filePosition, SEEK_SET) == -1)
+  {
+    ERRORLOG("unable to seek to position: %lu", filePosition);
+    return 0;
+  }
+
+  // try to read the block
+  int bytes_read = read(m_file, buffer, amount);
+
+  // we may got stuck at end of segment
+  if ((bytes_read == 0) && (position < m_totalLength))
+    bytes_read += getBlock(buffer, position+1 , amount);
+
+  if(bytes_read <= 0)
+  {
+    return 0;
+  }
+
+  if (!m_inProgress)
+  {
+#ifndef __FreeBSD__
+    // Tell linux not to bother keeping the data in the FS cache
+    posix_fadvise(m_file, filePosition, bytes_read, POSIX_FADV_DONTNEED);
+#endif
+  }
+
+  return bytes_read;
+}
+
+uint64_t cRecPlayer::positionFromFrameNumber(uint32_t frameNumber)
+{
+  uint16_t retFileNumber;
+  off_t retFileOffset;
+  bool retPicType;
+  int retLength;
+
+  if (!m_indexFile.Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
+    return 0;
+
+  if (retFileNumber >= m_segments.size()) 
+    return 0;
+
+  uint64_t position = m_segments[retFileNumber].start + retFileOffset;
+  return position;
+}
+
+uint32_t cRecPlayer::frameNumberFromPosition(uint64_t position)
+{
+  if (position >= m_totalLength)
+  {
+    DEBUGLOG("Client asked for data starting past end of recording!");
+    return m_totalFrames;
+  }
+
+  std::vector<cSegment>::iterator begin = m_segments.begin(),
+    end = m_segments.end(), segmentIterator = end;
+  for (std::vector<cSegment>::iterator i = begin; i != end; ++i) {
+    if ((position >= i->start) && (position < i->end)) {
+      segmentIterator = i;
+      break;
+    }
+  }
+
+  if (segmentIterator == end)
+    return m_totalFrames;
+
+  uint32_t askposition = position - segmentIterator->start;
+  int segmentNumber = std::distance(begin, segmentIterator);
+  return m_indexFile.Get((int)segmentNumber, askposition);
+}
+
+
+bool cRecPlayer::getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength)
+{
+  // 0 = backwards
+  // 1 = forwards
+
+  uint16_t waste1;
+  off_t waste2;
+
+  int iframeLength;
+  int indexReturnFrameNumber;
+
+  indexReturnFrameNumber = (uint32_t)m_indexFile.GetNextIFrame(frameNumber, (direction==1 ? true : false), &waste1, &waste2, &iframeLength);
+  DEBUGLOG("GNIF input framenumber:%u, direction=%u, output:framenumber=%i, framelength=%i", frameNumber, direction, indexReturnFrameNumber, iframeLength);
+
+  if (indexReturnFrameNumber == -1) return false;
+
+  *rfilePosition = positionFromFrameNumber(indexReturnFrameNumber);
+  *rframeNumber = (uint32_t)indexReturnFrameNumber;
+  *rframeLength = (uint32_t)iframeLength;
+
+  return true;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/recplayer.h b/v/vdr-plugin-vnsiserver-1.8.0/recplayer.h
new file mode 100644 (file)
index 0000000..776b791
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2004-2005 Chris Tallon
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This code is taken from VOMP for VDR plugin.
+ */
+
+#ifndef VNSI_RECPLAYER_H
+#define VNSI_RECPLAYER_H
+
+#include <stdio.h>
+#include <vdr/recording.h>
+
+#include "config.h"
+
+#include <vector>
+#include <string>
+
+class cSegment
+{
+  public:
+    uint64_t start;
+    uint64_t end;
+};
+
+class cRecPlayer
+{
+public:
+  cRecPlayer(const cRecording* rec, bool inProgress = false);
+  ~cRecPlayer();
+  uint64_t getLengthBytes();
+  uint32_t getLengthFrames();
+  double getFPS();
+  int getBlock(unsigned char* buffer, uint64_t position, int amount);
+
+  bool openFile(int index);
+  void closeFile();
+
+  void scan();
+  void reScan();
+  uint64_t positionFromFrameNumber(uint32_t frameNumber);
+  uint32_t frameNumberFromPosition(uint64_t position);
+  bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength);
+
+private:
+  void cleanup();
+  char* fileNameFromIndex(int index);
+  void checkBufferSize(int s);
+
+  const bool m_inProgress;
+  const std::string m_recordingFilename;
+  const bool m_pesrecording;
+  cIndexFile m_indexFile;
+  int m_file;
+  int m_fileOpen;
+  char m_fileName[512];
+  std::vector<cSegment> m_segments;
+  uint64_t m_totalLength;
+  uint32_t m_totalFrames;
+  double m_fps;
+};
+
+#endif // VNSI_RECPLAYER_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/requestpacket.c b/v/vdr-plugin-vnsiserver-1.8.0/requestpacket.c
new file mode 100644 (file)
index 0000000..86fec04
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2007 Chris Tallon
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "requestpacket.h"
+#include "vnsicommand.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __FreeBSD__
+#include <asm/byteorder.h>
+#else
+#include <sys/endian.h>
+#define __be64_to_cpu be64toh
+#define __cpu_to_be64 htobe64
+#endif
+
+cRequestPacket::cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, size_t dataLength)
+ : userData(data), userDataLength(dataLength), opCode(opcode), requestID(requestID)
+{
+  packetPos       = 0;
+  channelID       = 0;
+  streamID        = 0;
+  flag            = 0;
+}
+
+cRequestPacket::~cRequestPacket()
+{
+  delete[] userData;
+}
+
+bool cRequestPacket::end() const
+{
+  return (packetPos >= userDataLength);
+}
+
+char* cRequestPacket::extract_String()
+{
+  char *p = (char *)&userData[packetPos];
+  const char *end = (const char *)memchr(p, '\0', userDataLength - packetPos);
+  if (end == NULL)
+    /* string is not terminated - fail */
+    throw MalformedVNSIPacket();
+
+  int length = end - p;
+  packetPos += length + 1;
+  return p;
+}
+
+uint8_t cRequestPacket::extract_U8()
+{
+  if ((packetPos + sizeof(uint8_t)) > userDataLength)
+    throw MalformedVNSIPacket();
+  uint8_t uc = userData[packetPos];
+  packetPos += sizeof(uint8_t);
+  return uc;
+}
+
+uint32_t cRequestPacket::extract_U32()
+{
+  if ((packetPos + sizeof(uint32_t)) > userDataLength)
+    throw MalformedVNSIPacket();
+  uint32_t ul;
+  memcpy(&ul, &userData[packetPos], sizeof(uint32_t));
+  ul = ntohl(ul);
+  packetPos += sizeof(uint32_t);
+  return ul;
+}
+
+uint64_t cRequestPacket::extract_U64()
+{
+  if ((packetPos + sizeof(uint64_t)) > userDataLength)
+    throw MalformedVNSIPacket();
+  uint64_t ull;
+  memcpy(&ull, &userData[packetPos], sizeof(uint64_t));
+  ull = __be64_to_cpu(ull);
+  packetPos += sizeof(uint64_t);
+  return ull;
+}
+
+int64_t cRequestPacket::extract_S64()
+{
+  if ((packetPos + sizeof(int64_t)) > userDataLength)
+    throw MalformedVNSIPacket();
+  int64_t ll;
+  memcpy(&ll, &userData[packetPos], sizeof(int64_t));
+  ll = __be64_to_cpu(ll);
+  packetPos += sizeof(int64_t);
+  return ll;
+}
+
+double cRequestPacket::extract_Double()
+{
+  if ((packetPos + sizeof(uint64_t)) > userDataLength)
+    throw MalformedVNSIPacket();
+  uint64_t ull;
+  memcpy(&ull, &userData[packetPos], sizeof(uint64_t));
+  ull = __be64_to_cpu(ull);
+  double d;
+  memcpy(&d, &ull, sizeof(double));
+  packetPos += sizeof(uint64_t);
+  return d;
+}
+
+int32_t cRequestPacket::extract_S32()
+{
+  if ((packetPos + sizeof(int32_t)) > userDataLength)
+    throw MalformedVNSIPacket();
+  int32_t l;
+  memcpy(&l, &userData[packetPos], sizeof(int32_t));
+  l = ntohl(l);
+  packetPos += sizeof(int32_t);
+  return l;
+}
+
+uint8_t* cRequestPacket::getData()
+{
+  return userData;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/requestpacket.h b/v/vdr-plugin-vnsiserver-1.8.0/requestpacket.h
new file mode 100644 (file)
index 0000000..65d0f66
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2007 Chris Tallon
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_REQUESTPACKET_H
+#define VNSI_REQUESTPACKET_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <stdexcept>
+
+class MalformedVNSIPacket : public std::runtime_error {
+public:
+  MalformedVNSIPacket()
+    :std::runtime_error("Malformed VNSI packet") {}
+};
+
+class cRequestPacket
+{
+public:
+  cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, size_t dataLength);
+  ~cRequestPacket();
+
+  size_t    getDataLength() const { return userDataLength; }
+  uint32_t  getChannelID() const { return channelID; }
+  uint32_t  getRequestID() const { return requestID; }
+  uint32_t  getStreamID() const { return streamID; }
+  uint32_t  getFlag() const { return flag; }
+  uint32_t  getOpCode() const { return opCode; }
+
+  char*     extract_String();
+  uint8_t   extract_U8();
+  uint32_t  extract_U32();
+  uint64_t  extract_U64();
+  int64_t   extract_S64();
+  int32_t   extract_S32();
+  double    extract_Double();
+
+  bool      end() const;
+
+  // If you call this, the memory becomes yours. Free with free()
+  uint8_t* getData();
+
+private:
+  uint8_t* userData;
+  size_t userDataLength;
+  size_t packetPos;
+  uint32_t opCode;
+
+  uint32_t channelID;
+
+  uint32_t requestID;
+  uint32_t streamID;
+
+  uint32_t flag; // stream only
+};
+
+#endif // VNSI_REQUESTPACKET_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/responsepacket.c b/v/vdr-plugin-vnsiserver-1.8.0/responsepacket.c
new file mode 100644 (file)
index 0000000..8e944f1
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2007 Chris Tallon
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This code is taken from VOMP for VDR plugin.
+ */
+
+#include "responsepacket.h"
+#include "vnsicommand.h"
+#include "config.h"
+
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __FreeBSD__
+#include <asm/byteorder.h>
+#else
+#include <sys/endian.h>
+#define __be64_to_cpu be64toh
+#define __cpu_to_be64 htobe64
+#endif
+
+/* Packet format for an RR channel response:
+
+4 bytes = channel ID = 1 (request/response channel)
+4 bytes = request ID (from serialNumber)
+4 bytes = length of the rest of the packet
+? bytes = rest of packet. depends on packet
+*/
+
+cResponsePacket::cResponsePacket()
+{
+  buffer = NULL;
+  bufSize = 0;
+  bufUsed = 0;
+}
+
+cResponsePacket::~cResponsePacket()
+{
+  if (buffer) free(buffer);
+}
+
+void cResponsePacket::initBuffers()
+{
+  if (buffer == NULL) {
+    bufSize = 512;
+    buffer = (uint8_t*)malloc(bufSize);
+  }
+}
+
+void cResponsePacket::init(uint32_t requestID)
+{
+  initBuffers();
+
+  uint32_t ul;
+
+  ul = htonl(VNSI_CHANNEL_REQUEST_RESPONSE);                     // RR channel
+  memcpy(&buffer[0], &ul, sizeof(uint32_t));
+  ul = htonl(requestID);
+  memcpy(&buffer[4], &ul, sizeof(uint32_t));
+  ul = 0;
+  memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
+
+  bufUsed = headerLength;
+}
+
+void cResponsePacket::initScan(uint32_t opCode)
+{
+  initBuffers();
+
+  uint32_t ul;
+
+  ul = htonl(VNSI_CHANNEL_SCAN);                     // RR channel
+  memcpy(&buffer[0], &ul, sizeof(uint32_t));
+  ul = htonl(opCode);
+  memcpy(&buffer[4], &ul, sizeof(uint32_t));
+  ul = 0;
+  memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
+
+  bufUsed = headerLength;
+}
+
+void cResponsePacket::initStatus(uint32_t opCode)
+{
+  initBuffers();
+
+  uint32_t ul;
+
+  ul = htonl(VNSI_CHANNEL_STATUS);                     // RR channel
+  memcpy(&buffer[0], &ul, sizeof(uint32_t));
+  ul = htonl(opCode);
+  memcpy(&buffer[4], &ul, sizeof(uint32_t));
+  ul = 0;
+  memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
+
+  bufUsed = headerLength;
+}
+
+void cResponsePacket::initStream(uint32_t opCode, uint32_t streamID, uint32_t duration, int64_t pts, int64_t dts, uint32_t serial)
+{
+  initBuffers();
+
+  uint32_t ul;
+  uint64_t ull;
+
+  ul =  htonl(VNSI_CHANNEL_STREAM);            // stream channel
+  memcpy(&buffer[0], &ul, sizeof(uint32_t));
+  ul = htonl(opCode);                          // Stream packet operation code
+  memcpy(&buffer[4], &ul, sizeof(uint32_t));
+  ul = htonl(streamID);                        // Stream ID
+  memcpy(&buffer[8], &ul, sizeof(uint32_t));
+  ul = htonl(duration);                        // Duration
+  memcpy(&buffer[12], &ul, sizeof(uint32_t));
+  ull = __cpu_to_be64(pts);                    // PTS
+  memcpy(&buffer[16], &ull, sizeof(uint64_t));
+  ull = __cpu_to_be64(dts);                    // DTS
+  memcpy(&buffer[24], &ull, sizeof(uint64_t));
+  ul = htonl(serial);
+  memcpy(&buffer[32], &ul, sizeof(uint32_t));
+  ul = 0;
+  memcpy(&buffer[userDataLenPosStream], &ul, sizeof(uint32_t));
+
+  bufUsed = headerLengthStream;
+}
+
+void cResponsePacket::initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32_t x0, int32_t y0, int32_t x1, int32_t y1)
+{
+  initBuffers();
+
+  uint32_t ul;
+  int32_t l;
+
+  ul =  htonl(VNSI_CHANNEL_OSD);               // stream OSD
+  memcpy(&buffer[0], &ul, sizeof(uint32_t));
+  ul = htonl(opCode);                          // OSD operation code
+  memcpy(&buffer[4], &ul, sizeof(uint32_t));
+  l = htonl(wnd);                              // Window
+  memcpy(&buffer[8], &l, sizeof(int32_t));
+  l = htonl(color);                            // Color
+  memcpy(&buffer[12], &l, sizeof(int32_t));
+  l = htonl(x0);                               // x0
+  memcpy(&buffer[16], &l, sizeof(int32_t));
+  l = htonl(y0);                               // y0
+  memcpy(&buffer[20], &l, sizeof(int32_t));
+  l = htonl(x1);                               // x1
+  memcpy(&buffer[24], &l, sizeof(int32_t));
+  l = htonl(y1);                               // y1
+  memcpy(&buffer[28], &l, sizeof(int32_t));
+  ul = 0;
+  memcpy(&buffer[userDataLenPosOSD], &ul, sizeof(uint32_t));
+
+  bufUsed = headerLengthOSD;
+}
+
+void cResponsePacket::finalise()
+{
+  uint32_t ul = htonl(bufUsed - headerLength);
+  memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
+}
+
+void cResponsePacket::finaliseStream()
+{
+  uint32_t ul = htonl(bufUsed - headerLengthStream);
+  memcpy(&buffer[userDataLenPosStream], &ul, sizeof(uint32_t));
+}
+
+void cResponsePacket::finaliseOSD()
+{
+  uint32_t ul = htonl(bufUsed - headerLengthOSD);
+  memcpy(&buffer[userDataLenPosOSD], &ul, sizeof(uint32_t));
+}
+
+bool cResponsePacket::copyin(const uint8_t* src, uint32_t len)
+{
+  if (!checkExtend(len)) return false;
+  memcpy(buffer + bufUsed, src, len);
+  bufUsed += len;
+  return true;
+}
+
+uint8_t* cResponsePacket::reserve(uint32_t len) {
+  if (!checkExtend(len)) return 0;
+  uint8_t* result = buffer + bufUsed;
+  bufUsed += len;
+  return result;
+}
+
+bool cResponsePacket::unreserve(uint32_t len) {
+  if(bufUsed < len) return false;
+  bufUsed -= len;
+  return true;
+}
+
+bool cResponsePacket::add_String(const char* string)
+{
+  uint32_t len = strlen(string) + 1;
+  if (!checkExtend(len)) return false;
+  memcpy(buffer + bufUsed, string, len);
+  bufUsed += len;
+  return true;
+}
+
+bool cResponsePacket::add_U32(uint32_t ul)
+{
+  if (!checkExtend(sizeof(uint32_t))) return false;
+  uint32_t tmp = htonl(ul);
+  memcpy(&buffer[bufUsed], &tmp, sizeof(uint32_t));
+  bufUsed += sizeof(uint32_t);
+  return true;
+}
+
+bool cResponsePacket::add_U8(uint8_t c)
+{
+  if (!checkExtend(sizeof(uint8_t))) return false;
+  buffer[bufUsed] = c;
+  bufUsed += sizeof(uint8_t);
+  return true;
+}
+
+bool cResponsePacket::add_S32(int32_t l)
+{
+  if (!checkExtend(sizeof(int32_t))) return false;
+  int32_t tmp = htonl(l);
+  memcpy(&buffer[bufUsed], &tmp, sizeof(int32_t));
+  bufUsed += sizeof(int32_t);
+  return true;
+}
+
+bool cResponsePacket::add_U64(uint64_t ull)
+{
+  if (!checkExtend(sizeof(uint64_t))) return false;
+  uint64_t tmp = __cpu_to_be64(ull);
+  memcpy(&buffer[bufUsed], &tmp, sizeof(uint64_t));
+  bufUsed += sizeof(uint64_t);
+  return true;
+}
+
+bool cResponsePacket::add_double(double d)
+{
+  if (!checkExtend(sizeof(double))) return false;
+  uint64_t ull;
+  memcpy(&ull, &d, sizeof(double));
+  ull = __cpu_to_be64(ull);
+  memcpy(&buffer[bufUsed], &ull, sizeof(uint64_t));
+  bufUsed += sizeof(uint64_t);
+  return true;
+}
+
+
+bool cResponsePacket::checkExtend(uint32_t by)
+{
+  if ((bufUsed + by) < bufSize) return true;
+  if (512 > by) by = 512;
+  uint8_t* newBuf = (uint8_t*)realloc(buffer, bufSize + by);
+  if (!newBuf) return false;
+  buffer = newBuf;
+  bufSize += by;
+  return true;
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/responsepacket.h b/v/vdr-plugin-vnsiserver-1.8.0/responsepacket.h
new file mode 100644 (file)
index 0000000..6d7af8f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2007 Chris Tallon
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This code is taken from VOMP for VDR plugin.
+ */
+
+#ifndef VNSI_RESPONSEPACKET_H
+#define VNSI_RESPONSEPACKET_H
+
+#include <stdint.h>
+
+class cResponsePacket
+{
+public:
+  cResponsePacket();
+  ~cResponsePacket();
+
+  void init(uint32_t requestID);
+  void initScan(uint32_t opCode);
+  void initStatus(uint32_t opCode);
+  void initStream(uint32_t opCode, uint32_t streamID, uint32_t duration, int64_t pts, int64_t dts, uint32_t serial);
+  void initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+  void finalise();
+  void finaliseStream();
+  void finaliseOSD();
+  bool copyin(const uint8_t* src, uint32_t len);
+  uint8_t* reserve(uint32_t len);
+  bool unreserve(uint32_t len);
+
+  bool add_String(const char* string);
+  bool add_U32(uint32_t ul);
+  bool add_S32(int32_t l);
+  bool add_U8(uint8_t c);
+  bool add_U64(uint64_t ull);
+  bool add_double(double d);
+
+  uint8_t* getPtr() { return buffer; }
+  uint32_t getLen() { return bufUsed; }
+  uint32_t getStreamHeaderLength() { return headerLengthStream; } ;
+  uint32_t getOSDHeaderLength() { return headerLengthOSD; } ;
+  void     setLen(uint32_t len) { bufUsed = len; }
+
+private:
+  uint8_t* buffer;
+  uint32_t bufSize;
+  uint32_t bufUsed;
+
+  void initBuffers();
+  bool checkExtend(uint32_t by);
+
+  const static uint32_t headerLength          = 12;
+  const static uint32_t userDataLenPos        = 8;
+  const static uint32_t headerLengthStream    = 40;
+  const static uint32_t userDataLenPosStream  = 36;
+  const static uint32_t headerLengthOSD       = 36;
+  const static uint32_t userDataLenPosOSD     = 32;
+};
+
+#endif // VNSI_RESPONSEPACKET_H
+
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/setup.c b/v/vdr-plugin-vnsiserver-1.8.0/setup.c
new file mode 100644 (file)
index 0000000..9684137
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "setup.h"
+#include "vnsicommand.h"
+
+int PmtTimeout = 0;
+int TimeshiftMode = 0;
+int TimeshiftBufferSize = 5;
+int TimeshiftBufferFileSize = 6;
+char TimeshiftBufferDir[PATH_MAX] = "\0";
+int PlayRecording = 0;
+int GroupRecordings = 1;
+int AvoidEPGScan = 1;
+int DisableScrambleTimeout = 0;
+int DisableCamBlacklist = 0;
+int EdlMode = 0;
+
+cMenuSetupVNSI::cMenuSetupVNSI(void)
+{
+  timeshiftModesTexts[0] = tr("Off");
+  timeshiftModesTexts[1] = tr("RAM");
+  timeshiftModesTexts[2] = tr("File");
+  newTimeshiftMode = TimeshiftMode;
+  Add(new cMenuEditStraItem( tr("Time Shift Mode"), &newTimeshiftMode, 3, timeshiftModesTexts));
+
+  newTimeshiftBufferSize = TimeshiftBufferSize;
+  Add(new cMenuEditIntItem( tr("TS Buffersize (RAM) (1-80) x 100MB"), &newTimeshiftBufferSize));
+
+  newTimeshiftBufferFileSize = TimeshiftBufferFileSize;
+  Add(new cMenuEditIntItem( tr("TS Buffersize (File) (1-10) x 1GB"), &newTimeshiftBufferFileSize));
+
+  strn0cpy(newTimeshiftBufferDir, TimeshiftBufferDir, sizeof(newTimeshiftBufferDir));
+  Add(new cMenuEditStrItem(tr("TS Buffer Directory"), newTimeshiftBufferDir, sizeof(newTimeshiftBufferDir)));
+
+  newPlayRecording = PlayRecording;
+  Add(new cMenuEditBoolItem( tr("Play Recording instead of live"), &newPlayRecording));
+
+  newGroupRecordings = GroupRecordings;
+  Add(new cMenuEditBoolItem( tr("Group series recordings"), &newGroupRecordings));
+
+  newAvoidEPGScan = AvoidEPGScan;
+  Add(new cMenuEditBoolItem( tr("Avoid EPG scan while streaming"), &newAvoidEPGScan));
+
+  newDisableScrambleTimeout = DisableScrambleTimeout;
+  Add(new cMenuEditBoolItem( tr("Disable scramble timeout"), &newDisableScrambleTimeout));
+
+  newDisableCamBlacklist = DisableCamBlacklist;
+  Add(new cMenuEditBoolItem( tr("Disable cam blacklist"), &newDisableCamBlacklist));
+
+  edlModesTexts[0] = tr("scene");
+  edlModesTexts[1] = tr("comskip");
+  edlModesTexts[2] = tr("cut");
+  newEdlMode = EdlMode;
+  Add(new cMenuEditStraItem( tr("EDL Mode"), &newEdlMode, 3, edlModesTexts));
+}
+
+void cMenuSetupVNSI::Store(void)
+{
+  if (newPmtTimeout > 10 || newPmtTimeout < 0)
+    newPmtTimeout = 2;
+  SetupStore(CONFNAME_PMTTIMEOUT, PmtTimeout = newPmtTimeout);
+
+  SetupStore(CONFNAME_TIMESHIFT, TimeshiftMode = newTimeshiftMode);
+
+  if (newTimeshiftBufferSize > 80)
+    newTimeshiftBufferSize = 80;
+  else if (newTimeshiftBufferSize < 1)
+    newTimeshiftBufferSize = 1;
+  SetupStore(CONFNAME_TIMESHIFTBUFFERSIZE, TimeshiftBufferSize = newTimeshiftBufferSize);
+
+  if (newTimeshiftBufferFileSize > 20)
+    newTimeshiftBufferFileSize = 20;
+  else if (newTimeshiftBufferFileSize < 1)
+    newTimeshiftBufferFileSize = 1;
+  SetupStore(CONFNAME_TIMESHIFTBUFFERFILESIZE, TimeshiftBufferFileSize = newTimeshiftBufferFileSize);
+
+  strn0cpy(TimeshiftBufferDir, newTimeshiftBufferDir, sizeof(TimeshiftBufferDir));
+  if (*TimeshiftBufferDir && TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] == '/')
+    /* strip trailing slash */
+    TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] = 0;
+
+  SetupStore(CONFNAME_TIMESHIFTBUFFERDIR, TimeshiftBufferDir);
+
+  SetupStore(CONFNAME_PLAYRECORDING, PlayRecording = newPlayRecording);
+
+  SetupStore(CONFNAME_GROUPRECORDINGS, GroupRecordings = newGroupRecordings);
+
+  SetupStore(CONFNAME_AVOIDEPGSCAN, AvoidEPGScan = newAvoidEPGScan);
+
+  SetupStore(CONFNAME_DISABLESCRAMBLETIMEOUT, DisableScrambleTimeout = newDisableScrambleTimeout);
+
+  SetupStore(CONFNAME_DISABLECAMBLACKLIST, DisableCamBlacklist = newDisableCamBlacklist);
+
+  SetupStore(CONFNAME_EDL, EdlMode = newEdlMode);
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/setup.h b/v/vdr-plugin-vnsiserver-1.8.0/setup.h
new file mode 100644 (file)
index 0000000..89c4c55
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_SETUP_H
+#define VNSI_SETUP_H
+
+#include <vdr/plugin.h>
+
+class cMenuSetupVNSI : public cMenuSetupPage
+{
+private:
+  int newPmtTimeout;
+  int newTimeshiftMode;
+  const char *timeshiftModesTexts[3];
+  int newTimeshiftBufferSize;
+  int newTimeshiftBufferFileSize;
+  char newTimeshiftBufferDir[PATH_MAX];
+  int newPlayRecording;
+  int newGroupRecordings;
+  int newAvoidEPGScan;
+  int newDisableScrambleTimeout;
+  int newDisableCamBlacklist;
+  int newEdlMode;
+  const char *edlModesTexts[3];
+protected:
+  virtual void Store(void);
+public:
+  cMenuSetupVNSI(void);
+};
+
+#endif // VNSI_SETUP_H
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/status.c b/v/vdr-plugin-vnsiserver-1.8.0/status.c
new file mode 100644 (file)
index 0000000..be91bbb
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2014 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "status.h"
+#include "vnsi.h"
+
+#include <vdr/tools.h>
+#include <vdr/recording.h>
+#include <vdr/videodir.h>
+#include <vdr/shutdown.h>
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+cVNSIStatus::cVNSIStatus() : cThread("VNSIStatus")
+{
+}
+
+cVNSIStatus::~cVNSIStatus()
+{
+  Shutdown();
+}
+
+void cVNSIStatus::Init(CVNSITimers *timers)
+{
+  m_vnsiTimers = timers;
+  Start();
+}
+
+void cVNSIStatus::Shutdown()
+{
+  Cancel(5);
+  cMutexLock lock(&m_mutex);
+  m_clients.clear();
+}
+
+static bool CheckFileSuffix(const char *name,
+                            const char *suffix, size_t suffix_length)
+{
+  size_t name_length = strlen(name);
+  return name_length > suffix_length &&
+    memcmp(name + name_length - suffix_length, suffix, suffix_length) == 0;
+}
+
+static void DeleteFiles(const char *directory_path, const char *suffix)
+{
+  const size_t suffix_length = strlen(suffix);
+
+  DIR *dir = opendir(directory_path);
+  if (dir == nullptr)
+    return;
+
+  std::string path(directory_path);
+  path.push_back('/');
+  const size_t start = path.size();
+
+  while (auto *e = readdir(dir))
+  {
+    if (CheckFileSuffix(e->d_name, suffix, suffix_length))
+    {
+      path.replace(start, path.size(), e->d_name);
+
+      if (unlink(path.c_str()) < 0)
+      {
+        ERRORLOG("Failed to delete %s: %s", path.c_str(), strerror(errno));
+      }
+    }
+  }
+
+  closedir(dir);
+}
+
+void cVNSIStatus::AddClient(int fd, unsigned int id, const char *ClientAdr, CVNSITimers &timers)
+{
+  cMutexLock lock(&m_mutex);
+  std::shared_ptr<cVNSIClient> client = std::make_shared<cVNSIClient>(fd, id, ClientAdr, timers);
+  m_clients.push_back(client);
+}
+
+void cVNSIStatus::Action(void)
+{
+  cTimeMs chanTimer(0);
+  cTimeMs epgTimer(0);
+  cTimeMs recTimer(0);
+  int recCnt = 0;
+
+  // get initial state of the recordings
+#if VDRVERSNUM >= 20301
+  cStateKey chanState;
+  const cChannels *channels = cChannels::GetChannelsRead(chanState);
+  chanState.Remove(false);
+#endif
+
+  // get initial state of the recordings
+#if VDRVERSNUM >= 20301
+  cStateKey recState;
+  const cRecordings *recordings = cRecordings::GetRecordingsRead(recState);
+  recState.Remove(false);
+#else
+  int recState = -1;
+  Recordings.StateChanged(recState);
+#endif
+
+  // get initial state of the timers
+#if VDRVERSNUM >= 20301
+  cStateKey timerState;
+  const cTimers *timers = cTimers::GetTimersRead(timerState);
+  timerState.Remove(false);
+#else
+  int timerState = -1;
+  Timers.Modified(timerState);
+#endif
+
+  // vnsitimer
+  int vnsitimerState;
+  m_vnsiTimers->StateChange(vnsitimerState);
+
+  // last update of epg
+#if VDRVERSNUM >= 20301
+  cStateKey epgState;
+  const cSchedules *epg = cSchedules::GetSchedulesRead(epgState);
+  epgState.Remove(false);
+#else
+  time_t epgUpdate = cSchedules::Modified();
+#endif
+
+  // delete old timeshift file
+  struct stat sb;
+  if ((*TimeshiftBufferDir) && stat(TimeshiftBufferDir, &sb) == 0 && S_ISDIR(sb.st_mode))
+  {
+    DeleteFiles(TimeshiftBufferDir, ".vnsi");
+  }
+  else
+  {
+#if VDRVERSNUM >= 20102
+    DeleteFiles(cVideoDirectory::Name(), ".vnsi");
+#else
+    DeleteFiles(VideoDirectory, ".vnsi");
+#endif
+  }
+
+  // set thread priority
+  SetPriority(1);
+
+  while (Running())
+  {
+    m_mutex.Lock();
+
+    // remove disconnected clients
+    for (auto i = m_clients.begin(); i != m_clients.end();)
+    {
+      if (!(*i)->Active())
+      {
+        INFOLOG("removing client with ID %u from client list", (*i)->GetID());
+        i = m_clients.erase(i);
+      }
+      else
+      {
+        ++i;
+      }
+    }
+
+    // Don't to updates during running channel scan, KODI's PVR manager becomes
+    //restarted of finished scan.
+    if (!cVNSIClient::InhibidDataUpdates())
+    {
+      // reset inactivity timeout as long as there are clients connected
+      if (!m_clients.empty())
+      {
+        ShutdownHandler.SetUserInactiveTimeout();
+      }
+
+      // trigger clients to reload the modified channel list
+      if (chanTimer.TimedOut())
+      {
+#if VDRVERSNUM >= 20301
+        if (channels->Lock(chanState))
+        {
+          chanState.Remove(false);
+          INFOLOG("Requesting clients to reload channel list");
+          for (auto client : m_clients)
+            client->ChannelsChange();
+          chanTimer.Set(5000);
+        }
+#else
+        int modified = Channels.Modified();
+        if (modified)
+        {
+          Channels.SetModified((modified == CHANNELSMOD_USER) ? true : false);
+          INFOLOG("Requesting clients to reload channel list");
+          for (auto client : m_clients)
+            client->ChannelsChange();
+        }
+        chanTimer.Set(5000);
+#endif
+      }
+
+#if VDRVERSNUM >= 20301
+      if (recordings->Lock(recState))
+      {
+        recState.Remove();
+        recTimer.Set(2500);
+        ++recCnt;
+      }
+      else if (recCnt && recTimer.TimedOut())
+      {
+        INFOLOG("Requesting clients to reload recordings list (%d)", recCnt);
+        recCnt = 0;
+        for (auto client : m_clients)
+        {
+          client->RecordingsChange();
+        }
+      }
+
+      if (timers->Lock(timerState))
+      {
+        timerState.Remove(false);
+        INFOLOG("Requesting clients to reload timers");
+        for (auto client : m_clients)
+        {
+          client->SignalTimerChange();
+        }
+      }
+
+      if (m_vnsiTimers->StateChange(vnsitimerState))
+      {
+        INFOLOG("Requesting clients to reload vnsi-timers");
+        for (auto client : m_clients)
+        {
+          client->SignalTimerChange();
+        }
+      }
+
+      if (epgTimer.TimedOut())
+      {
+        if (epg->Lock(epgState))
+        {
+          epgState.Remove(false);
+          DEBUGLOG("Requesting clients to load epg");
+          int callAgain = 0;
+          for (auto client : m_clients)
+          {
+            callAgain |= client->EpgChange();
+          }
+          if (callAgain & VNSI_EPG_AGAIN)
+          {
+            epgTimer.Set(100);
+            epgState.Reset();
+          }
+          else
+          {
+            if (callAgain & VNSI_EPG_PAUSE)
+            {
+              epgState.Reset();
+            }
+            epgTimer.Set(5000);
+            m_vnsiTimers->Scan();
+          }
+        }
+      }
+#else
+      // update recordings
+      if (Recordings.StateChanged(recState))
+      {
+        INFOLOG("Recordings state changed (%i)", recState);
+        recTimer.Set(2500);
+        ++recCnt;
+      }
+      else if (recCnt && recTimer.TimedOut())
+      {
+        INFOLOG("Requesting clients to reload recordings list");
+        recCnt = 0;
+        for (auto client : m_clients)
+          client->RecordingsChange();
+      }
+
+      // update timers
+      if (Timers.Modified(timerState))
+      {
+        INFOLOG("Timers state changed (%i)", timerState);
+        INFOLOG("Requesting clients to reload timers");
+        for (auto client : m_clients)
+        {
+          client->SignalTimerChange();
+        }
+      }
+
+      // update epg
+      if ((cSchedules::Modified() > epgUpdate + 10) || time(NULL) > epgUpdate + 300)
+      {
+        for (auto client : m_clients)
+        {
+          client->EpgChange();
+        }
+        epgUpdate = time(NULL);
+      }
+#endif
+    }
+
+    m_mutex.Unlock();
+
+    usleep(250*1000);
+  }
+}
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/status.h b/v/vdr-plugin-vnsiserver-1.8.0/status.h
new file mode 100644 (file)
index 0000000..5afd5ae
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2005-2014 Team XBMC
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <vdr/thread.h>
+#include <list>
+#include <memory>
+#include "vnsitimer.h"
+#include "vnsiclient.h"
+
+class cVNSIClient;
+
+class cVNSIStatus : public cThread
+{
+public:
+  cVNSIStatus();
+  virtual ~cVNSIStatus();
+
+  cVNSIStatus(const cVNSIStatus &) = delete;
+  cVNSIStatus &operator=(const cVNSIStatus &) = delete;
+
+  void Init(CVNSITimers *timers);
+  void Shutdown();
+
+  void AddClient(int fd, unsigned int id, const char *ClientAdr, CVNSITimers &timers);
+
+protected:
+  virtual void Action(void);
+
+  std::list<std::shared_ptr<cVNSIClient>> m_clients;
+  cMutex m_mutex;
+  CVNSITimers *m_vnsiTimers;
+};
diff --git a/v/vdr-plugin-vnsiserver-1.8.0/streamer.c b/v/vdr-plugin-vnsiserver-1.8.0/streamer.c
new file mode 100644 (file)
index 0000000..7419692
--- /dev/null
@@ -0,0 +1,923 @@
+/*
+ *      vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ *      Copyright (C) 2010 Alwin Esch (Team XBMC)
+ *      Copyright (C) 2010, 2011 Alexander Pipelka
+ *      Copyright (C) 2015 Team KODI
+ *
+ *      http://kodi.tv
+ *
+ *  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, 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 KODI; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <time.h>
+
+// work-around for VDR's tools.h
+#if VDRVERSNUM < 20400
+#define __STL_CONFIG_H 1
+#else
+#define DISABLE_TEMPLATES_COLLIDING_WITH_STL 1
+#endif
+#include "streamer.h"
+
+#include "config.h"
+#include "cxsocket.h"
+#include "vnsicommand.h"
+#include "responsepacket.h"
+#include "vnsi.h"
+#include "videobuffer.h"
+
+#include <vdr/channels.h>
+#include <vdr/eitscan.h>
+
+// --- cLiveStreamer -------------------------------------------------
+
+cLiveStreamer::cLiveStreamer(int clientID, bool bAllowRDS, int protocol, uint8_t timeshift, uint32_t timeout)
+ : cThread("cLiveStreamer stream processor")
+ , m_ClientID(clientID)
+ , m_scanTimeout(timeout)
+ , m_Demuxer(bAllowRDS)
+ , m_VideoInput(m_Event)
+{
+  m_protocolVersion = protocol;
+  m_Timeshift = timeshift;
+
+  memset(&m_FrontendInfo, 0, sizeof(m_FrontendInfo));
+
+  if(m_scanTimeout == 0)
+    m_scanTimeout = VNSIServerConfig.stream_timeout;
+}
+
+cLiveStreamer::~cLiveStreamer()
+{
+  DEBUGLOG("Started to delete live streamer");
+
+  Cancel(5);
+  Close();
+
+  DEBUGLOG("Finished to delete live streamer");
+}
+
+bool cLiveStreamer::Open(int serial)
+{
+  Close();
+
+#if APIVERSNUM >= 10725
+  m_Device = cDevice::GetDevice(m_Channel, m_Priority, true, true);
+#else
+  m_Device = cDevice::GetDevice(m_Channel, m_Priority, true);
+#endif
+
+  if (!m_Device)
+    return false;
+
+  bool recording = false;
+  if (VNSIServerConfig.testStreamActive) // test harness
+  {
+    recording = true;
+    m_VideoBuffer = cVideoBuffer::Create(VNSIServerConfig.testStreamFile);
+  }
+  else if (PlayRecording && serial == -1)
+  {
+#if VDRVERSNUM >= 20301
+    LOCK_TIMERS_READ;
+    for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer))
+#else
+    for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer))
+#endif
+    {
+      if (timer &&
+          timer->Recording() &&
+          timer->Channel() == m_Channel)
+      {
+#if VDRVERSNUM >= 20301
+        LOCK_RECORDINGS_READ;
+        cTimer t(*timer);
+        cRecording matchRec(&t, t.Event());
+        const cRecording *rec;
+        {
+          rec = Recordings->GetByName(matchRec.FileName());
+          if (!rec)
+          {
+            return false;
+          }
+        }
+#else
+        Recordings.Load();
+        cRecording matchRec(timer, timer->Event());
+        cRecording *rec;
+        {
+          cThreadLock RecordingsLock(&Recordings);
+          rec = Recordings.GetByName(matchRec.FileName());
+          if (!rec)
+          {
+            return false;
+          }
+        }
+#endif
+        m_VideoBuffer = cVideoBuffer::Create(rec);
+        recording = true;
+        break;
+      }
+    }
+  }
+  if (!recording)
+  {
+    m_VideoBuffer = cVideoBuffer::Create(m_ClientID, m_Timeshift);
+  }
+
+  if (!m_VideoBuffer)
+    return false;
+
+  if (!recording)
+  {
+    if (m_Channel && ((m_Channel->Source() >> 24) == 'V'))
+      m_IsMPEGPS = true;
+
+    if (!m_VideoInput.Open(m_Channel, m_Priority, m_VideoBuffer))
+    {
+      ERRORLOG("Can't switch to channel %i - %s", m_Channel->Number(), m_Channel->Name());
+      return false;
+    }
+  }
+
+  m_Demuxer.Open(*m_Channel, m_VideoBuffer);
+  if (serial >= 0)
+    m_Demuxer.SetSerial(serial);
+
+  return true;
+}
+
+void cLiveStreamer::Close(void)
+{
+  INFOLOG("LiveStreamer::Close - close");
+  m_VideoInput.Close();
+  m_Demuxer.Close();
+  if (m_VideoBuffer)
+  {
+    delete m_VideoBuffer;
+    m_VideoBuffer = NULL;
+  }
+
+  if (m_Frontend >= 0)
+  {
+    close(m_Frontend);
+    m_Frontend = -1;
+  }
+}
+
+void cLiveStreamer::Action(void)
+{
+  int ret;
+  sStreamPacket pkt_data;
+  sStreamPacket pkt_side_data; // Additional data
+  memset(&pkt_data, 0, sizeof(sStreamPacket));
+  memset(&pkt_side_data, 0, sizeof(sStreamPacket));
+  bool requestStreamChangeData = false;
+  bool requestStreamChangeSideData = false;
+  cTimeMs last_info(1000);
+  cTimeMs bufferStatsTimer(1000);
+  int openFailCount = 0;
+
+  while (Running())
+  {
+    cVideoInput::eReceivingStatus retune = cVideoInput::NORMAL;
+    if (m_VideoInput.IsOpen())
+      retune = m_VideoInput.ReceivingStatus();
+    if (retune == cVideoInput::RETUNE)
+      // allow timeshift playback when retune == cVideoInput::CLOSE
+      ret = -1;
+    else
+      ret = m_Demuxer.Read(&pkt_data, &pkt_side_data);
+
+    if (ret > 0)
+    {
+      if (pkt_data.pmtChange)
+      {
+        requestStreamChangeData = true;
+        requestStreamChangeSideData = true;
+      }
+
+      // Process normal data if present
+      if (pkt_data.data)
+      {
+        if (pkt_data.streamChange || requestStreamChangeData)
+          sendStreamChange();
+        requestStreamChangeData = false;
+        if (pkt_data.reftime)
+        {
+          m_refTime = pkt_data.reftime;
+          m_refDTS = pkt_data.dts;
+          m_curDTS = (pkt_data.dts - m_refDTS) / DVD_TIME_BASE + m_refTime;
+          if (m_protocolVersion >= 11)
+          {
+            sendStreamTimes();
+            bufferStatsTimer.Set(1000);
+          }
+          else
+            sendRefTime(pkt_data);
+          pkt_data.reftime = 0;
+        }
+        m_curDTS = (pkt_data.dts - m_refDTS) / DVD_TIME_BASE + m_refTime;
+        if (bufferStatsTimer.TimedOut())
+        {
+          sendStreamTimes();
+          bufferStatsTimer.Set(1000);
+        }
+        sendStreamPacket(&pkt_data);
+      }
+
+      // If some additional data is present inside the stream, it is written there (currently RDS inside MPEG2-Audio)
+      if (pkt_side_data.data)
+      {
+        if (pkt_side_data.streamChange || requestStreamChangeSideData)
+          sendStreamChange();
+        requestStreamChangeSideData = false;
+
+        sendStreamPacket(&pkt_side_data);
+        pkt_side_data.data = NULL;
+      }
+
+      // send signal info every 10 sec.
+      if (last_info.TimedOut())
+      {
+        last_info.Set(10000);
+        sendSignalInfo();
+
+        // prevent EPG scan (activity timeout is 60s)
+        // EPG scan can cause artifacts on dual tuner cards
+        if (AvoidEPGScan)
+        {
+          EITScanner.Activity();
+        }
+      }
+
+      if (m_protocolVersion < 11)
+      {
+        // send buffer stats
+        if (bufferStatsTimer.TimedOut())
+        {
+          sendBufferStatus();
+          bufferStatsTimer.Set(1000);
+        }
+      }
+    }
+    else if (ret == -1)
+    {
+      // no data
+      if (retune == cVideoInput::CLOSE)
+      {
+        m_Socket->Shutdown();
+        break;
+      }
+      if (m_Demuxer.GetError() & ERROR_CAM_ERROR)
+      {
+        INFOLOG("CAM error, try reset");
+        cCamSlot *cs = m_Device->CamSlot();
+        if (cs)
+          cs->StopDecrypting();
+        retune = cVideoInput::RETUNE;
+      }
+      if (retune == cVideoInput::RETUNE)
+      {
+        INFOLOG("re-tuning...");
+        m_VideoInput.Close();
+        if (!m_VideoInput.Open(m_Channel, m_Priority, m_VideoBuffer))
+        {
+          if (++openFailCount == 3)
+          {
+            openFailCount = 0;
+            cCondWait::SleepMs(2000);
+          }
+          else
+            cCondWait::SleepMs(100);
+        }
+        else
+          openFailCount = 0;
+      }
+      else
+        m_Event.Wait(10);
+
+      if(m_last_tick.Elapsed() >= (uint64_t)(m_scanTimeout*1000))
+      {
+        sendStreamStatus();
+        m_last_tick.Set(0);
+        m_SignalLost = true;
+      }
+    }
+    else if (ret == -2)
+    {
+      if (!Open(m_Demuxer.GetSerial()))
+      {
+        m_Socket->Shutdown();
+        break;
+      }
+    }
+  }
+  INFOLOG("exit streamer thread");
+}
+
+bool cLiveStreamer::StreamChannel(const cChannel *channel, int priority, cxSocket *Socket, cResponsePacket *resp)
+{
+  if (channel == NULL)
+  {
+    ERRORLOG("Starting streaming of channel without valid channel");
+    return false;
+  }
+
+  m_Channel   = channel;
+  m_Priority  = priority;
+  m_Socket    = Socket;
+
+  if (m_Priority < 0)
+    m_Priority = 0;
+
+  if (!Open())
+    return false;
+
+  // Send the OK response here, that it is before the Stream end message
+  resp->add_U32(VNSI_RET_OK);
+  resp->finalise();
+  m_Socket->write(resp->getPtr(), resp->getLen());
+
+  Activate(true);
+
+  INFOLOG("Successfully switched to channel %i - %s", m_Channel->Number(), m_Channel->Name());
+  return true;
+}
+
+inline void cLiveStreamer::Activate(bool On)
+{
+  if (On)
+  {
+    DEBUGLOG("VDR active, sending stream start message");
+    Start();
+  }
+  else
+  {
+    DEBUGLOG("VDR inactive, sending stream end message");
+    Cancel(5);
+  }
+}
+
+void cLiveStreamer::sendStreamPacket(sStreamPacket *pkt)
+{
+  if (pkt == NULL)
+    return;
+
+  if (pkt->size == 0)
+    return;
+
+  m_streamHeader.initStream(VNSI_STREAM_MUXPKT, pkt->id, pkt->duration, pkt->pts, pkt->dts, pkt->serial);
+  m_streamHeader.setLen(m_streamHeader.getStreamHeaderLength() + pkt->size);
+  m_streamHeader.finaliseStream();
+
+  m_Socket->LockWrite();
+  m_Socket->write(m_streamHeader.getPtr(), m_streamHeader.getStreamHeaderLength(), -1, true);
+  m_Socket->write(pkt->data, pkt->size);
+  m_Socket->UnlockWrite();
+
+  m_last_tick.Set(0);
+  m_SignalLost = false;
+}
+
+void cLiveStreamer::sendStreamChange()
+{
+  cResponsePacket resp;
+  resp.initStream(VNSI_STREAM_CHANGE, 0, 0, 0, 0, 0);
+
+  uint32_t FpsScale, FpsRate, Height, Width;
+  double Aspect;
+  uint32_t Channels, SampleRate, BitRate, BitsPerSample, BlockAlign;
+  for (cTSStream* stream = m_Demuxer.GetFirstStream(); stream; stream = m_Demuxer.GetNextStream())
+  {
+    resp.add_U32(stream->GetPID());
+    if (stream->Type() == stMPEG2AUDIO)
+    {
+      stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
+      resp.add_String("MPEG2AUDIO");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(Channels);
+      resp.add_U32(SampleRate);
+      resp.add_U32(BlockAlign);
+      resp.add_U32(BitRate);
+      resp.add_U32(BitsPerSample);
+
+      for (const auto &i : stream->GetSideDataTypes())
+      {
+        resp.add_U32(i.first);
+        if (i.second == scRDS)
+        {
+          resp.add_String("RDS");
+          resp.add_String(stream->GetLanguage());
+          resp.add_U32(stream->GetPID());
+        }
+      }
+    }
+    else if (stream->Type() == stMPEG2VIDEO)
+    {
+      stream->GetVideoInformation(FpsScale, FpsRate, Height, Width, Aspect);
+      resp.add_String("MPEG2VIDEO");
+      resp.add_U32(FpsScale);
+      resp.add_U32(FpsRate);
+      resp.add_U32(Height);
+      resp.add_U32(Width);
+      resp.add_double(Aspect);
+    }
+    else if (stream->Type() == stAC3)
+    {
+      stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
+      resp.add_String("AC3");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(Channels);
+      resp.add_U32(SampleRate);
+      resp.add_U32(BlockAlign);
+      resp.add_U32(BitRate);
+      resp.add_U32(BitsPerSample);
+    }
+    else if (stream->Type() == stH264)
+    {
+      stream->GetVideoInformation(FpsScale, FpsRate, Height, Width, Aspect);
+      resp.add_String("H264");
+      resp.add_U32(FpsScale);
+      resp.add_U32(FpsRate);
+      resp.add_U32(Height);
+      resp.add_U32(Width);
+      resp.add_double(Aspect);
+    }
+    else if (stream->Type() == stHEVC)
+    {
+      stream->GetVideoInformation(FpsScale, FpsRate, Height, Width, Aspect);
+      resp.add_String("HEVC");
+      resp.add_U32(FpsScale);
+      resp.add_U32(FpsRate);
+      resp.add_U32(Height);
+      resp.add_U32(Width);
+      resp.add_double(Aspect);
+    }
+    else if (stream->Type() == stDVBSUB)
+    {
+      resp.add_String("DVBSUB");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(stream->CompositionPageId());
+      resp.add_U32(stream->AncillaryPageId());
+    }
+    else if (stream->Type() == stTELETEXT)
+    {
+      resp.add_String("TELETEXT");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(stream->CompositionPageId());
+      resp.add_U32(stream->AncillaryPageId());
+    }
+    else if (stream->Type() == stAACADTS)
+    {
+      stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
+      resp.add_String("AAC");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(Channels);
+      resp.add_U32(SampleRate);
+      resp.add_U32(BlockAlign);
+      resp.add_U32(BitRate);
+      resp.add_U32(BitsPerSample);
+    }
+    else if (stream->Type() == stAACLATM)
+    {
+      stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
+      resp.add_String("AAC_LATM");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(Channels);
+      resp.add_U32(SampleRate);
+      resp.add_U32(BlockAlign);
+      resp.add_U32(BitRate);
+      resp.add_U32(BitsPerSample);
+    }
+    else if (stream->Type() == stEAC3)
+    {
+      stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
+      resp.add_String("EAC3");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(Channels);
+      resp.add_U32(SampleRate);
+      resp.add_U32(BlockAlign);
+      resp.add_U32(BitRate);
+      resp.add_U32(BitsPerSample);
+    }
+    else if (stream->Type() == stDTS)
+    {
+      stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
+      resp.add_String("DTS");
+      resp.add_String(stream->GetLanguage());
+      resp.add_U32(Channels);
+      resp.add_U32(SampleRate);
+      resp.add_U32(BlockAlign);
+      resp.add_U32(BitRate);
+      resp.add_U32(BitsPerSample);
+    }
+  }
+
+  resp.finaliseStream();
+  m_Socket->write(resp.getPtr(), resp.getLen());
+}
+
+// taken from vdr 2.3.4+ keeping the comments
+static uint16_t dB1000toRelative(__s64 dB1000, int Low, int High)
+{
+  // Convert the given value, which is in 1/1000 dBm, to a percentage in the
+  // range 0..0xffff. Anything below Low is considered 0, and anything above
+  // High counts as 0xffff.
+  if (dB1000 < Low)
+    return 0;
+  if (dB1000 > High)
+    return 0xffff;
+  // return 0xffff - 0xffff * (High - dB1000) / (High - Low); // linear conversion
+  // return 0xffff - 0xffff * sqr(dB1000 - High) / sqr(Low - High); // quadratic conversion, see https://www.adriangranados.com/blog/dbm-to-percent-conversion
+  dB1000 = 256 * 256 * (dB1000 - High) / (Low - High); // avoids the sqr() function
+  dB1000 = (dB1000 * dB1000) / 0x10000;
+
+  if (dB1000 > 0xffff)
+    return 0;
+  return (uint16_t)(0xffff - dB1000);
+}
+
+void cLiveStreamer::sendSignalInfo()
+{
+
+  /* If no frontend is found m_Frontend is set to -2, in this case
+     return a empty signalinfo package */
+  if (m_Frontend == -2)
+  {
+    cResponsePacket resp;
+    resp.initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0);
+    resp.add_String(*cString::sprintf("Unknown"));
+    resp.add_String(*cString::sprintf("Unknown"));
+    resp.add_U32(0);
+    resp.add_U32(0);
+    resp.add_U32(0);
+    resp.add_U32(0);
+
+    resp.finaliseStream();
+
+    if (m_statusSocket)
+      m_statusSocket->write(resp.getPtr(), resp.getLen());
+    else
+      m_Socket->write(resp.getPtr(), resp.getLen());
+    return;
+  }
+
+  if (m_Channel && ((m_Channel->Source() >> 24) == 'V'))
+  {
+    if (m_Frontend < 0)
+    {
+      for (int i = 0; i < 8; i++)
+      {
+        m_DeviceString = cString::sprintf("/dev/video%d", i);
+        m_Frontend = open(m_DeviceString, O_RDONLY | O_NONBLOCK);
+        if (m_Frontend >= 0)
+        {
+          if (ioctl(m_Frontend, VIDIOC_QUERYCAP, &m_vcap) < 0)
+          {
+            ERRORLOG("cannot read analog frontend info.");
+            close(m_Frontend);
+            m_Frontend = -1;
+            memset(&m_vcap, 0, sizeof(m_vcap));
+            continue;
+          }
+          break;
+        }
+      }
+      if (m_Frontend < 0)
+        m_Frontend = -2;
+    }
+
+    if (m_Frontend >= 0)
+    {
+      cResponsePacket resp;
+      resp.initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0);
+      resp.add_String(*cString::sprintf("Analog #%s - %s (%s)", *m_DeviceString, (char *) m_vcap.card, m_vcap.driver));
+      resp.add_String("");
+      resp.add_U32(0);
+      resp.add_U32(0);
+      resp.add_U32(0);
+      resp.add_U32(0);
+
+      resp.finaliseStream();
+
+      if (m_statusSocket)
+        m_statusSocket->write(resp.getPtr(), resp.getLen());
+      else
+        m_Socket->write(resp.getPtr(), resp.getLen());
+    }
+  }
+  else
+  {
+    if (m_Frontend < 0)
+    {
+      m_DeviceString = cString::sprintf(FRONTEND_DEVICE, m_Device->CardIndex(), 0);
+      m_Frontend = open(m_DeviceString, O_RDONLY | O_NONBLOCK);
+      if (m_Frontend >= 0)
+      {
+        if (ioctl(m_Frontend, FE_GET_INFO, &m_FrontendInfo) < 0)
+        {
+          ERRORLOG("cannot read frontend info.");
+          close(m_Frontend);
+          m_Frontend = -2;
+          memset(&m_FrontendInfo, 0, sizeof(m_FrontendInfo));
+          return;
+        }
+      }
+    }
+
+    if (m_Frontend >= 0)
+    {
+      cResponsePacket resp;
+      resp.initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0);
+
+      fe_status_t status;
+      uint16_t fe_snr;
+      uint16_t fe_signal;
+      uint32_t fe_ber;
+      uint32_t fe_unc;
+
+      memset(&status, 0, sizeof(status));
+      ioctl(m_Frontend, FE_READ_STATUS, &status);
+
+      bool signal_needed(true), snr_needed(true), ber_needed(true), unc_needed(true);
+      dtv_property fe_props[4];
+      dtv_properties fe_cmd;
+      memset(&fe_props, 0, sizeof(fe_props));
+      memset(&fe_cmd, 0, sizeof(fe_cmd));
+
+      fe_props[0].cmd = DTV_STAT_SIGNAL_STRENGTH;
+      fe_props[1].cmd = DTV_STAT_CNR;
+      fe_props[2].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT;
+      fe_props[3].cmd = DTV_STAT_ERROR_BLOCK_COUNT;
+
+      fe_cmd.props = fe_props;
+      fe_cmd.num = 4;
+
+      if (ioctl(m_Frontend, FE_GET_PROPERTY, &fe_cmd) == 0)
+      {
+        if (fe_props[0].u.st.len > 0)
+        {
+          switch (fe_props[0].u.st.stat[0].scale)
+          {
+            case FE_SCALE_RELATIVE:
+              fe_signal = (uint16_t)fe_props[0].u.st.stat[0].uvalue;
+              signal_needed = false;
+              break;
+            case FE_SCALE_DECIBEL:
+              fe_signal = dB1000toRelative(fe_props[0].u.st.stat[0].svalue, -95000, -20000);
+              signal_needed = false;
+              DEBUGLOG("Signal decibel: %d -> %d",
+                       (int)fe_props[0].u.st.stat[0].svalue, (int)fe_signal);
+              break;
+          }
+        }
+        if (fe_props[1].u.st.len > 0)
+        {
+          switch (fe_props[1].u.st.stat[0].scale)
+          {
+            case FE_SCALE_RELATIVE:
+              fe_snr = (uint16_t)fe_props[1].u.st.stat[0].uvalue;
+              snr_needed = false;
+              break;
+            case FE_SCALE_DECIBEL:
+              fe_snr = dB1000toRelative(fe_props[1].u.st.stat[0].svalue, 5000, 20000);
+              snr_needed = false;
+              DEBUGLOG("SNR decibel: %d -> %d",
+                       (int)fe_props[1].u.st.stat[0].svalue, (int)fe_snr);
+              break;
+          }
+        }
+        if (fe_props[2].u.st.len > 0)
+        {
+          switch (fe_props[2].u.st.stat[0].scale)
+          {
+            case FE_SCALE_COUNTER:
+              fe_ber = (uint32_t)fe_props[2].u.st.stat[0].uvalue;
+              ber_needed = false;
+              break;
+            case FE_SCALE_NOT_AVAILABLE:
+              break;
+            default:
+              DEBUGLOG("BER scale: %d", fe_props[2].u.st.stat[0].scale);
+          }
+        }
+        if (fe_props[3].u.st.len > 0)
+        {
+          switch (fe_props[3].u.st.stat[0].scale)
+          {
+            case FE_SCALE_COUNTER:
+              fe_unc = (uint32_t)fe_props[3].u.st.stat[0].uvalue;
+              unc_needed = false;
+              break;
+            case FE_SCALE_NOT_AVAILABLE:
+              break;
+            default:
+              DEBUGLOG("UNC scale: %d", fe_props[3].u.st.stat[0].scale);
+          }
+        }
+      }
+
+      if (signal_needed && ioctl(m_Frontend, FE_READ_SIGNAL_STRENGTH, &fe_signal) == -1)
+        fe_signal = -2;
+      if (snr_needed && ioctl(m_Frontend, FE_READ_SNR, &fe_snr) == -1)
+        fe_snr = -2;
+      if (ber_needed && ioctl(m_Frontend, FE_READ_BER, &fe_ber) == -1)
+        fe_ber = -2;
+      if (unc_needed && ioctl(m_Frontend, FE_READ_UNCORRECTED_BLOCKS, &fe_unc) == -1)
+        fe_unc = -2;
+
+      switch (m_Channel->Source() & cSource::st_Mask)
+      {
+        case cSource::stSat:
+          resp.add_String(*cString::sprintf("DVB-S%s #%d - %s", (m_FrontendInfo.caps & 0x10000000) ? "2" : "",  m_Device->CardIndex(), m_FrontendInfo.name));
+          break;
+        case cSource::stCable:
+          resp.add_String(*cString::sprintf("DVB-C #%d - %s", m_Device->CardIndex(), m_FrontendInfo.name));
+          break;
+        case cSource::stTerr:
+          resp.add_String(*cString::sprintf("DVB-T #%d - %s", m_Device->CardIndex(), m_FrontendInfo.name));
+          break;
+        case cSource::stAtsc:
+          resp.add_String(*cString::sprintf("ATSC #%d - %s", m_Device->CardIndex(), m_FrontendInfo.name));
+          break;
+        default:
+          resp.add_U8(0);
+          break;
+      }
+      resp.add_String(*cString::sprintf("%s:%s:%s:%s:%s", (status & FE_HAS_LOCK) ? "LOCKED" : "-", (status & FE_HAS_SIGNAL) ? "SIGNAL" : "-", (status & FE_HAS_CARRIER) ? "CARRIER" : "-", (status & FE_HAS_VITERBI) ? "VITERBI" : "-", (status & FE_HAS_SYNC) ? "SYNC" : "-"));
+      resp.add_U32(fe_snr);
+      resp.add_U32(fe_signal);
+      resp.add_U32(fe_ber);
+      resp.add_U32(fe_unc);
+
+      resp.finaliseStream();
+
+      if (m_statusSocket)
+        m_statusSocket->write(resp.getPtr(), resp.getLen());
+      else
+        m_Socket->write(resp.getPtr(), resp.getLen());
+    }
+  }
+}
+
+void cLiveStreamer::sendStreamStatus()
+{
+  cResponsePacket resp;
+  resp.initStream(VNSI_STREAM_STATUS, 0, 0, 0, 0, 0);
+  uint16_t error = m_Demuxer.GetError();
+  if (error & ERROR_PES_SCRAMBLE)
+  {
+    INFOLOG("Channel: scrambled (PES) %d", error);
+    resp.add_String(cString::sprintf("Channel: scrambled (%d)", error));
+  }
+  else if (error & ERROR_TS_SCRAMBLE)
+  {
+    INFOLOG("Channel: scrambled (TS) %d", error);
+    resp.add_String(cString::sprintf("Channel: scrambled (%d)", error));
+  }
+  else if (error & ERROR_PES_STARTCODE)
+  {
+    INFOLOG("Channel: startcode %d", error);
+    resp.add_String(cString::sprintf("Channel: encrypted? (%d)", error));
+  }
+  else if (error & ERROR_DEMUX_NODATA)
+  {
+    INFOLOG("Channel: no data %d", error);
+    resp.add_String(cString::sprintf("Channel: no data"));
+  }
+  else
+  {
+    INFOLOG("Channel: unknown error %d", error);
+    resp.add_String(cString::sprintf("Channel: unknown error (%d)", error));
+  }
+
+  resp.finaliseStream();
+
+  if (m_statusSocket)
+    m_statusSocket->write(resp.getPtr(), resp.getLen());
+  else
+    m_Socket->write(resp.getPtr(), resp.getLen());
+}
+
+void cLiveStreamer::sendStreamTimes()
+{
+  if (m_Channel == NULL)
+    return;
+
+  cResponsePacket resp;
+  resp.initStream(VNSI_STREAM_TIMES, 0, 0, 0, 0, 0);
+
+  time_t starttime = m_refTime;
+  int64_t refDTS = m_refDTS;
+  time_t current = m_curDTS;
+
+  {
+#if VDRVERSNUM >= 20301
+    LOCK_SCHEDULES_READ;
+    const cSchedule *schedule = Schedules->GetSchedule(m_Channel);
+#else
+    cSchedulesLock MutexLock;
+    const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
+    if (!Schedules)
+      return;
+    const cSchedule *schedule = Schedules->GetSchedule(m_Channel);
+#endif
+    if (!schedule)
+      return;
+    const cEvent *event = schedule->GetEventAround(current);
+    if (event)
+    {
+      starttime = event->StartTime();
+      refDTS = (starttime - m_refTime) * DVD_TIME_BASE + m_refDTS;
+    }
+  }
+  uint32_t start, end;
+  bool timeshift;
+  int64_t mintime = current;
+  int64_t maxtime = current;
+  m_Demuxer.BufferStatus(timeshift, start, end);
+  if (timeshift)
+  {
+    mintime = (start - starttime) * DVD_TIME_BASE + refDTS;
+    maxtime = (end - starttime) * DVD_TIME_BASE + refDTS;
+  }
+
+  resp.add_U8(timeshift);
+  resp.add_U32(starttime);
+  resp.add_U64(refDTS);
+  resp.add_U64(mintime);
+  resp.add_U64(maxtime);
+  resp.finaliseStream();
+
+  if (m_statusSocket)
+    m_statusSocket->write(resp.getPtr(), resp.getLen());
+  else
+    m_Socket->write(resp.getPtr(), resp.getLen());
+}
+
+void cLiveStreamer::sendBufferStatus()
+{
+  cResponsePacket resp;
+  resp.initStream(VNSI_STREAM_BUFFERSTATS, 0, 0, 0, 0, 0);
+  uint32_t start, end;
+  bool timeshift;
+  m_Demuxer.BufferStatus(timeshift, start, end);
+  resp.add_U8(timeshift);
+  resp.add_U32(start);
+  resp.add_U32(end);
+  resp.finaliseStream();
+  m_Socket->write(resp.getPtr(), resp.getLen());
+}
+
+void cLiveStreamer::sendRefTime(sStreamPacket &pkt)
+{
+  cResponsePacket resp;
+  resp.initStream(VNSI_STREAM_REFTIME, 0, 0, 0, 0, 0);
+  resp.add_U32(pkt.reftime);
+  resp.add_U64(pkt.pts);
+  resp.finaliseStream();
+  m_Socket->write(resp.getPtr(), resp.getLen());
+}
+
+bool cLiveStreamer::SeekTime(int64_t time, uint32_t &serial)
+{
+  bool ret = m_Demuxer.SeekTime(time);
+  serial = m_Demuxer.GetSerial();
+  return ret;
+}
+
+void cLiveStreamer::RetuneChannel(const cChannel *channel)
+{
+  if (m_Channel != channel || !m_VideoInput.IsOpen())
+    return;
+
+  INFOLOG("re-tune to channel %s", m_Channel->Name());
+  m_VideoInput.RequestRetune();
+}
+
+void cLiveStreamer::AddStatusSocket(int fd)
+{
+  m_statusSocket.reset(new cxSocket(fd));
+}