mpgtx-1.3.1/0000755000175000001440000000000010165256470012447 5ustar esusers00000000000000mpgtx-1.3.1/man/0000755000175000001440000000000010165256352013221 5ustar esusers00000000000000mpgtx-1.3.1/man/Makefile0000644000175000001440000000030607262311261014653 0ustar esusers00000000000000all: ln -sf mpgtx.1 mpgcat.1 ln -sf mpgtx.1 mpgjoin.1 ln -sf mpgtx.1 mpginfo.1 ln -sf mpgtx.1 mpgsplit.1 ln -sf mpgtx.1 mpgdemux.1 clean: rm mpgcat.1 mpgjoin.1 mpginfo.1 mpgsplit.1 mpgdemux.1 mpgtx-1.3.1/man/mpgtx.10000644000175000001440000001277410165224523014450 0ustar esusers00000000000000.TH mpgtx 1 "DECEMBER 2004" Linux "User manual" .SH NAME mpgtx, mpgsplit, mpgcat, mpgjoin, mpginfo, mpgdemux \- manipulate mpeg files .SH SYNOPSIS .B mpgtx .I command .B [ .I options .B ] .I file .B [ .I range | .I file .B ] ... .SH DESCRIPTION mpgtx can split and join MPEG files in various ways. Three file types are currently handled (more to come): MPEG 1 Video files, MPEG 1/2 Audio files (mp1, mp2, and mp3), MPEG 1 System files (audio and video files), MPEG 2 Program files (Experimental), MPEG 2 Transport files (demultiplex and info modes only). mpgtx is a GOP (Group of Pictures) based editor. This means that mpgtx cuts MPEG files on a Group Of Picture basis, not on a frame-by-frame basis. A typical GOP duration is about 0.5 sec (approx. 15 frames), limiting the maximum accuracy of mpgtx. .SH COMMANDS .IP -i prints information about files, such as duration, dimention, bitrate, etc. .IP -j joins files (ranges may be specified, see the RANGES section). .IP -s splits files according to the specified ranges (see the RANGES section). .IP -d demultiplexes composite mpeg file. .IP -T manipulates ID3v1 tags from mp3 files (see \fBtagmp3(1)\fP). .IP -h prints a (not so) short help message. .IP -v prints version and exit. .IP -# where .B # is a number, splits the given files in .B # parts. .IP --force enables joining of incompatible files (some players are very robust) .IP --no-parachute prevents mpgtx to try to catch SIGSEGV signal. This is usefull for debugging. .SH "" In addition, when invoked with the names mpgjoin, mpgcat, mpgsplit, mpgdemux, tagmp3 or mpginfo, mpgtx will modify its behaviour in the following ways: .br .B "mpginfo " behaves as .B mpgtx -i .br .B "mpgsplit" behaves as .B mpgtx -s .br .B "mpgjoin " behaves as .B mpgtx -j .br .B "mpgcat " behaves as .B mpgtx -j -o - .br .B mpgdemux behaves as .B mpgtx -d .br .B "tagmp3" behaves as .B mpgtx -T .SH OPTIONS .IP -f force overwriting of files, never ask. .IP -Ax Change aspect ratio of mpeg. Valid are 1,2,3,4 for 1:1, 4:3, 16:9, 2.2:1 .IP -P Keep junk or unusual headers in splits .IP -X Desperate mode, search the whole movie for a valid PACK. In addition with Option -N no search infos will be displayed, only end summary. .IP -N Suppress progress output to the console. Speeds up operation a little on most Systems and much on Macintosh OS9. .br Suppress time line check in .B mpginfo mode. .IP "-b NAME" each output file will have the basename .B NAME . .IP "-o FILE" .B FILE will be used as the output file (used with the join command). if .B FILE is -, standard output will be used. .SH RANGES Each range must follow a filename or another range. A range in an MPEG file can be specified using one of this three notations: Note for OSX Users: Ranges must be enclosed in single or double Quotes! .IP [a-b] from value .B a inclusive to value .B b inclusive. If you want half opened ranges, you may want to use ]a-b], [a-b[ or ]a-b[. .IP [n/ntot] the .B n th part out of .B ntot. [1/4] would result in the first quarter of the specified file. .IP "{a-b-...}" with .B a , .B b , .B ... in ascending order. Split specified file at given boundaries. {55M} therefore means from beginnig of file to 55Megs and from 55Megs to the end of file. .SH VALID VALUES Values of ranges can be specified in seconds or as a byte offset. .IP "Time Format" HH:MM:SS.SS where the HH: part can be omited .IP "Offset Format" a number optionally followed by .B M for Megabytes .B k for kilobytes .br .IP "Omitted Values" An empty value is valid and is equivalent to the corresponding file boundary: .br [-10M] are the first 10 Megabytes of the file. .br [1:10:04-] from 1 hour 10 minutes 4 seconds to the end of file. .SH RETURN VALUE All programs return 0 upon successful completion and 1 on failure. .SH EXAMPLES .IP "mpgjoin movie1.mpg [-0:32] [45M-75M] movie2.mpg -o joined.mpg" joined.mpg will contain the first 32 seconds of movie1.mpg followed by 30 Megs of movie1.mpg starting at 45 Megs followed by the whole file movie2.mpg .IP "mpgtx -124 myfile.mpg -b output" will split myfile.mpg in 124 parts with names output-001.mpg to output-124.mpg .IP "mpgtx -i Wazzup.mp3" will print infos about given file such as duration, bitrate, but also album, track, song name if this file has an ID3 tag. .IP "mpgcat myfile.mpg [2/2] | lpr" will redirect the second half of myfile.mpg to your printer, emptying it from toner and paper and make you be fired by your boss... Use carefully. .SH BUGS Plenty of them :) .br GOP (Group of Picture) based: well this is not a bug but it's a limitation. As explained in the \fBDESCRIPTION\fP section, this limits the accuracy of mpgtx on joins and splits to approximately 15 frames, or 0.5 seconds. .br Some artifacts can be seen with bad MPEG players playing joined files. These players don't take into account the broken link flag used to discard the first B frames they encounter. This is a bug in their MPEG decoding engine, not mpgtx. .SH AUTHOR Laurent Alacoque CopyLeft 2001. .br Modified by Chris Danis , copyleft 2001. .br Philipp Biermann , copyleft 2002. .br Erik Schanze , copyleft 2004. .br Get new releases and information from, and send patches, bugs, girls, money etc. to: .br http://mpgtx.sourceforge.net/ .SH THANKS for your attention. Have a good day. .br Godmar Back and Brent Phillips helped me to tune the command line interface. .br Volker Moell patiently teach me how to build rpms. Danke Volker. .br Jean Fransisco Sytem (alias Nicolas Schieli) helped me correct some nasty bugs. .br Thank you guys. mpgtx-1.3.1/man/tagmp3.10000644000175000001440000000621210157121413014465 0ustar esusers00000000000000.TH tagmp3 1 "APRIL 2001" Linux "User manual" .SH NAME tagmp3 \- manipulate ID3v1 tags .SH SYNOPSIS .B tagmp3 [ .I -n .B ] .I mode .B [ .I format .B ] [ .I file .B ] ... .SH DESCRIPTION tagmp3 allows you to set and remove ID3v1 tags from mp3 files. Additionaly .B move mode can be used to move mp3 files according to their ID3v1 tag. An ID3v1 tag is a chunk of extra informations such as artist name, album and genre. ID3v1 tags are displayed by most mp3 players. .SH MODE .IP show show file's ID3v1 tag. .IP set sets file's ID3v1 tag according to format. .IP move move file to a destination based on FORMAT. .IP del remove file's ID3v1 tag if any. .IP list displays numeric music genres along with their meaning. .IP -h print a (not so) short help message. .IP -v print version and exit. .SH OPTIONS .IP -n Show what will be done, don't alter any file. .SH FORMAT STRING The format string is a character string composed of zero or more directives: ordinary characters (not %), which are not interpreted and conversion specifications, each of which results in the corresponding ID3v1 tag field substitution. Each conversion specification is introduced by the character %. The following lines describes each conversion specification along with its associated ID3v1 field. Special sequence %% is substituted with a single %. .IP %A Artist Name .IP %a Album Name .IP %t Song Title .IP %T Track Number .IP %y Year .IP %g Genre .IP %c Comments .SH format string for set mode For set mode the format string is a list of ID3v1 fields followed by a ':' (next chars are the field value) or a '?' (ask user for field value) .IP example: tagmp3 set "%A:Pink Floyd %a:The Wall %t? %T?" *.mp3 .br .br For each mp3 of this directory, sets the artist name to Pink Floyd and the album to The Wall. For each file ask for the title and the track number. Leave the other fields untouched. Be aware that genre field require a numeric value. Known genres can be displayed with the list mode. .SH format string for move mode The format string is the destination path where each field identifier is substituted with the tag value. .IP example: tagmp3 move "/home/foo/mp3/%A/%a/%T-%t.mp3" *.mp3 .br with the set example above will move all mp3 to "/home/foo/mp3/Pink Floyd/The Wall/{track}-{title}.mp3" .br If you prefer the "flat" naming scheme, you will use something like .br tagmp3 move "%A-%t.mp3" *.mp3 .SH NOTES move mode never overwrite files. .br move mode creates intermediate directories specified in the format string. Each directory creation is to be confirmed by the user. .br ID3v2 tags are not supported so far. .br If a file can't be moved ( wrong file type, ID3v1 tag absent or blank field , ...) then it is left untouched. .br Fake mp3 (i.e. Wave file with .mp3 extension) are moved into "fake-mp3/" directory in move mode. set mode refuses to tag them since this would add noisy artifact at the end of the song. .SH BUGS Plenty of :) .br For move mode, source and destination must reside on the same file system / partition. .SH AUTHOR Laurent Alacoque CopyLeft 2001 .br Bugs, patch, infos, new releases, girls, money go to : .br http://mpgtx.sourceforge.net/ mpgtx-1.3.1/AUTHORS0000644000175000001440000000032410165224673013516 0ustar esusers00000000000000mpgtx was designed by laurent Alacoque (c) 2001 Modifications for V1.2 & 1.3 by Philipp Biermann Modifications for V1.3.1 by Erik Schanze mpgtx-1.3.1/COPYING0000644000175000001440000004311007256373231013503 0ustar esusers00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mpgtx-1.3.1/ChangeLog0000644000175000001440000001402510165227511014215 0ustar esusers0000000000000031 December 2004: [es] - Added very simple check for a continously increasing MPEG time line in mpginfo by default, can suppressed by option "-N" - Update mpgtx.spec, but untested 14 December 2004: [es] - Fixed compiler version check in configure - Added and formated some comments for my understanding - Cleaned splitting of declarations and definitions in .cxx and .hh files - Clearify output and manpage of tagmp3 that only ID3v1 tags are supported. 24 November 2004: [la] - web/index.html updated - web/Makefile now requires MPGTX_user env var to be set, then make install installs the page onto mpgtx.sf.net 21 November 2004: [es] - mpeg.cxx: * remove extra ";" for gcc 3.4 * "-N" now also suppress repeated search messages on mpginfo, much faster [es] - id3command.cxx: * Fixes tagmp3 error in truncating year when entered interactively (Debian BTS #167313) [es] - configure: * Applied Julian Hall patch (CYGWIN support) * Applied Eric Sokolowsky patch (--manprefix support) [es] - config.guess: * Updated from Erik's source tree 26 November 2002: [la] - Got rid of the inlines finally in mpeg.cxx [la] - remove -pedantic from configure [la] - Fixed some Warnings in mpegOut.cxx 04 October 2002: [la] - Applied Eric Sokolowsky patch on configure script (IRIX support) (thanks Eric) 30 August 2002 (Version 1.3): [pb] - Added support and fixes for mpeg2 muxed files. mpgtx should now split and join mpeg2 files correct [pb] - Improved mpgtx knowledge about length of mpeg2 movies [pb] - removed bug which was introduced in 1.2 where demuxing was broken 18 August 2002 (Version 1.2): [pb] - mpgtx is now able to search for a valid pack through a whole file (-X) [pb] - added option to suppress progress output (faster) (-N) [pb] - fixed a bug where a buffer is at end and data could not be processed -> unplayable movies [pb] - increased file buffer for better performace to 2MB [pb] - added option to change the aspect ratio of a movie (-A ) [pb] - added option to keep junk headers in splits (-P) 27 August 2001: [la] - mpgtx now supports MPEG streams with leading zeros and skip them gracefully [la] - added some support for ill-formed system streams that don't begin with a PACK header. (both, thank to Søren Roug) 22 August 2001: [la] - Created a home made configure script that automagically checks Large File support and GCC 3.0 tricks to produce correct CFLAGS and LFLAGS. 20 August 2001: [la] - Restored compatibility for systems older than glibc2.2+ to enable large file support build with `make lfs-support' 10 August 2001: (large file support) [ms] - support for files larger than 2GB on systems supporting Single UNIX Specification 2.0. Requires glibc2.1+ for build but actual support requires both glibc2.2+ and Linux kernel 2.4+ [la] - Cosmetic changes (The Entire Large File Support code is the courtesy of Mattias Sandgren Please stand up and applause ) 6 August 2001 [la] - tagmp3 used to return 1 even on success. changed that so that it could be used in scripts. (A big thank to C. R. Johnson for that.) 23 July 2001 : mpgtx v 1.0 released [la] - bug reports are rare by now. So I guess it's time for the first so called "stable" version. Here it is. [la] - replaced friend foo with friend class foo that caused compilation errors with gcc 3.0 (thank to Fred Hernandez) 19 June 2001 : [la] - fixed a bug in demultiplexer (thank to Steven M Shultz) 29 May 2001 : mpgtx version 0.8b released [la] - fixed another segfault, still on exotic files. (thank to Aaron Brick) 23 May 2001 : [la] - renamed mp3tag to tagmp3 because of a conflict with mp3blaster in debian 17 May 2001 : mpgtx version 0.7b released [la] - segfault fixed on exotic mpeg files. (thank to Steven M. Schultz) 24 April 2001 : mpgtx version 0.6b released [la] - MAJOR bug fixed that caused unplayable files. [la] - fixed bug in mp3tag : ERROR : No valid ID3 tag in WriteID3 13 April 2001 : mpgtx version 0.5b released [la] - Added bug report helper. [la] - Added mp3tag, a handy ID3 tagging and file sorting utility [la] - Corrected bug in Timestamping : players should not freeze anymore [la] - MPEG 2 timestamping should be okay. 3 April 2001 : mpgtx version 0.4b released [la] - demultiplex is available (-d option) [la] - MPEG 2 transport stream support (info and demultiplex) [la] - MPEG 2 support improved [la] - various bug fixes (and many other added): [la] - Sigsegv when outputing on an existing file (Thank to Jean-Fransisco system (alias Nicolas Schieli)) [la] - Wrong audio frame boundary computation produced empty ranges. [la] - Muxrate is now parsed and printed in info mode. 23 March 2001 : mpgtx version 0.3b released [la] - makefile has now three goals : devel shared & static default goal is devel. [la] - mpgtx now looks for a valid audio frame boundary, this was an issue with variable bitrate mp3s [vm] - Volker Moell contributed a mpgtx.spec for rpm building rpms are coming soon. [vm] - minor bug corrected in mpeg::ParseRIFF thank to Volker again. 22 March 2001 : mpgtx version 0.2b released [la] - mt is now called mpgtx (old name was the same as a well known magnetic tape utility. sorry) (thank to hundred of mails) [la] - -o is now allowed in split mode (if only one chunk) mpgtx does not append a "-1.mpg" when base name is specified and only one chunk is present. [la] - fixed the 80 column issue for the -h option (thank to Volker Moell) [la] - access() is now home made mpgtx_access for portability reasons. [la] - various compiler errors under RedHat 7 fixed (thank to Chris Chabot) 20 March 2001 : mt version 0.1b released [la] - mt initial release Major contributors: [la] : laurent alacoque [pb] : philipp biermann mpgtx-1.3.1/README0000644000175000001440000000265510165226052013330 0ustar esusers00000000000000INSTALLATION * To build mpgtx with the default options, try : "./configure && make" * You may want to see available options such as installation prefix with : "./configure --help" Then type : "./configure [options] && make" To actually build mpgtx. * Once mpgtx has been successfully built type : "make install" to install mpgtx. BUGS AND LIMITATIONS * mpgtx is a GOP (Group Of Pictures) based mpeg editor. GOP contains typically 15 frames/pictures (around 0.5 sec) This means that mpgtx can not cut exactly where you wanted it to. * We trust in a correct time in MPEG for our duration and split point calculation. If the timestamps jump, we will run into problems. * Another issue about GOP editing is that bad mpeg players will show artifacts when you join two files with mpgtx. These artifacts appear at the join point because these players won't care about the "Broken link flag" wich tell them to discard leading interpolated B frames. * Some mp3 files won't be cut at the right place thus displaying a bogus framerate/version/duration with mpginfo. This do not affect them in any other way. * Files produced by mpgtx might be not Video CD compatible, even if input files were. * Some joined mpeg files will just stop at the splice point. This is often because they have a End Of Sequence tag in them which mpgtx currently fail to find and remove. * Surely plenty of other bugs, please tell me :) mpgtx-1.3.1/TODO0000644000175000001440000000034010165227303013125 0ustar esusers00000000000000Planned Features: - time line correction on given MPEG - add multiplex mode - switch all ID3 handling to id3lib, they are better on that ;-) Planned Improvements: - split on frame basis (tough!) - mpgtx-1.3.1/chunkTab.cxx0000644000175000001440000003303510156636562014742 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #include "chunkTab.hh" #include #include void chunkTab::PrintInfos() { BTRACK; int i; for ( i = 0; i < current_mpeg; i++) MpegTab[i]->PrintInfos(); RTRACK; } chunk** chunkTab::GetChunks(int* nchunks) { *nchunks = current_chunk; return TheTab; } chunkTab::chunkTab(int _max) :max(_max), current_mpeg_ptr(0) { BTRACK; max = (max > 0)?max:1; TheTab = new chunk*[max]; current_chunk = current_mpeg=0; MpegTab = new mpeg*[max]; RTRACK; } bool chunkTab::AddFile(char* filename) { BTRACK; int i; if (!filename) { RTRACK; return false; } for ( i=0; i< current_mpeg;i++){ if(!strcmp(filename, MpegTab[i]->Name())) { current_mpeg_ptr = MpegTab[i]; RTRACK; return true; } } //if we're here, filename is a new mpeg file if (current_mpeg == max) MoreRoom(20); mpeg* newmpeg = new mpeg(filename); if (!newmpeg->has_audio() && ! newmpeg->has_video()){ delete newmpeg; RTRACK; return false; } MpegTab[current_mpeg++] = newmpeg; current_mpeg_ptr = newmpeg; // current_file=new char[strlen(filename)+1]; // strcpy(current_file,filename); RTRACK; return true; } // this adds some room to the internal tabs void chunkTab::MoreRoom(int n){ BTRACK; int i; max += n; chunk** tempchunk = new chunk*[max]; mpeg** tempmpeg = new mpeg*[max]; for ( i = 0; i < current_chunk; i++) tempchunk[i] = TheTab[i]; for ( i = 0; i < current_mpeg; i++) tempmpeg[i] = MpegTab[i]; delete[] TheTab; delete[] MpegTab; TheTab = tempchunk; MpegTab = tempmpeg; RTRACK; } bool chunkTab::ParseRange(char* range) { BTRACK; char* first_range = range+1; char* second_range = range; int first_range_size = 0; int second_range_size = 0; int slash_sep = 0; int sep = 0; unsigned int i; for ( i = 1; i < strlen(range); i++) { if (range[i] == '-') { sep++; second_range = &range[i+1]; first_range_size = i-1; } if (range[i] == '/') { slash_sep++; second_range = &range[i+1]; first_range_size = i-2; } } second_range_size = strlen(range)-3-first_range_size; if ((sep + slash_sep) == 0) { fprintf(stderr,"Error : No separator in range %s\n", range); RTRACK; return false; } if (sep > 1) { fprintf(stderr,"Invalid range argument %s : too many '-' in format\n", range); RTRACK; return false; } if (slash_sep >1) { fprintf(stderr,"Invalid range argument %s : too many '/' in format\n", range); RTRACK; return false; } if (slash_sep + sep >1) { fprintf(stderr,"Invalid range argument %s : can't mix '-' and '/'\n", range); RTRACK; return false; } off_t part,nparts; chunk* tempchunk = new chunk; tempchunk->file = 0; tempchunk->from = -1; tempchunk->to = -1; tempchunk->to_included = false; tempchunk->from_included = false; tempchunk->until_file_size = false; tempchunk->unit_is_second = false; if (current_mpeg_ptr != 0) tempchunk->mpegfile = current_mpeg_ptr; else { fprintf(stderr, "Range argument must follow an mpeg file %s \n", range); delete tempchunk; RTRACK; return false; } if (current_chunk == max) MoreRoom(20); char* offset = range + 1; // after [ or ] if (range[0] == ']') tempchunk->from_included = false; else tempchunk->from_included = true; switch (range[strlen(range) - 1]) { case ']': tempchunk->to_included = true; break; case '[': tempchunk->to_included = false; break; default: fprintf(stderr, "malformed range argument %s" " (range must end with ] or [ )\n", range); delete tempchunk; return false; } if (first_range_size == 0 && second_range_size == 0) { fprintf(stderr, "Invalid range %s\n", range); delete tempchunk; RTRACK; return false; } if (sscanf(offset, _OFF_d "/" _OFF_d , &part, &nparts) == 2) { if ((part <= 0) || (nparts < 0) || (part > nparts)) { fprintf(stderr, "invalid part %s\n", range); delete tempchunk; RTRACK; return false; } // printf("part %d out of %d\n",part,nparts); tempchunk->from = off_t((((tempchunk->mpegfile->Size())*1.0)/nparts)*(part-1)); tempchunk->to = off_t((((tempchunk->mpegfile->Size())*1.0)/nparts)*(part)); if (part == nparts) tempchunk->until_file_size = true; TheTab[current_chunk++] = tempchunk; RTRACK; return true; } if (slash_sep) { fprintf(stderr, "Invalid part %s\n", range); delete tempchunk; RTRACK; return false; } if (first_range_size == 0) { tempchunk->from = 0; tempchunk->sfrom = 0; tempchunk->from_included = false; if(!ParseValue(second_range, second_range_size, &(tempchunk->to), &(tempchunk->sto), &(tempchunk->unit_is_second))) { fprintf(stderr,"Invalid range %s\n",range); delete tempchunk; RTRACK; return false; } if (tempchunk->unit_is_second) { tempchunk->to = off_t((tempchunk->sto/tempchunk->mpegfile->Duration())* tempchunk->mpegfile->Size()); } TheTab[current_chunk++] = tempchunk; RTRACK; return true; } if (second_range_size == 0) { tempchunk->to = tempchunk->mpegfile->Size(); tempchunk->sto = tempchunk->mpegfile->Duration(); tempchunk->to_included = true; if (!ParseValue(first_range, first_range_size, &(tempchunk->from), &(tempchunk->sfrom), &(tempchunk->unit_is_second))) { fprintf(stderr,"Invalid range %s\n",range); delete tempchunk; RTRACK; return false; } if (tempchunk->unit_is_second) { tempchunk->from = off_t((tempchunk->sfrom/tempchunk->mpegfile->Duration()) * tempchunk->mpegfile->Size()); } TheTab[current_chunk++] = tempchunk; RTRACK; return true; } bool insecs; if(!ParseValue(first_range, first_range_size, &(tempchunk->from), &(tempchunk->sfrom), &(tempchunk->unit_is_second))) { fprintf(stderr,"Invalid range %s\n",range); delete tempchunk; RTRACK; return false; } if(!ParseValue(second_range, second_range_size, &(tempchunk->to), &(tempchunk->sto),&insecs)) { fprintf(stderr,"Invalid range %s\n",range); delete tempchunk; RTRACK; return false; } if (insecs != tempchunk->unit_is_second) { fprintf(stderr, "Error, mixed seconds with bytes in range %s\n", range); delete tempchunk; RTRACK; return false; } if (!insecs) { if (tempchunk->from>tempchunk->to) { fprintf(stderr,"Invalid range %s : start greater than stop\n", range); delete tempchunk; RTRACK; return false; } } else { if (tempchunk->sfrom>tempchunk->sto) { fprintf(stderr,"Invalid range %s : start greater than stop\n", range); delete tempchunk; RTRACK; return false; } } //convert time to offset if needed if (tempchunk->unit_is_second) { if(tempchunk->sfrom != 0) { tempchunk->from= off_t((tempchunk->sfrom/tempchunk->mpegfile->Duration())* tempchunk->mpegfile->Size()); } if(tempchunk->sto != tempchunk->mpegfile->Duration()) { tempchunk->to = off_t((tempchunk->sto/tempchunk->mpegfile->Duration())* tempchunk->mpegfile->Size()); } } // is it okay? if ((tempchunk->from < 0) || (tempchunk->to < tempchunk->from) || (tempchunk->to > tempchunk->mpegfile->Size())) { fprintf(stderr, "range %s results in invalid [" _OFF_d "-" _OFF_d "] range\n", range, tempchunk->from,tempchunk->to); delete tempchunk; RTRACK; return false; } TheTab[current_chunk++] = tempchunk; RTRACK; return true; } bool chunkTab::ParseValue( char* value, int value_length, off_t* translation, float* stranslation, bool* time) { BTRACK; int i; bool Time=false; bool byte=false; int nbytes=0; int ncolon=0; for ( i = 0; i < value_length; i++) { switch (value[i]) { case 'M': case 'k': nbytes++; byte=true; break; case ':': ncolon++; Time=true; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': break; default : RTRACK; return false; break; } } if (Time && byte) { RTRACK; return false; } if (ncolon>2){ RTRACK; return false; } if (nbytes>1){ RTRACK; return false; } if (Time) *time = true; else { *time = false; byte = true; } if (byte) { if (sscanf(value, _OFF_d , translation) != 1) { RTRACK; return false; } if (nbytes) { switch(value[value_length - 1]) { case 'M': *translation = *translation * 1024 * 1024; RTRACK; return true; break; case 'k': *translation = *translation * 1024; RTRACK; return true; break; default: RTRACK; return false; } } } // okay, let's parse the time float m1, m2, m3, start = 0; int nconv; nconv = sscanf(value,"%f:%f:%f", &m1, &m2, &m3); if ((nconv == 0) || (nconv-1 != ncolon)) { RTRACK; return false; } switch (nconv) { case 1: start = m1; break; case 2: start = m2 + m1 * 60; break; case 3: start = m3 + m2 * 60 + m1 * 3600; break; } *stranslation = start; RTRACK; return true; } bool chunkTab::ParseBoundaries(char* boundaries) { BTRACK; char* start = boundaries + 1; int size; if (boundaries[strlen(boundaries) - 1] != '}') { fprintf(stderr, "Invalid range %s\n", boundaries); RTRACK; return false; } chunk* tc = new chunk; if (current_mpeg_ptr != 0) tc->mpegfile = current_mpeg_ptr; else { fprintf(stderr, "Range argument must follow an mpeg file %s\n", boundaries); delete tc; RTRACK; return false; } tc->from = 0; tc->sfrom = 0; tc->from_included = false; tc->to_included = true; for (unsigned int i = 1; i <= strlen(boundaries) -1; i++) { if ((boundaries[i] == '-') || (boundaries[i] == '}')) { size = (&boundaries[i] - start); if (size <= 0) { fprintf(stderr,"Invalid range %s\n",boundaries); RTRACK; return false; } if (!ParseValue(start, size, &(tc->to), &(tc->sto), &(tc->unit_is_second))) { fprintf(stderr,"Invalid range %s\n",boundaries); RTRACK; return false; } if (current_chunk >= max) MoreRoom(max+20); if (tc->unit_is_second) { if(tc->sfrom != 0) { tc->from = off_t((tc->sfrom/tc->mpegfile->Duration())* tc->mpegfile->Size()); } if(tc->sto != tc->mpegfile->Duration()) { tc->to = off_t((tc->sto/tc->mpegfile->Duration())* tc->mpegfile->Size()); } } // is it okay? if ((tc->from < 0) || (tc->to < tc->from) || (tc->to > tc->mpegfile->Size())) { if((tc->to>tc->mpegfile->Size())) fprintf(stderr, "invalid range %s :boundary below end of file " _OFF_d "\n", boundaries, tc->to); else fprintf(stderr, "range %s results in invalid range [" _OFF_d "-" _OFF_d "]\n", boundaries, tc->from, tc->to); delete tc; RTRACK; return false; } TheTab[current_chunk] = tc; tc = new chunk; tc->mpegfile = current_mpeg_ptr; tc->from = TheTab[current_chunk]->to; tc->sfrom = TheTab[current_chunk]->sto; current_chunk++; tc->from_included = false; tc->to_included = true; start = &boundaries[i + 1]; //after the '-' } } if (current_chunk >= max) MoreRoom(max + 20); tc->from_included = false; tc->to_included = true; tc->to = tc->mpegfile->Size(); tc->sto = tc->mpegfile->Duration(); // is it okay? if ((tc->from < 0) || (tc->to < tc->from) || (tc->to > tc->mpegfile->Size())) { if((tc->to > tc->mpegfile->Size())) fprintf(stderr, "invalid range %s :boundary below end of file " _OFF_d "\n", boundaries, tc->to); else fprintf(stderr,"range %s results in invalid range [" _OFF_d "-" _OFF_d "]\n", boundaries, tc->from, tc->to); delete tc; RTRACK; return false; } TheTab[current_chunk++] = tc; RTRACK; return true; } void chunkTab::PrintTab() { BTRACK; int i; printf("%d chunks in %d files\n\n", current_chunk,current_mpeg); for (i = 0; i < current_chunk; i++) { printf("chunk %.2d : %p\n ", i, (void*)(TheTab[i]->mpegfile)); if (TheTab[i]->from_included) printf("["); else printf("]"); printf( _OFF_d "|" _OFF_d , TheTab[i]->from, TheTab[i]->to); if (TheTab[i]->to_included) printf("]"); else printf("["); if (TheTab[i]->until_file_size) printf(" til EOF"); printf("\n\n"); } for (i = 0; i < current_mpeg; i++) { printf("mpeg %.2d : %s [%p](" _OFF_d " bytes)\n", i, MpegTab[i]->Name(), (void*)(MpegTab[i]), MpegTab[i]->Size()); } RTRACK; } chunkTab::~chunkTab(){ BTRACK; int i; for (i = 0; i < current_chunk; i++) delete TheTab[i]; for (i = 0; i < current_mpeg; i++) delete MpegTab[i]; delete[] MpegTab; delete[] TheTab; RTRACK; } bool chunkTab::Nchunks(int n){ BTRACK; int i; if (n <=1 ) { fprintf(stderr,"Can not cut in %d parts\n",n); RTRACK; return false; } if (!current_mpeg_ptr) { fprintf(stderr,"No mpeg file for option -%d\n",n); RTRACK; return false; } if ((current_chunk + n) >= max) { MoreRoom(n - (max-current_chunk)+20); } chunk* tempchunk; for (i = 1; i <= n; i++) { tempchunk = new chunk; tempchunk->file = 0; tempchunk->from = -1; tempchunk->to = -1; tempchunk->to_included = true; tempchunk->from_included = false; tempchunk->until_file_size = false; tempchunk->unit_is_second = false; tempchunk->mpegfile = current_mpeg_ptr; tempchunk->from = off_t((((tempchunk->mpegfile->Size())*1.0)/n)*(i-1)); tempchunk->to = off_t((((tempchunk->mpegfile->Size())*1.0)/n)*(i)); if (i == n) tempchunk->until_file_size = true; TheTab[current_chunk++] = tempchunk; } RTRACK; return true; } mpgtx-1.3.1/chunkTab.hh0000644000175000001440000000223010156645051014521 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #ifndef __chunkTab_hh_ #define __chunkTab_hh_ #include "mpeg.hh" class chunkTab { public: chunkTab(int _max = 20); ~chunkTab(); bool AddFile(char* filename); bool ParseRange(char* range); bool ParseBoundaries(char* boundaries); void PrintTab(); void PrintInfos(); bool Nchunks(int n); chunk** GetChunks(int* n); protected: /** * adds some room to the internal tabs */ void MoreRoom(int n); bool ParseValue( char* value, int value_length, off_t* translation, float* stranlslation, bool* time); /// ordered tab of chunks chunk** TheTab; int max; int current_chunk; int current_mpeg; mpeg* current_mpeg_ptr; mpeg** MpegTab; // char* current_file; }; #endif // __chunkTab_hh_ mpgtx-1.3.1/commandline.cxx0000644000175000001440000005531110165222424015456 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #include #include #include #include "mpeg.hh" #include "mpegOut.hh" #include "chunkTab.hh" // declared in id3command.hh extern int ParseID3Command(int argc, char** argv, int argc_offset); // philipp bool desperate_mode = false; bool preserve_header = false; bool print_progress = true; // [L] ifdef the endMessage #ifdef NEED_END_MESSAGE void endMessage(void); #endif bool aspect_correction = false; byte forced_sequence_header = 0; char* progname; #ifndef NOSIGNAL_H // for bug report #include #include // for bug report char** myargv; int myargc; c_char mpgtx_stack[mpgtx_stack_count]; int mpgtx_stack_current=0; /*! * Callback for SIGSEGV, SIGBUS and SIGFPE. * prints a formated bug report, warns user and opens the bug report file * * @param signum catched signal: SIGSEGV, SIGBUS or SIGFPE */ void CatchBug(int signum) { //print a formated bug report and warn user //open the bug report file FILE* bugreport; bugreport=fopen("bug.report","w+"); //warn user fprintf(stderr,"BUG: Sorry you shouldn't read this...\n"); fprintf(stderr,"Please help me to correct this and send a bug report\n"); fprintf(stderr,"To send a bug report go to http://mpgtx.sourceforge.net\n"); fprintf(stderr,"and click the submit new bug link (top right)\n"); fprintf(stderr,"you can send it to either\n"); if (!bugreport) { bugreport=stderr; fprintf(stderr,"Please Include the following lines and the program output in the bug report\n"); fprintf(stderr, "---------------------------------------------------------------------------\n"); }else{ fprintf(stderr,"Please include the file \"bug.report\" and the program output in the bug report\n"); } //start of bug report //version fprintf(bugreport,"%s version %s\n",progname,MPGTX_VERSION); // arguments to the program fprintf(bugreport,"args : "); for (int i=0; i < myargc; i++){ fprintf (bugreport,"%s ",myargv[i]); } fprintf(bugreport,"\n"); //what killed me switch(signum){ case SIGSEGV: fprintf(bugreport,"SIGSEGV");break; case SIGBUS: fprintf(bugreport,"SIGBUS");break; case SIGFPE: fprintf(bugreport,"SIGFPE");break; } fprintf(bugreport," received\n"); //print the calling stack fprintf(bugreport,"stack : "); for (int j=0; j #include #include struct timeval tv; struct timezone tz; double MainClockStart; double Clock_Now(){ double time_now; gettimeofday(&tv,&tz); time_now=tv.tv_sec + 0.000001 * tv.tv_usec; gettimeofday(&tv,&tz); functions_cummulated_time[SELF]+=2*((tv.tv_sec + 0.000001 * tv.tv_usec)-time_now); return tv.tv_sec + 0.000001 * tv.tv_usec; } void AddTime(double timestart, int function){ functions_cummulated_time[function]+= Clock_Now()-timestart; } double functions_cummulated_time[N_FUNCTIONS]; void init_cummulated_time(){ MainClockStart=Clock_Now(); atexit(PrintTime); for (int i=0; i 1:1, n=2 -> 4:3, n=3 -> 16:9, n=4 -> 2.21:1 \n"); printf(" All Numbers from 0 - 16 will be accepted but the above are valid!\n"); if (invocation != mpgjoin) printf(" -b NAME set the basename for the output files\n"); if (invocation != mpgsplit && invocation != mpgdemux){ printf(" -o FILE set the output file name (join implied)\n"); printf(" if FILE is - , standard output will be used\n"); printf(" --force force joining of incompatible files\n"); } printf(" --no-parachute don't try to catch SIGSEGV (usefull for debugging)\n"); } if (invocation==mpgdemux) return; printf("Ranges :\n"); printf(" Ranges must follow an mpeg file\n"); printf(" [a-b] from 'a' inclusive to 'b' inclusive. If you want half opened\n"); printf(" ranges, you may want to use ]a-b], [a-b[ or ]a-b[ instead\n"); printf(" [num/total] the 'num' part if the mpeg file was split in 'total'.\n"); printf(" [1/4] would result in the first quarter of the mpeg file.\n"); if (invocation !=mpgjoin){ printf(" {a-b-...} where 'a', 'b', ... are in ascending order. Split the file\n"); printf(" at given values. {700M} is therefore equivalent to ranges\n"); printf(" [-700M] ]700M-]\n"); } printf("Values :\n"); printf(" Values can be time or offsets in the mpeg file\n"); printf(" Time Format HH:MM:SS where the HH: part can be omited\n"); printf(" Offset Format a number optionally followed by:\n"); printf(" M : offset is in Megabytes\n"); printf(" k : offset is in Kilobytes\n"); printf(" An empty value means the corresponding file boundary:\n"); printf(" [-10M] the first 10 Megabytes of file\n"); printf(" [500M-] from 500 Megabytes to the end of file\n"); return; } // added 22 March 2001 to get rid of unistd (portability) int mpgtx_access(char* filename){ BTRACK; // returns 0 if file exist (readable) // returns 1 if not. FILE* test_file = fopen(filename,"r+"); if (test_file == NULL) { return 1; } else { fclose(test_file); return 0; } } int main (int argc,char** argv){ #ifndef NOSIGNAL_H signal(SIGBUS,CatchBug); signal(SIGSEGV,CatchBug); signal(SIGFPE,CatchBug); signal(SIGINT,CatchBreak); for (int k=0; k < mpgtx_stack_count; k++) mpgtx_stack[k]=0; BTRACK; myargv=argv; myargc=argc; #endif #ifdef ENABLE_OPTIMIZATION init_cummulated_time(); #endif mpegOutFactory TheFac; chunkTab Tab(20); //char* current_filename=0; mpegOut* current_out; char* number; char* mybasename=0; char* myoutfile=0; chunk** ChunkTab; int ChunkCount; int nparts; char answer; bool want_info=false; bool basename_specified=false; bool joined=false; bool inparts=false; bool opresent=false; bool confirm_files=true; bool Id3Tag=false; bool force_option=false; bool catch_sigsegv=true; argtype lastarg=none; programname invocation; bool demux=false; int tmp_seq; //////////////////////////////////////// // Parse the program name // //////////////////////////////////////// ATRACK("parse progname"); int i; int length=strlen(argv[0]); int start=0; for ( i = length-1; i >= 0; i--) { if((argv[0][i] == '/') || (argv[0][i] == '\\')) { start = i + 1; break; } } progname=new char[length-start+1]; strcpy(progname,&argv[0][start]); if (!strcmp(progname,"mpgsplit")){ invocation=mpgsplit; inparts=true; } else { if (!strcmp(progname,"mpgcat")) { invocation=mpgcat; joined=true; opresent=true; myoutfile=new char[2]; myoutfile[0]='-'; myoutfile[1]=0; } else { if (!strcmp(progname,"mpgjoin")){ invocation=mpgjoin; joined=true; } else{ if (!strcmp(progname,"mpginfo")){ invocation=mpginfo; want_info=true; } else { if (!strcmp(progname,"mpgdemux")){ invocation=mpgdemux; demux=true; } else{ if (!strcmp(progname,"tagmp3")){ return ParseID3Command(argc,argv,1); } else{ invocation=other; } } } } } } // Warn user. /*fprintf(stderr,"%s version %s\n" "THIS IS *BETA* SOFTWARE I really need your help to correct all remaining bugs.\n" "If you find any bug in this program you are encouraged to post a bug report on\n" "mpgtx homepage .Thanks in advance for your help.\n\n" ,progname,MPGTX_VERSION); */ /////////////////////////////////////// // Parse remaining args // ///////////////////////////////////// ATRACK("Parse Args"); for ( i=1; i '0')&&(argv[i][1]<='9')) { number=&argv[i][1]; sscanf(number,"%d",&nparts); if(i+1>=argc){ fprintf(stderr,"%s option used without a filename\n",argv[i]); return 1; } if(!Tab.AddFile(argv[++i])){ fprintf(stderr,"%s is not a valid mpeg file\n",argv[i-1]); if(!want_info) return 1; } Tab.Nchunks(nparts); inparts=true; } else { switch (argv[i][1]){ case 'd' : demux=true; break; case 'X' : desperate_mode =true; break; case 'P' : preserve_header = true; break; case 'N': print_progress = false; break; case 'A': aspect_correction = true; tmp_seq = -1; sscanf(&(argv[i][2]),"%d",&tmp_seq); if ((tmp_seq < 0 ) || (tmp_seq > 15)) { fprintf(stderr,"invalid Value for aspect correction %d, exit!\n",tmp_seq); exit(1); } forced_sequence_header = tmp_seq << 4; break; case 'h' : print_help(invocation); return 0; break; case 'i' : want_info=true; break; case 'f' : confirm_files=false; break; case 's' : inparts=true; break; case 'j' : joined=true; if(!myoutfile) myoutfile="output.mpg"; break; case 'T' : Id3Tag=true; return ParseID3Command(argc,argv,i+1); break; case 'b' : inparts=true; if (joined) { fprintf(stderr,"-o and -b options are mutually exclusive\n"); return 1; } else { if (basename_specified) { fprintf(stderr,"only one basename is allowed\n"); return 1; } basename_specified=true; if(i+1>=argc){ fprintf(stderr,"-b option used without basename\n"); return 1; } else { //TODO copy basename i++; // fprintf(stderr,"option -b read, basename : %s\n",argv[i]); mybasename=new char [strlen(argv[i])+1]; strcpy(mybasename,argv[i]); } } break; case 'o' : if (basename_specified) { fprintf(stderr,"-b and -o options are mutually exclusive\n"); return 1; } else { if (opresent){ fprintf(stderr,"only one -o option allowed\n"); return 1; } opresent=true; if(i+1>=argc){ fprintf(stderr,"-o option used without outfile name\n"); return 1; } else { i++; // fprintf(stderr,"option -o read, will join all in file : %s\n",argv[i]); myoutfile=new char [strlen(argv[i])+1]; strcpy(myoutfile,argv[i]); } } break; case 'v': printf("%s Version %s\n",progname,MPGTX_VERSION); printf("Copyleft 2001 Laurent Alacoque \n"); printf("Partial work 2002 by Philipp Biermann \n"); printf("updates, bugs, patch, money : http://mpgtx.sourceforge.net\n"); return 0; break; case '-': // this is a long option (--xxxx) if (strcmp(argv[i],"--force")==0) force_option=true; if (strcmp(argv[i],"--no-parachute")==0) catch_sigsegv=false; break; default: fprintf(stderr,"unrecognized option %s\n",argv[i]); return 1; break; } } break; case ']': case '[': // this is a range lastarg=range; if(!Tab.ParseRange(argv[i])){ return 1; } break; case '{': // comma separated list of boundaries lastarg=range; if(!Tab.ParseBoundaries(argv[i])){ return 1; } break; default: // might be an input file, check! if (lastarg==file && !(want_info)){ // two file arguments encountered, apply 100% range to the first //one Tab.ParseRange("]0-]"); } lastarg=file; if(!Tab.AddFile(argv[i])) { fprintf(stderr,"%s is not a valid mpeg file\n",argv[i]); if(!want_info) return 1; } } }//for if (lastarg==file && (!want_info)){ //range's missing Tab.ParseRange("]0-]"); } /////////////////////////////////////////////////////////////////// // Args are parsed /////////////////////////////////////////////////////////////////// #ifndef NOSIGNAL_H if (!catch_sigsegv){ // if the --no-parachute was used, restore the default behaviour signal(SIGBUS,SIG_DFL); signal(SIGSEGV,SIG_DFL); signal(SIGFPE,SIG_DFL); signal(SIGINT,SIG_DFL); } #endif ChunkTab = Tab.GetChunks(&ChunkCount); #ifdef _DEBUG_ Tab.PrintTab(); #endif ATRACK("handling info mode"); ///////////////////////////////////////////////////////////////// // Handle Info mode ///////////////////////////////////////////////////////////////// if (want_info){ Tab.PrintInfos(); #ifdef NEED_END_MESSAGE endMessage(); #endif return 0; } ChunkTab=Tab.GetChunks(&ChunkCount); // from here we need at least one chunk if (ChunkCount==0){ fprintf(stderr,"nothing to do \n"); return 0; } RTRACK; ATRACK("demux mode"); ///////////////////////////////////////////////////////////////// // Handle demux mode ///////////////////////////////////////////////////////////////// if (demux){ if (ChunkCount!=1){ fprintf(stderr,"demux currently requires exactly one mpeg file\n"); return 1; } if (!basename_specified){ fprintf(stderr,"No base name specified, defaulting to basename : chunk\n"); mybasename="chunk"; } demuxer Dmux(ChunkTab[0]->mpegfile, mybasename,confirm_files); Dmux.Process(); //check the errors! #ifdef NEED_END_MESSAGE endMessage(); #endif return 0; } // from here we need at least one chunk if (ChunkCount==0){ fprintf(stderr,"nothing to do \n"); return 0; } // Tab.PrintTab(); RTRACK; ATRACK("join mode"); ///////////////////////////////////////////////////////////////// // All files are joined ///////////////////////////////////////////////////////////////// if (joined) { if (!opresent) { myoutfile = new char[500]; if (ChunkTab[0]->mpegfile->has_video() == false) sprintf(myoutfile, "chunk.mp3"); else sprintf(myoutfile, "chunk.mpg"); } if (ChunkCount >1) { for ( i = 1; i < ChunkCount ; i++) { if(!ChunkTab[0]->mpegfile->Match(ChunkTab[i]->mpegfile)) { if (force_option) fprintf(stderr, "Specified files don't seem to be compatible\n"); else { fprintf(stderr, "Specified files are not compatible, if you still want to join them use --force switch\n"); return 1; } } //okay they match } } if (!strcmp(myoutfile,"-")){ //output to stdout current_out=TheFac.NewMpegFrom(ChunkTab[0]->mpegfile,stdout); if (!current_out){ fprintf(stderr,"\nFatal : could not process file\n"); } } else { //output to myoutfile // if (!force_action) if (confirm_files && !mpgtx_access(myoutfile)) { fprintf(stderr,"file %s already exist. erase ? [n/y/a]:", myoutfile); fflush(stderr); answer=getchar(); while (getchar() != '\n'); //flush the leading \n if (answer!='y' && answer !='Y' && answer != 'a' && answer != 'A') { fprintf(stderr,"Aborted\n"); return 0; } if (answer == 'a' || answer == 'A') confirm_files = false; } current_out = TheFac.NewMpegFrom(ChunkTab[0]->mpegfile, myoutfile); if (!current_out) fprintf(stderr,"\nFatal : could not process file %s\n",myoutfile); } if (!current_out){ //something went wrong return 0; } for ( i=0;impegfile->FileName, i+1, ChunkCount); fflush(stderr); if (!current_out->WriteChunk(ChunkTab[i]->mpegfile, ChunkTab[i]->from, ChunkTab[i]->from_included, ChunkTab[i]->to, ChunkTab[i]->to_included)) fprintf (stderr," failed, range results in an empty chunk\n"); else fprintf(stderr,"\n"); } current_out->Finish(); #ifdef NEED_END_MESSAGE endMessage(); #endif return 0; } if (inparts) { RTRACK; ATRACK("split mode"); ///////////////////////////////////////////////////////////////// // each chunk in one file ///////////////////////////////////////////////////////////////// int myprec; char sChunkCount[50]; //write ChunkCount as a string sprintf(sChunkCount,"%d", ChunkCount + 1); //now we now how many digits we need -> in myprec myprec = strlen(sChunkCount); if (!basename_specified) { if (!opresent) //neither -o nor -b, use default basename mybasename="chunk"; else { if (ChunkCount >1){ fprintf(stderr,"-o option invalid for %d output files\n",ChunkCount); return 1; } mybasename = new char[strlen(myoutfile)+1]; strcpy(mybasename, myoutfile); } } myoutfile = new char[500]; for (i = 0;i < ChunkCount; i++) { //compute the name if (ChunkTab[i]->mpegfile->has_video()==false) { if (opresent) sprintf(myoutfile,"%s",mybasename); else { if (ChunkCount==1) sprintf(myoutfile,"%s.mp3",mybasename); else sprintf(myoutfile,"%s-%0*d.mp3",mybasename,myprec,i+1); } } else { if (opresent) sprintf(myoutfile,"%s",mybasename); else { if (ChunkCount==1) sprintf(myoutfile,"%s.mpg",mybasename); else sprintf(myoutfile,"%s-%0*d.mpg",mybasename,myprec,i+1); } } if (confirm_files && !mpgtx_access(myoutfile)) { fprintf(stderr,"file %s already exist. erase ?" " [n/y/a]:",myoutfile); fflush(stderr); answer=getchar(); while (getchar() != '\n'); //flush the leading \n if (answer != 'y' && answer != 'Y' && answer != 'a' && answer != 'A') { fprintf(stderr,"Aborted\n"); return 0; } if (answer == 'a' || answer == 'A') confirm_files = false; } current_out = TheFac.NewMpegFrom(ChunkTab[0]->mpegfile, myoutfile); if (!current_out) { fprintf(stderr,"\nFatal : could not process %s\n", myoutfile); return 1; } fprintf(stderr,"Now processing %s [%d/%d] ... ", ChunkTab[i]->mpegfile->FileName, i+1, ChunkCount); fflush(stderr); if (!current_out->WriteChunk(ChunkTab[i]->mpegfile, ChunkTab[i]->from, ChunkTab[i]->from_included, ChunkTab[i]->to, ChunkTab[i]->to_included)) fprintf (stderr," failed, range results in an empty chunk\n"); else fprintf(stderr,"\n"); current_out->Finish(); } // for delete [] myoutfile; #ifdef NEED_END_MESSAGE endMessage(); #endif return 0; } //no action were taken fprintf(stdout, "You must choose one options between -i -s -j\n"); fprintf(stdout, "Type %s -h for help\n", progname); return 0; } #ifdef NEED_END_MESSAGE void endMessage(void) { fprintf(stderr,"-------Done--------\n"); } #endif mpgtx-1.3.1/common.hh0000644000175000001440000001171710165227176014270 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #ifndef __common_hh_ #define __common_hh_ #define MPGTX_VERSION "1.3.1" // SYSTEM INCLUDE FILES #include // for fopen, fprintf, printf, fread... #include // fseeko(), ftello() conforms to SUS 2 for LFS suppport // Also needed for strcpy, strlen.. #include // if you don't have the signal system call (Windows for ex.) // then uncomment the next line //#define NOSIGNAL_H 1 #define mpeg_SILENT 0 #define mpeg_NORMAL 1 #define mpeg_VERBOSE 2 // packlength is variable since mpeg2 //#define PACKlength 12 #define PaddingPkt 0xBE #define VideoPkt 0xE0 #define AudioPkt 0xC0 #define SystemPkt 0xBB #define mpeg_AUDIO 1 #define mpeg_VIDEO 2 #define mpeg_SYSTEM 3 #define mpeg_UNKNOWN 4 #define mpeg_EMPTY 5 #define mpeg_TRANSPORT 6 // #define BUFFERSIZE 512 /// 16k buffer #define BUFFERSIZE 16384 //#define COPYBUFFERSIZE 512 /// 64k buffer //#define COPYBUFFERSIZE 65536 /// 2meg buffer for better performance #define COPYBUFFERSIZE 2097152 //#define ENABLE_OPTIMIZATION 1 // this is used to calculate time // used by 1)printf 2)mpeg::GetByte 3) mpegOut::Copy #ifdef ENABLE_OPTIMIZATION #define MAIN 0 #define PRINTF 1 #define GETBYTE 2 #define COPY 3 #define SELF 4 #define N_FUNCTIONS 5 double Clock_Now(); void AddTime(double timestart, int function); extern double functions_cummulated_time[N_FUNCTIONS]; void init_cummulated_time(); void PrintTime(); #define START_CLOCK double StartOfClock = Clock_Now(); #define STOP_CLOCK(x) AddTime(StartOfClock,x); extern double MainClockStart; #else #define START_CLOCK ; #define STOP_CLOCK(x) ; #endif #define MAX_ID3_GENRE 148 extern const char *genre[MAX_ID3_GENRE]; typedef unsigned char byte; typedef unsigned char marker; typedef const char* c_char; /** * ID3v1 TAG */ typedef struct { char name[30]; char artist[30]; char album [30]; char year [4]; char comment [30]; unsigned char genre; } id3; typedef struct { int mpeg_ver; int layer; int protect; int bitrate; float byte_rate; int sampling_rate; int mode; int padding; int modext; int emphasis_index; bool copyright; bool original; double duration; int frame_length; id3* tag; off_t first_frame_offset; } mpgtx_audio; typedef struct { unsigned long hsize,vsize; double frame_rate; unsigned long bitrate; double duration; byte aspect_ratio; byte* video_header; int video_header_size; off_t first_gop_offset; } mpgtx_video; typedef struct { byte* video_system_header; off_t video_system_header_length; byte* audio_system_header; off_t audio_system_header_length; byte* first_video_packet; off_t first_video_packet_length; /// initial timestamp double initial_TS; unsigned long muxrate; } mpgtx_system; typedef struct { bool progressive; byte chroma_format; bool low_delay; } sequence_ext; typedef struct { byte video_format; byte colour_prim; byte transfer_char; byte matrix_coef; unsigned long h_display_size; unsigned long v_display_size; } display_ext; typedef struct { char* ud; int ud_length; } user_data; #ifndef NOSIGNAL_H /// a "portable" call stack for bug reports #define mpgtx_stack_count 20 extern c_char mpgtx_stack[mpgtx_stack_count]; extern int mpgtx_stack_current; #define BTRACK mpgtx_stack[(mpgtx_stack_current)%mpgtx_stack_count]=__FUNCTION__;mpgtx_stack_current++; #define ATRACK(X) mpgtx_stack[(mpgtx_stack_current)%mpgtx_stack_count]=(X);mpgtx_stack_current++; #define RTRACK mpgtx_stack_current--; if (mpgtx_stack_current < 0) mpgtx_stack_current=mpgtx_stack_count -1; mpgtx_stack[(mpgtx_stack_current)%mpgtx_stack_count]=0; #else // no bug reports #define BTRACK ; #define ATRACK(X) ; #define RTRACK ; #endif //NOSIGNAL_H /*! @name Macros for compatibility and LFS * The following Macros ensure compatibility for glibc < 2.2+ and kernel < 2.4 * It also gives opportunity to support large files (>4 Go) such as DVDs * _OFF_d and _OFF_x are used in format strings of printf. They refer to the off_t type * and substitute to %lld %llx resp, whith large file support and %ld %lx otherwise. * * FSEEK will be substituted to the new fseeko function if possible or becomes standard fseek otherwise * * FTELL does the same with ftello and ftell */ //@{ #ifdef _LARGEFILE_SOURCE #ifdef _MACOSX #define _OFF_d "%qd" #define _OFF_x "%qx" #else #define _OFF_d "%lld" #define _OFF_x "%llx" #endif #define FSEEK fseeko #define FTELL ftello #else #define _OFF_d "%ld" #define _OFF_x "%lx" #define FSEEK fseek #define FTELL ftell #endif //@} #endif // __common_hh_ mpgtx-1.3.1/config.guess0000755000175000001440000012430710150416337014770 0ustar esusers00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. timestamp='2004-08-13' # This file 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amd64:OpenBSD:*:*) echo x86_64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; cats:OpenBSD:*:*) echo arm-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; luna88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mips64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit 0 ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; *:OS400:*:*) echo powerpc-ibm-os400 exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms && exit 0 ;; I*) echo ia64-dec-vms && exit 0 ;; V*) echo vax-dec-vms && exit 0 ;; esac esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mpgtx-1.3.1/configure0000755000175000001440000002632710165227052014362 0ustar esusers00000000000000#!/bin/sh ################################################# # # # Assign/reset vars we will use # # # ################################################# prefix="/usr/local" manprefix='$(PREFIX)' #compiler flags CC="g++" common_cflags="-Wall" devel_cflags="-g -Werror -fno-builtin" optimization_cflags="-O3" release_cflags=$optimization_cflags OFLAGS="-ansi" cflags=$common_cflags #linker flags lflags="" #state vars debug="no" devel="no" parachute="no" static="no" LFS="yes" # cp flags cpflags="d" # some stuff for MacOSX ----------------------------- HOSTNAME=`./config.guess` if [ "${HOSTNAME}" = "powerpc-apple-darwin6.0" ]; then #compiler flags CC="c++" common_cflags="-pedantic -Wall" #devel_cflags="-g -Werror -fno-builtin" devel_cflags="-g -fno-builtin" optimization_cflags="-O0" release_cflags=$optimization_cflags cflags=$common_cflags OFLAGS="-D_MACOSX" #linker flags lflags="-x" #state vars debug="no" devel="no" parachute="no" static="no" LFS="yes" #cp flags macosx does not know about cp -d ! cpflags="" fi # IRIX support (thank to Eric Sokolowsky) if [ "${HOSTNAME}" = "mips-sgi-irix6.5" ]; then OFLAGS=""; fi # cygwin support if [ "${HOSTNAME}" = "i686-pc-cygwin" ]; then OFLAGS=""; fi ################################################# # # # Process command line arguments # # # ################################################# for option in $* ; do case "$option" in -debug | --debug) debug="yes";; -man=* | --man=* | -manprefix=* | --manprefix=*) manprefix=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; -devel | --devel) devel="yes";; -no-LFS | --no-LFS | -no-lfs | --no-lfs) LFS="no";; -stat | -static | --stat | --static) static="yes";; -par | -parachute | --par | --parachute) parachute="yes";; -prefix=* | --prefix=*) prefix=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; -dist | dist | --distrib | -distrib) rm -f Makefile && cat << EOF >makefile && exit 0;; # Dummy Makefile, please run ./configure default: @echo "" @echo " -----------------------------------------------------------------------------" @echo " Hello !" @echo " I'm afraid I'm a dummy Makefile." @echo "" @echo " My goal in life is to politely ask you to run the configure script to actual-" @echo " ly generate a real Makefile." @echo " Would you be kind enough to type \"./configure --help\" to see the options that" @echo " will suit your needs ? Please note that typing \"./configure\" without option" @echo " will generate a Makefile that will suit most people needs." @echo "" @echo " I wish you a good day. Please don't drive to fast." @echo " -----------------------------------------------------------------------------" @echo "" EOF -h | -help | --help) cat << EOF && exit 0;; This dumb piece of script is NOT the standard GNU configure script. Use this to generate a Makefile that suits your needs. The default target is to use shared libraries, disable builtin parachute, enable Large File support (i.e. files > 2/4 Go) whenever possible, disable debugging facility and install mpgtx with prefix /usr/local Options you can use to change this dramatically standard behaviour are : --no-LFS Do not try to include Large File support. --static Link statically. Usefull if you plan to use mpgtx on the multiple systems with different libraries. --parachute Enable a builtin parachute that can catch segmentation faults and tell the user who to call and what to tell. --manprefix=MPTH Set the manual page installation directory to a different path from the regular installation directory. --devel Add some debugger facility and disable optimizations. --debug Same as above but changes mpgtx output to something ugly and usefull. --prefix=PREFIX Set the installation directory to PREFIX. --distrib Try to make the source files distribution ready. You can not build anything with this option EOF *) echo "the option [$option] is not known try \"configure --help\" for known options."; exit 1; esac done ################################################# # # # Check some things here # # # ################################################# # test if compiler is gcc version 3.0 or 3.1 # if so change optimization flags to -O2 # they do not seem to like -O3 with mpgtx very much gcc_major=`gcc --version 2>&1 | head -n1 | sed 's/^[^0-9]*//' | cut -d. -f1` gcc_minor=`gcc --version 2>&1 | head -n1 | sed 's/^[^0-9]*//' | cut -d. -f2` if test "$gcc_major" = "3"; then if test "$gcc_minor" = "0" -o "$gcc_minor" = "1"; then optimization_cflags="-O2"; fi fi # Now check if the system handles large file support # unless user has specified not to do so if test $LFS = "yes"; then echo -n "Checking Large File Support ... "; cat << EOF >__LFStest.cpp #include int main(){ return (int)(fseeko(stdin,0,SEEK_SET)); } EOF $CC __LFStest.cpp -o __LFStestPASSED -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE 1>__LFSout 2>__LFSerror if test -f __LFStestPASSED; then echo "PASSED"; cflags="$cflags -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE"; else echo "FAILED"; LFS="no (not supported)" fi rm -rf __LFStest.cpp __LFStestPASSED __LFSerror __LFSout; fi ################################################# # # # Format CFLAGS and LFAGS # # # ################################################# if test $parachute = "no"; then cflags="$cflags -DNOSIGNAL_H"; fi if test $debug = "yes"; then if test $devel = "yes"; then cflags="$cflags -D_DEBUG_"; else cflags="$cflags $devel_cflags -D_DEBUG_"; fi fi if test $devel = "yes"; then cflags="$cflags $devel_cflags"; fi if test $static = "yes"; then lflags="$lflags -static"; fi if test $devel = "no" -a $debug = "no"; then lflags="$lflags -s"; cflags="$cflags $optimization_cflags"; fi ################################################# # # # Actually generate makefile # # # ################################################# makefilename="Makefile" echo "Generating $makefilename ..." # remove dumb makefile rm -f makefile # generate actual Makefile cat << EOF >$makefilename ################################################### # Hi. # # This file was generated by the configure script # # but you may want to edit it at your convenience # # If unsure, try a ./configure --help to see if # # standard options suit your needs. # # Have a nice day. laureck # ################################################### # Installation directories. Edit at your convenience EOF echo "PREFIX=$prefix" >> $makefilename echo "OFLAGS=$OFLAGS" >> $makefilename echo "manprefix=$manprefix" >> $makefilename echo "cpflags=$cpflags" >> $makefilename cat << EOF >>$makefilename INSTALLDIR=\$(PREFIX)/bin MANDIR=\$(manprefix)/man/man1 # Compilation and linker flags EOF echo "CFLAGS=$cflags" >> $makefilename echo "LFLAGS=$lflags" >> $makefilename cat << EOF >>$makefilename # Now onto the targets default: warn mpgtx @echo "----------------------------------------------------------------------" @echo "Success building mpgtx. Now type \"make install\" to install it" @echo "----------------------------------------------------------------------" warn: @echo "----------------------------------------------------------------------" @echo "I'm building mpgtx with following options :" @echo "" EOF if test $devel = "no" -a $debug = "no"; then echo -e "\t@echo \" Target : RELEASE\"" >> $makefilename else if test $debug = "yes"; then echo -e "\t@echo \" Target : DEBUG\"" >> $makefilename else echo -e "\t@echo \" Target : DEVELOPMENT\"" >> $makefilename fi fi echo -e "\t@echo \" Manual installation prefix: $manprefix\"" >>$makefilename echo -e "\t@echo \" Large File support : $LFS\"" >>$makefilename echo -e "\t@echo \" Link statically : $static\"" >>$makefilename echo -e "\t@echo \" Support builtin parachute : $parachute\"" >>$makefilename echo -e "\t@echo \" Install prefix : $prefix\"" >>$makefilename cat << EOF >>$makefilename @echo "" @echo "Type \"./configure --help\" to see available options." @echo "----------------------------------------------------------------------" @echo "" mpgtx : commandline.cxx mpegOut.o mpeg.o chunkTab.o id3command.o common.hh $CC \$(CFLAGS) \$(OFLAGS) -o mpgtx commandline.cxx mpegOut.o mpeg.o chunkTab.o id3command.o \$(LFLAGS) mpegOut.o : mpegOut.cxx mpegOut.hh mpeg.hh common.hh $CC \$(CFLAGS) \$(OFLAGS) -c mpegOut.cxx mpeg.o : mpeg.cxx mpeg.hh mpegOut.hh common.hh $CC \$(CFLAGS) \$(OFLAGS) -c mpeg.cxx chunkTab.o : chunkTab.cxx chunkTab.hh common.hh $CC \$(CFLAGS) \$(OFLAGS) -c chunkTab.cxx id3command.o : id3command.cxx id3command.hh common.hh $CC \$(CFLAGS) \$(OFLAGS) -c id3command.cxx clean : rm -f *.o mpgtx mpgjoin mpgcat mpgsplit mpginfo mpgdemux tagmp3 man/mpginfo.1 man/mpgsplit.1 man/mpgcat.1 man/mpgjoin.1 man/mpgdemux.1 install: ln -sf mpgtx mpgjoin ln -sf mpgtx mpgsplit ln -sf mpgtx mpgcat ln -sf mpgtx mpginfo ln -sf mpgtx mpgdemux ln -sf mpgtx tagmp3 install -d -m 755 \$(INSTALLDIR) install -d -m 755 \$(MANDIR) install -s -m 755 mpgtx \$(INSTALLDIR) cp -\$(cpflags)f mpgdemux mpgjoin mpgcat mpginfo mpgsplit tagmp3 \$(INSTALLDIR) install -m 644 man/mpgtx.1 man/tagmp3.1 \$(MANDIR) cd man ; make cd .. cp -\$(cpflags)f ./man/mpgdemux.1 ./man/mpgjoin.1 man/mpgsplit.1 man/mpgcat.1 man/mpginfo.1 \$(MANDIR) uninstall: rm -f \$(INSTALLDIR)/mpgtx rm -f \$(INSTALLDIR)/mpgjoin rm -f \$(INSTALLDIR)/mpgsplit rm -f \$(INSTALLDIR)/mpgcat rm -f \$(INSTALLDIR)/mpginfo rm -f \$(INSTALLDIR)/mpgdemux rm -f \$(INSTALLDIR)/tagmp3 rm -f \$(MANDIR)/mpgtx.1 rm -f \$(MANDIR)/mpgjoin.1 rm -f \$(MANDIR)/mpgsplit.1 rm -f \$(MANDIR)/mpgcat.1 rm -f \$(MANDIR)/mpginfo.1 rm -f \$(MANDIR)/mpgdemux.1 rm -f \$(MANDIR)/tagmp3.1 EOF ################################################# # # # Tell Mr X what he'll have # # # ################################################# echo "" echo "Here are the options you choosed : " if test $devel = "no" -a $debug = "no"; then echo " Target : RELEASE" else if test $debug = "yes"; then echo " Target : DEBUG" else echo " Target : DEVELOPMENT" fi fi echo " Large File support : $LFS" echo " Link statically : $static" echo " Support builtin parachute : $parachute" echo " Install prefix : $prefix" echo "" echo "Now Type \"make\" to build mpgtx (and have a nice day by the way) " exit 0 mpgtx-1.3.1/id3command.cxx0000644000175000001440000006123010157046157015213 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #include "id3command.hh" /** * Parses commandline and decide what happens. * * @param argc argc of calling parent programm * @param argv argv of calling parent programm * @param arc_offset index begin of interesting args * @return 0 - ok, 1 - error or return code of called subroutine [0;1] */ int ParseID3Command(int argc, char** argv, int argc_offset){ BTRACK; // starting from argc_offset format is : // -h or // set FORMAT file ... file ... // mov FORMAT2 file .... file ... // del file ... file ... int argcount= argc -argc_offset; if (argcount==0){ fprintf(stderr,"You must specify at least a mode\n"); return 1; } if (!strcmp(argv[argc_offset],"-h")){ // this is -h option printf("tagmp3 an ID3v1 tag editor\n"); printf("Usage : tagmp3 [-n] [-v] [set|move|del|list|show] [FORMAT] [file...]\n\n"); printf(" OPTIONS:\n"); printf(" -v prints version information\n"); printf(" set sets ID3v1 tag according to FORMAT\n"); printf(" move moves mp3 file according to the FORMAT\n"); printf(" del removes ID3v1 tag from file (if any)\n"); printf(" list lists known music genres along with their numeric values\n\n"); printf(" FORMAT:\n"); printf(" for set mode : \"%%Y? %%X:VALUE ...\" sets the X field of tag\n"); printf(" with VALUE and asks for the value of Y field\n"); printf(" for move mode : \"mymp3/%%X/%%Y/%%Z.mp3\" move file to\n"); printf(" ./mymp3/tag{X}/tag{Y}/tag{Z}.mp3\n\n"); printf(" valid fields are : %%A artist %%t title %%T track %%y year\n"); printf(" %%a album %%c comment %%g genre\n"); return 0; } if (!strcmp(argv[argc_offset],"-n")){ //show only id3_Show_Only=true; argc_offset++; } if (!strcmp(argv[argc_offset],"list")){ // list genres for (int i=0; i< MAX_ID3_GENRE; i+=4){ if (i\n"); printf("updates, bugs, patch, money : http://mpgtx.sourceforge.net\n"); return 0; } if (!strcmp(argv[argc_offset],"show")){ if (argcount<2){ fprintf(stderr,"show id3v1 tag of what file?\n"); return 1; } return ParseShow(argc,argv,argc_offset+1); } if (!strcmp(argv[argc_offset],"set")){ if (argcount<3){ fprintf(stderr,"Not enough arguments for set mode\n"); return 1; } return ParseSet(argc,argv,argc_offset+1); } if (!strcmp(argv[argc_offset],"move")){ if (argcount<3){ fprintf(stderr,"Not enough argument for mov mode\n"); return 1; } return ParseMov(argc,argv,argc_offset+1); } if (!strcmp(argv[argc_offset],"del")){ if (argcount<2){ fprintf(stderr,"remove id3v1 tag from what?\n"); return 1; } return ParseDel(argc,argv,argc_offset+1); } // not a valid id3 mode fprintf(stderr,"invalid mode : %s\n",argv[argc_offset]); return 1; } /** * Shows ID3v1 TAG of files. * * @param argc argc of calling parent programm * @param argv argv of calling parent programm * @param arc_offset index begin of interesting args * @return allways 0, no error if there are no ID3v1 TAGs in file */ int ParseShow(int argc, char** argv, int argc_offset){ BTRACK; OpenedFile* my; for (int i = argc_offset; i < argc; i++){ my = OpenFile(argv[i]); if ((!my->thefile)){ continue; } // okay we have a file here. if (!my->thetag){ fprintf(stdout, "%s doesn't have any ID3v1 tag (Note: ID3v2 not supported)\n", argv[i]); } else{ printf("%s\n", argv[i]); printf(" Artist : %s\n", my->thetag->artist); printf(" Title : %s\n", my->thetag->title); printf(" Album : %s\n", my->thetag->album); if (my->thetag->track>0) printf(" Track : %d\n", my->thetag->track); printf(" Year : %s\n", my->thetag->year); if (my->thetag->genre < MAX_ID3_GENRE) printf(" Genre : %s\n", genre[my->thetag->genre]); printf(" Comment: %s\n\n", my->thetag->comment); } // lets delete and close before next opened file if (my->thefile) fclose (my->thefile); if (my->thetag) delete my->thetag; delete my; } return 0; } /** * Sets ID3v1 TAG of files. * * @param argc argc of calling parent programm * @param argv argv of calling parent programm * @param arc_offset index begin of interesting args * @return allways 0, no error if there are no ID3v1 TAGs in file */ int ParseSet(int argc, char** argv, int argc_offset){ BTRACK; OpenedFile* my; int retval=1; for (int i = argc_offset + 1; i < argc; i++) { my = OpenFile(argv[i]); if ((!my->thefile) || (my->filetype != REAL_MP3)) { continue; } // okay we have a file here. // FIXME: This could not be reached, DEPRECATED? if (my->filetype != REAL_MP3) { fprintf(stderr, "Skipping file %s ", argv[i]); if (my->filetype== FAKE_MP3) fprintf(stderr,"(Wave file)\n"); else fprintf(stderr,"(not an mp3)\n"); } printf("Setting %s tag \n",argv[i]); fflush(stdout); if (!SetID3(argv[argc_offset],my)){ // something's wrong with the format fprintf(stderr,"ERROR while setting the format\n"); retval=1; break; } else{ if(!id3_Show_Only) { // printf("Setting %s tag\n",argv[i]); WriteID3(my); retval=0; } else{ // printf("\n"); } } // lets delete and close before next opened file if (my->thefile) fclose (my->thefile); if (my->thetag) delete my->thetag; delete my; } return retval; } /** * Parses command line to prepare moving of MP3 files. * * @param argc argc of calling parent programm * @param argv argv of calling parent programm * @param arc_offset index begin of interesting args * @return allways 0, no error if there are no ID3v1 TAGs in file */ int ParseMov(int argc, char** argv, int argc_offset){ BTRACK OpenedFile* my; int i; int j; int last_slash; char* tempfilename=new char[300]; char mybasename[300]; char myfilename[300]; // for each remaining arg for ( i=argc_offset+1; ithefile){ delete my; continue; } // opened, with a tag // compute basename and filename last_slash=-1; if (!strstr(argv[i],"/")){ // no base directory in file name mybasename[0]=0; } else{ for(j =0; j < int(strlen(argv[i])); j++){ if (argv[i][j]=='/') last_slash=j; } for (j=0; j <= last_slash; j++){ mybasename[j]=argv[i][j]; } mybasename[j]=0; } // now we have the basename, last_slash is either // -1 (no basename) or the offset of the last slash last_slash++; for (j=last_slash; j<=int(strlen(argv[i])); j++){ myfilename[j-last_slash]=argv[i][j]; } //basename and filename are okay // if this is a fake move it in fake-mp3 // fake is a wav with mp3 extension if (my->filetype==FAKE_MP3){ sprintf(tempfilename,"fake-mp3/"); strcat(tempfilename,myfilename); Move2(argv[i],mybasename,tempfilename); if (my->thetag) delete my->thetag; delete my; continue; } // if this file doesn't have a tag // skip it if (! my->thetag){ fprintf(stderr,"Skipping file %s (no tag)\n",argv[i]); fclose (my->thefile); delete my; continue; } // if this is not a mp3 if (my->filetype==NOT_MP3){ fprintf(stderr,"Skipping %s(not an mpeg file)\n",argv[i]); } else { // Now we have to handle the format string. tempfilename[0] = 0; int name_offset=0; int fieldsize=-1; char *source=0; char* format= argv[argc_offset]; bool error_found=false; char temptracknum[10]; int track; int t,h,k,m; char* fieldname=0; unsigned char genre_num; const char* genre_as_string; int genre_length; j=0; // the format string is argv[argc_offset] while ((j < int(strlen(format)))&& !error_found ){ if (format[j] == '%'){ if (format[j+1] != '%'){ // it starts like a field name fieldsize=-1; switch (format[j+1]){ case 'a': fieldname="album"; source= my->thetag->album; fieldsize=30; break; case 'A': fieldname="artist"; source= my->thetag->artist; fieldsize=30; break; case 't': fieldname="title"; source= my->thetag->title; fieldsize=30; break; case 'y': fieldname="year"; source= my->thetag->year; fieldsize=4; break; case 'c': fieldname="comment"; source= my->thetag->comment; fieldsize=30; break; case 'T': track= my->thetag->track; if (track <0){ fprintf(stderr,"%s: empty track value needed by format\n",argv[i]); error_found=true; } else { sprintf(temptracknum,"%02d",track); for (h=0; h < int(strlen(temptracknum));h++){ tempfilename[name_offset++]=temptracknum[h]; } } break; case 'g': genre_num = my->thetag->genre; if (genre_num >= MAX_ID3_GENRE){ genre_as_string = "Unknown"; genre_length=7; } else { genre_as_string=genre[genre_num]; genre_length=strlen(genre_as_string); } for (t=0; t 0){ //eat leading white spaces for (k=0;(k = fieldsize) || (source[k] == 0)){ // this was a all white field... skip ? fprintf(stderr,"%s: empty field %s needed by format\n",argv[i],fieldname); error_found=true; } else { // k points to the first valid char int last_valid=k; for (int l =0; (lthefile) fclose (my->thefile); if (my->thetag) delete my->thetag; delete my; } delete[] tempfilename; return 0; } /** * Removes ID3v1 TAG from files. * * @param argc argc of calling parent programm * @param argv argv of calling parent programm * @param arc_offset index begin of interesting args * @return 1 - error: windows version dos not work yet, otherwise allways 0 */ int ParseDel(int argc, char** argv, int argc_offset){ BTRACK #ifdef _WIN32 // windows version /* * from: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/setendoffile.asp * * The SetEndOfFile function moves the end-of-file (EOF) position for the specified file * to the current position of the file pointer. * * This function sets the physical end of a file (as indicated by allocated clusters). * To set the logical end of a file, use the SetFileValidData function. * * BOOL SetEndOfFile( * HANDLE hFile * ); */ printf("del\n"); fprintf(stderr,"del mode is not implemented under windows : \nstill don't know how to truncate a file"); return 1; #else off_t FileSize; OpenedFile* my; for (int i=argc_offset; i < argc; i++){ printf("Deleting tag in %s\n",argv[i]); my=OpenFile(argv[i]); if (!my->thefile){ printf("Can not open file\n"); if (my->thetag) delete my->thetag; delete my; continue; } // okay we have a file here. if (my->thetag) { // printf("tag is present\n"); // this file has a tag FSEEK(my->thefile,0,SEEK_END); // printf("Size before : %ld\n",ftello(my->thefile)); FileSize=FTELL(my->thefile)-128; // printf("Size after : %ld\n",FileSize); if (!id3_Show_Only) if(truncate(argv[i],FileSize)){ fprintf(stderr,"Unable to truncate file \n"); perror(argv[i]); } } //printf("File doesn't have any tag\n"); // lets delete and close before next opened file if (my->thefile) fclose (my->thefile); if (my->thetag) delete my->thetag; delete my; } return 0; #endif // _WIN32 } /** * Fills a OpenedFile structure with TAG infos of a file according given FileName * * @param FileName Name of file to open * @return Pointer to filled structure */ OpenedFile* OpenFile(char* FileName){ BTRACK; unsigned char start[4]; char TAG[128]; OpenedFile* my = new OpenedFile; my->thetag=0; my->thefile=0; my->filetype=NOT_MP3; my->thefile=fopen(FileName,"r+b"); if (!my->thefile){ // error perror(FileName); return my; } fread(start,4,1,my->thefile); if (!strncmp((char*)(start),"RIFF",4)){ if (!strstr(FileName,".mp")||!strstr(FileName,".MP")){ // fprintf(stderr,"Skipping Fake mp3 file %s (Wave file)\n",FileName); my->filetype=FAKE_MP3; return my; } else { // fprintf(stderr,"Skipping Wave file %s\n",FileName); my->filetype=NOT_MP3; return my; } } if ((start[0]==0xFF) && ((start[1] & 0xE0) == 0xE0)){ my->filetype=REAL_MP3; } else if (start[0]== 'I' && start[1]=='D' && start[2]=='3'){ my->filetype=REAL_MP3; } else{ //doesn't start like an mp3 if (!strstr(FileName,".mp")||!strstr(FileName,".MP")){ my->filetype=REAL_MP3; } else { fprintf(stderr,"Skipping unknown file %s\n",FileName); my->filetype=NOT_MP3; return my; } } FSEEK(my->thefile,-128,SEEK_END); fread(TAG,128,1,my->thefile); if ( strncmp (TAG,"TAG",3) ){ // doesn't begin with TAG : no tag return my; } // begins with TAG : parse it. my->thetag=new myID3tag; strncpy(my->thetag->title,&TAG[3],30); strncpy(my->thetag->artist,&TAG[33],30); strncpy(my->thetag->album,&TAG[63],30); strncpy(my->thetag->year,&TAG[93],4); strncpy(my->thetag->comment,&TAG[97],30); if (TAG[125]==0){ my->thetag->track=TAG[126]; } else { my->thetag->track=-1; } my->thetag->genre=(unsigned char) TAG[127]; return my; } /** * Sets ID3v1 TAG of a MP3 file according given format string. * * @param format Format string with TAGs to set * @param tag File to tag. * @return false on format errors, true otherwise */ bool SetID3(char* format,OpenedFile* tag){ BTRACK; // change tag->thetag to reflect format if (! tag->thetag) { tag->thetag=new myID3tag; tag->thetag->album[0]=0; tag->thetag->artist[0]=0; tag->thetag->year[0]=0; tag->thetag->comment[0]=0; tag->thetag->title[0]=0; tag->thetag->track=-1; tag->thetag->genre=255; } char *target=0; // parse the format int fieldsize; int tracknum=-1; int genre=-1; int length = strlen(format); for(int i=0; i <= length-3;){ // first char must be % // second char must be tAaycgT // third char must be : or ? while(format[i]==' ') i++; if (format[i]!='%' || (format[i+2] != ':' && format [i+2] != '?')){ fprintf(stderr,"Invalid format \"%s\"\n",format+i); return false; } fieldsize=-1; switch (format[i+1]){ case 'a': if (format[i+2]=='?') fprintf(stdout,"Album : "); target= tag->thetag->album; fieldsize=30; break; case 'A': if (format[i+2]=='?') fprintf(stdout,"Artist : "); target= tag->thetag->artist; fieldsize=30; break; case 't': if (format[i+2]=='?') fprintf(stdout,"Title : "); target= tag->thetag->title; fieldsize=30; break; case 'c': if (format[i+2]=='?') fprintf(stdout,"Comment: "); target= tag->thetag->comment; fieldsize=30; break; case 'y': if (format[i+2]=='?') fprintf(stdout,"Year : "); target= tag->thetag->year; fieldsize=4; break; case 'g': if (format[i+2]=='?') fprintf(stdout,"Genre : "); break; case 'T': if (format[i+2]=='?') fprintf(stdout,"Track : "); break; } // treat the '?' if (format[i+2]=='?'){ // ask user if (fieldsize>0){ //any char* fgets(target,fieldsize,stdin); // now remove the trailing \n if any if (strlen(target)!=0){ if (target[strlen(target)-1]=='\n') target[strlen(target)-1]=0; else { // mmmmm no \n at the end : flush input while (getchar()!='\n'); } } } else{ // a number for genre or track if (format[i+1]=='T') scanf("%d",&tracknum); if (format[i+1]=='g') scanf("%d",&genre); // printf("read T %d g %d\n",tracknum,genre); } i+=3; continue; } // treat the ':' // is this a 'standard' field? if (fieldsize==-1){ if (length-i >3){ if (format[i+1]=='T') sscanf(&format[i+3],"%d",&tracknum); if (format[i+1]=='g') sscanf(&format[i+3],"%d",&genre); // printf("scanned T %d g %d\n",tracknum,genre); i+=3; } while ((format[i]>='0' && format[i]<='9')||(format[i]==' ')) i++; continue; } // this is a char * field // move i to the start of field i+=3; // now copy everything until a % or fieldsize or format length bool finished=false; int n_processed=0; while (!finished){ if ( // a % not followed by a % (format[i]=='%' && format[i+1]!='%')|| // end of format (format[i]=='\0') ) { finished=true; // while (n_processed thetag->genre=255; // unspecified genre //} if (genre>=0) tag->thetag->genre=genre; if (tracknum >=0 && tracknum <256 ){ tag->thetag->track=(unsigned char) tracknum; } return true; } /** * Write ID3v1 TAG to given file. * * @param filename MP3 file to set ID3v1 TAG. */ void WriteID3(OpenedFile* filename){ BTRACK //write tag->thetag in tag->thefile /* printf ("artist %s\ntitle %s \nalbum %s\nyear %s\ncomment %s\ngenre %d\ntrack%d\n\n", filename->thetag->artist , filename->thetag->title , filename->thetag->album, filename->thetag->year , filename->thetag->comment , filename->thetag->genre , filename->thetag->track); */ if (filename->thefile==0){ fprintf(stderr,"ERROR : no valid FILE* in WriteID3\n"); return; } if (filename->thetag==0){ fprintf(stderr,"ERROR : no valid tag in WriteID3\n"); return; } char TAG[128]; TAG[0]='T'; TAG[1]='A'; TAG[2]='G'; int length,i; length=strlen(filename->thetag->title); for (i=0; i < length; i++) TAG[3+i]=filename->thetag->title[i]; for (;i<30; i++) TAG[3+i]=' '; length=strlen(filename->thetag->artist); for (i=0; i < length; i++) TAG[33+i]=filename->thetag->artist[i]; for (;i<30; i++) TAG[33+i]=' '; length=strlen(filename->thetag->album); for (i=0; i < length; i++) TAG[63+i]=filename->thetag->album[i]; for (;i<30; i++) TAG[63+i]=' '; length=strlen(filename->thetag->year); for (i=0; i < length; i++) TAG[93+i]=filename->thetag->year[i]; for (;i<4; i++) TAG[93+i]=' '; length=strlen(filename->thetag->comment); for (i=0; i < length; i++) TAG[97+i]=filename->thetag->comment[i]; for (;i<30; i++) TAG[97+i]=' '; if (filename->thetag->track >0){ TAG[125]=0; TAG[126]=(unsigned char) filename->thetag->track; } //if(filename->thetag->genre !=255) TAG[127]=(unsigned char) filename->thetag->genre; TAG[127]= filename->thetag->genre; // okay we have our chunk. char checkTAG[3]; FSEEK(filename->thefile, -128, SEEK_END); fread(checkTAG,3,1,filename->thefile); if (!strncmp(checkTAG,"TAG",3)){ // a TAG is present FSEEK(filename->thefile, -128, SEEK_END); fwrite(TAG,128,1,filename->thefile); }else{ // no tag in this file FSEEK(filename->thefile,0,SEEK_END); fwrite(TAG,128,1,filename->thefile); } } /** * Asks user for creation of a new directory. * *@param path Path of new directory *@return true if user allows creation, false if deny */ bool AskDirCreation(char* path){ BTRACK fprintf(stderr,"Create directory %s ?:[N/y]",path); char answer=getchar(); while(getchar()!='\n'); RTRACK if (answer=='y' || answer=='Y') return true; return false; } /** * Moves file to destination, creates intermediate directories if necessary. * * @param name Filename * @param basedir Source directory * @param dest Destination directory */ void Move2(const char* name,const char* basedir,const char* dest){ BTRACK struct stat mystats; int ret; char *tempdest; char *fullname; int move2dirsize=0; fullname = new char [strlen(name)+strlen(basedir)+1]; strcpy(fullname,basedir); strcat(fullname,name); // if the dest ends with a / , keep space for the name if (dest[strlen(dest)-1]=='/'){ move2dirsize=strlen (name); } //handle the full path (begins with a /) if (dest[0]=='/'){ tempdest=new char[strlen(dest)+1+move2dirsize]; strcpy(tempdest,dest); } //handle the ~/ (home dir) else if(dest[0]=='~' && dest[1]=='/'){ struct passwd* mypassentry; mypassentry=getpwuid(getuid()); if (!mypassentry || !(mypassentry->pw_dir)){ fprintf(stderr,"Could not resolve your home directory, use absolute path\n"); return; } tempdest= new char [strlen(mypassentry->pw_dir)+strlen(dest)+1+move2dirsize]; if (mypassentry->pw_dir[strlen(mypassentry->pw_dir)-1] == '/'){ // pwdir ends with a slash strcpy(tempdest,mypassentry->pw_dir); strcat(tempdest,&dest[2]); // dest[2] after the / } else { //pw_dir doesn't end with a slash strcpy(tempdest,mypassentry->pw_dir); strcat(tempdest,&dest[1]); } } //handle the ./ else if (dest[0]=='.' && dest[1]=='/'){ //explicitely relative path tempdest= new char[strlen(dest)+strlen(basedir)+1+move2dirsize]; strcpy(tempdest,basedir); strcat(tempdest,&dest[2]); //after the slash } // dest is relative, don't change it else { tempdest= new char[strlen(dest)+strlen(basedir)+1+move2dirsize]; strcpy(tempdest,basedir); strcat(tempdest,dest); } if (move2dirsize){ //the format ends with a /, append name strcat(tempdest,name); } //printf("%s\n =>%s\n\n",name,tempdest); //this for is to create intermediate directories for (int i= 0; i < int(strlen(tempdest)); i++){ if (tempdest[i]=='/' && i!=0){ //check if dir exists //hide the trailing path tempdest[i]=0; ret=stat(tempdest,&mystats); if (!ret){ //stat worked //check if this is a directory if ((mystats.st_mode & S_IFMT)==S_IFREG){ fprintf(stderr,"Error : %s is not a directory\n",tempdest); delete [] tempdest; return; } } else{ //didn't work... check the error // printf("%s ",tempdest); switch(errno){ case ENOENT: // printf("ENOENT\n"); if (id3_Show_Only) { printf("Would Create directory %s (if not created before)\n",tempdest); } else{ if(AskDirCreation(tempdest)) mkdir(tempdest,0777); else return; } break; case ENOTDIR: // a part of the path is a directory fprintf(stderr,"Error : %s is not a directory\n",tempdest); delete[]tempdest; return; break; case EACCES: perror(tempdest); delete[] tempdest; return; break; default : perror(tempdest); delete[] tempdest; return; break; } } //show the trailing path again tempdest[i]='/'; } } // okay we can rename // check if the destination already exist ret = stat(tempdest,&mystats); if (!ret){ printf("Skipping %s (file exists)\n",tempdest); delete[] tempdest; return; } if(id3_Show_Only){ printf("Would move %s\n",fullname); printf("to %s\n\n",tempdest); } else{ ret=rename(fullname,tempdest); if (ret){ perror(fullname); } else{ //printf("%s=>%s\n",name,tempdest); } } } mpgtx-1.3.1/id3command.hh0000644000175000001440000000335610157050274015010 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #ifndef __id3command_hh_ #define __id3command_hh_ #include #include #include "common.hh" // needed by move #include #include #include #include //for the home dir #include // end needed bool id3_Show_Only =false; /** * ID3v1 TAG with additional character for each string termination */ typedef struct { char title [31]; char artist [31]; char album [31]; char year [5]; char comment [31]; int track; unsigned char genre; } myID3tag; #define NOT_MP3 0 #define REAL_MP3 1 #define FAKE_MP3 2 typedef struct { FILE* thefile; myID3tag* thetag; int filetype; } OpenedFile; int ParseID3Command(int argc, char** argv, int argc_offset); int ParseShow(int argc, char** argv, int argc_offset); int ParseSet(int argc, char** argv, int argc_offset); int ParseMov(int argc, char** argv, int argc_offset); int ParseDel(int argc, char** argv, int argc_offset); // include for ParseDel() #ifdef _WIN32 // windows version // del mode is not implemented under windows #else #include #endif OpenedFile* OpenFile(char* FileName); bool SetID3(char* format,OpenedFile* tag); void WriteID3(OpenedFile* filename); bool AskDirCreation(char* path); void Move2(const char* name,const char* basedir,const char* dest); #endif // __id3command_hh_ mpgtx-1.3.1/makefile0000644000175000001440000000140707342410322014140 0ustar esusers00000000000000# Dummy Makefile, please run ./configure default: @echo "" @echo " -----------------------------------------------------------------------------" @echo " Hello !" @echo " I'm afraid I'm a dummy Makefile." @echo "" @echo " My goal in life is to politely ask you to run the configure script to actual-" @echo " ly generate a real Makefile." @echo " Would you be kind enough to type \"./configure --help\" to see the options that" @echo " will suit your needs ? Please note that typing \"./configure\" without option" @echo " will generate a Makefile that will suit most people needs." @echo "" @echo " I wish you a good day. Please don't drive to fast." @echo " -----------------------------------------------------------------------------" @echo "" mpgtx-1.3.1/mpeg.cxx0000644000175000001440000021534510165223437014132 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #include "mpeg.hh" #include //philipp #include extern bool desperate_mode; extern bool preserve_header; extern bool print_progress; int mpeg2found = 0; // #define _DEBUG_ int mpeg_bitrate_index [2][3][16] = { // MPEG 1 { // layer 1 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, // layer 2 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, // layer 3 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0} }, // MPEG 2 or 2.5 { // layer 1 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, // layer 2 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0}, // layer 3 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} } }; int mpeg_sampling_index [3][4] = { {44100,48000,32000,0}, //mpeg 1 {22050,24000,16000,0}, //mpeg 2 {11025,12000, 8000,0} //mpeg 2.5 }; double mpeg_frame_rate_index [9] = { 0., 24000./1001., 24., 25., 30000./1001., 30., 50., 60000./1001., 60. }; // ripped from id3ed V1.10.2 (Thx to Matt Mueller) // HEY you didn't want me to type *that* ! const char *genre[MAX_ID3_GENRE]={ "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap","Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop" }; float mpeg::Duration(){ BTRACK; if (Audio) return float(Audio->duration); if (Video) return float(Video->duration); return 0; } bool mpeg::Match(mpeg* peer){ BTRACK; if (MpegType != peer->MpegType) { fprintf(stderr, "mpeg files are not the same type!\n"); return false; } if (MpegType == mpeg_AUDIO || MpegType == mpeg_SYSTEM) { if (Audio->bitrate != peer->Audio->bitrate) { fprintf (stderr, "Incompatible audio bitrates %s (%d bps) %s (%d bps)\n", FileName, Audio->bitrate, peer->FileName, peer->Audio->bitrate); return false; } if (Audio->mpeg_ver != peer->Audio->mpeg_ver) { fprintf (stderr, "Incompatible mpeg audio versions " "%s is mpeg %d %s is mpeg %d\n", FileName,Audio->mpeg_ver, peer->FileName, peer->Audio->mpeg_ver); return false; } if (Audio->layer != peer->Audio->layer) { fprintf (stderr, "Incompatible audio layers %s is layer %d %s is layer %d", FileName, Audio->layer, peer->FileName, peer->Audio->layer); return false; } if (Audio->sampling_rate != peer->Audio->sampling_rate){ fprintf (stderr,"Incompatible sampling rates %s (%d Hz) %s (%d Hz)\n", FileName, Audio->sampling_rate, peer->FileName, peer->Audio->sampling_rate); return false; } return true; } if (MpegType == mpeg_VIDEO || MpegType == mpeg_SYSTEM){ if ( (Video->hsize != peer->Video->hsize) || (Video->vsize != peer->Video->vsize)) { fprintf(stderr,"Incompatible size %s [%ldx%ld] %s [%ldx%ld]\n", FileName, Video->hsize,Video->vsize, peer->FileName, peer->Video->hsize, peer->Video->vsize); return false; } if (Video->bitrate != peer->Video->bitrate) { fprintf(stderr,"incompatible video bitrate %s (%ld bps) %s (%ld bps)\n", FileName, Video->bitrate, peer->FileName, peer->Video->bitrate); return false; } if (Video->frame_rate != peer->Video->frame_rate) { fprintf(stderr, "incompatible video frame rate %s (%f fps) %s (%f fps)\n", FileName, Video->frame_rate, peer->FileName, peer->Video->frame_rate); return false; } return true; } // no known file return false; } mpeg::mpeg(const char* filename,int verbosity) : MpegFile(0), Verboseness(verbosity), HasAudio(false), HasVideo(false), composite(false), editable(false), MpegType(mpeg_UNKNOWN), Audio(0), n_audio(0), Video(0), n_video(0), System(0), Transport(0), start_with_id3(false), mpeg_version(1), buffstart(0),buffend(0),buffer(0) { BTRACK; UData=0; SExt=0; DExt=0; // keep track of filename (usefull for debugging) // TODO : only on mpeg_VERBOSE ? FileName = new char[strlen(filename) + 1]; strcpy(FileName , filename); // open infile read-only, binary type (for compatibility with other than POSIX/GNU) MpegFile = fopen(filename, "rb"); #ifdef _DEBUG_ Verboseness = mpeg_VERBOSE; #endif // case unable to open if (MpegFile == 0) { if (Verboseness!=mpeg_SILENT) { printf("Unable to open %s\n",filename); if(Verboseness == mpeg_VERBOSE) perror(filename); } //nothing more to do... return; } // Allocate buffer buffer = new byte[BUFFERSIZE]; // Seek to end of file if (FSEEK(MpegFile, 0, SEEK_END)) { if (Verboseness != mpeg_SILENT) { printf("Unable to seek in file %s\n", filename); if (Verboseness == mpeg_VERBOSE) perror(filename); } //give up.. return; } // File size off_t off_eof = FTELL(MpegFile); if (off_eof == -1) { if (Verboseness != mpeg_SILENT) { printf("Seeking to end of input file %s failed.\n", filename); if (Verboseness == mpeg_VERBOSE) perror(filename); } //give up.. return; } else FileSize = off_eof; // if (Verboseness==mpeg_VERBOSE){ #ifdef _DEBUG_ printf("%s has size " _OFF_d "\n", FileName, FileSize); #endif // } // nothing to do on an empty file if (!FileSize) { if (Verboseness != mpeg_SILENT) { printf("File %s is empty.\n", filename); if (Verboseness == mpeg_VERBOSE) perror(filename); } //give up.. return; } // first determine the file type between audio/video/system if (ParseAudio(0)) { // this is an Audio only mpeg file MpegType = mpeg_AUDIO; composite = false; editable = true; } else if (ParseVideo(0)) { // this is a Video only mpeg file MpegType = mpeg_VIDEO; composite = false; editable = true; } else if (ParseSystem()) { // this is an Audio and Video mpeg file MpegType = mpeg_SYSTEM; } else if (ParseID3()) { //this is an audio file with an ID3 v2 MpegType = mpeg_AUDIO; editable = true; composite = false; } else if (ParseRIFF()) { // this is either a Wave file or a divx or something else editable = false; composite = false; } else if (ParseTransportStream(0)) { // this is a MPEG 2 transport stream MpegType = mpeg_TRANSPORT; editable = false; composite = true; } else { // can not handle this mpeg file if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s is not a valid MPEG file (can't handle it)\n", FileName); } } // mpeg class destructor mpeg::~mpeg() { BTRACK; if (buffer) delete[] buffer; if (MpegFile) fclose(MpegFile); if (Audio) { if (Audio->tag) delete Audio->tag; delete Audio; } if (Video) { if (Video->video_header) delete[] Video->video_header; delete Video; } if (System) { if(System->audio_system_header) delete[] System->audio_system_header; if(System->video_system_header) delete[] System->video_system_header; delete System; } if (SExt) delete SExt; if (DExt) delete DExt; if (UData) { if (UData->ud) delete[] UData->ud; delete UData; } if (Transport) delete Transport; } // map a buffer onto file for efficiency byte mpeg::GetByte(off_t offset) { BTRACK; START_CLOCK; size_t nread; if ((offset >= buffend) || (offset < buffstart)) { // new buffer need (forward) if (FSEEK(MpegFile, offset, SEEK_SET)) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "could not get seek to offset (" _OFF_d ") in file %s (size:" _OFF_d ")\n", offset, FileName, FileSize); RTRACK; ATRACK("GetByte Invalid offset"); fprintf(stderr,"mpgtx: AT EOF - please stop me!\n"); return 0x11; } nread = fread(buffer, 1, BUFFERSIZE, MpegFile); buffstart = offset; buffend = offset + nread; if ((offset >= buffend) || (offset < buffstart)) { // weird if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "could not get offset " _OFF_d " in file %s [" _OFF_x "]\n", offset, FileName, FileSize); RTRACK; ATRACK("GetByte Invalid offset"); fprintf(stderr,"mpgtx: AT EOF - please stop me!\n"); return 0x11; } } STOP_CLOCK(GETBYTE); RTRACK; return buffer[offset - buffstart]; } byte mpeg::Byte(off_t offset){ return GetByte(offset); // because GetByte is inline } // same as above but improved for backward search byte mpeg::bdGetByte(off_t offset){ BTRACK; size_t nread; if ((offset >= buffend) || (offset < buffstart)){ // new buffer needed (backward) off_t start = offset-BUFFERSIZE+1 ; start = start >= 0?start:0; FSEEK(MpegFile, start, SEEK_SET); nread = fread(buffer, 1, BUFFERSIZE, MpegFile); buffstart = start; buffend = start + nread; if ((offset >= buffend) || (offset < buffstart)) { // weird if (Verboseness == mpeg_VERBOSE) fprintf(stderr,"could not get offset " _OFF_x " in file %s [" _OFF_x "]\n", offset, FileName, FileSize); RTRACK; ATRACK("bdGetByte Invalid offset"); return 0x11; } } RTRACK; return buffer[offset - buffstart]; } // make sure the sequence 0x00 00 01 mark // bool mpeg::EnsureMPEG(off_t offset, marker mark){ BTRACK; if (( GetByte(offset) == 0x00 ) && ( GetByte(offset+1) == 0x00 ) && ( GetByte(offset+2) == 0x01 ) && ( GetByte(offset+3) == mark )) return true; else return false; } // get a two byte size (word) // unsigned short int mpeg::GetSize(off_t offset ) { BTRACK; return GetByte(offset)*256 + GetByte(offset+1); } // print ID3v2 tag to stdout // bool mpeg::PrintID3() { BTRACK; // Byte 0-2: ID3v2/file identifier "ID3" if ( (GetByte(0)!='I') || (GetByte(1)!='D') || (GetByte(2)!='3')) return false; // Byte 3-4: ID3v2 version printf(" ID3 v2.%d.%d tag (more info on http://www.id3.org/)\n", GetByte(3), GetByte(4)); printf(" ----------------\n"); // Byte 5: ID3v2 flags (%abcd0000) // Byte 6-9: ID3v2 tag size (4 * %0xxxxxxx) size_t framesize; off_t tagsize; size_t i; tagsize = GetByte(6)<<21; tagsize |= GetByte(7)<<14; tagsize |= GetByte(8)<<7; tagsize |= GetByte(9); #ifdef _DEBUG_ printf("Tag size : " _OFF_d "\n", tagsize); #endif bool handled; off_t offset = 10; while (offset < tagsize+10) { if ((GetByte(offset)<'0') || (GetByte(offset)>'Z')) break; handled = false; framesize = (GetByte(offset+4)<<24) | (GetByte(offset+5)<<16) | (GetByte(offset+6)<<8) | (GetByte(offset+7)); // print tag printf(" %c%c%c%c : ", GetByte(offset), GetByte(offset+1), GetByte(offset+2), GetByte(offset+3)); // T... - all text tags if (GetByte(offset) == 'T') { if (!GetByte(offset+10)) //if text encoding = standard encoding for (i = 1; i < framesize; i++) { printf("%c", GetByte(offset + i + 10)); handled = true; } if (!handled) { printf("(empty)"); handled=true; } } // COMM - Comments tag if ( (GetByte(offset) =='C') && (GetByte(offset+1)=='O') && (GetByte(offset+2)=='M') && (GetByte(offset+3)=='M')) { printf("(lang: %c%c%c) : ", GetByte(offset+11), GetByte(offset+12), GetByte(offset+13)); for (i = 5; i < framesize; i++) { printf("%c", GetByte(offset + i + 10)); handled = true; } if (!handled) { printf("(empty)"); handled=true; } } if (!handled) printf("(skipped)"); printf("\n"); offset += 10 + framesize; } printf(" ----------------\n"); return true; } // check if ID3v2 tag is present and audio follows // bool mpeg::ParseID3(){ BTRACK; if ( (GetByte(0)!='I') || (GetByte(1)!='D') || (GetByte(2)!='3')) return false; start_with_id3 = true; // get tag size size_t tagsize=0; tagsize = GetByte(6)<<21; tagsize |= GetByte(7)<<14; tagsize |= GetByte(8)<<7; tagsize |= GetByte(9); return ParseAudio(tagsize + 10); } // Parses Audio header returns false on not audio // bool mpeg::ParseAudio(off_t myoffset) { BTRACK; HasAudio = false; bool mpeg2_5 = false; int i; // ensure that two first bytes are FFFx // TODO: give it a chance and search for a valid start after the beginning // even if most audio players will refuse to play such a file if ((GetByte(myoffset+0)!=0xFF)||((GetByte(myoffset+1) & 0xF0)!=0xF0)) { // doesn't start with 12 bits set if ((GetByte(myoffset+0)!=0xFF)||((GetByte(myoffset+1) & 0xE0)!=0xE0)) { // doesn't start with 11 bits set return false; } else { // start with 11 bits set mpeg2_5 = true; } } // seems to be audio, let's allocate the struct Audio=new mpgtx_audio; Audio->tag=0; Audio->first_frame_offset=myoffset; // Find mpeg version 1.0 or 2.0 if(GetByte(myoffset + 1) & 0x08) { if (!mpeg2_5) Audio->mpeg_ver = 1; else return false; // invalid 01 encountered } else { if (!mpeg2_5) Audio->mpeg_ver = 2; else Audio->mpeg_ver = 3; //for mpeg 2.5 } // Find Layer Audio->layer = (GetByte(myoffset + 1) & 0x06)>>1; switch(Audio->layer) { case 0: Audio->layer=-1; return false; case 1: Audio->layer=3; break; case 2: Audio->layer=2; break; case 3: Audio->layer=1; break; } // Protection Bit Audio->protect = GetByte(myoffset + 1) & 0x01; if (Audio->protect) Audio->protect = 0; else Audio->protect = 1; // Bitrate index and sampling index to pass through the array int bitrate_index = GetByte(myoffset+2)>>4; int sampling_index = (GetByte(myoffset+2)&0x0f)>>2; if (sampling_index >= 3) return false; if (bitrate_index == 15) return false; Audio->bitrate = mpeg_bitrate_index[Audio->mpeg_ver-1][Audio->layer-1][bitrate_index]; Audio->byte_rate = (float)((Audio->bitrate*1000)/8.0); Audio->sampling_rate = mpeg_sampling_index[Audio->mpeg_ver-1][sampling_index]; // Padding bit if (GetByte(myoffset+2)&0x02) Audio->padding = 1; else Audio->padding = 0; // Audio mode Audio->mode=GetByte(myoffset+3)>>6; if (Audio->mode==1) Audio->modext=(GetByte(myoffset+3)>>4)&0x03; else Audio->modext=-1; // Copyright bit if(GetByte(myoffset+3)&0x08) Audio->copyright=true; else Audio->copyright=false; // Original/Copy bit if(GetByte(myoffset+3)&0x04) Audio->original=true; else Audio->original=false; // emphasis index Audio->emphasis_index=GetByte(myoffset+3)&0x03; // Frame Length if (Audio->mpeg_ver == 1) { if (Audio->layer == 1) Audio->frame_length = int((48000.0*Audio->bitrate)/Audio->sampling_rate) + 4*Audio->padding; else Audio->frame_length = int((144000.0*Audio->bitrate)/Audio->sampling_rate) + Audio->padding; } else if (Audio->mpeg_ver == 2) { if (Audio->layer == 1) Audio->frame_length = int((24000.0*Audio->bitrate)/Audio->sampling_rate) +4*Audio->padding; else Audio->frame_length = int((72000.0*Audio->bitrate)/Audio->sampling_rate) +Audio->padding; } else { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Audio mpeg file layer invalid : " "%d (should be 1 or 2)\n", FileName,Audio->mpeg_ver); return false; } // size of CRC if (Audio->protect) Audio->frame_length += 2; //Audio->frame_length += 4; // size of standard header // let's get the id3 tag if present. if ( GetByte(FileSize-128) == 'T' && GetByte(FileSize-127) == 'A' && GetByte(FileSize-126) == 'G') { FSEEK(MpegFile, FileSize-125, SEEK_SET); Audio->tag = new id3; fread(Audio->tag, 1, sizeof(id3), MpegFile); FileSize -= 128; //empty unused fields bool keep_it=false; for ( i=0; i<30;i++) { if (Audio->tag->name[i] != ' ') { if (Audio->tag->name[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->name[0] = 0; keep_it = false; for ( i=0; i<30;i++){ if (Audio->tag->artist[i] != ' ') { if (Audio->tag->artist[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->artist[0] = 0; keep_it = false; for ( i=0; i<30;i++) { if (Audio->tag->album[i] != ' ') { if (Audio->tag->album[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->album[0] = 0; keep_it = false; for ( i=0; i<4;i++){ if (Audio->tag->year[i] != ' ') { if (Audio->tag->year[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->year[0] = 0; keep_it = false; for ( i=0; i<30;i++) { if (Audio->tag->comment[i] != ' '){ if (Audio->tag->comment[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->comment[0] = 0; } Audio->duration = ((FileSize*1.0)/Audio->bitrate)*0.008; HasAudio = true; // fprintf(stderr, "found audio.\n"); return true; } //Parses Video header returns false on not video bool mpeg::ParseVideo(off_t myoffset){ BTRACK; // the MPEG video file should start with // the video start sequence, if not exit. // TODO: give it a chance and seek a video start elsewhere if(!EnsureMPEG(myoffset, 0xB3)) return false; off_t header_start=myoffset; // seems to be video okay, let's allocate the struct Video = new mpgtx_video; Video->video_header = 0; // Get vertical and horizontal picture sizes myoffset += 4; // after video sequence code Video->hsize = GetSize(myoffset) >> 4; Video->vsize = GetSize(myoffset+1) & 0x0FFF; // Get picture rate myoffset += 3; // after picture sizes int frame_rate_index = GetByte(myoffset) & 0x0F; if (frame_rate_index > 8) { // invalid frame rate index if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "Invalid frame rate index in file %s : %d\n", FileName, frame_rate_index); Video->frame_rate = 0.0; } else Video->frame_rate = mpeg_frame_rate_index[frame_rate_index]; Video->aspect_ratio = (GetByte(myoffset) & 0xF0) >>4; if (!Video->aspect_ratio) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "Invalid aspect ratio in file %s : %d\n", FileName, Video->aspect_ratio); } //Get Bitrate for duration estimation myoffset += 1; // after picture rate // 18 following bytes are the bitrate /400 //read first 16 bytes Video->bitrate = GetSize(myoffset); // scale Video->bitrate <<= 2; byte lasttwo = GetByte(myoffset + 2); lasttwo >>= 6; Video->bitrate |= lasttwo; //Given bitrate and FileSize, compute an estimation of the duration. Video->duration = (FileSize*8.0) / (Video->bitrate*400); //////////// Begin changes marker mymark; while (true) { myoffset = FindNextMarker(myoffset, &mymark); if (mymark == 0xB8) break; switch (GetByte(myoffset + 3)) { case 0xB5 : ParseExtension(myoffset); break; case 0xB2 : #ifdef _DEBUG_ printf("user data start code found\n"); #endif ParseUserData(myoffset); break; } myoffset++; } ///////////// end changes //Okay let's save the video sequence header somewhere // find first GOP after video sequence header off_t header_end = FindNextMarker(myoffset, 0xB8); Video->first_gop_offset = header_end; // did we find header end or are we lost in cyberspace? if (header_end < 0){ //could not find first GOP if(Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: could not find first GOP after Video Sequence start [" _OFF_x " (decimal)]\n", FileName, header_start); return false; } // okay we have header boundaries, let's fill the appropriate // field. Video->video_header_size = header_end - header_start; Video->video_header = new byte[Video->video_header_size]; // fprintf(stderr,"philipp found header: 0x%qx 0x%qx\n", header_end, header_start); FSEEK(MpegFile, header_start, SEEK_SET); if(fread(Video->video_header, Video->video_header_size, 1, MpegFile) != 1) { // couldn't read video header if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Found video header but couldn't read it [" _OFF_x "-" _OFF_x "]\n", FileName, header_start, header_end); return false; } HasVideo = true; return true; } //Parses System header returns false on not system bool mpeg::ParseSystem() { BTRACK; off_t offset = 0; off_t PACKlength = 0; unsigned short packetsize; byte packettype; int found = 0; // the MPEG system file should start with // the video start sequence, if not exit. // TODO: give it a chance and seek a PACK elsewhere // try to skip any zeros at mpeg start (some begin with a BUNCH of zeros while(GetByte(offset)== 0x00) offset ++; //here we're on the first non null byte let's get back to leave two zeros (packet start code) offset -=2; if (offset != 0) { // we actually skipped some zeroes fprintf(stderr,"Skipped " _OFF_d " zeroes at start of file\n",offset); } if (!EnsureMPEG(offset, 0xBA)){ //this file does not begin with a pack! fprintf(stderr,"mmm, this file does not start with a pack, offset: " _OFF_d " \n",offset); fprintf(stderr,"use the desperate_mode switch as the first option -X to search for a header in the whole file!\n"); fprintf(stderr,"if you want to force the operation. May yield to an endless loop if no valid header is found!\n"); if (GetByte(offset+2) != 0x01) { fprintf(stderr,"Does not even begin with a 00 00 01 xx sequence!\n"); // does not even begin with a 00 00 01 xx sequence ! if (desperate_mode) { // philipp tries here to search further .... offset +=3; while (found == 0) { if (print_progress) { fprintf(stderr,"Searching for a mpeg signature:\n"); fprintf(stderr,"Searching for 0x00 at offset: "); } while (GetByte(offset) != 0x00) { if (print_progress) fprintf (stderr,"\b\b\b\b\b\b\b\b\b\b%10qd", offset); offset++; } if (print_progress) fprintf(stderr,"\nSearching for != 0x00 at offset: "); while (GetByte(offset) == 0x00) { offset++; if (print_progress) fprintf (stderr,"\b\b\b\b\b\b\b\b\b\b%10qd", offset); } // now from the beginning .. offset -=2; if (!EnsureMPEG(offset, 0xBA)){ if (print_progress) fprintf(stderr,"\nno success......\n"); offset += 3; } else { fprintf(stderr,"\nsuccess! at " _OFF_d " \n",offset); found = 1; fprintf(stderr,"I dont know which kind of crazy header you have put into this file!\n"); if (!preserve_header) { fprintf(stderr,"But I will assume this is ok. If you split or join this file, it will be discarded\n"); } else { fprintf(stderr,"But I will assume this is ok. And if you split this file, it will be inserted\n"); } fprintf(stderr,"Before any segment. This movie maybe wil not play with quicktime, use Videolan instead\n"); fprintf(stderr,"If you dont want this, please correct the file, so its start with a valid Pack!\n"); } } } if (found == 0) { fprintf(stderr,"\nNo success at all.\n"); return false; } } } // allocate necessary space System = new mpgtx_system; System->audio_system_header = 0; System->video_system_header = 0; System->first_video_packet = 0; // tries to find the two system packets and store them bool keep_going = true; marker mark = 0; // fprintf(stderr, "Philipp: Searching for system packets (audio, video).\n"); while (keep_going) { // fprintf(stderr,"philipp: offset4 ?: 0x%qx\n",offset); offset = FindNextMarker(offset, &mark); // fprintf(stderr,"philipp: offset5 ?: 0x%qx\n",offset); // if error exit if (offset == -1) { fprintf(stderr, "offset error (-1)\n"); break; } // if this is a Video or Audio packet we're done with system if ((mark == VideoPkt) || (mark == AudioPkt)) break; // if this is a padding packet if (mark == PaddingPkt) { offset += GetSize(offset + 4); continue; } // if this is a PACK if (mark==0xBA) { System->muxrate = ReadPACKMuxRate(offset + 4); //standard pack length offset += 12; continue; } //Hey no more guess... if (mark != SystemPkt) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Unhandled packet encountered (%x @" _OFF_x ") while seeking system headers\n", FileName, mark, offset); offset += 4; continue; } // it has to be a system packet // March 27 changed because of variable length PACK in mpeg 2 // are we lost? // fprintf(stderr,"philipp: offset3 ?: 0x%qx\n",offset); off_t startofpack = bdFindNextMarker(offset, 0xBA); // fprintf(stderr,"philipp: offset2 ?: 0x%qx\n",offset); if (startofpack !=-1){ //found a PACK before system packet, compute its size (mpeg1 != mpeg2) if ((GetByte(startofpack + 4) & 0xF0) == 0x20) { // standard mpeg1 pack PACKlength=12; } else { if ((GetByte(startofpack + 4) & 0xC0) == 0x40){ // new mpeg2 pack : 14 bytes + stuffing PACKlength = 14 + (GetByte(startofpack + 13) & 0x07); } else{ // wazup? fprintf(stderr, "Weird PACK encountered\n"); PACKlength = 12; } } } if ((startofpack == -1) || (startofpack + PACKlength != offset)) { // we're probably lost fprintf(stderr, "%s: System Packet not preceded by a PACK [" _OFF_x "] start of pack : " _OFF_x " PACKlength : " _OFF_x " I'll probably crash but I love risk\n", FileName, offset,startofpack,PACKlength); startofpack=offset; // keep going anyway return false; } // end of modif. ParseSystemPacket(offset,startofpack); packetsize = GetSize(offset + 4); // to size field packettype = GetByte(offset + 12); // to ccode field if (GetByte(offset + 15) == AudioPkt || GetByte(offset + 15) == VideoPkt) { // system packet with both audio and vid infos packettype = VideoPkt; // since video is mandatory } if (packettype == AudioPkt){ if (System->audio_system_header != 0){ if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Warning two or more audio sys header encountered [" _OFF_x "]\n", FileName, offset); delete[] System->audio_system_header; } System->audio_system_header_length = PACKlength + 4 + 2 + packetsize; System->audio_system_header = new byte [System->audio_system_header_length]; FSEEK(MpegFile, offset-PACKlength, SEEK_SET); fread( System->audio_system_header, System->audio_system_header_length, 1, MpegFile); } else if (packettype == VideoPkt) { if (System->video_system_header != 0) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Warning two or more video sys header encountered [" _OFF_x "]\n", FileName, offset); delete[] System->video_system_header; } // does this video packet begin System->video_system_header_length = PACKlength + 4 + 2 + packetsize; System->video_system_header = new byte [System->video_system_header_length]; // keep track of the initial timestamp if (PACKlength == 12) { #ifdef _DEBUG_ fprintf(stderr,"Now read mpeg initial_TS at [" _OFF_x "] \n",offset - PACKlength); fprintf(stderr,"Should all TS be printed? [n/y]:"); if (getchar() == 'y') print_all_ts(0xba); while(getchar() != '\n') ; #endif System->initial_TS = ReadTS(offset - PACKlength); mpeg2found = 0; } else { // off_t firstmpeg2gop = FindNextMarker(1, 0xB8); #ifdef _DEBUG_ fprintf(stderr,"Now read mpeg2 initial_TS at [" _OFF_x "] \n",offset - PACKlength); fprintf(stderr,"Should all TS be printed? [n/y]:"); if (getchar() == 'y') print_all_ts(0xba); while(getchar() != '\n') ; #endif mpeg2found = 1; // System->initial_TS = ReadTSMpeg2(firstmpeg2gop + 4); System->initial_TS = ReadTSMpeg2(offset - PACKlength); } FSEEK(MpegFile, (offset - PACKlength), SEEK_SET); fread( System->video_system_header, System->video_system_header_length, 1, MpegFile); } else { if (Verboseness==mpeg_VERBOSE) fprintf(stderr, "%s: Unknown system packet %x [" _OFF_x "]\n", FileName, packettype, offset); } offset += 4; } //okay this is a miracle but we have what we wanted here. // hey wait! are we really okay? if (!System->video_system_header) { //GOSH! we don't have video here! if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any video system header in this mpeg system file\n", FileName); // return false; fprintf(stderr, "warning: couldn't find any valid system header. I'm continuing anyway\n"); } // let's go on and find audio and video infos // Video! offset = FindNextMarker(0, 0xB3); // fprintf(stderr,"philipp: offset1 ?: 0x%qx\n",offset); if (offset == -1) { //couldn't find any valid video if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any video sequence header in this mpeg system file\n", FileName); return false; } // mkay, we have the video sequence header if (!ParseVideo(offset)) { return false; } off_t xB3_offset = offset; // now get the pack and the packet header just before the video sequence offset = bdFindNextMarker(offset, 0xBA); if (offset == -1) { //couldn't find any PACK before... if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any PACK before video sequence\n", FileName); return false; } // May 2, PACK don't necessarily precede video sequence! off_t start_of_vid_packet = bdFindNextMarker(xB3_offset, 0xE0); // start of packet off_t offset2 = bdFindNextMarker(start_of_vid_packet-1, &mark); if (offset != offset2) { // the packet that precedes video sequence is not a PACK offset = start_of_vid_packet; } else { // end May 2 // March 27 compute pack length if ((GetByte(offset + 4) & 0xF0) == 0x20) { //standard mpeg1 pack PACKlength = 12; } else { if ((GetByte(offset + 4) & 0xC0) == 0x40) { //new mpeg2 pack : 14 bytes + stuffing PACKlength = 14 + (GetByte(offset + 13) & 0x07); } else { //wazup? fprintf(stderr,"Weird PACK encountered\n"); PACKlength = 12; } } // end March 27 // May 2 } //end May 2 // okay let's save this... System->first_video_packet = new byte[xB3_offset-offset]; System->first_video_packet_length = xB3_offset-offset; readHeader(MpegFile,offset,1); // save this if needed for later FSEEK(MpegFile,offset,SEEK_SET); fread(System->first_video_packet, 1, xB3_offset-offset, MpegFile); // Now look for an audio packet if necessary HasAudio = false; offset = FindNextMarker(0, AudioPkt); if ((offset == -1) || (offset > FileSize - 15)) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any audio packet in this mpeg system file\n",FileName); } else { // we assume that we are on the first audio packet... offset = SkipPacketHeader(offset); if (!ParseAudio(offset)) { //mmm audio packet doesn't begin with FFF while ((offsetinitial_TS; if (HasVideo) Video->duration = duration; if (HasAudio) Audio->duration = duration; //okay okay this is redundant return true; } // print mpeg infos on stdout void mpeg::PrintInfos() { BTRACK; char HMS[30]; if (MpegType == mpeg_AUDIO){ SecsToHMS(HMS, Audio->duration); printf("%s\n", FileName); if (Audio->mpeg_ver != 3) printf(" Audio : Mpeg %d layer %d\n", Audio->mpeg_ver,Audio->layer); else printf(" Audio : Mpeg 2.5 (rare) layer %d\n", Audio->layer); printf(" Estimated Duration: %s\n", HMS); if (Audio->bitrate) { printf(" %d kbps %d Hz\n", Audio->bitrate,Audio->sampling_rate); printf(" Frame size: %d bytes\n", Audio->frame_length); } else { printf(" free bitrate %d Hz (this file is currently unsplitable)\n",Audio->sampling_rate); } switch (Audio->mode) { case 0: printf(" Stereo,"); break; case 1: printf(" Joint Stereo: "); if (Audio->layer==1 || Audio->layer==2) { switch (Audio->modext) { case 0: printf("(Intensity stereo on bands 4-31/32)\n"); break; case 1: printf("(Intensity stereo on bands 8-31/32)\n"); break; case 2: printf("(Intensity stereo on bands 12-31/32)\n"); break; case 3: printf("(Intensity stereo on bands 16-31/32)\n"); break; } } else { // mp3 switch (Audio->modext){ case 0: printf("(Intensity stereo off, M/S stereo off)\n"); break; case 1: printf("(Intensity stereo on, M/S stereo off)\n"); break; case 2: printf("(Intensity stereo off, M/S stereo on)\n"); break; case 3: printf("(Intensity stereo on, M/S stereo on)\n"); break; } } break; case 2: printf(" Dual Channel,"); break; case 3: printf(" Mono,"); break; } switch (Audio->emphasis_index){ case 0: printf(" No emphasis,"); break; case 1: printf(" Emphasis: 50/15 microsecs,"); break; case 2: printf(" Emphasis Unknown,"); break; case 3: printf(" Emphasis CCITT J 17,"); break; } if (Audio->copyright) printf(" (c),"); if (Audio->original) printf(" original\n"); else printf(" copy\n"); if (Audio->tag) { //print id3v1 tag---------------- if (Audio->tag->comment[28] == 0) printf (" ID3 v1.1 tag\n ----------------\n"); else printf(" ID3 v1.0 tag\n ----------------\n"); if (Audio->tag->name[0]) printf(" title : %.30s\n", Audio->tag->name); if (Audio->tag->artist[0]) printf(" artist : %.30s\n", Audio->tag->artist); if (Audio->tag->album[0]) { printf(" album : %.30s\n", Audio->tag->album); if(Audio->tag->comment[28]==0) printf(" track : %d\n", Audio->tag->comment[29]); } if (Audio->tag->year[0]) printf(" year : %.4s\n", Audio->tag->year); if (Audio->tag->comment[0]) printf(" comment : %.30s\n", Audio->tag->comment); if (Audio->tag->genre < MAX_ID3_GENRE) printf(" genre : %s\n", genre[Audio->tag->genre]); printf(" ----------------\n"); } if (start_with_id3) PrintID3(); printf("\n"); return; } if (MpegType == mpeg_VIDEO) { SecsToHMS(HMS, Video->duration); printf("%s\n", FileName); printf(" Mpeg %d Video File\n Estimated Duration: %s\n", mpeg_version, HMS); switch(Video->aspect_ratio) { case 0: printf(" Invalid aspect ratio (forbidden)\n"); break; case 1: printf(" Aspect ratio 1/1 (VGA)\n"); break; case 2: printf(" Aspect ratio 4/3 (TV)\n"); break; case 3: printf(" Aspect ratio 16/9 (large TV)\n"); break; case 4: printf(" Aspect ratio 2.21/1 (Cinema)\n"); break; #ifdef _DEBUG_ default: printf(" Invalid Aspect ratio (reserved)\n"); #endif } if (SExt) { if (SExt->progressive) printf(" Not interlaced, chroma format: "); else printf(" Interlaced, chroma format: "); switch (SExt->chroma_format) { case 1 : printf ("4:2:0\n"); break; case 2 : printf ("4:2:2\n"); break; case 3 : printf ("4:4:4\n"); break; } } if (DExt){ switch (DExt->video_format) { case 0 : printf (" Video Format: Component\n"); break; case 1 : printf (" Video Format: PAL\n"); break; case 2 : printf (" Video Format: NTSC\n"); break; case 3 : printf (" Video Format: SECAM\n"); break; case 4 : printf (" Video Format: MAC\n"); break; case 5 : printf (" Video Format: Unspecified\n"); break; } if ( (DExt->h_display_size != Video->hsize) || (DExt->v_display_size != Video->vsize)) printf(" Display Size [%ld x %ld]\n", DExt->h_display_size, DExt->v_display_size); } printf(" Size [%ld x %ld] %0.2f fps %.2f Mbps\n", Video->hsize,Video->vsize, Video->frame_rate, Video->bitrate/2500.0); if (UData) printf("\nUser Data:\n------------\n%s------------\n\n",UData->ud); return; } if (MpegType == mpeg_SYSTEM ) { if (composite) { printf(" Mpeg System File [%d Video/ %d Audio]\n", n_video,n_audio); } else { if (HasVideo) { SecsToHMS(HMS, Video->duration); printf("%s\n", FileName); if (mpeg_version == 1) { printf(" Mpeg 1 System File [Video"); } else { // TODO: [es] What is this if-clause for? if (mpeg_version!=2); printf(" Mpeg 2 Program Stream File [Video"); } if (HasAudio) printf("/Audio]\n"); else printf("]\n"); printf(" Muxrate : %.2f Mbps\n", (System->muxrate * 8.0) / 1000000); printf(" Estimated Duration: %s\n", HMS); if (print_progress) { // do time stamps continuing increase? int tlbreaks = 0; printf(" Checking all time stamps (This may take a while.) ...\n"); if ( (tlbreaks = CheckTimeline(0xBA)) ) { printf(" Time line is interupted at %d times.\n",tlbreaks); printf(" That means at these points the time stamp is earlier than the previous one.\n"); printf(" You may have problems in joining and splitting this file, sorry.\n"); } else printf(" Time line seems to be ok.\n"); } switch (Video->aspect_ratio) { case 0: printf(" Invalid aspect ratio (forbidden)\n"); break; case 1: printf(" Aspect ratio 1/1 (VGA)\n"); break; case 2: printf(" Aspect ratio 4/3 (TV)\n"); break; case 3: printf(" Aspect ratio 16/9 (large TV)\n"); break; case 4: printf(" Aspect ratio 2.21/1 (Cinema)\n"); break; #ifdef _DEBUG_ default: printf(" Invalid Aspect ratio (reserved)\n"); #endif } if (SExt){ if (SExt->progressive) printf(" Not interlaced, chroma format: "); else printf(" Interlaced, chroma format: "); switch (SExt->chroma_format){ case 1 : printf ("4:2:0\n");break; case 2 : printf ("4:2:2\n");break; case 3 : printf ("4:4:4\n");break; } } if (DExt){ switch(DExt->video_format){ case 0 : printf (" Video Format: Component\n");break; case 1 : printf (" Video Format: PAL\n");break; case 2 : printf (" Video Format: NTSC\n");break; case 3 : printf (" Video Format: SECAM\n");break; case 4 : printf (" Video Format: MAC\n");break; case 5 : printf (" Video Format: Unspecified\n");break; } if ((DExt->h_display_size != Video->hsize)|| (DExt->v_display_size != Video->vsize)) printf(" Display Size [%ld x %ld]\n", DExt->h_display_size,DExt->v_display_size); } printf(" Size [%ld x %ld] %0.2f fps %.2f Mbps\n", Video->hsize,Video->vsize, Video->frame_rate, (Video->bitrate/2500.0)); } if(UData) printf("\nUser Data:\n------------\n%s------------\n\n",UData->ud); if (HasAudio){ if (Audio->mpeg_ver !=3) printf(" Audio : Mpeg %d layer %d\n",Audio->mpeg_ver,Audio->layer); else printf(" Audio : Mpeg 2.5 (rare) layer %d\n",Audio->layer); if (Audio->bitrate) printf(" %d kbps %d Hz\n",Audio->bitrate,Audio->sampling_rate); else printf(" free bitrate %d Hz\n",Audio->sampling_rate); switch (Audio->mode){ case 0: printf(" Stereo,"); break; case 1: printf(" Joint Stereo: "); if (Audio->layer==1 || Audio->layer==2){ switch (Audio->modext){ case 0: printf("(Intensity stereo on bands 4-31/32)\n"); break; case 1: printf("(Intensity stereo on bands 8-31/32)\n"); break; case 2: printf("(Intensity stereo on bands 12-31/32)\n"); break; case 3: printf("(Intensity stereo on bands 16-31/32)\n"); break; } } else { //mp3 switch (Audio->modext){ case 0: printf("(Intensity stereo off, M/S stereo off)\n"); break; case 1: printf("(Intensity stereo on, M/S stereo off)\n"); break; case 2: printf("(Intensity stereo off, M/S stereo on)\n"); break; case 3: printf("(Intensity stereo on, M/S stereo on)\n"); break; } } break; case 2: printf(" Dual Channel,"); break; case 3: printf(" Mono,"); break; } switch (Audio->emphasis_index){ case 0: printf(" No emphasis\n"); break; case 1: printf(" Emphasis: 50/15 microsecs\n"); break; case 2: printf(" Emphasis Unknown\n"); break; case 3: printf(" Emphasis CCITT J 17\n"); break; } } } return; } if (MpegType== mpeg_TRANSPORT){ printf("%s\n",FileName); if (!Transport) { fprintf(stdout," Invalid MPEG 2 Transport Stream\n"); return; } Transport->PrintInfos(); return; } printf("%s can not be handled by this program\n",FileName); return; } //PrintInfos // convert a time in second to HH:mm:ss notation // void mpeg::SecsToHMS(char* HMS, float duration){ BTRACK; byte hours = (byte)(duration / 3600); byte mins = (byte)((duration / 60) - (hours * 60)); float secs = duration - 60 * mins - 3600 * hours; if (hours != 0) { sprintf (HMS,"%02d:%02d:%05.2fs",hours,mins,secs); return; } if (mins != 0) { sprintf(HMS,"%02d:%05.2fs",mins,secs); return; } sprintf(HMS,"%05.2fs",secs); } // find next 0x 00 00 01 xx sequence, returns offset or -1 on err // off_t mpeg::FindNextMarker(off_t from){ BTRACK; off_t offset; for (offset = from; offset < (FileSize - 4); offset++) { if ( (GetByte(offset + 0) == 0x00) && (GetByte(offset + 1) == 0x00) && (GetByte(offset + 2) == 0x01)) { RTRACK; return offset; } } RTRACK; return -1; } // find next 0x 00 00 01 xx sequence, returns offset or -1 on err and // change mark to xx // off_t mpeg::FindNextMarker(off_t from, marker* mark){ BTRACK; off_t offset = FindNextMarker(from); if (offset >= 0) { *mark = GetByte(offset + 3); RTRACK; return offset; } else { RTRACK; return -1; } } // find next 0X00 00 01 mark // off_t mpeg::FindNextMarker(off_t from, marker mark){ BTRACK; off_t offset = from; while(offset >= 0){ offset = FindNextMarker(offset); if (offset == -1) { RTRACK; return -1; } if (EnsureMPEG(offset, mark)) { RTRACK; return offset; } else offset++; } //shouldn't be here RTRACK; return -1; } // same as above but optimized for backward search // off_t mpeg::bdFindNextMarker(off_t from, marker mark) { BTRACK; off_t offset; for( offset = from; offset >= 0; offset--) { if( (bdGetByte(offset) == 0x00) && (bdGetByte(offset+1) == 0x00) && (bdGetByte(offset+2) == 0x01) && (bdGetByte(offset+3) == mark)) { RTRACK; return offset; } } RTRACK; return -1; } off_t mpeg::bdFindNextMarker(off_t from, marker* mark) { BTRACK; off_t offset; for (offset = from; offset >= 0; offset--) { if ( (bdGetByte(offset) ==0x00) && (bdGetByte(offset+1)==0x00) && (bdGetByte(offset+2)==0x01)) { *mark=bdGetByte(offset+3); RTRACK; return offset; } } RTRACK; return -1; } // read Time Stamp at given offset // NOTE: The guys at MPEG are really mad. // look at what we have to do to get a timestamp :/ double mpeg::ReadTS(off_t offset) { BTRACK; byte highbit; unsigned long low4Bytes; double TS; #ifdef _DEBUG_ // fprintf(stderr,"Offset: [" _OFF_x "] The bytes...: %2x %2x %2x %2x %2x\n",offset,GetByte(offset + 0),GetByte(offset + 1),GetByte(offset + 2),GetByte(offset + 3),GetByte(offset + 4) ); #endif highbit = (GetByte(offset) >> 3) & 0x01; low4Bytes = ((GetByte(offset) >> 1) & 0x03) << 30; low4Bytes |= GetByte(offset + 1) << 22; low4Bytes |= (GetByte(offset + 2) >> 1) << 15; low4Bytes |= GetByte(offset + 3) << 7; low4Bytes |= GetByte(offset + 4) >> 1; #define FLOAT_0x10000 (double)((unsigned long)1 << 16) #define STD_SYSTEM_CLOCK_FREQ (unsigned long)90000 TS = (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000); TS += (double)(low4Bytes); TS /= (double)(STD_SYSTEM_CLOCK_FREQ); #ifdef _DEBUG_ // printf("read TS : %lf, base : 0x%d,%032lx\n",TS,highbit,low4Bytes); #endif return TS; } double mpeg::ReadTSMpeg2(off_t offset){ BTRACK; byte highbit; unsigned long low4Bytes; unsigned long sys_clock_ref; double TS; #ifdef _DEBUG_ // fprintf(stderr,"Offset: [" _OFF_x "] The bytes...: %2x %2x %2x %2x %2x %2x",offset,GetByte(offset + 0),GetByte(offset + 1),GetByte(offset + 2),GetByte(offset + 3),GetByte(offset + 4),GetByte(offset + 5) ); #endif highbit = (GetByte(offset)&0x20)>>5; low4Bytes = ((GetByte(offset) & 0x18) >> 3) << 30; low4Bytes |= (GetByte(offset) & 0x03) << 28; low4Bytes |= GetByte(offset + 1 ) << 20; low4Bytes |= (GetByte(offset + 2 ) & 0xF8) << 12; low4Bytes |= (GetByte(offset + 2 ) & 0x03) << 13; low4Bytes |= GetByte(offset + 3 ) << 5; low4Bytes |= (GetByte(offset + 4 )) >> 3; sys_clock_ref=(GetByte(offset + 4) & 0x3) << 7; sys_clock_ref|=(GetByte(offset + 5) >> 1); TS = (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000); TS += (double)(low4Bytes); if (sys_clock_ref ==0) TS /= (double)(STD_SYSTEM_CLOCK_FREQ); else { // this is what I understood... CHECK // if not zero, then we have a 27 MHz accuracy with a max of 27 MHz // so clockfreq might well be 27MHz / sys_clock_ref // nonsense: TS /= (double)(27000000 / sys_clock_ref); TS /= (double)(STD_SYSTEM_CLOCK_FREQ); } //debug #ifdef _DEBUG_ // printf("read TS2 : %lf, base : 0x%d,%032lx ref : %016lx\n",TS,highbit,low4Bytes,sys_clock_ref); #endif return TS; } off_t mpeg::SkipPacketHeader(off_t myoffset){ BTRACK; byte mybyte; if (mpeg_version == 1) { // skip startcode and packet size myoffset += 6; //remove stuffing bytes mybyte = GetByte(myoffset); while (mybyte & 0x80) mybyte = GetByte(++myoffset); if ((mybyte & 0xC0) == 0x40) // next two bits are 01 myoffset += 2; mybyte=GetByte(myoffset); if ((mybyte & 0xF0) == 0x20) myoffset += 5; else if ((mybyte & 0xF0) == 0x30) myoffset += 10; else myoffset++; return myoffset; } else if (mpeg_version==2) { // this is a PES, easyer // offset + 9 is the header length (-9) return (myoffset + 9 +GetByte(myoffset + 8)); } else return (myoffset + 10); } bool mpeg::ParseSystemPacket(off_t startofpacket, off_t startofpack){ BTRACK; int size = Read2Bytes(startofpacket + 4); int i; byte code; size -= 6; //TODO check if there's already a system packet if ((size%3) != 0) return false; #ifdef _DEBUG_ else printf("%d streams found\n", size/3); #endif for (i=0; i < size/3; i++) { code = GetByte(startofpacket + 12 + i * 3); #ifdef _DEBUG_ printf("%02x ",code); #endif if ((code&0xF0)==0xC0) n_audio++; else if ((code&0xF0)==0xE0 || (code & 0xF0)==0xD0) n_video++; } if (n_audio) { HasAudio = true; if (n_audio > 1) { composite = true; editable = false; } } if (n_video) { HasVideo = true; if (n_video > 1){ composite = true; editable = false; } } #ifdef _DEBUG_ printf("\n audio %d video %d \n",n_audio,n_video); #endif return true; } void mpeg::ParseFramesInGOP(off_t offset){ BTRACK; int pict_ref; int pict_type; char type; marker mark; off_t off = offset + 1; off = FindNextMarker(off , &mark); while (off > 0) { switch (mark) { case 0xB8 : printf("GOP ends at [" _OFF_x "]\n",off); return; case 0x00 : //picture pict_ref=(GetByte(off+4)<<2); pict_ref |= ((GetByte(off+5)&0xC0)>>6); pict_type = ((GetByte(off+5)&0x38)>>3); switch (pict_type){ case 1: type ='I';break; case 2: type ='P';break; case 3: type ='B';break; default:type ='U';break; } printf("\n\n%c (%.2d) [" _OFF_x "]\n", type, pict_ref, off); break; case 0xba: printf(" PACK [" _OFF_x "]\n", off); break; case VideoPkt: printf(" Video [" _OFF_x "]\n", off); break; case AudioPkt: printf(" Audio [" _OFF_x "]\n", off); break; case PaddingPkt: printf(" Padding [" _OFF_x "]\n", off); break; } off++; off=FindNextMarker(off,&mark); } } bool mpeg::ParseExtension(off_t myoffset) { BTRACK; myoffset+=4; switch (GetByte(myoffset) >> 4) { case 1: return ParseSequenceExt(myoffset); case 2: return ParseSequenceDisplayExt(myoffset); } return false; } bool mpeg::ParseUserData(off_t myoffset) { BTRACK; off_t end = FindNextMarker(myoffset + 1); off_t i; bool allprintable=true; byte car; off_t mysize = end - myoffset - 4; if (mysize <= 0) return false; for (i = myoffset+4 ; i < end; i++) { car=GetByte(i); if ((car < 0x20) && (car != 0x0A) && (car != 0x0D)) { allprintable = false; break; } } if (allprintable) { if (!UData) { UData = new user_data; UData->ud = new char[1]; UData->ud[0] = 0; UData->ud_length = 1; } char* temp = new char[mysize+UData->ud_length+1]; //1 is for \n //copy all until \0 for ( i=0; i < UData->ud_length-1; i++){ temp[i] = UData->ud[i]; } //okay now copy the new string for ( i=0; i < mysize; i++){ temp[i + UData->ud_length -1] = GetByte(myoffset + 4 + i); } temp[UData->ud_length- 1 + mysize] = '\n'; temp[UData->ud_length + mysize] = '\0'; UData->ud_length += mysize + 1; delete[] UData->ud; UData->ud = temp; } return true; } bool mpeg::ParseSequenceExt(off_t myoffset) { BTRACK; unsigned long hsize; unsigned long vsize; unsigned long bitrate; // We are an mpeg 2 file mpeg_version=2; if (!SExt) SExt = new sequence_ext; //13TH if (GetByte(myoffset + 1) & 0x08) SExt->progressive = true; SExt->chroma_format = (GetByte(myoffset + 1) & 0x06) >> 1; hsize = (GetByte(myoffset + 1) & 0x01) << 1; hsize |= (GetByte(myoffset + 2) & 80) >> 7; hsize <<= 12; if (!Video) return false; Video->hsize |= hsize; vsize = (GetByte(myoffset+2)&0x60) << 7; Video->vsize |= vsize; bitrate = (GetByte(myoffset + 2) & 0x1F) << 7; bitrate |= (GetByte(myoffset+3)&0xFE) >> 1; bitrate <<= 18; Video->bitrate |= bitrate; if (GetByte(myoffset + 5) & 0x80) SExt->low_delay = true; else SExt->low_delay = false; byte frate_n = (GetByte(myoffset + 5) & 0x60) >> 5; byte frate_d = (GetByte(myoffset + 5) & 0x1F); frate_n++; frate_d++; Video->frame_rate = (Video->frame_rate * frate_n) / frate_d; return true; } bool mpeg::ParseSequenceDisplayExt(off_t myoffset){ BTRACK; if (!DExt) DExt = new display_ext; DExt->video_format = (GetByte(myoffset) & 0x0E) >> 1; if (GetByte(myoffset) & 0x01) { // three bytes to read DExt->colour_prim = GetByte(myoffset + 1); DExt->transfer_char = GetByte(myoffset + 2); DExt->matrix_coef = GetByte(myoffset + 3); myoffset += 3; } else { DExt->colour_prim = 0; DExt->transfer_char = 0; DExt->matrix_coef = 0; } DExt->h_display_size = GetByte(myoffset + 1) << 6; DExt->h_display_size |= (GetByte(myoffset + 2) & 0xFC) >> 2; DExt->v_display_size = (GetByte(myoffset + 2) & 0x01) << 13; DExt->v_display_size |= GetByte(myoffset + 3) << 5; DExt->v_display_size |= (GetByte(myoffset + 4) & 0xF8) >> 3; return true; } bool mpeg::ParseRIFF(){ BTRACK; // RIFF if ( GetByte(0) != 'R' || GetByte(1) != 'I' || GetByte(2) != 'F' || GetByte(3) != 'F') return false; // 23 march 2001 != changed to == in the following // Thank to Volker Moell // WAVE if ( GetByte(8) == 'W' || GetByte(9) == 'A' || GetByte(10) == 'V' || GetByte(11) =='E') { fprintf(stderr,"%s is a Wave file\n", FileName); return false; } // 'AVI ' if ( GetByte(8)=='A' || GetByte(9)=='V' || GetByte(10) == 'I' || GetByte(11) ==' ') { fprintf(stderr,"%s is an AVI file\n",FileName); } return false; } off_t mpeg::FindMatchingAudio(off_t myoffset){ BTRACK; for( ; myoffset < FileSize - 5; myoffset++) { if (GetByte(myoffset) == 0xFF) // maybe an audio sync if (MatchAudio(myoffset)) return myoffset; } if (myoffset >= FileSize) return FileSize; return -1; } off_t mpeg::bdFindMatchingAudio(off_t myoffset){ BTRACK; for( ; myoffset >= Audio->first_frame_offset; myoffset--) { if (bdGetByte(myoffset) == 0xFF) if (MatchAudio(myoffset)) return myoffset; } return -1; } bool mpeg::MatchAudio(off_t myoffset){ BTRACK; // do we have audio anyway? if (!Audio) return false; //does this start as an mpeg audio frame? if (GetByte(myoffset) != 0xFF || (GetByte(myoffset + 1) & 0xE0) != 0xE0) return false; // are version compatibles? int version = ((GetByte(myoffset + 1)) & 0x18) >> 3; switch (Audio->mpeg_ver){ case 1: if (version != 3) return false; break; case 2: if (version != 2) return false; break; case 3: if (version != 0) return false; break; default: return false; break; } //are layers compatible? int layer = (GetByte(myoffset+1)&0x06)>>1; switch (Audio->layer) { case 1: if (layer != 3) return false; break; case 2: if (layer != 2) return false; break; case 3: if (layer != 1) return false; break; default: return false; break; } //are mode compatibles? int mode = (GetByte(myoffset + 3) & 0xC0) >> 6; if (mode != Audio->mode) return false; return true; } long mpeg::ReadPACKMuxRate(off_t offset) { BTRACK; // at start of a PACK long muxrate = 0; if ((GetByte(offset) & 0xC0) == 0x40) { // mpeg2 muxrate = GetByte(offset + 6) << 14; muxrate |= GetByte(offset + 7) << 6; muxrate |= GetByte(offset + 8) >> 2; } else { //maybe mpeg1 if ((GetByte(offset)&0xF0)!=0x20) fprintf(stderr, "weird pack header while parsing muxrate (offset " _OFF_x ")\n", offset); muxrate = (GetByte(offset + 5) & 0x7F) << 15; muxrate |= (GetByte(offset + 6) << 7); muxrate |= (GetByte(offset + 7) >> 1); } muxrate *= 50; return muxrate; } void mpeg::ParsePAT(off_t offset){ BTRACK; // offset++; //skip the first byte int pnum,ppid,i; int n_progs; if (GetByte(offset + 1) != 0x00) { #ifdef _DEBUG_ printf("wrong table_id in PAT\n"); #endif return; } // next 4 bits are 10XX int length = Read12bitLength(offset + 2); #ifdef _DEBUG_ printf("PAT: %d programs in %d bytes described\n",(length-9)/4,length-9); #endif if ( ( (length - 9)%4) != 0) { #ifdef _DEBUG_ printf("malformed PAT \n"); #endif return; } n_progs=(length-9)/4; if (Transport->PMT_PIDs) delete [] Transport->PMT_PIDs; Transport->PMT_PIDs = new PID [n_progs]; Transport->n_progs = n_progs; Transport->delete_programs(); Transport->programs = new program[n_progs]; for ( i=0; i < n_progs; i++){ Transport->programs[i].prog_num = -1; Transport->programs[i].nstreams = -1; Transport->programs[i].TStreams = 0; } for ( i=0; i< n_progs; i++){ pnum = Read2Bytes(offset + 9 + (i*4)); ppid = ReadPID(offset + 11 + (i*4)); if (pnum == 0) { Transport->network_PID = ppid; Transport->n_progs--; } else { Transport->PMT_PIDs[Transport->n_PMT_PIDs++] = ppid; } } } long mpeg::Read12bitLength(off_t offset){ BTRACK; // length must be xxxxAAAA AAAAAAAA return (((GetByte(offset) & 0x0F) << 8) | GetByte(offset + 1)); } long mpeg::Read2Bytes(off_t offset){ BTRACK; return((GetByte(offset) << 8) | GetByte(offset + 1)); } long mpeg::ReadPID(off_t offset){ BTRACK; // PID must be xxxAAAAA AAAAAAAA return (((GetByte(offset) & 0x1F) << 8) | GetByte(offset + 1)); } void mpeg::ParseCAT(off_t offset){ BTRACK; // conditional access table if(GetByte(offset + 1) != 0x01) { fprintf(stderr,"malformed CAT\n"); return; } // int length=Read12bitLength(offset+2); // long desc_offset=ParseDescriptor(offset+9); // while (desc_offset < offset+length+4-4){ // desc_offset=ParseDescriptor(desc_offset); // } } void mpeg::ParsePMT(off_t offset){ BTRACK; off_t i, desc_offset; int prog_index=0; if (GetByte(offset + 1) != 0x02) { #ifdef _DEBUG_ printf("malformed PMT\n"); #endif return; } // next 4 bits are 10XX int length = Read12bitLength(offset + 2); #ifdef _DEBUG_ printf("PMT length : %d\n",length); #endif int pnum = Read2Bytes(offset + 4); #ifdef _DEBUG_ printf("This PMT describes Program N° %d\n",pnum); #endif // check if the program is already here for (i = 0; i < Transport->n_progs; i++) { if (Transport->programs[i].prog_num == pnum) { // already have info on this! fprintf(stderr, "Warning, prog num %d redefined ! \n", pnum); if (Transport->programs[i].TStreams != 0) Transport->delete_ES(Transport->programs[i].TStreams); Transport->programs[i].TStreams = 0; } } // fetch the first empty index for (i = 0; i < Transport->n_progs; i++){ if (Transport->programs[i].prog_num == -1) { prog_index = i; } } if (prog_index >= Transport->n_progs) { fprintf(stderr,"Error : no room for program %d\n", pnum); return; } program* temp = &(Transport->programs[prog_index]); temp->prog_num = pnum; temp->nstreams = 0; // temp->next=Transport->programs; // Transport->programs=temp; // Transport->n_progs++; // temp->prog_num=pnum; #ifdef _DEBUG_ int pcrpid = ReadPID(offset + 9); if (pcrpid != 0x1FFF) printf("PCR of this program is in PID %d\n", pcrpid); #endif int infolen = Read12bitLength(offset + 11); #ifdef _DEBUG_ printf("info length : %d\n", infolen); #endif //parsing descriptors if (infolen > 0) { desc_offset = ParseDescriptor(offset + 12, &(temp->descs)); while (desc_offset < (offset + 12 + infolen)){ desc_offset = ParseDescriptor(desc_offset, &(temp->descs)); } } desc_offset = (offset + 13 + infolen); off_t max_offset = offset + 4 + length - 4; //-4 is for CRC size_t desc_size; int ES_type; int ES_pid; int ES_infolen; for ( i = desc_offset;instreams++; EStream* tempES = new EStream; tempES->next = temp->TStreams; temp->TStreams = tempES; tempES->pid = ES_pid; tempES->type = ES_type; tempES->demuxFile = 0; tempES->demuxFileOk = true; /* switch(ES_type){ case 0 : printf("reserved"); break; case 1: printf("MPEG 1 video");break; case 2: printf("MPEG 2 video");break; case 3: printf("MPEG 1 audio");break; case 4: printf("MPEG 2 audio");break; case 5: printf("MPEG 2 private section");break; case 6: printf("MPEG 2 PES with private data");break; case 7: printf("MHEG");break; case 8: printf("DSM_CC");break; case 9: printf("Private data");break; default: if (ES_type <0x80) printf("MPEG 2 reserved"); else printf("User Private data"); break; } */ /* printf(" info@%4lx (%d bytes) PID [%d]\n",i+5,ES_infolen,ES_pid);*/ if (ES_infolen > 0) { desc_offset = ParseDescriptor(i + 5, &tempES->descs); while (desc_offset < (i + 5 + ES_infolen)) desc_offset = ParseDescriptor(desc_offset, &tempES->descs); } } } off_t mpeg::ParseDescriptor(off_t offset,mpeg_descriptors* target){ BTRACK; int tag = GetByte(offset); int length = GetByte(offset+1); #ifdef _DEBUG_ printf("Descriptor %d length %d\n",tag,length); #endif bool handled = false; switch (tag) { case 0: case 1: //printf("reserved descriptor\n"); break; case 2: //printf("video stream descriptor : video version %d\n",GetByte(offset+2)); target->video_coding_version = GetByte(offset + 2); handled = true; break; case 3: //printf("audio stream descriptor : audio version %d\n",GetByte(offset+2)); target->audio_coding_version = GetByte(offset + 2); handled = true; break; case 4: //printf("hierarchy descriptor\n"); break; case 5: //printf("registration descriptor\n"); break; case 6: //printf("data stream alignment descriptor\n"); break; case 7: //printf("target background grid descriptor\n"); break; case 8: //printf("video window descriptor\n"); break; case 9: DescCA(offset, target); handled = true; break; case 10:DescLang(offset, target); handled = true; break; case 11: //printf("System clock descriptor\n"); break; case 12: //printf("multiplex buffer utilization descriptor\n"); break; case 13: //printf("copyright descriptor\n"); target->copyright = true; break; default : #ifdef _DEBUG_ if (tag < 63) printf("MPEG 2 reserved descriptor\n"); else printf("User Private descriptor\n"); #endif break; } if (!handled) { /* for (int i=0;in_unhandled_desc++; } #ifdef _DEBUG_ printf("\n"); #endif return (offset + length + 2); } void mpeg::DescCA(off_t offset, mpeg_descriptors* target){ BTRACK; #ifdef _DEBUG_ printf("Conditional Access descriptor\n"); #endif // int length=GetByte(offset+1); int CAsysID = Read2Bytes(offset + 2); PID CA_PID = ReadPID(offset + 4); target->CA = CAsysID; target->CA_PID = CA_PID; /* printf("Conditional access ID : %d related PID is %d\n",CAsysID,CA_PID); if (length>4){ printf("private data:\n"); byte thebyte; for (long i=offset+6;i=0x20) printf("%02x ",thebyte); else printf("%02x ",thebyte); } printf("\n"); for (long i=offset+6;i=0x20) printf(" %c ",thebyte); else printf(" "); } printf("\n"); } */ } void mpeg::DescLang(off_t offset, mpeg_descriptors* target){ BTRACK; int i; #ifdef _DEBUG_ printf("Language descriptor (untested)\n"); #endif int length = GetByte(offset + 1); int audio_type = GetByte(offset + 1 + length); target->lang_audio_type=audio_type; if (length > 1) { // there are languages inside length--; //without the trailing audio_type if (length%3 != 0) { fprintf(stderr,"invalid language in descriptor encountered\n"); return; } target->languages = new char[length + 1]; for (i=0; i < length; i++) { target->languages[i] = GetByte(offset + 2 + i); } target->languages[length] = '\0'; // length /=3; #ifdef _DEBUG_ printf("languages(s) : "); #endif /* for (i=0; i < length; i++){ printf("%c%c%c ", GetByte(offset+2+(i*3)), GetByte(offset+3+(i*3)), GetByte(offset+4+(i*3))); } printf("\n"); */ } } bool mpeg::ParseTransportStream(off_t offset){ BTRACK; if (GetByte(offset) != 0x47) return false; // int packetnum=0; // int pmt; Transport = new transport; int pid, scramble, adaptation; int i; off_t payload_offset; // well this is a mpeg 2? transport stream mpeg_version = 2; #define MPEG2_TR_PKT_LENGTH 188 #define TRANSPORT_PAT 0 #define TRANSPORT_CAT 1 #define PAT_SID 0 #define CAT_SID 1 #define PMT_SID 2 for (; offset < FileSize-1; offset += MPEG2_TR_PKT_LENGTH) { if (GetByte(offset) != 0x47) { fprintf(stderr,"Bad Packet start code %#0x should be 0x47\n",GetByte(offset)); return false; } pid = ReadPID(offset + 1); scramble = GetByte(offset + 3) >> 6; adaptation = (GetByte(offset + 3) & 0x30) >> 4; if (adaptation == 0) { // this is reserved, skip! continue; } //compute the payload offset payload_offset = offset + 4; if (adaptation & 0x02){ //adaptation fiel is present. // skip it // first byte of adaptation field is adaptation field length payload_offset += GetByte(offset + 4) + 1; } // if this is a Program association table parse it if (pid == 0x00) { ParsePAT(payload_offset); } // if this is a Program Map Table parse it for (i = 0; i < Transport->n_PMT_PIDs; i++) { if (Transport->PMT_PIDs[i] == pid) { ParsePMT(payload_offset); Transport->read_pmts++; #ifdef _DEBUG_ printf("PMT at [" _OFF_x "]\n", payload_offset); #endif break; } } if (Transport->n_PMT_PIDs !=0 && Transport->n_PMT_PIDs == Transport->read_pmts) { // we read all program map table... // Transport->PrintInfos(); HasAudio=HasVideo = true; return true; } /* switch(GetByte(payload_offset+1)){ case PAT_SID : ParsePAT(payload_offset); break; case CAT_SID : ParseCAT(payload_offset); break; case PMT_SID : ParsePMT(payload_offset); break; default : continue; break; } printf ("\n\n"); */ } #ifdef _DEBUG_ fprintf(stderr,"Sorry MPEG-2 Transport Stream is currently not handled\n"); #endif fprintf(stderr,"Warning didn't find the promised Program Map Tables\n"); return false; } PID mpeg::NextTrPacket(off_t* offset,off_t* payload_start, off_t* payload_end){ BTRACK; PID pid; byte adaptation; off_t payload_offset; *payload_start = 0; *payload_end = 0; // *offset = *offset + MPEG2_TR_PKT_LENGTH; // *offset = *offset + 188; pid = ReadPID(*offset + 1); adaptation = (GetByte(*offset + 3) & 0x30) >> 4; if (adaptation == 0){ // this is reserved, skip! *offset += MPEG2_TR_PKT_LENGTH; return pid; } if (pid == 0x1FFF) { //null packet *payload_start = 0; *payload_end = 0; *offset += MPEG2_TR_PKT_LENGTH; return pid; } //compute the payload offset payload_offset = *offset + 4; if (adaptation & 0x02) { //adaptation fiel is present. // skip it // first byte of adaptation field is adaptation field length payload_offset += GetByte(*offset + 4) + 1; } *payload_start = payload_offset; *offset += MPEG2_TR_PKT_LENGTH; *payload_end = *offset; if (*offset >= FileSize) *payload_start = *payload_end=-1; return pid; } transport::transport() :programs(0), n_progs(0), n_audio_streams(0), n_video_streams(0), n_other_streams(0), network_PID(-1), PMT_PIDs(0), n_PMT_PIDs(0), read_pmts(0) {} transport::~transport() { BTRACK; if (n_progs >0) { delete [] programs; } } void transport::delete_programs(){ BTRACK; if (!programs) return; for (int i = 0; i < n_progs; i++){ if (programs[i].TStreams != 0) delete_ES(programs[i].TStreams); } delete[] programs; programs=0; } void transport::delete_ES(EStream* stream) { BTRACK; if (stream == 0) return; if (stream->next == 0) delete stream; else delete_ES(stream->next); } void transport::PrintInfos(){ BTRACK; EStream* current; if (n_progs == 1) printf(" Mpeg 2 Transport Stream [1 program]\n"); else printf(" Mpeg 2 Transport Stream [%d programs]\n",n_progs); for(int i = 0; i < n_progs; i++) { printf(" Program N° %d contains %d Elementary Streams:\n",programs[i].prog_num, programs[i].nstreams); programs[i].descs.PrintInfos(" "); current=programs[i].TStreams; int stream_count = 1; while (current != 0) { printf(" Stream %d: ", stream_count++); switch (current->type) { case 0: printf("reserved"); break; case 1: printf("MPEG 1 video");break; case 2: printf("MPEG 2 video");break; case 3: printf("MPEG 1 audio");break; case 4: printf("MPEG 2 audio");break; case 5: printf("MPEG 2 private section");break; case 6: printf("MPEG 2 PES with private data");break; case 7: printf("MHEG");break; case 8: printf("DSM_CC");break; case 9: printf("Private data");break; default: if (current->type <0x80) printf("MPEG 2 reserved"); else printf("User Private data"); break; } printf(" [pid: %d]\n", current->pid); current->descs.PrintInfos(" "); current=current->next; } } } void mpeg_descriptors::PrintInfos(char* prefix){ BTRACK; unsigned int i; if (prefix==0) prefix = ""; char* description = new char[300]; char temp[100]; description[0] = '\0'; if (video_coding_version != -1) { sprintf(temp, "%svideo version %d\n", prefix, video_coding_version); strcat(description,temp); } if (audio_coding_version != -1) { sprintf(temp,"%saudio version %d\n",prefix, audio_coding_version); strcat(description, temp); } if (CA != -1) { sprintf(temp,"%smaybe scrambled (CA ID %d)\n",prefix,CA); strcat(description, temp); } if (languages) { sprintf(temp,"%sstream language: ", prefix); for (i = 0; i < strlen(languages)/3; i++) { sprintf(temp,"%c%c%c ",languages[i*3], languages[i*3+1], languages[i*3+2]); strcat(description,temp); } strcat(description,"\n"); } if (lang_audio_type >= 1 && lang_audio_type <= 3) { switch (lang_audio_type) { case 1: sprintf(temp,"%sClean effects : not a language\n",prefix);break; case 2: sprintf(temp,"%sStream is prepared for hearing impaired\n",prefix);break; case 3: sprintf(temp,"%sStream is prepared for commentaries for visually impaired viewers\n",prefix); } strcat(description,temp); } if (copyright) { sprintf(temp,"%sThis stream has copyright limitations\n",prefix); strcat(description,temp); } if (n_unhandled_desc>0) { if (n_unhandled_desc==1) sprintf(temp,"%s1 additional descriptor was not handled\n",prefix); else sprintf(temp,"%s%d additional descriptors were not handled\n",prefix, n_unhandled_desc); strcat(description,temp); } printf("%s", description); delete[] description; } header_buf *readHeader(FILE *myMpegfile, off_t offset, int rw) { static byte *nix; static off_t size; static header_buf *p; if (rw == 1) { p = new header_buf; size = offset; nix = new byte[size]; if (!nix) { fprintf(stderr,"unable to alloc buffer for header\n"); exit(1); } FSEEK(myMpegfile,0L,SEEK_SET); fread(nix,size,1L,myMpegfile); p->size = size; p->buf = nix; if (preserve_header) fprintf(stderr,"Size of Fix: 0x%qx\n",size); return(NULL); } if (rw == 2) return(p); fprintf(stderr,"unable to understand command\n"); exit(1); } /// prints all time stamps on stdout void mpeg::print_all_ts(byte kind){ off_t p = 0; byte *nix; double tsx; // FIXME [es] What is "nix" for? nix = &kind; while( (p = FindNextMarker(p,kind)) != -1) { if (mpeg_version == 2) tsx = ReadTSMpeg2(p+4); else tsx = ReadTS(p+4); fprintf (stderr,"offset: " _OFF_x " TS: %lf\n",p,tsx); p+=4; } } /// Checks time line of increasing time stamps and return amount of breaks int mpeg::CheckTimeline(byte kind){ off_t p = 0; double tsx = 0, tsx_prev = 0; int ret = 0; while( (p = FindNextMarker(p,kind)) != -1) { if (mpeg_version == 2) tsx = ReadTSMpeg2(p+4); else tsx = ReadTS(p+4); if ( !(tsx >= tsx_prev) ){ ++ret; //#ifdef _DEBUG_ printf("\tTime stamps jumped from %lf to %lf at position " _OFF_x "\n",tsx_prev,tsx,p); //#endif } tsx_prev = tsx; p+=4; } return ret; } mpgtx-1.3.1/mpeg.hh0000644000175000001440000002115510162367453013725 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #ifndef __mpeg_hh_ #define __mpeg_hh_ #include "common.hh" #include "mpegOut.hh" // [laureck] Aug 2002 // We really should find its place for the following (any idea Phil ?) : typedef struct { // this stores the junk header of mpeg files, in case someone needs it later off_t size; byte *buf; } header_buf; /** * * @return pointer to the junk */ header_buf *readHeader(FILE *myMpegfile, off_t offset, int rw); typedef int PID; class mpeg_descriptors { public: mpeg_descriptors() { video_coding_version=-1; audio_coding_version=-1; CA=-1; CA_PID=-1; lang_audio_type=-1; languages=0; copyright=false; n_unhandled_desc=0; } ~mpeg_descriptors() { if (languages) delete[] languages; } void PrintInfos(char* prefix); int video_coding_version; int audio_coding_version; int CA; PID CA_PID; int lang_audio_type; char* languages; bool copyright; byte n_unhandled_desc; }; typedef struct ES_t { PID pid; byte type; ES_t *next; mpeg_descriptors descs; FILE* demuxFile; bool demuxFileOk; } EStream; typedef struct t_prog { EStream *TStreams; int nstreams; int prog_num; mpeg_descriptors descs; } program; class mpeg; //#define MAX_PROGS 100 //helper class that carries transport stream infos class transport { friend class mpeg; friend class demuxer; public : transport(); ~transport(); protected: void delete_programs(); void delete_ES(EStream* stream); void PrintInfos(); program* programs; int n_progs; int n_audio_streams; int n_video_streams; int n_other_streams; PID network_PID; PID* PMT_PIDs; int n_PMT_PIDs; int read_pmts; }; class mpeg { friend class mpegSystemOut; friend class demuxer; protected: // disallow basic constructors mpeg(){}; // Functions // General ToolBox /** * Gives a byte from address offset. * If offset is out of buffer, it creates new buffer beginning on offset * and load mpeg file in for forward operations. * * @param offset address to get byte * @return byte value from offset */ byte GetByte(off_t offset); /** * Gives a byte from address offset. * If offset is out of buffer, it creates new buffer ending on offset * and load mpeg file in for backward operations. * * @param offset address to get byte * @return byte value from offset */ byte bdGetByte(off_t offset); bool EnsureMPEG(off_t offset,marker mark); double ReadTS (off_t offset); double ReadTSMpeg2(off_t offset); long ReadPACKMuxRate(off_t offset); /** * find any marker. * find next 0x 00 00 01 xx sequence * * @param from start address of search * @return offset of found mark or -1 on error */ off_t FindNextMarker(off_t from); /** Searchs forward for any next marker, change mark accordingly. * find next 0x 00 00 01 xx sequence and set mark = xx * * @param from start address of search * @param mark pointer to mark to change * @return offset of found mark or -1 on error */ off_t FindNextMarker(off_t from, marker* mark); /** Searchs backward for any next marker, change mark accordingly. * find next 0x 00 00 01 xx sequence and set mark = xx * * @param from start address of search * @param mark pointer to mark to change * @return offset of found mark or -1 on error */ off_t bdFindNextMarker(off_t from, marker* mark); /** Prints every timestamp that follows a "0x 00 00 01 kind" sequence. * time stamp format depends on mpeg_version * * @param kind header mark of time stamp headers */ void print_all_ts(byte kind); /** Checks time line of increasing time stamps and return amount of breaks. * * @param kind header mark of time stamp headers * @return amount of breaks in time line */ int CheckTimeline(byte kind); public: /** * Constuctor. * Create a mpeg object from given file * * @param filename MPEG file to read * @param verbosity Amount of process messages: * mpeg_SILENT suppress all messages * mpeg_VERBOSE additional error messages * other normal process messages */ mpeg(const char* filename,int verbosity=mpeg_SILENT); ~mpeg(); // General ToolBox /** * Prints infos about MPEG stream to stdout. * Infos depending on MpegType: * mpeg_AUDIO: duration, version, layer, bitrate, sampling rate, frame lengh, * mode, emphasis, copyright, original/copy, ID3v1 tag * * mpeg_VIDEO: duration, aspect ratio, interlace, video format, display size, * frame rate, bit rate, user data * * mpeg_SYSTEM: infos above if available * * mpeg_TRANSPORT: call transport::PrintInfos() * */ void PrintInfos(); bool has_audio() {return HasAudio;} bool has_video() {return HasVideo;} off_t Size() {return FileSize;} const char* Name() {return FileName;} int Version() {return mpeg_version;} /** * Compare attributes of this and another MPEG * * @param peer pointer to the other MPEG * @return true if they fit, false otherwise */ bool Match(mpeg* peer); /// gets audio duration, video duration or zero (first valid will serve, of course ;-) float Duration(); /** * Calls mpeg::GetByte(). * * @param offset address to give to GetByte() * @return a byte got from GetByte() */ byte Byte(off_t offset); /** search forward for specific marker. * find next 0x 00 00 01 mark sequence * * @param from start address of search * @param mark mark to look for * @return offset of found marker or -1 on error */ off_t FindNextMarker(off_t from, marker mark); /** search backward for specific marker. * find next 0x 00 00 01 mark sequence * * @param from start address of search * @param mark mark to look for * @return offset of found marker or -1 on error */ off_t bdFindNextMarker(off_t from, marker mark); /** gets two byte from address and next one. * * @param offset address of higher byte, offset+1 is lower byte * @return two byte value of offset and offset+1 */ unsigned short int GetSize(off_t offset); /** * Converts seconds in a String HH:MM:SS.xxs * * @param HMS char array (min. 13 bytes) * @param duration in seconds */ void SecsToHMS(char* HMS, float duration); // Audio ToolBox /// check if audio is present after myoffset bool ParseAudio(off_t myoffset); /// check if ID3v2 tag is present and audio follows. bool ParseID3(); bool PrintID3(); off_t FindMatchingAudio(off_t myoffset); off_t bdFindMatchingAudio(off_t myoffset); bool MatchAudio(off_t myoffset); // Video ToolBox bool ParseVideo(off_t myoffset); bool ParseExtension(off_t myoffset); bool ParseSequenceExt(off_t myoffset); bool ParseSequenceDisplayExt(off_t myoffset); bool ParseUserData(off_t myoffset); // System ToolBox bool ParseSystem(); bool ParseSystemPacket(off_t startofpacket, off_t startofpack); bool ParseSystemHeader(off_t myoffset); off_t SkipPacketHeader(off_t myoffset); void ParseFramesInGOP(off_t offset); bool ParseRIFF(); bool ParseTransportStream(off_t offset); void ParseCAT(off_t offset); void ParsePAT(off_t offset); void ParsePMT(off_t offset); off_t ParseDescriptor(off_t offset, mpeg_descriptors* target); void DescCA(off_t offset, mpeg_descriptors* target); void DescLang(off_t offset, mpeg_descriptors* target); long Read12bitLength(off_t offset); long Read2Bytes(off_t offset); long ReadPID(off_t offset); PID NextTrPacket(off_t* offset, off_t* payload_start, off_t* payload_end); /// file handle (I hate iostream and I can't use read/write on windows) FILE* MpegFile; /// how much we speak int Verboseness; // mpeg Internals to be filled by constructor bool HasAudio,HasVideo; bool composite,editable; off_t FileSize; char* FileName; int MpegType; // audio internals mpgtx_audio* Audio; byte n_audio; // video internals mpgtx_video* Video; byte n_video; /// system internals mpgtx_system* System; /// transport stream internals transport* Transport; // extentions sequence_ext* SExt; display_ext* DExt; user_data* UData; /// start with id3v2 tag bool start_with_id3; /// for mpeg 1/ mpeg2 byte mpeg_version; // for GetByte off_t buffstart; off_t buffend; byte* buffer; }; typedef struct { char* file; off_t from; float sfrom; off_t to; float sto; bool from_included; bool to_included; bool until_file_size; bool unit_is_second; mpeg* mpegfile; } chunk; #endif // __mpeg_hh_ mpgtx-1.3.1/mpegOut.cxx0000644000175000001440000013674610157126533014631 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #include "mpegOut.hh" #include "common.hh" #include #include // original was 0.015 #define base_TS_correction 0.015 // hate me for the globals ... Begin philipp mod // extern bool aspect_correction; // flag if corretion is needed extern byte forced_sequence_header; // the new aspect ratio extern bool preserve_header; // flag if junk at the start of a file should be preserved extern bool print_progress; // print more info while processing void print_ts(byte *p); // prints the timestamp of a mpeg2 gop - only for testing // end philipp mod // #define _DEBUG_ #ifdef _DEBUG_ int count=0; #endif mpegOut::mpegOut(char* filename) { BTRACK; // fprintf(stderr, "constructing mpegOut %s\n",filename); if (!access(filename, F_OK)) { // file already exist //fprintf(stderr,"File %s already exist\n",filename); } //open file for writing/truncate MpegOut = fopen(filename, "wb"); if (MpegOut == 0) { // Gosh ! unable to open fprintf(stderr, "Unable to open %s for writing\n", filename); perror("reason: "); } HasAudio = HasVideo = false; FileType = mpeg_EMPTY; } mpegOut::mpegOut(FILE* filehandle) { BTRACK; // fprintf(stderr,"constructing mpegOut with filehandle\n"); MpegOut = filehandle; HasAudio = HasVideo = false; FileType = mpeg_EMPTY; } mpegOut::~mpegOut() { BTRACK; // printf("destructing mpegOut \n"); if (MpegOut != 0) fclose (MpegOut); } void mpegSystemOut::WriteHeader(mpeg* Mpeg){ header_buf *pbfix; int mpeg2stuff_bytes; BTRACK; //Have to write system headers and video sequence if (!MpegOut) return; if (!Mpeg) return; if (preserve_header) { fprintf(stderr,"now reapplying junk-header ....\n"); /* read original bytes of header */ /* from 0 to offset to video */ pbfix = readHeader(MpegOut,0,2); // fprintf(stderr,"Size of header still: 0x%qx\n",pbfix->size); fwrite(pbfix->buf,pbfix->size,1,MpegOut); } mpeg_version = Mpeg->Version(); if (!preserve_header) { // alternatively, create our own header if(Mpeg->System->video_system_header) fwrite(Mpeg->System->video_system_header, 1, Mpeg->System->video_system_header_length, MpegOut); if (Mpeg->System->audio_system_header) fwrite(Mpeg->System->audio_system_header, 1, Mpeg->System->audio_system_header_length, MpegOut); } // okay system headers are written... // let's write the PACK + video packet header // we keep the remaining in mem because we need to // correct the packet length before outputing it (stdout is not // seekable:/ off_t PACKlength = 0; mpeg2stuff_bytes = 4; if ((Mpeg->System->first_video_packet[4] & 0xF0) == 0x20) { //standard mpeg1 pack PACKlength = 12; } else { if ((Mpeg->System->first_video_packet[4] & 0xC0) == 0x40) { //new mpeg2 pack : 14 bytes + what stuffing ? mpeg2stuff_bytes = Mpeg->System->first_video_packet[13] & 0x07; PACKlength = 14; #ifdef _DEBUG_ fprintf(stderr,"packlength %qx\n",PACKlength); fprintf(stderr,"firstVideopacket: \n"); for (count = 0; count < Mpeg->System->first_video_packet_length; ++count) { fprintf(stderr,"%02x ",Mpeg->System->first_video_packet[count]); } fprintf(stderr,"\n-------\n"); #endif } else { //wazup? // May 28 2001: maybe there's no pack at all... byte packetcode = Mpeg->System->first_video_packet[3] & 0xF0; if (packetcode == 0xE0 || packetcode == 0xD0 ) { // this is a video packet that dosnt have a pack before PACKlength = 0; } else { if(Mpeg->System->first_video_packet[3] != 0xba) { //neither a PACK nor a video packet fprintf(stderr, "I'm lost, ciao\n"); exit(1); } fprintf(stderr, "Weird PACK encountered don't seem to be mpeg 1 nor mpeg 2.\n"); fprintf(stderr, "I most certainly crash in a minute but I love risk.\n"); // try to find the end of the pack "manually" i.e. till the first video packet bool endofpackfound = false; PACKlength = 12; for (; PACKlength < Mpeg->System->first_video_packet_length; PACKlength++) { if ( Mpeg->System->first_video_packet[PACKlength] == 0x0 && Mpeg->System->first_video_packet[PACKlength + 1] == 0x0 && Mpeg->System->first_video_packet[PACKlength + 2] == 0x1 && ((Mpeg->System->first_video_packet[PACKlength + 3] & 0xF0) == 0xE0|| (Mpeg->System->first_video_packet[PACKlength + 3] & 0xF0) == 0xD0) ) { endofpackfound=true; break; PACKlength--; // TODO: Laurent what's this? break exits.. } //if } //for if ((!endofpackfound) || (Mpeg->System->first_video_packet_length-PACKlength-4-2 <=0)) { fprintf(stderr,"Now I'm really lost, ciao\n"); exit(1); } } // end May 28 } } fwrite(Mpeg->System->first_video_packet, 1, PACKlength + mpeg2stuff_bytes, MpegOut); // now allocate required mem partial_packet_length = Mpeg->System->first_video_packet_length-PACKlength - mpeg2stuff_bytes - (mpeg2stuff_bytes == 0?0:2); //after the size field partial_packet_length += Mpeg->Video->video_header_size; partial_packet = new byte[partial_packet_length]; // printf("allocating %ld bytes\n",partial_packet_length); memcpy(partial_packet, (Mpeg->System->first_video_packet) + PACKlength + mpeg2stuff_bytes + (mpeg2stuff_bytes == 0?0:2), Mpeg->System->first_video_packet_length - PACKlength - mpeg2stuff_bytes - (mpeg2stuff_bytes == 0?0:2)); memcpy(&partial_packet[(Mpeg->System->first_video_packet_length) - PACKlength - mpeg2stuff_bytes - (mpeg2stuff_bytes == 0?0:2)], Mpeg->Video->video_header, Mpeg->Video->video_header_size); HasAudio = HasVideo = true; FileType = mpeg_SYSTEM; currentTS = Mpeg->System->initial_TS; #ifdef _DEBUG_ fprintf(stderr,"Mpeg initial_TS: %lf\n",currentTS); #endif fflush(MpegOut); } void mpegVideoOut::WriteHeader(mpeg* Mpeg) { BTRACK; //Have to write video sequence if (!MpegOut) return; fwrite(Mpeg->Video->video_header, 1, Mpeg->Video->video_header_size, MpegOut); } int mpegVideoOut::WriteChunk( mpeg* Mpeg, off_t from, bool from_included, off_t to, bool to_included) { BTRACK; if (!MpegOut) return 0; off_t real_from, real_to; if ((from > to) || (from < 0) || (to < 0)) { //pffff return 0; } if (from_included) { real_from = Mpeg->bdFindNextMarker(from, 0xB8); if (real_from == -1) { //couldn't find a GOP before from! real_from = Mpeg->FindNextMarker(from, 0xB8); if (real_from == -1) { //gosh couldn't find GOP at all! return 0; } } } else { real_from = Mpeg->FindNextMarker(from, 0xB8); if (real_from == -1) { real_from = Mpeg->bdFindNextMarker(from, 0xB8); if(real_from == -1) { //couldn't find any GOP! return 0; } } } //okay we have a real from if (to_included) { real_to = Mpeg->FindNextMarker(to, 0xB8); if (real_to == -1) real_to = Mpeg->FileSize; } else { real_to = Mpeg->bdFindNextMarker(to, 0xB8); if (real_to == -1) { //couldn't find any GOP! return 0; } } if (real_from >= real_to) return 0; //now let's Copy from GOP boundary to GOP boundary if (print_progress) fprintf(stderr, " "); Copy(Mpeg->MpegFile, real_from,real_to); return 1; } int mpegAudioOut::WriteChunk( mpeg* Mpeg, off_t from, bool from_included, off_t to,bool to_included) { BTRACK; if (!MpegOut) return 0; off_t real_from,real_to; // 23 March 2001, real_to an real_from are now seeked // because there are plenty of variable bitrates mp3 /* real_from=from -(from% Mpeg->Audio->frame_length); if ((real_from!=from)&&(!from_included)) real_from+=Mpeg->Audio->frame_length; real_to= to -(from%Mpeg->Audio->frame_length); if ((real_to!=to)&&(to_included)) real_to += Mpeg->Audio->frame_length; if (real_to > Mpeg->Size()) real_to=Mpeg->Size(); */ if (from_included) real_from = Mpeg->bdFindMatchingAudio(from); else real_from = Mpeg->FindMatchingAudio(from); if (to_included) real_to=Mpeg->FindMatchingAudio(to); else real_to=Mpeg->bdFindMatchingAudio(to); if (real_to==-1 || real_from==-1 || real_from >= real_to) return false; if(print_progress) fprintf(stderr," "); Copy(Mpeg->MpegFile, real_from, real_to); return 1; } int mpegSystemOut::WriteChunk( mpeg* Mpeg, off_t from, bool from_included, off_t to, bool to_included) { int count; BTRACK; if (!MpegOut) return 0; #ifdef _DEBUG_ fprintf(stderr,"new Chunk: from:0x%qx, to:0x%qx\n",from,to); #endif off_t real_from, real_to; int sequence_header; //given the from and to offsets, find GOP boundaries if ((from > to) || (from < 0) || (to < 0)) { //pffff return 0; } if (from_included) { real_from = Mpeg->bdFindNextMarker(from, 0xB8); if (real_from == -1) { //couldn't find a GOP before from! real_from = Mpeg->FindNextMarker(from, 0xB8); if (real_from == -1) { //gosh couldn't find GOP at all! return 0; } } } else { real_from= Mpeg->FindNextMarker(from, 0xB8); if (real_from == -1) { //couldn't find any GOP! return 0; } } //okay we have a real from if (to_included) { real_to = Mpeg->FindNextMarker(to, 0xB8); if (real_to == -1) real_to = Mpeg->FileSize; } else { real_to = Mpeg->bdFindNextMarker(to, 0xB8); if (real_to == -1) { //couldn't find any GOP! return 0; } } if (real_from >= real_to) return 0; // printf("[%ld - %ld ] becomes [%ld - %ld]\n",from,to, real_from,real_to); // while(getchar()!='\n'); //okay the file is there but artifacts too.. //we have to correct the packet length //we already know the data size we have, //let's compute what we just added : from GOP to end of packet off_t EOP = real_from - 1; marker mark; while (true) { EOP = Mpeg->FindNextMarker(EOP + 1, &mark); if (((mark & 0xF0) != 0x0) && (mark != 0xB8)) { // this is neither a slice, nor a pic nor a gop : // we are then at the end of the packet break; } if (EOP == -1) break; } off_t GOP2EOP = EOP - real_from; //if FindNextMarker returned -1 there was no pack after->take filesize if (GOP2EOP < 0) GOP2EOP = Mpeg->FileSize-real_from; //okay the packet size must now be ::partial_packet_length+GOP2EOP //let's write that off_t real_packet_length = partial_packet_length+GOP2EOP; #ifdef _DEBUG_ fprintf(stderr,"real_packet_length: [" _OFF_x "]\n", real_packet_length ); #endif byte low = real_packet_length & 0xFF; byte high = (real_packet_length >> 8) & 0xFF; //fseeko(MpegOut, size_field_offset, SEEK_SET); if (Mpeg->Version() == 2) { // dont touch valuable data, maybe mpeg1 files have a size here but mpeg2 wont play // if filesize is written here // this is not good, who nows what the effect will be on other mpeg2s ? // but currently I dont know it better ; } else { fwrite(&high, 1, 1, MpegOut); fwrite(&low, 1, 1, MpegOut); //fseeko(MpegOut, 0, SEEK_END); } fflush(MpegOut); //write what we kept in mem and free memory // fprintf(stderr,"partial_packet_length %qd\n",partial_packet_length); // for (count = 0; count < partial_packet_length; ++count) { // fprintf(stderr, "%02x.",*(partial_packet + count)); // } // fprintf(stderr,"\n"); sequence_header = -1; for (count = 0; count < partial_packet_length - 4; ++count) { if ( (*(partial_packet + 0 + count) == 0x00) && (*(partial_packet + 1 + count) == 0x00) && (*(partial_packet + 2 + count) == 0x01) && (*(partial_packet + 3 + count) == 0xb3) ) { sequence_header = count + 4; // fprintf(stderr, "found sequence header at: %d\n",sequence_header); count = partial_packet_length; // this is the important sequence header in the file! } } if ((sequence_header != -1) && ((partial_packet_length - sequence_header) > 4) && (aspect_correction)) { // found it, room to change is there, user wants it if (print_progress) fprintf(stderr,"\nCurrent Value of aspect ratio is: %2x ",*(partial_packet + sequence_header + 3)); // fprintf(stderr, "position: %d is: %2x\n", sequence_header + 3,*(partial_packet + sequence_header + 3)); *(partial_packet + sequence_header + 3) = ((*(partial_packet + sequence_header + 3) & 0xf) | forced_sequence_header ); // fprintf(stderr, "position: %d is new: %2x\n", sequence_header + 3,*(partial_packet + sequence_header + 3)); if (print_progress) fprintf(stderr,"New Value of aspect ratio is: %2x\n",*(partial_packet + sequence_header + 3)); } fwrite(partial_packet, 1, partial_packet_length, MpegOut); fflush(MpegOut); // printf("deleting partial_packet in WriteChunk\n"); delete[] partial_packet; //now recreate buffer with everything from start of packet //to GOP end (real_to) and copy it in partial_packet off_t last_packet_offset= Mpeg->bdFindNextMarker(real_to, 0xE0); // fprintf(stderr,"last_packet_offset: [" _OFF_x "]\n",last_packet_offset); partial_packet_length = real_to-last_packet_offset - 6; partial_packet = new byte[partial_packet_length]; // printf("allocating %ld bytes\n",partial_packet_length); FSEEK(Mpeg->MpegFile, last_packet_offset + 6, SEEK_SET); fread(partial_packet, 1, partial_packet_length, Mpeg->MpegFile); //now let's Copy from start of packet boundary to beg of last packet if (print_progress) fprintf(stderr," "); #ifdef _DEBUG_ fprintf(stderr,"Starting copy %qd %qd \n",real_from,last_packet_offset); #endif Copy(Mpeg->MpegFile, real_from,last_packet_offset + 4); // Copy updated the current time stamp. // we must now correct the partial packet timestamp. byte* OldBuffer = buffer; buffer = partial_packet; if (CorrectTS(partial_packet_length) != 0) { fprintf(stderr,"unhandled result code of CorrectTS, results in playback or sync problem!\n"); } buffer = OldBuffer; return 1; } void mpegSystemOut::Copy(FILE* file, off_t from, off_t to) { BTRACK; #ifdef ENABLE_OPTIMIZATION double Copy_time_start=Clock_Now(); #endif if (!MpegOut) return ; // long DBGsize; off_t size = to - from; off_t read_size = 0; off_t prev_read_size = 0; long rewind_pos = 0; // if buffer at end and TS could not be corrected, reread from correct position float percent; first_TS_correction = true; // fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut)); size_t size2read = (size > COPYBUFFERSIZE)?COPYBUFFERSIZE:size; buffer = new byte[size2read]; while(read_size < size) { size2read = ((size - read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size; if (rewind_pos != 0) { // last buffer was at end, and a TS could not be corrected FSEEK(file, from + read_size - (prev_read_size - rewind_pos), SEEK_SET); #ifdef _DEBUG_ // fprintf(stderr,"rewinded by %qd bytes to prevent short buffer problem\n",(prev_read_size - rewind_pos)); #endif prev_read_size = 0; rewind_pos = 0; } else FSEEK(file, from + read_size, SEEK_SET); read_size += fread(buffer, 1, size2read, file); // fprintf(stderr,"read bytes: %qd\n",read_size); if (first_TS_correction) { #ifdef _DEBUG_ fprintf(stderr,"The bytes from start...: %02x %02x %02x %02x %02x %02x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5] ); #endif // hehe we have to set the broken link flag on the first GOP! // why? because those players will try to play the leading B frames // wich are predicted from former frames (and they're not any, cause // we just happen to cut them, remember?) // broken_link flag is just for that! // we must be on a GOP start here // broken link is 27 bit after GOP start sequence // it is @ 4 + 3 bytes + 3 bits buffer[7] |= 0x20; // pfiouuu that one line was hard to find! // now that broken link is set we must unset the closed gop bit buffer[7] &= 0xBF; //TODO: some players ignore this broken link flag... // (I hate them) // another dirty way to do that is to find all B (and P?) // frames preceding the first I frame and change their type // (offset of frame type : 00 00 01 00 +10bits /3bits // to something like 000b wich is not a valid frame type, // they may be discarded by the player // I guess the best way to make it robust is to parse the whole // GOP, delete the preceding B frames and change the temporal ref // of every other frames... // This is a though job because a single frame can span over multiple // video packets... // final versions of this soft might cut mpg files on frame // boundaries... we'll take care of that at this very moment. } rewind_pos = CorrectTS(size2read); // correct TS of buffer if (rewind_pos) { #ifdef _DEBUG_ // fprintf(stderr,"we now take care of the buffer problem! %ld size2read: %ld\n",rewind_pos,size2read); #endif fwrite(buffer,1,rewind_pos,MpegOut); // only write the part which is ok! prev_read_size = size2read; } else fwrite(buffer, 1, size2read, MpegOut); //printf("Written %ld bytes on %ld wanted\n",DBGsize,size2read); if (print_progress) { START_CLOCK percent = (read_size*1.0) / (size/100.0); percent = (percent>100.0)?100.0:percent; fprintf(stderr,"\b\b\b\b\b\b\b\b%5.2f%% ", percent); fflush(stdout); STOP_CLOCK(PRINTF); } } delete buffer; #ifdef ENABLE_OPTIMIZATION AddTime(Copy_time_start,COPY); #endif } void mpegAudioOut::Finish() { // write id3 tag if present } void mpegSystemOut::Finish(){ BTRACK; if (!MpegOut) return; if (partial_packet) { byte low = partial_packet_length & 0xFF; byte high = (partial_packet_length >> 8) & 0xFF; fwrite(&high, 1, 1, MpegOut); fwrite(&low, 1, 1, MpegOut); fwrite(partial_packet, 1, partial_packet_length, MpegOut); // printf("deleting partial packet in finish\n"); delete[] partial_packet; } fclose(MpegOut); } void mpegVideoOut::Copy(FILE* file, off_t from, off_t to){ BTRACK; #ifdef ENABLE_OPTIMIZATION double Copy_time_start=Clock_Now(); #endif if (!MpegOut) return ; off_t size = to - from; off_t read_size = 0; first_TS_correction = true; float percent; // fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut)); size_t size2read = (size > COPYBUFFERSIZE)?COPYBUFFERSIZE:size; buffer = new byte[size2read]; while (read_size < size) { size2read = ((size - read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size; FSEEK(file, from + read_size, SEEK_SET); read_size += fread(buffer, 1, size2read, file); if (first_TS_correction) { buffer[7] |= 0x20; first_TS_correction = false; } fwrite(buffer, 1, size2read, MpegOut); if (print_progress) { //lperc=(read_size*100)/(size/100); START_CLOCK; percent = (read_size*1.0) / (size/100.0); fprintf(stderr, "\b\b\b\b\b\b\b\b%5.2f%% ", percent); fflush(stderr); STOP_CLOCK(PRINTF); } } delete buffer; #ifdef ENABLE_OPTIMIZATION AddTime(Copy_time_start,COPY); #endif } void mpegAudioOut::Copy(FILE* file, off_t from, off_t to) { BTRACK; #ifdef ENABLE_OPTIMIZATION double Copy_time_start=Clock_Now(); #endif if (!MpegOut) return; off_t size = to - from; off_t read_size = 0; float percent; // fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut)); size_t size2read = (size > COPYBUFFERSIZE)?COPYBUFFERSIZE:size; buffer = new byte[size2read]; while (read_size < size) { size2read = ((size - read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size; FSEEK(file, from + read_size, SEEK_SET); read_size += fread(buffer, 1, size2read, file); fwrite(buffer, 1, size2read, MpegOut); if (print_progress) { START_CLOCK; //lperc=(read_size*100)/(size/100); percent = (read_size*1.0) / (size/100); percent = (percent>100.0)?100.0:percent; fprintf(stderr, "\b\b\b\b\b\b\b\b%5.2f%% ", percent); fflush(stderr); STOP_CLOCK(PRINTF); } } delete buffer; #ifdef ENABLE_OPTIMIZATION AddTime(Copy_time_start,COPY); #endif } void foo(){ printf("ici"); } #ifndef _WIN32 inline #endif long mpegOutWithVideo::CorrectTS(long bufferlength) { BTRACK; // for each pack we encounter in that buffer, // get the timestamp long nix; // stores the location of the a GOP in the buffer double ts; double ts2; double ts3; //added April 24 2001 if (first_TS_correction) ts_correction = 0.0; //end added int nbofTS; long i; long saved_i; nix = -1; //9 is for 4 bytes PACKstartcode + 5 bytes PACKTS for ( i=0; i < bufferlength - 9; i++){ // printf("i vaut %d\n",i); if ((buffer[i]== 0x00) && (buffer[i + 1] == 0x00) && (buffer[i + 2] == 0x01)) { switch(buffer[i + 3]) { case 0xB3: // found a sequence header if (aspect_correction) { buffer[i + 7] = ((buffer[i + 7] & 0xf ) | forced_sequence_header); } break; case 0xB8: // found a GOP if (mpeg_version != 2) { // it worked before without correction of GOPS in mpeg1 so why change ? break; } else { #ifdef _DEBUG_ fprintf(stderr,"mpeg2 GOP found!\n"); fprintf(stderr,"TS GOP mpeg2: %f before : %f (delta %f) [pack]\n",ts+ts_correction,ts,ts_correction); #endif memReadTS(i + 4, &ts, true); if (first_TS_correction) { // did another GOP appear before a pack ? - problem if (nix != -1) fprintf(stderr,"lost one gop correction, this should not happen!\n"); nix = i; // do that later impossible to know now the correct value // I figured out the the TS of GOPS most time are higher then in the PACKs // TS must be corrected, but if the value would be taken from the GOP TS // that would be wrong, so do it later #ifdef _DEBUG_ fprintf(stderr,"first TS correction delayed\n"); #endif } } break; case 0xBA: //we have a PACK //DBG // printf("PACK "); if (mpeg_version == 2) { memReadTS(i + 4, &ts, true,true); } else memReadTS(i + 4, &ts); if (first_TS_correction) { first_TS_correction = false; ts_correction=currentTS - ts + base_TS_correction; #ifdef _DEBUG_ fprintf(stderr,"FirstTS Corr: current: %f, ts: %f, base_TS_corr %f\n",currentTS,ts,base_TS_correction); #endif if ( nix != -1) { memReadTS(nix + 4, &ts3,true); #ifdef _DEBUG_ fprintf(stderr,"delayed correction executed now: at: %ld ts: %lf tscorrection: %lf TS: %lf \n",nix,ts3,ts_correction, ts3 + ts_correction); #endif memWriteTS(nix + 4, ts3 + ts_correction,true); nix = -1; // clear } } #ifdef _DEBUG_ fprintf(stderr,"TS: %f before : %f (delta %f) [pack]\n",ts+ts_correction,ts,ts_correction); #endif currentTS=ts + ts_correction; #ifdef _DEBUG fprintf(stderr, "pack current TS is now %f\n",currentTS); #endif if (currentTS < 0.0 ){ currentTS = 0.0; fprintf(stderr,"PACK: TS <0, corrected to 0, movie will have problems playing!\n"); } if (mpeg_version == 2) { #ifdef _DEBUG_ fprintf(stderr,"memwriteTS mpeg2\n"); #endif memWriteTS(i + 4, currentTS, true,true); } else memWriteTS(i + 4, currentTS); #ifdef _DEBUG_ // debug fprintf(stderr,"PACK "); memReadTS(i+4,&ts,true); #endif break; // philipp xxx case 0xC0 : // Found a mpeg audio PES header case 0xE0 : // Found a mpeg video PED header // for processing DVDs, this must be expanded in a future version ! #ifdef _DEBUG_ fprintf(stderr,"PES HEADER, "); if (buffer[i + 3] == 0xE0) fprintf(stderr,"video stream\n" ); else fprintf(stderr,"audio stream\n" ); #endif //skip packet start code & length field #ifdef _DEBUG_ fprintf(stderr,"\nOffset: %ld The bytes...: %2x %2x %2x %2x %2x %2x\n",i,buffer[i + 0],buffer[i + 1],buffer[i + 2],buffer[i + 3],buffer[i + 4],buffer[i + 5] ); #endif saved_i = i + 6; i += 6; #ifdef _DEBUG_ fprintf(stderr,"Offset: %ld The bytes...: %2x %2x %2x %2x %2x %2x\n",i,buffer[i + 0],buffer[i + 1],buffer[i + 2],buffer[i + 3],buffer[i + 4],buffer[i + 5] ); #endif nbofTS = memReadPktTS(&i, &ts, &ts2, bufferlength); if (first_TS_correction) { //ooops ts_correction not initialized... cheat. if (nbofTS >= 1) ts_correction=currentTS - ts + base_TS_correction; } #ifdef _DEBUG_ if (nbofTS != 0) fprintf(stderr,"!!!!!!!!1nbofTS: %d\n",nbofTS); #endif if (nbofTS == 1) { //only one pts to change ts += ts_correction; if (ts < 0) { ts = 0; fprintf(stderr,"PES01: TS <0, corrected to 0, movie will have problems playing!\n"); // negative TS are no good, better set to 0 but what about playback ..? } // ts = (ts < 0)?0:ts; //I know this is dirty // for what ever reason my compile did ignore the above statement replaced by above it // printf("pts current TS is now %f\n",ts); if (mpeg_version == 2) memWriteTS(i - 5, ts); else memWriteTS(i - 5, ts); // fprintf(stderr,"1 TS written at %d\n", (i - 5) - saved_i); // if (i - 5 - saved_i == 0) fprintf(stderr, "ZERO FOUND\n"); // fprintf(stderr,"-3"); break; } if (nbofTS == 2) { //two ts to change ts += ts_correction; ts2 += ts_correction; if ( ts < 0 ) { ts = 0; fprintf(stderr,"PES02: TS <0, corrected to 0, movie will have problems playing!\n"); } if ( ts2 < 0 ) { ts2 = 0; fprintf(stderr,"PES03: TS <0, corrected to 0, movie will have problems playing!\n"); } // fprintf(stderr,"pts current TS is now %f\n",ts); // fprintf(stderr,"dts current TS is now %f\n",ts2); /* memWriteTS(i-5,ts); memWriteTS(i,ts2); */ if (mpeg_version == 2) { memWriteTS(i - 10, ts); memWriteTS(i - 5, ts2); } else { memWriteTS(i - 10, ts); memWriteTS(i - 5, ts2); } //fprintf(stderr,"2 TS written at %d and %d\n", // (i - 10) - saved_i, (i - 5) - saved_i); // fprintf(stderr,"--3"); break; } if (nbofTS == -1) { // fprintf(stderr,"buffer problem here not handled, taking care later buffer: %ld\n",i); return i; break; } if (nbofTS) { // all other return codes are impossible! fprintf(stderr,"we should not get to this point please report this error! nbofTS: %d\n",nbofTS); return -1; break; } break; } //switch } //if } //for return 0; } void mpegOutWithVideo::memReadTS(long offset, double* ts, bool mpeg2pack, bool pack){ BTRACK; byte highbit; unsigned long low4Bytes; double TS; byte *nix; #ifdef _DEBUG_ printf("\nReading TS at offset [" _OFF_x "]\n", offset + FTELL(MpegOut)); print_ts(&(buffer[offset ])); #endif //debug if (!mpeg2pack) { // mpeg1 is different from 2! highbit= (buffer[offset]>>3)&0x01; low4Bytes = ((buffer[offset] >> 1) & 0x03) << 30; low4Bytes |= buffer[offset + 1] << 22; // hours low4Bytes |= (buffer[offset + 2] >> 1) <<15; // minutes low4Bytes |= buffer[offset + 3] << 7; low4Bytes |= buffer[offset + 4] >> 1; #define FLOAT_0x10000 (double)((unsigned long)1 << 16) #define STD_SYSTEM_CLOCK_FREQ (unsigned long)90000 TS = (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000); TS += (double)(low4Bytes); TS /= (double)(STD_SYSTEM_CLOCK_FREQ); *ts = TS; #ifdef _DEBUG_ printf("TS1 : base : 0x%d,%032lx ",highbit,low4Bytes); printf ("TS1 : %lf\n",TS); fprintf(stderr,"\nTS mpeg 1 : %02x, %02x %02x %02x %02x, [%lx]\n", highbit, byte((low4Bytes>>24)&0xFF), byte((low4Bytes>>16)&0xFF), byte((low4Bytes>>8)&0xFF), byte((low4Bytes)&0xFF), (unsigned long) (offset) ); fprintf(stderr,"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x highBit=%d low4Bytes=%ld\n", buffer[offset-4], buffer[offset-3], buffer[offset-2], buffer[offset-1], buffer[offset-0], buffer[offset+1], buffer[offset+2], buffer[offset+3], buffer[offset+4], buffer[offset+5], highbit, low4Bytes ); #endif } else { //mpeg2 header PACK or GOP unsigned long sys_clock_ref; highbit= (buffer[offset] & 0x20) >> 5; if (pack) { #ifdef _DEBUG fprintf(stderr,"NO gop!\n"); #endif low4Bytes = ((buffer[offset] & 0x18) >> 3) << 30; low4Bytes |= (buffer[offset] & 0x03) << 28; low4Bytes |= buffer[offset + 1] << 20; low4Bytes |= ((buffer[offset + 2] & 0xF8)) << 12; low4Bytes |= (buffer[offset + 2] & 0x03) << 13; low4Bytes |= buffer[offset + 3] << 5; low4Bytes |= (buffer[offset + 4]) >> 3; } else // a GOP { // move the 32 bit in a long low4Bytes = ( (buffer[offset] & 0x7c) >> 2) << 24; low4Bytes |= (buffer[offset] & 0x3) << 20; low4Bytes |= (buffer[offset +1 ] & 0xF0) << 12; low4Bytes |= (buffer[offset +1 ] & 0x7) << 11; low4Bytes |= (buffer[offset +2 ] & 0xE0) << 3; low4Bytes |= (buffer[offset +2 ] & 0x1F) << 1; low4Bytes |= (buffer[offset +3 ] & 0x80) >> 7; } sys_clock_ref=(buffer[offset + 4] & 0x3) << 7; sys_clock_ref|=(buffer[offset + 5] >> 1); if (pack) { TS = (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000); TS += (double)(low4Bytes); // + (double) ((double) sys_clock_ref / 512); } else { // I love "nix" nix = (byte *) &low4Bytes; TS = 60 * 60 * *nix; TS += 60 * *(nix +1); TS += *(nix +2); TS += ((double) *(nix +3)) / 60; } if (pack) { if (sys_clock_ref == 0) { TS /= (double)(STD_SYSTEM_CLOCK_FREQ); #ifdef _DEBUG_ fprintf(stderr,"**ts divided by std_sysclock_fewq, now: %lf\n",TS); #endif } else { // this is what I understood... CHECK // if not zero, then we have a 27 MHz accuracy with a max of 27 MHz // so clockfreq might well be 27MHz / sys_clock_ref // this is nonsense ... // sysclockref is only the remainder of the division of 27MHZ/300 // I guess we can safely ignore it // fprintf(stderr,"syslockref: %ld\n",sys_clock_ref); // TS /= (double)(27000000 / sys_clock_ref); TS /= (double)(STD_SYSTEM_CLOCK_FREQ); // if sysclock ref != 0, this is the remainder of the divison of 27mhz by300 #ifdef _DEBUG_ fprintf(stderr,"XXts divided by sys_clock_ref, now: %lf\n",TS); #endif } } //debug #ifdef _DEBUG_ printf("TS2 : base : 0x%d,%032lx ref : %016lx\n",highbit,low4Bytes,sys_clock_ref); printf ("TS2 : %lf\n",TS); fprintf(stderr,"\nTS mpeg 2 : %02x, %02x %02x %02x %02x, %lx [%lx]\n", highbit, byte((low4Bytes>>24)&0xFF), byte((low4Bytes>>16)&0xFF), byte((low4Bytes>>8)&0xFF), byte((low4Bytes)&0xFF), sys_clock_ref, (unsigned long) (offset) ); fprintf(stderr,"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x highBit=%d low4Bytes=%ld sysclockref=%ld\n", buffer[offset-4], buffer[offset-3], buffer[offset-2], buffer[offset-1], buffer[offset-0], buffer[offset+1], buffer[offset+2], buffer[offset+3], buffer[offset+4], buffer[offset+5], highbit, low4Bytes, sys_clock_ref ); #endif *ts=TS; } //DBG // fprintf(stderr,"------ TS = %f ",TS); } void mpegOutWithVideo::memWriteTS (long offset, double ts, bool mpeg2pack, bool pack){ BTRACK; // fprintf(stderr, " ts is %f\n",ts); byte uppercode = buffer[offset] & 0xF0; byte hiBit; long lowInt=0; double TS=ts; int hour; int minute; int sec; int pics; if (!mpeg2pack) { ; } TS *= STD_SYSTEM_CLOCK_FREQ; if (TS > FLOAT_0x10000 * FLOAT_0x10000) { hiBit = 1; TS -= FLOAT_0x10000 * FLOAT_0x10000; } else { hiBit = 0; lowInt = (long) TS; } if (!mpeg2pack){ uppercode = uppercode | (hiBit << 3) | ((lowInt & 0xC0000000) >> 29) | 0x01; lowInt = 0x00010001 | ((lowInt & 0x3FFF8000) << 2) | ((lowInt & 0x00007FFF) << 1); buffer[offset] = uppercode; buffer[offset+1] = (byte)(lowInt>>24); buffer[offset+2] = (byte)((lowInt>>16)&0xFF); buffer[offset+3] = (byte)((lowInt>>8)&0xFF); buffer[offset+4] = (byte)(lowInt&0xFF); } else { if (pack) { // mpeg 2 PACK byte work; work = 0x40; //marker bit work |= hiBit << 5; //hiBit work |= lowInt >> 27 ; // two MSBs work |= 0x04; //marker bit work &= 0xFC; // clear the two LSB work |= (lowInt >> 28) & 0x03; // two more MSBs buffer[offset] = work; // marker buffer[offset+1] = (byte)((lowInt>>20)&0xFF); buffer[offset+2] = (byte)((((lowInt>>12)&0xF8))|((lowInt>>13)&0x03)|0x04); buffer[offset+3] = (byte)((lowInt>>5)&0xFF); buffer[offset+4] = (byte)(((lowInt<<3)&0xFF)|0x04); buffer[offset+5] = 0x01;//sys clock ref extension =0 } else { // mpeg2 GOP hour = int(TS / 60 / 60); minute = int(TS / 60); sec = int(TS); pics = int((TS - ((long) TS)) * 60); buffer[offset] &= 0x7f; // clear hour & 2 bits from minute buffer[offset +1] &= 0x8; // clear minutes & seconds buffer[offset +2] &= 0; buffer[offset +3] &= 0x7f; buffer[offset] |= ( hour << 2); buffer[offset] |= ( minute >> 4); buffer[offset +1] |= (( minute & 0xf) << 4); buffer[offset +1] |= ( sec >> 3); buffer[offset +2] |= ( sec & 0x7) << 5; buffer[offset +2] |= ( pics >> 1); buffer[offset +3] |= ( pics & 0x1) << 7; } } // fprintf(stderr,"TS Write %lf ------\n",ts); //if (mpeg2pack) { // fprintf(stderr,"\n xxxxxxxxxxx"); // memReadTS(offset,&ts9,true,true); // fprintf(stderr," xxxxxxxxxxxx\n"); //} } int mpegOutWithVideo::memReadPktTS(long* off, double* pts, double* dts, long bufferlength) { BTRACK; //just after the packet start code. and the length field byte mybyte; off_t offset=*off; //get rid of stuffing bytes mybyte=buffer[offset]; if (mpeg_version != 2) // currenlty I dont believe in stuffing bytes here in case of mpeg2! { // also stuffing bytes should be FF and not 80 ? // next time check if this is not better with mpeg1 also....! while((mybyte & 0x80) && (offset <= bufferlength - 5)) { //this has to be a stuffing byte // fprintf(stderr,"removed a stuffing byte ??\n"); mybyte = buffer[++offset]; } } //here mybyte is the first valid byte if (mpeg_version == 2){ //skip the first byte ++offset; mybyte = buffer[offset]; mybyte >>= 6; switch (mybyte) { case 0: return 0; case 1: #ifdef _DEBUG_ fprintf(stderr,"Invalid PTS DTS flag at [" _OFF_x "]\n", offset); #endif return 0; case 2: //only PTS; if (offset > bufferlength - 7) { // we have a valid header but no room to read the entire TS // fprintf(stderr,"Copy Buffer-problem! -1\n"); return -1; } offset += 2; memReadTS(offset,pts); offset += 5; *off = offset; return 1; case 3: //both PTS and DTS if (offset > bufferlength - 5) { // we have a valid header but no room to read the entire TS // fprintf(stderr,"Copy Buffer-problem! -1\n"); return -1; } offset += 2; memReadTS(offset, pts); offset += 5; if (offset > bufferlength - 5) { // we have a valid header but no room to read the entire TS // fprintf(stderr,"Copy Buffer-problem! -1\n"); return -1; } memReadTS(offset, dts); offset += 5; *off = offset; return 2; } //switch return 0; } else { // MPEG 1 if ((mybyte >> 6) == 0x01) { //std buffer scale stuff... let's skip it offset += 2; mybyte = buffer[offset]; } if ((mybyte >> 4) == 0x02) { // dts Time stamp if (offset > bufferlength - 5) { // we have a valid header but no room to read the entire TS // fprintf(stderr,"Copy Buffer-problem! -1\n"); return -1; } //DBG // printf("PTS "); memReadTS(offset, pts); offset += 5; *off = offset; return 1; } else if ((mybyte >> 4) == 0x03) { //both pts and dts time stamps if (offset > bufferlength - 5) { // we have a valid header but no room to read the entire TS // fprintf(stderr,"Copy Buffer-problem! -2\n"); return -1; } *off = offset; //DBG // printf("PTS "); memReadTS(offset, pts); offset += 5; if (offset > bufferlength - 5) { // we have a valid header but no room to read the entire TS *off = offset; return 1; //1 for one valid TS found } //DBG // printf("DTS "); memReadTS(offset, dts); offset += 5; *off = offset; return 2; } } return 0; } mpegOut* mpegOutFactory::NewMpegFrom(mpeg* MpegIn, char* filename){ BTRACK; mpegOut* object; switch(MpegIn->MpegType) { case mpeg_AUDIO: object = new mpegAudioOut(filename); break; case mpeg_VIDEO: object = new mpegVideoOut(filename); break; case mpeg_SYSTEM: object = new mpegSystemOut(filename); break; default: object = 0; break; } if (object) { if (object->OutFile()) object->WriteHeader(MpegIn); else { delete object; object = 0; } } return object; } mpegOut* mpegOutFactory::NewMpegFrom(mpeg* MpegIn, FILE* filehandle){ BTRACK; mpegOut* object; switch (MpegIn->MpegType) { case mpeg_AUDIO: object = new mpegAudioOut(filehandle); break; case mpeg_VIDEO: object = new mpegVideoOut(filehandle); break; case mpeg_SYSTEM: object = new mpegSystemOut(filehandle); break; default: object = 0; break; } if (object) object->WriteHeader(MpegIn); return object; } /* class demuxer{ public: demuxer(mpeg* _Mpeg,char* videofile, char* audiofile); WriteChunk(off_t from, off_t to, bool from_included, bool to_included); protected: demuxer(){}; FILE* AudioOut; FILE* VideoOut; mpeg* Mpeg; }; */ demuxer::demuxer(mpeg* _Mpeg, char* _basename, bool _confirm) :n_audio(0),n_video(0),n_programs(0),Mpeg(_Mpeg),confirm(_confirm),buffer(0) { BTRACK; basename = new char[strlen(_basename) + 1]; strcpy(basename,_basename); // convention for Audiofile and Videofile : // if Audiofile[i]==0 : file is to be opened with basename // if Audiofile[i]==-1 stream is to be ignored. // this way piping a stream to stdout is eq to Audiofile[i]=stdout for(int i = 0; i < 16; i++){ AudioFile[i] = VideoFile[i] = 0; } } demuxer::~demuxer() { BTRACK; if (buffer) delete[]buffer; for (int i = 0; i < 16; i++) { if (AudioFile[i]) fclose(AudioFile[i]); if (VideoFile[i]) fclose(VideoFile[i]); } } int demuxer::Process(){ BTRACK; if (Mpeg == 0) return 0; // fprintf(stderr,"start demux run \n"); if (Mpeg->MpegType == mpeg_SYSTEM) { // fprintf(stderr,"ProcessProgramStream\n"); return ProcessProgramStream(); } if (Mpeg->MpegType == mpeg_TRANSPORT) { // fprintf(stderr,"ProcessTransportStream\n"); return ProcessTransportStream(); } //else :) fprintf(stderr,"mpeg file %s can not be demultiplexed" " (neither System nor Program stream)\n", Mpeg->FileName); return 0; } int demuxer::ProcessTransportStream() { BTRACK; if (!Mpeg->Transport) return 0; int pr; int stream_num; off_t offset = 0; off_t FileSize = Mpeg->Size(); PID pid; EStream *currentStream; off_t start, end; n_programs = Mpeg->Transport->n_progs; int feedback = 0; while (true) { pid = Mpeg->NextTrPacket(&offset,&start,&end); if (start == -1) { if (print_progress){ fprintf(stderr," Demultiplexing : [Programs %02d audio %02d video %02d] [100.00%%]\n", n_programs,n_audio,n_video); } return n_audio + n_video; } if (start == end) continue; for (pr = 0; pr < Mpeg->Transport->n_progs; pr++) { currentStream = Mpeg->Transport->programs[pr].TStreams; stream_num = 0; while (currentStream !=0){ stream_num++; if (currentStream->pid == pid) { // this is the good one if (currentStream->demuxFileOk) { if (currentStream->demuxFile == 0x0) { // file is not created char* tempname = new char[300]; sprintf(tempname, "%s-%d-%d.", basename, Mpeg->Transport->programs[pr].prog_num, stream_num); switch (currentStream->type) { case 1: strcat(tempname, "m1v"); n_video++; break; case 2: strcat(tempname, "m2v"); n_video++; break; case 3: strcat(tempname, "mp3"); n_audio++; break; case 4: strcat(tempname, "mp3"); n_audio++; break; default: strcat(tempname, "unk"); break; } currentStream->demuxFile = openfile(tempname); delete[] tempname; } // if currentStream->demuxFile still 0 : problem if (currentStream->demuxFile == 0x0) { fprintf(stderr, "skipping Program %d stream %d\n", Mpeg->Transport->programs[pr].prog_num, stream_num); currentStream->demuxFileOk = false; } else { // Copy(currentStream->demuxFile,start,end); DemuxTrPkt(currentStream->demuxFile, start, end); if ((feedback++ == 100)) { feedback = 0; if (print_progress){ fprintf(stderr, " Demultiplexing : [Programs %02d audio %02d video %02d] [%6.2f%%]\r", n_programs, n_audio, n_video, offset*100.0/FileSize); } } } //else } //if } //if currentStream = currentStream->next; } //while } //for #ifdef _DEBUG_ // printf("PID %d has payload [%llx %llx]\n", pid, start, end); #endif } //while (true) return 0; } int demuxer::DemuxTrPkt(FILE* out, off_t start, off_t end){ BTRACK; // we have a transport packet, let's remove the program packet headers marker mark; off_t packetheader = Mpeg->FindNextMarker(start, &mark); off_t packetend = Mpeg->SkipPacketHeader(packetheader); mark &= 0xF0; if (mark==0xC0 || mark==0xE0 || mark==0xD0) { if (packetheader < 0 || packetheader > end) { // no packet header in the boundaries Copy(out, start, end); return 0; } if (packetend > end) { //serious problem return -1; } //here we have to issue two Copy Copy(out, start, packetheader); Copy(out, packetend, end); return 1; } else { Copy(out, start, end); return 1; } } int demuxer::ProcessProgramStream(){ BTRACK; marker mark; off_t from, to; off_t FileSize = Mpeg->Size(); off_t bytestoskip = 1; FILE* outfile; char* filename; int streamnumber; off_t offset; int progress = 0; // fprintf(stderr,"sizeof Mpeg->Size(): %ld \n", sizeof(Mpeg->Size())); // fprintf(stderr,"Mpeg->Size(): %qd \n", Mpeg->Size()); for (offset = 0; offset < Mpeg->Size(); offset += bytestoskip) { // fprintf(stderr,"Mpeg->Size(): %qd, offset: %qd\n", Mpeg->Size(), offset); offset = Mpeg->FindNextMarker(offset,&mark); // fprintf(stderr,"ok, next marker found offset: %qd\n",offset); if (offset == -1) { // either we finished or unrecoverable error if (print_progress){ fprintf(stderr," Demultiplexing : [audio %02d video %02d] [100.00%%]\n", n_audio,n_video); } return n_audio+n_video; } ++progress; if ((print_progress) && (progress % 100 == 0)){ progress = 0; fprintf(stderr," DemultiplexingXXX : [audio %02d video %02d] [%6.2f%%]\r", n_audio,n_video, offset*100.0/FileSize); } fflush(stderr); if (((mark&0xF0) == 0xC0) || ((mark&0xF0) == 0xD0)) { //new in mpeg 2 : audio streams are : 110x xxxx //audio packet streamnumber = mark&0x0F; if (AudioFile[streamnumber]) { //file is already opened or stream has to be ignored } else { //file has to be opened filename = new char[300]; n_audio++; sprintf(filename,"%s-%d.mp%d", basename, streamnumber, Mpeg->Audio->layer); AudioFile[streamnumber] = openfile(filename); delete[] filename; } outfile = AudioFile[streamnumber]; } else if ((mark&0xF0)==0xE0){ // fprintf(stderr,"here 01\n"); //video packet streamnumber=mark&0x0F; if (VideoFile[streamnumber]){ //file is already opened } else{ //file has to be opened filename=new char[300]; n_video++; sprintf(filename,"%s-%d.m%dv",basename,streamnumber,Mpeg->mpeg_version); VideoFile[streamnumber]=openfile(filename); delete[] filename; } outfile=VideoFile[streamnumber]; } else { //neither Audio nor Video continue; } // fprintf(stderr,"here 02\n"); //whatever it is it outfile mustn't be 0 nor 1 // if outfile is still 0 there was a problem opening it // if outfile is -1 we were asked to skip it if (outfile==0 || outfile==(FILE*)(0x1)) { // fprintf(stderr,"skipped stream %x\n",mark); continue; } // now we have to find out where it begins and where it ends int length = ((Mpeg->Byte(offset+4)<<8) | Mpeg->Byte(offset+5)); from = Mpeg->SkipPacketHeader(offset); to = offset + length + 6; if (to <= from) { fprintf(stderr, "Erroneous packet size, skipping\n"); offset++; continue; } START_CLOCK Copy(outfile, from, to); STOP_CLOCK(COPY) offset = to - 1; if (to >= FileSize) offset = FileSize; } START_CLOCK if ((print_progress ) && (progress % 1000 == 0)){ progress = 0; fprintf(stderr," Demultiplexing: [audio %02d video %02d] [100.00%%]\n", n_audio,n_video); } STOP_CLOCK(PRINTF) return 1; } off_t demuxer::Copy(FILE* into, off_t from, off_t to) { BTRACK; off_t size = to -from; off_t read_size = 0; // float percent; // fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut)); size_t size2read=(size>COPYBUFFERSIZE)?COPYBUFFERSIZE:size; if(!buffer) buffer= new byte[COPYBUFFERSIZE]; while (read_size < size) { size2read = ((size-read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size; FSEEK(Mpeg->MpegFile, from + read_size, SEEK_SET); read_size += fread(buffer, 1, size2read, Mpeg->MpegFile); fwrite(buffer, 1, size2read, into); // if(print_progress){ //lperc=(read_size*100)/(size/100); // percent= (read_size*1.0)/(size/100); // fprintf(stderr,"\b\b\b\b\b\b\b\b%5.2f%% ",percent); // fflush(stderr); // } } // delete buffer; return to; } FILE* demuxer::openfile(char* filename) { BTRACK; FILE* temp; if (!confirm){ temp = fopen(filename, "wb"); if (temp==0){ // problem fprintf(stderr,"\n"); perror(filename); } return temp; } else { //must check if file exist temp = fopen(filename, "rb"); if (temp != 0) { //file is readable, it exists fprintf(stderr,"file %s exists, overwrite ? [N/y/a]: \b\b\b\b",filename); fflush(stderr); char answer = getchar(); switch (answer) { case 'a': case 'A': confirm = false; break; case 'y': case 'Y': temp = fopen(filename, "wb"); if (temp == 0) { // problem fprintf(stderr, "\n"); perror(filename); } return temp; break; // default: return 0; default: fprintf(stderr,"Aborted\n"); exit(1); } //switch } else { //file does not exist temp = fopen(filename, "wb"); if (temp == 0) { // problem fprintf(stderr, "\n"); perror(filename); } return temp; } } fprintf(stderr,"we should not get here!\n"); return NULL; } void print_ts(byte *p) { int hour, min, sec, pictures, drop, closed, broken; byte *head; head = (byte *) (p); // calculate GOP information .. this is from gop Chop, thanks! /* 4 5 6 7 | | | | 7 65432 107654 3 210765 432107 6 543210 1 11111 111111 1 111111 111111 1 1 d hour min m sec pic c b r a l roken o r osed p k */ fprintf(stderr,"data: %2x %2x %2x %2x\n",head[0],head[1],head[2],head[3]); drop=((head[0]&0x80)>0); hour=((head[0]&0x7C)>>2); min=((head[0]&0x3)<<4)|((head[1]&0xF0)>>4); sec=((head[1]&0x7)<<3)|((head[2]&0xE0)>>6); pictures=((head[2]&0x3F)<<1)|((head[3]&0x80)>>7); closed=((head[3]&0x40)>0); broken=((head[3]&0x20)>0); fprintf(stderr,"TS mpg2 INFO: %02d:%02d:%02d.%02d\n",hour,min,sec,pictures); } mpgtx-1.3.1/mpegOut.hh0000644000175000001440000000753010157126506014412 0ustar esusers00000000000000/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #ifndef __mpegOut_hh_ #define __mpegOut_hh_ #include "common.hh" #include "mpeg.hh" // required by access() // FIXME: Still needed, because we have mpgtx_access()? #include class mpeg; class mpegOut { public: mpegOut(char *filename); mpegOut(FILE *filehandle); virtual ~mpegOut(); const FILE* OutFile() {return MpegOut;} int WriteChunk(mpeg* Mpeg, off_t from, off_t to) {return WriteChunk(Mpeg, from, false, to, true);}; virtual void WriteHeader(mpeg* Mpeg) = 0; virtual int WriteChunk (mpeg* Mpeg, off_t from, bool from_included, off_t to, bool to_included) = 0; virtual void Finish() {}; protected: mpegOut() {}; virtual void Copy(FILE* file, off_t from, off_t to) = 0; int FileType; bool HasAudio,HasVideo; FILE* MpegOut; byte* buffer; }; class mpegOutWithVideo : public mpegOut { protected: mpegOutWithVideo(char* filename) : mpegOut(filename) {mpeg_version = 0;}; mpegOutWithVideo(FILE* filehandle) : mpegOut(filehandle) {mpeg_version = 0;}; mpegOutWithVideo(){}; long CorrectTS(long bufferlength); void memReadTS(long offset, double* ts, bool mpeg2pack = false, bool pack = false); int memReadPktTS(long* off, double* pts, double* dts, long bufferlength); void memWriteTS(long offset, double ts, bool mpeg2pack = false, bool pack = false); double currentTS; double ts_correction; bool first_TS_correction; int mpeg_version; }; class mpegVideoOut : public mpegOutWithVideo { public: mpegVideoOut(char* filename) : mpegOutWithVideo(filename) {}; mpegVideoOut(FILE* filehandle) : mpegOutWithVideo(filehandle) {}; void WriteHeader(mpeg* Mpeg); int WriteChunk (mpeg* Mpeg, off_t from, bool from_included, off_t to, bool to_included ); protected: mpegVideoOut(){}; void Copy(FILE* file, off_t from, off_t to); }; class mpegSystemOut : public mpegOutWithVideo { public: mpegSystemOut(char* filename) : mpegOutWithVideo(filename) {partial_packet = 0;}; mpegSystemOut(FILE* filehandle) : mpegOutWithVideo(filehandle) {partial_packet = 0;}; void WriteHeader(mpeg* Mpeg); int WriteChunk(mpeg* Mpeg, off_t from, bool from_included, off_t to, bool to_included ); void Finish(); protected: mpegSystemOut() {}; void Copy(FILE* file, off_t from, off_t to); //size of data from the end of the packet header to the end of file off_t partial_packet_length; //keep the partial packet in memory (because stdout is not seekable) byte* partial_packet; }; class mpegAudioOut : public mpegOut { public: mpegAudioOut(char* filename): mpegOut(filename){}; mpegAudioOut(FILE* filehandle): mpegOut(filehandle){}; void WriteHeader(mpeg* Mpeg){}; int WriteChunk(mpeg* Mpeg, off_t from, bool from_included, off_t to, bool to_included ); void Finish(); protected: mpegAudioOut(){}; void Copy(FILE* file, off_t from, off_t to); }; class mpegOutFactory { public: mpegOut* NewMpegFrom(mpeg* MpegIn, char* filename); mpegOut* NewMpegFrom(mpeg* MpegIn, FILE* filehandle); }; class demuxer { public: demuxer(mpeg* _Mpeg, char* _basename, bool _confirm = true); ~demuxer(); int Process(); protected: int ProcessTransportStream(); int ProcessProgramStream(); int DemuxTrPkt(FILE* out, off_t start, off_t end); FILE* openfile(char* filename); off_t Copy(FILE* into, off_t from, off_t to); demuxer() {}; FILE* AudioFile[16]; int n_audio; FILE* VideoFile[16]; int n_video; int n_programs; mpeg* Mpeg; char* basename; bool confirm; byte* buffer; }; #endif //__mpegOut_hh_ mpgtx-1.3.1/mpgtx.spec0000644000175000001440000000272510165227425014466 0ustar esusers00000000000000# Note that this is NOT a relocatable package Name: mpgtx Version: 1.3.1 Release: 1 Summary: mpgtx, an MPeG ToolboX Copyright: GPL Group: Applications/File Vendor: Laurent Alacoque Packager: Volker Moell URL: http://mpgtx.sourceforge.net/ Source: http://download.sourceforge.net/mpgtx/%{name}-%{version}-%{release}-src.tgz BuildRoot: %{_tmppath}/%{name}-buildroot Prefix: %{_prefix} #Requires: %description mpgtx allows you to split, join, demultiplex, manipulate ID3v1 tags and fetch detailed information about a variety of MPEG files. mpgtx was designed with the good old Unix philosophy in mind: 'do little, but do it well, and provide the end user with an austary yet powerfull command line interface.' %prep %setup %build configure && make %install make install PREFIX=$RPM_BUILD_ROOT%{prefix} %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT %pre %post %preun %postun %files %defattr(-,root,root) %{prefix} %doc AUTHORS COPYING ChangeLog README %changelog * Sat Dec 25 2004 Erik Schanze - Update to current version * Wed Aug 22 2001 Laurent Alacoque - changed the default target since Makefile has dramatically changed * Mon Mar 26 2001 Laurent Alacoque - fixed the libxalflaunch.so dependency * Fri Mar 23 2001 Laurent Alacoque - install -d are now in makefile - changed make to make shared * Tue Mar 23 2001 Volker Moell - Wrote this specfile; first build