From 31c1a72e0591c7c6db4329145248d1dfbb861010 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 28 Jun 2005 22:13:04 +0000 Subject: [PATCH 1/1] Initial import --- COPYING | 340 +++++ HISTORY | 7 + Makefile | 90 ++ README | 13 + config.c | 516 ++++++++ config.h | 77 ++ defines.h | 33 + dsock.c | 174 +++ dsock.h | 65 + libdvbmpeg/DVB.hh | 446 +++++++ libdvbmpeg/Makefile | 33 + libdvbmpeg/OSD.h | 30 + libdvbmpeg/channel.h | 58 + libdvbmpeg/ci.hh | 167 +++ libdvbmpeg/cpptools.cc | 946 ++++++++++++++ libdvbmpeg/cpptools.hh | 330 +++++ libdvbmpeg/ctools.c | 2379 +++++++++++++++++++++++++++++++++++ libdvbmpeg/ctools.h | 404 ++++++ libdvbmpeg/devices.hh | 310 +++++ libdvbmpeg/osd.hh | 84 ++ libdvbmpeg/remux.c | 1215 ++++++++++++++++++ libdvbmpeg/remux.h | 149 +++ libdvbmpeg/ringbuffy.c | 200 +++ libdvbmpeg/ringbuffy.h | 52 + libdvbmpeg/transform.c | 2681 ++++++++++++++++++++++++++++++++++++++++ libdvbmpeg/transform.h | 250 ++++ mvpclient.c | 750 +++++++++++ mvpclient.h | 83 ++ mvpserver.c | 138 +++ mvpserver.h | 53 + recplayer.c | 167 +++ recplayer.h | 56 + remux/README | 7 + remux/ts2es.c | 87 ++ remux/ts2es.h | 21 + remux/ts2ps.c | 108 ++ remux/ts2ps.h | 22 + remux/tsremux.c | 209 ++++ remux/tsremux.h | 42 + ringbuffer.c | 100 ++ ringbuffer.h | 48 + tcp.c | 412 ++++++ tcp.h | 78 ++ transceiver.c | 197 +++ transceiver.h | 71 ++ udpreplier.c | 79 ++ udpreplier.h | 49 + vompserver.c | 103 ++ 48 files changed, 13929 insertions(+) create mode 100644 COPYING create mode 100644 HISTORY create mode 100644 Makefile create mode 100644 README create mode 100644 config.c create mode 100644 config.h create mode 100644 defines.h create mode 100644 dsock.c create mode 100644 dsock.h create mode 100644 libdvbmpeg/DVB.hh create mode 100644 libdvbmpeg/Makefile create mode 100644 libdvbmpeg/OSD.h create mode 100644 libdvbmpeg/channel.h create mode 100644 libdvbmpeg/ci.hh create mode 100644 libdvbmpeg/cpptools.cc create mode 100644 libdvbmpeg/cpptools.hh create mode 100644 libdvbmpeg/ctools.c create mode 100644 libdvbmpeg/ctools.h create mode 100644 libdvbmpeg/devices.hh create mode 100644 libdvbmpeg/osd.hh create mode 100644 libdvbmpeg/remux.c create mode 100644 libdvbmpeg/remux.h create mode 100644 libdvbmpeg/ringbuffy.c create mode 100644 libdvbmpeg/ringbuffy.h create mode 100644 libdvbmpeg/transform.c create mode 100644 libdvbmpeg/transform.h create mode 100644 mvpclient.c create mode 100644 mvpclient.h create mode 100644 mvpserver.c create mode 100644 mvpserver.h create mode 100644 recplayer.c create mode 100644 recplayer.h create mode 100644 remux/README create mode 100644 remux/ts2es.c create mode 100644 remux/ts2es.h create mode 100644 remux/ts2ps.c create mode 100644 remux/ts2ps.h create mode 100644 remux/tsremux.c create mode 100644 remux/tsremux.h create mode 100644 ringbuffer.c create mode 100644 ringbuffer.h create mode 100644 tcp.c create mode 100644 tcp.h create mode 100644 transceiver.c create mode 100644 transceiver.h create mode 100644 udpreplier.c create mode 100644 udpreplier.h create mode 100644 vompserver.c diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/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/HISTORY b/HISTORY new file mode 100644 index 0000000..d7cdb3e --- /dev/null +++ b/HISTORY @@ -0,0 +1,7 @@ +VDR Plugin 'vompserver' Revision History +---------------------------------------- + +2005-06-28: Version 0.0.0 + +- Upload to SF CVS. Not a release yet! + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fdea30e --- /dev/null +++ b/Makefile @@ -0,0 +1,90 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id$ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = vompserver + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: + +CXX ?= g++ +CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual -Werror + +### The directory environment: + +DVBDIR = ../../../../DVB +VDRDIR = ../../.. +LIBDIR = ../../lib +TMPDIR = /tmp + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR (taken from VDR's "config.h"): + +VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -Iremux -Ilibdvbmpeg + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o mvpclient.o tcp.o \ + transceiver.o remux/ts2ps.o remux/ts2es.o remux/tsremux.o ringbuffer.o \ + recplayer.o config.o + + +libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.cc libdvbmpeg/*.h libdvbmpeg/*.hh + make -C ./libdvbmpeg libdvbmpegtools.a + + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +all: libvdr-$(PLUGIN).so + +libvdr-$(PLUGIN).so: $(OBJS) libdvbmpeg/libdvbmpegtools.a + $(CXX) $(CXXFLAGS) -shared $(OBJS) libdvbmpeg/libdvbmpegtools.a -o $@ + @cp $@ $(LIBDIR)/$@.$(VDRVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + make -C libdvbmpeg clean + rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ remux/*.o diff --git a/README b/README new file mode 100644 index 0000000..494c85f --- /dev/null +++ b/README @@ -0,0 +1,13 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Chris Tallon + +Project's homepage: http://www.loggytronic.com/vomp + +Latest version available at: http://www.loggytronic.com/vomp + +See the file COPYING for license information. + +Description: + +Server side of VDR on MVP by Chris Tallon diff --git a/config.c b/config.c new file mode 100644 index 0000000..c70fe7d --- /dev/null +++ b/config.c @@ -0,0 +1,516 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2004-2005 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "config.h" + +Config::Config() +{ + initted = 0; + lastLineLength = 0; +} + +int Config::init(char* takeFileName) +{ + if (initted) return 1; + + pthread_mutex_init(&fileLock, NULL); + + if (strlen(takeFileName) > (MAX_FILENAME_LENGTH - 1)) + { + printf("Config error: Config filename too long\n"); + return 0; + } + + strcpy(fileName, takeFileName); + file = fopen(fileName, "r"); + if (!file) + { + file = fopen(fileName, "w"); + if (!file) + { + printf("Config error: Could not access config file\n"); + return 0; + } + } + fclose(file); + + initted = 1; + + return 1; +} + +int Config::shutdown() +{ + if (!initted) return 1; + + pthread_mutex_lock(&fileLock); + initted = 0; + pthread_mutex_unlock(&fileLock); + pthread_mutex_destroy(&fileLock); + + return 1; +} + +int Config::openFile() +{ + if (!initted) return 0; + if (pthread_mutex_lock(&fileLock)) + { + printf("Config error: Could not get lock\n"); + return 0; + } + if (!initted) + { + printf("Config error: Initted 0 after lock\n"); + pthread_mutex_unlock(&fileLock); + return 0; + } + + file = fopen(fileName, "r"); + if (!file) + { + printf("Config error: Could not open config file\n"); + pthread_mutex_unlock(&fileLock); + return 0; + } + return 1; +} + +void Config::closeFile() +{ + if (!initted) return; + + fclose(file); + file = NULL; + pthread_mutex_unlock(&fileLock); +} + +int Config::readLine() +{ + if (!initted || !file) { printf("1\n"); return 0; } + if (!fgets(buffer, BUFFER_LENGTH-1, file)) { printf("2\n"); return 0; } + lastLineLength = strlen(buffer); + printf("buffer before trim: '%s'\n", buffer); + trim(buffer); + printf("buffer after trim: '%s'\n", buffer); + return 1; +} + +// START HERE + +FILE* Config::copyToHere(long position) +{ + strcpy(fileNameTemp, "/tmp/configXXXXXX"); + int newFileDes = mkstemp(fileNameTemp); + FILE* newFile = fdopen(newFileDes, "w"); + + if (!newFile) return NULL; + + long newPos = 0; + rewind(file); + + while (newPos < position) + { + fgets(buffer, BUFFER_LENGTH-1, file); + fputs(buffer, newFile); + newPos += strlen(buffer); + } + return newFile; +} + +int Config::copyRest(FILE* newFile) +{ + if (newFile) + { + while(fgets(buffer, BUFFER_LENGTH-1, file)) + { + fputs(buffer, newFile); + } + + fclose(newFile); + } + fclose(file); + file = NULL; + + if (newFile) rename(fileNameTemp, fileName); + + pthread_mutex_unlock(&fileLock); + return 1; +} + +int Config::deleteValue(char* section, char* key) +{ + if (!initted) return 0; + if (!openFile()) return 0; + + if (!findSection(section)) + { + closeFile(); + printf("Config error: Section %s not found\n", section); + return 0; + } + if (!findKey(key)) + { + closeFile(); + printf("Config error: Key %s not found\n", key); + return 0; + } + + FILE* newFile = copyToHere(ftell(file) - lastLineLength); + fgets(buffer, BUFFER_LENGTH-1, file); + + return copyRest(newFile); +} + +int Config::setValueLong(char* section, char* key, long newValue) +{ + char longBuffer[50]; + sprintf(longBuffer, "%li", newValue); + return setValueString(section, key, longBuffer); +} + +int Config::setValueLongLong(char* section, char* key, long long newValue) +{ + char longBuffer[50]; + sprintf(longBuffer, "%lli", newValue); + return setValueString(section, key, longBuffer); +} + +int Config::setValueDouble(char* section, char* key, double newValue) +{ + char doubleBuffer[50]; + sprintf(doubleBuffer, "%f", newValue); + return setValueString(section, key, doubleBuffer); +} + +int Config::setValueString(char* section, char* key, char* newValue) +{ + if (!initted) return 0; + if (!openFile()) return 0; + + if (findSection(section)) + { + if (findKey(key)) + { + FILE* newFile = copyToHere(ftell(file) - lastLineLength); + if (!newFile) + { + closeFile(); + printf("Config error: Could not write temp config file\n"); + return 0; + } + + fgets(buffer, BUFFER_LENGTH-1, file); + fprintf(newFile, "%s = %s\n", key, newValue); + return copyRest(newFile); + } + else + { + rewind(file); + findSection(section); + FILE* newFile = copyToHere(ftell(file)); + if (!newFile) + { + closeFile(); + printf("Config error: Could not write temp config file\n"); + return 0; + } + + fprintf(newFile, "%s = %s\n", key, newValue); + return copyRest(newFile); + } + } + else + { + // section not found + fseek(file, 0, SEEK_END); + FILE* newFile = copyToHere(ftell(file)); + if (!newFile) + { + closeFile(); + printf("Config error: Could not write temp config file\n"); + return 0; + } + + fprintf(newFile, "[%s]\n%s = %s\n", section, key, newValue); + return copyRest(newFile); + } +} + +char* Config::getSectionKeyNames(char* section, int& numberOfReturns, int& allKeysSize) +{ + numberOfReturns = 0; + allKeysSize = 0; + char* allKeys = NULL; + int allKeysIndex = 0; + int keyLength; + char* equalspos; + + if (!initted) return NULL; + if (!openFile()) return NULL; + if (!findSection(section)) return NULL; + + char foundKey[BUFFER_LENGTH]; + + while(readLine()) + { + // Is this line a section header? if so, exit + if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) break; + + equalspos = strstr(buffer, "="); + if (!equalspos) continue; // if there is no = then it's not a key + memcpy(foundKey, buffer, equalspos-buffer); + foundKey[equalspos-buffer] = '\0'; + trim(foundKey); + keyLength = strlen(foundKey); + allKeysSize += keyLength + 1; + allKeys = (char*)realloc(allKeys, allKeysSize); + memcpy(&allKeys[allKeysIndex], foundKey, keyLength); + allKeysIndex += keyLength; + allKeys[allKeysIndex] = '\0'; + allKeysIndex++; + numberOfReturns++; + } + + closeFile(); + return allKeys; +} + + +// END HERE + +int Config::findSection(char* section) +{ + if (!initted || !file) return 0; + if (strlen(section) > (BUFFER_LENGTH-2)) + { + printf("Config error: Section given exceeds max length\n"); + return 0; + } + + char toFind[BUFFER_LENGTH]; + toFind[0] = '['; + toFind[1] = '\0'; + strcat(toFind, section); + strcat(toFind, "]"); + + while(readLine()) + { + printf("to find '%s' this line '%s'\n", toFind, buffer); + if (!strcmp(toFind, buffer)) return 1; + } + return 0; +} + +int Config::findKey(char* key) +{ + if (!initted || !file) return 0; + + if (strlen(key) > (BUFFER_LENGTH-1)) + { + printf("Config error: Key given exceeds max length\n"); + return 0; + } + + char prepForTest[BUFFER_LENGTH]; + + // do a rough search first, this could match substrings that we don't want + while(readLine()) + { + // Is this line a section header? if so, exit + if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) return 0; + if (strstr(buffer, key)) + { + // rough search found match + char* equalspos = strstr(buffer, "="); + if (!equalspos) continue; + memcpy(prepForTest, buffer, equalspos-buffer); + prepForTest[equalspos-buffer] = '\0'; + trim(prepForTest); + + if (!strcmp(key, prepForTest)) + { + // in buffer, set all up to equals to space, then trim! + for(char* curPos = buffer; curPos <= equalspos; curPos++) + { + *curPos = ' '; + } + trim(buffer); + return 1; + } + } + } + return 0; +} + +char* Config::getValueString(char* section, char* key) +{ + if (!initted) return NULL; + if (!openFile()) return NULL; + + if (!findSection(section)) + { + closeFile(); + printf("Config error: Section %s not found\n", section); + return 0; + } + if (!findKey(key)) + { + closeFile(); + printf("Config error: Key %s not found\n", key); + return 0; + } + + char* returnString = new char[strlen(buffer)+1]; + strcpy(returnString, buffer); + + closeFile(); + + return returnString; +} + +long Config::getValueLong(char* section, char* key, int* failure) +{ + *failure = 1; + if (!initted) return 0; + if (!openFile()) return 0; + + if (!findSection(section)) + { + closeFile(); + printf("Config error: Section %s not found\n", section); + return 0; + } + if (!findKey(key)) + { + closeFile(); + printf("Config error: Key %s not found\n", key); + return 0; + } + *failure = 0; + + char* check; + long retVal = strtol(buffer, &check, 10); + if ((retVal == 0) && (check == buffer)) *failure = 1; + closeFile(); + + return retVal; +} + +long long Config::getValueLongLong(char* section, char* key, int* failure) +{ + *failure = 1; + if (!initted) return 0; + if (!openFile()) return 0; + + if (!findSection(section)) + { + closeFile(); + printf("Config error: Section %s not found\n", section); + return 0; + } + if (!findKey(key)) + { + closeFile(); + printf("Config error: Key %s not found\n", key); + return 0; + } + *failure = 0; + + char* check; + long long retVal = strtoll(buffer, &check, 10); + if ((retVal == 0) && (check == buffer)) *failure = 1; + closeFile(); + + return retVal; +} + +double Config::getValueDouble(char* section, char* key, int* failure) +{ + *failure = 1; + if (!initted) return 0; + if (!openFile()) return 0; + + if (!findSection(section)) + { + closeFile(); + printf("Config error: Section %s not found\n", section); + return 0; + } + if (!findKey(key)) + { + closeFile(); + printf("Config error: Key %s not found\n", key); + return 0; + } + + *failure = 0; + + char* check; + double retVal = strtod(buffer, &check); + if ((retVal == 0) && (check == buffer)) *failure = 1; + + closeFile(); + + return retVal; +} + + + +void Config::trim(char* str) +{ + int pos, len, start, end; + + // Kill comments + len = strlen(str); + for(pos = 0; pos < len; pos++) + { + if ((str[pos] == '#') || (str[pos] == ';')) + { + // Mod. If #/; is at start of line ok. Else, if it is after a space, ok. + + if ((pos == 0) || (isspace(str[pos - 1]))) + { + str[pos] = '\0'; + break; + } + + } + } + + len = strlen(str); + end = len; + if (!len) return; + + start = 0; + while(isspace(str[start])) start++; + while(isspace(str[end-1])) + { + end--; + if (end == 0) + { + str[0] = '\0'; + return; + } + } + for(pos = start; pos < end; pos++) str[pos - start] = str[pos]; + str[end - start] = '\0'; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..161a497 --- /dev/null +++ b/config.h @@ -0,0 +1,77 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2004-2005 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include +#include +#include + +#define MAX_FILENAME_LENGTH 500 +#define BUFFER_LENGTH 1500 + +class Config +{ + public: + Config(); + + int init(char* fileName); + int shutdown(); + int status(); + + char* getValueString(char* section, char* key); + long getValueLong(char* section, char* key, int* failure); + long long getValueLongLong(char* section, char* key, int* failure); + double getValueDouble(char* section, char* key, int* failure); + + int setValueString(char* section, char* key, char* newValue); + int setValueLong(char* section, char* key, long newValue); + int setValueLongLong(char* section, char* key, long long newValue); + int setValueDouble(char* section, char* key, double newValue); + + int deleteValue(char* section, char* key); // err.. delete "key". + char* getSectionKeyNames(char* section, int& numberOfReturns, int& length); + + private: + pthread_mutex_t fileLock; + int initted; + int lastLineLength; + + char fileName[MAX_FILENAME_LENGTH]; + char fileNameTemp[MAX_FILENAME_LENGTH]; + + FILE* file; + char buffer[BUFFER_LENGTH]; + + int openFile(); + void closeFile(); + int readLine(); + int findSection(char* section); + int findKey(char* key); + void trim(char* sting); + FILE* copyToHere(long position); + int copyRest(FILE* newFile); +}; + +#endif diff --git a/defines.h b/defines.h new file mode 100644 index 0000000..1144743 --- /dev/null +++ b/defines.h @@ -0,0 +1,33 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DEFINES_H +#define DEFINES_H + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned long ULONG; +typedef unsigned long long ULLONG; + +ULLONG htonll(ULLONG a); +ULLONG ntohll(ULLONG a); + + +#endif diff --git a/dsock.c b/dsock.c new file mode 100644 index 0000000..77755b4 --- /dev/null +++ b/dsock.c @@ -0,0 +1,174 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "dsock.h" + +DatagramSocket::DatagramSocket(short port) +{ + myPort = port; + addrlen = sizeof(struct sockaddr); + + if ((socketnum = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { perror("socket"); exit(1); } + + myAddr.sin_family = AF_INET; // host byte order + myAddr.sin_port = htons(myPort); // short, network byte order + myAddr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP + memset(&(myAddr.sin_zero), 0, 8); // zero the rest of the struct + if (bind(socketnum, (struct sockaddr *)&myAddr, addrlen) == -1) + { perror("bind"); printf(" %s ", strerror(errno)); exit(1); } + + FD_ZERO(&readfds); + FD_SET(socketnum, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 0; +} + +DatagramSocket::~DatagramSocket() +{ + close(socketnum); +} + +unsigned char DatagramSocket::waitforMessage(unsigned char how) +{ + /* how = 0 - block + how = 1 - start new wait + how = 2 - continue wait + */ + + struct timeval* passToSelect = NULL; + + + if (how == 0) + { + passToSelect = NULL; + } + else if (how == 1) + { + tv.tv_sec = 1; + tv.tv_usec = 100000; + passToSelect = &tv; + } + else if (how == 2) + { + if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) // protection in case timer = 0 + { + tv.tv_sec = 1; + tv.tv_usec = 100000; + } + passToSelect = &tv; + } + FD_ZERO(&readfds); + FD_SET(socketnum, &readfds); + + if (select(socketnum + 1, &readfds, NULL, NULL, passToSelect) <= 0) + { return 1; } + + if ((mlength = recvfrom(socketnum, buf, MAXBUFLEN, 0, + (struct sockaddr *)&theirAddr, &addrlen)) == -1) + { perror("recvfrom"); return 0; } + else + { + memset(&buf[mlength], 0, MAXBUFLEN - mlength); + strcpy(fromIPA, inet_ntoa(theirAddr.sin_addr)); + fromPort = ntohs(theirAddr.sin_port); + + if (DSOCKDEBUG) + { + printf("%s:%i\tIN %i\t", fromIPA, fromPort, mlength); + int k; + for(k = 0; k < mlength; k++) + printf("%u ", (unsigned char)buf[k]); + printf("\n"); + } + return 2; + } + + /* Return 0, failure + Return 1, nothing happened, timer expired + Return 2, packet arrived (timer not expired) + */ +} + +int DatagramSocket::getDataLength(void) const +{ + return mlength; +} + +char *DatagramSocket::getData(void) { return buf; } +char *DatagramSocket::getFromIPA(void) { return fromIPA; } +short DatagramSocket::getFromPort(void) const { return fromPort; } + +void DatagramSocket::send(char *ipa, short port, char *message, int length) +{ + if (DSOCKDEBUG) + { + printf("%s:%i\tOUT %i\t", ipa, port, length); + int k; + uchar l; + for (k = 0; k < length; k++) + { l = (uchar)message[k]; printf("%u ", l); } + } + + int sentLength = 0; + + theirAddr.sin_family = AF_INET; // host byte order + theirAddr.sin_port = htons(port); // short, network byte order + struct in_addr tad; // temp struct tad needed to pass to theirAddr.sin_addr + tad.s_addr = inet_addr(ipa); + theirAddr.sin_addr = tad; // address + memset(&(theirAddr.sin_zero), 0, 8); // zero the rest of the struct + + unsigned char crypt[MAXBUFLEN]; + memcpy(crypt, message, length); + + sentLength = sendto(socketnum, crypt, length, 0, (struct sockaddr *)&theirAddr, addrlen); + if (sentLength == length) + { + printf(" GOOD\n"); + } + else + { + printf(" --BAD--"); fflush(stdout); + sentLength = sendto(socketnum, crypt, length, 0, (struct sockaddr *)&theirAddr, addrlen); + if (sentLength == length) + printf(" GOOD\n"); + else + { + printf(" -#-FAILED-#-\n"); + + if (DSOCKDEBUG && (sentLength != length)) + { + printf("--------------\n"); + printf("Sendto failure\n"); + printf("--------------\n"); + printf("%s:%i\tOUT %i %i ...\n", ipa, port, length, sentLength); + perror("Perror reports"); + printf("errno value: %d\n", errno); + printf("errno translated: %s\n", strerror(errno)); + // printf("h_errno value: %d\n", h_errno); + // printf("\nActual address: %s\n", inet_ntoa(tad)); + // printf("Actual port: %i\n", ntohs(theirAddr.sin_port)); + printf("continuing...\n\n"); + } + } + } +} + diff --git a/dsock.h b/dsock.h new file mode 100644 index 0000000..28ddf5c --- /dev/null +++ b/dsock.h @@ -0,0 +1,65 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DSOCK_H +#define DSOCK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXBUFLEN 2000 +const char DSOCKDEBUG = 1; +typedef unsigned char uchar; + +class DatagramSocket +{ + public: + DatagramSocket(short); // port + ~DatagramSocket(); + unsigned char waitforMessage(unsigned char); // int =0-block =1-new wait =2-continue wait + int getDataLength(void) const; + char *getData(void); // returns a pointer to the data + char *getFromIPA(void); // returns a pointer to from IP address + short getFromPort(void) const; + void send(char *, short, char *, int); // send wants: IP Address ddn style, port, + // data, length of data + private: + int socketnum; // Socket descriptor + short myPort; // My port number + struct sockaddr_in myAddr; // My address + struct sockaddr_in theirAddr; // User address + socklen_t addrlen; // length of sockaddr struct + char buf[MAXBUFLEN]; // main data buffer + char fromIPA[20]; // from string (ip address) + short fromPort; // which port user sent on + int mlength; // length of message + struct timeval tv; + fd_set readfds; +}; + +#endif diff --git a/libdvbmpeg/DVB.hh b/libdvbmpeg/DVB.hh new file mode 100644 index 0000000..e713bee --- /dev/null +++ b/libdvbmpeg/DVB.hh @@ -0,0 +1,446 @@ +#ifndef _DVB_DEV_HH_ +#define _DVB_DEV_HH_ + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NEWSTRUCT +#include +} + +#include +#include +#include +using namespace std; + +#include +#include + +#ifndef MAXNAM +#define MAXNAM 80 +#endif + + + +#define FRONT_DVBS 1 +#define FRONT_DVBC 2 +#define FRONT_DVBT 3 + +#define VTXDIR "/var/vtx" + +#define DEC(N) dec << setw(N) << setfill('0') +#define HEX(N) hex << setw(N) << setfill('0') + +#define MAXSECSIZE 4096 + +#define NK 10 +enum {LNB=0,DIS,ROTOR,TRANS,CHAN,BOU,SAT,PICS,SWI,NTW}; +static const int nums[]={LNB,DIS,ROTOR,TRANS,CHAN,BOU,SAT,PICS,SWI,NTW}; +static const int maxs[]={ 32, 32, 32, 512,16384,512,100, 50, 10, 100}; + +#define MAX_TRANS_CHAN 1024 + +enum{DVB_ORIG=0, DVB_NOKIA, DVB_XML, DVB_SATCO}; + +typedef struct frontend_stat_s{ + fe_status_t status; + uint16_t snr; + uint16_t strength; + uint32_t ber; + uint32_t u_blocks; +} frontend_stat; + + +extern uint8_t hamtab[256]; +extern uint8_t invtab[256]; + +#define MAX_MAG 8 +typedef struct mag_struct_ { + int valid; + int magn; + uint8_t flags; + uint8_t lang; + int pnum,sub; + uint8_t pagebuf[25*40]; +} magazin_t; + + +class DVB { +public: + int no_open; + int fd_frontend; + int fd_demuxa; + int fd_demuxv; + int fd_demuxpcr; + int fd_demuxtt; + int fdvb; + + int minor; + int adapter; + int max_tpid; + int max_satid; + int max_chanid; + + frontend_stat festat; + + struct dvb_diseqc_master_cmd dcmd; + fe_sec_tone_mode_t tone; + fe_sec_voltage_t voltage; + int burst; + struct dmx_pes_filter_params pesFilterParamsV; + struct dmx_pes_filter_params pesFilterParamsA; + struct dmx_pes_filter_params pesFilterParamsP; + struct dmx_pes_filter_params pesFilterParamsTT; + struct dvb_frontend_parameters front_param; + int front_type; + int dvr_enabled; + OSD osd; + uint32_t transponder_freq; + char transponder_pol; + uint32_t transponder_srate; + + + + fe_status_t status; + uint32_t ber, uncorrected_blocks; + uint16_t snr, signal; + + + struct Lnb *lnbs; + struct DiSEqC *diseqcs; + struct Rotor *rotors; + struct Transponder *tps; + struct Channel *chans; + struct Bouquet *bouqs; + struct Sat *sats; + struct Picture *pics; + struct Switch *swis; + struct Network *ntws; + int num[NK]; + int oldsec; + int tryit; + int oldpol; + + char *vtxdir; + magazin_t magazin[MAX_MAG]; + + DVB(){ + no_open = 0; + max_tpid = 0; + max_satid = 0; + max_chanid = 0; + minor = 0; + + fd_frontend = -1; + fd_demuxa = -1; + fd_demuxpcr = -1; + fd_demuxv = -1; + fd_demuxtt = -1; + fdvb = -1; + vtxdir = NULL; + transponder_freq=0; + transponder_pol=0; + transponder_srate=0; + } + + DVB(int i){ + if (i >= 0) + no_open = 0; + else + no_open = 1; + max_tpid = 0; + max_satid = 0; + max_chanid = 0; + + fd_frontend = -1; + fd_demuxa = -1; + fd_demuxpcr = -1; + fd_demuxv = -1; + fd_demuxtt = -1; + fdvb = -1; + vtxdir = NULL; + transponder_freq=0; + transponder_pol=0; + transponder_srate=0; + + init("","",i); + } + + DVB(char *a, char *b) { + max_tpid = 0; + max_satid = 0; + max_chanid = 0; + + fd_frontend = -1; + fd_demuxa = -1; + fd_demuxpcr = -1; + fd_demuxv = -1; + fd_demuxtt = -1; + + fdvb = -1; + vtxdir = NULL; + init(a,b,0); + } + + ~DVB(); + + void use_osd(int fd = -1){ + char dvn[32]; + if (no_open) return; + if (fd < 0) fd = 0; + sprintf(dvn,OSD_DEV,adapter,fd); + fdvb = open(dvn, O_RDWR); + + if (fdvb >= 0){ + cerr << dvn << " for OSD" << endl; + osd.init(fdvb); + } else perror("osd"); + osd.Open(80, 500, 640, 540, 2, 0, 2); + osd.SetColor(0, 0, 0, 0, 255); + osd.SetColor(1, 240, 240, 240, 255); + osd.Show(); + } + + void set_vtxdir(char *newname){ + if (!newname) return; + if (vtxdir) free(vtxdir); + vtxdir = (char *) malloc(sizeof(char)*(strlen(newname)+1)); + if (vtxdir) + strncpy(vtxdir, newname, strlen(newname)); + } + + void close_osd(){ + osd.Close(fdvb); + close(fdvb); + } + + int DVR_enabled(){ + if (no_open) return -1; + return dvr_enabled; + } + + void enable_DVR(){ + if (no_open) return; + dvr_enabled = 1; + } + + void enable_DVR_other(){ + if (no_open) return; + dvr_enabled = 2; + } + + void disable_DVR(){ + if (no_open) return; + dvr_enabled = 0; + } + + void init(char *a="/dev/video0", char *b="/dev/vbi0",int adapt=0, + int minor = 0); + + + inline void init(char *a, char *b){ + if (no_open) return; + init(a,b,0,0); + } + + int check_frontend(); + + void set_apid(ushort apid); + void set_vpid(ushort vpid); + void set_pcrpid(ushort vpid); + void set_ttpid(ushort ttpid); + int set_apid_fd(ushort apid, int fd); + int set_vpid_fd(ushort vpid, int fd); + int set_ttpid_fd(ushort ttpid, int fd); + int set_pcrpid_fd(ushort pcrpid, int fd); + int set_otherpid_fd(ushort otherpid, int fd); + + + int set_lnb(int dis); + void set_diseqc_nb(int nr); + int set_front(void); + void get_front(void); + + void scan_pf_eit(int chnr, + int (*callback)(uint8_t *data, int l, int pnr, + int c_n, uint8_t *t)); + + void scan_pf_eit(Channel *chan, + int (*callback)(uint8_t *data, int l, int pnr, + int c_n, uint8_t *t)); + void scan_pf_eit(int chnr); + + + int search_in_TP(Transponder &tp, int show=1, int verbose=0); + int search_in_TP(uint16_t tpid, uint16_t satid, int show=1, + int verbose=0); + int scan_TP(uint16_t tpid, uint16_t satid, int timeout=-1, int verbose=0); + + int GetSection(uint8_t *buf, + uint16_t PID, uint8_t TID, uint16_t TIDExt, + uint16_t FilterTIDExt, + uint8_t secnum, uint8_t &msecnum); + int GetSection(uint8_t *buf, + uint16_t PID, uint8_t *filter, uint8_t *mask, + uint8_t secnum, uint8_t &msecnum); + int GetSection(uint8_t *buf, ushort PID, uint8_t sec, + uint8_t secnum, uint8_t &msecnum); + int SetFilter(uint16_t pid, uint8_t *filter, + uint8_t *mask, + uint32_t timeout, uint32_t flags); + uint16_t SetFilter(uint16_t pid, uint16_t section, uint16_t mode); + int CloseFilter(int h); + + + void bar2(int x, int y, int w, int h, int val, int col1, int col2); + + int SetTP(unsigned int, unsigned int); + int scan(void); + int scan_all_tps(void); + int scan_lnb(struct Lnb &); + int scan_cable(Sat &sat); + int scan_sat(struct Sat &); + int scan_tp(struct Transponder &); + + int AddLNB(int id, int t, uint l1, uint l2, uint sl, + int dnr, int dis, int sw); + int AddSat(Sat &sat); + int AddSat(int satid, unsigned int lnbid, char *name, uint fmin, uint fmax); + int AddTP(Transponder &tp); + int AddChannel(Channel &chan); + int parse_descriptor(Channel *chan, uint8_t *data, int length); + int parse_pmt(Channel *chan, uint8_t *data); + int parse_pat(Channel *chan, uint8_t *data); + + int check_pids(Channel *chan); + void check_all_pids(); + void scan_sdt(Channel *chan); + int scan_sdts(int *chs, int n); + + int channel_num(void) { + return num[CHAN]; + }; + + int channel_change(int n) { + return 0; + }; + int SetChannel(uint16_t, uint16_t, uint16_t, uint16_t); + int SetChannel(Channel *chan, char* apref=NULL, uint16_t *apidp=NULL, + uint16_t *vpidp=NULL) ; + int SetChannel(int chnr, char *apref=NULL, uint16_t *apidp=NULL, + uint16_t *vpidp=NULL); + int GetChannel(int chnr, struct channel *); + int NumChannel(void) { + return num[CHAN]; + } + int tune_it(struct dvb_frontend_parameters *qpsk); + void find_satid(Channel &chan); + int check_input_format(istream &ins); + void read_original(istream &ins); + int get_all_progs(uint16_t *progbuf, uint16_t *pnrbuf, int length); + uint16_t find_pnr(uint16_t vpid, uint16_t apid); + int get_pids(uint16_t prog_pid, uint16_t *vpid, uint16_t *apids, + uint16_t *ttpid, uint8_t *apids_name=NULL); + void AddECM(Channel *chan, uint8_t *data, int length); + int check_ecm(Channel *chan); + void add_vtx_line(magazin_t *mag, int line, uint8_t *data, int pnr); + + friend ostream &operator<<(ostream &stream, DVB &x); + friend istream &operator>>(istream &stream, DVB &x); + +}; + +#define NOKIA_MAX_SAT 4 +class nokiaconv{ +public: + DVB *dvb; + struct lnb_sat_l{ + int n; + int diseqc[NOKIA_MAX_SAT]; + char sat_names[NOKIA_MAX_SAT][MAXNAM+1]; + int satid[NOKIA_MAX_SAT]; + } lnb_sat; + + nokiaconv(DVB *d){ + dvb = d; + } + + friend istream &operator>>(istream &stream, nokiaconv &x); +}; + +#define XML_MAX_SAT 4 +class xmlconv{ +public: + DVB *dvb; + struct lnb_sat_l{ + int n; + int diseqc[XML_MAX_SAT]; + char sat_names[XML_MAX_SAT][MAXNAM+1]; + int satid[XML_MAX_SAT]; + } lnb_sat; + + xmlconv(DVB *d){ + dvb = d; + } + int read_stream(istream &ins, int nchan); + int read_desc(istream &ins, int nchan); + int read_serv(istream &ins, int ctp, int csat); + int read_trans(istream &ins, int satid); + int read_sat(istream &ins, int satid = -1); + int skip_tag(istream &ins, char *tag); + int read_iso639(istream &ins, int nchan, int apids); + + friend istream &operator>>(istream &stream, xmlconv &x); +}; + + + +#define SATCO_MAX_SAT 10 +class satcoconv{ +public: + DVB *dvb; + int nlnb; + + satcoconv(DVB *d){ + dvb = d; + } + + friend istream &operator>>(istream &stream, satcoconv &x); +}; + +void hdump(uint8_t *buf, int n); +int get_dvbrc(char *path, DVB &dv, int dev, int len); +int set_dvbrc(char *path, DVB &dv, int dev, int len); +void dvb2txt(char *out, char *in, int len); +int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum, fe_code_rate_t fec); +void set_pes_filt(int fd,uint16_t pes_pid); +void set_diseqc(int fdf, int snum, fe_sec_voltage_t v, fe_sec_tone_mode_t t); +int tune(int fdf, uint32_t freq, uint32_t sr, fe_code_rate_t fec); +int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum, + fe_code_rate_t fec); + + +struct in_addr getaddress (const char *name); +int tcp_client_connect(const char *hostname, int sckt); +int udp_client_connect(const char *filename); +void client_send_msg(int fd, uint8_t *msg, int size); +int chck_frontend (int fefd, frontend_stat *festat); + +uint8_t deham(uint8_t x, uint8_t y); + +#endif diff --git a/libdvbmpeg/Makefile b/libdvbmpeg/Makefile new file mode 100644 index 0000000..a56cb6b --- /dev/null +++ b/libdvbmpeg/Makefile @@ -0,0 +1,33 @@ +INCS = -I. +CFLAGS = -g -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE +MFLAG = -M +OBJS = ctools.o ringbuffy.o remux.o transform.o cpptools.o +SRC = $(wildcard *.c) +CPPSRC = $(wildcard *.cpp) +CSRC = $(wildcard *.cc) + +DESTDIR = /usr/local + +.PHONY: depend clean install uninstall + +clean: + - rm -f *.o *~ *.a .depend + +libdvbmpegtools.a: $(OBJS) + ar -rcs libdvbmpegtools.a $(OBJS) + +%.o: %.cc + $(CXX) -c $(CFLAGS) $(INCS) $(DEFINES) $< + +%.o: %.cpp + $(CXX) -c $(CFLAGS) $(INCS) $(DEFINES) $< + +%.o: %.c + $(CC) -c $(CFLAGS) $(INCS) $(DEFINES) $< + +.depend: + $(CXX) $(DEFINES) $(MFLAG) $(SRC) $(CSRC) $(CPPSRC) $(INCS)> .depend + + + +-include .depend diff --git a/libdvbmpeg/OSD.h b/libdvbmpeg/OSD.h new file mode 100644 index 0000000..385ac78 --- /dev/null +++ b/libdvbmpeg/OSD.h @@ -0,0 +1,30 @@ +#ifndef _OSD_H_ +#define _OSD_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +int OSDClose(int dev); +int OSDOpen(int dev, int x0, int y0, int x1, int y1, int BitPerPixel, int mix); +int OSDShow(int dev); +int OSDHide(int dev); +int OSDClear(int dev); +int OSDFill(int dev, int color); +int OSDSetColor(int dev, int color, int r, int g, int b, int op); +int OSDText(int dev, int x, int y, int size, int color, const char *text); +int OSDSetPalette(int dev, int first, int last, unsigned char *data); +int OSDSetTrans(int dev, int trans); +int OSDSetPixel(int dev, int x, int y, unsigned int color); +int OSDGetPixel(int dev, int x, int y); +int OSDSetRow(int dev, int x, int y, int x1, unsigned char *data); +int OSDSetBlock(int dev, int x, int y, int x1, int y1, int inc, unsigned char *data); +int OSDFillRow(int dev, int x, int y, int x1, int color); +int OSDFillBlock(int dev, int x, int y, int x1, int y1, int color); +int OSDLine(int dev, int x, int y, int x1, int y1, int color); +int OSDQuery(int dev); +int OSDSetWindow(int dev, int win); +int OSDMoveWindow(int dev, int x, int y); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/libdvbmpeg/channel.h b/libdvbmpeg/channel.h new file mode 100644 index 0000000..c4f62b4 --- /dev/null +++ b/libdvbmpeg/channel.h @@ -0,0 +1,58 @@ +#ifndef _CHANNEL_H +#define _CHANNEL_H + +#include + +struct channel { + int id; + char name[81]; + int type; + ushort pnr; + ushort vpid; + ushort apids[8]; + ushort apidnum; + ushort ac3pid; + ushort pcrpid; + + uint freq; + int pol; + int qam; + uint srate; + int fec; +}; + +#ifdef NEWSTRUCT + +#include +#include +#include +#include + +#define DVR_DEV "/dev/dvb/adapter%d/dvr%d" +#define VIDEO_DEV "/dev/dvb/adapter%d/video%d" +#define AUDIO_DEV "/dev/dvb/adapter%d/audio%d" +#define DEMUX_DEV "/dev/dvb/adapter%d/demux%d" +#define FRONT_DEV "/dev/dvb/adapter%d/frontend%d" +#define OSD_DEV "/dev/dvb/adapter%d/osd%d" +#define CA_DEV "/dev/dvb/adapter%d/ca%d" + +#else + +#include +#include +#include +#include +#include + +#define DVR_DEV "/dev/ost/dvr%d" +#define VIDEO_DEV "/dev/ost/video%d" +#define AUDIO_DEV "/dev/ost/audio%d" +#define DEMUX_DEV "/dev/ost/demux%d" +#define FRONT_DEV "/dev/ost/frontend%d" +#define OSD_DEV "/dev/ost/osd%d" +#define CA_DEV "/dev/ost/ca%d" + +#endif + + +#endif diff --git a/libdvbmpeg/ci.hh b/libdvbmpeg/ci.hh new file mode 100644 index 0000000..77e7684 --- /dev/null +++ b/libdvbmpeg/ci.hh @@ -0,0 +1,167 @@ +/* + * ci.hh: Common Interface + * + * Copyright (C) 2000 Klaus Schmidinger + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * The author can be reached at kls@cadsoft.de + * + * The project's page is at http://www.cadsoft.de/people/kls/vdr + * + */ + +#ifndef __CI_H +#define __CI_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAXCASYSTEMIDS 16 + +class cMutex { + friend class cCondVar; +private: + pthread_mutex_t mutex; + pid_t lockingPid; + int locked; +public: + cMutex(void); + ~cMutex(); + void Lock(void); + void Unlock(void); + }; + +class cMutexLock { +private: + cMutex *mutex; + bool locked; +public: + cMutexLock(cMutex *Mutex = NULL); + ~cMutexLock(); + bool Lock(cMutex *Mutex); + }; + + +class cCiMMI; + +class cCiMenu { + friend class cCiMMI; +private: + enum { MAX_CIMENU_ENTRIES = 64 }; ///< XXX is there a specified maximum? + cCiMMI *mmi; + bool selectable; + char *titleText; + char *subTitleText; + char *bottomText; + char *entries[MAX_CIMENU_ENTRIES]; + int numEntries; + bool AddEntry(char *s); + cCiMenu(cCiMMI *MMI, bool Selectable); +public: + ~cCiMenu(); + const char *TitleText(void) { return titleText; } + const char *SubTitleText(void) { return subTitleText; } + const char *BottomText(void) { return bottomText; } + const char *Entry(int n) { return n < numEntries ? entries[n] : NULL; } + int NumEntries(void) { return numEntries; } + bool Selectable(void) { return selectable; } + bool Select(int Index); + bool Cancel(void); + }; + +class cCiEnquiry { + friend class cCiMMI; +private: + cCiMMI *mmi; + char *text; + bool blind; + int expectedLength; + cCiEnquiry(cCiMMI *MMI); +public: + ~cCiEnquiry(); + const char *Text(void) { return text; } + bool Blind(void) { return blind; } + int ExpectedLength(void) { return expectedLength; } + bool Reply(const char *s); + bool Cancel(void); + }; + +class cCiCaPmt { + friend class cCiConditionalAccessSupport; +private: + int length; + int esInfoLengthPos; + uint8_t capmt[2048]; ///< XXX is there a specified maximum? +public: + cCiCaPmt(int ProgramNumber); + void AddPid(int Pid); + void AddCaDescriptor(int Length, uint8_t *Data); + }; + +#define MAX_CI_SESSION 16 //XXX + +class cCiSession; +class cCiTransportLayer; +class cCiTransportConnection; + +class cCiHandler { +private: + cMutex mutex; + int numSlots; + bool newCaSupport; + bool hasUserIO; + cCiSession *sessions[MAX_CI_SESSION]; + cCiTransportLayer *tpl; + cCiTransportConnection *tc; + int ResourceIdToInt(const uint8_t *Data); + bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1); + cCiSession *GetSessionBySessionId(int SessionId); + cCiSession *GetSessionByResourceId(int ResourceId, int Slot); + cCiSession *CreateSession(int ResourceId); + bool OpenSession(int Length, const uint8_t *Data); + bool CloseSession(int SessionId); + int CloseAllSessions(int Slot); + cCiHandler(int Fd, int NumSlots); +public: + ~cCiHandler(); + static cCiHandler *CreateCiHandler(const char *FileName); + int NumSlots(void) { return numSlots; } + bool Process(void); + bool HasUserIO(void) { return hasUserIO; } + bool EnterMenu(int Slot); + cCiMenu *GetMenu(void); + cCiEnquiry *GetEnquiry(void); + bool SetCaPmt(cCiCaPmt &CaPmt); + const unsigned short *GetCaSystemIds(int Slot); + bool SetCaPmt(cCiCaPmt &CaPmt, int Slot); + bool Reset(int Slot); + }; + +int tcp_listen(struct sockaddr_in *name,int sckt,unsigned long address=INADDR_ANY); +int accept_tcp(int ip_sock,struct sockaddr_in *ip_name); +int udp_listen(struct sockaddr_un *name,char const * const filename); +int accept_udp(int ip_sock,struct sockaddr_un *ip_name); + +#endif //__CI_H diff --git a/libdvbmpeg/cpptools.cc b/libdvbmpeg/cpptools.cc new file mode 100644 index 0000000..91808cc --- /dev/null +++ b/libdvbmpeg/cpptools.cc @@ -0,0 +1,946 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002 Marcus Metzler + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at mocm@metzlerbros.de + */ + +#include "cpptools.hh" + +#define HEX(N) "0x" << hex << setw(2) << setfill('0') \ +<< int(N) << " " << dec +#define HHEX(N,M) "0x" << hex << setw(M) << setfill('0') \ +<< int(N) << " " << dec +#define LHEX(N,M) "0x" << hex << setw(M) << setfill('0') \ +<< long(N) << " " << dec + +#define MAX_SEARCH 1024 * 1024 + +ostream & operator << (ostream & stream, PES_Packet & x){ + + if (x.info){ + cerr << "PES Packet: " ; + switch ( x.p.stream_id ) { + + case PROG_STREAM_MAP: + cerr << "Program Stream Map"; + break; + case PRIVATE_STREAM2: + cerr << "Private Stream 2"; + break; + case PROG_STREAM_DIR: + cerr << "Program Stream Directory"; + break; + case ECM_STREAM : + cerr << "ECM Stream"; + break; + case EMM_STREAM : + cerr << "EMM Stream"; + break; + case PADDING_STREAM : + cerr << "Padding Stream"; + break; + case DSM_CC_STREAM : + cerr << "DSM Stream"; + break; + case ISO13522_STREAM: + cerr << "ISO13522 Stream"; + break; + case PRIVATE_STREAM1: + cerr << "Private Stream 1"; + break; + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + cerr << "Audio Stream " << HEX(x.p.stream_id); + break; + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + cerr << "Video Stream " << HEX(x.p.stream_id); + break; + + } + cerr << " MPEG" << x.p.mpeg << endl; + if ( x.p.mpeg == 2 ){ + cerr << " FLAGS: "; + + if (x.p.flags1 & SCRAMBLE_FLAGS){ + cerr << " SCRAMBLE("; + cerr << ((x.p.flags1 & SCRAMBLE_FLAGS)>>4); + cerr << ")"; + } + if (x.p.flags1 & PRIORITY_FLAG) + cerr << " PRIORITY"; + if (x.p.flags1 & DATA_ALIGN_FLAG) + cerr << " DATA_ALIGN"; + if (x.p.flags1 & COPYRIGHT_FLAG) + cerr << " COPYRIGHT"; + if (x.p.flags1 & ORIGINAL_FLAG) + cerr << " ORIGINAL"; + + if (x.p.flags2 & PTS_DTS_FLAGS){ + cerr << " PTS_DTS("; + cerr << ((x.p.flags2 & PTS_DTS_FLAGS)>>6); + cerr << ")"; + } + if (x.p.flags2 & ESCR_FLAG) + cerr << " ESCR"; + if (x.p.flags2 & ES_RATE_FLAG) + cerr << " ES_RATE"; + if (x.p.flags2 & DSM_TRICK_FLAG) + cerr << " DSM_TRICK"; + if (x.p.flags2 & ADD_CPY_FLAG) + cerr << " ADD_CPY"; + if (x.p.flags2 & PES_CRC_FLAG) + cerr << " CRC"; + if (x.p.flags2 & PES_EXT_FLAG) + cerr << " EXT"; + + cerr << endl; + + if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY) + cerr << " PTS: " + << LHEX(ntohl(x.WPTS()),8) + << "(h" << int(x.high_pts()) << ")" + << endl; + else if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){ + cerr << " PTS: " + << LHEX(ntohl(x.WPTS()),8) + << "(h" << int(x.high_pts()) << ")"; + cerr << " DTS: " + << LHEX(ntohl(x.WDTS()),8) + << "(h" << int(x.high_dts()) << ")" + << endl; + } +/* + if (x.p.flags2 & ESCR_FLAG) + + + if (x.p.flags2 & ES_RATE_FLAG) + + + if (x.p.flags2 & DSM_TRICK_FLAG) + + + if (x.p.flags2 & ADD_CPY_FLAG) + + + if (x.p.flags2 & PES_CRC_FLAG) + + + if (x.p.flags2 & PES_EXT_FLAG){ + + if (x.p.priv_flags & PRIVATE_DATA) + stream.write(x.p.pes_priv_data,16); + + if (x.p.priv_flags & HEADER_FIELD){ + stream.write(&x.p.pack_field_length,1); + x.p.pack_header = new + uint8_t[x.p.pack_field_length]; + stream.write(x.p.pack_header, + x.p.pack_field_length); + } + + if ( x.p.priv_flags & PACK_SEQ_CTR){ + stream.write(&x.p.pck_sqnc_cntr,1); + stream.write(&x.p.org_stuff_length,1); + } + + if ( x.p.priv_flags & P_STD_BUFFER) + stream.write(x.p.p_std,2); + + if ( x.p.priv_flags & PES_EXT_FLAG2){ + stream.write(&x.p.pes_ext_lngth,1); + x.p.pes_ext = new + uint8_t[x.p.pes_ext_lngth]; + stream.write(x.p.pes_ext, + x.p.pes_ext_lngth); + } + } + } else { + if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY) + stream.write(x.p.pts,5); + else if ((x.p.flags2 & PTS_DTS_FLAGS) == + PTS_DTS){ + stream.write(x.p.pts,5); + stream.write(x.p.dts,5); + } +*/ + } + cerr << endl << endl; + return stream; + } + + int l = x.p.length+x.p.pes_hlength+9; + uint8_t buf[l]; + int length = cwrite_pes(buf,&(x.p),l); + stream.write((char *)buf,length); + + return stream; +} + +static unsigned int find_length(istream & stream){ + streampos p = 0; + streampos start = 0; + streampos q = 0; + int found = 0; + uint8_t sync4[4]; + + start = stream.tellg(); + start -=2; + stream.seekg(start); + while ( !stream.eof() && !found ){ + p = stream.tellg(); + stream.read((char *)&sync4,4); + if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { + switch ( sync4[3] ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + found = 1; + break; + default: + q = stream.tellg(); + break; + } + } + } + q = stream.tellg(); + stream.seekg(streampos(2)+start); + if (found) return (unsigned int)(q-start)-4-2; + else return (unsigned int)(q-start)-2; + +} + +istream & operator >> (istream & stream, PES_Packet & x){ + + uint8_t sync4[4]; + int found=0; + int done=0; + streampos p = 0; + + while (!stream.eof() && !found) { + p = stream.tellg(); + stream.read((char *)&sync4,4); + if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { + x.p.stream_id = sync4[3]; + + switch ( sync4[3] ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + found = 1; + stream.read((char *)x.p.llength,2); + x.setlength(); + if (!x.p.length){ + x.p.length = find_length(stream); + x.Nlength(); + } + stream.read((char *)x.p.pes_pckt_data,x.p.length); + done = 1; + break; + case PADDING_STREAM : + found = 1; + stream.read((char *)x.p.llength,2); + x.setlength(); + if (!x.p.length){ + x.p.length = find_length(stream); + x.Nlength(); + } + x.p.padding = x.p.length; + stream.read((char *)x.p.pes_pckt_data,x.p.length); + done = 1; + break; + + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + stream.read((char *)x.p.llength,2); + x.setlength(); + if (!x.p.length){ + x.p.length = find_length(stream); + x.Nlength(); + } + found = 1; + break; + + default: + stream.seekg(p+streampos(1)); + break; + } + } else stream.seekg(p+streampos(1)); + } + + if ( found && !done) { + p = stream.tellg(); + stream.read((char *)&x.p.flags1,1); + if ( (x.p.flags1 & 0xC0) == 0x80 ) + x.p.mpeg = 2; + else + x.p.mpeg = 1; + if ( x.p.mpeg == 2 ){ + stream.read((char *)&x.p.flags2,1); + stream.read((char *)&x.p.pes_hlength,1); + + if ((int)x.p.length > x.p.pes_hlength+3) + x.p.length -=x.p.pes_hlength+3; + else + return stream; + + uint8_t count = x.p.pes_hlength; + + if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ + stream.read((char *)x.p.pts,5); + count -=5; + } else + if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){ + stream.read((char *)x.p.pts,5); + stream.read((char *)x.p.dts,5); + count -= 10; + } + + if (x.p.flags2 & ESCR_FLAG){ + stream.read((char *)x.p.escr,6); + count -= 6; + } + + if (x.p.flags2 & ES_RATE_FLAG){ + stream.read((char *)x.p.es_rate,3); + count -= 6; + } + + if (x.p.flags2 & DSM_TRICK_FLAG){ + stream.read((char *)&x.p.trick,1); + count -= 1; + } + + if (x.p.flags2 & ADD_CPY_FLAG){ + stream.read((char *)&x.p.add_cpy,1); + count -= 1; + } + + if (x.p.flags2 & PES_CRC_FLAG){ + stream.read((char *)x.p.prev_pes_crc,2); + count -= 2; + } + + if (x.p.flags2 & PES_EXT_FLAG){ + stream.read((char *)&x.p.priv_flags,1); + count -= 1; + + if (x.p.priv_flags & PRIVATE_DATA){ + stream.read((char *)x.p.pes_priv_data,16); + count -= 16; + } + + if (x.p.priv_flags & HEADER_FIELD){ + stream.read((char *)&x.p.pack_field_length,1); + x.p.pack_header = new + uint8_t[x.p.pack_field_length]; + stream.read((char *)x.p.pack_header, + x.p.pack_field_length); + count -= 1+x.p.pack_field_length; + } + + if ( x.p.priv_flags & PACK_SEQ_CTR){ + stream.read((char *)&x.p.pck_sqnc_cntr,1); + stream.read((char *)&x.p.org_stuff_length,1); + count -= 2; + } + + if ( x.p.priv_flags & P_STD_BUFFER){ + stream.read((char *)x.p.p_std,2); + count -= 2; + } + + if ( x.p.priv_flags & PES_EXT_FLAG2){ + stream.read((char *)&x.p.pes_ext_lngth,1); + x.p.pes_ext = new + uint8_t[x.p.pes_ext_lngth]; + stream.read((char *)x.p.pes_ext, + x.p.pes_ext_lngth); + count -= 1+x.p.pes_ext_lngth; + } + } + x.p.stuffing = count; + uint8_t dummy; + for(int i = 0; i< count ;i++) + stream.read((char *)&dummy,1); + + } else { + uint8_t check; + x.p.mpeg1_pad = 1; + check = x.p.flags1; + while (check == 0xFF){ + stream.read((char *)&check,1); + x.p.mpeg1_pad++; + } + + if ( (check & 0xC0) == 0x40){ + stream.read((char *)&check,1); + x.p.mpeg1_pad++; + stream.read((char *)&check,1); + x.p.mpeg1_pad++; + } + x.p.flags2 = 0; + x.p.length -= x.p.mpeg1_pad; + + stream.seekg(p); + if ( (check & 0x30)){ + x.p.length ++; + x.p.mpeg1_pad --; + + if (check == x.p.flags1){ + x.p.pes_hlength = 0; + } else { + x.p.mpeg1_headr = + new uint8_t[x.p.mpeg1_pad]; + x.p.pes_hlength = x.p.mpeg1_pad; + stream.read((char *)x.p.mpeg1_headr, + x.p.mpeg1_pad); + } + + x.p.flags2 = (check & 0xF0) << 2; + if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ + stream.read((char *)x.p.pts,5); + x.p.length -= 5; + x.p.pes_hlength += 5; + } + else if ((x.p.flags2 & PTS_DTS_FLAGS) == + PTS_DTS){ + stream.read((char *)x.p.pts,5); + stream.read((char *)x.p.dts,5); + x.p.length -= 10; + x.p.pes_hlength += 10; + } + } else { + x.p.mpeg1_headr = new uint8_t[x.p.mpeg1_pad]; + x.p.pes_hlength = x.p.mpeg1_pad; + stream.read((char *)x.p.mpeg1_headr,x.p.mpeg1_pad); + } + } + stream.read((char *)x.p.pes_pckt_data,x.p.length); + } + return stream; +} + +ostream & operator << (ostream & stream, TS_Packet & x){ + + uint8_t buf[TS_SIZE]; + int length = cwrite_ts(buf,&(x.p),TS_SIZE); + stream.write((char *)buf,length); + + return stream; +} + +istream & operator >> (istream & stream, TS_Packet & x){ + uint8_t sync; + int found=0; + streampos p,q; + + sync=0; + while (!stream.eof() && !found) { + stream.read((char *)&sync,1); + if (sync == 0x47) + found = 1; + } + stream.read((char *)x.p.pid,2); + stream.read((char *)&x.p.flags,1); + x.p.count = x.p.flags & COUNT_MASK; + + if (!(x.p.flags & ADAPT_FIELD) && (x.p.flags & PAYLOAD)){ + //no adapt. field only payload + stream.read((char *)x.p.data,184); + x.p.rest = 184; + return stream; + } + + if ( x.p.flags & ADAPT_FIELD ) { + // adaption field + stream.read((char *)&x.p.adapt_length,1); + if (x.p.adapt_length){ + p = stream.tellg(); + stream.read((char *)&x.p.adapt_flags,1); + + if ( x.p.adapt_flags & PCR_FLAG ) + stream.read((char *) x.p.pcr,6); + + if ( x.p.adapt_flags & OPCR_FLAG ) + stream.read((char *) x.p.opcr,6); + + if ( x.p.adapt_flags & SPLICE_FLAG ) + stream.read((char *) &x.p.splice_count,1); + + if( x.p.adapt_flags & TRANS_PRIV){ + stream.read((char *)&x.p.priv_dat_len,1); + x.p.priv_dat = new uint8_t[x.p.priv_dat_len]; + stream.read((char *)x.p.priv_dat,x.p.priv_dat_len); + } + + if( x.p.adapt_flags & ADAP_EXT_FLAG){ + stream.read((char *)&x.p.adapt_ext_len,1); + stream.read((char *)&x.p.adapt_eflags,1); + if( x.p.adapt_eflags & LTW_FLAG) + stream.read((char *)x.p.ltw,2); + + if( x.p.adapt_eflags & PIECE_RATE) + stream.read((char *)x.p.piece_rate,3); + + if( x.p.adapt_eflags & SEAM_SPLICE) + stream.read((char *)x.p.dts,5); + } + q = stream.tellg(); + x.p.stuffing = x.p.adapt_length -(q-p); + x.p.rest = 183-x.p.adapt_length; + stream.seekg(q+streampos(x.p.stuffing)); + if (x.p.flags & PAYLOAD) // payload + stream.read((char *)x.p.data,x.p.rest); + else + stream.seekg(q+streampos(x.p.rest)); + } else { + x.p.rest = 182; + stream.read((char *)x.p.data, 183); + return stream; + } + + } + return stream; +} + + +ostream & operator << (ostream & stream, PS_Packet & x){ + + uint8_t buf[PS_MAX]; + int length = cwrite_ps(buf,&(x.p),PS_MAX); + stream.write((char *)buf,length); + + return stream; +} + +istream & operator >> (istream & stream, PS_Packet & x){ + uint8_t headr[4]; + int found=0; + streampos p = 0; + streampos q = 0; + int count = 0; + + p = stream.tellg(); + while (!stream.eof() && !found && count < MAX_SEARCH) { + stream.read((char *)&headr,4); + if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01) + if ( headr[3] == 0xBA ) + found = 1; + else if ( headr[3] == 0xB9 ) break; + else stream.seekg(p+streampos(1)); + count++; + } + + if (found){ + stream.read((char *)x.p.scr,6); + if (x.p.scr[0] & 0x40) + x.p.mpeg = 2; + else + x.p.mpeg = 1; + + if (x.p.mpeg == 2){ + stream.read((char *)x.p.mux_rate,3); + stream.read((char *)&x.p.stuff_length,1); + p = stream.tellg(); + stream.seekg(p+streampos(x.p.stuff_length & 3)); + } else { + x.p.mux_rate[0] = x.p.scr[5]; //mpeg1 scr is only 5 bytes + stream.read((char *)x.p.mux_rate+1,2); + } + + p=stream.tellg(); + stream.read((char *)headr,4); + if (headr[0] == 0x00 && headr[1] == 0x00 && + headr[2] == 0x01 && headr[3] == 0xBB ) { + stream.read((char *)x.p.sheader_llength,2); + x.setlength(); + if (x.p.mpeg == 2){ + stream.read((char *)x.p.rate_bound,3); + stream.read((char *)&x.p.audio_bound,1); + stream.read((char *)&x.p.video_bound,1); + stream.read((char *)&x.p.reserved,1); + } + stream.read((char *)x.p.data,x.p.sheader_length); + } else { + stream.seekg(p); + x.p.sheader_length = 0; + } + + int i = 0; + int done = 0; + q = stream.tellg(); + PES_Packet pes; + do { + p=stream.tellg(); + stream.read((char *)headr,4); + stream.seekg(p); + if ( headr[0] == 0x00 && headr[1] == 0x00 + && headr[2] == 0x01 && headr[3] != 0xBA){ + pes.init(); + stream >> pes; + i++; + } else done = 1; + } while (!stream.eof() && !done); + x.p.npes = i; + stream.seekg(q); + } + return stream; +} + +void extract_audio_from_PES(istream &in, ostream &out){ + PES_Packet pes; + + while(!in.eof()){ + pes.init(); + in >> pes ; + if (pes.Stream_ID() == 0xC0) + out << pes; + } +} + +void extract_video_from_PES(istream &in, ostream &out){ + PES_Packet pes; + + while(!in.eof()){ + pes.init(); + in >> pes ; + if (pes.Stream_ID() == 0xE0) + out << pes; + } +} + +void extract_es_audio_from_PES(istream &in, ostream &out){ + PES_Packet pes; + + while(!in.eof()){ + pes.init(); + in >> pes ; + if (pes.Stream_ID() == 0xC0) + out.write((char *)pes.Data(),pes.Length()); + } +} + +void extract_es_video_from_PES(istream &in, ostream &out){ + PES_Packet pes; + + while(!in.eof()){ + pes.init(); + in >> pes ; + if (pes.Stream_ID() == 0xE0) + out.write((char *)pes.Data(),pes.Length()); + } +} + + + +#define MAX_PID 20 +int TS_PIDS(istream &in, ostream &out){ + int pid[MAX_PID]; + TS_Packet ts; + int npid=0; + + for (int i=0 ; i> ts; + int j; + int found = 0; + for (j=0;j> 4 | headr[0] << 4; + vsize = (headr[1] &0x0F) << 8 | headr[2]; + cerr << "SIZE: " << hsize << "x" << vsize << endl; + + switch(((headr[3]&0xF0) >>4)){ + case 1: + cerr << "ASPECT: 1:1" << endl; + break; + case 2: + cerr << "ASPECT: 4:3" << endl; + break; + case 3: + cerr << "ASPECT: 16:9" << endl; + break; + case 4: + cerr << "ASPECT: 2.21:1" << endl; + break; + } + + switch (int(headr[3]&0x0F)){ + case 1: + cerr << "FRAMERATE: 23.976" << endl; + form = pDUNNO; + break; + case 2: + cerr << "FRAMERATE: 24" << endl; + form = pDUNNO; + break; + case 3: + cerr << "FRAMERATE: 25" << endl; + form = pPAL; + break; + case 4: + cerr << "FRAMERATE: 29.97" << endl; + form = pNTSC; + break; + case 5: + cerr << "FRAMERATE: 30" << endl; + form = pNTSC; + break; + case 6: + cerr << "FRAMERATE: 50" << endl; + form = pPAL; + break; + case 7: + cerr << "FRAMERATE: 59.94" << endl; + form = pNTSC; + break; + case 8: + cerr << "FRAMERATE: 60" << endl; + form = pNTSC; + break; + } + + int mpeg = 0; + found = 0; + while (!stream.eof() && !found) { + p = stream.tellg(); + stream.read((char *)headr,4); + if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01) + if ( headr[3] == 0xB5 ){ + char *profile[] = {"reserved", "High", "Spatially Scalable", + "SNR Scalable", "Main", "Simple", "undef", + "undef"}; + char *level[] = {"res", "res", "res", "res", + "High","res", "High 1440", "res", + "Main","res", "Low", "res", + "res", "res", "res", "res"}; + char *chroma[] = {"res", "4:2:0", "4:2:2", "4:4:4:"}; + mpeg = 2; + stream.read((char *)headr,4); + cerr << "PROFILE: " << profile[headr[0] & 0x7] << endl; + cerr << "LEVEL: " << level[headr[1]>>4 & 0xF] << endl; + cerr << "CHROMA: " << chroma[headr[1]>>1 & 0x3] << endl; + found = 1; + } else { + mpeg = 1; + found = 1; + } + if (! found) stream.seekg(p+streampos(1)); + } + + stream.seekg(q); + return (form | mpeg << 4); +} + + + +int stream_type(istream &fin){ + uint8_t headr[4]; + streampos p=fin.tellg(); + + TS_Packet ts; + fin >> ts; + fin.read((char *)headr,1); + fin.seekg(p); + if(fin && headr[0] == 0x47){ + return TS_STREAM; + } + + PS_Packet ps; + fin >> ps; + PES_Packet pes; + for(int j=0;j < ps.NPES();j++){ + fin >> pes; + } + fin.read((char *)headr,4); + fin.seekg(p); + if (fin && headr[0] == 0x00 && headr[1] == 0x00 + && headr[2] == 0x01 && headr[3] == 0xBA){ + return PS_STREAM; + } + + fin >> pes; + fin.read((char *)!headr,4); + fin.seekg(p); + if (fin && headr[0] == 0x00 && headr[1] == 0x00 + && headr[2] == 0x01 ){ + int found = 0; + switch ( headr[3] ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + found = 1; + break; + } + if (found){ + return PES_STREAM; + } + } + + + + return -1; +} + + +void analyze(istream &fin) +{ + PS_Packet ps; + PES_Packet pes; + int fc = 0; + char *frames[3] = {"I-Frame","P-Frame","B-Frame"}; + + while(fin){ + uint32_t pts; + fin >> ps; + cerr << "SCR base: " << hex << setw(5) + << setfill('0') \ + << ps.SCR_base() << " " << dec + << "ext : " << ps.SCR_ext(); + + cerr << " MUX rate: " << ps.MUX()*50*8/1000000.0 + << " Mbit/s "; + cerr << "RATE bound: " << ps.Rate()*50*8/1000000.0 + << " Mbit/s" << endl; + cerr << " Audio bound: " + << hex << "0x" + << int(ps.P()->audio_bound); + cerr << " Video bound: " << hex << "0x" + << int(ps.P()->video_bound) + << dec + << endl; + cerr << endl; + + for (int i=0; i < ps.NPES(); i++){ + pes.init(); + fin >> pes; + pts2pts((uint8_t *)&pts,pes.PTS()); + pes.Info() = 1; + cerr << pes; + + uint8_t *buf = pes.P()->pes_pckt_data; + int c = 0; + int l; + switch (pes.P()->stream_id){ + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + l=pes.P()->length; + break; + default: + l = 0; + break; + } + while ( c < l - 6){ + if (buf[c] == 0x00 && + buf[c+1] == 0x00 && + buf[c+2] == 0x01 && + buf[c+3] == 0xB8) { + c += 4; + cerr << "TIME hours: " + << int((buf[c]>>2)& 0x1F) + << " minutes: " + << int(((buf[c]<<4)& 0x30)| + ((buf[c+1]>>4)& 0x0F)) + << " seconds: " + << int(((buf[c+1]<<3)& 0x38)| + ((buf[c+2]>>5)& 0x0F)) + << endl; + } + + if ( buf[c] == 0x00 && + buf[c+1] == 0x00 && + buf[c+2] == 0x01 && + buf[c+3] == 0x00) { + fc++; + c += 4; + cerr << "picture: " + << fc + << " (" + << frames[((buf[c+1]&0x38) >>3)-1] + << ")" << endl << endl; + } else c++; + } + } + } +} + + diff --git a/libdvbmpeg/cpptools.hh b/libdvbmpeg/cpptools.hh new file mode 100644 index 0000000..49ea5de --- /dev/null +++ b/libdvbmpeg/cpptools.hh @@ -0,0 +1,330 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002 Marcus Metzler + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at mocm@metzlerbros.de, + */ + +#include +#include +#include +#include +using namespace std; + + +#ifndef _CPPTOOLS_HH_ +#define _CPPTOOLS_HH_ + +#include "ctools.h" + + +class PES_Packet{ + int info; + pes_packet p; +public: + PES_Packet(){ + info = 0; + init_pes(&p); + } + + ~PES_Packet(){ + if (p.pack_header) + delete [] p.pack_header; + if (p.pes_ext) + delete [] p.pes_ext; + if (p.pes_pckt_data) + delete [] p.pes_pckt_data; + if (p.mpeg1_headr) + delete [] p.mpeg1_headr; + } + + inline void init(){ + if (p.pack_header) + delete [] p.pack_header; + if (p.pes_ext) + delete [] p.pes_ext; + if (p.pes_pckt_data) + delete [] p.pes_pckt_data; + if (p.mpeg1_headr) + delete [] p.mpeg1_headr; + + info = 0; + init_pes(&p); + } + + inline pes_packet *P(){ + return &p; + } + + inline void setlength(){ + setlength_pes(&p); + if (p.length) + p.pes_pckt_data = new uint8_t[p.length]; + } + + inline void Nlength(){ + nlength_pes(&p); + p.pes_pckt_data = new uint8_t[p.length]; + } + + + inline uint8_t &Stream_ID(){ + return p.stream_id; + } + + inline uint8_t &Flags1(){ + return p.flags1; + } + + inline uint8_t &Flags2(){ + return p.flags2; + } + + inline uint32_t &Length(){ + return p.length; + } + + inline uint8_t &HLength(){ + return p.pes_hlength; + } + + inline uint8_t &Stuffing(){ + return p.stuffing; + } + + inline uint8_t *Data(){ + return p.pes_pckt_data; + } + + inline int has_pts(){ + return (p.flags2 & PTS_DTS); + } + + inline int &MPEG(){ + return p.mpeg; + } + inline uint8_t *PTS(){ + return p.pts; + } + + inline uint8_t *DTS(){ + return p.dts; + } + + inline int &Info(){ + return info; + } + + + + inline uint8_t high_pts(){ + if (has_pts()) + return ((p.pts[0] & 0x08)>>3); + else + return 0; + } + + inline uint8_t high_dts(){ + return ((p.dts[0] & 0x08)>>3); + } + + inline int WDTS(){ + int w_dts; + w_dts = (int)trans_pts_dts(p.dts); + return w_dts; + } + + inline int WPTS(){ + int w_dts; + w_dts = (int)trans_pts_dts(p.pts); + return w_dts; + } + + friend ostream & operator << (ostream & stream, PES_Packet & x); + friend istream & operator >> (istream & stream, PES_Packet & x); + +}; + + +class TS_Packet{ + ts_packet p; + int info; + +public: + TS_Packet(){ + init_ts(&p); + info = 0; + } + + ~TS_Packet(){ + if (p.priv_dat) + delete [] p.priv_dat; + } + + inline void init(){ + if (p.priv_dat) + delete [] p.priv_dat; + + init_ts(&p); + info = 0; + } + + inline ts_packet *P(){ + return &p; + } + + inline int &Rest(){ + return p.rest; + } + + inline uint8_t *Data(){ + return p.data; + } + + inline short PID(){ + return pid_ts(&p); + } + + inline uint8_t FLAG1(){ + return (p.pid[0] & ~PID_MASK_HI); + } + + inline int &Info(){ + return info; + } + + friend ostream & operator << (ostream & stream, TS_Packet & x); + friend istream & operator >> (istream & stream, TS_Packet & x); +}; + + +class PS_Packet{ + int info; + ps_packet p; +public: + + PS_Packet(){ + init_ps(&p); + info = 0; + } + + ~PS_Packet(){ + if (p.data) + delete [] p.data; + } + + inline void init(){ + if (p.data) + delete [] p.data; + + init_ps(&p); + info = 0; + } + + inline ps_packet *P(){ + return &p; + } + + inline int MUX(){ + return mux_ps(&p); + } + + inline int Rate(){ + return rate_ps(&p); + } + + inline void setlength(){ + setlength_ps(&p); + p.data = new uint8_t[p.sheader_length]; + } + + inline int Stuffing(){ + return p.stuff_length & PACK_STUFF_MASK; + } + + inline int NPES(){ + return p.npes; + } + + inline int &MPEG(){ + return p.mpeg; + } + + inline uint8_t &operator()(int l){ + return p.data[l]; + } + + inline char * Data() { + return (char *)p.data+p.stuff_length; + } + + inline int &SLENGTH(){ + return p.sheader_length; + } + + inline int &Info(){ + return info; + } + + uint32_t SCR_base(){ + return scr_base_ps(&p); + } + + uint16_t SCR_ext(){ + return scr_ext_ps(&p); + } + + friend ostream & operator << (ostream & stream, PS_Packet & x); + friend istream & operator >> (istream & stream, PS_Packet & x); +}; + + +typedef void (* FILTER)(istream &in, ostream &out); + +typedef struct thread_args_{ + FILTER function; + int *fd; + int in; + int out; +} thread_args; + + +void extract_audio_from_PES(istream &in, ostream &out); +void extract_video_from_PES(istream &in, ostream &out); +void extract_es_audio_from_PES(istream &in, ostream &out); +void extract_es_video_from_PES(istream &in, ostream &out); +int TS_PIDS(istream &in, ostream &out); +int ifilter (istream &in, FILTER function); +int ofilter (istream &in, FILTER function); +int itfilter (int in, FILTER function); +int otfilter (istream &in, FILTER function); +int stream_type(int fd); +int stream_type(istream &stream); +int tv_norm(istream &fin); + +void analyze(istream &fin); + + +#endif //_CPPTOOLS_HH_ + diff --git a/libdvbmpeg/ctools.c b/libdvbmpeg/ctools.c new file mode 100644 index 0000000..dfd1751 --- /dev/null +++ b/libdvbmpeg/ctools.c @@ -0,0 +1,2379 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002 Marcus Metzler + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at mocm@metzlerbros.de, + */ + +#include "ctools.h" + +#define MAX_SEARCH 1024 * 1024 + + +/* + + PES + +*/ + +ssize_t save_read(int fd, void *buf, size_t count) +{ + ssize_t neof = 1; + size_t re = 0; + + while(neof >= 0 && re < count){ + neof = read(fd, buf+re, count - re); + if (neof > 0) re += neof; + else break; + } + + if (neof < 0 && re == 0) return neof; + else return re; +} + +void init_pes(pes_packet *p){ + p->stream_id = 0; + p->llength[0] = 0; + p->llength[1] = 0; + p->length = 0; + p->flags1 = 0x80; + p->flags2 = 0; + p->pes_hlength = 0; + p->trick = 0; + p->add_cpy = 0; + p->priv_flags = 0; + p->pack_field_length = 0; + p->pack_header = (uint8_t *) NULL; + p->pck_sqnc_cntr = 0; + p->org_stuff_length = 0; + p->pes_ext_lngth = 0; + p->pes_ext = (uint8_t *) NULL; + p->pes_pckt_data = (uint8_t *) NULL; + p->padding = 0; + p->mpeg = 2; // DEFAULT MPEG2 + p->mpeg1_pad = 0; + p->mpeg1_headr = NULL; + p->stuffing = 0; +} + +void kill_pes(pes_packet *p){ + if (p->pack_header) + free(p->pack_header); + if (p->pes_ext) + free(p->pes_ext); + if (p->pes_pckt_data) + free(p->pes_pckt_data); + if (p->mpeg1_headr) + free(p->mpeg1_headr); + init_pes(p); +} + +void setlength_pes(pes_packet *p){ + short *ll; + ll = (short *) p->llength; + p->length = ntohs(*ll); +} + +static void setl_pes(pes_packet *p){ + setlength_pes(p); + if (p->length) + p->pes_pckt_data = (uint8_t *)malloc(p->length); +} + +void nlength_pes(pes_packet *p){ + if (p->length <= 0xFFFF){ + short *ll = (short *) p->llength; + short l = p->length; + *ll = htons(l); + } else { + p->llength[0] =0x00; + p->llength[1] =0x00; + } +} + +static void nl_pes(pes_packet *p) +{ + nlength_pes(p); + p->pes_pckt_data = (uint8_t *) malloc(p->length); +} + +void pts2pts(uint8_t *av_pts, uint8_t *pts) +{ + + av_pts[0] = ((pts[0] & 0x06) << 5) | + ((pts[1] & 0xFC) >> 2); + av_pts[1] = ((pts[1] & 0x03) << 6) | + ((pts[2] & 0xFC) >> 2); + av_pts[2] = ((pts[2] & 0x02) << 6) | + ((pts[3] & 0xFE) >> 1); + av_pts[3] = ((pts[3] & 0x01) << 7) | + ((pts[4] & 0xFE) >> 1); + +} + + +int cwrite_pes(uint8_t *buf, pes_packet *p, long length){ + int count,i; + uint8_t dummy; + int more = 0; + uint8_t headr[3] = { 0x00, 0x00 , 0x01}; + + if (length < p->length+p->pes_hlength){ + fprintf(stderr,"Wrong buffer size in cwrite_pes\n"); + exit(1); + } + + + memcpy(buf,headr,3); + count = 3; + buf[count] = p->stream_id; + count++; + + switch ( p->stream_id ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + buf[count] = p->llength[0]; + count++; + buf[count] = p->llength[1]; + count++; + memcpy(buf+count,p->pes_pckt_data,p->length); + count += p->length; + break; + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + buf[count] = p->llength[0]; + count++; + buf[count] = p->llength[1]; + count++; + more = 1; + break; + } + + + if ( more ) { + if ( p->mpeg == 2 ){ + memcpy(buf+count,&p->flags1,1); + count++; + memcpy(buf+count,&p->flags2,1); + count++; + memcpy(buf+count,&p->pes_hlength,1); + count++; + + if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ + memcpy(buf+count,p->pts,5); + count += 5; + } else + if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ + memcpy(buf+count,p->pts,5); + count += 5; + memcpy(buf+count,p->dts,5); + count += 5; + } + if (p->flags2 & ESCR_FLAG){ + memcpy(buf+count,p->escr,6); + count += 6; + } + if (p->flags2 & ES_RATE_FLAG){ + memcpy(buf+count,p->es_rate,3); + count += 3; + } + if (p->flags2 & DSM_TRICK_FLAG){ + memcpy(buf+count,&p->trick,1); + count++; + } + if (p->flags2 & ADD_CPY_FLAG){ + memcpy(buf+count,&p->add_cpy,1); + count++; + } + if (p->flags2 & PES_CRC_FLAG){ + memcpy(buf+count,p->prev_pes_crc,2); + count += 2; + } + if (p->flags2 & PES_EXT_FLAG){ + memcpy(buf+count,&p->priv_flags,1); + count++; + + if (p->priv_flags & PRIVATE_DATA){ + memcpy(buf+count,p->pes_priv_data,16); + count += 16; + } + if (p->priv_flags & HEADER_FIELD){ + memcpy(buf+count,&p->pack_field_length, + 1); + count++; + memcpy(buf+count,p->pack_header, + p->pack_field_length); + count += p->pack_field_length; + + } + + if ( p->priv_flags & PACK_SEQ_CTR){ + memcpy(buf+count,&p->pck_sqnc_cntr,1); + count++; + memcpy(buf+count,&p->org_stuff_length, + 1); + count++; + } + + if ( p->priv_flags & P_STD_BUFFER){ + memcpy(buf+count,p->p_std,2); + count += 2; + } + if ( p->priv_flags & PES_EXT_FLAG2){ + memcpy(buf+count,&p->pes_ext_lngth,1); + count++; + memcpy(buf+count,p->pes_ext, + p->pes_ext_lngth); + count += p->pes_ext_lngth; + } + } + dummy = 0xFF; + for (i=0;istuffing;i++) { + memcpy(buf+count,&dummy,1); + count++; + } + } else { + if (p->mpeg1_pad){ + memcpy(buf+count,p->mpeg1_headr,p->mpeg1_pad); + count += p->mpeg1_pad; + } + if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ + memcpy(buf+count,p->pts,5); + count += 5; + } + else if ((p->flags2 & PTS_DTS_FLAGS) == + PTS_DTS){ + memcpy(buf+count,p->pts,5); + count += 5; + memcpy(buf+count,p->dts,5); + count += 5; + } + } + memcpy(buf+count,p->pes_pckt_data,p->length); + count += p->length; + } + + return count; + +} + +void write_pes(int fd, pes_packet *p){ + long length; + uint8_t *buf; + int l = p->length+p->pes_hlength; + + buf = (uint8_t *) malloc(l); + length = cwrite_pes(buf,p,l); + write(fd,buf,length); + free(buf); +} + +static unsigned int find_length(int f){ + uint64_t p = 0; + uint64_t start = 0; + uint64_t q = 0; + int found = 0; + uint8_t sync4[4]; + int neof = 1; + + start = lseek(f,0,SEEK_CUR); + start -=2; + lseek(f,start,SEEK_SET); + while ( neof > 0 && !found ){ + p = lseek(f,0,SEEK_CUR); + neof = save_read(f,&sync4,4); + if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { + switch ( sync4[3] ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + found = 1; + break; + default: + q = lseek(f,0,SEEK_CUR); + break; + } + } + } + q = lseek(f,0,SEEK_CUR); + lseek(f,start+2,SEEK_SET); + if (found) return (unsigned int)(q-start)-4-2; + else return (unsigned int)(q-start-2); + +} + + +void cread_pes(char *buf, pes_packet *p){ + + uint8_t count, dummy, check; + int i; + uint64_t po = 0; + int c=0; + + switch ( p->stream_id ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + memcpy(p->pes_pckt_data,buf+c,p->length); + return; + break; + case PADDING_STREAM : + p->padding = p->length; + memcpy(p->pes_pckt_data,buf+c,p->length); + return; + break; + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + break; + default: + return; + break; + } + + po = c; + memcpy(&p->flags1,buf+c,1); + c++; + if ( (p->flags1 & 0xC0) == 0x80 ) p->mpeg = 2; + else p->mpeg = 1; + + if ( p->mpeg == 2 ){ + memcpy(&p->flags2,buf+c,1); + c++; + memcpy(&p->pes_hlength,buf+c,1); + c++; + + p->length -=p->pes_hlength+3; + count = p->pes_hlength; + + if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ + memcpy(p->pts,buf+c,5); + c += 5; + count -=5; + } else + if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ + memcpy(p->pts,buf+c,5); + c += 5; + memcpy(p->dts,buf+c,5); + c += 5; + count -= 10; + } + + if (p->flags2 & ESCR_FLAG){ + memcpy(p->escr,buf+c,6); + c += 6; + count -= 6; + } + + if (p->flags2 & ES_RATE_FLAG){ + memcpy(p->es_rate,buf+c,3); + c += 3; + count -= 3; + } + + if (p->flags2 & DSM_TRICK_FLAG){ + memcpy(&p->trick,buf+c,1); + c += 1; + count -= 1; + } + + if (p->flags2 & ADD_CPY_FLAG){ + memcpy(&p->add_cpy,buf+c,1); + c++; + count -= 1; + } + + if (p->flags2 & PES_CRC_FLAG){ + memcpy(p->prev_pes_crc,buf+c,2); + c += 2; + count -= 2; + } + + if (p->flags2 & PES_EXT_FLAG){ + memcpy(&p->priv_flags,buf+c,1); + c++; + count -= 1; + + if (p->priv_flags & PRIVATE_DATA){ + memcpy(p->pes_priv_data,buf+c,16); + c += 16; + count -= 16; + } + + if (p->priv_flags & HEADER_FIELD){ + memcpy(&p->pack_field_length,buf+c,1); + c++; + p->pack_header = (uint8_t *) + malloc(p->pack_field_length); + memcpy(p->pack_header,buf+c, + p->pack_field_length); + c += p->pack_field_length; + count -= 1+p->pack_field_length; + } + + if ( p->priv_flags & PACK_SEQ_CTR){ + memcpy(&p->pck_sqnc_cntr,buf+c,1); + c++; + memcpy(&p->org_stuff_length,buf+c,1); + c++; + count -= 2; + } + + if ( p->priv_flags & P_STD_BUFFER){ + memcpy(p->p_std,buf+c,2); + c += 2; + count -= 2; + } + + if ( p->priv_flags & PES_EXT_FLAG2){ + memcpy(&p->pes_ext_lngth,buf+c,1); + c++; + p->pes_ext = (uint8_t *) + malloc(p->pes_ext_lngth); + memcpy(p->pes_ext,buf+c, + p->pes_ext_lngth); + c += p->pes_ext_lngth; + count -= 1+p->pes_ext_lngth; + } + } + p->stuffing = count; + for(i = 0; i< count ;i++){ + memcpy(&dummy,buf+c,1); + c++; + } + } else { + p->mpeg1_pad = 1; + check = p->flags1; + while (check == 0xFF){ + memcpy(&check,buf+c,1); + c++; + p->mpeg1_pad++; + } + + if ( (check & 0xC0) == 0x40){ + memcpy(&check,buf+c,1); + c++; + p->mpeg1_pad++; + memcpy(&check,buf+c,1); + c++; + p->mpeg1_pad++; + } + p->flags2 = 0; + p->length -= p->mpeg1_pad; + + c = po; + if ( (check & 0x30)){ + p->length ++; + p->mpeg1_pad --; + + if (check == p->flags1){ + p->pes_hlength = 0; + } else { + p->mpeg1_headr = (uint8_t *) + malloc(p->mpeg1_pad); + p->pes_hlength = p->mpeg1_pad; + memcpy(p->mpeg1_headr,buf+c, + p->mpeg1_pad); + c += p->mpeg1_pad; + } + + p->flags2 = (check & 0xF0) << 2; + if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ + memcpy(p->pts,buf+c,5); + c += 5; + p->length -= 5; + p->pes_hlength += 5; + } + else if ((p->flags2 & PTS_DTS_FLAGS) == + PTS_DTS){ + memcpy(p->pts,buf+c,5); + c += 5; + memcpy(p->dts,buf+c,5); + c += 5; + p->length -= 10; + p->pes_hlength += 10; + } + } else { + p->mpeg1_headr = (uint8_t *) malloc(p->mpeg1_pad); + p->pes_hlength = p->mpeg1_pad; + memcpy(p->mpeg1_headr,buf+c, + p->mpeg1_pad); + c += p->mpeg1_pad; + } + } + memcpy(p->pes_pckt_data,buf+c,p->length); +} + + +int read_pes(int f, pes_packet *p){ + + uint8_t sync4[4]; + int found=0; + uint64_t po = 0; + int neof = 1; + uint8_t *buf; + + while (neof > 0 && !found) { + po = lseek(f,0,SEEK_CUR); + if (po < 0) return -1; + if ((neof = save_read(f,&sync4,4)) < 4) return -1; + if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { + p->stream_id = sync4[3]; + switch ( sync4[3] ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + if((neof = save_read(f,p->llength,2)) < 2) + return -1; + setl_pes(p); + if (!p->length){ + p->length = find_length(f); + nl_pes(p); + } + found = 1; + break; + + default: + if (lseek(f,po+1,SEEK_SET) < po+1) return -1; + break; + } + } else if(lseek(f,po+1,SEEK_SET) < po+1) return -1; + } + + if (!found || !p->length) return 0; + + if (p->length >0){ + buf = (uint8_t *) malloc(p->length); + if((neof = save_read(f,buf,p->length))< p->length) return -1; + cread_pes((char *)buf,p); + free(buf); + } else return 0; + + return neof; +} + +/* + + Transport Stream + +*/ + +void init_ts(ts_packet *p){ + p->pid[0] = 0; + p->pid[1] = 0; + p->flags = 0; + p->count = 0; + p->adapt_length = 0; + p->adapt_flags = 0; + p->splice_count = 0; + p->priv_dat_len = 0; + p->priv_dat = NULL; + p->adapt_ext_len = 0; + p->adapt_eflags = 0; + p->rest = 0; + p->stuffing = 0; +} + +void kill_ts(ts_packet *p){ + if (p->priv_dat) + free(p->priv_dat); + init_ts(p); +} + + + +unsigned short pid_ts(ts_packet *p) +{ + return get_pid(p->pid); +} + +int cwrite_ts(uint8_t *buf, ts_packet *p, long length){ + long count,i; + uint8_t sync,dummy; + + sync = 0x47; + memcpy(buf,&sync,1); + count = 1; + memcpy(buf+count,p->pid,2); + count += 2; + memcpy(buf+count,&p->flags,1); + count++; + + + if (! (p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ + memcpy(buf+count,p->data,184); + count += 184; + } else { + memcpy(buf+count,&p->adapt_length,1); + count++; + memcpy(buf+count,&p->adapt_flags,1); + count++; + + if ( p->adapt_flags & PCR_FLAG ){ + memcpy(buf+count, p->pcr,6); + count += 6; + } + if ( p->adapt_flags & OPCR_FLAG ){ + memcpy(buf+count, p->opcr,6); + count += 6; + } + if ( p->adapt_flags & SPLICE_FLAG ){ + memcpy(buf+count, &p->splice_count,1); + count++; + } + if( p->adapt_flags & TRANS_PRIV){ + memcpy(buf+count,&p->priv_dat_len,1); + count++; + memcpy(buf+count,p->priv_dat,p->priv_dat_len); + count += p->priv_dat_len; + } + + if( p->adapt_flags & ADAP_EXT_FLAG){ + memcpy(buf+count,&p->adapt_ext_len,1); + count++; + memcpy(buf+count,&p->adapt_eflags,1); + count++; + + if( p->adapt_eflags & LTW_FLAG){ + memcpy(buf+count,p->ltw,2); + count += 2; + } + if( p->adapt_eflags & PIECE_RATE){ + memcpy(buf+count,p->piece_rate,3); + count += 3; + } + if( p->adapt_eflags & SEAM_SPLICE){ + memcpy(buf+count,p->dts,5); + count += 5; + } + } + dummy = 0xFF; + for(i=0; i < p->stuffing ; i++){ + memcpy(buf+count,&dummy,1); + count++; + } + if (p->flags & PAYLOAD){ + memcpy(buf+count,p->data,p->rest); + count += p->rest; + } + } + + + return count; +} + +void write_ts(int fd, ts_packet *p){ + long length; + uint8_t buf[TS_SIZE]; + + length = cwrite_ts(buf,p,TS_SIZE); + write(fd,buf,length); +} + +int read_ts (int f, ts_packet *p){ + uint8_t sync; + int found=0; + uint64_t po,q; + int neof = 1; + + sync=0; + while (neof > 0 && !found) { + neof = save_read(f,&sync,1); + if (sync == 0x47) + found = 1; + } + neof = save_read(f,p->pid,2); + neof = save_read(f,&p->flags,1); + p->count = p->flags & COUNT_MASK; + + if (!(p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ + //no adapt. field only payload + neof = save_read(f,p->data,184); + p->rest = 184; + return neof; + } + + if ( p->flags & ADAPT_FIELD ) { + // adaption field + neof = save_read(f,&p->adapt_length,1); + po = lseek(f,0,SEEK_CUR); + neof = save_read(f,&p->adapt_flags,1); + + if ( p->adapt_flags & PCR_FLAG ) + neof = save_read(f, p->pcr,6); + + if ( p->adapt_flags & OPCR_FLAG ) + neof = save_read(f, p->opcr,6); + + if ( p->adapt_flags & SPLICE_FLAG ) + neof = save_read(f, &p->splice_count,1); + + if( p->adapt_flags & TRANS_PRIV){ + neof = save_read(f,&p->priv_dat_len,1); + p->priv_dat = (uint8_t *) malloc(p->priv_dat_len); + neof = save_read(f,p->priv_dat,p->priv_dat_len); + } + + if( p->adapt_flags & ADAP_EXT_FLAG){ + neof = save_read(f,&p->adapt_ext_len,1); + neof = save_read(f,&p->adapt_eflags,1); + if( p->adapt_eflags & LTW_FLAG) + neof = save_read(f,p->ltw,2); + + if( p->adapt_eflags & PIECE_RATE) + neof = save_read(f,p->piece_rate,3); + + if( p->adapt_eflags & SEAM_SPLICE) + neof = save_read(f,p->dts,5); + } + q = lseek(f,0,SEEK_CUR); + p->stuffing = p->adapt_length -(q-po); + p->rest = 183-p->adapt_length; + lseek(f,q+p->stuffing,SEEK_SET); + if (p->flags & PAYLOAD) // payload + neof = save_read(f,p->data,p->rest); + else + lseek(f,q+p->rest,SEEK_SET); + } + return neof; +} + +void cread_ts (char *buf, ts_packet *p, long length){ + uint8_t sync; + int found=0; + uint64_t po,q; + long count=0; + + sync=0; + while (count < length && !found) { + sync=buf[count]; + count++; + if (sync == 0x47) + found = 1; + } + memcpy(p->pid,buf+count,2); + count += 2; + p->flags = buf[count]; + count++; + p->count = p->flags & COUNT_MASK; + + if (!(p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ + //no adapt. field only payload + memcpy(p->data,buf+count,184); + p->rest = 184; + return; + } + + if ( p->flags & ADAPT_FIELD ) { + // adaption field + p->adapt_length = buf[count]; + count++; + po = count; + memcpy(&p->adapt_flags,buf+count,1); + count++; + + if ( p->adapt_flags & PCR_FLAG ){ + memcpy( p->pcr,buf+count,6); + count += 6; + } + if ( p->adapt_flags & OPCR_FLAG ){ + memcpy( p->opcr,buf+count,6); + count += 6; + } + if ( p->adapt_flags & SPLICE_FLAG ){ + memcpy( &p->splice_count,buf+count,1); + count++; + } + if( p->adapt_flags & TRANS_PRIV){ + memcpy(&p->priv_dat_len,buf+count,1); + count++; + p->priv_dat = (uint8_t *) malloc(p->priv_dat_len); + memcpy(p->priv_dat,buf+count,p->priv_dat_len); + count += p->priv_dat_len; + } + + if( p->adapt_flags & ADAP_EXT_FLAG){ + memcpy(&p->adapt_ext_len,buf+count,1); + count++; + memcpy(&p->adapt_eflags,buf+count,1); + count++; + if( p->adapt_eflags & LTW_FLAG){ + memcpy(p->ltw,buf+count,2); + count += 2; + } + if( p->adapt_eflags & PIECE_RATE){ + memcpy(p->piece_rate,buf+count,3); + count += 3; + } + if( p->adapt_eflags & SEAM_SPLICE){ + memcpy(p->dts,buf+count,5); + count += 5; + } + } + q = count; + p->stuffing = p->adapt_length -(q-po); + p->rest = 183-p->adapt_length; + count = q+p->stuffing; + if (p->flags & PAYLOAD){ // payload + memcpy(p->data,buf+count,p->rest); + count += p->rest; + } else + count = q+p->rest; + } +} + + +/* + + Program Stream + +*/ + + +void init_ps(ps_packet *p) +{ + p->stuff_length=0xF8; + p->data = NULL; + p->sheader_length = 0; + p->audio_bound = 0; + p->video_bound = 0; + p->npes = 0; + p->mpeg = 2; +} + +void kill_ps(ps_packet *p) +{ + if (p->data) + free(p->data); + init_ps(p); +} + +void setlength_ps(ps_packet *p) +{ + short *ll; + ll = (short *) p->sheader_llength; + if (p->mpeg == 2) + p->sheader_length = ntohs(*ll) - 6; + else + p->sheader_length = ntohs(*ll); +} + +static void setl_ps(ps_packet *p) +{ + setlength_ps(p); + p->data = (uint8_t *) malloc(p->sheader_length); +} + +int mux_ps(ps_packet *p) +{ + uint32_t mux = 0; + uint8_t *i = (uint8_t *)&mux; + + i[1] = p->mux_rate[0]; + i[2] = p->mux_rate[1]; + i[3] = p->mux_rate[2]; + mux = ntohl(mux); + mux = (mux >>2); + return mux; +} + +int rate_ps(ps_packet *p) +{ + uint32_t rate=0; + uint8_t *i= (uint8_t *) &rate; + + i[1] = p->rate_bound[0] & 0x7F; + i[2] = p->rate_bound[1]; + i[3] = p->rate_bound[2]; + + rate = ntohl(rate); + rate = (rate >> 1); + return rate; +} + + +uint32_t scr_base_ps(ps_packet *p) // only 32 bit!! +{ + uint32_t base = 0; + uint8_t *buf = (uint8_t *)&base; + + buf[0] |= (long int)((p->scr[0] & 0x18) << 3); + buf[0] |= (long int)((p->scr[0] & 0x03) << 4); + buf[0] |= (long int)((p->scr[1] & 0xF0) >> 4); + + buf[1] |= (long int)((p->scr[1] & 0x0F) << 4); + buf[1] |= (long int)((p->scr[2] & 0xF0) >> 4); + + buf[2] |= (long int)((p->scr[2] & 0x08) << 4); + buf[2] |= (long int)((p->scr[2] & 0x03) << 5); + buf[2] |= (long int)((p->scr[3] & 0xF8) >> 3); + + buf[3] |= (long int)((p->scr[3] & 0x07) << 5); + buf[3] |= (long int)((p->scr[4] & 0xF8) >> 3); + + base = ntohl(base); + return base; +} + +uint16_t scr_ext_ps(ps_packet *p) +{ + short ext = 0; + + ext = (short)(p->scr[5] >> 1); + ext += (short) (p->scr[4] & 0x03) * 128; + + return ext; +} + +int cwrite_ps(uint8_t *buf, ps_packet *p, long length) +{ + long count,i; + uint8_t headr1[4] = {0x00, 0x00, 0x01, 0xBA }; + uint8_t headr2[4] = {0x00, 0x00, 0x01, 0xBB }; + uint8_t buffy = 0xFF; + + + memcpy(buf,headr1,4); + count = 4; + if (p->mpeg == 2){ + memcpy(buf+count,p->scr,6); + count += 6; + memcpy(buf+count,p->mux_rate,3); + count += 3; + memcpy(buf+count,&p->stuff_length,1); + count++; + for(i=0; i< (p->stuff_length & 3); i++){ + memcpy(buf+count,&buffy,1); + count++; + } + } else { + memcpy(buf+count,p->scr,5); + count += 5; + memcpy(buf+count,p->mux_rate,3); + count += 3; + } + if (p->sheader_length){ + memcpy(buf+count,headr2,4); + count += 4; + memcpy(buf+count,p->sheader_llength,2); + count += 2; + if ( p->mpeg == 2){ + memcpy(buf+count,p->rate_bound,3); + count += 3; + memcpy(buf+count,&p->audio_bound,1); + count++; + memcpy(buf+count,&p->video_bound,1); + count++; + memcpy(buf+count,&p->reserved,1); + count++; + } + memcpy(buf+count,p->data,p->sheader_length); + count += p->sheader_length; + } + + return count; +} + +void write_ps(int fd, ps_packet *p){ + long length; + uint8_t buf[PS_MAX]; + + length = cwrite_ps(buf,p,PS_MAX); + write(fd,buf,length); +} + +int read_ps (int f, ps_packet *p){ + uint8_t headr[4]; + pes_packet pes; + int i,done; + int found=0; + uint64_t po = 0; + uint64_t q = 0; + long count = 0; + int neof = 1; + + po = lseek(f,0,SEEK_CUR); + while (neof > 0 && !found && count < MAX_SEARCH) { + neof = save_read(f,&headr,4); + if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01){ + if ( headr[3] == 0xBA ) + found = 1; + else + if ( headr[3] == 0xB9 ) break; + else lseek(f,po+1,SEEK_SET); + } + count++; + } + + if (found){ + neof = save_read(f,p->scr,6); + if (p->scr[0] & 0x40) + p->mpeg = 2; + else + p->mpeg = 1; + + if (p->mpeg == 2){ + neof = save_read(f,p->mux_rate,3); + neof = save_read(f,&p->stuff_length,1); + po = lseek(f,0,SEEK_CUR); + lseek(f,po+(p->stuff_length & 3),SEEK_SET); + } else { + p->mux_rate[0] = p->scr[5]; //mpeg1 scr is only 5 bytes + neof = save_read(f,p->mux_rate+1,2); + } + + po = lseek(f,0,SEEK_CUR); + neof = save_read(f,headr,4); + if (headr[0] == 0x00 && headr[1] == 0x00 && + headr[2] == 0x01 && headr[3] == 0xBB ) { + neof = save_read(f,p->sheader_llength,2); + setl_ps(p); + if (p->mpeg == 2){ + neof = save_read(f,p->rate_bound,3); + neof = save_read(f,&p->audio_bound,1); + neof = save_read(f,&p->video_bound,1); + neof = save_read(f,&p->reserved,1); + } + neof = save_read(f,p->data,p->sheader_length); + } else { + lseek(f,po,SEEK_SET); + p->sheader_length = 0; + } + + i = 0; + done = 0; + q = lseek(f,0,SEEK_CUR); + do { + po = lseek(f,0,SEEK_CUR); + neof = save_read(f,headr,4); + lseek(f,po,SEEK_SET); + if ( headr[0] == 0x00 && headr[1] == 0x00 + && headr[2] == 0x01 && headr[3] != 0xBA){ + init_pes(&pes); + neof = read_pes(f,&pes); + i++; + } else done = 1; + kill_pes(&pes); + } while ( neof > 0 && !done); + p->npes = i; + lseek(f,q,SEEK_SET); + } + return neof; +} + +void cread_ps (char *buf, ps_packet *p, long length){ + uint8_t *headr; + pes_packet pes; + int i,done; + int found=0; + uint64_t po = 0; + uint64_t q = 0; + long count = 0; + long c = 0; + + po = c; + while ( count < length && !found && count < MAX_SEARCH) { + headr = (uint8_t *)buf+c; + c += 4; + if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01){ + if ( headr[3] == 0xBA ) + found = 1; + else + if ( headr[3] == 0xB9 ) break; + else c = po+1; + } + count++; + } + + if (found){ + memcpy(p->scr,buf+c,6); + c += 6; + if (p->scr[0] & 0x40) + p->mpeg = 2; + else + p->mpeg = 1; + + if (p->mpeg == 2){ + memcpy(p->mux_rate,buf+c,3); + c += 3; + memcpy(&p->stuff_length,buf+c,1); + c++; + po = c; + c = po+(p->stuff_length & 3); + } else { + p->mux_rate[0] = p->scr[5]; //mpeg1 scr is only 5 bytes + memcpy(p->mux_rate+1,buf+c,2); + c += 2; + } + + po = c; + headr = (uint8_t *)buf+c; + c += 4; + if (headr[0] == 0x00 && headr[1] == 0x00 && + headr[2] == 0x01 && headr[3] == 0xBB ) { + memcpy(p->sheader_llength,buf+c,2); + c += 2; + setl_ps(p); + if (p->mpeg == 2){ + memcpy(p->rate_bound,buf+c,3); + c += 3; + memcpy(&p->audio_bound,buf+c,1); + c++; + memcpy(&p->video_bound,buf+c,1); + c++; + memcpy(&p->reserved,buf+c,1); + c++; + } + memcpy(p->data,buf+c,p->sheader_length); + c += p->sheader_length; + } else { + c = po; + p->sheader_length = 0; + } + + i = 0; + done = 0; + q = c; + do { + headr = (uint8_t *)buf+c; + if ( headr[0] == 0x00 && headr[1] == 0x00 + && headr[2] == 0x01 && headr[3] != 0xBA){ + init_pes(&pes); + // cread_pes(buf+c,&pes); + i++; + } else done = 1; + kill_pes(&pes); + } while (c < length && !done); + p->npes = i; + c = q; + } +} + + + + + + + +/* + conversion +*/ + +void init_trans(trans *p) +{ + int i; + + p->found = 0; + p->pes = 0; + p->is_full = 0; + p->pes_start = 0; + p->pes_started = 0; + p->set = 0; + + for (i = 0; i < MASKL*MAXFILT ; i++){ + p->mask[i] = 0; + p->filt[i] = 0; + } + for (i = 0; i < MAXFILT ; i++){ + p->sec[i].found = 0; + p->sec[i].length = 0; + } +} + +int set_trans_filt(trans *p, int filtn, uint16_t pid, uint8_t *mask, uint8_t *filt, int pes) +{ + int i; + int off; + + if ( filtn > MAXFILT-1 || filtn<0 ) return -1; + p->pid[filtn] = pid; + if (pes) p->pes |= (tflags)(1 << filtn); + else { + off = MASKL*filtn; + p->pes &= ~((tflags) (1 << filtn) ); + for (i = 0; i < MASKL ; i++){ + p->mask[off+i] = mask[i]; + p->filt[off+i] = filt[i]; + } + } + p->set |= (tflags) (1 << filtn); + return 0; +} + +void clear_trans_filt(trans *p,int filtn) +{ + int i; + + p->set &= ~((tflags) (1 << filtn) ); + p->pes &= ~((tflags) (1 << filtn) ); + p->is_full &= ~((tflags) (1 << filtn) ); + p->pes_start &= ~((tflags) (1 << filtn) ); + p->pes_started &= ~((tflags) (1 << filtn) ); + + for (i = MASKL*filtn; i < MASKL*(filtn+1) ; i++){ + p->mask[i] = 0; + p->filt[i] = 0; + } + p->sec[filtn].found = 0; + p->sec[filtn].length = 0; +} + +int filt_is_set(trans *p, int filtn) +{ + if (p->set & ((tflags)(1 << filtn))) return 1; + return 0; +} + +int pes_is_set(trans *p, int filtn) +{ + if (p->pes & ((tflags)(1 << filtn))) return 1; + return 0; +} + +int pes_is_started(trans *p, int filtn) +{ + if (p->pes_started & ((tflags)(1 << filtn))) return 1; + return 0; +} + +int pes_is_start(trans *p, int filtn) +{ + if (p->pes_start & ((tflags)(1 << filtn))) return 1; + return 0; +} + +int filt_is_ready(trans *p,int filtn) +{ + if (p->is_full & ((tflags)(1 << filtn))) return 1; + return 0; +} + +void trans_filt(uint8_t *buf, int count, trans *p) +{ + int c=0; + //fprintf(stderr,"trans_filt\n"); + + + while (c < count && p->found <1 ){ + if ( buf[c] == 0x47) p->found = 1; + c++; + p->packet[0] = 0x47; + } + if (c == count) return; + + while( c < count && p->found < 188 && p->found > 0 ){ + p->packet[p->found] = buf[c]; + c++; + p->found++; + } + if (p->found == 188){ + p->found = 0; + tfilter(p); + } + + if (c < count) trans_filt(buf+c,count-c,p); +} + + +void tfilter(trans *p) +{ + int l,c; + int tpid; + uint8_t flag,flags; + uint8_t adapt_length = 0; + uint8_t cpid[2]; + + + // fprintf(stderr,"tfilter\n"); + + cpid[0] = p->packet[1]; + cpid[1] = p->packet[2]; + tpid = get_pid(cpid); + + if ( p->packet[1]&0x80){ + fprintf(stderr,"Error in TS for PID: %d\n", + tpid); + } + + flag = cpid[0]; + flags = p->packet[3]; + + if ( flags & ADAPT_FIELD ) { + // adaption field + adapt_length = p->packet[4]; + } + + c = 5 + adapt_length - (int)(!(flags & ADAPT_FIELD)); + if (flags & PAYLOAD){ + for ( l = 0; l < MAXFILT ; l++){ + if ( filt_is_set(p,l) ) { + if ( p->pid[l] == tpid) { + if ( pes_is_set(p,l) ){ + if (cpid[0] & PAY_START){ + p->pes_started |= + (tflags) + (1 << l); + p->pes_start |= + (tflags) + (1 << l); + } else { + p->pes_start &= ~ + ((tflags) + (1 << l)); + } + pes_filter(p,l,c); + } else { + sec_filter(p,l,c); + } + } + } + } + } +} + + +void pes_filter(trans *p, int filtn, int off) +{ + int count,c; + uint8_t *buf; + + if (filtn < 0 || filtn >= MAXFILT) return; + + count = 188 - off; + c = 188*filtn; + buf = p->packet+off; + if (pes_is_started(p,filtn)){ + p->is_full |= (tflags) (1 << filtn); + memcpy(p->transbuf+c,buf,count); + p->transcount[filtn] = count; + } +} + +section *get_filt_sec(trans *p, int filtn) +{ + section *sec; + + sec = &p->sec[filtn]; + p->is_full &= ~((tflags) (1 << filtn) ); + return sec; +} + +int get_filt_buf(trans *p, int filtn,uint8_t **buf) +{ + *buf = p->transbuf+188*filtn; + p->is_full &= ~((tflags) (1 << filtn) ); + return p->transcount[filtn]; +} + + + + +void sec_filter(trans *p, int filtn, int off) +{ + int i,j; + int error; + int count,c; + uint8_t *buf, *secbuf; + section *sec; + + // fprintf(stderr,"sec_filter\n"); + + if (filtn < 0 || filtn >= MAXFILT) return; + + count = 188 - off; + c = 0; + buf = p->packet+off; + sec = &p->sec[filtn]; + secbuf = sec->payload; + if(!filt_is_ready(p,filtn)){ + p->is_full &= ~((tflags) (1 << filtn) ); + sec->found = 0; + sec->length = 0; + } + + if ( !sec->found ){ + c = buf[c]+1; + if (c >= count) return; + sec->id = buf[c]; + secbuf[0] = buf[c]; + c++; + sec->found++; + sec->length = 0; + } + + while ( c < count && sec->found < 3){ + secbuf[sec->found] = buf[c]; + c++; + sec->found++; + } + if (c == count) return; + + if (!sec->length && sec->found == 3){ + sec->length |= ((secbuf[1] & 0x0F) << 8); + sec->length |= (secbuf[2] & 0xFF); + } + + while ( c < count && sec->found < sec->length+3){ + secbuf[sec->found] = buf[c]; + c++; + sec->found++; + } + + if ( sec->length && sec->found == sec->length+3 ){ + error=0; + for ( i = 0; i < MASKL; i++){ + if (i > 0 ) j=2+i; + else j = 0; + error += (sec->payload[j]&p->mask[MASKL*filtn+i])^ + (p->filt[MASKL*filtn+i]& + p->mask[MASKL*filtn+i]); + } + if (!error){ + p->is_full |= (tflags) (1 << filtn); + } + if (buf[0]+1 < c ) c=count; + } + + if ( c < count ) sec_filter(p, filtn, off); + +} + +#define MULT 1024 + + +void write_ps_headr( ps_packet *p, uint8_t *pts,int fd) +{ + long muxr = 37500; + uint8_t audio_bound = 1; + uint8_t fixed = 0; + uint8_t CSPS = 0; + uint8_t audio_lock = 1; + uint8_t video_lock = 1; + uint8_t video_bound = 1; + uint8_t stream1 = 0XC0; + uint8_t buffer1_scale = 1; + uint32_t buffer1_size = 32; + uint8_t stream2 = 0xE0; + uint8_t buffer2_scale = 1; + uint32_t buffer2_size = 230; + + init_ps(p); + + p->mpeg = 2; +// SCR = 0 + p->scr[0] = 0x44; + p->scr[1] = 0x00; + p->scr[2] = 0x04; + p->scr[3] = 0x00; + p->scr[4] = 0x04; + p->scr[5] = 0x01; + +// SCR = PTS + p->scr[0] = 0x44 | ((pts[0] >> 3)&0x18) | ((pts[0] >> 4)&0x03); + p->scr[1] = 0x00 | ((pts[0] << 4)&0xF0) | ((pts[1] >> 4)&0x0F); + p->scr[2] = 0x04 | ((pts[1] << 4)&0xF0) | ((pts[2] >> 4)&0x08) + | ((pts[2] >> 5)&0x03); + p->scr[3] = 0x00 | ((pts[2] << 3)&0xF8) | ((pts[3] >> 5)&0x07); + p->scr[4] = 0x04 | ((pts[3] << 3)&0xF8); + p->scr[5] = 0x01; + + p->mux_rate[0] = (uint8_t)(muxr >> 14); + p->mux_rate[1] = (uint8_t)(0xff & (muxr >> 6)); + p->mux_rate[2] = (uint8_t)(0x03 | ((muxr & 0x3f) << 2)); + + p->stuff_length = 0xF8; + + p->sheader_llength[0] = 0x00; + p->sheader_llength[1] = 0x0c; + + setl_ps(p); + + p->rate_bound[0] = (uint8_t)(0x80 | (muxr >>15)); + p->rate_bound[1] = (uint8_t)(0xff & (muxr >> 7)); + p->rate_bound[2] = (uint8_t)(0x01 | ((muxr & 0x7f)<<1)); + + + p->audio_bound = (uint8_t)((audio_bound << 2)|(fixed << 1)|CSPS); + p->video_bound = (uint8_t)((audio_lock << 7)| + (video_lock << 6)|0x20|video_bound); + p->reserved = (uint8_t)(0xFF); + + p->data[0] = stream2; + p->data[1] = (uint8_t) (0xc0 | (buffer2_scale << 5) | + (buffer2_size >> 8)); + p->data[2] = (uint8_t) (buffer2_size & 0xff); + p->data[3] = stream1; + p->data[4] = (uint8_t) (0xc0 | (buffer1_scale << 5) | + (buffer1_size >> 8)); + p->data[5] = (uint8_t) (buffer1_size & 0xff); + + write_ps(fd, p); + kill_ps(p); +} + + + +void twrite(uint8_t const *buf) +{ + int l = TS_SIZE; + int c = 0; + int w; + + + while (l){ + w = write(STDOUT_FILENO,buf+c,l); + if (w>=0){ + l-=w; + c+=w; + } + } +} + +void init_p2t(p2t_t *p, void (*fkt)(uint8_t const *buf)) +{ + memset(p->pes,0,TS_SIZE); + p->counter = 0; + p->pos = 0; + p->frags = 0; + if (fkt) p->t_out = fkt; + else p->t_out = twrite; +} + +void clear_p2t(p2t_t *p) +{ + memset(p->pes,0,TS_SIZE); + p->counter = 0; + p->pos = 0; + p->frags = 0; +} + + +long int find_pes_header(uint8_t const *buf, long int length, int *frags) +{ + int c = 0; + int found = 0; + + *frags = 0; + + while (c < length-3 && !found) { + if (buf[c] == 0x00 && buf[c+1] == 0x00 && + buf[c+2] == 0x01) { + switch ( buf[c+3] ) { + case 0xBA: + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + found = 1; + break; + + default: + c++; + break; + } + } else c++; + } + if (c == length-3 && !found){ + if (buf[length-1] == 0x00) *frags = 1; + if (buf[length-2] == 0x00 && + buf[length-1] == 0x00) *frags = 2; + if (buf[length-3] == 0x00 && + buf[length-2] == 0x00 && + buf[length-1] == 0x01) *frags = 3; + return -1; + } + + return c; +} + +void pes_to_ts( uint8_t const *buf, long int length, uint16_t pid, p2t_t *p) +{ + int c,c2,l,add; + int check,rest; + + c = 0; + c2 = 0; + if (p->frags){ + check = 0; + switch(p->frags){ + case 1: + if ( buf[c] == 0x00 && buf[c+1] == 0x01 ){ + check = 1; + c += 2; + } + break; + case 2: + if ( buf[c] == 0x01 ){ + check = 1; + c++; + } + break; + case 3: + check = 1; + } + if(check){ + switch ( buf[c] ) { + + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + p->pes[0] = 0x00; + p->pes[1] = 0x00; + p->pes[2] = 0x01; + p->pes[3] = buf[c]; + p->pos=4; + memcpy(p->pes+p->pos,buf+c,TS_SIZE-4-p->pos); + c += TS_SIZE-4-p->pos; + p_to_t(p->pes,TS_SIZE-4,pid,&p->counter, + p->t_out); + clear_p2t(p); + break; + + default: + c=0; + break; + } + } + p->frags = 0; + } + + if (p->pos){ + c2 = find_pes_header(buf+c,length-c,&p->frags); + if (c2 >= 0 && c2 < TS_SIZE-4-p->pos){ + l = c2+c; + } else l = TS_SIZE-4-p->pos; + memcpy(p->pes+p->pos,buf,l); + c += l; + p->pos += l; + p_to_t(p->pes,p->pos,pid,&p->counter, + p->t_out); + clear_p2t(p); + } + + add = 0; + while (c < length){ + c2 = find_pes_header(buf+c+add,length-c-add,&p->frags); + if (c2 >= 0) { + c2 += c+add; + if (c2 > c){ + p_to_t(buf+c,c2-c,pid,&p->counter, + p->t_out); + c = c2; + clear_p2t(p); + add = 0; + } else add = 1; + } else { + l = length-c; + rest = l % (TS_SIZE-4); + l -= rest; + p_to_t(buf+c,l,pid,&p->counter, + p->t_out); + memcpy(p->pes,buf+c+l,rest); + p->pos = rest; + c = length; + } + } +} + + + +void p_to_t( uint8_t const *buf, long int length, uint16_t pid, uint8_t *counter, + void (*ts_write)(uint8_t const *)) +{ + + int l, pes_start; + uint8_t obuf[TS_SIZE]; + long int c = 0; + pes_start = 0; + if ( length > 3 && + buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 ) + switch (buf[3]){ + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + pes_start = 1; + break; + + default: + break; + } + + while ( c < length ){ + memset(obuf,0,TS_SIZE); + if (length - c >= TS_SIZE-4){ + l = write_ts_header(pid, counter, pes_start + , obuf, TS_SIZE-4); + memcpy(obuf+l, buf+c, TS_SIZE-l); + c += TS_SIZE-l; + } else { + l = write_ts_header(pid, counter, pes_start + , obuf, length-c); + memcpy(obuf+l, buf+c, TS_SIZE-l); + c = length; + } + ts_write(obuf); + pes_start = 0; + } +} + + +int write_ps_header(uint8_t *buf, + uint32_t SCR, + long muxr, + uint8_t audio_bound, + uint8_t fixed, + uint8_t CSPS, + uint8_t audio_lock, + uint8_t video_lock, + uint8_t video_bound, + uint8_t stream1, + uint8_t buffer1_scale, + uint32_t buffer1_size, + uint8_t stream2, + uint8_t buffer2_scale, + uint32_t buffer2_size) +{ + ps_packet p; + uint8_t *pts; + long lpts; + init_ps(&p); + + lpts = htonl(SCR); + pts = (uint8_t *) &lpts; + + + p.mpeg = 2; +// SCR = 0 + p.scr[0] = 0x44; + p.scr[1] = 0x00; + p.scr[2] = 0x04; + p.scr[3] = 0x00; + p.scr[4] = 0x04; + p.scr[5] = 0x01; + +// SCR = PTS + p.scr[0] = 0x44 | ((pts[0] >> 3)&0x18) | ((pts[0] >> 4)&0x03); + p.scr[1] = 0x00 | ((pts[0] << 4)&0xF0) | ((pts[1] >> 4)&0x0F); + p.scr[2] = 0x04 | ((pts[1] << 4)&0xF0) | ((pts[2] >> 4)&0x08) + | ((pts[2] >> 5)&0x03); + p.scr[3] = 0x00 | ((pts[2] << 3)&0xF8) | ((pts[3] >> 5)&0x07); + p.scr[4] = 0x04 | ((pts[3] << 3)&0xF8); + p.scr[5] = 0x01; + + p.mux_rate[0] = (uint8_t)(muxr >> 14); + p.mux_rate[1] = (uint8_t)(0xff & (muxr >> 6)); + p.mux_rate[2] = (uint8_t)(0x03 | ((muxr & 0x3f) << 2)); + + p.stuff_length = 0xF8; + + if (stream1 && stream2){ + p.sheader_llength[0] = 0x00; + p.sheader_llength[1] = 0x0c; + + setl_ps(&p); + + p.rate_bound[0] = (uint8_t)(0x80 | (muxr >>15)); + p.rate_bound[1] = (uint8_t)(0xff & (muxr >> 7)); + p.rate_bound[2] = (uint8_t)(0x01 | ((muxr & 0x7f)<<1)); + + + p.audio_bound = (uint8_t)((audio_bound << 2)|(fixed << 1)|CSPS); + p.video_bound = (uint8_t)((audio_lock << 7)| + (video_lock << 6)|0x20|video_bound); + p.reserved = (uint8_t)(0xFF >> 1); + + p.data[0] = stream2; + p.data[1] = (uint8_t) (0xc0 | (buffer2_scale << 5) | + (buffer2_size >> 8)); + p.data[2] = (uint8_t) (buffer2_size & 0xff); + p.data[3] = stream1; + p.data[4] = (uint8_t) (0xc0 | (buffer1_scale << 5) | + (buffer1_size >> 8)); + p.data[5] = (uint8_t) (buffer1_size & 0xff); + + cwrite_ps(buf, &p, PS_HEADER_L2); + kill_ps(&p); + return PS_HEADER_L2; + } else { + cwrite_ps(buf, &p, PS_HEADER_L1); + kill_ps(&p); + return PS_HEADER_L1; + } +} + + + +#define MAX_BASE 80 +#define MAX_PATH 256 +#define MAX_EXT 10 + +int break_up_filename(char *name, char *base_name, char *path, char *ext) +{ + int l,i,sstop,sstart; + + l = strlen(name); + sstop = l; + sstart = -1; + for( i= l-1; i >= 0; i--){ + if (sstop == l && name[i] == '.') sstop = i; + if (sstart<0 && name[i] == '/') sstart = i+1; + } + if (sstart < 0) sstart = 0; + if (sstop-sstart < MAX_BASE){ + strncpy(base_name, name+sstart, sstop-sstart); + base_name[sstop-sstart]=0; + if(sstart > 0){ + if( l - sstop + sstart < MAX_PATH){ + strncpy(path, name, sstart); + path[sstart] = 0; + } else { + fprintf(stderr,"PATH too long\n"); + return -1; + } + + } else { + strcpy(path, "./"); + } + + if(sstop < l){ + if( l - sstop -1 < MAX_EXT){ + strncpy(ext, name+sstop+1, l-sstop-1); + ext[l-sstop-1]=0; + } else { + fprintf(stderr,"Extension too long\n"); + return -1; + } + + } else { + strcpy(ext, ""); + } + + } else { + fprintf(stderr,"Name too long\n"); + return -1; + } +/* + printf("%d %d\n",sstart, sstop); + printf("%s %d\n",name, strlen(name)); + printf("%s %d\n",base_name, strlen(base_name)); + printf("%s %d\n",path,strlen(path)); + printf("%s %d\n",ext,strlen(ext)); +*/ + return 0; +} + + +int seek_mpg_start(uint8_t *buf, int size) +{ + int found = 0; + int c=0; + int seq = 0; + int mpeg = 0; + int mark = 0; + + while ( !seq ){ + while (found != 4){ + switch (found) { + case 0: + if ( buf[c] == 0x00 ) found++; + c++; + break; + case 1: + if ( buf[c] == 0x00 ) found++; + else found = 0; + c++; + break; + case 2: + if ( buf[c] == 0x01 ) found++; + else found = 0; + if ( buf[c] == 0x00 ) found = 2; + c++; + break; + + case 3: + if ( (buf[c] & 0xe0) == 0xe0 ) found++; + else found = 0; + c++; + break; + } + if (c >= size) return -1; + } + + if (found == 4){ + mark = c-4; + c+=2; + if (c >= size) return -1; + + if ( (buf[c] & 0xC0) == 0x80 ){ + mpeg = 2; + c += 2; + if (c >= size) return -1; + c += buf[c]+1; + if (c >= size) return -1; + } else { + mpeg = 1; + while( buf[c] == 0xFF ) { + c++; + if (c >= size) return -1; + } + if ( (buf[c] & 0xC0) == 0x40) c+=2; + if (c >= size) return -1; + if ( (buf[c] & 0x30) ){ + if ( (buf[c] & 0x30) == 0x20) c+=5; + else c+=10; + } else c++; + if (c >= size) return -1; + } + + if ( buf[c] == 0x00 && + buf[c+1] == 0x00 && + buf[c+2] == 0x01 && + buf[c+3] == 0xB3 ) + seq = 1; + } + found = 0; + } + + return size-mark; +} + + +void write_mpg(int fstart, uint64_t length, int fdin, int fdout) +{ +// uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 }; + uint8_t *buf; + uint64_t l=0; + uint64_t count = 0; + struct stat sb; + int buf_size; + + fstat (fdout, &sb); + buf_size = sb.st_blksize; + + buf = (char *) alloca (buf_size + sizeof (int)); + + lseek(fdin, fstart, SEEK_SET); + + while ( count < length && (l = read(fdin,buf,buf_size)) >= 0){ + if (l > 0) count+=l; + write(fdout,buf,l); + printf("written %02.2f%%\r",(100.*count)/length); + } + printf("\n"); + + //write( fdout, mpeg_end, 4); +} + + +#define CHECKBUF (1024*1024) +#define ONE_GIG (1024UL*1024UL*1024UL) +void split_mpg(char *name, uint64_t size) +{ + char base_name[MAX_BASE]; + char path[MAX_PATH]; + char ext[MAX_EXT]; + char new_name[256]; + uint8_t buf[CHECKBUF]; + int fdin; + int fdout; + uint64_t length = 0; + uint64_t last; + int i; + int mark, csize; + struct stat sb; + + if (break_up_filename(name,base_name,path,ext) < 0) exit(1); + + + if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){ + fprintf(stderr,"Can't open %s\n",name); + exit(1); + } + + fstat (fdin, &sb); + + length = sb.st_size; + if ( length < ONE_GIG ) + printf("Filelength = %2.2f MB\n", length/1024./1024.); + else + printf("Filelength = %2.2f GB\n", length/1024./1024./1024.); + + if ( length < size ) length = size; + + printf("Splitting %s into Files with size <= %2.2f MB\n",name, + size/1024./1024.); + + csize = CHECKBUF; + read(fdin, buf, csize); + if ( (mark = seek_mpg_start(buf,csize)) < 0){ + fprintf(stderr,"Couldn't find sequence header\n"); + exit(1); + } + + last = csize-mark; + + for ( i = 0 ; i < length/size; i++){ + csize = CHECKBUF; + + if (csize > length-last) csize = length-last; + lseek(fdin, last+size-csize, SEEK_SET); + read(fdin, buf, csize); + if ( (mark = seek_mpg_start(buf,csize)) < 0){ + fprintf(stderr,"Couldn't find sequence header\n"); + exit(1); + } + + sprintf(new_name,"%s-%03d.%s",base_name,i,ext); + printf("writing %s\n",new_name); + + if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC + |O_LARGEFILE, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| + S_IROTH|S_IWOTH)) < 0){ + fprintf(stderr,"Can't open %s\n",new_name); + exit(1); + } + write_mpg(last, size-mark, fdin, fdout); + last = last + size - mark; + } + sprintf(new_name,"%s-%03d.%s",base_name,i,ext); + printf("writing %s\n",new_name); + + if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC + |O_LARGEFILE, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| + S_IROTH|S_IWOTH)) < 0){ + fprintf(stderr,"Can't open %s\n",new_name); + exit(1); + } + write_mpg(last, length-last, fdin, fdout); +} + + + + +void cut_mpg(char *name, uint64_t size) +{ + char base_name[MAX_BASE]; + char path[MAX_PATH]; + char ext[MAX_EXT]; + char new_name[256]; + uint8_t buf[CHECKBUF]; + int fdin; + int fdout; + uint64_t length = 0; + uint64_t last; + int mark, csize; + struct stat sb; + + if (break_up_filename(name,base_name,path,ext) < 0) exit(1); + + + if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){ + fprintf(stderr,"Can't open %s\n",name); + exit(1); + } + + fstat (fdin, &sb); + + length = sb.st_size; + if ( length < ONE_GIG ) + printf("Filelength = %2.2f MB\n", length/1024./1024.); + else + printf("Filelength = %2.2f GB\n", length/1024./1024./1024.); + + if ( length < size ) length = size; + + printf("Splitting %s into 2 Files with length %.2f MB and %.2f MB\n", + name, size/1024./1024., (length-size)/1024./1024.); + + csize = CHECKBUF; + read(fdin, buf, csize); + if ( (mark = seek_mpg_start(buf,csize)) < 0){ + fprintf(stderr,"Couldn't find sequence header\n"); + exit(1); + } + + last = csize-mark; + + if (csize > length-last) csize = length-last; + lseek(fdin, last+size-csize, SEEK_SET); + read(fdin, buf, csize); + if ( (mark = seek_mpg_start(buf,csize)) < 0){ + fprintf(stderr,"Couldn't find sequence header\n"); + exit(1); + } + + sprintf(new_name,"%s-1.%s",base_name,ext); + printf("writing %s\n",new_name); + + if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC + |O_LARGEFILE, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| + S_IROTH|S_IWOTH)) < 0){ + fprintf(stderr,"Can't open %s\n",new_name); + exit(1); + } + write_mpg(last, size-mark, fdin, fdout); + last = last + size - mark; + + sprintf(new_name,"%s-2.%s",base_name,ext); + printf("writing %s\n",new_name); + + if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC + |O_LARGEFILE, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| + S_IROTH|S_IWOTH)) < 0){ + fprintf(stderr,"Can't open %s\n",new_name); + exit(1); + } + write_mpg(last, length-last, fdin, fdout); +} + + + + +void write_all (int fd, uint8_t *data, int length) +{ + int r; + + while (length) { + if ((r = write(fd, data, length)) > 0) { + data += r; + length -= r; + } + } +} + + + +void read_all (int fd, uint8_t *data, int length) +{ + int c = 0; + + while(1) { + if( read(fd, data+c, 1) == 1) { + c++; + if(data[c-1] == '\n') { + data[c] = 0; + break; + } + } + else { + fprintf (stderr, "Error reading socket\n"); + exit(1); + } + } +} + + + +char *url2host (uint8_t *url, char **name, uint32_t *ip, uint32_t *port) +{ + uint8_t *murl; + struct hostent *hoste; + struct in_addr haddr; + int found_ip = 1; + + if (!(strncmp(url, "http://", 7))) + url += 7; + + *name = strdup(url); + if (!(*name)) { + *name = NULL; + return (NULL); + } + + murl = url; + while (*murl && *murl != ':' && *murl != '/') { + if ((*murl < '0' || *murl > '9') && *murl != '.') + found_ip = 0; + murl++; + } + + (*name)[murl - url] = 0; + if (found_ip) { + if ((*ip = inet_addr(*name)) == INADDR_NONE) + return (NULL); + } else { + if (!(hoste = gethostbyname(*name))) + return (NULL); + memcpy (&haddr, hoste->h_addr, sizeof(haddr)); + *ip = haddr.s_addr; + } + + if (!*murl || *murl == '/') { + *port = 80; + return (murl); + } + *port = atoi(++murl); + + while (*murl && *murl != '/') + murl++; + return (murl); +} + +#define ACCEPT "Accept: video/mpeg, video/x-mpegurl, */*\r\n" + +int http_open (char *url) +{ + char purl[1024], *host, req[1024], *sptr; + uint32_t ip; + uint32_t port; + int sock; + int reloc, relocnum = 0; + struct sockaddr_in server; + int mfd; + + strncpy (purl, url, 1023); + purl[1023] = '\0'; + + do { + host = NULL; + strcpy (req, "GET "); + if (!(sptr = url2host(purl, &host, &ip, &port))) { + fprintf (stderr, "Unknown host\n"); + exit (1); + } + strcat (req, sptr); + sprintf (req + strlen(req), + " HTTP/1.0\r\nUser-Agent: %s/%s\r\n", + "whatever", "you want"); + if (host) { + sprintf(req + strlen(req), + "Host: %s:%u\r\n", host, port); + free (host); + } + + strcat (req, ACCEPT); + strcat (req, "\r\n"); + + server.sin_port = htons(port); + server.sin_family = AF_INET; + server.sin_addr.s_addr = ip; + + if ((sock = socket(PF_INET, SOCK_STREAM, 6)) < 0) { + perror ("socket"); + exit (1); + } + + if (connect(sock, (struct sockaddr *)&server, + sizeof(server))) { + perror ("connect"); + exit (1); + } + + write_all (sock, req, strlen(req)); + if (!(mfd = fileno(fdopen(sock, "rb")))) { + perror ("open"); + exit (1); + } + reloc = 0; + purl[0] = '\0'; + read_all (mfd, req, 1023); + if ((sptr = strchr(req, ' '))) { + switch (sptr[1]) { + case '2': + break; + case '3': + reloc = 1; + default: + fprintf (stderr, "HTTP req failed:%s", + sptr+1); + exit (1); + } + } + do { + read_all (mfd,req, 1023); + if (!strncmp(req, "Location:", 9)) + strncpy (purl, req+10, 1023); + } while (req[0] != '\r' && req[0] != '\n'); + } while (reloc && purl[0] && relocnum++ < 3); + if (reloc) { + fprintf (stderr, "Too many HTTP relocations.\n"); + exit (1); + } + + return sock; +} + +extern int errno; +const char * strerrno (void) +{ + return strerror(errno); +} diff --git a/libdvbmpeg/ctools.h b/libdvbmpeg/ctools.h new file mode 100644 index 0000000..a7b0271 --- /dev/null +++ b/libdvbmpeg/ctools.h @@ -0,0 +1,404 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002, 2003 Marcus Metzler + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at mocm@metzlerbros.de + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "ringbuffy.h" +#include "transform.h" + +#ifndef _CTOOLS_H_ +#define _CTOOLS_H_ + +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + enum {PS_STREAM, TS_STREAM, PES_STREAM}; + enum {pDUNNO, pPAL, pNTSC}; + + uint64_t trans_pts_dts(uint8_t *pts); + +/* + PES +*/ + +#define PROG_STREAM_MAP 0xBC +#ifndef PRIVATE_STREAM1 +#define PRIVATE_STREAM1 0xBD +#endif +#define PADDING_STREAM 0xBE +#ifndef PRIVATE_STREAM2 +#define PRIVATE_STREAM2 0xBF +#endif +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define BUFFYSIZE 10*MAX_PLENGTH +#define MAX_PTS 8192 +#define MAX_FRAME 8192 +#define MAX_PACK_L 4096 +#define PS_HEADER_L1 14 +#define PS_HEADER_L2 (PS_HEADER_L1+18) +#define MAX_H_SIZE (PES_H_MIN + PS_HEADER_L1 + 5) +#define PES_MIN 7 +#define PES_H_MIN 9 + +//flags1 +#define FLAGS 0x40 +#define SCRAMBLE_FLAGS 0x30 +#define PRIORITY_FLAG 0x08 +#define DATA_ALIGN_FLAG 0x04 +#define COPYRIGHT_FLAG 0x02 +#define ORIGINAL_FLAG 0x01 + +//flags2 +#define PTS_DTS_FLAGS 0xC0 +#define ESCR_FLAG 0x20 +#define ES_RATE_FLAG 0x10 +#define DSM_TRICK_FLAG 0x08 +#define ADD_CPY_FLAG 0x04 +#define PES_CRC_FLAG 0x02 +#define PES_EXT_FLAG 0x01 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 + +//private flags +#define PRIVATE_DATA 0x80 +#define HEADER_FIELD 0x40 +#define PACK_SEQ_CTR 0x20 +#define P_STD_BUFFER 0x10 +#define PES_EXT_FLAG2 0x01 + +#define MPEG1_2_ID 0x40 +#define STFF_LNGTH_MASK 0x3F + + + typedef struct pes_packet_{ + uint8_t stream_id; + uint8_t llength[2]; + uint32_t length; + uint8_t flags1; + uint8_t flags2; + uint8_t pes_hlength; + uint8_t pts[5]; + uint8_t dts[5]; + uint8_t escr[6]; + uint8_t es_rate[3]; + uint8_t trick; + uint8_t add_cpy; + uint8_t prev_pes_crc[2]; + uint8_t priv_flags; + uint8_t pes_priv_data[16]; + uint8_t pack_field_length; + uint8_t *pack_header; + uint8_t pck_sqnc_cntr; + uint8_t org_stuff_length; + uint8_t p_std[2]; + uint8_t pes_ext_lngth; + uint8_t *pes_ext; + uint8_t *pes_pckt_data; + int padding; + int mpeg; + int mpeg1_pad; + uint8_t *mpeg1_headr; + uint8_t stuffing; + } pes_packet; + + void init_pes(pes_packet *p); + void kill_pes(pes_packet *p); + void setlength_pes(pes_packet *p); + void nlength_pes(pes_packet *p); + int cwrite_pes(uint8_t *buf, pes_packet *p, long length); + void write_pes(int fd, pes_packet *p); + int read_pes(int f, pes_packet *p); + void cread_pes(char *buf, pes_packet *p); + +/* + Transport Stream +*/ + +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + typedef struct ts_packet_{ + uint8_t pid[2]; + uint8_t flags; + uint8_t count; + uint8_t data[184]; + uint8_t adapt_length; + uint8_t adapt_flags; + uint8_t pcr[6]; + uint8_t opcr[6]; + uint8_t splice_count; + uint8_t priv_dat_len; + uint8_t *priv_dat; + uint8_t adapt_ext_len; + uint8_t adapt_eflags; + uint8_t ltw[2]; + uint8_t piece_rate[3]; + uint8_t dts[5]; + int rest; + uint8_t stuffing; + } ts_packet; + + void init_ts(ts_packet *p); + void kill_ts(ts_packet *p); + unsigned short pid_ts(ts_packet *p); + int cwrite_ts(uint8_t *buf, ts_packet *p, long length); + void write_ts(int fd, ts_packet *p); + int read_ts(int f, ts_packet *p); + void cread_ts (char *buf, ts_packet *p, long length); + + +/* + Program Stream +*/ + +#define PACK_STUFF_MASK 0x07 + +#define FIXED_FLAG 0x02 +#define CSPS_FLAG 0x01 +#define SAUDIO_LOCK_FLAG 0x80 +#define SVIDEO_LOCK_FLAG 0x40 + +#define PS_MAX 200 + + typedef struct ps_packet_{ + uint8_t scr[6]; + uint8_t mux_rate[3]; + uint8_t stuff_length; + uint8_t *data; + uint8_t sheader_llength[2]; + int sheader_length; + uint8_t rate_bound[3]; + uint8_t audio_bound; + uint8_t video_bound; + uint8_t reserved; + int npes; + int mpeg; + } ps_packet; + + void init_ps(ps_packet *p); + void kill_ps(ps_packet *p); + void setlength_ps(ps_packet *p); + uint32_t scr_base_ps(ps_packet *p); + uint16_t scr_ext_ps(ps_packet *p); + int mux_ps(ps_packet *p); + int rate_ps(ps_packet *p); + int cwrite_ps(uint8_t *buf, ps_packet *p, long length); + void write_ps(int fd, ps_packet *p); + int read_ps (int f, ps_packet *p); + void cread_ps (char *buf, ps_packet *p, long length); + + + +#define MAX_PLENGTH 0xFFFF + + typedef struct sectionstruct { + int id; + int length; + int found; + uint8_t payload[4096+3]; + } section; + + + typedef uint32_t tflags; +#define MAXFILT 32 +#define MASKL 16 + typedef struct trans_struct { + int found; + uint8_t packet[188]; + uint16_t pid[MAXFILT]; + uint8_t mask[MAXFILT*MASKL]; + uint8_t filt[MAXFILT*MASKL]; + uint8_t transbuf[MAXFILT*188]; + int transcount[MAXFILT]; + section sec[MAXFILT]; + tflags is_full; + tflags pes_start; + tflags pes_started; + tflags pes; + tflags set; + } trans; + + + void init_trans(trans *p); + int set_trans_filt(trans *p, int filtn, uint16_t pid, uint8_t *mask, + uint8_t *filt, int pes); + + void clear_trans_filt(trans *p,int filtn); + int filt_is_set(trans *p, int filtn); + int pes_is_set(trans *p, int filtn); + int pes_is_started(trans *p, int filtn); + int pes_is_start(trans *p, int filtn); + int filt_is_ready(trans *p,int filtn); + + void trans_filt(uint8_t *buf, int count, trans *p); + void tfilter(trans *p); + void pes_filter(trans *p, int filtn, int off); + void sec_filter(trans *p, int filtn, int off); + int get_filt_buf(trans *p, int filtn,uint8_t **buf); + section *get_filt_sec(trans *p, int filtn); + + + typedef struct a2pstruct{ + int type; + int fd; + int found; + int length; + int headr; + int plength; + uint8_t cid; + uint8_t flags; + uint8_t abuf[MAX_PLENGTH]; + int alength; + uint8_t vbuf[MAX_PLENGTH]; + int vlength; + uint8_t last_av_pts[4]; + uint8_t av_pts[4]; + uint8_t scr[4]; + uint8_t pid0; + uint8_t pid1; + uint8_t pidv; + uint8_t pida; + } a2p; + + + + void get_pespts(uint8_t *av_pts,uint8_t *pts); + void init_a2p(a2p *p); + void av_pes_to_pes(uint8_t *buf,int count, a2p *p); + int w_pesh(uint8_t id,int length ,uint8_t *pts, uint8_t *obuf); + int w_tsh(uint8_t id,int length ,uint8_t *pts, uint8_t *obuf,a2p *p,int startpes); + void pts2pts(uint8_t *av_pts, uint8_t *pts); + void write_ps_headr(ps_packet *p,uint8_t *pts,int fd); + + typedef struct p2t_s{ + uint8_t pes[TS_SIZE]; + uint8_t counter; + long int pos; + int frags; + void (*t_out)(uint8_t const *buf); + } p2t_t; + + void twrite(uint8_t const *buf); + void init_p2t(p2t_t *p, void (*fkt)(uint8_t const *buf)); + long int find_pes_header(uint8_t const *buf, long int length, int *frags); + void pes_to_ts( uint8_t const *buf, long int length, uint16_t pid, p2t_t *p); + void p_to_t( uint8_t const *buf, long int length, uint16_t pid, + uint8_t *counter, void (*ts_write)(uint8_t const *)); + + + int write_pes_header(uint8_t id,int length , long PTS, + uint8_t *obuf, int stuffing); + + int write_ps_header(uint8_t *buf, + uint32_t SCR, + long muxr, + uint8_t audio_bound, + uint8_t fixed, + uint8_t CSPS, + uint8_t audio_lock, + uint8_t video_lock, + uint8_t video_bound, + uint8_t stream1, + uint8_t buffer1_scale, + uint32_t buffer1_size, + uint8_t stream2, + uint8_t buffer2_scale, + uint32_t buffer2_size); + + + int seek_mpg_start(uint8_t *buf, int size); + + + void split_mpg(char *name, uint64_t size); + void cut_mpg(char *name, uint64_t size); + int http_open (char *url); + ssize_t save_read(int fd, void *buf, size_t count); + + const char * strerrno(void); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /*_CTOOLS_H_*/ diff --git a/libdvbmpeg/devices.hh b/libdvbmpeg/devices.hh new file mode 100644 index 0000000..02c62cd --- /dev/null +++ b/libdvbmpeg/devices.hh @@ -0,0 +1,310 @@ +#ifndef _channel_hh +#define _channel_hh + +using namespace std; +#include + +#include +#include +#include + +#include +#include +#include + +#include "DVB.hh" + +#define MAXNAM 80 +#define MAXKEY 15 + +const int maxname=80; +const int MAXAPIDS=32; +const uint32_t UNSET=0xffffffff; +const uint16_t NOID=0xffff; +const uint16_t NOPID=0xffff; + +class Transponder { +public: + uint16_t id; + uint16_t onid; + uint16_t satid; + int type; + char name[maxname+1]; + uint32_t freq; + int pol; + int qam; + uint32_t srate; + int fec; + int band; + int hp_rate; + int lp_rate; + int mod; + int transmode; + int guard; + int hierarchy; + + struct Sat *sat; + + Transponder() { + name[0]='\0'; + id = NOID; + onid = NOID; + satid = NOID; + type = 0; + } + + friend ostream &operator<<(ostream &stream, Transponder &x); + friend istream &operator>>(istream &stream, Transponder &x); +}; + +class Sat { +public: + uint16_t id; + char name[maxname+1]; + unsigned int lnbid; + struct Lnb *lnb; + unsigned int rotorid; + unsigned int fmin; + unsigned int fmax; + + Sat() { + id=NOID; + name[0]='\0'; + lnb=NULL; + rotorid=NOID; + lnbid=NOID; + fmin=fmax=0; + }; + int set(int sid, char *sname, int slnbid, int srotorid) { + return 0; + }; + + friend ostream &operator<<(ostream &stream, Sat &x); + friend istream &operator>>(istream &stream, Sat &x); +}; + + +class Lnb { +public: + Sat *sat; + uint16_t id; + struct DVB *dvbd; + char name[maxname+1]; + int type; + unsigned int lof1; + unsigned int lof2; + unsigned int slof; + int diseqcnr; + uint16_t diseqcid; + uint16_t swiid; + + + void cpy (const Lnb &olnb){ + this->id=olnb.id; + this->type=olnb.type; + this->lof1=olnb.lof1; + this->lof2=olnb.lof2; + this->slof=olnb.slof; + this->diseqcnr=olnb.diseqcnr; + this->diseqcid=olnb.diseqcid; + this->swiid=olnb.swiid; + strncpy(this->name,olnb.name,maxname); + } + + void init(int t, uint l1, uint l2, uint sl, + int dnr, int disid, int sw) { + type=t; + lof1=l1; + lof2=l2; + slof=sl; + diseqcnr=dnr; + diseqcid=disid; + swiid=sw; + dvbd=0; + name[0]='\0'; + } + + Lnb () { + lof1=lof2=slof=0; + swiid=NOID; + diseqcid=NOID; + diseqcnr=-1; + name[0]='\0'; + } + + Lnb (const Lnb &olnb){ + cpy(olnb); + } + + + + friend ostream &operator<<(ostream &stream, Lnb &x); + friend istream &operator>>(istream &stream, Lnb &x); +}; + +struct diseqcmsg { + int burst; + int len; + unsigned char msg[8]; +}; + +class DiSEqC { +public: + uint16_t id; + char name[maxname+1]; + diseqcmsg msgs[4]; + + friend ostream &operator<<(ostream &stream, DiSEqC &x); + friend istream &operator>>(istream &stream, DiSEqC &x); +}; + +class Rotor { +public: + uint16_t id; + char name[maxname+1]; + diseqcmsg msgs[4]; + + friend ostream &operator<<(ostream &stream, Rotor &x); + friend istream &operator>>(istream &stream, Rotor &x); +}; + +class Switch { +public: + uint16_t id; + int switchid; + char name[maxname+1]; + diseqcmsg msg; + + friend ostream &operator<<(ostream &stream, Switch &x); + friend istream &operator>>(istream &stream, Switch &x); +}; + +class Network { +public: + uint16_t id; + char name[maxname+1]; + + friend ostream &operator<<(ostream &stream, Network &x); + friend istream &operator>>(istream &stream, Network &x); +}; + +class Bouquet { +public: + uint16_t id; + char name[maxname+1]; + + friend ostream &operator<<(ostream &stream, Bouquet &x); + friend istream &operator>>(istream &stream, Bouquet &x); +}; + + +#define MAX_ECM 16 +#define MAX_ECM_DESC 256 +typedef struct ecm_struct { + int num; + uint16_t sysid[MAX_ECM]; + uint16_t pid[MAX_ECM]; + uint16_t length[MAX_ECM]; + uint8_t data[MAX_ECM*MAX_ECM_DESC]; +} ecm_t; + + + +class Channel{ +public: + Channel *next; + uint32_t id; + char name[maxname+1]; + int32_t type; + int checked; + + uint16_t pnr; + uint16_t vpid; + uint16_t apids[MAXAPIDS]; + char apids_name[MAXAPIDS*4]; + int32_t apidnum; + int last_apidn; + uint16_t ac3pid; + uint16_t ttpid; + uint16_t pmtpid; + uint16_t pcrpid; + uint16_t casystem; + uint16_t capid; + + ecm_t ecm; + int (*ecm_callback)(Channel *chan); + + int has_eit; + int pres_follow; + + uint16_t satid; + uint16_t tpid; + uint16_t onid; + uint16_t bid; + int8_t eit_ver_n; + int8_t eit_ver_c; + + void clearall(void) { + id=UNSET; + name[0]='\0'; + type=0; + checked = 0; + has_eit = -1; + pres_follow = -1; + eit_ver_c = -1; + eit_ver_n = -1; + + pnr=NOPID; + vpid=NOPID; + memset(apids, 0, sizeof(uint16_t)*MAXAPIDS); + memset(apids_name, 0, sizeof(char)*MAXAPIDS*4); + apidnum=0; + last_apidn=-1; + ac3pid=NOPID; + ttpid=NOPID; + pmtpid=NOPID; + pcrpid=NOPID; + capid=NOPID; + + satid=NOID; + tpid=NOID; + onid=NOID; + bid=NOID; + ecm_callback = NULL; + memset(&ecm,0, sizeof(ecm_t)); + }; + + Channel() { + clearall(); + } + + Channel(int cid, char *nam, int ty, int prognr, + int vid, int aid, int tid) { + int l=strlen(nam); + + clearall(); + if (l>maxname){ + cerr << "" << endl; + l=maxname; + } + strncpy(name, nam, l); + name[l]='\0'; + type=ty; + pnr=prognr; + vpid=vid; + apids[0]=aid; + } + +#ifdef DEBUG + ~Channel(){ + cerr <<"Channel " << name << " destroyed" << endl; + } +#endif + + friend ostream &operator<<(ostream &stream, Channel &x); + friend istream &operator>>(istream &stream, Channel &x); +}; + +int findkey(char *name, char *keys[]); +void getname(char *name,istream &ins); +#endif /*channel.h*/ diff --git a/libdvbmpeg/osd.hh b/libdvbmpeg/osd.hh new file mode 100644 index 0000000..9c6b530 --- /dev/null +++ b/libdvbmpeg/osd.hh @@ -0,0 +1,84 @@ +#ifndef _OSD_HH_ +#define _OSD_HH_ + +extern "C" { +#include "OSD.h" +} +struct OSD { + int dev; + + void init(int d) { + dev=d; + } + int Open(int x0, int y0, int x1, int y1, int BitPerPixel, int mix, int win) { + if (OSDSetWindow(dev, win)) + return -1; + return OSDOpen(dev, x0, y0, x1, y1, BitPerPixel, mix); + } + int Open(int x0, int y0, int x1, int y1, int BitPerPixel, int mix) { + return OSDOpen(dev, x0, y0, x1, y1, BitPerPixel, mix); + } + int Close(int win) { + if (OSDSetWindow(dev, win)) + return -1; + return OSDClose(dev); + } + int Close(void) { + return OSDClose(dev); + } + int Show(void) { + return OSDShow(dev); + } + int Hide(void) { + return OSDHide(dev); + } + int Clear(void) { + return OSDClear(dev); + } + int Fill(int color) { + return OSDFill(dev, color); + } + int SetColor(int color, int r, int g, int b, int op) { + return OSDSetColor(dev, color, r, g, b, op); + } + int Text(int x, int y, int size, int color, const char *text) { + return OSDText(dev, x, y, size, color, text); + } + int SetPalette(int first, int last, unsigned char *data) { + return OSDSetPalette(dev, first, last, data); + + } + int SetTrans(int trans) { + return OSDSetTrans(dev, trans); + + } + int SetPixel(int dev, int x, int y, unsigned int color) { + return OSDSetPixel(dev, x, y, color); + } + int GetPixel(int dev, int x, int y) { + return OSDGetPixel(dev, x, y); + } + int SetRow(int x, int y, int x1, unsigned char *data) { + return OSDSetRow(dev, x, y, x1, data); + } + int SetBlock(int x, int y, int x1, int y1, int inc, unsigned char *data) { + return OSDSetBlock(dev, x, y, x1, y1, inc, data); + } + int FillRow(int x, int y, int x1, int color) { + return OSDFillRow(dev, x, y, x1, color); + } + int FillBlock(int x, int y, int x1, int y1, int color) { + return OSDFillBlock(dev, x, y, x1, y1, color); + } + int Line(int x, int y, int x1, int y1, int color) { + return OSDLine(dev, x, y, x1, y1, color); + } + int Query() { + return OSDQuery(dev); + } + int SetWindow(int win) { + return OSDSetWindow(dev, win); + } +}; + +#endif diff --git a/libdvbmpeg/remux.c b/libdvbmpeg/remux.c new file mode 100644 index 0000000..6f8a44f --- /dev/null +++ b/libdvbmpeg/remux.c @@ -0,0 +1,1215 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002 Marcus Metzler + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at mocm@metzlerbros.de, + */ + +#include "remux.h" + +unsigned int bitrates[3][16] = +{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, + {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, + {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; + +uint32_t freq[4] = {441, 480, 320, 0}; +static uint32_t samples[4] = { 384, 1152, 0, 0}; +char *frames[3] = {"I-Frame","P-Frame","B-Frame"}; + + +void copy_ptslm(PTS_List *a, PTS_List *b) +{ + a->pos = b->pos; + a->PTS = b->PTS; + a->dts = b->dts; + a->spos = b->spos; +} + +void clear_ptslm(PTS_List *a) +{ + a->pos = 0; + a->PTS = 0; + a->dts = 0; + a->spos = 0; +} + +void init_ptsl(PTS_List *ptsl) +{ + int i; + for (i=0;i< MAX_PTS;i++){ + clear_ptslm(&ptsl[i]); + } +} + +int del_pts(PTS_List *ptsl, int pos, int nr) +{ + int i; + int del = 0; + + for( i = 0; i < nr-1; i++){ + if(pos > ptsl[i].pos && pos >= ptsl[i+1].pos) del++; + } + + if(del) + for( i = 0; i < nr-del; i++){ + copy_ptslm(&ptsl[i], &ptsl[i+del]); + } + + return nr-del; +} + +int del_ptss(PTS_List *ptsl, int pts, int *nb) +{ + int i; + int del = 0; + int sum = 0; + int nr = *nb; + + for( i = 0; i < nr; i++){ + if(pts > ptsl[i].PTS){ + del++; + sum += ptsl[i].pos; + } + } + + if(del) + for( i = 0; i < nr-del; i++){ + copy_ptslm(&ptsl[i], &ptsl[i+del]); + } + + *nb = nr-del; + return sum; +} + +int add_pts(PTS_List *ptsl, uint32_t pts, int pos, int spos, int nr, uint32_t dts) +{ + int i; + + for ( i=0;i < nr; i++) if (spos && ptsl[i].pos == pos) return nr; + if (nr == MAX_PTS) { + nr = del_pts(ptsl, ptsl[1].pos+1, nr); + } else nr++; + i = nr-1; + + ptsl[i].pos = pos; + ptsl[i].spos = spos; + ptsl[i].PTS = pts; + ptsl[i].dts = dts; + return nr; +} + +void add_vpts(Remux *rem, uint8_t *pts) +{ + uint32_t PTS = trans_pts_dts(pts); + rem->vptsn = add_pts(rem->vpts_list, PTS, rem->vwrite, rem->awrite, + rem->vptsn, PTS); +} + +void add_apts(Remux *rem, uint8_t *pts) +{ + uint32_t PTS = trans_pts_dts(pts); + rem->aptsn = add_pts(rem->apts_list, PTS, rem->awrite, rem->vwrite, + rem->aptsn, PTS); +} + +void del_vpts(Remux *rem) +{ + rem->vptsn = del_pts(rem->vpts_list, rem->vread, rem->vptsn); +} + +void del_apts(Remux *rem) +{ + rem->aptsn = del_pts(rem->apts_list, rem->aread, rem->aptsn); +} + + +void copy_framelm(FRAME_List *a, FRAME_List *b) +{ + a->type = b->type; + a->pos = b->pos; + a->FRAME = b->FRAME; + a->time = b->time; + a->pts = b->pts; + a->dts = b->dts; +} + +void clear_framelm(FRAME_List *a) +{ + a->type = 0; + a->pos = 0; + a->FRAME = 0; + a->time = 0; + a->pts = 0; + a->dts = 0; +} + +void init_framel(FRAME_List *framel) +{ + int i; + for (i=0;i< MAX_FRAME;i++){ + clear_framelm(&framel[i]); + } +} + +int del_frame(FRAME_List *framel, int pos, int nr) +{ + int i; + int del = 0; + + for( i = 0; i < nr-1; i++){ + if(pos > framel[i].pos && pos >= framel[i+1].pos) del++; + } + + if(del) + for( i = 0; i < nr-del; i++){ + copy_framelm(&framel[i], &framel[i+del]); + } + + return nr-del; +} + +int add_frame(FRAME_List *framel, uint32_t frame, int pos, int type, int nr, + uint32_t time, uint32_t pts, uint32_t dts) +{ + int i; + + if (nr == MAX_FRAME) { + nr = del_frame(framel, framel[1].pos+1, nr); + } else nr++; + i = nr-1; + + framel[i].type = type; + framel[i].pos = pos; + framel[i].FRAME = frame; + framel[i].time = time; + framel[i].pts = pts; + framel[i].dts = dts; + return nr; +} + +void add_vframe(Remux *rem, uint32_t frame, long int pos, int type, int time, + uint32_t pts, uint32_t dts) +{ + rem->vframen = add_frame(rem->vframe_list, frame, pos, type, + rem->vframen, time, pts, dts); +} + +void add_aframe(Remux *rem, uint32_t frame, long int pos, uint32_t pts) +{ + rem->aframen = add_frame(rem->aframe_list, frame, pos, 0, + rem->aframen, 0, pts, pts); +} + +void del_vframe(Remux *rem) +{ + rem->vframen = del_frame(rem->vframe_list, rem->vread, rem->vframen); +} + +void del_aframe(Remux *rem) +{ + rem->aframen = del_frame(rem->aframe_list, rem->aread, rem->aframen); +} + + +void printpts(uint32_t pts) +{ + fprintf(stderr,"%2d:%02d:%02d.%03d", + (int)(pts/90000.)/3600, + ((int)(pts/90000.)%3600)/60, + ((int)(pts/90000.)%3600)%60, + (((int)(pts/90.)%3600000)%60000)%1000 + ); +} + + +void find_vframes( Remux *rem, uint8_t *buf, int l) +{ + int c = 0; + int type; + uint32_t time = 0; + int hour; + int min; + int sec; + uint64_t pts=0; + uint64_t dts=0; + uint32_t tempref = 0; + + while ( c < l - 6){ + if (buf[c] == 0x00 && + buf[c+1] == 0x00 && + buf[c+2] == 0x01 && + buf[c+3] == 0xB8) { + c += 4; + hour = (int)((buf[c]>>2)& 0x1F); + min = (int)(((buf[c]<<4)& 0x30)| + ((buf[c+1]>>4)& 0x0F)); + sec = (int)(((buf[c+1]<<3)& 0x38)| + ((buf[c+2]>>5)& 0x07)); + + time = 3600*hour + 60*min + sec; + if ( rem->time_off){ + time = (uint32_t)((uint64_t)time - rem->time_off); + hour = time/3600; + min = (time%3600)/60; + sec = (time%3600)%60; + /* + buf[c] |= (hour & 0x1F) << 2; + buf[c] |= (min & 0x30) >> 4; + buf[c+1] |= (min & 0x0F) << 4; + buf[c+1] |= (sec & 0x38) >> 3; + buf[c+2] |= (sec & 0x07) >> 5;*/ + } + rem->group++; + rem->groupframe = 0; + } + if ( buf[c] == 0x00 && + buf[c+1] == 0x00 && + buf[c+2] == 0x01 && + buf[c+3] == 0x00) { + c += 4; + tempref = (buf[c+1]>>6) & 0x03; + tempref |= buf[c] << 2; + + type = ((buf[c+1]&0x38) >>3); + if ( rem->video_info.framerate){ + pts = ((uint64_t)rem->vframe + tempref + 1 + - rem->groupframe ) * 90000ULL + /rem->video_info.framerate + + rem->vpts_off; + dts = (uint64_t)rem->vframe * 90000ULL/ + rem->video_info.framerate + + rem->vpts_off; + + +fprintf(stderr,"MYPTS:"); +printpts((uint32_t)pts-rem->vpts_off); + fprintf(stderr," REALPTS:"); + printpts(rem->vpts_list[rem->vptsn-1].PTS-rem->vpts_off); + fprintf(stderr," DIFF:"); + printpts(pts-(uint64_t)rem->vpts_list[rem->vptsn-1].PTS); +// fprintf(stderr," DIST: %4d",-rem->vpts_list[rem->vptsn-1].pos+(rem->vwrite+c-4)); + //fprintf(stderr," ERR: %3f",(double)(-rem->vpts_list[rem->vptsn-1].PTS+pts)/(rem->vframe+1)); + fprintf(stderr,"\r"); + + + + rem->vptsn = add_pts(rem->vpts_list,(uint32_t)pts + ,rem->vwrite+c-4, + rem->awrite, + rem->vptsn, + (uint32_t)dts); + + + + } + rem->vframe++; + rem->groupframe++; + add_vframe( rem, rem->vframe, rem->vwrite+c, type, + time, pts, dts); + } else c++; + } +} + +void find_aframes( Remux *rem, uint8_t *buf, int l) +{ + int c = 0; + uint64_t pts = 0; + int sam; + uint32_t fr; + + + while ( c < l - 2){ + if ( buf[c] == 0xFF && + (buf[c+1] & 0xF8) == 0xF8) { + c += 2; + if ( rem->audio_info.layer >= 0){ + sam = samples[3-rem->audio_info.layer]; + fr = freq[rem->audio_info.frequency] ; + + pts = ( (uint64_t)rem->aframe * sam * 900ULL)/fr + + rem->apts_off; + + +fprintf(stderr,"MYPTS:"); +printpts((uint32_t)pts-rem->apts_off); + fprintf(stderr," REALPTS:"); + printpts(rem->apts_list[rem->aptsn-1].PTS-rem->apts_off); + fprintf(stderr," DIFF:"); + printpts((uint32_t)((uint64_t)rem->apts_list[rem->aptsn-1].PTS-pts)); +// fprintf(stderr," DIST: %4d",-rem->apts_list[rem->aptsn-1].pos+(rem->awrite+c-2)); + fprintf(stderr,"\r"); + + rem->aptsn = add_pts(rem->apts_list,(uint32_t)pts + ,rem->awrite+c-2, + rem->vwrite, + rem->aptsn, + (uint32_t)pts); + } + + rem->aframe++; + add_aframe( rem, rem->aframe, rem->awrite+c, pts); + + } else c++; + } +} + +int refill_buffy(Remux *rem) +{ + pes_packet pes; + int count = 0; + int acount, vcount; + ringbuffy *vbuf = &rem->vid_buffy; + ringbuffy *abuf = &rem->aud_buffy; + int fin = rem->fin; + + acount = abuf->size-ring_rest(abuf); + vcount = vbuf->size-ring_rest(vbuf); + + + while ( acount > MAX_PLENGTH && vcount > MAX_PLENGTH && count < 10){ + int neof; + count++; + init_pes(&pes); + if ((neof = read_pes(fin,&pes)) <= 0) return -1; + switch(pes.stream_id){ + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + rem->apes++; + if( rem->audio_info.layer < 0 && + (pes.flags2 & PTS_DTS) ) + add_apts(rem, pes.pts); + find_aframes( rem, pes.pes_pckt_data, pes.length); + ring_write(abuf,(char *)pes.pes_pckt_data,pes.length); + rem->awrite += pes.length; + break; + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + rem->vpes++; + if( !rem->video_info.framerate && + (pes.flags2 & PTS_DTS) ) + add_vpts(rem, pes.pts); + + find_vframes( rem, pes.pes_pckt_data, pes.length); + + ring_write(vbuf,(char *)pes.pes_pckt_data,pes.length); + rem->vwrite += pes.length; + break; + } + acount = abuf->size-ring_rest(abuf); + vcount = vbuf->size-ring_rest(vbuf); + kill_pes(&pes); + } + if (count < 10) return 0; + return 1; +} + +int vring_read( Remux *rem, uint8_t *buf, int l) +{ + int c = 0; + int r = 0; + + if (ring_rest(&rem->vid_buffy) <= l) + r = refill_buffy(rem); + if (r) return -1; + + c = ring_read(&rem->vid_buffy, (char *) buf, l); + rem->vread += c; + del_vpts(rem); + del_vframe(rem); + return c; +} + +int aring_read( Remux *rem, uint8_t *buf, int l) +{ + int c = 0; + int r = 0; + + if (ring_rest(&rem->aud_buffy) <= l) + r = refill_buffy(rem); + if (r) return -1; + + c = ring_read(&rem->aud_buffy, (char *)buf, l); + rem->aread += c; + del_apts(rem); + del_aframe(rem); + return c; +} + +int vring_peek( Remux *rem, uint8_t *buf, int l, long off) +{ + int c = 0; + + if (ring_rest(&rem->vid_buffy) <= l) + refill_buffy(rem); + + c = ring_peek(&rem->vid_buffy, (char *) buf, l, off); + return c; +} + +int aring_peek( Remux *rem, uint8_t *buf, int l, long off) +{ + int c = 0; + + if (ring_rest(&rem->aud_buffy) <= l) + refill_buffy(rem); + + c = ring_peek(&rem->aud_buffy, (char *)buf, l, off); + return c; +} + + +int get_video_info(Remux *rem) +{ + uint8_t buf[12]; + uint8_t *headr; + int found = 0; + int sw; + long off = 0; + int form = -1; + ringbuffy *vid_buffy = &rem->vid_buffy; + VideoInfo *vi = &rem->video_info; + + while (found < 4 && ring_rest(vid_buffy)){ + uint8_t b[3]; + + vring_peek( rem, b, 4, 0); + if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 + && b[3] == 0xb3) found = 4; + else { + off++; + vring_read( rem, b, 1); + } + } + rem->vframe = rem->vframen-1; + + if (! found) return -1; + buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x01; buf[3] = 0xb3; + headr = buf+4; + if(vring_peek(rem, buf, 12, 0) < 12) return -1; + + vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); + vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); + + sw = (int)((headr[3]&0xF0) >> 4) ; + + switch( sw ){ + case 1: + fprintf(stderr,"Videostream: ASPECT: 1:1"); + vi->aspect_ratio = 100; + break; + case 2: + fprintf(stderr,"Videostream: ASPECT: 4:3"); + vi->aspect_ratio = 133; + break; + case 3: + fprintf(stderr,"Videostream: ASPECT: 16:9"); + vi->aspect_ratio = 177; + break; + case 4: + fprintf(stderr,"Videostream: ASPECT: 2.21:1"); + vi->aspect_ratio = 221; + break; + + case 5 ... 15: + fprintf(stderr,"Videostream: ASPECT: reserved"); + vi->aspect_ratio = 0; + break; + + default: + vi->aspect_ratio = 0; + return -1; + } + + fprintf(stderr," Size = %dx%d",vi->horizontal_size,vi->vertical_size); + + sw = (int)(headr[3]&0x0F); + + switch ( sw ) { + case 1: + fprintf(stderr," FRate: 23.976 fps"); + vi->framerate = 24000/1001.; + form = -1; + break; + case 2: + fprintf(stderr," FRate: 24 fps"); + vi->framerate = 24; + form = -1; + break; + case 3: + fprintf(stderr," FRate: 25 fps"); + vi->framerate = 25; + form = VIDEO_MODE_PAL; + break; + case 4: + fprintf(stderr," FRate: 29.97 fps"); + vi->framerate = 30000/1001.; + form = VIDEO_MODE_NTSC; + break; + case 5: + fprintf(stderr," FRate: 30 fps"); + vi->framerate = 30; + form = VIDEO_MODE_NTSC; + break; + case 6: + fprintf(stderr," FRate: 50 fps"); + vi->framerate = 50; + form = VIDEO_MODE_PAL; + break; + case 7: + fprintf(stderr," FRate: 60 fps"); + vi->framerate = 60; + form = VIDEO_MODE_NTSC; + break; + } + + rem->dts_delay = (int)(7.0/vi->framerate/2.0*90000); + + vi->bit_rate = 400*(((headr[4] << 10) & 0x0003FC00UL) + | ((headr[5] << 2) & 0x000003FCUL) | + (((headr[6] & 0xC0) >> 6) & 0x00000003UL)); + + fprintf(stderr," BRate: %.2f Mbit/s",(vi->bit_rate)/1000000.); + + fprintf(stderr,"\n"); + vi->video_format = form; + + /* + marker_bit (&video_bs, 1); + vi->vbv_buffer_size = getbits (&video_bs, 10); + vi->CSPF = get1bit (&video_bs); + */ + return form; +} + + +int get_audio_info( Remux *rem) +{ + uint8_t *headr; + uint8_t buf[3]; + long off = 0; + int found = 0; + ringbuffy *aud_buffy = &rem->aud_buffy; + AudioInfo *ai = &rem->audio_info; + + while(!ring_rest(aud_buffy) && !refill_buffy(rem)); + while (found < 2 && ring_rest(aud_buffy)){ + uint8_t b[2]; + refill_buffy(rem); + aring_peek( rem, b, 2, 0); + + if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) + found = 2; + else { + off++; + aring_read( rem, b, 1); + } + } + + if (!found) return -1; + rem->aframe = rem->aframen-1; + + if (aring_peek(rem, buf, 3, 0) < 1) return -1; + headr = buf+2; + + ai->layer = (buf[1] & 0x06) >> 1; + + fprintf(stderr,"Audiostream: Layer: %d", 4-ai->layer); + + + ai->bit_rate = bitrates[(3-ai->layer)][(headr[0] >> 4 )]*1000; + + if (ai->bit_rate == 0) + fprintf (stderr," Bit rate: free"); + else if (ai->bit_rate == 0xf) + fprintf (stderr," BRate: reserved"); + else + fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); + + + ai->frequency = (headr[0] & 0x0c ) >> 2; + if (ai->frequency == 3) + fprintf (stderr, " Freq: reserved\n"); + else + fprintf (stderr," Freq: %2.1f kHz\n", + freq[ai->frequency]/10.); + + return 0; +} + + + +void init_remux(Remux *rem, int fin, int fout, int mult) +{ + rem->video_info.framerate = 0; + rem->audio_info.layer = -1; + rem->fin = fin; + rem->fout = fout; + ring_init(&rem->vid_buffy, 40*BUFFYSIZE*mult); + ring_init(&rem->aud_buffy, BUFFYSIZE*mult); + init_ptsl(rem->vpts_list); + init_ptsl(rem->apts_list); + init_framel(rem->vframe_list); + init_framel(rem->aframe_list); + + rem->vptsn = 0; + rem->aptsn = 0; + rem->vframen = 0; + rem->aframen = 0; + rem->vframe = 0; + rem->aframe = 0; + rem->vcframe = 0; + rem->acframe = 0; + rem->vpts = 0; + rem->vdts = 0; + rem->apts_off = 0; + rem->vpts_off = 0; + rem->apts_delay= 0; + rem->vpts_delay= 0; + rem->dts_delay = 0; + rem->apts = 0; + rem->vpes = 0; + rem->apes = 0; + rem->vpts_old = 0; + rem->apts_old = 0; + rem->SCR = 0; + rem->vwrite = 0; + rem->awrite = 0; + rem->vread = 0; + rem->aread = 0; + rem->group = 0; + rem->groupframe= 0; + rem->pack_size = 0; + rem->muxr = 0; + rem->time_off = 0; +} + +uint32_t bytes2pts(int bytes, int rate) +{ + if (bytes < 0xFFFFFFFFUL/720000UL) + return (uint32_t)(bytes*720000UL/rate); + else + return (uint32_t)(bytes/rate*720000UL); +} + +long pts2bytes( uint32_t pts, int rate) +{ + if (pts < 0xEFFFFFFFUL/rate) + return (pts*rate/720000); + else + return (pts* (rate/720000)); +} + +int write_audio_pes( Remux *rem, uint8_t *buf, int *alength) +{ + int add; + int pos = 0; + int p = 0; + uint32_t pts = 0; + int stuff = 0; + int length = *alength; + + if (!length) return 0; + p = PS_HEADER_L1+PES_H_MIN; + + if (rem->apts_old != rem->apts){ + pts = (uint32_t)((uint64_t)rem->apts + rem->apts_delay - rem->apts_off); + p += 5; + } + if ( length+p >= rem->pack_size){ + length = rem->pack_size; + } else { + if (rem->pack_size-length-p <= PES_MIN){ + stuff = rem->pack_size - length; + length = rem->pack_size; + } else + length = length+p; + } + pos = write_ps_header(buf,rem->SCR,rem->muxr, 1, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0); + + pos += write_pes_header( 0xC0, length-pos, pts, buf+pos, stuff); + add = aring_read( rem, buf+pos, length-pos); + *alength = add; + if (add < 0) return -1; + pos += add; + rem->apts_old = rem->apts; + rem->apts = rem->apts_list[0].PTS; + + if (pos+PES_MIN < rem->pack_size){ + pos += write_pes_header( PADDING_STREAM, rem->pack_size-pos, 0, + buf+pos, 0); + pos = rem->pack_size; + } + if (pos != rem->pack_size) { + fprintf(stderr,"apos: %d\n",pos); + exit(1); + } + + return pos; +} + +int write_video_pes( Remux *rem, uint8_t *buf, int *vlength) +{ + int add; + int pos = 0; + int p = 0; + uint32_t pts = 0; + uint32_t dts = 0; + int stuff = 0; + int length = *vlength; + long diff = 0; + + if (! length) return 0; + p = PS_HEADER_L1+PES_H_MIN; + + if (rem->vpts_old != rem->vpts){ + pts = (uint32_t)((uint64_t)rem->vpts + rem->vpts_delay - rem->vpts_off); + p += 5; + } + if ( length+p >= rem->pack_size){ + length = rem->pack_size; + } else { + if (rem->pack_size - length - p <= PES_MIN){ + stuff = rem->pack_size - length; + length = rem->pack_size; + } else + length = length+p; + } + + pos = write_ps_header(buf,rem->SCR,rem->muxr, 1, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0); + + pos += write_pes_header( 0xE0, length-pos, pts, buf+pos, stuff); + add = vring_read( rem, buf+pos, length-pos); + *vlength = add; + if (add < 0) return -1; + pos += add; + rem->vpts_old = rem->vpts; + dts = rem->vdts; + rem->vpts = rem->vpts_list[0].PTS; + rem->vdts = rem->vpts_list[0].dts; + if ( diff > 0) rem->SCR += diff; + if (pos+PES_MIN < rem->pack_size){ + // fprintf(stderr,"vstuffing: %d \n",rem->pack_size-pos); + pos += write_pes_header( PADDING_STREAM, rem->pack_size-pos, 0, + buf+pos, 0); + pos = rem->pack_size; + } + return pos; +} + +void print_info( Remux *rem , int ret) +{ + int newtime = 0; + static int time = 0; + int i = 0; + + while(! newtime && i < rem->vframen) { + if( (newtime = rem->vframe_list[i].time)) break; + i++; + } + if (newtime) time = newtime; + + fprintf(stderr,"SCR:"); + printpts(rem->SCR); + fprintf(stderr," VDTS:"); + printpts((uint32_t)((uint64_t)rem->vdts - rem->vpts_off + rem->vpts_delay)); + fprintf(stderr," APTS:"); + printpts((uint32_t)((uint64_t)rem->apts - rem->apts_off + rem->apts_delay)); + fprintf(stderr," TIME:%2d:", time/3600); + fprintf(stderr,"%02d:", (time%3600)/60); + fprintf(stderr,"%02d", (time%3600)%60); + if (ret) fprintf(stderr,"\n"); + else fprintf(stderr,"\r"); +} + +void remux(int fin, int fout, int pack_size, int mult) +{ + Remux rem; + long ptsdiff; + uint8_t buf[MAX_PACK_L]; + long pos = 0; + int r = 0; + int i, r1, r2; + long packets = 0; + uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 }; + uint32_t SCR_inc = 0; + int data_size; + long vbuf, abuf; + long vbuf_max, abuf_max; + PTS_List abufl[MAX_PTS]; + PTS_List vbufl[MAX_PTS]; + int abufn = 0; + int vbufn = 0; + uint64_t pts_d = 0; + int ok_audio; + int ok_video; + uint32_t apos = 0; + uint32_t vpos = 0; + int vpack_size = 0; + int apack_size = 0; + + init_ptsl(abufl); + init_ptsl(vbufl); + + if (mult < 0 || mult >1000){ + fprintf(stderr,"Multipler too large\n"); + exit(1); + } + init_remux(&rem, fin, fout, mult); + rem.pack_size = pack_size; + data_size = pack_size - MAX_H_SIZE; + fprintf(stderr,"pack_size: %d header_size: %d data size: %d\n", + pack_size, MAX_H_SIZE, data_size); + refill_buffy(&rem); + fprintf(stderr,"Package size: %d\n",pack_size); + + if ( get_video_info(&rem) < 0 ){ + fprintf(stderr,"ERROR: Can't find valid video stream\n"); + exit(1); + } + + i = 0; + while(! rem.time_off && i < rem.vframen) { + if( (rem.time_off = rem.vframe_list[i].time)) break; + i++; + } + + if ( get_audio_info(&rem) < 0 ){ + fprintf(stderr,"ERROR: Can't find valid audio stream\n"); + exit(1); + } + + rem.vpts = rem.vpts_list[0].PTS; + rem.vdts = rem.vpts; + rem.vpts_off = rem.vpts; + fprintf(stderr,"Video start PTS = %fs \n",rem.vpts_off/90000.); + rem.apts = rem.apts_list[0].PTS; + rem.apts_off = rem.apts; + ptsdiff = rem.vpts - rem.apts; + if (ptsdiff > 0) rem.vpts_off -= ptsdiff; + else rem.apts_off -= -ptsdiff; + fprintf(stderr,"Audio start PTS = %fs\n",rem.apts_off/90000.); + fprintf(stderr,"Difference Video - Audio = %fs\n",ptsdiff/90000.); + fprintf(stderr,"Time offset = %ds\n",rem.time_off); + + rem.muxr = (rem.video_info.bit_rate + + rem.audio_info.bit_rate)/400; + fprintf(stderr,"MUXRATE: %.2f Mb/sec\n",rem.muxr/2500.); + SCR_inc = 1800 * pack_size / rem.muxr; + + r = 0; + while ( rem.vptsn < 2 && !r) r = refill_buffy(&rem); + r = 0; + while ( rem.aptsn < 2 && !r) r = refill_buffy(&rem); + + //rem.vpts_delay = (uint32_t)(2*90000ULL* (uint64_t)pack_size/rem.muxr); + rem.vpts_delay = rem.dts_delay; + rem.apts_delay = rem.vpts_delay; + + vbuf_max = 29440; + abuf_max = 4096; + vbuf = 0; + abuf = 0; + pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, + 0xC0, 0, 32, 0xE0, 1, 230); + pos += write_pes_header( PADDING_STREAM, pack_size-pos, 0, buf+pos,0); + pos = rem.pack_size; + write( fout, buf, pos); + + apos = rem.aread; + vpos = rem.vread; + print_info( &rem, 1 ); + + while( ring_rest(&rem.aud_buffy) && ring_rest(&rem.vid_buffy) ){ + uint32_t next_apts; + uint32_t next_vdts; + int asize, vsize; + + r1 = 0; + r2 = 0; + while ( rem.aframen < 2 && !r1) + r1 = refill_buffy(&rem); + while ( rem.vframen < 2 && !r2) + r2 = refill_buffy(&rem); + if (r1 && r2) break; + + if ( !r1 && apos <= rem.aread) + apos = rem.aframe_list[1].pos; + if ( !r2 && vpos <= rem.vread) + vpos = rem.vframe_list[1].pos; + apack_size = apos - rem.aread; + vpack_size = vpos - rem.vread; + + + next_vdts = (uint32_t)((uint64_t)rem.vdts + rem.vpts_delay + - rem.vpts_off) ; + ok_video = ( rem.SCR < next_vdts); + + next_apts = (uint32_t)((uint64_t)rem.apts + rem.apts_delay + - rem.apts_off) ; + ok_audio = ( rem.SCR < next_apts); + + asize = (apack_size > data_size ? data_size: apack_size); + vsize = (vpack_size > data_size ? data_size: vpack_size); + + fprintf(stderr,"vframen: %d aframen: %d v_ok: %d a_ok: %d v_buf: %d a_buf: %d vpacks: %d apacks: %d\n",rem.vframen,rem.aframen, ok_video, ok_audio, (int)vbuf,(int)abuf,vsize, asize); + + + if( vbuf+vsize < vbuf_max && vsize && ok_audio ){ + fprintf(stderr,"1 "); + pos = write_video_pes( &rem, buf, &vpack_size); + write( fout, buf, pos); + vbuf += vpack_size; + vbufn = add_pts( vbufl, rem.vdts, vpack_size, + 0, vbufn, 0); + packets++; + } else if ( abuf+asize < abuf_max && asize && + ok_video ){ + fprintf(stderr,"2 "); + pos = write_audio_pes( &rem, buf, &apack_size); + write( fout, buf, pos); + abuf += apack_size; + abufn = add_pts( abufl, rem.apts, apack_size, + 0, abufn, 0); + packets++; + } else if ( abuf+asize < abuf_max && asize && + !ok_audio){ + fprintf(stderr,"3 "); + pos = write_audio_pes( &rem, buf, &apack_size); + write( fout, buf, pos); + abuf += apack_size; + abufn = add_pts( abufl, rem.apts, apack_size, + 0, abufn, 0); + packets++; + } else if (vbuf+vsize < vbuf_max && vsize && + !ok_video){ + fprintf(stderr,"4 "); + pos = write_video_pes( &rem, buf, &vpack_size); + write( fout, buf, pos); + vbuf += vpack_size; + vbufn = add_pts( vbufl, rem.vdts, vpack_size, + 0, vbufn, 0); + packets++; + } else { + fprintf(stderr,"5 "); + pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 0); + + pos += write_pes_header( PADDING_STREAM, pack_size-pos, + 0, buf+pos, 0); + write( fout, buf, pos); + } + + + //fprintf(stderr,"vbufn: %d abufn: %d ", vbufn,abufn); + //fprintf(stderr,"vbuf: %5d abuf: %4d\n", vbuf,abuf); + + if (rem.SCR > rem.vdts+rem.vpts_off -rem.vpts_delay) + rem.SCR = rem.vdts-rem.vpts_off; + rem.SCR = (uint32_t)((uint64_t) rem.SCR + SCR_inc); + + if ( rem.apts_off + rem.SCR < rem.apts_delay ) pts_d = 0; + else pts_d = (uint64_t) rem.SCR + rem.apts_off - rem.apts_delay; + abuf -= del_ptss( abufl, (uint32_t) pts_d, &abufn); + + if ( rem.vpts_off + rem.SCR < rem.vpts_delay ) pts_d = 0; + else pts_d = (uint64_t) rem.SCR + rem.vpts_off - rem.vpts_delay; + vbuf -= del_ptss( vbufl, (uint32_t) pts_d, &vbufn); + + print_info( &rem, 1); + //fprintf(stderr,"vbufn: %d abufn: %d ", vbufn,abufn); + //fprintf(stderr,"vbuf: %5d abuf: %4d\n\n", vbuf,abuf); + + + } + pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0); + + pos += write_pes_header( PADDING_STREAM, pack_size-pos-4, 0, + buf+pos, 0); + pos = rem.pack_size-4; + write( fout, buf, pos); + + write( fout, mpeg_end, 4); + fprintf(stderr,"\ndone\n"); +} + + +typedef +struct pes_buffer_s{ + ringbuffy pes_buffy; + uint8_t type; + PTS_List pts_list[MAX_PTS]; + FRAME_List frame_list[MAX_FRAME]; + int pes_size; + uint64_t written; + uint64_t read; +} PESBuffer; + + +void init_PESBuffer(PESBuffer *pbuf, int pes_size, int buf_size, uint8_t type) +{ + init_framel( pbuf->frame_list); + init_ptsl( pbuf->pts_list); + ring_init( &pbuf->pes_buffy, buf_size); + pbuf->pes_size = pes_size; + pbuf->type = type; + pbuf->written = 0; + pbuf->read = 0; +} + + +#define MAX_PBUF 4 + +typedef +struct remux_s{ + PESBuffer pbuf_list[MAX_PBUF]; + int num_pbuf; +} REMUX; + + +void init_REMUX(REMUX *rem) +{ + rem->num_pbuf = 0; +} + + + +#define REPACK 2048 +#define ABUF_SIZE REPACK*1024 +#define VBUF_SIZE REPACK*10240 + +void remux_main(uint8_t *buf, int count, void *pr) +{ + int i, b; + int bufsize = 0; + p2p *p = (p2p *) pr; + PESBuffer *pbuf; + REMUX *rem = (REMUX *) p->data; + uint8_t type = buf[3]; + int *npbuf = &(rem->num_pbuf); + + switch ( type ){ + case PRIVATE_STREAM1: + bufsize = ABUF_SIZE; + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + if (!bufsize) bufsize = VBUF_SIZE; + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + if (!bufsize) bufsize = ABUF_SIZE; + b = -1; + for ( i = 0; i < *npbuf; i++){ + if ( type == rem->pbuf_list[i].type ){ + b = i; + break; + } + } + if (b < 0){ + if ( *npbuf < MAX_PBUF ){ + init_PESBuffer(&rem->pbuf_list[*npbuf], + p->repack+6, bufsize, type); + b = *npbuf; + (*npbuf)++; + } else { + fprintf(stderr,"Not enough PES buffers\n"); + exit(1); + } + } + break; + default: + return; + } + + pbuf = &(rem->pbuf_list[b]); + if (ring_write(&(pbuf->pes_buffy),(char *)buf,count) != count){ + fprintf(stderr,"buffer overflow type 0x%2x\n",type); + exit(1); + } else { + pbuf->written += count; + if ((p->flag2 & PTS_DTS_FLAGS)){ + uint32_t PTS = trans_pts_dts(p->pts); + add_pts(pbuf->pts_list, PTS, pbuf->written, + pbuf->written, 0, 0); + } + p->flag2 = 0; + } + +} + +void output_mux(p2p *p) +{ + int i, filling; + PESBuffer *pbuf; + ringbuffy *pes_buffy; + REMUX *rem = (REMUX *) p->data; + int repack = p->repack; + int npbuf = rem->num_pbuf; + + for ( i = 0; i < npbuf; i++){ + pbuf = &(rem->pbuf_list[i]); + pes_buffy = &pbuf->pes_buffy; + filling = pes_buffy->size - ring_rest(pes_buffy); + if (filling/(2 *repack)){ + pbuf->read += ring_read_file(pes_buffy, p->fd1, + (filling/repack)*repack); + } + } +} + + + +#define SIZE 32768 + +void remux2(int fdin, int fdout) +{ + p2p p; + int count = 1; + uint8_t buf[SIZE]; + uint64_t length = 0; + uint64_t l = 0; + int verb = 0; + REMUX rem; + + init_p2p(&p, remux_main, REPACK); + p.fd1 = fdout; + p.data = (void *) &rem; + + + if (fdin != STDIN_FILENO) verb = 1; + + if (verb) { + length = lseek(fdin, 0, SEEK_END); + lseek(fdin,0,SEEK_SET); + } + + while (count > 0){ + count = read(fdin,buf,SIZE); + l += count; + if (verb) + fprintf(stderr,"Writing %2.2f %%\r", + 100.*l/length); + + get_pes(buf,count,&p,pes_repack); + output_mux(&p); + } + +} diff --git a/libdvbmpeg/remux.h b/libdvbmpeg/remux.h new file mode 100644 index 0000000..76c128b --- /dev/null +++ b/libdvbmpeg/remux.h @@ -0,0 +1,149 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002 Marcus Metzler + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at mocm@metzlerbros.de, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#include "ringbuffy.h" +#include "ctools.h" + +#ifndef _REMUX_H_ +#define _REMUX_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + typedef struct video_i{ + uint32_t horizontal_size; + uint32_t vertical_size ; + uint32_t aspect_ratio ; + double framerate ; + uint32_t video_format; + uint32_t bit_rate ; + uint32_t comp_bit_rate ; + uint32_t vbv_buffer_size; + uint32_t CSPF ; + uint32_t off; + } VideoInfo; + + typedef struct audio_i{ + int layer; + uint32_t bit_rate; + uint32_t frequency; + uint32_t mode; + uint32_t mode_extension; + uint32_t emphasis; + uint32_t framesize; + uint32_t off; + } AudioInfo; + + + + typedef + struct PTS_list_struct{ + uint32_t PTS; + int pos; + uint32_t dts; + int spos; + } PTS_List; + + typedef + struct frame_list_struct{ + int type; + int pos; + uint32_t FRAME; + uint32_t time; + uint32_t pts; + uint32_t dts; + } FRAME_List; + + typedef + struct remux_struct{ + ringbuffy vid_buffy; + ringbuffy aud_buffy; + PTS_List vpts_list[MAX_PTS]; + PTS_List apts_list[MAX_PTS]; + FRAME_List vframe_list[MAX_FRAME]; + FRAME_List aframe_list[MAX_FRAME]; + int vptsn; + int aptsn; + int vframen; + int aframen; + long apes; + long vpes; + uint32_t vframe; + uint32_t aframe; + uint32_t vcframe; + uint32_t acframe; + uint32_t vpts; + uint32_t vdts; + uint32_t apts; + uint32_t vpts_old; + uint32_t apts_old; + uint32_t SCR; + uint32_t apts_off; + uint32_t vpts_off; + uint32_t apts_delay; + uint32_t vpts_delay; + uint32_t dts_delay; + AudioInfo audio_info; + VideoInfo video_info; + int fin; + int fout; + long int awrite; + long int vwrite; + long int aread; + long int vread; + uint32_t group; + uint32_t groupframe; + uint32_t muxr; + int pack_size; + uint32_t time_off; + } Remux; + + enum { NONE, I_FRAME, P_FRAME, B_FRAME, D_FRAME }; + + void remux(int fin, int fout, int pack_size, int mult); + void remux2(int fdin, int fdout); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /*_REMUX_H_*/ diff --git a/libdvbmpeg/ringbuffy.c b/libdvbmpeg/ringbuffy.c new file mode 100644 index 0000000..8451009 --- /dev/null +++ b/libdvbmpeg/ringbuffy.c @@ -0,0 +1,200 @@ +/* + Ringbuffer Implementation for gtvscreen + + Copyright (C) 2000 Marcus Metzler (mocm@metzlerbros.de) + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "ringbuffy.h" + +int ring_init (ringbuffy *rbuf, int size) +{ + if (size > 0){ + rbuf->size = size; + if( !(rbuf->buffy = (char *) malloc(sizeof(char)*size)) ){ + fprintf(stderr,"Not enough memory for ringbuffy\n"); + return -1; + } + } else { + fprintf(stderr,"Wrong size for ringbuffy\n"); + return -1; + } + rbuf->read_pos = 0; + rbuf->write_pos = 0; + return 0; +} + + +void ring_destroy(ringbuffy *rbuf) +{ + free(rbuf->buffy); +} + + +int ring_write(ringbuffy *rbuf, char *data, int count) +{ + + int diff, free, pos, rest; + + if (count <=0 ) return 0; + pos = rbuf->write_pos; + rest = rbuf->size - pos; + diff = rbuf->read_pos - pos; + free = (diff > 0) ? diff-1 : rbuf->size+diff-1; + + if ( free <= 0 ) return FULL_BUFFER; + if ( free < count ) count = free; + + if (count >= rest){ + memcpy (rbuf->buffy+pos, data, rest); + if (count - rest) + memcpy (rbuf->buffy, data+rest, count - rest); + rbuf->write_pos = count - rest; + } else { + memcpy (rbuf->buffy+pos, data, count); + rbuf->write_pos += count; + } + + return count; +} + + + + +int ring_peek(ringbuffy *rbuf, char *data, int count, long off) +{ + + int diff, free, pos, rest; + + if (count <=0 ) return 0; + pos = rbuf->read_pos+off; + rest = rbuf->size - pos ; + diff = rbuf->write_pos - pos; + free = (diff >= 0) ? diff : rbuf->size+diff; + + if ( free <= 0 ) return FULL_BUFFER; + if ( free < count ) count = free; + + if ( count < rest ){ + memcpy(data, rbuf->buffy+pos, count); + } else { + memcpy(data, rbuf->buffy+pos, rest); + if ( count - rest) + memcpy(data+rest, rbuf->buffy, count - rest); + } + + return count; +} + +int ring_read(ringbuffy *rbuf, char *data, int count) +{ + + int diff, free, pos, rest; + + if (count <=0 ) return 0; + pos = rbuf->read_pos; + rest = rbuf->size - pos; + diff = rbuf->write_pos - pos; + free = (diff >= 0) ? diff : rbuf->size+diff; + + if ( rest <= 0 ) return 0; + if ( free < count ) count = free; + + if ( count < rest ){ + memcpy(data, rbuf->buffy+pos, count); + rbuf->read_pos += count; + } else { + memcpy(data, rbuf->buffy+pos, rest); + if ( count - rest) + memcpy(data+rest, rbuf->buffy, count - rest); + rbuf->read_pos = count - rest; + } + + return count; +} + + + +int ring_write_file(ringbuffy *rbuf, int fd, int count) +{ + + int diff, free, pos, rest, rr; + + if (count <=0 ) return 0; + pos = rbuf->write_pos; + rest = rbuf->size - pos; + diff = rbuf->read_pos - pos; + free = (diff > 0) ? diff-1 : rbuf->size+diff-1; + + if ( rest <= 0 ) return 0; + if ( free < count ) count = free; + + if (count >= rest){ + rr = read (fd, rbuf->buffy+pos, rest); + if (rr == rest && count - rest) + rr += read (fd, rbuf->buffy, count - rest); + if (rr >=0) + rbuf->write_pos = (pos + rr) % rbuf->size; + } else { + rr = read (fd, rbuf->buffy+pos, count); + if (rr >=0) + rbuf->write_pos += rr; + } + + return rr; +} + + + +int ring_read_file(ringbuffy *rbuf, int fd, int count) +{ + + int diff, free, pos, rest, rr; + + if (count <=0 ) return 0; + pos = rbuf->read_pos; + rest = rbuf->size - pos; + diff = rbuf->write_pos - pos; + free = (diff >= 0) ? diff : rbuf->size+diff; + + if ( free <= 0 ) return FULL_BUFFER; + if ( free < count ) count = free; + + if (count >= rest){ + rr = write (fd, rbuf->buffy+pos, rest); + if (rr == rest && count - rest) + rr += write (fd, rbuf->buffy, count - rest); + if (rr >=0) + rbuf->read_pos = (pos + rr) % rbuf->size; + } else { + rr = write (fd, rbuf->buffy+pos, count); + if (rr >=0) + rbuf->read_pos += rr; + } + + + return rr; +} + +int ring_rest(ringbuffy *rbuf){ + int diff, free, pos, rest; + pos = rbuf->read_pos; + rest = rbuf->size - pos; + diff = rbuf->write_pos - pos; + free = (diff >= 0) ? diff : rbuf->size+diff; + + return free; +} diff --git a/libdvbmpeg/ringbuffy.h b/libdvbmpeg/ringbuffy.h new file mode 100644 index 0000000..16011d7 --- /dev/null +++ b/libdvbmpeg/ringbuffy.h @@ -0,0 +1,52 @@ +/* + Ringbuffer Implementation for gtvscreen + + Copyright (C) 2000 Marcus Metzler (mocm@metzlerbros.de) + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef RINGBUFFY_H +#define RINGBUFFY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define FULL_BUFFER -1000 +typedef struct ringbuffy{ + int read_pos; + int write_pos; + int size; + char *buffy; +} ringbuffy; + +int ring_init (ringbuffy *rbuf, int size); +void ring_destroy(ringbuffy *rbuf); +int ring_write(ringbuffy *rbuf, char *data, int count); +int ring_read(ringbuffy *rbuf, char *data, int count); +int ring_write_file(ringbuffy *rbuf, int fd, int count); +int ring_read_file(ringbuffy *rbuf, int fd, int count); +int ring_rest(ringbuffy *rbuf); +int ring_peek(ringbuffy *rbuf, char *data, int count, long off); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* RINGBUFFY_H */ diff --git a/libdvbmpeg/transform.c b/libdvbmpeg/transform.c new file mode 100644 index 0000000..c53f1fb --- /dev/null +++ b/libdvbmpeg/transform.c @@ -0,0 +1,2681 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002 Marcus Metzler + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at marcus@convergence.de, + + * the project's page is at http://linuxtv.org/dvb/ + */ + + +#include "transform.h" +#include +#include +#include "ctools.h" + +static uint8_t tspid0[TS_SIZE] = { + 0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xb0, 0x11, + 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x10, 0x00, 0x01, 0xe4, 0x00, 0x2a, 0xd6, 0x1a, + 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +static uint8_t tspid1[TS_SIZE] = { + 0x47, 0x44, 0x00, 0x10, 0x00, 0x02, 0xb0, 0x1c, + 0x00, 0x01, 0xcb, 0x00, 0x00, 0xe0, 0xa0, 0xf0, + 0x05, 0x48, 0x03, 0x01, 0x00, 0x00, 0x02, 0xe0, + 0xa0, 0xf0, 0x00, 0x03, 0xe0, 0x50, 0xf0, 0x00, + 0xae, 0xea, 0x4e, 0x48, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +// CRC32 lookup table for polynomial 0x04c11db7 +static const uint32_t crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +static uint32_t +calc_crc32 (const uint8_t *sec, uint8_t len) +{ + int i; + uint32_t crc = 0xffffffff; + + for (i = 0; i < len; i++) + crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *sec++) & 0xff]; + + return crc; +} + + +uint64_t trans_pts_dts(uint8_t *pts) +{ + uint64_t wts; + + wts = ((uint64_t)((pts[0] & 0x0E) << 5) | + ((pts[1] & 0xFC) >> 2)) << 24; + wts |= (((pts[1] & 0x03) << 6) | + ((pts[2] & 0xFC) >> 2)) << 16; + wts |= (((pts[2] & 0x02) << 6) | + ((pts[3] & 0xFE) >> 1)) << 8; + wts |= (((pts[3] & 0x01) << 7) | + ((pts[4] & 0xFE) >> 1)); + return wts; +} + + +void get_pespts(uint8_t *av_pts,uint8_t *pts) +{ + + pts[0] = 0x21 | + ((av_pts[0] & 0xC0) >>5); + pts[1] = ((av_pts[0] & 0x3F) << 2) | + ((av_pts[1] & 0xC0) >> 6); + pts[2] = 0x01 | ((av_pts[1] & 0x3F) << 2) | + ((av_pts[2] & 0x80) >> 6); + pts[3] = ((av_pts[2] & 0x7F) << 1) | + ((av_pts[3] & 0x80) >> 7); + pts[4] = 0x01 | ((av_pts[3] & 0x7F) << 1); +} + +uint16_t get_pid(uint8_t *pid) +{ + uint16_t pp = 0; + + pp = (pid[0] & PID_MASK_HI)<<8; + pp |= pid[1]; + + return pp; +} + +int write_ts_header(uint16_t pid, uint8_t *counter, int pes_start, + uint8_t *buf, uint8_t length) +{ + int i; + int c = 0; + int fill; + uint8_t tshead[4] = { 0x47, 0x00, 0x00, 0x10}; + + + fill = TS_SIZE-4-length; + if (pes_start) tshead[1] = 0x40; + if (fill) tshead[3] = 0x30; + tshead[1] |= (uint8_t)((pid & 0x1F00) >> 8); + tshead[2] |= (uint8_t)(pid & 0x00FF); + tshead[3] |= ((*counter)++ & 0x0F) ; + memcpy(buf,tshead,4); + c+=4; + + + if (fill){ + buf[4] = fill-1; + c++; + if (fill >1){ + buf[5] = 0x00; + c++; + } + for ( i = 6; i < fill+4; i++){ + buf[i] = 0xFF; + c++; + } + } + + return c; +} + + +int write_pes_header(uint8_t id,int length , long PTS, uint8_t *obuf, + int stuffing) +{ + uint8_t le[2]; + uint8_t dummy[3]; + uint8_t *pts; + uint8_t ppts[5]; + long lpts; + int c; + uint8_t headr[3] = {0x00, 0x00, 0x01}; + + lpts = htonl(PTS); + pts = (uint8_t *) &lpts; + + get_pespts(pts,ppts); + + c = 0; + memcpy(obuf+c,headr,3); + c += 3; + memcpy(obuf+c,&id,1); + c++; + + le[0] = 0; + le[1] = 0; + length -= 6+stuffing; + + le[0] |= ((uint8_t)(length >> 8) & 0xFF); + le[1] |= ((uint8_t)(length) & 0xFF); + memcpy(obuf+c,le,2); + c += 2; + + if (id == PADDING_STREAM){ + memset(obuf+c,0xff,length); + c+= length; + return c; + } + + dummy[0] = 0x80; + dummy[1] = 0; + dummy[2] = 0; + if (PTS){ + dummy[1] |= PTS_ONLY; + dummy[2] = 5+stuffing; + } + memcpy(obuf+c,dummy,3); + c += 3; + memset(obuf+c,0xFF,stuffing); + + if (PTS){ + memcpy(obuf+c,ppts,5); + c += 5; + } + + return c; +} + + +void init_p2p(p2p *p, void (*func)(uint8_t *buf, int count, void *p), + int repack){ + p->found = 0; + p->cid = 0; + p->mpeg = 0; + memset(p->buf,0,MMAX_PLENGTH); + p->done = 0; + p->fd1 = -1; + p->func = func; + p->bigend_repack = 0; + p->repack = 0; + if ( repack < MAX_PLENGTH && repack > 265 ){ + p->repack = repack-6; + p->bigend_repack = (uint16_t)htons((short) + ((repack-6) & 0xFFFF)); + } else { + fprintf(stderr, "Repack size %d is out of range\n",repack); + exit(1); + } +} + + + +void pes_repack(p2p *p) +{ + int count = 0; + int repack = p->repack; + int rest = p->plength; + uint8_t buf[MAX_PLENGTH]; + int bfill = 0; + int diff; + uint16_t length; + + if (rest < 0) { + fprintf(stderr,"Error in repack\n"); + return; + } + + if (!repack){ + fprintf(stderr,"forgot to set repack size\n"); + return; + } + + if (p->plength == repack){ + memcpy(p->buf+4,(char *)&p->bigend_repack,2); + p->func(p->buf, repack+6, p); + return; + } + + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x01; + buf[3] = p->cid; + memcpy(buf+4,(char *)&p->bigend_repack,2); + memset(buf+6,0,MAX_PLENGTH-6); + + if (p->mpeg == 2){ + + if ( rest > repack){ + memcpy(p->buf+4,(char *)&p->bigend_repack,2); + p->func(p->buf, repack+6, p); + count += repack+6; + rest -= repack; + } else { + memcpy(buf,p->buf,9+p->hlength); + bfill = p->hlength; + count += 9+p->hlength; + rest -= p->hlength+3; + } + + while (rest >= repack-3){ + memset(buf+6,0,MAX_PLENGTH-6); + buf[6] = 0x80; + buf[7] = 0x00; + buf[8] = 0x00; + memcpy(buf+9,p->buf+count,repack-3); + rest -= repack-3; + count += repack-3; + p->func(buf, repack+6, p); + } + + if (rest){ + diff = repack - 3 - rest - bfill; + if (!bfill){ + buf[6] = 0x80; + buf[7] = 0x00; + buf[8] = 0x00; + } + + if ( diff < PES_MIN){ + length = rest+ diff + bfill+3; + buf[4] = (uint8_t)((length & 0xFF00) >> 8); + buf[5] = (uint8_t)(length & 0x00FF); + buf[8] = (uint8_t)(bfill+diff); + memset(buf+9+bfill,0xFF,diff); + memcpy(buf+9+bfill+diff,p->buf+count,rest); + } else { + length = rest+ bfill+3; + buf[4] = (uint8_t)((length & 0xFF00) >> 8); + buf[5] = (uint8_t)(length & 0x00FF); + memcpy(buf+9+bfill,p->buf+count,rest); + bfill += rest+9; + write_pes_header( PADDING_STREAM, diff, 0, + buf+bfill, 0); + } + p->func(buf, repack+6, p); + } + } + + if (p->mpeg == 1){ + + if ( rest > repack){ + memcpy(p->buf+4,(char *)&p->bigend_repack,2); + p->func(p->buf, repack+6, p); + count += repack+6; + rest -= repack; + } else { + memcpy(buf,p->buf,6+p->hlength); + bfill = p->hlength; + count += 6; + rest -= p->hlength; + } + + while (rest >= repack-1){ + memset(buf+6,0,MAX_PLENGTH-6); + buf[6] = 0x0F; + memcpy(buf+7,p->buf+count,repack-1); + rest -= repack-1; + count += repack-1; + p->func(buf, repack+6, p); + } + + + if (rest){ + diff = repack - 1 - rest - bfill; + + if ( diff < PES_MIN){ + length = rest+ diff + bfill+1; + buf[4] = (uint8_t)((length & 0xFF00) >> 8); + buf[5] = (uint8_t)(length & 0x00FF); + memset(buf+6,0xFF,diff); + if (!bfill){ + buf[6+diff] = 0x0F; + } + memcpy(buf+7+diff,p->buf+count,rest+bfill); + } else { + length = rest+ bfill+1; + buf[4] = (uint8_t)((length & 0xFF00) >> 8); + buf[5] = (uint8_t)(length & 0x00FF); + if (!bfill){ + buf[6] = 0x0F; + memcpy(buf+7,p->buf+count,rest); + bfill = rest+7; + } else { + memcpy(buf+6,p->buf+count,rest+bfill); + bfill += rest+6; + } + write_pes_header( PADDING_STREAM, diff, 0, + buf+bfill, 0); + } + p->func(buf, repack+6, p); + } + } +} + + + + + + + + +int filter_pes (uint8_t *buf, int count, p2p *p, int (*func)(p2p *p)) +{ + + int l; + unsigned short *pl; + int c=0; + int ret = 1; + + uint8_t headr[3] = { 0x00, 0x00, 0x01} ; + + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)){ + switch ( p->found ){ + case 0: + case 1: + if (buf[c] == 0x00) p->found++; + else { + if (p->fd1 >= 0) + write(p->fd1,buf+c,1); + p->found = 0; + } + c++; + break; + case 2: + if (buf[c] == 0x01) p->found++; + else if (buf[c] == 0){ + p->found = 2; + } else { + if (p->fd1 >= 0) + write(p->fd1,buf+c,1); + p->found = 0; + } + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]){ + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + if (p->fd1 >= 0) + write(p->fd1,buf+c,1); + p->done = 1; + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + if (p->fd1 >= 0) + write(p->fd1,buf+c,1); + p->found = 0; + break; + } + break; + + + case 4: + if (count-c > 1){ + pl = (unsigned short *) (buf+c); + p->plength = ntohs(*pl); + p->plen[0] = buf[c]; + c++; + p->plen[1] = buf[c]; + c++; + p->found+=2; + } else { + p->plen[0] = buf[c]; + p->found++; + return 1; + } + break; + case 5: + p->plen[1] = buf[c]; + c++; + pl = (unsigned short *) p->plen; + p->plength = ntohs(*pl); + p->found++; + break; + + + case 6: + if (!p->done){ + p->flag1 = buf[c]; + c++; + p->found++; + if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; + } + } + break; + + case 7: + if ( !p->done && p->mpeg == 2){ + p->flag2 = buf[c]; + c++; + p->found++; + } + break; + + case 8: + if ( !p->done && p->mpeg == 2){ + p->hlength = buf[c]; + c++; + p->found++; + } + break; + + default: + + break; + } + } + + if (!p->plength) p->plength = MMAX_PLENGTH-6; + + + if ( p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7)) ){ + switch (p->cid){ + + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + + memcpy(p->buf, headr, 3); + p->buf[3] = p->cid; + memcpy(p->buf+4,p->plen,2); + + if (p->mpeg == 2 && p->found == 9){ + p->buf[6] = p->flag1; + p->buf[7] = p->flag2; + p->buf[8] = p->hlength; + } + + if (p->mpeg == 1 && p->found == 7){ + p->buf[6] = p->flag1; + } + + + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14){ + while (c < count && p->found < 14){ + p->pts[p->found-9] = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + } + if (c == count) return 1; + } + + if (p->mpeg == 1 && p->which < 2000){ + + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } + + while (!p->which && c < count && + p->check == 0xFF){ + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + } + + if ( c == count) return 1; + + if ( (p->check & 0xC0) == 0x40 && !p->which){ + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + + p->which = 1; + if ( c == count) return 1; + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return 1; + } + + if (p->which == 1){ + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return 1; + } + + if ( (p->check & 0x30) && p->check != 0xFF){ + p->flag2 = (p->check & 0xF0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + + if ( c == count) return 1; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_ONLY){ + while (c < count && + p->which < 7){ + p->pts[p->which-2] = + buf[c]; + p->buf[p->found] = + buf[c]; + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return 1; + } else if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_DTS){ + while (c < count && + p->which< 12){ + if (p->which< 7) + p->pts[p->which + -2] = + buf[c]; + p->buf[p->found] = + buf[c]; + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return 1; + } + p->which = 2000; + } + + } + + while (c < count && p->found < p->plength+6){ + l = count -c; + if (l+p->found > p->plength+6) + l = p->plength+6-p->found; + memcpy(p->buf+p->found, buf+c, l); + p->found += l; + c += l; + } + if(p->found == p->plength+6){ + if (func(p)){ + if (p->fd1 >= 0){ + write(p->fd1,p->buf, + p->plength+6); + } + } else ret = 0; + } + break; + } + + + if ( p->done ){ + if( p->found + count - c < p->plength+6){ + p->found += count-c; + c = count; + } else { + c += p->plength+6 - p->found; + p->found = p->plength+6; + } + } + + if (p->plength && p->found == p->plength+6) { + p->found = 0; + p->done = 0; + p->plength = 0; + memset(p->buf, 0, MAX_PLENGTH); + if (c < count) + return filter_pes(buf+c, count-c, p, func); + } + } + return ret; +} + + +#define SIZE 4096 + + +int audio_pes_filt(p2p *p) +{ + uint8_t off; + + switch(p->cid){ + case PRIVATE_STREAM1: + if ( p->cid == p->filter) { + off = 9+p->buf[8]; + if (p->buf[off] == p->subid){ + return 1; + } + } + break; + + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + if ( p->cid == p->filter) + return 1; + break; + + default: + return 1; + break; + } + return 0; +} + + +void filter_audio_from_pes(int fdin, int fdout, uint8_t id, uint8_t subid) +{ + p2p p; + int count = 1; + uint8_t buf[2048]; + + init_p2p(&p, NULL, 2048); + p.fd1 = -1; + p.filter = id; + p.subid = subid; + + while (count > 0){ + count = read(fdin,buf,2048); + if(filter_pes(buf,count,&p,audio_pes_filt)) + write(fdout,buf,2048); + } +} + + +void pes_filt(p2p *p) +{ + int factor = p->mpeg-1; + + if ( p->cid == p->filter) { + if (p->es) + write(p->fd1,p->buf+p->hlength+6+3*factor, + p->plength-p->hlength-3*factor); + else + write(p->fd1,p->buf,p->plength+6); + } +} + +void extract_from_pes(int fdin, int fdout, uint8_t id, int es) +{ + p2p p; + int count = 1; + uint8_t buf[SIZE]; + + init_p2p(&p, NULL, 2048); + p.fd1 = fdout; + p.filter = id; + p.es = es; + + while (count > 0){ + count = read(fdin,buf,SIZE); + get_pes(buf,count,&p,pes_filt); + } +} + + +void pes_dfilt(p2p *p) +{ + int factor = p->mpeg-1; + int fd =0; + int head=0; + int type = NOPES; + int streamid; + int c = 6+p->hlength+3*factor; + + + switch ( p->cid ) { + case PRIVATE_STREAM1: + streamid = p->buf[c]; + head = 4; + if ((streamid & 0xF8) == 0x80+p->es-1){ + fd = p->fd1; + type = AC3; + } + break; + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + fd = p->fd1; + type = AUDIO; + break; + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + fd = p->fd2; + type = VIDEO; + break; + } + + if (p->es && !p->startv && type == VIDEO){ + int found = 0; + + if ( p->flag2 & PTS_DTS ) + p->vpts = trans_pts_dts(p->pts); + else return; + + while ( !found && c+3 < p->plength+6 ){ + if ( p->buf[c] == 0x00 && + p->buf[c+1] == 0x00 && + p->buf[c+2] == 0x01 && + p->buf[c+3] == 0xb3) + found = 1; + else c++; + } + if (found){ + p->startv = 1; + write(fd, p->buf+c, p->plength+6-c); + } + fd = 0; + } + + + if ( p->es && !p->starta && type == AUDIO){ + int found = 0; + if ( p->flag2 & PTS_DTS ) + p->apts = trans_pts_dts(p->pts); + else return; + + if (p->startv) + while ( !found && c+1 < p->plength+6){ + if ( p->buf[c] == 0xFF && + (p->buf[c+1] & 0xF8) == 0xF8) + found = 1; + else c++; + } + if (found){ + p->starta = 1; + write(fd, p->buf+c, p->plength+6-c); + } + fd = 0; + } + + if ( p->es && !p->starta && type == AC3){ + if ( p->flag2 & PTS_DTS ) + p->apts = trans_pts_dts(p->pts); + else return; + + if (p->startv){ + c+= ((p->buf[c+2] << 8)| p->buf[c+3]); + p->starta = 1; + write(fd, p->buf+c, p->plength+6-c); + } + fd = 0; + } + + + if (fd){ + if (p->es) + write(fd,p->buf+p->hlength+6+3*factor+head, + p->plength-p->hlength-3*factor-head); + else + write(fd,p->buf,p->plength+6); + } +} + +int64_t pes_dmx( int fdin, int fdouta, int fdoutv, int es) +{ + p2p p; + int count = 1; + uint8_t buf[SIZE]; + uint64_t length = 0; + uint64_t l = 0; + int verb = 0; + int percent, oldPercent = -1; + + init_p2p(&p, NULL, 2048); + p.fd1 = fdouta; + p.fd2 = fdoutv; + p.es = es; + p.startv = 0; + p.starta = 0; + p.apts=-1; + p.vpts=-1; + + if (fdin != STDIN_FILENO) verb = 1; + + if (verb) { + length = lseek(fdin, 0, SEEK_END); + lseek(fdin,0,SEEK_SET); + } + + while (count > 0){ + count = read(fdin,buf,SIZE); + l += count; + if (verb){ + percent = 100 * l / length; + + if (percent != oldPercent) { + fprintf(stderr, "Demuxing %d %%\r", percent); + oldPercent = percent; + } + } + get_pes(buf,count,&p,pes_dfilt); + } + + return (int64_t)p.vpts - (int64_t)p.apts; + +} + + +/* SV: made non-static */ +void pes_in_ts(p2p *p) +{ + int l, pes_start; + uint8_t obuf[TS_SIZE]; + long int c = 0; + int length = p->plength+6; + uint16_t pid; + uint8_t *counter; + pes_start = 1; + switch ( p->cid ) { + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + pid = p->pida; + counter = &p->acounter; + break; + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + pid = p->pidv; + counter = &p->acounter; + + tspid0[3] |= (p->count0++) + & 0x0F ; + tspid1[3] |= (p->count1++) + & 0x0F ; + + tspid1[24] = p->pidv; + tspid1[23] |= (p->pidv >> 8) & 0x3F; + tspid1[29] = p->pida; + tspid1[28] |= (p->pida >> 8) & 0x3F; + + p->func(tspid0,188,p); + p->func(tspid1,188,p); + break; + default: + return; + } + + while ( c < length ){ + memset(obuf,0,TS_SIZE); + if (length - c >= TS_SIZE-4){ + l = write_ts_header(pid, counter, pes_start + , obuf, TS_SIZE-4); + memcpy(obuf+l, p->buf+c, TS_SIZE-l); + c += TS_SIZE-l; + } else { + l = write_ts_header(pid, counter, pes_start + , obuf, length-c); + memcpy(obuf+l, p->buf+c, TS_SIZE-l); + c = length; + } + p->func(obuf,188,p); + pes_start = 0; + } +} + +static +void write_out(uint8_t *buf, int count,void *p) +{ + write(STDOUT_FILENO, buf, count); +} + + +void pes_to_ts2( int fdin, int fdout, uint16_t pida, uint16_t pidv) +{ + p2p p; + int count = 1; + uint8_t buf[SIZE]; + uint64_t length = 0; + uint64_t l = 0; + int verb = 0; + + init_p2p(&p, NULL, 2048); + p.fd1 = fdout; + p.pida = pida; + p.pidv = pidv; + p.acounter = 0; + p.vcounter = 0; + p.count1 = 0; + p.count0 = 0; + p.func = write_out; + + if (fdin != STDIN_FILENO) verb = 1; + + if (verb) { + length = lseek(fdin, 0, SEEK_END); + lseek(fdin,0,SEEK_SET); + } + + while (count > 0){ + count = read(fdin,buf,SIZE); + l += count; + if (verb) + fprintf(stderr,"Writing TS %2.2f %%\r", + 100.*l/length); + + get_pes(buf,count,&p,pes_in_ts); + } + +} + + +#define IN_SIZE TS_SIZE*10 +void find_avpids(int fd, uint16_t *vpid, uint16_t *apid) +{ + uint8_t buf[IN_SIZE]; + int count; + int i; + int off =0; + + while ( *apid == 0 || *vpid == 0){ + count = read(fd, buf, IN_SIZE); + for (i = 0; i < count-7; i++){ + if (buf[i] == 0x47){ + if (buf[i+1] & 0x40){ + off = 0; + if ( buf[3+i] & 0x20)//adapt field? + off = buf[4+i] + 1; + switch(buf[i+7+off]){ + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + *vpid = get_pid(buf+i+1); + break; + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + *apid = get_pid(buf+i+1); + break; + } + } + i += 187; + } + if (*apid != 0 && *vpid != 0) break; + } + } +} + +void find_bavpids(uint8_t *buf, int count, uint16_t *vpid, uint16_t *apid) +{ + int i; + int founda = 0; + int foundb = 0; + int off = 0; + + *vpid = 0; + *apid = 0; + for (i = 0; i < count-7; i++){ + if (buf[i] == 0x47){ + if ((buf[i+1] & 0xF0) == 0x40){ + off = 0; + if ( buf[3+i] & 0x20) // adaptation field? + off = buf[4+i] + 1; + + if (buf[off+i+4] == 0x00 && + buf[off+i+5] == 0x00 && + buf[off+i+6] == 0x01){ + switch(buf[off+i+7]){ + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + *vpid = get_pid(buf+i+1); + foundb=1; + break; + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + *apid = get_pid(buf+i+1); + founda=1; + break; + } + } + } + i += 187; + } + if (founda && foundb) break; + } +} + + +void ts_to_pes( int fdin, uint16_t pida, uint16_t pidv, int ps) +{ + + uint8_t buf[IN_SIZE]; + uint8_t mbuf[TS_SIZE]; + int i; + int count = 1; + uint16_t pid; + uint16_t dummy; + ipack pa, pv; + ipack *p; + + if (fdin != STDIN_FILENO && (!pida || !pidv)) + find_avpids(fdin, &pidv, &pida); + + init_ipack(&pa, IPACKS,write_out, ps); + init_ipack(&pv, IPACKS,write_out, ps); + + if ((count = save_read(fdin,mbuf,TS_SIZE))<0) + perror("reading"); + + for ( i = 0; i < 188 ; i++){ + if ( mbuf[i] == 0x47 ) break; + } + if ( i == 188){ + fprintf(stderr,"Not a TS\n"); + return; + } else { + memcpy(buf,mbuf+i,TS_SIZE-i); + if ((count = save_read(fdin,mbuf,i))<0) + perror("reading"); + memcpy(buf+TS_SIZE-i,mbuf,i); + i = 188; + } + count = 1; + while (count > 0){ + if ((count = save_read(fdin,buf+i,IN_SIZE-i)+i)<0) + perror("reading"); + + + if (!pidv){ + find_bavpids(buf+i, IN_SIZE-i, &pidv, &dummy); + if (pidv) fprintf(stderr, "vpid %d (0x%02x)\n", + pidv,pidv); + } + + if (!pida){ + find_bavpids(buf+i, IN_SIZE-i, &dummy, &pida); + if (pida) fprintf(stderr, "apid %d (0x%02x)\n", + pida,pida); + } + + + for( i = 0; i < count; i+= TS_SIZE){ + uint8_t off = 0; + + if ( count - i < TS_SIZE) break; + + pid = get_pid(buf+i+1); + if (!(buf[3+i]&0x10)) // no payload? + continue; + if ( buf[1+i]&0x80){ + fprintf(stderr,"Error in TS for PID: %d\n", + pid); + } + if (pid == pidv){ + p = &pv; + } else { + if (pid == pida){ + p = &pa; + } else continue; + } + + if ( buf[1+i]&0x40) { + if (p->plength == MMAX_PLENGTH-6){ + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + reset_ipack(p); + } + } + + if ( buf[3+i] & 0x20) { // adaptation field? + off = buf[4+i] + 1; + } + + instant_repack(buf+4+off+i, TS_SIZE-4-off, p); + } + i = 0; + + } + +} + + +#define INN_SIZE 2*IN_SIZE +void insert_pat_pmt( int fdin, int fdout) +{ + + uint8_t buf[INN_SIZE]; + uint8_t mbuf[TS_SIZE]; + int i; + int count = 1; + uint16_t pida = 0; + uint16_t pidv = 0; + int written,c; + uint8_t c0 = 0; + uint8_t c1 = 0; + uint8_t pmt_len; + uint32_t crc32; + + + find_avpids(fdin, &pidv, &pida); + + count = save_read(fdin,mbuf,TS_SIZE); + for ( i = 0; i < 188 ; i++){ + if ( mbuf[i] == 0x47 ) break; + } + if ( i == 188){ + fprintf(stderr,"Not a TS\n"); + return; + } else { + memcpy(buf,mbuf+i,TS_SIZE-i); + count = save_read(fdin,mbuf,i); + memcpy(buf+TS_SIZE-i,mbuf,i); + i = 188; + } + + count = 1; + /* length is not correct, but we only create a very small + * PMT, so it doesn't matter :-) + */ + pmt_len = tspid1[7] + 3; + while (count > 0){ + tspid1[24] = pidv; + tspid1[23] |= (pidv >> 8) & 0x3F; + tspid1[29] = pida; + tspid1[28] |= (pida >> 8) & 0x3F; + crc32 = calc_crc32 (&tspid1[5], pmt_len - 4); + tspid1[5 + pmt_len - 4] = (crc32 & 0xff000000) >> 24; + tspid1[5 + pmt_len - 3] = (crc32 & 0x00ff0000) >> 16; + tspid1[5 + pmt_len - 2] = (crc32 & 0x0000ff00) >> 8; + tspid1[5 + pmt_len - 1] = (crc32 & 0x000000ff) >> 0; + + write(fdout,tspid0,188); + write(fdout,tspid1,188); + + count = save_read(fdin,buf+i,INN_SIZE-i); + + written = 0; + while (written < IN_SIZE){ + c = write(fdout,buf,INN_SIZE); + if (c>0) written += c; + } + tspid0[3] &= 0xF0 ; + tspid0[3] |= (c0++)& 0x0F ; + + tspid1[3] &= 0xF0 ; + tspid1[3] |= (c1++)& 0x0F ; + + i=0; + } + +} + +void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)) +{ + + int l; + unsigned short *pl; + int c=0; + + uint8_t headr[3] = { 0x00, 0x00, 0x01} ; + + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)){ + switch ( p->found ){ + case 0: + case 1: + if (buf[c] == 0x00) p->found++; + else p->found = 0; + c++; + break; + case 2: + if (buf[c] == 0x01) p->found++; + else if (buf[c] == 0){ + p->found = 2; + } else p->found = 0; + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]){ + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + p->done = 1; + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + p->found = 0; + break; + } + break; + + + case 4: + if (count-c > 1){ + pl = (unsigned short *) (buf+c); + p->plength = ntohs(*pl); + p->plen[0] = buf[c]; + c++; + p->plen[1] = buf[c]; + c++; + p->found+=2; + } else { + p->plen[0] = buf[c]; + p->found++; + return; + } + break; + case 5: + p->plen[1] = buf[c]; + c++; + pl = (unsigned short *) p->plen; + p->plength = ntohs(*pl); + p->found++; + break; + + + case 6: + if (!p->done){ + p->flag1 = buf[c]; + c++; + p->found++; + if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; + } + } + break; + + case 7: + if ( !p->done && p->mpeg == 2){ + p->flag2 = buf[c]; + c++; + p->found++; + } + break; + + case 8: + if ( !p->done && p->mpeg == 2){ + p->hlength = buf[c]; + c++; + p->found++; + } + break; + + default: + + break; + } + } + + if (!p->plength) p->plength = MMAX_PLENGTH-6; + + + if ( p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7)) ){ + switch (p->cid){ + + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + + memcpy(p->buf, headr, 3); + p->buf[3] = p->cid; + memcpy(p->buf+4,p->plen,2); + + if (p->mpeg == 2 && p->found == 9){ + p->buf[6] = p->flag1; + p->buf[7] = p->flag2; + p->buf[8] = p->hlength; + } + + if (p->mpeg == 1 && p->found == 7){ + p->buf[6] = p->flag1; + } + + + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14){ + while (c < count && p->found < 14){ + p->pts[p->found-9] = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + } + if (c == count) return; + } + + if (p->mpeg == 1 && p->which < 2000){ + + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } + + while (!p->which && c < count && + p->check == 0xFF){ + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + } + + if ( c == count) return; + + if ( (p->check & 0xC0) == 0x40 && !p->which){ + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + + p->which = 1; + if ( c == count) return; + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return; + } + + if (p->which == 1){ + p->check = buf[c]; + p->buf[p->found] = buf[c]; + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return; + } + + if ( (p->check & 0x30) && p->check != 0xFF){ + p->flag2 = (p->check & 0xF0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + + if ( c == count) return; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_ONLY){ + while (c < count && + p->which < 7){ + p->pts[p->which-2] = + buf[c]; + p->buf[p->found] = + buf[c]; + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return; + } else if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_DTS){ + while (c < count && + p->which< 12){ + if (p->which< 7) + p->pts[p->which + -2] = + buf[c]; + p->buf[p->found] = + buf[c]; + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return; + } + p->which = 2000; + } + + } + + while (c < count && p->found < p->plength+6){ + l = count -c; + if (l+p->found > p->plength+6) + l = p->plength+6-p->found; + memcpy(p->buf+p->found, buf+c, l); + p->found += l; + c += l; + } + if(p->found == p->plength+6) + func(p); + + break; + } + + + if ( p->done ){ + if( p->found + count - c < p->plength+6){ + p->found += count-c; + c = count; + } else { + c += p->plength+6 - p->found; + p->found = p->plength+6; + } + } + + if (p->plength && p->found == p->plength+6) { + p->found = 0; + p->done = 0; + p->plength = 0; + memset(p->buf, 0, MAX_PLENGTH); + if (c < count) + get_pes(buf+c, count-c, p, func); + } + } + return; +} + + + + +void setup_pes2ts( p2p *p, uint32_t pida, uint32_t pidv, + void (*ts_write)(uint8_t *buf, int count, void *p)) +{ + init_p2p( p, ts_write, 2048); + p->pida = pida; + p->pidv = pidv; + p->acounter = 0; + p->vcounter = 0; + p->count1 = 0; + p->count0 = 0; +} + +void kpes_to_ts( p2p *p,uint8_t *buf ,int count ) +{ + get_pes(buf,count, p,pes_in_ts); +} + + +void setup_ts2pes( p2p *pa, p2p *pv, uint32_t pida, uint32_t pidv, + void (*pes_write)(uint8_t *buf, int count, void *p)) +{ + init_p2p( pa, pes_write, 2048); + init_p2p( pv, pes_write, 2048); + pa->pid = pida; + pv->pid = pidv; +} + +void kts_to_pes( p2p *p, uint8_t *buf) // don't need count (=188) +{ + uint8_t off = 0; + uint16_t pid = 0; + + if (!(buf[3]&PAYLOAD)) // no payload? + return; + + pid = get_pid(buf+1); + + if (pid != p->pid) return; + if ( buf[1]&0x80){ + fprintf(stderr,"Error in TS for PID: %d\n", + pid); + } + + if ( buf[1]&PAY_START) { + if (p->plength == MMAX_PLENGTH-6){ + p->plength = p->found-6; + p->found = 0; + pes_repack(p); + } + } + + if ( buf[3] & ADAPT_FIELD) { // adaptation field? + off = buf[4] + 1; + if (off+4 > 187) return; + } + + get_pes(buf+4+off, TS_SIZE-4-off, p , pes_repack); +} + + + + +// instant repack + + +void reset_ipack(ipack *p) +{ + p->found = 0; + p->cid = 0; + p->plength = 0; + p->flag1 = 0; + p->flag2 = 0; + p->hlength = 0; + p->mpeg = 0; + p->check = 0; + p->which = 0; + p->done = 0; + p->count = 0; + p->size = p->size_orig; +} + +void init_ipack(ipack *p, int size, + void (*func)(uint8_t *buf, int size, void *priv), int ps) +{ + if ( !(p->buf = malloc(size)) ){ + fprintf(stderr,"Couldn't allocate memory for ipack\n"); + exit(1); + } + p->ps = ps; + p->size_orig = size; + p->func = func; + reset_ipack(p); + p->has_ai = 0; + p->has_vi = 0; + p->start = 0; +} + +void free_ipack(ipack * p) +{ + if (p->buf) free(p->buf); +} + + + +int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) +{ + uint8_t *headr; + int found = 0; + int sw; + int form = -1; + int c = 0; + + while (found < 4 && c+4 < count){ + uint8_t *b; + + b = mbuf+c; + if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 + && b[3] == 0xb3) found = 4; + else { + c++; + } + } + + if (! found) return -1; + c += 4; + if (c+12 >= count) return -1; + headr = mbuf+c; + + vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); + vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); + + sw = (int)((headr[3]&0xF0) >> 4) ; + + switch( sw ){ + case 1: + if (pr) + fprintf(stderr,"Videostream: ASPECT: 1:1"); + vi->aspect_ratio = 100; + break; + case 2: + if (pr) + fprintf(stderr,"Videostream: ASPECT: 4:3"); + vi->aspect_ratio = 133; + break; + case 3: + if (pr) + fprintf(stderr,"Videostream: ASPECT: 16:9"); + vi->aspect_ratio = 177; + break; + case 4: + if (pr) + fprintf(stderr,"Videostream: ASPECT: 2.21:1"); + vi->aspect_ratio = 221; + break; + + case 5 ... 15: + if (pr) + fprintf(stderr,"Videostream: ASPECT: reserved"); + vi->aspect_ratio = 0; + break; + + default: + vi->aspect_ratio = 0; + return -1; + } + + if (pr) + fprintf(stderr," Size = %dx%d",vi->horizontal_size, + vi->vertical_size); + + sw = (int)(headr[3]&0x0F); + + switch ( sw ) { + case 1: + if (pr) + fprintf(stderr," FRate: 23.976 fps"); + vi->framerate = 24000/1001.; + form = -1; + break; + case 2: + if (pr) + fprintf(stderr," FRate: 24 fps"); + vi->framerate = 24; + form = -1; + break; + case 3: + if (pr) + fprintf(stderr," FRate: 25 fps"); + vi->framerate = 25; + form = VIDEO_MODE_PAL; + break; + case 4: + if (pr) + fprintf(stderr," FRate: 29.97 fps"); + vi->framerate = 30000/1001.; + form = VIDEO_MODE_NTSC; + break; + case 5: + if (pr) + fprintf(stderr," FRate: 30 fps"); + vi->framerate = 30; + form = VIDEO_MODE_NTSC; + break; + case 6: + if (pr) + fprintf(stderr," FRate: 50 fps"); + vi->framerate = 50; + form = VIDEO_MODE_PAL; + break; + case 7: + if (pr) + fprintf(stderr," FRate: 60 fps"); + vi->framerate = 60; + form = VIDEO_MODE_NTSC; + break; + } + + vi->bit_rate = 400*(((headr[4] << 10) & 0x0003FC00UL) + | ((headr[5] << 2) & 0x000003FCUL) | + (((headr[6] & 0xC0) >> 6) & 0x00000003UL)); + + if (pr){ + fprintf(stderr," BRate: %.2f Mbit/s",(vi->bit_rate)/1000000.); + fprintf(stderr,"\n"); + } + vi->video_format = form; + + vi->off = c-4; + return c-4; +} + +extern unsigned int bitrates[3][16]; +extern uint32_t freq[4]; + +int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) +{ + uint8_t *headr; + int found = 0; + int c = 0; + int fr =0; + + while (!found && c < count){ + uint8_t *b = mbuf+c; + + if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) + found = 1; + else { + c++; + } + } + + if (!found) return -1; + + if (c+3 >= count) return -1; + headr = mbuf+c; + + ai->layer = (headr[1] & 0x06) >> 1; + + if (pr) + fprintf(stderr,"Audiostream: Layer: %d", 4-ai->layer); + + + ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; + + if (pr){ + if (ai->bit_rate == 0) + fprintf (stderr," Bit rate: free"); + else if (ai->bit_rate == 0xf) + fprintf (stderr," BRate: reserved"); + else + fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); + } + + fr = (headr[2] & 0x0c ) >> 2; + ai->frequency = freq[fr]*100; + + if (pr){ + if (ai->frequency == 3) + fprintf (stderr, " Freq: reserved\n"); + else + fprintf (stderr," Freq: %2.1f kHz\n", + ai->frequency/1000.); + } + ai->off = c; + return c; +} + +unsigned int ac3_bitrates[32] = + {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, + 0,0,0,0,0,0,0,0,0,0,0,0,0}; + +uint32_t ac3_freq[4] = {480, 441, 320, 0}; +uint32_t ac3_frames[3][32] = + {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, + 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, + 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, + 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + +int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr) +{ + uint8_t *headr; + int found = 0; + int c = 0; + uint8_t frame; + int fr = 0; + + while ( !found && c < count){ + uint8_t *b = mbuf+c; + if ( b[0] == 0x0b && b[1] == 0x77 ) + found = 1; + else { + c++; + } + } + + + if (!found){ + return -1; + } + ai->off = c; + + if (c+5 >= count) return -1; + + ai->layer = 0; // 0 for AC3 + headr = mbuf+c+2; + + frame = (headr[2]&0x3f); + ai->bit_rate = ac3_bitrates[frame>>1]*1000; + + if (pr) fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); + + fr = (headr[2] & 0xc0 ) >> 6; + ai->frequency = freq[fr]*100; + if (pr) fprintf (stderr," Freq: %d Hz\n", ai->frequency); + + ai->framesize = ac3_frames[fr][frame >> 1]; + if ((frame & 1) && (fr == 1)) ai->framesize++; + ai->framesize = ai->framesize << 1; + if (pr) fprintf (stderr," Framesize %d\n", ai->framesize); + + return c; +} + + +void ps_pes(ipack *p) +{ + int check; + uint8_t pbuf[PS_HEADER_L2]; + static int muxr = 0; + static int ai = 0; + static int vi = 0; + static int start = 0; + static uint32_t SCR = 0; + + if (p->mpeg == 2){ + switch(p->buf[3]){ + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + if (!p->has_vi){ + if(get_vinfo(p->buf, p->count, &p->vi,1) >=0) { + p->has_vi = 1; + vi = p->vi.bit_rate; + } + } + break; + + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + if (!p->has_ai){ + if(get_ainfo(p->buf, p->count, &p->ai,1) >=0) { + p->has_ai = 1; + ai = p->ai.bit_rate; + } + } + break; + } + + if (p->has_vi && vi && !muxr){ + muxr = (vi+ai)/400; + } + + if ( start && muxr && (p->buf[7] & PTS_ONLY) && (p->has_ai || + p->buf[9+p->buf[8]+4] == 0xb3)){ + SCR = trans_pts_dts(p->pts)-3600; + + check = write_ps_header(pbuf, + SCR, + muxr, 1, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0); + + p->func(pbuf, check , p->data); + } + + if (muxr && !start && vi){ + SCR = trans_pts_dts(p->pts)-3600; + check = write_ps_header(pbuf, + SCR, + muxr, 1, 0, 0, 1, 1, 1, + 0xC0, 0, 64, 0xE0, 1, 460); + start = 1; + p->func(pbuf, check , p->data); + } + + if (start) + p->func(p->buf, p->count, p->data); + } +} + +void send_ipack(ipack *p) +{ + int streamid=0; + int off; + int ac3_off = 0; + AudioInfo ai; + int nframes= 0; + int f=0; + + if (p->count < 10) return; + p->buf[3] = p->cid; + p->buf[4] = (uint8_t)(((p->count-6) & 0xFF00) >> 8); + p->buf[5] = (uint8_t)((p->count-6) & 0x00FF); + + + if (p->cid == PRIVATE_STREAM1){ + + off = 9+p->buf[8]; + streamid = p->buf[off]; + if ((streamid & 0xF8) == 0x80){ + ai.off = 0; + ac3_off = ((p->buf[off+2] << 8)| p->buf[off+3]); + if (ac3_off < p->count) + f=get_ac3info(p->buf+off+3+ac3_off, + p->count-ac3_off, &ai,0); + if ( !f ){ + nframes = (p->count-off-3-ac3_off)/ + ai.framesize + 1; + p->buf[off+1] = nframes; + p->buf[off+2] = (ac3_off >> 8)& 0xFF; + p->buf[off+3] = (ac3_off)& 0xFF; + + ac3_off += nframes * ai.framesize - p->count; + } + } + } + + if (p->ps) ps_pes(p); + else p->func(p->buf, p->count, p->data); + + switch ( p->mpeg ){ + case 2: + + p->buf[6] = 0x80; + p->buf[7] = 0x00; + p->buf[8] = 0x00; + p->count = 9; + + if (p->cid == PRIVATE_STREAM1 && (streamid & 0xF8)==0x80 ){ + p->count += 4; + p->buf[9] = streamid; + p->buf[10] = 0; + p->buf[11] = (ac3_off >> 8)& 0xFF; + p->buf[12] = (ac3_off)& 0xFF; + } + + break; + case 1: + p->buf[6] = 0x0F; + p->count = 7; + break; + } + +} + + +static void write_ipack(ipack *p, uint8_t *data, int count) +{ + AudioInfo ai; + uint8_t headr[3] = { 0x00, 0x00, 0x01} ; + int diff =0; + + if (p->count < 6){ + if (trans_pts_dts(p->pts) > trans_pts_dts(p->last_pts)) + memcpy(p->last_pts, p->pts, 5); + p->count = 0; + memcpy(p->buf+p->count, headr, 3); + p->count += 6; + } + if ( p->size == p->size_orig && p->plength && + (diff = 6+p->plength - p->found + p->count +count) > p->size && + diff < 3*p->size/2){ + + p->size = diff/2; +// fprintf(stderr,"size: %d \n",p->size); + } + + if (p->cid == PRIVATE_STREAM1 && p->count == p->hlength+9){ + if ((data[0] & 0xF8) != 0x80){ + int ac3_off; + + ac3_off = get_ac3info(data, count, &ai,0); + if (ac3_off>=0 && ai.framesize){ + p->buf[p->count] = 0x80; + p->buf[p->count+1] = (p->size - p->count + - 4 - ac3_off)/ + ai.framesize + 1; + p->buf[p->count+2] = (ac3_off >> 8)& 0xFF; + p->buf[p->count+3] = (ac3_off)& 0xFF; + p->count+=4; + + } + } + } + + if (p->count + count < p->size){ + memcpy(p->buf+p->count, data, count); + p->count += count; + } else { + int rest = p->size - p->count; + if (rest < 0) rest = 0; + memcpy(p->buf+p->count, data, rest); + p->count += rest; +// fprintf(stderr,"count: %d \n",p->count); + send_ipack(p); + if (count - rest > 0) + write_ipack(p, data+rest, count-rest); + } +} + +void instant_repack (uint8_t *buf, int count, ipack *p) +{ + + int l; + unsigned short *pl; + int c=0; + + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)){ + switch ( p->found ){ + case 0: + case 1: + if (buf[c] == 0x00) p->found++; + else p->found = 0; + c++; + break; + case 2: + if (buf[c] == 0x01) p->found++; + else if (buf[c] == 0){ + p->found = 2; + } else p->found = 0; + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]){ + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + p->done = 1; + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + p->found = 0; + break; + } + break; + + + case 4: + if (count-c > 1){ + pl = (unsigned short *) (buf+c); + p->plength = ntohs(*pl); + p->plen[0] = buf[c]; + c++; + p->plen[1] = buf[c]; + c++; + p->found+=2; + } else { + p->plen[0] = buf[c]; + p->found++; + return; + } + break; + case 5: + p->plen[1] = buf[c]; + c++; + pl = (unsigned short *) p->plen; + p->plength = ntohs(*pl); + p->found++; + break; + + + case 6: + if (!p->done){ + p->flag1 = buf[c]; + c++; + p->found++; + if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; + } + } + break; + + case 7: + if ( !p->done && p->mpeg == 2){ + p->flag2 = buf[c]; + c++; + p->found++; + } + break; + + case 8: + if ( !p->done && p->mpeg == 2){ + p->hlength = buf[c]; + c++; + p->found++; + } + break; + + default: + + break; + } + } + + + if (c == count) return; + + if (!p->plength) p->plength = MMAX_PLENGTH-6; + + + if ( p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7)) ){ + switch (p->cid){ + + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + + if (p->mpeg == 2 && p->found == 9){ + write_ipack(p, &p->flag1, 1); + write_ipack(p, &p->flag2, 1); + write_ipack(p, &p->hlength, 1); + } + + if (p->mpeg == 1 && p->found == 7){ + write_ipack(p, &p->flag1, 1); + } + + + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14){ + while (c < count && p->found < 14){ + p->pts[p->found-9] = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + } + if (c == count) return; + } + + if (p->mpeg == 1 && p->which < 2000){ + + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } + + while (!p->which && c < count && + p->check == 0xFF){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + } + + if ( c == count) return; + + if ( (p->check & 0xC0) == 0x40 && !p->which){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + + p->which = 1; + if ( c == count) return; + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return; + } + + if (p->which == 1){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return; + } + + if ( (p->check & 0x30) && p->check != 0xFF){ + p->flag2 = (p->check & 0xF0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + + if ( c == count) return; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_ONLY){ + while (c < count && + p->which < 7){ + p->pts[p->which-2] = + buf[c]; + write_ipack(p,buf+c,1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return; + } else if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_DTS){ + while (c < count && + p->which< 12){ + if (p->which< 7) + p->pts[p->which + -2] = + buf[c]; + write_ipack(p,buf+c,1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return; + } + p->which = 2000; + } + + } + + while (c < count && p->found < p->plength+6){ + l = count -c; + if (l+p->found > p->plength+6) + l = p->plength+6-p->found; + write_ipack(p, buf+c, l); + p->found += l; + c += l; + } + + break; + } + + + if ( p->done ){ + if( p->found + count - c < p->plength+6){ + p->found += count-c; + c = count; + } else { + c += p->plength+6 - p->found; + p->found = p->plength+6; + } + } + + if (p->plength && p->found == p->plength+6) { + send_ipack(p); + reset_ipack(p); + if (c < count) + instant_repack(buf+c, count-c, p); + } + } + return; +} + +void write_out_es(uint8_t *buf, int count,void *priv) +{ + ipack *p = (ipack *) priv; + uint8_t payl = buf[8]+9+p->start-1; + + write(p->fd, buf+payl, count-payl); + p->start = 1; +} + +void write_out_pes(uint8_t *buf, int count,void *priv) +{ + ipack *p = (ipack *) priv; + write(p->fd, buf, count); +} + + + +int64_t ts_demux(int fdin, int fdv_out,int fda_out,uint16_t pida, + uint16_t pidv, int es) +{ + uint8_t buf[IN_SIZE]; + uint8_t mbuf[TS_SIZE]; + int i; + int count = 1; + uint16_t pid; + ipack pa, pv; + ipack *p; + uint8_t *sb; + int64_t apts=0; + int64_t vpts=0; + int verb = 0; + uint64_t length =0; + uint64_t l=0; + int perc =0; + int last_perc =0; + + if (fdin != STDIN_FILENO) verb = 1; + + if (verb) { + length = lseek(fdin, 0, SEEK_END); + lseek(fdin,0,SEEK_SET); + } + + if (!pida || !pidv) + find_avpids(fdin, &pidv, &pida); + + if (es){ + init_ipack(&pa, IPACKS,write_out_es, 0); + init_ipack(&pv, IPACKS,write_out_es, 0); + } else { + init_ipack(&pa, IPACKS,write_out_pes, 0); + init_ipack(&pv, IPACKS,write_out_pes, 0); + } + pa.fd = fda_out; + pv.fd = fdv_out; + pa.data = (void *)&pa; + pv.data = (void *)&pv; + + count = save_read(fdin,mbuf,TS_SIZE); + if (count) l+=count; + for ( i = 0; i < 188 ; i++){ + if ( mbuf[i] == 0x47 ) break; + } + if ( i == 188){ + fprintf(stderr,"Not a TS\n"); + return 0; + } else { + memcpy(buf,mbuf+i,TS_SIZE-i); + count = save_read(fdin,mbuf,i); + if (count) l+=count; + memcpy(buf+TS_SIZE-i,mbuf,i); + i = 188; + } + + count = 1; + while (count > 0){ + count = save_read(fdin,buf+i,IN_SIZE-i)+i; + if (count) l+=count; + if (verb && perc >last_perc){ + perc = (100*l)/length; + fprintf(stderr,"Reading TS %d %%\r",perc); + last_perc = perc; + } + + for( i = 0; i < count; i+= TS_SIZE){ + uint8_t off = 0; + + if ( count - i < TS_SIZE) break; + + pid = get_pid(buf+i+1); + if (!(buf[3+i]&0x10)) // no payload? + continue; + if ( buf[1+i]&0x80){ + fprintf(stderr,"Error in TS for PID: %d\n", + pid); + } + if (pid == pidv){ + p = &pv; + } else { + if (pid == pida){ + p = &pa; + } else continue; + } + + if ( buf[3+i] & 0x20) { // adaptation field? + off = buf[4+i] + 1; + } + + if ( buf[1+i]&0x40) { + if (p->plength == MMAX_PLENGTH-6){ + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + reset_ipack(p); + } + sb = buf+4+off+i; + if( es && + !p->start && (sb[7] & PTS_DTS_FLAGS)){ + uint8_t *pay = sb+sb[8]+9; + int l = TS_SIZE - 13 - off - sb[8]; + if ( pid == pidv && + (p->start = + get_vinfo( pay, l,&p->vi,1)+1) >0 + ){ + vpts = trans_pts_dts(sb+9); + printf("vpts : %fs\n", + vpts/90000.); + } + if ( pid == pida && es==1 && + (p->start = + get_ainfo( pay, l,&p->ai,1)+1) >0 + ){ + apts = trans_pts_dts(sb+9); + printf("apts : %fs\n", + apts/90000.); + } + if ( pid == pida && es==2 && + (p->start = + get_ac3info( pay, l,&p->ai,1)+1) >0 + ){ + apts = trans_pts_dts(sb+9); + printf("apts : %fs\n", + apts/90000.); + } + } + } + + if (p->start) + instant_repack(buf+4+off+i, TS_SIZE-4-off, p); + } + i = 0; + + } + + return (vpts-apts); +} + +void ts2es_opt(int fdin, uint16_t pidv, ipack *p, int verb) +{ + uint8_t buf[IN_SIZE]; + uint8_t mbuf[TS_SIZE]; + int i; + int count = 1; + uint64_t length =0; + uint64_t l=0; + int perc =0; + int last_perc =0; + uint16_t pid; + + if (verb) { + length = lseek(fdin, 0, SEEK_END); + lseek(fdin,0,SEEK_SET); + } + + count = save_read(fdin,mbuf,TS_SIZE); + if (count) l+=count; + for ( i = 0; i < 188 ; i++){ + if ( mbuf[i] == 0x47 ) break; + } + if ( i == 188){ + fprintf(stderr,"Not a TS\n"); + return; + } else { + memcpy(buf,mbuf+i,TS_SIZE-i); + count = save_read(fdin,mbuf,i); + if (count) l+=count; + memcpy(buf+TS_SIZE-i,mbuf,i); + i = 188; + } + + count = 1; + while (count > 0){ + count = save_read(fdin,buf+i,IN_SIZE-i)+i; + if (count) l+=count; + if (verb && perc >last_perc){ + perc = (100*l)/length; + fprintf(stderr,"Reading TS %d %%\r",perc); + last_perc = perc; + } + + for( i = 0; i < count; i+= TS_SIZE){ + uint8_t off = 0; + + if ( count - i < TS_SIZE) break; + + pid = get_pid(buf+i+1); + if (!(buf[3+i]&0x10)) // no payload? + continue; + if ( buf[1+i]&0x80){ + fprintf(stderr,"Error in TS for PID: %d\n", + pid); + } + if (pid != pidv){ + continue; + } + + if ( buf[3+i] & 0x20) { // adaptation field? + off = buf[4+i] + 1; + } + + if ( buf[1+i]&0x40) { + if (p->plength == MMAX_PLENGTH-6){ + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + reset_ipack(p); + } + } + + instant_repack(buf+4+off+i, TS_SIZE-4-off, p); + } + i = 0; + + } +} + +void ts2es(int fdin, uint16_t pidv) +{ + ipack p; + int verb = 0; + + init_ipack(&p, IPACKS,write_out_es, 0); + p.fd = STDOUT_FILENO; + p.data = (void *)&p; + + if (fdin != STDIN_FILENO) verb = 1; + + ts2es_opt(fdin, pidv, &p, verb); +} + + +void change_aspect(int fdin, int fdout, int aspect) +{ + ps_packet ps; + pes_packet pes; + int neof,i; + + do { + init_ps(&ps); + neof = read_ps(fdin,&ps); + write_ps(fdout,&ps); + for (i = 0; i < ps.npes; i++){ + uint8_t *buf; + int c = 0; + int l; + + init_pes(&pes); + read_pes(fdin, &pes); + + buf = pes.pes_pckt_data; + + switch (pes.stream_id){ + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + l=pes.length; + break; + default: + l = 0; + break; + } + while ( c < l - 6){ + if (buf[c] == 0x00 && + buf[c+1] == 0x00 && + buf[c+2] == 0x01 && + buf[c+3] == 0xB3) { + c += 4; + buf[c+3] &= 0x0f; + buf[c+3] |= aspect; + } + else c++; + } + write_pes(fdout,&pes); + } + } while( neof > 0 ); +} diff --git a/libdvbmpeg/transform.h b/libdvbmpeg/transform.h new file mode 100644 index 0000000..ad32706 --- /dev/null +++ b/libdvbmpeg/transform.h @@ -0,0 +1,250 @@ +/* + * dvb-mpegtools for the Siemens Fujitsu DVB PCI card + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * Copyright (C) 2002 Marcus Metzler + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at mocm@metzlerbros.de, + + */ + +#ifndef _TS_TRANSFORM_H_ +#define _TS_TRANSFORM_H_ + +#include +#include +#include +#include +#include "remux.h" + +#define PROG_STREAM_MAP 0xBC +#ifndef PRIVATE_STREAM1 +#define PRIVATE_STREAM1 0xBD +#endif +#define PADDING_STREAM 0xBE +#ifndef PRIVATE_STREAM2 +#define PRIVATE_STREAM2 0xBF +#endif +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define BUFFYSIZE 10*MAX_PLENGTH +#define MAX_PTS 8192 +#define MAX_FRAME 8192 +#define MAX_PACK_L 4096 +#define PS_HEADER_L1 14 +#define PS_HEADER_L2 (PS_HEADER_L1+18) +#define MAX_H_SIZE (PES_H_MIN + PS_HEADER_L1 + 5) +#define PES_MIN 7 +#define PES_H_MIN 9 + +//flags2 +#define PTS_DTS_FLAGS 0xC0 +#define ESCR_FLAG 0x20 +#define ES_RATE_FLAG 0x10 +#define DSM_TRICK_FLAG 0x08 +#define ADD_CPY_FLAG 0x04 +#define PES_CRC_FLAG 0x02 +#define PES_EXT_FLAG 0x01 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 + +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +#define MAX_PLENGTH 0xFFFF +#define MMAX_PLENGTH (8*MAX_PLENGTH) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define P2P_LENGTH 2048 + + enum{NOPES, AUDIO, VIDEO, AC3}; + + typedef struct p2pstruct { + int found; + uint8_t buf[MMAX_PLENGTH]; + uint8_t cid; + uint8_t subid; + uint32_t plength; + uint8_t plen[2]; + uint8_t flag1; + uint8_t flag2; + uint8_t hlength; + uint8_t pts[5]; + int mpeg; + uint8_t check; + int fd1; + int fd2; + int es; + int filter; + int which; + int done; + int repack; + uint16_t bigend_repack; + void (*func)(uint8_t *buf, int count, void *p); + int startv; + int starta; + int64_t apts; + int64_t vpts; + uint16_t pid; + uint16_t pida; + uint16_t pidv; + uint8_t acounter; + uint8_t vcounter; + uint8_t count0; + uint8_t count1; + void *data; + } p2p; + + + uint64_t trans_pts_dts(uint8_t *pts); + int write_ts_header(uint16_t pid, uint8_t *counter, int pes_start, + uint8_t *buf, uint8_t length); + uint16_t get_pid(uint8_t *pid); + void init_p2p(p2p *p, void (*func)(uint8_t *buf, int count, void *p), + int repack); + void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)); + void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)); + void pes_repack(p2p *p); + void setup_pes2ts( p2p *p, uint32_t pida, uint32_t pidv, + void (*ts_write)(uint8_t *buf, int count, void *p)); + void kpes_to_ts( p2p *p,uint8_t *buf ,int count ); + void setup_ts2pes( p2p *pa, p2p *pv, uint32_t pida, uint32_t pidv, + void (*pes_write)(uint8_t *buf, int count, void *p)); + void kts_to_pes( p2p *p, uint8_t *buf); + void pes_repack(p2p *p); + void extract_from_pes(int fdin, int fdout, uint8_t id, int es); + int64_t pes_dmx(int fdin, int fdouta, int fdoutv, int es); + void pes_to_ts2( int fdin, int fdout, uint16_t pida, uint16_t pidv); + void ts_to_pes( int fdin, uint16_t pida, uint16_t pidv, int pad); + int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr); + int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr); + int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr); + void filter_audio_from_pes(int fdin, int fdout, uint8_t id, + uint8_t subid); + + +//instant repack + + typedef struct ipack_s { + int size; + int size_orig; + int found; + int ps; + int has_ai; + int has_vi; + AudioInfo ai; + VideoInfo vi; + uint8_t *buf; + uint8_t cid; + uint32_t plength; + uint8_t plen[2]; + uint8_t flag1; + uint8_t flag2; + uint8_t hlength; + uint8_t pts[5]; + uint8_t last_pts[5]; + int mpeg; + uint8_t check; + int which; + int done; + void *data; + void *data2; + void (*func)(uint8_t *buf, int size, void *priv); + int count; + int start; + int fd; + int fd1; + int fd2; + int ffd; + int playing; + } ipack; + + void instant_repack (uint8_t *buf, int count, ipack *p); + void init_ipack(ipack *p, int size, + void (*func)(uint8_t *buf, int size, void *priv), + int pad); + void free_ipack(ipack * p); + void send_ipack(ipack *p); + void reset_ipack(ipack *p); + void ps_pes(ipack *p); + // use with ipack structure, repack size and callback func + + int64_t ts_demux(int fd_in, int fdv_out,int fda_out,uint16_t pida, + uint16_t pidv, int es); + + void ts2es(int fdin, uint16_t pidv); + void ts2es_opt(int fdin, uint16_t pidv, ipack *p, int verb); + void insert_pat_pmt( int fdin, int fdout); + void change_aspect(int fdin, int fdout, int aspect); + +// SV: all made non-static: + void pes_in_ts(p2p *p); + +// SV: moved from .c file: +#define IPACKS 2048 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _TS_TRANSFORM_H_*/ + + + diff --git a/mvpclient.c b/mvpclient.c new file mode 100644 index 0000000..74a5380 --- /dev/null +++ b/mvpclient.c @@ -0,0 +1,750 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mvpclient.h" + +MVPClient::MVPClient(int tsocket) + : tcp(tsocket) +{ + cm = NULL; + rp = NULL; + recordingManager = NULL; + + // Get IP address of client for config module + + char ipa[20]; + struct sockaddr_in peer; + socklen_t salen = sizeof(struct sockaddr); + if(getpeername(tsocket, (struct sockaddr*)&peer, &salen) == 0) + { + strcpy(ipa, inet_ntoa(peer.sin_addr)); + } + else + { + ipa[0] = '\0'; + printf("Cannot get peer name!\n"); + } + + const char* configDir = cPlugin::ConfigDirectory(); + if (!configDir) + { + printf("No config dir!\n"); + return; + } + + char configFileName[PATH_MAX]; + snprintf(configFileName, PATH_MAX - strlen(configDir) - strlen(ipa) - 20, "%s/vomp-%s.conf", configDir, ipa); + config.init(configFileName); + + printf("Config file name: %s\n", configFileName); + +// processGetChannelSchedule(NULL, 0); + +// printf("here\n"); +//test(); + +} + +MVPClient::~MVPClient() +{ + printf("MVP client destructor\n"); + if (cm) + { + cm->Stop(); + delete cm; + cm = NULL; + } + else if (rp) + { + writeResumeData(); + + delete rp; + delete recordingManager; + rp = NULL; + recordingManager = NULL; + } + + cleanConfig(); +} + +cChannel* MVPClient::channelFromNumber(unsigned long channelNumber) +{ + cChannel* channel = NULL; + + for (channel = Channels.First(); channel; channel = Channels.Next(channel)) + { + if (!channel->GroupSep()) + { + printf("Looking for channel %lu::: number: %i name: '%s'\n", channelNumber, channel->Number(), channel->Name()); + + if (channel->Number() == (int)channelNumber) + { + int vpid = channel->Vpid(); + int apid1 = channel->Apid1(); + + printf("Found channel number %lu, vpid = %i, apid1 = %i\n", channelNumber, vpid, apid1); + return channel; + } + } + } + + if (!channel) + { + printf("Channel not found\n"); + } + + return channel; +} + + +void MVPClient::writeResumeData() +{ + config.setValueLongLong("ResumeData", (char*)rp->getCurrentRecording()->FileName(), rp->getLastPosition()); +} + +void MVPClient::sendULONG(ULONG ul) +{ + unsigned char sendBuffer[8]; + *(unsigned long*)&sendBuffer[0] = htonl(4); + *(unsigned long*)&sendBuffer[4] = htonl(ul); + + tcp.sendPacket(sendBuffer, 8); + printf("written ULONG %lu\n", ul); +} + +void MVPClientStartThread(void* arg) +{ + MVPClient* m = (MVPClient*)arg; + m->run2(); + // Nothing external to this class has a reference to it + // This is the end of the thread.. so delete m + delete m; + pthread_exit(NULL); +} + +int MVPClient::run() +{ + if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0; + printf("MVPClient run success\n"); + return 1; +} + +void MVPClient::run2() +{ + // Thread stuff + sigset_t sigset; + sigfillset(&sigset); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); + pthread_detach(runThread); // Detach + + tcp.disableReadTimeout(); + + tcp.setSoKeepTime(3); + tcp.setNonBlocking(); + + unsigned char* buffer; + unsigned char* data; + int packetLength; + unsigned long opcode; + + while(1) + { + printf("starting wait\n"); + buffer = (unsigned char*)tcp.receivePacket(); + printf("back from wait\n"); + if (buffer == NULL) + { + printf("Detected connection closed\n"); + break; + } + + packetLength = tcp.getDataLength() - 4; + opcode = ntohl(*(unsigned long*)buffer); + data = buffer + 4; + + + switch(opcode) + { + case 1: + processLogin(data, packetLength); + break; + case 2: + processGetRecordingsList(data, packetLength); + break; + case 3: + processDeleteRecording(data, packetLength); + break; + case 4: + processGetSummary(data, packetLength); + break; + case 5: + processGetChannelsList(data, packetLength); + break; + case 6: + processStartStreamingChannel(data, packetLength); + break; + case 7: + processGetBlock(data, packetLength); + break; + case 8: + processStopStreaming(data, packetLength); + break; + case 9: + processStartStreamingRecording(data, packetLength); + break; + case 10: + processGetChannelSchedule(data, packetLength); + break; + case 11: + processConfigSave(data, packetLength); + break; + case 12: + processConfigLoad(data, packetLength); + break; + } + + free(buffer); + } +} + +void MVPClient::processLogin(unsigned char* buffer, int length) +{ + time_t timeNow = time(NULL); + struct tm* timeStruct = localtime(&timeNow); + timeOffset = timeStruct->tm_gmtoff; + + // seems dhcp is sending timezone out to mvp + // so just supply utc timestamp + timeOffset = 0; + + sendULONG(timeNow + timeOffset); + printf("written time\n"); +} + +void MVPClient::processGetRecordingsList(unsigned char* data, int length) +{ + unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough + int count = 4; // leave space for the packet length + char* point; + + + int FreeMB; + int Percent = VideoDiskSpace(&FreeMB); + int Total = (FreeMB / (100 - Percent)) * 100; + + *(unsigned long*)&sendBuffer[count] = htonl(Total); + count += sizeof(unsigned long); + *(unsigned long*)&sendBuffer[count] = htonl(FreeMB); + count += sizeof(unsigned long); + *(unsigned long*)&sendBuffer[count] = htonl(Percent); + count += sizeof(unsigned long); + + + cRecordings Recordings; + Recordings.Load(); + + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) + { + if (count > 49000) break; // just how big is that hard disk?! + *(unsigned long*)&sendBuffer[count] = htonl(recording->start + timeOffset); + count += 4; + + point = (char*)recording->Name(); + strcpy((char*)&sendBuffer[count], point); + count += strlen(point) + 1; + + point = (char*)recording->FileName(); + strcpy((char*)&sendBuffer[count], point); + count += strlen(point) + 1; + } + + *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + + printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0])); + + tcp.sendPacket(sendBuffer, count); + delete[] sendBuffer; + printf("Written list\n"); +} + +void MVPClient::processDeleteRecording(unsigned char* data, int length) +{ + // data is a pointer to the fileName string + + cRecordings Recordings; + Recordings.Load(); // probably have to do this + + cRecording* recording = Recordings.GetByName((char*)data); + + printf("recording pointer %p\n", recording); + + if (recording) + { + printf("deleting recording: %s\n", recording->Name()); + recording->Delete(); + sendULONG(1); + } + else + { + sendULONG(0); + } +} + +void MVPClient::processGetSummary(unsigned char* data, int length) +{ + // data is a pointer to the fileName string + + cRecordings Recordings; + Recordings.Load(); // probably have to do this + + cRecording* recording = Recordings.GetByName((char*)data); + + printf("recording pointer %p\n", recording); + + if (recording) + { + unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough + int count = 4; // leave space for the packet length + + char* point; + + point = (char*)recording->Summary(); + strcpy((char*)&sendBuffer[count], point); + count += strlen(point) + 1; + *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + + printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0])); + + tcp.sendPacket(sendBuffer, count); + delete[] sendBuffer; + printf("Written summary\n"); + + + } + else + { + sendULONG(0); + } +} + +void MVPClient::processGetChannelsList(unsigned char* data, int length) +{ + unsigned char* sendBuffer = new unsigned char[50000]; // FIXME hope this is enough + int count = 4; // leave space for the packet length + char* point; + unsigned long type; + + for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) + { + if (!channel->GroupSep()) + { + printf("name: '%s'\n", channel->Name()); + + if (count > 49000) break; + *(unsigned long*)&sendBuffer[count] = htonl(channel->Number()); + count += 4; + + if (channel->Vpid()) type = 1; + else type = 2; + + *(unsigned long*)&sendBuffer[count] = htonl(type); + count += 4; + + point = (char*)channel->Name(); + strcpy((char*)&sendBuffer[count], point); + count += strlen(point) + 1; + } + } + + *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + + printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0])); + + tcp.sendPacket(sendBuffer, count); + delete[] sendBuffer; + printf("Written channels list\n"); +} + +void MVPClient::processStartStreamingChannel(unsigned char* data, int length) +{ + printf("length = %i\n", length); + unsigned long channelNumber = ntohl(*(unsigned long*)data); + + cChannel* channel = channelFromNumber(channelNumber); + if (!channel) + { + sendULONG(0); + return; + } + +// MVPReceiver* m = new MVPReceiver(channel->Vpid(), channel->Apid1()); + cm = new cMediamvpTransceiver(channel, 0, 0, cDevice::ActualDevice()); + cDevice::ActualDevice()->AttachReceiver(cm); + //cDevice::ActualDevice()->SwitchChannel(channel, false); + + sendULONG(1); +} + +void MVPClient::processStopStreaming(unsigned char* data, int length) +{ + printf("STOP STREAMING RECEIVED\n"); + if (cm) + { + delete cm; + cm = NULL; + } + else if (rp) + { + writeResumeData(); + + delete rp; + delete recordingManager; + rp = NULL; + recordingManager = NULL; + } + + sendULONG(1); +} + +void MVPClient::processGetBlock(unsigned char* data, int length) +{ + if (!cm && !rp) + { + printf("Get block called when no streaming happening!\n"); + return; + } + + ULLONG position = ntohll(*(ULLONG*)data); + printf("getblock called for position = %llu\n", position); + + data += sizeof(ULLONG); + + unsigned long amount = ntohl(*(unsigned long*)data); + printf("getblock called for length = %lu\n", amount); + + unsigned char sendBuffer[amount + 4]; + unsigned long amountReceived = 0; // compiler moan. + if (cm) + { + printf("getting from live\n"); + amountReceived = cm->getBlock(&sendBuffer[4], amount); + } + else if (rp) + { + printf("getting from recording\n"); + amountReceived = rp->getBlock(&sendBuffer[4], position, amount); + } + + *(unsigned long*)&sendBuffer[0] = htonl(amountReceived); + printf("sendpacket go\n"); + tcp.sendPacket(sendBuffer, amountReceived + 4); + printf("written ok %lu\n", amountReceived); +} + +void MVPClient::processStartStreamingRecording(unsigned char* data, int length) +{ + // data is a pointer to the fileName string + + recordingManager = new cRecordings; + recordingManager->Load(); + + cRecording* recording = recordingManager->GetByName((char*)data); + + printf("recording pointer %p\n", recording); + + if (recording) + { + rp = new RecPlayer(recording); + + unsigned char sendBuffer[12]; + *(unsigned long*)&sendBuffer[0] = htonl(8); + *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength()); + + tcp.sendPacket(sendBuffer, 12); + printf("written totalLength\n"); + } + else + { + delete recordingManager; + recordingManager = NULL; + } +} + +void MVPClient::processGetChannelSchedule(unsigned char* data, int length) +{ + ULONG channelNumber = ntohl(*(ULLONG*)data); + printf("get schedule called for channel %lu\n", channelNumber); + + cChannel* channel = channelFromNumber(channelNumber); + if (!channel) + { + unsigned char sendBuffer[4]; + *(unsigned long*)&sendBuffer[0] = htonl(0); + tcp.sendPacket(sendBuffer, 4); + printf("written null\n"); + return; + } + + cMutexLock MutexLock; + const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock); +// const cSchedules* Schedules = cSchedules::Schedules(MutexLock); + if (!Schedules) + { + unsigned char sendBuffer[8]; + *(unsigned long*)&sendBuffer[0] = htonl(4); + *(unsigned long*)&sendBuffer[4] = htonl(0); + tcp.sendPacket(sendBuffer, 8); + printf("written 0\n"); + return; + } + + unsigned char sendBuffer[8]; + *(unsigned long*)&sendBuffer[0] = htonl(4); + *(unsigned long*)&sendBuffer[4] = htonl(1); + tcp.sendPacket(sendBuffer, 8); + printf("written 1\n"); + + +} + +void MVPClient::testChannelSchedule(unsigned char* data, int length) +{ + FILE* f = fopen("/tmp/s.txt", "w"); + + cMutexLock MutexLock; + const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock); +// const cSchedules* Schedules = cSchedules::Schedules(MutexLock); + if (!Schedules) + { + fprintf(f, "Schedules = NULL\n"); + fclose(f); + return; + } + + fprintf(f, "Schedules dump:\n"); + Schedules->Dump(f); + + + const cSchedule *Schedule; + int scheduleNumber = 0; + + tChannelID tchid; + cChannel *thisChannel; + + const cEventInfo* event; + int eventNumber = 0; + +// Schedule = Schedules->GetSchedule(channel->GetChannelID()); +// Schedule = Schedules->GetSchedule(); + Schedule = Schedules->First(); + if (!Schedule) + { + fprintf(f, "First Schedule = NULL\n"); + fclose(f); + return; + } + + while (Schedule) + { + fprintf(f, "Schedule #%i\n", scheduleNumber); + fprintf(f, "-------------\n\n"); + + tchid = Schedule->GetChannelID(); + fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString()); + fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents()); + thisChannel = Channels.GetByChannelID(tchid, true); + if (thisChannel) + { + fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number()); + } + else + { + fprintf(f, "thisChannel = NULL for tchid\n"); + } + + for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++) + { + event = Schedule->GetEventNumber(eventNumber); + fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString()); + fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent()); + fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription()); + fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle()); + fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber()); + fprintf(f, "Event %u dump:\n", eventNumber); + event->Dump(f); + fprintf(f, "\n\n"); + } + + + + fprintf(f, "\nDump from object:\n"); + Schedule->Dump(f); + fprintf(f, "\nEND\n"); + + + + +/* + const cEventInfo *GetPresentEvent(void) const; + const cEventInfo *GetFollowingEvent(void) const; + const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const; + const cEventInfo *GetEventAround(time_t tTime) const; + const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } + + + const unsigned char GetTableID(void) const; + const char *GetTimeString(void) const; + const char *GetEndTimeString(void) const; + const char *GetDate(void) const; + bool IsFollowing(void) const; + bool IsPresent(void) const; + const char *GetExtendedDescription(void) const; + const char *GetSubtitle(void) const; + const char *GetTitle(void) const; + unsigned short GetEventID(void) const; + long GetDuration(void) const; + time_t GetTime(void) const; + tChannelID GetChannelID(void) const; + int GetChannelNumber(void) const { return nChannelNumber; } + void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' + void Dump(FILE *f, const char *Prefix = "") const; + +*/ + + + + + + fprintf(f, "End of current Schedule\n\n\n"); + + Schedule = (const cSchedule *)Schedules->Next(Schedule); + scheduleNumber++; + } + + fclose(f); +} + +void MVPClient::processConfigSave(unsigned char* buffer, int length) +{ + char* section = (char*)buffer; + char* key = NULL; + char* value = NULL; + + for (int k = 0; k < length; k++) + { + if (buffer[k] == '\0') + { + if (!key) + { + key = (char*)&buffer[k+1]; + } + else + { + value = (char*)&buffer[k+1]; + break; + } + } + } + + // if the last string (value) doesnt have null terminator, give up + if (buffer[length - 1] != '\0') return; + + printf("Config save:\n%s\n%s\n%s\n", section, key, value); + if (config.setValueString(section, key, value)) + { + sendULONG(1); + } + else + { + sendULONG(0); + } +} + +void MVPClient::processConfigLoad(unsigned char* buffer, int length) +{ + char* section = (char*)buffer; + char* key = NULL; + + for (int k = 0; k < length; k++) + { + if (buffer[k] == '\0') + { + key = (char*)&buffer[k+1]; + break; + } + } + + char* value = config.getValueString(section, key); + + if (value) + { + unsigned char sendBuffer[4 + strlen(value) + 1]; + *(unsigned long*)&sendBuffer[0] = htonl(strlen(value) + 1); + strcpy((char*)&sendBuffer[4], value); + tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1); + + printf("Written config load packet\n"); + delete[] value; + } + else + { + unsigned char sendBuffer[8]; + *(unsigned long*)&sendBuffer[0] = htonl(0); + *(unsigned long*)&sendBuffer[4] = htonl(0); + tcp.sendPacket(sendBuffer, 8); + + printf("Written config load failed packet\n"); + } +} + +void MVPClient::cleanConfig() +{ + printf("Clean config\n"); + + cRecordings Recordings; + Recordings.Load(); + + int numReturns; + int length; + char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length); + char* position = resumes; + for(int k = 0; k < numReturns; k++) + { + printf("EXAMINING: %i %i %p %s\n", k, numReturns, position, position); + + cRecording* recording = Recordings.GetByName(position); + if (!recording) + { + // doesn't exist anymore + printf("Found a recording that doesn't exist anymore\n"); + config.deleteValue("ResumeData", position); + } + else + { + printf("This recording still exists\n"); + } + + position += strlen(position) + 1; + } + + delete[] resumes; +} + + diff --git a/mvpclient.h b/mvpclient.h new file mode 100644 index 0000000..d704314 --- /dev/null +++ b/mvpclient.h @@ -0,0 +1,83 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MVPCLIENT_H +#define MVPCLIENT_H + +#include +#include +#include +#include + +#include // sleep + +#include +#include +#include +#include + +#include "tcp.h" +#include "transceiver.h" +#include "recplayer.h" +#include "config.h" + +class MVPClient +{ + public: + MVPClient(int tsocket); + ~MVPClient(); + + int run(); + // not for external use + void run2(); + + private: + pthread_t runThread; + int initted; + TCP tcp; + Config config; + cMediamvpTransceiver* cm; + cRecordings* recordingManager; + RecPlayer* rp; + int timeOffset; + + void processLogin(unsigned char* buffer, int length); + void processGetRecordingsList(unsigned char* data, int length); + void processDeleteRecording(unsigned char* data, int length); + void processGetSummary(unsigned char* data, int length); + void processGetChannelsList(unsigned char* data, int length); + void processStartStreamingChannel(unsigned char* data, int length); + void processGetBlock(unsigned char* data, int length); + void processStopStreaming(unsigned char* data, int length); + void processStartStreamingRecording(unsigned char* data, int length); + void processGetChannelSchedule(unsigned char* data, int length); + void processConfigSave(unsigned char* data, int length); + void processConfigLoad(unsigned char* data, int length); + + cChannel* channelFromNumber(unsigned long channelNumber); + void writeResumeData(); + void cleanConfig(); + + void sendULONG(ULONG ul); + + void testChannelSchedule(unsigned char* data, int length); +}; + +#endif diff --git a/mvpserver.c b/mvpserver.c new file mode 100644 index 0000000..35bb3f1 --- /dev/null +++ b/mvpserver.c @@ -0,0 +1,138 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mvpserver.h" + +// undeclared function +void MVPServerStartThread(void *arg) +{ + MVPServer *m = (MVPServer *)arg; + m->run2(); +} + + +MVPServer::MVPServer() +{ + runThread = 0; + running = 0; +} + +MVPServer::~MVPServer() +{ + if (running) stop(); +} + +int MVPServer::stop() +{ + if (!running) return 0; + + udpr.stop(); + + pthread_cancel(runThread); + pthread_join(runThread, NULL); + + close(listeningSocket); + + return 1; +} + +int MVPServer::run() +{ + if (running) return 1; + +// logger.init(Log::DEBUG, "/tmp/vompserver.log"); + + if (udpr.run() == 0) return 0; + + if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPServerStartThread, (void *)this) == -1) return 0; + printf("MVPServer run success\n"); + return 1; +} + +void MVPServer::run2() +{ + // Thread stuff + // I don't want signals and I want to die as soon as I am cancelled because I'll be in accept() + sigset_t sigset; + sigfillset(&sigset); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + struct sockaddr_in address; + address.sin_family = AF_INET; + address.sin_port = htons(3024); + address.sin_addr.s_addr = INADDR_ANY; + socklen_t length = sizeof(address); + + listeningSocket = socket(AF_INET, SOCK_STREAM, 0); + if (listeningSocket < 0) + { + printf("Could not get TCP socket in vompserver\n"); + return; + } + + int value=1; + setsockopt(listeningSocket,SOL_SOCKET,SO_REUSEADDR,&value,sizeof(value)); + + if (bind(listeningSocket,(struct sockaddr *)&address,sizeof(address)) < 0) + { + printf("Could not bind to socket in vompserver\n"); + close(listeningSocket); + return; + } + + listen(listeningSocket, 5); + + int clientSocket; + + while(1) + { + clientSocket = accept(listeningSocket,(struct sockaddr *)&address, &length); + MVPClient* m = new MVPClient(clientSocket); + m->run(); + } +} + + +ULLONG ntohll(ULLONG a) +{ + return htonll(a); +} + +ULLONG htonll(ULLONG a) +{ + #if BYTE_ORDER == BIG_ENDIAN + return a; + #else + ULLONG b = 0; + + b = ((a << 56) & 0xFF00000000000000ULL) + | ((a << 40) & 0x00FF000000000000ULL) + | ((a << 24) & 0x0000FF0000000000ULL) + | ((a << 8) & 0x000000FF00000000ULL) + | ((a >> 8) & 0x00000000FF000000ULL) + | ((a >> 24) & 0x0000000000FF0000ULL) + | ((a >> 40) & 0x000000000000FF00ULL) + | ((a >> 56) & 0x00000000000000FFULL) ; + + return b; + #endif +} diff --git a/mvpserver.h b/mvpserver.h new file mode 100644 index 0000000..64caaff --- /dev/null +++ b/mvpserver.h @@ -0,0 +1,53 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MVPSERVER_H +#define MVPSERVER_H + +#include +#include +#include // sleep +#include + +#include "defines.h" +#include "udpreplier.h" +#include "mvpclient.h" + +class MVPServer +{ + public: + MVPServer(); + ~MVPServer(); + + int run(); + int stop(); + + // not for external use + void run2(); + + private: + pthread_t runThread; + int running; + + UDPReplier udpr; + int listeningSocket; +}; + +#endif diff --git a/recplayer.c b/recplayer.c new file mode 100644 index 0000000..6c24033 --- /dev/null +++ b/recplayer.c @@ -0,0 +1,167 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "recplayer.h" + +RecPlayer::RecPlayer(cRecording* rec) +{ + file = NULL; + totalLength = 0; + lastPosition = 0; + recording = rec; + + // FIXME find out max file path / name lengths + + + char fileName[2048]; + for(int i = 1; i < 1001; i++) + { + snprintf(fileName, 2047, "%s/%03i.vdr", rec->FileName(), i); + printf("FILENAME: %s\n", fileName); + file = fopen(fileName, "r"); + if (file) + { + segments[i] = new Segment(); + segments[i]->start = totalLength; + + fseek(file, 0, SEEK_END); + totalLength += ftell(file); + printf("File %i found, totalLength now %llu\n", i, totalLength); + segments[i]->end = totalLength; + fclose(file); + } + else + { + segments[i] = NULL; + break; + } + } + openFile(1); +} + +RecPlayer::~RecPlayer() +{ + printf("RecPlayer destructor\n"); + int i = 1; + while(segments[i++]) delete segments[i]; + if (file) fclose(file); +} + +int RecPlayer::openFile(int index) +{ + if (file) fclose(file); + + char fileName[2048]; + snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index); + printf("openFile called for index %i string:%s\n", index, fileName); + + file = fopen(fileName, "r"); + if (!file) + { + printf("file failed to open\n"); + fileOpen = 0; + return 0; + } + fileOpen = index; + return 1; +} + +ULLONG RecPlayer::getTotalLength() +{ + return totalLength; +} + +unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsigned long amount) +{ + if ((amount > totalLength) || (amount > 100000)) + { + printf("Amount %lu requested and rejected\n", amount); + return 0; + } + + if (position >= totalLength) + { + printf("Client asked for data starting past end of recording!\n"); + return 0; + } + + if ((position + amount) > totalLength) + { + printf("Client asked for some data past the end of recording, adjusting amount\n"); + amount = totalLength - position; + } + + // work out what block position is in + int segmentNumber; + for(segmentNumber = 1; segmentNumber < 1000; segmentNumber++) + { + if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break; + // position is in this block + } + + // we could be seeking around + if (segmentNumber != fileOpen) + { + if (!openFile(segmentNumber)) return 0; + } + + ULLONG currentPosition = position; + ULONG yetToGet = amount; + ULONG got = 0; + ULONG getFromThisSegment = 0; + ULONG filePosition; + + while(got < amount) + { + if (got) + { + // if(got) then we have already got some and we are back around + // advance the file pointer to the next file + if (!openFile(++segmentNumber)) return 0; + } + + // is the request completely in this block? + if ((currentPosition + yetToGet) <= segments[segmentNumber]->end) + getFromThisSegment = yetToGet; + else + getFromThisSegment = segments[segmentNumber]->end - currentPosition; + + filePosition = currentPosition - segments[segmentNumber]->start; + fseek(file, filePosition, SEEK_SET); + if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem. + + got += getFromThisSegment; + currentPosition += getFromThisSegment; + yetToGet -= getFromThisSegment; + } + + lastPosition = position; + return got; +} + +ULLONG RecPlayer::getLastPosition() +{ + return lastPosition; +} + +cRecording* RecPlayer::getCurrentRecording() +{ + return recording; +} diff --git a/recplayer.h b/recplayer.h new file mode 100644 index 0000000..0a48b41 --- /dev/null +++ b/recplayer.h @@ -0,0 +1,56 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef RECPLAYER_H +#define RECPLAYER_H + +#include +#include + +#include "defines.h" + +class Segment +{ + public: + ULLONG start; + ULLONG end; +}; + +class RecPlayer +{ + public: + RecPlayer(cRecording* rec); + ~RecPlayer(); + ULLONG getTotalLength(); + unsigned long getBlock(unsigned char* buffer, ULLONG position, unsigned long amount); + int openFile(int index); + ULLONG getLastPosition(); + cRecording* getCurrentRecording(); + + private: + cRecording* recording; + FILE* file; + int fileOpen; + Segment* segments[1001]; + ULLONG totalLength; + ULLONG lastPosition; +}; + +#endif diff --git a/remux/README b/remux/README new file mode 100644 index 0000000..0ee66d8 --- /dev/null +++ b/remux/README @@ -0,0 +1,7 @@ +These remux files are taken from the mediamvp plugin for VDR, +which takes them from the streamdev plugin for VDR. + +So these files are written by, and Copyright, Sascha Volkenandt. +I think. + + diff --git a/remux/ts2es.c b/remux/ts2es.c new file mode 100644 index 0000000..68b41f0 --- /dev/null +++ b/remux/ts2es.c @@ -0,0 +1,87 @@ +#include "ts2es.h" + +// from VDR's remux.c +#define MAXNONUSEFULDATA (10*1024*1024) + +class cTS2ES: public ipack { + friend void PutES(uint8_t *Buffer, int Size, void *Data); + +private: + uint8_t *m_ResultBuffer; + int *m_ResultCount; + +public: + cTS2ES(uint8_t *ResultBuffer, int *ResultCount); + ~cTS2ES(); + + void PutTSPacket(const uint8_t *Buffer); +}; + +void PutES(uint8_t *Buffer, int Size, void *Data) { + cTS2ES *This = (cTS2ES*)Data; + uint8_t payl = Buffer[8] + 9 + This->start - 1; + int count = Size - payl; + + if (*This->m_ResultCount + count > RESULTBUFFERSIZE) { + esyslog("ERROR: result buffer overflow (%d + %d > %d)", + *This->m_ResultCount, count, RESULTBUFFERSIZE); + count = RESULTBUFFERSIZE - *This->m_ResultCount; + } + memcpy(This->m_ResultBuffer + *This->m_ResultCount, Buffer + payl, count); + *This->m_ResultCount += count; + This->start = 1; +} + +cTS2ES::cTS2ES(uint8_t *ResultBuffer, int *ResultCount) { + m_ResultBuffer = ResultBuffer; + m_ResultCount = ResultCount; + + init_ipack(this, IPACKS, PutES, 0); + data = (void*)this; +} + +cTS2ES::~cTS2ES() { +} + +void cTS2ES::PutTSPacket(const uint8_t *Buffer) { + if (!Buffer) + return; + + if (Buffer[1] & 0x80) { // ts error + // TODO + } + + if (Buffer[1] & 0x40) { // payload start + if (plength == MMAX_PLENGTH - 6) { + plength = found - 6; + found = 0; + send_ipack(this); + reset_ipack(this); + } + } + + uint8_t off = 0; + + if (Buffer[3] & 0x20) { // adaptation field? + off = Buffer[4] + 1; + if (off + 4 > TS_SIZE - 1) + return; + } + + instant_repack((uint8_t*)(Buffer + 4 + off), TS_SIZE - 4 - off, this); +} + +cTS2ESRemux::cTS2ESRemux(int Pid): + cTSRemux(false) { + m_Pid = Pid; + m_Remux = new cTS2ES(m_ResultBuffer, &m_ResultCount); +} + +cTS2ESRemux::~cTS2ESRemux() { + delete m_Remux; +} + +void cTS2ESRemux::PutTSPacket(int Pid, const uint8_t *Data) { + if (Pid == m_Pid) m_Remux->PutTSPacket(Data); +} + diff --git a/remux/ts2es.h b/remux/ts2es.h new file mode 100644 index 0000000..52e9918 --- /dev/null +++ b/remux/ts2es.h @@ -0,0 +1,21 @@ +#ifndef VDR_STREAMDEV_TS2ESREMUX_H +#define VDR_STREAMDEV_TS2ESREMUX_H + +#include "tsremux.h" + +class cTS2ES; + +class cTS2ESRemux: public cTSRemux { +private: + int m_Pid; + cTS2ES *m_Remux; + +protected: + virtual void PutTSPacket(int Pid, const uint8_t *Data); + +public: + cTS2ESRemux(int Pid); + virtual ~cTS2ESRemux(); +}; + +#endif // VDR_STREAMDEV_TS2ESREMUX_H diff --git a/remux/ts2ps.c b/remux/ts2ps.c new file mode 100644 index 0000000..e23fdca --- /dev/null +++ b/remux/ts2ps.c @@ -0,0 +1,108 @@ +#include "ts2ps.h" + +class cTS2PS { + friend void PutPES(uint8_t *Buffer, int Size, void *Data); + +private: + ipack m_Ipack; + uint8_t *m_ResultBuffer; + int *m_ResultCount; + +public: + cTS2PS(uint8_t *ResultBuffer, int *ResultCount, uint8_t AudioCid = 0x00, + bool PS = false); + ~cTS2PS(); + + void PutTSPacket(const uint8_t *Buffer); +}; + +void PutPES(uint8_t *Buffer, int Size, void *Data) { + cTS2PS *This = (cTS2PS*)Data; + if (Size <= 0 || !Buffer || !This ) { + esyslog("ERROR: negative size or null pointers"); + return; + } + if (*This->m_ResultCount + Size > RESULTBUFFERSIZE) { + esyslog("ERROR: result buffer overflow (%d + %d > %d)", + *This->m_ResultCount, Size, RESULTBUFFERSIZE); + Size = RESULTBUFFERSIZE - *This->m_ResultCount; + } + memcpy(This->m_ResultBuffer + *This->m_ResultCount, Buffer, Size); + *This->m_ResultCount += Size; +} + +cTS2PS::cTS2PS(uint8_t *ResultBuffer, int *ResultCount, uint8_t AudioCid, + bool PS) { + m_ResultBuffer = ResultBuffer; + m_ResultCount = ResultCount; + + init_ipack(&m_Ipack, IPACKS, PutPES, PS); + m_Ipack.cid = AudioCid; + m_Ipack.data = (void*)this; +} + +cTS2PS::~cTS2PS() { +} + +void cTS2PS::PutTSPacket(const uint8_t *Buffer) { + if (!Buffer) + return; + + if (Buffer[1] & 0x80) { // ts error + // TODO + } + + if (Buffer[1] & 0x40) { // payload start + if (m_Ipack.plength == MMAX_PLENGTH - 6 && m_Ipack.found > 6) { + m_Ipack.plength = m_Ipack.found - 6; + m_Ipack.found = 0; + send_ipack(&m_Ipack); + reset_ipack(&m_Ipack); + } + } + + uint8_t off = 0; + + if (Buffer[3] & 0x20) { // adaptation field? + off = Buffer[4] + 1; + if (off + 4 > TS_SIZE - 1) + return; + } + + instant_repack((uint8_t*)(Buffer + 4 + off), TS_SIZE - 4 - off, &m_Ipack); +} + +cTS2PSRemux::cTS2PSRemux(int VPid, int APid1, int APid2, int DPid1, + int DPid2, bool PS) { + m_VPid = VPid; + m_APid1 = APid1; + m_APid2 = APid2; + m_DPid1 = DPid1; + m_DPid2 = DPid2; + m_VRemux = new cTS2PS(m_ResultBuffer, &m_ResultCount, 0x00, PS); + m_ARemux1 = new cTS2PS(m_ResultBuffer, &m_ResultCount, 0xC0, PS); + m_ARemux2 = APid2 ? new cTS2PS(m_ResultBuffer, &m_ResultCount, 0xC1, PS) + : NULL; + m_DRemux1 = DPid1 ? new cTS2PS(m_ResultBuffer, &m_ResultCount, 0x00, PS) + : NULL; + //XXX don't yet know how to tell apart primary and secondary DD data... + m_DRemux2 = /*XXX m_DPid2 ? new cTS2PS(m_ResultBuffer, &m_ResultCount, + 0x00, PS) : XXX*/ NULL; +} + +cTS2PSRemux::~cTS2PSRemux() { + if (m_DRemux2) delete m_DRemux2; + if (m_DRemux1) delete m_DRemux1; + if (m_ARemux2) delete m_ARemux2; + delete m_ARemux1; + delete m_VRemux; +} + +void cTS2PSRemux::PutTSPacket(int Pid, const uint8_t *Data) { + if (Pid == m_VPid) m_VRemux->PutTSPacket(Data); + else if (Pid == m_APid1) m_ARemux1->PutTSPacket(Data); + else if (Pid == m_APid2 && m_ARemux2) m_ARemux2->PutTSPacket(Data); + else if (Pid == m_DPid1 && m_DRemux1) m_DRemux1->PutTSPacket(Data); + else if (Pid == m_DPid2 && m_DRemux2) m_DRemux2->PutTSPacket(Data); +} + diff --git a/remux/ts2ps.h b/remux/ts2ps.h new file mode 100644 index 0000000..5760f09 --- /dev/null +++ b/remux/ts2ps.h @@ -0,0 +1,22 @@ +#ifndef VDR_STREAMDEV_TS2PESREMUX_H +#define VDR_STREAMDEV_TS2PESREMUX_H + +#include "tsremux.h" + +class cTS2PS; + +class cTS2PSRemux: public cTSRemux { +private: + int m_VPid, m_APid1, m_APid2, m_DPid1, m_DPid2; + cTS2PS *m_VRemux, *m_ARemux1, *m_ARemux2, *m_DRemux1, *m_DRemux2; + +protected: + virtual void PutTSPacket(int Pid, const uint8_t *Data); + +public: + cTS2PSRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, + bool PS = false); + virtual ~cTS2PSRemux(); +}; + +#endif // VDR_STREAMDEV_TS2PESREMUX_H diff --git a/remux/tsremux.c b/remux/tsremux.c new file mode 100644 index 0000000..895a435 --- /dev/null +++ b/remux/tsremux.c @@ -0,0 +1,209 @@ +#include "tsremux.h" + +// from VDR's remux.c +#define MAXNONUSEFULDATA (10*1024*1024) +#define SC_PICTURE 0x00 // "picture header" +#define VIDEO_STREAM_S 0xE0 + +cTSRemux::cTSRemux(bool Sync) { + memset(m_PROTECTION1, 0x20, PROTECTIONSIZE); + m_ResultCount = 0; + m_ResultDelivered = 0; + m_Synced = false; + m_Skipped = 0; + m_Sync = Sync; +} + +cTSRemux::~cTSRemux(void) { +} + +uchar *cTSRemux::Process(const uchar *Data, int &Count, int &Result) { + // Remove any previously delivered data from the result buffer: + if (m_ResultDelivered) { + if (m_ResultDelivered < m_ResultCount) + memmove(m_ResultBuffer, m_ResultBuffer + m_ResultDelivered, m_ResultCount + - m_ResultDelivered); + m_ResultCount -= m_ResultDelivered; + m_ResultDelivered = 0; + } + + int used = 0; + + // Make sure we are looking at a TS packet: + while (Count > TS_SIZE) { + if (Data[0] == 0x47 && Data[TS_SIZE] == 0x47) + break; + Data++; + Count--; + used++; + } + if (used) + esyslog("ERROR: skipped %d byte to sync on TS packet", used); + + // Convert incoming TS data + for (int i = 0; i < Count; i += TS_SIZE) { + if (Count - i < TS_SIZE) + break; + if (Data[i] != 0x47) + break; + int pid = get_pid((uint8_t*)(Data + i + 1)); + if (Data[i + 3] & 0x10) // got payload + PutTSPacket(pid, Data + i); + /*if (pid == m_VPid) m_VRemux->ConvertTSPacket(Data + i); + else if (pid == m_APid1) m_ARemux1->ConvertTSPacket(Data + i); + else if (pid == m_APid2 && m_ARemux2) m_ARemux2->ConvertTSPacket(Data + i); + else if (pid == m_DPid1 && m_DRemux1) m_DRemux1->ConvertTSPacket(Data + i); + else if (pid == m_DPid2 && m_DRemux2) m_DRemux2->ConvertTSPacket(Data + i);*/ + used += TS_SIZE; + if (m_ResultCount > (int)sizeof(m_ResultBuffer) / 2) + break; + +#if 0 + if (memcmp(m_PROTECTION1, m_PROTECTION1+(PROTECTIONSIZE/2), PROTECTIONSIZE/2)) { + int ow_from = -1; // counted from _end_ of protection buffer + int ow_to = -1; // counted from _end_ of protection buffer + for (int pi=0; pi= 0) { + if (m_Skipped > MAXNONUSEFULDATA) { + esyslog("ERROR: no useful data seen within %d byte of video stream", m_Skipped); + m_Skipped = -1; + //if (exitOnFailure) + //cThread::EmergencyExit(true); + } + else + m_Skipped += Count; + } + + // Check for frame borders: + + if (m_ResultCount >= MINVIDEODATA) { + for (int i = 0; i < m_ResultCount; i++) { + if (m_ResultBuffer[i] == 0 && m_ResultBuffer[i + 1] == 0 && m_ResultBuffer[i + 2] == 1) { + switch (m_ResultBuffer[i + 3]) { + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + { + uchar pt = NO_PICTURE; + int l = ScanVideoPacket(m_ResultBuffer, m_ResultCount, i, pt); + if (l < 0) + return NULL; // no useful data found, wait for more + if (pt != NO_PICTURE) { + if (pt < I_FRAME || B_FRAME < pt) + esyslog("ERROR: unknown picture type '%d'", pt); + else if (!m_Synced) { + if (pt == I_FRAME) { + m_ResultDelivered = i; // will drop everything before this position + SetBrokenLink(m_ResultBuffer + i, l); + m_Synced = true; + } + else { + m_ResultDelivered = i + l; // will drop everything before and including this packet + return NULL; + } + } + } + if (m_Synced) { + Result = l; + uchar *p = m_ResultBuffer + m_ResultDelivered; + m_ResultDelivered += l; + return p; + } + else { + m_ResultDelivered = i + l; // will drop everything before and including this packet + return NULL; + } + } + break; + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + { + int l = GetPacketLength(m_ResultBuffer, m_ResultCount, i); + if (l < 0) + return NULL; // no useful data found, wait for more + + /* This shouldn't be happening - why does it for some channels? */ + if ( l > m_ResultCount ) + return NULL; + if (m_Synced) { + Result = l; + uchar *p = m_ResultBuffer + m_ResultDelivered; + m_ResultDelivered += l; + return p; + } + else { + m_ResultDelivered = i + l; // will drop everything before and including this packet + return NULL; + } + } + break; + } + } + } + } + return NULL; // no useful data found, wait for more +} + +int cTSRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType) { + // Scans the video packet starting at Offset and returns its length. + // If the return value is -1 the packet was not completely in the buffer. + + int Length = GetPacketLength(Data, Count, Offset); + if (Length > 0 && Offset + Length <= Count) { + int i = Offset + 8; // the minimum length of the video packet header + i += Data[i] + 1; // possible additional header bytes + for (; i < Offset + Length; i++) { + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { + switch (Data[i + 3]) { + case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07; + return Length; + } + } + } + PictureType = NO_PICTURE; + return Length; + } + return -1; +} + +int cTSRemux::GetPacketLength(const uchar *Data, int Count, int Offset) { + // Returns the entire length of the packet starting at offset, or -1 in case of error. + return (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1; +} + +void cTSRemux::SetBrokenLink(uchar *Data, int Length) { + if (Length > 9 && Data[0] == 0 && Data[1] == 0 && Data[2] == 1 && (Data[3] & VIDEO_STREAM_S) == VIDEO_STREAM_S) { + for (int i = Data[8] + 9; i < Length - 7; i++) { // +9 to skip video packet header + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) { + if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed + Data[i + 7] |= 0x20; + return; + } + } + dsyslog("SetBrokenLink: no GOP header found in video packet"); + } + else + dsyslog("SetBrokenLink: no video packet in frame"); +} diff --git a/remux/tsremux.h b/remux/tsremux.h new file mode 100644 index 0000000..2a28a35 --- /dev/null +++ b/remux/tsremux.h @@ -0,0 +1,42 @@ +#ifndef VDR_STREAMDEV_TSREMUX_H +#define VDR_STREAMDEV_TSREMUX_H + +#include "transform.h" +#include + +#define IPACKS 2048 + +#define PROTECTIONSIZE 32768 + +#ifndef RESULTBUFFERSIZE +#define RESULTBUFFERSIZE KILOBYTE(256) +#endif +#ifndef MINVIDEODATA +#define MINVIDEODATA (16*1024) +#endif + +class cTSRemux { +protected: + uchar m_PROTECTION1[PROTECTIONSIZE]; // something sometimes overwrites vtbl without this buffer + uchar m_ResultBuffer[RESULTBUFFERSIZE]; + int m_ResultCount; + int m_ResultDelivered; + int m_Synced; + int m_Skipped; + int m_Sync; + + int GetPacketLength(const uchar *Data, int Count, int Offset); + int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); + + virtual void PutTSPacket(int Pid, const uint8_t *Data) = 0; + +public: + cTSRemux(bool Sync = true); + virtual ~cTSRemux(); + + virtual uchar *Process(const uchar *Data, int &Count, int &Result); + + static void SetBrokenLink(uchar *Data, int Length); +}; + +#endif // VDR_STREAMDEV_TSREMUX_H diff --git a/ringbuffer.c b/ringbuffer.c new file mode 100644 index 0000000..abe7d7d --- /dev/null +++ b/ringbuffer.c @@ -0,0 +1,100 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ringbuffer.h" + +Ringbuffer::Ringbuffer() +{ + capacity = 0; + content = 0; + buffer = NULL; + start = NULL; + end = NULL; +} + +Ringbuffer::~Ringbuffer() +{ + free(buffer); + capacity = 0; + content = 0; + buffer = NULL; + start = NULL; + end = NULL; +} + +int Ringbuffer::init(size_t size) +{ + capacity = size; + buffer = (UCHAR*)malloc(capacity); + if (!buffer) return 0; + start = buffer; + end = buffer; + return 1; +} + +int Ringbuffer::put(UCHAR* from, size_t amount) +{ + if (amount > capacity) return 0; + + if ((end + amount) <= (buffer + capacity)) + { + memcpy(end, from, amount); + end += amount; + content += amount; + + if (end == (buffer + capacity)) end = buffer; + if (content >= capacity) + { + start = end; + content = capacity; + } + return 1; + } + else + { + size_t firstAmount = buffer + capacity - end; + return (put(from, firstAmount) && put(from + firstAmount, amount - firstAmount)); + } +} + +int Ringbuffer::get(UCHAR* to, size_t amount) +{ + if (amount > content) return get(to, content); + + if ((start + amount) <= (buffer + capacity)) + { + memcpy(to, start, amount); + start += amount; + content -= amount; + + if (start == (buffer + capacity)) start = buffer; + return amount; + } + else + { + size_t firstAmount = buffer + capacity - start; + return (get(to, firstAmount) + get(to + firstAmount, amount - firstAmount)); + } +} + +int Ringbuffer::getContent() +{ + return content; +} diff --git a/ringbuffer.h b/ringbuffer.h new file mode 100644 index 0000000..568a286 --- /dev/null +++ b/ringbuffer.h @@ -0,0 +1,48 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef RINGBUFFER_H +#define RINGBUFFER_H + +#include +#include +#include + +#include "defines.h" + +class Ringbuffer +{ + public: + Ringbuffer(); + ~Ringbuffer(); + int init(size_t size); + int put(UCHAR* from, size_t amount); + int get(UCHAR* to, size_t amount); + int getContent(); + + private: + UCHAR* buffer; + UCHAR* start; + UCHAR* end; + size_t capacity; + size_t content; +}; + +#endif diff --git a/tcp.c b/tcp.c new file mode 100644 index 0000000..b1d09c3 --- /dev/null +++ b/tcp.c @@ -0,0 +1,412 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "tcp.h" + +TCP::TCP(int tsocket) +{ + sock = -1; + connected = 0; + readTimeoutEnabled = 1; + + if (tsocket) + { + sock = tsocket; + connected = 1; + } +} + +TCP::~TCP() +{ + if (connected) cleanup(); +} + +void TCP::cleanup() +{ + close(sock); + sock = -1; + connected = 0; + printf("TCP has closed socket\n"); +} + + +void TCP::disableReadTimeout() +{ + readTimeoutEnabled = 0; +} + +int TCP::connectTo(char* host, unsigned short port) +{ + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock == -1) return 0; + + struct sockaddr_in dest_addr; + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(port); + + if (!inet_aton(host, &dest_addr.sin_addr)) + { + cleanup(); + return 0; + } + + memset(&(dest_addr.sin_zero), '\0', 8); + + int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)); + if (success == -1) + { + cleanup(); + return 0; + } + + connected = 1; + return 1; +} + +void TCP::setNonBlocking() +{ + int oldflags = fcntl(sock, F_GETFL, 0); + oldflags |= O_NONBLOCK; + fcntl(sock, F_SETFL, oldflags); +} + +int TCP::setSoKeepTime(int timeOut) +{ + int option; + int s1, s2, s3, s4; + + option = 1; + s1 = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)); + printf("SO_KEEPALIVE = %i\n", s1); + + option = timeOut; + s2 = setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &option, sizeof(option)); + printf("TCP_KEEPIDLE = %i\n", s2); + + s3 = setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &option, sizeof(option)); + printf("TCP_KEEPINTVL = %i\n", s3); + + option = 2; + s4 = setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &option, sizeof(option)); + printf("TCP_KEEPCNT = %i\n", s4); + + if (s1 || s2 || s3 || s4) return 0; + return 1; +} + +void TCP::assignSocket(int tsocket) +{ + sock = tsocket; + connected = 1; +} + +int TCP::isConnected() +{ + return connected; +} + +UCHAR* TCP::receivePacket() +{ + if (!connected) return NULL; + + int packetLength; + int success; + + success = readData((UCHAR*)&packetLength, sizeof(int)); + if (!success) + { + cleanup(); + return NULL; + } + + packetLength = ntohl(packetLength); + + if (packetLength > 200000) return NULL; + UCHAR* buffer = (UCHAR*) malloc(packetLength); + + success = readData(buffer, packetLength); + if (!success) + { + cleanup(); + free(buffer); + return NULL; + } + + dump((unsigned char*)buffer, packetLength); + + dataLength = packetLength; + return buffer; +} + +int TCP::getDataLength() +{ + return dataLength; +} + +int TCP::readData(UCHAR* buffer, int totalBytes) +{ + if (!connected) return 0; + + int bytesRead = 0; + int thisRead; + int readTries = 0; + int success; + fd_set readSet; + struct timeval timeout; + struct timeval* passToSelect; + + if (readTimeoutEnabled) passToSelect = &timeout; + else passToSelect = NULL; + + while(1) + { + FD_ZERO(&readSet); + FD_SET(sock, &readSet); + timeout.tv_sec = 10; + timeout.tv_usec = 0; + success = select(sock + 1, &readSet, NULL, NULL, passToSelect); + if (success < 1) + { + cleanup(); + printf("TCP: error or timeout\n"); + return 0; // error, or timeout + } + + thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead); + if (!thisRead) + { + // if read returns 0 then connection is closed + // in non-blocking mode if read is called with no data available, it returns -1 + // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway. + cleanup(); + return 0; + } + bytesRead += thisRead; + + printf("Bytes read now: %u\n", bytesRead); + if (bytesRead == totalBytes) + { + return 1; + } + else + { + if (++readTries == 100) + { + cleanup(); + printf("too many reads\n"); + return 0; + } + } + } +} + +int TCP::sendPacket(UCHAR* buf, size_t count) +{ + if (!connected) return 0; + + unsigned int bytesWritten = 0; + int thisWrite; + int writeTries = 0; + int success; + fd_set writeSet; + struct timeval timeout; + + while(1) + { + FD_ZERO(&writeSet); + FD_SET(sock, &writeSet); + timeout.tv_sec = 10; + timeout.tv_usec = 0; + success = select(sock + 1, NULL, &writeSet, NULL, &timeout); + if (success < 1) + { + cleanup(); + printf("TCP: error or timeout\n"); + return 0; // error, or timeout + } + + thisWrite = write(sock, &buf[bytesWritten], count - bytesWritten); + if (!thisWrite) + { + // if write returns 0 then connection is closed ? + // in non-blocking mode if read is called with no data available, it returns -1 + // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway. + cleanup(); + printf("Detected connection closed\n"); + return 0; + } + bytesWritten += thisWrite; + + printf("Bytes written now: %u\n", bytesWritten); + if (bytesWritten == count) + { + return 1; + } + else + { + if (++writeTries == 100) + { + cleanup(); + printf("too many writes\n"); + return 0; + } + } + } +} + + + + +void TCP::dump(unsigned char* data, USHORT size) +{ + printf("Size = %u\n", size); + + USHORT c = 0; + while(c < size) + { + if ((size - c) > 15) + { + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15])); + c += 16; + } + else + { + switch (size - c) + { + case 15: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14])); + c += 15; + break; + case 14: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13])); + c += 14; + break; + case 13: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12])); + c += 13; + break; + case 12: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11])); + c += 12; + break; + case 11: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10])); + c += 11; + break; + case 10: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9])); + c += 10; + break; + case 9: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8])); + c += 9; + break; + case 8: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7])); + c += 8; + break; + case 7: + printf(" %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6])); + c += 7; + break; + case 6: + printf(" %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5])); + c += 6; + break; + case 5: + printf(" %02X %02X %02X %02X %02X %c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4])); + c += 5; + break; + case 4: + printf(" %02X %02X %02X %02X %c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3])); + c += 4; + break; + case 3: + printf(" %02X %02X %02X %c%c%c\n", + data[c], data[c+1], data[c+2], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2])); + c += 3; + break; + case 2: + printf(" %02X %02X %c%c\n", + data[c], data[c+1], + dcc(data[c]), dcc(data[c+1])); + c += 2; + break; + case 1: + printf(" %02X %c\n", + data[c], + dcc(data[c])); + c += 1; + break; + } + } + } +} + +unsigned char TCP::dcc(UCHAR c) +{ + if (isspace(c)) return ' '; + if (isprint(c)) return c; + return '.'; +} diff --git a/tcp.h b/tcp.h new file mode 100644 index 0000000..f736707 --- /dev/null +++ b/tcp.h @@ -0,0 +1,78 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef TCP_H +#define TCP_H + +#include +#include +#include +#include +#include + +// For TCP_KEEPIDLE and co +#include + +#include +#include +#include +#include +#include + + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; + +class TCP +{ + public: + // Creation + TCP(int tsocket); + ~TCP(); + void assignSocket(int tsocket); + + // Setup + void disableReadTimeout(); + void setNonBlocking(); + int setSoKeepTime(int timeOut); + + int connectTo(char *host, unsigned short port); + int sendPacket(UCHAR*, size_t size); + UCHAR* receivePacket(); + + // Get methods + int isConnected(); + int getDataLength(); + + static void dump(unsigned char* data, USHORT size); + static UCHAR dcc(UCHAR c); + + private: + int sock; + int connected; + int readTimeoutEnabled; + int dataLength; + + void cleanup(); + int readData(UCHAR* buffer, int totalBytes); +}; + +#endif diff --git a/transceiver.c b/transceiver.c new file mode 100644 index 0000000..8a87fd0 --- /dev/null +++ b/transceiver.c @@ -0,0 +1,197 @@ +/* + Edited for VOMP by Chris Tallon + Edits Copyright 2004-2005 Chris Tallon +*/ + +/* + * MediaMVP Server + * + * (C) 2003 Dominic Morris + * + * $Id$ + * $Date$ + * + * Transceiver stuff - blatantly stolen from streamdev then changed + * a bit.. + */ + + + + + +#include "transceiver.h" +#include "ts2ps.h" +#include "ts2es.h" +//#include "setup.h" + +#include + +#include +#include + + +#define VIDEOBUFSIZE MEGABYTE(1) + +/* Disable logging if BUFCOUNT buffer overflows occur within BUFOVERTIME + milliseconds. Enable logging again if there is no error within BUFOVERTIME + milliseconds. */ +#define BUFOVERTIME 5000 +#define BUFOVERCOUNT 100 + +cMediamvpTransceiver::cMediamvpTransceiver(const cChannel *Channel, int Priority, int Socket, cDevice *Device) : + cReceiver(Channel->Ca(), Priority, 7, Channel->Vpid(), Channel->Ppid(), + Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2(), + Channel->Tpid()) { + m_Active = false; + m_Socket = Socket; + m_Remux = NULL; + m_Device = Device; + + m_RingBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true); +// m_RingBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 20, true); + + /* Select the correct Muxing depending on whether it's video or not */ + if ( Channel->Vpid() == 0 || Channel->Vpid() == 1 || Channel->Vpid() == 0x1FFF ) { + m_Remux = new cTS2ESRemux(Channel->Apid1()); + } else { + m_Remux = new cTS2PSRemux(Channel->Vpid(), Channel->Apid1(), 0, 0, 0, 0); + } + printf("Created transceiver at %p, remux @%p ringbuffer %p\n",this,m_Remux,m_RingBuffer); + + /* Suggested by Peter Wagner to assist single DVB card systems */ +#ifdef SINGLE_DEVICE + m_Device->SwitchChannel(Channel, true); +#else + m_Device->SwitchChannel(Channel, false); +#endif + Attach(); + + + // CJT + rb.init(1000000); + pthread_mutex_init(&ringLock, NULL); + +} + +cMediamvpTransceiver::~cMediamvpTransceiver(void) +{ + printf("Deleting transceiver at %p, remux @%p ringbuffer %p\n",this,m_Remux,m_RingBuffer); + + Detach(); + if (m_Remux) + delete m_Remux; + m_Remux = NULL; + if ( m_RingBuffer) + delete m_RingBuffer; + m_RingBuffer = NULL; +} + +void cMediamvpTransceiver::Activate(bool On) +{ + if (On) + Start(); + else if (m_Active) + Stop(); +} + +void cMediamvpTransceiver::Stop(void) +{ + if (m_Active) { + m_Active = false; + usleep(50000); + Cancel(0); + } +} + +void cMediamvpTransceiver::Receive(uchar *Data, int Length) +{ + static time_t firsterr = 0; + static int errcnt = 0; + static bool showerr = true; + + if (m_Active) { + int p = m_RingBuffer->Put(Data, Length); + if (p != Length) { + ++errcnt; + if (showerr) { + if (firsterr == 0) + firsterr = time_ms(); + else if (firsterr + BUFOVERTIME > time_ms() && errcnt > BUFOVERCOUNT) { + esyslog("ERROR: too many buffer overflows, logging stopped"); + showerr = false; + firsterr = time_ms(); + } + } else if (firsterr + BUFOVERTIME < time_ms()) { + showerr = true; + firsterr = 0; + errcnt = 0; + } + + if (showerr) + esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p); + else + firsterr = time_ms(); + } + } +} + +void cMediamvpTransceiver::Action(void) +{ + int max = 0; + + + printf("Mediamvp: Transceiver thread started (pid=%d)", getpid()); + + + m_Active = true; + + while (m_Active) { + int recvd; + const uchar *block = m_RingBuffer->Get(recvd); + + if (block && recvd > 0) { + const uchar *sendBlock; + int bytes = 0; + int taken = recvd; + + sendBlock = m_Remux->Process(block, taken, bytes); + + m_RingBuffer->Del(taken); + + if (bytes > max) + max = bytes; + // CJT + + // write(m_Socket,sendBlock,bytes); + // printf("Written %i bytes\n", bytes); + + + pthread_mutex_lock(&ringLock); + rb.put((unsigned char*)sendBlock, bytes); + pthread_mutex_unlock(&ringLock); +//printf("Put %i into buffer\n", bytes); + + + } else + usleep(1); + } + + + printf("Mediamvp: Transceiver thread ended"); +} + +unsigned long cMediamvpTransceiver::getBlock(unsigned char* buffer, unsigned long amount) +{ + pthread_mutex_lock(&ringLock); + + while ((unsigned long)rb.getContent() < amount) + { + pthread_mutex_unlock(&ringLock); + usleep(500000); + pthread_mutex_lock(&ringLock); + } + + unsigned long amountReceived = rb.get(buffer, amount); + pthread_mutex_unlock(&ringLock); + return amountReceived; +} diff --git a/transceiver.h b/transceiver.h new file mode 100644 index 0000000..e9b854c --- /dev/null +++ b/transceiver.h @@ -0,0 +1,71 @@ +/* + Edited for VOMP by Chris Tallon + Edits Copyright 2004-2005 Chris Tallon +*/ + +/* + * MediaMVP Plugin + * + * (C) 2003 Dominic Morris + * + * $Id$ + * $Date$ + * + * + * Transceiver stuff, stolen from streamdev again... + */ + +#ifndef VDR_MEDIAMVP_TRANSCEIVER_H +#define VDR_MEDIAMVP_TRANSCEIVER_H + +#include + +#include +#include + +class cRingBufferLinear; +class cRemux; +class cTSRemux; +class cServerConnection; +class cChannel; + + +#include +#include "ringbuffer.h" + +class cMediamvpTransceiver: public cReceiver, public cThread { +// friend class cMediamvpVdrURL; +private: + cDevice *m_Device; + cRingBufferLinear *m_RingBuffer; + cTSRemux *m_Remux; + int m_Socket; + + bool m_Active; + + // CJT + Ringbuffer rb; + pthread_mutex_t ringLock; + + +protected: + virtual void Receive(uchar *Data, int Length); + virtual void Action(void); + +public: + cMediamvpTransceiver(const cChannel *Channel, int Priority, int Socket, cDevice *Device); + virtual ~cMediamvpTransceiver(void); + + bool Attach(void) { return m_Device->AttachReceiver(this); } + void Detach(void) { cReceiver::Detach(); } + + void Stop(void); + + + // CJT + unsigned long getBlock(unsigned char* buffer, unsigned long amount); + virtual void Activate(bool On); + +}; + +#endif // VDR_MEDIAMVP_TRANSCEIVER_H diff --git a/udpreplier.c b/udpreplier.c new file mode 100644 index 0000000..d6a352f --- /dev/null +++ b/udpreplier.c @@ -0,0 +1,79 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "udpreplier.h" + +// undeclared function +void UDPReplierStartThread(void *arg) +{ + UDPReplier *m = (UDPReplier *)arg; + m->run2(); +} + + +UDPReplier::UDPReplier() + : ds(3024) +{ + runThread = 0; + running = 0; +} + +UDPReplier::~UDPReplier() +{ + if (running) stop(); +} + +int UDPReplier::stop() +{ + if (!running) return 0; + + running = 0; + pthread_cancel(runThread); + pthread_join(runThread, NULL); + + return 1; +} + +int UDPReplier::run() +{ + if (running) return 1; + running = 1; + if (pthread_create(&runThread, NULL, (void*(*)(void*))UDPReplierStartThread, (void *)this) == -1) return 0; + printf("UDPReplier run success\n"); + return 1; +} + +void UDPReplier::run2() +{ + // I don't want signals + sigset_t sigset; + sigfillset(&sigset); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); + + int retval; + while(1) + { + retval = ds.waitforMessage(0); + if (retval == 1) continue; + + if (!strcmp(ds.getData(), "VOMP CLIENT")) + ds.send(ds.getFromIPA(), 3024, "VOMP SERVER", 11); + } +} diff --git a/udpreplier.h b/udpreplier.h new file mode 100644 index 0000000..4d82ba8 --- /dev/null +++ b/udpreplier.h @@ -0,0 +1,49 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef UDPREPLIER_H +#define UDPREPLIER_H + +#include +#include +#include + +#include "dsock.h" + +class UDPReplier +{ + public: + UDPReplier(); + ~UDPReplier(); + + int run(); + int stop(); + + // not for external use + void run2(); + + private: + pthread_t runThread; + int running; + + DatagramSocket ds; +}; + +#endif diff --git a/vompserver.c b/vompserver.c new file mode 100644 index 0000000..1845937 --- /dev/null +++ b/vompserver.c @@ -0,0 +1,103 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * vomp-server.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#include + +#include "mvpserver.h" + +static const char *VERSION = "0.0.1"; +static const char *DESCRIPTION = "VDR on MVP plugin by Chris Tallon"; + +class cPluginVompserver : public cPlugin +{ +public: + cPluginVompserver(void); + virtual ~cPluginVompserver(); + virtual const char *Version(void) { return VERSION; } + virtual const char *Description(void) { return DESCRIPTION; } + virtual const char *CommandLineHelp(void); + virtual bool ProcessArgs(int argc, char *argv[]); + virtual bool Initialize(void); + virtual bool Start(void); + virtual bool SetupParse(const char *Name, const char *Value); + +private: + + MVPServer mvpserver; +}; + +cPluginVompserver::cPluginVompserver(void) +{ + // Initialize any member variables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! +} + +cPluginVompserver::~cPluginVompserver() +{ + // Clean up after yourself! + + mvpserver.stop(); +} + +const char *cPluginVompserver::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return NULL; +} + +bool cPluginVompserver::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + return true; +} + +bool cPluginVompserver::Initialize(void) +{ + // Initialize any background activities the plugin shall perform. + printf("VOMP Plugin init\n"); + return true; +} + +bool cPluginVompserver::Start(void) +{ + // Start any background activities the plugin shall perform. + printf("VOMP Plugin start\n"); + + int success = mvpserver.run(); + if (success) return true; + else return false; +} + +bool cPluginVompserver::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + return false; +} + +VDRPLUGINCREATOR(cPluginVompserver); // Don't touch this! -- 2.39.2