From 83632745c43d406856a3b9948cb5ea4a5ec22666 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 4 Sep 2016 11:18:57 +0100 Subject: Initial import --- genindex/COPYING | 340 ++++++++++++++++++ genindex/CVS/Entries | 17 + genindex/CVS/Repository | 1 + genindex/CVS/Root | 1 + genindex/Makefile | 89 +++++ genindex/README | 108 ++++++ genindex/fifo.c | 61 ++++ genindex/fifo.h | 27 ++ genindex/file.c | 270 ++++++++++++++ genindex/file.h | 77 ++++ genindex/genindex.c | 477 ++++++++++++++++++++++++ genindex/modulo.h | 41 +++ genindex/pes.c | 938 ++++++++++++++++++++++++++++++++++++++++++++++++ genindex/pes.h | 166 +++++++++ genindex/ringbuffer.c | 93 +++++ genindex/ringbuffer.h | 79 ++++ genindex/rmstream.c | 140 ++++++++ genindex/testindex.c | 68 ++++ genindex/thread.c | 45 +++ genindex/thread.h | 32 ++ genindex/tools.h | 690 +++++++++++++++++++++++++++++++++++ genindex/version.h | 40 +++ 22 files changed, 3800 insertions(+) create mode 100644 genindex/COPYING create mode 100644 genindex/CVS/Entries create mode 100644 genindex/CVS/Repository create mode 100644 genindex/CVS/Root create mode 100644 genindex/Makefile create mode 100644 genindex/README create mode 100644 genindex/fifo.c create mode 100644 genindex/fifo.h create mode 100644 genindex/file.c create mode 100644 genindex/file.h create mode 100644 genindex/genindex.c create mode 100755 genindex/modulo.h create mode 100644 genindex/pes.c create mode 100644 genindex/pes.h create mode 100644 genindex/ringbuffer.c create mode 100644 genindex/ringbuffer.h create mode 100644 genindex/rmstream.c create mode 100644 genindex/testindex.c create mode 100644 genindex/thread.c create mode 100644 genindex/thread.h create mode 100644 genindex/tools.h create mode 100644 genindex/version.h (limited to 'genindex') 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. + + + Copyright (C) + + 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. + + , 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 , (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 +#include +#define __STDC_FORMAT_MACROS // Required for format specifiers +#include +#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 +#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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 +#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 , (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 +#include +#include +#include +#include +#include +#include + +#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 && (readOffsetlastoff+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(ftypeB_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, (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 +#include +#define __STDC_FORMAT_MACROS // Required for format specifiers +#include +#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 ; iClear(); + Unlock(); +} + +bool cPES::ValidRuleset(const int num) +{ + if(num>=0 && num0) { + 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= 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=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=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) { + need=abs(HeaderSize(hbuff,have)); + if(haveneed) 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= 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= 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 +#include +#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 + * + * 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 +#include +#include +#include +#include +#include + +#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 + * + * 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 +#include +#include +#include +#include +#include + +#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 + +// --- 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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 inline T min(T a, T b) { return a <= b ? a : b; } +template inline T max(T a, T b) { return a >= b ? a : b; } +template inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; } +template inline void swap(T &a, T &b) { T t = a; a = b; b = t; } +#endif + +template 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 inline T get_unaligned(T *p) +{ + struct s { T v; } __attribute__((packed)); + return ((s *)p)->v; +} + +template 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 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 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 { +public: + cStringList(int Allocated = 10): cVector(Allocated) {} + virtual ~cStringList(); + int Find(const char *s) const; + void Sort(bool IgnoreCase = false) + { + if (IgnoreCase) + cVector::Sort(CompareStringsIgnoreCase); + else + cVector::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 **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 *GetList(unsigned int Id) const; + }; + +#define HASHSIZE 512 + +template 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 + * (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 -- cgit v1.2.3