summaryrefslogtreecommitdiff
path: root/genindex
diff options
context:
space:
mode:
authorRichard <richard@ha-server.local>2016-09-04 11:18:57 +0100
committerRichard <richard@ha-server.local>2016-09-04 11:18:57 +0100
commit83632745c43d406856a3b9948cb5ea4a5ec22666 (patch)
tree76b4e1210c2fdd8f732f17b119e315a2ec72d5e3 /genindex
downloadvdr-convert-83632745c43d406856a3b9948cb5ea4a5ec22666.tar.gz
vdr-convert-83632745c43d406856a3b9948cb5ea4a5ec22666.tar.bz2
Initial import
Diffstat (limited to 'genindex')
-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
22 files changed, 3800 insertions, 0 deletions
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