summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
l---------FFMPEG patches/FFMPEG-libavformat-reduce-exits-on-subs-error.patch1
-rw-r--r--Readme.txt97
l---------VDR patches/VDR2.20-increase-frame-detector-for-x264.patch1
l---------VDR patches/VDR2.20-proposal-to-fix-index-generation-for-radio-recording.patch1
l---------batch.sh1
-rw-r--r--genindex/COPYING340
-rw-r--r--genindex/CVS/Entries17
-rw-r--r--genindex/CVS/Repository1
-rw-r--r--genindex/CVS/Root1
-rw-r--r--genindex/Makefile89
-rw-r--r--genindex/README108
-rw-r--r--genindex/fifo.c61
-rw-r--r--genindex/fifo.h27
-rw-r--r--genindex/file.c270
-rw-r--r--genindex/file.h77
-rw-r--r--genindex/genindex.c477
-rwxr-xr-xgenindex/modulo.h41
-rw-r--r--genindex/pes.c938
-rw-r--r--genindex/pes.h166
-rw-r--r--genindex/ringbuffer.c93
-rw-r--r--genindex/ringbuffer.h79
-rw-r--r--genindex/rmstream.c140
-rw-r--r--genindex/testindex.c68
-rw-r--r--genindex/thread.c45
-rw-r--r--genindex/thread.h32
-rw-r--r--genindex/tools.h690
-rw-r--r--genindex/version.h40
l---------vdr-auto1
l---------vdr-convert1
29 files changed, 3903 insertions, 0 deletions
diff --git a/FFMPEG patches/FFMPEG-libavformat-reduce-exits-on-subs-error.patch b/FFMPEG patches/FFMPEG-libavformat-reduce-exits-on-subs-error.patch
new file mode 120000
index 0000000..00ad9f1
--- /dev/null
+++ b/FFMPEG patches/FFMPEG-libavformat-reduce-exits-on-subs-error.patch
@@ -0,0 +1 @@
+/opt/data/develop/FFmpeg-rf/FFMPEG-libavformat-reduce-exits-on-subs-error.patch \ No newline at end of file
diff --git a/Readme.txt b/Readme.txt
new file mode 100644
index 0000000..4b684e5
--- /dev/null
+++ b/Readme.txt
@@ -0,0 +1,97 @@
+
+VDR-convert
+===========
+vdr-convert is a shell script with associated tools to transcode the content of VDR1.x and VDR2.x recordings as accurately as possible, including all streams, audio, AD, subtitles, and metadata into more compressed format, maintaining perceived quality. H264 and AAC are the chosen codecs for the main streams. SD recordings are reduced to anywhere from 35% - 90% of original size depending on content and compression settings. On average, you can expect to save 1/3 of the disk space used for SD recordings.
+
+The user can leave the transcoded files in-place for use by VDR or use them with external players such as Kodi, MPC-HC, or VLC
+
+Refer to the WIKI here for full usage instructions
+https://projects.vdr-developer.org/projects/vdr-convert/wiki
+
+Software required
+=================
+
+All recordings: System running Linux/bash shell, FFMPEG 3.x, VDR 2.2x, core Linux utilities such as nice, timeout etc
+
+Additionally for VDR 1.x recordings:
+
+a) Modified GENINDEX (0.2) to convert subtitles to standard ETSI EN300743 format, and remove initial short segment sequences that currently prevent ffmpeg reliably detecting subtitle streams
+
+b) MPLEX13818 from http://www.scara.com/~schirmer/o/mplex13818 to reliably convert recordings into an mpegts container. ffmpeg doesn't handle dvbsubs in a program stream (.vdr native format), and sometimes fails to probe .vdr files correctly. In testing, this muxer produced much more reliable .ts files from VDR recordings than the myriad of versions of "ps2ts" etc. out there in the web.
+
+Optionally NCFTP if you want to upload files after conversion
+
+Configuring
+===========
+vdr-convert is a standalone bash script - no spcific installation
+It should be placed in the system path, somewhere like /usr/local/bin
+Make sure it's executable!
+
+There are a few parameters at the top of vdr-convert to configure:
+
+"ffmpeg" - set to the path of the version of ffmpeg you plan to use.
+ (See "patching" below) Don't alter the ffmpeg parameters on the end of the line!
+
+"LOGFILE" - a place where system logs are kept, e.g. /var/log.
+ Make sure it's writable by whatever user you run vdr-convert under (e.g. vdr)
+
+"aac" set to libfdk_aac if you built and linked your ffmpeg with the non-free Fraunhofer AAC library
+
+set default langauages if you are missing VDR "info" files.
+
+batch.sh if you use it
+- configure with the root of your VDR recording directory so that it can trigger VDR re-reads
+
+
+Building genindex
+=================
+Required to convert VDR1.x recordings.
+Copy the genindex source supplied in this project, and then type "make"
+Copy the executable genindex to somewhere in the system path - e.g. /usr/local/bin
+Make sure there are no other older copies or versions of genindex on the system!
+
+Building MPLEX13818
+===================
+Required to convert VDR1.x recordings.
+Obtain a copy from the URL above
+Build with the makefile supplied
+Several executables are built, but vdr-convert only needs "iso13818ts"
+Copy the executable iso13818ts to somewhere in the system path - e.g. /usr/local/bin
+
+Patching
+========
+FFMPEG
+------
+You may consider patching ffmpeg if you have "broken" recordings - e.g where there was reception interference during recording. Stock ffmpeg is intolerant of subtitles streams with any DTS timestamp errors.
+
+To do this:
+Get an up-to-date copy of ffmpeg, e.g.
+* git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg or see https://ffmpeg.org/download.html
+* build it using ffmpeg instructions
+* add the file FFMPEG-libavformat-reduce-exits-on-subs-error.patch to the libavformat subdirectory
+* patch -p1<FFMPEG-libavformat-reduce-exits-on-subs-error.patch
+* Rebuild (quick)
+
+VDR
+----
+VDR benefits from a couple of minor patches too:
+a) to suppress warnings when reindexing, and, at the time of writing
+b) to allow re-indexing of audio-only recordings.
+
+The patches are in the VDR patches subdirectory
+Copy them to the VDR source directory, and patch as ffmpeg above
+Rebuild VDR as usual.
+
+
+Other utilities
+===============
+You are more than likely wanting to convert a whole selection in a recordings together.
+A small script called "batch.sh" is provided to assist.
+The wiki provides details of how to use this, make sure it is copied somehwere in the path, and that it's executable
+
+If you want to run vdr-convert automatically after each recording, the supplied script "vdr-auto" can be used. The wiki describes it's use. The version supplied is what the author uses daily, and includes a call to the venerable "noad" utility as well, to mark commercial breaks.
+
+Noad completes very much more quickly than vdr-convert because the ffmpeg libraries are doing much less work than libx264. It will therefore complete long before the recording file is replaced by vdr-convert, avoiding conflicts.
+noad or similar utilities can of course be run on the converted files too, and in test noad produces the same output (within a second). For this reason vdr-convert does not re-run noad on converted files, just copies any marks.vdr file over (if required for VDR1.x recordings).
+
+RF August 2016
diff --git a/VDR patches/VDR2.20-increase-frame-detector-for-x264.patch b/VDR patches/VDR2.20-increase-frame-detector-for-x264.patch
new file mode 120000
index 0000000..4021e2c
--- /dev/null
+++ b/VDR patches/VDR2.20-increase-frame-detector-for-x264.patch
@@ -0,0 +1 @@
+/opt/data/develop/vdr/vdr-220/patches/VDR2.20-increase-frame-detector-for-x264.patch \ No newline at end of file
diff --git a/VDR patches/VDR2.20-proposal-to-fix-index-generation-for-radio-recording.patch b/VDR patches/VDR2.20-proposal-to-fix-index-generation-for-radio-recording.patch
new file mode 120000
index 0000000..a516d15
--- /dev/null
+++ b/VDR patches/VDR2.20-proposal-to-fix-index-generation-for-radio-recording.patch
@@ -0,0 +1 @@
+/opt/data/develop/vdr/vdr-220/patches/VDR2.20-proposal-to-fix-index-generation-for-radio-recording.patch \ No newline at end of file
diff --git a/batch.sh b/batch.sh
new file mode 120000
index 0000000..1d13ce5
--- /dev/null
+++ b/batch.sh
@@ -0,0 +1 @@
+/opt/data/develop/scripts/batch.sh \ No newline at end of file
diff --git a/genindex/COPYING b/genindex/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/genindex/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General
+Public License instead of this License.
diff --git a/genindex/CVS/Entries b/genindex/CVS/Entries
new file mode 100644
index 0000000..fce9f5c
--- /dev/null
+++ b/genindex/CVS/Entries
@@ -0,0 +1,17 @@
+/COPYING/1.1/Wed Aug 18 21:27:14 2010//
+/rmstream.c/1.1/Wed Aug 18 21:27:14 2010//
+/testindex.c/1.1/Wed Aug 18 21:27:14 2010//
+/thread.c/1.1/Wed Aug 18 21:27:14 2010//
+/thread.h/1.1/Wed Aug 18 21:27:14 2010//
+/file.c/1.2/Fri Jul 1 08:42:58 2016//
+/file.h/1.2/Thu Sep 1 15:37:42 2016//
+/genindex.c/1.2/Thu Sep 1 15:37:42 2016//
+/Makefile/1.2/Thu Sep 1 15:37:42 2016//
+/pes.c/1.2/Thu Sep 1 15:37:42 2016//
+/pes.h/1.2/Thu Sep 1 15:37:42 2016//
+/README/1.2/Thu Sep 1 15:03:50 2016//
+/ringbuffer.c/1.2/Thu Sep 1 15:37:42 2016//
+/ringbuffer.h/1.2/Thu Sep 1 15:37:42 2016//
+/tools.h/1.2/Thu Sep 1 15:37:42 2016//
+/version.h/1.2/Thu Sep 1 15:37:42 2016//
+D
diff --git a/genindex/CVS/Repository b/genindex/CVS/Repository
new file mode 100644
index 0000000..570ba38
--- /dev/null
+++ b/genindex/CVS/Repository
@@ -0,0 +1 @@
+vdr/ADDONS/genindex
diff --git a/genindex/CVS/Root b/genindex/CVS/Root
new file mode 100644
index 0000000..f7f47c5
--- /dev/null
+++ b/genindex/CVS/Root
@@ -0,0 +1 @@
+:pserver:richard@localhost:2401/opt/cvs
diff --git a/genindex/Makefile b/genindex/Makefile
new file mode 100644
index 0000000..01e2505
--- /dev/null
+++ b/genindex/Makefile
@@ -0,0 +1,89 @@
+#
+# A VDR index file generator
+#
+# (C) 2003-2006 Stefan Huelswitt <s.huelswitt@gmx.de>, (c) RF 2016
+#
+# This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+#
+#-------------------------------------------------------------------------------
+# Revision History
+# $Log: Makefile,v $
+# Revision 1.2 2016/09/01 15:37:42 richard
+# Extensively updated to V0.2 for EN 300 743 compliant subtitles
+# added -b and -n flags
+#
+#-------------------------------------------------------------------------------
+
+CC ?= gcc
+#CFLAGS ?= -O2
+
+CXX ?= g++
+#CXXFLAGS ?= -g -Wall -Woverloaded-virtual # debugging
+CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual
+
+DEFINES = -D_GNU_SOURCE
+
+OBJS = genindex.o file.o thread.o ringbuffer.o pes.o fifo.o
+
+VERSION = $(shell grep 'define PRG_VERSION' version.h | awk '{ print $$3 }' | sed -e 's/[";]//g')
+TMPDIR = /tmp
+ARCHIVE = "genindex-$(VERSION)"
+
+all: genindex
+
+debug: CXXFLAGS += -DDEBUG -g
+debug: CCFLAGS += -DDEBUG -g
+debug: genindex
+
+# Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+# The main program:
+
+genindex: $(OBJS)
+ $(CXX) $(CXXFLAGS) $^ -o $@
+
+rmstream: rmstream.o thread.o ringbuffer.o pes.o
+ $(CXX) $(CXXFLAGS) $^ -o $@
+
+testindex: testindex.o file.o
+ $(CXX) $(CXXFLAGS) $^ -o $@
+
+# Housekeeping:
+
+clean:
+ -rm -f $(OBJS) $(ARCHIVE).tar.gz $(DEPFILE) genindex rmstream rmstream.o testindex.o testindex core*
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(ARCHIVE).tar.gz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(ARCHIVE).tar.gz
+
+# --------- $Id: Makefile,v 1.2 2016/09/01 15:37:42 richard Exp $ ---------- END \ No newline at end of file
diff --git a/genindex/README b/genindex/README
new file mode 100644
index 0000000..afc579f
--- /dev/null
+++ b/genindex/README
@@ -0,0 +1,108 @@
+
+Genindex
+(C) 2003-2006 Stefan Hulswitt s.huelswitt@gmx.de, (c) RF 2016
+
+See the file COPYING for license information.
+----------------------------------------------------------------------
+
+This tool can be used to:
+a) Generate a VDR 1.x index file
+b) Generate subtitles in EN 300 743 compliant format as part of a
+ conversion to VDR2.x file (along with vdr-convert script)
+c) Split VDR1.x files at a specified point. Note max total input size is
+ now increased to 16Gb from the original 2Gb. vdr-convert needs 1 file
+
+Useful if you lost the orginal index file or if you want to create an index
+file for some other video stuff.
+
+The tool is suitable for MPEG2 video (e.g. VDR1.x recordings) and MPEG1 video
+(e.g. ripped VCD files).
+
+If the tool is called without any commandline options, it searchs for VDR video
+files (001.vdr, 002.vdr ...) in the current directory.
+The generated index file will be named "index.vdr" or "index.vdr.generated" if
+there is already an "index.vdr".
+
+There are some commandline options to influence the behaviour of the tool:
+
+ -q
+ --quiet no output to the console, except errors.
+
+ -r
+ --rewrite enables rewrite mode, i.e. genindex reads all data
+ contained in the input file(s), filters out any crap
+ and/or data not usefull for VDR and writes the remaining
+ data to new file(s).
+ The output file(s) will be named 001.vdr, 002.vdr ...
+ and will not exceed the 2GB limit.
+ In no case any existing file will be overwritten, so you
+ cannot rewrite files from the current directory to the
+ current directory (use either -i or -d option).
+ Only data which is actually used by VDR is written to
+ output file(s), i.e. PES packets of type 0xE0-0xEF,
+ 0xC0-0xCF, 0xBD and 0xBE.
+
+ -d DIR
+ --dest=DIR Writes output files to directory DIR.
+
+ -i FILE
+ --input=FILE Rather than scanning for input files, use FILE as single
+ input file.
+
+ -s SIZE
+ --split=SIZE Split output files at a size of SIZE megabytes. Allowed
+ input range is 1-2000.
+
+ --skip=STR In addition to the normal stream filtering, skip PES
+ packets of type STR too. The value has to be given in
+ hexdecimal. You can give multiple --skip options, if you
+ want to skip more than one stream.
+
+ -b Build EN 300 743 compliant subs instead of VDR1.x (implies -r)
+
+ -n No progress indicator (like ffmpeg)
+
+The rewrite mode is especially useful if you want to prepare a single, huge
+file for replay with VDR e.g. a DVD rip.
+Assuming you have ripped the DVD to the file /tmp/rip.vob, you can prepare it
+with (creating VDR video files in current directoy):
+
+ genindex -r -i /tmp/rip.vob
+
+If you additionaly want to skip any DolbyDigital audio stream:
+
+ genindex -r -i /tmp/rip.vob --skip=0xBD
+
+Or limit output files to 1GB:
+
+ genindex -r -i /tmp/rip.vob -s 1000
+
+This work was inspired by and is based on the work from Werner Fink and Sascha
+Volkenandt (although virtualy no code pieces from their work made it into this
+work).
+
+----------------------------------------------------------------------
+
+HISTORY:
+
+01.09.2016 - Version 0.2.0 rf
+- Modified principally to process subtitles for vdr-convert script
+ in EN 300 743 format, and remove initial short subs segments to help
+ ffmpeg successfully probe the streams
+- added -b and -n flags
+
+05.06.2006 - Version 0.1.3
+- Added mode to rewrite video files (including file splitting and removing of
+ PES streams).
+- Allow a single input file >2GB in rewrite mode.
+
+17.10.2003 - Version 0.1.2
+- Don't choke on files >2GB but give the user a hint about the limitation.
+
+27.07.2003 - Version 0.1.1
+- Fixed index creation behond the first video file.
+- Fixed index creation for broken video files (e.g. with skipped bytes).
+
+26.07.2003 - Version 0.1.0
+- Initial release.
+
diff --git a/genindex/fifo.c b/genindex/fifo.c
new file mode 100644
index 0000000..cf68cda
--- /dev/null
+++ b/genindex/fifo.c
@@ -0,0 +1,61 @@
+//fifo.h
+// Simple fifo
+// http://stratifylabs.co/embedded%20design%20tips/2013/10/02/Tips-A-FIFO-Buffer-Implementation/
+
+#include <stdio.h>
+#include <stdlib.h>
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
+#include "fifo.h"
+
+//This initializes the FIFO structure with the given buffer and size
+void fifo_init(fifo_t * f, uchar * buf, int size) {
+ f->head = 0;
+ f->tail = 0;
+ f->size = size;
+ f->buf = buf;
+}
+
+//This reads nbytes bytes from the FIFO
+//The number of bytes read is returned
+int fifo_read(fifo_t * f, uchar * buf, int nbytes) {
+ int i;
+ uchar * p;
+ p = buf;
+ for(i=0; i < nbytes; i++){
+ if( f->tail != f->head ){ //see if any data is available
+ *p++ = f->buf[f->tail]; //grab a byte from the buffer
+ f->tail++; //increment the tail
+ if( f->tail == f->size ){ //check for wrap-around
+ f->tail = 0;
+ }
+ } else {
+ return i; //number of bytes read
+ }
+ }
+ return nbytes;
+}
+
+//This writes up to nbytes bytes to the FIFO
+//If the head runs in to the tail, not all bytes are written
+//The number of bytes written is returned
+int fifo_write(fifo_t * f, const uchar * buf, int nbytes) {
+ int i;
+ const uchar * p;
+ p = buf;
+ for(i=0; i < nbytes; i++) {
+ //first check to see if there is space in the buffer
+ if ( (f->head + 1 == f->tail) ||
+ ( (f->head + 1 == f->size) && (f->tail == 0) )) {
+ return i; //no more room
+ } else {
+ f->buf[f->head] = *p++;
+ f->head++; //increment the head
+ if( f->head == f->size ){ //check for wrap-around
+ f->head = 0;
+ }
+ }
+ }
+ return nbytes;
+}
+// --------- $Id: vdr-convert,v 1.3 2016/09/01 13:01:48 richard Exp $ ---------- END
diff --git a/genindex/fifo.h b/genindex/fifo.h
new file mode 100644
index 0000000..c22343c
--- /dev/null
+++ b/genindex/fifo.h
@@ -0,0 +1,27 @@
+//fifo.h
+/*-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: xmltv2vdr.pl,v $
+ *-------------------------------------------------------------------------------
+*/
+
+#ifndef __FIFO_H
+#define __FIFO_H
+
+#include <stdio.h>
+#include "tools.h"
+
+typedef struct {
+ uchar * buf;
+ int head;
+ int tail;
+ int size;
+} fifo_t;
+
+void fifo_init(fifo_t * f, uchar * buf, int size);
+int fifo_read(fifo_t * f, uchar * buf, int nbytes);
+int fifo_write(fifo_t * f, const uchar * buf, int nbytes);
+
+#endif // __FIFO_H
+
+// --------- $Id: vdr-convert,v 1.3 2016/09/01 13:01:48 richard Exp $ ---------- END \ No newline at end of file
diff --git a/genindex/file.c b/genindex/file.c
new file mode 100644
index 0000000..12abbf1
--- /dev/null
+++ b/genindex/file.c
@@ -0,0 +1,270 @@
+/*
+ * A VDR index file generator (C++)
+ *
+ * (C) 2003-2006 Stefan Huelswitt <s.huelswitt@gmx.de>
+ *
+ * This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "file.h"
+
+#define INDEX "index.vdr"
+#define INDEX_ALT "index.vdr.generated"
+#define FILENAME "%03d.vdr"
+
+extern bool quiet;
+
+// --- cString ---------------------------------------------------------------
+
+/* RF using tools.h now
+class cString {
+private:
+ char *s;
+public:
+ cString(const char *S = NULL, bool TakePointer = false);
+ cString(const cString &String);
+ virtual ~cString();
+ operator const char * () const { return s; } // for use in (const char *) context
+ const char * operator*() const { return s; } // for use in (const void *) context (printf() etc.)
+ cString &operator=(const cString &String);
+ static cString sprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+ };
+*/
+
+cString::cString(const char *S, bool TakePointer)
+{
+ s = TakePointer ? (char *)S : S ? strdup(S) : NULL;
+}
+
+cString::cString(const cString &String)
+{
+ s = String.s ? strdup(String.s) : NULL;
+}
+
+cString::~cString()
+{
+ free(s);
+}
+
+cString &cString::operator=(const cString &String)
+{
+ if (this == &String)
+ return *this;
+ free(s);
+ s = String.s ? strdup(String.s) : NULL;
+ return *this;
+}
+
+// vdr tools.c
+cString &cString::operator=(const char *String)
+{
+ if (s == String)
+ return *this;
+ free(s);
+ s = String ? strdup(String) : NULL;
+ return *this;
+}
+
+cString cString::sprintf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ char *buffer;
+ vasprintf(&buffer, fmt, ap);
+ return cString(buffer, true);
+}
+
+// -----------------------------------------------------------------------------
+
+cString AddDirectory(const char *DirName, const char *FileName)
+{
+ char *buf;
+ asprintf(&buf, "%s/%s", DirName && *DirName ? DirName : ".", FileName);
+ return cString(buf, true);
+}
+
+// --- cIndex ------------------------------------------------------------------
+
+cIndex::cIndex(const char *Dir)
+{
+ dir=Dir; f=0;
+}
+
+cIndex::~cIndex()
+{
+ if(f) fclose(f);
+}
+
+bool cIndex::Open(bool Read)
+{
+ int r;
+ cString name=AddDirectory(dir,INDEX);
+ r=access(name,F_OK);
+ read=Read;
+ if(!Read) {
+ if(r==0) {
+ if(!quiet) printf("There is an existing index file. Trying alternative filename.\n");
+ name=AddDirectory(dir,INDEX_ALT);
+ r=access(name,F_OK);
+ if(r==0) printf("Alternative index file exists too. Aborting.\n");
+ }
+ if(r<0) {
+ if(errno==ENOENT) {
+ f=fopen(name,"w");
+ if(f) return true;
+ else printf("index file open: %s\n",strerror(errno));
+ }
+ else printf("index file check: %s\n",strerror(errno));
+ }
+ }
+ else {
+ if(r==0) {
+ f=fopen(name,"r");
+ if(f) return true;
+ else printf("index file open: %s\n",strerror(errno));
+ }
+ else printf("index file check: %s\n",strerror(errno));
+ }
+ return false;
+}
+
+bool cIndex::Write(int fileNr, int fileOff, int picType)
+{
+ if(f && !read) {
+ struct tIndex in;
+ in.offset=fileOff;
+ in.number=fileNr;
+ in.type=picType;
+ in.reserved=0;
+ if(fwrite(&in,sizeof(in),1,f)==1) return true;
+ else printf("index write failed\n");
+ }
+ else printf("internal: no open write index file\n");
+ return false;
+}
+
+bool cIndex::Read(int &fileNr, int &fileOff)
+{
+ if(f && read) {
+ struct tIndex in;
+ if(fread(&in,sizeof(in),1,f)==1) {
+ fileOff=in.offset;
+ fileNr=in.number;
+ return true;
+ }
+ else if(!feof(f)) printf("index read failed\n");
+ }
+ else printf("internal: no open read index file\n");
+ return false;
+}
+
+// --- cFileName ---------------------------------------------------------------
+
+cFileName::cFileName(const char *Input, bool LargeOK)
+{
+ input=Input; largeOK=LargeOK;
+ fd=-1;
+ fileno=1;
+}
+
+cFileName::~cFileName()
+{
+ close(fd);
+}
+
+int cFileName::Open(void)
+{
+ close(fd); fd=-1;
+ cString filename;
+ if(input) filename=input;
+ else filename=cString::sprintf(FILENAME,fileno);
+ fd=open64(filename,O_RDONLY);
+ if(fd>=0) {
+ struct stat64 st;
+ if(fstat64(fd,&st)==0) {
+ if(!(st.st_size>>31) || largeOK) {
+ size=st.st_size;
+ if(!quiet) printf("reading from %s \n",*filename);
+ }
+ else {
+ printf("%s: filesize exceeds 2GB limit\n",*filename);
+ close(fd); fd=-1;
+ }
+ }
+ else {
+ printf("fstat: %s\n",strerror(errno));
+ close(fd); fd=-1;
+ }
+ }
+ else if(fileno==1 || errno!=ENOENT)
+ printf("open %s: %s\n",*filename,strerror(errno));
+ return fd;
+}
+
+int cFileName::OpenWrite(void)
+{
+ close(fd); fd=-1;
+ cString filename=AddDirectory(input,cString::sprintf(FILENAME,fileno));
+ if(access(filename,F_OK)!=0) {
+ fd=open64(filename,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if(fd>=0) {
+ size=0;
+ if(!quiet) printf("writing to %s \n",*filename);
+ }
+ else printf("open %s: %s\n",*filename,strerror(errno));
+ }
+ else printf("%s: file already exists\n",*filename);
+ return fd;
+}
+
+int cFileName::NextFile(void)
+{
+ if(!input) {
+ fileno++;
+ return Open();
+ }
+ return -1;
+}
+
+int cFileName::NextWriteFile(void)
+{
+ fileno++;
+ return OpenWrite();
+}
+
+int cFileName::Skip(int nr, int off)
+{
+ if(fileno!=nr || fd<0) {
+ fileno=nr;
+ if(Open()<0) return -1;
+ }
+ if(lseek(fd,off,SEEK_SET)<0) {
+ printf("seek: %s\n",strerror(errno));
+ return -1;
+ }
+ return fd;
+}
diff --git a/genindex/file.h b/genindex/file.h
new file mode 100644
index 0000000..56f5a42
--- /dev/null
+++ b/genindex/file.h
@@ -0,0 +1,77 @@
+/*
+ * A VDR index file generator (C++)
+ *
+ * (C) 2003-2006 Stefan Huelswitt <s.huelswitt@gmx.de>
+ *
+ * This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: file.h,v $
+ * Revision 1.2 2016/09/01 15:37:42 richard
+ * Extensively updated to V0.2 for EN 300 743 compliant subtitles
+ * added -b and -n flags
+ *
+ *-------------------------------------------------------------------------------
+ */
+
+#ifndef __FILE_H
+#define __FILE_H
+
+#include <stdio.h>
+#include "tools.h"
+
+// -------------------------------------------------------------------
+
+class cIndex {
+private:
+ FILE *f;
+ bool read;
+ const char *dir;
+ struct tIndex { int offset; uchar type; uchar number; short reserved; };
+public:
+ cIndex(const char *Dir);
+ ~cIndex();
+ bool Open(bool Read=false);
+ bool Write(int fileNr, int fileOff, int picType);
+ bool Read(int &fileNr, int &fileOff);
+ };
+
+// -------------------------------------------------------------------
+
+class cFileName {
+private:
+ const char *input;
+ bool largeOK;
+ int fd;
+ int fileno;
+ long long size;
+ char filename[64];
+public:
+ cFileName(const char *Input, bool LargeOK);
+ ~cFileName();
+ int Open(void);
+ int NextFile(void);
+ int OpenWrite(void);
+ int NextWriteFile(void);
+ int Skip(int nr, int off);
+ int FileNumber(void) { return fileno; }
+ long long FileSize(void) { return size; }
+ };
+
+#endif
+
+// --------- $Id: file.h,v 1.2 2016/09/01 15:37:42 richard Exp $ ---------- END
diff --git a/genindex/genindex.c b/genindex/genindex.c
new file mode 100644
index 0000000..1a87616
--- /dev/null
+++ b/genindex/genindex.c
@@ -0,0 +1,477 @@
+/*
+ * A VDR index file generator (C++)
+ *
+ * (C) 2003-2006 Stefan Huelswitt <s.huelswitt@gmx.de>, (c) RF 2016
+ * (C) 2016 Richard Farthing, added subtitle functions
+ *
+ * This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: genindex.c,v $
+ * Revision 1.2 2016/09/01 15:37:42 richard
+ * Extensively updated to V0.2 for EN 300 743 compliant subtitles
+ * added -b and -n flags
+ *
+ *-------------------------------------------------------------------------------
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "file.h"
+#include "pes.h"
+#include "version.h"
+
+#define MAX_FILE_NR 99
+
+// Picture types:
+#define I_FRAME 1
+#define P_FRAME 2
+#define B_FRAME 3
+
+
+char *destdir=0;
+char *input=0;
+int splitsize=16000; // RF was 2000, but don't want to auto split - not req'd
+bool rewrite=false;
+bool build=false;
+bool nostats=false;
+bool quiet=false;
+
+// --- cGenIndex ---------------------------------------------------------------
+
+class cGenIndex : public cPES {
+private:
+ cFileName *fileName, *writeName;
+ cIndex *index;
+ //
+ int replayFile, writeFile;
+ int fileNo, fileOffset, packetOffset, packetNo;
+ bool eof, scan, error;
+ int state, skip;
+ int readNo;
+ long long readOffset;
+ long long fileSize[MAX_FILE_NR+1];
+ //
+ unsigned int sSize;
+ int64_t splitOffset;
+ bool pstart;
+ //
+ unsigned char buff[KILOBYTE(256)];
+ uchar store[KILOBYTE(66)];
+ //
+ bool NextFile(void);
+ void Count(int len);
+ bool SafeWrite(int fd, const unsigned char *data, int len);
+protected:
+ virtual int Output(const uchar *data, int len);
+ virtual int Action1(uchar type, uchar *data, int len);
+ virtual int Action2(uchar type, uchar *data, int len);
+ virtual void Skipped(uchar *data, int len);
+public:
+ cGenIndex(void);
+ ~cGenIndex();
+ void Work(void);
+ void Skip(int type);
+};
+
+cGenIndex::cGenIndex(void)
+{
+ index=new cIndex(destdir);
+ fileName=new cFileName(input,input && rewrite);
+ writeName=new cFileName(destdir,true);
+
+ if(rewrite) {
+ SetDefaultRule(prSkip);
+ SetRuleR(0xE0,0xEF,prAct2); //video
+ SetRuleR(0xC0,0xCF,prAct1); //audio
+ if (build) {
+ SetRule(0xBD,prAct3); //ac3 + subs
+ } else {
+ SetRule(0xBD,prAct1);
+ }
+ SetRule(0xBE,prAct1);
+ } else {
+ SetDefaultRule(prAct1);
+ SetRuleR(0xE0,0xEF,prAct2);
+ }
+}
+
+cGenIndex::~cGenIndex()
+{
+ delete fileName;
+ delete writeName;
+ delete index;
+}
+
+void cGenIndex::Skip(int type)
+{
+ if(rewrite) SetRule(type,prSkip);
+}
+
+bool cGenIndex::NextFile(void)
+{
+ if(replayFile>=0 && eof) {
+ replayFile=fileName->NextFile();
+ readNo=fileName->FileNumber();
+ readOffset=0;
+ fileSize[readNo]=fileName->FileSize();
+ }
+ eof=false;
+ return replayFile>=0;
+}
+
+void cGenIndex::Work(void)
+{
+ eof=error=pstart=false;
+ memset(fileSize,0,sizeof(fileSize));
+
+ if(rewrite) {
+ writeFile=writeName->OpenWrite();
+ if(writeFile<0) {
+ printf("Failed to open output file(s)\n");
+ exit (1);
+ }
+ }
+
+ replayFile=fileName->Open();
+ readNo=fileName->FileNumber();
+ fileSize[readNo]=fileName->FileSize();
+ readOffset=0;
+
+ fileNo=rewrite ? 1 : readNo;
+ fileOffset=0;
+ splitOffset=splitsize*MEGABYTE(1);
+ sSize=0;
+
+ if(replayFile>=0) {
+ if(index->Open()) {
+ int lastoff=0;
+ while(!error && NextFile()) {
+ int count=read(replayFile,buff,sizeof(buff));
+ if(count<0) {
+ printf("read vdr: %s\n",strerror(errno));
+ return;
+ }
+ else if(count==0) {
+ if(fileSize[readNo]!=readOffset)
+ printf("file %d read/size mismatch\n",readNo);
+ eof=true;
+ continue;
+ } else {
+ readOffset+=count;
+
+ if(!quiet && !nostats && (readOffset<lastoff || readOffset>lastoff+KILOBYTE(256)) && fileSize[readNo]) {
+ printf("offset %lld %d%%\r",readOffset,(int)(readOffset*100/fileSize[readNo]));
+ fflush(stdout);
+ lastoff=readOffset;
+ }
+
+ int used=Process(buff,count);
+ if(used<0) {
+ error=true;
+ break;
+ }
+ if(count-used) printf("bummer, count!=0\n");
+ }
+ }
+// if(!error && !quiet) Statistics();
+ if(!quiet) Statistics(build);
+ }
+ } else {
+ printf("Failed to open input file(s)\n");
+ exit (1);
+ }
+}
+
+void cGenIndex::Count(int len)
+{
+ fileOffset+=len;
+ if(!rewrite && fileOffset>=fileSize[fileNo]) {
+ fileOffset-=fileSize[fileNo];
+ fileNo++;
+ }
+}
+
+int cGenIndex::Output(const uchar *data, int len)
+{
+ if(rewrite && pstart && sSize>0) {
+ if(!SafeWrite(writeFile,store,sSize)) {
+ error=true;
+ return -1;
+ }
+ sSize=0;
+ }
+
+ int ftype=0;
+ if(scan) {
+ const uchar *d=data;
+ for(int i=len ; i>0 ; i--) {
+ uchar c=*d++;
+ if(skip>0) {
+ skip--;
+ continue;
+ }
+ // searching for sequence 00 00 01 00 xx PIC
+ switch(state) {
+ case 0:
+ case 1:
+ case 3:
+ if(c==0x00) {
+ state++;
+ } else {
+ state=0;
+ }
+ break;
+ case 2:
+ if(c==0x01) {
+ state++;
+ } else {
+ if(c!=0x00) {
+ state=0;
+ }
+ }
+ break;
+ case 4:
+ state++;
+ break;
+ case 5:
+ ftype=(c>>3)&0x07;
+ if(ftype<I_FRAME || ftype>B_FRAME) {
+ printf("unknown picture type %d at %d\n",ftype,packetOffset);
+ ftype=0;
+ }
+ scan=false;
+ state=0;
+ i=0;
+ break;
+ }
+ }
+ }
+
+ if(rewrite) {
+ if(scan && fileOffset>=splitOffset && (pstart || sSize)) {
+ if(sSize+len>sizeof(store)) {
+ printf("Oops! Packet buffer overflow\n");
+ error=true;
+ return -1;
+ }
+ memcpy(store+sSize,data,len);
+ sSize+=len;
+ } else {
+ if(fileOffset>=splitOffset && sSize && ftype==I_FRAME) {
+ writeFile=writeName->NextWriteFile();
+ if(writeFile<0) {
+ printf("Failed to open output file(s)\n");
+ error=true;
+ return -1;
+ }
+ packetNo=fileNo=writeName->FileNumber();
+ packetOffset=0;
+ fileOffset=sSize;
+ }
+
+ if(ftype>=I_FRAME) {
+ index->Write(packetNo,packetOffset,ftype);
+ }
+
+ //buffered data
+ if(sSize>0) {
+ if(!SafeWrite(writeFile,store,sSize)) {
+ error=true;
+ return -1;
+ }
+ sSize=0;
+ }
+ // normal data
+ if(!SafeWrite(writeFile,data,len)) {
+ error=true;
+ return -1;
+ }
+ }
+ } else {
+ if(ftype>=I_FRAME) {
+ index->Write(packetNo,packetOffset,ftype);
+ }
+ }
+
+ Count(len);
+ pstart=false;
+ return len;
+}
+
+int cGenIndex::Action1(uchar type, uchar *data, int len)
+{
+ if(SOP) {
+ scan=false;
+ pstart=true;
+ }
+ return len;
+}
+
+int cGenIndex::Action2(uchar type, uchar *data, int len)
+{
+ if(SOP) {
+ packetOffset=fileOffset;
+ packetNo=fileNo;
+ scan=true;
+ pstart=true;
+ skip=headerSize;
+ state=0;
+ }
+ return len;
+}
+
+void cGenIndex::Skipped(uchar *data, int len)
+{
+ if(!rewrite) Count(len);
+}
+
+bool cGenIndex::SafeWrite(int fd, const unsigned char *data, int len)
+{
+ while(len>0) {
+ int r=write(fd,data,len);
+ if(r<0) {
+ if(errno==EINTR) {
+ printf("EINTR on write. Retrying\n");
+ continue;
+ }
+ printf("write failed: %s\n",strerror(errno));
+ return false;
+ }
+ data+=r; len-=r;
+ }
+ return true;
+}
+
+// --- MAIN --------------------------------------------------------------------
+
+void about(void)
+{
+ static bool done=false;
+ if(!quiet && !done) {
+ printf("This is %s %s (%s), (C) 2003-2006 Stefan Huelswitt, (C) 2016 rf\n"
+ "Released under the GNU Public License\n\n",
+ PRG_NAME,PRG_VERSION,__DATE__);
+ done=true;
+ }
+}
+
+#define MAX_STR 16
+
+int main(int argc, char *argv[])
+{
+ static struct option long_options[] = {
+ { "rewrite", no_argument, NULL, 'r' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "build", no_argument, NULL, 'b' },
+ { "dest", required_argument, NULL, 'd' },
+ { "split", required_argument, NULL, 's' },
+ { "input", required_argument, NULL, 'i' },
+ { "skip", required_argument, NULL, 's'|0x100 },
+ { NULL }
+ };
+
+ int s=0, str[MAX_STR];
+ int c;
+ while((c=getopt_long(argc,argv,"rqbnd:s:i:",long_options,NULL))!=-1) {
+ switch (c) {
+ case 'r':
+ rewrite=true;
+ break;
+ case 'b':
+ build=true;
+ break;
+ case 'n':
+ nostats=true;
+ break;
+ case 'q':
+ quiet=true;
+ break;
+ case 'd':
+ destdir=optarg;
+ break;
+ case 'i':
+ input=optarg;
+ break;
+ case 's':
+ splitsize=atoi(optarg);
+ if(splitsize<1 || splitsize>2000) {
+ about();
+ printf("Splitsize must be between 1 and 2.000 MB\n");
+ return 2;
+ }
+ break;
+ case 's'|0x100:
+ {
+ int n=strtol(optarg,0,16);
+ if(n<0 || n>255) {
+ about();
+ printf("Stream type out of range\n");
+ return 2;
+ }
+ if(s>=MAX_STR) {
+ about();
+ printf("Too many streams\n");
+ return 2;
+ }
+ str[s]=n;
+ s++;
+ break;
+ }
+ case '?':
+ case ':':
+ about();
+ printf("\nUsage: genindex [-r] [-b] [-d DIR] [-s SIZE] [-q] [-i FILE]\n\n"
+ " -i FILE, --input FILE use a single input file\n"
+ " -r, --rewrite rewrite video files\n"
+ " -d DIR, --dest=DIR set destination dir\n"
+ " -s SIZE, --split=SIZE split files at megabyte count\n"
+ " --skip=STR skip stream STR (hex)\n"
+ " -q, --quiet no output, except errors\n"
+ " -b, --build build EN 300 743 compliant subs instead of VDR1.x (implies -r)\n"
+ " -n, --nostats No progress indicator (per ffmpeg)\n"
+ "\n");
+ default:
+ return 2;
+ }
+ }
+
+ if (build) rewrite=true;
+
+ about();
+ cGenIndex gi;
+ if(s>0) {
+ if(!rewrite) {
+ printf("Cannot skip streams in non-rewrite mode\n");
+ return 2;
+ }
+ if(!quiet) printf("Skipping stream");
+ for(int i=0; i<s; i++) {
+ if(!quiet) printf(" 0x%02X",str[i]);
+ gi.Skip(str[i]);
+ }
+ if(!quiet) printf("\n\n");
+ }
+ gi.Work();
+ return 0;
+}
+// --------- $Id: genindex.c,v 1.2 2016/09/01 15:37:42 richard Exp $ ---------- END \ No newline at end of file
diff --git a/genindex/modulo.h b/genindex/modulo.h
new file mode 100755
index 0000000..1c1fc4d
--- /dev/null
+++ b/genindex/modulo.h
@@ -0,0 +1,41 @@
+#ifndef __MODULO_H
+ #define __MODULO_H
+/****************************************************************************/
+/* FILE: modulo.h */
+/* */
+/* These files contain the attributes and methods for managing the */
+/* modulus arithmetic */
+/* */
+/* BY: Ken Wada */
+/* Aurium Technologies Inc. */
+/* Jul. 15, 2013 */
+/* */
+/****************************************************************************/
+/****************************************************************************/
+/* THE COMPANY: Aurium Technologies Inc. */
+/* */
+/* THIS FIRMWARE IS FREE TO USE AND TO MODIFY. IT IS PRESENTED HERE FOR */
+/* DEMONSTRATION PURPOSES AS AN EXAMPLE ON HOW TO CODE FOR ANY DEEPLY */
+/* EMBEDDED SYSTEM. */
+/* */
+/* AS A RESULT, THE COMPANY SHALL NOT BE HELD LIABLE FOR ANY DIRECT, */
+/* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING */
+/* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY USERS OF */
+/* THE CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR */
+/* PRODUCTS. */
+/****************************************************************************/
+
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ unsigned int modulo_inc (const unsigned int value, const unsigned int modulus);
+ unsigned int modulo_dec (const unsigned int value, const unsigned int modulus);
+ #ifdef __cplusplus
+ }
+ #endif
+#endif
+
+
+
+
+
diff --git a/genindex/pes.c b/genindex/pes.c
new file mode 100644
index 0000000..f1a5844
--- /dev/null
+++ b/genindex/pes.c
@@ -0,0 +1,938 @@
+/*
+ * (C) 2003-2006 Stefan Huelswitt <s.huelswitt@gmx.de>, (C) RF 2016
+ * pes.c:
+ *
+ * See the main source file 'genindex.c' for copyright information and
+ * how to reach the author.
+ *
+ *-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: pes.c,v $
+ * Revision 1.2 2016/09/01 15:37:42 richard
+ * Extensively updated to V0.2 for EN 300 743 compliant subtitles
+ * added -b and -n flags
+ *
+ *-------------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#define __STDC_FORMAT_MACROS // Required for format specifiers
+#include <inttypes.h>
+#include "pes.h"
+#include "ringbuffer.h"
+#include "tools.h"
+
+
+//#define DEBUG(x...) printf(x)
+#define DEBUG(x...)
+
+//#define PD(x...) printf(x)
+#define PD(x...)
+
+#define PAGE_COMPOSITION_SEGMENT 0x10
+#define REGION_COMPOSITION_SEGMENT 0x11
+#define CLUT_DEFINITION_SEGMENT 0x12
+#define OBJECT_DATA_SEGMENT 0x13
+#define DISPLAY_DEFINITION_SEGMENT 0x14
+#define DISPARITY_SIGNALING_SEGMENT 0x15 // DVB BlueBook A156
+#define END_OF_DISPLAY_SET_SEGMENT 0x80
+#define STUFFING_SEGMENT 0xFF
+
+#include "fifo.h"
+
+// from VDR remux.c
+
+void PesSetPts(uchar *p, int64_t Pts)
+{
+ p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
+ p[10] = Pts >> 22;
+ p[11] = ((Pts >> 14) & 0xFE) | 0x01;
+ p[12] = Pts >> 7;
+ p[13] = ((Pts << 1) & 0xFE) | 0x01;
+}
+
+void PesSetDts(uchar *p, int64_t Dts)
+{
+ p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
+ p[15] = Dts >> 22;
+ p[16] = ((Dts >> 14) & 0xFE) | 0x01;
+ p[17] = Dts >> 7;
+ p[18] = ((Dts << 1) & 0xFE) | 0x01;
+}
+
+int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
+{
+ int64_t d = Pts2 - Pts1;
+ if (d > MAX33BIT / 2)
+ return d - (MAX33BIT + 1);
+ if (d < -MAX33BIT / 2)
+ return d + (MAX33BIT + 1);
+ return d;
+}
+
+// from VDR dvbsubtitle.c to assemble subs - DIH.
+
+// --- cDvbSubtitleAssembler -------------------------------------------------
+
+class cDvbSubtitleAssembler {
+private:
+ uchar *data;
+ int length;
+ int pos;
+ int size;
+ bool Realloc(int Size);
+public:
+ cDvbSubtitleAssembler(void);
+ virtual ~cDvbSubtitleAssembler();
+ void Reset(void);
+ unsigned char *Get(int &Length);
+ void Put(const uchar *Data, int Length);
+
+};
+
+cDvbSubtitleAssembler::cDvbSubtitleAssembler(void)
+{
+ data = NULL;
+ size = 0;
+ Reset();
+}
+
+cDvbSubtitleAssembler::~cDvbSubtitleAssembler()
+{
+ free(data);
+}
+
+void cDvbSubtitleAssembler::Reset(void)
+{
+ length = 0;
+ pos = 0;
+}
+
+bool cDvbSubtitleAssembler::Realloc(int Size)
+{
+ if (Size > size) {
+ Size = max(Size, 2048);
+ if (uchar *NewBuffer = (uchar *)realloc(data, Size)) {
+ size = Size;
+ data = NewBuffer;
+ } else {
+ DEBUG("ERROR: can't allocate memory for subtitle assembler\n");
+ length = 0;
+ size = 0;
+ free(data);
+ data = NULL;
+ return false;
+ }
+ }
+ return true;
+}
+
+unsigned char *cDvbSubtitleAssembler::Get(int &Length)
+{
+ if (length > pos + 5) {
+ Length = (data[pos + 4] << 8) + data[pos + 5] + 6;
+ if (length >= pos + Length) {
+ unsigned char *result = data + pos;
+ pos += Length;
+ return result;
+ }
+ }
+ return NULL;
+}
+
+void cDvbSubtitleAssembler::Put(const uchar *Data, int Length)
+{
+ if (Length && Realloc(length + Length)) {
+ memcpy(data + length, Data, Length);
+ length += Length;
+ }
+}
+
+// --- cPES --------------------------------------------------------------------
+
+cPES::cPES(eRule ru)
+{
+ rb=new cRingBufferFrame(KILOBYTE(50));
+ defaultRule=ru;
+ Reset();
+ dvbSubtitleAssembler = new cDvbSubtitleAssembler;
+ fifo_init(&fifo, pktbuf, sizeof(pktbuf));
+}
+
+cPES::~cPES()
+{
+ delete rb;
+ //??
+ delete dvbSubtitleAssembler;
+}
+
+void cPES::Reset(void)
+{
+ for(int i=0 ; i<NUM_RULESETS ; i++) SetDefaultRule(defaultRule,i);
+ UseRuleset(0);
+ ClearSeen();
+ Clear();
+}
+
+void cPES::Clear(void)
+{
+ Lock();
+ mode=pmNewSync; frame=0; mpegType=2;
+ rb->Clear();
+ Unlock();
+}
+
+bool cPES::ValidRuleset(const int num)
+{
+ if(num>=0 && num<NUM_RULESETS) return true;
+ DEBUG("PES: illegal ruleset %d\n",num);
+ return false;
+}
+
+void cPES::UseRuleset(const int num)
+{
+ if(ValidRuleset(num)) {
+ currRules=rules[num];
+ currNum=num;
+ }
+}
+
+int cPES::CurrentRuleset(void)
+{
+ return currNum;
+}
+
+void cPES::SetDefaultRule(eRule ru, const int num)
+{
+ if(ValidRuleset(num)) {
+ for(int i=0 ; i<NUM_RULES ; i++) {
+ rules[num][i]=ru;
+ }
+ }
+}
+
+void cPES::SetRule(uchar type, eRule ru, const int num)
+{
+ if(ValidRuleset(num)) {
+ rules[num][type]=ru;
+ }
+}
+
+void cPES::SetRuleR(uchar ltype, uchar htype, eRule ru, const int num)
+{
+ if(ValidRuleset(num)) {
+ if(ltype<htype) {
+ for(; ltype<=htype ; ltype++) {
+ rules[num][ltype]=ru;
+ }
+ } else {
+ DEBUG("PES: bad range %x-%x\n",ltype,htype);
+ }
+ }
+}
+
+unsigned int cPES::Seen(uchar type) const
+{
+ return seen[type];
+}
+
+void cPES::ClearSeen(void)
+{
+ memset(seen,0,sizeof(seen));
+ totalBytes=totalSkipped=totalZeros=0;
+ skipped=zeros=0;
+}
+
+void cPES::Skip(uchar *data, int count)
+{
+ if(data) {
+ Skipped(data,count);
+ while(count>0) {
+ skipped++;
+ if(!*data++) {
+ zeros++;
+ }
+ count--;
+ }
+ } else if(skipped) {
+ totalSkipped+=skipped;
+ if(skipped==zeros) {
+ totalZeros+=zeros;
+ } else {
+ DEBUG("PES: skipped %d bytes\n",skipped);
+ }
+ skipped=zeros=0;
+ }
+}
+
+void cPES::Statistics(bool build)
+{
+ if(totalBytes) {
+ printf("PES: Stats %ld kbytes total, %ld kbytes skipped, %ld zero-gaps\n",
+ ROUNDUP(totalBytes,1024),ROUNDUP(totalSkipped,1024),totalZeros);
+ if (build) {
+ printf("PES: Stats %ld kbytes subtitle data output: %d subs packets (%d short packets)\n", totsubsize/1024, subspkts, errpkts);
+ }
+ for(int type=0 ; type<=0xFF ; type++) {
+ if(seen[type]) {
+ printf("PES: Stats %02X: %d packets PTS-first: %jd PTS-last: %jd\n",type,seen[type],ptsfirst[type], ptslast[type]);
+ }
+ }
+ }
+}
+
+void cPES::ModifyPaketSize(int mod)
+{
+ if(SOP) {
+ int size=header[4]*256 + header[5] + mod;
+ header[4]=(size>>8)&0xFF;
+ header[5]=(size )&0xFF;
+ } else {
+ DEBUG("PES: modify paket size called in middle of packet\n");
+ }
+}
+
+void cPES::Redirect(eRule ru)
+{
+ if(SOP) {
+ currRule=ru;
+ redirect=true;
+ } else {
+ DEBUG("PES: redirect called in middle of packet\n");
+ }
+}
+
+int cPES::HeaderSize(uchar *head, int len)
+{
+ if(len<PES_MIN_SIZE) return -PES_MIN_SIZE;
+ switch(head[3]) {
+ default:
+ // Program end
+ case 0xB9:
+ // Programm stream map
+ case 0xBC:
+ // video stream start codes
+ case 0x00 ... 0xB8:
+ // reserved
+ case 0xF0 ... 0xFF:
+ return PES_MIN_SIZE;
+
+ // Pack header
+ case 0xBA:
+ if(len<5) return -5;
+ switch(head[4]&0xC0) {
+ default:
+ DEBUG("PES: unknown mpegType in pack header (0x%02x)\n",head[4]);
+ // fall through
+ case 0x00:
+ mpegType=1;
+ return 12;
+ case 0x40:
+ mpegType=2;
+ if(len<14) return -14;
+ return 14+(head[13]&0x07); // add stuffing bytes
+ }
+
+ // System header
+ case 0xBB:
+ if(len<6) return -6;
+ return 6+head[4]*256+head[5]; //XXX+ is there a difference between mpeg1 & mpeg2??
+
+ // Padding stream
+ case 0xBE:
+ // Private stream2 (navigation data)
+ case 0xBF:
+ return 6; //XXX+ is there a difference between mpeg1 & mpeg2??
+
+ // all the rest (the real packets)
+ // Private stream1
+ case 0xBD:
+ case 0xC0 ... 0xCF:
+ case 0xD0 ... 0xDF:
+ //video
+ case 0xE0 ... 0xEF:
+ if(len<7) {
+ return -7;
+ }
+ int index=6;
+
+ while((head[index]&0xC0)==0xC0) { // skip stuffing bytes
+ index++;
+ if (index >= len) {
+ return -(index+1);
+ }
+ }
+
+ if((head[index]&0xC0)==0x80) { // mpeg2
+ mpegType=2;
+ index+=2;
+ if(index>=len) {
+ return -(index+1);
+ }
+ return index+1+head[index]; // mpeg2 header data bytes
+ }
+ mpegType=1;
+ if((head[index]&0xC0)==0x40) { // mpeg1 buff size
+ index+=2;
+ if(index>=len) {
+ return -(index+1);
+ }
+ }
+
+ switch(head[index]&0x30) {
+ case 0x30:
+ index+=9;
+ break; // mpeg1 pts&dts
+ case 0x20:
+ index+=4;
+ break; // mpeg1 pts
+ case 0x10:
+ DEBUG("PES: bad pts/dts flags in MPEG1 header (0x%02x)\n",head[index]);
+ break;
+ }
+ return index+1;
+ }
+}
+
+int cPES::PacketSize(uchar *head, int len)
+{
+ switch(head[3]) {
+ default:
+ // video stream start codes
+ case 0x00 ... 0xB8:
+ // Program end
+ case 0xB9:
+ // Pack header
+ case 0xBA:
+ // System header
+ case 0xBB:
+ // Programm stream map
+ case 0xBC:
+ // reserved
+ case 0xF0 ... 0xFF:
+ return len; // packet size = header size
+
+ // Private stream1
+ case 0xBD:
+ // Padding stream
+ case 0xBE:
+ // Private stream2 (navigation data)
+ case 0xBF:
+ // all the rest (the real packets)
+ case 0xC0 ... 0xCF:
+ case 0xD0 ... 0xDF:
+ case 0xE0 ... 0xEF:
+ return 6 + head[4]*256 + head[5];
+ }
+}
+
+int cPES::Return(int used, int len)
+{
+ PD("PES: return used=%d len=%d mode=%d\n",used,len,mode);
+ if(SOP && unsavedHeader && used>=len) {
+ // if we are about to finish the current data packet and we have
+ // an unsaved header inside, we must save the header to the buffer
+ memcpy(hbuff,header,headerSize);
+ header=hbuff;
+ unsavedHeader=false;
+ PD("PES: header saved\n"); // RF don't see this
+ }
+ if(used>len) {
+ DEBUG("PES: BUG! used %d > len %d\n",used,len);
+ used=len;
+ }
+ if(used>0) {
+ totalBytes+=used;
+ }
+
+ Unlock(); // release lock from Process()
+ return used;
+}
+
+// RF Note that this is called with file chunks - do not assume ends on whole packet boundary!
+int cPES::Process(const uchar *data, int len)
+{
+ Lock(); // lock is released in Return()
+ PD("PES: enter data=%p len=%d mode=%d have=%d need=%d old=%d\n",
+ data,len,mode,have,need,old);
+ int used=0;
+ static int size;
+ static uchar headerstore[64];
+ static int savedheadersize;
+ static int overrun;
+ static bool started;
+
+ while(used<len) {
+ uchar *c=(uchar *)data+used;
+ int rest=len-used, n;
+ switch(mode) {
+ case pmNewSync:
+ PD("PES: new sync from %d, rest %d\n",used,rest);
+ have=old=need=0;
+ unsavedHeader=false;
+ outputHeader=true;
+ SOP=true;
+ redirect=false;
+ mode=pmFastSync;
+ // fall through
+
+ case pmFastSync:
+ // a short cut for the most common case
+ // if matched here, header isn't copied around
+ if(rest>=PES_MIN_SIZE) {
+ PD("PES: fastsync try used=%d: %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ used,c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8]);
+ if(c[0]==0x00 && c[1]==0x00 && c[2]==0x01) {
+ headerSize=HeaderSize(c,rest);
+ if(headerSize>0 && rest>=headerSize) {
+ // found a packet start :-)
+ PD("PES: fastsync hit used=%d headerSize=%d rest=%d\n",used,headerSize,rest);
+ header=c;
+ unsavedHeader=true;
+ used+=headerSize;
+ mode=pmHeaderOk;
+ continue;
+ }
+ }
+ else if(c[2]!=0x00) {
+ used+=3;
+ Skip(c,3);
+ continue;
+ }
+ else {
+ used++;
+ Skip(c);
+ continue;
+ }
+ }
+ // copy remaining bytes to buffer
+ memcpy(hbuff,c,rest);
+ have=old=rest;
+ used+=rest;
+ mode=pmSync;
+ PD("PES: buffering started old=%d\n",old);
+ break;
+
+ case pmSync:
+ PD("PES: slowsync have=%d old=%d\n",have,old);
+ if(have<PES_MIN_SIZE && rest>=1) {
+ hbuff[have++]=c[0];
+ used++;
+ continue;
+ }
+ if(have>=PES_MIN_SIZE) {
+ PD("PES: slowsync try used=%d: %02x %02x %02x %02x\n",
+ used,hbuff[0],hbuff[1],hbuff[2],hbuff[3]);
+ if(hbuff[0]==0x00 && hbuff[1]==0x00 && hbuff[2]==0x01) {
+ need=abs(HeaderSize(hbuff,have));
+ mode=pmGetHeader;
+ continue;
+ }
+ // no sync found, move buffer one position ahead
+ have--; Skip(hbuff);
+ memmove(hbuff,hbuff+1,have);
+ // if all bytes from previous data block used up, switch to FastSync
+ if(!--old) {
+ used=0; mode=pmFastSync;
+ PD("PES: buffering ended\n");
+ }
+ continue;
+ }
+ break;
+
+ case pmGetHeader:
+ if(have<need) {
+ n=min(need-have,rest);
+ memcpy(hbuff+have,c,n);
+ have+=n;
+ used+=n;
+ PD("PES: get header n=%d need=%d have=%d used=%d\n",n,need,have,used);
+ continue;
+ }
+ if(have>=need) {
+ need=abs(HeaderSize(hbuff,have));
+ if(have<need) continue;
+ // header data complete
+ PD("PES: slowsync hit used=%d\n",used);
+ if(have>need) DEBUG("PES: bug, buffered too much. have=%d need=%d\n",have,need);
+ if(have>(int)sizeof(hbuff)) DEBUG("PES: bug, header buffer overflow. have=%d size=%d\n",have,(int)sizeof(hbuff));
+ headerSize=need;
+ header=hbuff;
+ mode=pmHeaderOk;
+ }
+ break;
+
+ case pmHeaderOk:
+ type=header[3];
+ seen[type]++;
+ if (PesHasPts(header) && len > 6) {
+ ptslast[type]=PesGetPts(header);
+ if (!ptsfirst[type]) {
+ ptsfirst[type]=ptslast[type];
+ }
+ }
+ Skip(0);
+ if(type<=0xB8) {
+ // packet types 0x00-0xb8 are video stream start codes
+ DEBUG("PES: invalid packet type 0x%02x, skipping\n",type);
+ mode=pmNewSync;
+ break;
+ }
+ payloadSize=PacketSize(header,headerSize)-headerSize;
+ if(payloadSize<0) {
+ DEBUG("PES: invalid payloadsize %d, skipping\n",payloadSize);
+ mode=pmNewSync;
+ break;
+ }
+ PD("PES: found sync at offset %d, type %02x, length %d, next expected %d\n",
+ used-headerSize,type,headerSize+payloadSize,used+payloadSize);
+ PD("PES: header type=%02x mpeg=%d header=%d payload=%d:",
+ type,mpegType,headerSize,payloadSize);
+ for(int i=0 ; i<headerSize ; i++) {
+ PD(" %02x",header[i]);
+ }
+ PD("\n");
+ currRule=currRules[type];
+ have=need=0;
+ mode=pmPayload;
+ // fall through
+
+ case pmPayload:
+ n=min(payloadSize-have,rest);
+ if(!n) {
+ if(payloadSize==0) {
+ n=1;
+ } else {
+ break;
+ }
+ }
+ // RF we crash into this 2nd time round, if have header (usual). So subhead set
+ PD("PES: payload have=%d n=%d SOP=%d\n",have,n,SOP);
+ switch(currRule) {
+ default:
+ DEBUG("PES: bug, unknown rule %d, assuming pass\n",currRule);
+ // fall through
+ case prPass: n=n; break;
+ case prSkip: n=-n; break;
+ case prAct1: n=Action1(type,c,n); break;
+ case prAct2: n=Action2(type,c,n); break;
+// case prAct3: n=Action3(type,c,n); break;
+ case prAct3:
+ /* RF Because we have to assemble AN ENTIRE PES packet of possibly several existing 2k PES packets,
+ and usually several subtitle segments, then as far as the long main loop is concerned,
+ we drop all the subs packets regardless.
+
+ VDR1.x packets can contain fragments of segments too
+
+ We have no idea how long we have to wait - need END_OF_DISPLAY_SET_SEGMENT to complete a PES
+ Then write out the assembled PES independently, hoping it's PTS doesn't
+ upset something downstream. Should in any case be indpendent, but ffmpeg is touchy
+ */
+ n = -n; //drop all content for main loop
+ if (-n ) {
+ int PayloadOffset = headerSize;
+ bool ResetSubtitleAssembler = 0;
+ //VDR 1.x subs, skip special 4 byte "substream header" (VDR always strips all packets)
+ int SubstreamHeaderLength = (have == 0 ? 4 : 0); // Full packet, not a continuation chunk from file
+ // c points to the payload only now
+ if (SOP && SubstreamHeaderLength) { // only if we have it
+ ResetSubtitleAssembler = c[3] == 0x00;
+ //PES hdr extension, RF original doesn't match vanilla 1.X recordings
+ if ((header[7] & 0x01) && (header[PayloadOffset - 3] & 0x81) == 0x01 && header[PayloadOffset - 2] == 0x81) {
+ PayloadOffset--;
+ SubstreamHeaderLength = 1;
+ ResetSubtitleAssembler = (header[8] >= 5);
+ }
+ if (PesHasPts(header)) {
+ int64_t oldpts = ptsnow[type];
+ ptsnow[type] = PesGetPts(header);
+ if (ptsnow[type] < oldpts) {
+ // Non-monotonic subs send ffmpeg loopy
+ printf("PES: OOPs Non-monotonic PTS at %jd (previous %jd!) - packet dropped\n",ptsnow[type],oldpts);
+ break;
+ }
+ int64_t ptsdiff = (PtsDiff(ptsnow[0xc0],ptsnow[type]))/90; //millisecs
+ DEBUG("PES: subtitle packet pts %jd, latest main audio pts %jd, subs ahead %jdms\n",ptsnow[type],ptsnow[0xc0],ptsdiff);
+ if (ptsnow[0xc0] && abs((int)ptsdiff) > 5000) {
+ printf("genindex: OOPs large subs timing offset! %jdms\n",ptsdiff);
+ }
+ if (headerSize +2 > (int)sizeof (headerstore)) {
+ printf("PES: OOPs huge header! %d at %jd\n",headerSize,ptsnow[type]);
+ exit(1);
+ }
+ if (overrun) { // continuation packets don't have a PTS AFAIK
+ DEBUG("PES: Suspect %d bytes left at start of new packet!\n",overrun);
+ }
+
+ memcpy (headerstore,header,headerSize);
+ headerstore[6] |= 0x01; // Set "Original" - per trouble-free .ts FWiW
+
+// if (audiopts) PesSetPts(headerstore,audiopts); // use existing if no audiopts
+
+// Working on theory that ffmpeg wants a DTS for some reason, copy the PTS
+// - it turns out that ffmpeg does this internally.
+// PesSetDtsbit(headerstore);
+// PesSetDts(headerstore,ptsnow[type]-18000); // ~200ms earlier similar to other streams
+// headerstore[8]+=5; // 5 for DTS (we know it has PES ext:this is safe)
+
+ savedheadersize = headerSize+2+0; // 5 for DTS
+ memset (headerstore+headerSize+0,0x20,1); // subs data_identifier which is stripped below
+ memset (headerstore+headerSize+1+0,0x00,1); // stream_id
+ }
+ }
+
+ if (-n > SubstreamHeaderLength) {
+ const uchar *data = c + SubstreamHeaderLength; // skip substream header
+ int length = -n - SubstreamHeaderLength; // skip substream header
+ if (ResetSubtitleAssembler) {
+ dvbSubtitleAssembler->Reset();
+ }
+ if (length > 3) {
+ int Count, offset;
+ int substotalthispacket=0;
+ if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F) {
+ offset = 2;
+ } else {
+ offset = 0;
+ }
+ int subslength = length - offset;
+ DEBUG("PES: Put payload length %d into dvbSubtitleAssembler\n",subslength);
+ dvbSubtitleAssembler->Put(data + offset, subslength);
+ while (true) {
+ unsigned char *b = dvbSubtitleAssembler->Get(Count); // Count = seg size *req'd*, not actual available!
+ if (b && b[0] == 0x0F && Count > 5) {
+ // a complete segement
+ uchar segmentType = b[1];
+ if (segmentType == STUFFING_SEGMENT) {
+ continue;
+ }
+ if (fifo_write(&fifo, b, Count) != Count) {
+ DEBUG("PES: FIFO error\n");
+ Return(used,len);
+ }
+ substotalthispacket+=Count-overrun;
+ size+=Count;
+ DEBUG("PES: subtitle complete segment length %d type %02X, subs in fifo %d (used %d this segment)\n",Count, segmentType, size, Count-overrun);
+ if (Count-overrun < 0) {
+ DEBUG("PES: Suspect overrun of %d bytes!\n",overrun);
+ }
+ overrun=0; // must have used up all available data at start ofa new segment
+
+ if (segmentType == END_OF_DISPLAY_SET_SEGMENT) {
+ uchar outbuf[KILOBYTE(64)];
+ if (fifo_read(&fifo, outbuf, size) != size) {
+ DEBUG("PES: FIFO error\n");
+ Return(used,len);
+ }
+ // skip the small 10...80 subs periodic "cleardown" packets at beginning of file only.
+ // These currently prevent reliable ffmpeg subs detection
+ int err = dvbsub_probe(outbuf,size,ptsnow[type]);
+ if (err == 1) started = 1;
+ if (started) {
+ if (err < 0 ) errpkts++; // mark it, but pass all the same as should be validly assembled
+ outbuf[size++] = 0xff; // end_of_PES_data_field_marker
+ totsubsize+=size; // Actual subs segment data = should match ffmpeg report
+ subspkts+=1;
+ int pkt = savedheadersize -6 + size; //6 for 00.00.01.bd.HH.hh, 1 for end_of_PES_data_field_marker
+ headerstore[4]=(pkt>>8)&0xFF;
+ headerstore[5]=(pkt )&0xFF;
+ // Now can output ALL re-assembled subs in a SINGLE PES pkt
+ DEBUG("PES: *** subtitle complete PES packet with subs of %d bytes @pts %jd ***\n",size, ptsnow[type]);
+ PD("PES: output buffered subtitle header=%p count=%d\n",headerstore,savedheadersize);
+ int r=Output(headerstore,savedheadersize);
+ if(r<0) return Return(-1,len);
+ PD("PES: output buffered subtitle count=%d\n",size);
+ r=Output(outbuf,size);
+ if(r<0) return Return(-1,len);
+ } else {
+ DEBUG("PES: Skipping inital short subs packet for ffmpeg compatibility!\n");
+ }
+ size = 0;
+ }
+ } else {
+ if (Count > subslength - substotalthispacket) {
+// if (c[SubstreamHeaderLength+offset+substotalthispacket] == 0xff) {
+ if (subslength - substotalthispacket < 6) { //cruft or stuffing
+ break;
+ }
+ // overrun the PES packet. Keep building packet with next PES segement.
+ overrun += subslength - substotalthispacket;
+ DEBUG("PES: subtitle incomplete segment, requires %d vs. %d available (needs %d)\n",Count, overrun, Count-overrun);
+ if (overrun < 0) {
+ printf("PES: BUG! Available %d bytes, @pts %jd ***\n",overrun, ptsnow[type]);
+ exit (1);
+ }
+ }
+ break;
+ }
+ }
+ // We have a complete disassembly of the sub(s)
+ }
+ }
+ }
+ break;
+ case prAct4: n=Action4(type,c,n); break;
+ case prAct5: n=Action5(type,c,n); break;
+ case prAct6: n=Action6(type,c,n); break;
+ case prAct7: n=Action7(type,c,n); break;
+ case prAct8: n=Action8(type,c,n); break;
+ }
+ if(n==0) {
+ if(redirect) {
+ redirect=false;
+ continue;
+ }
+ return Return(used,len);
+ }
+ need=n;
+ SOP=false;
+ mode=pmRingGet;
+ // fall through
+
+ case pmRingGet:
+ frame=rb->Get();
+ if(frame) { // RF doesn't happen
+ outCount=frame->Count();
+ outData=(uchar *)frame->Data();
+ PD("PES: ringbuffer got frame %p count=%d\n",frame,outCount);
+ nextMode=pmRingDrop;
+ mode=pmOutput;
+ break;
+ }
+ mode=pmDataPut;
+ // fall through
+
+ case pmDataPut:
+ if(need<0) { //for skipped
+ need=-need;
+ outputHeader=false;
+ mode=pmDataReady;
+ continue;
+ }
+ if(outputHeader) {
+ outData=header;
+ outCount=headerSize;
+ outputHeader=false;
+ nextMode=pmDataPut;
+ }
+ else if(payloadSize) {
+ outData=c;
+ outCount=need;
+ nextMode=pmDataReady;
+ } else {
+ mode=pmDataReady;
+ continue;
+ }
+ mode=pmOutput;
+ // fall through
+
+ case pmOutput:
+ for(;;) {
+ PD("PES: output data=%p count=%d -> ",outData,outCount);
+ n=Output(outData,outCount);
+ PD("n=%d\n",n);
+ if(n<0) return Return(-1,len);
+ if(n==0) return Return(used,len);
+ outCount-=n;
+ outData+=n;
+ if(outCount<=0) {
+ mode=nextMode;
+ break;
+ }
+ }
+ break;
+
+ case pmDataReady:
+ if(payloadSize) {
+ used+=need;
+ have+=need;
+ }
+ PD("PES: data ready need=%d have=%d paySize=%d used=%d\n",
+ need,have,payloadSize,used);
+ if(have>=payloadSize) {
+ PD("PES: packet finished\n");
+ if(have>payloadSize) DEBUG("PES: payload exceeded, size=%d have=%d\n",payloadSize,have);
+ mode=pmNewSync;
+ } else {
+ mode=pmPayload;
+ }
+ break;
+
+ case pmRingDrop:
+ PD("PES: ringbuffer drop %p\n",frame);
+ rb->Drop(frame); frame=0;
+ mode=pmRingGet;
+ break;
+
+ default:
+ DEBUG("PES: bug, bad mode %d\n",mode);
+ return Return(-1,len);
+ }
+ }
+ PD("PES: leave\n");
+ return Return(used,len);
+}
+
+
+// From ffmpeg - This is the code used to score the dvbsub packets
+// (If there aren't a complete set of segments 0x10 - 13 & 5 segments total, not useful pkt)
+// ***NOTE*** This is modified from ffmpeg which appears to have logical bugs
+
+int cPES::dvbsub_probe(uchar *p, int size, int64_t pts)
+{
+ int i, j, k;
+ const uint8_t *end = p + size;
+ int type, len;
+ int max_score = 0;
+ const uint8_t *ptr = p;
+
+ for(i=0; i<size; i++) {
+ if (p[i] == 0x0f) {
+ ptr = p + i;
+ uint8_t histogram[6] = {0};
+ int min = 255;
+ for(j=0; 5 < end - ptr; j++) { // was 6. Relevant to this environment as tested pkt doesn't have 0xff tail
+ if (*ptr != 0x0f) {
+ if (*ptr == 0xff) {
+ ptr++; // similar to dvbsub_decode, continue if (allowable) stuffing
+ continue;
+ } else {
+ break;
+ }
+ }
+ type = ptr[1];
+// page_id = AV_RB16(ptr + 2);
+// len = AV_RB16(ptr + 4);
+ len = (*(ptr+4) << 8) + *(ptr+5);
+ if (type == 0x80) {
+ ;
+ } else if (type >= 0x10 && type <= 0x14) {
+ histogram[type - 0x10] ++;
+ } else
+ break;
+ if (6 + len > end - ptr)
+ break;
+ ptr += 6 + len;
+ }
+ for (k=0; k < 4; k++) {
+ min = FFMIN(min, histogram[k]);
+ }
+ if (min && j > max_score)
+ max_score = j;
+ }
+ if (max_score >= 5) { // was > 5. Test was in outer loop, not clear why, can invalidate good scores
+ return 1;
+ } else {
+ // if (end - ptr > 6) {
+ // printf("PES: dvbsub probe warning hex offset %04X in packet pts %jd : %02X %02X %02X %02X %02X %02X %02X %02X\n",int(ptr-p),pts,p[i],p[i+1],p[i+2],p[i+3],p[i+4],p[i+5],p[i+6],p[i+7]);
+ // return -1;
+ // }
+
+ // if it wasn't one of the expected short clear-down packets + margin, flag it as suspect
+ return -1;
+ // If i incremented after scoring, stomps though FROM START + i looking for anything like 0f.
+ // So don't stomp once started it's not helpful, be happy with what you have
+ }
+ }
+ return 0;
+}
diff --git a/genindex/pes.h b/genindex/pes.h
new file mode 100644
index 0000000..8fe7481
--- /dev/null
+++ b/genindex/pes.h
@@ -0,0 +1,166 @@
+/*
+ * pes.h:
+ *
+ * See the main source file 'genindex.c' for copyright information and
+ * how to reach the author.
+ *
+ *-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: pes.h,v $
+ * Revision 1.2 2016/09/01 15:37:42 richard
+ * Extensively updated to V0.2 for EN 300 743 compliant subtitles
+ * added -b and -n flags
+ *
+ *-------------------------------------------------------------------------------
+ *
+ */
+
+#ifndef __PES_H
+#define __PES_H
+
+#include "thread.h"
+#include "tools.h"
+#include "fifo.h"
+
+#define PES_MIN_SIZE 4 // min. number of bytes to identify a packet
+#define PES_HDR_SIZE 6 // length of PES header
+#define PES_EXT_SIZE 3 // length of PES extension
+
+#define NUM_RULESETS 4 // number of rule sets
+#define NUM_RULES 256 // how many rules in every set
+
+class cFrame;
+class cRingBufferFrame;
+//RF
+class cDvbSubtitleAssembler; // for legacy PES recordings
+
+class cPES : public cMutex {
+protected:
+ enum eRule { prPass, prSkip, prAct1, prAct2, prAct3, prAct4, prAct5, prAct6, prAct7, prAct8 };
+private:
+ eRule rules[NUM_RULESETS][NUM_RULES], *currRules, currRule, defaultRule;
+ int currNum;
+ // Statistics
+ unsigned int seen[256];
+ int skipped, zeros;
+ int64_t totalBytes, totalSkipped, totalZeros;
+ //
+ enum eMode { pmNewSync, pmFastSync, pmSync, pmGetHeader, pmHeaderOk, pmPayload,
+ pmRingGet, pmRingDrop, pmDataPut, pmDataReady, pmOutput };
+ eMode mode, nextMode;
+ uchar hbuff[PES_HDR_SIZE+PES_EXT_SIZE+256];
+ uchar type;
+ int have, need, old;
+ bool unsavedHeader, outputHeader, redirect;
+ //
+ cFrame *frame;
+ const uchar *outData;
+ int outCount;
+ int saveddata;
+ //
+ bool ValidRuleset(const int num);
+ void Skip(uchar *data, int count=1);
+ int Return(int used, int len);
+ int HeaderSize(uchar *head, int len);
+ int PacketSize(uchar *head, int len);
+//RF
+ cDvbSubtitleAssembler *dvbSubtitleAssembler;
+ int dvbsub_probe(uchar *p, int size, int64_t pts);
+ uchar pktbuf[KILOBYTE(64)];
+ fifo_t fifo;
+ int64_t ptsnow[256];
+ int64_t ptsfirst[256];
+ int64_t ptslast[256];
+ int64_t totsubsize;
+ int subspkts;
+ int errpkts;
+
+protected:
+ bool SOP; // true if we process the start of packet
+ int headerSize; // size of the header including additional header data
+ uchar *header; // the actual header
+ int mpegType; // gives type of packet 1=mpeg1 2=mpeg2
+ int payloadSize; // number of data bytes in the packet
+ //
+ cRingBufferFrame *rb;
+ //
+ // Rule Management
+ void UseRuleset(int num);
+ int CurrentRuleset(void);
+ void SetDefaultRule(eRule ru, const int num=0);
+ void SetRule(uchar type, eRule ru, const int num=0);
+ void SetRuleR(uchar ltype, uchar htype, eRule ru, const int num=0);
+ void Reset(void);
+ // Misc
+ unsigned int Seen(uchar type) const;
+ void ClearSeen(void);
+ void Statistics(bool);
+ void ModifyPaketSize(int mod);
+ // Data Processing
+ int Process(const uchar *data, int len);
+ void Redirect(eRule ru);
+ void Clear(void);
+ virtual int Output(const uchar *data, int len) { return len; }
+ virtual int Action1(uchar type, uchar *data, int len) { return len; }
+ virtual int Action2(uchar type, uchar *data, int len) { return len; }
+ virtual int Action3(uchar type, uchar *data, int len) { return len; }
+ virtual int Action4(uchar type, uchar *data, int len) { return len; }
+ virtual int Action5(uchar type, uchar *data, int len) { return len; }
+ virtual int Action6(uchar type, uchar *data, int len) { return len; }
+ virtual int Action7(uchar type, uchar *data, int len) { return len; }
+ virtual int Action8(uchar type, uchar *data, int len) { return len; }
+ virtual void Skipped(uchar *data, int len) {}
+public:
+
+ cPES(eRule ru=prPass);
+ virtual ~cPES();
+ };
+
+inline bool PesHasPts(const uchar *p)
+{
+ return (p[7] & 0x80) && p[8] >= 5;
+}
+
+inline bool PesHasDts(const uchar *p)
+{
+ return (p[7] & 0x40) && p[8] >= 10;
+}
+
+inline void PesSetDtsbit(uchar *p)
+{
+ p[7] |= 0x40;
+}
+
+inline void PesSetPtsbit(uchar *p)
+{
+ p[7] |= 0x80;
+}
+
+inline int64_t PesGetPts(const uchar *p)
+{
+ return ((((int64_t)p[ 9]) & 0x0E) << 29) |
+ (( (int64_t)p[10]) << 22) |
+ ((((int64_t)p[11]) & 0xFE) << 14) |
+ (( (int64_t)p[12]) << 7) |
+ ((((int64_t)p[13]) & 0xFE) >> 1);
+}
+
+inline int64_t PesGetDts(const uchar *p)
+{
+ return ((((int64_t)p[14]) & 0x0E) << 29) |
+ (( (int64_t)p[15]) << 22) |
+ ((((int64_t)p[16]) & 0xFE) << 14) |
+ (( (int64_t)p[17]) << 7) |
+ ((((int64_t)p[18]) & 0xFE) >> 1);
+}
+
+
+#define MAX33BIT 0x00000001FFFFFFFFLL // max. possible value with 33 bit
+#define ROUNDUP(N, S) ((N + (S>>1)) / S)
+
+//ffmpeg
+#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
+
+#endif
+
+// --------- $Id: pes.h,v 1.2 2016/09/01 15:37:42 richard Exp $ ---------- END \ No newline at end of file
diff --git a/genindex/ringbuffer.c b/genindex/ringbuffer.c
new file mode 100644
index 0000000..d5fcf0b
--- /dev/null
+++ b/genindex/ringbuffer.c
@@ -0,0 +1,93 @@
+/*
+ * ringbuffer.c: A ring buffer
+ *
+ * See the main source file 'genindex.c' for copyright information and
+ * how to reach the author.
+ *
+ * Parts of this file were inspired by the 'ringbuffy.c' from the
+ * LinuxDVB driver (see linuxtv.org).
+ *
+ * $Id: ringbuffer.c,v 1.2 2016/09/01 15:37:42 richard Exp $
+ *
+ * This was taken from the VDR package, which was released under the GPL.
+ * Stripped down to make the PES parser happy
+ */
+
+#include "ringbuffer.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include "tools.h"
+
+// --- cRingBuffer -----------------------------------------------------------
+
+cRingBuffer::cRingBuffer(int Size, bool Statistics)
+{
+}
+
+cRingBuffer::~cRingBuffer()
+{
+}
+
+void cRingBuffer::WaitForPut(void)
+{
+}
+
+void cRingBuffer::WaitForGet(void)
+{
+}
+
+void cRingBuffer::EnablePut(void)
+{
+}
+
+void cRingBuffer::EnableGet(void)
+{
+}
+
+void cRingBuffer::SetTimeouts(int PutTimeout, int GetTimeout)
+{
+}
+
+// --- cFrame ----------------------------------------------------------------
+
+cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index)
+{
+}
+
+cFrame::~cFrame()
+{
+}
+
+// --- cRingBufferFrame ------------------------------------------------------
+
+cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics)
+:cRingBuffer(Size, Statistics)
+{
+}
+
+cRingBufferFrame::~cRingBufferFrame()
+{
+}
+
+void cRingBufferFrame::Clear(void)
+{
+}
+
+bool cRingBufferFrame::Put(cFrame *Frame)
+{
+ return false;
+}
+
+cFrame *cRingBufferFrame::Get(void)
+{
+ return 0;
+}
+
+void cRingBufferFrame::Drop(cFrame *Frame)
+{
+}
+
+int cRingBufferFrame::Available(void)
+{
+ return 0;
+}
diff --git a/genindex/ringbuffer.h b/genindex/ringbuffer.h
new file mode 100644
index 0000000..665dd6e
--- /dev/null
+++ b/genindex/ringbuffer.h
@@ -0,0 +1,79 @@
+/*
+ * ringbuffer.h: A ring buffer
+ *
+ * See the main source file 'genindex.c' for copyright information and
+ * how to reach the author.
+ *
+ * This was taken from the VDR package, which was released under the GPL.
+ * Stripped down to make the PES parser happy
+ *
+ *-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: ringbuffer.h,v $
+ * Revision 1.2 2016/09/01 15:37:42 richard
+ * Extensively updated to V0.2 for EN 300 743 compliant subtitles
+ * added -b and -n flags
+ *
+ *-------------------------------------------------------------------------------
+ */
+
+#ifndef __RINGBUFFER_H
+#define __RINGBUFFER_H
+
+#include "thread.h"
+#include "tools.h"
+
+class cRingBuffer {
+private:
+protected:
+ void WaitForPut(void);
+ void WaitForGet(void);
+ void EnablePut(void);
+ void EnableGet(void);
+ virtual void Clear(void) = 0;
+ virtual int Available(void) = 0;
+ int Free(void) { return 0; }
+ void Lock(void) { }
+ void Unlock(void) { }
+ int Size(void) { return 0; }
+public:
+ cRingBuffer(int Size, bool Statistics = false);
+ virtual ~cRingBuffer();
+ void SetTimeouts(int PutTimeout, int GetTimeout);
+ };
+
+enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby };
+
+class cFrame {
+ friend class cRingBufferFrame;
+private:
+public:
+ cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1);
+ ~cFrame();
+ uchar *Data(void) const { return 0; }
+ int Count(void) const { return 0; }
+ eFrameType Type(void) const { return ftUnknown; }
+ int Index(void) const { return 0; }
+ };
+
+class cRingBufferFrame : public cRingBuffer {
+private:
+public:
+ cRingBufferFrame(int Size, bool Statistics = false);
+ virtual ~cRingBufferFrame();
+ virtual int Available(void);
+ virtual void Clear(void);
+ // Immediately clears the ring buffer.
+ bool Put(cFrame *Frame);
+ // Puts the Frame into the ring buffer.
+ // Returns true if this was possible.
+ cFrame *Get(void);
+ // Gets the next frame from the ring buffer.
+ // The actual data still remains in the buffer until Drop() is called.
+ void Drop(cFrame *Frame);
+ // Drops the Frame that has just been fetched with Get().
+ };
+
+#endif // __RINGBUFFER_H
+
+// --------- $Id: ringbuffer.h,v 1.2 2016/09/01 15:37:42 richard Exp $ ---------- END \ No newline at end of file
diff --git a/genindex/rmstream.c b/genindex/rmstream.c
new file mode 100644
index 0000000..b77a7af
--- /dev/null
+++ b/genindex/rmstream.c
@@ -0,0 +1,140 @@
+/*
+ * A VDR stream removing tool (C++)
+ *
+ * (C) 2005 Stefan Huelswitt <s.huelswitt@gmx.de>
+ *
+ * This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "pes.h"
+#include "version.h"
+
+// --- cRmStream ---------------------------------------------------------------
+
+class cRmStream : public cPES {
+private:
+ int infile, outfile;
+ unsigned char buff[KILOBYTE(256)];
+protected:
+ virtual int Output(const uchar *data, int len);
+public:
+ cRmStream(void);
+ void Work(const char *inName, const char *outName);
+ void Skip(int type);
+ };
+
+cRmStream::cRmStream(void)
+{
+ SetDefaultRule(prPass);
+}
+
+void cRmStream::Skip(int type)
+{
+ SetRule(type,prSkip);
+}
+
+void cRmStream::Work(const char *inName, const char *outName)
+{
+ infile=open(inName,O_RDONLY);
+ if(infile>=0) {
+ if(access(outName,F_OK)<0) {
+ if(errno==ENOENT) {
+ outfile=open(outName,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if(outfile>=0) {
+ while(1) {
+ int c=read(infile,buff,sizeof(buff));
+ if(c>0) {
+ int u=Process(buff,c);
+ if(c!=u) printf("bummer, count!=0\n");
+ }
+ else {
+ if(c<0) printf("read failed: %s\n",strerror(errno));
+ break;
+ }
+ }
+ close(outfile);
+ Statistics();
+ }
+ else printf("open failed: %s: %s\n",outName,strerror(errno));
+ }
+ else printf("access failed: %s: %s\n",outName,strerror(errno));
+ }
+ else printf("file exists: %s\n",outName);
+ close(infile);
+ }
+ else printf("open failed: %s: %s\n",inName,strerror(errno));
+}
+
+int cRmStream::Output(const uchar *data, int len)
+{
+ int c=write(outfile,data,len);
+ if(c<0) printf("write failed: %s\n",strerror(errno));
+ return c;
+}
+
+// --- MAIN --------------------------------------------------------------------
+
+void usage(void)
+{
+ printf("Usage: rmstream -d str [-o outfile] infile\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ printf("This is %s %s (%s), (C) 2005 Stefan Hülswitt\n"
+ "Released under the GNU Public License\n",
+ "rmstream",PRG_VERSION,__DATE__);
+
+ cRmStream gi;
+ char *inName=0, *outName=0;
+ int c, num=0;
+ while((c=getopt(argc,argv,"d:o:"))!=-1) {
+ switch(c) {
+ case 'd':
+ {
+ int type=strtol(optarg,0,0);
+ gi.Skip(type);
+ printf("skipping stream 0x%x\n",type);
+ num++;
+ break;
+ }
+ case 'o':
+ outName=optarg;
+ break;
+ case '?':
+ usage();
+ }
+ }
+
+ if(optind<argc) inName=argv[optind];
+ else usage();
+
+ if(num<1) usage();
+
+ if(outName==0)
+ asprintf(&outName,"%s.new",inName);
+
+ gi.Work(inName,outName);
+ return 0;
+}
diff --git a/genindex/testindex.c b/genindex/testindex.c
new file mode 100644
index 0000000..4b3f900
--- /dev/null
+++ b/genindex/testindex.c
@@ -0,0 +1,68 @@
+/*
+ * A VDR index tester (C++)
+ *
+ * (C) 2003-2006 Stefan Huelswitt <s.huelswitt@gmx.de>
+ *
+ * This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "file.h"
+
+// Picture types:
+#define I_FRAME 1
+#define P_FRAME 2
+#define B_FRAME 3
+
+// --- MAIN --------------------------------------------------------------------
+
+int main(int argc, char *argv[])
+{
+ cFileName fileName;
+ cIndex index;
+
+ int startNo=1;
+ if(argc>1) {
+ startNo=atoi(argv[1]);
+ if(startNo<1) startNo=1;
+ if(startNo>=99) startNo=99;
+ }
+
+ if(index.Open(true)) {
+ int nr, off, fd;
+ unsigned char buff[64];
+ while(index.Read(nr,off)) {
+ if(nr<startNo) continue;
+ fd=fileName.Skip(nr,off);
+ printf("offset %d\r",off); fflush(stdout);
+ if(fd<0) break;
+ int r=read(fd,buff,sizeof(buff));
+ if(r<0) printf("read vdr: %s\n",strerror(errno));
+ if(buff[0]!=0x00 || buff[1]!=0x00 || buff[2]!=0x01 || (buff[3]&0xF0)!=0xE0) {
+ printf("bad packet start file=%d off=%d\n",nr,off);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/genindex/thread.c b/genindex/thread.c
new file mode 100644
index 0000000..6b7ea0f
--- /dev/null
+++ b/genindex/thread.c
@@ -0,0 +1,45 @@
+/*
+ * thread.c: A simple thread base class
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: thread.c,v 1.1 2010/08/18 21:27:14 richard Exp $
+ *
+ * This was taken from the VDR package, which was released under the GPL.
+ * Stripped down to make the PES parser happy
+ */
+
+#include "thread.h"
+#include <unistd.h>
+
+// --- cMutex ----------------------------------------------------------------
+
+cMutex::cMutex(void)
+{
+ lockingPid = 0;
+ locked = 0;
+ pthread_mutex_init(&mutex, NULL);
+}
+
+cMutex::~cMutex()
+{
+ pthread_mutex_destroy(&mutex);
+}
+
+void cMutex::Lock(void)
+{
+ if (getpid() != lockingPid || !locked) {
+ pthread_mutex_lock(&mutex);
+ lockingPid = getpid();
+ }
+ locked++;
+}
+
+void cMutex::Unlock(void)
+{
+ if (!--locked) {
+ lockingPid = 0;
+ pthread_mutex_unlock(&mutex);
+ }
+}
diff --git a/genindex/thread.h b/genindex/thread.h
new file mode 100644
index 0000000..d8931b2
--- /dev/null
+++ b/genindex/thread.h
@@ -0,0 +1,32 @@
+/*
+ * thread.h: A simple thread base class
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: thread.h,v 1.1 2010/08/18 21:27:14 richard Exp $
+ *
+ * This was taken from the VDR package, which was released under the GPL.
+ * Stripped down to make the PES parser happy
+ */
+
+#ifndef __THREAD_H
+#define __THREAD_H
+
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+class cMutex {
+private:
+ pthread_mutex_t mutex;
+ pid_t lockingPid;
+ int locked;
+public:
+ cMutex(void);
+ ~cMutex();
+ void Lock(void);
+ void Unlock(void);
+ };
+
+#endif //__THREAD_H
diff --git a/genindex/tools.h b/genindex/tools.h
new file mode 100644
index 0000000..3819850
--- /dev/null
+++ b/genindex/tools.h
@@ -0,0 +1,690 @@
+/*
+ * tools.h: Various tools
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * RF copied direct from vdr (2.20)
+ *-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: tools.h,v $
+ * Revision 1.2 2016/09/01 15:37:42 richard
+ * Extensively updated to V0.2 for EN 300 743 compliant subtitles
+ * added -b and -n flags
+ *
+ *-------------------------------------------------------------------------------
+ */
+
+#ifndef __TOOLS_H
+#define __TOOLS_H
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <float.h>
+#include <iconv.h>
+#include <math.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+typedef unsigned char uchar;
+
+extern int SysLogLevel;
+
+#define esyslog(a...) void( (SysLogLevel > 0) ? syslog_with_tid(LOG_ERR, a) : void() )
+#define isyslog(a...) void( (SysLogLevel > 1) ? syslog_with_tid(LOG_INFO, a) : void() )
+#define dsyslog(a...) void( (SysLogLevel > 2) ? syslog_with_tid(LOG_DEBUG, a) : void() )
+
+#define LOG_ERROR esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__)
+#define LOG_ERROR_STR(s) esyslog("ERROR (%s,%d): %s: %m", __FILE__, __LINE__, s)
+
+#define SECSINDAY 86400
+
+#define KILOBYTE(n) ((n) * 1024)
+#define MEGABYTE(n) ((n) * 1024LL * 1024LL)
+
+#define MALLOC(type, size) (type *)malloc(sizeof(type) * (size))
+
+template<class T> inline void DELETENULL(T *&p) { T *q = p; p = NULL; delete q; }
+
+#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
+#define FATALERRNO (errno && errno != EAGAIN && errno != EINTR)
+
+#ifndef __STL_CONFIG_H // in case some plugin needs to use the STL
+template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
+template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
+template<class T> inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; }
+template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
+#endif
+
+template<class T> inline T constrain(T v, T l, T h) { return v < l ? l : v > h ? h : v; }
+
+void syslog_with_tid(int priority, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+#define BCDCHARTOINT(x) (10 * ((x & 0xF0) >> 4) + (x & 0xF))
+int BCD2INT(int x);
+
+#define IsBitSet(v, b) ((v) & (1 << (b))) // checks if the bit at index b is set in v, where the least significant bit has index 0
+
+// Unfortunately there are no platform independent macros for unaligned
+// access, so we do it this way:
+
+template<class T> inline T get_unaligned(T *p)
+{
+ struct s { T v; } __attribute__((packed));
+ return ((s *)p)->v;
+}
+
+template<class T> inline void put_unaligned(unsigned int v, T* p)
+{
+ struct s { T v; } __attribute__((packed));
+ ((s *)p)->v = v;
+}
+
+// Comparing doubles for equality is unsafe, but unfortunately we can't
+// overwrite operator==(double, double), so this will have to do:
+
+inline bool DoubleEqual(double a, double b)
+{
+ return fabs(a - b) <= DBL_EPSILON;
+}
+
+// When handling strings that might contain UTF-8 characters, it may be necessary
+// to process a "symbol" that consists of several actual character bytes. The
+// following functions allow transparently accessing a "char *" string without
+// having to worry about what character set is actually used.
+
+int Utf8CharLen(const char *s);
+ ///< Returns the number of character bytes at the beginning of the given
+ ///< string that form a UTF-8 symbol.
+uint Utf8CharGet(const char *s, int Length = 0);
+ ///< Returns the UTF-8 symbol at the beginning of the given string.
+ ///< Length can be given from a previous call to Utf8CharLen() to avoid calculating
+ ///< it again. If no Length is given, Utf8CharLen() will be called.
+int Utf8CharSet(uint c, char *s = NULL);
+ ///< Converts the given UTF-8 symbol to a sequence of character bytes and copies
+ ///< them to the given string. Returns the number of bytes written. If no string
+ ///< is given, only the number of bytes is returned and nothing is copied.
+int Utf8SymChars(const char *s, int Symbols);
+ ///< Returns the number of character bytes at the beginning of the given
+ ///< string that form at most the given number of UTF-8 symbols.
+int Utf8StrLen(const char *s);
+ ///< Returns the number of UTF-8 symbols formed by the given string of
+ ///< character bytes.
+char *Utf8Strn0Cpy(char *Dest, const char *Src, int n);
+ ///< Copies at most n character bytes from Src to Dest, making sure that the
+ ///< resulting copy ends with a complete UTF-8 symbol. The copy is guaranteed
+ ///< to be zero terminated.
+ ///< Returns a pointer to Dest.
+int Utf8ToArray(const char *s, uint *a, int Size);
+ ///< Converts the given character bytes (including the terminating 0) into an
+ ///< array of UTF-8 symbols of the given Size. Returns the number of symbols
+ ///< in the array (without the terminating 0).
+int Utf8FromArray(const uint *a, char *s, int Size, int Max = -1);
+ ///< Converts the given array of UTF-8 symbols (including the terminating 0)
+ ///< into a sequence of character bytes of at most Size length. Returns the
+ ///< number of character bytes written (without the terminating 0).
+ ///< If Max is given, only that many symbols will be converted.
+ ///< The resulting string is always zero-terminated if Size is big enough.
+
+// When allocating buffer space, make sure we reserve enough space to hold
+// a string in UTF-8 representation:
+
+#define Utf8BufSize(s) ((s) * 4)
+
+// The following macros automatically use the correct versions of the character
+// class functions:
+
+#define Utf8to(conv, c) (cCharSetConv::SystemCharacterTable() ? to##conv(c) : tow##conv(c))
+#define Utf8is(ccls, c) (cCharSetConv::SystemCharacterTable() ? is##ccls(c) : isw##ccls(c))
+
+class cCharSetConv {
+private:
+ iconv_t cd;
+ char *result;
+ size_t length;
+ static char *systemCharacterTable;
+public:
+ cCharSetConv(const char *FromCode = NULL, const char *ToCode = NULL);
+ ///< Sets up a character set converter to convert from FromCode to ToCode.
+ ///< If FromCode is NULL, the previously set systemCharacterTable is used
+ ///< (or "UTF-8" if no systemCharacterTable has been set).
+ ///< If ToCode is NULL, "UTF-8" is used.
+ ~cCharSetConv();
+ const char *Convert(const char *From, char *To = NULL, size_t ToLength = 0);
+ ///< Converts the given Text from FromCode to ToCode (as set in the constructor).
+ ///< If To is given, it is used to copy at most ToLength bytes of the result
+ ///< (including the terminating 0) into that buffer. If To is not given,
+ ///< the result is copied into a dynamically allocated buffer and is valid as
+ ///< long as this object lives, or until the next call to Convert(). The
+ ///< return value always points to the result if the conversion was successful
+ ///< (even if a fixed size To buffer was given and the result didn't fit into
+ ///< it). If the string could not be converted, the result points to the
+ ///< original From string.
+ static const char *SystemCharacterTable(void) { return systemCharacterTable; }
+ static void SetSystemCharacterTable(const char *CharacterTable);
+ };
+
+class cString {
+private:
+ char *s;
+public:
+ cString(const char *S = NULL, bool TakePointer = false);
+ cString(const char *S, const char *To); ///< Copies S up to To (exclusive). To must be a valid pointer into S. If To is NULL, everything is copied.
+ cString(const cString &String);
+ virtual ~cString();
+ operator const void * () const { return s; } // to catch cases where operator*() should be used
+ operator const char * () const { return s; } // for use in (const char *) context
+ const char * operator*() const { return s; } // for use in (const void *) context (printf() etc.)
+ cString &operator=(const cString &String);
+ cString &operator=(const char *String);
+ cString &Truncate(int Index); ///< Truncate the string at the given Index (if Index is < 0 it is counted from the end of the string).
+ cString &CompactChars(char c); ///< Compact any sequence of characters 'c' to a single character, and strip all of them from the beginning and end of this string.
+ static cString sprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+ static cString vsprintf(const char *fmt, va_list &ap);
+ };
+
+
+ssize_t safe_read(int filedes, void *buffer, size_t size);
+ssize_t safe_write(int filedes, const void *buffer, size_t size);
+void writechar(int filedes, char c);
+int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs = 0, int RetryMs = 0);
+ ///< Writes either all Data to the given file descriptor, or nothing at all.
+ ///< If TimeoutMs is greater than 0, it will only retry for that long, otherwise
+ ///< it will retry forever. RetryMs defines the time between two retries.
+char *strcpyrealloc(char *dest, const char *src);
+char *strn0cpy(char *dest, const char *src, size_t n);
+char *strreplace(char *s, char c1, char c2);
+char *strreplace(char *s, const char *s1, const char *s2); ///< re-allocates 's' and deletes the original string if necessary!
+const char *strchrn(const char *s, char c, size_t n); ///< returns a pointer to the n'th occurrence (counting from 1) of c in s, or NULL if no such character was found. If n is 0, s is returned.
+int strcountchr(const char *s, char c); ///< returns the number of occurrences of 'c' in 's'.
+inline char *skipspace(const char *s)
+{
+ if ((uchar)*s > ' ') // most strings don't have any leading space, so handle this case as fast as possible
+ return (char *)s;
+ while (*s && (uchar)*s <= ' ') // avoiding isspace() here, because it is much slower
+ s++;
+ return (char *)s;
+}
+char *stripspace(char *s);
+char *compactspace(char *s);
+char *compactchars(char *s, char c); ///< removes all occurrences of 'c' from the beginning an end of 's' and replaces sequences of multiple 'c's with a single 'c'.
+cString strescape(const char *s, const char *chars);
+bool startswith(const char *s, const char *p);
+bool endswith(const char *s, const char *p);
+bool isempty(const char *s);
+int numdigits(int n);
+bool isnumber(const char *s);
+int64_t StrToNum(const char *s);
+ ///< Converts the given string to a number.
+ ///< The numerical part of the string may be followed by one of the letters
+ ///< K, M, G or T to abbreviate Kilo-, Mega-, Giga- or Terabyte, respectively
+ ///< (based on 1024). Everything after the first non-numeric character is
+ ///< silently ignored, as are any characters other than the ones mentioned here.
+bool StrInArray(const char *a[], const char *s);
+ ///< Returns true if the string s is equal to one of the strings pointed
+ ///< to by the (NULL terminated) array a.
+double atod(const char *s);
+ ///< Converts the given string, which is a floating point number using a '.' as
+ ///< the decimal point, to a double value, independent of the currently selected
+ ///< locale.
+cString dtoa(double d, const char *Format = "%f");
+ ///< Converts the given double value to a string, making sure it uses a '.' as
+ ///< the decimal point, independent of the currently selected locale.
+ ///< If Format is given, it will be used instead of the default.
+cString itoa(int n);
+cString AddDirectory(const char *DirName, const char *FileName);
+bool EntriesOnSameFileSystem(const char *File1, const char *File2);
+ ///< Checks whether the given files are on the same file system. If either of the
+ ///< files doesn't exist, this function returns *true* to avoid any actions that might be
+ ///< triggered if files are on different file system.
+int FreeDiskSpaceMB(const char *Directory, int *UsedMB = NULL);
+bool DirectoryOk(const char *DirName, bool LogErrors = false);
+bool MakeDirs(const char *FileName, bool IsDirectory = false);
+bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);
+bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false, const char *IgnoreFiles[] = NULL);
+ ///< Removes all empty directories under the given directory DirName.
+ ///< If RemoveThis is true, DirName will also be removed if it is empty.
+ ///< IgnoreFiles can be set to an array of file names that will be ignored when
+ ///< considering whether a directory is empty. If IgnoreFiles is given, the array
+ ///< must end with a NULL pointer.
+int DirSizeMB(const char *DirName); ///< returns the total size of the files in the given directory, or -1 in case of an error
+char *ReadLink(const char *FileName); ///< returns a new string allocated on the heap, which the caller must delete (or NULL in case of an error)
+bool SpinUpDisk(const char *FileName);
+void TouchFile(const char *FileName);
+time_t LastModifiedTime(const char *FileName);
+off_t FileSize(const char *FileName); ///< returns the size of the given file, or -1 in case of an error (e.g. if the file doesn't exist)
+cString WeekDayName(int WeekDay);
+ ///< Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter
+ ///< day name.
+cString WeekDayName(time_t t);
+ ///< Converts the week day of the given time to a three letter day name.
+cString WeekDayNameFull(int WeekDay);
+ ///< Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a full
+ ///< day name.
+cString WeekDayNameFull(time_t t);
+ ///< Converts the week day of the given time to a full day name.
+cString DayDateTime(time_t t = 0);
+ ///< Converts the given time to a string of the form "www dd.mm. hh:mm".
+ ///< If no time is given, the current time is taken.
+cString TimeToString(time_t t);
+ ///< Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
+cString DateString(time_t t);
+ ///< Converts the given time to a string of the form "www dd.mm.yyyy".
+cString ShortDateString(time_t t);
+ ///< Converts the given time to a string of the form "dd.mm.yy".
+cString TimeString(time_t t);
+ ///< Converts the given time to a string of the form "hh:mm".
+uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality = 100);
+ ///< Converts the given Memory to a JPEG image and returns a pointer
+ ///< to the resulting image. Mem must point to a data block of exactly
+ ///< (Width * Height) triplets of RGB image data bytes. Upon return, Size
+ ///< will hold the number of bytes of the resulting JPEG data.
+ ///< Quality can be in the range 0..100 and controls the quality of the
+ ///< resulting image, where 100 is "best". The caller takes ownership of
+ ///< the result and has to delete it once it is no longer needed.
+ ///< The result may be NULL in case of an error.
+
+class cBase64Encoder {
+private:
+ const uchar *data;
+ int length;
+ int maxResult;
+ int i;
+ char *result;
+ static const char *b64;
+public:
+ cBase64Encoder(const uchar *Data, int Length, int MaxResult = 64);
+ ///< Sets up a new base 64 encoder for the given Data, with the given Length.
+ ///< Data will not be copied and must be valid as long as NextLine() will be
+ ///< called. MaxResult defines the maximum number of characters in any
+ ///< result line. The resulting lines may be shorter than MaxResult in case
+ ///< its value is not a multiple of 4.
+ ~cBase64Encoder();
+ const char *NextLine(void);
+ ///< Returns the next line of encoded data (terminated by '\0'), or NULL if
+ ///< there is no more encoded data. The caller must call NextLine() and process
+ ///< each returned line until NULL is returned, in order to get the entire
+ ///< data encoded. The returned data is only valid until the next time NextLine()
+ ///< is called, or until the object is destroyed.
+ };
+
+class cBitStream {
+private:
+ const uint8_t *data;
+ int length; // in bits
+ int index; // in bits
+public:
+ cBitStream(const uint8_t *Data, int Length) : data(Data), length(Length), index(0) {}
+ ~cBitStream() {}
+ int GetBit(void);
+ uint32_t GetBits(int n);
+ void ByteAlign(void);
+ void WordAlign(void);
+ bool SetLength(int Length);
+ void SkipBits(int n) { index += n; }
+ void SkipBit(void) { SkipBits(1); }
+ bool IsEOF(void) const { return index >= length; }
+ void Reset(void) { index = 0; }
+ int Length(void) const { return length; }
+ int Index(void) const { return (IsEOF() ? length : index); }
+ const uint8_t *GetData(void) const { return (IsEOF() ? NULL : data + (index / 8)); }
+ };
+
+class cTimeMs {
+private:
+ uint64_t begin;
+public:
+ cTimeMs(int Ms = 0);
+ ///< Creates a timer with ms resolution and an initial timeout of Ms.
+ ///< If Ms is negative the timer is not initialized with the current
+ ///< time.
+ static uint64_t Now(void);
+ void Set(int Ms = 0);
+ bool TimedOut(void) const;
+ uint64_t Elapsed(void) const;
+ };
+
+class cReadLine {
+private:
+ size_t size;
+ char *buffer;
+public:
+ cReadLine(void);
+ ~cReadLine();
+ char *Read(FILE *f);
+ };
+
+class cPoller {
+private:
+ enum { MaxPollFiles = 16 };
+ pollfd pfd[MaxPollFiles];
+ int numFileHandles;
+public:
+ cPoller(int FileHandle = -1, bool Out = false);
+ bool Add(int FileHandle, bool Out);
+ bool Poll(int TimeoutMs = 0);
+ };
+
+class cReadDir {
+private:
+ DIR *directory;
+ struct dirent *result;
+ union { // according to "The GNU C Library Reference Manual"
+ struct dirent d;
+ char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
+ } u;
+public:
+ cReadDir(const char *Directory);
+ ~cReadDir();
+ bool Ok(void) { return directory != NULL; }
+ struct dirent *Next(void);
+ };
+
+class cFile {
+private:
+ static bool files[];
+ static int maxFiles;
+ int f;
+public:
+ cFile(void);
+ ~cFile();
+ operator int () { return f; }
+ bool Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
+ bool Open(int FileDes);
+ void Close(void);
+ bool IsOpen(void) { return f >= 0; }
+ bool Ready(bool Wait = true);
+ static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000);
+ static bool FileReady(int FileDes, int TimeoutMs = 1000);
+ static bool FileReadyForWriting(int FileDes, int TimeoutMs = 1000);
+ };
+
+class cSafeFile {
+private:
+ FILE *f;
+ char *fileName;
+ char *tempName;
+public:
+ cSafeFile(const char *FileName);
+ ~cSafeFile();
+ operator FILE* () { return f; }
+ bool Open(void);
+ bool Close(void);
+ };
+
+/// cUnbufferedFile is used for large files that are mainly written or read
+/// in a streaming manner, and thus should not be cached.
+
+class cUnbufferedFile {
+private:
+ int fd;
+ off_t curpos;
+ off_t cachedstart;
+ off_t cachedend;
+ off_t begin;
+ off_t lastpos;
+ off_t ahead;
+ size_t readahead;
+ size_t written;
+ size_t totwritten;
+ int FadviseDrop(off_t Offset, off_t Len);
+public:
+ cUnbufferedFile(void);
+ ~cUnbufferedFile();
+ int Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
+ int Close(void);
+ void SetReadAhead(size_t ra);
+ off_t Seek(off_t Offset, int Whence);
+ ssize_t Read(void *Data, size_t Size);
+ ssize_t Write(const void *Data, size_t Size);
+ static cUnbufferedFile *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
+ };
+
+class cLockFile {
+private:
+ char *fileName;
+ int f;
+public:
+ cLockFile(const char *Directory);
+ ~cLockFile();
+ bool Lock(int WaitSeconds = 0);
+ void Unlock(void);
+ };
+
+class cListObject {
+private:
+ cListObject *prev, *next;
+public:
+ cListObject(void);
+ virtual ~cListObject();
+ virtual int Compare(const cListObject &ListObject) const { return 0; }
+ ///< Must return 0 if this object is equal to ListObject, a positive value
+ ///< if it is "greater", and a negative value if it is "smaller".
+ void Append(cListObject *Object);
+ void Insert(cListObject *Object);
+ void Unlink(void);
+ int Index(void) const;
+ cListObject *Prev(void) const { return prev; }
+ cListObject *Next(void) const { return next; }
+ };
+
+class cListBase {
+protected:
+ cListObject *objects, *lastObject;
+ cListBase(void);
+ int count;
+public:
+ virtual ~cListBase();
+ void Add(cListObject *Object, cListObject *After = NULL);
+ void Ins(cListObject *Object, cListObject *Before = NULL);
+ void Del(cListObject *Object, bool DeleteObject = true);
+ virtual void Move(int From, int To);
+ void Move(cListObject *From, cListObject *To);
+ virtual void Clear(void);
+ cListObject *Get(int Index) const;
+ int Count(void) const { return count; }
+ void Sort(void);
+ };
+
+template<class T> class cList : public cListBase {
+public:
+ T *Get(int Index) const { return (T *)cListBase::Get(Index); }
+ T *First(void) const { return (T *)objects; }
+ T *Last(void) const { return (T *)lastObject; }
+ T *Prev(const T *object) const { return (T *)object->cListObject::Prev(); } // need to call cListObject's members to
+ T *Next(const T *object) const { return (T *)object->cListObject::Next(); } // avoid ambiguities in case of a "list of lists"
+ };
+
+template<class T> class cVector {
+ ///< cVector may only be used for *simple* types, like int or pointers - not for class objects that allocate additional memory!
+private:
+ mutable int allocated;
+ mutable int size;
+ mutable T *data;
+ cVector(const cVector &Vector) {} // don't copy...
+ cVector &operator=(const cVector &Vector) { return *this; } // ...or assign this!
+ void Realloc(int Index) const
+ {
+ if (++Index > allocated) {
+ data = (T *)realloc(data, Index * sizeof(T));
+ if (!data) {
+ esyslog("ERROR: out of memory - abort!");
+ abort();
+ }
+ for (int i = allocated; i < Index; i++)
+ data[i] = T(0);
+ allocated = Index;
+ }
+ }
+public:
+ cVector(int Allocated = 10)
+ {
+ allocated = 0;
+ size = 0;
+ data = NULL;
+ Realloc(Allocated);
+ }
+ virtual ~cVector() { free(data); }
+ T& At(int Index) const
+ {
+ Realloc(Index);
+ if (Index >= size)
+ size = Index + 1;
+ return data[Index];
+ }
+ const T& operator[](int Index) const
+ {
+ return At(Index);
+ }
+ T& operator[](int Index)
+ {
+ return At(Index);
+ }
+ int IndexOf(const T &Data) // returns the index of Data, or -1 if not found
+ {
+ for (int i = 0; i < size; i++) {
+ if (data[i] == Data)
+ return i;
+ }
+ return -1;
+ }
+ int Size(void) const { return size; }
+ virtual void Insert(T Data, int Before = 0)
+ {
+ if (Before < size) {
+ Realloc(size);
+ memmove(&data[Before + 1], &data[Before], (size - Before) * sizeof(T));
+ size++;
+ data[Before] = Data;
+ }
+ else
+ Append(Data);
+ }
+ bool InsertUnique(T Data, int Before = 0)
+ {
+ if (IndexOf(Data) < 0) {
+ Insert(Data, Before);
+ return true;
+ }
+ return false;
+ }
+ virtual void Append(T Data)
+ {
+ if (size >= allocated)
+ Realloc(allocated * 3 / 2); // increase size by 50%
+ data[size++] = Data;
+ }
+ bool AppendUnique(T Data)
+ {
+ if (IndexOf(Data) < 0) {
+ Append(Data);
+ return true;
+ }
+ return false;
+ }
+ virtual void Remove(int Index)
+ {
+ if (Index < 0)
+ return; // prevents out-of-bounds access
+ if (Index < size - 1)
+ memmove(&data[Index], &data[Index + 1], (size - Index) * sizeof(T));
+ size--;
+ }
+ bool RemoveElement(const T &Data)
+ {
+ int i = IndexOf(Data);
+ if (i >= 0) {
+ Remove(i);
+ return true;
+ }
+ return false;
+ }
+ virtual void Clear(void)
+ {
+ for (int i = 0; i < size; i++)
+ data[i] = T(0);
+ size = 0;
+ }
+ void Sort(__compar_fn_t Compare)
+ {
+ qsort(data, size, sizeof(T), Compare);
+ }
+ };
+
+inline int CompareStrings(const void *a, const void *b)
+{
+ return strcmp(*(const char **)a, *(const char **)b);
+}
+
+inline int CompareStringsIgnoreCase(const void *a, const void *b)
+{
+ return strcasecmp(*(const char **)a, *(const char **)b);
+}
+
+class cStringList : public cVector<char *> {
+public:
+ cStringList(int Allocated = 10): cVector<char *>(Allocated) {}
+ virtual ~cStringList();
+ int Find(const char *s) const;
+ void Sort(bool IgnoreCase = false)
+ {
+ if (IgnoreCase)
+ cVector<char *>::Sort(CompareStringsIgnoreCase);
+ else
+ cVector<char *>::Sort(CompareStrings);
+ }
+ virtual void Clear(void);
+ };
+
+class cFileNameList : public cStringList {
+public:
+ cFileNameList(const char *Directory = NULL, bool DirsOnly = false);
+ bool Load(const char *Directory, bool DirsOnly = false);
+ };
+
+class cHashObject : public cListObject {
+ friend class cHashBase;
+private:
+ unsigned int id;
+ cListObject *object;
+public:
+ cHashObject(cListObject *Object, unsigned int Id) { object = Object; id = Id; }
+ cListObject *Object(void) { return object; }
+ };
+
+class cHashBase {
+private:
+ cList<cHashObject> **hashTable;
+ int size;
+ unsigned int hashfn(unsigned int Id) const { return Id % size; }
+protected:
+ cHashBase(int Size);
+public:
+ virtual ~cHashBase();
+ void Add(cListObject *Object, unsigned int Id);
+ void Del(cListObject *Object, unsigned int Id);
+ void Clear(void);
+ cListObject *Get(unsigned int Id) const;
+ cList<cHashObject> *GetList(unsigned int Id) const;
+ };
+
+#define HASHSIZE 512
+
+template<class T> class cHash : public cHashBase {
+public:
+ cHash(int Size = HASHSIZE) : cHashBase(Size) {}
+ T *Get(unsigned int Id) const { return (T *)cHashBase::Get(Id); }
+};
+
+#endif //__TOOLS_H
+
+// * $Id: tools.h,v 1.2 2016/09/01 15:37:42 richard Exp $
diff --git a/genindex/version.h b/genindex/version.h
new file mode 100644
index 0000000..df19e14
--- /dev/null
+++ b/genindex/version.h
@@ -0,0 +1,40 @@
+/*
+ * A VDR index file generator (C++)
+ *
+ * (C) 2003-2006 Stefan Huelswitt <s.huelswitt@gmx.de>
+ * (C) 2016 Richard Farthing
+ *
+ * This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *-------------------------------------------------------------------------------
+ * Revision History
+ * $Log: version.h,v $
+ * Revision 1.2 2016/09/01 15:37:42 richard
+ * Extensively updated to V0.2 for EN 300 743 compliant subtitles
+ * added -b and -n flags
+ *
+ *-------------------------------------------------------------------------------
+ */
+
+#ifndef ___VERSION_H
+#define ___VERSION_H
+
+#define PRG_NAME "genindex"
+#define PRG_VERSION "0.2.0"
+
+#endif //___VERSION_H
+
+// --------- $Id: version.h,v 1.2 2016/09/01 15:37:42 richard Exp $ ---------- END \ No newline at end of file
diff --git a/vdr-auto b/vdr-auto
new file mode 120000
index 0000000..2325c68
--- /dev/null
+++ b/vdr-auto
@@ -0,0 +1 @@
+/opt/data/develop/scripts/vdr-auto \ No newline at end of file
diff --git a/vdr-convert b/vdr-convert
new file mode 120000
index 0000000..04a323e
--- /dev/null
+++ b/vdr-convert
@@ -0,0 +1 @@
+/opt/data/develop/scripts/vdr-convert \ No newline at end of file