diff options
author | Sascha Volkenandt <sascha@akv-soft.de> | 2004-01-02 23:13:00 +0100 |
---|---|---|
committer | Sascha Volkenandt <sascha@akv-soft.de> | 2004-01-02 23:13:00 +0100 |
commit | 4a775c82c82597c65345b3b1fdad71792ef2e486 (patch) | |
tree | d3a5fc2a34e6746f8d7ee51e793ff3645bf3e814 | |
download | vdr-plugin-osdpip-4a775c82c82597c65345b3b1fdad71792ef2e486.tar.gz vdr-plugin-osdpip-4a775c82c82597c65345b3b1fdad71792ef2e486.tar.bz2 |
Release version 0.0.1v0.0.1
- Initial revision.
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 6 | ||||
-rw-r--r-- | Makefile | 88 | ||||
-rw-r--r-- | README | 57 | ||||
-rw-r--r-- | i18n.c | 22 | ||||
-rw-r--r-- | i18n.h | 8 | ||||
-rw-r--r-- | libdvbmpeg/.cvsignore | 1 | ||||
-rw-r--r-- | libdvbmpeg/DVB.hh | 446 | ||||
-rw-r--r-- | libdvbmpeg/Makefile | 33 | ||||
-rw-r--r-- | libdvbmpeg/OSD.h | 30 | ||||
-rw-r--r-- | libdvbmpeg/channel.h | 58 | ||||
-rw-r--r-- | libdvbmpeg/ci.hh | 167 | ||||
-rw-r--r-- | libdvbmpeg/cpptools.cc | 946 | ||||
-rw-r--r-- | libdvbmpeg/cpptools.hh | 330 | ||||
-rw-r--r-- | libdvbmpeg/ctools.c | 2379 | ||||
-rw-r--r-- | libdvbmpeg/ctools.h | 404 | ||||
-rw-r--r-- | libdvbmpeg/devices.hh | 310 | ||||
-rw-r--r-- | libdvbmpeg/osd.hh | 84 | ||||
-rw-r--r-- | libdvbmpeg/remux.c | 1215 | ||||
-rw-r--r-- | libdvbmpeg/remux.h | 149 | ||||
-rw-r--r-- | libdvbmpeg/ringbuffy.c | 200 | ||||
-rw-r--r-- | libdvbmpeg/ringbuffy.h | 52 | ||||
-rw-r--r-- | libdvbmpeg/transform.c | 2681 | ||||
-rw-r--r-- | libdvbmpeg/transform.h | 250 | ||||
-rw-r--r-- | osd.c | 199 | ||||
-rw-r--r-- | osd.h | 38 | ||||
-rw-r--r-- | osdpip.c | 85 | ||||
-rw-r--r-- | receiver.c | 56 | ||||
-rw-r--r-- | receiver.h | 29 | ||||
-rw-r--r-- | remux/ts2es.c | 87 | ||||
-rw-r--r-- | remux/ts2es.h | 21 | ||||
-rw-r--r-- | remux/ts2ps.c | 104 | ||||
-rw-r--r-- | remux/ts2ps.h | 22 | ||||
-rw-r--r-- | remux/tsremux.c | 185 | ||||
-rw-r--r-- | remux/tsremux.h | 30 |
35 files changed, 11112 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. @@ -0,0 +1,6 @@ +VDR Plugin 'osdpip' Revision History +------------------------------------ + +2004-01-02: Version 0.0.1 + +- Initial revision. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..619f239 --- /dev/null +++ b/Makefile @@ -0,0 +1,88 @@ +# +# 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 = osdpip + +### 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 + +### 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 -I. +LIBS = -lmpeg2 -lmpeg2convert +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o osd.o receiver.o i18n.o \ + \ + remux/tsremux.o remux/ts2ps.o remux/ts2es.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 -o $@ $^ $(LIBS) + @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: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ + make -C libdvbmpeg clean @@ -0,0 +1,57 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Sascha Volkenandt <sascha@akv-soft.de> + +Project's homepage: http://www.magoa.net/linux/index.php?view=osdpip + +Latest version available at: http://www.magoa.net/linux/index.php?view=osdpip + +See the file COPYING for license information. + + +Requirements: + +- libmpeg2 (http://libmpeg2.sourceforge.net) version 0.4.0 (OLDER VERSIONS + DON'T WORK) + + +Description: + +OSD Picture-in-Picture is a PlugIn that displays the current channel in a +small box on the screen (default upper right corner). You can switch up and +down now, watching the progress of the previous channel in the box. Quality is +not too good yet, and only I-Frames are displayed. You'll need to upgrade your +VDR to support a 256 color OSD with the provided patching instruction. + + +Installation: + +Let's say osdpip's version is 0.0.1 and vdr's version is 1.2.6. If you +use anything else please exchange the version numbers appropriately (this +way I don't have to update this section all the times;) ). + +cd vdr-1.2.6/PLUGINS/src +tar xvfz vdr-osdpip-0.0.1.tgz +ln -s osdpip-0.0.1 osdpip +cd ../.. + +Now, you have to call your favourite editor to open osdbase.h and jump to line +number 16. I don't provide a patch here because some patches already touch that +area. Well this one's easy, though. Just increase the number of colors in this +line to 256. + +#define MAXNUMCOLORS 256 + +Now, you have to re-build VDR and Plugins. + +make [options, if necessary] vdr +make [options, if necessary] plugins + + +Controls: + +Up/Down Switch Channel up/down +1-9 Set Box Position +0 Switch back to PiP channel and exit PiP +Back Exit PiP without switching back + @@ -0,0 +1,22 @@ +#include "i18n.h" + +const tI18nPhrase Phrases[] = { + { "Picture-in-Picture", // English + "Bild-in-Bild", // Deutsch + "", // Slovenski + "", // Italiano + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "", // Suomi + "", // Polski + "", // Español + "", // Ellinika + "", // Svenska + "", // Romaneste + "", // Magyar + "" // Catala + }, + { NULL } +}; @@ -0,0 +1,8 @@ +#ifndef VDR_OSDPIP_I18N_H +#define VDR_OSDPIP_I18N_H + +#include <vdr/i18n.h> + +extern const tI18nPhrase Phrases[]; + +#endif // VDR_OSDPIP_I18N_H diff --git a/libdvbmpeg/.cvsignore b/libdvbmpeg/.cvsignore new file mode 100644 index 0000000..4671378 --- /dev/null +++ b/libdvbmpeg/.cvsignore @@ -0,0 +1 @@ +.depend 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 <asm/errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <stdint.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <sys/un.h> +#include <time.h> +#include <unistd.h> + +#define NEWSTRUCT +#include <channel.h> +} + +#include <sstream> +#include <iostream> +#include <iomanip> +using namespace std; + +#include <osd.hh> +#include <devices.hh> + +#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 <sys/types.h> + +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 <linux/dvb/dmx.h> +#include <linux/dvb/frontend.h> +#include <linux/dvb/video.h> +#include <linux/dvb/audio.h> + +#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 <ost/dmx.h> +#include <ost/frontend.h> +#include <ost/sec.h> +#include <ost/video.h> +#include <ost/audio.h> + +#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 <stdint.h> +#include <stdio.h> + +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/uio.h> + +#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<MAX_PID; i++) + pid[i] = -1; + while (!in.eof()) { + ts.init(); + in >> ts; + int j; + int found = 0; + for (j=0;j<npid;j++){ + if ( ts.PID() == pid[j] ) + found = 1; + } + if (! found){ + out << ts.PID() << " "; + pid[npid] = ts.PID(); + npid++; + if (npid == MAX_PID) return -1; + } + } + out << endl; + return 0; +} + +int tv_norm(istream &stream){ + uint8_t headr[4]; + int found=0; + streampos p = 0; + streampos q = 0; + int hsize,vsize; + int form= 0; + + q = stream.tellg(); + 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] == 0xB3 ){ + found = 1; + } + if (! found) stream.seekg(p+streampos(1)); + } + stream.read((char *)headr,4); + + hsize = (headr[1] &0xF0) >> 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 <fstream> +#include <sstream> +#include <iostream> +#include <iomanip> +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;i<p->stuffing;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 <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <netinet/in.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <libgen.h> +#include <stdint.h> +#include <netdb.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + + +#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 <stdint.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <iostream> +#include <fstream> +#include <sstream> + +#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 <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <netinet/in.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +//#include <libgen.h> +#include <stdint.h> + +#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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#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 <stdlib.h> +#include <string.h> +#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 <stdint.h> +#include <netinet/in.h> +#include <stdio.h> +#include <unistd.h> +#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_*/ + + + @@ -0,0 +1,199 @@ +#include "osd.h" +#include "receiver.h" + +#include <vdr/ringbuffer.h> +#include <vdr/remux.h> + +const uint palette[256] = { + 0xff000000, 0xff400000, 0xff800000, 0xffc00000, 0xff002000, 0xff402000, + 0xff802000, 0xffc02000, 0xff004000, 0xff404000, 0xff804000, 0xffc04000, + 0xff006000, 0xff406000, 0xff806000, 0xffc06000, 0xff008000, 0xff408000, + 0xff808000, 0xffc08000, 0xff00a000, 0xff40a000, 0xff80a000, 0xffc0a000, + 0xff00c000, 0xff40c000, 0xff80c000, 0xffc0c000, 0xff00e000, 0xff40e000, + 0xff80e000, 0xffc0e000, 0xff000020, 0xff400020, 0xff800020, 0xffc00020, + 0xff002020, 0xff402020, 0xff802020, 0xffc02020, 0xff004020, 0xff404020, + 0xff804020, 0xffc04020, 0xff006020, 0xff406020, 0xff806020, 0xffc06020, + 0xff008020, 0xff408020, 0xff808020, 0xffc08020, 0xff00a020, 0xff40a020, + 0xff80a020, 0xffc0a020, 0xff00c020, 0xff40c020, 0xff80c020, 0xffc0c020, + 0xff00e020, 0xff40e020, 0xff80e020, 0xffc0e020, 0xff000040, 0xff400040, + 0xff800040, 0xffc00040, 0xff002040, 0xff402040, 0xff802040, 0xffc02040, + 0xff004040, 0xff404040, 0xff804040, 0xffc04040, 0xff006040, 0xff406040, + 0xff806040, 0xffc06040, 0xff008040, 0xff408040, 0xff808040, 0xffc08040, + 0xff00a040, 0xff40a040, 0xff80a040, 0xffc0a040, 0xff00c040, 0xff40c040, + 0xff80c040, 0xffc0c040, 0xff00e040, 0xff40e040, 0xff80e040, 0xffc0e040, + 0xff000060, 0xff400060, 0xff800060, 0xffc00060, 0xff002060, 0xff402060, + 0xff802060, 0xffc02060, 0xff004060, 0xff404060, 0xff804060, 0xffc04060, + 0xff006060, 0xff406060, 0xff806060, 0xffc06060, 0xff008060, 0xff408060, + 0xff808060, 0xffc08060, 0xff00a060, 0xff40a060, 0xff80a060, 0xffc0a060, + 0xff00c060, 0xff40c060, 0xff80c060, 0xffc0c060, 0xff00e060, 0xff40e060, + 0xff80e060, 0xffc0e060, 0xff000080, 0xff400080, 0xff800080, 0xffc00080, + 0xff002080, 0xff402080, 0xff802080, 0xffc02080, 0xff004080, 0xff404080, + 0xff804080, 0xffc04080, 0xff006080, 0xff406080, 0xff806080, 0xffc06080, + 0xff008080, 0xff408080, 0xff808080, 0xffc08080, 0xff00a080, 0xff40a080, + 0xff80a080, 0xffc0a080, 0xff00c080, 0xff40c080, 0xff80c080, 0xffc0c080, + 0xff00e080, 0xff40e080, 0xff80e080, 0xffc0e080, 0xff0000a0, 0xff4000a0, + 0xff8000a0, 0xffc000a0, 0xff0020a0, 0xff4020a0, 0xff8020a0, 0xffc020a0, + 0xff0040a0, 0xff4040a0, 0xff8040a0, 0xffc040a0, 0xff0060a0, 0xff4060a0, + 0xff8060a0, 0xffc060a0, 0xff0080a0, 0xff4080a0, 0xff8080a0, 0xffc080a0, + 0xff00a0a0, 0xff40a0a0, 0xff80a0a0, 0xffc0a0a0, 0xff00c0a0, 0xff40c0a0, + 0xff80c0a0, 0xffc0c0a0, 0xff00e0a0, 0xff40e0a0, 0xff80e0a0, 0xffc0e0a0, + 0xff0000c0, 0xff4000c0, 0xff8000c0, 0xffc000c0, 0xff0020c0, 0xff4020c0, + 0xff8020c0, 0xffc020c0, 0xff0040c0, 0xff4040c0, 0xff8040c0, 0xffc040c0, + 0xff0060c0, 0xff4060c0, 0xff8060c0, 0xffc060c0, 0xff0080c0, 0xff4080c0, + 0xff8080c0, 0xffc080c0, 0xff00a0c0, 0xff40a0c0, 0xff80a0c0, 0xffc0a0c0, + 0xff00c0c0, 0xff40c0c0, 0xff80c0c0, 0xffc0c0c0, 0xff00e0c0, 0xff40e0c0, + 0xff80e0c0, 0xffc0e0c0, 0xff0000e0, 0xff4000e0, 0xff8000e0, 0xffc000e0, + 0xff0020e0, 0xff4020e0, 0xff8020e0, 0xffc020e0, 0xff0040e0, 0xff4040e0, + 0xff8040e0, 0xffc040e0, 0xff0060e0, 0xff4060e0, 0xff8060e0, 0xffc060e0, + 0xff0080e0, 0xff4080e0, 0xff8080e0, 0xffc080e0, 0xff00a0e0, 0xff40a0e0, + 0xff80a0e0, 0xffc0a0e0, 0xff00c0e0, 0xff40c0e0, 0xff80c0e0, 0xffc0c0e0, + 0xff00e0e0, 0xff40e0e0, 0xff80e0e0, 0xffc0e0e0, +}; + +cOsdPipObject::cOsdPipObject(cDevice *Device, const cChannel *Channel): + cOsdObject(true) { + m_Channel = Channel; + m_Osd = NULL; + m_ESBuffer = new cRingBufferLinear(MEGABYTE(3), 0, true); + + m_Xpos = 25; + m_Ypos = 25; + + Device->SwitchChannel(m_Channel, false); + m_Receiver = new cOsdPipReceiver(m_Channel, m_ESBuffer); + Device->AttachReceiver(m_Receiver); +} + +cOsdPipObject::~cOsdPipObject() { + if (m_Active) { + m_Active = false; + Cancel(3); + } + + delete m_Receiver; + if (m_Osd != NULL) + delete m_Osd; +} + +void cOsdPipObject::Action(void) { + m_Active = true; + + isyslog("osdpip: decoder thread started (pid = %d)", getpid()); + + mpeg2dec_t *handle = mpeg2_init(); + const mpeg2_info_t *info = mpeg2_info(handle); + mpeg2_state_t state; + + while (m_Active) { + cBitmap frame(312, 236, 8); + const uchar *block; + int recvd; + + state = mpeg2_parse(handle); + switch (state) { + case STATE_BUFFER: + block = m_ESBuffer->Get(recvd); + if (block && recvd > 0) { + mpeg2_buffer(handle, (uint8_t*)block, (uint8_t*)block + recvd); + m_ESBuffer->Del(recvd); + } else + usleep(1); + break; + + case STATE_SEQUENCE: + mpeg2_convert(handle, mpeg2convert_rgb8, NULL); + break; + + case STATE_SLICE: + case STATE_END: + case STATE_INVALID_END: + if (info->display_fbuf && (info->display_picture->flags + & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I) { + for (int x = 0; x < 312; ++x) { + for (int y = 0; y < 236; ++y) { + uint8_t *ptr = info->display_fbuf->buf[0] + ((50 + y * 2) + * info->sequence->width + (50 + x * 2)); + frame.SetPixel(x, y, (eDvbColor)palette[(int)*ptr]); + } + } + m_Osd->SetBitmap(m_Xpos, m_Ypos, frame); + m_Osd->Flush(); + } + break; + + default: + break; + } + } + + isyslog("osdpip: decoder thread stopped"); +} + +void cOsdPipObject::Show(void) { + m_Osd = cOsd::OpenRaw(0, 0); + m_Window = m_Osd->Create(m_Xpos, m_Ypos, 312, 236, 8, false); + if (m_Osd) { + m_Osd->Clear(); + Start(); + } +} + +eOSState cOsdPipObject::ProcessKey(eKeys Key) { + eOSState state = cOsdObject::ProcessKey(Key); + if (state == osUnknown) { + switch (Key & ~k_Repeat) { + case k0: Channels.SwitchTo(m_Channel->Number()); + case kBack: return osEnd; + + case k1...k9: + switch (Key & ~k_Repeat) { + case k1: + m_Xpos = 25; + m_Ypos = 25; + break; + case k2: + m_Xpos = (Setup.OSDwidth * cOsd::CellWidth()) / 2 - 75; + m_Ypos = 25; + break; + case k3: + m_Xpos = (Setup.OSDwidth * cOsd::CellWidth()) - 175; + m_Ypos = 25; + break; + case k4: + m_Xpos = 25; + m_Ypos = (Setup.OSDheight * cOsd::LineHeight()) / 2 - 55; + break; + case k5: + m_Xpos = (Setup.OSDwidth * cOsd::CellWidth()) / 2 - 75; + m_Ypos = (Setup.OSDheight * cOsd::LineHeight()) / 2 - 55; + break; + case k6: + m_Xpos = (Setup.OSDwidth * cOsd::CellWidth()) - 155; + m_Ypos = (Setup.OSDheight * cOsd::LineHeight()) / 2 - 55; + break; + case k7: + m_Xpos = 25; + m_Ypos = (Setup.OSDheight * cOsd::LineHeight()) - 105; + break; + case k8: + m_Xpos = (Setup.OSDwidth * cOsd::CellWidth()) / 2 - 75; + m_Ypos = (Setup.OSDheight * cOsd::LineHeight()) - 105; + break; + case k9: + m_Xpos = (Setup.OSDwidth * cOsd::CellWidth()) - 175; + m_Ypos = (Setup.OSDheight * cOsd::LineHeight()) - 105; + break; + } + m_Osd->Relocate(m_Window, m_Xpos, m_Ypos); + break; + + case kUp: + case kDown: cDevice::SwitchChannel(NORMALKEY(Key) == kUp ? 1 : -1); + break; + + default: return state; + } + state = osContinue; + } + return state; +} @@ -0,0 +1,38 @@ +#ifndef VDR_OSDPIP_OSD_H +#define VDR_OSDPIP_OSD_H + +#include <vdr/osd.h> +#include <vdr/thread.h> +#include <vdr/receiver.h> + +extern "C" { +#include <mpeg2dec/mpeg2.h> +#include <mpeg2dec/mpeg2convert.h> +}; + +class cRingBufferLinear; +class cOsdPipReceiver; + +class cOsdPipObject: public cOsdObject, public cThread { +private: + cOsdBase *m_Osd; + cRingBufferLinear *m_ESBuffer; + cOsdPipReceiver *m_Receiver; + const cChannel *m_Channel; + tWindowHandle m_Window; + + bool m_Active; + int m_Xpos, m_Ypos; + +protected: + virtual void Action(void); + +public: + cOsdPipObject(cDevice *Device, const cChannel *Channel); + virtual ~cOsdPipObject(void); + + virtual void Show(void); + eOSState ProcessKey(eKeys k); +}; + +#endif // VDR_OSDPIP_OSD_H diff --git a/osdpip.c b/osdpip.c new file mode 100644 index 0000000..afa76d1 --- /dev/null +++ b/osdpip.c @@ -0,0 +1,85 @@ +/* + * osdpip.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#include "osd.h" +#include "i18n.h" + +#include <vdr/plugin.h> + +static const char *VERSION = "0.0.1"; +static const char *DESCRIPTION = "OSD Picture-in-Picture"; +static const char *MAINMENUENTRY = "Picture-in-Picture"; + +class cPluginOsdpip : public cPlugin { +private: + +public: + cPluginOsdpip(void); + virtual ~cPluginOsdpip(); + 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 void Housekeeping(void); + virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); } + virtual cOsdObject *MainMenuAction(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); +}; + +cPluginOsdpip::cPluginOsdpip(void) { +} + +cPluginOsdpip::~cPluginOsdpip() { +} + +const char *cPluginOsdpip::CommandLineHelp(void) { + return NULL; +} + +bool cPluginOsdpip::ProcessArgs(int argc, char *argv[]) { + return true; +} + +bool cPluginOsdpip::Initialize(void) { + return true; +} + +bool cPluginOsdpip::Start(void) { + RegisterI18n(Phrases); + return true; +} + +void cPluginOsdpip::Housekeeping(void) { +} + +cOsdObject *cPluginOsdpip::MainMenuAction(void) { + const cChannel *chan; + cDevice *dev; + + chan = cDevice::CurrentChannel() != 0 + ? Channels.GetByNumber(cDevice::CurrentChannel()) : NULL; + if (chan != NULL) { + dev = cDevice::GetDevice(chan, 1); + if (dev) + return new cOsdPipObject(dev, chan); + } + return NULL; +} + +cMenuSetupPage *cPluginOsdpip::SetupMenu(void) { + return NULL; +} + +bool cPluginOsdpip::SetupParse(const char *Name, const char *Value) { + return false; +} + +VDRPLUGINCREATOR(cPluginOsdpip); // Don't touch this! diff --git a/receiver.c b/receiver.c new file mode 100644 index 0000000..22a481c --- /dev/null +++ b/receiver.c @@ -0,0 +1,56 @@ +#include "receiver.h" +#include "remux/ts2es.h" + +#include <vdr/channels.h> +#include <vdr/ringbuffer.h> + +cOsdPipReceiver::cOsdPipReceiver(const cChannel *Channel, + cRingBufferLinear *ESBuffer): + cReceiver(Channel->Ca(), 0, 2, Channel->Vpid(), Channel->Apid1()) { + m_TSBuffer = new cRingBufferLinear(MEGABYTE(3), TS_SIZE * 2, true); + m_ESBuffer = ESBuffer; + m_Remux = new cTS2ESRemux(Channel->Vpid()); + m_Active = false; +} + +cOsdPipReceiver::~cOsdPipReceiver() { + Detach(); + delete m_Remux; + delete m_TSBuffer; +} + +void cOsdPipReceiver::Activate(bool On) { + if (On) + Start(); + else if (m_Active) { + m_Active = false; + Cancel(3); + } +} + +void cOsdPipReceiver::Receive(uchar *Data, int Length) { + int put = m_TSBuffer->Put(Data, Length); + if (put != Length) + esyslog("osdpip: ringbuffer overflow (%d bytes dropped)", Length - put); +} + +void cOsdPipReceiver::Action(void) { + dsyslog("osdpip: receiver thread started (pid=%d)", getpid()); + + m_Active = true; + while (m_Active) { + int r; + const uchar *b = m_TSBuffer->Get(r); + if (b) { + int Count = r, Result; + uchar *p = m_Remux->Process(b, Count, Result); + m_TSBuffer->Del(Count); + + if (p) + m_ESBuffer->Put(p, Result); + } else + usleep(1); // this keeps the CPU load low + } + + dsyslog("osdpip: receiver thread ended (pid=%d)", getpid()); +} diff --git a/receiver.h b/receiver.h new file mode 100644 index 0000000..7de50db --- /dev/null +++ b/receiver.h @@ -0,0 +1,29 @@ +#ifndef VDR_OSDPIP_RECEIVER_H +#define VDR_OSDPIP_RECEIVER_H + +#include <vdr/receiver.h> +#include <vdr/thread.h> + +class cRingBufferLinear; +class cTS2ESRemux; + +class cOsdPipReceiver: public cReceiver, public cThread { +private: + cRingBufferLinear *m_TSBuffer; + cRingBufferLinear *m_ESBuffer; + cTS2ESRemux *m_Remux; + + bool m_Active; + +protected: + virtual void Activate(bool On); + virtual void Receive(uchar *Data, int Length); + virtual void Action(void); + +public: + cOsdPipReceiver::cOsdPipReceiver(const cChannel *Channel, + cRingBufferLinear *ESBuffer); + virtual ~cOsdPipReceiver(); +}; + +#endif // VDR_OSDPIP_RECEIVER_H diff --git a/remux/ts2es.c b/remux/ts2es.c new file mode 100644 index 0000000..2f27d4f --- /dev/null +++ b/remux/ts2es.c @@ -0,0 +1,87 @@ +#include "remux/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..8026a1b --- /dev/null +++ b/remux/ts2es.h @@ -0,0 +1,21 @@ +#ifndef VDR_STREAMDEV_TS2ESREMUX_H +#define VDR_STREAMDEV_TS2ESREMUX_H + +#include "remux/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..222c39a --- /dev/null +++ b/remux/ts2ps.c @@ -0,0 +1,104 @@ +#include "remux/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 (*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..4e43ed2 --- /dev/null +++ b/remux/ts2ps.h @@ -0,0 +1,22 @@ +#ifndef VDR_STREAMDEV_TS2PESREMUX_H +#define VDR_STREAMDEV_TS2PESREMUX_H + +#include "remux/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..93f513b --- /dev/null +++ b/remux/tsremux.c @@ -0,0 +1,185 @@ +#include "remux/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) { + 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; + } + Count = used; + + // When we don't need to sync, we don't need to sync :-) + if (!m_Sync) { + Result = m_ResultDelivered = m_ResultCount; + return Result ? m_ResultBuffer : NULL; + } + + // Check if we're getting anywhere here: + + if (!m_Synced && m_Skipped >= 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 + 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..3e83c73 --- /dev/null +++ b/remux/tsremux.h @@ -0,0 +1,30 @@ +#ifndef VDR_STREAMDEV_TSREMUX_H +#define VDR_STREAMDEV_TSREMUX_H + +#include "libdvbmpeg/transform.h" +#include <vdr/remux.h> + +class cTSRemux { +protected: + 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 |