Projects
Multimedia
lxdvdrip
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
lxdvdrip.spec
Changed
@@ -12,8 +12,8 @@ Summary(de): Video-DVD Backup Programm License: GPL Group: Productivity/Multimedia/Video/Editors and Convertors -URL: http://lxdvdrip.berlios.de/ -Version: 1.76 +URL: http://sourceforge.net/p/lxdvdrip/home/Homepage/ +Version: 1.77 Release: 1 Source0: lxdvdrip-%{version}.tar.bz2 Patch0: lxdvdrip_conf.diff @@ -82,7 +82,7 @@ cd vamps && make && cd .. cd dvdbackup && make && cd .. cd requant && make && cd .. -cd buffer && make && cd .. +cd mbuffer && make && cd .. %install %{__rm} -rf CVS @@ -97,7 +97,7 @@ %{__install} -m 0755 vamps/play_cell_lxdvdrip %{buildroot}/%{_bindir}/ %{__install} -m 0755 dvdbackup/dvdbackup_lxdvdrip %{buildroot}/%{_bindir}/ %{__install} -m 0755 requant/requant_lxdvdrip %{buildroot}/%{_bindir}/ -%{__install} -m 0755 buffer/buffer %{buildroot}/%{_bindir}/buffer_lxdvdrip +%{__install} -m 0755 mbuffer/mbuffer_lxdvdrip %{buildroot}/%{_bindir}/ %{__install} -m 0644 doc-pak/lxdvdrip.conf.DE %{buildroot}%{_sysconfdir}/lxdvdrip.conf %{__install} -m 0644 lxdvdrip.wav %{buildroot}%{_datadir}/ %{__install} -m 0644 lxdvdrip.1 %{buildroot}%{_mandir}/man1/ @@ -115,6 +115,15 @@ %{_mandir}/man1/lxdvdrip.* %changelog +* Thu Nov 24 2011 Manfred Tremmel <Manfred.Tremmel@iiv.de> - 1.77-0.pm.1 +update to 1.77: +- Bugfix mode "vamps_menu": DVD-structure from hardisk can be copied. +- wodim/genisoimage replaces cdrecord/mkisofs. +- Fix building on Ubuntu 11.10. +- Mbuffer replaces buffer (lxdvdrip -st=trans_par). +- Support for dvdauthor 0.7: Create file ~./config/video_format with content PAL/NTSC. +- Support for dvdauthor 0.7: Patches (against error "SCR moves backwards"). +- Bugfix vlc as streamtool: Use dvdsimple instead of dvd. Else vlc does not quit. * Wed Apr 14 2010 Manfred Tremmel <Manfred.Tremmel@iiv.de> - 1.76-0.pm.1 - update to 1.76 * Thu Feb 18 2010 Manfred Tremmel <Manfred.Tremmel@iiv.de> - 1.75-1.pm.3
View file
lxdvdrip_conf.diff
Changed
@@ -1,5 +1,5 @@ ---- doc-pak/lxdvdrip.conf.DE.orig 2010-02-20 17:37:42.000000000 +0100 -+++ doc-pak/lxdvdrip.conf.DE 2010-04-14 02:46:21.239015369 +0200 +--- doc-pak/lxdvdrip.conf.DE.orig 2011-10-21 20:51:44.000000000 +0200 ++++ doc-pak/lxdvdrip.conf.DE 2011-11-24 11:54:16.825663254 +0100 @@ -54,13 +54,13 @@ # Device fuer DVD-Leselaufwerk. @@ -9,7 +9,7 @@ # Device fuer DVD-Brenner. # Beim Brennen mit "growisofs" ist zumeist "/dev/sr0" die richtige Wahl. - # Bei "cdrecord" zumeist "0,0,0", testen mit "cdrecord -scanbus". + # Bei "wodim" zumeist "0,0,0", testen mit "wodim -scanbus". # Entspricht "-db=". -dvdbrenner=/dev/sr0 +dvdbrenner=/dev/dvdrecorder
View file
lxdvdrip_conf_new.diff
Changed
@@ -1,5 +1,5 @@ ---- doc-pak/lxdvdrip.conf.DE.orig 2010-02-20 17:37:42.000000000 +0100 -+++ doc-pak/lxdvdrip.conf.DE 2010-04-14 02:50:15.491015708 +0200 +--- doc-pak/lxdvdrip.conf.DE.orig 2011-10-21 20:51:44.000000000 +0200 ++++ doc-pak/lxdvdrip.conf.DE 2011-11-24 11:57:03.940463719 +0100 @@ -54,13 +54,13 @@ # Device fuer DVD-Leselaufwerk. @@ -9,7 +9,7 @@ # Device fuer DVD-Brenner. # Beim Brennen mit "growisofs" ist zumeist "/dev/sr0" die richtige Wahl. - # Bei "cdrecord" zumeist "0,0,0", testen mit "cdrecord -scanbus". + # Bei "wodim" zumeist "0,0,0", testen mit "wodim -scanbus". # Entspricht "-db=". -dvdbrenner=/dev/sr0 +dvdbrenner=/dev/dvd
View file
lxdvdrip-1.76.tar.bz2/buffer
Deleted
-(directory)
View file
lxdvdrip-1.76.tar.bz2/buffer/COPYING
Deleted
@@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, 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 - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License.
View file
lxdvdrip-1.76.tar.bz2/buffer/Makefile
Deleted
@@ -1,34 +0,0 @@ -# Make the buffer program - -# You might need to add the following to CGFLAGS: -# -# Add -DSYS5 for A System 5 (USG) version of Unix -# You should also add -DSYS5 for Ultrix, AIX, and Solaris. -# Add -DDEF_SHMEM=n if you can only have n bytes of shared memory -# (eg: -DDEF_SHMEM=524288 if you can only have half a meg.) -# Add -DAMPEX to change the default settings suitable for the high capacity -# Ampex drives, such as the DST 310. - -CC=gcc -CFLAGS=-Wall - -# Where to install buffer -INSTBIN=/usr/local/bin - -RM=/bin/rm -ALL=README Makefile buffer.c sem.c sem.h COPYING - -all: buffer - -buffer: buffer.o sem.o - $(CC) -o buffer $(CFLAGS) buffer.o sem.o - -clean: - $(RM) -f *.o core buffer .merrs - -install: buffer - cp buffer $(INSTBIN)/buffer_lxdvdrip - chmod 755 $(INSTBIN)/buffer_lxdvdrip - -uninstall: buffer - rm -f $(INSTBIN)/buffer_lxdvdrip
View file
lxdvdrip-1.76.tar.bz2/buffer/README
Deleted
@@ -1,51 +0,0 @@ -This is a program designed to speed up writing tapes on remote tape -drives. Requirements are shared memory and locks which normally -means that these are supported in your kernel. - -Buffer has been tested under SunOS 4.0.*, SunOS 4.1.*, Solarix, HP-UX 7.0, -and Gould UTX 2.1A (sv universe). - -The program splits itself into two processes. The first process reads -(and reblocks) from stdin into a shared memory buffer. The second -writes from the shared memory buffer to stdout. Doing it this way -means that the writing side effectly sits in a tight write loop and -doesn't have to wait for input. Similarly for the input side. It is -this waiting that slows down other reblocking processes, like dd. - -I run an archive and need to write large chunks out to tape regularly -with an ethernet in the way. Using 'buffer' in a command like: - - tar cvf - stuff | rsh somebox buffer -o /dev/rst8 - -is a factor of 5 faster than the best alternative, gnu tar with its -remote tape option: - - tar cvf somebox:/dev/rst8 stuff - -We have been using buffer here at Imperial for a couple of years now -for writing tar tapes and the main system dumps. - -Thanks to Kevin Twidle <kpt@doc.ic.ac.uk> for the -p and -B code. -Thanks to Bard Isley <brad@slammer.atl.ga.us> for fixes to the - read loop/SIGCHLD handling. -Thanks to PerSteinar.Iversen@fi.uib.no for the DEC Alpha patches. -Thanks to kargard@ampex.com (Erik L. Kargard) for the AMPEX enhancements. - -INSTALLATION: - Check that your kernel supports shared memory and semaphores. - A quick way to check is to build buffer and run it. - If it says "couldn't create shared memory segment" you probably - need to reconfigure and rebuild your kernel. - - To install edit the Makefile and tailor the variables to - your local systems. Then type make. - -DISCLAIMER: - This package is under the GNU GENERAL PUBLIC LICENSE! - In addtion under NO circumstances can I, or Imperial College, - be held liable for any event caused by the running or storing - of this program or its documentation. - -Lee McLoughlin. Phone: +44 171 594 8388 -IC-Parc, William Penney Lab, Fax: +44 171 594 8449 -Imperial College, London, SW7 2BZ, UK Email: L.McLoughlin@doc.ic.ac.uk
View file
lxdvdrip-1.76.tar.bz2/buffer/buffer.c
Deleted
@@ -1,1014 +0,0 @@ -/* - Buffer. Very fast reblocking filter speedy writing of tapes. - Copyright (C) 1990,1991 Lee McLoughlin - - 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 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Lee McLoughlin. - Dept of Computing, Imperial College, - 180 Queens Gate, London, SW7 2BZ, UK. - - Email: L.McLoughlin@doc.ic.ac.uk -*/ - -/* This is a reblocking process, designed to try and read from stdin - * and write to stdout - but to always try and keep the writing side - * busy. It is meant to try and stream tape writes. - * - * This program runs in two parts. The reader and the writer. They - * communicate using shared memory with semaphores locking the access. - * The shared memory implements a circular list of blocks of data. - * - * L.McLoughlin, Imperial College, 1990 - * - * $Log: buffer.c,v $ - * Revision 1.1.1.13 2010/01/10 15:40:05 stefanbecker - * Fix vlc-calls (dvdsimple=>dvd). - * - * Revision 1.1.1.12 2009/11/03 18:14:04 stefanbecker - * dvdbackup / libdvdread4. - * - * Revision 1.1.1.11 2009/08/08 11:42:07 stefanbecker - * Update to dvd95-1.50p3. - * - * Revision 1.1.1.10 2009/05/19 16:41:45 stefanbecker - * Update to dvd95 1.51. - * - * Revision 1.1.1.9 2009/04/19 19:10:28 stefanbecker - * Bugfix Copy Mode. - * - * Revision 1.1.1.8 2009/03/29 19:30:35 stefanbecker - * dvdbackup buxfix. - * - * Revision 1.1.1.7 2009/02/21 17:20:12 stefanbecker - * call requant_lxdvdrip like tcrequant. - * - * Revision 1.1.1.6 2009/02/18 15:08:38 stefanbecker - * dvdwizard / PAL / NTSC. - * - * Revision 1.1.1.5 2009/01/25 10:46:35 stefanbecker - * Set version to 1.73. - * - * Revision 1.1.1.4 2009/01/20 23:12:24 stefanbecker - * Replace tcrequant with requant_lxdvdrip. - * - * Revision 1.1.1.3 2008/08/06 17:36:41 stefanbecker - * Bugfix reading DVD Structure with Angles. - * - * Revision 1.1.1.2 2008/06/14 22:34:17 stefanbecker - * Fix Compiler Warnings on Suse11. - * - * Revision 1.19 1995/08/24 17:46:28 lmjm - * Be more careful abour EINTR errors - * Ingnore child processes dying. - * - * Revision 1.18 1993/08/25 19:07:31 lmjm - * Added Brad Isleys patchs to read/sigchld handling. - * - * Revision 1.17 1993/06/04 10:26:39 lmjm - * Cleaned up error reporting. - * Spot when the child terminating is not mine but inherited from via exec. - * Use only one semaphore group. - * Print out why writer died on error. - * - * Revision 1.16 1993/05/28 10:47:32 lmjm - * Debug shutdown sequence. - * - * Revision 1.15 1992/11/23 23:32:58 lmjm - * Oops! This should be outside the ifdef - * - * Revision 1.14 1992/11/23 23:29:58 lmjm - * allow MAX_BLOCKSIZE and DEF_SHMEM to be configured - * - * Revision 1.13 1992/11/23 23:22:29 lmjm - * Printf's use %lu where appropriate. - * - * Revision 1.12 1992/11/23 23:17:55 lmjm - * Got rid of floats and use Kbyte counters instead. - * - * Revision 1.11 1992/11/03 23:11:51 lmjm - * Forgot Andi Karrer on the patch list. - * - * Revision 1.10 1992/11/03 22:58:41 lmjm - * Cleaned up the debugging prints. - * - * Revision 1.9 1992/11/03 22:53:00 lmjm - * Corrected stdin, stout and showevery use. - * - * Revision 1.8 1992/11/03 22:41:34 lmjm - * Added 2Gig patches from: - * Andi Karrer <karrer@bernina.ethz.ch> - * Rumi Zahir <rumi@iis.ethz.ch> - * Christoph Wicki <wicki@iis.ethz.ch> - * - * Revision 1.7 1992/07/23 20:42:03 lmjm - * Added 't' option to print total writen at end. - * - * Revision 1.6 1992/04/07 19:57:30 lmjm - * Added Kevins -B and -p options. - * Turn off buffering to make -S output appear ok. - * Added GPL. - * - * Revision 1.5 90/07/22 18:46:38 lmjm - * Added system 5 support. - * - * Revision 1.4 90/07/22 18:29:48 lmjm - * Updated arg handling to be more consistent. - * Make sofar printing size an option. - * - * Revision 1.3 90/05/15 23:27:46 lmjm - * Added -S option (show how much has been writen). - * Added -m option to specify how much shared memory to grab. - * Now tries to fill this with blocks. - * reader waits for writer to terminate and then frees the shared mem and sems. - * - * Revision 1.2 90/01/20 21:37:59 lmjm - * Reset default number of blocks and blocksize for best thruput of - * standard tar 10K Allow. - * blocks number of blocks to be changed. - * Don't need a hole in the circular queue since the semaphores prevent block - * clash. - * - * Revision 1.1 90/01/17 11:30:23 lmjm - * Initial revision - * - */ -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdio.h> -#include <signal.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#include <sys/sem.h> -#include <sys/wait.h> -#include "sem.h" - - -/* General macros */ -#define TRUE 1 -#define FALSE 0 -#define K *1024 -#define M *1024*1024 - -/* Some forward declarations */ -void byee(int exit_val); -void start_reader_and_writer(); -void parse_args(int argc, char **argv); -void set_handlers(); -void buffer_allocate(); -void report_proc(); -int do_size(char *arg); -void get_buffer(); -void reader(); -void writer(); -void writer_end(); -void wait_for_writer_end(); -void get_next_free_block(); -void test_writer(); -int fill_block(); -void get_next_filled_block(); -int data_to_write(); -void write_blocks_to_stdout(int filled, int first_block); -void write_block_to_stdout(); -void pr_out(); -void end_writer(); - -/* When showing print a note every this many bytes writen */ -int showevery = 0; -#define PRINT_EVERY 10 K - -/* Pause after every write */ -unsigned write_pause; - -/* This is the inter-process buffer - it implements a circular list - * of blocks. */ - -#ifdef AMPEX -#define MAX_BLOCKSIZE (4 M) -#define DEF_BLOCKSIZE MAX_BLOCKSIZE -#define DEF_SHMEM (32 M) -#endif - - -#ifndef MAX_BLOCKSIZE -#define MAX_BLOCKSIZE (512 K) -#endif -#ifndef DEF_BLOCKSIZE -#define DEF_BLOCKSIZE (10 K) -#endif - -int blocksize = DEF_BLOCKSIZE; - -/* Which process... in error reports*/ -char *proc_string = "buffer"; - -/* Numbers of blocks in the queue. - */ -#define MAX_BLOCKS 2048 -int blocks = 1; -/* Circular increment of a buffer index */ -#define INC(i) (((i)+1) == blocks ? 0 : ((i)+1)) - -/* Max amount of shared memory you can allocate - can't see a way to look - * this up. - */ -#ifndef DEF_SHMEM -#define DEF_SHMEM (1 K K) -#endif -int max_shmem = DEF_SHMEM; - -/* Just a flag to show unfilled */ -#define NONE (-1) - -/* the shared memory id of the buffer */ -int buffer_id = NONE; -struct block { - int bytes; - char *data; -} *curr_block; - -#define NO_BUFFER ((struct buffer *)-1) -struct buffer { - /* Id of the semaphore group */ - int semid; - - /* writer will hang trying to lock this till reader fills in a block */ - int blocks_used_lock; - /* reader will hang trying to lock this till writer empties a block */ - int blocks_free_lock; - - int next_block_in; - int next_block_out; - - struct block block[ MAX_BLOCKS ]; - - /* These actual space for the blocks is here - the array extends - * pass 1 */ - char data_space[ 1 ]; -} *pbuffer = NO_BUFFER; -int buffer_size; - -int fdin = 0; -int fdout = 1; -int in_ISCHR = 0; -int out_ISCHR = 0; -int padblock = FALSE; -int writer_pid = 0; -int reader_pid = 0; -int free_shm = 1; -int percent = 0; -int debug = 0; -int Zflag = 0; -int writer_status = 0; -char *progname = "buffer"; - -char print_total = 0; -/* Number of K output */ -unsigned long outk = 0; - -int -main( argc, argv ) - int argc; - char **argv; -{ - parse_args( argc, argv ); - - set_handlers(); - - buffer_allocate(); - - start_reader_and_writer(); - - byee( 0 ); - - /* NOTREACHED */ - exit( 0 ); -} - -void -parse_args( argc, argv ) - int argc; - char **argv; -{ - int c; - int iflag = 0; - int oflag = 0; - int zflag = 0; - extern char *optarg; - char blocks_given = FALSE; - struct stat buf; - - - while( (c = getopt( argc, argv, "BS:Zdm:s:b:p:u:ti:o:z:" )) != -1 ){ - switch( c ){ - case 't': /* Print to stderr the total no of bytes writen */ - print_total++; - break; - case 'u': /* pause after write for given microseconds */ - write_pause = atoi( optarg ); - break; - case 'B': /* Pad last block */ - padblock = TRUE; - break; - case 'Z': /* Zero by lseek on the tape device */ - Zflag = TRUE; - break; - case 'i': /* Input file */ - iflag++; - if( iflag > 1 ){ - report_proc(); - fprintf( stderr, "-i given twice\n" ); - byee( -1 ); - } - if( (fdin = open( optarg, O_RDONLY )) < 0 ){ - report_proc(); - perror( "cannot open input file" ); - fprintf( stderr, "filename: %s\n", optarg ); - byee ( -1 ); - } - break; - case 'o': /* Output file */ - oflag++; - if( oflag > 1 ){ - report_proc(); - fprintf( stderr, "-o given twice\n" ); - byee( -1 ); - } - if( (fdout = open( optarg, O_WRONLY | O_CREAT | O_TRUNC, 0666 )) < 0 ){ - report_proc(); - perror( "cannot open output file" ); - fprintf( stderr, "filename: %s\n", optarg ); - byee ( -1 ); - } - break; - case 'S': - /* Show every once in a while how much is printed */ - showevery = do_size( optarg ); - if( showevery <= 0 ) - showevery = PRINT_EVERY; - break; - case 'd': /* debug */ - debug++; - if( debug == 1 ){ - setbuf( stdout, NULL ); - setbuf( stderr, NULL ); - fprintf( stderr, "debugging turned on\n" ); - } - break; - case 'm': - /* Max size of shared memory lump */ - max_shmem = do_size( optarg ); - - if( max_shmem < (sizeof( struct buffer ) + (blocksize * blocks)) ){ - fprintf( stderr, "max_shmem %d too low\n", max_shmem ); - byee( -1 ); - } - break; - case 'b': - /* Number of blocks */ - blocks_given = TRUE; - blocks = atoi( optarg ); - if( (blocks <= 0) || (MAX_BLOCKS < blocks) ){ - fprintf( stderr, "blocks %d out of range\n", blocks ); - byee( -1 ); - } - break; - case 'p': /* percent to wait before dumping */ - percent = atoi( optarg ); - - if( (percent < 0) || (100 < percent) ){ - fprintf( stderr, "percent %d out of range\n", percent ); - byee( -1 ); - } - if( debug ) - fprintf( stderr, "percent set to %d\n", percent ); - break; - case 'z': - zflag++; - /* FALL THRU */ - case 's': /* Size of a block */ - blocksize = do_size( optarg ); - - if( (blocksize <= 0) || (MAX_BLOCKSIZE < blocksize) ){ - fprintf( stderr, "blocksize %d out of range\n", blocksize ); - byee( -1 ); - } - break; - default: - fprintf( stderr, "Usage: %s [-B] [-t] [-S size] [-m memsize] [-b blocks] [-p percent] [-s blocksize] [-u pause] [-i infile] [-o outfile] [-z size]\n", - progname ); - fprintf( stderr, "-B = blocked device - pad out last block\n" ); - fprintf( stderr, "-t = show total amount writen at end\n" ); - fprintf( stderr, "-S size = show amount writen every size bytes\n" ); - fprintf( stderr, "-m size = size of shared mem chunk to grab\n" ); - fprintf( stderr, "-b num = number of blocks in queue\n" ); - fprintf( stderr, "-p percent = don't start writing until percent blocks filled\n" ); - fprintf( stderr, "-s size = size of a block\n" ); - fprintf( stderr, "-u usecs = microseconds to sleep after each write\n" ); - fprintf( stderr, "-i infile = file to read from\n" ); - fprintf( stderr, "-o outfile = file to write to\n" ); - fprintf( stderr, "-z size = combined -S/-s flag\n" ); - byee( -1 ); - } - } - - if (zflag) showevery = blocksize; - - /* If -b was not given try and work out the max buffer size */ - if( !blocks_given ){ - blocks = (max_shmem - sizeof( struct buffer )) / blocksize; - if( blocks <= 0 ){ - fprintf( stderr, "Cannot handle blocks that big, aborting!\n" ); - byee( -1 ); - } - if( MAX_BLOCKS < blocks ){ - fprintf( stderr, "Cannot handle that many blocks, aborting!\n" ); - byee( -1 ); - } - } - - /* check if fdin or fdout are character special files */ - if( fstat( fdin, &buf ) != 0 ){ - report_proc(); - perror( "can't stat input file" ); - byee( -1 ); - } - in_ISCHR = S_ISCHR( buf.st_mode ); - if( fstat( fdout, &buf ) != 0 ){ - report_proc(); - perror( "can't stat output file" ); - byee( -1 ); - } - out_ISCHR = S_ISCHR( buf.st_mode ); -} - -/* The interrupt handler */ -void -shutdown() -{ - static int shutting; - if( shutting ){ - if( debug ) - fprintf( stderr, "%s: ALREADY SHUTTING!\n", proc_string ); - return; - } - shutting = 1; - if( debug ) - fprintf( stderr, "%s: shutdown on signal\n", proc_string ); - - byee( -1 ); -} - -/* Shutdown because the child has ended */ -void -child_shutdown() -{ - /* Find out which child has died. (They may not be my - * children if buffer was exec'd on top of something that had - * childred.) - */ - int deadpid; - - while( (deadpid = waitpid( -1, &writer_status, WNOHANG )) && - deadpid != -1 && deadpid != 0 ){ - if( debug > 2 ) - fprintf( stderr, "child_shutdown %d: 0x%04x\n", deadpid, writer_status ); - if( deadpid == writer_pid ){ - if( debug > 2 ) - fprintf( stderr, "writer has ended\n" ); - writer_pid = 0; - byee( 0 ); - } - } -} - -void -set_handlers() -{ - if( debug ) - fprintf( stderr, "%s: setting handlers\n", proc_string ); - - signal( SIGHUP, shutdown ); - signal( SIGINT, shutdown ); - signal( SIGQUIT, shutdown ); - signal( SIGTERM, shutdown ); -#ifdef SIGCHLD - signal( SIGCHLD, child_shutdown ); -#else -#ifdef SIGCLD - signal( SIGCLD, child_shutdown ); -#endif -#endif -} - -void -buffer_allocate() -{ - /* Allow for the data space */ - buffer_size = sizeof( struct buffer ) + - ((blocks * blocksize) - sizeof( char )); - - /* Create the space for the buffer */ - buffer_id = shmget( IPC_PRIVATE, - buffer_size, - IPC_CREAT|S_IREAD|S_IWRITE ); - if( buffer_id < 0 ){ - report_proc(); - perror( "couldn't create shared memory segment" ); - byee( -1 ); - } - - get_buffer(); - - if( debug ) - fprintf( stderr, "%s pbuffer is 0x%08ld, buffer_size is %d [%d x %d]\n", - proc_string, - (long)pbuffer, buffer_size, blocks, blocksize ); - -#ifdef SYS5 - memset( (char *)pbuffer, '\0', buffer_size ); -#else - bzero( (char *)pbuffer, buffer_size ); -#endif - pbuffer->semid = -1; - pbuffer->blocks_used_lock = -1; - pbuffer->blocks_free_lock = -1; - - pbuffer->semid = new_sems( 2 ); /* Get a read and a write sem */ - pbuffer->blocks_used_lock = 0; - /* Start it off locked - it is unlocked when a buffer gets filled in */ - lock( pbuffer->semid, pbuffer->blocks_used_lock ); - - pbuffer->blocks_free_lock = 1; - /* start this off so lock() can be called on it for each block - * till all the blocks are used up */ - sem_set( pbuffer->semid, pbuffer->blocks_free_lock, blocks - 1 ); - - /* Detattach the shared memory so the fork doesnt do anything odd */ - shmdt( (char *)pbuffer ); - pbuffer = NO_BUFFER; -} - -void -buffer_remove() -{ - static char removing = FALSE; - - /* Avoid accidental recursion */ - if( removing ) - return; - removing = TRUE; - - /* Buffer not yet created */ - if( buffer_id == NONE ) - return; - - /* There should be a buffer so this must be after its detached it - * but before the fork picks it up */ - if( pbuffer == NO_BUFFER ) - get_buffer(); - - if( debug ) - fprintf( stderr, "%s: removing semaphores and buffer\n", proc_string ); - remove_sems( pbuffer->semid ); - - if( shmctl( buffer_id, IPC_RMID, (struct shmid_ds *)0 ) == -1 ){ - report_proc(); - perror( "failed to remove shared memory buffer" ); - } -} - -void -get_buffer() -{ - int b; - - /* Grab the buffer space */ - pbuffer = (struct buffer *)shmat( buffer_id, (char *)0, 0 ); - if( pbuffer == NO_BUFFER ){ - report_proc(); - perror( "failed to attach shared memory" ); - byee( -1 ); - } - - /* Setup the data space pointers */ - for( b = 0; b < blocks; b++ ) - pbuffer->block[ b ].data = - &pbuffer->data_space[ b * blocksize ]; - -} - -void -start_reader_and_writer() -{ - fflush( stdout ); - fflush( stderr ); - - if( (writer_pid = fork()) == -1 ){ - report_proc(); - perror( "unable to fork" ); - byee( -1 ); - } - else if( writer_pid == 0 ){ - free_shm = 0; - proc_string = "buffer (writer)"; - reader_pid = getppid(); - - /* Never trust fork() to propogate signals - reset them */ - set_handlers(); - - writer(); - } - else { - proc_string = "buffer (reader)"; - reader(); - - wait_for_writer_end(); - } -} - -/* Read from stdin into the buffer */ -void -reader() -{ - if( debug ) - fprintf( stderr, "R: Entering reader\n" ); - - get_buffer(); - - while( 1 ){ - get_next_free_block(); - if( ! fill_block() ) - break; - } - - if( debug ) - fprintf( stderr, "R: Exiting reader\n" ); -} - -void -get_next_free_block() -{ - test_writer(); - - /* Maybe wait till there is room in the buffer */ - lock( pbuffer->semid, pbuffer->blocks_free_lock ); - - curr_block = &pbuffer->block[ pbuffer->next_block_in ]; - - pbuffer->next_block_in = INC( pbuffer->next_block_in ); -} - -int -fill_block() -{ - int bytes; - char *start; - int toread; - static char eof_reached = 0; - - if( eof_reached ){ - curr_block->bytes = 0; - unlock( pbuffer->semid, pbuffer->blocks_used_lock ); - return 0; - } - - start = curr_block->data; - toread = blocksize; - - /* Fill the block with input. This reblocks the input. */ - while( toread != 0 ){ - bytes = read( fdin, start, toread ); - if( bytes <= 0 ){ - /* catch interrupted system calls for death - * of children in pipeline */ - if( bytes < 0 && errno == EINTR ) - continue; - break; - } - start += bytes; - toread -= bytes; - } - - if( bytes == 0 ) - eof_reached = 1; - - if( bytes < 0 ){ - report_proc(); - perror( "failed to read input" ); - byee( -1 ); - } - - /* number of bytes available. Zero will be taken as eof */ - if( !padblock || toread == blocksize ) - curr_block->bytes = blocksize - toread; - else { - if( toread ) bzero( start, toread ); - curr_block->bytes = blocksize; - } - - if( debug > 1 ) - fprintf( stderr, "R: got %d bytes\n", curr_block->bytes ); - - unlock( pbuffer->semid, pbuffer->blocks_used_lock ); - - return curr_block->bytes; -} - -/* Write the buffer to stdout */ -void -writer() -{ - int filled = 0; - int maxfilled = (blocks * percent) / 100; - int first_block; - - if( debug ) - fprintf( stderr, "\tW: Entering writer\n blocks = %d\n maxfilled = %d\n", - blocks, - maxfilled ); - - get_buffer(); - - while( 1 ){ - if( !filled ) - first_block = pbuffer->next_block_out; - get_next_filled_block(); - if( !data_to_write() ) - break; - - filled++; - if( debug > 1 ) - fprintf( stderr, "W: filled = %d\n", filled ); - if( filled >= maxfilled ){ - if( debug > 1 ) - fprintf( stderr, "W: writing\n" ); - write_blocks_to_stdout( filled, first_block ); - filled = 0; - } - } - - write_blocks_to_stdout( filled, first_block ); - - if( showevery ){ - pr_out(); - fprintf( stderr, "\n" ); - } - - if( print_total ){ - fprintf( stderr, "Kilobytes Out %lu\n", outk ); - } - - if( debug ) - fprintf( stderr, "\tW: Exiting writer\n" ); -} - -void -get_next_filled_block() -{ - /* Hang till some data is available */ - lock( pbuffer->semid, pbuffer->blocks_used_lock ); - - curr_block = &pbuffer->block[ pbuffer->next_block_out ]; - - pbuffer->next_block_out = INC( pbuffer->next_block_out ); -} - -int -data_to_write() -{ - return curr_block->bytes; -} - -void -write_blocks_to_stdout( filled, first_block ) - int filled; - int first_block; -{ - pbuffer->next_block_out = first_block; - - while( filled-- ){ - curr_block = &pbuffer->block[ pbuffer->next_block_out ]; - pbuffer->next_block_out = INC( pbuffer->next_block_out ); - write_block_to_stdout(); - } -} - -void -write_block_to_stdout() -{ - static unsigned long out = 0; - static unsigned long last_gb = 0; - static unsigned long next_k = 0; - int written; - - if( next_k == 0 && showevery ){ - if( debug > 3 ) - fprintf( stderr, "W: next_k = %lu showevery = %d\n", next_k, showevery ); - showevery = showevery / 1024; - next_k = showevery; - } - - if( (written = write( fdout, curr_block->data, curr_block->bytes )) != curr_block->bytes ){ - report_proc(); - perror( "write of data failed" ); - fprintf( stderr, "bytes to write=%d, bytes written=%d, total written %10luK\n", curr_block->bytes, written, outk ); - byee( -1 ); - } - - if( write_pause ){ - usleep( write_pause ); - } - - out = curr_block->bytes / 1024; - outk += out; - last_gb += out; - - /* - * on character special devices (tapes), do an lseek() every 1 Gb, - * to overcome the 2Gb limit. This resets the file offset to - * zero, but -- at least on exabyte SCSI drives -- does not perform - * any actual action on the tape. - */ - if( Zflag && last_gb >= 1 K K ){ - last_gb = 0; - if( in_ISCHR ) - (void) lseek( fdin, 0, SEEK_SET); - if( out_ISCHR ) - (void) lseek( fdout, 0, SEEK_SET); - } - if( showevery ){ - if( debug > 3 ) - fprintf( stderr, "W: outk = %lu, next_k = %lu\n", - outk, next_k ); - if( outk >= next_k ){ - pr_out(); - next_k += showevery; - } - } - - unlock( pbuffer->semid, pbuffer->blocks_free_lock ); -} - - -void -byee( int exit_val ) -{ - if( writer_pid != 0 ){ - if( exit_val != 0 ){ - /* I am shutting down due to an error. - * Shut the writer down or else it will try to access - * the freed up locks */ - end_writer(); - } - wait_for_writer_end(); - } - - if( free_shm ){ - buffer_remove(); - } - -#ifdef SIGCHLD - signal( SIGCHLD, SIG_IGN ); -#else -#ifdef SIGCLD - signal( SIGCLD, SIG_IGN ); -#endif -#endif - - /* If the child died or was killed show this in the exit value */ - if( writer_status ){ - if( WEXITSTATUS( writer_status ) || WIFSIGNALED( writer_status ) ){ - if( debug ) - fprintf( stderr, "writer died badly: 0x%04x\n", writer_status ); - exit( -2 ); - } - } - - exit( exit_val ); -} - -/* Kill off the writer */ -void -end_writer() -{ - if( writer_pid ) - kill( writer_pid, SIGHUP ); -} - -void -wait_for_writer_end() -{ - int deadpid; - - /* Now wait for the writer to finish */ - while( writer_pid && ((deadpid = wait( &writer_status )) != writer_pid) && - deadpid != -1 ) - ; -} - -void -test_writer() -{ - /* Has the writer gone unexpectedly? */ - if( writer_pid == 0 ){ - fprintf( stderr, "writer has died unexpectedly\n" ); - byee( -1 ); - } -} - -/* Given a string of <num>[<suff>] returns a num - * suff = - * m/M for 1meg - * k/K for 1k - * b/B for 512 - */ -int -do_size( arg ) - char *arg; -{ - char format[ 20 ]; - int ret; - - *format = '\0'; - sscanf( arg, "%d%s", &ret, format ); - - switch( *format ){ - case 'm': - case 'M': - ret = ret K K; - break; - case 'k': - case 'K': - ret = ret K; - break; - case 'b': - case 'B': - ret *= 512; - break; - } - - return ret; -} - -void -pr_out() -{ - fprintf( stderr, " %10luK\r", outk ); -} - -#ifdef SYS5 -#include <sys/time.h> - -#ifndef __alpha -bzero( b, l ) - char *b; - unsigned l; -{ - memset( b, '\0', l ); -} -#endif /* __alpha */ - -usleep_back() -{ -} - -void -usleep( u ) - unsigned u; -{ - struct itimerval old, t; - signal( SIGALRM, usleep_back ); - t.it_interval.tv_sec = 0; - t.it_interval.tv_usec = 0; - t.it_value.tv_sec = u / 1000000; - t.it_value.tv_usec = u % 1000000; - setitimer( ITIMER_REAL, &t, &old ); - pause(); - setitimer( ITIMER_REAL, &old, NULL ); -} -#endif - -/* Called before error reports */ -void -report_proc() -{ - fprintf( stderr, "%s: ", proc_string ); -}
View file
lxdvdrip-1.76.tar.bz2/buffer/sem.c
Deleted
@@ -1,160 +0,0 @@ -/* - Buffer. Very fast reblocking filter speedy writing of tapes. - Copyright (C) 1990,1991 Lee McLoughlin - - 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 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Lee McLoughlin. - Dept of Computing, Imperial College, - 180 Queens Gate, London, SW7 2BZ, UK. - - Email: L.McLoughlin@doc.ic.ac.uk -*/ - -/* This is a simple module to provide an easier to understand interface to - * semaphores */ - -#include <stdio.h> -#include <sys/types.h> -#include <unistd.h> -#include <sys/stat.h> -#include <sys/ipc.h> -#include <sys/sem.h> -#include <errno.h> -#include "sem.h" - -#if defined(SYS5) || defined(ultrix) || defined(_AIX) || defined _SEM_SEMUN_UNDEFINED -union semun { - int val; - struct semid_ds *buf; - ushort *array; -}; -#endif - -/* IMPORTS */ - -/* Used to print error messages */ -extern void report_proc(); - -/* Used to end the program - on error */ -extern void byee(int exit_val); - - - -/* Set a semaphore to a particular value - meant to be used before - * first lock/unlock */ -void -sem_set( sem_id, semn, val ) - int sem_id; - int semn; - int val; -{ - union semun arg; - extern int errno; - - arg.val = val; - - errno = 0; - semctl( sem_id, semn, SETVAL, arg ); - if( errno != 0 ){ - report_proc(); - perror( "internal error, sem_set" ); - byee( -1 ); - } -} - -int -new_sems( nsems ) - int nsems; -{ - int sem; - int i; - - sem = semget( IPC_PRIVATE, nsems, IPC_CREAT|S_IREAD|S_IWRITE ); - if( sem < 0 ){ - report_proc(); - perror( "internal error, couldn't create semaphore" ); - byee( -1 ); - } - - for( i = 0; i < nsems; i++ ){ - sem_set( sem, i, 1 ); - } - - return sem; -} - -static void -do_sem( sem_id, pbuf, err ) - int sem_id; - struct sembuf *pbuf; - char *err; -{ - /* This just keeps us going in case of EINTR */ - while( 1 ){ - if( semop( sem_id, pbuf, 1 ) == -1 ){ - if( errno == EINTR ){ - continue; - } - report_proc(); - fprintf( stderr, "internal error pid %d, lock id %d\n", - getpid(), sem_id ); - perror( err ); - byee( -1 ); - } - return; - } -} - -void -lock( sem_id, semn ) - int sem_id; - int semn; -{ - struct sembuf sembuf; - - sembuf.sem_num = semn; - sembuf.sem_op = -1; - sembuf.sem_flg = 0; - - do_sem( sem_id, &sembuf, "lock error" ); -} - -void -unlock( sem_id, semn ) - int sem_id; - int semn; -{ - struct sembuf sembuf; - - sembuf.sem_num = semn; - sembuf.sem_op = 1; - sembuf.sem_flg = 0; - - do_sem( sem_id, &sembuf, "unlock error" ); -} - -void -remove_sems( sem_id ) - int sem_id; -{ - if( sem_id == -1 ) - return; - - if( semctl( sem_id, 0, IPC_RMID, (union semun) 0 ) == -1 ){ - report_proc(); - perror( "internal error, failed to remove semaphore" ); - } -}
View file
lxdvdrip-1.76.tar.bz2/buffer/sem.h
Deleted
@@ -1,37 +0,0 @@ -/* - Buffer. Very fast reblocking filter speedy writing of tapes. - Copyright (C) 1990,1991 Lee McLoughlin - - 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 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Lee McLoughlin. - Dept of Computing, Imperial College, - 180 Queens Gate, London, SW7 2BZ, UK. - - Email: L.McLoughlin@doc.ic.ac.uk -*/ - -/* This is a simple module to provide an easier to understand interface to - * semaphores */ - -/* Allocate new semaphores */ -int new_sems(int nsems); - -/* Perform actions on semaphores */ -void sem_set( int sem_id, int semn, int val ); - -void lock( int sem_id, int semn); -void unlock(int sem_id, int semn); -void remove_sems(int sem_id);
View file
lxdvdrip-1.76.tar.bz2/doc-pak/TODO
Deleted
@@ -1,1 +0,0 @@ -Full copy with Menu.
View file
lxdvdrip-1.76.tar.bz2/dvdauthor/0.6.14
Deleted
-(directory)
View file
lxdvdrip-1.76.tar.bz2/dvdauthor/0.6.14/dvdvob.c
Deleted
@@ -1,1796 +0,0 @@ -/* - * Copyright (C) 2002 Scott Smith (trckjunky@users.sourceforge.net) - * - * 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 - */ - -#include "config.h" - -#include "compat.h" - -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <ctype.h> - -#include "dvdauthor.h" -#include "da-internal.h" - - - -struct colorremap { - int newcolors[16]; - int state,curoffs,maxlen,nextoffs,skip,ln_ctli; - struct colorinfo *origmap; -}; - -struct vscani { - int lastrefsect; - int firstgop,firsttemporal,lastadjust,adjustfields; -}; - -static pts_t timeline[19]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 20,60,120,240}; - -#define BIGWRITEBUFLEN (16*2048) -static unsigned char bigwritebuf[BIGWRITEBUFLEN]; -static int writebufpos=0; -static int writefile=-1; - -static unsigned char videoslidebuf[15]={255,255,255,255, 255,255,255, 0,0,0,0, 0,0,0,0}; - - -/* The following are variants for the ways I've seen DVD's encoded */ - -// Grosse Pointe Blank uses exactly 1/2 second for the FF/REW records -// Bullitt uses 1/2 video second (i.e. in NTSC, 45045 PTS) -#define DVD_FFREW_HALFSEC 45000 -// #define DVD_FFREW_HALFSEC (getratedenom(va)>>1) - -static pts_t calcpts(struct vobgroup *va,int cancomplain,int *didcomplain,pts_t *align,pts_t basepts,int nfields) -{ - // I assume pts should round down? That seems to be how mplex deals with it - // also see later comment - - pts_t fpts=getframepts(va); - int bpframe=(basepts*2-*align+fpts/2)/fpts; - if( (*align+bpframe*fpts)/2 != basepts ) { - if( !*didcomplain ) { - if( cancomplain ) - fprintf(stderr,"WARN: Video PTS does not line up on a multiple of a field.\n"); - *didcomplain=1; - } - *align=basepts*2; - } else - nfields += bpframe; - return (*align+nfields*fpts)/2; -} - -static int findnextvideo(struct vob *va, int cur, int dir) -{ - // find next (dir=1) or previous(dir=-1) vobu with video - int i, numvobus; - - numvobus = va->numvobus; - switch(dir){ - case 1: // forward - for(i = cur+1; i < numvobus; i++) if(va->vi[i].hasvideo) return i; - return -1; - case -1: // backward - for(i = cur-1; i > -1; i--) if(va->vi[i].hasvideo) return i; - return -1; - default: - // ?? - return -1; - } -} - -static int findaudsect(struct vob *va,int aind,pts_t pts0,pts_t pts1) -{ - struct audchannel *ach=&va->audch[aind]; - int l=0,h=ach->numaudpts-1; - - if( h<l ) - return -1; - while(h>l) { - int m=(l+h+1)/2; - if( pts0<ach->audpts[m].pts[0] ) - h=m-1; - else - l=m; - } - if( ach->audpts[l].pts[0] > pts1 ) - return -1; - return ach->audpts[l].sect; -} - -static int findvobubysect(struct vob *va,int sect) -{ - int l=0,h=va->numvobus-1; - - if( h<0 ) - return -1; - if( sect<va->vi[0].sector ) - return -1; - while(l<h) { - int m=(l+h+1)/2; - if( sect < va->vi[m].sector ) - h=m-1; - else - l=m; - } - return l; -} - -static int findspuidx(struct vob *va,int ach,pts_t pts0) -{ - int l=0,h=va->audch[ach].numaudpts-1; - - if( h<l ) - return -1; - while(h>l) { - int m=(l+h+1)/2; - if( pts0<va->audch[ach].audpts[m].pts[0] ) - h=m-1; - else - l=m; - } - return l; -} - -static unsigned int getsect(struct vob *va,int curvobnum,int jumpvobnum,int skip,unsigned notfound) -{ - if( skip ) { - int l,h,i; - - // only set skip bit if one of hte VOBU's from here to there contain video - if( curvobnum<jumpvobnum ) { - l=curvobnum+1; - h=jumpvobnum-1; - } else { - l=jumpvobnum+1; - h=curvobnum-1; - } - for( i=l; i<=h; i++ ) - if( va->vi[i].hasvideo ) - break; - if( i<=h ) - skip=0x40000000; - else - skip=0; - } - if( jumpvobnum < 0 || jumpvobnum >= va->numvobus || - va->vi[jumpvobnum].vobcellid != va->vi[curvobnum].vobcellid ) - return notfound|skip; - return abs(va->vi[jumpvobnum].sector-va->vi[curvobnum].sector) - |(va->vi[jumpvobnum].hasvideo?0x80000000:0) - |skip; -} - -static pts_t readscr(const unsigned char *buf) -{ - return (((pts_t)(buf[0]&0x38))<<27)| - ((buf[0]&3)<<28)| - (buf[1]<<20)| - ((buf[2]&0xf8)<<12)| - ((buf[2]&3)<<13)| - (buf[3]<<5)| - ((buf[4]&0xf8)>>3); -} - -static void writescr(unsigned char *buf,pts_t scr) -{ - buf[0]=((scr>>27)&0x38)|((scr>>28)&3)|68; - buf[1]=scr>>20; - buf[2]=((scr>>12)&0xf8)|((scr>>13)&3)|4; - buf[3]=scr>>5; - buf[4]=((scr<<3)&0xf8)|(buf[4]&7); -} - -static pts_t readpts(const unsigned char *buf) -{ - int a1,a2,a3; - a1=(buf[0]&0xe)>>1; - a2=((buf[1]<<8)|buf[2])>>1; - a3=((buf[3]<<8)|buf[4])>>1; - - return (((pts_t)a1)<<30)| - (a2<<15)| - a3; -} - - -static void writepts(unsigned char *buf,pts_t pts) -{ - buf[0]=((pts>>29)&0xe)|(buf[0]&0xf1); // this preserves the PTS / DTS / PTSwDTS top bits - write2(buf+1,(pts>>14)|1); - write2(buf+3,(pts<<1)|1); -} - -static int findbutton(struct pgc *pg,char *dest,int dflt) -{ - int i; - - if( !dest ) - return dflt; - for( i=0; i<pg->numbuttons; i++ ) - if( !strcmp(pg->buttons[i].name,dest) ) - return i+1; - return dflt; -} - -static void transpose_ts(unsigned char *buf,pts_t tsoffs) -{ - // pack scr - if( buf[0] == 0 && - buf[1] == 0 && - buf[2] == 1 && - buf[3] == 0xba ) - { - writescr(buf+4,readscr(buf+4)+tsoffs); - - // video/audio? - // pts? - if( buf[14] == 0 && - buf[15] == 0 && - buf[16] == 1 && - (buf[17]==0xbd || (buf[17]>=0xc0 && buf[17]<=0xef)) && - (buf[21] & 128)) - { - writepts(buf+23,readpts(buf+23)+tsoffs); - // dts? - if( buf[21] & 64 ) { - writepts(buf+28,readpts(buf+28)+tsoffs); - } - } - } -} - -static int mpa_valid(unsigned char *b) -{ - unsigned int v=(b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3]; - int t; - - // sync, mpeg1, layer2, 48khz - if( (v&0xFFFE0C00) != 0xFFFC0400 ) - return 0; - // bitrate 1..14 - t=(v>>12)&15; - if( t==0 || t==15 ) - return 0; - // emphasis reserved - if( (v&3)==2 ) - return 0; - return 1; -} - - -static int mpa_len(unsigned char *b) -{ - static int bitratetable[16]={0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}; - int padding=(b[2]>>1)&1; - int bitrate=bitratetable[(b[2]>>4)&15]; - - return 3*bitrate+padding; // 144*bitrate/sampling; 144/48=3 -} - -static void writeflush() -{ - if( !writebufpos ) return; - if( writefile!=-1 ) { - if( write(writefile,bigwritebuf,writebufpos) != writebufpos ) { - fprintf(stderr,"ERR: Error writing data\n"); - exit(1); - } - } - writebufpos=0; -} - -static unsigned char *writegrabbuf() -{ - unsigned char *buf; - if( writebufpos == BIGWRITEBUFLEN ) - writeflush(); - buf=bigwritebuf+writebufpos; - writebufpos+=2048; - return buf; -} - -static void writeundo() -{ - writebufpos-=2048; -} - -static void writeclose() -{ - writeflush(); - if( writefile!=-1 ) { - close(writefile); - writefile=-1; - } -} - -static void writeopen(const char *newname) -{ - writefile=open(newname,O_CREAT|O_WRONLY|O_BINARY,0666); - if( writefile < 0 ) { - fprintf(stderr,"ERR: Error opening %s: %s\n",newname,strerror(errno)); - exit(1); - } -} - -static void closelastref(struct vobuinfo *thisvi,struct vscani *vsi,int cursect) -{ - if( vsi->lastrefsect && thisvi->numref < 3 ) { - thisvi->lastrefsect[thisvi->numref++]=cursect; - vsi->lastrefsect=0; - } -} - -// this function is allowed to update buf[7] and gaurantee it will end up -// in the output stream -// prevbytesect is the sector for the byte immediately preceding buf[0] -static void scanvideoptr(struct vobgroup *va,unsigned char *buf,struct vobuinfo *thisvi,int prevbytesect,struct vscani *vsi) -{ - if( buf[0]==0 && - buf[1]==0 && - buf[2]==1 ) { - switch(buf[3]) { - case 0: { - int ptype=(buf[5]>>3)&7; - int temporal=(buf[4]<<2)|(buf[5]>>6); - - closelastref(thisvi,vsi,prevbytesect); - if( vsi->firsttemporal==-1 ) - vsi->firsttemporal=temporal; - vsi->lastadjust=( temporal < vsi->firsttemporal ); - if( ptype == 1 || ptype == 2 ) // I or P frame - vsi->lastrefsect=1; - - if( va->vd.vmpeg==VM_MPEG1) { - thisvi->numfields+=2; - if(vsi->lastadjust && vsi->firstgop==2) - thisvi->firstIfield+=2; - } - - // fprintf(stderr,"INFO: frame type %d, tempref=%d, prevsect=%d\n",ptype,temporal,prevbytesect); - break; - } - - case 0xb3: { // sequence header - int hsize,vsize,aspect,frame,newaspect; - char sizestring[30]; - - closelastref(thisvi,vsi,prevbytesect); - - hsize=(buf[4]<<4)|(buf[5]>>4); - vsize=((buf[5]<<8)&0xf00)|buf[6]; - aspect=buf[7]>>4; - frame=buf[7]&0xf; - - vobgroup_set_video_framerate(va,frame); - switch(frame) { - case 1: // 24000/1001 - case 4: // 30000/1001 - case 7: // 60000/1001 - vobgroup_set_video_attr(va,VIDEO_FORMAT,"ntsc"); - break; - - case 3: // 25 - case 6: // 50 - vobgroup_set_video_attr(va,VIDEO_FORMAT,"pal"); - break; - - case 2: // 24 - case 5: // 30 - case 8: // 60 - break; // these are nonstandard, but at least we know what they are - - default: - fprintf(stderr,"WARN: unknown frame rate %d\n",frame); - break; - } - - sprintf(sizestring,"%dx%d",hsize,vsize); - vobgroup_set_video_attr(va,VIDEO_RESOLUTION,sizestring); - - if( va->vd.vmpeg==VM_MPEG1) { - switch( aspect ) { - case 3: - vobgroup_set_video_attr(va,VIDEO_ASPECT,"16:9"); - vobgroup_set_video_attr(va,VIDEO_FORMAT,"pal"); - break; - case 6: - vobgroup_set_video_attr(va,VIDEO_ASPECT,"16:9"); - vobgroup_set_video_attr(va,VIDEO_FORMAT,"ntsc"); - break; - case 8: - vobgroup_set_video_attr(va,VIDEO_ASPECT,"4:3"); - vobgroup_set_video_attr(va,VIDEO_FORMAT,"pal"); - break; - case 12: - vobgroup_set_video_attr(va,VIDEO_ASPECT,"4:3"); - vobgroup_set_video_attr(va,VIDEO_FORMAT,"ntsc"); - break; - default: - fprintf(stderr,"WARN: unknown mpeg1 aspect ratio %d\n",aspect); - break; - } - newaspect=3+ - (va->vd.vaspect==VA_4x3)*5+ - (va->vd.vformat==VF_NTSC)*3; - if( newaspect==11 ) newaspect++; - buf[7]=(buf[7]&0xf)|(newaspect<<4); // reset the aspect ratio - } else if( va->vd.vmpeg==VM_MPEG2 ) { - if( aspect==2 ) - vobgroup_set_video_attr(va,VIDEO_ASPECT,"4:3"); - else if( aspect==3 ) - vobgroup_set_video_attr(va,VIDEO_ASPECT,"16:9"); - else - fprintf(stderr,"WARN: unknown mpeg2 aspect ratio %d\n",aspect); - buf[7]=(buf[7]&0xf)|(va->vd.vaspect==VA_4x3?2:3)<<4; // reset the aspect ratio - } - break; - } - - case 0xb5: { // extension header - vobgroup_set_video_attr(va,VIDEO_MPEG,"mpeg2"); - switch(buf[4]&0xF0) { - case 0x10: // sequence extension - closelastref(thisvi,vsi,prevbytesect); - break; - - case 0x20: // sequence display extension - closelastref(thisvi,vsi,prevbytesect); - switch(buf[4]&0xE) { - case 2: vobgroup_set_video_attr(va,VIDEO_FORMAT,"pal"); break; - case 4: vobgroup_set_video_attr(va,VIDEO_FORMAT,"ntsc"); break; - // case 6: // secam - // case 10: // unspecified - } - break; - - case 0x80: { // picture coding extension - int padj=1; // default field pic - - if( (buf[6]&3)==3 ) padj++; // adj for frame pic - if( buf[7]&2 ) padj++; // adj for repeat flag - - thisvi->numfields+=padj; - if(vsi->lastadjust && vsi->firstgop==2) - thisvi->firstIfield+=padj; - // fprintf(stderr,"INFO: repeat flag=%d, cursect=%d\n",buf[7]&2,cursect); - break; - } - - } - break; - } - - case 0xb7: { // sequence end code - thisvi->hasseqend=1; - break; - } - - case 0xb8: // gop header - closelastref(thisvi,vsi,prevbytesect); - if( vsi->firstgop==1 ) { - vsi->firstgop=2; - vsi->firsttemporal=-1; - vsi->lastadjust=0; - vsi->adjustfields=0; - } else if( vsi->firstgop==2 ) { - vsi->firstgop=0; - } - break; - - /* - case 0xb8: { // gop header - int hr,mi,se,fr; - - hr=(buf[4]>>2)&31; - mi=((buf[4]&3)<<4)|(buf[5]>>4); - se=((buf[5]&7)<<3)|(buf[6]>>5); - fr=((buf[6]&31)<<1)|(buf[7]>>7); - fprintf(stderr,"INFO: GOP header, %d:%02d:%02d:%02d, drop=%d\n",hr,mi,se,fr,(buf[4]>>7)); - break; - } - */ - - } - } -} - -static void scanvideoframe(struct vobgroup *va,unsigned char *buf,struct vobuinfo *thisvi,int cursect,int prevsect,struct vscani *vsi) -{ - int i,f=0x17+buf[0x16],l=0x14+buf[0x12]*256+buf[0x13]; - int mpf; - struct vobuinfo oldtvi; - struct vscani oldvsi; - - if( l-f<8 ) { - memcpy(videoslidebuf+7,buf+f,l-f); - for( i=0; i<l-f; i++ ) - scanvideoptr(va,videoslidebuf+i,thisvi,prevsect,vsi); - memcpy(buf+f,videoslidebuf+7,l-f); - memset(videoslidebuf,255,7); - return; - } - - rescan: - mpf=va->vd.vmpeg; - oldtvi=*thisvi; - oldvsi=*vsi; - - // copy the first 7 bytes to use with the prev 7 bytes in hdr detection - memcpy(videoslidebuf+7,buf+f,8); // we scan the first header using the slide buffer - for( i=0; i<=7; i++ ) - scanvideoptr(va,videoslidebuf+i,thisvi,prevsect,vsi); - memcpy(buf+f,videoslidebuf+7,8); - - // quickly scan all but the last 7 bytes for a hdr - // buf[f]... was already scanned in the videoslidebuffer to give the correct sector - for( i=f+1; i<l-7; i++ ) { - if( buf[i]==0 && buf[i+1]==0 && buf[i+2]==1 ) - scanvideoptr(va,buf+i,thisvi,cursect,vsi); - } - if( !va->vd.vmpeg ) - vobgroup_set_video_attr(va,VIDEO_MPEG,"mpeg1"); - // if the mpeg version changed, then rerun scanvideoframe, because - // scanvideoptr updates the aspect ratio in the sequence header - if( mpf != va->vd.vmpeg ) { - *thisvi=oldtvi; // we must undo all the frame pointer changes - *vsi=oldvsi; - goto rescan; - } - - // use the last 7 bytes in the next iteration - memcpy(videoslidebuf,buf+l-7,7); -} - -static void finishvideoscan(struct vobgroup *va,int vob,int prevsect,struct vscani *vsi) -{ - struct vobuinfo *lastvi=&va->vobs[vob]->vi[va->vobs[vob]->numvobus-1]; - int i; - - memset(videoslidebuf+7,0,7); - for( i=0; i<7; i++ ) - scanvideoptr(va,videoslidebuf+i,lastvi,prevsect,vsi); - memset(videoslidebuf,255,7); - closelastref(lastvi,vsi,prevsect); -} - -static void printpts(pts_t pts) -{ - fprintf(stderr,"%d.%03d",(int)(pts/90000),(int)((pts/90)%1000)); -} - -enum { CR_BEGIN0, CR_BEGIN1, CR_BEGIN2, CR_BEGIN3, CR_SKIP0, - CR_SKIP1, CR_NEXTOFFS0, CR_NEXTOFFS1, CR_WAIT, CR_CMD, - CR_SKIPWAIT, CR_COL0, CR_COL1, CR_CHGARG, CR_CHGLN0, - CR_CHGLN1, CR_CHGLN2, CR_CHGLN3, CR_CHGPX0, CR_CHGPX1, - CR_CHGPX2 }; - -static char *readpstr(char *b,int *i) -{ - char *s=strdup(b+i[0]); - i[0]+=strlen(s)+1; - return s; -} - -static void initremap(struct colorremap *cr) -{ - int i; - - for( i=0; i<16; i++ ) - cr->newcolors[i]=i; - cr->state=CR_BEGIN0; - cr->origmap=0; -} - -static int remapcolor(struct colorremap *cr,int idx) -{ - int i,nc; - - if( cr->newcolors[idx] < 16 ) - return cr->newcolors[idx]; - - nc=cr->newcolors[idx]&0xffffff; - for( i=0; i<16; i++ ) - if( cr->origmap->colors[i]==nc ) { - cr->newcolors[idx]=i; - return i; - } - for( i=0; i<16; i++ ) - if( cr->origmap->colors[i]==0x1000000 ) { - cr->origmap->colors[i]=nc; - cr->newcolors[idx]=i; - return i; - } - fprintf(stderr,"ERR: color map full, unable to allocate new colors.\n"); - exit(1); -} - -static void remapbyte(struct colorremap *cr,unsigned char *b) -{ - b[0]=remapcolor(cr,b[0]&15)|(remapcolor(cr,b[0]>>4)<<4); -} - -static void procremap(struct colorremap *cr,unsigned char *b,int l,pts_t *timespan) -{ - while(l) { - // fprintf(stderr,"INFO: state=%d, byte=%02x (%d)\n",cr->state,*b,*b); - switch(cr->state) { - case CR_BEGIN0: cr->curoffs=0; cr->skip=0; cr->maxlen=b[0]*256; cr->state=CR_BEGIN1; break; - case CR_BEGIN1: cr->maxlen+=b[0]; cr->state=CR_BEGIN2; break; - case CR_BEGIN2: cr->nextoffs=b[0]*256; cr->state=CR_BEGIN3; break; - case CR_BEGIN3: cr->nextoffs+=b[0]; cr->state=CR_WAIT; break; - - case CR_WAIT: - if( cr->curoffs==cr->maxlen ) { - cr->state=CR_BEGIN0; - continue; // execute BEGIN0 right away - } - if( cr->curoffs!=cr->nextoffs ) - break; - cr->state=CR_SKIP0; - // fall through to CR_SKIP0 - case CR_SKIP0: *timespan+=1024*b[0]*256; cr->state=CR_SKIP1; break; - case CR_SKIP1: *timespan+=1024*b[0]; cr->state=CR_NEXTOFFS0; break; - case CR_NEXTOFFS0: cr->nextoffs=b[0]*256; cr->state=CR_NEXTOFFS1; break; - case CR_NEXTOFFS1: cr->nextoffs+=b[0]; cr->state=CR_CMD; break; - case CR_SKIPWAIT: - if( cr->skip ) { - cr->skip--; - break; - } - cr->state=CR_CMD; - // fall through to CR_CMD - case CR_CMD: - switch(*b) { - case 0: break; - case 1: break; - case 2: break; - case 3: cr->state=CR_COL0; break; - case 4: cr->skip=2; cr->state=CR_SKIPWAIT; break; - case 5: cr->skip=6; cr->state=CR_SKIPWAIT; break; - case 6: cr->skip=4; cr->state=CR_SKIPWAIT; break; - case 7: cr->skip=2; cr->state=CR_CHGARG; break; - case 255: cr->state=CR_WAIT; break; - default: - fprintf(stderr,"ERR: procremap encountered unknown subtitle command: %d\n",*b); - exit(1); - } - break; - - case CR_COL0: - remapbyte(cr,b); - cr->state=CR_COL1; - break; - - case CR_COL1: - remapbyte(cr,b); - cr->state=CR_CMD; - break; - - case CR_CHGARG: - if (!--cr->skip) - cr->state=CR_CHGLN0; - break; - - case CR_CHGLN0: cr->ln_ctli =b[0]<<24; cr->state=CR_CHGLN1; break; - case CR_CHGLN1: cr->ln_ctli|=b[0]<<16; cr->state=CR_CHGLN2; break; - case CR_CHGLN2: cr->ln_ctli|=b[0]<< 8; cr->state=CR_CHGLN3; break; - - case CR_CHGLN3: - cr->ln_ctli|=b[0]; - - if (cr->ln_ctli==0x0fffffff) - cr->state=CR_CMD; - else { - cr->ln_ctli>>=12; - cr->ln_ctli&=0xf; - cr->skip=2; - cr->state=CR_CHGPX0; - } - break; - - case CR_CHGPX0: - if (!--cr->skip) { cr->skip=2; cr->state=CR_CHGPX1; } - break; - - case CR_CHGPX1: - remapbyte(cr,b); - if (!--cr->skip) { cr->skip=2; cr->state=CR_CHGPX2; } - break; - - case CR_CHGPX2: - if (!--cr->skip) { - if (!--cr->ln_ctli) cr->state=CR_CHGLN0; - else { cr->skip=2; cr->state=CR_CHGPX0; } - } - break; - - default: - assert(0); - } - cr->curoffs++; - b++; - l--; - } -} - -static void printvobustatus(struct vobgroup *va,int cursect) -{ - int j,nv=0; - - for( j=0; j<va->numvobs; j++ ) - nv+=va->vobs[j]->numvobus; - - // fprintf(stderr,"STAT: VOBU %d at %dMB, %d PGCS, %d:%02d:%02d\r",nv,cursect/512,va->numallpgcs,total/324000000,(total%324000000)/5400000,(total%5400000)/90000); - fprintf(stderr,"STAT: VOBU %d at %dMB, %d PGCS\r",nv,cursect/512,va->numallpgcs); -} - -static void audio_scan_ac3(struct audchannel *ach,unsigned char *buf,int sof,int len) -{ - uint32_t parse; - int acmod,lfeon,nch=0; - char attr[4]; - - if( sof+8>len ) // check if there's room to parse all the interesting info - return; - if( buf[sof]!=0x0b || buf[sof+1]!=0x77 ) // verify ac3 sync - return; - parse=read4(buf+sof+4); - if( (parse>>30)!=0 ) { // must be 48kHz - fprintf(stderr,"WARN: Unknown AC3 sample rate: %d\n",parse>>30); - } - audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_SAMPLERATE,"48khz"); - parse<<=8; - // check bsid - if( (parse>>27)!=8 && (parse>>27)!=6 ) // must be v6 or v8 - return; - parse<<=5; - // ignore bsmod - parse<<=3; - // acmod gives # of channels - acmod=(parse>>29); - parse<<=3; - // skip cmixlev? - if( (acmod&1) && (acmod!=1) ) - parse<<=2; - // skip surmixlev? - if( acmod&4 ) - parse<<=2; - // dsurmod - if( acmod==2 ) { - if( (parse>>30)==2 ) - audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_DOLBY,"surround"); - // else if( (parse>>30)==1 ) - // audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_DOLBY,"nosurround"); - parse<<=2; - } - // lfeon - lfeon=(parse>>31); - - // calc # channels - switch(acmod) { - case 0: nch=2; break; - case 1: nch=1; break; - case 2: nch=2; break; - case 3: nch=3; break; - case 4: nch=3; break; - case 5: nch=4; break; - case 6: nch=4; break; - case 7: nch=5; break; - } - if( lfeon ) nch++; - sprintf(attr,"%dch",nch); - audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_CHANNELS,attr); -} - -static void audio_scan_dts(struct audchannel *ach,unsigned char *buf,int sof,int len) -{ -} - -static void audio_scan_pcm(struct audchannel *ach,unsigned char *buf,int len) -{ - char attr[6]; - - switch(buf[1]>>6) { - case 0: audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_QUANT,"16bps"); break; - case 1: audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_QUANT,"20bps"); break; - case 2: audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_QUANT,"24bps"); break; - } - sprintf(attr,"%dkhz",48*(1+((buf[1]>>4)&1))); - audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_SAMPLERATE,attr); - sprintf(attr,"%dch",(buf[1]&7)+1); - audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_CHANNELS,attr); -} - -int FindVobus(char *fbase,struct vobgroup *va,int ismenu) -{ - unsigned char *buf; - int cursect=0,fsect=-1,vnum,outnum=-ismenu+1; - int vobid=0; - struct mp2info { - int hdrptr; - unsigned char buf[6]; - } mp2hdr[8]; - struct colorremap *crs; - - crs=malloc(sizeof(struct colorremap)*32); - for( vnum=0; vnum<va->numvobs; vnum++ ) { - int i,j; - int hadfirstvobu=0; - pts_t backoffs=0, lastscr=0; - struct vob *s=va->vobs[vnum]; - int prevvidsect=-1; - struct vscani vsi; - struct vfile vf; - - vsi.lastrefsect=0; - for( i=0; i<32; i++ ) - initremap(crs+i); - - vobid++; - s->vobid=vobid; - vsi.firstgop=1; - - fprintf(stderr,"\nSTAT: Processing %s...\n",s->fname); - vf=varied_open(s->fname,O_RDONLY); - if( !vf.h ) { - fprintf(stderr,"ERR: Error opening %s: %s\n",s->fname,strerror(errno)); - exit(1); - } - memset(mp2hdr,0,8*sizeof(struct mp2info)); - while(1) { - if( fsect == 524272 ) { - writeclose(); - if( outnum<=0 ) { - fprintf(stderr,"\nERR: Menu VOB reached 1gb\n"); - exit(1); - } - outnum++; - fsect=-1; - } - buf=writegrabbuf(); - - i=fread(buf,1,2048,vf.h); - if( i!=2048 ) { - if( i==-1 ) { - fprintf(stderr,"\nERR: Error while reading: %s\n",strerror(errno)); - exit(1); - } else if( i>0 ) - fprintf(stderr,"\nWARN: Partial sector read (%d bytes); discarding data.\n",i); - writeundo(); - break; - } - if( buf[14]==0 && buf[15]==0 && buf[16]==1 && buf[17]==0xbe && !strcmp(buf+20,"dvdauthor-data")) { - // private dvdauthor data, should be removed from the final stream - int i=35; - if( buf[i]!=1 ) { - fprintf(stderr,"ERR: dvd info packet is version %d\n",buf[i]); - exit(1); - } - switch(buf[i+1]) { // packet type - - case 1: // subtitle/menu color and button information - { - int st=buf[i+2]&31; - i+=3; - i+=8; // skip start pts and end pts - while(buf[i]!=0xff) { - switch(buf[i]) { - case 1: // new colormap - { - int j; - crs[st].origmap=s->p->ci; - for( j=0; j<buf[i+1]; j++ ) { - crs[st].newcolors[j]=0x1000000| - (buf[i+2+3*j]<<16)| - (buf[i+3+3*j]<<8)| - (buf[i+4+3*j]); - } - for( ; j<16; j++ ) - crs[st].newcolors[j]=j; - i+=2+3*buf[i+1]; - break; - } - case 2: // new buttoncoli - { - int j; - - memcpy(s->buttoncoli,buf+i+2,buf[i+1]*8); - for( j=0; j<buf[i+1]; j++ ) { - remapbyte(&crs[st],s->buttoncoli+j*8+0); - remapbyte(&crs[st],s->buttoncoli+j*8+1); - remapbyte(&crs[st],s->buttoncoli+j*8+4); - remapbyte(&crs[st],s->buttoncoli+j*8+5); - } - i+=2+8*buf[i+1]; - break; - } - case 3: // button position information - { - int j,k; - - k=buf[i+1]; - i+=2; - for( j=0; j<k; j++ ) { - struct button *b; - struct buttoninfo *bi,bitmp; - char *bn=readpstr(buf,&i); - - if( !findbutton(s->p,bn,0) ) { - fprintf(stderr,"ERR: Cannot find button '%s' as referenced by the subtitle\n",bn); - exit(1); - } - b=&s->p->buttons[findbutton(s->p,bn,0)-1]; - free(bn); - - if( b->numstream>=MAXBUTTONSTREAM ) { - fprintf(stderr,"WARN: Too many button streams; ignoring buttons\n"); - bi=&bitmp; - } else { - bi=&b->stream[b->numstream++]; - } - - bi->st=st; - - i+=2; // skip modifier - bi->autoaction=buf[i++]; - if( !bi->autoaction ) { - bi->grp=buf[i]; - bi->x1=read2(buf+i+1); - bi->y1=read2(buf+i+3); - bi->x2=read2(buf+i+5); - bi->y2=read2(buf+i+7); - i+=9; - // up down left right - bi->up=readpstr(buf,&i); - bi->down=readpstr(buf,&i); - bi->left=readpstr(buf,&i); - bi->right=readpstr(buf,&i); - } - } - break; - } - default: - fprintf(stderr,"ERR: dvd info packet command within subtitle: %d\n",buf[i]); - exit(1); - } - } - - break; - } - - default: - fprintf(stderr,"ERR: unknown dvd info packet type: %d\n",buf[i+1]); - exit(1); - } - - writeundo(); - continue; - } - if( buf[0]==0 && buf[1]==0 && buf[2]==1 && buf[3]==0xba ) { - pts_t newscr=readscr(buf+4); - if( newscr < lastscr ) { - fprintf(stderr,"WARNING: SCR moves backwards, remultiplex input.\n"); -// exit(1); - } - lastscr=newscr; - if( !hadfirstvobu ) - backoffs=newscr; - } - transpose_ts(buf,-backoffs); - if( fsect == -1 ) { - char newname[200]; - fsect=0; - if( fbase ) { - if( outnum>=0 ) - sprintf(newname,"%s_%d.VOB",fbase,outnum); - else - strcpy(newname,fbase); - writeopen(newname); - } - } - if( buf[14] == 0 && - buf[15] == 0 && - buf[16] == 1 && - buf[17] == 0xbb ) // system header - { - if( buf[38] == 0 && - buf[39] == 0 && - buf[40] == 1 && - buf[41] == 0xbf && // 1st private2 - buf[1024] == 0 && - buf[1025] == 0 && - buf[1026] == 1 && - buf[1027] == 0xbf ) // 2nd private2 - { - struct vobuinfo *vi; - if( s->numvobus ) - finishvideoscan(va,vnum,prevvidsect,&vsi); - // fprintf(stderr,"INFO: vobu\n"); - hadfirstvobu=1; - s->numvobus++; - if( s->numvobus > s->maxvobus ) { - if( !s->maxvobus ) - s->maxvobus=1; - else - s->maxvobus<<=1; - s->vi=(struct vobuinfo *)realloc(s->vi,s->maxvobus*sizeof(struct vobuinfo)); - } - vi=&s->vi[s->numvobus-1]; - memset(vi,0,sizeof(struct vobuinfo)); - vi->sector=cursect; - vi->fsect=fsect; - vi->fnum=outnum; - vi->firstvideopts=-1; - vi->firstIfield=0; - vi->numfields=0; - vi->numref=0; - vi->hasseqend=0; - vi->hasvideo=0; - memcpy(s->vi[s->numvobus-1].sectdata,buf,0x26); // save pack and system header; the rest will be reconstructed later - if( !(s->numvobus&15) ) - printvobustatus(va,cursect); - vsi.lastrefsect=0; - vsi.firstgop=1; - } else { - fprintf(stderr,"WARN: System header found, but PCI/DSI information is not where expected\n\t(make sure your system header is 18 bytes!)\n"); - } - } - if( !hadfirstvobu ) { - fprintf(stderr,"WARN: Skipping sector, waiting for first VOBU...\n"); - writeundo(); - continue; - } - s->vi[s->numvobus-1].lastsector=cursect; - - i=14; - j=-1; - while(i<=2044) { - if( buf[i]==0 && buf[i+1]==0 && buf[i+2]==1 ) { - if (buf[i+3]>=0xBD && buf[i+3]<=0xEF ) { - j=i; - i+=6+read2(buf+i+4); - continue; - } else if( buf[i+3]==0xB9 && j>=14 && buf[j+3]==0xBE ) { - write2(buf+j+4,read2(buf+j+4)+4); - memset(buf+i,0,4); // mplex uses 0 for padding, so will I - } - } - break; - } - - if( buf[0] == 0 && - buf[1] == 0 && - buf[2] == 1 && - buf[3] == 0xba && - buf[14] == 0 && - buf[15] == 0 && - buf[16] == 1 && - buf[17] == 0xe0 ) { // video - struct vobuinfo *vi=&s->vi[s->numvobus-1]; - vi->hasvideo=1; - scanvideoframe(va,buf,vi,cursect,prevvidsect,&vsi); - if( (buf[21] & 128) && vi->firstvideopts==-1 ) { // check whether there's a pts - vi->firstvideopts=readpts(buf+23); - } - prevvidsect=cursect; - } - if( buf[0] == 0 && - buf[1] == 0 && - buf[2] == 1 && - buf[3] == 0xba && - buf[14] == 0 && - buf[15] == 0 && - buf[16] == 1 && - ((buf[17] & 0xf8) == 0xc0 || buf[17]==0xbd)) { - pts_t pts0=0,pts1=0,backpts1=0; - int dptr=buf[22]+23,endop=read2(buf+18)+20; - int audch,haspts=(buf[21]&128); - if( buf[17]==0xbd ) { - int sid=buf[dptr],offs=read2(buf+dptr+2); - - switch(sid&0xf8) { - case 0x20: // subpicture - case 0x28: // subpicture - case 0x30: // subpicture - case 0x38: audch=sid; break; // subpicture - case 0x80: // ac3 - pts1+=2880*buf[dptr+1]; - audch=sid&7; - audio_scan_ac3(&s->audch[audch],buf+dptr+4,offs-1,endop-(dptr+4)); - break; - case 0x88: // dts - audch=24|(sid&7); - audio_scan_dts(&s->audch[audch],buf+dptr+4,offs-1,endop-(dptr+4)); - break; - case 0xa0: // pcm - pts1+=150*buf[dptr+1]; - audch=16|(sid&7); - audio_scan_pcm(&s->audch[audch],buf+dptr+4,endop-(dptr+4)); - break; - default: audch=-1; break; // unknown - } - } else { - int len=endop-dptr; - int index=buf[17]&7; - audch=8|index; // mp2 - memcpy(mp2hdr[index].buf+3,buf+dptr,3); - while(mp2hdr[index].hdrptr+4<=len) { - unsigned char *h; - - if( mp2hdr[index].hdrptr < 0 ) - h=mp2hdr[index].buf+3+mp2hdr[index].hdrptr; - else - h=buf+dptr+mp2hdr[index].hdrptr; - - if( !mpa_valid(h) ) { - mp2hdr[index].hdrptr++; - continue; - } - if( mp2hdr[index].hdrptr<0 ) - backpts1+=2160; - else - pts1+=2160; - mp2hdr[index].hdrptr+=mpa_len(h); - } - mp2hdr[index].hdrptr-=len; - memcpy(mp2hdr[index].buf,buf+dptr+len-3,3); - audiodesc_set_audio_attr(&s->audch[audch].ad,&s->audch[audch].adwarn,AUDIO_SAMPLERATE,"48khz"); - } - if( haspts ) { - pts0=readpts(buf+23); - pts1+=pts0; - } else if( pts1>0 ) { - fprintf(stderr,"WARN: Audio channel %d contains sync headers but has no PTS.\n",audch); - } - // fprintf(stderr,"aud ch=%d pts %d - %d (%d)\n",audch,pts0,pts1,pts1-pts0); - // fprintf(stderr,"pts[%d] %d (%02x %02x %02x %02x %02x)\n",va->numaudpts,pts,buf[23],buf[24],buf[25],buf[26],buf[27]); - if( audch<0 || audch>=64 ) { - fprintf(stderr,"WARN: Invalid audio channel %d\n",audch); - } else if( haspts ) { - struct audchannel *ach=&s->audch[audch]; - - if( ach->numaudpts>=ach->maxaudpts ) { - if( ach->maxaudpts ) - ach->maxaudpts<<=1; - else - ach->maxaudpts=1; - ach->audpts=(struct audpts *)realloc(ach->audpts,ach->maxaudpts*sizeof(struct audpts)); - } - if( ach->numaudpts ) { - // we cannot compute the length of a DTS audio packet - // so just backfill if it is one - // otherwise, for mp2 add any pts to the previous - // sector for a header that spanned two sectors - if( (audch&0x38) == 0x18 ) // is this DTS? - ach->audpts[ach->numaudpts-1].pts[1]=pts0; - else - ach->audpts[ach->numaudpts-1].pts[1]+=backpts1; - - if( ach->audpts[ach->numaudpts-1].pts[1]<pts0 ) { - if( audch>=32 ) - goto noshow; - fprintf(stderr,"WARN: Discontinuity of %" PRId64" in audio channel %d; please remultiplex input.\n",pts0-ach->audpts[ach->numaudpts-1].pts[1],audch); - // fprintf(stderr,"last=%d, this=%d\n",ach->audpts[ach->numaudpts-1].pts[1],pts0); - } else if( ach->audpts[ach->numaudpts-1].pts[1]>pts0 ) - fprintf(stderr,"WARN: Audio pts for channel %d moves backwards by %" PRId64 "; please remultiplex input.\n",audch,ach->audpts[ach->numaudpts-1].pts[1]-pts0); - else - goto noshow; - fprintf(stderr,"WARN: Previous sector: "); - printpts(ach->audpts[ach->numaudpts-1].pts[0]); - fprintf(stderr," - "); - printpts(ach->audpts[ach->numaudpts-1].pts[1]); - fprintf(stderr,"\nWARN: Current sector: "); - printpts(pts0); - fprintf(stderr," - "); - printpts(pts1); - fprintf(stderr,"\n"); - ach->audpts[ach->numaudpts-1].pts[1]=pts0; - } - noshow: - ach->audpts[ach->numaudpts].pts[0]=pts0; - ach->audpts[ach->numaudpts].pts[1]=pts1; - ach->audpts[ach->numaudpts].sect=cursect; - ach->numaudpts++; - } - } - // the following code scans subtitle code in order to - // remap the colors and update the end pts - if( buf[0] == 0 && - buf[1] == 0 && - buf[2] == 1 && - buf[3] == 0xba && - buf[14] == 0 && - buf[15] == 0 && - buf[16] == 1 && - buf[17] == 0xbd) { - int dptr=buf[22]+23,ml=read2(buf+18)+20; - int st=buf[dptr]; - dptr++; - if( (st&0xf8)==0x20 ) { // subtitle - procremap(&crs[st&31],buf+dptr,ml-dptr,&s->audch[st].audpts[s->audch[st].numaudpts-1].pts[1]); - } - } - cursect++; - fsect++; - } - varied_close(vf); - if( s->numvobus ) { - int i; - pts_t finalaudiopts; - - finishvideoscan(va,vnum,prevvidsect,&vsi); - // find end of audio - finalaudiopts=-1; - for( i=0; i<32; i++ ) { - struct audchannel *ach=s->audch+i; - if( ach->numaudpts && - ach->audpts[ach->numaudpts-1].pts[1] > finalaudiopts ) - finalaudiopts=ach->audpts[ach->numaudpts-1].pts[1]; - } - - // pin down all video vobus - // note: we make two passes; one assumes that the PTS for the - // first frame is exact; the other assumes that the PTS for - // the first frame is off by 1/2. If both fail, then the third pass - // assumes things are exact and throws a warning - for( i=0; i<3; i++ ) { - pts_t pts_align=-1; - int complain=0, j; - - for( j=0; j<s->numvobus; j++ ) { - struct vobuinfo *vi=s->vi+j; - - if( vi->hasvideo ) { - if( pts_align==-1 ) { - pts_align=vi->firstvideopts*2; - if( i==1 ) { - // I assume pts should round down? That seems to be how mplex deals with it - // also see earlier comment - - // since pts round down, then the alternative base we should try is - // firstvideopts+0.5, thus increment - pts_align++; - } - // MarkChapters will complain if firstIfield!=0 - } - - vi->videopts[0]=calcpts(va,i==2,&complain,&pts_align,vi->firstvideopts,-vi->firstIfield); - vi->videopts[1]=calcpts(va,i==2,&complain,&pts_align,vi->firstvideopts,-vi->firstIfield+vi->numfields); - // if this looks like a dud, abort and try the next pass - if( complain && i<2 ) - break; - - vi->sectpts[0]=vi->videopts[0]; - if( j+1 == s->numvobus && finalaudiopts > vi->videopts[1] ) - vi->sectpts[1]=finalaudiopts; - else - vi->sectpts[1]=vi->videopts[1]; - } - } - if( !complain ) - break; - } - - // guess at non-video vobus - for( i=0; i<s->numvobus; i++ ) { - struct vobuinfo *vi=s->vi+i; - if( !vi->hasvideo ) { - int j,k; - pts_t firstaudiopts=-1,p; - - for( j=0; j<32; j++ ) { - struct audchannel *ach=s->audch+j; - for( k=0; k<ach->numaudpts; k++ ) - if( ach->audpts[k].sect>=vi->sector ) { - if( firstaudiopts==-1 || ach->audpts[k].pts[0]<firstaudiopts ) - firstaudiopts=ach->audpts[k].pts[0]; - break; - } - } - if( firstaudiopts==-1 ) { - fprintf(stderr,"WARN: Cannot detect pts for VOBU if there is no audio or video\nWARN: Using SCR instead.\n"); - firstaudiopts=readscr(vi->sectdata+4)+4*147; // 147 is roughly the minumum pts that must transpire between packets; we give a couple packets of buffer to allow the dvd player to process the data - } - if( i ) { - pts_t frpts=getframepts(va); - p=firstaudiopts-s->vi[i-1].sectpts[0]; - // ensure this is a multiple of a framerate, just to be nice - p+=frpts-1; - p-=p%frpts; - p+=s->vi[i-1].sectpts[0]; - assert(p>=s->vi[i-1].sectpts[1]); - s->vi[i-1].sectpts[1]=p; - } else { - fprintf(stderr,"ERR: Cannot infer pts for VOBU if there is no audio or video and it is the\nERR: first VOBU.\n"); - exit(1); - } - vi->sectpts[0]=p; - - // if we can easily predict the end pts of this sector, - // then fill it in. otherwise, let the next iteration do it - if( i+1==s->numvobus ) { // if this is the end of the vob, use the final audio pts as the last pts - if( finalaudiopts>vi->sectpts[0] ) - p=finalaudiopts; - else - p=vi->sectpts[0]+getframepts(va); // add one frame of a buffer, so we don't have a zero (or less) length vobu - } else if( s->vi[i+1].hasvideo ) // if the next vobu has video, use the start of the video as the end of this vobu - p=s->vi[i+1].sectpts[0]; - else // the next vobu is an audio only vobu, and will backfill the pts as necessary - continue; - if( p<=vi->sectpts[0] ) { - fprintf(stderr, "ERR: Audio and video are too poorly synchronised; you must remultiplex.\n"); - exit(1); - } - vi->sectpts[1]=p; - } - } - - fprintf(stderr,"\nINFO: Video pts = "); - printpts(s->vi[0].videopts[0]); - fprintf(stderr," .. "); - for( i=s->numvobus-1; i>=0; i-- ) - if( s->vi[i].hasvideo ) { - printpts(s->vi[i].videopts[1]); - break; - } - if( i<0 ) - fprintf(stderr,"??"); - for( i=0; i<64; i++ ) { - struct audchannel *ach=&s->audch[i]; - - if( ach->numaudpts ) { - fprintf(stderr,"\nINFO: Audio[%d] pts = ",i); - printpts(ach->audpts[0].pts[0]); - fprintf(stderr," .. "); - printpts(ach->audpts[ach->numaudpts-1].pts[1]); - } - } - fprintf(stderr,"\n"); - } - } - writeclose(); - printvobustatus(va,cursect); - fprintf(stderr,"\n"); - free(crs); - return 1; -} - -static pts_t pabs(pts_t pts) -{ - if( pts<0 ) - return -pts; - return pts; -} - -static int findnearestvobu(struct vobgroup *pg,struct vob *va,pts_t pts) -{ - int l=0,h=va->numvobus-1,i; - - if( h<0 ) - return -1; - pts+=va->vi[0].sectpts[0]; - i=findvobu(va,pts,l,h); - if( i+1<va->numvobus && i>=0 && - pabs(pts-va->vi[i+1].sectpts[0])<pabs(pts-va->vi[i].sectpts[0]) ) - i++; - return i; -} - -void MarkChapters(struct vobgroup *va) -{ - int i,j,k,lastcellid; - - // mark start and stop points - lastcellid=-1; - for( i=0; i<va->numallpgcs; i++ ) - for( j=0; j<va->allpgcs[i]->numsources; j++ ) { - struct source *s=va->allpgcs[i]->sources[j]; - - for( k=0; k<s->numcells; k++ ) { - int v; - - v=findnearestvobu(va,s->vob,s->cells[k].startpts); - if( v>=0 && v<s->vob->numvobus ) - s->vob->vi[v].vobcellid=1; - s->cells[k].scellid=v; - - if( lastcellid!=v && - s->vob->vi[v].firstIfield!=0) { - fprintf(stderr,"WARN: GOP may not be closed on cell %d of source %s of pgc %d\n",k+1,s->fname,i+1); - } - - if( s->cells[k].endpts>=0 ) { - v=findnearestvobu(va,s->vob,s->cells[k].endpts); - if( v>=0 && v<s->vob->numvobus ) - s->vob->vi[v].vobcellid=1; - } else - v=s->vob->numvobus; - s->cells[k].ecellid=v; - - lastcellid=v; - } - } - // tally up actual cells - for( i=0; i<va->numvobs; i++ ) { - int cellvobu=0; - int cellid=0; - va->vobs[i]->vi[0].vobcellid=1; - for( j=0; j<va->vobs[i]->numvobus; j++ ) { - struct vobuinfo *v=&va->vobs[i]->vi[j]; - if( v->vobcellid ) { - cellid++; - cellvobu=j; - } - v->vobcellid=cellid+va->vobs[i]->vobid*256; - v->firstvobuincell=cellvobu; - } - cellvobu=va->vobs[i]->numvobus-1; - for( j=cellvobu; j>=0; j-- ) { - struct vobuinfo *v=&va->vobs[i]->vi[j]; - v->lastvobuincell=cellvobu; - if(v->firstvobuincell==j ) - cellvobu=j-1; - } - va->vobs[i]->numcells=cellid; - if( cellid>=256 ) { - fprintf(stderr,"ERR: VOB %s has too many cells (%d, 256 allowed)\n",va->vobs[i]->fname,cellid); - exit(1); - } - } - - // now compute scellid and ecellid - for( i=0; i<va->numallpgcs; i++ ) - for( j=0; j<va->allpgcs[i]->numsources; j++ ) { - struct source *s=va->allpgcs[i]->sources[j]; - - for( k=0; k<s->numcells; k++ ) { - struct cell *c=&s->cells[k]; - - if( c->scellid<0 ) - c->scellid=1; - else if( c->scellid<s->vob->numvobus ) - c->scellid=s->vob->vi[c->scellid].vobcellid&255; - else - c->scellid=s->vob->numcells+1; - - if( c->ecellid<0 ) - c->ecellid=1; - else if( c->ecellid<s->vob->numvobus ) - c->ecellid=s->vob->vi[c->ecellid].vobcellid&255; - else - c->ecellid=s->vob->numcells+1; - - va->allpgcs[i]->numcells+=c->ecellid-c->scellid; - if( c->scellid!=c->ecellid && c->ischapter ) { - va->allpgcs[i]->numprograms++; - if( c->ischapter==1 ) - va->allpgcs[i]->numchapters++; - if( va->allpgcs[i]->numprograms>=256 ) { - fprintf(stderr,"ERR: PGC %d has too many programs (%d, 256 allowed)\n",i+1,va->allpgcs[i]->numprograms); - exit(1); - } - // if numprograms<256, then numchapters<256, so - // no need to doublecheck - } - } - } -} - -static pts_t getcellaudiopts(const struct vobgroup *va,int vcid,int ach,int w) -{ - const struct vob *v=va->vobs[(vcid>>8)-1]; - const struct audchannel *a=&v->audch[ach]; - int ai=0; - - assert((vcid&255)==(w?v->numcells:1)); - if( w ) - ai=a->numaudpts-1; - return a->audpts[ai].pts[w]; -} - -static int hasaudio(const struct vobgroup *va,int vcid,int ach,int w) -{ - const struct vob *v=va->vobs[(vcid>>8)-1]; - const struct audchannel *a=&v->audch[ach]; - - assert((vcid&255)==(w?v->numcells:1)); - - return a->numaudpts!=0; -} - -static pts_t getcellvideopts(const struct vobgroup *va,int vcid,int w) -{ - const struct vob *v=va->vobs[(vcid>>8)-1]; - int vi=0; - - assert((vcid&255)==(w?v->numcells:1)); - if( w ) - vi=v->numvobus-1; - // we use sectpts instead of videopts because sometimes you will - // present the last video frame for a long time; we want to know - // the last presented time stamp: sectpts - return v->vi[vi].sectpts[w]; -} - -static pts_t calcaudiodiff(const struct vobgroup *va,int vcid,int ach,int w) -{ - return getcellvideopts(va,vcid,w)-getcellaudiopts(va,vcid,ach,w); -} - -int calcaudiogap(const struct vobgroup *va,int vcid0,int vcid1,int ach) -{ - if( vcid0==-1 || vcid1==-1 ) - return 0; - if( vcid1==vcid0+1 ) - return 0; - if( (vcid1&255)==1 && va->vobs[(vcid0>>8)-1]->numcells==(vcid0&255) ) { - int g1,g2; - - // there is no discontinuity if there is no audio in the second half - if( !hasaudio(va,vcid1,ach,0) ) - return 0; - - // we have problems if the second half has audio but the first doesn't - if( !hasaudio(va,vcid0,ach,1) && hasaudio(va,vcid1,ach,0) ) { - fprintf(stderr,"WARN: Transition from non-audio to audio VOB; assuming discontinuity.\n"); - return 1; - } - - g1=calcaudiodiff(va,vcid0,ach,1); - g2=calcaudiodiff(va,vcid1,ach,0); - return g1!=g2; - } - fprintf(stderr,"WARN: Do not know how to compute the audio gap between '%s' and '%s', assuming discontinuity.\n",va->vobs[(vcid0>>8)-1]->fname,va->vobs[(vcid1>>8)-1]->fname); - return 1; -} - -void FixVobus(char *fbase,const struct vobgroup *va,const struct workset *ws,int ismenu) -{ - int h=-1; - int i,j,pn,fnum=-2; - pts_t scr; - int vff,vrew,totvob,curvob; - - totvob=0; - for( pn=0; pn<va->numvobs; pn++ ) - totvob+=va->vobs[pn]->numvobus; - curvob=0; - - for( pn=0; pn<va->numvobs; pn++ ) { - struct vob *p=va->vobs[pn]; - - for( i=0; i<p->numvobus; i++ ) { - struct vobuinfo *vi=&p->vi[i]; - static unsigned char buf[2048]; - - if( vi->fnum!=fnum ) { - char fname[200]; - if( h >= 0 ) - close(h); - fnum=vi->fnum; - if( fbase ) { - if( fnum==-1 ) - strcpy(fname,fbase); - else - sprintf(fname,"%s_%d.VOB",fbase,fnum); - h=open(fname,O_WRONLY|O_BINARY); - if( h < 0 ) { - fprintf(stderr,"\nERR: Error opening %s: %s\n",fname,strerror(errno)); - exit(1); - } - } - } - memcpy(buf,vi->sectdata,0x26); - write4(buf+0x26,0x1bf); // private stream 2 - write2(buf+0x2a,0x3d4); // length - buf[0x2c]=0; - memset(buf+0x2d,0,0x400-0x2d); - write4(buf+0x400,0x1bf); // private stream 2 - write2(buf+0x404,0x3fa); // length - buf[0x406]=1; - memset(buf+0x407,0,0x7ff-0x407); - - scr=readscr(buf+4); - - write4(buf+0x2d,vi->sector); - write4(buf+0x39,vi->sectpts[0]); // vobu_s_ptm - write4(buf+0x3d,vi->sectpts[1]); // vobu_e_ptm - if( vi->hasseqend ) // if sequence_end_code - write4(buf+0x41,vi->videopts[1]); // vobu_se_e_ptm - write4(buf+0x45,buildtimeeven(va,vi->sectpts[0]-p->vi[vi->firstvobuincell].sectpts[0])); // total guess - - if( p->p->numbuttons ) { - struct pgc *pg=p->p; - int mask=getsubpmask(&va->vd),ng,grp; - char idmap[3]; - - write2(buf+0x8d,1); - write4(buf+0x8f,p->vi[0].sectpts[0]); - write4(buf+0x93,-1); - write4(buf+0x97,-1); - - ng=0; - write2(buf+0x9b,0); - for( j=0; j<4; j++ ) - if( mask&(1<<j) ) { - assert(ng<3); - idmap[ng]=j; - write2(buf+0x9b,read2(buf+0x9b)+0x1000+(((1<<j)>>1)<<(2-ng)*4)); - ng++; - } - assert(ng>0); - - buf[0x9e]=pg->numbuttons; - buf[0x9f]=pg->numbuttons; - memcpy(buf+0xa3,p->buttoncoli,24); - for( grp=0; grp<ng; grp++ ) { - unsigned char *boffs=buf+0xbb+18*(grp*36/ng); - int sid=pg->subpmap[0][(int)idmap[grp]]&127; - - for( j=0; j<pg->numbuttons; j++ ) { - static unsigned char compilebuf[128*8],*rbuf; - struct button *b=pg->buttons+j; - struct buttoninfo *bi; - int k; - - for( k=0; k<b->numstream; k++ ) - if( b->stream[k].st==sid ) - break; - if( k==b->numstream ) - continue; - bi=&b->stream[k]; - - if( bi->autoaction ) { - boffs[3]=64; - } else { - boffs[0]=(bi->grp*64)|(bi->x1>>4); - boffs[1]=(bi->x1<<4)|(bi->x2>>8); - boffs[2]=bi->x2; - boffs[3]=(bi->y1>>4); - boffs[4]=(bi->y1<<4)|(bi->y2>>8); - boffs[5]=bi->y2; - boffs[6]=findbutton(pg,bi->up,(j==0)?pg->numbuttons:j); - boffs[7]=findbutton(pg,bi->down,(j+1==pg->numbuttons)?1:j+2); - boffs[8]=findbutton(pg,bi->left,(j==0)?pg->numbuttons:j); - boffs[9]=findbutton(pg,bi->right,(j+1==pg->numbuttons)?1:j+2); - } - rbuf=vm_compile(compilebuf,compilebuf,ws,pg->pgcgroup,pg,b->cs,ismenu); - if( rbuf-compilebuf==8 ) { - memcpy(boffs+10,compilebuf,8); - } else if( allowallreg ) { - fprintf(stderr,"ERR: Button command is too complex to fit in one instruction, and allgprm==true.\n"); - exit(1); - } else - write8(boffs+10,0x71,0x01,0x00,0x0F,0x00,j+1,0x00,0x0d); // g[15]=j && linktailpgc - boffs+=18; - } - } - } - - write4(buf+0x407,scr); - write4(buf+0x40b,vi->sector); // current lbn - if( vi->numref>0 ) { - for( j=0; j<vi->numref; j++ ) - write4(buf+0x413+j*4,vi->lastrefsect[j]-vi->sector); - for( ; j<3; j++ ) - write4(buf+0x413+j*4,vi->lastrefsect[vi->numref-1]-vi->sector); - } - write2(buf+0x41f,vi->vobcellid>>8); - buf[0x422]=vi->vobcellid; - write4(buf+0x423,read4(buf+0x45)); - write4(buf+0x433,p->vi[0].sectpts[0]); - write4(buf+0x437,p->vi[p->numvobus-1].sectpts[1]); - - write4(buf+0x4f1,getsect(p,i,findnextvideo(p,i,1),0,0xbfffffff)); - write4(buf+0x541,getsect(p,i,i+1,0,0x3fffffff)); - write4(buf+0x545,getsect(p,i,i-1,0,0x3fffffff)); - write4(buf+0x595,getsect(p,i,findnextvideo(p,i,-1),0,0xbfffffff)); - for( j=0; j<va->numaudiotracks; j++ ) { - int s=getaudch(va,j); - - if( s>=0 ) - s=findaudsect(p,s,vi->sectpts[0],vi->sectpts[1]); - - if( s>=0 ) { - s=s-vi->sector; - if( s > 0x1fff || s < -(0x1fff)) { - fprintf(stderr,"\nWARN: audio sector out of range: %d (vobu #%d, pts ",s,i); - printpts(vi->sectpts[0]); - fprintf(stderr,")\n"); - s=0; - } - if( s < 0 ) - s=(-s)|0x8000; - } else - s=0x3fff; - write2(buf+0x599+j*2,s); - } - for( j=0; j<va->numsubpicturetracks; j++ ) { - struct audchannel *ach=&p->audch[j|32]; - int s; - - if( ach->numaudpts ) { - int id=findspuidx(p,j|32,vi->sectpts[0]); - - // if overlaps A, point to A - // else if (A before here or doesn't exist) and (B after here or doesn't exist), point to here - // else point to B - - if( id>=0 && - ach->audpts[id].pts[0]<vi->sectpts[1] && - ach->audpts[id].pts[1]>=vi->sectpts[0] ) - s=findvobubysect(p,ach->audpts[id].sect); - else if( (id<0 || ach->audpts[id].pts[1]<vi->sectpts[0]) && - (id+1==ach->numaudpts || ach->audpts[id+1].pts[0]>=vi->sectpts[1]) ) - s=i; - else - s=findvobubysect(p,ach->audpts[id+1].sect); - id=(s<i); - s=getsect(p,i,s,0,0x7fffffff)&0x7fffffff; - if(!s) - s=0x7fffffff; - if(s!=0x7fffffff && id) - s|=0x80000000; - } else - s=0; - write4(buf+0x5a9+j*4,s); - } - write4(buf+0x40f,vi->lastsector-vi->sector); - vff=i; - vrew=i; - for( j=0; j<19; j++ ) { - int nff,nrew; - - nff=findvobu(p,vi->sectpts[0]+timeline[j]*DVD_FFREW_HALFSEC, - vi->firstvobuincell, - vi->lastvobuincell); - // a hack -- the last vobu in the cell shouldn't have any forward ptrs - // EXCEPT this hack violates both Grosse Pointe Blank and Bullitt -- what was I thinking? - // if( i==vi->lastvobuincell ) - // nff=i+1; - - nrew=findvobu(p,vi->sectpts[0]-timeline[j]*DVD_FFREW_HALFSEC, - vi->firstvobuincell, - vi->lastvobuincell); - write4(buf+0x53d-j*4,getsect(p,i,nff,j>=15 && nff>vff+1,0x3fffffff)); - write4(buf+0x549+j*4,getsect(p,i,nrew,j>=15 && nrew<vrew-1,0x3fffffff)); - vff=nff; - vrew=nrew; - } - - if( h!=-1 ) { - lseek(h,vi->fsect*2048,SEEK_SET); - write(h,buf,2048); - } - curvob++; - if( !(curvob&15) ) - fprintf(stderr,"STAT: fixing VOBU at %dMB (%d/%d, %d%%)\r",vi->sector/512,curvob+1,totvob,curvob*100/totvob); - } - } - if( h!=-1 ) - close(h); - if( totvob>0 ) - fprintf(stderr,"STAT: fixed %d VOBUS ",totvob); - fprintf(stderr,"\n"); -} -
View file
lxdvdrip-1.76.tar.bz2/dvdauthor/0.6.14/spuunmux.c
Deleted
@@ -1,1171 +0,0 @@ -/* - * Copyright (C) 2002, 2003 Jan Panteltje <panteltje@yahoo.com>, - * - * Modified by Zachary Brewster-Geisz, 2003, to work on big-endian - * machines. - * - * Modified by Henry Mason, 2003, to use both PNG and BMP, and to use - * the dvdauthor submux format. - * - * Modified and copy right Jan Panteltje 2002 - * 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. - * - * With many changes by Scott Smith (trckjunky@users.sourceforge.net) - * - * 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 - */ - -#include "config.h" - -#include "compat.h" - -#include <fcntl.h> - -#include <netinet/in.h> - -#include <png.h> - -#include "rgb.h" - -#define FALSE 0 -#define TRUE (!FALSE) - -#define CBUFSIZE 65536 -#define PSBUFSIZE 10 - - -static unsigned int add_offset; - -static int debug = 0; - -static int full_size = FALSE; -static unsigned int pts, spts, subi, subs, subno; -static int ofs, ofs1; -static unsigned char sub[65536]; -static unsigned char next_bits; -static char *base_name; -static int have_bits; -static FILE *fdo; - -typedef struct { - unsigned char r, g, b, t; -} palt; -static palt bpal[16]; - -struct spu { - unsigned char *img; - unsigned int x0, y0, xd, yd, pts[2], subno, force_display, nummap; - struct colormap *map; - struct spu *next; -}; - -static struct spu *spus=0; - -struct button { - char *name; - int autoaction; - int x1,y1,x2,y2; - char *up,*down,*left,*right; - int grp; -}; - -struct dispdetails { - int pts[2]; - int numpal; - uint32_t palette[16]; - int numcoli; - uint32_t coli[6]; - int numbuttons; - struct button *buttons; - struct dispdetails *next; -}; - -static struct dispdetails *dd=0; - -struct colormap { - uint16_t color; - uint16_t contrast; - int x1,y1,x2,y2; -}; - -static unsigned int read4(unsigned char *p) -{ - return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; -} - -static unsigned int read2(unsigned char *p) -{ - return (p[0]<<8)|p[1]; -} - -static char *readpstr(char *b,int *i) -{ - char *s=strdup(b+i[0]); - i[0]+=strlen(s)+1; - return s; -} - -static unsigned char get_next_bits() -{ - if (!have_bits) { - next_bits = sub[ofs++]; - have_bits = TRUE; - return next_bits >> 4; - } - have_bits = FALSE; - return next_bits & 15; -} - -static unsigned int getpts(unsigned char *buf) -{ - if (!(buf[1] & 0xc0) || - (buf[2] < 4) || ((buf[3] & 0xe1) != 0x21) || - ((buf[5] & 1) != 1) || ((buf[7] & 1) != 1)) - return -1; - return (buf[7] >> 1) + ((unsigned int) buf[6] << 7) + - (((unsigned int) buf[5] & 254) << 14) + - ((unsigned int) buf[4] << 22) + - (((unsigned int) buf[3] & 14) << 29); -} - -static void addspu(struct spu *s) -{ - struct spu **f=&spus; - - while( *f ) - f=&(f[0]->next); - *f=s; -} - -static void adddd(struct dispdetails *d) -{ - struct dispdetails **dp=ⅆ - - while (*dp ) - dp=&(dp[0]->next); - *dp=d; -} - -static int dvddecode() -{ - unsigned int io; - uint16_t size, dsize, i, x, y, t; - unsigned char c; - struct spu *s; - - size = read2(sub); - dsize = read2(sub+2); - - ofs = -1; - - if (debug > 1) - fprintf(stderr, "packet: %d bytes, first block offset=%d\n", size, - dsize); - - s=malloc(sizeof(struct spu)); - memset(s,0,sizeof(struct spu)); - - s->subno=subno++; - - s->pts[0] = s->pts[1] = -1; - s->nummap=1; - s->map=malloc(sizeof(struct colormap)); - memset(s->map,0,sizeof(struct colormap)); - s->map[0].x2=0x7fffffff; - s->map[0].y2=0x7fffffff; - i = dsize + 4; - - t = read2(sub+dsize); - - if (debug > 2) - fprintf(stderr, "\tBLK(%5d): time offset: %d; next: %d\n", dsize, t, read2(sub+dsize+2)); - - while (i < size) { - c = sub[i]; - - switch (c) { - case 0x0: //force start display - if (debug > 4) - fprintf(stderr, "\tcmd(%5d): force start display\n",i); - s->force_display = TRUE; - // fall through - case 0x01: - if (debug > 4 && c==0x01) - fprintf(stderr, "\tcmd(%5d): start display\n",i); - i++; - s->pts[0] = t * 1024 + spts; - break; - - case 0x02: - if (debug > 4) - fprintf(stderr, "\tcmd(%5d): end display\n",i); - s->pts[1] = t * 1024 + spts; - i++; - break; - - case 0x03: - if (debug > 4) - fprintf(stderr, "\tcmd(%5d): palette=%02x%02x\n", i, sub[i + 1], sub[i + 2]); - - s->map[0].color=read2(sub+i+1); - i += 3; - break; - - case 0x04: - if (debug > 4) - fprintf(stderr, "\tcmd(%5d): transparency=%02x%02x\n", i, sub[i + 1], sub[i + 2]); - - s->map[0].contrast=read2(sub+i+1); - i += 3; - break; - - case 0x05: - s->x0 = ((((unsigned int) sub[i + 1]) << 4) + (sub[i + 2] >> 4)); - s->xd = (((sub[i + 2] & 0x0f) << 8) + sub[i + 3]) - s->x0 + 1; - - s->y0 = ((((unsigned int) sub[i + 4]) << 4) + (sub[i + 5] >> 4)); - s->yd = (((sub[i + 5] & 0x0f) << 8) + sub[i + 6]) - s->y0 + 1; - - if (debug > 4) - fprintf(stderr, "\tcmd(%5d): image corner=%d,%d, size=%d,%d\n", i, s->x0, - s->y0, s->xd, s->yd); - i += 7; - break; - - case 0x06: - if( ofs>=0 ) - fprintf(stderr,"WARN: image pointer already supplied for this subpicture\n"); - ofs = read2(sub+i+1); - ofs1 = read2(sub+i+3); - if (debug > 4) - fprintf(stderr, "\tcmd(%5d): image offsets=%d,%d\n", i, ofs, - ofs1); - i += 5; - break; - - case 0xff: - if (i + 5 > size) { - if (debug > 4) - fprintf(stderr,"\tcmd(%5d): end cmd\n",i); - - i = size; - break; - } - - t = read2(sub + i + 1); - if (debug > 4) { - fprintf(stderr, "\tcmd(%5d): end cmd\n",i); - fprintf(stderr, "\tBLK(%5d): time offset: %d; next: %d\n", i+1, t, read2(sub+i+3)); - } - - if ((sub[i + 3] != sub[dsize + 2]) - || (sub[i + 4] != sub[dsize + 3])) { - if (debug > 0) { - fprintf(stderr, - "invalid control header (%02x%02x != %02x%02x) dsize=%d!\n", - sub[i + 3], sub[i + 4], sub[dsize + 2], - sub[dsize + 3], dsize); - } - - i = size; - break; - } - - i += 5; - break; - - default: - if (debug > 4) - fprintf(stderr, "\tcmd(%5d): 0x%x\n", i, c); - if (debug > 0) - fprintf(stderr, - "invalid sequence in control header (%02x)!\n", c); - return -1; - } /* end switch command */ - } /* end while i < size */ - - have_bits = FALSE; - x = y = 0; - io = 0; - s->img = malloc( s->xd*s->yd); - - if( ofs<0 && y<s->yd ) { - fprintf(stderr,"WARN: No image data supplied for this subtitle\n"); - } else { - while ((ofs < dsize) && (y < s->yd)) { - i = get_next_bits(); - - if (i < 4) { - i = (i << 4) + get_next_bits(); - if (i < 16) { - i = (i << 4) + get_next_bits(); - if (i < 0x40) { - i = (i << 4) + get_next_bits(); - if (i < 4) { - i=i+(s->xd-x)*4; - } - } - } - } - - c = i & 3; - i = i >> 2; - while (i--) { - s->img[io++] = c; - if (++x == s->xd) { - y += 2; - x = 0; - if ((y >= s->yd) && !(y & 1)) { - y = 1; - io = s->xd; - ofs = ofs1; - } else - io += s->xd; - have_bits = FALSE; - } - } - } - } - - if (s->pts[0] == -1) - return 0; - - s->pts[0] += add_offset; - if( s->pts[1] != -1 ) - s->pts[1] += add_offset; - - addspu(s); - - return 0; -} /* end fuction dvd_decode */ - - - - /* - * from Y -> R - * from V -> G - * from U -> B - */ - -static void ycrcb_to_rgb(int *Y, int *Cr, int *Cb) -{ - int R, G, B; - R = YCrCb2R(*Y,*Cr,*Cb); - G = YCrCb2G(*Y,*Cr,*Cb); - B = YCrCb2B(*Y,*Cr,*Cb); - *Y = R; - *Cr = G; - *Cb = B; -} - -static void absorb_palette(struct dispdetails *d) -{ - int i; - for( i=0; i<d->numpal; i++ ) { - int Y,Cr,Cb; - - Y=(d->palette[i]>>16)&255; - Cr=(d->palette[i]>>8)&255; - Cb=(d->palette[i])&255; - bpal[i].r=YCrCb2R(Y,Cr,Cb); - bpal[i].g=YCrCb2G(Y,Cr,Cb); - bpal[i].b=YCrCb2B(Y,Cr,Cb); - } -} - -static void pluck_dd() -{ - struct dispdetails *d=dd; - int i; - - dd=d->next; - absorb_palette(d); - for( i=0; i<d->numbuttons; i++ ) { - free(d->buttons[i].name); - free(d->buttons[i].up); - free(d->buttons[i].down); - free(d->buttons[i].left); - free(d->buttons[i].right); - } - free(d->buttons); - free(d); -} - -static unsigned char cmap_find(int x,int y,struct colormap *map,int nummap,int ci) -{ - int i; - unsigned char cix=0; - - for( i=0; i<nummap; i++ ) - if( x>=map[i].x1 && - y>=map[i].y1 && - x<=map[i].x2 && - y<=map[i].y2 ) - cix=(((map[i].contrast>>(ci*4))&15)<<4) | - (((map[i].color>>(ci*4))&15)); - return cix; -} - -static int write_png(char *file_name,struct spu *s,struct colormap *map,int nummap) -{ - unsigned int a, x, y, nonzero; - unsigned char *out_buf, *temp; - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - - temp = out_buf = malloc(s->xd * s->yd * 4); - nonzero=0; - for (y = 0; y < s->yd; y++) { - for (x = 0; x < s->xd; x++) { - unsigned char cix=cmap_find(x+s->x0,y+s->y0,map,nummap,s->img[y * s->xd + x]); - *temp++ = bpal[cix&15].r; - *temp++ = bpal[cix&15].g; - *temp++ = bpal[cix&15].b; - *temp++ = (cix>>4)*17; - if( cix&0xf0 ) nonzero=1; - } - } - if( !nonzero ) { - free(out_buf); - return 1; - } - - fp = fopen(file_name, "wb"); - if (!fp) { - fprintf(stderr, "error, unable to open/create file: %s\n", - file_name); - return -1; - } - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!png_ptr) - return -1; - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - return -1; - } - - if (setjmp(png_ptr->jmpbuf)) { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - return -1; - } - - png_init_io(png_ptr, fp); - - /* turn on or off filtering, and/or choose specific filters */ - png_set_filter(png_ptr, 0, PNG_FILTER_NONE); - - /* set the zlib compression level */ - png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - - if (full_size) { - png_set_IHDR(png_ptr, info_ptr, 720, 576, - 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - } else { - png_set_IHDR(png_ptr, info_ptr, s->xd, s->yd, - 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - } - - png_write_info(png_ptr, info_ptr); - - png_set_packing(png_ptr); - - if (out_buf != NULL) { - png_byte *row_pointers[576]; - - if (full_size) { - char *image; - temp = out_buf; - image = malloc(720 * 576 * 4); - memset(image, 0, 720 * 576 * 4); // fill image full transparrent - // insert image on the correct position - for (y = s->y0; y < s->y0 + s->yd; y++) { - char *to = &image[y * 720 * 4 + s->x0 * 4]; - for (x = 0; x < s->xd; x++) { - *to++ = *temp++; - *to++ = *temp++; - *to++ = *temp++; - *to++ = *temp++; - } - } - - s->y0 = 0; - s->x0 = 0; - s->yd = 576; - s->xd = 720; - free(out_buf); - out_buf = image; - } - - - for (a = 0; a < s->yd; a++) { - row_pointers[a] = out_buf + a * (s->xd * 4); - } - - png_write_image(png_ptr, row_pointers); - - png_write_end(png_ptr, info_ptr); - free(out_buf); - } - - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - - return 0; -} - -static void write_pts(char *preamble,int pts) -{ - fprintf(fdo, - " %s=\"%02d:%02d:%02d.%02d\"",preamble, - (pts / (60 * 60 * 90000)) % 24, - (pts / (60 * 90000)) % 60, - (pts / 90000) % 60, - (pts / 900) % 100); -} - -/* - copy the content of buf to expbuf converting '&' '<' '>' '"' - expbuf must be big enough to contain the expanded buffer -*/ -static void xml_buf(unsigned char *expbuf,unsigned char *buf) -{ - unsigned char *p; - - do { - switch (*buf) { - case '&': - p="&"; - break; - case '<': - p="<"; - break; - case '>': - p=">"; - break; - case '"': - p="""; - break; - default: - p=NULL; - break; - } - if( p ) { - while ( (*expbuf++ = *p++) ) - ; - --expbuf; - } else - *expbuf++ = *buf; - } while ( *buf++ ) ; -} - -static void write_menu_image(struct spu *s,struct dispdetails *d,char *type,int offset) -{ - unsigned char nbuf[256]; - unsigned char ebuf[256*6]; - int nummap=d->numbuttons+1, i; - struct colormap *map=malloc(sizeof(struct colormap)*nummap); - memset(map,0,sizeof(struct colormap)); // set the first one blank - map[0].x2=0x7fffffff; - map[0].y2=0x7fffffff; - for( i=0; i<d->numbuttons; i++ ) { - uint32_t cc=d->coli[2*d->buttons[i].grp-2+offset]; - map[i+1].x1=d->buttons[i].x1; - map[i+1].y1=d->buttons[i].y1; - map[i+1].x2=d->buttons[i].x2; - map[i+1].y2=d->buttons[i].y2; - map[i+1].color=cc>>16; - map[i+1].contrast=cc; - } - - sprintf(nbuf, "%s%05d%c.png", base_name, s->subno, type[0]); - if( !write_png(nbuf,s,map,nummap) ) { - xml_buf(ebuf,nbuf); - fprintf(fdo," %s=\"%s\"",type,ebuf); - } - free(map); -} - -static void write_spu(struct spu *s,struct dispdetails *d) -{ - unsigned char nbuf[256]; - unsigned char ebuf[256*6]; - int i; - - if( d ) - absorb_palette(d); - fprintf(fdo,"\t\t<spu"); - - sprintf(nbuf, "%s%05d.png", base_name, s->subno); - if( !write_png(nbuf,s,s->map,s->nummap) ) { - xml_buf(ebuf,nbuf); - fprintf(fdo," image=\"%s\"",ebuf); - } - - if( d && d->numbuttons ) { - write_menu_image(s,d,"highlight",0); - write_menu_image(s,d,"select",1); - } - - write_pts("start",s->pts[0]); - if( s->pts[1] != -1 ) - write_pts("end",s->pts[1]); - if( s->x0 || s->y0 ) - fprintf(fdo," xoffset=\"%d\" yoffset=\"%d\"",s->x0,s->y0); - if (s->force_display) - fprintf(fdo, " force=\"yes\""); - if( d && d->numbuttons ) { - fprintf(fdo,">\n"); - for( i=0; i<d->numbuttons; i++ ) { - struct button *b=d->buttons+i; - if( b->autoaction ) - fprintf(fdo,"\t\t\t<action name=\"%s\" />\n",b->name); - else { - fprintf(fdo,"\t\t\t<button name=\"%s\" x0=\"%d\" y0=\"%d\" x1=\"%d\" y1=\"%d\" up=\"%s\" down=\"%s\" left=\"%s\" right=\"%s\" />\n", - b->name,b->x1,b->y1,b->x2,b->y2, - b->up,b->down,b->left,b->right); - } - } - fprintf(fdo,"\t\t</spu>\n"); - } else - fprintf(fdo, " />\n"); - -} - -static void flushspus(unsigned int lasttime) -{ - while(spus) { - struct spu *s=spus; - if( s->pts[0]>=lasttime ) - return; - spus=spus->next; - - while( dd && dd->pts[1]<s->pts[0] && dd->pts[1]!=-1 ) - pluck_dd(); - - if( dd && (dd->pts[0]<s->pts[1] || s->pts[1]==-1) && - (dd->pts[1]>s->pts[0] || dd->pts[1]==-1) ) - write_spu(s,dd); - else - write_spu(s,0); - if(s->img) free(s->img); - if(s->map) free(s->map); - free(s); - } -} - -#define bps(n,R,G,B) do { bpal[n].r=R; bpal[n].g=G; bpal[n].b=B; } while (0) - -static void usage(void) -{ - fprintf(stderr, - "\nUse: %s [options] [input file] [input file] ...\n\n", - "spuunmux"); - fprintf(stderr, "options:\n"); - fprintf(stderr, - "-o <name> base name for script and images [sub]\n"); - fprintf(stderr, - "-v <level> verbosity level [0]\n"); - fprintf(stderr, - "-f resize images to full size [720x576]\n"); - fprintf(stderr, - "-s <stream> number of the substream to extract [0]\n"); - fprintf(stderr, - "-p <file> name of file with dvd palette [none]\n"); - fprintf(stderr, " if palette file ends with .rgb\n"); - fprintf(stderr, " treated as a RGB\n"); - fprintf(stderr, " else as a YCbCr color\n"); - fprintf(stderr, "-h print this help\n"); - fprintf(stderr, "-V print version number\n"); - fprintf(stderr, "\n"); -} - - -int main(int argc, char **argv) -{ - struct vfile fd; - int option, n; - int rgb; - char *temp; - int firstvideo=-1; - unsigned int c, next_word, stream_number, inc, Inc; - unsigned short int package_length; - unsigned char cbuf[CBUFSIZE]; - unsigned char psbuf[PSBUFSIZE]; - unsigned char nbuf[256], *palet_file, *iname[256]; - - fputs(PACKAGE_HEADER("spuunmux"),stderr); - - base_name = "sub"; - stream_number = 0; - palet_file = 0; - Inc = inc = 0; - - while ((option = getopt(argc, argv, "o:v:fs:p:Vh")) != -1) { - switch (option) { - case 'o': - base_name = optarg; - break; - case 'v': - debug = atoi(optarg); - break; - case 'f': - full_size = TRUE; - break; - case 's': - stream_number = atoi(optarg); - break; - case 'p': - palet_file = optarg; - break; - case 'V': - exit(-1); - - case 'h': - default: - usage(); - return -1; - } - } - - if (optind < argc) { - int n, i; - for (i = 0, n = optind; n < argc; n++, i++) - iname[i] = argv[n]; - Inc = i; - } else { - usage(); - return -1; - } - - bps(0, 0, 0, 0); - bps(1, 127, 0, 0); - bps(2, 0, 127, 0); - bps(3, 127, 127, 0); - bps(4, 0, 0, 127); - bps(5, 127, 0, 127); - bps(6, 0, 127, 127); - bps(7, 127, 127, 127); - bps(8, 192, 192, 192); - bps(9, 128, 0, 0); - bps(10, 0, 128, 0); - bps(11, 128, 128, 0); - bps(12, 0, 0, 128); - bps(13, 128, 0, 128); - bps(14, 0, 128, 128); - bps(15, 128, 128, 128); - - if( palet_file ) { - rgb = FALSE; - temp = strrchr(palet_file, '.'); - if (temp != NULL) { - if (strcmp(temp, ".rgb") == 0) - rgb = TRUE; - } - - fdo = fopen(palet_file, "r"); - if (fdo != NULL) { - for (n = 0; n < 16; n++) { - int r, g, b; - fscanf(fdo, "%02x%02x%02x", &r, &g, &b); - if (!rgb) - ycrcb_to_rgb(&r, &g, &b); - bpal[n].r = r; - bpal[n].g = g; - bpal[n].b = b; - - if (debug > 3) - fprintf(stderr, "pal: %d #%02x%02x%02x\n", n, - bpal[n].r, bpal[n].g, bpal[n].b); - - } - fclose(fdo); - } else { - fprintf(stderr, "unable to open %s, using defaults\n", palet_file); - } - } - - if (strlen(base_name) > 246) { - fprintf(stderr, - "error: max length of base for filename creation is 246 characters\n"); - return -1; - } - - sprintf(nbuf, "%s.xml", base_name); - fdo = fopen(nbuf, "w+"); - fprintf(fdo, "<subpictures>\n\t<stream>\n"); - - pts = 0; - subno = 0; - subi = 0; - - add_offset = 450; // for rounding purposes - - while (inc < Inc) { - fd = varied_open(iname[inc], O_RDONLY); - if (fd.h == 0) { - fprintf(stderr, "error opening file %s\n", iname[inc]); - - exit(-1); - } - - if (debug > 0) - fprintf(stderr, "file: %s\n", iname[inc]); - - inc++; - - while (fread(&c, 1, 4, fd.h) == 4) { - c=ntohl(c); - if (c == 0x000001ba) { // start PS (Program stream) - static unsigned int old_system_time = -1; - unsigned int new_system_time; - l_01ba: - if (debug > 5) - fprintf(stderr, "pack_start_code\n"); - - if (fread(psbuf, 1, PSBUFSIZE, fd.h) < 1) - break; - - if ( (psbuf[0] & 0xc0) != 0x40 ) { - if (debug > 1) - fprintf(stderr, "not a MPEG-2 file, skipping.\n"); - continue; -// break; - } - - new_system_time = (psbuf[4] >> 3) + (psbuf[3] * 32) + - ((psbuf[2] & 3) * 32 * 256) + - ((psbuf[2] & 0xf8) * 32 * 128) + - (psbuf[1] * 1024 * 1024) + - ((psbuf[0] & 3) * 1024 * 1024 * 256) + - ((psbuf[0] & 0x38) * 1024 * 1024 * 128); - - if (new_system_time < old_system_time) { - if (old_system_time != -1) { - if (debug > 0) - printf - ("Time changed in stream header, use old time as offset for timecode in subtitle stream\n"); - add_offset += old_system_time; - } - } - old_system_time = new_system_time; - - flushspus(old_system_time); - - if (debug > 5) { - fprintf(stderr, "system time: %u\n", new_system_time); - } - - c=psbuf[9]&7; - if (c) { - char s[7]; - - if (debug > 5) - fprintf(stderr, "found %d stuffing bytes\n", c); - if (fread(s, 1, c, fd.h) < c) - break; - } - } else if( c==0x1b9 ) { - if (debug > 5) - fprintf(stderr, "end packet\n"); - } else { - fread(&package_length, 1, 2, fd.h); - package_length=ntohs(package_length); - if (package_length != 0) { - - switch (c) { - case 0x01bb: - if (debug > 5) - fprintf(stderr, "system header\n"); - break; - case 0x01bf: - if (debug > 5) - fprintf(stderr, "private stream 2\n"); - break; - case 0x01bd: - if (debug > 5) - fprintf(stderr, "private stream\n"); - fread(cbuf, 1, package_length, fd.h); - - next_word = getpts(cbuf); - if (next_word != -1) { - pts = next_word; - } - - next_word = cbuf[2] + 3; - - if (debug > 5) - for (c = 0; c < next_word; c++) - fprintf(stderr, "0x%02x ", cbuf[c]); - - if (debug > 5) - fprintf(stderr, "tid: %d\n", pts); - - if ( /*(debug > 1) && */ (cbuf[next_word] == 0x70)) - fprintf(stderr, "substr: %d\n", - cbuf[next_word + 1]); - - if (cbuf[next_word] == stream_number + 32) { - if ((debug < 6) && (debug > 1)) { - fprintf(stderr, - "id: 0x%x 0x%x %d tid: %d\n", - cbuf[next_word], package_length, - next_word, pts); - } - - if (!subi) { - subs = - ((unsigned int) cbuf[next_word + 1] << - 8) + cbuf[next_word + 2]; - - spts = pts; - } - - memcpy(sub + subi, cbuf + next_word + 1, - package_length - next_word - 1); - - if (debug > 1) { - fprintf(stderr, "found %d bytes of data\n", - package_length - next_word - 1); - } - - subi += package_length - next_word - 1; - - if (debug > 2) { - fprintf(stderr, - "subi: %d (0x%x) subs: %d (0x%x) b-a-1: %d (0x%x)\n", - subi, subi, subs, subs, - package_length - next_word - 1, - package_length - next_word - 1); - } - - if (subs == subi) { - subi = 0; - - next_word = dvddecode(); - - if (next_word) { - fprintf(stderr, - "found unreadable subtitle at %.2fs, skipping\n", - (double) spts / 90000); - continue; - } - } /* end if subs == subi */ - } - package_length=0; - break; - case 0x01e0: - if( firstvideo==-1 ) { - fread(cbuf, 1, package_length, fd.h); - firstvideo=getpts(cbuf); - add_offset-=firstvideo; - package_length=0; - } - if (debug > 5) - fprintf(stderr, "video stream 0\n"); - break; - case 0x01e1: - case 0x01e2: - case 0x01e3: - case 0x01e4: - case 0x01e5: - case 0x01e6: - case 0x01e7: - case 0x01e8: - case 0x01e9: - case 0x01ea: - case 0x01eb: - case 0x01ec: - case 0x01ed: - case 0x01ee: - case 0x01ef: - if (debug > 5) - fprintf(stderr, "video stream %d\n",c-0x1e0); - break; - case 0x01be: - if (debug > 5) - fprintf(stderr, "padding stream %d bytes\n", - package_length); - fread(cbuf, 1, package_length, fd.h); - if( package_length > 30 ) { - int i; - - package_length=0; - i=0; - if( strcmp(cbuf+i,"dvdauthor-data") ) - break; - i=15; - if( cbuf[i]!=1 ) - break; - switch(cbuf[i+1]) { - case 1: // subtitle/menu color and button information - { - // int st=cbuf[i+2]&31; // we ignore which subtitle stream for now - struct dispdetails *d; - i+=3; - d=malloc(sizeof(struct dispdetails)); - memset(d,0,sizeof(struct dispdetails)); - d->pts[0]=read4(cbuf+i); - d->pts[1]=read4(cbuf+i+4); - i+=8; - while(cbuf[i]!=0xff) { - switch(cbuf[i]) { - case 1: - { - int j; - - d->numpal=0; - for( j=0; j<cbuf[i+1]; j++ ) { - int c=read4(cbuf+i+1+3*j)&0xffFFff; - d->palette[j]=c; - d->numpal++; - } - i+=2+3*d->numpal; - break; - } - case 2: - { - int j; - - d->numcoli=cbuf[i+1]; - for( j=0; j<2*d->numcoli; j++ ) - d->coli[j]=read4(cbuf+i+2+j*4); - i+=2+8*d->numcoli; - break; - } - case 3: - { - int j; - d->numbuttons=cbuf[i+1]; - d->buttons=malloc(d->numbuttons*sizeof(struct button)); - i+=2; - for( j=0; j<d->numbuttons; j++ ) { - struct button *b=&d->buttons[j]; - b->name=readpstr(cbuf,&i); - i+=2; - b->autoaction=cbuf[i++]; - if(!b->autoaction) { - b->grp=cbuf[i]; - b->x1=read2(cbuf+i+1); - b->y1=read2(cbuf+i+3); - b->x2=read2(cbuf+i+5); - b->y2=read2(cbuf+i+7); - i+=9; - // up down left right - b->up=readpstr(cbuf,&i); - b->down=readpstr(cbuf,&i); - b->left=readpstr(cbuf,&i); - b->right=readpstr(cbuf,&i); - } - } - break; - } - - default: - fprintf(stderr,"ERR: unknown dvd info packet command: %d\n",cbuf[i]); - exit(1); - } - } - adddd(d); - break; - } - } - } - package_length=0; - break; - case 0x01c0: - case 0x01c1: - case 0x01c2: - case 0x01c3: - case 0x01c4: - case 0x01c5: - case 0x01c6: - case 0x01c7: - case 0x01c8: - case 0x01c9: - case 0x01ca: - case 0x01cb: - case 0x01cc: - case 0x01cd: - case 0x01ce: - case 0x01cf: - case 0x01d0: - case 0x01d1: - case 0x01d2: - case 0x01d3: - case 0x01d4: - case 0x01d5: - case 0x01d6: - case 0x01d7: - case 0x01d8: - case 0x01d9: - case 0x01da: - case 0x01db: - case 0x01dc: - case 0x01dd: - case 0x01de: - case 0x01df: - if (debug > 5) - fprintf(stderr, "audio stream %d\n",c-0x1c0); - break; - default: - if (debug > 0) - fprintf(stderr, "unknown header %x\n", c); - next_word = (c<<16) | package_length; - package_length = 2; - while (next_word != 0x1ba) { - next_word = next_word << 8; - if (fread(&next_word, 1, 1, fd.h) < 1) - break; - package_length++; - } - - if (debug > 0) - fprintf(stderr, - "skipped %d bytes of garbage\n", - package_length); - goto l_01ba; - } /* end switch */ - fread(cbuf, 1, package_length, fd.h); - } - - } /* end if 0xbd010000 */ - - } /* end while read 4 */ - - varied_close(fd); - } /* end while inc < Inc */ - - flushspus(0x7fffffff); - - fprintf(fdo, "\t</stream>\n</subpictures>\n"); - fclose(fdo); - - return 0; -} /* end function main */
View file
lxdvdrip-1.76.tar.bz2/Makefile -> lxdvdrip-1.77.tar.bz2/Makefile
Changed
@@ -1,22 +1,40 @@ INSTALLDIR = /usr/local -HINWEIS0 = 'Bitte Konfigdatei in /etc mit Changelog abgleichen' +HINWEIS0 = 'Bitte Konfigurationsdatei in /etc mit Changelog abgleichen' HINWEIS1 = 'Check the configuration file in /etc with the Changelog' HINWEIS2 = 'Comparez le fichier de config. en /etc avec le Changelog' all: - gcc -g -lm -ldvdread -lpthread -o lxdvdrip lxdvdrip.c streamanalyze.c ifo.c dvdinfo.c dvdbackup.c dvdcell.c systools.c vaporize.c dvdtools.c dvdcopy.c requant.c cputest.c tcmemcpy.c dvdformat.c badsect.c mpeg2dec.c + if test -f badsect.o; then rm *.o; fi + gcc -g -c badsect.c + gcc -g -c cputest.c + gcc -g -c dvdbackup.c + gcc -g -c dvdcell.c + gcc -g -c dvdcopy.c + gcc -g -c dvdformat.c + gcc -g -c dvdinfo.c + gcc -g -c dvdtools.c + gcc -g -c ifo.c + gcc -g -c lxdvdrip.c + gcc -g -c mpeg2dec.c + gcc -g -c requant.c + gcc -g -c streamanalyze.c + gcc -g -c systools.c + gcc -g -c tcmemcpy.c + gcc -g -c vaporize.c + gcc -pthread -g -o lxdvdrip *o -ldvdread -lm + if test -f badsect.o; then rm *.o; fi gcc -g -lm -o lxac3scan lxac3scan.c cd vamps && make && cd .. cd dvdbackup && make && cd .. cd requant && make && cd .. - cd buffer && make && cd .. + cd mbuffer && make && cd .. clean: rm -f lxdvdrip lxac3scan *.o cd vamps && make clean && cd .. cd dvdbackup && make clean && cd .. cd requant && make clean && cd .. - cd buffer && make clean && cd .. + cd mbuffer && make clean && cd .. install: cp lxdvdrip $(INSTALLDIR)/bin @@ -26,7 +44,7 @@ cd vamps && make install && cd .. cd dvdbackup && make install && cd .. cd requant && make install && cd .. - cd buffer && make install && cd .. + cd mbuffer && make install && cd .. if test -f /etc/lxdvdrip.conf; then echo $(HINWEIS0); fi; if test -f /etc/lxdvdrip.conf; then echo $(HINWEIS1); fi; if test -f /etc/lxdvdrip.conf; then echo $(HINWEIS2); else cp lxdvdrip.conf /etc; fi; @@ -40,4 +58,4 @@ rm $(INSTALLDIR)/bin/play_cell_lxdvdrip rm $(INSTALLDIR)/bin/dvdbackup_lxdvdrip rm $(INSTALLDIR)/bin/requant_lxdvdrip - rm $(INSTALLDIR)/bin/buffer_lxdvdrip + rm $(INSTALLDIR)/bin/mbuffer_lxdvdrip
View file
lxdvdrip-1.76.tar.bz2/doc-pak/Changelog.de -> lxdvdrip-1.77.tar.bz2/doc-pak/Changelog.de
Changed
@@ -1,6 +1,15 @@ Aenderungen LXDVDRIP ==================== +Version 1.77 / 30.10.11: +- Bugfix Modus "vamps_menu": Auch DVD-Struktur von der Festplatte ist kopierbar. +- wodim/genisoimage ersetzen cdrecord/mkisofs. +- Buxfix compilieren unter Ubuntu 11.10. +- Mbuffer ersetzt buffer (lxdvdrip -st=trans_par). +- Unterstützung dvdauthor 0.7: Datei ~./config/video_format mit PAL/NTSC erstellen. +- Unterstützung dvdauthor 0.7: Patches (gegen Fehler "SCR moves backwards"). +- Bugfix vlc als Streamtool: Umstellung auf dvdsimple-Zugriff. Sonst beendet sich vlc nicht. + Version 1.76 / 11.04.10: - Anpassungen an aktuelle DVD95 Version (1.5p3/1.6p0). - Anpassungen fuer libdvdread4.
View file
lxdvdrip-1.76.tar.bz2/doc-pak/Changelog.en -> lxdvdrip-1.77.tar.bz2/doc-pak/Changelog.en
Changed
@@ -1,6 +1,15 @@ Changes LXDVDRIP ================ +Version 1.77 / 30.10.11: +- Bugfix mode "vamps_menu": DVD-structure from hardisk can be copied. +- wodim/genisoimage replaces cdrecord/mkisofs. +- Fix building on Ubuntu 11.10. +- Mbuffer replaces buffer (lxdvdrip -st=trans_par). +- Support for dvdauthor 0.7: Create file ~./config/video_format with content PAL/NTSC. +- Support for dvdauthor 0.7: Patches (against error "SCR moves backwards"). +- Bugfix vlc as streamtool: Use dvdsimple instead of dvd. Else vlc does not quit. + Version 1.76 / 11.04.10: - Changes from recent DVD95 Version (1.5p3/1.6p0). - Fixes for libdvdread4.
View file
lxdvdrip-1.76.tar.bz2/doc-pak/Changelog.fr -> lxdvdrip-1.77.tar.bz2/doc-pak/Changelog.fr
Changed
@@ -1,6 +1,14 @@ Changes LXDVDRIP ================ +Version 1.77 / 30.10.11: +- Correction "vamps_menu": Lecture d'une structure DVD sur disque dur. +- cdrecord/mkisofs => wodim/genisoimage. +- Correction Ubuntu 11.10 +- Replacement buffer => mbuffer (lxdvdrip -st=trans_par). +- Support dvdauthor 0.7: ~./config/video_format. +- Correction vlc/dvdsimple. + Version 1.76 / 11.04.10: - Modifications de DVD95 Version (1.5p3/1.6p0). - libdvdread4.
View file
lxdvdrip-1.76.tar.bz2/doc-pak/Credits -> lxdvdrip-1.77.tar.bz2/doc-pak/Credits
Changed
@@ -11,4 +11,6 @@ Requant Module is M2VRequant (Metakine). +Mbuffer source is from: http://www.maier-komor.de + French Translation is from Jean Luc Damnet.
View file
lxdvdrip-1.76.tar.bz2/doc-pak/README.dvdwizard.DE -> lxdvdrip-1.77.tar.bz2/doc-pak/README.dvdwizard.DE
Changed
@@ -6,7 +6,7 @@ mit Menü zur Titelauswahl und Start, Auswahl der Audiotracks, Untertitel und einer Kapitelübersicht. -Erforderlich ist mindestens die Version 0.5.0. +Erforderlich ist mindestens die Version 0.7.0. 1) Download der Original Version des dvdwizard @@ -45,19 +45,19 @@ 3) Zusätzliche Software installieren dvdwizard benötigt einige Programme. Eine Auflistung siehe in der Datei -"README.DE" des dvdwizards. Außerdem wird hier noch einiges erklärt: +"TOOLS" des dvdwizards. Außerdem wird hier noch einiges erklärt: -http://udrecsuite.sourceforge.net/doku_dvdwizard.html +http://dvdwizard.wershofen.net/ (Documentation) Zusätzlich wird ein True Type Font für das Menü gebraucht: /usr/share/fonts/default/TrueType/arial.ttf -(abhängig von der Distribution auch /usr/share/fonts/TrueType/arial.ttf) +(abhängig von der Distribution auch /usr/share/fonts/TrueType/arial.ttf oder /usr/share/fonts/truetype/arial.ttf) Verzeichnis anlegen, wenn nicht da. Den Zeichensatz von der Windows Partition dorthin kopieren. Oder den Font downloaden: -http://www.mplayerhq.hu/homepage/design7/dload.html +http://www.mplayerhq.hu/MPlayer/releases/fonts/ Weitere Option: @@ -142,11 +142,6 @@ 6) Bekannte Probleme -- Anzahl der Titel (nur im (part-)copy Modus) - -Das Menü wird bei mehr als 6 Titeln unübersichtlich, es gehts etwas über den Bildschirmrand hinaus. -Außerdem sind maximal 9 Titel möglich. Derzeit keine Lösung. - - dvdwizard meldet Fehler Im Verzeichnis, wo lxdvdrip aufgerufen wird, legt dvdwizard eine Logdatei "dvdwizard.log" an.
View file
lxdvdrip-1.76.tar.bz2/doc-pak/README.dvdwizard.EN -> lxdvdrip-1.77.tar.bz2/doc-pak/README.dvdwizard.EN
Changed
@@ -4,7 +4,7 @@ Since Version 1.40 lxdvdrip uses "dvdwizard" to make a Backup with a Menu for Selection of Titles, Audio Tracks, Subtitles and Chapters. -As a minimum you need Version 0.5.0. +As a minimum you need Version 0.7.0. 1) Download of the Original Version of dvdwizard @@ -43,23 +43,23 @@ 3) Install additional Software dvdwizard needs some Tools. Please read the Documentation in the File -"README" or "README.DE" (german). +"TOOLS". Please read this Page, too: -http://udrecsuite.sourceforge.net/doku_dvdwizard.html +http://dvdwizard.wershofen.net/ (Documentation) You need the following True Type Font for the Creation of Menus: /usr/share/fonts/default/TrueType/arial.ttf -(on other distributions /usr/share/fonts/TrueType/arial.ttf) +(on other distributions /usr/share/fonts/TrueType/arial.ttf or /usr/share/fonts/truetype/arial.ttf) Create the Directory, if it doesnt exist. The Font File you can copy from your Windows Partition. Else you can download the Font from: -http://www.mplayerhq.hu/homepage/design7/dload.html +http://www.mplayerhq.hu/MPlayer/releases/fonts/ Or: @@ -144,11 +144,6 @@ 6) Known Problems -- Title count (only in (part-)copy Mode) - -If there are more than 6 Titles, the Menu is bigger then the Screen. -There are 9 Titles possible. At this Time there is no Solution. - - dvdwizard fails In the Directory where you are calling lxdvdrip there will be a Logfile "dvdwizard.log".
View file
lxdvdrip-1.76.tar.bz2/doc-pak/README.dvdwizard.FR -> lxdvdrip-1.77.tar.bz2/doc-pak/README.dvdwizard.FR
Changed
@@ -4,7 +4,7 @@ A partir de la version 1.40 lxdvdrip utilise "dvdwizard" pour réaliser une sauvegarde avec des menus de élection des films, des pistes audio, sous-titres et des chapitres. -Vous aurez besoin d'une version 0.5.0 ou plus récente de dvdwizard. +Vous aurez besoin d'une version 0.7.0 ou plus récente de dvdwizard. 1) Téléchargez la version courante de dvdwizard depuis : @@ -37,13 +37,12 @@ 3) Installer les logiciels nécessaires -dvdwizard nécessite l'installation de quelques outils. Reportez-vous au fichier de documentation "README.FR" +dvdwizard nécessite l'installation de quelques outils. Reportez-vous au fichier de documentation "TOOLS" pour en avoir la liste détaillée. -(dans les versions plus anciennes n'existent que "README" en anglais ou "README.DE" en allemand) Une autre source d'informations importantes à lire se trouve à l'adresse: -http://udrecsuite.sourceforge.net/doku_dvdwizard.html +http://dvdwizard.wershofen.net/ (Documentation) Il vous faut aussi la police True Type arial pour la création des menus: @@ -53,10 +52,14 @@ /usr/share/fonts/TrueType/arial.ttf +ou + +/usr/share/fonts/truetype/arial.ttf + Créez le répertoire s'il n'existe pas. Vous pouvez utiliser les polices provenant d'une partition Windows, vous pouvez aussi aller voir sur: -http://www.mplayerhq.hu/homepage/design7/dload.html +http://www.mplayerhq.hu/MPlayer/releases/fonts/ Ou: @@ -137,11 +140,6 @@ 6) Problèmes connus -- Nombre de titres (seulement dans le mode Copie (partielle)) - -S'il y a plus de 6 titres, le menu devient plus grand que l'écran. -La limite est à 9 titres, pas de solution pour le moment. - - dvdwizard plante Dans le répertoire où vous appelez lxdvdrip vous trouverez le fichier de log "dvdwizard.log".
View file
lxdvdrip-1.76.tar.bz2/doc-pak/lxdvdrip.conf.DE -> lxdvdrip-1.77.tar.bz2/doc-pak/lxdvdrip.conf.DE
Changed
@@ -6,7 +6,7 @@ # Leerzeichen angegeben werden. # Version der Config-Datei -version=1.76 +version=1.77 # Auswahl des zu rippenden Titels, bestimmen mit "lsdvd". # Alternative: bei titel=0 bestimmt lxdvdrip den laengsten Titel der DVD @@ -58,7 +58,7 @@ # Device fuer DVD-Brenner. # Beim Brennen mit "growisofs" ist zumeist "/dev/sr0" die richtige Wahl. -# Bei "cdrecord" zumeist "0,0,0", testen mit "cdrecord -scanbus". +# Bei "wodim" zumeist "0,0,0", testen mit "wodim -scanbus". # Entspricht "-db=". dvdbrenner=/dev/sr0 @@ -75,9 +75,9 @@ # Entspricht "-file=". file=0 -# Brennprogramm. Bei "1" wird growisofs verwendet, bei "2" cdrecord. -# Bei "3" wird cdrecord mit mkisofs on the fly gestartet. -# "4"=ISO-Image "/tmp/dvdrip.img" durch mkisofs. +# Brennprogramm. Bei "1" wird growisofs verwendet, bei "2" wodim. +# Bei "3" wird wodim mit genisoimage on the fly gestartet. +# "4"=ISO-Image "/tmp/dvdrip.img" durch genisoimage. # "5"=ISO-Image mit "Volume-ID.img" (=Name der DVD) als Namen. # 0=kein Brennen. # Entspricht "-bp=". @@ -153,7 +153,7 @@ # Entspricht "-free=" free=1 -# Brenngeschwindigkeit fuer growisofs als auch cdrecord. +# Brenngeschwindigkeit fuer growisofs als auch wodim. # Bei speed=0 wird der Parameter beim Brennen nicht uebergeben. speed=4 @@ -162,16 +162,16 @@ # Beschreibung siehe "man growisofs". dvdcompat=1 -# Extra-Parameter fuer mkisofs. +# Extra-Parameter fuer genisoimage. # Parameter muss in Hochkommas stehen, z. B. -# mkisofs_param="-input-charset iso8859-1" -# Parameter werden beim Aufruf an mkisofs bzw. growisofs uebergeben. -mkisofs_param="" +# genisoimage_param="-input-charset iso8859-1" +# Parameter werden beim Aufruf an genisoimage bzw. growisofs uebergeben. +genisoimage_param="" -# Extra-Parameter fuer cdrecord/growisofs. +# Extra-Parameter fuer wodim/growisofs. # Parameter muss in Hochkommas stehen, z. B. # burn_param="-tao" -# Parameter werden beim Aufruf an cdrecord bzw. growisofs uebergeben. +# Parameter werden beim Aufruf an wodim bzw. growisofs uebergeben. burn_param="" # DVD nach Rippen auswerfen. @@ -187,9 +187,9 @@ # z. B. "dvdauthor=/usr/local/bin/dvdauthor", damit koennen z. B. # mehrere Versionen parallel auf dem Rechner liegen. dvdauthor_name=dvdauthor -buffer_name=buffer_lxdvdrip +#buffer_name=buffer #buffer_name=bfr -#buffer_name=mbuffer +buffer_name=mbuffer_lxdvdrip tccat_name=tccat tcextract_name=tcextract requant_name=requant_lxdvdrip @@ -201,8 +201,8 @@ spuunmux_name=spuunmux dvdbackup_name=dvdbackup_lxdvdrip # Alternative: dvdbackup_name=vobcopy -mkisofs_name=mkisofs -cdrecord_name=cdrecord +genisoimage_name=genisoimage +wodim_name=wodim growisofs_name=growisofs dvd+rw-format=dvd+rw-format dvdunauthor_name=dvdunauthor @@ -218,7 +218,7 @@ # Nice-Level fuer Programmgruppen # nice_rip fuer das Rippen (tccat, mplayer, spuunmux, vamps_play_cell) -# nice_burn fuer das Brennen (growisofs, cdrecord) +# nice_burn fuer das Brennen (growisofs, wodim) # Moegliche Werte von "-20" (hoch) bis "19" (niedrig), bei "off" ohne nice-Angaben nice_rip=off nice_burn=off
View file
lxdvdrip-1.76.tar.bz2/doc-pak/lxdvdrip.conf.EN -> lxdvdrip-1.77.tar.bz2/doc-pak/lxdvdrip.conf.EN
Changed
@@ -3,7 +3,7 @@ # All Parameters must be like "paramter=value" without blanks. # version of Config File -version=1.76 +version=1.77 # Selection of the ripping Title, look with "lsdvd". # With "titel=0" lxdvdrip selects automatically the longest Title. @@ -54,7 +54,7 @@ # Device for DVD-Burner. # growisofs: normally "/dev/sr0". -# cdrecord: normally "0,0,0", test with "cdrecord -scanbus". +# wodim: normally "0,0,0", test with "wodim -scanbus". # On the Commandline: "-db=". dvdbrenner=/dev/sr0 @@ -71,9 +71,9 @@ file=0 # Burning Program. -# "1": growisofs, "2": cdrecord, "3": cdrecord on the fly, -# "4": create ISO-Image "/tmp/dvdrip.img" with mkisofs. -# "5": create ISO-Image with Name "Volume-ID.img" (=Name of DVD) with mkisofs. +# "1": growisofs, "2": wodim, "3": wodim on the fly, +# "4": create ISO-Image "/tmp/dvdrip.img" with genisoimage. +# "5": create ISO-Image with Name "Volume-ID.img" (=Name of DVD) with genisoimage. # "0": no Burning. # On the Commandline: "-bp=". brennprogramm=1 @@ -148,7 +148,7 @@ # On the Commandline: "-free=" free=1 -# Burning Speed for growisofs and cdrecord. +# Burning Speed for growisofs and wodim. # speed=0: Start without "-speed=" speed=4 @@ -157,16 +157,16 @@ # For a Description see "man growisofs". dvdcompat=1 -# Extra-Parameter(s) for mkisofs. +# Extra-Parameter(s) for genisoimage. # Parameter must be marked with apostrophes "xxx", i. E.: -# mkisofs_param="-input-charset iso8859-1" -# Parameter would be set by calling mkisofs or growisofs. -mkisofs_param="" +# genisoimage_param="-input-charset iso8859-1" +# Parameter would be set by calling genisoimage or growisofs. +genisoimage_param="" -# Extra-Parameter(s) for cdrecord/growisofs. +# Extra-Parameter(s) for wodim/growisofs. # Parameter must be marked with apostrophes "xxx", i. E.: # burn_param="-tao" -# Parameter would be set by calling cdrecord or growisofs. +# Parameter would be set by calling wodim or growisofs. burn_param="" # Eject DVD after Ripping @@ -181,9 +181,9 @@ # Optional the full Path could be set, i. E. # "play_cell_name=/usr/local/bin/play_cell". dvdauthor_name=dvdauthor -buffer_name=buffer_lxdvdrip +#buffer_name=buffer #buffer_name=bfr -#buffer_name=mbuffer +buffer_name=mbuffer_lxdvdrip tccat_name=tccat tcextract_name=tcextract requant_name=requant_lxdvdrip @@ -195,8 +195,8 @@ spuunmux_name=spuunmux dvdbackup_name=dvdbackup_lxdvdrip # Alternative: dvdbackup_name=vobcopy -mkisofs_name=mkisofs -cdrecord_name=cdrecord +genisoimage_name=genisoimage +wodim_name=wodim growisofs_name=growisofs dvd+rw-format=dvd+rw-format dvdunauthor_name=dvdunauthor @@ -212,7 +212,7 @@ # Nice-Level for Programgroups # nice_rip for ripping (tccat, mplayer, spuunmux, vamps_play_cell) -# nice_burn for burning (growisofs, cdrecord) +# nice_burn for burning (growisofs, wodim) # Possible values from "-20" (high) to "19" (low), "off" without nice nice_rip=off nice_burn=off
View file
lxdvdrip-1.76.tar.bz2/doc-pak/lxdvdrip.conf.FR -> lxdvdrip-1.77.tar.bz2/doc-pak/lxdvdrip.conf.FR
Changed
@@ -4,7 +4,7 @@ # Toutes les entrées sont de la forme "option=valeur" sans espaces. # version du fichier de configuration -version=1.76 +version=1.77 # Choix du titre à ripper (vérifiez avec "lsdvd"). # Entrer "titel=0" pour choisir automatiquement le titre le plus long. @@ -54,7 +54,7 @@ # Graveur de DVD. # Pour growisofs, normalement de la forme "/dev/sr0". -# Pour cdrecord, normalement de la forme "0,0,0" (voir "cdrecord -scanbus"). +# Pour wodim, normalement de la forme "0,0,0" (voir "wodim -scanbus"). # Pour la ligne de commande: "-db=". dvdbrenner=/dev/sr0 @@ -72,10 +72,10 @@ # Programme à utiliser pour la gravure. # "1": growisofs -# "2": cdrecord -# "3": cdrecord à la volée -# "4": mkisofs (ISO-Image) "/tmp/dvdrip.img" -# "5": mkisofs (ISO-Image) "Volume-ID.img" +# "2": wodim +# "3": wodim à la volée +# "4": genisoimage (ISO-Image) "/tmp/dvdrip.img" +# "5": genisoimage (ISO-Image) "Volume-ID.img" # "0": gravure=non # Pour la ligne de commande: "-bp=". brennprogramm=1 @@ -165,7 +165,7 @@ # 0=pas Signal, 1=Signal. playsound=1 -# Vitesse de gravure (pour "growisofs" et "cdrecord"). +# Vitesse de gravure (pour "growisofs" et "wodim"). # Note: entrer la valeur "0" pour supprimer la commande "-speed=" speed=4 @@ -174,16 +174,16 @@ # Reportez-vous à "man growisofs" pour plus de détails. dvdcompat=1 -# Paramètre(s) additionnel(s) pour mkisofs. +# Paramètre(s) additionnel(s) pour genisoimage. # A encadrer par des guillemets, comme ceci: -# mkisofs_param="input-charset iso8859-1" -# Sera passé dans l'appel de mkisofs ou growisofs. -mkisofs_param="" +# genisoimage_param="input-charset iso8859-1" +# Sera passé dans l'appel de genisoimage ou growisofs. +genisoimage_param="" -# Option à passer à cdrecord/growisofs. +# Option à passer à wodim/growisofs. # Cette option doit être entre guillemets "xxx", p.ex.: # burn_param="-tao" -# Cette option sera utilisée lors de l'appel à cdrecord ou growisofs. +# Cette option sera utilisée lors de l'appel à wodim ou growisofs. burn_param="" # Ejection du DVD après extraction. @@ -203,9 +203,9 @@ # pour préciser le chemin: "mplayer_name=/usr/local/bin/mplayer" # et pourquoi pas: "mplayer_name=mon_propre_streamer". dvdauthor_name=dvdauthor -buffer_name=buffer_lxdvdrip +#buffer_name=buffer #buffer_name=bfr -#buffer_name=mbuffer +buffer_name=mbuffer_lxdvdrip tccat_name=tccat tcextract_name=tcextract requant_name=requant_lxdvdrip @@ -217,8 +217,8 @@ spuunmux_name=spuunmux dvdbackup_name=dvdbackup_lxdvdrip # Alternative: dvdbackup_name=vobcopy -mkisofs_name=mkisofs -cdrecord_name=cdrecord +genisoimage_name=genisoimage +wodim_name=wodim growisofs_name=growisofs dvd+rw-format=dvd+rw-format dvdunauthor_name=dvdunauthor @@ -234,7 +234,7 @@ # niveau Nice par groupes de programmes # nice_rip pour l'extraction (tccat, mplayer, spuunmux, vamps_play_cell) -# nice_burn pour la gravure (growisofs, cdrecord) +# nice_burn pour la gravure (growisofs, wodim) # Valeurs possibles de "-20" (haut) à "19" (bas), "off" sans nice nice_rip=off nice_burn=off
View file
lxdvdrip-1.77.tar.bz2/dvdauthor/0.7.0
Added
+(directory)
View file
lxdvdrip-1.77.tar.bz2/dvdauthor/0.7.0/dvdvob.c
Added
@@ -0,0 +1,2571 @@ +/* + dvdauthor -- generation of .VOB files +*/ +/* + * Copyright (C) 2002 Scott Smith (trckjunky@users.sourceforge.net) + * + * 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 + */ + +#include "config.h" + +#include "compat.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <ctype.h> + +#include "dvdauthor.h" +#include "da-internal.h" + + + +struct colorremap /* for remapping colours to indexes into a common palette */ + { + int newcolors[16]; /* bottom 24 bits are YCbCr, bit 24 is set to indicate a colour needs remapping */ + int state,curoffs,maxlen,nextoffs,skip,ln_ctli; /* state of SPU parser machine (procremap) */ + struct colorinfo *origmap; /* colours merged into common indexes into this palette */ + }; + +struct vscani { + int lastrefsect; /* flag that last sector should be recorded as a reference sector */ + int firstgop; /* 1 => looking for first GOP, 2 => found first GOP, 0 => don't bother looking any more */ + int firsttemporal; /* first temporal sequence number seen in current sequence */ + int lastadjust; /* temporal sequence reset */ +}; + +static pts_t const timeline[19]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 20,60,120,240}; + /* various time steps for VOBU offsets needed in DSI packet, in units of half a second */ + +#define BIGWRITEBUFLEN (16*2048) +static unsigned char bigwritebuf[BIGWRITEBUFLEN]; +static int writebufpos=0; +static int writefile=-1; /* fd of output file */ + +static void flushclose(int fd) + /* ensures all data has been successfully written to disk before closing fd. */ + { + if + ( +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 + fdatasync(fd) +#else + fsync(fd) +#endif + ) + { + if (errno != EINVAL) + { + fprintf(stderr, "ERR: Error %d -- %s -- flushing output VOB\n", errno, strerror(errno)); + exit(1); + } + else + { + /* non-flushable output */ + errno = 0; + } /*if*/ + } /*if*/ + close(fd); + } /*flushclose*/ + +static unsigned char videoslidebuf[15]={255,255,255,255, 255,255,255, 0,0,0,0, 0,0,0,0}; + + +/* The following are variants for the ways I've seen DVD's encoded */ + +// Grosse Pointe Blank uses exactly 1/2 second for the FF/REW records +// Bullitt uses 1/2 video second (i.e. in NTSC, 45045 PTS) +#define DVD_FFREW_HALFSEC 45000 +// #define DVD_FFREW_HALFSEC (getratedenom(va)>>1) + +static pts_t calcpts + ( + const struct vobgroup *va, + int cancomplain, + int *didcomplain, + pts_t *align, + pts_t basepts, + int nfields /* count of prior fields */ + ) + /* returns basepts aligned to a whole number of fields, offset by *align. */ + { + // I assume pts should round down? That seems to be how mplex deals with it + // also see later comment + const pts_t fpts = getframepts(va); + const int bpframe = (basepts * 2 - *align + fpts / 2) / fpts; /* nearest whole field number */ + if ((*align + bpframe * fpts) / 2 != basepts) + { + if (!*didcomplain) + { + if (cancomplain) + fprintf(stderr, "WARN: Video PTS does not line up on a multiple of a field.\n"); + *didcomplain = 1; + } /*if*/ + *align = basepts * 2; /* assume this will avoid further warnings */ + } + else + nfields += bpframe; + return (*align + nfields * fpts) / 2; + } /*calcpts*/ + +static int findnextvideo(const struct vob *va, int cur, int dir) + // find next (dir=1) or previous(dir=-1) vobu with video + { + int i, numvobus; + numvobus = va->numvobus; + switch(dir) + { + case 1: // forward + for (i = cur+1; i < numvobus; i++) + if(va->vobu[i].hasvideo) + return i; + return -1; + case -1: // backward + for (i = cur-1; i > -1; i--) + if(va->vobu[i].hasvideo) + return i; + return -1; + default: + // ?? + return -1; + } /*switch*/ + } /*findnextvideo*/ + +static int findaudsect(const struct vob *va, int aind, pts_t pts0, pts_t pts1) + /* finds the audpts entry, starting from aind, that includes the time pts0 .. pts1, + or -1 if not found. */ + { + const struct audchannel * const ach = &va->audch[aind]; + int l = 0, h = ach->numaudpts - 1; + + if (h < l) + return -1; + while (h > l) + { + const int m =(l + h + 1) / 2; /* binary search */ + if (pts0 < ach->audpts[m].pts[0]) + h = m - 1; + else + l = m; + } /*while*/ + if (ach->audpts[l].pts[0] > pts1) + return -1; + return ach->audpts[l].asect; + } /*findaudsect*/ + +static int findvobubysect(const struct vob *va, int sect) + /* returns the index of the VOBU that spans the specified sector. */ + { + int l = 0, h = va->numvobus - 1; + if (h < 0) + return -1; + if (sect < va->vobu[0].sector) + return -1; + while (l < h) + { + const int m = (l + h + 1) / 2; /* binary search */ + if (sect < va->vobu[m].sector) + h = m - 1; + else + l = m; + } /*while*/ + return l; + } /*findvobubysect*/ + +static int findspuidx(const struct vob *va, int ach, pts_t pts0) + /* returns the index of the subpicture packet spanning the specified time. */ + { + int l = 0, h = va->audch[ach].numaudpts - 1; + if (h < l) + return -1; + while (h > l) + { + const int m = (l + h + 1) / 2; /* binary search */ + if (pts0 < va->audch[ach].audpts[m].pts[0]) + h = m - 1; + else + l = m; + } /*while*/ + return l; + } /*findspuidx*/ + +static unsigned int getsect + ( + const struct vob * va, + int curvobunum, /* the VOBU number I'm jumping from */ + int jumpvobunum, /* the VOBU number I'm jumping to */ + int skip, /* whether to set the skipping-more-than-one-VOBU bit */ + unsigned notfound /* what to return if there is no matching VOBU */ + ) + /* computes relative VOBU offsets needed at various points in a DSI packet, + including the mask bit that indicates a backward jump, and optionally the + one indicating skipping multiple video VOBUs as well. */ + { + if (skip) + { + int l, h, i; + // only set skip bit if one of the VOBU's from here to there contain video + /* hmm, this page <http://www.mpucoder.com/DVD/dsi_pkt.html> doesn't say + it has to contain video */ + if (curvobunum < jumpvobunum) + { + l = curvobunum + 1; + h = jumpvobunum - 1; + } + else + { + l = jumpvobunum + 1; + h = curvobunum - 1; + } /*if*/ + for (i = l; i <= h; i++) + if (va->vobu[i].hasvideo) + break; /* found an in-between VOBU containing video */ + if (i <= h) + skip = 0x40000000; + else + skip = 0; + } /*if*/ + if + ( + jumpvobunum < 0 + || + jumpvobunum >= va->numvobus + || + va->vobu[jumpvobunum].vobcellid != va->vobu[curvobunum].vobcellid + /* never cross cells */ + ) + return + notfound | skip; + return + abs(va->vobu[jumpvobunum].sector - va->vobu[curvobunum].sector) + | + (va->vobu[jumpvobunum].hasvideo ? 0x80000000 : 0) + | + skip; + } /*getsect*/ + +static pts_t readscr(const unsigned char *buf) + /* returns the timestamp as found in the pack header. This is actually supposed to + be units of a 27MHz clock, but I ignore the extra precision and truncate it to + the usual 90kHz clock units. */ + { + return + ((pts_t)(buf[0] & 0x38)) << 27 /* SCR 32 .. 30 */ + | + (buf[0] & 3) << 28 /* SCR 29 .. 28 */ + | + buf[1] << 20 /* SCR 27 .. 20 */ + | + (buf[2] & 0xf8) << 12 /* SCR 19 .. 15 */ + | + (buf[2] & 3) << 13 /* SCR 14 .. 13 */ + | + buf[3] << 5 /* SCR 12 .. 5 */ + | + (buf[4] & 0xf8) >> 3; /* SCR 4 .. 0 */ + /* ignore SCR_ext */ + } /*readscr*/ + +static void writescr(unsigned char *buf, pts_t scr) + /* writes a new timestamp for a pack header, ignoring the additional 27MHz + precision. */ + { + buf[0] = ((scr >> 27) & 0x38) | ((scr >> 28) & 3) | 68; + buf[1] = scr >> 20; + buf[2] = ((scr >> 12) & 0xf8) | ((scr >> 13) & 3) | 4; + buf[3] = scr >> 5; + buf[4] = ((scr << 3) & 0xf8) | (buf[4] & 7); + } /*writescr*/ + +static pts_t readpts(const unsigned char *buf) + /* reads a timestamp from a PES header as expressed in 90kHz clock units. */ + { + int a1, a2, a3; + a1 = (buf[0] & 0xe) >> 1; + a2 = ((buf[1] << 8) | buf[2]) >> 1; + a3 = ((buf[3] << 8) | buf[4]) >> 1; + return + ((pts_t)a1) << 30 + | + a2 << 15 + | + a3; + } /*readpts*/ + +static void writepts(unsigned char *buf, pts_t pts) + /* writes a timestamp to a PES header as expressed in 90kHz clock units. */ + { + buf[0] = ((pts >> 29) & 0xe) | (buf[0] & 0xf1); + // this preserves the PTS / DTS / PTSwDTS top bits + write2(buf + 1, (pts >> 14) | 1); + write2(buf + 3, (pts << 1) | 1); + } /*writepts*/ + +static int findbutton(const struct pgc *pg, const char *dest, int dflt) + /* returns the index of the button with name dest, or dflt if not found or no name specified. */ + { + int i; + if (!dest) + return dflt; + for (i = 0; i < pg->numbuttons; i++) + if (!strcmp(pg->buttons[i].name,dest)) + return i + 1; + return dflt; + } /*findbutton*/ + +static void transpose_ts(unsigned char *buf, pts_t tsoffs) + /* adjusts the timestamps in the specified PACK header and its constituent packets + by the specified amount. */ + { + // pack scr + if + ( + buf[0] == 0 + && + buf[1] == 0 + && + buf[2] == 1 + && + buf[3] == MPID_PACK + ) + { + const int sysoffs = + buf[14] == 0 && buf[15] == 0 && buf[16] == 1 && buf[17] == MPID_SYSTEM ? + /* skip system header if present */ + (buf[18] << 8 | buf[19]) + 6 + : + 0; + writescr(buf + 4, readscr(buf + 4) + tsoffs); + // video/audio? + // pts? + if + ( + buf[14 + sysoffs] == 0 + && + buf[15 + sysoffs] == 0 + && + buf[16 + sysoffs] == 1 + && + ( + buf[17 + sysoffs] == MPID_PRIVATE1 + /* audio or subpicture stream */ + || + buf[17 + sysoffs] >= MPID_AUDIO_FIRST && buf[17 + sysoffs] <= MPID_VIDEO_LAST + /* audio or video stream */ + ) + && + (buf[21 + sysoffs] & 128) /* PTS present */ + ) + { + writepts(buf + 23 + sysoffs, readpts(buf + 23 + sysoffs) + tsoffs); + // dts? + if (buf[21 + sysoffs] & 64) /* decoder timestamp present */ + { + writepts(buf + 28 + sysoffs, readpts(buf + 28 + sysoffs) + tsoffs); + } /*if*/ + } /*if*/ + } + } /*transpose_ts*/ + +static bool has_gop(const unsigned char *buf) + /* returns true iff there is a video GOP present in the sector in buf. */ + { + if + ( + buf[14] == 0 + && + buf[15] == 0 + && + buf[16] == 1 + && + buf[17] == MPID_SYSTEM + && + buf[38] == 0 + && + buf[39] == 0 + && + buf[40] == 1 + && + buf[41] == MPID_VIDEO_FIRST + ) + { + int i = 42; + while (i < 1024) + { + if + ( + buf[i] == 0 + && + buf[i + 1] == 0 + && + buf[i + 2] == 1 + && + buf[i + 3] == MPID_GOP + ) + return true; + i += 4; + } /*while*/ + } /*if*/ + return false; + } /*has_gop*/ + +static bool mpa_valid(const unsigned char *b) + /* does b look like it points at a valid MPEG audio packet header. */ + { + const unsigned int v = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; + int t; + // sync, mpeg1, layer2, 48khz + if ((v & 0xFFFE0C00) != 0xFFFC0400) + return false; + // bitrate 1..14 + t = (v >> 12) & 15; + if (t == 0 || t == 15) + return false; + // emphasis reserved + if ((v & 3) == 2) + return false; + return true; + } /*mpa_valid*/ + +static int mpa_len(const unsigned char *b) + /* returns the length of an MPEG audio packet. */ + { + static int const bitratetable[16]={0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}; + const int padding =(b[2] >> 1) & 1; + const int bitrate = bitratetable[(b[2] >> 4) & 15]; + return 3 * bitrate + padding; // 144 * bitrate / sampling; 144 / 48 = 3 + } /*mpa_len*/ + +static void writeflush() + /* writes out the data buffered so far. */ + { + if (!writebufpos) /* nothing in buffer */ + return; + if (writefile != -1) + { + if (write(writefile, bigwritebuf, writebufpos) != writebufpos) + { + fprintf(stderr, "ERR: Error %d -- %s -- writing data\n", errno, strerror(errno)); + exit(1); + } /*if*/ + } /*if*/ + writebufpos = 0; + } /*writeflush*/ + +static unsigned char *writegrabbuf() + /* returns the start address at which to write the next sector, + automatically flushing previously-written sectors as necessary. */ + { + unsigned char *buf; + if (writebufpos == BIGWRITEBUFLEN) + writeflush(); + buf=bigwritebuf+writebufpos; + writebufpos += 2048; /* sector will be written to output file */ + return buf; + } /*writegrabbuf*/ + +static void writeundo() + /* drops the last sector from the output buffer. */ + { + writebufpos -= 2048; + } /*writeundo*/ + +static void writeclose() + /* flushes and closes the output file. */ + { + writeflush(); + if (writefile != -1) + { + flushclose(writefile); + writefile = -1; + } /*if*/ + } /*writeclose*/ + +static void writeopen(const char *newname) + /* opens an output file for writing. */ + { + writefile = open(newname, O_CREAT | O_WRONLY | O_BINARY, 0666); + if (writefile < 0) + { + fprintf(stderr, "ERR: Error %d opening %s: %s\n", errno, newname, strerror(errno)); + exit(1); + } /*if*/ + } + +static void closelastref(struct vobuinfo *thisvi, struct vscani *vsi, int cursect) + /* collects another end-sector of another reference frame, if I don't have enough already. */ + { + if (vsi->lastrefsect && thisvi->numref < 3) + { + thisvi->lastrefsect[thisvi->numref++] = cursect; + vsi->lastrefsect = 0; + } /*if*/ + } /*closelastref*/ + +// this function is allowed to update buf[7] and guarantee it will end up +// in the output stream +// prevbytesect is the sector for the byte immediately preceding buf[0] +static void scanvideoptr + ( + struct vobgroup *va, + unsigned char *buf, + struct vobuinfo *thisvi, + int prevbytesect, + struct vscani *vsi + ) + { + if + ( + buf[0] == 0 + && + buf[1] == 0 + && + buf[2] == 1 /* looks like a packet header */ + ) + { + switch(buf[3]) + { + case MPID_PICTURE: /* picture header */ + { + const int ptype = (buf[5] >> 3) & 7; /* frame type, 1 => I, 2 => P, 3 => B, 4 => D */ + const int temporal = (buf[4] << 2) | (buf[5] >> 6); /* temporal sequence number */ + closelastref(thisvi, vsi, prevbytesect); + if (vsi->firsttemporal == -1) + vsi->firsttemporal = temporal; + vsi->lastadjust = (temporal < vsi->firsttemporal); + if (ptype == 1 || ptype == 2) // I or P frame + vsi->lastrefsect = 1; /* it's a reference frame */ + if (va->vd.vmpeg == VM_MPEG1) + { + thisvi->numfields += 2; + if (vsi->lastadjust && vsi->firstgop == 2) + thisvi->firstIfield += 2; + } /*if*/ + + // fprintf(stderr,"INFO: frame type %d, tempref=%d, prevsect=%d\n",ptype,temporal,prevbytesect); + break; + } /*case 0*/ + + case MPID_SEQUENCE: /* sequence header */ + { + /* collect information about video attributes */ + int hsize, vsize, aspect, framerate, newaspect; + char sizestring[30]; + closelastref(thisvi, vsi, prevbytesect); + hsize = (buf[4] << 4) | (buf[5] >> 4); + vsize = ((buf[5] << 8) & 0xf00) | buf[6]; + aspect = buf[7] >> 4; + framerate = buf[7] & 0xf; + + vobgroup_set_video_framerate(va, framerate); + switch (framerate) + { + case VR_NTSCFILM: // 24000/1001 + case VR_NTSC: // 30000/1001 + case VR_NTSCFIELD: // 60000/1001 + vobgroup_set_video_attr(va, VIDEO_FORMAT, "ntsc"); + break; + + case VR_PAL: // 25 + case VR_PALFIELD: // 50 + vobgroup_set_video_attr(va, VIDEO_FORMAT, "pal"); + break; + + case VR_FILM: // 24 + case VR_30: // 30 + case VR_60: // 60 + // these are nonstandard, but at least we know what they are + break; + + default: + fprintf(stderr, "WARN: unknown frame rate %d\n", framerate); + break; + } /* switch(framerate) */ + sprintf(sizestring, "%dx%d", hsize, vsize); + vobgroup_set_video_attr(va, VIDEO_RESOLUTION, sizestring); + if (va->vd.vmpeg == VM_MPEG1) + { + switch (aspect) + { + case 3: + vobgroup_set_video_attr(va, VIDEO_ASPECT, "16:9"); + vobgroup_set_video_attr(va, VIDEO_FORMAT, "pal"); + break; + case 6: + vobgroup_set_video_attr(va, VIDEO_ASPECT, "16:9"); + vobgroup_set_video_attr(va, VIDEO_FORMAT, "ntsc"); + break; + case 8: + vobgroup_set_video_attr(va, VIDEO_ASPECT, "4:3"); + vobgroup_set_video_attr(va, VIDEO_FORMAT, "pal"); + break; + case 12: + vobgroup_set_video_attr(va, VIDEO_ASPECT, "4:3"); + vobgroup_set_video_attr(va, VIDEO_FORMAT, "ntsc"); + break; + default: + fprintf(stderr,"WARN: unknown mpeg1 aspect ratio %d\n",aspect); + break; + } /*switch*/ + newaspect = + 3 + + + (va->vd.vaspect == VA_4x3) * 5 + + + (va->vd.vformat == VF_NTSC) * 3; + if (newaspect == 11) + newaspect++; + buf[7] = (buf[7] & 0xf) | (newaspect << 4); // reset the aspect ratio + } + else if (va->vd.vmpeg == VM_MPEG2) + { + if (aspect == 2) + vobgroup_set_video_attr(va, VIDEO_ASPECT, "4:3"); + else if (aspect == 3) + vobgroup_set_video_attr(va, VIDEO_ASPECT, "16:9"); + else + fprintf(stderr, "WARN: unknown mpeg2 aspect ratio %d\n", aspect); + buf[7] = (buf[7] & 0xf) | (va->vd.vaspect == VA_4x3 ? 2 : 3) << 4; + // reset the aspect ratio + } /*if*/ + break; + } /* case MPID_SEQUENCE */ + + case MPID_EXTENSION: /* extension header */ + { + vobgroup_set_video_attr(va, VIDEO_MPEG, "mpeg2"); + switch (buf[4] & 0xF0) + { + case 0x10: // sequence extension + closelastref(thisvi, vsi, prevbytesect); + break; + + case 0x20: // sequence display extension + closelastref(thisvi, vsi, prevbytesect); + switch (buf[4] & 0xE) /* video format */ + { + case 2: + vobgroup_set_video_attr(va, VIDEO_FORMAT, "pal"); + break; + case 4: + vobgroup_set_video_attr(va, VIDEO_FORMAT, "ntsc"); + break; + // case 6: // secam + // case 10: // unspecified + } + break; + + case 0x80: // picture coding extension + { + int padj = 1; // default field pic + if ((buf[6] & 3) /* picture structure */ == 3) + padj++; // adj for frame pic + if (buf[7] & 2) /* repeat first field */ + padj++; // adj for repeat flag + thisvi->numfields += padj; + if (vsi->lastadjust && vsi->firstgop == 2) + thisvi->firstIfield += padj; + // fprintf(stderr,"INFO: repeat flag=%d, cursect=%d\n",buf[7]&2,cursect); + } + break; + } /*switch*/ + break; + } /* case MPID_EXTENSION */ + + case MPID_SEQUENCE_END: + thisvi->hasseqend = 1; + break; + + case MPID_GOP: // gop header + closelastref(thisvi, vsi, prevbytesect); + if (vsi->firstgop == 1) + { + vsi->firstgop = 2; /* found first GOP */ + vsi->firsttemporal = -1; + vsi->lastadjust = 0; + } + else if (vsi->firstgop == 2) + { + vsi->firstgop = 0; /* no need to find any more GOPs */ + } /*if*/ + if (false) + { + int hr, mi, se, fr; + hr = (buf[4] >> 2) & 31; + mi = ((buf[4] & 3) << 4) | (buf[5] >> 4); + se = ((buf[5] & 7) << 3) | (buf[6] >> 5); + fr = ((buf[6] & 31) << 1) | (buf[7] >> 7); + fprintf + ( + stderr, + "INFO: GOP header, %d:%02d:%02d:%02d, drop=%d\n", + hr, mi, se, fr, buf[4] >> 7 + ); + } /*if*/ + break; /* case MPID_GOP */ + } /*switch*/ + } /*if*/ + } /*scanvideoptr*/ + +static void scanvideoframe(struct vobgroup *va, unsigned char *buf, struct vobuinfo *thisvi, int cursect, int prevsect, struct vscani *vsi) + { + int i, f = 0x17 + buf[0x16], l = 0x14 + buf[0x12] * 256 + buf[0x13]; + int mpf; + struct vobuinfo oldtvi; + struct vscani oldvsi; + if (l - f < 8) + { + memcpy(videoslidebuf + 7, buf + f, l - f); + for (i = 0; i < l - f; i++) + scanvideoptr(va, videoslidebuf + i, thisvi, prevsect, vsi); + memcpy(buf + f, videoslidebuf + 7, l - f); + memset(videoslidebuf, 255, 7); + return; + } /*if*/ + rescan: + mpf = va->vd.vmpeg; + oldtvi = *thisvi; + oldvsi = *vsi; + // copy the first 7 bytes to use with the prev 7 bytes in hdr detection + memcpy(videoslidebuf + 7, buf + f, 8); // we scan the first header using the slide buffer + for (i = 0; i <= 7; i++) + scanvideoptr(va, videoslidebuf + i, thisvi, prevsect, vsi); + memcpy(buf + f, videoslidebuf + 7, 8); + // quickly scan all but the last 7 bytes for a hdr + // buf[f]... was already scanned in the videoslidebuffer to give the correct sector + for (i = f + 1; i < l - 7; i++) + { + if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) + scanvideoptr(va, buf + i, thisvi, cursect, vsi); + } /*for*/ + if (!va->vd.vmpeg) + vobgroup_set_video_attr(va, VIDEO_MPEG, "mpeg1"); + // if the mpeg version changed, then rerun scanvideoframe, because + // scanvideoptr updates the aspect ratio in the sequence header + if (mpf != va->vd.vmpeg) + { + *thisvi = oldtvi; // we must undo all the frame pointer changes + *vsi = oldvsi; + goto rescan; + } /*if*/ + // use the last 7 bytes in the next iteration + memcpy(videoslidebuf, buf + l - 7, 7); + } /*scanvideoframe*/ + +static void finishvideoscan(struct vobgroup *va, int vob, int prevsect, struct vscani *vsi) + { + struct vobuinfo * const lastvi = &va->vobs[vob]->vobu[va->vobs[vob]->numvobus - 1]; + int i; + memset(videoslidebuf + 7, 0, 7); + for (i = 0; i < 7; i++) + scanvideoptr(va, videoslidebuf + i, lastvi, prevsect, vsi); + memset(videoslidebuf, 255, 7); + closelastref(lastvi, vsi, prevsect); + } /*finishvideoscan*/ + +static void printpts(pts_t pts) + /* displays a PTS value in seconds. */ + { + fprintf(stderr,"%d.%03d",(int)(pts/90000),(int)((pts/90)%1000)); + } + +enum { CR_BEGIN0, CR_BEGIN1, CR_BEGIN2, CR_BEGIN3, CR_SKIP0, + CR_SKIP1, CR_NEXTOFFS0, CR_NEXTOFFS1, CR_WAIT, CR_CMD, + CR_SKIPWAIT, CR_COL0, CR_COL1, CR_CHGARG, CR_CHGLN0, + CR_CHGLN1, CR_CHGLN2, CR_CHGLN3, CR_CHGPX0, CR_CHGPX1, + CR_CHGPX2 }; + +static char *readpstr(const unsigned char *b, int *i) +/* extracts a null-terminated string beginning at b[*i], advances *i past it and returns +a copy of the string. */ + { + char *s = strdup((const char *)b + i[0]); + i[0] += strlen(s) + 1; + return s; + } /*readpstr*/ + +static void initremap(struct colorremap *cr) + /* initializes the remap table to all identity mappings, and the state machine + ready to start processing a new SPU. */ + { + int i; + for (i = 0; i < 16; i++) /* initially don't remap any colours */ + cr->newcolors[i] = i; + cr->state = CR_BEGIN0; + cr->origmap = 0; + } /*initremap*/ + +static int remapcolor(struct colorremap *cr, int idx) + /* returns the appropriate remapping of the colour with the specified index + to the corresponding index in cr->origmap. */ + { + int i, nc; + if (cr->newcolors[idx] < 16) + return + cr->newcolors[idx]; /* remapping already worked out */ + nc = cr->newcolors[idx] & 0xffffff; /* get colour to be remapped */ + for (i = 0; i < 16; i++) /* find existing entry, if any */ + if (cr->origmap->color[i] == nc) /* got one */ + { + cr->newcolors[idx] = i; + return + i; + } /*if; for*/ + for (i = 0; i < 16; i++) + /* allocate a new entry in origmap for it, if there is room */ + if (cr->origmap->color[i] == COLOR_UNUSED) + { + cr->origmap->color[i] = nc; + cr->newcolors[idx] = i; + return + i; + } /*if; for */ + fprintf(stderr, "ERR: color map full, unable to allocate new colors.\n"); + exit(1); + } /*remapcolor*/ + +static void remapbyte(struct colorremap *cr, unsigned char *b) + /* remaps the two colours in the two nibbles of *b. */ + { + b[0] = remapcolor(cr, b[0] & 15) | (remapcolor(cr, b[0] >> 4) << 4); + } /*remapbyte*/ + +static void procremap + ( + struct colorremap *cr, + unsigned char *b, + int blen, /* length of SPU chunk beginning at b */ + pts_t *timespan /* has duration of SPU display added to it */ + ) + /* interprets the subpicture stream in order to pick up the colour information so it + can be remapped. */ + { + while(blen) + { + // fprintf(stderr,"INFO: state=%d, byte=%02x (%d)\n",cr->state,*b,*b); + switch(cr->state) + { + case CR_BEGIN0: /* pick up high byte of Sub-Picture Unit length */ + cr->curoffs = 0; + cr->skip = 0; + cr->maxlen = b[0] * 256; + cr->state = CR_BEGIN1; + break; + case CR_BEGIN1: /* pick up low byte of Sub-Picture Unit length */ + cr->maxlen += b[0]; + cr->state = CR_BEGIN2; + break; + case CR_BEGIN2: /* pick up high byte of offset to SP_DCSQT */ + cr->nextoffs = b[0] * 256; + cr->state = CR_BEGIN3; + break; + case CR_BEGIN3: /* pick up low byte of offset to SP_DCSQT */ + cr->nextoffs += b[0]; + cr->state = CR_WAIT; + break; + case CR_WAIT: /* skipping bytes until start of SP_DCSQT */ + if (cr->curoffs == cr->maxlen) + { + cr->state = CR_BEGIN0; /* finished this SPU */ + continue; // execute BEGIN0 right away + } /*if*/ + if (cr->curoffs != cr->nextoffs) + break; + cr->state = CR_SKIP0; /* found start of SP_DCSQT */ + // fall through to CR_SKIP0 + case CR_SKIP0: /* pick up high byte of SP_DCSQ_TM */ + *timespan += 1024 * b[0] * 256; + cr->state = CR_SKIP1; + break; + case CR_SKIP1: /* pick up low byte of SP_DCSQ_TM */ + *timespan += 1024 * b[0]; + cr->state = CR_NEXTOFFS0; + break; + case CR_NEXTOFFS0: /* pick up high byte of offset to next SP_DCSQ */ + cr->nextoffs = b[0] * 256; + cr->state = CR_NEXTOFFS1; + break; + case CR_NEXTOFFS1: /* pick up low byte of offset to next SP_DCSQ */ + cr->nextoffs += b[0]; + cr->state = CR_CMD; /* expecting first command */ + break; + case CR_SKIPWAIT: /* skipping rest of current command */ + if (cr->skip) + { + cr->skip--; + break; + } /*if*/ + cr->state = CR_CMD; + // fall through to CR_CMD + case CR_CMD: /* pick up start of next command */ + switch (*b) + { + case SPU_FSTA_DSP: + case SPU_STA_DSP: + case SPU_STP_DSP: + /* nothing to do */ + break; + case SPU_SET_COLOR: + cr->state = CR_COL0; + break; + case SPU_SET_CONTR: + cr->skip = 2; /* no need to look at this */ + cr->state = CR_SKIPWAIT; + break; + case SPU_SET_DAREA: + cr->skip = 6; /* no need to look at this */ + cr->state = CR_SKIPWAIT; + break; + case SPU_SET_DSPXA: + cr->skip = 4; /* no need to look at this */ + cr->state = CR_SKIPWAIT; + break; + case SPU_CHG_COLCON: + cr->skip = 2; /* skip size of parameter area */ + cr->state = CR_CHGARG; + break; + case SPU_CMD_END: + cr->state = CR_WAIT; /* end of SP_DCSQ */ + break; + default: + fprintf(stderr, "ERR: procremap encountered unknown subtitle command: %d\n",*b); + exit(1); + } /*switch*/ + break; + case CR_COL0: /* first and second of four colours for SET_COLOR */ + remapbyte(cr, b); + cr->state = CR_COL1; + break; + case CR_COL1: /* third and fourth of four colours for SET_COLOR */ + remapbyte(cr, b); + cr->state = CR_CMD; + break; + case CR_CHGARG: /* skipping size word for CHG_COLCON */ + if (!--cr->skip) + cr->state = CR_CHGLN0; + break; + case CR_CHGLN0: /* expecting first byte of LN_CTLI subcommand for CHG_COLCON */ + cr->ln_ctli = b[0] << 24; + cr->state = CR_CHGLN1; + break; + case CR_CHGLN1: + cr->ln_ctli |= b[0] << 16; + cr->state = CR_CHGLN2; + break; + case CR_CHGLN2: + cr->ln_ctli |= b[0] << 8; + cr->state = CR_CHGLN3; + break; + case CR_CHGLN3: + cr->ln_ctli |= b[0]; /* got complete four bytes at start of LN_CTLI */ + if (cr->ln_ctli == 0x0fffffff) /* end of CHG_COLCON parameter area */ + cr->state = CR_CMD; + else + { + cr->ln_ctli >>= 12; + cr->ln_ctli &= 0xf; /* number of PX_CTLI to follow */ + cr->skip = 2; + cr->state = CR_CHGPX0; + } /*if*/ + break; + case CR_CHGPX0: /* expecting starting column nr for PX_CTLI subcommand for CHG_COLCON */ + if (!--cr->skip) + { + cr->skip = 2; + cr->state = CR_CHGPX1; + } /*if*/ + break; + case CR_CHGPX1: /* expecting new colour values for PX_CTLI subcommand */ + remapbyte(cr, b); + if (!--cr->skip) + { + cr->skip = 2; + cr->state = CR_CHGPX2; + } /*if*/ + break; + case CR_CHGPX2: /* expecting new contrast values for PX_CTLI subcommand */ + if (!--cr->skip) + { + /* done this PX_CTLI */ + if (!--cr->ln_ctli) + cr->state = CR_CHGLN0; /* done this LN_CTLI */ + else + { + cr->skip = 2; + cr->state = CR_CHGPX0; /* next PX_CTLI in this LN_CTLI */ + } /*if*/ + } /*if*/ + break; + default: /* shouldn't occur */ + assert(false); + } /*switch*/ + cr->curoffs++; + b++; + blen--; + } /*while*/ + } /*procremap*/ + +static void printvobustatus(struct vobgroup *va, int cursect, bool checknonempty) + /* report total number of VOBUs and PGCs seen so far, and how much of the + input file has been processed. */ + { + int j, nv = 0; + for (j = 0; j < va->numvobs; j++) + nv += va->vobs[j]->numvobus; + // fprintf(stderr, "STAT: VOBU %d at %dMB, %d PGCs, %d:%02d:%02d\r", nv, cursect / 512, va->numallpgcs, total / 324000000, (total % 324000000) / 5400000, (total % 5400000) / 90000); + fprintf(stderr, "STAT: VOBU %d at %dMB, %d PGCs\r", nv, cursect / 512, va->numallpgcs); + if (checknonempty && nv == 0) + { + fprintf(stderr, "\nERR: no VOBUs found.\n"); + exit(1); + } /*if*/ + } /*printvobustatus*/ + +static void audio_scan_ac3(struct audchannel *ach, const unsigned char *buf, int sof, int len) + /* gets information about AC3 audio. */ + { + uint32_t parse; + int acmod,lfeon,nch=0; + char attr[4]; + + if( sof+8>len ) // check if there's room to parse all the interesting info + return; + if( buf[sof]!=0x0b || buf[sof+1]!=0x77 ) // verify ac3 sync + return; + parse=read4(buf+sof+4); + if( (parse>>30)!=0 ) { // must be 48kHz + fprintf(stderr,"WARN: Unknown AC3 sample rate: %d\n",parse>>30); + } + audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_SAMPLERATE,"48khz"); + /* now figure out how many channels are present ... (yes, all this code) */ + parse<<=8; + // check bsid + if( (parse>>27)!=8 && (parse>>27)!=6 ) // must be v6 or v8 + return; + parse<<=5; + // ignore bsmod + parse<<=3; + // acmod gives # of channels + acmod=(parse>>29); + parse<<=3; + if( (acmod&1) && (acmod!=1) ) /* centre channel present */ + parse<<=2; /* skip cmixlev */ + if( acmod&4 ) /* surround channel(s) present */ + parse<<=2; /* skip surmixlev */ + if( acmod==2 ) { /* simple stereo */ + /* process dsurmod */ + if( (parse>>30)==2 ) /* 2 => Dolby Surround encoded, 1 => not encoded, 0 => not indicated, 3 => reserved */ + audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_DOLBY,"surround"); + // else if( (parse>>30)==1 ) + // audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_DOLBY,"nosurround"); + parse<<=2; + } + lfeon=(parse>>31); /* low-frequency effects on */ + // calc # channels + switch(acmod) { + case 0: nch=2; break; + case 1: nch=1; break; + case 2: nch=2; break; + case 3: nch=3; break; + case 4: nch=3; break; + case 5: nch=4; break; + case 6: nch=4; break; + case 7: nch=5; break; + } + if( lfeon ) nch++; /* include LFE channel */ + sprintf(attr,"%dch",nch); + audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_CHANNELS,attr); + } /*audio_scan_ac3*/ + +static void audio_scan_dts(struct audchannel *ach,const unsigned char *buf,int sof,int len) + /* gets information about DTS audio. */ +{ +/* fixme: could determine number of channels and sampling rate, but I'm not bothering for now */ +} + +static void audio_scan_pcm(struct audchannel *ach,const unsigned char *buf,int len) + /* gets information about LPCM audio. */ +{ + char attr[6]; + + switch(buf[1]>>6) { + case 0: audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_QUANT,"16bps"); break; + case 1: audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_QUANT,"20bps"); break; + case 2: audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_QUANT,"24bps"); break; + /* case 3: illegal */ + } + sprintf(attr,"%dkhz",48*(1+((buf[1]>>4)&1))); /* 48 or 96kHz */ + audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_SAMPLERATE,attr); + sprintf(attr,"%dch",(buf[1]&7)+1); /* nr channels */ + audiodesc_set_audio_attr(&ach->ad,&ach->adwarn,AUDIO_CHANNELS,attr); +} + +int FindVobus(const char *fbase, struct vobgroup *va, vtypes ismenu) + /* collects audio/video/subpicture information, remaps subpicture colours and generates + output VOB files for a menu or titleset, complete except for the NAV packs. */ + { + unsigned char *buf; + static unsigned char deferred_buf[2048]; + int cursect = 0; /* sector nr in input file */ + int fsect = -1; /* sector nr in current output VOB file, -ve => not opened yet */ + int vnum; + int outnum = -(int)ismenu + 1; /* +ve for a titleset, in which case used to generate output VOB file names */ + int vobid =0; + struct mp2info + { + int hdrptr; /* index at which packet header starts */ + unsigned char buf[6]; /* save partial packet in case it crosses sector boundaries */ + } mp2hdr[8]; /* enough for the allowed 8 audio streams */ + struct colorremap *crs; + + crs = malloc(sizeof(struct colorremap) * 32); /* enough for 32 subpicture streams */ + for (vnum = 0; vnum < va->numvobs; vnum++) + { + int i, j; + int sysoffs; + bool hadfirstvobu = false; + pts_t backoffs = 0, lastscr = 0; + bool fill_in_vobus = false, got_deferred_buf = false; + struct vob * const thisvob = va->vobs[vnum]; + int prevvidsect = -1; + struct vscani vsi; + struct vfile vf; + vsi.lastrefsect = 0; + for (i = 0; i < 32; i++) + initremap(crs + i); + + vobid++; + thisvob->vobid = vobid; + vsi.firstgop = 1; + + fprintf(stderr, "\nSTAT: Processing %s...\n", thisvob->fname); + vf = varied_open(thisvob->fname, O_RDONLY, "input video file"); + memset(mp2hdr, 0, 8 * sizeof(struct mp2info)); + while (true) + { + if (fsect == 524272) + { + /* VOB file reached maximum allowed size */ + writeclose(); + if (outnum <= 0) + { /* menu VOB cannot be split */ + fprintf(stderr, "\nERR: Menu VOB reached 1gb\n"); + exit(1); + } /*if*/ + outnum++; /* for naming next VOB file */ + fsect = -1; + } /*if*/ + buf = writegrabbuf(); + if (got_deferred_buf) + memcpy(buf, deferred_buf, 2048); + else + { + i = fread(buf, 1, 2048, vf.h); + if (i != 2048) + { + if (i == -1) + { + fprintf(stderr, "\nERR: Error %d while reading: %s\n", errno, strerror(errno)); + exit(1); + } + else if (i > 0) /* shouldn't occur */ + fprintf(stderr ,"\nWARN: Partial sector read (%d bytes); discarding data.\n", i); + writeundo(); + break; + } /*if*/ + } /*if*/ + if + ( + buf[14] == 0 + && + buf[15] == 0 + && + buf[16] == 1 + && + buf[17] == MPID_PAD + && + !strcmp((const char *)buf + 20, "dvdauthor-data") /* message from spumux */ + ) + { + // private dvdauthor data, interpret and remove from final stream + int i = 35; + if (buf[i] != 2) + { + fprintf(stderr, "ERR: dvd info packet is version %d\n", buf[i]); + exit(1); + } /*if*/ + switch (buf[i + 1]) // packet type + { + case 1: // subtitle/menu color and button information + { + int substreamid = buf[i + 2] & 31; + i += 3; + i += 8; // skip start pts and end pts + while (buf[i] != 0xff) + { + switch (buf[i]) + { + case 1: // new colormap + { + int j; + crs[substreamid].origmap = thisvob->progchain->colors; + /* where to merge colours into */ + for (j = 0; j < buf[i + 1]; j++) + { + /* collect colours needing remapping, which won't happen + until they're actually referenced */ + crs[substreamid].newcolors[j] = + COLOR_UNUSED /* indicate colour needs remapping */ + | + buf[i + 2 + 3 * j] << 16 + | + buf[i + 3 + 3 * j] << 8 + | + buf[i + 4 + 3 * j]; + } /*for*/ + for (; j < 16; j++) /* fill in unused entries with identity mapping */ + crs[substreamid].newcolors[j] = j; + i += 2 + 3 * buf[i + 1]; + } + break; + case 2: // new buttoncoli + { + int j; + memcpy(thisvob->buttoncoli, buf + i + 2, buf[i + 1] * 8); + for (j = 0; j < buf[i + 1]; j++) + { + /* remap the colours, not the contrast values */ + remapbyte(&crs[substreamid], thisvob->buttoncoli + j * 8 + 0); + remapbyte(&crs[substreamid], thisvob->buttoncoli + j * 8 + 1); + remapbyte(&crs[substreamid], thisvob->buttoncoli + j * 8 + 4); + remapbyte(&crs[substreamid], thisvob->buttoncoli + j * 8 + 5); + } /*for*/ + i += 2 + 8 * buf[i + 1]; + } + break; + case 3: // button position information + { + int j; + const int nrbuttons = buf[i + 1]; + i += 2; + for (j = 0; j < nrbuttons; j++) + { + struct button * b; + struct buttoninfo * bi, bitmp; + char * const bn = readpstr(buf, &i); + if (!findbutton(thisvob->progchain, bn, 0)) + { + fprintf + ( + stderr, + "ERR: Cannot find button '%s' as referenced by" + " the subtitle\n", + bn + ); + exit(1); + } /*if*/ + b = &thisvob->progchain->buttons[findbutton(thisvob->progchain, bn, 0) - 1]; + free(bn); + + if (b->numstream >= MAXBUTTONSTREAM) + { + fprintf + ( + stderr, + "WARN: Too many button streams; ignoring buttons\n" + ); + bi = &bitmp; /* place to put discarded data */ + } + else + { + bi = &b->stream[b->numstream++]; + } /*if*/ + bi->substreamid = substreamid; + i += 2; // skip modifier + bi->autoaction = buf[i++] != 0; + bi->grp = buf[i]; + bi->x1 = read2(buf + i + 1); + bi->y1 = read2(buf + i + 3); + bi->x2 = read2(buf + i + 5); + bi->y2 = read2(buf + i + 7); + i += 9; + /* neighbouring button names */ + bi->up = readpstr(buf, &i); + bi->down = readpstr(buf, &i); + bi->left = readpstr(buf, &i); + bi->right = readpstr(buf, &i); + } /*for*/ + } /*case 3*/ + break; + default: + fprintf + ( + stderr, + "ERR: dvd info packet command within subtitle: %d\n", + buf[i] + ); + exit(1); + } /*switch*/ + } /*while*/ + + } /*case 1*/ + break; + + default: + fprintf(stderr, "ERR: unknown dvdauthor-data packet type: %d\n", buf[i + 1]); + exit(1); + } /*switch*/ + + writeundo(); /* drop private data from output */ + continue; + } /*if*/ + // we should get a VOBU before a video with GOP + if + ( + (fill_in_vobus || !hadfirstvobu) + && + !got_deferred_buf + && + has_gop(buf) + ) + { + // create VOBU + if (!hadfirstvobu) + { /* let user know the first time this happens */ + fprintf + ( + stderr, "INFO: found video GOP without a preceding VOBU - creating VOBU\n" + ); + } /*if*/ + fill_in_vobus = true; /* keep doing it from now on */ + memcpy(deferred_buf, buf, 2048); /* save just-read sector for processing on next iteration */ + got_deferred_buf = true; /* remember I've saved it */ + /* buf already has a system header */ + buf[41] = MPID_PRIVATE2; + buf[42] = 0x03; + buf[43] = 0xd4; + buf[44] = 0x81; /* rest of PCI will be correctly filled in later by FixVobus */ + memset(buf + 45, 0, 2048 - 45); + buf[1026] = 1; + buf[1027] = MPID_PRIVATE2; + buf[1028] = 0x03; + buf[1029] = 0xfa; + buf[1030] = 0x81; /* rest of DSI will be correctly filled in later by FixVobus */ + } + else if (got_deferred_buf) + got_deferred_buf = false; /* already picked it up */ + if (buf[0] == 0 && buf[1] == 0 && buf[2] == 1 && buf[3] == MPID_PACK) + { + const pts_t newscr = readscr(buf + 4); + if (hadfirstvobu && newscr == 0 && lastscr > 0) + /* suggestion from Philippe Sarazin -- alternatively, Shaun Jackman suggests + simply treating newscr < lastscr as a warning and continuing */ + { + backoffs -= lastscr; /* adjust to remove SCR discontinuity */ + fprintf(stderr, "\nWARN: SCR reset. New back offset = %" PRId64"\n", backoffs); + } + else if (newscr < lastscr) + { + fprintf + ( + stderr, + "ERR: SCR moves backwards, remultiplex input: %" PRId64" < %" PRId64"\n", + newscr, + lastscr + ); +// exit(1); + } /*if*/ + lastscr = newscr; + if (!hadfirstvobu) + backoffs = newscr; /* start SCR from 0 */ + } /*if*/ + transpose_ts(buf, -backoffs); + if (fsect == -1) + { + /* start a new VOB file */ + char newname[200]; + fsect = 0; + if (fbase) + { + if (outnum >= 0) + sprintf(newname, "%s_%d.VOB", fbase, outnum); + else + strcpy(newname, fbase); + writeopen(newname); + } /*if*/ + } /*if*/ + if + ( + buf[14] == 0 + && + buf[15] == 0 + && + buf[16] == 1 + && + buf[17] == MPID_SYSTEM + ) + { + if + ( + buf[38] == 0 + && + buf[39] == 0 + && + buf[40] == 1 + && + buf[41] == MPID_PRIVATE2 // 1st private2 + && + buf[1024] == 0 + && + buf[1025] == 0 + && + buf[1026] == 1 + && + buf[1027] == MPID_PRIVATE2 // 2nd private2 + ) /* looks like a NAV PACK, which means the start of a new VOBU */ + { + struct vobuinfo *vi; + if (thisvob->numvobus) + finishvideoscan(va, vnum, prevvidsect, &vsi); + // fprintf(stderr,"INFO: vobu\n"); + hadfirstvobu = true; /* NAV PACK starts a VOBU */ + if (thisvob->numvobus == thisvob->maxvobus) /* need more space */ + { + if (!thisvob->maxvobus) + thisvob->maxvobus = 1; /* first allocation */ + else + thisvob->maxvobus <<= 1; + /* resize in powers of 2 to reduce reallocation calls */ + thisvob->vobu = (struct vobuinfo *)realloc + ( + /*ptr =*/ thisvob->vobu, + /*size =*/ thisvob->maxvobus * sizeof(struct vobuinfo) + ); + } /*if*/ + vi = &thisvob->vobu[thisvob->numvobus]; /* for the new VOBU */ + memset(vi, 0, sizeof(struct vobuinfo)); + vi->sector = cursect; + vi->fsect = fsect; + vi->fnum = outnum; + vi->firstvideopts = -1; + vi->firstIfield = 0; + vi->numfields = 0; + vi->numref = 0; + vi->hasseqend = 0; + vi->hasvideo = 0; + memcpy(thisvob->vobu[thisvob->numvobus].sectdata, buf, 0x26); // save pack and system header; the rest will be reconstructed later + thisvob->numvobus++; + if (!(thisvob->numvobus & 15)) /* time to let user know progress */ + printvobustatus(va, cursect, false); + vsi.lastrefsect = 0; + vsi.firstgop = 1; /* restart scan for first GOP */ + } /*if*/ + } /*if*/ + if (!hadfirstvobu) + { + fprintf(stderr, "WARN: Skipping sector, waiting for first VOBU...\n"); + writeundo(); /* ignore it */ + continue; + } /*if*/ + thisvob->vobu[thisvob->numvobus - 1].lastsector = cursect; + + i = 14; + j = -1; + while (i <= 2044) + { + if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) + { + if (buf[i + 3] >= MPID_PRIVATE1 && buf[i + 3] <= MPID_VIDEO_LAST) + /* private, padding, audio or video stream */ + { + j = i; + i += 6 + read2(buf + i + 4); /* start of next packet */ + continue; + } + else if + ( + buf[i + 3] == MPID_PROGRAM_END + && + j >= 14 + && + buf[j + 3] == MPID_PAD /* previous was padding stream */ + ) + { + write2(buf + j + 4, read2(buf + j + 4) + 4); + /* merge program-end packet into prior pad packet */ + memset(buf + i, 0, 4); // mplex uses 0 for padding, so will I + } /*if*/ + } /*if*/ + break; + } /*while*/ + + sysoffs = + buf[14] == 0 && buf[15] == 0 && buf[16] == 1 && buf[17] == MPID_SYSTEM ? + /* skip system header if present */ + (buf[18] << 8 | buf[19]) + 6 + : + 0; + if + ( + buf[0] == 0 + && + buf[1] == 0 + && + buf[2] == 1 + && + buf[3] == MPID_PACK + && + buf[14 + sysoffs] == 0 + && + buf[15 + sysoffs] == 0 + && + buf[16 + sysoffs] == 1 + && + buf[17 + sysoffs] == MPID_VIDEO_FIRST /* only video stream */ + ) + { + struct vobuinfo * const vi = &thisvob->vobu[thisvob->numvobus - 1]; + vi->hasvideo = 1; + scanvideoframe(va, buf + sysoffs, vi, cursect, prevvidsect, &vsi); + if + ( + (buf[21 + sysoffs] & 128) /* PTS present */ + && + vi->firstvideopts == -1 /* not seen one yet */ + ) + { + vi->firstvideopts = readpts(buf + 23 + sysoffs); + } /*if*/ + prevvidsect = cursect; + } /*if*/ + if + ( + buf[0] == 0 + && + buf[1] == 0 + && + buf[2] == 1 + && + buf[3] == MPID_PACK + && + buf[14 + sysoffs] == 0 + && + buf[15 + sysoffs] == 0 + && + buf[16 + sysoffs] == 1 + && + ( + (buf[17 + sysoffs] & 0xf8) == 0xc0 /* MPEG audio stream */ + || + buf[17 + sysoffs] == MPID_PRIVATE1 /* DVD audio or subpicture */ + ) + ) + { + pts_t pts0 = 0, pts1 = 0, backpts1 = 0; + const int dptr = buf[22 + sysoffs] /* PES header data length */ + 23 + sysoffs; /* offset to packet data */ + const int endop = read2(buf + 18 + sysoffs) /* PES packet length */ + 20 /* fixed PES header length */ + sysoffs; /* end of packet */ + int audch; + const int haspts = (buf[21 + sysoffs] & 128) != 0; + if (buf[17 + sysoffs] == MPID_PRIVATE1) /* DVD audio or subpicture */ + { + const int sid = buf[dptr]; /* sub-stream ID */ + const int offs = read2(buf + dptr + 2); + /* offset to audio sample frame which corresponds to PTS value */ + const int nrframes = buf[dptr + 1]; + /* nr audio sample frames beginning in this packet */ + switch (sid & 0xf8) + { + case 0x20: // subpicture + case 0x28: // subpicture + case 0x30: // subpicture + case 0x38: // subpicture + audch = sid; + break; + case 0x80: // ac3 audio + pts1 += 2880 * nrframes; + audch = sid & 7; + audio_scan_ac3(&thisvob->audch[audch], buf + dptr + 4, offs - 1, endop - (dptr + 4)); + break; + case 0x88: // dts audio + /* pts1 += 960 * nrframes; */ /* why not? */ + audch = 24 | (sid & 7); + audio_scan_dts(&thisvob->audch[audch], buf + dptr + 4, offs - 1, endop - (dptr + 4)); + break; + case 0xa0: // pcm audio + pts1 += 150 * nrframes; + audch = 16 | (sid & 7); + audio_scan_pcm(&thisvob->audch[audch], buf + dptr + 4, endop - (dptr + 4)); + break; + default: // unknown + audch = -1; + break; + } /*switch*/ + } + else /* regular MPEG audio */ + { + const int len = endop - dptr; /* length of packet data */ + const int index = buf[17 + sysoffs] & 7; /* audio stream ID */ + audch = 8 | index; // mp2 + memcpy(mp2hdr[index].buf + 3, buf + dptr, 3); + while (mp2hdr[index].hdrptr + 4 <= len) + { + const unsigned char * h; + if (mp2hdr[index].hdrptr < 0) + h = mp2hdr[index].buf + 3 + mp2hdr[index].hdrptr; + /* overlap from previous */ + else + h = buf + dptr + mp2hdr[index].hdrptr; + if (!mpa_valid(h)) + { + mp2hdr[index].hdrptr++; /* try the next likely offset */ + continue; + } /*if*/ + if (mp2hdr[index].hdrptr < 0) + backpts1 += 2160; /* how much time to add to end of previous packet */ + else + pts1 += 2160; + mp2hdr[index].hdrptr += mpa_len(h); /* to next header */ + } /*while*/ + mp2hdr[index].hdrptr -= len; /* will be -ve if extends into next sector */ + memcpy(mp2hdr[index].buf, buf + dptr + len - 3, 3); + audiodesc_set_audio_attr(&thisvob->audch[audch].ad, &thisvob->audch[audch]. adwarn, AUDIO_SAMPLERATE, "48khz"); + } /*if*/ + /* at this point, pts1 is the duration of the audio in the packet */ + if (haspts) + { + pts0 = readpts(buf + 23 + sysoffs); + pts1 += pts0; + } + else if (pts1 > 0) + { + fprintf + ( + stderr, + "WARN: Audio channel %d contains sync headers but has no PTS.\n", + audch + ); + } /*if*/ + // fprintf(stderr,"aud ch=%d pts %d - %d (%d)\n",audch,pts0,pts1,pts1-pts0); + // fprintf(stderr,"pts[%d] %d (%02x %02x %02x %02x %02x)\n",va->numaudpts,pts,buf[23],buf[24],buf[25],buf[26],buf[27]); + if (audch < 0 || audch >= 64) + { + fprintf(stderr,"WARN: Invalid audio channel %d\n",audch); + /* and ignore */ + } + else if (haspts) + { + struct audchannel * const ach = &thisvob->audch[audch]; + if (ach->numaudpts == ach->maxaudpts) { /* need more space */ + if (ach->maxaudpts) + ach->maxaudpts <<= 1; + /* resize in powers of 2 to reduce reallocation calls */ + else + ach->maxaudpts = 1; /* first allocation */ + ach->audpts = (struct audpts *)realloc + ( + /*ptr =*/ ach->audpts, + /*size =*/ ach->maxaudpts * sizeof(struct audpts) + ); + } /*if*/ + if (ach->numaudpts) + { + // we cannot compute the length of a DTS audio packet + // so just backfill if it is one + // otherwise, for mp2 add any pts to the previous + // sector for a header that spanned two sectors + if ((audch & 0x38) == 0x18) // is this DTS? + ach->audpts[ach->numaudpts - 1].pts[1] = pts0; + else + ach->audpts[ach->numaudpts - 1].pts[1] += backpts1; + + if (ach->audpts[ach->numaudpts - 1].pts[1] < pts0) + { + if (audch >= 32) + goto noshow; /* not audio */ + fprintf(stderr, "WARN: Discontinuity of %" PRId64" in audio channel %d; please remultiplex input.\n", pts0 - ach->audpts[ach->numaudpts - 1].pts[1], audch); + // fprintf(stderr,"last=%d, this=%d\n",ach->audpts[ach->numaudpts-1].pts[1],pts0); + } + else if (ach->audpts[ach->numaudpts - 1].pts[1] > pts0) + fprintf + ( + stderr, + "WARN: Audio pts for channel %d moves backwards by %" + PRId64 "; please remultiplex input.\n", + audch, + ach->audpts[ach->numaudpts - 1].pts[1] - pts0 + ); + else + goto noshow; + fprintf(stderr, "WARN: Previous sector: "); + printpts(ach->audpts[ach->numaudpts - 1].pts[0]); + fprintf(stderr, " - "); + printpts(ach->audpts[ach->numaudpts - 1].pts[1]); + fprintf(stderr, "\nWARN: Current sector: "); + printpts(pts0); + fprintf(stderr, " - "); + printpts(pts1); + fprintf(stderr, "\n"); + ach->audpts[ach->numaudpts - 1].pts[1] = pts0; + } /*if*/ +noshow: + /* fill in new entry */ + ach->audpts[ach->numaudpts].pts[0] = pts0; + ach->audpts[ach->numaudpts].pts[1] = pts1; + ach->audpts[ach->numaudpts].asect = cursect; + ach->numaudpts++; + } /*if*/ + } /*if*/ + // the following code scans subtitle code in order to + // remap the colors and update the end pts + if + ( + buf[0] == 0 + && + buf[1] == 0 + && + buf[2] == 1 + && + buf[3] == MPID_PACK + && + buf[14 + sysoffs] == 0 + && + buf[15 + sysoffs] == 0 + && + buf[16 + sysoffs] == 1 + && + buf[17 + sysoffs] == MPID_PRIVATE1 + ) + { + int dptr = buf[22 + sysoffs] /* PES header data length */ + 23 + sysoffs; /* offset to packet data */ + const int ml = read2(buf + 18) /* PES packet length */ + 20 /* fixed PES header length */ + sysoffs; /* end of packet */ + const int st = buf[dptr]; /* sub-stream ID */ + dptr++; /* skip sub-stream ID */ + if ((st & 0xe0) == 0x20) + { /* subpicture stream */ + procremap + ( + /*cr =*/ &crs[st & 31], + /*b =*/ buf + dptr, + /*blen =*/ ml - dptr, + /*timespan =*/ + &thisvob->audch[st].audpts[thisvob->audch[st].numaudpts - 1].pts[1] + ); + } /*if*/ + } /*if*/ + cursect++; + fsect++; + } /*while*/ + varied_close(vf); + if (thisvob->numvobus) + { + int i; + pts_t finalaudiopts; + finishvideoscan(va, vnum, prevvidsect, &vsi); + // find end of audio + finalaudiopts = -1; + for (i = 0; i < 32; i++) + { + struct audchannel * const ach = thisvob->audch + i; + if + ( + ach->numaudpts + && + ach->audpts[ach->numaudpts - 1].pts[1] > finalaudiopts + ) + finalaudiopts = ach->audpts[ach->numaudpts - 1].pts[1]; + } /*for*/ + // pin down all video vobus + // note: we make two passes; one assumes that the PTS for the + // first frame is exact; the other assumes that the PTS for + // the first frame is off by 1/2. If both fail, then the third pass + // assumes things are exact and throws a warning + for (i = 0; i < 3; i++) + { + pts_t pts_align = -1; /* initially undefined */ + int complained = 0, j; + for (j = 0; j < thisvob->numvobus; j++) + { + struct vobuinfo * const vi = thisvob->vobu + j; + if (vi->hasvideo) + { + if (pts_align == -1) + { + pts_align = vi->firstvideopts * 2; + if (i == 1) + { + // I assume pts should round down? That seems to be how mplex deals with it + // also see earlier comment + + // since pts round down, then the alternative base we should try is + // firstvideopts+0.5, thus increment + pts_align++; + } /*if*/ + // MarkChapters will complain if firstIfield!=0 + } /*if*/ + + vi->videopts[0] = calcpts(va, i == 2, &complained, &pts_align, vi->firstvideopts, -vi->firstIfield); + vi->videopts[1] = calcpts(va, i == 2, &complained, &pts_align, vi->firstvideopts, -vi->firstIfield + vi->numfields); + // if this looks like a dud, abort and try the next pass + if (complained && i < 2) + break; + vi->sectpts[0] = vi->videopts[0]; + if (j + 1 == thisvob->numvobus && finalaudiopts > vi->videopts[1]) + vi->sectpts[1] = finalaudiopts; + else + vi->sectpts[1] = vi->videopts[1]; + } /*if*/ + } /*for*/ + if (!complained) + break; + } /*for*/ + // guess at non-video vobus + for (i = 0; i < thisvob->numvobus; i++) + { + struct vobuinfo * const vi = thisvob->vobu + i; + if (!vi->hasvideo) + { + int j, k; + pts_t firstaudiopts = -1, p; + + for (j = 0; j < 32; j++) + { + const struct audchannel * const ach = thisvob->audch + j; + for (k = 0; k < ach->numaudpts; k++) + if (ach->audpts[k].asect >= vi->sector) + { + if (firstaudiopts == -1 || ach->audpts[k].pts[0] < firstaudiopts) + firstaudiopts = ach->audpts[k].pts[0]; + break; + } /*if; for*/ + } /*for*/ + if (firstaudiopts == -1) + { + fprintf + ( + stderr, + "WARN: Cannot detect pts for VOBU if there is no audio or video\n" + "WARN: Using SCR instead.\n" + ); + firstaudiopts = readscr(vi->sectdata + 4) + 4 * 147; + // 147 is roughly the minumum pts that must transpire between packets; + // we give a couple packets of buffer to allow the dvd player to + // process the data + } /*if*/ + if (i) + { + pts_t frpts = getframepts(va); + p = firstaudiopts - thisvob->vobu[i - 1].sectpts[0]; + // ensure this is a multiple of a framerate, just to be nice + p += frpts - 1; + p -= p % frpts; + p += thisvob->vobu[i - 1].sectpts[0]; + assert(p >= thisvob->vobu[i - 1].sectpts[1]); + thisvob->vobu[i - 1].sectpts[1] = p; + } + else + { + fprintf + ( + stderr, + "ERR: Cannot infer pts for VOBU if there is no audio or video" + " and it is the\nERR: first VOBU.\n" + ); + exit(1); + } /*if*/ + vi->sectpts[0] = p; + // if we can easily predict the end pts of this sector, + // then fill it in. otherwise, let the next iteration do it + if (i + 1 == thisvob->numvobus) + { // if this is the end of the vob, use the final audio pts as the last pts + if( finalaudiopts>vi->sectpts[0] ) + p = finalaudiopts; + else + p = vi->sectpts[0] + getframepts(va); + // add one frame of a buffer, so we don't have a zero (or less) length vobu + } + else if (thisvob->vobu[i+1].hasvideo) + // if the next vobu has video, use the start of the video as the end of this vobu + p = thisvob->vobu[i + 1].sectpts[0]; + else + // the next vobu is an audio only vobu, and will backfill the pts as necessary + continue; + if (p <= vi->sectpts[0]) + { + fprintf + ( + stderr, + "ERR: Audio and video are too poorly synchronised; you must" + " remultiplex.\n" + ); + exit(1); + } /*if*/ + vi->sectpts[1] = p; + } /*if*/ + } /*for*/ + + fprintf(stderr, "\nINFO: Video pts = "); + printpts(thisvob->vobu[0].videopts[0]); + fprintf(stderr, " .. "); + for (i = thisvob->numvobus - 1; i >= 0; i--) + if (thisvob->vobu[i].hasvideo) + { + printpts(thisvob->vobu[i].videopts[1]); + break; + } /*if; for*/ + if (i < 0) + fprintf(stderr, "??"); + for (i = 0; i < 64; i++) + { + const struct audchannel * const ach = &thisvob->audch[i]; + if (ach->numaudpts) + { + fprintf(stderr, "\nINFO: Audio[%d] pts = ", i); + printpts(ach->audpts[0].pts[0]); + fprintf(stderr, " .. "); + printpts(ach->audpts[ach->numaudpts - 1].pts[1]); + } /*if*/ + } /*for*/ + fprintf(stderr, "\n"); + } /*if*/ + } /*for*/ + writeclose(); + printvobustatus(va, cursect, true); + fprintf(stderr, "\n"); + free(crs); + return 1; + } /*FindVobus*/ + +static pts_t pabs(pts_t pts) + /* returns the absolute value of pts. */ + { + if (pts < 0) + return -pts; + return pts; + } /*pabs*/ + +static int findnearestvobu(struct vobgroup *pg, struct vob *va, pts_t pts) + /* returns the index of the VOBU closest in time to pts. */ + { + int l = 0, h = va->numvobus - 1, i; + if (h < 0) + return -1; + pts += va->vobu[0].sectpts[0]; + i = findvobu(va, pts, l, h); + if + ( + i + 1 < va->numvobus + && + i >= 0 + && + pabs(pts - va->vobu[i + 1].sectpts[0]) < pabs(pts - va->vobu[i].sectpts[0]) + /* next one is closer */ + ) + i++; + return i; + } /*findnearestvobu*/ + +void MarkChapters(struct vobgroup *va) + /* fills in scellid, ecellid, vobcellid, firstvobuincell, lastvobuincell, numcells fields + to mark all the cells and programs. */ + { + int i, j, k, lastvobuid; + // mark start and stop points + lastvobuid = -1; + for (i = 0; i < va->numallpgcs; i++) + for (j = 0; j < va->allpgcs[i]->numsources; j++) + { + /* use vobcellid fields to mark start of cells, and scellid and ecellid fields + to hold vobu indexes, all to be replaced later with right values */ + struct source * const thissource = va->allpgcs[i]->sources[j]; + for (k = 0; k < thissource->numcells; k++) + { + int v; + v = findnearestvobu(va, thissource->vob, thissource->cells[k].startpts); + if (v >= 0 && v < thissource->vob->numvobus) + { + if (thissource->cells[k].ischapter != CELL_NEITHER) /* from Wolfgang Wershofen */ + { /* info for user corresponding to the points they marked */ + fprintf(stderr, "CHAPTERS: VTS[%d/%d] ", i + 1, j + 1); + printpts(thissource->vob->vobu[v].sectpts[0] - thissource->vob->vobu[0].sectpts[0]); + fprintf(stderr, "\n"); + } /*if*/ + thissource->vob->vobu[v].vobcellid = 1; /* cell starts here */ + } /*if*/ + thissource->cells[k].scellid = v; /* cell starts here */ + if + ( + lastvobuid != v + && + thissource->vob->vobu[v].firstIfield != 0 + ) + { + fprintf + ( + stderr, + "WARN: GOP may not be closed on cell %d of source %s of pgc %d\n", + k + 1, + thissource->fname, + i + 1 + ); + } /*if*/ + if (thissource->cells[k].endpts >= 0) + { + v = findnearestvobu(va, thissource->vob, thissource->cells[k].endpts); + if (v >= 0 && v < thissource->vob->numvobus) + thissource->vob->vobu[v].vobcellid = 1; /* another cell should start here */ + } + else /* -ve end time => cell goes to end of vob */ + v = thissource->vob->numvobus; + thissource->cells[k].ecellid = v; /* next cell starts here */ + lastvobuid = v; + } /*for*/ + } /*for; for*/ + /* At this point, the vobcellid fields have been set to 1 for all VOBUs which + are supposed to start new cells. */ + for (i = 0; i < va->numvobs; i++) + { + /* fill in the vobcellid fields with the right values, and also + firstvobuincell and lastvobuincell */ + int cellvobu = 0; + int cellid = 0; + va->vobs[i]->vobu[0].vobcellid = 1; /* ensure first vobu starts a cell */ + for (j = 0; j < va->vobs[i]->numvobus; j++) + { + struct vobuinfo * const thisvobu = &va->vobs[i]->vobu[j]; + if (thisvobu->vobcellid) + { + cellid++; /* start new cell */ + cellvobu = j; /* this VOBU is first in cell */ + } /*if*/ + thisvobu->vobcellid = cellid + va->vobs[i]->vobid * 256; + thisvobu->firstvobuincell = cellvobu; + } /*for*/ + cellvobu = va->vobs[i]->numvobus - 1; + for (j = cellvobu; j >= 0; j--) + { /* fill in the lastvobuincell fields */ + struct vobuinfo * const thisvobu = &va->vobs[i]->vobu[j]; + thisvobu->lastvobuincell = cellvobu; + if (thisvobu->firstvobuincell == j) /* reached start of this cell */ + cellvobu = j - 1; + } /*for*/ + va->vobs[i]->numcells = cellid; + if (cellid >= 256) + { + fprintf + ( + stderr, + "ERR: VOB %s has too many cells (%d, 256 allowed)\n", + va->vobs[i]->fname, + cellid + ); + exit(1); + } /*if*/ + } /*for*/ + /* Now fill in right values for scellid and ecellid fields, replacing the + vobu indexes I previously put in with the corresponding vobcellid values I + have just computed. */ + for (i = 0; i < va->numallpgcs; i++) + for (j = 0; j < va->allpgcs[i]->numsources; j++) + { + struct source * const thissource = va->allpgcs[i]->sources[j]; + for (k = 0; k < thissource->numcells; k++) + { + struct cell * const thiscell = &thissource->cells[k]; + if (thiscell->scellid < 0) + thiscell->scellid = 1; + else if (thiscell->scellid < thissource->vob->numvobus) + thiscell->scellid = thissource->vob->vobu[thiscell->scellid].vobcellid & 255; + else + thiscell->scellid = thissource->vob->numcells + 1; + if (thiscell->ecellid < 0) + thiscell->ecellid = 1; + else if (thiscell->ecellid < thissource->vob->numvobus) + thiscell->ecellid = thissource->vob->vobu[thiscell->ecellid].vobcellid & 255; + else + thiscell->ecellid = thissource->vob->numcells + 1; + /* near as I can tell, ecellid will either be equal to scellid or 1 greater */ + va->allpgcs[i]->numcells += thiscell->ecellid - thiscell->scellid; + if (thiscell->scellid != thiscell->ecellid && thiscell->ischapter != CELL_NEITHER) + { + va->allpgcs[i]->numprograms++; /* ischapter is CELL_PROGRAM or CELL_CHAPTER_PROGRAM */ + if (thiscell->ischapter == CELL_CHAPTER_PROGRAM) + va->allpgcs[i]->numchapters++; + if (va->allpgcs[i]->numprograms >= 256) + { + fprintf + ( + stderr, + "ERR: PGC %d has too many programs (%d, 256 allowed)\n", + i + 1, + va->allpgcs[i]->numprograms + ); + exit(1); + } /*if*/ + // if numprograms<256, then numchapters<256, so + // no need to doublecheck + } /*if*/ + } /*for*/ + } /*for; for*/ + } /*MarkChapters*/ + +static pts_t getcellaudiopts(const struct vobgroup *va,int vcid,int ach,int w) +{ + const struct vob *v=va->vobs[(vcid>>8)-1]; + const struct audchannel *a=&v->audch[ach]; + int ai=0; + + assert((vcid&255)==(w?v->numcells:1)); + if( w ) + ai=a->numaudpts-1; + return a->audpts[ai].pts[w]; +} + +static int hasaudio(const struct vobgroup *va,int vcid,int ach,int w) +{ + const struct vob *v=va->vobs[(vcid>>8)-1]; + const struct audchannel *a=&v->audch[ach]; + + assert((vcid&255)==(w?v->numcells:1)); + + return a->numaudpts!=0; +} + +static pts_t getcellvideopts(const struct vobgroup *va,int vcid,int w) +{ + const struct vob *v=va->vobs[(vcid>>8)-1]; + int vi=0; + + assert((vcid&255)==(w?v->numcells:1)); + if( w ) + vi=v->numvobus-1; + // we use sectpts instead of videopts because sometimes you will + // present the last video frame for a long time; we want to know + // the last presented time stamp: sectpts + return v->vobu[vi].sectpts[w]; +} + +static pts_t calcaudiodiff(const struct vobgroup *va,int vcid,int ach,int w) +{ + return getcellvideopts(va,vcid,w)-getcellaudiopts(va,vcid,ach,w); +} + +int calcaudiogap(const struct vobgroup *va,int vcid0,int vcid1,int ach) +{ + if( vcid0==-1 || vcid1==-1 ) + return 0; + if( vcid1==vcid0+1 ) + return 0; + if( (vcid1&255)==1 && va->vobs[(vcid0>>8)-1]->numcells==(vcid0&255) ) { + int g1,g2; + + // there is no discontinuity if there is no audio in the second half + if( !hasaudio(va,vcid1,ach,0) ) + return 0; + + // we have problems if the second half has audio but the first doesn't + if( !hasaudio(va,vcid0,ach,1) && hasaudio(va,vcid1,ach,0) ) { + fprintf(stderr,"WARN: Transition from non-audio to audio VOB; assuming discontinuity.\n"); + return 1; + } + + g1=calcaudiodiff(va,vcid0,ach,1); + g2=calcaudiodiff(va,vcid1,ach,0); + return g1!=g2; + } + fprintf(stderr,"WARN: Do not know how to compute the audio gap between '%s' and '%s', assuming discontinuity.\n",va->vobs[(vcid0>>8)-1]->fname,va->vobs[(vcid1>>8)-1]->fname); + return 1; +} + +void FixVobus(const char *fbase,const struct vobgroup *va,const struct workset *ws,vtypes ismenu) + /* fills in the NAV packs (i.e. PCI and DSI packets) for each VOBU in the + already-written output VOB files. */ + { + int outvob = -1; + int vobuindex, j, pn, fnum = -2; + pts_t scr; + int vff, vrew; + int totvob, curvob; /* for displaying statistics */ + + totvob = 0; + for (pn = 0; pn < va->numvobs; pn++) + totvob += va->vobs[pn]->numvobus; + curvob = 0; + + for (pn = 0; pn < va->numvobs; pn++) + { + const struct vob * const thisvob = va->vobs[pn]; + for (vobuindex = 0; vobuindex < thisvob->numvobus; vobuindex++) + { + const struct vobuinfo * const thisvobu = &thisvob->vobu[vobuindex]; + static unsigned char buf[2048]; + + if (thisvobu->fnum != fnum) + { + /* time to start a new output file */ + char fname[200]; + if (outvob >= 0) + flushclose(outvob); + fnum = thisvobu->fnum; + if (fbase) + { + if (fnum == -1) + strcpy(fname, fbase); + else + sprintf(fname, "%s_%d.VOB", fbase, fnum); + outvob = open(fname, O_WRONLY | O_BINARY); + if (outvob < 0) + { + fprintf + ( + stderr, + "\nERR: Error %d opening %s: %s\n", + errno, + fname, + strerror(errno) + ); + exit(1); + } /*if*/ + } /*if*/ + } /*if*/ + + memcpy(buf, thisvobu->sectdata, 0x26); + write4(buf + 0x26, 0x100 + MPID_PRIVATE2); // private stream 2 + write2(buf + 0x2a, 0x3d4); // length + buf[0x2c] = 0; /* substream ID, 0 = PCI */ + memset(buf + 0x2d,0, 0x400 - 0x2d); + write4(buf + 0x400, 0x100 + MPID_PRIVATE2); // private stream 2 + write2(buf + 0x404, 0x3fa); // length + buf[0x406] = 1; /* substream ID, 1 = DSI */ + memset(buf + 0x407, 0, 0x7ff - 0x407); + + scr = readscr(buf + 4); + + write4(buf + 0x2d, thisvobu->sector); /* sector number of this block */ + /* buf[0x35 .. 0x38] -- prohibited user ops -- none for now */ + write4(buf + 0x39, thisvobu->sectpts[0]); /* start presentation time (vobu_s_ptm) */ + write4(buf + 0x3d, thisvobu->sectpts[1]); /* end presentation time (vobu_e_ptm) */ + if (thisvobu->hasseqend) // if sequence_end_code + write4(buf + 0x41, thisvobu->videopts[1]); // vobu_se_e_ptm + write4 + ( + buf + 0x45, + buildtimeeven + ( + va, + thisvobu->sectpts[0] - thisvob->vobu[thisvobu->firstvobuincell].sectpts[0] + ) // total guess + ); + /* c_eltm -- BCD cell elapsed time + frame rate */ + + if (thisvob->progchain->numbuttons) + { + /* fill in PCI packet with button info */ + const struct pgc * const pg = thisvob->progchain; + int mask = getsubpmask(&va->vd), nrgrps, grp; + char idmap[3]; + + write2(buf + 0x8d, 1); /* highlight status = all new highlight information for this VOBU */ + write4(buf + 0x8f, thisvob->vobu[0].sectpts[0]); /* highlight start time */ + write4(buf + 0x93, -1); /* highlight end time */ + write4(buf + 0x97, -1); /* button selection end time (ignore user after this) */ + + nrgrps = 0; + write2(buf + 0x9b, 0); /* button groupings, none to begin with */ + for (j = 0; j < 4; j++) + if (mask & (1 << j)) + { + assert(nrgrps < 3); + idmap[nrgrps] = j; + write2 + ( + buf + 0x9b, + read2(buf + 0x9b) + + + 0x1000 /* add another button group */ + + + ( + ((1 << j) >> 1) + /* panscan/letterbox/normal bit for widescreen, + 0 for narrowscreen */ + << + (2 - nrgrps) * 4 + /* bit-shifted into appropriate button group nibble */ + ) + ); + nrgrps++; + } /*if; for*/ + assert(nrgrps > 0); + + buf[0x9e] = pg->numbuttons; /* number of buttons */ + buf[0x9f] = pg->numbuttons; /* number of numerically-selected buttons */ + memcpy(buf + 0xa3, thisvob->buttoncoli, 24); + for (grp = 0; grp < nrgrps; grp++) + { + unsigned char *boffs = buf + 0xbb + 18 * (grp * 36 / nrgrps); + /* divide BTN_IT entries equally among all groups -- does this matter? */ + const int sid = pg->subpmap[0][(int)idmap[grp]] & 127; + + for (j = 0; j < pg->numbuttons; j++) + /* fixme: no check against overrunning allocated portion of BTN_IT array? */ + { + static unsigned char compilebuf[128 * 8], *rbuf; + const struct button * const b = pg->buttons + j; + const struct buttoninfo *bi; + int k; + + for (k = 0; k < b->numstream; k++) + if (b->stream[k].substreamid == sid) + break; + if (k == b->numstream) + continue; /* no matching button def for this substream */ + bi = &b->stream[k]; + + /* construct BTN_IT -- Button Information Table entry */ + boffs[0] = (bi->grp * 64) | (bi->x1 >> 4); + boffs[1] = (bi->x1 << 4) | (bi->x2 >> 8); + boffs[2] = bi->x2; + boffs[3] = (bi->autoaction ? 64 : 0) | (bi->y1 >> 4); + boffs[4] = (bi->y1 << 4) | (bi->y2 >> 8); + boffs[5] = bi->y2; + boffs[6] = findbutton(pg, bi->up, (j == 0) ? pg->numbuttons : j); + boffs[7] = findbutton(pg, bi->down, (j + 1 == pg->numbuttons) ? 1 : j + 2); + boffs[8] = findbutton(pg, bi->left, (j == 0) ? pg->numbuttons : j); + boffs[9] = findbutton(pg, bi->right, (j + 1 == pg->numbuttons) ? 1 : j + 2); + rbuf = vm_compile(compilebuf, compilebuf, ws, pg->pgcgroup, pg, b->commands, ismenu); + if (rbuf - compilebuf == 8) + { + memcpy(boffs + 10, compilebuf, 8); + } + else if (allowallreg) + { + fprintf + ( + stderr, + "ERR: Button command is too complex to fit in one instruction," + " and allgprm==true.\n" + ); + exit(1); + } + else + write8(boffs + 10, 0x71, 0x01, 0x00, 0x0F, 0x00, j + 1, 0x00, 0x0d); + // g[15] = j && linktailpgc + /* transfer to full instruction sequence which will be + generated by dvdpgc.c:genpgc */ + boffs += 18; + } /*for j*/ + } /*for grp*/ + } /* if thisvob->progchain->numbuttons */ + + /* fill in DSI packet */ + write4(buf + 0x407, scr); + write4(buf + 0x40b, thisvobu->sector); // current lbn + if (thisvobu->numref > 0) + { + /* up to three reference frame relative end blocks */ + for (j = 0; j < thisvobu->numref; j++) + write4(buf + 0x413 + j * 4, thisvobu->lastrefsect[j] - thisvobu->sector); + for (; j < 3; j++) /* duplicate last one if less than 3 */ + write4(buf + 0x413 + j * 4, thisvobu->lastrefsect[thisvobu->numref - 1] - thisvobu->sector); + } /*if*/ + write2(buf + 0x41f, thisvobu->vobcellid >> 8); /* VOB number */ + buf[0x422] = thisvobu->vobcellid; /* cell number within VOB */ + write4(buf + 0x423, read4(buf + 0x45)); /* cell elapsed time, BCD + frame rate */ + /* interleaved unit stuff not supported for now */ + write4(buf + 0x433, thisvob->vobu[0].sectpts[0]); + /* time of first video frame in first GOP of VOB */ + write4(buf + 0x437, thisvob->vobu[thisvob->numvobus - 1].sectpts[1]); + /* time of last video frame in last GOP of VOB */ + /* audio gap stuff not supported for now */ + /* seamless angle stuff not supported for now */ + write4 + ( + buf + 0x4f1, + getsect(thisvob, vobuindex, findnextvideo(thisvob, vobuindex, 1), 0, 0xbfffffff) + ); + /* offset to next VOBU with video */ + /* offset to next VOBU at various times forward filled in below */ + write4(buf + 0x541, getsect(thisvob, vobuindex, vobuindex + 1, 0, 0x3fffffff)); + /* offset to next VOBU */ + write4(buf + 0x545, getsect(thisvob, vobuindex, vobuindex - 1, 0, 0x3fffffff)); + /* offset to previous VOBU */ + /* offset to previous VOBU at various times backward filled in below */ + write4 + ( + buf + 0x595, + getsect(thisvob, vobuindex, findnextvideo(thisvob, vobuindex, -1), 0, 0xbfffffff) + ); + /* offset to previous VOBU with video */ + for (j = 0; j < va->numaudiotracks; j++) + { + int s = getaudch(va, j); + if (s >= 0) + s = findaudsect(thisvob, s, thisvobu->sectpts[0], thisvobu->sectpts[1]); + if (s >= 0) + { + s = s - thisvobu->sector; + if (s > 0x1fff || s < -(0x1fff)) + { + fprintf + ( + stderr, + "\nWARN: audio sector out of range: %d (vobu #%d, pts ", + s, + vobuindex + ); + printpts(thisvobu->sectpts[0]); + fprintf(stderr, ")\n"); + s = 0; + } /*if*/ + if (s < 0) + s = (-s) | 0x8000; /* absolute value + backward-direction flag */ + } + else + s = 0x3fff; /* no more audio for this stream */ + write2(buf + 0x599 + j * 2, s); + /* relative offset to first audio packet in this stream for this VOBU */ + } /*for*/ + for (j = 0; j < va->numsubpicturetracks; j++) + { + const struct audchannel * const ach = &thisvob->audch[j | 32]; + int s; + if (ach->numaudpts) + { + int id = findspuidx(thisvob, j | 32, thisvobu->sectpts[0]); + // if overlaps A, point to A + // else if (A before here or doesn't exist) and (B after here or doesn't exist), + // point to here + // else point to B + if + ( + id >= 0 + && + ach->audpts[id].pts[0] < thisvobu->sectpts[1] + && + ach->audpts[id].pts[1] >= thisvobu->sectpts[0] + ) + s = findvobubysect(thisvob, ach->audpts[id].asect); + else if + ( + (id < 0 || ach->audpts[id].pts[1] < thisvobu->sectpts[0]) + && + ( + id + 1 == ach->numaudpts + || + ach->audpts[id + 1].pts[0] >= thisvobu->sectpts[1] + ) + ) + s = vobuindex; + else + s = findvobubysect(thisvob, ach->audpts[id + 1].asect); + id = (s < vobuindex); + s = getsect(thisvob, vobuindex, s, 0, 0x7fffffff) & 0x7fffffff; + if (!s) /* same VOBU */ + s = 0x7fffffff; + /* indicates current or later VOBU, no explicit forward offsets */ + if (s != 0x7fffffff && id) + s |= 0x80000000; /* indicates offset to prior VOBU */ + } + else + s = 0; /* doesn't exist */ + write4(buf + 0x5a9 + j * 4, s); + /* relative offset to VOBU (NAV pack) containing subpicture data + for this stream for this VOBU */ + } /*for*/ + write4(buf + 0x40f, thisvobu->lastsector - thisvobu->sector); + /* relative offset to last sector of VOBU */ + vff = vobuindex; + vrew = vobuindex; + for (j = 0; j < 19; j++) + { + /* fill in offsets to next/previous VOBUs at various time steps */ + int nff, nrew; + nff = findvobu + ( + thisvob, + thisvobu->sectpts[0] + timeline[j] * DVD_FFREW_HALFSEC, + thisvobu->firstvobuincell, + thisvobu->lastvobuincell + ); + // a hack -- the last vobu in the cell shouldn't have any forward ptrs + // EXCEPT this hack violates both Grosse Pointe Blank and Bullitt -- what was I thinking? + // if (i == thisvobu->lastvobuincell) + // nff = i + 1; + nrew = findvobu + ( + thisvob, + thisvobu->sectpts[0] - timeline[j] * DVD_FFREW_HALFSEC, + thisvobu->firstvobuincell, + thisvobu->lastvobuincell + ); + /* note table entries are in order of decreasing time step */ + write4 + ( + buf + 0x53d - j * 4, /* forward jump */ + getsect(thisvob, vobuindex, nff, j >= 15 && nff > vff + 1, 0x3fffffff) + ); + write4 + ( + buf + 0x549 + j * 4, /* backward jump */ + getsect(thisvob, vobuindex, nrew, j >= 15 && nrew < vrew - 1, 0x3fffffff) + ); + vff = nff; + vrew = nrew; + } /*for*/ + + /* NAV pack all done, write it out */ + if (outvob != -1) + { + if (lseek(outvob, thisvobu->fsect * 2048, SEEK_SET) == (off_t)-1) + /* where the NAV pack should go */ + { + fprintf(stderr, "ERR: Error %d -- %s -- seeking in output VOB\n", errno, strerror(errno)); + exit(1); + } /*if*/ + if (write(outvob, buf, 2048) != 2048) + { + fprintf + ( + stderr, + "ERR: Error %d -- %s -- writing NAV PACK to output VOB\n", + errno, + strerror(errno) + ); + exit(1); + } /*if*/ + /* update it */ + } /*if*/ + curvob++; + if (!(curvob & 15)) /* time for another progress update */ + fprintf + ( + stderr, + "STAT: fixing VOBU at %dMB (%d/%d, %d%%)\r", + thisvobu->sector / 512, + curvob + 1, + totvob, + curvob * 100 / totvob + ); + } /*for vobuindex*/ + } /*for pn*/ + if (outvob != -1) + flushclose(outvob); + if (totvob > 0) + fprintf(stderr, "STAT: fixed %d VOBUs ", totvob); + fprintf(stderr, "\n"); + } /*FixVobus*/ +
View file
lxdvdrip-1.77.tar.bz2/dvdauthor/0.7.0/spuunmux.c
Added
@@ -0,0 +1,1598 @@ +/* + spuunmux mainline +*/ +/* + * Copyright (C) 2002, 2003 Jan Panteltje <panteltje@yahoo.com>, + * + * Modified by Zachary Brewster-Geisz, 2003, to work on big-endian + * machines. + * + * Modified by Henry Mason, 2003, to use both PNG and BMP, and to use + * the dvdauthor submux format. + * + * Modified and copy right Jan Panteltje 2002 + * 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. + * + * With many changes by Scott Smith (trckjunky@users.sourceforge.net) + * + * Svcd decoding by Giacomo Comes <encode2mpeg@users.sourceforge.net> + * + * 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 + */ + +#include "config.h" +#include "compat.h" + +#include <fcntl.h> + +#include <netinet/in.h> + +#include <png.h> + +#include "rgb.h" +#include "common.h" +#include "conffile.h" + +#define CBUFSIZE 65536 /* big enough for any MPEG packet */ +#define PSBUFSIZE 10 + +static unsigned int add_offset; + +static int debug = 0; + +static int video_format = VF_NONE; +static bool full_size = false; +static unsigned int pts, spts, subi, subs, subno; +static int ofs, ofs1; + /* offsets from beginning of SPU to bottom and top field data set by last SPU_SET_DSPXA command */ +static unsigned char sub[65536]; +static unsigned char next_bits; +static const char *base_name; +static unsigned int have_bits; +static FILE *fdo; +static unsigned char svcd_adjust; + +static colorspec + current_palette[16]; /* current PGC colour table, alpha unused */ + +struct spu /* data for one subpicture unit (SPU) */ + { + unsigned char *img; /* image data */ + unsigned int x0, y0, xd, yd; /* display bounds */ + unsigned int pts[2]; /* start time, end time */ + unsigned int subno; /* index used for generating unique filenames */ + unsigned int force_display; + unsigned int nummap; /* length of map array */ + struct colormap *map; + /* array where entry 0 is for colours as specified in SPU, other entries + are for button colours as specified in PGC, so if they overlap, the + last entry takes precedence */ + struct spu *next; /* linked list */ + }; + +static struct spu + *pending_spus = 0; + +struct button /* information about a button */ + { + char *name; + bool autoaction; + int x1, y1, x2, y2; + char *up, *down, *left, *right; /* names of neighbouring buttons */ + int grp; /* which group button belongs to */ + }; + +struct dispdetails /* information about button grouping */ + { + int pts[2]; /* start time, end time */ + int numpal; /* nr used entries in palette */ + uint32_t palette[16]; /* RGB colours */ + int numcoli; /* nr of SL_COLI entries present, not checked! */ + uint32_t coli[6]; /* up to 3 8-byte SL_COLI entries */ + int numbuttons; /* length of buttons array */ + struct button *buttons; /* array */ + struct dispdetails *next; /* linked list */ + }; + +static struct dispdetails + *pending_buttons = 0; + +struct colormap /* for determining which colours take precedence in overlapping areas */ + { + uint16_t color; /* four 4-bit colour indexes */ + uint16_t contrast; /* four 4-bit contrast (transparency) values */ + int x1, y1, x2, y2; /* bounds of area over which entries are valid */ + }; + +static unsigned int read4(const unsigned char *p) + /* decodes 4 bytes as a big-endian integer starting at p. */ + { + return + p[0] << 24 + | + p[1] << 16 + | + p[2] << 8 + | + p[3]; + } /*read4*/ + +static unsigned int read2(const unsigned char *p) + /* decodes 2 bytes as a big-endian integer starting at p. */ + { + return + p[0] << 8 + | + p[1]; + } /*read2*/ + +static char *readpstr(const unsigned char *b, int *i) + /* extracts a null-terminated string beginning at b[*i], advances *i past it and returns + a copy of the string. */ + { + char * const s = strdup((const char *)b + i[0]); + i[0] += strlen(s) + 1; + return s; + } /*readpstr*/ + +static unsigned char get_next_bits() + /* returns next nibble from sub at offset ofs. */ + { + if (!have_bits) + { + next_bits = sub[ofs++]; + have_bits = true; + return next_bits >> 4; + } /*if*/ + have_bits = false; + return next_bits & 15; + } /*get_next_bits*/ + +static unsigned char get_next_svcdbits() + /* returns next two bits from sub at offset ofs. */ + { + switch (have_bits) + { + case 0: + ++have_bits; + return sub[++ofs] >> 6; + break; + case 1: + ++have_bits; + return (sub[ofs] & 0x30) >> 4; + break; + case 2: + ++have_bits; + return (sub[ofs] & 0x0c) >> 2; + break; + default: + have_bits = 0; + return sub[ofs] & 0x03; + break; + } /*switch*/ + } /*get_next_svcdbits*/ + +static unsigned int getpts(const unsigned char *buf) + /* decodes a presentation time stamp (PTS) beginning at location buf. */ + { + if + ( + !(buf[1] & 0xc0) + || + buf[2] < 4 + || + (buf[3] & 0xe1) != 0x21 + || + (buf[5] & 1) != 1 + || + (buf[7] & 1) != 1 + ) + return -1; /* doesn't look like a proper PTS */ + return + (buf[7] >> 1) + + + ((unsigned int)buf[6] << 7) + + + (((unsigned int)buf[5] & 254) << 14) + + + ((unsigned int)buf[4] << 22) + + + (((unsigned int)buf[3] & 14) << 29); + } /*getpts*/ + +static void addspu(struct spu *s) + /* appends s onto pending_spus. */ + { + struct spu **f = &pending_spus; + while (*f) + f = &f[0]->next; + *f = s; + } /*addspu*/ + +static void add_pending_buttons(struct dispdetails *d) + /* appends d onto pending_buttons. */ + { + struct dispdetails **dp = &pending_buttons; + while (*dp) + dp = &dp[0]->next; + *dp = d; + } /*add_pending_buttons*/ + +static int dvddecode() + /* decodes DVD-Video subpicture data from sub and appends a new entry containing + the results onto pending_spus. */ + { + unsigned int io; + uint16_t total_spu_size, dsize, thiscmdoffset, nextcmdoffset, i, x, y, t; + unsigned char c; + struct spu *newspu; + total_spu_size = read2(sub); /* SPDSZ = size of SPU */ + dsize = read2(sub + 2); /* SP_DCSQTA = offset to SP_DCSQT */ + ofs = -1; + if (debug > 1) + fprintf(stderr, "packet: %d bytes, first block offset=%d\n", total_spu_size, dsize); + newspu = malloc(sizeof(struct spu)); + memset(newspu, 0, sizeof(struct spu)); + newspu->subno = subno++; + newspu->pts[0] = newspu->pts[1] = -1; + newspu->nummap = 1; + newspu->map = malloc(sizeof(struct colormap)); + memset(newspu->map, 0, sizeof(struct colormap)); + newspu->map[0].x2 = 0x7fffffff; + newspu->map[0].y2 = 0x7fffffff; + i = dsize + 4; /* start of commands */ + thiscmdoffset = dsize; + nextcmdoffset = read2(sub + thiscmdoffset + 2); + if (nextcmdoffset < dsize) + { + if (debug > 0) + { + fprintf + ( + stderr, + "invalid control header nextcommand=%d dsize=%d!\n", + nextcmdoffset, + dsize + ); + } /*if*/ + nextcmdoffset = thiscmdoffset; + } /*if*/ + t = read2(sub + dsize); /* SP_DCSQ_STM = delay in 90kHz units / 1024 before executing commands */ + if (debug > 2) + fprintf + ( + stderr, + "\tBLK(%5d): time offset: %d; next: %d\n", + dsize, t, read2(sub + dsize + 2) + ); + /* decode the commands, including finding out where the image data is */ + while (i < total_spu_size) + { + c = sub[i]; /* get next command */ + switch (c) + { + case SPU_FSTA_DSP: + if (debug > 4) + fprintf(stderr, "\tcmd(%5d): force start display\n", i); + newspu->force_display = true; + // fall through + case SPU_STA_DSP: + if (debug > 4 && c == SPU_STA_DSP) + fprintf(stderr, "\tcmd(%5d): start display\n", i); + i++; + newspu->pts[0] = t * 1024 + spts; + break; + + case SPU_STP_DSP: + if (debug > 4) + fprintf(stderr, "\tcmd(%5d): end display\n", i); + newspu->pts[1] = t * 1024 + spts; + i++; + break; + + case SPU_SET_COLOR: + if (debug > 4) + fprintf(stderr, "\tcmd(%5d): palette=%02x%02x\n", i, sub[i + 1], sub[i + 2]); + newspu->map[0].color = read2(sub + i + 1); + i += 3; + break; + + case SPU_SET_CONTR: + if (debug > 4) + fprintf(stderr, "\tcmd(%5d): transparency=%02x%02x\n", i, sub[i + 1], sub[i + 2]); + newspu->map[0].contrast = read2(sub + i + 1); + i += 3; + break; + + case SPU_SET_DAREA: + newspu->x0 = ((((unsigned int)sub[i + 1]) << 4) + (sub[i + 2] >> 4)); + newspu->xd = (((sub[i + 2] & 0x0f) << 8) + sub[i + 3]) - newspu->x0 + 1; + newspu->y0 = ((((unsigned int)sub[i + 4]) << 4) + (sub[i + 5] >> 4)); + newspu->yd = (((sub[i + 5] & 0x0f) << 8) + sub[i + 6]) - newspu->y0 + 1; + if (debug > 4) + fprintf + ( + stderr, + "\tcmd(%5d): image corner=%d,%d, size=%d,%d\n", + i, newspu->x0, newspu->y0, newspu->xd, newspu->yd + ); + i += 7; + break; + + case SPU_SET_DSPXA: + if (ofs >= 0) + fprintf(stderr, "WARN: image pointer already supplied for this subpicture\n"); + /* not necessarily wrong, it's just I can't handle it */ + ofs = read2(sub + i + 1); /* offset to top field data */ + ofs1 = read2(sub + i + 3); /* offset to bottom field data */ + if (debug > 4) + fprintf(stderr, "\tcmd(%5d): image offsets=%d,%d\n", i, ofs, ofs1); + i += 5; + break; + + case SPU_CMD_END: + if (thiscmdoffset == nextcmdoffset) /* no next SP_DCSQ */ + { + if (debug > 4) + { + fprintf(stderr, "cmd: last end command\n"); + if (i + 1 < total_spu_size) + { + fprintf + ( + stderr, + "data present after last command (%d bytes, size=%d)\n", + total_spu_size - (i + 1), + total_spu_size + ); + } /*if*/ + } /*if*/ + i = total_spu_size; /* indicate I'm finished */ + break; + } /*if*/ + if (debug > 4) + fprintf(stderr, "\tcmd(%5d): end cmd\n", i); + /* another SP_DCSQT follows */ + thiscmdoffset = nextcmdoffset; + nextcmdoffset = read2(sub + thiscmdoffset + 2); + if (nextcmdoffset < dsize) + { + if (debug > 0) + { + fprintf + ( + stderr, + "invalid control header nextcommand=%d dsize=%d!\n", + nextcmdoffset, + dsize + ); + } /*if*/ + nextcmdoffset = thiscmdoffset; + i = total_spu_size; /* force an end to all this */ + break; + } /*if*/ + t = read2(sub + thiscmdoffset); /* SP_DCSQ_STM = delay in 90kHz units / 1024 before executing commands */ + if (debug > 4) + { + fprintf(stderr, "\tcmd(%5d): end cmd\n", i); + fprintf(stderr, "\tBLK(%5d): time offset: %d; next: %d\n", i + 1, t, read2(sub + i + 3)); + } /*if*/ + if (debug > 4 && i + 1 < thiscmdoffset) + { + fprintf(stderr, "next packet jump: %d bytes\n", thiscmdoffset - (i + 1)); + } /*if*/ + i = thiscmdoffset + 4; /* start of next lot of commands */ + break; + + /* case SPU_CHG_COLCON: */ /* fixme: not handled */ + default: + if (debug > 4) + fprintf(stderr, "\tcmd(%5d): 0x%x\n", i, c); + if (debug > 0) + fprintf(stderr, "invalid sequence in control header (%02x)!\n", c); + return -1; + } /*switch*/ + } /*while*/ + + /* now to decode the actual image data */ + have_bits = false; + x = y = 0; + io = 0; + newspu->img = malloc(newspu->xd * newspu->yd); + if (ofs < 0 && y < newspu->yd) + { + fprintf(stderr, "WARN: No image data supplied for this subtitle\n"); + } + else + { + /* decode image data */ + while (ofs < dsize && y < newspu->yd) + { + i = get_next_bits(); + if (i < 4) + { + i = (i << 4) + get_next_bits(); + if (i < 16) + { + i = (i << 4) + get_next_bits(); + if (i < 0x40) + { + i = (i << 4) + get_next_bits(); + if (i < 4) + { + i = i + (newspu->xd - x) * 4; /* run ends at end of line */ + } /*if*/ + } /*if*/ + } /*if*/ + } /*if*/ + c = i & 3; /* pixel value */ + i = i >> 2; /* count */ + while (i--) + { + newspu->img[io++] = c; + if (++x == newspu->xd) + { + /* end of scanline */ + y += 2; + x = 0; + if (y >= newspu->yd && !(y & 1)) + { + /* end of top (odd) field, now do bottom (even) field */ + y = 1; + io = newspu->xd; + ofs = ofs1; + } + else + io += newspu->xd; /* next scanline */ + have_bits = false; + } /*if*/ + } /*while*/ + } /*while*/ + } /*if*/ + if (newspu->pts[0] == -1) + return 0; /* fixme: free newspu or report error? */ + newspu->pts[0] += add_offset; + if (newspu->pts[1] != -1) + newspu->pts[1] += add_offset; + addspu(newspu); + return 0; + } /*dvddecode*/ + + /* + * from Y -> R + * from V -> G + * from U -> B + */ + +static void ycrcb_to_rgb(int *Y, int *Cr, int *Cb) +{ + int R, G, B; + R = YCrCb2R(*Y,*Cr,*Cb); + G = YCrCb2G(*Y,*Cr,*Cb); + B = YCrCb2B(*Y,*Cr,*Cb); + *Y = R; + *Cr = G; + *Cb = B; +} + +static void absorb_palette(const struct dispdetails *d) + /* extracts the colour palette from d and puts it in RGB format into current_palette. */ + { + int i; + for (i = 0; i < d->numpal; i++) + { + int Y, Cr, Cb; + Y = d->palette[i] >> 16 & 255; + Cr = d->palette[i] >> 8 & 255; + Cb = d->palette[i] & 255; + current_palette[i].r = YCrCb2R(Y, Cr, Cb); + current_palette[i].g = YCrCb2G(Y, Cr, Cb); + current_palette[i].b = YCrCb2B(Y, Cr, Cb); + } /*for*/ + } /*absorb_palette*/ + +static void pluck_pending_buttons() + /* removes the head of pending_buttons, copies its palette into current_palette, + and gets rid of it. */ + { + struct dispdetails * const d = pending_buttons; + int i; + pending_buttons = d->next; + absorb_palette(d); + for (i = 0; i < d->numbuttons; i++) + { + free(d->buttons[i].name); + free(d->buttons[i].up); + free(d->buttons[i].down); + free(d->buttons[i].left); + free(d->buttons[i].right); + } /*for*/ + free(d->buttons); + free(d); + } /*pluck_pending_buttons*/ + +static unsigned char cmap_find + ( + int x, + int y, + const struct colormap *map, /* array */ + int nummap, /* length of map array */ + int ci /* pixel value */ + ) + /* returns the colour index (low nibble) and contrast (high nibble) of the + specified pixel, as determined from the highest-numbered entry of map that + covers its coordinates. Returns 0 if no entry is found. */ + { + int i; + unsigned char cix = 0; + for (i = 0; i < nummap; i++) + /* fixme: why not just start from the other end and terminate when a match is found? */ + if + ( + x >= map[i].x1 + && + y >= map[i].y1 + && + x <= map[i].x2 + && + y <= map[i].y2 + ) + cix = + (map[i].contrast >> ci * 4 & 15) << 4 + | + map[i].color >> ci * 4 & 15; + return cix; + } /*cmap_find*/ + +static int write_png + ( + const char *file_name, + const struct spu *s, + const struct colormap *map, /* array of entries for assigning colours to overlapping areas */ + int nummap /* length of map array */ + ) + /* outputs the contents of s as a PNG file, converting pixels to colours + according to map. */ + { + unsigned int a, x, y; + bool nonzero; + unsigned char *out_buf, *temp; + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + const unsigned short subwidth = svcd_adjust ? 704 : 720; + const unsigned short subheight = video_format == VF_NTSC ? 480 : 576; + temp = out_buf = malloc(s->xd * s->yd * 4); + nonzero = false; + for (y = 0; y < s->yd; y++) + { + for (x = 0; x < s->xd; x++) + { + const unsigned char cix = + cmap_find(x + s->x0, y + s->y0, map, nummap, s->img[y * s->xd + x]); + *temp++ = current_palette[cix & 15].r; + *temp++ = current_palette[cix & 15].g; + *temp++ = current_palette[cix & 15].b; + *temp++ = (cix >> 4) * 17; + if (cix & 0xf0) + nonzero = true; + } /*for*/ + } /*for*/ + if (!nonzero) + { + /* all transparent, don't bother writing any image */ + free(out_buf); + return 1; + } /*if*/ + fp = fopen(file_name, "wb"); + if (!fp) + { + fprintf(stderr, "ERR: unable to open/create file: %s\n", file_name); + return -1; + } /*if*/ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + return -1; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return -1; + } /*if*/ + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return -1; + } /*if*/ + png_init_io(png_ptr, fp); + /* turn on or off filtering, and/or choose specific filters */ + png_set_filter(png_ptr, 0, PNG_FILTER_NONE); + /* set the zlib compression level */ + png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + if (full_size) + { + png_set_IHDR + ( + /*png_ptr =*/ png_ptr, + /*info_ptr =*/ info_ptr, + /*width =*/ subwidth, + /*height =*/ subheight, + /*bit_depth =*/ 8, + /*color_type =*/ PNG_COLOR_TYPE_RGB_ALPHA, + /*interlace_method =*/ PNG_INTERLACE_NONE, + /*compression_method =*/ PNG_COMPRESSION_TYPE_DEFAULT, + /*filter_method =*/ PNG_FILTER_TYPE_DEFAULT + ); + } + else + { + png_set_IHDR + ( + /*png_ptr =*/ png_ptr, + /*info_ptr =*/ info_ptr, + /*width =*/ s->xd, + /*height =*/ s->yd, + /*bit_depth =*/ 8, + /*color_type =*/ PNG_COLOR_TYPE_RGB_ALPHA, + /*interlace_method =*/ PNG_INTERLACE_NONE, + /*compression_method =*/ PNG_COMPRESSION_TYPE_DEFAULT, + /*filter_method =*/ PNG_FILTER_TYPE_DEFAULT + ); + } /*if*/ + png_write_info(png_ptr, info_ptr); + png_set_packing(png_ptr); + if (out_buf != NULL) + { + unsigned int x0 = s->x0, y0 = s->y0, xd = s->xd, yd = s->yd; + png_byte *row_pointers[576]; /* big enough for both PAL and NTSC */ + if (full_size) + { + unsigned char *image; + temp = out_buf; + image = malloc(subwidth * subheight * 4); + memset(image, 0, subwidth * subheight * 4); // fill image full transparent + // insert image on the correct position + for (y = s->y0; y < s->y0 + s->yd; y++) + { + unsigned char *to = &image[y * subwidth * 4 + s->x0 * 4]; + if (y >= subheight) + { + fprintf(stderr, "WARN: subtitle %s truncated\n", file_name); + break; + } /*if*/ + for (x = 0; x < s->xd; x++) + { + *to++ = *temp++; + *to++ = *temp++; + *to++ = *temp++; + *to++ = *temp++; + } /*for*/ + } /*for*/ + y0 = 0; + x0 = 0; + yd = subheight; + xd = subwidth; + free(out_buf); + out_buf = image; + } /*if*/ + for (a = 0; a < yd; a++) + { + row_pointers[a] = out_buf + a * (xd * 4); + } /*for*/ + png_write_image(png_ptr, row_pointers); + png_write_end(png_ptr, info_ptr); + free(out_buf); + } /*if*/ + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return 0; + } /*write_png*/ + +static void write_pts(const char *preamble, int pts) + /* outputs a formatted representation of a timestamp to fdo. */ + { + fprintf + ( + fdo, + " %s=\"%02d:%02d:%02d.%02d\"", + preamble, + (pts / (60 * 60 * 90000)) % 24, + (pts / (60 * 90000)) % 60, + (pts / 90000) % 60, + (pts / 900) % 100 + ); + } /*write_pts*/ + +/* + copy the content of buf to expbuf converting '&' '<' '>' '"' + expbuf must be big enough to contain the expanded buffer +*/ +static void xml_buf + ( + unsigned char *expbuf, + const unsigned char *buf + ) + { + const unsigned char *p; + do + { + switch (*buf) + { + case '&': + p = (const unsigned char *)"&"; + break; + case '<': + p = (const unsigned char *)"<"; + break; + case '>': + p = (const unsigned char *)">"; + break; + case '"': + p = (const unsigned char *)"""; + break; + default: + p = NULL; + break; + } /*switch*/ + if (p) + { + while ((*expbuf++ = *p++)) + /* copy the representation */; + --expbuf; + } + else + *expbuf++ = *buf; /* copy as is */ + } + while (*buf++); + } /*xml_buf*/ + +static void write_menu_image + ( + const struct spu *s, + const struct dispdetails *d, + const char *type, /* name of attribute to fill in with name of generated file */ + int offset /* 0 => highlighted, 1 => selected */ + ) + /* outputs the subpicture image with the buttons in the highlighted or selected state. */ + { + unsigned char nbuf[256]; + int nummap = d->numbuttons + 1, i; + struct colormap *map = malloc(sizeof(struct colormap) * nummap); + memset(map, 0, sizeof(struct colormap)); // set the first one blank + map[0].x2 = 0x7fffffff; + map[0].y2 = 0x7fffffff; + for (i = 0; i < d->numbuttons; i++) + { + const uint32_t cc = d->coli[2 * d->buttons[i].grp - 2 + offset]; + map[i + 1].x1 = d->buttons[i].x1; + map[i + 1].y1 = d->buttons[i].y1; + map[i + 1].x2 = d->buttons[i].x2; + map[i + 1].y2 = d->buttons[i].y2; + map[i + 1].color = cc >> 16; + map[i + 1].contrast = cc; + } /*for*/ + sprintf((char *)nbuf, "%s%05d%c.png", base_name, s->subno, type[0]); + if (!write_png((char *)nbuf, s, map, nummap)) + { + unsigned char ebuf[sizeof nbuf * 6]; + xml_buf(ebuf, nbuf); + fprintf(fdo," %s=\"%s\"", type, ebuf); + } /*if*/ + free(map); + } /*write_menu_image*/ + +static void write_spu + ( + const struct spu * curspu, + const struct dispdetails * buttons /* applicable button highlight info, if any */ + ) + /* writes out all information about a subpicture unit as an <spu> tag. */ + { + unsigned char nbuf[256]; + int i; + if (buttons) + absorb_palette(buttons); + fprintf(fdo, "\t\t<spu"); + sprintf((char *)nbuf, "%s%05d.png", base_name, curspu->subno); + if (!write_png((char *)nbuf, curspu, curspu->map, curspu->nummap)) + { + unsigned char ebuf[sizeof nbuf * 6]; + xml_buf(ebuf, nbuf); + fprintf(fdo, " image=\"%s\"", ebuf); + } /*if*/ + if (buttons && buttons->numbuttons) + { + write_menu_image(curspu, buttons, "highlight", 0); + write_menu_image(curspu, buttons, "select", 1); + } /*if*/ + write_pts("start", curspu->pts[0]); + if (curspu->pts[1] != -1) + write_pts("end", curspu->pts[1]); + if (curspu->x0 || curspu->y0) + fprintf(fdo, " xoffset=\"%d\" yoffset=\"%d\"", curspu->x0, curspu->y0); + if (curspu->force_display) + fprintf(fdo, " force=\"yes\""); + if (buttons && buttons->numbuttons) + { + fprintf(fdo, ">\n"); + for (i = 0; i < buttons->numbuttons; i++) + { + const struct button * const b = buttons->buttons + i; + fprintf + ( + fdo, + "\t\t\t<%s name=\"%s\" x0=\"%d\" y0=\"%d\" x1=\"%d\" y1=\"%d\"" + " up=\"%s\" down=\"%s\" left=\"%s\" right=\"%s\" />\n", + b->autoaction ? "action" : "button", b->name, + b->x1, b->y1, b->x2, b->y2, + b->up, b->down, b->left, b->right + ); + } /*for*/ + fprintf(fdo, "\t\t</spu>\n"); + } + else + fprintf(fdo, " />\n"); + } /*write_spu*/ + +static void flushspus(unsigned int lasttime) + /* pops and outputs elements from pending_spus and pending_buttons that start + prior to lasttime. */ + { + while (pending_spus) + { + const struct spu * const curspu = pending_spus; + if (curspu->pts[0] >= lasttime) + return; /* next entry not yet due */ + pending_spus = pending_spus->next; + while + ( + pending_buttons + && + pending_buttons->pts[1] < curspu->pts[0] + && + pending_buttons->pts[1] != -1 + ) + /* merge colours from expired entries into colour table, but otherwise ignore them */ + pluck_pending_buttons(); + if + ( + pending_buttons + && + (pending_buttons->pts[0] < curspu->pts[1] || curspu->pts[1] == -1) + && + (pending_buttons->pts[1] > curspu->pts[0] || pending_buttons->pts[1] == -1) + ) + /* head of pending_buttons overlaps duration of curspu */ + write_spu(curspu, pending_buttons); + else + write_spu(curspu, 0); + free(curspu->img); + free(curspu->map); + free((void *)curspu); + } /*while*/ + } /*flushspus*/ + +#define bps(n,R,G,B) do { current_palette[n].r = R; current_palette[n].g = G; current_palette[n].b = B; } while (false) + +static int svcddecode() + { + unsigned int io; + unsigned short int size, i, x, y; + unsigned char c; + struct spu *s; + int n; + size = read2(sub); + if (debug > 1) + fprintf(stderr, "packet: 0x%x bytes\n", size); + s = malloc(sizeof(struct spu)); + memset(s, 0, sizeof(struct spu)); + s->subno = subno++; + s->pts[0] = spts; + s->pts[1] = -1; + s->nummap = 1; + s->map = malloc(sizeof(struct colormap)); + memset(s->map, 0, sizeof(struct colormap)); + s->map[0].x2 = 0x7ffffff; /* single colour map covers entire picture */ + s->map[0].y2 = 0x7ffffff; + i = 2; + if (sub[i] & 0x08) /* timestamp present */ + { + s->pts[1] = spts + read4(sub + i + 2); + i += 4; + } /*if*/ + i += 2; + s->x0 = read2(sub + i); + s->y0 = read2(sub + i + 2); + s->xd = read2(sub + i + 4); + s->yd = read2(sub + i + 6); + i += 8; + if (debug > 4) + fprintf(stderr, "img ofs: %d,%d size: %d,%d\n", s->x0, s->y0, s->xd, s->yd); + for (n = 0; n < 4; n++) + { + /* collect colour table */ + int r, g, b; + r = sub[i + 0 + n * 4]; + g = sub[i + 1 + n * 4]; + b = sub[i + 2 + n * 4]; + ycrcb_to_rgb(&r, &g, &b); + bps(n, r, g, b); + if (debug > 4) + { + fprintf + ( + stderr, + "palette: %d => 0x%02x 0x%02x 0x%02x 0x%02x => (%d, %d, %d)\n", + n, + sub[i + 0 + n * 4], + sub[i + 1 + n * 4], + sub[i + 2 + n * 4], + sub[i + 3 + n * 4], + r, + g, + b + ); + } /*if*/ + } /*for*/ + s->map[0].color = 0x3210; + s->map[0].contrast = + (sub[i + 3] >> 4) + + + (sub[i + 7] & 0xf0) + + + ((sub[i + 11] & 0xf0) << 4) + + + ((sub[i + 15] & 0xf0) << 8); + if (debug > 4) + fprintf(stderr, "tpalette: %04x\n", s->map[0].contrast); + i += 16; + if (sub[i++] >> 6) + { + if (debug > 4) + { + fprintf + ( + stderr, + "cmd: shift (unsupported), direction=%d time=%f\n", + sub[i - 1] >> 4 & 0x3, + read4(sub) / 90000.0 + ); + } /*if*/ + i += 4; + } /*if*/ + ofs = i + 2 - 1; // get_next_svcdbits will increment ofs by 1 + ofs1 = ofs + read2(sub + i); + i += 2; + if (debug > 4) + fprintf(stderr, "cmd: image offsets 0x%x 0x%x\n", ofs, ofs1); + have_bits = 0; + x = y = 0; + io = 0; + s->img = malloc(s->xd * s->yd); + memset(s->img, 0, s->xd * s->yd); + /* decode the pixels */ + while (ofs < size && y < s->yd) + { + if ((c = get_next_svcdbits()) != 0) + { + s->img[io++] = c; + ++x; + } + else + { + c = get_next_svcdbits() + 1; + x += c; + io += c; + } /*if*/ + if (x >= s->xd) + { + y += 2; + x = 0; + if (y >= s->yd && !(y & 1)) + { + y = 1; + ofs = ofs1; + } /*if*/ + io = s->xd * y; + have_bits = 0; + } /*if*/ + } /*while*/ + s->pts[0] += add_offset; + if (s->pts[1] != -1) + s->pts[1] += add_offset; + addspu(s); + if (debug > 2) + fprintf(stderr, "ofs: 0x%x y: %d\n", ofs, y); + return 0; + } /*svcddecode*/ + +static void usage(void) + { + fprintf(stderr, + "\nUse: %s [options] [input file] [input file] ...\n\n", + "spuunmux"); + fprintf(stderr, "options:\n"); + fprintf(stderr, + "-o <name> base name for script and images [sub]\n"); + fprintf(stderr, + "-v <level> verbosity level [0]\n"); + fprintf(stderr, + "-f resize images to full size [720x576 or 720x480]\n"); + fprintf(stderr, + "-F <format> specify video format, NTSC or PAL\n"); + fprintf(stderr, + "-s <stream> number of the substream to extract [0]\n"); + fprintf(stderr, + "-p <file> name of file with dvd palette [none]\n"); + fprintf(stderr, " if palette file ends with .rgb\n"); + fprintf(stderr, " treated as a RGB\n"); + fprintf(stderr, " else as a YCbCr color\n"); + fprintf(stderr, "-h print this help\n"); + fprintf(stderr, "-V print version number\n"); + fprintf(stderr, "\n"); + } /*usage*/ + +int main(int argc, char **argv) + { + int option, n; + int firstvideo = -1; + unsigned int pid, next_word, stream_number, fileindex, nrinfiles; + unsigned char cbuf[CBUFSIZE]; + unsigned char psbuf[PSBUFSIZE]; + char *palet_file; + char *iname[256]; /* names of input files -- fixme: no range checking */ + unsigned int last_system_time = -1; + + video_format = get_video_format(); + fputs(PACKAGE_HEADER("spuunmux"), stderr); + if (video_format != VF_NONE) + { + fprintf + ( + stderr, + "INFO: default video format is %s\n", + video_format == VF_PAL ? "PAL" : "NTSC" + ); + } + else + { +#if defined(DEFAULT_VIDEO_FORMAT) +# if DEFAULT_VIDEO_FORMAT == 1 + fprintf(stderr, "INFO: default video format is NTSC\n"); + video_format = VF_NTSC; +# elif DEFAULT_VIDEO_FORMAT == 2 + fprintf(stderr, "INFO: default video format is PAL\n"); + video_format = VF_PAL; +# endif +#else + fprintf(stderr, "INFO: no default video format, must explicitly specify NTSC or PAL\n"); +#endif + } /*if*/ + base_name = "sub"; + stream_number = 0; + palet_file = 0; + nrinfiles = 0; + while ((option = getopt(argc, argv, "o:v:fF:s:p:Vh")) != -1) + { + switch (option) + { + case 'o': + base_name = optarg; + break; + case 'v': + debug = strtounsigned(optarg, "verbosity"); + break; + case 'f': + full_size = true; + break; + case 'F': + if (!strcasecmp(optarg, "ntsc")) + { + video_format = VF_NTSC; + } + else if (!strcasecmp(optarg, "pal")) + { + video_format = VF_PAL; + } + else + { + fprintf(stderr, "ERR: Unrecognized video format \"%s\"\n", optarg); + exit(-1); + } /*if*/ + break; + case 's': + stream_number = strtounsigned(optarg, "stream number"); + break; + case 'p': + palet_file = optarg; + break; + case 'V': + exit(-1); + + case 'h': + default: + usage(); + return -1; + } /*switch*/ + } /*while*/ + + if (optind < argc) + { + /* remaining args are input filenames */ + int n, i; + for (i = 0, n = optind; n < argc; n++, i++) + iname[i] = argv[n]; + nrinfiles = i; + } + else + { + usage(); + return -1; + } /*if*/ + if (full_size && video_format == VF_NONE) + { + fprintf(stderr, "ERR: cannot determine meaning of full size without knowing if it's NTSC or PAL\n"); + exit(-1); + } /*if*/ + + /* initialize current_palette to default palette */ + bps(0, 0, 0, 0); + bps(1, 127, 0, 0); + bps(2, 0, 127, 0); + bps(3, 127, 127, 0); + bps(4, 0, 0, 127); + bps(5, 127, 0, 127); + bps(6, 0, 127, 127); + bps(7, 127, 127, 127); + bps(8, 192, 192, 192); + bps(9, 128, 0, 0); + bps(10, 0, 128, 0); + bps(11, 128, 128, 0); + bps(12, 0, 0, 128); + bps(13, 128, 0, 128); + bps(14, 0, 128, 128); + bps(15, 128, 128, 128); + + if (palet_file) + { + bool rgb = false; + char * const temp = strrchr(palet_file, '.'); + if (temp != NULL) + { + if (strcmp(temp, ".rgb") == 0) + rgb = true; + } /*if*/ + fdo = fopen(palet_file, "r"); + if (fdo != NULL) + { + for (n = 0; n < 16; n++) + { + int r, g, b; + fscanf(fdo, "%02x%02x%02x", &r, &g, &b); + if (!rgb) + ycrcb_to_rgb(&r, &g, &b); + current_palette[n].r = r; + current_palette[n].g = g; + current_palette[n].b = b; + if (debug > 3) + fprintf + ( + stderr, + "pal: %d #%02x%02x%02x\n", + n, current_palette[n].r, current_palette[n].g, current_palette[n].b + ); + } /*for*/ + fclose(fdo); + } + else + { + fprintf(stderr, "unable to open %s, using defaults\n", palet_file); + } /*if*/ + } /*if*/ + if (strlen(base_name) > 246) + { + fprintf(stderr, + "error: max length of base for filename creation is 246 characters\n"); + return -1; + } /*if*/ + { + char nbuf[256]; + sprintf(nbuf, "%s.xml", base_name); + fdo = fopen(nbuf, "w+"); + } + fprintf(fdo, "<subpictures>\n\t<stream>\n"); + pts = 0; + subno = 0; + subi = 0; + add_offset = 450; // for rounding purposes + fileindex = 0; + while (fileindex < nrinfiles) + { + struct vfile fd = varied_open(iname[fileindex], O_RDONLY, "input file"); + if (debug > 0) + fprintf(stderr, "file: %s\n", iname[fileindex]); + fileindex++; + while (fread(&pid, 1, 4, fd.h) == 4) + { + pid = ntohl(pid); + if (pid == 0x00000100 + MPID_PACK) + { // start PS (Program stream) + unsigned int new_system_time, stuffcount; +l_01ba: + if (debug > 5) + fprintf(stderr, "pack_start_code\n"); + if (fread(psbuf, 1, PSBUFSIZE, fd.h) < 1) + break; + if ((psbuf[0] & 0xc0) != 0x40) + { + if (debug > 1) + fprintf(stderr, "not a MPEG-2 file, skipping.\n"); + continue; +// break; + } /*if*/ + new_system_time = + (psbuf[4] >> 3) + + + psbuf[3] * 32 + + + (psbuf[2] & 3) * 32 * 256 + + + (psbuf[2] & 0xf8) * 32 * 128 + + + psbuf[1] * 1024 * 1024 + + + (psbuf[0] & 3) * 1024 * 1024 * 256 + + + (psbuf[0] & 0x38) * 1024 * 1024 * 128; + if (new_system_time < last_system_time) + { + if (last_system_time != -1) + { + if (debug > 0) + fprintf + ( + stderr, + "Time changed in stream header, use old time as offset for" + " timecode in subtitle stream\n" + ); + add_offset += last_system_time; + } /*if*/ + } /*if*/ + last_system_time = new_system_time; + flushspus(last_system_time); + if (debug > 5) + { + fprintf(stderr, "system time: %u\n", new_system_time); + } /*if*/ + stuffcount = psbuf[9] & 7; + if (stuffcount != 0) + { + char stuff[7]; + if (debug > 5) + fprintf(stderr, "found %d stuffing bytes\n", stuffcount); + if (fread(stuff, 1, stuffcount, fd.h) < stuffcount) + break; + } /*if*/ + } + else if (pid == 0x100 + MPID_PROGRAM_END) + { + if (debug > 5) + fprintf(stderr, "end packet\n"); + } + else /* packet with a length field */ + { + unsigned short int package_length; + fread(&package_length, 1, 2, fd.h); + package_length = ntohs(package_length); + if (package_length != 0) + { + switch (pid) + { + case 0x0100 + MPID_SYSTEM: + if (debug > 5) + fprintf(stderr, "system header\n"); + break; + case 0x0100 + MPID_PRIVATE2: /* PCI & DSI packets, not my problem */ + if (debug > 5) + fprintf(stderr, "private stream 2\n"); + break; + case 0x0100 + MPID_PRIVATE1: /* subpicture or audio stream */ + if (debug > 5) + fprintf(stderr, "private stream 1\n"); + fread(cbuf, 1, package_length, fd.h); + next_word = getpts(cbuf); + if (next_word != -1) + { + pts = next_word; + } /*if*/ + next_word = cbuf[2] /* additional data length */ + 3 /* length of fixed part of MPEG-2 extension */; + if (debug > 5) + { + /* dump PES header + extension */ + int c; + for (c = 0; c < next_word; c++) + fprintf(stderr, "0x%02x ", cbuf[c]); + } /*if*/ + if (debug > 5) + fprintf(stderr, "tid: %d\n", pts); + if + ( + cbuf[next_word] == stream_number + 32 /* DVD-Video stream nr */ + || + cbuf[next_word] == 0x70 && cbuf[next_word + 1] == stream_number + /* SVCD stream nr */ + ) + { + /* this is the subpicture stream the user wants dumped */ + svcd_adjust = cbuf[next_word] == 0x70 ? 4 : 0; + if (/*debug < 6 &&*/ debug > 1) + { + fprintf(stderr, + "id: 0x%x 0x%x %d tid: %d\n", + cbuf[next_word], package_length, + next_word, pts); + } /*if*/ + if (!subi) + { + /* starting a new SPU */ + subs = + ((unsigned int)cbuf[next_word + 1 + svcd_adjust] << 8) + + + cbuf[next_word + 2 + svcd_adjust]; + /* SPDSZ, size of total subpicture data */ + spts = pts; + } /*if*/ + memcpy + ( + /*dest =*/ sub + subi, + /*src =*/ cbuf + next_word + 1 + svcd_adjust, + /*n =*/ package_length - next_word - 1 - svcd_adjust + ); + /* collect the subpicture data */ + if (debug > 1) + { + fprintf(stderr, "found %d bytes of data\n", + package_length - next_word - 1 - svcd_adjust); + } /*if*/ + subi += package_length - next_word - 1 - svcd_adjust; + /* how much I just collected */ + if (debug > 2) + { + fprintf(stderr, + "subi: %d (0x%x) subs: %d (0x%x) b-a-1: %d (0x%x)\n", + subi, subi, subs, subs, + package_length - next_word - 1 - svcd_adjust, + package_length - next_word - 1 - svcd_adjust); + } /*if*/ + if (svcd_adjust) + { + if (cbuf[next_word + 2] & 0x80) + { + subi = 0; + next_word = svcddecode(); + if (next_word) + { + fprintf + ( + stderr, + "found unreadable subtitle at %.2fs, skipping\n", + (double) spts / 90000 + ); + continue; + } /*if*/ + } /*if*/ + } + else if (subs == subi) + { + /* got a complete SPU */ + subi = 0; + if (dvddecode()) + { + fprintf(stderr, + "found unreadable subtitle at %.2fs, skipping\n", + (double) spts / 90000); + continue; + } /*if*/ + } /*if*/ + } /*if dump the stream*/ + package_length = 0; + break; + case 0x0100 + MPID_VIDEO_FIRST: + if (firstvideo == -1) + { + fread(cbuf, 1, package_length, fd.h); + firstvideo = getpts(cbuf); + add_offset -= firstvideo; + package_length = 0; + } /*if*/ + if (debug > 5) + fprintf(stderr, "video stream 0\n"); + break; + case 0x01e1: + case 0x01e2: + case 0x01e3: + case 0x01e4: + case 0x01e5: + case 0x01e6: + case 0x01e7: + case 0x01e8: + case 0x01e9: + case 0x01ea: + case 0x01eb: + case 0x01ec: + case 0x01ed: + case 0x01ee: + case 0x01ef: + if (debug > 5) + fprintf(stderr, "video stream %d\n", pid - 0x100 - MPID_VIDEO_FIRST); + break; + case 0x0100 + MPID_PAD: + if (debug > 5) + fprintf(stderr, "padding stream %d bytes\n", package_length); + fread(cbuf, 1, package_length, fd.h); + if (package_length > 30) + { + int i; + package_length = 0; + i = 0; + if (strcmp((const char *)cbuf + i, "dvdauthor-data")) + break; + /* pad packet contains DVDAuthor private data */ + i = 15; + if (cbuf[i] != 2) + break; + switch(cbuf[i + 1]) + { + case 1: // subtitle/menu color and button information + { + // int st = cbuf[i + 2] & 31; // we ignore which subtitle stream for now + struct dispdetails *buttons; + i += 3; + buttons = malloc(sizeof(struct dispdetails)); + memset(buttons, 0, sizeof(struct dispdetails)); + buttons->pts[0] = read4(cbuf + i); + buttons->pts[1] = read4(cbuf + i + 4); + i += 8; + while(cbuf[i] != 0xff) + { + switch(cbuf[i]) + { + case 1: /* colour table */ + { + int j; + buttons->numpal = 0; + for (j = 0; j < cbuf[i + 1]; j++) + { + const int c = read4(cbuf + i + 1 + 3 * j) & 0xffffff; + buttons->palette[j] = c; + buttons->numpal++; + } /*for*/ + i += 2 + 3 * buttons->numpal; + } + break; + case 2: /* button groups */ + { + int j; + buttons->numcoli = cbuf[i + 1]; + for (j = 0; j < 2 * buttons->numcoli; j++) + buttons->coli[j] = read4(cbuf + i + 2 + j * 4); + i += 2 + 8 * buttons->numcoli; + } + break; + case 3: /* button placement */ + { + int j; + buttons->numbuttons = cbuf[i + 1]; + buttons->buttons = malloc(buttons->numbuttons * sizeof(struct button)); + i += 2; + for (j = 0; j < buttons->numbuttons; j++) + { + struct button *b = &buttons->buttons[j]; + b->name = readpstr(cbuf, &i); + i += 2; + b->autoaction = cbuf[i++] != 0; + b->grp = cbuf[i]; + b->x1 = read2(cbuf + i + 1); + b->y1 = read2(cbuf + i + 3); + b->x2 = read2(cbuf + i + 5); + b->y2 = read2(cbuf + i + 7); + i += 9; + // up down left right + b->up = readpstr(cbuf, &i); + b->down = readpstr(cbuf, &i); + b->left = readpstr(cbuf, &i); + b->right = readpstr(cbuf, &i); + } /*for*/ + } + break; + default: + fprintf(stderr,"ERR: unknown dvd info packet command: %d, offset %d\n",cbuf[i], i); + exit(1); + } /*switch*/ + } /*while*/ + add_pending_buttons(buttons); + } /*case 1*/ + break; + } /*switch*/ + } /*if*/ + package_length = 0; + break; + case 0x01c0: + case 0x01c1: + case 0x01c2: + case 0x01c3: + case 0x01c4: + case 0x01c5: + case 0x01c6: + case 0x01c7: + case 0x01c8: + case 0x01c9: + case 0x01ca: + case 0x01cb: + case 0x01cc: + case 0x01cd: + case 0x01ce: + case 0x01cf: + case 0x01d0: + case 0x01d1: + case 0x01d2: + case 0x01d3: + case 0x01d4: + case 0x01d5: + case 0x01d6: + case 0x01d7: + case 0x01d8: + case 0x01d9: + case 0x01da: + case 0x01db: + case 0x01dc: + case 0x01dd: + case 0x01de: + case 0x01df: + if (debug > 5) + fprintf(stderr, "audio stream %d\n", pid - 0x100 - MPID_AUDIO_FIRST); + break; + default: + if (debug > 0) + fprintf(stderr, "unknown header %x\n", pid); + next_word = pid << 16 | package_length; + package_length = 2; + while (next_word != 0x100 + MPID_PACK) + { + next_word = next_word << 8; + if (fread(&next_word, 1, 1, fd.h) < 1) + break; + package_length++; + } /*while*/ + if (debug > 0) + fprintf(stderr, "skipped %d bytes of garbage\n", package_length); + goto l_01ba; + } /*switch*/ + fread(cbuf, 1, package_length, fd.h); + } /*if*/ + } /*if*/ + } /*while read next packet header*/ + varied_close(fd); + } /*while fileindex < nrinfiles*/ + flushspus(0x7fffffff); /* ensure all remaining spus elements are output */ + fprintf(fdo, "\t</stream>\n</subpictures>\n"); + fclose(fdo); + return 0; + } /*main*/
View file
lxdvdrip-1.76.tar.bz2/dvdbackup.c -> lxdvdrip-1.77.tar.bz2/dvdbackup.c
Changed
@@ -125,6 +125,8 @@ MenuCopied[vts] = 1; + printf ("Funktion CopyMenu (%ld)\n", (long)vts); + if( NoMenuF ) return( 0 ); if( !vts ) { @@ -156,9 +158,6 @@ int size; res = MyDVDRead1Block( dvd_file, sector, buffer ); - if( res != 1 ) { - ret = -1; goto out; - } if( fwrite( buffer, 1, sizeof(buffer), fp ) != sizeof(buffer)) { ret = -1; goto out; } @@ -231,6 +230,7 @@ static int CopyEmptyPgc( Cell_t * cell ) { + uint32_t sector; char buffer[DVD_VIDEO_LB_LEN]; dvd_file_t * dvd_file; @@ -239,7 +239,7 @@ Vobu_t * v; int res; -// DBG('b',fprintf(stderr,"%s: startSector: %u vts: %d\n", __FUNCTION__, cell->startSector, cell->vts );); + printf("Copy Empty PGC: startSector: %u vts: %d\n", cell->startSector, cell->vts ); if( NoMenuF ) return( 0 ); @@ -248,7 +248,6 @@ sector = cell->startSector; res = MyDVDRead1Block( dvd_file, sector, buffer ); - if( res == -1 ) return( -1 ); if( !res || !isNavPack((unsigned char *)buffer) ) { /* Faulty sector */ CreateDummyNavPack( (unsigned char *)buffer, sector ); } @@ -276,7 +275,6 @@ nsectors = 1; res = MyDVDRead1Block( dvd_file, sector+1, buffer ); - if( res == -1 ) return( -1 ); if( !res ) { /* Faulty sector */ CreateDummyPack( (unsigned char *)buffer ); } @@ -1016,6 +1014,7 @@ int ret; + printf ("Copy Cell %ld - %ld\n", (long)c->vts, (long)CurVTS); if( c->vts != CurVTS ) { char vobFile[512]; int menuSize; @@ -1026,7 +1025,7 @@ OutFp = NULL; UpdateIfo( targetDir ); VobSize[CurVOB] = OutSize; - if( UpdateVobs( targetDir ) < 0 ) return( -1 ); + UpdateVobs( targetDir ); } menuSize = CopyMenu( c->vts, targetDir ); if( menuSize < 0 ) return( -1 ); @@ -1369,11 +1368,7 @@ /* Copy cells */ for( i = 0; i < CellArray.nbCells; i++ ) { Cell_t * c = CellArray.cells + i; - - if( CopyCell( c, targetDir ) < 0 ) { - ret = -1; - goto out; - } + CopyCell( c, targetDir ); if( c->selected ) { if( dynQual ) { double nFactor = ReCpuFactor( ); @@ -1403,8 +1398,7 @@ VobSize[CurVOB] = OutSize; UpdateIfo( targetDir ); UpdateMainIfo( targetDir, fullBackup ); -// if( UpdateVob( CurVTS, CurVOB, OutSize, targetDir ) < 0 ) return( -1 ); - if( UpdateVobs( targetDir ) < 0 ) return( -1 ); + UpdateVobs( targetDir ); }
View file
lxdvdrip-1.76.tar.bz2/dvdbackup/dvdbackup_lxdvdrip.c -> lxdvdrip-1.77.tar.bz2/dvdbackup/dvdbackup_lxdvdrip.c
Changed
@@ -707,7 +707,6 @@ /* Temp helpers */ int channels; - int temp; int found; int chapters_1; int chapters_2; @@ -914,7 +913,6 @@ /* Now lets see if we can find our candidate among the top most chapters */ found_chapter=6; - temp = chapter_chapter_array[0]; for (i=0 ; (i < titles) && (i < 4) ; i++ ) { if ( candidate == title_set_chapter_array[i] ) { found_chapter=i+1; @@ -982,7 +980,6 @@ /* Now lets see if we can find our candidate among the top most chapters */ found_chapter=5; - temp = chapter_chapter_array[0]; for (i=0 ; (i < titles) && (i < 4) ; i++ ) { if ( candidate == title_set_chapter_array[i] ) { found_chapter=i+1; @@ -2051,7 +2048,6 @@ int result; int chapters = 0; - int feature; int i, s; int spg, epg; int pgc; @@ -2080,7 +2076,6 @@ if(titles == 0) { fprintf(stderr, "No title specified for chapter extraction, will try to figure out main feature title\n"); - feature = titles_info->main_title_set; for (i=0; i < titles_info->number_of_titles ; i++ ) { if ( titles_info->titles[i].title_set == titles_info->main_title_set ) { if(chapters < titles_info->titles[i].chapters) {
View file
lxdvdrip-1.76.tar.bz2/dvdcell.c -> lxdvdrip-1.77.tar.bz2/dvdcell.c
Changed
@@ -197,13 +197,13 @@ int nrTS = Ifo_zero->vmgi_mat->vmg_nr_of_title_sets; /* Number of title sets */ int i,j,k; - DBG('b',fprintf(stderr,"%s: nrTS=%d noPisteVideo=%d\n", __FUNCTION__, nrTS, noPisteVideo );); + printf("nrTS=%d noPisteVideo=%d\n", nrTS, noPisteVideo ); for( k = 1; k <= nrTS; k++ ) { ifo_handle_t * ifo = Ifo[k]; int vts_ttn, title_set_nr; int nbChapter; - if( !ifo->vtsi_mat ) continue; + if( !ifo->vtsi_mat ) { continue; } DBG('b',fprintf(stderr,"VTS: %d PGCS: %d ifo: %p\n", k, ifo->vts_pgcit->nr_of_pgci_srp, ifo );); vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn; /* Title number within VTS */ @@ -248,7 +248,7 @@ } if( lastF ) UnSelectLastCell( ca ); - DBG('b',fprintf(stderr,"NrCells: %d\n", ca->nbCells ); + printf("NrCells: %d\n", ca->nbCells ); long long tSize = 0; for( i = 0; i < ca->nbCells; i++ ) { Cell_t * c = ca->cells + i; @@ -262,8 +262,7 @@ fprintf(stderr,"size: %s ", LLSize2Giga( size ) ); fprintf(stderr,"selected: %d\n", c->selected ); } - fprintf(stderr,"Total size: %s\n", LLSize2Giga( tSize ) ); - ); + printf("Total size: %s\n", LLSize2Giga( tSize ) ); return( 0 ); }
View file
lxdvdrip-1.76.tar.bz2/lxdvdrip.c -> lxdvdrip-1.77.tar.bz2/lxdvdrip.c
Changed
@@ -300,10 +300,12 @@ * 19.04.2009, Stefan Becker, Bugfix copy Mode (subpicture tag) * 18.02.2010, Stefan Becker, dvd95 1.6p0, Parameter region-code/check (1.76) * 10.04.2010, Stefan Becker, dvdauthor 0.6.18 + * xx.05.2010, Stefan Becker, vamps_menu von platte, wodim/genisoimage statt cdrecord/mkisofs (version 1.77) + * 24.10.2011, Stefan Becker, Ubuntu 11.10, dvdauthor 0.7 * */ -#define VERSION "1.76" +#define VERSION "1.77" @@ -1552,7 +1554,7 @@ char szDVDNameOverwrite[128]; long lMitKapiteln; long lPALDvd = 0; - char szMkisofsParam[1024]; + char szgenisoimageParam[1024]; char szBurnParam[1024]; char szPreviewParam[1024]; @@ -1587,8 +1589,8 @@ char dvdunauthor_name[128]; char vamps_name[128]; char tcprobe_name[128]; - char mkisofs_name[128]; - char cdrecord_name[128]; + char genisoimage_name[128]; + char wodim_name[128]; char growisofs_name[128]; char eject_name[128]; char dvdformat_name[128]; @@ -1670,8 +1672,8 @@ strcpy (play_cell_name, "play_cell_lxdvdrip"); strcpy (vamps_name, "vamps_lxdvdrip"); strcpy (tcprobe_name, "tcprobe"); - strcpy (mkisofs_name, "mkisofs"); - strcpy (cdrecord_name, "cdrecord"); + strcpy (genisoimage_name, "genisoimage"); + strcpy (wodim_name, "wodim"); strcpy (growisofs_name, "growisofs"); strcpy (eject_name, "eject"); strcpy (dvdformat_name, "dvd+rw-format"); @@ -1720,8 +1722,8 @@ lRWFormat = 0; // RWs nicht formatieren vor dem Brennen strcpy (szVideoAngaben, ""); // Standard: ohne Videoangaben an dvdauthor lMitVideoAngaben = 0; - strcpy (szMkisofsParam, ""); // Keine Extra-Parameter fuer mkisofs - strcpy (szBurnParam, ""); // Keine Zusatz-Parameter fuer cdrecord + strcpy (szgenisoimageParam, ""); // Keine Extra-Parameter fuer genisoimage + strcpy (szBurnParam, ""); // Keine Zusatz-Parameter fuer wodim strcpy (szPreviewParam, ""); // Keine Zusatz-Parameter fuer Preview lHighQuality = 0; // Normal DVD 9 => 5 strcpy (szHQChapters, ""); // Kapitel von-bis im High Quality Modus @@ -1742,13 +1744,17 @@ // Auslesen der Parameter aus einer Datei // Zuerst lokal versuchen - j = strlen (getenv ("HOME")); - if (j > 7000) - j = 7000; - strncpy (szBefehl, getenv ("HOME"), j); - szBefehl[j] = 0; - strcat (szBefehl, "/.lxdvdrip.conf"); - fConf = fopen (szBefehl, "r"); + fConf = NULL; + if (getenv ("HOME") != NULL) + { + j = strlen (getenv ("HOME")); + if (j > 7000) + j = 7000; + strncpy (szBefehl, getenv ("HOME"), j); + szBefehl[j] = 0; + strcat (szBefehl, "/.lxdvdrip.conf"); + fConf = fopen (szBefehl, "r"); + } if (!fConf) { // Ausgabe in allen 3 Sprachen, weil Sprache noch nicht eingestellt ist (steht in Parameterdatei) @@ -2135,14 +2141,14 @@ strcpy (tcprobe_name, &szParameter[13]); continue; } - if (strstr (szParameter, "mkisofs_name=")) + if (strstr (szParameter, "genisoimage_name=")) { - strcpy (mkisofs_name, &szParameter[13]); + strcpy (genisoimage_name, &szParameter[17]); continue; } - if (strstr (szParameter, "cdrecord_name=")) + if (strstr (szParameter, "wodim_name=")) { - strcpy (cdrecord_name, &szParameter[14]); + strcpy (wodim_name, &szParameter[11]); continue; } if (strstr (szParameter, "growisofs_name=")) @@ -2222,30 +2228,30 @@ lRWFormat = atol (szDummy); continue; } - if (strstr (szParameter, "mkisofs_param=")) + if (strstr (szParameter, "genisoimage_param=")) { // Ueberlesen des ersten Zeichens, weil Hochkomma char cTmpChar; - strcpy (szMkisofsParam, &szParameter[14]); - if (szMkisofsParam[0] == '"' && szMkisofsParam[1] == '"') // leer? dann ignorieren und wieder leer setzen + strcpy (szgenisoimageParam, &szParameter[18]); + if (szgenisoimageParam[0] == '"' && szgenisoimageParam[1] == '"') // leer? dann ignorieren und wieder leer setzen { - strcpy (szMkisofsParam, ""); + strcpy (szgenisoimageParam, ""); continue; } - szMkisofsParam[0] = ' '; // erstes Hochkomma abschneiden - if (szMkisofsParam[strlen (szMkisofsParam) - 1] == '"') // " zum Abschluss => String ist vollstaendig + szgenisoimageParam[0] = ' '; // erstes Hochkomma abschneiden + if (szgenisoimageParam[strlen (szgenisoimageParam) - 1] == '"') // " zum Abschluss => String ist vollstaendig { - szMkisofsParam[strlen (szMkisofsParam) - 1] = ' '; + szgenisoimageParam[strlen (szgenisoimageParam) - 1] = ' '; continue; } - strcat (szMkisofsParam, " "); // 1 Blank anhaengen + strcat (szgenisoimageParam, " "); // 1 Blank anhaengen // Jetzt Zeichen fuer Zeichen lesen, bis das abschliessende Hochkomma kommt for (;;) { fscanf (fConf, "%c", &cTmpChar); if (cTmpChar == '"') break; - sprintf (szMkisofsParam + strlen (szMkisofsParam), "%c", + sprintf (szgenisoimageParam + strlen (szgenisoimageParam), "%c", cTmpChar); if (strlen (szBurnParam) == (sizeof (szBurnParam) - 1)) break; // wg. Bufferoverflow @@ -2658,8 +2664,8 @@ printf ("%s\n", play_cell_name); printf ("%s\n", vamps_name); printf ("%s\n", tcprobe_name); - printf ("%s\n", mkisofs_name); - printf ("%s\n", cdrecord_name); + printf ("%s\n", genisoimage_name); + printf ("%s\n", wodim_name); printf ("%s\n", growisofs_name); printf ("%s\n", dvdformat_name); printf ("%s\n", mpgtx_name); @@ -2718,9 +2724,9 @@ printf ("Die Voreinstellung steht in Klammern hintern jedem Parameter.\n\n"); printf - ("-st=Streamtool : vamps, mplayer, transcode, trans_par (Transcode\n"); + ("-st=Streamtool : vamps, vamps_menu, mplayer, transcode, trans_par,\n"); printf - (" parallel), vlc, vlc_par, copy, partcopy (Titel waehlen) (-st=trans_par)\n"); + (" vlc, vlc_par, copy, partcopy (Titel waehlen) (-st=trans_par)\n"); printf ("-mp=mplex : Multiplexer, nur bei -st=mplayer beruecksichtigt,\n"); printf @@ -2780,9 +2786,9 @@ printf ("\nSeite 3: Enter druecken"); eatToNL (stdin); printf - ("-bp=Brenn-Programm : 1=growisofs, 2=cdrecord, 3=cdrecord on the\n"); + ("-bp=Brenn-Programm : 1=growisofs, 2=wodim, 3=wodim on the\n"); printf - (" fly, 4=ISO-Image per mkisofs,5=ISO-\n"); + (" fly, 4=ISO-Image per genisoimage,5=ISO-\n"); printf (" Image mit Volume-ID als Name,0=kein Brennen (-bp=1)\n"); printf ("-mc=x : Mehrere Kopien (1=ja, 0=nein) (-mc=0)\n"); @@ -2836,9 +2842,9 @@ printf ("The default values are printed in brackets () behind the parameters.\n\n"); printf - ("-st=Streamtool : vamps, mplayer, transcode, trans_par (Transcode\n"); + ("-st=Streamtool : vamps, vamps_menu, mplayer, transcode, trans_par,\n"); printf - (" parallel), vlc, vlc_par, copy, partcopy (Select Titles) (-st=trans_par)\n"); + (" vlc, vlc_par, copy, partcopy (Select Titles) (-st=trans_par)\n"); printf ("-mp=mplex : Multiplexer, only with -st=mplayer, use mplex instead of\n"); printf @@ -2893,9 +2899,9 @@ printf ("-db=Burner-Device : Device of the Burner (-db=/dev/scd0)\n"); printf - ("-bp=Burn-Program : 1=growisofs, 2=cdrecord, 3=cdrecord on the fly,\n"); + ("-bp=Burn-Program : 1=growisofs, 2=wodim, 3=wodim on the fly,\n"); printf - (" 4=ISO-Image/mkisofs,5=ISO with VolumeID,0=no Burning (-bp=1)\n"); + (" 4=ISO-Image/genisoimage,5=ISO with VolumeID,0=no Burning (-bp=1)\n"); printf ("-mc=x : Multi Copies (1=yes, 0=no) (-mc=0)\n"); printf ("\nPage 3: Please press Enter\n"); eatToNL (stdin); @@ -2947,9 +2953,9 @@ printf ("c'est la valeur donnée ici entre parenthèse qui est utilisée.\n\n"); printf - ("-st=extracteur : vamps, mplayer, transcode, trans_par (Transcode\n"); + ("-st=extracteur : vamps, vamps_menu, mplayer, transcode, trans_par,\n"); printf - (" parallèle), vlc, vlc_par, copy, partcopy (Choix de titres) (-st=trans_par)\n"); + (" vlc, vlc_par, copy, partcopy (Choix de titres) (-st=trans_par)\n"); printf ("-mp=multiplexeur : uniquement si -st=mplayer, utilisez mplex au lieu de\n"); printf @@ -3005,9 +3011,9 @@ printf ("-db=graveur DVD : nom du graveur de DVD (-db=/dev/scd0)\n"); printf - ("-bp=prog. de gravure : 1=growisofs, 2=cdrecord, 3=cdrecord à la volée\n"); + ("-bp=prog. de gravure : 1=growisofs, 2=wodim, 3=wodim à la volée\n"); printf - (" 4=ISO-Image/mkisofs, 5=ISO-Image/Volume-ID, 0=ne pas graver (-bp=1)\n"); + (" 4=ISO-Image/genisoimage, 5=ISO-Image/Volume-ID, 0=ne pas graver (-bp=1)\n"); printf ("-mc=x         : Multi Copies (1=oui, 0=non) (-mc=0)\n"); printf ("\nEntrée pour continuer\n"); @@ -3108,7 +3114,7 @@ { printf ("DVD-Brenner: %s (Device-Name)\n", szDVDBrenner); printf - ("Brennprogramm: %ld (1=growisofs,2=cdrecord,3=cdrecord on the fly, 4=mkisofs,5=mkisofs/VolumeID,0=aus)\n", + ("Brennprogramm: %ld (1=growisofs,2=wodim,3=wodim on the fly, 4=genisoimage,5=genisoimage/VolumeID,0=aus)\n", lBrennProgramm); printf ("RW formatieren:%ld (0=nein, 1=ja)\n", lRWFormat); printf ("Warte auf DVDR:%ld (1=ja, 0=nein)\n", lWaitBurn); @@ -3166,7 +3172,7 @@ { printf ("DVD-Burner: %s (Device-Name)\n", szDVDBrenner); printf - ("Burn-Prog: %ld (1=growisofs,2=cdrecord,3=cdrecord on the fly,4=mkisofs,5=mkisofs/VolumeID,0=off)\n", + ("Burn-Prog: %ld (1=growisofs,2=wodim,3=wodim on the fly,4=genisoimage,5=genisoimage/VolumeID,0=off)\n", lBrennProgramm); printf ("RW format: %ld (0=no, 1=yes)\n", lRWFormat); printf ("Wait for DVDR: %ld (1=yes, 0=no)\n", lWaitBurn); @@ -3224,7 +3230,7 @@ { printf ("Graveur DVD: %s (Nom du graveur)\n", szDVDBrenner); printf - ("Prog.gravure: %ld (1=growisofs,2=cdrecord,3=cdrecord à la volée,4=mkisofs,5=mkisofs/VolumeID,0=ne pas graver)\n", + ("Prog.gravure: %ld (1=growisofs,2=wodim,3=wodim à la volée,4=genisoimage,5=genisoimage/VolumeID,0=ne pas graver)\n", lBrennProgramm); printf ("Formater RW: %ld (0=non, 1=oui)\n", lRWFormat); printf ("Attente DVDR: %ld (1=oui, 0=non)\n", lWaitBurn); @@ -3651,6 +3657,28 @@ } } + // Datei erstellen für DVD-Author >= 0.70 + if (getenv ("HOME") != NULL) + { + char filename[1024]; + sprintf (filename, "%s/.config/video_format", getenv ("HOME")); + FILE* videoFormat = fopen (filename, "w"); + if (videoFormat != NULL) + { + vtsi_mat = ifo[ifo_zero->tt_srpt->title[0].title_set_nr]->vtsi_mat; + vts_pgcit = ifo[ifo_zero->tt_srpt->title[0].title_set_nr]->vts_pgcit; + video_attr = &vtsi_mat->vts_video_attr; + if (strcmp (video_format[video_attr->video_format], "PAL") == 0) + { + fprintf (videoFormat, "PAL"); + } else + { + fprintf (videoFormat, "NTSC"); + } + fclose (videoFormat); + } + } + if (lPackMethode >= 5) // DVD-Backup { // PAL-DVD ? @@ -3979,8 +4007,8 @@ } } - // Title-Set-Nr. zum Titel speichern - opt_vts = ifo_zero->tt_srpt->title[opt_t - 1].title_set_nr; + // Titel-Nr. für Fullbackup speichern + opt_vts = opt_t; // Angaben zum Format auslesen // Diese Angaben koennen optional an dvdauthor weitergegeben werden @@ -4297,7 +4325,7 @@ { // vlc und tcprobe muessen getrennt sein, sonst keine Rueckkehr long lTestKapitel=(lAnzahlKapitel/2+1); - sprintf (szBefehl, "%s %s dvd://%s@%ld:%ld-%ld:%ld --intf dummy --sout-all --no-spu " + sprintf (szBefehl, "%s %s dvdsimple://%s@%ld:%ld-%ld:%ld --intf dummy --sout-all --no-spu " "--sout '#standard{access=file,mux=ps,dst=%s/vlctestrip.vob}' vlc://quit", szNiceRip, vlc_name, dvd_device, (long)opt_t, (long)lTestKapitel, @@ -5952,7 +5980,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld:%ld%s --intf dummy --sout-all --no-spu --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " + "%s %s dvdsimple://%s@%ld:%ld%s --intf dummy --sout-all --no-spu --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | tee %s/aud1.fifo %s/aud2.fifo %s/vid.fifo > /dev/null", szNiceRip, vlc_name, dvd_device, (long) opt_t, lTestKapitel, szAngle, szTmpDir, szTmpDir, @@ -5972,7 +6000,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld:%ld%s --intf dummy " + "%s %s dvdsimple://%s@%ld:%ld%s --intf dummy " "--audio-track %ld " "--sout '#standard{access=file,mux=ps," "dst=/dev/stdout}' vlc://quit " @@ -6594,7 +6622,19 @@ strcat (szFilmVerzeichnis, "_1"); if (lHighQuality == 2) strcat (szFilmVerzeichnis, "_2"); - } + } else + { +// Methode vamps_menu von Platte ohne DVD Titel, also "DVD" anhängen + if (lPackMethode == 1 && lMenues == 1) + { + if (szFilmVerzeichnis[strlen (szFilmVerzeichnis) - 1] != '/') + { + strcat (szFilmVerzeichnis, "/"); + } + strcat (szFilmVerzeichnis, "DVD"); + } + + } // Test, ob Datei im Rip-Verzeichnis vorhanden checkLastRip (szFilmVerzeichnis, lSprache); @@ -7120,7 +7160,7 @@ // DVD auslesen if (lUseVLC > 0) sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy --sout-all --sout " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy --sout-all --sout " "'#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | tee ", szNiceRip, vlc_name, dvd_device, (long) opt_t, szHQChapters, @@ -7487,7 +7527,7 @@ // ac3 Stream zerrissen wird char szAudioScan[128]; strcpy (szAudioScan, ""); - if (strstr (szAudioFormat1, "ac3") && lHighQuality == 2) + if (strstr (szAudioFormat1, "ac3") ) { sprintf (szAudioScan, " | %s ", lxac3scan_name); } @@ -7555,7 +7595,7 @@ // ac3 Stream zerrissen wird char szAudioScan[128]; strcpy (szAudioScan, ""); - if (strstr (szAudioFormat2, "ac3") && lHighQuality == 2) + if (strstr (szAudioFormat2, "ac3") ) { sprintf (szAudioScan, " | %s ", lxac3scan_name); } @@ -7580,7 +7620,7 @@ else strcpy (szNoSPU, ""); sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy --sout-all %s --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy --sout-all %s --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | tee %s/foo.s1 %s/foo.s2 %s/foo.s3 %s >/dev/null", szNiceRip, vlc_name, dvd_device, (long) opt_t, szHQChapters, szAngle, szNoSPU, szTmpDir, szTmpDir, szTmpDir, @@ -7611,7 +7651,7 @@ lUntertitel-1); } sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy " "--audio-track %ld %s " "--sout '#standard{access=file,mux=ps,dst=/dev/stdout}' " "vlc://quit " @@ -7622,7 +7662,7 @@ } else { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy --sout-all " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy --sout-all " "--sout '#standard{access=file,mux=ps,dst=/dev/stdout}' " "vlc://quit " " | tee %s/foo.s1 %s/foo.s2 %s >/dev/null", @@ -8133,14 +8173,14 @@ { if (dFaktor > 1) sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy --no-audio --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy --no-audio --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x mpeg2 | %s -f %f -s %lld > %sofile.m2v", szNiceRip, vlc_name, dvd_device, (long) opt_t, szHQChapters, szAngle, tcextract_name, requant_name, dFaktor, lPlatzVideo - lPlatzAudio, szTmpDir); else sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy --no-audio --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy --no-audio --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x mpeg2 > %sofile.m2v", szNiceRip, vlc_name, dvd_device, (long) opt_t, szHQChapters, szAngle, tcextract_name, szTmpDir); @@ -8194,7 +8234,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --audio-track %ld --no-video " + "%s %s dvdsimple://%s@%ld%s%s --audio-track %ld --no-video " "--intf dummy --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x %s | " "%s -x null,raw -y null,mp2enc -i /dev/stdin " @@ -8226,7 +8266,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --audio-track %ld --no-video " + "%s %s dvdsimple://%s@%ld%s%s --audio-track %ld --no-video " "--intf dummy --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x %s | " "%s -x null,auto -y null,mp2enc -i /dev/stdin " @@ -8264,7 +8304,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --audio-track %ld --no-video " + "%s %s dvdsimple://%s@%ld%s%s --audio-track %ld --no-video " "--intf dummy --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x %s %s > %sofile.%s", szNiceRip, vlc_name, dvd_device, (long) opt_t, szHQChapters, @@ -8306,7 +8346,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --audio-track %ld --no-video " + "%s %s dvdsimple://%s@%ld%s%s --audio-track %ld --no-video " "--intf dummy --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x %s | " "%s -x null,raw -y null,mp2enc -i /dev/stdin " @@ -8337,7 +8377,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --audio-track %ld --no-video " + "%s %s dvdsimple://%s@%ld%s%s --audio-track %ld --no-video " "--intf dummy --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x %s | " "%s -x null,auto -y null,mp2enc -i /dev/stdin " @@ -8376,7 +8416,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --audio-track %ld --no-video " + "%s %s dvdsimple://%s@%ld%s%s --audio-track %ld --no-video " "--intf dummy --sout '#standard{access=file,mux=ps,dst=/dev/stdout}' vlc://quit " " | %s -t vob -x %s %s > %sofile_2.%s", szNiceRip, vlc_name, dvd_device, (long) opt_t, szHQChapters, @@ -8477,7 +8517,7 @@ if (lUseVLC) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy " "--sout-spu --sub-track %ld " "--sout '#standard{access=file,mux=ps,dst=/dev/stdout}' " " vlc://quit " @@ -8534,7 +8574,7 @@ if (lUseVLC > 0) { sprintf (szBefehl, - "%s %s dvd://%s@%ld%s%s --intf dummy " + "%s %s dvdsimple://%s@%ld%s%s --intf dummy " "--sout-spu --sub-track %ld " "--sout '#standard{access=file,mux=ps,dst=/dev/stdout}' " " vlc://quit " @@ -10484,7 +10524,7 @@ int lLaengeName; char szFormatBefehl[1024]; // RW formatieren ? - if (lRWFormat && lBrennProgramm < 4) // nicht bei mkisofs + if (lRWFormat && lBrennProgramm < 4) // nicht bei genisoimage { if (lBrennProgramm == 1) // Brennen mit growisofs { @@ -10492,16 +10532,16 @@ sprintf (szFormatBefehl, "%s %s -format -force %s ", szNiceBurn, dvdformat_name, szDVDBrenner); } - else // Brennen mit cdrecord + else // Brennen mit wodim { char szSpeed[20]; - check_program (cdrecord_name, lSprache, 1); + check_program (wodim_name, lSprache, 1); if (lDVDSpeed > 0) sprintf (szSpeed, "speed=%ld", lDVDSpeed); else strcpy (szSpeed, ""); sprintf (szFormatBefehl, "%s %s dev=%s -format -force %s", - szNiceBurn, cdrecord_name, szDVDBrenner, szSpeed); + szNiceBurn, wodim_name, szDVDBrenner, szSpeed); } } // Titel der DVD setzen @@ -10534,7 +10574,7 @@ // Growisofs sprintf (szBefehl, "%s %s %s %s %s -Z %s -V %s %s -dvd-video %s", szNiceBurn, growisofs_name, szBurnParam, szSpeed, szDVDCompat, - szDVDBrenner, szDVDNameOverwrite, szMkisofsParam, + szDVDBrenner, szDVDNameOverwrite, szgenisoimageParam, szFilmVerzeichnis); for (;;) { @@ -10629,7 +10669,7 @@ { char szSpeed[128]; char szTemp[128]; - long lRCmkisofs = 0; + long lRCgenisoimage = 0; if (lBrennProgramm != 5) { sprintf (szTemp, "%s/dvdrip.img", szTmpDir); @@ -10638,37 +10678,37 @@ { sprintf (szTemp, "%s/%s.img", szTmpDir, szDVDNameOverwrite); } - check_program (mkisofs_name, lSprache, 1); + check_program (genisoimage_name, lSprache, 1); if (lBrennProgramm < 4) { - check_program (cdrecord_name, lSprache, 1); + check_program (wodim_name, lSprache, 1); } - // Mkisofs + cdrecord + // genisoimage + wodim // Geschwindigkeit explizit angeben? if (lDVDSpeed > 0) sprintf (szSpeed, "speed=%ld", lDVDSpeed); else strcpy (szSpeed, ""); - if (lBrennProgramm == 2 || lBrennProgramm >= 4) // erst mkisofs, dann cdrecord, aber in 2 Befehlen + if (lBrennProgramm == 2 || lBrennProgramm >= 4) // erst genisoimage, dann wodim, aber in 2 Befehlen { sprintf (szBefehl, "%s %s -dvd-video -V %s %s -o %s %s", - szNiceBurn, mkisofs_name, szDVDNameOverwrite, szMkisofsParam, + szNiceBurn, genisoimage_name, szDVDNameOverwrite, szgenisoimageParam, szTemp, szFilmVerzeichnis); printf ("%s\n", szBefehl); - lRCmkisofs = system (szBefehl); + lRCgenisoimage = system (szBefehl); if (lBrennProgramm >= 4) { - lGebrannt = 1; // ausser mkisofs kein weiterer Befehl mehr + lGebrannt = 1; // ausser genisoimage kein weiterer Befehl mehr if (lPlaySound > 0) play_sound_if_ready (lxdvdrip_wav_name); } else sprintf (szBefehl, "%s %s -v dev=%s %s %s -eject %s", - szNiceBurn, cdrecord_name, szDVDBrenner, szSpeed, + szNiceBurn, wodim_name, szDVDBrenner, szSpeed, szBurnParam, szTemp); } else - { // mkisofs | cdrecord (on the fly) + { // genisoimage | wodim (on the fly) long lSektoren = 0; FILE *fp; // Anzahl Sektoren muss bestimmt werden, ohne geht on the fly nicht @@ -10676,7 +10716,7 @@ sprintf (szImgeSizeFile, "%s/imgsize.lxdvdrip", szTmpDir); sprintf (szBefehl, "%s %s -dvd-video -print-size %s 2>&1 | tail -n1 | sed -e 's/^.*\\ =\\ //' > %s", - szNiceBurn, mkisofs_name, szFilmVerzeichnis, szImgeSizeFile); + szNiceBurn, genisoimage_name, szFilmVerzeichnis, szImgeSizeFile); printf ("%s\n", szBefehl); system (szBefehl); // Anzahl Sektoren aus der Datei auslesen @@ -10705,12 +10745,12 @@ // Brennbefehl zusammemsetzen sprintf (szBefehl, "%s %s -dvd-video -V %s %s %s | %s -v dev=%s %s %s -eject tsize=%lds -", - szNiceBurn, mkisofs_name, szDVDNameOverwrite, szMkisofsParam, - szFilmVerzeichnis, cdrecord_name, + szNiceBurn, genisoimage_name, szDVDNameOverwrite, szgenisoimageParam, + szFilmVerzeichnis, wodim_name, szDVDBrenner, szSpeed, szBurnParam, lSektoren); } - if (lRCmkisofs == 0 && lBrennProgramm < 4) // Nur bei mkisofs OK + if (lRCgenisoimage == 0 && lBrennProgramm < 4) // Nur bei genisoimage OK { for (;;) {
View file
lxdvdrip-1.76.tar.bz2/lxdvdrip.conf -> lxdvdrip-1.77.tar.bz2/lxdvdrip.conf
Changed
@@ -6,7 +6,7 @@ # Leerzeichen angegeben werden. # Version der Config-Datei -version=1.76 +version=1.77 # Auswahl des zu rippenden Titels, bestimmen mit "lsdvd". # Alternative: bei titel=0 bestimmt lxdvdrip den laengsten Titel der DVD @@ -58,7 +58,7 @@ # Device fuer DVD-Brenner. # Beim Brennen mit "growisofs" ist zumeist "/dev/sr0" die richtige Wahl. -# Bei "cdrecord" zumeist "0,0,0", testen mit "cdrecord -scanbus". +# Bei "wodim" zumeist "0,0,0", testen mit "wodim -scanbus". # Entspricht "-db=". dvdbrenner=/dev/sr0 @@ -75,9 +75,9 @@ # Entspricht "-file=". file=0 -# Brennprogramm. Bei "1" wird growisofs verwendet, bei "2" cdrecord. -# Bei "3" wird cdrecord mit mkisofs on the fly gestartet. -# "4"=ISO-Image "/tmp/dvdrip.img" durch mkisofs. +# Brennprogramm. Bei "1" wird growisofs verwendet, bei "2" wodim. +# Bei "3" wird wodim mit genisoimage on the fly gestartet. +# "4"=ISO-Image "/tmp/dvdrip.img" durch genisoimage. # "5"=ISO-Image mit "Volume-ID.img" (=Name der DVD) als Namen. # 0=kein Brennen. # Entspricht "-bp=". @@ -153,7 +153,7 @@ # Entspricht "-free=" free=1 -# Brenngeschwindigkeit fuer growisofs als auch cdrecord. +# Brenngeschwindigkeit fuer growisofs als auch wodim. # Bei speed=0 wird der Parameter beim Brennen nicht uebergeben. speed=4 @@ -162,16 +162,16 @@ # Beschreibung siehe "man growisofs". dvdcompat=1 -# Extra-Parameter fuer mkisofs. +# Extra-Parameter fuer genisoimage. # Parameter muss in Hochkommas stehen, z. B. -# mkisofs_param="-input-charset iso8859-1" -# Parameter werden beim Aufruf an mkisofs bzw. growisofs uebergeben. -mkisofs_param="" +# genisoimage_param="-input-charset iso8859-1" +# Parameter werden beim Aufruf an genisoimage bzw. growisofs uebergeben. +genisoimage_param="" -# Extra-Parameter fuer cdrecord/growisofs. +# Extra-Parameter fuer wodim/growisofs. # Parameter muss in Hochkommas stehen, z. B. # burn_param="-tao" -# Parameter werden beim Aufruf an cdrecord bzw. growisofs uebergeben. +# Parameter werden beim Aufruf an wodim bzw. growisofs uebergeben. burn_param="" # DVD nach Rippen auswerfen. @@ -187,9 +187,9 @@ # z. B. "dvdauthor=/usr/local/bin/dvdauthor", damit koennen z. B. # mehrere Versionen parallel auf dem Rechner liegen. dvdauthor_name=dvdauthor -buffer_name=buffer_lxdvdrip +#buffer_name=buffer #buffer_name=bfr -#buffer_name=mbuffer +buffer_name=mbuffer_lxdvdrip tccat_name=tccat tcextract_name=tcextract requant_name=requant_lxdvdrip @@ -201,8 +201,8 @@ spuunmux_name=spuunmux dvdbackup_name=dvdbackup_lxdvdrip # Alternative: dvdbackup_name=vobcopy -mkisofs_name=mkisofs -cdrecord_name=cdrecord +genisoimage_name=genisoimage +wodim_name=wodim growisofs_name=growisofs dvd+rw-format=dvd+rw-format dvdunauthor_name=dvdunauthor @@ -218,7 +218,7 @@ # Nice-Level fuer Programmgruppen # nice_rip fuer das Rippen (tccat, mplayer, spuunmux, vamps_play_cell) -# nice_burn fuer das Brennen (growisofs, cdrecord) +# nice_burn fuer das Brennen (growisofs, wodim) # Moegliche Werte von "-20" (hoch) bis "19" (niedrig), bei "off" ohne nice-Angaben nice_rip=off nice_burn=off
View file
lxdvdrip-1.77.tar.bz2/mbuffer
Added
+(directory)
View file
lxdvdrip-1.77.tar.bz2/mbuffer/AUTHORS
Added
@@ -0,0 +1,2 @@ +Thomas Maier-Komor +e-mail: thomas@maier-komor.de
View file
lxdvdrip-1.77.tar.bz2/mbuffer/LICENSE
Added
@@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
View file
lxdvdrip-1.77.tar.bz2/mbuffer/Makefile
Added
@@ -0,0 +1,26 @@ + +# Where to install buffer +INSTBIN=/usr/local/bin + +RM=/bin/rm +ALL=Makefile log.c mbuffer.c network.c + +all: buffer + +buffer: log.c mbuffer.c network.c + if test -f log.o; then rm *.o; fi + gcc -g -O2 -c log.c -Wno-unused-result + gcc -g -O2 -c mbuffer.c -w + gcc -g -O2 -c network.c -Wno-unused-result + gcc -pthread -O2 -g -o mbuffer_lxdvdrip *o -lrt -lm + if test -f log.o; then rm *.o; fi + +clean: + $(RM) -f *.o core mbuffer_lxdvdrip .merrs + +install: buffer + cp mbuffer_lxdvdrip $(INSTBIN)/mbuffer_lxdvdrip + chmod 755 $(INSTBIN)/mbuffer_lxdvdrip + +uninstall: buffer + rm -f $(INSTBIN)/mbuffer_lxdvdrip
View file
lxdvdrip-1.77.tar.bz2/mbuffer/config.h
Added
@@ -0,0 +1,88 @@ +/* config.h. Generated from config.h.in by configure. */ +/* + * Copyright (C) 2000-2009, Thomas Maier-Komor + * + * This is the source code of mbuffer. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +/* package */ +#define PACKAGE "mbuffer" + +/* version of mbuffer */ +#define VERSION "20110724" + +/* Define if you want support for debugging messages. */ +#define DEBUG 1 + +/* Undefine if you want asserts enabled. */ +/* #undef NDEBUG */ + +/* md5hashing is enabled by default, + default is libmhash fallback is libmd5 */ +#undef HAVE_LIBMHASH +#undef HAVE_LIBMD5 +#undef HAVE_LIBCRYPTO + +/* Define if you have a working `mmap' system call. */ +/* #undef HAVE_MMAP */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Needed for thread safe compilation */ +#define _REENTRANT 1 + +/* Define if you have the hstrerror function. */ +#define HAVE_HSTRERROR 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if your `struct stat' has `st_blksize'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLKSIZE' instead. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if `st_blksize' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define if you have libsendfile. */ +#define HAVE_SENDFILE 1 +#define HAVE_SENDFILE_H 1 + +/* seteuid ? */ +#define HAVE_SETEUID 1 + +/* atoll availble? */ +/* #undef HAVE_ATOLL */ + +/* alloca in alloca.h */ +#define HAVE_ALLOCA_H 1 + +/* largefile support */ +/* #undef _LARGE_FILE */ +/* #undef _LARGEFILE_SOURCE */ +/* #undef _LARGEFILE64_SOURCE */ +#define _FILE_OFFSET_BITS 64 + +#ifndef lint +#define restrict __restrict +/* #undef inline */ +#endif + +#endif
View file
lxdvdrip-1.77.tar.bz2/mbuffer/dest.h
Added
@@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010, Thomas Maier-Komor + * + * This is the source code of mbuffer. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DEST_H +#define DEST_H + +#include <pthread.h> + +typedef struct destination { + struct destination *next; + const char *arg, *name, *port, *result; + int fd; + int mode; + pthread_t thread; +} dest_t; + +#endif
View file
lxdvdrip-1.77.tar.bz2/mbuffer/log.c
Added
@@ -0,0 +1,219 @@ +/* + * Copyright (C) 2000-2009, Thomas Maier-Komor + * + * This is the source code of mbuffer. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#include "log.h" + +#if !(defined(__sun) || defined(__linux) || defined(__GLIBC__)) +#define NEED_IO_INTERLOCK +#endif + +#include <assert.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if defined(__linux) +#include <linux/limits.h> +#elif defined(__bsd) +#include <sys/syslimits.h> +#endif +#include <sys/types.h> +#include <unistd.h> + +int Verbose = 3, Log = STDERR_FILENO, ErrorOccurred = 0, ErrorsFatal = 0; +extern char *Prefix; +extern size_t PrefixLen; + +#ifdef NEED_IO_INTERLOCK +#include <pthread.h> +pthread_mutex_t + LogMut = PTHREAD_MUTEX_INITIALIZER; +#endif + + +#ifdef DEBUG +void logdebug(const char *msg, ...) +{ + va_list val; + char buf[256]; + size_t b = PrefixLen; + + va_start(val,msg); + (void) memcpy(buf,Prefix,b); + b += vsnprintf(buf + b,sizeof(buf)-b,msg,val); + assert(b < sizeof(buf)); +#ifdef NEED_IO_INTERLOCK + if (b <= PIPE_BUF) { + (void) write(Log,buf,b); + } else { + int err; + err = pthread_mutex_lock(&LogMut); + assert(err == 0); + (void) write(Log,buf,b); + err = pthread_mutex_unlock(&LogMut); + assert(err == 0); + } +#else + (void) write(Log,buf,b); +#endif + va_end(val); +} +#define debugmsg if (Verbose >= 5) logdebug +#else +#define debugmsg +#endif + + +void infomsg(const char *msg, ...) +{ + if (Verbose >= 4) { + va_list val; + char buf[256], *b = buf + PrefixLen; + size_t s; + + va_start(val,msg); + (void) memcpy(buf,Prefix,PrefixLen); + b += vsnprintf(b,sizeof(buf)-(b-buf),msg,val); + s = b - buf; + assert(s < sizeof(buf)); +#ifdef NEED_IO_INTERLOCK + if (s <= PIPE_BUF) { + (void) write(Log,buf,s); + } else { + int err; + err = pthread_mutex_lock(&LogMut); + assert(err == 0); + (void) write(Log,buf,s); + err = pthread_mutex_unlock(&LogMut); + assert(err == 0); + } +#else + (void) write(Log,buf,s); +#endif + va_end(val); + } +} + + +void warningmsg(const char *msg, ...) +{ + if (Verbose >= 3) { + va_list val; + char buf[256], *b = buf + PrefixLen; + size_t s; + + va_start(val,msg); + (void) memcpy(buf,Prefix,PrefixLen); + (void) memcpy(b,"warning: ",9); + b += 9; + b += vsnprintf(b,sizeof(buf)-(b-buf),msg,val); + s = b - buf; + assert(s < sizeof(buf)); +#ifdef NEED_IO_INTERLOCK + if (s <= PIPE_BUF) { + (void) write(Log,buf,s); + } else { + int err; + err = pthread_mutex_lock(&LogMut); + assert(err == 0); + (void) write(Log,buf,s); + err = pthread_mutex_unlock(&LogMut); + assert(err == 0); + } +#else + (void) write(Log,buf,s); +#endif + va_end(val); + } +} + + +void errormsg(const char *msg, ...) +{ + ErrorOccurred = 1; + if (Verbose >= 2) { + va_list val; + char buf[256], *b = buf + PrefixLen; + size_t s; + + va_start(val,msg); + (void) memcpy(buf,Prefix,PrefixLen); + (void) memcpy(b,"error: ",7); + b += 7; + b += vsnprintf(b,sizeof(buf)-(b-buf),msg,val); + s = b - buf; + assert(s < sizeof(buf)); +#ifdef NEED_IO_INTERLOCK + if (s <= PIPE_BUF) { + (void) write(Log,buf,s); + } else { + int err; + err = pthread_mutex_lock(&LogMut); + assert(err == 0); + (void) write(Log,buf,s); + err = pthread_mutex_unlock(&LogMut); + assert(err == 0); + } +#else + (void) write(Log,buf,s); +#endif + va_end(val); + } + if (ErrorsFatal) { + close(Log); + exit(EXIT_FAILURE); + } +} + + +void fatal(const char *msg, ...) +{ + if (Verbose >= 1) { + va_list val; + char buf[256], *b = buf + PrefixLen; + size_t s; + + va_start(val,msg); + (void) memcpy(buf,Prefix,PrefixLen); + (void) memcpy(b,"fatal: ",7); + b += 7; + b += vsnprintf(b,sizeof(buf)-(b-buf),msg,val); + s = b - buf; + assert(s < sizeof(buf)); +#ifdef NEED_IO_INTERLOCK + if (s <= PIPE_BUF) { + (void) write(Log,buf,s); + } else { + int err; + err = pthread_mutex_lock(&LogMut); + assert(err == 0); + (void) write(Log,buf,s); + err = pthread_mutex_unlock(&LogMut); + assert(err == 0); + } +#else + (void) write(Log,buf,s); +#endif + va_end(val); + } + exit(EXIT_FAILURE); +} + +
View file
lxdvdrip-1.77.tar.bz2/mbuffer/log.h
Added
@@ -0,0 +1,51 @@ +/* + * Copyright (C) 2000-2009, Thomas Maier-Komor + * + * This is the source code of mbuffer. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LOG_H +#define LOG_H + +#include "config.h" + +#if !(defined(__sun) || defined(__linux)) +#define NEED_IO_INTERLOCK +#endif + +#ifdef NEED_IO_INTERLOCK +#include <pthread.h> +extern pthread_mutex_t LogMut; +#endif + +extern int Verbose, Log, ErrorOccurred, ErrorsFatal; + +#ifdef DEBUG +void logdebug(const char *msg, ...); +#define debugmsg if (Verbose >= 5) logdebug +#define debugiomsg if (Verbose >= 6) logdebug +#else +#define debugmsg +#define debugiomsg +#endif + +void infomsg(const char *msg, ...); +void warningmsg(const char *msg, ...); +void errormsg(const char *msg, ...); +void fatal(const char *msg, ...); + + +#endif
View file
lxdvdrip-1.77.tar.bz2/mbuffer/mbuffer.c
Added
@@ -0,0 +1,2227 @@ +/* + * Copyright (C) 2000-2011, Thomas Maier-Komor + * + * This is the source code of mbuffer. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#ifdef S_SPLINT_S +typedef int caddr_t; +#include <sys/_types.h> +#include <cygwin/types.h> +#include <cygwin/in.h> +#endif + +#define _GNU_SOURCE 1 /* needed for O_DIRECT */ +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <limits.h> +#include <math.h> +#include <netdb.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <termios.h> +#include <unistd.h> + + +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#endif + +#ifdef HAVE_SENDFILE +#ifdef HAVE_SENDFILE_H +#include <sys/sendfile.h> +#endif +/* if this sendfile implementation does not support sending from buffers, + disable sendfile support */ + #ifndef SFV_FD_SELF + #ifdef __GNUC__ + #warning sendfile is unable to send from buffers + #endif + #undef HAVE_SENDFILE + #endif +#endif + +#ifndef EBADRQC +#define EBADRQC EINVAL +#endif + +#ifdef HAVE_LIBMHASH +#include <mhash.h> +#define HAVE_MD5 1 +#elif defined HAVE_LIBMD5 +#include <md5.h> +static MD5_CTX MD5ctxt; +#define MD5_INIT(ctxt) MD5Init(&ctxt); +#define MD5_UPDATE(ctxt,at,num) MD5Update(&ctxt,(unsigned char *)(at),(unsigned int)(num)) +#define MD5_END(hash,ctxt) MD5Final(hash,&(ctxt)) +#define HAVE_MD5 1 +#elif defined HAVE_LIBCRYPTO +#include <openssl/md5.h> +static MD5_CTX MD5ctxt; +#define MD5_INIT(ctxt) MD5_Init(&ctxt); +#define MD5_UPDATE(ctxt,at,num) MD5_Update(&ctxt,at,num) +#define MD5_END(hash,ctxt) MD5_Final(hash,&(ctxt)) +#define HAVE_MD5 1 +#endif + +/* + * _POSIX_THREADS is only defined if full thread support is available. + * We don't need full thread support, so we skip this test... + * #ifndef _POSIX_THREADS + * #error posix threads are required + * #endif + */ + +#ifndef S_SPLINT_S +#ifndef _POSIX_SEMAPHORES +#error posix sempahores are required +#endif +#endif + +#ifdef O_LARGEFILE +#define LARGEFILE O_LARGEFILE +#else +#define LARGEFILE 0 +#endif + +#ifdef O_DIRECT +#define DIRECT O_DIRECT +#else +#define DIRECT 0 +#endif + + +#include "dest.h" +#include "network.h" +#include "log.h" + +char + *Prefix; +int + In = -1; +size_t + PrefixLen = 0; + +static pthread_t + Reader; +static long + Tmp = -1, Pause = 0, Memmap = 0, + Status = 1, Append = O_CREAT, Nooverwrite = O_EXCL, Outblocksize = 0, + Autoload_time = 0, OptSync = 0; +static unsigned long + Outsize = 10240; +static volatile int + Terminate = 0, /* abort execution, because of error or signal */ + EmptyCount = 0, /* counter incremented when buffer runs empty */ + FullCount = 0, /* counter incremented when buffer gets full */ + NumSenders = -1,/* number of sender threads */ + Done = 0, + MainOutOK = 1; /* is the main outputThread still writing or just coordinating senders */ +static unsigned long long + Blocksize = 10240, MaxReadSpeed = 0, MaxWriteSpeed = 0, OutVolsize = 0; +static volatile unsigned long long + Rest = 0, Numin = 0, Numout = 0; +static double + StartWrite = 0, StartRead = 1; +static char + *Tmpfile = 0, **Buffer; +static const char + *Infile = 0, *Autoload_cmd = 0; +static int + Memlock = 0, TermQ[2], + Hashers = 0, Direct = 0, SetOutsize = 0; +static long + NumVolumes = 1, /* number of input volumes, 0 for interactive prompting */ + Finish = -1, /* this is for graceful termination */ + Numblocks = 512; /* number of buffer blocks */ +static long long + TickTime = 0; + +static clockid_t + ClockSrc = CLOCK_REALTIME; + +#ifdef __sun +#include <synch.h> +#define sem_t sema_t +#define sem_init(a,b,c) sema_init(a,c,USYNC_THREAD,0) +#define sem_post sema_post +#define sem_getvalue(a,b) ((*(b) = (a)->count), 0) +#if defined(__SunOS_5_8) || defined(__SunOS_5_9) +#define sem_wait SemWait +int SemWait(sema_t *s) +{ + int err; + do { + err = sema_wait(s); + } while (err == EINTR); + return err; +} +#else +#define sem_wait sema_wait +#endif +#endif + +static sem_t Dev2Buf, Buf2Dev; +static pthread_cond_t + PercLow = PTHREAD_COND_INITIALIZER, /* low watermark */ + PercHigh = PTHREAD_COND_INITIALIZER, /* high watermark */ + SendCond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t + TermMut = PTHREAD_MUTEX_INITIALIZER, /* prevents statusThread from interfering with request*Volume */ + LowMut = PTHREAD_MUTEX_INITIALIZER, + HighMut = PTHREAD_MUTEX_INITIALIZER, + SendMut = PTHREAD_MUTEX_INITIALIZER; +static int Terminal = 1, Autoloader = 0; +static struct timeval Starttime; +static dest_t *Dest = 0; +static char *volatile SendAt = 0; +static volatile int SendSize = 0, ActSenders = 0; + +#ifdef __CYGWIN__ +#include <malloc.h> +#undef assert +#define assert(x) ((x) || (*(char *) 0 = 1)) +#endif + + + +static int kb2str(char *s, double v) +{ + const char *dim = "KMGT", *f; + + while (v > 10000.0) { + v /= 1024.0; + ++dim; + if (*dim == 0) { + v *= 1024.0*1024.0*1024.0*1024.0; + break; + } + } + if (v < 0) + f = " ??? "; + else if (v < 100) + f = "%4.1f %ci"; + else if (v < 10000) { + v = rint(v); + f = "%4.0f %ci"; + } else + f = "%5.lg "; + return sprintf(s,f,v,*dim); +} + + + +static void summary(unsigned long long numb, int numthreads) +{ + int h,m; + double secs,av; + char buf[256], *msg = buf; + struct timeval now; + + (void) gettimeofday(&now,0); + if (Status) + *msg++ = '\n'; + if ((Terminate == 1) && (numthreads == 0)) + numthreads = 1; + secs = now.tv_sec - Starttime.tv_sec + (double) now.tv_usec / 1000000 - (double) Starttime.tv_usec / 1000000; + assert(secs > 0); + numb >>= 10; + av = (double)(numb)/secs*numthreads; + h = (int) secs/3600; + m = (int) (secs - h * 3600)/60; + secs -= m * 60 + h * 3600; + if (numthreads > 1) + msg += sprintf(msg,"summary: %d x ",numthreads); + else + msg += sprintf(msg,"summary: "); + msg += kb2str(msg,numb); + msg += sprintf(msg,"Byte in "); + if (h > 0) + msg += sprintf(msg,"%d h %02d min ",h,m); + else if (m > 0) { + msg += sprintf(msg,"%2d min ",m); + msg += sprintf(msg,"%04.1f sec - average of ",secs); + } else + msg += sprintf(msg,"%4.1f sec - average of ",secs); + msg += kb2str(msg,av); + msg += sprintf(msg,"B/s"); + if (EmptyCount != 0) + msg += sprintf(msg,", %dx empty",EmptyCount); + if (FullCount != 0) + msg += sprintf(msg,", %dx full",FullCount); + *msg++ = '\n'; + *msg = '\0'; + if (Log != STDERR_FILENO) + (void) write(Log,buf,msg-buf); + (void) write(STDERR_FILENO,buf,msg-buf); +} + + + +static void cancelAll(void) +{ + dest_t *d = Dest; + do { + (void) pthread_cancel(d->thread); + if (d->result == 0) + d->result = "canceled"; + d = d->next; + } while (d); + if (Status) + (void) pthread_cancel(Reader); +} + + + +static RETSIGTYPE sigHandler(int signr) +{ + switch (signr) { + case SIGHUP: + case SIGINT: + ErrorOccurred = 1; + Terminate = 1; + (void) close(In); + if (TermQ[1] != -1) { + (void) write(TermQ[1],"0",1); + } + if (StartWrite > 0) + (void) pthread_cond_signal(&PercHigh); + if (StartRead < 1) + (void) pthread_cond_signal(&PercLow); + break; + default: + (void) raise(SIGABRT); + } +} + + + +/* Thread-safe replacement for usleep. Argument must be a whole + * number of microseconds to sleep. + */ +static int mt_usleep(unsigned long sleep_usecs) +{ + struct timespec tv; + tv.tv_sec = sleep_usecs / 1000000; + tv.tv_nsec = (sleep_usecs % 1000000) * 1000; + + do { + /* Sleep for the time specified in tv. If interrupted by a + * signal, place the remaining time left to sleep back into tv. + */ + if (0 == nanosleep(&tv, &tv)) + return 0; + } while (errno == EINTR); + return -1; +} + + + +static void statusThread(void) +{ + struct timeval last, now; + double in = 0, out = 0, total, diff, fill; + unsigned long long lin = 0, lout = 0; + int unwritten = 1; /* assumption: initially there is at least one unwritten block */ + fd_set readfds; + struct timeval timeout = {0,200000}; + int maxfd = 0; + + last = Starttime; +#ifdef __alpha + (void) mt_usleep(1000); /* needed on alpha (stderr fails with fpe on nan) */ +#endif + if (TermQ[0] != -1) + maxfd = TermQ[0]+1; + while ((Numin == 0) && (Terminate == 0) && (Finish == -1)) { + timeout.tv_sec = 0; + timeout.tv_usec = 200000; + FD_ZERO(&readfds); + if (TermQ[0] != -1) + FD_SET(TermQ[0],&readfds); + switch (select(maxfd,&readfds,0,0,&timeout)) { + case 0: continue; + case 1: break; + case -1: + if (errno == EINTR) + break; + default: abort(); + } + } + while (!Done) { + int err,numsender; + ssize_t nw; + char buf[256], *b = buf; + + timeout.tv_sec = 0; + timeout.tv_usec = 500000; + FD_ZERO(&readfds); + if (TermQ[0] != -1) + FD_SET(TermQ[0],&readfds); + err = select(maxfd,&readfds,0,0,&timeout); + switch (err) { + case 0: break; + case 1: return; + case -1: + if (errno == EINTR) + break; + default: abort(); + } + (void) gettimeofday(&now,0); + diff = now.tv_sec - last.tv_sec + (double) (now.tv_usec - last.tv_usec) / 1000000; + err = pthread_mutex_lock(&TermMut); + assert(0 == err); + err = sem_getvalue(&Buf2Dev,&unwritten); + assert(0 == err); + fill = (double)unwritten / (double)Numblocks * 100.0; + in = (double)(((Numin - lin) * Blocksize) >> 10); + in /= diff; + out = (double)(((Numout - lout) * Blocksize) >> 10); + out /= diff; + lin = Numin; + lout = Numout; + last = now; + total = (double)((Numout * Blocksize) >> 10); + fill = (fill < 0.0) ? 0.0 : fill; + b += sprintf(b,"\rin @ "); + b += kb2str(b,in); + numsender = NumSenders + MainOutOK - Hashers; + b += sprintf(b,"B/s, out @ "); + b += kb2str(b, out * numsender); + if (numsender != 1) + b += sprintf(b,"B/s, %d x ",numsender); + else + b += sprintf(b,"B/s, "); + b += kb2str(b,total); + b += sprintf(b,"B total, buffer %3.0f%% full",fill); +#ifdef NEED_IO_INTERLOCK + if (Log == STDERR_FILENO) { + int e; + e = pthread_mutex_lock(&LogMut); + assert(e == 0); + nw = write(STDERR_FILENO,buf,strlen(buf)); + e = pthread_mutex_unlock(&LogMut); + assert(e == 0); + } else +#endif + nw = write(STDERR_FILENO,buf,strlen(buf)); + err = pthread_mutex_unlock(&TermMut); + assert(0 == err); + if (nw == -1) /* stop trying to print status messages after a write error */ + break; + } +} + + + +static inline long long timediff(struct timespec *restrict t1, struct timespec *restrict t2) +{ + long long tdiff; + tdiff = (t1->tv_sec - t2->tv_sec) * 1000000; + tdiff += (t1->tv_nsec - t2->tv_nsec) / 1000; + if (tdiff < 0) + tdiff = 0; + return tdiff; +} + + + +static long long enforceSpeedLimit(unsigned long long limit, long long num, struct timespec *last) +{ + struct timespec now; + long long tdiff; + double dt; + long self = (long) pthread_self(); + + num += Blocksize; + if (num < 0) { + debugmsg("enforceSpeedLimit(%lld,%lld): thread %ld\n",limit,num,self); + return num; + } + (void) clock_gettime(ClockSrc,&now); + tdiff = timediff(&now,last); + dt = (double)tdiff * 1E-6; + if (((double)num/dt) > (double)limit) { + double req = (double)num/limit - dt; + long long w = (long long) (req * 1E6); + if (w >= TickTime) { + long long slept, ret; + (void) mt_usleep(w); + (void) clock_gettime(ClockSrc,last); + slept = timediff(last,&now); + ret = -(long long)((double)limit * (double)(slept-w) * 1E-6); + debugmsg("thread %ld: slept for %lld usec (planned for %lld), ret = %lld\n",self,slept,w,ret); + return ret; + } else { + debugmsg("thread %ld: request for sleeping %lld usec delayed\n",self,w); + /* + * Sleeping now would cause too much of a slowdown. So + * we defer this sleep until the sleeping time is + * longer than the tick time. Like this we can stay as + * close to the speed limit as possible. + */ + return num; + } + } + debugmsg("thread %ld: %lld/%g (%g) <= %g\n",self,num,dt,num/dt,(double)limit); + return num; +} + + + +static int promptInteractive(unsigned at, unsigned num) +{ + static const char prompt[] = "\nContinue with next volume? Press 'y' to continue or 'n' to finish..."; + static const char contmsg[] = "\nyes - continuing with next volume...\n"; + static const char donemsg[] = "\nno - input done, waiting for output to finish...\n"; + int err; + + err = pthread_mutex_lock(&TermMut); + assert(0 == err); + if (-1 == write(STDERR_FILENO,prompt,sizeof(prompt))) { + errormsg("error accessing controlling terminal for manual volume change request: %s\nConsider using autoload option, when running mbuffer without terminal.\n",strerror(errno)); + Terminate = 1; + pthread_exit((void *) -1); + } + for (;;) { + char c = 0; + if (-1 == read(STDERR_FILENO,&c,1) && (errno != EINTR)) { + errormsg("error accessing controlling terminal for manual volume change request: %s\nConsider using autoload option, when running mbuffer without terminal.\n",strerror(errno)); + Terminate = 1; + pthread_exit((void *) -1); + } + debugmsg("prompt input %c\n",c); + switch (c) { + case 'n': + case 'N': + Rest = num; + (void) write(STDERR_FILENO,donemsg,sizeof(donemsg)); + err = pthread_mutex_lock(&HighMut); + assert(err == 0); + err = sem_post(&Buf2Dev); + assert(err == 0); + err = pthread_cond_signal(&PercHigh); + assert(err == 0); + err = pthread_mutex_unlock(&HighMut); + assert(err == 0); + err = pthread_mutex_unlock(&TermMut); + assert(0 == err); + Finish = at; + if (Status) + pthread_exit(0); + return 0; + case 'y': + case 'Y': + (void) write(STDERR_FILENO,contmsg,sizeof(contmsg)); + err = pthread_mutex_unlock(&TermMut); + assert(0 == err); + return 1; + default:; + } + } +} + + + +static int requestInputVolume(unsigned at, unsigned num) +{ + static struct timeval volstart = {0,0}; + const char *cmd; + struct timeval now; + double diff; + unsigned min,hr; + char cmd_buf[15+strlen(Infile)]; + + debugmsg("requesting new volume for input\n"); + (void) gettimeofday(&now,0); + if (volstart.tv_sec) + diff = now.tv_sec - volstart.tv_sec + (double) (now.tv_usec - volstart.tv_usec) * 1E-6; + else + diff = now.tv_sec - Starttime.tv_sec + (double) (now.tv_usec - Starttime.tv_usec) * 1E-6; + if (diff > 3600) { + hr = (unsigned) (diff / 3600); + diff -= hr * 3600; + min = (unsigned) (diff / 60); + diff -= min * 60; + infomsg("time for reading volume: %u:%02u:%02f\n",hr,min,diff); + } else if (diff > 60) { + min = (unsigned) (diff / 60); + diff -= min * 60; + infomsg("time for reading volume: %02u:%02f\n",min,diff); + } else + infomsg("time for reading volume: %02fsec.\n",diff); + if (-1 == close(In)) + errormsg("error closing input: %s\n",strerror(errno)); + do { + if ((Autoloader) && (Infile)) { + int ret; + if (Autoload_cmd) { + cmd = Autoload_cmd; + } else { + (void) snprintf(cmd_buf, sizeof(cmd_buf), "mt -f %s offline", Infile); + cmd = cmd_buf; + } + infomsg("requesting new input volume with command '%s'\n",cmd); + ret = system(cmd); + if (0 < ret) { + warningmsg("error running \"%s\" to change volume in autoloader: exitcode %d\n",cmd,ret); + Terminate = 1; + pthread_exit((void *) 0); + } else if (0 > ret) { + errormsg("error starting \"%s\" to change volume in autoloader: %s\n", cmd, strerror(errno)); + Terminate = 1; + pthread_exit((void *) -1); + } + if (Autoload_time) { + infomsg("waiting for drive to get ready...\n"); + (void) sleep(Autoload_time); + } + } else { + if (0 == promptInteractive(at,num)) + return 0; + } + In = open(Infile, O_RDONLY | LARGEFILE | Direct); + if ((-1 == In) && (errno == EINVAL)) + In = open(Infile, O_RDONLY | Direct); + if (-1 == In) + errormsg("could not reopen input: %s\n",strerror(errno)); +#ifdef __sun + if (-1 == directio(In,DIRECTIO_ON)) + infomsg("direct I/O hinting failed for input: %s\n",strerror(errno)); +#endif + } while (In == -1); + (void) gettimeofday(&volstart,0); + diff = volstart.tv_sec - now.tv_sec + (double) (volstart.tv_usec - now.tv_usec) * 1E-6; + infomsg("tape-change took %fsec. - continuing with next volume\n",diff); + NumVolumes--; + if (Terminal && ! Autoloader) { + char msg[] = "\nOK - continuing...\n"; + (void) write(STDERR_FILENO,msg,sizeof(msg)); + } + return 1; +} + + + +static void releaseLock(void *l) +{ + int err = pthread_mutex_unlock((pthread_mutex_t *)l); + assert(err == 0); +} + + + +static void *inputThread(void *ignored) +{ + int fill = 0; + unsigned long long num; + int at = 0; + long long xfer = 0; + const double startread = StartRead, startwrite = StartWrite; + struct timespec last; +#ifndef __sun + int maxfd = TermQ[0] > In ? TermQ[0] + 1 : In + 1; + + if (Status != 0) + assert(TermQ[0] != -1); +#endif + (void) clock_gettime(ClockSrc,&last); + assert(ignored == 0); + infomsg("inputThread: starting with threadid %ld...\n",(long)pthread_self()); + for (;;) { + int err; + + if (startread < 1) { + err = pthread_mutex_lock(&LowMut); + assert(err == 0); + err = sem_getvalue(&Buf2Dev,&fill); + assert(err == 0); + if (fill == Numblocks - 1) { + debugmsg("inputThread: buffer full, waiting for it to drain.\n"); + pthread_cleanup_push(releaseLock,&LowMut); + err = pthread_cond_wait(&PercLow,&LowMut); + assert(err == 0); + pthread_cleanup_pop(0); + ++FullCount; + debugmsg("inputThread: low watermark reached, continuing...\n"); + } + err = pthread_mutex_unlock(&LowMut); + assert(err == 0); + } + if (Terminate) { /* for async termination requests */ + debugmsg("inputThread: terminating early upon request...\n"); + if (-1 == close(In)) + errormsg("error closing input: %s\n",strerror(errno)); + if (Status) + pthread_exit((void *)1); + return (void *) 1; + } + err = sem_wait(&Dev2Buf); /* Wait for one or more buffer blocks to be free */ + assert(err == 0); + num = 0; + do { + int in; +#ifndef __sun + if (Status != 0) { + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(TermQ[0],&readfds); + FD_SET(In,&readfds); + err = select(maxfd,&readfds,0,0,0); + debugiomsg("inputThread: select(%d, {%d,%d}, 0, 0, 0) = %d\n", maxfd,In,TermQ[0],err); + assert((err > 0) || (errno == EBADF)); + if (FD_ISSET(TermQ[0],&readfds)) + return (void *)-1; + assert(FD_ISSET(In,&readfds)); + } +#endif + in = read(In,Buffer[at] + num,Blocksize - num); + debugiomsg("inputThread: read(In, Buffer[%d] + %llu, %llu) = %d\n", at, num, Blocksize - num, in); + if (in > 0) { + num += in; + } else if ((0 == in) && (Terminal||Autoloader) && (NumVolumes != 1)) { + if (0 == requestInputVolume(at,num)) + return 0; + } else if ((-1 == in) && (errno == EIO) && (Terminal||Autoloader) && (NumVolumes != 1)) { + requestInputVolume(at,num); + } else if (in <= 0) { + /* error or end-of-file */ + if ((-1 == in) && (Terminate == 0)) + errormsg("inputThread: error reading at offset 0x%llx: %s\n",Numin*Blocksize,strerror(errno)); + Rest = num; + Finish = at; + debugmsg("inputThread: last block has %llu bytes\n",num); + err = pthread_mutex_lock(&HighMut); + assert(err == 0); + err = sem_post(&Buf2Dev); + assert(err == 0); + err = pthread_cond_signal(&PercHigh); + assert(err == 0); + err = pthread_mutex_unlock(&HighMut); + assert(err == 0); + infomsg("inputThread: exiting...\n"); + if (Status) + pthread_exit((void *) in); + return (void *) in; + } + } while (num < Blocksize); + if (MaxReadSpeed) + xfer = enforceSpeedLimit(MaxReadSpeed,xfer,&last); + err = sem_post(&Buf2Dev); + assert(err == 0); + if (startwrite > 0) { + err = pthread_mutex_lock(&HighMut); + assert(err == 0); + err = sem_getvalue(&Buf2Dev,&fill); + assert(err == 0); + if (((double) fill / (double) Numblocks) >= startwrite) { + err = pthread_cond_signal(&PercHigh); + assert(err == 0); + } + err = pthread_mutex_unlock(&HighMut); + assert(err == 0); + } + if (++at == Numblocks) + at = 0; + Numin++; + } +} + + + +static inline int syncSenders(char *b, int s) +{ + static volatile int size = 0; + static char *volatile buf = 0; + int err; + + err = pthread_mutex_lock(&SendMut); + assert(err == 0); + if (b) { + buf = b; + size = s; + } + if (s < 0) + --NumSenders; + if (--ActSenders) { + debugiomsg("syncSenders(%p,%d): ActSenders = %d\n",b,s,ActSenders); + pthread_cleanup_push(releaseLock,&SendMut); + err = pthread_cond_wait(&SendCond,&SendMut); + assert(err == 0); + pthread_cleanup_pop(1); + debugiomsg("syncSenders(): continue\n"); + return 0; + } else { + ActSenders = NumSenders + 1; + assert((buf != 0) || Terminate); + SendAt = buf; + SendSize = size; + buf = 0; + err = pthread_mutex_unlock(&SendMut); + assert(err == 0); + err = sem_post(&Dev2Buf); + assert(err == 0); + debugiomsg("syncSenders(): send %d@%p, BROADCAST\n",SendSize,SendAt); + err = pthread_cond_broadcast(&SendCond); + assert(err == 0); + return 1; + } +} + + + +static inline void terminateSender(int fd, dest_t *d, int ret) +{ + debugmsg("terminating operation on %s\n",d->arg); + if (-1 != fd) { + int err; + infomsg("syncing %s...\n",d->arg); + do + err = fsync(fd); + while ((err != 0) && (errno == EINTR)); + if (err != 0) { + if ((errno == EINVAL) || (errno == EBADRQC)) { + infomsg("syncing unsupported on %s: omitted.\n",d->arg); + } else { + warningmsg("unable to sync %s: %s\n",d->arg,strerror(errno)); + } + } + if (-1 == close(fd)) + errormsg("error closing file %s: %s\n",d->arg,strerror(errno)); + } + if (ret != 0) { + int ret = syncSenders(0,-1); + debugmsg("terminateSender(%s): sendSender(0,-1) = %d\n",d->arg,ret); + } + pthread_exit((void *) ret); +} + + + +static void *senderThread(void *arg) +{ + unsigned long long outsize = Blocksize; + dest_t *dest = (dest_t *)arg; + int out = dest->fd; +#ifdef HAVE_SENDFILE + int sendout = 1; +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + struct stat st; + + debugmsg("sender(%s): checking output device...\n",dest->arg); + if (-1 == fstat(out,&st)) + warningmsg("could not stat output %s: %s\n",dest->arg,strerror(errno)); + else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { + infomsg("blocksize is %d bytes on output device\n",st.st_blksize); + if ((Blocksize < st.st_blksize) || (Blocksize % st.st_blksize != 0)) { + warningmsg("Blocksize should be a multiple of the blocksize of the output device!\n" + "This can cause problems with some device/OS combinations...\n" + "Blocksize on output device %s is %d (transfer block size is %lld)\n", dest->arg, st.st_blksize, Blocksize); + if (SetOutsize) { + errormsg("unable to set output blocksize\n"); + dest->result = strerror(errno); + terminateSender(out,dest,1); + } + } else { + if (SetOutsize) { + infomsg("setting output blocksize to %d\n",st.st_blksize); + outsize = st.st_blksize; + } + } + } else + infomsg("no device on output stream %s\n",dest->arg); +#endif + debugmsg("sender(%s): starting...\n",dest->arg); + for (;;) { + int size, num = 0; + (void) syncSenders(0,0); + size = SendSize; + if (0 == size) { + debugmsg("senderThread(\"%s\"): done.\n",dest->arg); + terminateSender(out,dest,0); + return 0; /* for lint */ + } + if (Terminate) { + infomsg("senderThread(\"%s\"): terminating early upon request...\n",dest->arg); + dest->result = "canceled"; + terminateSender(out,dest,1); + } + do { + unsigned long long rest = size - num; + int ret; + assert(size >= num); +#ifdef HAVE_SENDFILE + if (sendout) { + off_t baddr = (off_t) (SendAt+num); + ret = sendfile(out,SFV_FD_SELF,&baddr,rest > outsize ? outsize : rest); + debugiomsg("sender(%s): sendfile(%d, SFV_FD_SELF, &%p, %llu) = %d\n", dest->arg, dest->fd, (void*)baddr, (unsigned long long) (rest > outsize ? outsize : rest), ret); + if ((ret == -1) && ((errno == EINVAL) || (errno == EOPNOTSUPP))) { + sendout = 0; + debugmsg("sender(%s): sendfile unsupported - falling back to write\n", dest->arg); + continue; + } + } else +#endif + { + char *baddr = SendAt+num; + ret = write(out,baddr,rest > outsize ? outsize :rest); + debugiomsg("sender(%s): writing %llu@0x%p: ret = %d\n",dest->arg,rest,(void*)baddr,ret); + } + if (-1 == ret) { + errormsg("error writing to %s: %s\n",dest->arg,strerror(errno)); + dest->result = strerror(errno); + terminateSender(out,dest,1); + } + num += ret; + } while (num != size); + } +} + + + +static void *hashThread(void *arg) +{ +#ifdef HAVE_MD5 + dest_t *dest = (dest_t *) arg; +#ifdef HAVE_LIBMHASH + int algo = dest->fd; + + MHASH ctxt = mhash_init(algo); + assert(ctxt != MHASH_FAILED); +#else + MD5_INIT(MD5ctxt); +#endif + debugmsg("hashThread(): starting...\n"); + for (;;) { + int size; + + (void) syncSenders(0,0); + size = SendSize; + if (0 == size) { + size_t ds; + unsigned char hashvalue[128]; + char *msg, *m; + const char *an; + int i; + + msg = malloc(300); + m = msg; + debugmsg("hashThread(): done.\n"); +#ifdef HAVE_LIBMHASH + mhash_deinit(ctxt,hashvalue); + an = (const char *) mhash_get_hash_name_static(algo); + ds = mhash_get_block_size(algo); +#else + MD5_END(hashvalue,MD5ctxt); + an = "md5"; + ds = 16; +#endif + assert(sizeof(hashvalue) >= ds); + m += sprintf(m,"%s hash: ",an); + for (i = 0; i < ds; ++i) + m += sprintf(m,"%02x",(unsigned int)hashvalue[i]); + *m++ = '\n'; + *m = 0; + dest->result = msg; + pthread_exit((void *) msg); + return 0; /* for lint */ + } + if (Terminate) { + (void) syncSenders(0,-1); + infomsg("hashThread(): terminating early upon request...\n"); + pthread_exit((void *) 0); + } + debugiomsg("hashThread(): hashing %d@0x%p\n",size,(void*)SendAt); +#ifdef HAVE_LIBMHASH + mhash(ctxt,SendAt,size); +#else + MD5_UPDATE(MD5ctxt,SendAt,size); +#endif + } +#endif +} + + +static int requestOutputVolume(int out, const char *outfile) +{ + static struct timeval volstart = {0,0}; + struct timeval now; + double diff; + unsigned min,hr; + + if (!outfile) { + errormsg("End of volume, but not end of input:\n" + "Output file must be given (option -o) for multi volume support!\n"); + return -1; + } + infomsg("end of volume - last block on volume: %lld\n",Numout); + (void) gettimeofday(&now,0); + if (volstart.tv_sec) + diff = now.tv_sec - volstart.tv_sec + (double) (now.tv_usec - volstart.tv_usec) * 1E-6; + else + diff = now.tv_sec - Starttime.tv_sec + (double) (now.tv_usec - Starttime.tv_usec) * 1E-6; + if (diff > 3600) { + hr = (unsigned) (diff / 3600); + diff -= hr * 3600; + min = (unsigned) (diff / 60); + diff -= min * 60; + infomsg("time for writing volume: %u:%02u:%02f\n",hr,min,diff); + } else if (diff > 60) { + min = (unsigned) (diff / 60); + diff -= min * 60; + infomsg("time for writing volume: %02u:%02f\n",min,diff); + } else + infomsg("time for writing volume: %02fsec.\n",diff); + if (-1 == close(out)) + errormsg("error closing output %s: %s\n",outfile,strerror(errno)); + do { + mode_t mode; + if (Autoloader) { + const char default_cmd[] = "mt -f %s offline"; + char cmd_buf[sizeof(default_cmd)+strlen(outfile)]; + const char *cmd = Autoload_cmd; + int err; + + if (cmd == 0) { + (void) snprintf(cmd_buf, sizeof(cmd_buf), default_cmd, Infile); + cmd = cmd_buf; + } + infomsg("requesting new output volume with command '%s'\n",cmd); + err = system(cmd); + if (0 < err) { + errormsg("error running \"%s\" to change volume in autoloader - exitcode %d\n", cmd, err); + Autoloader = 0; + return -1; + } else if (0 > err) { + errormsg("error starting \"%s\" to change volume in autoloader: %s\n", cmd, strerror(errno)); + Autoloader = 0; + return -1; + } + if (Autoload_time) { + infomsg("waiting for drive to get ready...\n"); + (void) sleep(Autoload_time); + } + } else { + int err; + char c = 0, msg[] = "\nvolume full - insert new media and press return when ready...\n"; + if (Terminal == 0) { + errormsg("End of volume, but not end of input.\n" + "Specify an autoload command, if you are working without terminal.\n"); + return -1; + } + err = pthread_mutex_lock(&TermMut); + assert(0 == err); + if (-1 == write(STDERR_FILENO,msg,sizeof(msg))) { + errormsg("error accessing controlling terminal for manual volume change request: %s\nConsider using autoload option, when running mbuffer without terminal.\n",strerror(errno)); + return -1; + } + do { + if (-1 == read(STDERR_FILENO,&c,1) && (errno != EINTR)) { + errormsg("error accessing controlling terminal for manual volume change request: %s\nConsider using autoload option, when running mbuffer without terminal.\n",strerror(errno)); + return -1; + } + } while (c != '\n'); + err = pthread_mutex_unlock(&TermMut); + assert(0 == err); + } + mode = O_WRONLY|O_TRUNC|OptSync|LARGEFILE|Direct; + if (strncmp(outfile,"/dev/",5)) + mode |= Nooverwrite|O_CREAT; + out = open(outfile,mode,0666); + if (-1 == out) + errormsg("error reopening output file: %s\n",strerror(errno)); +#ifdef __sun + if (-1 == directio(out,DIRECTIO_ON)) + infomsg("direct I/O hinting failed for output: %s\n",strerror(errno)); +#endif + } while (-1 == out); + (void) gettimeofday(&volstart,0); + diff = volstart.tv_sec - now.tv_sec + (double) (volstart.tv_usec - now.tv_usec) * 1E-6; + infomsg("tape-change took %fsec. - continuing with next volume\n",diff); + if (Terminal && ! Autoloader) { + char msg[] = "\nOK - continuing...\n"; + (void) write(STDERR_FILENO,msg,sizeof(msg)); + } + return out; +} + + + +static int checkIncompleteOutput(int out, const char *outfile) +{ + static unsigned long mulretry = 0; /* well this isn't really good design, + but better than a global variable */ + + debugmsg("Outblocksize = %ld, mulretry = %lu\n",Outblocksize,mulretry); + if ((0 != mulretry) || (0 == Outblocksize)) { + out = requestOutputVolume(out,outfile); + debugmsg("resetting outputsize to normal\n"); + if (0 != mulretry) { + Outsize = mulretry; + mulretry = 0; + } + } else { + debugmsg("setting to new outputsize (end of device)\n"); + mulretry = Outsize; + Outsize = Outblocksize; + } + return out; +} + + + +static void terminateOutputThread(dest_t *d, int status) +{ + int err; + + infomsg("outputThread: syncing %s...\n",d->arg); + do + err = fsync(d->fd); + while ((err != 0) && (errno == EINTR)); + if (err != 0) { + if ((errno == EINVAL) || (errno == EBADRQC)) { + infomsg("syncing unsupported on %s: omitted.\n",d->arg); + } else { + warningmsg("unable to sync %s: %s\n",d->arg,strerror(errno)); + } + } + infomsg("outputThread: finished - exiting...\n"); + if (-1 == close(d->fd)) + errormsg("error closing %s: %s\n",d->arg,strerror(errno)); + if (TermQ[1] != -1) { + err = write(TermQ[1],"0",1); + if (err == -1) + errormsg("error writing to termination queue: %s\n",strerror(errno)); + } + if (status) { + (void) sem_post(&Dev2Buf); + (void) pthread_cond_broadcast(&SendCond); + } + Done = 1; + pthread_exit((void *)status); +} + + + +static void *outputThread(void *arg) +{ + dest_t *dest = (dest_t *) arg; + unsigned at = 0; + int fill = 0, haderror = 0, out, multipleSenders; +#ifdef HAVE_SENDFILE + int sendout = 1; +#endif + const double startwrite = StartWrite, startread = StartRead; + unsigned long long blocksize = Blocksize; + long long xfer = 0; + struct timespec last; + + assert(NumSenders >= 0); + if (dest->next) { + int ret; + dest_t *d = dest->next; + debugmsg("NumSenders = %d\n",NumSenders); + ActSenders = NumSenders + 1; + ret = pthread_mutex_init(&SendMut,0); + assert(ret == 0); + ret = pthread_cond_init(&SendCond,0); + assert(ret == 0); + do { + if (d->arg == 0) { + debugmsg("creating hash thread with algorithm %s\n",d->name); + ret = pthread_create(&d->thread,0,hashThread,d); + assert(ret == 0); + } else if (d->fd != -1) { + debugmsg("creating sender for %s\n",d->arg); + ret = pthread_create(&d->thread,0,senderThread,d); + assert(ret == 0); + } else { + debugmsg("outputThread: ignoring destination %s\n",d->arg); + d->name = 0; + } + d = d->next; + } while (d); + } + multipleSenders = (NumSenders > 0); + dest->result = 0; + out = dest->fd; + if (startwrite > 0) { + int err; + err = pthread_mutex_lock(&HighMut); + assert(err == 0); + debugmsg("outputThread: delaying start until buffer reaches high watermark\n"); + pthread_cleanup_push(releaseLock,&HighMut); + err = pthread_cond_wait(&PercHigh,&HighMut); + assert(err == 0); + pthread_cleanup_pop(0); + debugmsg("outputThread: high watermark reached, starting...\n"); + err = pthread_mutex_unlock(&HighMut); + assert(err == 0); + } else + infomsg("outputThread: starting output on %s...\n",dest->arg); + /* initialize last to 0, because we don't want to wait initially */ + (void) clock_gettime(ClockSrc,&last); + for (;;) { + unsigned long long rest = blocksize; + int err; + + if ((startwrite > 0) && (fill <= 0)) { + assert(fill == 0); + err = pthread_mutex_lock(&HighMut); + assert(err == 0); + err = sem_getvalue(&Buf2Dev,&fill); + assert(err == 0); + if (fill == 0) { + debugmsg("outputThread: buffer empty, waiting for it to fill\n"); + pthread_cleanup_push(releaseLock,&HighMut); + err = pthread_cond_wait(&PercHigh,&HighMut); + assert(err == 0); + pthread_cleanup_pop(0); + ++EmptyCount; + debugmsg("outputThread: high watermark reached, continuing...\n"); + (void) clock_gettime(ClockSrc,&last); + } + err = pthread_mutex_unlock(&HighMut); + assert(err == 0); + } else + --fill; + err = sem_wait(&Buf2Dev); + assert(err == 0); + if (Terminate) { + infomsg("outputThread: terminating upon termination request...\n"); + dest->result = "canceled"; + terminateOutputThread(dest,1); + } + if (Finish == at) { + err = sem_getvalue(&Buf2Dev,&fill); + assert(err == 0); + if ((fill == 0) && (0 == Rest)) { + if (multipleSenders) + (void) syncSenders((char*)0xdeadbeef,0); + infomsg("outputThread: finished - exiting...\n"); + terminateOutputThread(dest,haderror); + } else { + blocksize = rest = Rest; + debugmsg("outputThread: last block has %llu bytes\n",(unsigned long long)Rest); + } + } + if (multipleSenders) + (void) syncSenders(Buffer[at],blocksize); + /* switch output volume if -D <size> has been reached */ + if ( (OutVolsize != 0) && (Numout > 0) && (Numout % (OutVolsize/Blocksize)) == 0 ) { + /* Sleep to let status thread "catch up" so that the displayed total is a multiple of OutVolsize */ + (void) mt_usleep(500000); + out = requestOutputVolume(out,dest->name); + if (out == -1) { + haderror = 1; + dest->result = strerror(errno); + } + } + do { + /* use Outsize which could be the blocksize of the device (option -d) */ + int num; + if (haderror) { + if (NumSenders == 0) + Terminate = 1; + num = (int)rest; + } else +#ifdef HAVE_SENDFILE + if (sendout) { + off_t baddr = (off_t) (Buffer[at] + blocksize - rest); + num = sendfile(out,SFV_FD_SELF,&baddr,(size_t)(rest > Outsize ? Outsize : rest)); + debugiomsg("outputThread: sendfile(%d, SFV_FD_SELF, &(Buffer[%d] + %llu), %llu) = %d\n", out, at, blocksize - rest, rest > Outsize ? Outsize : rest, num); + if ((num == -1) && ((errno == EOPNOTSUPP) || (errno == EINVAL))) { + infomsg("sendfile not supported - falling back to write...\n"); + sendout = 0; + continue; + } + } else +#endif + { + num = write(out,Buffer[at] + blocksize - rest, rest > Outsize ? Outsize : rest); + debugiomsg("outputThread: writing %lld@0x%p: ret = %d\n",rest > Outsize ? Outsize : rest,Buffer[at] + blocksize - rest,num); + } + if ((-1 == num) && (Terminal||Autoloader) && ((errno == ENOMEM) || (errno == ENOSPC))) { + /* request a new volume - but first check + * whether we are really at the + * end of the device */ + out = checkIncompleteOutput(out,dest->name); + if (out == -1) + haderror = 1; + continue; + } else if (-1 == num) { + dest->result = strerror(errno); + errormsg("outputThread: error writing to %s at offset 0x%llx: %s\n",dest->arg,(long long)Blocksize*Numout+blocksize-rest,strerror(errno)); + MainOutOK = 0; + if (NumSenders == 0) { + debugmsg("outputThread: terminating...\n"); + Terminate = 1; + err = sem_post(&Dev2Buf); + assert(err == 0); + terminateOutputThread(dest,1); + } + debugmsg("outputThread: %d senders remaining - continuing...\n",NumSenders); + haderror = 1; + } + rest -= num; + } while (rest > 0); + if (multipleSenders == 0) { + err = sem_post(&Dev2Buf); + assert(err == 0); + } + if (MaxWriteSpeed) + xfer = enforceSpeedLimit(MaxWriteSpeed,xfer,&last); + if (Pause) + (void) mt_usleep(Pause); + if (Finish == at) { + err = sem_getvalue(&Buf2Dev,&fill); + assert(err == 0); + if (fill == 0) { + if (multipleSenders) + (void) syncSenders((char*)0xdeadbeef,0); + terminateOutputThread(dest,0); + return 0; /* make lint happy */ + } + } + if (Numblocks == ++at) + at = 0; + if (startread < 1) { + err = pthread_mutex_lock(&LowMut); + assert(err == 0); + err = sem_getvalue(&Buf2Dev,&fill); + assert(err == 0); + if (((double)fill / (double)Numblocks) < startread) { + err = pthread_cond_signal(&PercLow); + assert(err == 0); + } + err = pthread_mutex_unlock(&LowMut); + assert(err == 0); + } + Numout++; + } +} + + + +static void version(void) +{ + (void) fprintf(stderr, + "mbuffer version "VERSION"\n"\ + "Copyright 2001-2011 - T. Maier-Komor\n"\ + "License: GPLv3 - see file LICENSE\n"\ + "This program comes with ABSOLUTELY NO WARRANTY!!!\n" + "Donations via PayPal to thomas@maier-komor.de are welcome and support this work!\n" + "\n" + ); + exit(EXIT_SUCCESS); +} + + + +static void usage(void) +{ + const char *dim = "bkMGTP"; + unsigned long long m = Numblocks * Blocksize; + while (m >= 10000) { + m >>= 10; + ++dim; + } + (void) fprintf(stderr, + "usage: mbuffer [Options]\n" + "Options:\n" + "-b <num> : use <num> blocks for buffer (default: %ld)\n" + "-s <size> : use blocks of <size> bytes for processing (default: %llu)\n" +#if defined(_SC_AVPHYS_PAGES) && defined(_SC_PAGESIZE) && !defined(__CYGWIN__) || defined(__FreeBSD__) + "-m <size> : memory <size> of buffer in b,k,M,G,%% (default: 2%% = %llu%c)\n" +#else + "-m <size> : memory <size> of buffer in b,k,M,G,%% (default: %llu%c)\n" +#endif +#ifdef _POSIX_MEMLOCK_RANGE + "-L : lock buffer in memory (unusable with file based buffers)\n" +#endif + "-d : use blocksize of device for output\n" + "-D <size> : assumed output device size (default: infinite/auto-detect)\n" + "-P <num> : start writing after buffer has been filled more than <num>%%\n" + "-p <num> : start reading after buffer has been filled less than <num>%%\n" + "-i <file> : use <file> for input\n" + "-o <file> : use <file> for output (this option can be passed MULTIPLE times)\n" + "--append : append to output file (must be passed before -o)\n" + "--truncate : truncate next file (must be passed before -o)\n" + "-I <h>:<p> : use network port <port> as input, allow only host <h> to connect\n" + "-I <p> : use network port <port> as input\n" + "-O <h>:<p> : output data to host <h> and port <p> (MUTLIPLE outputs supported)\n" + "-n <num> : <num> volumes for input, '0' to prompt interactively\n" + "-t : use memory mapped temporary file (for huge buffer)\n" + "-T <file> : as -t but uses <file> as buffer\n" + "-l <file> : use <file> for logging messages\n" + "-u <num> : pause <num> milliseconds after each write\n" + "-r <rate> : limit read rate to <rate> B/s, where <rate> can be given in b,k,M,G\n" + "-R <rate> : same as -r for writing; use eiter one, if your tape is too fast\n" + "-f : overwrite existing files\n" + "-a <time> : autoloader which needs <time> seconds to reload\n" + "-A <cmd> : issue command <cmd> to request new volume\n" + "-v <level> : set verbose level to <level> (valid values are 0..6)\n" + "-q : quiet - do not display the status on stderr\n" + "-c : write with synchronous data integrity support\n" + "-e : stop processing on any kind of error\n" +#ifdef O_DIRECT + "--direct : open input and output with O_DIRECT\n" +#endif +#if defined HAVE_LIBCRYPTO || defined HAVE_LIBMD5 || defined HAVE_LIBMHASH + "-H\n" + "--md5 : generate md5 hash of transfered data\n" + "--hash <a> : use alogritm <a>, if <a> is 'list' possible algorithms are listed\n" +#endif + "-4 : force use of IPv4\n" + "-6 : force use of IPv6\n" + "-0 : use IPv4 or IPv6\n" + "-V\n" + "--version : print version information\n" + "Unsupported buffer options: -t -Z -B\n" + ,Numblocks + ,Blocksize + ,m,*dim + ); + exit(EXIT_SUCCESS); +} + + + +static unsigned long long calcint(const char **argv, int c, unsigned long long d) +{ + char ch; + unsigned long long i; + + switch (sscanf(argv[c],"%llu%c",&i,&ch)) { + default: + assert(0); + break; + case 2: + if (i == 0) + fatal("invalid argument - must be > 0\n"); + switch (ch) { + case 'k': + case 'K': + i <<= 10; + return i; + case 'm': + case 'M': + i <<= 20; + return i; + case 'g': + case 'G': + i <<= 30; + return i; + case 't': + case 'T': + i <<= 40; + return i; + case '%': + if (i >= 100) + fatal("invalid value for percentage (must be < 100)\n"); + return i; + case 'b': + case 'B': + if (i < 128) + fatal("invalid value for number of bytes\n"); + return i; + default: + if (argv[c][-2] == '-') + fatal("unrecognized size charakter \"%c\" for option \"%s\"\n",ch,&argv[c][-2]); + else + fatal("unrecognized size charakter \"%c\" for option \"%s\"\n",ch,argv[c-1]); + return d; + } + case 1: + if (i <= 100) { + if (argv[c][-2] == '-') + fatal("invalid low value for option \"%s\" - missing suffix?\n",&argv[c][-2]); + else + fatal("invalid low value for option \"%s\" - missing suffix?\n",argv[c-1]); + } + return i; + case 0: + break; + } + errormsg("unrecognized argument \"%s\" for option \"%s\"\n",argv[c],argv[c-1]); + return d; +} + + + +static int argcheck(const char *opt, const char **argv, int *c, int argc) +{ + if (strncmp(opt,argv[*c],strlen(opt))) + return 1; + if (strlen(argv[*c]) > 2) + argv[*c] += 2; + else { + (*c)++; + if (*c == argc) + fatal("missing argument to option %s\n",opt); + } + return 0; +} + + + +static void addHashAlgorithm(const char *name) +{ + const char *algoname = ""; + int algo = 0; +#if HAVE_LIBMHASH + int numalgo = mhash_count(); + + while (algo <= numalgo) { + algoname = (const char *) mhash_get_hash_name_static(algo); + if (algoname && (strcmp(algoname,name) == 0)) + break; + ++algo; + } +#else + algoname = "MD5"; +#endif + if (strcmp(algoname,name) == 0) { + dest_t *dest = malloc(sizeof(dest_t)); + bzero(dest,sizeof(dest_t)); + dest->name = name; + dest->fd = algo; + if (Dest) { + dest->next = Dest->next; + Dest->next = dest; + } else { + Dest = dest; + dest->next = 0; + } + debugmsg("enabled hash algorithm %s\n",name); + ++NumSenders; + ++Hashers; + } else + fatal("invalid or unsupported hash function %s\n",name); +} + + +static void openDestinationFiles(dest_t *d) +{ + while (d) { + if (d->fd == -1) { + if (0 == strncmp(d->arg,"/dev/",5)) + d->mode &= ~O_EXCL; + d->fd = open(d->arg,d->mode,0666); + if ((-1 == d->fd) && (errno == EINVAL)) { + d->mode &= ~LARGEFILE; + d->fd = open(d->arg,d->mode,0666); + } + if ((-1 == d->fd) && (errno == EINVAL)) { + d->mode &= ~O_TRUNC; + d->fd = open(d->arg,d->mode,0666); + } + if (-1 == d->fd) { + d->result = strerror(errno); + errormsg("unable to open output %s: %s\n",d->arg,strerror(errno)); + } else { + debugmsg("successfully opened destination file %s with fd %d\n",d->arg,d->fd); + } + } + if (-1 == d->fd) { + d->name = 0; /* tag destination as unstartable */ + --NumSenders; + } +#ifdef __sun + else if (d->arg) { + if (0 == directio(d->fd,DIRECTIO_ON)) + infomsg("direct I/O hinting enabled for output to %s\n",d->arg); + else + infomsg("direct I/O hinting failed for output to %s: %s\n",d->arg,strerror(errno)); + } +#endif + d = d->next; + } +} + +int main(int argc, const char **argv) +{ + unsigned long long totalmem = 0; + int optMset = 0, optSset = 0, optBset = 0, optMode = O_EXCL, numOut = 0; + int numstdout = 0, numthreads = 0; + long mxnrsem; + int c, fl, err; + sigset_t signalSet; +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + struct stat st; +#endif + unsigned short netPortIn = 0; + unsigned short netPortOut = 0; + char *argv0 = strdup(argv[0]), *progname, null; + const char *outfile = 0; + struct sigaction sig; + dest_t *dest = 0; +#if defined(_SC_AVPHYS_PAGES) && defined(_SC_PAGESIZE) && !defined(__CYGWIN__) + long pgsz, nump; + + TickTime = 1000000 / sysconf(_SC_CLK_TCK); + pgsz = sysconf(_SC_PAGESIZE); + assert(pgsz > 0); + nump = sysconf(_SC_AVPHYS_PAGES); + assert(nump > 0); + Blocksize = pgsz; + Numblocks = nump/50; +#elif defined(__FreeBSD__) + size_t nump_size = sizeof(nump_size); + unsigned long pgsz,nump; + sysctlbyname("hw.availpages", &nump, &nump_size, NULL, 0); + pgsz = sysconf(_SC_PAGESIZE); + assert(pgsz > 0); +#endif +#if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0) && defined(CLOCK_MONOTONIC) + if (sysconf(_SC_MONOTONIC_CLOCK) > 0) + ClockSrc = CLOCK_MONOTONIC; +#endif + progname = basename(argv0); + PrefixLen = strlen(progname) + 2; + Prefix = malloc(PrefixLen); + (void) strcpy(Prefix,progname); + Prefix[PrefixLen - 2] = ':'; + Prefix[PrefixLen - 1] = ' '; + for (c = 1; c < argc; c++) { + if (!argcheck("-s",argv,&c,argc)) { + Blocksize = Outsize = calcint(argv,c,Blocksize); + optSset = 1; + debugmsg("Blocksize = %llu\n",Blocksize); + if (Blocksize < 100) + fatal("cannot set blocksize as percentage of total physical memory\n"); + } else if (!strcmp("--append",argv[c])) { + optMode = O_APPEND; + debugmsg("append to next file\n"); + } else if (!strcmp("--truncate",argv[c])) { + optMode = O_TRUNC; + debugmsg("truncate next file\n"); + } else if (!argcheck("-m",argv,&c,argc)) { + totalmem = calcint(argv,c,totalmem); + optMset = 1; + if (totalmem < 100) { +#if defined(_SC_AVPHYS_PAGES) && defined(_SC_PAGESIZE) && !defined(__CYGWIN__) || defined(__FreeBSD__) + totalmem = ((unsigned long long) nump * pgsz * totalmem) / 100 ; +#else + fatal("Unable to determine page size or amount of available memory - please specify an absolute amount of memory.\n"); +#endif + } + debugmsg("totalmem = %lluk\n",totalmem>>10); + } else if (!argcheck("-b",argv,&c,argc)) { + long nb = strtol(argv[c],0,0); + if ((nb == 0) && (errno == EINVAL)) { + errormsg("invalid argument to option -b: \"%s\"\n",argv[c]); + } else { + Numblocks = nb; + optBset = 1; + } + debugmsg("Numblocks = %llu\n",Numblocks); + } else if (!strcmp("--tcpbuffer",argv[c])) { + TCPBufSize = calcint(argv,++c,TCPBufSize); + debugmsg("TCPBufSize = %lu\n",TCPBufSize); + } else if (!argcheck("-d",argv,&c,argc)) { +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + SetOutsize = 1; + debugmsg("setting output size according to the blocksize of the device\n"); +#else + fatal("cannot determine blocksize of device (unsupported by OS)\n"); +#endif + } else if (!argcheck("-v",argv,&c,argc)) { + int verb; + if (c == argc) + fatal("missing argument for option -v\n"); + verb = strtol(argv[c],0,0); + if ((verb == 0) && (errno == EINVAL)) + errormsg("invalid argument to option -v: \"%s\"\n",argv[c]); + else + Verbose = verb; + debugmsg("Verbose = %d\n",Verbose); +#if defined(_SC_AVPHYS_PAGES) && defined(_SC_PAGESIZE) && !defined(__CYGWIN__) + debugmsg("total # of phys pages: %li (pagesize %li)\n",nump,pgsz); +#endif + debugmsg("default buffer set to %d blocks of %lld bytes\n",Numblocks,Blocksize); + } else if (!argcheck("-u",argv,&c,argc)) { + + long p = strtol(argv[c],0,0); + if ((p == 0) && (errno == EINVAL)) + errormsg("invalid argument to option -u: \"%s\"\n",argv[c]); + else + Pause = p; + debugmsg("Pause = %d\n",Pause); + } else if (!argcheck("-r",argv,&c,argc)) { + MaxReadSpeed = calcint(argv,c,0); + debugmsg("MaxReadSpeed = %lld\n",MaxReadSpeed); + } else if (!argcheck("-R",argv,&c,argc)) { + MaxWriteSpeed = calcint(argv,c,0); + debugmsg("MaxWriteSpeed = %lld\n",MaxWriteSpeed); + } else if (!argcheck("-n",argv,&c,argc)) { + long nv = strtol(argv[c],0,0); + if ((nv < 0) || ((nv == 0) && (errno == EINVAL))) + fatal("invalid argument to option -n: \"%s\"\n",argv[c]); + else + NumVolumes = nv; + if (NumVolumes < 0) + fatal("argument for number of volumes must be > 0\n"); + debugmsg("NumVolumes = %d\n",NumVolumes); + } else if (!argcheck("-i",argv,&c,argc)) { + if (strcmp(argv[c],"-")) { + Infile = argv[c]; + debugmsg("Infile = %s\n",Infile); + } else { + Infile = STDIN_FILENO; + debugmsg("Infile is stdin\n"); + } + } else if (!argcheck("-o",argv,&c,argc)) { + dest_t *dest = malloc(sizeof(dest_t)); + if (strcmp(argv[c],"-")) { + debugmsg("output file: %s\n",argv[c]); + dest->arg = argv[c]; + dest->name = argv[c]; + dest->fd = -1; + dest->mode = O_CREAT|O_WRONLY|optMode|Direct|LARGEFILE|OptSync; + } else { + if (numstdout++) + fatal("cannot output multiple times to stdout"); + debugmsg("output to stdout\n",argv[c]); + dest->fd = dup(STDOUT_FILENO); + err = dup2(STDERR_FILENO,STDOUT_FILENO); + assert(err != -1); + dest->arg = "<stdout>"; + dest->name = "<stdout>"; + dest->mode = 0; + } + optMode = Nooverwrite; + dest->port = 0; + dest->result = 0; + bzero(&dest->thread,sizeof(dest->thread)); + dest->next = Dest; + Dest = dest; + if (outfile == 0) + outfile = argv[c]; + ++numOut; + ++NumSenders; +#ifdef AF_INET6 + } else if (!strcmp("-0",argv[c])) { + AddrFam = AF_UNSPEC; + } else if (!strcmp("-4",argv[c])) { + AddrFam = AF_INET; + } else if (!strcmp("-6",argv[c])) { + AddrFam = AF_INET6; +#endif + } else if (!argcheck("-I",argv,&c,argc)) { + initNetworkInput(argv[c]); + } else if (!argcheck("-O",argv,&c,argc)) { + dest_t *d = createNetworkOutput(argv[c]); + if (d->fd == -1) { + free(d); + } else { + d->next = Dest; + Dest = d; + ++NumSenders; + } + ++numOut; + } else if (!argcheck("-T",argv,&c,argc)) { + Tmpfile = malloc(strlen(argv[c]) + 1); + if (!Tmpfile) + fatal("out of memory\n"); + (void) strcpy(Tmpfile, argv[c]); + Memmap = 1; + debugmsg("Tmpfile = %s\n",Tmpfile); + } else if (!strcmp("-t",argv[c])) { + Memmap = 1; + debugmsg("Memmap = 1\n"); + } else if (!argcheck("-l",argv,&c,argc)) { + Log = open(argv[c],O_WRONLY|O_APPEND|O_TRUNC|O_CREAT|LARGEFILE,0666); + if (-1 == Log) { + Log = STDERR_FILENO; + errormsg("error opening log file: %s\n",strerror(errno)); + } + debugmsg("logFile set to %s\n",argv[c]); + } else if (!strcmp("-f",argv[c])) { + Nooverwrite = 0; + debugmsg("Nooverwrite = 0\n"); + } else if (!strcmp("-q",argv[c])) { + debugmsg("disabling display of status\n"); + Status = 0; + } else if (!strcmp("-c",argv[c])) { + debugmsg("enabling full synchronous I/O\n"); + OptSync = O_SYNC; + } else if (!strcmp("-e",argv[c])) { + debugmsg("will terminate on any kind of error\n"); + ErrorsFatal = 1; + } else if (!argcheck("-a",argv,&c,argc)) { + long at = strtol(argv[c],0,0) - 1; + if ((at == 0) && (errno == EINVAL)) + errormsg("invalid argument to option -a: \"%s\"\n",argv[c]); + else { + Autoloader = 1; + Autoload_time = at; + } + debugmsg("Autoloader time = %d\n",Autoload_time); + } else if (!argcheck("-A",argv,&c,argc)) { + Autoloader = 1; + Autoload_cmd = argv[c]; + debugmsg("Autoloader command = \"%s\"\n", Autoload_cmd); + } else if (!argcheck("-P",argv,&c,argc)) { + if (1 != sscanf(argv[c],"%lf",&StartWrite)) + StartWrite = 0; + StartWrite /= 100; + if ((StartWrite > 1) || (StartWrite <= 0)) + fatal("error in argument -P: must be bigger than 0 and less or equal 100"); + debugmsg("StartWrite = %1.2lf\n",StartWrite); + } else if (!argcheck("-p",argv,&c,argc)) { + if (1 == sscanf(argv[c],"%lf",&StartRead)) + StartRead /= 100; + else + StartRead = 1.0; + if ((StartRead >= 1) || (StartRead < 0)) + fatal("error in argument -p: must be bigger or equal to 0 and less than 100"); + debugmsg("StartRead = %1.2lf\n",StartRead); + } else if (!strcmp("-L",argv[c])) { +#ifdef _POSIX_MEMLOCK_RANGE + Memlock = 1; + debugmsg("memory locking enabled\n"); +#else + warning("POSIX memory locking is unsupported on this system.\n"); +#endif + } else if (!strcmp("--direct",argv[c])) { +#ifdef O_DIRECT + debugmsg("using O_DIRECT to open file descriptors\n"); + Direct = O_DIRECT; +#else + warningmsg("--direct is unsupported on this system\n"); +#endif + } else if (!strcmp("--help",argv[c]) || !strcmp("-h",argv[c])) { + usage(); + } else if (!strcmp("--version",argv[c]) || !strcmp("-V",argv[c])) { + version(); + } else if (!strcmp("--md5",argv[c]) || !strcmp("-H",argv[c])) { +#ifdef HAVE_MD5 + addHashAlgorithm("MD5"); +#else + fatal("hash calculation support has not been compiled in!\n"); +#endif + } else if (!strcmp("--hash",argv[c])) { + ++c; +#if HAVE_LIBMHASH + if (!strcmp(argv[c],"list")) { + (void) fprintf(stderr,"valid hash functions are:\n"); + int algo = mhash_count(); + while (algo >= 0) { + const char *algoname = (const char *) mhash_get_hash_name_static(algo); + if (algoname) + (void) fprintf(stderr,"\t%s\n",algoname); + --algo; + } + exit(EXIT_SUCCESS); + } +#elif defined HAVE_MD5 + if (!strcmp(argv[c],"list")) { + (void) fprintf(stderr,"valid hash functions are:\n"); + (void) fprintf(stderr,"\tmd5\n"); + exit(EXIT_SUCCESS); + } +#else + fatal("hash calculation support has not been compiled in!\n"); +#endif + addHashAlgorithm(argv[c]); + } else if (!argcheck("-D",argv,&c,argc)) { + OutVolsize = calcint(argv,c,0); + debugmsg("OutVolsize = %llu\n",OutVolsize); + } else + fatal("unknown option \"%s\"\n",argv[c]); + } + + /* consistency check for options */ + if (optBset&optSset&optMset) { + if (Numblocks * Blocksize != totalmem) + fatal("inconsistent options: blocksize * number of blocks != totalsize!\n"); + } else if ((!optBset&optSset&optMset) || (optMset&!optBset&!optSset)) { + if (totalmem <= Blocksize) + fatal("total memory must be larger than block size\n"); + Numblocks = totalmem / Blocksize; + infomsg("Numblocks = %llu, Blocksize = %llu, totalmem = %llu\n",(unsigned long long)Numblocks,(unsigned long long)Blocksize,(unsigned long long)totalmem); + } else if (optBset&!optSset&optMset) { + if (Blocksize == 0) + fatal("blocksize must be greater than 0\n"); + if (totalmem <= Blocksize) + fatal("total memory must be larger than block size\n"); + Blocksize = totalmem / Numblocks; + infomsg("blocksize = %llu\n",(unsigned long long)Blocksize); + } + if ((StartRead < 1) && (StartWrite > 0)) + fatal("setting both low watermark and high watermark doesn't make any sense...\n"); + if ((NumSenders-Hashers > 0) && (Autoloader || OutVolsize)) + fatal("multi-volume support is unsupported with multiple outputs\n"); + if (Autoloader) { + if ((!outfile) && (!Infile)) + fatal("Setting autoloader time without using a device doesn't make any sense!\n"); + if (outfile && Infile) { + fatal("Which one is your autoloader? Input or output? Replace input or output with a pipe.\n"); + } + } + if (Infile && netPortIn) + fatal("Setting both network input port and input file doesn't make sense!\n"); + if (outfile && netPortOut) + fatal("Setting both network output and output file doesn't make sense!\n"); + + /* multi volume input consistency checking */ + if ((NumVolumes != 1) && (!Infile)) + fatal("multi volume support for input needs an explicit given input device (option -i)\n"); + + /* SPW: Volsize consistency checking */ + if (OutVolsize && !outfile) + fatal("Setting OutVolsize without an output device doesn't make sense!\n"); + if ((OutVolsize != 0) && (OutVolsize < Blocksize)) + /* code assumes we can write at least one block */ + fatal("If non-zero, OutVolsize must be at least as large as the buffer blocksize (%llu)!\n",Blocksize); + /* SPW END */ + + /* check that we stay within system limits */ +#ifdef __FreeBSD__ + { + size_t semvmx_size = sizeof(mxnrsem); + if (sysctlbyname("kern.ipc.semvmx", &mxnrsem, &semvmx_size, 0, 0) == -1) + mxnrsem = -1; + } +#else + mxnrsem = sysconf(_SC_SEM_VALUE_MAX); +#endif + if (-1 == mxnrsem) { +#ifdef SEM_MAX_VALUE + mxnrsem = SEM_MAX_VALUE; +#else + mxnrsem = LONG_MAX; + warningmsg("unable to determine maximum value of semaphores\n"); +#endif + } + if (Numblocks > mxnrsem) { + fatal("cannot allocate more than %d blocks.\nThis is a system dependent limit, depending on the maximum semaphore value.\nPlease choose a bigger block size.\n",mxnrsem); + } + + if ((Blocksize * (long long)Numblocks) > (long long)SSIZE_MAX) + fatal("Cannot address so much memory (%lld*%d=%lld>%lld).\n",Blocksize,Numblocks,Blocksize*(long long)Numblocks,(long long)SSIZE_MAX); + /* create buffer */ + Buffer = (char **) valloc(Numblocks * sizeof(char *)); + if (!Buffer) + fatal("Could not allocate enough memory (%d requested): %s\n",Numblocks * sizeof(char *),strerror(errno)); + if (Memmap) { + infomsg("mapping temporary file to memory with %llu blocks with %llu byte (%llu kB total)...\n",(unsigned long long) Numblocks,(unsigned long long) Blocksize,(unsigned long long) ((Numblocks*Blocksize) >> 10)); + if (!Tmpfile) { + char tmplname[] = "mbuffer-XXXXXX"; + char *tmpdir = getenv("TMPDIR") ? getenv("TMPDIR") : "/var/tmp"; + char tfilename[sizeof(tmplname) + strlen(tmpdir) + 1]; + (void) strcpy(tfilename,tmpdir); + (void) strcat(tfilename,"/"); + (void) strcat(tfilename,tmplname); + Tmp = mkstemp(tfilename); + Tmpfile = malloc(strlen(tfilename)); + if (!Tmpfile) + fatal("out of memory: %s\n",strerror(errno)); + (void) strcpy(Tmpfile,tfilename); + infomsg("tmpfile is %s\n",Tmpfile); + } else { + mode_t mode = O_RDWR | LARGEFILE; + if (strncmp(Tmpfile,"/dev/",5)) + mode |= O_CREAT|O_EXCL; + Tmp = open(Tmpfile,mode,0600); + } + if (-1 == Tmp) + fatal("could not create temporary file (%s): %s\n",Tmpfile,strerror(errno)); + if (strncmp(Tmpfile,"/dev/",5)) + (void) unlink(Tmpfile); + /* resize the file. Needed - at least under linux, who knows why? */ + if (-1 == lseek(Tmp,Numblocks * Blocksize - sizeof(int),SEEK_SET)) + fatal("could not resize temporary file: %s\n",strerror(errno)); + if (-1 == write(Tmp,&c,sizeof(int))) + fatal("could not resize temporary file: %s\n",strerror(errno)); + Buffer[0] = mmap(0,Blocksize*Numblocks,PROT_READ|PROT_WRITE,MAP_SHARED,Tmp,0); + if (MAP_FAILED == Buffer[0]) + fatal("could not map buffer-file to memory: %s\n",strerror(errno)); + debugmsg("temporary file mapped to address %p\n",Buffer[0]); + } else { + infomsg("allocating memory for %d blocks with %llu byte (%llu kB total)...\n",Numblocks,(unsigned long long) Blocksize,(unsigned long long) ((Numblocks*Blocksize) >> 10)); + Buffer[0] = (char *) valloc(Blocksize * Numblocks); + if (Buffer[0] == 0) + fatal("Could not allocate enough memory (%lld requested): %s\n",(unsigned long long)Blocksize * Numblocks,strerror(errno)); + } + for (c = 1; c < Numblocks; c++) { + Buffer[c] = Buffer[0] + Blocksize * c; + *Buffer[c] = 0; /* touch every block before locking */ + } + +#ifdef _POSIX_MEMLOCK_RANGE + if (Memlock) { + uid_t uid; +#ifndef HAVE_SETEUID +#define seteuid setuid +#endif + uid = geteuid(); + if (0 != seteuid(0)) + warningmsg("could not change to uid 0 to lock memory (is mbuffer setuid root?)\n"); + else if ((0 != mlock((char *)Buffer,Numblocks * sizeof(char *))) || (0 != mlock(Buffer[0],Blocksize * Numblocks))) + warningmsg("could not lock buffer in memory: %s\n",strerror(errno)); + else + infomsg("memory locked successfully\n"); + err = seteuid(uid); /* don't give anyone a chance to attack this program, so giveup uid 0 after locking... */ + assert(err == 0); + } +#endif + + debugmsg("creating semaphores...\n"); + if (0 != sem_init(&Buf2Dev,0,0)) + fatal("Error creating semaphore Buf2Dev: %s\n",strerror(errno)); + if (0 != sem_init(&Dev2Buf,0,Dest ? Numblocks - 1 : Numblocks)) + fatal("Error creating semaphore Dev2Buf: %s\n",strerror(errno)); + + debugmsg("opening input...\n"); + if (Infile) { + int flags = O_RDONLY | LARGEFILE | Direct; + In = open(Infile,flags); + if (-1 == In) { + if (errno == EINVAL) { + flags &= ~LARGEFILE; + In = open(Infile,flags); + } + if (-1 == In) + fatal("could not open input file: %s\n",strerror(errno)); + } + } else if (In == -1) { + In = STDIN_FILENO; + } +#ifdef __sun + if (0 == directio(In,DIRECTIO_ON)) + infomsg("direct I/O hinting enabled for input\n"); + else + infomsg("direct I/O hinting failed for input: %s\n",strerror(errno)); +#endif + if (numOut == 0) { + dest_t *d = malloc(sizeof(dest_t)); + d->fd = dup(STDOUT_FILENO); + err = dup2(STDERR_FILENO,STDOUT_FILENO); + assert(err != -1); + d->name = "<stdout>"; + d->arg = "<stdout>"; + d->port = 0; + d->result = 0; + bzero(&d->thread,sizeof(d->thread)); + d->next = Dest; + Dest = d; + ++NumSenders; + } + openDestinationFiles(Dest); + if (NumSenders == -1) { + fatal("no output left - nothing to do\n"); + } + + debugmsg("checking if we have a controlling terminal...\n"); + sig.sa_sigaction = SIG_IGN; + err = sigaction(SIGTTIN,&sig,0); + assert(err == 0); + fl = fcntl(STDERR_FILENO,F_GETFL); + err = fcntl(STDERR_FILENO,F_SETFL,fl | O_NONBLOCK); + assert(err == 0); + if ((read(STDERR_FILENO,&c,1) == -1) && (errno != EAGAIN)) { + int tty = open("/dev/tty",O_RDWR); + if (-1 == tty) { + Terminal = 0; + if (Autoloader == 0) + warningmsg("No controlling terminal and no autoloader command specified.\n"); + } else { + Terminal = 1; + err = dup2(tty,STDERR_FILENO); + assert(err != -1); + } + } + err = fcntl(STDERR_FILENO,F_SETFL,fl); + assert(err == 0); + if ((Terminal == 1) && (NumVolumes != 1)) { + struct termios tset; + if (-1 == tcgetattr(STDERR_FILENO,&tset)) { + warningmsg("unable to get terminal attributes: %s\n",strerror(errno)); + } else { + tset.c_lflag &= (~ICANON) & (~ECHO); + tset.c_cc[VTIME] = 0; + tset.c_cc[VMIN] = 1; + if (-1 == tcsetattr(STDERR_FILENO,TCSANOW,&tset)) + warningmsg("unable to set terminal attributes: %s\n",strerror(errno)); + } + } + + debugmsg("registering signals...\n"); + sig.sa_handler = sigHandler; + err = sigemptyset(&sig.sa_mask); + assert(err == 0); + err = sigaddset(&sig.sa_mask,SIGINT); + assert(err == 0); + sig.sa_flags = SA_RESTART; + if (0 != sigaction(SIGINT,&sig,0)) + warningmsg("error registering new SIGINT handler: %s\n",strerror(errno)); + err = sigemptyset(&sig.sa_mask); + assert(err == 0); + err = sigaddset(&sig.sa_mask,SIGHUP); + assert(err == 0); + if (0 != sigaction(SIGHUP,&sig,0)) + warningmsg("error registering new SIGHUP handler: %s\n",strerror(errno)); + + debugmsg("starting threads...\n"); + (void) gettimeofday(&Starttime,0); + err = sigfillset(&signalSet); + assert(0 == err); + (void) pthread_sigmask(SIG_BLOCK, &signalSet, NULL); + + /* select destination for output thread */ + dest = Dest; + while (dest->fd == -1) { + dest->name = 0; + debugmsg("skipping destination %s\n",dest->arg); + assert(dest->next); + dest = dest->next; + } + +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + debugmsg("checking output device...\n"); + if (-1 == fstat(dest->fd,&st)) + errormsg("could not stat output: %s\n",strerror(errno)); + else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { + infomsg("blocksize is %d bytes on output device\n",st.st_blksize); + if (Blocksize % st.st_blksize != 0) { + warningmsg("Blocksize should be a multiple of the blocksize of the output device!\n" + "This can cause problems with some device/OS combinations...\n" + "Blocksize on output device is %d (transfer block size is %lld)\n", st.st_blksize, Blocksize); + if (SetOutsize) + fatal("unable to set output blocksize\n"); + } else { + if (SetOutsize) { + infomsg("setting output blocksize to %d\n",st.st_blksize); + Outsize = st.st_blksize; + } + } + } else + infomsg("no device on output stream\n"); + debugmsg("checking input device...\n"); + if (-1 == fstat(In,&st)) + warningmsg("could not stat input: %s\n",strerror(errno)); + else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { + infomsg("blocksize is %d bytes on input device\n",st.st_blksize); + if (Blocksize % st.st_blksize != 0) { + warningmsg("Blocksize should be a multiple of the blocksize of the input device!\n" + "Use option -s to adjust transfer block size if you get an out-of-memory error on input.\n" + "Blocksize on input device is %d (transfer block size is %lld)\n", st.st_blksize, Blocksize); + } + } else + infomsg("no device on input stream\n"); +#else + warningmsg("Could not stat output device (unsupported by system)!\n" + "This can result in incorrect written data when\n" + "using multiple volumes. Continue at your own risk!\n"); +#endif + if (Status) { + if (-1 == pipe(TermQ)) + fatal("could not create termination pipe: %s\n",strerror(errno)); + } else { + TermQ[0] = -1; + TermQ[1] = -1; + } + err = pthread_create(&dest->thread,0,&outputThread,dest); + assert(0 == err); + if (Status) { + err = pthread_create(&Reader,0,&inputThread,0); + assert(0 == err); + (void) pthread_sigmask(SIG_UNBLOCK, &signalSet, NULL); + statusThread(); + err = pthread_join(Reader,0); + if (err != 0) + errormsg("error joining reader: %s\n",strerror(errno)); + } else { + (void) pthread_sigmask(SIG_UNBLOCK, &signalSet, NULL); + (void) inputThread(0); + debugmsg("waiting for output to finish...\n"); + if (TermQ[0] != -1) { + err = read(TermQ[0],&null,1); + assert(err == 1); + } + } + if (Dest) { + dest_t *d = Dest; + int ret; + + infomsg("waiting for senders...\n"); + if (Terminate) + cancelAll(); + do { + if (d->name) { + void *status; + if (d->arg) { + debugmsg("joining sender for %s\n",d->arg); + } else { + debugmsg("joining hasher for %s\n",d->name); + } + ret = pthread_join(d->thread,&status); + if (ret != 0) + errormsg("error joining %s: %s\n",d->arg,d->name,strerror(errno)); + if (status == 0) + ++numthreads; + } + d = d->next; + } while (d); + } + if (Status || Log != STDERR_FILENO) + summary(Numout * Blocksize + Rest, numthreads); + if (Memmap) { + int ret = munmap(Buffer[0],Blocksize*Numblocks); + assert(ret == 0); + } + if (Tmp != -1) + (void) close(Tmp); + if (Dest) { + dest_t *d = Dest; + do { + dest_t *n = d->next; + if (d->result) { + if (d->arg) { + warningmsg("error during output to %s: %s\n",d->arg,d->result); + } else { + (void) write(STDERR_FILENO,d->result,strlen(d->result)); + if (Log != STDERR_FILENO) + (void) write(Log,d->result,strlen(d->result)); + } + } + free(d); + d = n; + } while (d); + } + if (ErrorOccurred) + exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); +} + +/* vim:tw=0 + */
View file
lxdvdrip-1.77.tar.bz2/mbuffer/network.c
Added
@@ -0,0 +1,414 @@ +/* + * Copyright (C) 2000-2009, Thomas Maier-Komor + * + * This is the source code of mbuffer. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#elif defined __GNUC__ +#define alloca __builtin_alloca +#elif defined _AIX +#define alloca __alloca +#else +#include <stddef.h> +void *alloca(size_t); +#endif + + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "dest.h" +#include "network.h" +#include "log.h" + +extern int In; +int32_t TCPBufSize = 1 << 20; +#if defined(PF_INET6) && defined(PF_UNSPEC) +int AddrFam = PF_UNSPEC; +#else +int AddrFam = PF_INET; +#endif + + +static void setTCPBufferSize(int sock, unsigned buffer) +{ + int err; + int32_t osize, size; + socklen_t bsize = sizeof(osize); + + assert(buffer == SO_RCVBUF || buffer == SO_SNDBUF); + err = getsockopt(sock,SOL_SOCKET,buffer,&osize,&bsize); + assert((err == 0) && (bsize == sizeof(osize))); + if (osize < TCPBufSize) { + size = TCPBufSize; + do { + err = setsockopt(sock,SOL_SOCKET,buffer,(void *)&size,sizeof(size)); + size >>= 1; + } while ((-1 == err) && (errno == ENOMEM) && (size > osize)); + if (err == -1) { + warningmsg("unable to set socket buffer size: %s\n",strerror(errno)); + return; + } + } + bsize = sizeof(size); + err = getsockopt(sock,SOL_SOCKET,buffer,&size,&bsize); + assert(err != -1); + if (buffer == SO_RCVBUF) + infomsg("set TCP receive buffer size to %d\n",size); + else + infomsg("set TCP send buffer size to %d\n",size); +} + + +#ifdef HAVE_GETADDRINFO + +void initNetworkInput(const char *addr) +{ + char *host, *port; + struct addrinfo hint, *pinfo = 0, *x, *cinfo = 0; + int err, sock = -1, l; + + debugmsg("initNetworkInput(\"%s\")\n",addr); + l = strlen(addr) + 1; + host = alloca(l); + memcpy(host,addr,l); + port = strrchr(host,':'); + if (port == 0) { + port = host; + host = 0; + } else if (port == host) { + port = host + 1; + host = 0; + } else { + *port = 0; + ++port; + bzero(&hint,sizeof(hint)); + hint.ai_family = AddrFam; + hint.ai_protocol = IPPROTO_TCP; + hint.ai_socktype = SOCK_STREAM; + hint.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; + err = getaddrinfo(host,0,&hint,&cinfo); + if (err != 0) + fatal("unable to resolve address information for expected host '%s': %s\n",host,gai_strerror(err)); + } + bzero(&hint,sizeof(hint)); + hint.ai_family = AddrFam; + hint.ai_protocol = IPPROTO_TCP; + hint.ai_socktype = SOCK_STREAM; + hint.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + err = getaddrinfo(0,port,&hint,&pinfo); + if (err != 0) + fatal("unable to get address information for port/service '%s': %s\n",port,gai_strerror(err)); + assert(pinfo); + for (x = pinfo; x; x = x->ai_next) { + int reuse_addr = 1; + debugmsg("creating socket for address familiy %d\n",x->ai_family); + sock = socket(x->ai_family, SOCK_STREAM, 0); + if (sock == -1) { + warningmsg("unable to create socket for input: %s\n",strerror(errno)); + continue; + } + if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr))) + warningmsg("cannot set socket to reuse address: %s\n",strerror(errno)); + if (0 == bind(sock, x->ai_addr, x->ai_addrlen)) { + debugmsg("successfully bound socket - address length %d\n",x->ai_addrlen); + break; + } + warningmsg("could not bind to socket for network input: %s\n",strerror(errno)); + (void) close(sock); + } + if (x == 0) + fatal("Unable to initialize network input.\n"); + infomsg("listening on socket...\n"); + if (0 > listen(sock,0)) /* accept only 1 incoming connection */ + fatal("could not listen on socket for network input: %s\n",strerror(errno)); + for (;;) { + char chost[NI_MAXHOST], serv[NI_MAXSERV]; + struct sockaddr_in6 caddr; + struct addrinfo *c; + socklen_t len = sizeof(caddr); + int err; + + debugmsg("waiting for incoming connection\n"); + In = accept(sock, (struct sockaddr *) &caddr, &len); + if (0 > In) + fatal("Unable to accept connection for network input: %s\n",strerror(errno)); + err = getnameinfo((struct sockaddr *) &caddr,len,chost,sizeof(chost),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN); + if (0 != err) { + fatal("unable to get name information for hostname of incoming connection: %s\n",gai_strerror(err)); + } + infomsg("incoming connection from %s:%s\n",chost,serv); + if (host == 0) + break; + for (c = cinfo; c; c = c->ai_next) { + char xhost[NI_MAXHOST]; + if (0 == getnameinfo((struct sockaddr *)c->ai_addr,c->ai_addrlen,xhost,sizeof(xhost),0,0,NI_NUMERICHOST|NI_NOFQDN)) { + debugmsg("checking against host '%s'\n",xhost); + if (0 == strcmp(xhost,chost)) + break; + } + } + if (c) + break; + warningmsg("rejected connection from %s\n",chost); + if (-1 == close(In)) + warningmsg("error closing rejected input: %s\n",strerror(errno)); + } + freeaddrinfo(pinfo); + if (cinfo) + freeaddrinfo(cinfo); + debugmsg("input connection accepted\n"); + setTCPBufferSize(In,SO_RCVBUF); + (void) close(sock); +} + + +dest_t *createNetworkOutput(const char *addr) +{ + char *host, *port; + struct addrinfo hint, *ret = 0, *x; + int err, fd = -1; + dest_t *d; + + assert(addr); + host = strdup(addr); + assert(host); + port = strrchr(host,':'); + if (port == 0) { + fatal("syntax error - target must be given in the form <host>:<port>\n"); + } + *port++ = 0; + bzero(&hint,sizeof(hint)); + hint.ai_family = AddrFam; + hint.ai_protocol = IPPROTO_TCP; + hint.ai_socktype = SOCK_STREAM; + hint.ai_flags = AI_ADDRCONFIG; + debugmsg("getting address info for %s\n",addr); + err = getaddrinfo(host,port,&hint,&ret); + if (err != 0) + fatal("unable to resolve address information for '%s': %s\n",addr,gai_strerror(err)); + for (x = ret; x; x = x->ai_next) { + fd = socket(x->ai_family, SOCK_STREAM, 0); + if (fd == -1) { + errormsg("unable to create socket: %s\n",strerror(errno)); + continue; + } + if (0 == connect(fd, x->ai_addr, x->ai_addrlen)) { + debugmsg("successfully connected to %s\n",addr); + break; + } + (void) close(fd); + fd = -1; + warningmsg("error connecting to %s: %s\n",addr,strerror(errno)); + } + if ((x == 0) || (fd == -1)) + errormsg("unable to connect to %s\n",addr); + freeaddrinfo(ret); + if (fd != -1) + setTCPBufferSize(fd,SO_SNDBUF); + d = (dest_t *) malloc(sizeof(dest_t)); + d->arg = addr; + d->name = host; + d->port = port; + d->fd = fd; + bzero(&d->thread,sizeof(d->thread)); + d->result = 0; + d->next = 0; + return d; +} + + +#else /* HAVE_GETADDRINFO */ + + +static void openNetworkInput(const char *host, unsigned short port) +{ + struct sockaddr_in saddr; + struct hostent *h = 0, *r = 0; + const int reuse_addr = 1; + int sock; + + debugmsg("openNetworkInput(\"%s\",%hu)\n",host,port); + sock = socket(AF_INET, SOCK_STREAM, 6); + if (0 > sock) + fatal("could not create socket for network input: %s\n",strerror(errno)); + if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr))) + warningmsg("cannot set socket to reuse address: %s\n",strerror(errno)); + setTCPBufferSize(sock,SO_RCVBUF); + if (host[0]) { + debugmsg("resolving hostname '%s' of input...\n",host); + if (0 == (h = gethostbyname(host))) +#ifdef HAVE_HSTRERROR + fatal("could not resolve server hostname: %s\n",hstrerror(h_errno)); +#else + fatal("could not resolve server hostname: error code %d\n",h_errno); +#endif + } + bzero((void *) &saddr, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons(port); + debugmsg("binding socket to port %d...\n",port); + if (0 > bind(sock, (struct sockaddr *) &saddr, sizeof(saddr))) + fatal("could not bind to socket for network input: %s\n",strerror(errno)); + debugmsg("listening on socket...\n"); + if (0 > listen(sock,1)) /* accept only 1 incoming connection */ + fatal("could not listen on socket for network input: %s\n",strerror(errno)); + for (;;) { + struct sockaddr_in caddr; + socklen_t clen = sizeof(caddr); + char **p; + debugmsg("waiting to accept connection...\n"); + In = accept(sock, (struct sockaddr *)&caddr, &clen); + if (0 > In) + fatal("could not accept connection for network input: %s\n",strerror(errno)); + if (host[0] == 0) { + infomsg("accepted connection from %s\n",inet_ntoa(caddr.sin_addr)); + (void) close(sock); + return; + } + for (p = h->h_addr_list; *p; ++p) { + if (0 == memcmp(&caddr.sin_addr,*p,h->h_length)) { + infomsg("accepted connection from %s\n",inet_ntoa(caddr.sin_addr)); + (void) close(sock); + return; + } + } + r = gethostbyaddr((char *)&caddr.sin_addr,sizeof(caddr.sin_addr.s_addr),AF_INET); + if (r) + warningmsg("rejected connection from %s (%s)\n",r->h_name,inet_ntoa(caddr.sin_addr)); + else + warningmsg("rejected connection from %s\n",inet_ntoa(caddr.sin_addr)); + if (-1 == close(In)) + warningmsg("error closing rejected input: %s\n",strerror(errno)); + } +} + + +void initNetworkInput(const char *addr) +{ + char *host, *portstr; + unsigned pnr; + size_t l; + + debugmsg("initNetworkInput(\"%s\")\n",addr); + l = strlen(addr) + 1; + host = alloca(l); + memcpy(host,addr,l); + portstr = strrchr(host,':'); + if (portstr == 0) { + portstr = host; + host = ""; + } else if (portstr == host) { + portstr = host + 1; + host = ""; + *portstr = 0; + } else { + *portstr = 0; + ++portstr; + } + if (1 != sscanf(portstr,"%u",&pnr)) + fatal("invalid port string '%s' - port must be given by its number, not service name\n", portstr); + openNetworkInput(host,pnr); +} + + +static void openNetworkOutput(dest_t *dest) +{ + struct sockaddr_in saddr; + struct hostent *h = 0; + int out; + unsigned short pnr; + + debugmsg("creating socket for output to %s:%d...\n",dest->name,dest->port); + if (1 != sscanf(dest->port,"%hu",&pnr)) + fatal("port must be given by its number, not service name\n"); + out = socket(PF_INET, SOCK_STREAM, 0); + if (0 > out) { + errormsg("could not create socket for network output: %s\n",strerror(errno)); + return; + } + setTCPBufferSize(out,SO_SNDBUF); + bzero((void *) &saddr, sizeof(saddr)); + saddr.sin_port = htons(pnr); + infomsg("resolving host %s...\n",dest->name); + if (0 == (h = gethostbyname(dest->name))) { +#ifdef HAVE_HSTRERROR + dest->result = hstrerror(h_errno); + errormsg("could not resolve hostname %s: %s\n",dest->name,dest->result); +#else + dest->result = "unable to resolve hostname"; + errormsg("could not resolve hostname %s: error code %d\n",dest->name,h_errno); +#endif + dest->fd = -1; + (void) close(out); + return; + } + saddr.sin_family = h->h_addrtype; + assert(h->h_length <= sizeof(saddr.sin_addr)); + (void) memcpy(&saddr.sin_addr,h->h_addr_list[0],h->h_length); + infomsg("connecting to server at %s...\n",inet_ntoa(saddr.sin_addr)); + if (0 > connect(out, (struct sockaddr *) &saddr, sizeof(saddr))) { + dest->result = strerror(errno); + errormsg("could not connect to %s:%d: %s\n",dest->name,dest->port,dest->result); + (void) close(out); + out = -1; + } + dest->fd = out; +} + + +dest_t *createNetworkOutput(const char *addr) +{ + char *host, *portstr; + dest_t *d = (dest_t *) malloc(sizeof(dest_t)); + + debugmsg("createNetworkOutput(\"%s\")\n",addr); + host = strdup(addr); + portstr = strrchr(host,':'); + if ((portstr == 0) || (portstr == host)) + fatal("argument '%s' doesn't match <host>:<port> format\n",addr); + *portstr++ = 0; + bzero(d, sizeof(dest_t)); + d->fd = -1; + d->arg = addr; + d->name = host; + d->port = portstr; + openNetworkOutput(d); + return d; +} + + +#endif /* HAVE_GETADDRINFO */ + + +/* vim:tw=0 + */
View file
lxdvdrip-1.77.tar.bz2/mbuffer/network.h
Added
@@ -0,0 +1,31 @@ +/* + * Copyright (C) 2000-2009, Thomas Maier-Komor + * + * This is the source code of mbuffer. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NETWORK_H +#define NETWORK_H + +#include <sys/types.h> + +extern int32_t TCPBufSize; +extern int AddrFam; + +void initNetworkInput(const char *addr); +struct destination *createNetworkOutput(const char *addr); + +#endif
View file
lxdvdrip-1.76.tar.bz2/requant/Makefile -> lxdvdrip-1.77.tar.bz2/requant/Makefile
Changed
@@ -7,7 +7,7 @@ CC = gcc CFLAGS ?= -O2 -g -D_LARGEFILE_SOURCE -DLARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 \ -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -D_REENTRANT -CFLAGS += -Wall +CFLAGS += -Wall -Wno-unused-result LDFLAGS += -s LOADLIBES += -lm
View file
lxdvdrip-1.76.tar.bz2/vamps/Makefile -> lxdvdrip-1.77.tar.bz2/vamps/Makefile
Changed
@@ -22,7 +22,7 @@ -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -D_REENTRANT CFLAGS += -Wall LDFLAGS += -s -LOADLIBES += -lm -lpthread -ldvdread +LOADLIBES += -lm -pthread -ldvdread INSTALL ?= install
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.