summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Meyerholt <dxm523@googlemail.com>2011-02-06 16:02:09 +0100
committerDaniel Meyerholt <dxm523@googlemail.com>2011-02-06 16:02:09 +0100
commita0674cc59c6aaad845ed0a48768fb56b90c41d52 (patch)
treebe828ed0f61ebe85db7f1098e8e8942126b3e7fc
downloadvdr-plugin-vdrrip-a0674cc59c6aaad845ed0a48768fb56b90c41d52.tar.gz
vdr-plugin-vdrrip-a0674cc59c6aaad845ed0a48768fb56b90c41d52.tar.bz2
Init'd using http://www.a-land.de/vdr-vdrrip-0.3.0.tgz
-rwxr-xr-xCOPYING340
-rwxr-xr-xFAQ137
-rwxr-xr-xHISTORY114
-rwxr-xr-xINSTALL317
-rwxr-xr-xMakefile91
-rwxr-xr-xREADME118
-rwxr-xr-xTODO27
-rwxr-xr-xa-tools.c111
-rwxr-xr-xa-tools.h23
-rwxr-xr-xcodecs.c200
-rwxr-xr-xcodecs.h36
-rwxr-xr-xi18n.c1356
-rwxr-xr-xi18n.h10
-rwxr-xr-xmenu-vdrrip.c1275
-rwxr-xr-xmenu-vdrrip.h209
-rwxr-xr-xmovie.c985
-rwxr-xr-xmovie.h163
-rwxr-xr-xpatches/MPlayer_vdrac3.diff38
-rwxr-xr-xqueue.c289
-rwxr-xr-xqueue.h69
-rwxr-xr-xscripts/queuehandler.sh1012
-rwxr-xr-xscripts/queuehandler.sh.conf71
-rwxr-xr-xscripts/sleephalt.sh83
-rwxr-xr-xscripts/vdrshutdown.sh24
-rwxr-xr-xscripts/vdrsync.pl2806
-rwxr-xr-xtemplates.c289
-rwxr-xr-xtemplates.h67
-rwxr-xr-xvdrrip.c159
-rwxr-xr-xvdrriprecordings.c87
-rwxr-xr-xvdrriprecordings.h27
-rwxr-xr-xxaver.jpgbin0 -> 20042 bytes
31 files changed, 10533 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100755
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/FAQ b/FAQ
new file mode 100755
index 0000000..af36672
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,137 @@
+What is the bpp-value ?
+
+ This is copied from the file DOCS/tech/encoding-tips.txt in the MPlayer-
+ source directory:
+
+ $videobitrate * 1024
+ $bpp = -----------------------
+ $width * $height * $fps
+
+
+What bpp-value should I use ?
+
+ This is copied from the file DOCS/tech/encoding-tips.txt in the MPlayer-
+ source directory:
+
+ < 0.10: don't do it. Please. I beg you!
+ < 0.15: It will look bad.
+ < 0.20: You will notice blocks, but it will look ok.
+ < 0.25: It will look really good.
+ > 0.25: It won't really improve visually.
+ > 0.30: Don't do that either - try a bigger resolution instead.
+
+
+What is matroska ? I have heard it is a "container format" ? What's that ?
+
+ A container format allows you to combine different multimedia streams
+ (most of the time Audio and video) into one single file. Multimedia
+ containers are for example the well known AVI (.avi), MPEG (.mpg, .mpeg),
+ OGM (.ogm), MP4 (.mp4) or Realmedia (.rm, .rmvb)
+
+ The matroska project is a free, opensource container format, aiming to be
+ able to offer a lot of advanced features, which older formats like AVI
+ can't handle, on an extensible basis. Matroska supports for example the
+ storage of Variable Bitrate audio content (VBR) without any hassles,
+ Variable Framerates (VFR), Chapters, attachment of files, Error Detection
+ (EDC) and modern A/V Codecs like "Advanced Audio Coding" (AAC), "Ogg
+ Vorbis" or "Realvideo 9" (RV9), all things AVI can't handle.
+
+ (This text is copied from the "Matroska FAQ" <http://forum.doom9.org>
+ Forum: New AV/Formats - Containers)
+
+
+Which deinterlacing-Filter should i use ?
+
+ I don't know, but there are really interesting informations/pictures at
+ <http://home.knuut.de/MWieser_/vf_raw_ntv_3/>.
+
+
+I don't like your encoding-options. How can I change them ?
+
+ feel free to change them in the file queuehandler.sh:
+
+ ...
+ case "$vcodec" in
+ "lavc")
+ local vopts="-ovc lavc -lavcopts vcodec=mpeg4:vhq:vbitrate=$br_video\
+ :vqmin=$min_q:vqmax=$max_q:vpass=$pass -sws 2"
+ ;;
+ "xvid")
+ local vopts="-ovc xvid -xvidencopts bitrate=$br_video:me_quality=6:\
+ pass=$pass -sws 2"
+ ;;
+ "divx4")
+ local vopts="-ovc divx4 -divx4opts br=$br_video:q=5:min_quant=$min_q\
+ :max_quant=$max_q:pass=$pass -sws 2"
+ ;;
+ ...
+
+
+The resulting file-size is smaller then the requested. What's the reason ?
+
+ I am using the abr-mode of lame. The resulting audio-bitrate should be
+ smaller then the requested. You can use vbr or cbr mode (see lame &
+ mplayer manpage), but then you will get less audio quality.
+
+
+I couldn't add the movie to the queue. What's wrong ?
+
+ You can only add the movie to the queuefile, if the cursor isn't on the
+ FileName dialog.
+
+
+What does the fields in the file queue.vdrrip mean ?
+
+ e.g.: /video/%Irgendwie_und_Sowieso/2003-09-11.21:43.50.50.rec/001.vdr;
+ Irgendwie_und_Sowieso;350;1;lavc;896;2;15;712;568;0;4;496;360;
+ lame;96;0;lb;1;avi;1
+
+ /video/.../001.vdr: path of the first vdr-file
+ Irgendwie_und_Sowieso: name of the encoded movie
+ 350: filesize of one file
+ 1: number of resulting Files
+ lavc: video codec
+ 896: video bitrate
+ 2: min quantizer
+ 15: max quantizer
+ 712: crop width
+ 568: crop height
+ 0: crop pos x
+ 4: crop pos y
+ 496: scale width
+ 360: scale height
+ lame: audio codec
+ 96: audio bitrate
+ 0: audio id
+ lb: postprocess-setting(s)
+ 1: rename vdr-dir after encoding (0: don't rename)
+ avi: container-format
+ 1: encode only preview (0: encode all)
+
+
+Is it possible to do the real encoding process on an other machine within
+a network ?
+
+ Yes, it is !
+
+ First you have to mount two directories (e.g. nfs) on the other machine:
+
+ - /video* to the same mountpoint to access the vdr-files. Read-only is
+ enough, if you didn't set the parameter "rename after encoding" to
+ "yes" in the setup-menu.
+ - /<vdr-config-dir>/plugins to a arbitary mountpoint (read-write),
+ because there are the nessecary files queue.vdrrip, lock.vdrrip and
+ encode.vdrrip.
+
+ Then you only have to install mplayer/mencoder with all needed codecs and
+ container-tools, and copy the queuehandler (/scripts/queuehandler.sh &
+ /scripts/queuehandler.sh.conf) and perhaps vdrsync.pl to e.g.
+ /usr/local/bin. See the table in the file INSTALL for further
+ informations.
+
+
+Why do I get the error "Can't open main ifo from dvd !" or "Can't open
+ifo x !" if I try to encode a DVD ?
+
+ Probably the DVD is encrypted. Copying encrypted DVD's is illegal in many
+ countries. Don't send any questions regarding encrypted DVD's.
diff --git a/HISTORY b/HISTORY
new file mode 100755
index 0000000..2dd4448
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,114 @@
+VDR Plugin 'vdrrip' Revision History
+------------------------------------
+
+2003-09-14: Version 0.0.7
+
+- Initial revision.
+
+2003-09-15: Version 0.0.7a
+
+- added -frames 0 to get -identify in MPlayer1.0pre1 running
+- some changes in the README and FAQ - file
+
+2003-09-15: Version 0.0.7b
+
+- vdr-recordings can only be selected with selectvdrrip.sh,
+ if the file marks.vdr is available
+- menue changes in menu-vdrrip.c:
+ VDR to 'encode vdr-rec. (Movie-Name)' (it is only
+ displayed if a recording is selected
+- a lot of changes in the error handling in movie.c:
+ (vdrrip shouldn't crash, even if mplayer/mencoder isn't
+ available)
+
+2003-09-18: Version 0.0.8
+
+- add pclose(p) in cMovieBase::queryCodecs() to avoid zombie-processes
+ (reported by Chrillepup@www.vdrportal.de)
+- set the movie names in brackets at the #defines in movie.c
+ (reported by zuse@www.vdrportal.de)
+- (first) code-cleanup of menu-vdrrip.c
+- don't save/delete save.vdrrip if the video/audio-codec isn't detected
+ (reported by dbox.network@www.vdrportal.de)
+- add (optional) renaming of encoded vdr-recordings
+ (thx to memed@www.vdrportal.de)
+- selectvdrrip.sh works if the video-directory is a subdirectory
+ (thx to memed@www.vdrportal.de)
+- 001.vdr is copied, if a symbolic-link could not created (for fat-partitions)
+ (reported by memed@www.vdrportal.de)
+- add (alternative) usage of svdrpsend.pl in queuehandler.sh
+- fixed OSD-bugs (help-keys etc.)
+- add experts-menu (with postprocess-filters)
+- add handling of postprocess-filters to queuehandler.sh
+
+2003-10-12: Version 0.0.9
+- add command line arguments for mplayer/mencoder-location, to avoid
+ problems with $PATH (see ./vdr --help)
+- fix a bug in menu-vdrrip.c (with postprocess-filters)
+- fix a bug in menu-vdrrip.c (display Audio-ID, if more then one audio-id is available)
+- add templates-handling (templates.c)
+- moved codecs-handling to codecs.c
+- removed the bitrate-line from osd
+- some changes in the README and FAQ - file
+
+2003-11-24: Version 0.1.0
+- code-cleanup of codecs.c
+- add ScaleType & Bpp to templates-handling
+- write all messages and errors to syslog instead of stdout/stderr
+- add Bpp-Value to expert-menu
+- add internationalization support
+- changed " to ' at the #defines in movie.c
+ (thx to memed@www.vdrportal.de)
+- changed menu-handling (selectvdrrip.sh is now obsolete)
+- some changes in the README and FAQ - file
+
+2003-12-14: Version 0.1.1
+- add italian translation (thx to tinconn@virgilio.it)
+- moved queue-handling to queue.c
+- add locking-mechanism to allow the editing of the queue
+- changed vdrriprecordings.c to display recordings with more than
+ two subdirectories (reported by frissi@www.vdrportal.de)
+- some cosmetic changes of the menus in menu-vdrrip.c
+
+2004-01-17: Version 0.2.0
+- add ogg-vorbis support
+- add ac3-support
+- add ogm-support
+- add matroska-support
+- now display more audio-informations
+- display container-type in queuefile-menu
+- get movie length from index.vdr instead of marks.vdr
+ (the template "default-fixed Bitrate" is now obsolete)
+- add a ac3 MPlayer-patch to the /patches directory
+- avoid VideoBitrates < 150 in cMovieBase::setBitrate
+- avoid AudioBitrates < 32 in cMovieBase::setBitrate
+- decrease VideoBitrate if AudioBitrate is increased
+- some cosmetic changes of the menus in menu-vdrrip.c
+- add french translation (thx to mak_addikt@yahoo.fr)
+- splitted the install-section from README to INSTALL
+- lot's of changes in the queuehandler.sh
+
+2004-01-20: Version 0.2.0a
+- fixed a bug in cMovie::setCodecs (thx to markus.maeder@oase.ch)
+- fixed a bug in queuehandler.sh (reported by cosmo@www.vdrportal.de)
+
+2004-04-22: Version 0.3.0
+- add dvd as input source
+- add one line in i18.c to be compatible with vdr-1.3.2 and newer
+- changed cMovie::setCropValues() to support dvd's
+- switch between 'crop boarders' and 'reset boarders' possible
+- now round crop & scale-values to a multiple of 16 (to avoid errors with
+ xvid and divx)
+- add more deinterlacing filters (requested by sebastian.kemper@web.de)
+- now colored items are used to display informations
+- decide between preview or full mode while adding a movie to the queue
+- close the encoding-menue after adding the movie to the queue (requested
+ by mariom@www.vdrportal.de)
+- display the encoding step in the queue menue (requested by
+ skyalex@www.vdrportal.de)
+- switching between preview mode and normal mode is possible in the
+ queue menu
+- moved 2-pass logfiles of the queuehandler to $tempdir.
+ (requested by mrmoe@www.vdrportal.de)
+- check for mplayer&mencoder (requested by hapemo@www.vdrportal.de)
+- some cosmetic changes in queue.c
diff --git a/INSTALL b/INSTALL
new file mode 100755
index 0000000..916a19f
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,317 @@
+Installation:
+=============
+
+Vdrrip is able to handle some different output-formats/codecs:
+
+- lavc, XviD and DivX as video-codecs
+- lame, ogg-vorbis, mp2, ac3 as audio-codecs
+- avi, ogm, matroska as container-format
+
+The requirements of vdrrip depend on the audio-codecs and container-
+formats, which you want to use. See the following table to know what
+you have to install. No fear, you need only MPlayer[5] to create an
+avi-file with divx-video(lavc) and mp2/ac3-audio(copy). If you want
+mp3-audio for example, you have to install LAME[2a], too.
+
+=======================================================================
+Contanier-formats/ | avi | ogm **) | matroska **) |
+Audio-codecs: | | | |
+=======================================================================
+LAME | 2a/5 | 2a/3b/4a/4b/5 | 2a/3c/4a/4b/5 |
+-----------------------------------------------------------------------
+ogg-vorbis **) | not possible | 2b/3b/4a/4b/5 | 2b/3c/4a/4b/5 |
+-----------------------------------------------------------------------
+mpg (stream-copy) | 5 | 3b/4a/4b/5 *) | 3c/4b/5 |
+-----------------------------------------------------------------------
+ac3 (stream-copy) | 5 | 3b/4b/5 | 3c/4b/5 |
+-----------------------------------------------------------------------
+
+*) It is not possible to mux a mpg2-stream into an ogm-container. So the
+ mpg2-stream is converted to ac3 (with the same bitrate).
+
+**) Ogg-Vorbis/ac3/ogm/matroska-support isn't automatically detected by
+ vdrrip. You have to activate them manually in the plugins-setup menu.
+
+
+See 6) how to encode movies from DVD with vdrrip.
+
+
+1) Video-codecs:
+================
+
+Use only lavc for a minimal configuration, XviD and DivX are optional !
+
+ 1a) lavc <http://ffmpeg.sourceforge.net>:
+ -----------------------------------------
+ This open source divx-codec is shipped with MPlayer. It is very fast and
+ has a really good quality. Highly recommend !
+
+
+ 1b) XviD <http://www.xvid.org>:
+ -------------------------------
+ XviD is an open source divx-codec. If you want to use it as (additional)
+ video-codec, you have to run the following commands:
+
+ > cd /usr/local/src
+ > tar xzvf xvidcore-X.X.X.tgz
+ > cd xvidcore-X.X.X/build/generic
+ > ./configure
+ > make
+ > make install
+ > ldconfig (/etc/ld.so.conf should include /usr/local/lib)
+
+
+ 1c) DivX 4/5: <http://www.divx.com>
+ -----------------------------------
+ DivX is a closed source divx-codec. It is free for personal use. If you
+ want to use it as (additional) video-codec, you have to run the following
+ commands:
+
+ > cd /usr/local/src
+ > tar xzvf divx4linux-XXXXXXXX.tgz
+ > cd divx4linux-XXXXXXXX
+ > ./install.sh
+
+ If you use a mplayer version lower then 1.0pre, you need the version
+ 20020418 from
+ <http://sourceforge.net/project/showfiles.php?group_id=11050>. Else you
+ can use the version 5.0.5 from <http://www.divx.com>.
+
+
+
+2) Audio-codecs:
+================
+
+ 2a) LAME <http://lame.sourceforge.net>:
+ ---------------------------------------
+ Lame is an open source mp3 encoder. Using the LAME encoding engine (or
+ other mp3 encoding technology) may require a patent license in some
+ countries <http://lame.sourceforge.net/links.html#patents>.
+ If you want to use it as audio codec, you have to to run the following
+ commands:
+
+ > cd /usr/local/src
+ > tar xzvf lame-X.X.X.tgz
+ > cd lame-X.X.X
+ > ./configure
+ > make
+ > make install
+ > ldconfig (/etc/ld.so.conf should include /usr/local/lib)
+
+
+ 2b) ogg Vorbis <http://www.vorbis.com>:
+ ---------------------------------------
+ Ogg Vorbis is an patent free open source audio encoder.
+ If you want to use it audio codec, you have to download the following
+ sources from <http://www.voribs.com/download.psp>:
+
+ - libogg-X.X.X.tar.gz, install it with
+
+ > cd /usr/local/src
+ > tar xzvf libogg-X.X.X.tar.gz
+ > cd libogg-X.X.X
+ > ./configure
+ > make
+ > make install
+ > ldconfig (/etc/ld.so.conf should include /usr/local/lib)
+
+ - libvorbis-X.X.X.tar.gz, install it with
+ > cd /usr/local/src
+ > tar xzvf libvorbis-X.X.X.tar.gz
+ > cd libvorbis-X.X.X
+ > ./configure
+ > make
+ > make install
+ > ldconfig (/etc/ld.so.conf should include /usr/local/lib)
+
+
+3) Container-formats:
+=====================
+
+ 3a) avi:
+ --------
+ MPlayer/MEncoder supports the avi-format. You don't have to install
+ something else.
+
+
+ 3b) ogm <http://www.bunkus.org/videotools/ogmtools/index.html>:
+ ---------------------------------------------------------------
+ To use ogm as (additional) container format, you have to install the
+ OGMtools with:
+
+ > cd /usr/local/src
+ > tar xjvf ogmtools-X.X.tar.bz2
+ > cd ogmtools-X.X
+ > ./configure
+ > make
+ > make install
+
+ OGMtools depend on libogg and libvorbis [see 2b)] !
+
+
+ 3c) matroska <http://www.bunkus.org/videotools/mkvtoolnix/index.html>:
+ ----------------------------------------------------------------------
+ To use matroska as (additional) container format, you have to install the
+ following libraries/tools (I had to install libexpat on my testsystem !):
+
+ - libebml:
+
+ > cd /usr/local/src
+ > tar xjvf libebml-X.X.X.tar.bz2
+ > cd libebml-X.X.X/make/linux
+ > make
+ > make install
+ > ldconfig (/etc/ld.so.conf should include /usr/local/lib)
+
+ - libmatroska:
+
+ > cd /usr/local/src
+ > tar xjvf libmatroska-X.X.X.tar.bz2
+ > cd libmatroska-X.X.X/make/linux
+ > make
+ > make install
+ > ldconfig (/etc/ld.so.conf should include /usr/local/lib)
+
+ - mkvtoolnix:
+
+ > cd /usr/local/src
+ > tar xjvf mkvtoolnix-X.X.X.tar.bz2
+ > cd mkvtoolnix-X.X.X
+ > ./configure
+ > make
+ > make install
+
+ Mkvtoolnix depend on libogg and libvorbis [see 2b)] !
+
+
+4) Tools:
+=========
+
+ 4a) ffmpeg <http://ffmpeg.sourceforge.net>:
+ -------------------------------------------
+ ffmpeg is an open source tool, to convert between several video and audio
+ formats. You only need it together with ogm/matroska-containers. You can
+ install it with the following commands:
+
+ > cd /usr/local/src
+ > tar xzvf ffmpeg-X.X.X.tar.gz
+ > cd ffmpeg-X.X.X
+ > ./configure --disable-ffserver --disable-ffplay --disable-debug \
+ --enable-a52 --enable-mp3lame --enable-vorbis
+ (only use --enable-mp3lame, if LAME [2a] is installed)
+ (only use --enable-vorbis, if ogg Vorbis [2b] is installed)
+ > make
+ > make install
+
+
+ 4b) vdrsync <http://vdrsync.vdr-portal.de>:
+ -------------------------------------------
+ The perl-script vdrsync is used to demux the vdr-recordings. You only
+ need it together with ogm/matroska-containers. There is a copy of it
+ (version 0.1.2.2 without Documentation) in the directory /scripts. To use
+ it, type:
+
+ > cp vdrrip/scripts/vdrsync.pl /usr/local/bin
+
+ The version 0.1.2.2dev1 isn't supported at the moment (because of changes
+ in the output format) !
+
+
+5) MPlayer <http://www.mplayerhq.hu>:
+=====================================
+
+All Codecs [see 1/2] have to be installed before the MPlayer installation.
+All version higher than 0.90 should run. To compile and install mplayer run
+the following commands:
+
+ > cd /usr/local/src
+ > tar xjvf MPlayer-X.X.bz2
+ > cd MPlayer-X.X
+ > ./configure --with-extraincdir=<your path to the DVB-drivers>/include \
+ --enable-largefiles
+ > make
+ > make install (This mplayer/mencoder-version is used to encode
+ vdr-streams (without ac3) and dvd's !!!)
+
+
+ If you want to encode/copy ac3-audio from vdr-recordings (not dvd's), you
+ have to install a second, patched (form the directory /patches) version
+ of MPlayer (thx to viking@www.vdrportal.de):
+
+ > cd /usr/local/src
+ > cp -a MPlayer-X.X MPlayer-X.X_ac3
+ > cd MPlayer-X.X_ac3
+ > cat MPlayer_vdrac3.diff | patch libmpdemux/demux_mpg.c
+ > cd libmpdemux
+ > make clean
+ > cd ..
+
+ > ./configure --with-extraincdir=<your path to the DVB-drivers>/include \
+ --enable-largefiles
+ > make (don't type make install after this !!!)
+ > cp mplayer /usr/local/bin/mplayer_ac3
+ > cp mencoder /usr/local/bin/mencoder_ac3
+
+
+6) encoding from DVD:
+=====================
+
+To encode movies from DVD you have to install the library libdvdnav from
+<http://dvd.sourceforge.net>:
+
+ > cd /usr/local/src
+ > tar xzvf libdvdnav-X.X.X.tar.gz
+ > ./configure
+ > make
+ > make install
+
+Then uncomment the line VDRRIP_DVD=1 in the file Makefile.
+
+The tested version is libdvdnav-0.1.9. This is the same version which is
+recommend for the dvd-plugin.
+
+The default DVD-device is /dev/dvd. If you have a different path, set a
+symlink or specify the value -d DEV in your vdr start-script.
+
+HINTS: If the kernel-module ide-scsi is loaded, your DVD-device is probably
+/dev/sr0 or /dev/sr1.
+
+And don't forget to give read-privileges to the user which starts vdr.
+
+
+7) vdrrip-plugin:
+=================
+
+ > cd vdr/PLUGINS/src
+ > tar xzvf vdr-vdrrip-X.X.X.tgz
+ > ln -s vdrrip-X.X.X vdrrip
+ > cp vdrrip/scripts/queuehandler.sh /usr/local/bin (or e.g. /usr/bin)
+ > cp vdrrip/scripts/queuehandler.sh.conf /usr/local/bin (or e.g. /usr/bin)
+ > cd ../..
+ > make plugins
+
+ Now you have to adjust the settings in the file queuehandler.sh.conf
+
+ See the README and FAQ how to use the queuehandler.
+
+
+ optional:
+ > cp vdrrip/scripts/vdrshutdown.sh /usr/local/bin (or e.g. /usr/bin)
+ > cp vdrrip/scripts/sleephalt.sh /usr/local/bin (or e.g. /usr/bin)
+
+
+ To load the plugin add '-Pvdrrip' to your vdr start-script. If mplayer/
+ mencoder aren't installed to /usr/local/bin, you have to add the
+ following paramter:
+
+ -p LOC, --MPlayer=LOC use LOC as location of MPlayer
+ (default is /usr/local/bin/mplayer)
+ -e LOC, --MEncoder=LOC use LOC as location of MEncoder
+ (default is /usr/local/bin/mencoder)
+ This parameter could be used to specify you DVD-device:
+ -d DEV, --DVD=DEV use DEV as your DVD-device
+ (default is /dev/dvd)
+
+ e.g: -P'vdrrip -p /bin/mplayer -e /bin/mencoder'
+
+ To use the shutdown scripts, add -s <path-to-vdrshutdown.sh>.
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..719ab9d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,91 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id$
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = vdrrip
+
+### uncomment this line, if you want to encode DVD's
+#VDRRIP_DVD=1
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX ?= g++
+CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o \
+ menu-vdrrip.o movie.o templates.o codecs.o queue.o vdrriprecordings.o a-tools.o i18n.o
+
+ifdef VDRRIP_DVD
+ DEFINES += -DVDRRIP_DVD
+ LIBS += -ldvdnav
+endif
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: libvdr-$(PLUGIN).so
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(VDRVERSION)
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
diff --git a/README b/README
new file mode 100755
index 0000000..156694e
--- /dev/null
+++ b/README
@@ -0,0 +1,118 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: herbert attenberger <herbsl at a-land.de>
+
+Project's homepage: <http://www.a-land.de>
+
+Latest version available at: <http://www.a-land.de>
+
+See the file COPYING for license information.
+
+See the file INSTALL for the installation instructions.
+
+
+Description:
+============
+
+Vdrrip is a plugin to encode the vdr-recordings or dvd's into several
+formats. The supported output-formats are:
+
+Containers: avi, ogm, matroska
+Video-codecs(divx): lavc, xvid, divx4/5
+Audio-codecs: mp3, ogg-vorbis, stream-copy for ac3 and mpeg2
+
+Ogg-vorbis, ac3, ogm and matroska have to be manually activated in the
+setup-menu of the plugin. All further codecs are automatically detected by
+the plugin.
+
+You can manually adjust the encoding values, or simply select a
+template (read the section 'Templates' in this manual to find out
+more about them). If you input the resulting movie size (or number of
+files), the video/audio bitrate is calculated. If you change the video/
+audio bitrate, the file size is calculated. If there is more then one
+audio-stream available, you can toggle between them.
+
+You can choose between four scaling mechanism:
+
+off: Don't scale, use the original resolution
+auto: The scale values are calculated on a algorithm which is based on
+ the bpp-value. Read the file DOCS/tech/encoding-tips.txt in your
+ MPlayer-source directory for further informations. The aspect ratio
+ is corrected
+dvb: You can only choose values, which are supported by the DVB-Card
+ without needing a further scaling while playing. This option
+ (together with streamcopy as audio codec) is very useful for slow
+ computers (it is possible to play those files on my Celeron 466
+ Mhz).
+manual: Select the resolution manually.
+
+In the auto and manual-mode you can automatically detect and crop the black
+movie-boarders with the green key. All settings are saved in the file
+save.vdrrip in the movie directory. After this you can add the movie with
+the red key to the encoding queue (this is the file queue.vdrrip in the
+plugins-directory) and select between preview or full encoding-mode.
+The script queuehandler.sh reads the data from the queue, joins
+or demuxes the vdr-files and encodes the movie.
+
+Some parameters of vdrrip can be adjusted in the setup menu.
+
+DVD's:
+======
+
+See the INSTALL-file how to compile vdrrip with DVD-support.
+
+Vdrrip automatically takes the longest title of the DVD. It is possible
+to switch between them in the menu. If you press <ok> on the title-
+line, a more comfortable title-menu is opened. The last settings
+are saved in the file /tmp/<DVD-NAME>.vdrrip, and will be restored
+if you want to encode the same dvd again.
+
+WARNING !
+
+Most DVDs are encrypted with CSS (Contents Scrambling System). Copying
+of encrypted DVDs is illegal in many countries. This program is not
+meant for those who intend on breaking copyright laws. Every illegal
+use of this software is strictly prohibited. In no way I will be held
+responsible if you do. Be aware to check your countries law !
+
+
+Templates:
+==========
+
+Within a template ('Vdrrip - edit template') you can predefine the encoding-
+settings (either with a fixed file size or a fixed bitrate). The default
+settings are taken from the template 'default'. You can add further
+templates (e.g 1/2-CD, 2/3-CD ...). All templates are saved in the file
+templates.vdrrip in the dir <vdr-config-dir>/PLUGINS.
+
+
+usage of the quehandler-script:
+===============================
+
+queuehandler.sh queuefile tempdir
+
+The queuefile is the file queue.vdrrip in the dir <vdr-config-dir>/PLUGINS.
+This file is only created, if you add a movie to the queue. After the
+encoding the file is deleted by the queuehandler-script. If the movie
+couldn't be encoded by the queuehandler because of an error, the queue-
+data will be moved to the file queue.vdrrip.rejected. Then you have to look
+into the syslog, correct the error and move the movie back to the queue
+with the commands: "cat queue.vdrrip.rejected >> queue.vdrrip" and
+"rm queue.vdrrip.rejected"
+
+Tempdir is the directory where all temporary files are created and where the
+encoded movies are saved. There should be enough space free !
+
+There is no audio-stream in the preview-mode, if the container type is ogm
+or matroska !
+
+
+The file <vdr-config>/PLUGINS/encode.vdrrip is created while an active
+encoding process. You can use it to keep vdr from an automatic shutdown.
+I added my sample scripts vdrshutdown.sh and sleephalt.sh in the dir
+scripts. Feel free to use them. Read the file FAQ to see how you can add
+the queuehandler to the file commands.conf.
+
+
+Please read the files INSTALL, FAQ and TODO for further informations.
+And beware of the dangerous xaver.jpg ...
diff --git a/TODO b/TODO
new file mode 100755
index 0000000..c073c55
--- /dev/null
+++ b/TODO
@@ -0,0 +1,27 @@
+high priority:
+
+
+low priority:
+
+- add pp-filters to templates
+- support more then one audio-stream in ogm/matroska-containers
+
+no priority:
+
+- add music-cd encoding support
+- support different output formats (svcd ...)
+- add possibility to burn the encoded movies to a cd/dvd
+
+done:
+
+- add setup menu (13.09.2003)
+- fix the osd-bugs (help-keys, etc.) (25.09.2003)
+- (first) code-cleanup (25.09.2003)
+- add menu for postprocessing filters (28.09.2003)
+- add script-changes from memed@www.vdrportal.de (28.09.2003)
+- add templates (12.10.2003)
+- add ScaleType, Bpp to templates(19.10.2003)
+- add internationalization support(20.10.2003)
+- add ogg/ogm/matroska-formats (13.01.2004)
+- add status-informations in the encoding-queue (16.04.2004)
+- add dvd encoding support (16.04.2004)
diff --git a/a-tools.c b/a-tools.c
new file mode 100755
index 0000000..e8d36b5
--- /dev/null
+++ b/a-tools.c
@@ -0,0 +1,111 @@
+/* a-tools.c:
+ some tools from herbert attenberger <herbsl@a-land.de>
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <vdr/plugin.h>
+
+#include "a-tools.h"
+
+char *strsub(char* s, int p, int n) {
+ char *s1;
+ int l;
+
+ // let's do some checks:
+ if (s == NULL) {return NULL;}
+
+ l = strlen(s);
+ if (p > l || p < 1 || n < 1) {return NULL;}
+ if (p + n > l + 1) {n = l - p + 1;}
+
+ // point s to the beginning of the substring
+ s = s + p - 1;
+
+ // allocate memory and store the substring in s1
+ s1 = (char*) malloc(sizeof(char) * (n + 1));
+ memmove(s1, s, sizeof(char) * n);
+ s1[n] = '\0';
+
+ return s1;
+}
+
+char *strcol(char *s, char *d, int c) {
+ char *s1, *s2;
+ int i;
+ int l, l1;
+
+ // let's do some checks:
+
+ if (s == NULL) {return NULL;}
+ if (d == NULL) {return NULL;}
+ if (c < 1) {return NULL;}
+
+ l = strlen(d);
+
+ // point s to the beginning of the column
+ for (i = 1; i < c; i++) {
+ s = strstr(s, d);
+ if (s == NULL) {return NULL;}
+ s = s + l;
+ }
+
+ // point s1 to the end of the column
+ s1 = strstr(s, d);
+ if (s1 == NULL) {
+ // check newline or end of string
+ s1 = strchr(s, '\n');
+ if (s1 == NULL) {s1 = strchr(s,'\0');}
+ }
+
+ l1 = s1 -s; // store length of column in l1
+
+ // allocate memory and store the column in s2
+ s2 = (char*) malloc(sizeof(char) * (l1 + 1));
+ memmove(s2, s, sizeof(char) * l1);
+ s2[l1] = '\0';
+
+ return s2;
+}
+
+int strnumcol(const char *s, char *d) {
+ char *s1;
+ int i, l;
+
+ // let's do some checks:
+ if (s == NULL) {return 0;}
+ if (d == NULL) {return 0;}
+
+ i = 1;
+ l = strlen(d);
+
+ s1 = strstr(s, d);
+ while (s1 != NULL) {
+ i++;
+ s1 = s1 + l;
+ s1 = strstr(s1, d);
+ }
+
+ return i;
+}
+
+char *strgrep(char *s, FILE *f) {
+ char *s1 = "";
+ size_t i = 0;
+
+ // let's do some checks
+ if (s == NULL) {return NULL;}
+
+ // search the line
+ while (strstr(s1, s) == NULL) {
+ if (getline(&s1, &i, f) == -1) {
+ dsyslog("string %s not found !", s);
+ return NULL;
+ }
+ }
+
+ return s1;
+}
+
+int roundValue(int i, int i1) {return i / i1 * i1;}
diff --git a/a-tools.h b/a-tools.h
new file mode 100755
index 0000000..312c5ca
--- /dev/null
+++ b/a-tools.h
@@ -0,0 +1,23 @@
+/* a-tools.h:
+ some tools from herbert attenberger <herbsl@a-land.de>
+*/
+
+#ifndef __A_TOOLS_H
+#define __A_TOOLS_H
+
+#include <stdio.h>
+
+#define FREE(x) if (x) {free(x); x = NULL;}
+#define DELETE(x) if (x) {delete x; x = NULL;}
+
+char *strsub(char *s, int p, int numbers);
+
+char *strcol(char *s, char *d, int c);
+
+int strnumcol(const char *s, char *d);
+
+char *strgrep(char *s, FILE *f);
+
+int roundValue(int i, int i1);
+
+#endif //__A_TOOLS_H
diff --git a/codecs.c b/codecs.c
new file mode 100755
index 0000000..5b159a2
--- /dev/null
+++ b/codecs.c
@@ -0,0 +1,200 @@
+/* codecs.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vdr/plugin.h>
+
+#include "codecs.h"
+#include "menu-vdrrip.h"
+#include "a-tools.h"
+
+#define MENCCMD "%s %s help 2>/dev/null"
+#define VCODECS "lavc, xvid, divx4"
+#define ACODECS "lame, copy, ogg-vorbis"
+
+extern const char *MEncoder;
+
+// --- cCodecs ------------------------------------------------------------
+
+cCodecs::cCodecs() {
+ VCodecs = ACodecs = Containers = NULL;
+
+ queryCodecs(VCODECS, ACODECS);
+ queryContainers();
+}
+
+cCodecs::~cCodecs() {
+ FREE(VCodecs);
+ FREE(ACodecs);
+ FREE(Containers);
+}
+
+void cCodecs::queryCodecs(char *v, char *a) {
+ char *buf = NULL, *cmd = NULL;
+ size_t i = 0;
+ int c, c1, nvc, nac;
+
+ // get number of codecs
+ nvc = strnumcol(v, ", ");
+ nac = strnumcol(a, ", ");
+
+ // reserve memory for arrays
+ VCodecs = (char**)malloc(nvc * sizeof(char*));
+ ACodecs = (char**)malloc(nac * sizeof(char*));
+
+ // read codecs in arryas
+ for (c = 0; c < nvc; c++) {
+ VCodecs[c] = strcol(v, ", ", c + 1);
+ }
+ for (c = 0; c < nac; c++) {
+ ACodecs[c] = strcol(a, ", ", c + 1);
+ }
+
+ // detect available video codecs with mencoder,
+ // move them to the beginning of the array and
+ // save the number of supported codecs in NumVCodecs
+ c1 = 0;
+
+ NumVCodecs = 0;
+ asprintf(&cmd, MENCCMD, MEncoder, "-ovc");
+ FILE *p = popen(cmd, "r");
+ if (p) {
+ while (getline(&buf, &i, p) != -1) {
+ for (c = c1; c < nvc; c++) {
+ if (strstr(buf, VCodecs[c])) {
+ // move found video codec to VCodecs[i1]
+ char *tmp = VCodecs[c1];
+ VCodecs[c1] = VCodecs[c];
+ VCodecs[c] = tmp;
+ c1++;
+ NumVCodecs++;
+ }
+ }
+ }
+ }
+ pclose(p);
+ FREE(cmd);
+
+ // detect available audio codecs with mencoder,
+ // move them to the beginning of the array and
+ // save the number of supported codecs in NumACodecs
+ c1 = 0;
+
+ NumACodecs = 0;
+ asprintf(&cmd, MENCCMD, MEncoder, "-oac");
+ p = popen(cmd, "r");
+ if (p) {
+ while (getline(&buf, &i, p) != -1) {
+ for (c = c1; c < nac; c++) {
+ if (strstr(buf, ACodecs[c])) {
+ // switch found audio codec with ACodecs[i1]
+ char *tmp = ACodecs[c1];
+ ACodecs[c1] = ACodecs[c];
+ ACodecs[c] = tmp;
+ c1++;
+ NumACodecs++;
+ }
+ }
+ }
+ }
+ pclose(p);
+ FREE(cmd);
+
+ if (VdrripSetup.OggVorbis == 1) {
+ ACodecs[NumACodecs] = strdup("ogg-vorbis");
+ NumACodecs++;
+ }
+
+ FREE(buf);
+}
+
+void cCodecs::queryContainers() {
+ NumContainers = 1;
+ int i = 1;
+ if (VdrripSetup.Ogm == 1) {NumContainers++;}
+ if (VdrripSetup.Matroska == 1) {NumContainers++;}
+
+ Containers = (char**)malloc(NumContainers * sizeof(char*));
+
+ Containers[0] = "avi";
+
+ if (VdrripSetup.Ogm == 1) {
+ Containers[i] = "ogm";
+ i++;}
+
+ if (VdrripSetup.Matroska == 1) {Containers[i] = "matroska";}
+}
+
+
+int cCodecs::getNumVCodecs() {return NumVCodecs;}
+
+int cCodecs::getNumACodecs() {return NumACodecs;}
+
+int cCodecs::getNumContainers() {return NumContainers;}
+
+char **cCodecs::getVCodecs() {return VCodecs;}
+
+char **cCodecs::getACodecs() {return ACodecs;}
+
+char **cCodecs::getContainers() {return Containers;}
+
+char *cCodecs::getVCodec(int i) {return VCodecs[i];}
+
+char *cCodecs::getACodec(int i) {return ACodecs[i];}
+
+char *cCodecs::getContainer(int i) {return Containers[i];}
+
+int cCodecs::getNumVCodec(char *v) {
+ int i = 0;
+
+ // check if there are video codecs available
+ if (NumVCodecs == 0) {
+ dsyslog("[vdrrip] fatal error: no video codec found !");
+ return -2;
+ }
+
+ while (strcmp(v, VCodecs[i]) != 0) {
+ i++;
+ if (i == NumVCodecs) {
+ dsyslog("[vdrrip] video codec %s not found !", v);
+ return -1;
+ }
+ }
+
+ return i;
+}
+
+int cCodecs::getNumACodec(char *a) {
+ int i = 0;
+
+ // check if there are audio codecs available
+ if (NumACodecs == 0) {
+ dsyslog("[vdrrip] fatal error: no audio codec found !");
+ return -2;
+ }
+
+ while (strcmp(a, ACodecs[i]) != 0) {
+ i++;
+ if (i == NumACodecs) {
+ dsyslog("[vdrrip] audio codec %s not found !", a);
+ return -1;
+ }
+ }
+
+ return i;
+}
+
+int cCodecs::getNumContainer(char *c) {
+ int i = 0;
+
+ while (strcmp(c, Containers[i]) != 0) {
+ i++;
+ if (i == NumContainers) {
+ dsyslog("[vdrrip] container %s not found !", c);
+ return -1;
+ }
+ }
+
+ return i;
+}
diff --git a/codecs.h b/codecs.h
new file mode 100755
index 0000000..d9f1a2c
--- /dev/null
+++ b/codecs.h
@@ -0,0 +1,36 @@
+// codecs.h
+
+#ifndef __CODECS_H
+#define __CODECS_H
+
+class cCodecs {
+ protected:
+ int NumVCodecs;
+ int NumACodecs;
+ int NumContainers;
+
+ char **VCodecs;
+ char **ACodecs;
+ char **Containers;
+
+ void queryCodecs(char *v, char *a);
+ void queryContainers();
+ public:
+ cCodecs();
+ ~cCodecs();
+
+ int getNumVCodecs();
+ int getNumACodecs();
+ int getNumContainers();
+ char *getVCodec(int i);
+ char *getACodec(int i);
+ char *getContainer(int i);
+ int getNumVCodec(char *v);
+ int getNumACodec(char *a);
+ int getNumContainer(char *c);
+ char **getACodecs();
+ char **getVCodecs();
+ char **getContainers();
+};
+
+#endif // __CODECS_H
diff --git a/i18n.c b/i18n.c
new file mode 100755
index 0000000..b25b29a
--- /dev/null
+++ b/i18n.c
@@ -0,0 +1,1356 @@
+// i18n.c
+
+#include "i18n.h"
+
+const tI18nPhrase Phrases[] = {
+ { "encode vdr-recording",
+ "VDR-Aufzeichnung encodieren",
+ "",// TODO
+ "Comprimi registrazioni di vdr",
+ "",// TODO
+ "",// TODO
+ "Encoder un enregistrement",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "edit encoding queue",
+ "Warteschlange bearbeiten",
+ "",// TODO
+ "Visualizza coda di compressione",
+ "",// TODO
+ "",// TODO
+ "Voir les encodages en attente",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "edit templates",
+ "Schablonen bearbeiten",
+ "",// TODO
+ "Editare le maschere",
+ "",// TODO
+ "",// TODO
+ "Editer les gabarits",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "encoding queue",
+ "Warteschlange",
+ "",// TODO
+ "Coda di compressione",
+ "",// TODO
+ "",// TODO
+ "Queue d'encodage",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "edit template",
+ "Schablone bearbeiten",
+ "",// TODO
+ "Editare la maschera",
+ "",// TODO
+ "",// TODO
+ "Editer les gabarits",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "reading movie-data...",
+ "lese Film-Daten...",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif //VDRVERSNUM
+ },
+
+ { "edit",
+ "bearbeiten",
+ "",// TODO
+ "Editare",
+ "",// TODO
+ "",// TODO
+ "Editer",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "new",
+ "neu",
+ "",// TODO
+ "Nuovo",
+ "",// TODO
+ "",// TODO
+ "Nouveau",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "delete",
+ "löschen",
+ "",// TODO
+ "Cancellare",
+ "",// TODO
+ "",// TODO
+ "Effacer",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "delete template %s ?",
+ "Schablone %s löschen ?",
+ "",// TODO
+ "Cancellare maschera %s ?",
+ "",// TODO
+ "",// TODO
+ "Effacer le gabarit %s ?",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Name",
+ "Name",
+ "",// TODO
+ "Nome",
+ "",// TODO
+ "",// TODO
+ "Nom",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "FileSize",
+ "Datei-Grösse",
+ "",// TODO
+ "Dimensione file",
+ "",// TODO
+ "",// TODO
+ "TailleFich",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "FileNumbers",
+ "Anzahl Dateien",
+ "",// TODO
+ "Numero di file",
+ "",// TODO
+ "",// TODO
+ "Nb fichiers",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "BitrateVideo",
+ "Bitrate Video",
+ "",// TODO
+ "Video bitrate",
+ "",// TODO
+ "",// TODO
+ "Bitrate Video",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "BitrateAudio",
+ "Bitrate Audio",
+ "",// TODO
+ "Audio bitrate",
+ "",// TODO
+ "",// TODO
+ "Bitrate Audio",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Container",
+ "Container",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Video-Codec",
+ "Video Codec",
+ "",// TODO
+ "Codec video",
+ "",// TODO
+ "",// TODO
+ "Codec Video",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Audio-Codec",
+ "Audio Codec",
+ "",// TODO
+ "Codec audio",
+ "",// TODO
+ "",// TODO
+ "Codec Audio",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Bpp-Value (*100)",
+ "Bpp-Wert (*100)",
+ "",// TODO
+ "Valore Bpp (*100)",
+ "",// TODO
+ "",// TODO
+ "ValeurBpp (*100)",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "ScaleType",
+ "Skalierungsart",
+ "",// TODO
+ "Tipo scalatura",
+ "",// TODO
+ "",// TODO
+ "Dimensionnement",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "encode movie",
+ "Film encodieren",
+ "",// TODO
+ "Compressione video",
+ "",// TODO
+ "",// TODO
+ "Encoder le film",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "add movie to encoding queue ?",
+ "Film zur Warteschlange hinzufügen ?",
+ "",// TODO
+ "Aggiungere un film alla coda di compressione ?",
+ "",// TODO
+ "",// TODO
+ "Ajouter le film à la queue d'encodage ?",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "crop black movie boarders ?",
+ "schwarze Filmränder schneiden ?",
+ "",// TODO
+ "Tagliare i bordi neri del video ?",
+ "",// TODO
+ "",// TODO
+ "Découper le film entre les limites noires ?",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "reset black movie boarders ?",
+ "schwarze Filmränder löschen ?",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "search for black movie boarders",
+ "suche nach schwarzen Filmrändern",
+ "",// TODO
+ "Ricerca bordi neri nel video",
+ "",// TODO
+ "",// TODO
+ "Rechercher les limites noires dans le film",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "couldn't detect black movie boarders !",
+ "konnte keine schwarzen Filmränder erkennen !",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "add to queue",
+ "in Warteschl.",
+ "",// TODO
+ "Aggiunto in coda",
+ "",// TODO
+ "",// TODO
+ "Ajout. Queue",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "crop boarders",
+ "Ränder schn.",
+ "",// TODO
+ "Taglio bordi",
+ "",// TODO
+ "",// TODO
+ "Supp. les limites",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "reset boarders",
+ "Ränder lösch.",
+ "",// TODO
+ "Taglio bordi",
+ "",// TODO
+ "",// TODO
+ "Supp. les limites",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "expert modus(off)",
+ "Exp.-Modus(aus)",
+ "",// TODO
+ "Modo esperto(off)",
+ "",// TODO
+ "",// TODO
+ "Mode Expert(off)",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "expert modus(on)",
+ "Exp.-Modus(ein)",
+ "",// TODO
+ "Modo esperto(on)",
+ "",// TODO
+ "",// TODO
+ "Mode Expert(on)",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Template",
+ "Schablone",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "Gabarit",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Audio-Str.",
+ "Audiospur",
+ "",// TODO
+ "Stream audio",
+ "",// TODO
+ "",// TODO
+ "Flux Audio",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "MovieData",
+ "Film-Daten",
+ "",// TODO
+ "Dati del Film",
+ "",// TODO
+ "",// TODO
+ "Film-Infos",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "CropData",
+ "Schnitt-Daten",
+ "",// TODO
+ "Valori di taglio",
+ "",// TODO
+ "",// TODO
+ "ValeursDécoupage",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "ScaleData",
+ "Skalierung",
+ "",// TODO
+ "Valore di scalatura",
+ "",// TODO
+ "",// TODO
+ "ValeursRedimensionnement",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "ScaleWidth",
+ "Skal.-breite",
+ "",// TODO
+ "Scalatura larghezza",
+ "",// TODO
+ "",// TODO
+ "Largeur Redimensionnement",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "ScaleHeight",
+ "Skal.-höhe",
+ "",// TODO
+ "Scalatura altezza",
+ "",// TODO
+ "",// TODO
+ "Hauteur Redimensionnement",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "------ expert settings: ------",
+ "--- Experten-Einstellungen: ---",
+ "",// TODO
+ "------ settaggi esperto: ------",
+ "",// TODO
+ "",// TODO
+ "--- Paramètres Mode Expert: ---",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "- adjust crop values:",
+ "- Schnittwerte anpassen:",
+ "",// TODO
+ "- aggiustatura valori di taglio:",
+ "",// TODO
+ "",// TODO
+ "- Ajuster les valeurs de découpage:",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "CropWidth",
+ "Schnittbreite",
+ "",// TODO
+ "Taglio larghezza",
+ "",// TODO
+ "",// TODO
+ "Largeur Découpage",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "CropHeight",
+ "Schnitthöhe",
+ "",// TODO
+ "Taglio altezza",
+ "",// TODO
+ "",// TODO
+ "Hauteur Découpage",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "- postprocessing Filters(%s):",
+ "- Nachbearbeitungsfilter(%s):",
+ "",// TODO
+ "- Filtri dopo il processo(%s):",
+ "",// TODO
+ "",// TODO
+ "- Filtres de PostTraitement(%s):",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "- remaining:",
+ "- sonstiges:",
+ "",// TODO
+ "- rimanenti:",
+ "",// TODO
+ "",// TODO
+ "- restant:",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "MaxScaleWidth",
+ "max. Skal.-breite",
+ "",// TODO
+ "Massima scalatura larghezza",
+ "",// TODO
+ "",// TODO
+ "LargeurMaxiRedimensionnement",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "MinScaleWidth",
+ "min. Skal.-breite",
+ "",// TODO
+ "Minima scalatura larghezza",
+ "",// TODO
+ "",// TODO
+ "LargeurMiniRedimensionnement",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Crop Mode",
+ "Schnittmodus",
+ "",// TODO
+ "Modo di taglio",
+ "",// TODO
+ "",// TODO
+ "Mode de découpage",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Crop DetectLength (s)",
+ "Schnitt-Suchdauer (s)",
+ "",// TODO
+ "Ricerca larghezza di taglio (s)",
+ "",// TODO
+ "",// TODO
+ "Découpage-Longeur de détection (s)",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "Rename movie after encoding",
+ "Film nach Enc. umbenennen",
+ "",// TODO
+ "Rinnominare il film dopo la compressione",
+ "",// TODO
+ "",// TODO
+ "Renommer le film après l'encodage",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "up",
+ "nach oben",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "down",
+ "nach unten",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "switch mode",
+ "Modus wechseln",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "<ok> for preview-mode",
+ "<ok> fuer Vorschau-Modus",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "the queuefile is locked by the queuehandler !",
+ "die Warteschlange wird momentan vom queuehandler gesperrt !",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+
+ { "delete movie %s from queue ?",
+ "Film %s von Warteschl. löschen ?",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+
+ { "not used",
+ "keine Nutzung",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "unknown",
+ "unbekannt",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+ { "not found",
+ "nicht gefunden",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif
+ },
+
+#ifdef VDRRIP_DVD
+ { "encode dvd",
+ "DVD encodieren",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif //VDRVERSNUM
+ },
+
+ { "back",
+ "zurueck",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif //VDRVERSNUM
+ },
+
+ { "checking dvd...",
+ "ueberpruefe dvd...",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif //VDRVERSNUM
+ },
+
+ { "Title*",
+ "Titel*",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif //VDRVERSNUM
+ },
+
+ { "accept",
+ "akzeptieren",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif //VDRVERSNUM
+ },
+
+ { "reading audio-data from dvd...",
+ "lese Audio-Daten von DVD...",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+#if VDRVERSNUM>10301
+ "",// TODO
+#endif //VDRVERSNUM
+ },
+
+#endif //VDRRIP_DVD
+
+ { NULL }
+ };
diff --git a/i18n.h b/i18n.h
new file mode 100755
index 0000000..dbdeaef
--- /dev/null
+++ b/i18n.h
@@ -0,0 +1,10 @@
+// i18n.h
+
+#ifndef _I18N__H
+#define _I18N__H
+
+#include <vdr/i18n.h>
+
+extern const tI18nPhrase Phrases[];
+
+#endif //_I18N__H
diff --git a/menu-vdrrip.c b/menu-vdrrip.c
new file mode 100755
index 0000000..356ddba
--- /dev/null
+++ b/menu-vdrrip.c
@@ -0,0 +1,1275 @@
+//
+// menu-vdrrip.c
+//
+
+#include <vdr/plugin.h>
+#include <vdr/videodir.h>
+
+#ifdef VDRRIP_DVD
+ #include <dvdnav/ifo_read.h>
+#endif //VDRRIP_DVD
+
+#include "menu-vdrrip.h"
+#include "movie.h"
+#include "a-tools.h"
+#include "templates.h"
+#include "queue.h"
+#include "vdrriprecordings.h"
+
+#define MINQUANT 2
+#define MAXQUANT 15
+
+#define NUMSCALETYPES 4
+#define NUMPPDEINT 6
+
+static const char *ScaleTypes[] = { "off", "auto", "dvb", "manual" };
+static const char *DVBScaleWidths[] = { "352", "480", "544", "688", "704", "720" };
+static const char *DVBScaleHeights[] = { "288", "576" };
+static const char *CropModes[] = { "crop width & height", "crop only height"};
+static const char *PPDeint[] = { "off", "fd", "lb", "li", "ci", "md", };
+
+// --- cMenuVdrrip ---------------------------------------------------------
+
+cMenuVdrrip::cMenuVdrrip():cOsdMenu("Vdrrip") {Set();}
+
+void cMenuVdrrip::Set() {
+ Clear();
+
+ Add(new cOsdItem(tr("encode vdr-recording"), osUser1));
+
+#ifdef VDRRIP_DVD
+ Add(new cOsdItem(tr("encode dvd"), osUser2));
+#endif //VDRRIP_DVD
+
+ Add(new cOsdItem(tr("edit encoding queue"), osUser3));
+ Add(new cOsdItem(tr("edit templates"), osUser4));
+}
+
+eOSState cMenuVdrrip::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ switch (state) {
+ case osUser1: {
+ AddSubMenu(new cMenuVdrripEncode);
+ break;
+ }
+
+#ifdef VDRRIP_DVD
+ case osUser2: {
+ const char *s = "Most DVDs are encrypted with CSS (Contents "
+ "Scrambling System). Copying of encrypted DVDs is illegal in "
+ "many countries. This program is not meant for those who intend "
+ "on breaking copyright laws. Every illegal use of this software "
+ "is strictly prohibited. In no way I will be held responsible "
+ "if you do. "
+ "Be aware to check your countries law !";
+
+ AddSubMenu(new cMenuVdrripWarning("Warning", s));
+ break;
+ }
+#endif
+
+ case osUser3: {
+ AddSubMenu(new cMenuVdrripQueue);
+ break;
+ }
+
+ case osUser4: {
+ AddSubMenu(new cMenuVdrripTemplates);
+ break;
+ }
+
+ default: break;
+ }
+
+ return state;
+}
+
+
+// --- cMenuVdrripWarning ----------------------------------------------------------
+
+# ifdef VDRRIP_DVD
+
+cMenuVdrripWarning::cMenuVdrripWarning(const char *Title, const char *Text)
+:cOsdMenu(Title)
+{
+ bool warning;
+ warning = true;
+ //warning = false;
+
+ if (warning) {
+ Add(new cMenuTextItem(Text, 1, 2, Setup.OSDwidth - 2, MAXOSDITEMS, clrWhite, clrBackground, fontOsd));
+ SetHelp(tr("back"), tr("accept"), NULL, NULL);
+ hadsubmenu = false;
+ } else {
+ if (CheckDVD()) AddSubMenu(new cMenuVdrripMovie("dvd://", ""));
+ hadsubmenu = true;
+ }
+}
+
+eOSState cMenuVdrripWarning::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (HasSubMenu()) {
+ hadsubmenu = true;
+ return osContinue;
+ }
+
+ if (hadsubmenu) {return osBack;}
+
+ switch (Key) {
+ case kRed: return osBack;
+
+ case kGreen: {
+ if (CheckDVD()) AddSubMenu(new cMenuVdrripMovie("dvd://", ""));
+ break;
+ }
+
+ default: break;
+ }
+
+ return state;
+}
+
+bool cMenuVdrripWarning::CheckDVD() {
+ dvd_reader_t *dvd = NULL;
+ ifo_handle_t *ifo_zero = NULL;
+ ifo_handle_t *ifo_tmp = NULL;
+
+ Interface->Status(tr("checking dvd..."));
+ Interface->Flush();
+
+ if (access(DVD, R_OK) == -1) {
+ char *s = NULL;
+ asprintf(&s, "No read privileges on %s !", DVD);
+ Interface->Error(s);
+ FREE(s);
+ return false;
+ }
+
+ dvd = DVDOpen(DVD);
+
+ if (dvd) {
+ ifo_zero = ifoOpen(dvd, 0);
+ if (ifo_zero) {
+ for (int i = 1; i < ifo_zero->vts_atrt->nr_of_vtss; i++) {
+ ifo_tmp = ifoOpen(dvd, i);
+ if (ifo_tmp) ifoClose(ifo_tmp);
+ else {
+ char *s = NULL;
+ asprintf(&s, "Can't open ifo %d !", i);
+ Interface->Error(s);
+ FREE(s);
+ DVDClose(dvd);
+ return false;
+ }
+ }
+ ifoClose(ifo_zero);
+ DVDClose(dvd);
+ return true;
+ } else {
+ DVDClose(dvd);
+ Interface->Error("Can't open main ifo from dvd !");
+ return false;
+ }
+ }
+
+ char *s = NULL;
+ asprintf(&s, "Can 't open %s !", DVD);
+ Interface->Error(s);
+ FREE(s);
+ return false;
+}
+
+#endif //VDRRIP_DVD
+
+// --- cMenuVdrripEncode ----------------------------------------------------
+
+cMenuVdrripEncode::cMenuVdrripEncode():cOsdMenu(tr("encode vdr-recording")) {
+ R = NULL;
+
+ Interface->Status(tr("scanning recordings..."));
+ Interface->Flush();
+
+ R = new cVdrripRecordings;
+ Set();
+}
+
+cMenuVdrripEncode::~cMenuVdrripEncode() {
+ DELETE(R);
+}
+
+void cMenuVdrripEncode::Set() {
+ char *s = NULL;
+ int i;
+
+ for (i = 0; i < R->getNumRec(); i++) {
+ asprintf(&s, "%s %s", R->getDate(i), R->getName(i));
+ Add(new cOsdItem(s));
+ FREE(s);
+ }
+}
+
+eOSState cMenuVdrripEncode::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (HasSubMenu()) return osContinue;
+
+ if (Key == kOk) AddSubMenu(new cMenuVdrripMovie(R->getPath(Current()), R->getName(Current())));
+
+ return state;
+}
+
+
+// --- cMenuVdrripQueue ----------------------------------------------------
+
+cMenuVdrripQueue::cMenuVdrripQueue():cOsdMenu(tr("edit encoding queue")) {
+ Q = NULL;
+ Q = new cQueue;
+ NumMovie = 0;
+ Set();
+}
+
+cMenuVdrripQueue::~cMenuVdrripQueue() {
+ DELETE(Q);
+}
+
+void cMenuVdrripQueue::Set() {
+ char *s = NULL, *s1 = NULL;
+ int c;
+ struct QueueData *q;
+
+ for (c = 0; c < Q->getNumMovies(); c++) {
+ q = Q->getData(c);
+
+ asprintf(&s, "%s%s - %s:", (strstr(q->Dir, "dvd://")) ? "DVD": "VDR", (q->Preview == 1) ? " (preview)": "", q->Name);
+ asprintf(&s1, "- %s, %ix%i MB, %s:%i kbit/s, %s:%i kbit/s", q->Container, q->FileNumbers, q->FileSize, q->VCodec, q->BitrateVideo, q->ACodec, q->BitrateAudio);
+ if (c == 0 && Q->IsEncoding()) {
+ AddColItem(new cOsdItem(s));
+ AddColItem(new cOsdItem(s1));
+ AddColItem(new cOsdItem(Q->getQueueStat()));
+ } else {
+ Add(new cOsdItem(s));
+ Add(new cOsdItem(s1));
+ }
+ FREE(s);
+ FREE(s1);
+ }
+
+ if (Q->getLockStat()) {Interface->Error(tr("the queuefile is locked by the queuehandler !"));}
+
+ SetHelpKeys();
+}
+
+eOSState cMenuVdrripQueue::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (HasSubMenu()) return osContinue;
+
+ if (Q->IsEncoding()) {
+ NumMovie = (Current() - 1) / 2;
+ if (NumMovie < 0) NumMovie = 0;
+ } else NumMovie = Current() / 2;
+
+ SetHelpKeys();
+
+ switch (Key) {
+
+ case kRed: {
+ if (Delete) {
+ char *buf = NULL;
+ asprintf(&buf, tr("delete movie %s from queue ?"), Q->getShortname(NumMovie));
+ if (Interface->Confirm(buf)) {
+ Q->Del(NumMovie);
+ RefreshOSD();
+ }
+ FREE(buf);
+ }
+ break;
+ }
+
+ case kGreen: {
+ if (Up) {
+ Q->Up(NumMovie);
+ RefreshOSD();
+ }
+ break;
+ }
+
+ case kYellow: {
+ if (Down) {
+ Q->Down(NumMovie);
+ RefreshOSD();
+ }
+ break;
+ }
+
+ case kBlue: {
+ if (Switch) {
+ Q->Switch(NumMovie);
+ RefreshOSD();
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return state;
+}
+
+void cMenuVdrripQueue::RefreshOSD() {
+ int i = Current();
+ Clear();
+ Set();
+ SetCurrent(Get(i));
+ SetHelpKeys();
+ Display();
+}
+
+void cMenuVdrripQueue::SetHelpKeys() {
+ if (Q->getLockStat() || Q->getNumMovies() == 0 || (NumMovie == 0 && Q->IsEncoding())) {
+ Delete = Up = Down = Switch = false;
+ } else {
+ Delete = true;
+ Switch = true;
+
+ // up-Key:
+ if (NumMovie >= 1 && NumMovie < Q->getNumMovies()) {
+ (NumMovie == 1 && Q->IsEncoding()) ? Up = false : Up = true;
+ } else {Up = false;}
+
+ // down-key
+ if (NumMovie >= 0 && NumMovie < Q->getNumMovies() - 1) {
+ (NumMovie == 0 && Q->IsEncoding()) ? Down = false : Down = true;
+ } else {Down = false;}
+ }
+
+ SetHelp(Delete ? tr("delete") : NULL, Up ? tr("up") : NULL, Down ? tr("down") : NULL, Switch ? tr("switch mode") : NULL);
+}
+
+void cMenuVdrripQueue::AddColItem(cOsdItem *i) {
+#ifdef clrScrolLine
+ i->SetColor(clrScrolLine, clrBackground);
+#else
+ i->SetColor(clrCyan, clrBackground);
+#endif
+
+ Add(i);
+}
+
+// --- cMenuVdrripTemplates -------------------------------------------------
+
+cMenuVdrripTemplates::cMenuVdrripTemplates():cOsdMenu(tr("edit templates")) {
+
+ T = new cTemplate();
+
+ Set();
+ SetHelp(tr("edit"), tr("new"), tr("delete"), NULL);
+}
+
+cMenuVdrripTemplates::~cMenuVdrripTemplates() {
+ DELETE(T);
+}
+
+void cMenuVdrripTemplates::Set() {
+ for (int i = 0; i < T->getNumTemplates(); i++) {
+ Add(new cOsdItem(T->getName(i)));
+ }
+
+ hadsubmenu = false;
+}
+
+eOSState cMenuVdrripTemplates::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (HasSubMenu()) {
+ hadsubmenu = true;
+ return osContinue;
+ }
+
+ if (hadsubmenu) {RefreshOSD();}
+
+ switch (Key) {
+ case kOk: {
+ AddSubMenu(new cMenuVdrripEditTemplate(T, Current()));
+ break;
+ }
+
+ case kRed: {
+ AddSubMenu(new cMenuVdrripEditTemplate(T, Current()));
+ break;
+ }
+
+ case kGreen: {
+ AddSubMenu(new cMenuVdrripEditTemplate(T, T->New("new")));
+ break;
+ }
+
+ case kYellow: {
+ char *buf;
+ asprintf(&buf, tr("delete template %s ?"), T->getShortname(Current()));
+ if (Interface->Confirm(buf)) {T->Del(Current());}
+ FREE(buf);
+ RefreshOSD();
+ break;
+ }
+
+ default: break;
+ }
+
+ return state;
+}
+
+void cMenuVdrripTemplates::RefreshOSD() {
+ int i = Current();
+ Clear();
+ Set();
+ SetCurrent(Get(i));
+ Display();
+}
+
+
+
+// --- cMenuVdrripEditTemplate -----------------------------------------------
+
+cMenuVdrripEditTemplate::cMenuVdrripEditTemplate(cTemplate *t, int i):cOsdMenu(tr("edit template"), 15) {
+ T = t;
+ NumTemplate = i;
+ TempOSDsaveName = NULL;
+ OSDupdate = true;
+
+ SetHelp(tr("ABC/abc"), tr("Overwrite"), tr("Delete"), NULL);
+ Set();
+}
+
+cMenuVdrripEditTemplate::~cMenuVdrripEditTemplate() {
+ FREE(TempOSDsaveName);
+}
+
+void cMenuVdrripEditTemplate::Set() {
+
+ // get data
+ TempOSD.Name = T->getName(NumTemplate);
+ TempOSD.FileSize = T->getFileSize(NumTemplate);
+ TempOSD.FileNumbers = T->getFileNumbers(NumTemplate);
+ TempOSD.BitrateAudio = T->getBitrateAudio(NumTemplate);
+ TempOSD.BitrateVideo = T->getBitrateVideo(NumTemplate);
+ TempOSD.Container = T->getContainer(NumTemplate);
+ TempOSD.VCodec = T->getVCodec(NumTemplate);
+ TempOSD.ACodec = T->getACodec(NumTemplate);
+ TempOSD.ScaleType = T->getScaleType(NumTemplate);
+ TempOSD.Bpp = T->getBpp(NumTemplate);
+
+ // save data
+ FREE(TempOSDsaveName);
+ TempOSDsaveName = strdup(TempOSD.Name);
+ TempOSDsave = TempOSD;
+
+ // rebuild osd
+ int i = Current();
+ Clear();
+ OSDCreate();
+ SetCurrent(Get(i));
+ Display();
+}
+
+void cMenuVdrripEditTemplate::OSDCreate() {
+
+ Add(new cMenuEditStrItem(tr("Name"), TempOSD.Name, 32, FileNameChars));
+ Add(new cMenuEditIntItem(tr("FileSize"), &TempOSD.FileSize, -1, 9999));
+ Add(new cMenuEditIntItem(tr("FileNumbers"), &TempOSD.FileNumbers, 1, 99));
+ Add(new cMenuEditIntItem(tr("BitrateVideo"), &TempOSD.BitrateVideo, -1, 99999));
+ if (strcmp(T->C->getACodec(TempOSD.ACodec), "copy") == 0 ) {
+ AddColItem(new cMenuEditIntItem(tr("BitrateAudio"), &TempOSD.BitrateAudio, TempOSD.BitrateAudio, TempOSD.BitrateAudio));
+ } else {
+ Add(new cMenuEditIntItem(tr("BitrateAudio"), &TempOSD.BitrateAudio, 1, 9999));
+ }
+ Add(new cMenuEditStraItem(tr("Container"), &TempOSD.Container,
+ T->C->getNumContainers(), T->C->getContainers()));
+ Add(new cMenuEditStraItem(tr("Video-Codec"), &TempOSD.VCodec,
+ T->C->getNumVCodecs(), T->C->getVCodecs()));
+ Add(new cMenuEditStraItem(tr("Audio-Codec"), &TempOSD.ACodec,
+ T->C->getNumACodecs(), T->C->getACodecs()));
+ Add(new cMenuEditIntItem(tr("Bpp-Value (*100)"), &TempOSD.Bpp, 1, 99));
+ Add(new cMenuEditStraItem(tr("ScaleType"), &TempOSD.ScaleType,
+ NUMSCALETYPES, ScaleTypes));
+}
+
+void cMenuVdrripEditTemplate::OSDChange() {
+
+ if (TempOSD.FileSize != TempOSDsave.FileSize || TempOSD.FileNumbers != TempOSDsave.FileNumbers) {
+ T->setFileSize(NumTemplate, TempOSD.FileSize, TempOSD.FileNumbers);
+ T->Save();
+ Set();
+
+ } else if (TempOSD.BitrateVideo != TempOSDsave.BitrateVideo || TempOSD.BitrateAudio != TempOSDsave.BitrateAudio) {
+ T->setBitrate(NumTemplate, TempOSD.BitrateVideo, TempOSD.BitrateAudio);
+ T->Save();
+ Set();
+
+ } else if (TempOSD.VCodec != TempOSDsave.VCodec) {
+ T->setCodecs(NumTemplate, TempOSD.VCodec, TempOSD.ACodec);
+ T->Save();
+ Set();
+
+ } else if (TempOSD.ACodec != TempOSDsave.ACodec) {
+ if (strcmp(T->C->getContainer(TempOSD.Container), "avi") == 0 &&
+ strcmp(T->C->getACodec(TempOSD.ACodec), "ogg-vorbis") == 0) {
+ // avi couldn't contain ogg-vorbis audio
+ T->setCodecs(NumTemplate, TempOSD.VCodec, TempOSDsave.ACodec);
+ } else {
+ T->setCodecs(NumTemplate, TempOSD.VCodec, TempOSD.ACodec);
+ }
+ T->Save();
+ Set();
+
+ } else if (TempOSD.Container != TempOSDsave.Container) {
+ if (strcmp(T->C->getContainer(TempOSD.Container), "avi") == 0 &&
+ strcmp(T->C->getACodec(TempOSD.ACodec), "ogg-vorbis") == 0) {
+ // avi couldn't contain ogg-vorbis audio
+ T->setContainer(NumTemplate, TempOSDsave.Container);
+ } else {
+ T->setContainer(NumTemplate, TempOSD.Container);
+ }
+ T->Save();
+ Set();
+
+ } else if (TempOSD.ScaleType != TempOSDsave.ScaleType) {
+ T->setScaleType(NumTemplate, TempOSD.ScaleType);
+ T->Save();
+ Set();
+
+ } else if (TempOSD.Bpp != TempOSDsave.Bpp) {
+ T->setBpp(NumTemplate, TempOSD.Bpp);
+ T->Save();
+ Set();
+
+ } else if (strcmp(TempOSD.Name, TempOSDsaveName) != 0) {
+ T->setName(NumTemplate, TempOSD.Name);
+ T->Save();
+ }
+}
+
+eOSState cMenuVdrripEditTemplate::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (Current() == 0) {
+ SetHelp(tr("ABC/abc"), tr("Overwrite"), tr("Delete"), NULL);
+ } else {
+ SetHelp(NULL, NULL, NULL, NULL);
+
+ switch (Key) {
+ case k0 ... k9: {
+ OSDupdate = false;
+ break;
+ }
+
+ default: {
+ OSDupdate = true;
+ break;
+ }
+ }
+ }
+
+ if (OSDupdate) {OSDChange();}
+
+ return state;
+}
+
+void cMenuVdrripEditTemplate::AddColItem(cOsdItem *i) {
+#ifdef clrScrolLine
+ i->SetColor(clrScrolLine, clrBackground);
+#else
+ i->SetColor(clrCyan, clrBackground);
+#endif
+
+ Add(i);
+}
+
+// --- cMenuVdrripMovie ------------------------------------------------------
+
+cMenuVdrripMovie::cMenuVdrripMovie(char *p, char *n):cOsdMenu(tr("encode movie"), 15) {
+ M = NULL;
+ MovOSDsaveName = NULL;
+ FileSize[0] = MovieData[0] = CropData[0] = ScaleData[0] = NULL;
+
+ Interface->Status(tr("reading movie-data..."));
+ Interface->Flush();
+
+ M = new cMovie(p, n);
+ Init();
+ Set();
+}
+
+cMenuVdrripMovie::~cMenuVdrripMovie() {
+ DELETE(M);
+
+ FREE(MovOSDsaveName);
+ FREE(FileSize[0]);
+ FREE(MovieData[0]);
+ FREE(CropData[0]);
+ FREE(ScaleData[0]);
+}
+
+void cMenuVdrripMovie::Init() {
+
+ OSDupdate = true;
+ Expert = false;
+ Crop = false;
+ CropReset = false;
+
+
+ // set DVBScaleWidth & DVBScaleHeight
+ MovOSD.DVBScaleWidth = 0;
+ MovOSD.DVBScaleHeight = 0;
+
+ if (M->getScaleType() == 2) {
+ for (int i = 0; i < 6; i++) {
+ if (atoi(DVBScaleWidths[i]) == M->getScaleWidth()) {
+ MovOSD.DVBScaleWidth = i;
+ }
+ }
+
+ for (int i = 0; i < 2; i++) {
+ if (atoi(DVBScaleHeights[i]) == M->getScaleHeight()) {
+ MovOSD.DVBScaleHeight = i;
+ }
+ }
+ }
+
+ CropWidthsave = -1;
+ CropHeightsave = -1;
+
+ MovOSD.PPDeinterlace = 0;
+ MovOSD.PPDeblock = 0;
+
+ NumStatic = 0;
+}
+
+void cMenuVdrripMovie::Set() {
+
+ //get movie data
+ MovOSD.Name = M->getName();
+ MovOSD.Template = M->getNumTemplate();
+#ifdef VDRRIP_DVD
+ if (M->isDVD()) MovOSD.Title = M->getDVDTitle();
+#endif //VDRRIP_DVD
+ MovOSD.FileSize = M->getFileSize();
+ MovOSD.FileNumbers = M->getFileNumbers();
+ MovOSD.BitrateAudio = M->getBitrateAudio();
+ MovOSD.BitrateVideo = M->getBitrateVideo();
+ MovOSD.Container = M->getContainer();
+ MovOSD.VCodec = M->getVCodec();
+ MovOSD.ACodec = M->getACodec();
+ MovOSD.AudioID = M->getAudioID();
+ MovOSD.ScaleType = M->getScaleType();
+ MovOSD.ScaleWidth = M->getScaleWidth();
+ MovOSD.ScaleHeight = M->getScaleHeight();
+
+ MovOSD.CropWidth = M->getCropWidth();
+ MovOSD.CropHeight = M->getCropHeight();
+ if (M->getPPValues()) {
+ if (strstr(M->getPPValues(), "fd")) MovOSD.PPDeinterlace = 1;
+ else if (strstr(M->getPPValues(), "lb")) MovOSD.PPDeinterlace = 2;
+ else if (strstr(M->getPPValues(), "li")) MovOSD.PPDeinterlace = 3;
+ else if (strstr(M->getPPValues(), "ci")) MovOSD.PPDeinterlace = 4;
+ else if (strstr(M->getPPValues(), "md")) MovOSD.PPDeinterlace = 5;
+ else MovOSD.PPDeinterlace = 0;
+
+ if (strstr(M->getPPValues(), "hb/vb/dr/al")) MovOSD.PPDeblock = 1;
+ else MovOSD.PPDeblock = 0;
+ } else {
+ MovOSD.PPDeinterlace = 0;
+ MovOSD.PPDeblock = 0;
+ }
+ MovOSD.Bpp = (int)M->getBpp();
+
+ // save data
+ FREE(MovOSDsaveName);
+ MovOSDsaveName = strdup(MovOSD.Name);
+ MovOSDsave = MovOSD;
+
+ // rebuild osd
+ int current = Current();
+ Clear();
+ OSDCreate();
+ SetCurrent(Get(current));
+ Display();
+
+ SetHelpKeys();
+}
+
+
+void cMenuVdrripMovie::SetHelpKeys() {
+ if (Current() == 0) {
+ SetHelp(tr("ABC/abc"), tr("Overwrite"), tr("Delete"), NULL);
+ } else {
+ MovOSD.ScaleType == 1 | MovOSD.ScaleType == 3 ? Crop = true : Crop = false;
+ MovOSD.CropWidth == -1 && MovOSD.CropHeight == -1 ? CropReset = false :
+ CropReset = true;
+
+ SetHelp(tr("add to queue"),
+ Crop ? tr(CropReset ? "reset boarders" : "crop boarders" ) : NULL,
+ tr(Expert ? "expert modus(off)" : "expert modus(on)"),
+ NULL);
+ }
+}
+
+
+
+
+void cMenuVdrripMovie::OSDCreate() {
+ char *s = NULL, *l = NULL;
+ cOsdItem *i;
+
+ Add(new cMenuEditStrItem(tr("Name"), MovOSD.Name, 32, FileNameChars));
+
+ // Templates:
+ i = new cMenuEditStraItem(tr("Template"), &MovOSD.Template, M->T->getNumTemplates(), M->T->getTNames());
+ (M->T->getNumTemplates() > 1) ? Add(i) : AddColItem(i);
+ FREE(s);
+
+#ifdef VDRRIP_DVD
+ if (M->isDVD()) {
+ i = new cMenuEditIntItem(tr("Title*") , &MovOSD.Title, 1, M->getNumDVDTitles());
+ (M->getNumDVDTitles() > 1) ? Add(i) : AddColItem(i);
+ FREE(s);
+ }
+#endif //VDRRIP_DVD
+
+ // FileSize+Numbers
+ if (M->getLength() == -1) {
+ FREE(FileSize[0]);
+ asprintf(&FileSize[0], "%s", tr("unknown"));
+ asprintf(&s, "%s", tr("FileSize"));
+ AddColItem(new cMenuEditStraItem(s, &NumStatic, 1, FileSize));
+ asprintf(&s, "%s", tr("FileNumbers"));
+ AddColItem(new cMenuEditIntItem(s, &MovOSD.FileNumbers, 1, 1));
+ FREE(s);
+ l = strdup("Len: ?");
+ } else {
+ Add(new cMenuEditIntItem(tr("FileSize"), &MovOSD.FileSize, 1, 9999));
+ asprintf(&l, "Len: %i", M->getLength());
+ Add(new cMenuEditIntItem(tr("FileNumbers"), &MovOSD.FileNumbers, 1, 99));
+ }
+
+ // MovieData:
+ asprintf(&MovieData[0], "%i:%i(Asp: %1.2f %s Fps: %1.2f)", M->getWidth(),
+ M->getHeight(), M->getAspect(), l, M->getFps() / 100);
+ AddColItem(new cMenuEditStraItem(tr("MovieData"), &NumStatic, 1,
+ MovieData));
+ FREE(l);
+
+ // CropData:
+ if (M->getCropWidth() == -1 && M->getCropHeight() == -1) {
+ if (M->getScaleType() == 0 || M->getScaleType() == 2) {
+ asprintf(&CropData[0], "%s", tr("not used"));
+ } else {
+ asprintf(&CropData[0], "%s", tr("unknown"));
+ }
+ } else {
+ asprintf(&CropData[0], "%i:%i(Asp: %1.2f)", M->getCropWidth(),
+ M->getCropHeight(), M->getCalcAspect());
+ }
+ AddColItem(new cMenuEditStraItem(tr("CropData"), &NumStatic, 1, CropData));
+
+
+ // Bitrate Video
+ Add(new cMenuEditIntItem(tr("BitrateVideo"), &MovOSD.BitrateVideo,
+ 150, 99999));
+
+ // check, if there is a audio-codec available
+ if (MovOSD.ACodec != -1) {
+ if (strcmp(M->C->getACodec(MovOSD.ACodec), "copy") == 0 ) {
+ AddColItem(new cMenuEditIntItem(tr("BitrateAudio"),
+ &MovOSD.BitrateAudio, MovOSD.BitrateAudio, MovOSD.BitrateAudio));
+ FREE(s);
+ } else {
+ Add(new cMenuEditIntItem(tr("BitrateAudio"), &MovOSD.BitrateAudio,
+ 32, 999));
+ }
+ }
+
+ // Container Format
+ i = new cMenuEditStraItem(tr("Container"), &MovOSD.Container,
+ M->C->getNumContainers(), M->C->getContainers());
+ (M->C->getNumContainers() > 1) ? Add(i) : AddColItem(i);
+ FREE(s);
+
+ // check, if there is a video-codec available
+ if (MovOSD.VCodec != -1) {
+ Add(new cMenuEditStraItem(tr("Video-Codec"), &MovOSD.VCodec,
+ M->C->getNumVCodecs(), M->C->getVCodecs()));
+ Add(new cMenuEditStraItem(tr("Audio-Codec"), &MovOSD.ACodec,
+ M->C->getNumACodecs(), M->C->getACodecs()));
+ }
+
+ // Audio-Stream
+ asprintf(&s, "%s %i*", tr("Audio-Str."), M->getAudioID(MovOSD.AudioID));
+ i = new cMenuEditStraItem(s, &MovOSD.AudioID, M->getNumAudioID(),
+ M->getAudioData());
+ FREE(s);
+ (M->getNumAudioID() > 1) ? Add(i) : AddColItem(i);
+
+ // ScaleType
+ Add(new cMenuEditStraItem(tr("ScaleType"), &MovOSD.ScaleType,
+ NUMSCALETYPES, ScaleTypes));
+
+ switch (MovOSD.ScaleType) {
+ case 0: { //ScaleType off
+ break;
+ }
+
+ case 1: { //ScaleType auto
+ asprintf(&ScaleData[0], "%i:%i(Asp: %1.2f Bpp: %1.3f)", M->getScaleWidth(), M->getScaleHeight(), (double)M->getScaleWidth() / (double)M->getScaleHeight(), M->getResBpp());
+ AddColItem(new cMenuEditStraItem(tr("ScaleData"), &NumStatic, 1,
+ ScaleData));
+ Add(new cMenuEditIntItem(tr("Bpp-Value (*100)"), &MovOSD.Bpp, 1, 99));
+ break;
+ }
+
+ case 2: { //ScaleType dvb
+ Add(new cMenuEditStraItem(tr("ScaleWidth"), &MovOSD.DVBScaleWidth, 6, DVBScaleWidths));
+ Add(new cMenuEditStraItem(tr("ScaleHeight"), &MovOSD.DVBScaleHeight, 2, DVBScaleHeights));
+ break;
+ }
+
+ case 3: { //ScaleType manual
+ Add(new cMenuEditIntItem(tr("ScaleWidth"), &MovOSD.ScaleWidth, 1, 9999));
+ Add(new cMenuEditIntItem(tr("ScaleHeight"), &MovOSD.ScaleHeight, 1, 9999));
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ //expert menu:
+ if (Expert) {
+ AddColItem(new cOsdItem(tr("------ expert settings: ------")));
+ if (MovOSD.CropWidth != -1 && MovOSD.CropHeight != -1) {
+ AddColItem(new cOsdItem(tr("- adjust crop values:")));
+ Add(new cMenuEditIntItem(tr("CropWidth"), &MovOSD.CropWidth, 0, M->getWidth()));
+ Add(new cMenuEditIntItem(tr("CropHeight"), &MovOSD.CropHeight, 0, M->getHeight()));
+ }
+ asprintf(&s, tr("- postprocessing Filters(%s):"), M->getPPValues() ? M->getPPValues() : "off");
+ AddColItem(new cOsdItem(s));
+ FREE(s);
+ Add(new cMenuEditStraItem("deinterlacing", &MovOSD.PPDeinterlace, NUMPPDEINT, PPDeint));
+ Add(new cMenuEditBoolItem("deblocking", &MovOSD.PPDeblock, "off", "on"));
+ }
+
+ hadsubmenu = false;
+}
+
+
+void cMenuVdrripMovie::OSDChange() {
+
+ if (MovOSD.Template != MovOSDsave.Template) {
+ // save old crop values
+ if (M->getScaleType() == 1 || M->getScaleType() == 3) {
+ CropWidthsave = M->getCropWidth();
+ CropHeightsave = M->getCropHeight();
+ }
+ M->setNumTemplate(MovOSD.Template);
+ // restore old crop values
+ if (M->getScaleType() == 1 || M->getScaleType() == 3) {
+ M->setCropValues(CropWidthsave, CropHeightsave);
+ }
+ M->saveMovieData();
+ Set();
+
+#ifdef VDRRIP_DVD
+ } else if (M->isDVD() && MovOSD.Title != MovOSDsave.Title && MovOSD.Title > 0) {
+ Interface->Status(tr("reading audio-data from dvd..."));
+ Interface->Flush();
+ M->setDVDTitle(MovOSD.Title, true);
+ M->saveMovieData();
+ Set();
+#endif //VDRRIP_DVD
+
+ } else if ((MovOSD.FileSize != MovOSDsave.FileSize ||
+ MovOSD.FileNumbers != MovOSDsave.FileNumbers) &&
+ MovOSD.FileNumbers > 0) {
+ M->setFileSize(MovOSD.FileSize, MovOSD.FileNumbers);
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.BitrateVideo != MovOSDsave.BitrateVideo) {
+ M->setBitrate(MovOSD.BitrateVideo, MovOSD.BitrateAudio);
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.BitrateAudio != MovOSDsave.BitrateAudio) {
+ M->setBitrate(-1 , MovOSD.BitrateAudio);
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.Container != MovOSDsave.Container) {
+ if (strcmp(M->C->getContainer(MovOSD.Container), "avi") == 0 &&
+ strcmp(M->C->getACodec(MovOSD.ACodec), "ogg-vorbis") == 0) {
+ // avi couldn't contain ogg-vorbis audio
+ M->setContainer(MovOSDsave.Container);
+ } else {
+ M->setContainer(MovOSD.Container);
+ }
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.VCodec != MovOSDsave.VCodec) {
+ M->setCodecs(MovOSD.VCodec, MovOSD.ACodec);
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.ACodec != MovOSDsave.ACodec) {
+ if (strcmp(M->C->getContainer(MovOSD.Container), "avi") == 0 &&
+ strcmp(M->C->getACodec(MovOSD.ACodec), "ogg-vorbis") == 0) {
+ // avi couldn't contain ogg-vorbis audio
+ M->setCodecs(MovOSD.VCodec, MovOSDsave.ACodec);
+ } else {
+ M->setCodecs(MovOSD.VCodec, MovOSD.ACodec);
+ }
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.AudioID != MovOSDsave.AudioID) {
+ M->setAudioID(MovOSD.AudioID);
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.ScaleType != MovOSDsave.ScaleType) {
+ // restore - save old crop values
+ if (MovOSDsave.ScaleType == 1 || MovOSDsave.ScaleType == 3) {
+ CropWidthsave = M->getCropWidth();
+ CropHeightsave = M->getCropHeight();
+ M->setScaleType(MovOSD.ScaleType);
+ } else {
+ M->setScaleType(MovOSD.ScaleType);
+ M->setCropValues(CropWidthsave, CropHeightsave);
+ }
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.ScaleWidth != MovOSDsave.ScaleWidth ||
+ MovOSD.ScaleHeight != MovOSDsave.ScaleHeight) {
+ M->setScale(MovOSD.ScaleWidth, MovOSD.ScaleHeight);
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.DVBScaleWidth != MovOSDsave.DVBScaleWidth ||
+ MovOSD.DVBScaleHeight != MovOSDsave.DVBScaleHeight) {
+ M->setScale(atoi(DVBScaleWidths[MovOSD.DVBScaleWidth]),
+ atoi(DVBScaleHeights[MovOSD.DVBScaleHeight]));
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.CropWidth != MovOSDsave.CropWidth || MovOSD.CropHeight != MovOSDsave.CropHeight) {
+ if (MovOSD.CropWidth <= MovOSDsave.CropWidth) {
+ MovOSD.CropWidth = roundValue(MovOSD.CropWidth, 16);
+ } else {MovOSD.CropWidth = roundValue(MovOSD.CropWidth, 16) + 16;}
+
+ if (MovOSD.CropHeight <= MovOSDsave.CropHeight) {
+ MovOSD.CropHeight = roundValue(MovOSD.CropHeight, 16);
+ } else {MovOSD.CropHeight = roundValue(MovOSD.CropHeight, 16) + 16;}
+
+ M->setCropValues(MovOSD.CropWidth, MovOSD.CropHeight);
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.PPDeinterlace != MovOSDsave.PPDeinterlace || MovOSD.PPDeblock != MovOSDsave.PPDeblock) {
+ if (MovOSD.PPDeinterlace == 0 && MovOSD.PPDeblock == 0) M->setPPValues(NULL);
+ else if (MovOSD.PPDeinterlace == 0 && MovOSD.PPDeblock == 1) M->setPPValues("hb/vb/dr/al");
+ else if (MovOSD.PPDeinterlace >= 1 && MovOSD.PPDeblock == 0) M->setPPValues(PPDeint[MovOSD.PPDeinterlace]);
+ else {
+ char *pp = NULL;
+ asprintf(&pp, "%s/hb/vb/dr/al", PPDeint[MovOSD.PPDeinterlace]);
+ dsyslog(pp);
+ M->setPPValues(pp);
+ FREE(pp);
+ }
+ M->saveMovieData();
+ Set();
+
+ } else if (MovOSD.Bpp != MovOSDsave.Bpp) {
+ M->setBpp(MovOSD.Bpp);
+ M->saveMovieData();
+ Set();
+
+ } else if (strcmp(MovOSD.Name, MovOSDsaveName) != 0) {
+ M->setName(MovOSD.Name);
+ M->saveMovieData();
+ }
+}
+
+eOSState cMenuVdrripMovie::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (HasSubMenu()) {
+ hadsubmenu = true;
+ return osContinue;
+ }
+
+ if (hadsubmenu) {
+ Set();
+ return osContinue;
+ }
+
+ SetHelpKeys();
+
+ if (Current() != 0) {
+
+ switch (Key) {
+ case k0 ... k9: {
+ OSDupdate = false;
+ break;
+ }
+
+ case kRed: {
+ int p;
+ Interface->Confirm(tr("<ok> for preview-mode")) ? p = 1 : p = 0;
+ if (Interface->Confirm(tr("add movie to encoding queue ?"))) {
+ cQueue *Q;
+ struct QueueData *q;
+ Q = new cQueue;
+ q = (struct QueueData*)malloc(sizeof(struct QueueData));
+
+ q->Dir = M->getDir();
+ q->Name = M->getName();
+ q->FileSize = M->getFileSize();
+ q->FileNumbers = M->getFileNumbers();
+ q->VCodec = M->C->getVCodec(M->getVCodec());
+ q->BitrateVideo = M->getBitrateVideo();
+ q->MinQuant = MINQUANT;
+ q->MaxQuant = MAXQUANT;
+ q->CropWidth = M->getCropWidth();
+ q->CropHeight = M->getCropHeight();
+ q->CropPosX = M->getCropPosX();
+ q->CropPosY = M->getCropPosY();
+ q->ScaleWidth = M->getScaleWidth();
+ q->ScaleHeight = M->getScaleHeight();
+ q->ACodec = M->C->getACodec(M->getACodec());
+ q->BitrateAudio = M->getBitrateAudio();
+ q->AudioID = M->getAudioID(M->getAudioID());
+ q->PPValues = M->getPPValues();
+ q->Rename = VdrripSetup.Rename;
+ q->Container = M->C->getContainer(M->getContainer());
+ q->Preview = p;
+
+ if(Q->New(q)) {
+ FREE(q);
+ DELETE(Q);
+ return osBack;
+ } else {Interface->Error(tr("the queuefile is locked by the queuehandler !"));}
+
+ FREE(q);
+ DELETE(Q);
+
+ Set();
+ }
+ break;
+ }
+
+ case kGreen: {
+ if (MovOSD.ScaleType == 1 | MovOSD.ScaleType == 3) {
+ if (CropReset) {
+ if (Interface->Confirm(tr("reset black movie boarders ?"))) {
+ CropReset = false;
+ M->initCropValues();
+ M->setScale();
+ M->saveMovieData();
+ }
+ } else {
+ if (Interface->Confirm(tr("crop black movie boarders ?"))) {
+ CropReset = true;
+ Interface->Status(tr("search for black movie boarders"));
+ Interface->Flush();
+ if (! M->setCropValues()) {
+ CropReset = false;
+ Interface->Error(tr("couldn't detect black movie boarders !"));
+ }
+ M->saveMovieData();
+ }
+ }
+ Set();
+ }
+ break;
+ }
+
+ case kYellow: {
+ Expert ? Expert = false : Expert = true;
+ Set();
+ break;
+ }
+
+ case kOk: {
+ const char *l = Get(Current())->Text();
+ if (strstr(l, tr("Audio-Str."))) {
+ AddSubMenu(new cMenuVdrripMovieAudio(M));
+#ifdef VDRRIP_DVD
+ } else if (strstr(l, tr("Title*"))) {
+ AddSubMenu(new cMenuVdrripMovieTitles(M));
+#endif //VDRRIP_DVD
+ }
+ break;
+ }
+
+ default:
+ OSDupdate = true;
+ break;
+ }
+ }
+
+ if (OSDupdate) {OSDChange();}
+
+ return state;
+}
+
+void cMenuVdrripMovie::AddColItem(cOsdItem *i) {
+#ifdef clrScrolLine
+ i->SetColor(clrScrolLine, clrBackground);
+#else
+ i->SetColor(clrCyan, clrBackground);
+#endif
+
+ Add(i);
+}
+
+
+// --- cMenuVdrripMovieTitles --------------------------------------------
+
+#ifdef VDRRIP_DVD
+cMenuVdrripMovieTitles::cMenuVdrripMovieTitles(cMovie *m):cOsdMenu(tr("select dvd title")) {
+ M = m;
+ char **s = M->getTitleData();
+ for (int i = 0; i < M->getNumDVDTitles(); i++) {
+ Add(new cOsdItem(s[i]));
+ }
+ SetCurrent(Get(M->getDVDTitle() - 1));
+ SetHelp(NULL, NULL, NULL, NULL);
+}
+
+cMenuVdrripMovieTitles::~cMenuVdrripMovieTitles() {}
+
+eOSState cMenuVdrripMovieTitles::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (Key == kOk) {
+ Interface->Status(tr("reading audio-data from dvd..."));
+ Interface->Flush();
+ M->setDVDTitle(Current() + 1, true);
+ M->saveMovieData();
+ return osBack;
+ }
+
+ return state;
+}
+#endif //VDRRIP_DVD
+
+// --- cMenuVdrripMovieAudio --------------------------------------------
+
+cMenuVdrripMovieAudio::cMenuVdrripMovieAudio(cMovie *m):cOsdMenu(tr("select audio stream(s)")) {
+ M = m;
+ char **s = M->getAudioData2();
+ for (int i = 0; i < M->getNumAudioID(); i++) {
+ Add(new cOsdItem(s[i]));
+ }
+ SetCurrent(Get(M->getAudioID()));
+ SetHelp(NULL, NULL, NULL, NULL);
+}
+
+cMenuVdrripMovieAudio::~cMenuVdrripMovieAudio() {}
+
+eOSState cMenuVdrripMovieAudio::ProcessKey(eKeys Key) {
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (Key == kOk) {
+ M->setAudioID(Current());
+ M->saveMovieData();
+ return osBack;
+ }
+
+ return state;
+}
+
+
+// --- cVdrripSetup -----------------------------------------------------------
+
+cVdrripSetup VdrripSetup;
+
+cVdrripSetup::cVdrripSetup(void)
+{
+ MaxScaleWidth = 704;
+ MinScaleWidth = 480;
+ CropMode = 0;
+ CropLength = 5;
+ Rename = 0;
+ OggVorbis = 0;
+ AC3 = 0;
+ Ogm = 0;
+ Matroska = 0;
+}
+
+bool cVdrripSetup::SetupParse(const char *Name, const char *Value)
+{
+ if (!strcasecmp(Name, "MaxScaleWidth")) MaxScaleWidth = atoi(Value);
+ else if (!strcasecmp(Name, "MinScaleWidth")) MinScaleWidth = atoi(Value);
+ else if (!strcasecmp(Name, "CropMode")) CropMode = atoi(Value);
+ else if (!strcasecmp(Name, "CropLength")) CropLength = atoi(Value);
+ else if (!strcasecmp(Name, "Rename")) Rename = atoi(Value);
+ else if (!strcasecmp(Name, "OggVorbis")) OggVorbis = atoi(Value);
+ else if (!strcasecmp(Name, "AC3")) AC3 = atoi(Value);
+ else if (!strcasecmp(Name, "Ogm")) Ogm = atoi(Value);
+ else if (!strcasecmp(Name, "Matroska")) Matroska = atoi(Value);
+ else
+ return false;
+ return true;
+}
+
+
+// --- cMenuVdrripSetup --------------------------------------------------------
+
+cMenuVdrripSetup::cMenuVdrripSetup()
+{
+ data = VdrripSetup;
+
+ Add(new cMenuEditIntItem(tr("MaxScaleWidth"), &data.MaxScaleWidth, 1, 9999));
+ Add(new cMenuEditIntItem(tr("MinScaleWidth"), &data.MinScaleWidth, 1, 9999));
+ Add(new cMenuEditStraItem(tr("Crop Mode"), &data.CropMode, 2, CropModes));
+ Add(new cMenuEditIntItem(tr("Crop DetectLength (s)"), &data.CropLength, 1, 999));
+ Add(new cMenuEditBoolItem(tr("Rename movie after encoding"), &data.Rename, tr("no"), tr("yes")));
+ Add(new cMenuEditBoolItem(tr("Ogg-Vorbis support"), &data.OggVorbis, tr("no"), tr("yes")));
+ Add(new cMenuEditBoolItem(tr("AC3 support (MPlayer-patch inst.)"), &data.AC3, tr("no"), tr("yes")));
+ Add(new cMenuEditBoolItem(tr("Ogm support"), &data.Ogm, tr("no"), tr("yes")));
+ Add(new cMenuEditBoolItem(tr("Matroska support"), &data.Matroska, tr("no"), tr("yes")));
+}
+
+void cMenuVdrripSetup::Store(void)
+{
+ // delete unused setup data
+ SetupStore("FileSize");
+ SetupStore("FileNumbers");
+ SetupStore("LameAudioBitrate");
+ SetupStore("Bpp");
+
+
+ VdrripSetup = data;
+ SetupStore("MaxScaleWidth", VdrripSetup.MaxScaleWidth);
+ SetupStore("MinScaleWidth", VdrripSetup.MinScaleWidth);
+ SetupStore("CropMode", VdrripSetup.CropMode);
+ SetupStore("CropLength", VdrripSetup.CropLength);
+ SetupStore("Rename", VdrripSetup.Rename);
+ SetupStore("OggVorbis", VdrripSetup.OggVorbis);
+ SetupStore("AC3", VdrripSetup.AC3);
+ SetupStore("Ogm", VdrripSetup.Ogm);
+ SetupStore("Matroska", VdrripSetup.Matroska);
+}
diff --git a/menu-vdrrip.h b/menu-vdrrip.h
new file mode 100755
index 0000000..476e8d3
--- /dev/null
+++ b/menu-vdrrip.h
@@ -0,0 +1,209 @@
+//
+// menu-vdrrip.h
+//
+
+#ifndef __MENU_VDRRIP_H
+#define __MENU_VDRRIP_H
+
+#include <vdr/osd.h>
+#include <vdr/menuitems.h>
+
+#include "movie.h"
+#include "vdrriprecordings.h"
+#include "templates.h"
+#include "queue.h"
+#include "codecs.h"
+
+struct MovieOSDData {
+ char *Name;
+ int Title;
+ int Template;
+ int FileSize;
+ int FileNumbers;
+ int BitrateVideo;
+ int BitrateAudio;
+ int Container;
+ int VCodec;
+ int ACodec;
+ int AudioID;
+ int ScaleWidth;
+ int ScaleHeight;
+ int ScaleType;
+ int DVBScaleWidth;
+ int DVBScaleHeight;
+
+ //expert menu:
+ int CropWidth;
+ int CropHeight;
+ int PPDeinterlace;
+ int PPDeblock;
+ int Bpp;
+};
+
+class cMenuVdrrip : public cOsdMenu {
+private:
+ virtual void Set();
+
+public:
+ cMenuVdrrip();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+#ifdef VDRRIP_DVD
+
+class cMenuVdrripWarning : public cOsdMenu {
+private:
+ bool hadsubmenu;
+
+ bool CheckDVD();
+public:
+ cMenuVdrripWarning(const char *Title, const char *Text);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+#endif //VDRRIP_DVD};
+
+class cMenuVdrripEncode : public cOsdMenu {
+private:
+ virtual void Set();
+
+ cVdrripRecordings *R;
+public:
+ cMenuVdrripEncode();
+ ~cMenuVdrripEncode();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cMenuVdrripQueue : public cOsdMenu {
+private:
+ virtual void Set();
+ void RefreshOSD();
+ void SetHelpKeys();
+ void AddColItem(cOsdItem *i);
+
+ cQueue *Q;
+ int NumMovie;
+ bool Delete, Up, Down, Switch;
+
+public:
+ cMenuVdrripQueue();
+ ~cMenuVdrripQueue();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cMenuVdrripTemplates : public cOsdMenu {
+private:
+ virtual void Set();
+ void RefreshOSD();
+
+ cTemplate *T;
+ bool hadsubmenu;
+public:
+ cMenuVdrripTemplates();
+ ~cMenuVdrripTemplates();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cMenuVdrripEditTemplate : public cOsdMenu {
+private:
+ virtual void Set();
+ void OSDChange();
+ void OSDCreate();
+ void AddColItem(cOsdItem *i);
+
+ cTemplate *T;
+ int NumTemplate;
+ struct TemplateData TempOSD, TempOSDsave;
+ char *TempOSDsaveName;
+
+ bool OSDupdate;
+public:
+ cMenuVdrripEditTemplate(cTemplate *t, int i);
+ ~cMenuVdrripEditTemplate();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+
+class cMenuVdrripMovie : public cOsdMenu {
+private:
+ virtual void Set();
+ void Init();
+ void OSDChange();
+ void OSDCreate();
+ void SetHelpKeys();
+ void AddColItem(cOsdItem *i);
+
+ cMovie *M;
+ struct MovieOSDData MovOSD, MovOSDsave;
+ char *MovOSDsaveName;
+ char *Templates;
+ char *FileSize[1];
+ char *MovieData[1];
+ char *CropData[1];
+ char *ScaleData[1];
+
+ bool OSDupdate, Crop, CropReset, Expert;
+
+ int CropWidthsave;
+ int CropHeightsave;
+
+ int NumStatic;
+
+ bool hadsubmenu;
+
+public:
+ cMenuVdrripMovie(char *p, char *n);
+ ~cMenuVdrripMovie();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cMenuVdrripMovieTitles : public cOsdMenu {
+private:
+ cMovie *M;
+public:
+ cMenuVdrripMovieTitles(cMovie *m);
+ ~cMenuVdrripMovieTitles();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cMenuVdrripMovieAudio : public cOsdMenu {
+private:
+ cMovie *M;
+public:
+ cMenuVdrripMovieAudio(cMovie *m);
+ ~cMenuVdrripMovieAudio();
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+
+class cVdrripSetup {
+public:
+ int MaxScaleWidth;
+ int MinScaleWidth;
+ int CropMode;
+ int CropLength;
+ int Rename;
+ int OggVorbis;
+ int AC3;
+ int Ogm;
+ int Matroska;
+
+public:
+ cVdrripSetup();
+ bool SetupParse(const char *Name, const char *Value);
+};
+
+
+class cMenuVdrripSetup : public cMenuSetupPage {
+private:
+ cVdrripSetup data;
+protected:
+ virtual void Store(void);
+public:
+ cMenuVdrripSetup();
+};
+
+extern cVdrripSetup VdrripSetup;
+
+#endif //__MENU_VDRRIP_H
+
diff --git a/movie.c b/movie.c
new file mode 100755
index 0000000..4664913
--- /dev/null
+++ b/movie.c
@@ -0,0 +1,985 @@
+//
+// movie.c
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef VDRRIP_DVD
+ #include <dvdnav/ifo_read.h>
+#endif //VDRRIP_DVD
+
+#include <vdr/plugin.h>
+
+#include "movie.h"
+#include "menu-vdrrip.h"
+#include "a-tools.h"
+#include "queue.h"
+#include "templates.h"
+
+#define SAVEFILE "save.vdrrip"
+
+#define IDENTCMD "%s \'%s\'%s -identify -frames 0 2>/dev/null | sed -e \'s/[`\\!$\"]/\\&/g\'"
+#define CROPCMD "%s \'%s\'%s -vo null -ao null -really-quiet -ss %i -frames %i -vop cropdetect 2>/dev/null | grep \"crop=\" | sed \"s/.*crop\\(.*\\)).*/\\1/\" | sort | uniq -c | sort -r"
+#define AUDIOCMD "%s \'%s/001.vdr\' -vo null -ao null -frames 0 -aid %i 2>/dev/null | grep AUDIO"
+#define AUDIOCMDDVD "%s %s -vo null -ao null -frames 0 -aid %i 2>/dev/null | grep AUDIO"
+#define MENCCMD "%s %s help 2>/dev/null"
+
+// --- cMovie ------------------------------------------------------------
+
+
+cMovie::cMovie(char *d, char *n) {
+ C = NULL;
+ T = NULL;
+#ifdef VDRRIP_DVD
+ D = NULL;
+ StrTitles = NULL;
+#endif //VDRRIP_DVD
+
+ Dir = OrigName = Name = PPValues = NULL;
+ A = NULL;
+ StrAudioData = StrAudioData2 = NULL;
+
+ Dir = strdup(d);
+ Name = strdup(n);
+
+ // detect codecs
+ C = new cCodecs();
+
+ // detect templates
+ T = new cTemplate();
+
+ // init some values
+ AudioID = 0;
+ initCropValues();
+
+ if (strstr(Dir, "dvd://")) {
+ Dvd = true;
+
+#ifdef VDRRIP_DVD
+ // detect dvd-data
+ queryDVDName();
+ queryDVDData();
+
+ if (! restoreMovieData()) {
+ NumTemplate = T->getNumTemplate(TDEFAULT);
+
+ setDVDTitle(Title, true);
+ // save Movie Data
+ saveMovieData();
+ }
+#endif //VDRRIP_DVD
+ } else {
+ Dvd = false;
+
+ // detect vdr-data
+ setLengthVDR();
+ queryMpValuesVDR();
+ queryAudioDataVDR();
+
+ if (! restoreMovieData()) {
+ // set to default template
+ NumTemplate = T->getNumTemplate(TDEFAULT);
+ setNumTemplate(NumTemplate);
+
+ // save Movie Data
+ saveMovieData();
+ }
+ }
+}
+
+cMovie::~cMovie() {
+ int i;
+
+ DELETE(C);
+ DELETE(T);
+
+ FREE(Dir);
+ FREE(OrigName);
+ FREE(Name);
+ FREE(PPValues);
+
+ for (i = 0; i < NumAudioID; i++) {
+ FREE(A[i].Lang);
+ FREE(A[i].Format);
+ FREE(StrAudioData[i]);
+ FREE(StrAudioData2[i]);
+ }
+ FREE(A);
+ FREE(StrAudioData);
+ FREE(StrAudioData2);
+
+#ifdef VDRRIP_DVD
+ if (Dvd) {
+ for (i = 0; i < NumTitles; i++) {
+ //TODO: fix this
+ //for (i1 = 0; i1 < D[i].NumAudio; i1++) {
+ //FREE(D[i].A[i1].Lang);
+ //FREE(D[i].A[i1].Format);
+ //}
+ FREE(D[i].A);
+ if (StrTitles) FREE(StrTitles[i]);
+ }
+ FREE(D);
+ FREE(StrTitles);
+ }
+#endif // VDRRIP_DVD
+}
+
+bool cMovie::isDVD() {return Dvd;}
+
+void cMovie::setFileSize(int s, int n) {
+ FileNumbers = n;
+
+ if (s == -1 ) {
+ // calculate FileSize
+ if (Length < 1) {
+ FileSize = -1;
+ } else {
+ FileSize = Bitrate * Length / FileNumbers / 8 / 1024;
+ }
+ } else {
+ // calculate Bitrate
+ FileSize = s;
+ setBitrate(-1, BitrateAudio);
+ }
+}
+
+void cMovie::setName(char *n) {Name = n;}
+
+void cMovie::setNumTemplate(int i) {
+ // init some values
+ NumTemplate = i;
+ Bpp = T->getBpp(NumTemplate);
+ FileNumbers = T->getFileNumbers(NumTemplate);
+ FileSize = T->getFileSize(NumTemplate);
+ ScaleType = T->getScaleType(NumTemplate);
+
+ // the rest is done here ...
+ setContainer(T->getContainer(NumTemplate));
+ setCodecs(T->getVCodec(NumTemplate), T->getACodec(NumTemplate));
+}
+
+int cMovie::getFileSize() {return FileSize;}
+
+int cMovie::getFileNumbers() {return FileNumbers;}
+
+void cMovie::setBitrate(int v, int a) {
+ // avoid BitrateAudio < 32
+ if (a < 32 && strcmp(C->getACodec(ACodec), "copy") != 0) {a = 32;}
+ BitrateAudio = a;
+
+ if (v == -1) {
+ // calculate BitrateVideo
+ if (FileSize == -1) {
+ // fixed Bitrate
+ Bitrate = BitrateVideo + BitrateAudio;
+ } else {
+ // fixed FileSize
+ Bitrate = FileSize * 1024 * FileNumbers * 8 / Length;
+
+ // avoid BitrateVideo < 150
+ if (Bitrate <= BitrateAudio + 150) {
+ Bitrate = BitrateAudio + 150;
+ setFileSize(-1, FileNumbers);
+ }
+
+ // avoid BitrateVideo > 99999
+ if (Bitrate > BitrateAudio + 99999) {
+ Bitrate = BitrateAudio + 99999;
+ setFileSize(-1, FileNumbers);
+ }
+
+ BitrateVideo = Bitrate - BitrateAudio;
+ }
+ } else {
+ // calculate FileSize
+ BitrateVideo = v;
+ Bitrate = BitrateVideo + BitrateAudio;
+ setFileSize(-1, FileNumbers);
+ }
+
+ setScale();
+}
+
+void cMovie::setContainer(int c) {
+ if (c >= 0 && c < C->getNumContainers()) {Container = c;
+ } else {
+ dsyslog("[vdrrip] unknown container, falling back to avi !");
+ Container = C->getNumContainer("avi");
+ }
+}
+
+void cMovie::setScaleType(int s) {
+ ScaleType = s;
+ setScale();
+}
+
+void cMovie::setScale() {
+ switch (ScaleType) {
+ case 0: {
+ // off
+ ScaleWidth = -1;
+ ScaleHeight = -1;
+ initCropValues();
+ break;
+ }
+
+ case 1: {
+ // auto: this is based on encoding-tips.txt from the mplayer-documentation
+ ScaleWidth = roundValue((int)sqrt(BitrateVideo * 1024 * CalcAspect * 100 / Bpp /Fps), 16);
+ if (ScaleWidth > VdrripSetup.MaxScaleWidth) {ScaleWidth = VdrripSetup.MaxScaleWidth;}
+ if (ScaleWidth < VdrripSetup.MinScaleWidth) {ScaleWidth = VdrripSetup.MinScaleWidth;}
+ ScaleHeight = roundValue((int)(ScaleWidth / CalcAspect), 16);
+ break;
+ }
+
+ case 2: {
+ // dvb: set default dvb-values
+ ScaleWidth = 352;
+ ScaleHeight = 288;
+ initCropValues();
+ break;
+ }
+
+ case 3: {
+ // manual
+ ScaleWidth = Width;
+ ScaleHeight = Height;
+ break;
+ }
+
+ }
+}
+
+void cMovie::setScale(int width, int height) {
+ ScaleWidth = width;
+ ScaleHeight = height;
+}
+
+void cMovie::setCropValues(int width, int height) {
+ CropWidth = width;
+ if (CropWidth > Width) CropWidth = Width;
+
+ CropHeight = height;
+ if (CropHeight > Height) CropHeight = Height;
+
+ if (CropWidth == -1) CropPosX = -1;
+ else CropPosX = (Width - CropWidth) / 2;
+
+ if (CropHeight == -1) {
+ CropPosY = -1;
+ CalcAspect = Aspect;
+ } else {
+ CropPosY = (Height - CropHeight) / 2;
+ CalcAspect = Height * Aspect / CropHeight;
+ }
+
+ setScale();
+}
+
+
+bool cMovie::setCropValues() {
+ char *cmd = NULL, *buf = NULL;
+ bool ret = true;
+
+ size_t i = 0;
+ int l = 0;
+ int l1;
+
+ if (Dvd) {asprintf(&cmd, IDENTCMD, MPlayer, Dir, "");
+ } else {asprintf(&cmd, IDENTCMD, MPlayer, Dir, "/001.vdr");}
+
+ FILE *p = popen(cmd, "r");
+ if (p) {
+ char *s = NULL;
+ s = strcol(strgrep("ID_LENGTH", p), "=", 2);
+ if (s) {l = atoi(s);}
+ FREE(s);
+ } else {
+ dsyslog("[vdrrip] could not open pipe to %s !", cmd);
+ }
+ pclose(p);
+ FREE(cmd);
+
+
+ l1 = VdrripSetup.CropLength * (int)Fps;
+ if (Dvd) {
+ asprintf(&cmd, CROPCMD, MPlayer, Dir, "", l/2, l1);
+ isyslog("[vdrrip] detecting crop values in %s", Dir);
+ } else {
+ asprintf(&cmd, CROPCMD, MPlayer, Dir, "/001.vdr", l/2, l1);
+ isyslog("[vdrrip] detecting crop values in %s/001.vdr", Dir);
+ }
+ p = popen(cmd, "r");
+ FREE(cmd);
+
+ if (p) {
+ // get first line
+ if (getline(&buf, &i, p) != -1) {
+ char *s = NULL;
+
+ s = strcol(buf, "=", 2);
+ CropWidth = roundValue(atoi(strcol(s, ":", 1)), 16);
+ if (CropWidth > Width || CropWidth < 0) {
+ ret = false;
+ CropWidth = Width;
+ }
+
+ CropHeight = roundValue(atoi(strcol(s, ":", 2)), 16);
+ if (CropHeight > Height || CropHeight < 0) {
+ ret = false;
+ CropHeight = Height;
+ }
+
+ if (VdrripSetup.CropMode == 1) {CropWidth = Width;}
+ CropPosX = (Width - CropWidth) / 2;
+ CropPosY = (Height - CropHeight) / 2;
+ // CalcAspect is changed now:
+ CalcAspect = Height * Aspect / CropHeight;
+ setScale();
+
+ FREE(s);
+ FREE(buf);
+ } else {
+ ret = false;
+ }
+
+ pclose(p);
+ } else ret = false;
+
+ if (! ret) initCropValues();
+
+ return ret;
+}
+
+void cMovie::initCropValues() {
+ CropWidth = -1;
+ CropHeight = -1;
+ CropPosX = -1;
+ CropPosY = -1;
+ CalcAspect = Aspect;
+}
+
+void cMovie::setCodecs(int v, int a) {
+ // validate video codec
+ if (v >= 0 && v < C->getNumVCodecs()) {VCodec = v;
+ } else {
+ dsyslog("[vdrrip] unknown video codec, falling back to %s !", C->getVCodec(0));
+ VCodec = 0;
+ }
+
+ // validate audio codec
+ if (a >= 0 && a < C->getNumACodecs()) {
+ if (strcmp(C->getContainer(Container), "avi") == 0 &&
+ strcmp(C->getACodec(a), "ogg-vorbis") == 0) {
+ dsyslog("[vdrrip] avi couldn't contain ogg-vorbis audio, falling back to copy !");
+ ACodec = C->getNumACodec("copy");
+ } else {ACodec = a;}
+ } else {
+ dsyslog("[vdrrip] unknown audio codec, falling back to copy !"),
+ ACodec = C->getNumACodec("copy");
+ }
+
+ // set audio bitrates
+ if (ACodec == C->getNumACodec("copy")) {
+ setBitrate(T->getBitrateVideo(NumTemplate), A[AudioID].Bitrate);
+ } else {
+ setBitrate(T->getBitrateVideo(NumTemplate), T->getBitrateAudio(NumTemplate));
+ }
+}
+
+void cMovie::setBpp(int i) {
+ Bpp = i;
+ setScale();
+}
+
+int cMovie::getBitrateAudio() {return BitrateAudio;}
+
+int cMovie::getBitrateVideo() {return BitrateVideo;}
+
+int cMovie::getLength() {return Length;}
+
+int cMovie::getWidth() {return Width;}
+
+int cMovie::getHeight() {return Height;}
+
+double cMovie::getAspect() {return Aspect;}
+
+double cMovie::getCalcAspect() {return CalcAspect;}
+
+double cMovie::getFps() {return Fps;}
+
+int cMovie::getContainer() {return Container;}
+
+int cMovie::getScaleType() {return ScaleType;}
+
+int cMovie::getScaleWidth() {return ScaleWidth;}
+
+int cMovie::getScaleHeight() {return ScaleHeight;}
+
+int cMovie::getCropWidth() {return CropWidth;}
+
+int cMovie::getCropHeight() {return CropHeight;}
+
+int cMovie::getCropPosX() {return CropPosX;}
+
+int cMovie::getCropPosY() {return CropPosY;}
+
+double cMovie::getResBpp() {
+ return (double)BitrateVideo * 1024. / (double)ScaleWidth / (double)ScaleHeight / Fps;}
+
+double cMovie::getBpp() {return (double)Bpp;}
+
+char *cMovie::getName() {return Name;}
+
+int cMovie::getNumTemplate() {return NumTemplate;}
+
+char *cMovie::getDir() {return Dir;}
+
+int cMovie::getNumAudioID() {return NumAudioID;}
+
+int cMovie::getAudioID() {return AudioID;}
+
+void cMovie::setAudioID(int i) {
+ if (i >= 0 && i < NumAudioID) {
+ AudioID = i;
+ } else {
+ dsyslog("[vdrrip] %d is not a valid audio-id, falling back to 0 !", AudioID);
+ AudioID = 0;
+ }
+ setCodecs(VCodec, ACodec);
+}
+
+int cMovie::getVCodec() {return VCodec;}
+
+int cMovie::getACodec() {return ACodec;}
+
+void cMovie::setPPValues(const char *pp) {
+ FREE(PPValues);
+ if (pp) {
+ PPValues = strdup(pp);
+ } else {
+ PPValues = NULL;
+ }
+}
+
+const char* cMovie::getPPValues() {return PPValues;}
+
+
+// --- VDR-Movie ---------------------------------------------------------
+
+
+void cMovie::setLengthVDR() {
+ char *file = NULL;
+
+ asprintf(&file, "%s/index.vdr", Dir);
+ FILE *f = fopen(file, "r");
+ if (f) {
+ fseek(f, 0, SEEK_END);
+ Length = ftell(f) / 200;
+ fclose(f);
+ } else {
+ dsyslog("[vdrrip] could not open file %s !", file);
+ dsyslog("[vdrrip] perhaps you have to create it with genindex.c !");
+ Length = -1;
+ }
+
+ FREE(file);
+}
+
+
+void cMovie::queryMpValuesVDR() {
+ char *cmd = NULL, *s = NULL;
+
+ asprintf(&cmd, IDENTCMD, MPlayer, Dir, "/001.vdr");
+ FILE *p = popen(cmd, "r");
+ if (p) {
+ s = strcol(strgrep("ID_VIDEO_WIDTH", p), "=", 2);
+ if (s) {
+ Width = atoi(s);
+ } else {Width = -1;}
+ FREE(s);
+
+ s = strcol(strgrep("ID_VIDEO_HEIGHT", p), "=", 2);
+ if (s) {
+ Height = atoi(s);
+ } else {Height = -1;}
+ FREE(s);
+
+ s = strcol(strgrep("ID_VIDEO_FPS", p), "=", 2);
+ if (s) {
+ Fps = atof(s);
+ } else {Fps = -1;}
+ FREE(s);
+
+ s = strcol(strgrep("ID_VIDEO_ASPECT", p), "=", 2);
+ if (s) {
+ Aspect = atof(s);
+ } else {Aspect = -1;}
+
+ CalcAspect = Aspect;
+
+ pclose(p);
+ } else {dsyslog("[vdrrip] could not open pipe to %s !", cmd);}
+
+ FREE(s);
+ FREE(cmd);
+}
+
+
+void cMovie::queryAudioDataVDR() {
+ char *cmd = NULL, *buf = NULL;
+ size_t i = 0;
+ int n = 0;
+ int c = 0;
+ bool next = true;
+
+ while (next) {
+ asprintf(&cmd, AUDIOCMD, MPlayer, Dir, c);
+ FILE *p = popen(cmd, "r");
+ if (p) {
+ if (getline(&buf, &i, p) != -1) {
+ if (c == 128) {next = false;}
+ A = (struct AudioData*)realloc(A, (n + 1) * sizeof(struct AudioData));
+
+ A[n].AudioID = c;
+ A[n].Lang = strdup(tr("unknown"));
+
+ if (c == 128) {A[n].Format = strdup("ac3");
+ } else {A[n].Format = strdup("mp2");}
+
+ char *s = NULL;
+ s = strcol(buf, " ", 2);
+ if (s) {A[n].Freq = atoi(s);
+ } else {A[n].Freq = 0;}
+ FREE(s);
+
+ s = strcol(buf, " ", 4);
+ if (s) {A[n].Chan = atoi(s);
+ } else {A[n].Chan = 0;}
+ FREE(s);
+
+ s = strcol(buf, " ", 11);
+ if (s) {
+ A[n].Bitrate = atoi(s + sizeof(char));
+ } else {A[n].Bitrate = 192;}
+ FREE(s);
+
+ // isyslog("[vdrrip] Audio-ID %i found: lang %s, format %s, %i kbit, %i Hz, %i ch", A[n].AudioID, A[n].Lang, A[n].Format, A[n].Bitrate, A[n].Freq, A[n].Chan);
+ n++;
+ c++;
+ } else {
+ // nothing found:
+ if (c < 128 && VdrripSetup.AC3 == 1) {c = 128;
+ } else {next = false;}
+ }
+ pclose(p);
+ } else {dsyslog("[vdrrip] could not open pipe to %s !", cmd);}
+ }
+
+ NumAudioID = n;
+
+ // write AudioData to an array
+ if (NumAudioID > 0) {
+ StrAudioData = (char **)malloc(NumAudioID * sizeof(char*));
+ StrAudioData2 = (char **)malloc(NumAudioID * sizeof(char*));
+ for (c = 0; c < NumAudioID; c++) {
+ asprintf(&StrAudioData[c], "%s, %i kbit, lang: %s", A[c].Format, A[c].Bitrate, A[c].Lang);
+
+ asprintf(&StrAudioData2[c], "%d: %s, %d kbit, %i chan, %d hz, lang: %s", A[c].AudioID, A[c].Format, A[c].Bitrate, A[c].Chan, A[c].Freq, A[c].Lang);
+ }
+ } else {
+ dsyslog("[vdrrip] no Audio ID found !");
+ A = (struct AudioData*)malloc(sizeof(struct AudioData));
+ A[0].Lang = strdup(tr("unknown"));
+ A[0].Format = strdup(tr("unknown"));
+ A[0].Bitrate = 0;
+ A[0].Freq = 0;
+ A[0].Chan = 0;
+ A[0].AudioID = 0;
+
+ StrAudioData = (char **)malloc(sizeof(char*));
+ asprintf(&StrAudioData[0], tr("not found"));
+ NumAudioID = 1;
+ }
+
+ FREE(buf);
+ FREE(cmd);
+}
+
+int cMovie::getAudioID(int i) {
+ if (i >= 0 && i < NumAudioID) {
+ return A[i].AudioID;
+ } else {return 0;}
+}
+
+char **cMovie::getAudioData() {return StrAudioData;}
+
+char **cMovie::getAudioData2() {return StrAudioData2;}
+
+void cMovie::saveMovieData() {
+ char *file = NULL;
+
+ if (Dvd) {
+ if (OrigName) asprintf(&file, "/tmp/%s.vdrrip", OrigName);
+ else return;
+ } else asprintf(&file, "%s/%s", Dir, SAVEFILE);
+
+ FILE *f = fopen(file,"w");
+ if (f) {
+ fprintf(f,"%s;%i;%i;%i;%s;%i;%i;%i;%i;%i;%i;%i;%i;%i;%s;%i;%i;%s;%s;%s;%d\n",
+ Name, FileSize, FileNumbers, Bitrate, C->getVCodec(VCodec), BitrateVideo,
+ CropWidth, CropHeight, CropPosX, CropPosY, ScaleType, ScaleWidth,
+ ScaleHeight, Bpp, C->getACodec(ACodec), BitrateAudio, AudioID, PPValues,
+ T->getName(NumTemplate), C->getContainer(Container),
+#ifdef VDRRIP_DVD
+ Dvd ? Title : 0
+#else
+ 0
+#endif //VDRRIP_DVD
+ );
+
+ fclose(f);
+ } else {dsyslog("[vdrrip] could not open file %s !", file);}
+
+ FREE(file);
+}
+
+bool cMovie::restoreMovieData() {
+ char *file = NULL, *vcodec = NULL, *acodec = NULL, *tname = NULL,
+ *container = NULL, *buf = NULL;
+ size_t i = 0;
+
+ if (Dvd) {
+ if (OrigName) asprintf(&file, "/tmp/%s.vdrrip", OrigName);
+ else return false;
+ } else asprintf(&file, "%s/%s", Dir, SAVEFILE);
+
+ FILE *f = fopen(file,"r");
+ if (f) {
+ if (getline(&buf, &i, f) != -1) {
+ Name = strcol(buf, ";", 1);
+ FileSize = atoi(strcol(buf, ";", 2));
+ FileNumbers = atoi(strcol(buf, ";", 3));
+ Bitrate = atoi( strcol(buf, ";", 4));
+ vcodec = strcol(buf, ";", 5);
+ BitrateVideo = atoi(strcol(buf, ";", 6));
+ CropWidth = atoi(strcol(buf, ";", 7));
+ CropHeight = atoi(strcol(buf, ";", 8));
+ CropPosX = atoi(strcol(buf, ";", 9));
+ CropPosY = atoi(strcol(buf, ";", 10));
+ ScaleType = atoi(strcol(buf, ";", 11));
+ ScaleWidth = atoi(strcol(buf, ";", 12));
+ ScaleHeight = atoi(strcol(buf, ";", 13));
+ Bpp = atoi(strcol(buf, ";", 14));
+ acodec = strcol(buf, ";", 15);
+ BitrateAudio = atoi(strcol(buf, ";", 16));
+ AudioID = atoi(strcol(buf, ";", 17));
+ PPValues = strcol(buf, ";", 18);
+ if (strcmp(PPValues, "(null)") == 0) PPValues = NULL;
+ tname = strcol(buf, ";", 19);
+ // migrate from version 0.1.1
+ container = strcol(buf, ";", 20);
+ if (! container) container = strdup("avi");
+#ifdef VDRRIP_DVD
+ // migrate from version 0.2.0a
+ if (Dvd) Title = atoi(strcol(buf, ";", 21));
+#endif //VDRRIP_DVD
+
+ FREE(buf);
+
+ fclose(f);
+ isyslog("[vdrrip] restored data from file %s !", file);
+
+ // validate some values:
+ if (! Dvd) setCropValues(CropWidth, CropHeight);
+
+ NumTemplate = T->getNumTemplate(tname);
+ if (NumTemplate == -1) {
+ dsyslog("[vdrrip] %s is not a valid template, falling back to default !", tname);
+ NumTemplate = T->getNumTemplate(TDEFAULT);
+ }
+ FREE(tname);
+
+#ifdef VDRRIP_DVD
+ if (Dvd) setDVDTitle(Title, false);
+#endif //VDRRIP_DVD
+
+ setContainer(C->getNumContainer(container));
+ FREE(container);
+
+ setCodecs(C->getNumVCodec(vcodec), C->getNumACodec(acodec));
+ FREE(vcodec);
+ FREE(acodec);
+
+ setAudioID(AudioID);
+
+ } else {
+ dsyslog("[vdrrip] could not read data from file %s !", file);
+ FREE(file);
+ return false;
+ }
+ } else {
+ dsyslog("[vdrrip] could not open file %s, perhaps it is not available !", file);
+ FREE(file);
+ return false;
+ }
+ FREE(file);
+
+ saveMovieData();
+ return true;
+}
+
+
+// --- DVD-Movie ---------------------------------------------------------
+
+#ifdef VDRRIP_DVD
+void cMovie::queryDVDName() {
+ int i;
+ char name[33];
+
+ FILE *f = fopen(DVD, "r");
+
+ if (f) {
+ if (! fseek(f, 32808, SEEK_SET )) {
+ i = fread(name, 1, 32, f);
+ if (i == 32) {
+ name[32] = '\0';
+ while(i-- > 2) {if (name[i] == ' ') name[i] = '\0';}
+ Name = strdup(name);
+ OrigName = strdup(name);
+ } else {
+ dsyslog("[vdrrip] Couldn't read enough bytes for title !");
+ Name = strdup(tr("unknown"));
+ }
+ } else {
+ dsyslog("[vdrrip] Couldn't seek in %s for title", DVD);
+ Name = strdup(tr("unknown"));
+ }
+
+ fclose(f);
+ } else {
+ dsyslog("[vdrrip] Couldn't open %s for title", DVD);
+ Name = strdup(tr("unknown"));
+ }
+}
+
+void cMovie::queryDVDData() {
+ //
+ // parts of this code are pasted from the tool lsdvd by chris phillips
+ // which is hosted at http://sourceforge.net/projects/acidrip/
+ //
+ // thx a lot...
+ //
+ dvd_reader_t *dvd = NULL;
+ ifo_handle_t *ifo_zero = NULL, **ifo = NULL;
+ pgcit_t *vts_pgcit;
+ vtsi_mat_t *vtsi_mat;
+ vmgi_mat_t *vmgi_mat;
+ audio_attr_t *audio_attr;
+ video_attr_t *video_attr;
+ pgc_t *pgc;
+ dvd_time_t *dt;
+
+ int i, i1, vts_ttn, numifos, numifo;
+ int l = 0;
+
+ Title = 1;
+ NumTitles = 0;
+
+ const char *audio_format[] = {"ac3", "?", "mpeg1", "mp2", "lpcm ", "sdds ", "dts"};
+ const char *sample_freq[] = {"48000", "48000"};
+ const int height[] = {480, 576};
+ const int width[] = {720, 704, 352, 352};
+ const double aspect[] = {4.0/3.0, 16.0/9.0, 1/1, 16.0/9.0};
+ const double fps[] = {-1.0, 25.00, -1.0, 29.97};
+
+
+ dvd = DVDOpen(DVD);
+
+ if (dvd) {
+ ifo_zero = ifoOpen(dvd, 0);
+
+ if (ifo_zero) {
+ // read needed data from ifo_zero
+ numifos = ifo_zero->vts_atrt->nr_of_vtss;
+ vmgi_mat = ifo_zero->vmgi_mat;
+ NumTitles = ifo_zero->tt_srpt->nr_of_srpts;
+
+ // reserve memory for numifos ifos
+ ifo = (ifo_handle_t **)malloc((numifos + 1) * sizeof(ifo_handle_t *));
+
+ // save ifo data
+ for (i = 1; i <= numifos; i++) {
+ ifo[i] = ifoOpen(dvd, i);
+ if (! ifo[i]) dsyslog("[vdrrip] Can't open ifo %d !", i);
+ }
+
+ // reserve memory for DVDData
+ D = (struct DVDData *)malloc((NumTitles + 1) * sizeof(struct DVDData));
+
+ // read movie data
+ for (i = 0; i < NumTitles; i++) {
+ // get ifo number for title i
+ numifo = ifo_zero->tt_srpt->title[i].title_set_nr;
+
+ if (ifo[numifo]->vtsi_mat) {
+ vtsi_mat = ifo[numifo]->vtsi_mat;
+ vts_pgcit = ifo[numifo]->vts_pgcit;
+ video_attr = &vtsi_mat->vts_video_attr;
+ vts_ttn = ifo_zero->tt_srpt->title[i].vts_ttn;
+ vmgi_mat = ifo_zero->vmgi_mat;
+ pgc = vts_pgcit->pgci_srp[ifo[numifo]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;
+ dt = &pgc->playback_time;
+
+ // read the movie-data of the title into the struc DVDData:
+ D[i].Length = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600;
+ D[i].Length += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60;
+ D[i].Length += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f));
+ if (D[i].Length == 0) {D[i].Length = -1;}
+
+ D[i].Width = width[video_attr->picture_size];
+ D[i].Height = height[video_attr->video_format];
+ D[i].Aspect = aspect[video_attr->display_aspect_ratio];
+ D[i].Fps = fps[(pgc->playback_time.frame_u & 0xc0) >> 6];
+
+ D[i].NumAudio = vtsi_mat->nr_of_vts_audio_streams;
+ // reserve memory for DVDAudioData
+ D[i].A = (struct AudioData*)malloc(D[i].NumAudio * sizeof(struct AudioData));
+
+ for (i1 = 0; i1 < D[i].NumAudio; i1++) {
+ audio_attr = &vtsi_mat->vts_audio_attr[i1];
+
+ asprintf(&D[i].A[i1].Lang, "%c%c", audio_attr->lang_code >> 8, audio_attr -> lang_code & 0xff);
+ D[i].A[i1].Format = strdup(audio_format[audio_attr->audio_format]);
+ D[i].A[i1].Freq = atoi(sample_freq[audio_attr->sample_frequency]);
+ D[i].A[i1].Chan = audio_attr->channels+1;
+ D[i].A[i1].AudioID = 128 + i1;
+ D[i].A[i1].Bitrate = -1;
+ }
+
+ // save number of the longest Title
+ if (D[i].Length > l) {
+ l = D[i].Length;
+ Title = i + 1;
+ LongestTitle = Title;
+ }
+ }
+ }
+
+ // close ifos
+ ifoClose(ifo_zero);
+ for (i = 1; i <= numifos; i++) {
+ if(ifo[i]) ifoClose(ifo[i]);
+ }
+ FREE(ifo);
+
+
+ DVDClose(dvd);
+ } else {dsyslog("[vdrrip] Can't open main ifo !");}
+ } else {dsyslog("[vdrrip] Can't open disc %s !", DVD);}
+
+
+}
+
+
+void cMovie::setDVDTitle(int t, bool st) {
+
+ if (t > 0 && t <= NumTitles) Title = t;
+ else {
+ dsyslog("[vdrrip] Unknown title %d, setting back to longest Title %d !", t, LongestTitle);
+ Title = LongestTitle;
+ st = true;
+ }
+
+ // set directory-name (for the queuehandler)
+ FREE(Dir);
+ asprintf(&Dir, "dvd://%i", Title);
+
+ // set video data:
+ Length = D[Title - 1].Length;
+ Width = D[Title - 1].Width;
+ Height = D[Title - 1].Height;
+ Fps = D[Title - 1].Fps;
+ Aspect = D[Title - 1].Aspect;
+
+ if (st) initCropValues(); // no restore
+ else setCropValues(CropWidth, CropHeight);
+
+ // set audio data:
+ if (st) AudioID = 0; // no restore
+ NumAudioID = D[Title - 1].NumAudio;
+
+ if (NumAudioID > 0) {
+ A = (struct AudioData*)realloc(A, NumAudioID * sizeof(struct AudioData));
+ StrAudioData = (char **)realloc(StrAudioData, NumAudioID * sizeof(char*));
+ StrAudioData2 = (char **)realloc(StrAudioData2, NumAudioID * sizeof(char*));
+
+ for (int i = 0; i < NumAudioID; i++) {
+
+ // get audio bitrate
+ if (D[Title -1].A[i].Bitrate == -1) {D[Title -1].A[i].Bitrate = queryAudioBrDVD(D[Title -1].A[i].AudioID);}
+ A[i] = D[Title - 1].A[i];
+
+ asprintf(&StrAudioData[i], "%s, %d kbit, lang: %s", A[i].Format, A[i].Bitrate, A[i].Lang);
+
+ asprintf(&StrAudioData2[i], "%d: %s, %d kbit, %d chan, %d hz, lang: %s", A[i].AudioID, A[i].Format, A[i].Bitrate, A[i].Chan, A[i].Freq, A[i].Lang);
+ }
+ } else {
+ dsyslog("[vdrrip] no Audio ID found !");
+ A = (struct AudioData*)realloc(A, sizeof(struct AudioData));
+ A[0].Lang = strdup(tr("unknown"));
+ A[0].Format = strdup(tr("unknown"));
+ A[0].Bitrate = 0;
+ A[0].Freq = 0;
+ A[0].Chan = 0;
+ A[0].AudioID = 0;
+
+ StrAudioData = (char **)realloc(StrAudioData, sizeof(char*));
+ asprintf(&StrAudioData[0], tr("not found"));
+ NumAudioID = 1;
+ }
+
+ if (st) setNumTemplate(NumTemplate); // no restore
+}
+
+int cMovie::queryAudioBrDVD(int c) {
+ char *cmd = NULL, *buf = NULL;
+ size_t i = 0;
+ int b = 0;
+
+ asprintf(&cmd, AUDIOCMDDVD, MPlayer, Dir, c);
+ FILE *p = popen(cmd, "r");
+ if (p) {
+ if (getline(&buf, &i, p) != -1) {
+ char *s = strcol(buf, " ", 11);
+ if (s) {
+ b = atoi(s + sizeof(char));
+ FREE(s);
+ }
+ }
+ pclose(p);
+ } else {dsyslog("[vdrrip] could not open pipe to %s !", cmd);}
+
+
+ FREE(buf);
+ FREE(cmd);
+
+ return b;
+}
+
+int cMovie::getDVDTitle() {return Title;}
+
+int cMovie::getNumDVDTitles() {return NumTitles;}
+
+char **cMovie::getTitleData() {
+ StrTitles = (char **)malloc(NumTitles * sizeof(char*));
+ for (int i = 0; i < NumTitles; i++)
+ asprintf(&StrTitles[i], "Title %d: %i audio channels, length: %d sec.", i + 1, D[i].NumAudio, D[i].Length);
+
+ return StrTitles;
+}
+#endif //VDRRIP_DVD
diff --git a/movie.h b/movie.h
new file mode 100755
index 0000000..1b257ff
--- /dev/null
+++ b/movie.h
@@ -0,0 +1,163 @@
+/* movie.h */
+
+#ifndef __MOVIE_H
+#define __MOVIE_H
+
+#include <stdio.h>
+
+#include "templates.h"
+#include "codecs.h"
+
+
+extern const char *MPlayer;
+#ifdef VDRRIP_DVD
+ extern const char *DVD;
+#endif //VDRRIP_DVD
+
+struct AudioData {
+ char* Lang;
+ char* Format;
+ int Bitrate;
+ int Freq;
+ int Chan;
+ int AudioID;
+};
+
+#ifdef VDRRIP_DVD
+ struct DVDData {
+ int Length;
+ int Width;
+ int Height;
+ double Aspect;
+ double Fps;
+ int NumAudio;
+ struct AudioData *A;
+ };
+#endif //VDRRIP_DVD
+
+
+class cMovie {
+ protected:
+ bool Dvd;
+
+ char *OrigName;
+ char *Name;
+ char *Dir;
+ int Length;
+ int FileSize;
+ int FileNumbers;
+ int NumTemplate;
+ int Bitrate;
+ int BitrateVideo;
+ int BitrateAudio;
+ int Width;
+ int Height;
+ double Aspect;
+ double CalcAspect;
+ double Fps;
+ int ScaleType;
+ int ScaleWidth;
+ int ScaleHeight;
+ int CropWidth;
+ int CropHeight;
+ int CropPosX;
+ int CropPosY;
+ int Bpp;
+ int Container;
+ int VCodec;
+ int ACodec;
+ int AudioID;
+ int NumAudioID;
+ struct AudioData *A;
+ char *PPValues;
+
+ char *MarksFile;
+ char **StrAudioData;
+ char **StrAudioData2;
+
+#ifdef VDRRIP_DVD
+ int Title;
+ int LongestTitle;
+ int NumTitles;
+ char **StrTitles;
+ struct DVDData* D;
+#endif
+
+ public:
+ cMovie(char *d, char *n);
+ ~cMovie();
+
+ cTemplate *T;
+ cCodecs *C;
+
+ bool isDVD();
+
+ void setName(char *n);
+ char *getName();
+ char *getDir();
+ void setNumTemplate(int i);
+ int getNumTemplate();
+ void setBitrate(int v, int a);
+ int getBitrateVideo();
+ int getBitrateAudio();
+ int getLength();
+
+ void setFileSize(int s, int n);
+ int getFileSize();
+ int getFileNumbers();
+ int getHeight();
+ int getWidth();
+ double getAspect();
+ double getCalcAspect();
+ double getFps();
+ void setScaleType(int s);
+ void setScale();
+ void setScale(int width, int height);
+ int getScaleType();
+ int getScaleWidth();
+ int getScaleHeight();
+ void setCropValues(int width, int height);
+ bool setCropValues();
+ int getCropHeight();
+ int getCropWidth();
+ int getCropPosX();
+ int getCropPosY();
+ void setBpp(int i);
+ double getBpp();
+ double getResBpp();
+ void initCropValues();
+ void setContainer(int c);
+ int getContainer();
+ void setCodecs(int v, int a);
+ int getVCodec();
+ int getACodec();
+ void setAudioID(int i);
+ int getAudioID();
+ int getNumAudioID();
+ void setPPValues(const char *pp);
+ const char* getPPValues();
+ char** getAudioData();
+ char** getAudioData2();
+ int getAudioID(int i);
+
+ // VDR-Movie
+ void setLengthVDR();
+ void queryMpValuesVDR();
+ void queryAudioDataVDR();
+
+ void saveMovieData();
+ bool restoreMovieData();
+
+#ifdef VDRRIP_DVD
+ // DVD
+ void queryDVDName();
+ void queryDVDData();
+ void setDVDTitle(int t, bool st);
+ int getDVDTitle();
+ int queryAudioBrDVD(int c);
+ int getNumDVDTitles();
+ char** getTitleData();
+#endif //VDRRIP_DVD
+};
+
+#endif //__MOVIE_H
diff --git a/patches/MPlayer_vdrac3.diff b/patches/MPlayer_vdrac3.diff
new file mode 100755
index 0000000..6acdd15
--- /dev/null
+++ b/patches/MPlayer_vdrac3.diff
@@ -0,0 +1,38 @@
+--- libmpdemux/demux_mpg.c.orig Fri Apr 4 17:38:46 2003
++++ libmpdemux/demux_mpg.c Mon Jun 16 11:54:20 2003
+@@ -124,7 +124,7 @@
+
+ //============== DVD Audio sub-stream ======================
+ if(id==0x1BD){
+- int aid=stream_read_char(demux->stream);--len;
++ int aid=128; //stream_read_char(demux->stream);--len;
+ if(len<3) return -1; // invalid audio packet
+
+ // AID:
+@@ -145,10 +145,11 @@
+ ds=demux->sub;
+ }
+
+- } else if((aid & 0xC0) == 0x80 || (aid & 0xE0) == 0x00) {
++ } else if((aid & 0xC0) == 0x80) {
+
+ // aid=128+(aid&0x7F);
+ // aid=0x80..0xBF
++// if(aid<0x20) aid+=0x80; // hack
+
+ if(!demux->a_streams[aid]) new_sh_audio(demux,aid);
+ if(demux->audio->id==-1) demux->audio->id=aid;
+@@ -158,11 +159,13 @@
+ ds=demux->audio;
+ if(!ds->sh) ds->sh=demux->a_streams[aid];
+ // READ Packet: Skip additional audio header data:
++ #if 0
+ c=stream_read_char(demux->stream);//num of frames
+ type=stream_read_char(demux->stream);//startpos hi
+ type=(type<<8)|stream_read_char(demux->stream);//startpos lo
+ // printf("\r[%02X][%04X]",c,type);
+ len-=3;
++ #endif
+ if((aid&0xE0)==0xA0 && len>=3){
+ unsigned char* hdr;
+ // save audio header as codecdata!
diff --git a/queue.c b/queue.c
new file mode 100755
index 0000000..354ca08
--- /dev/null
+++ b/queue.c
@@ -0,0 +1,289 @@
+//
+// queue.c
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vdr/plugin.h>
+
+#include "queue.h"
+#include "a-tools.h"
+
+cQueue::cQueue() {
+ Q = NULL;
+
+ WaitUnlock();
+ if (! Locked) {Lock();}
+ Load();
+}
+
+cQueue::~cQueue() {
+ if (! Locked) {Unlock();}
+ DELETE(Q);
+}
+
+void cQueue::Load() {
+ char *buf = NULL;
+ size_t i = 0;
+ int c = 0;
+
+ FILE *q = fopen(AddDirectory(cPlugin::ConfigDirectory(), QUEUEFILE), "r");
+ if (q) {
+ // read QueueData
+ while (getline(&buf, &i, q) != -1) {
+ // reserve memory for QueueData
+ Q = (struct QueueData*)realloc(Q, (c + 1) * sizeof(struct QueueData));
+ Q[c].Dir = strcol(buf, ";", 1);
+ Q[c].Name = strcol(buf, ";", 2);
+ Q[c].FileSize = atoi(strcol(buf, ";", 3));
+ Q[c].FileNumbers = atoi(strcol(buf, ";", 4));
+ Q[c].VCodec = strcol(buf, ";", 5);
+ Q[c].BitrateVideo = atoi(strcol(buf, ";", 6));
+ Q[c].MinQuant = atoi(strcol(buf, ";", 7));
+ Q[c].MaxQuant = atoi(strcol(buf, ";", 8));
+ Q[c].CropWidth = atoi(strcol(buf, ";", 9));
+ Q[c].CropHeight = atoi(strcol(buf, ";", 10));
+ Q[c].CropPosX = atoi(strcol(buf, ";", 11));
+ Q[c].CropPosY = atoi(strcol(buf, ";", 12));
+ Q[c].ScaleWidth = atoi(strcol(buf, ";", 13));
+ Q[c].ScaleHeight = atoi(strcol(buf, ";", 14));
+ Q[c].ACodec = strcol(buf, ";", 15);
+ Q[c].BitrateAudio = atoi(strcol(buf, ";", 16));
+ Q[c].AudioID = atoi(strcol(buf, ";", 17));
+ Q[c].PPValues = strcol(buf, ";", 18);
+ Q[c].Rename = atoi(strcol(buf, ";", 19));
+ // migrate from version 0.1.1
+ char *cont = strcol(buf, ";", 20);
+ cont ? Q[c].Container = cont : Q[c].Container = strdup("avi");
+ // migrate from version 0.2.0a
+ char *prev = strcol(buf, ";", 21);
+ prev ? Q[c].Preview = atoi(prev) : Q[c].Preview = 0;
+
+ FREE(buf);
+ c++;
+ }
+
+ fclose(q);
+ } else {dsyslog("[vdrrip] could not open file %s, the queue is probably empty !", QUEUEFILE);}
+
+ NumMovies = c;
+}
+
+
+bool cQueue::Save() {
+ FILE *q;
+ int c;
+ int n = 0;
+
+ if (Locked) {
+ Load();
+ return false;
+ }
+
+ q = fopen(AddDirectory(cPlugin::ConfigDirectory(), QUEUEFILE), "w");
+ if (q) {
+ for (c = 0; c < NumMovies; c++) {
+ if (strcmp(Q[c].Name, "delete") != 0) {
+ fprintf(q,"%s;%s;%i;%i;%s;%i;%i;%i;%i;%i;%i;%i;%i;%i;%s;%i;%i;%s;%i;%s;%i\n",
+ Q[c].Dir, Q[c].Name, Q[c].FileSize, Q[c].FileNumbers, Q[c].VCodec,
+ Q[c].BitrateVideo, Q[c].MinQuant, Q[c].MaxQuant, Q[c].CropWidth,
+ Q[c].CropHeight, Q[c].CropPosX, Q[c].CropPosY, Q[c].ScaleWidth,
+ Q[c].ScaleHeight, Q[c].ACodec, Q[c].BitrateAudio, Q[c].AudioID,
+ Q[c].PPValues, Q[c].Rename, Q[c].Container, Q[c].Preview);
+ n++;
+ }
+ }
+ NumMovies = n;
+
+ fclose(q);
+
+ // delete queuefile if it's empty
+ if (NumMovies < 1) {
+ remove(AddDirectory(cPlugin::ConfigDirectory(), QUEUEFILE));
+ }
+ } else {dsyslog("[vdrrip] could not save %s", QUEUEFILE);}
+
+ Load();
+
+ return true;
+}
+
+bool cQueue::New(struct QueueData *q) {
+ if (Locked) {return false;}
+
+ Q = (struct QueueData*)realloc(Q, ((NumMovies + 1) * sizeof(struct QueueData)));
+ Q[NumMovies] = *q;
+
+ NumMovies++;
+ Save();
+
+ return true;
+}
+
+
+bool cQueue::Del(int i) {
+ if (i >= 0 && i < NumMovies) {
+
+ // don't delete the first entry of the queuefile,
+ // if there is an aktiv encoding
+ if (i == 0 && IsEncoding()) {return false;}
+
+ isyslog("added delete flag on movie %s", Q[i].Name);
+ Q[i].Name = strdup("delete");
+ Save();
+
+ return true;
+ }
+ return false;
+}
+
+bool cQueue::Up(int i) {
+ if (i >= 1 && i < NumMovies) {
+
+ // don't move to the first entry of the queuefile,
+ // if there is an aktiv encoding
+ if (i == 1 && IsEncoding()) return false;
+
+ struct QueueData q;
+ q = Q[i];
+ Q[i] = Q[i-1];
+ Q[i-1] = q;
+ Save();
+
+ return true;
+ }
+ return false;
+}
+
+bool cQueue::Down(int i) {
+ if (i >= 0 && i < NumMovies - 1) {
+
+ // don't move the first entry of the queuefile,
+ // if there is an aktiv encoding
+ if (i == 0 && IsEncoding()) return false;
+
+ struct QueueData q;
+ q = Q[i];
+ Q[i] = Q[i+1];
+ Q[i+1] = q;
+ Save();
+
+ return true;
+ }
+ return false;
+}
+
+bool cQueue::Switch(int i) {
+ if (i >= 0 && i < NumMovies) {
+
+ // don't switch the first entry of the queuefile,
+ // if there is an aktiv encoding
+ if (i == 0 && IsEncoding()) return false;
+
+ (Q[i].Preview == 0) ? Q[i].Preview = 1 : Q[i].Preview = 0;
+ Save();
+
+ return true;
+ }
+ return false;
+}
+
+
+int cQueue::getNumMovies() {return NumMovies;}
+
+struct QueueData* cQueue::getData(int i) {
+ if (i >= 0 && i < NumMovies) {return &Q[i];
+ } else {return NULL;}
+}
+
+char *cQueue::getName(int i) {
+ if (i >= 0 && i < NumMovies) {return Q[i].Name;
+ } else {return NULL;}
+}
+
+char *cQueue::getShortname(int i) {
+ if (i >= 0 && i < NumMovies) {
+ if (strlen(Q[i].Name) > 20) {
+ char *s, *s1;
+ s = strsub(Q[i].Name,1 , 17);
+ asprintf(&s1, "%s...", s);
+ return s1;
+ } else {return Q[i].Name;}
+ } else {return NULL;}
+}
+
+bool cQueue::getLockStat() {return Locked;}
+
+void cQueue::Lock() {
+ FILE *l;
+ l = fopen(AddDirectory(cPlugin::ConfigDirectory(), LOCKFILE), "w");
+ if (l) {
+ fprintf(l,"0");
+ isyslog("[vdrrip] queuefile locked");
+ fclose(l);
+ } else {
+ dsyslog("[vdrrip] could not lock queuefile");
+ }
+}
+
+void cQueue::Unlock() {
+ int r = remove(AddDirectory(cPlugin::ConfigDirectory(), LOCKFILE));
+ if (r == -1) {dsyslog("[vdrrip] could not unlock queuefile");
+ } else {isyslog("[vdrrip] queuefile unlocked");}
+}
+
+void cQueue::WaitUnlock() {
+ FILE *l;
+ int i = 0;
+ bool loop = true;
+
+ while (loop) {
+ l = fopen(AddDirectory(cPlugin::ConfigDirectory(), LOCKFILE), "r");
+ if (l) {
+
+ // check if the content of the lockfile 0
+ int c = fgetc(l);
+ if (c == 48) {
+ loop = false;
+ Locked = false;
+ break;
+ }
+
+ i++;
+ if (i > 2) {
+ loop = false;
+ Locked = true;
+ }
+ isyslog("[vdrrip] %d. try: queuefile is locked by another process", i);
+ sleep(1);
+ fclose(l);
+ } else {
+ isyslog("[vdrrip] queuefile is not locked by another process");
+ loop = false;
+ Locked = false;
+ }
+ }
+}
+
+bool cQueue::IsEncoding() {
+ FILE *e;
+ e = fopen(AddDirectory(cPlugin::ConfigDirectory(), ENCODEFILE), "r");
+ if (! e) return false;
+
+ fclose(e);
+ return true;
+}
+
+char *cQueue::getQueueStat() {
+ char *buf = NULL;
+ size_t i = 0;
+
+ FILE *e = fopen(AddDirectory(cPlugin::ConfigDirectory(), ENCODEFILE), "r");
+ if (e) {
+ if (getline(&buf, &i, e) != -1) {
+ fclose(e);
+ return buf;
+ }
+ }
+ return NULL;
+}
diff --git a/queue.h b/queue.h
new file mode 100755
index 0000000..e819901
--- /dev/null
+++ b/queue.h
@@ -0,0 +1,69 @@
+//
+// queue.h
+//
+
+#ifndef __QUEUE_H
+#define __QUEUE_H
+
+#define QUEUEFILE "queue.vdrrip"
+#define LOCKFILE "lock.vdrrip"
+#define ENCODEFILE "encode.vdrrip"
+
+struct QueueData {
+ const char *Dir;
+ char *Name;
+ int FileSize;
+ int FileNumbers;
+ char *VCodec;
+ int BitrateVideo;
+ int MinQuant;
+ int MaxQuant;
+ int CropWidth;
+ int CropHeight;
+ int CropPosX;
+ int CropPosY;
+ int ScaleWidth;
+ int ScaleHeight;
+ char *ACodec;
+ int BitrateAudio;
+ int AudioID;
+ const char *PPValues;
+ int Rename;
+ char *Container;
+ int Preview;
+};
+
+class cQueue {
+ private:
+ struct QueueData *Q;
+ int NumMovies;
+ bool Locked;
+
+ void Load();
+ void Set(char *s, int c);
+
+ public:
+ cQueue();
+ ~cQueue();
+
+ bool Save();
+ bool New(struct QueueData *q);
+ bool Del(int i);
+ bool Up(int i);
+ bool Down(int i);
+ bool Switch(int i);
+
+ void Lock();
+ void Unlock();
+ void WaitUnlock();
+ bool IsEncoding();
+ char *getQueueStat();
+
+ struct QueueData* getData(int i);
+ char *getName(int i);
+ char *getShortname(int i);
+ int getNumMovies();
+ bool getLockStat();
+};
+
+#endif // __QUEUE_H
diff --git a/scripts/queuehandler.sh b/scripts/queuehandler.sh
new file mode 100755
index 0000000..759b603
--- /dev/null
+++ b/scripts/queuehandler.sh
@@ -0,0 +1,1012 @@
+#!/bin/sh
+
+#################################################################
+# #
+# this scrip handles the queue which is generated from #
+# the vdr-plugin vdrrip. #
+# #
+# usage: queuehandler.sh queuefile tempdir #
+# #
+# #
+# written by herbert attenberger <herbsl@a-land.de> #
+# #
+# 15.07.2003: 0.1.0: - initial version #
+# 24.07.2003: 0.1.1: - added split function #
+# 28.07.2003: 0.1.2: - added video codec "divx4/divx5" #
+# 22.08.2003: 0.1.3: - added vdrecho function #
+# 07.09.2003: 0.1.4: - added (preview) to the output filename #
+# in preview mode #
+# 15.09.2003: 0.1.5: - added -frames 0 to get -identify with #
+# mplayer1.0pre1 working (thx to ronny) #
+# 24.09.2003: 0.1.6: - added (optional) svdrpsend.pl in #
+# function vdrecho #
+# - added dvd-handling #
+# 28.09.2003: 0.1.7: - added handling of postprocess-filters #
+# - added rename function (thx to #
+# memed@www.vdrportal.de) #
+# - copy 001.vdr if a symbolic link couldn't #
+# be created (for fat-partitions) #
+# (thx to memed@www.vdrportal.de) #
+# 30.09.2003: 0.1.8: - added -sws 2 to xvid/divx5 encoding #
+# 25.11.2003: 0.1.9: - moved loop function to read_queue #
+# - added lock, unlock and wait_unlock #
+# functions #
+# - moved encode.vdrrip to the plugins-dir #
+# 14.12.2003: 0.2.0: - added check_exe function #
+# 16.12.2003: 0.2.1: - removed mod_quant from xvid encoding #
+# 20.12.2003: 0.2.2: - moved pp-filters to the last position #
+# - added log_error function to output the #
+# errors to the syslog & stderr #
+# - added log_info function to output the #
+# infos to the syslog & stdout #
+# - added log_debug function to output the #
+# debug-infos infos to the syslog & stdout #
+# 10.01.2004: 0.2.4: - renamed check function to initialize #
+# - added ogg-vorbis, ac3-handling #
+# - added ogm, matroska-handling #
+# - moved configuration to the file #
+# queuehandler.sh.conf #
+# - improved error-handling #
+# - added execute function #
+# - added trap-command & _trap-function #
+# 18.01.2004: 0.2.5: - fixed a bug if scaling is off (thx to #
+# cosmo@www.vdrportal.de) #
+# 21.01.2004: 0.2.6: - added option $useropts #
+# - completed dvd-handling #
+# 13.02.2004: 0.2.7: - changed some if statements to elif #
+# - changed preview-handling #
+# 10.03.2004: 0.2.8: - added calc_steps function #
+# - write status to encode.vdrrip #
+# 22.03.2004: 0.2.9: - moved 2-pass logiles to $tempdir #
+# 26.03.2004: 0.3.0: - added evecho function #
+# - added $mencoder_ac3 & $mplayer_ac3 #
+# - added $qh_ver & qh_conf_ver #
+# #
+#################################################################
+qh_ver="0.3.0"
+
+
+function initialize () {
+#
+# make initial checks
+#
+
+ scriptname=`basename $0`
+ scriptdir=`dirname $0`
+
+ cfgfile="$scriptname.conf"
+
+ if [ -e "$scriptdir/$cfgfile" ]
+ then
+ source "$scriptdir/$cfgfile"
+ else
+ log_error "file $cfgfile not found in $scriptdir, aborting !" 1
+ fi
+
+ if [ "$1" -a "$2" ]
+ then
+ queuefile="$1"
+ tempdir="$2"
+ pluginsdir=`dirname "$queuefile"`
+ else
+ log_error "usage: $scriptname queuefile tempdir" 1
+ fi
+
+ if [ ! -d "$tempdir" ]
+ then
+ log_error "directory $tempdir doesn't exist, aborting !" 1
+ fi
+
+ if [ "$3" ]; then log_info "the option -preview isn't supported anymore"; fi
+
+ local pids=`pgrep -d" " "$scriptname"`
+ local pid1=`echo "$pids" | cut -d" " -f1`
+ local pid2=`echo "$pids" | cut -d" " -f3`
+
+ if [ "$pid1" != "$pid2" ]
+ then
+ log_error "$scriptname is already running with pid $pid1, aborting !" 2
+ fi
+
+ # now the 2-pass logfiles are created in $tempdir ;-)
+ # (because -passlogfile doesn't do its job for xvid)
+ cd "$tempdir"
+}
+
+
+function read_queue () {
+#
+# wait for the queuefile and read the first line
+#
+
+ while [ ! -e "$queuefile" ]
+ do
+ echo
+ echo "waiting for queuefile $queuefile"
+ echo "sleeping $check seconds"
+ echo
+ sleep $check
+ done
+
+ wait_unlock # wait until the queuefile is unlocked
+ lock # locks the queuefile
+
+ local saveifs="$IFS"
+ IFS=";"
+ read dir name filesize filenumbers vcodec br_video min_q max_q \
+ crop_w crop_h crop_x crop_y scale_w scale_h acodec br_audio audio_id \
+ ppvalues rename container preview < "$queuefile"
+ IFS=$saveifs
+
+ # there is an active encoding
+ echo "- reading queuefile..." > "$pluginsdir/encode.vdrrip"
+
+ unlock # unlocks the queuefile
+
+ # correct some data
+ name=`echo "$name" | sed "s/ /_/g"`
+
+ local name_length=`echo "$name" | wc -c`
+ if [ $name_length -gt 20 ]
+ then
+ shortname=`echo "$name" | cut -c 1-17`
+ shortname="$shortname..."
+ else
+ shortname="$name"
+ fi
+
+ if [ "$ppvalues" = "(null)" ]; then ppvalues=""; fi
+
+ dvd=`echo "$dir" | grep "^dvd://"`
+
+ if [ "$preview" = "1" ]
+ then
+ local mode="preview"
+ else
+ local mode="full"
+ fi
+
+ log_info "### start encoding movie $shortname in $mode mode ###"
+
+ log_debug "version of queuehandler.sh: $qh_ver"
+ log_debug "version of queuehandler.sh.conf: $qh_conf_ver"
+ log_debug "dir: $dir"
+ log_debug "name: $name"
+ log_debug "filesize: $filesize"
+ log_debug "filenumbers: $filenumbers"
+ log_debug "vcodec: $vcodec"
+ log_debug "br_video: $br_video"
+ log_debug "min_q: $min_q"
+ log_debug "max_q: $max_q"
+ log_debug "crop_w: $crop_w"
+ log_debug "crop_h: $crop_h"
+ log_debug "crop_x: $crop_x"
+ log_debug "crop_y: $crop_y"
+ log_debug "scale_w: $scale_w"
+ log_debug "scale_h: $scale_h"
+ log_debug "acodec: $acodec"
+ log_debug "br_audio: $br_audio"
+ log_debug "audio_id: $audio_id"
+ log_debug "ppvalues: $ppvalues"
+ log_debug "rename: $rename"
+ log_debug "container: $container"
+ log_debug "preview: $preview"
+}
+
+
+function pre_check () {
+#
+# make some checks before the encoding
+#
+ if [ "$error" ]; then return; fi
+
+ # check mplayer/mencoder
+ if [ ! "$dvd" -a $audio_id -ge 128 ]
+ then
+ # encoding a vdr-recording with selected ac3-stream
+ check_exe "$mencoder_ac3" "mencoder_ac3="
+ check_exe "$mplayer_ac3" "mplayer_ac3="
+ mc=$mencoder_ac3
+ mp=$mplayer_ac3
+ else
+ check_exe "$mencoder" "mencoder="
+ check_exe "$mplayer" "mplayer="
+ mc=$mencoder
+ mp=$mplayer
+ fi
+
+ # check needed tools
+ case "$container" in
+ "avi")
+ if [ "$acodec" = "ogg-vorbis" ]
+ then
+ log_error "ogg-vorbis isn't a valid audio-codec for a avi-container"
+ fi
+ ;;
+ "ogm")
+ check_exe "$vdrsync" "vdrsync="
+ check_exe "$ogmmerge" "ogmmerge="
+
+ if [ "$acodec" = "lame" -o "$acodec" = "ogg-vorbis" ]
+ then
+ check_exe "$ffmpeg" "ffmpeg="
+ fi
+
+ if [ $filenumbers -gt 1 ]
+ then
+ check_exe "$ogmsplit" "ogmsplit="
+ fi
+ ;;
+ "matroska")
+ check_exe "$vdrsync" "vdrsync="
+ check_exe "$mkvmerge" "mkvmerge="
+
+ if [ "$acodec" = "lame" -o "$acodec" = "ogg-vorbis" ]
+ then
+ check_exe "$ffmpeg" "ffmpeg="
+ fi
+ ;;
+ *)
+ log_error "unknown container $container"
+ ;;
+ esac
+}
+
+
+function calc_steps () {
+#
+# calculate the nuber of encoding-steps
+#
+ if [ "$error" ]; then return
+ elif [ "$preview" = "1" ]
+ then
+ if [ "$container" = "avi" ]; then steps="2"
+ else steps="3"; fi
+ return
+ fi
+
+ steps="8"
+
+ if [ "$filenumbers" = "1" ]; then let steps=steps-1; fi
+
+ case "$container" in
+ "avi")
+ let steps=steps-4
+ if [ "$dvd" ]; then let steps=steps-1
+ elif [ ! -e "$dir/002.vdr" ]; then let steps=steps-1; fi
+ ;;
+ "ogm")
+ let steps=steps-2
+ if [ "$acodec" = "copy" -a $audio_id -ge 128 ]
+ then
+ let steps=steps-1
+ fi
+ ;;
+ "matroska")
+ let steps=steps-2
+ if [ "$acodec" = "copy" ]; then let steps=steps-1; fi
+ ;;
+ *)
+ ;;
+ esac
+}
+
+
+function preview () {
+#
+# get the preview values
+#
+ if [ "$error" ]; then return
+ elif [ "$preview" != "1" ]; then return; fi
+
+ name="$name(preview)"
+ shortname="$shortname(preview)"
+
+ # start the preview in the middle of the movie
+ local length=`"$mp" -identify -frames 0 "$dir/001.vdr" 2>/dev/null | grep ID_LENGTH | cut -d"=" -f2`
+ let local ss=length/2
+ previewval="-ss $ss -endpos $previewlength"
+}
+
+
+function prepare() {
+#
+# prepares the encoding-process
+#
+ if [ "$error" ]; then return
+ elif [ "$dvd" ]; then return; fi
+
+ case "$container" in
+ "avi")
+ # join all vdr-files to $tempdir/temp.vdr
+ if [ -e "$dir/002.vdr" -a "$preview" != "1" ]
+ then
+ log_info "joining all vdr-files from directory $dir"
+ evecho "joining vdr-files"
+ nice -+19 cat $dir/[0-9][0-9][0-9].vdr > "$tempdir/temp.vdr"
+ else
+ create_symbolic_link
+ fi
+ ;;
+ "ogm"|"matroska")
+ # demux vdr-recording with vdrsync
+ if [ "$preview" = "1" ]
+ then
+ create_symbolic_link
+ else
+ log_info "demuxing all vdr-files from directory $dir"
+ evecho "demuxing vdr-files"
+ execute "$vdrsync $dir -o $tempdir"
+ fi
+ ;;
+ *)
+ ;;
+ esac
+}
+
+
+function create_symbolic_link() {
+#
+# creates a symbolic link of 001.vdr to $temdir/temp.vdr
+#
+ if [ "$error" ]; then return
+ elif [ "$dvd" ]; then return; fi
+
+ log_info "create a symbolic link from $dir/001.vdr to $tempdir/temp.vdr"
+ ln -s "$dir/001.vdr" "$tempdir/temp.vdr"
+
+ if [ ! -e "$tempdir/temp.vdr" ]
+ then
+ log_info "could not create a symolic link"
+ log_info "try to copy $dir/001.vdr to $tempdir/temp.vdr"
+ execute "cp $dir/001.vdr $tempdir/temp.vdr"
+ fi
+}
+
+
+function check_exe () {
+#
+# checks if $1 is a executable and exit the queuehandler with
+# rc $3, if this one is set
+#
+ if [ ! -x "$1" ]
+ then
+ if [ "$1" ]; then log_error "$1 isn't a executable"; fi
+ log_error "set a valid path for $2 in the file $scriptdir/$cfgfile." $3
+ fi
+}
+
+
+function encode () {
+#
+# encodes the movie
+#
+ if [ "$error" ]; then return; fi
+
+ # set mencoder audio values
+ case "$container" in
+ "avi")
+ case "$acodec" in
+ "lame")
+ if [ "$dvd" ]
+ then
+ local aopts="-oac mp3lame -lameopts br=$br_audio:abr:q=2:vol=8 -aid $audio_id"
+ else
+ local aopts="-oac mp3lame -lameopts br=$br_audio:abr:q=2 -aid $audio_id"
+ fi
+ ;;
+ "copy")
+ local aopts="-oac copy -aid $audio_id"
+ ;;
+ "ogg-vorbis")
+ # this shouldn't happen
+ ;;
+ *)
+ log_error "unknown audio codec $acodec"
+ ;;
+ esac
+ ;;
+ "ogm")
+ local aopts="-nosound"
+ case "$acodec" in
+ "lame"|"ogg-vorbis")
+ if [ "$dvd" ]; then dump_audio_mplayer; fi
+ encode_ffmpeg
+ ;;
+ "copy")
+ # convert mp2-files to ac3, because
+ # mp2 isn't supported by ogm
+ if [ "$dvd" ]; then dump_audio_mplayer; fi
+ if [ $audio_id -lt 128 ]; then encode_ffmpeg; fi
+ ;;
+ *)
+ log_error "unknown audio codec $acodec"
+ ;;
+ esac
+ ;;
+ "matroska")
+ local aopts="-nosound"
+ case "$acodec" in
+ "lame"|"ogg-vorbis")
+ if [ "$dvd" ]; then dump_audio_mplayer; fi
+ encode_ffmpeg
+ ;;
+ "copy")
+ if [ "$dvd" ]; then dump_audio_mplayer; fi
+ ;;
+ *)
+ log_error "unknown audio codec $acodec"
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+
+ # set mencoder -vop values
+ if [ "$crop_w" = "-1" -a "$crop_h" = "-1" -a "$crop_x" = "-1" -a \
+ "$crop_y" = "-1" -a "$scale_w" = "-1" -a "$scale_h" = "-1" ]
+ then
+ local vopopts=""
+ elif [ "$crop_w" = "-1" -a "$crop_h" = "-1" -a "$crop_x" = "-1" -a \
+ "$crop_y" = "-1" ]
+ then
+ local vopopts="scale=$scale_w:$scale_h"
+ else
+ local vopopts="scale=$scale_w:$scale_h,crop=$crop_w:$crop_h:$crop_x:$crop_y"
+ fi
+
+ if [ "$ppvalues" ]
+ then
+ local vopopts="-vop pp=$ppvalues,$vopopts"
+ elif [ "$vopopts" ]
+ then
+ local vopopts="-vop $vopopts"
+ fi
+
+ # encode in two passes
+ for pass in 1 2
+ do
+ if [ "$pass" = "1" ]
+ then
+ local ofile="-o /dev/null"
+ else
+ local ofile="-o $tempdir/$name.avi"
+ fi
+
+ # set mencoder video values
+ case "$vcodec" in
+ "lavc")
+ local vopts="-ovc lavc -lavcopts vcodec=mpeg4:vhq:vbitrate=$br_video:vqmin=$min_q:vqmax=$max_q:vpass=$pass -sws 2"
+ ;;
+ "xvid")
+ local vopts="-ovc xvid -xvidencopts bitrate=$br_video:me_quality=6:pass=$pass -sws 2"
+ ;;
+ "divx4")
+ local vopts="-ovc divx4 -divx4opts br=$br_video:q=5:min_quant=$min_q:max_quant=$max_q:pass=$pass -sws 2"
+ ;;
+ *)
+ log_error "unknown video codec $vcodec"
+ ;;
+ esac
+
+ # set mencoder input file
+ if [ "$dvd" ]
+ then
+ # dvd
+ local ifile="$dvd"
+ elif [ "$container" = "avi" -o "$preview" = "1" ]
+ then
+ # no dvd, avi container
+ local ifile="$tempdir/temp.vdr"
+ else
+ # no dvd, ogm/matroska container
+
+ # search for the first video-file
+ local num=0
+ while [ ! "$ifile" ]
+ do
+ if [ ! -e "$tempdir/e$num.mpv" ]
+ then
+ log_info "video-file $tempdir/e$num.mpv not found !"
+ if [ $num -ge 9 ]
+ then
+ log_error "no video-stream found !"
+ # exit loop
+ local ifile="dummy"
+ fi
+ let num=num+1
+ else
+ log_info "video-file $tempdir/e$num.mpv found !"
+ local ifile="$tempdir/e$num.mpv"
+ fi
+ done
+ fi
+
+ if [ "$error" ]; then return; fi
+
+ log_info "encoding movie $shortname (pass: $pass)"
+
+ if [ "$aopts" = "-nosound" ]
+ then
+ local encstr="video"
+ else
+ local encstr="video & audio"
+ fi
+
+ evecho "enc. $encstr ($pass. pass)"
+ if [ "$useropts" ]; then log_info "\$useropts are set to \"$useropts\""; fi
+ execute "$mc $ifile $ofile $useropts $vopts $vopopts $aopts $previewval"
+ done
+}
+
+
+function dump_audio_mplayer() {
+#
+# dump audio-stream from dvd with mplayer
+#
+ if [ "$error" ]; then return
+ elif [ "$preview" = "1" ]; then return
+ elif [ ! "$dvd" ]; then return; fi
+
+ log_info "dumping audio-stream $audio_id from $dvd with $mp"
+ evecho "dumping audio-stream from dvd"
+ execute "$mp $dir -vo null -vc dummy -aid $audio_id -aop list=volnorm -dumpaudio -dumpfile $tempdir/bd.ac3"
+}
+
+
+function encode_ffmpeg() {
+#
+# encode the audio-stream with ffmpeg
+#
+ if [ "$error" ]; then return
+ elif [ "$preview" = "1" ]; then return; fi
+
+ if [ $audio_id -ge 128 ]
+ then
+ local ifile="$tempdir/bd.ac3"
+ else
+ local ifile="$tempdir/c$audio_id.mpa"
+ local forceinput="-f mp3"
+ fi
+
+ case "$acodec" in
+ "lame")
+ local filetype="mp3"
+ ;;
+ "ogg-vorbis")
+ local filetype="ogg"
+ ;;
+ "copy")
+ log_info "ogm doesn't support mp2 audio-streams, i will convert it into ac3"
+ local filetype="ac3"
+ ;;
+ *)
+ ;;
+ esac
+
+ log_info "converting $ifile into $filetype-format"
+ evecho "conv. audio into $filetype-format"
+ execute "$ffmpeg -hq -y $forceinput -i $ifile -ab $br_audio $tempdir/c$audio_id.$filetype"
+}
+
+
+function merge_ogm_mkv() {
+ if [ "$error" ]; then return; fi
+ if [ "$container" != "ogm" -a "$container" != "matroska" ]; then return; fi
+
+
+ case "$container" in
+ "ogm")
+ local merge="$ogmmerge"
+ local filetype="ogm"
+ ;;
+ "matroska")
+ local merge="$mkvmerge"
+ local filetype="mkv"
+ ;;
+ *)
+ ;;
+ esac
+
+
+ if [ "$preview" != "1" ]
+ then
+ case "$acodec" in
+ "lame")
+ local afile="$tempdir/c$audio_id.mp3"
+ ;;
+ "ogg-vorbis")
+ local afile="$tempdir/c$audio_id.ogg"
+ ;;
+ "copy")
+ if [ $audio_id -ge 128 ]
+ then
+ # ac3
+ local afile="$tempdir/bd.ac3"
+ elif [ "$container" = "ogm" ]
+ then
+ # mpg2, container ogm
+ local afile="$tempdir/c$audio_id.ac3"
+ else
+ # mpg2
+ local afile="$tempdir/c$audio_id.mpa"
+ fi
+ ;;
+ *)
+ ;;
+ esac
+ fi
+
+ log_info "merging movie $shortname into $filetype-container"
+ evecho "merging into $filetype-container"
+ execute "$merge -o $tempdir/$name.$filetype $tempdir/$name.avi $afile"
+}
+
+
+function cleanup () {
+#
+# delete temp-files and reset variables
+#
+ # temp. codec-files
+ rm -f "$tempdir/divx2pass.log"
+ rm -f "$tempdir/lavc_stats.txt"
+ rm -f "$tempdir/analyse.log"
+ rm -f "$tempdir/c:\\trace_b.txt"
+ rm -f "$tempdir/xvid-twopass.stats"
+
+ # temp. movie-files
+ rm -f "$tempdir/temp.vdr"
+ if [ "$container" = "ogm" -o "$container" = "matroska" ]
+ then
+ rm -f "$tempdir/$name.avi"
+ fi
+ rm -f "$tempdir"/e[0-9].mpv
+ rm -f "$tempdir"/c[0-9].mpa
+ rm -f "$tempdir"/c[0-9].mp3
+ rm -f "$tempdir"/c[0-9].ogg
+ rm -f "$tempdir"/c[0-9].ac3
+ rm -f "$tempdir"/c[0-9][0-9][0-9].mp3
+ rm -f "$tempdir"/c[0-9][0-9][0-9].ogg
+ rm -f "$tempdir"/bd.ac3
+
+ # temp. queuehandler-files
+ rm -f "$pluginsdir/encode.vdrrip"
+ rm -f /tmp/queuehandler.err
+
+
+ # reset variables
+ dir=""
+ name=""
+ filesize=""
+ filenumbers=""
+ vcodec=""
+ br_video=""
+ min_q=""
+ max_q=""
+ crop_w=""
+ crop_h=""
+ crop_x=""
+ crop_y=""
+ scale_w=""
+ scale_h=""
+ acodec=""
+ br_audio=""
+ audio_id=""
+ ppvalues=""
+ rename=""
+ container=""
+ preview=""
+
+ mc=""
+ mp=""
+
+ dvd=""
+ previewval=""
+ error=""
+
+ step="0"
+}
+
+
+function del_queue () {
+#
+# delete first line from the queuefile
+#
+ # waits until the queuefile is unlocked, and locks it
+ wait_unlock
+ lock
+
+ if [ "$error" ]
+ then
+ head -n 1 "$queuefile" >> "$queuefile.rejected"
+ fi
+
+ # delete first entry of the queuefile
+ local lines=`cat "$queuefile" | wc -l`
+ if [ "$lines" -le 1 ]
+ then
+ rm -f "$queuefile"
+ else
+ let lines=lines-1
+ tail -n $lines "$queuefile" > /tmp/queuefile.tmp
+ mv /tmp/queuefile.tmp $queuefile
+ fi
+
+ if [ "$error" ]
+ then
+ log_info "### moved movie $shortname to $queuefile.rejected ###"
+ else
+ log_info "### movie $shortname deleted from queuefile ###"
+ fi
+
+ # unlock queuefile
+ unlock
+}
+
+
+function split () {
+#
+# splits the encoded movie into $filenumbers pieces
+#
+ if [ "$error" ]; then return
+ elif [ "$filenumbers" = "1" -o "$preview" = "1" ]; then return; fi
+
+ log_info "splitting $shortname in $filenumbers pieces"
+ evecho "splitting movie"
+
+ case "$container" in
+ "avi")
+ local overlap=3
+
+ local count=1
+ local splitpos=0
+
+ # workaround to get the correct filesize from mencoder with -endpos
+ let local splitsize=filesize*99/100
+
+ log_info "splitting $shortname in $filenumbers pieces"
+ while [ $count -le $filenumbers ]
+ do
+ local ofile="$name-$count.avi"
+
+ if [ $count -eq $filenumbers ]
+ then
+ local endpos=""
+ else
+ local endpos="-endpos ${splitsize}mb"
+ fi
+
+ # split file
+ execute "$mc -ovc copy -oac copy $tempdir/$name.avi \
+ -ss $splitpos $endpos -o $tempdir/$ofile"
+
+ # detect length of splitted file and add it to $splitpos
+ local length=`$mplayer -identify -frames 0 $tempdir/$ofile 2>/dev/null | \
+ grep ID_LENGTH | cut -d= -f2`
+ let splitpos=splitpos+length-overlap
+ let count=count+1
+ done
+ ;;
+ "ogm")
+ execute "$ogmsplit -s $filesize -n $filenumbers $tempdir/$name.ogm"
+ ;;
+ "matroska")
+ execute "$mkvmerge --split d${filesize}m --split-max-files \
+ $filenumbers -o $tempdir/$ofile"
+ ;;
+ *)
+ ;;
+ esac
+}
+
+
+function vdrecho () {
+#
+# echo $1 in the vdr-infobar (or console)
+#
+
+ if [ -x "$svdrpsend" ]
+ then
+ $svdrpsend -d "$vdrhostname" "MESG $1" 2>/dev/null 1>/dev/null
+ elif [ -x "$netcat" ]
+ then
+ echo "MESG $1" | $netcat -q 1 "$vdrhostname" 2001 2>/dev/null 1>/dev/null
+ else
+ log_info "$1"
+ fi
+}
+
+
+function evecho () {
+#
+# echo $ in the file encode.vdrrip
+#
+ let step=step+1
+ local time=`date +"%k:%M h"`
+ echo "- step $step/$steps (since $time): $1" > "$pluginsdir/encode.vdrrip"
+}
+
+
+function log_error () {
+#
+# echo $1 on stderr and write it to the syslog with priority user.error
+#
+ logger -s -p user.error -t [vdrrip-qh] "$1"
+
+ if [ "$2" ]
+ then
+ vdrecho "$1"
+ exit "$2"
+ else
+ error="1"
+ fi
+}
+
+
+function log_info () {
+#
+# echo $1 on stdout and write it to the syslog with priority user.info
+#
+ logger -s -p user.info -t [vdrrip-qh] "$1" 2>&1
+}
+
+
+function log_debug () {
+#
+# echo $1 on stdout and write it to the syslog with priority user.debug
+#
+ if [ "$debug" = "1" ]
+ then
+ logger -s -p user.debug -t [vdrrip-qh] "$1"
+ fi
+}
+
+
+function execute () {
+#
+# executes $1 and checks the rc
+#
+ local cmd="$1"
+
+ log_debug "execute command: $cmd"
+
+ # execute $cmd and save the return-code:
+ if [ "$stdout" = "1" ]
+ then
+ nice -+19 $cmd 2>/tmp/queuehandler.err
+ local rc="$?"
+ else
+ nice -+19 $cmd 1>/dev/null 2>/tmp/queuehandler.err
+ local rc="$?"
+ fi
+
+ if [ "$rc" != "0" ]
+ then
+ # display stderr if the return-code isn't 0
+ log_error "an error occured (rc $rc) while processing the command: $cmd"
+ local err_message=`cat /tmp/queuehandler.err 2>/dev/null`
+ if [ "$err_message" ]
+ then
+ log_error "error message: $err_message"
+ fi
+ elif [ "$debug" = "1" ]
+ then
+ # display stderr if the debug-mode is set
+ local dbg_message=`cat /tmp/queuehandler.err 2>/dev/null`
+ if [ "$dbg_message" ]
+ then
+ log_debug "debug message: $dbg_message"
+ fi
+ fi
+}
+
+
+function rename () {
+#
+# renames the vdr recording to indicate it was encoded properly
+# this function is written by memed@www.vdrportal.de
+#
+ if [ "$error" ]; then return
+ elif [ "$dvd" ]; then return
+ elif [ "$preview" = "1" ]; then return
+ elif [ "$rename" = "0" ]; then return; fi
+
+ new_dir="$(dirname $dir)${append_string}"
+ mkdir -p "$new_dir"
+ #move finished subdir to new folder
+ mv "$dir" "$new_dir"
+ #if all subdirs are empty, also delete dir one up
+ [ $(find $(dirname $dir) -type f|wc -l) -eq 0 ] && rm -rf $(dirname $dir)
+}
+
+
+function wait_unlock () {
+#
+# wait until the queuefile is unlocked
+#
+ local lockstat
+ read lockstat 2>/dev/null < "$pluginsdir/lock.vdrrip"
+
+ while [ -e "$pluginsdir/lock.vdrrip" -a "$lockstat" != "1" ]
+ do
+ echo
+ echo "queuefile is locked !"
+ echo "sleeping $lock seconds"
+ echo
+ sleep $lock
+ done
+}
+
+
+function lock () {
+#
+# locks the queuefile
+#
+ local lockfile="$pluginsdir/lock.vdrrip"
+ echo 1 > $lockfile 2>/dev/null
+
+ if [ ! -e "$lockfile" ]
+ then
+ log_error "couldn't write to $lockfile" 1
+ fi
+}
+
+
+function unlock () {
+#
+# unlocks the queuefile
+#
+ rm -f $pluginsdir/lock.vdrrip
+
+ if [ -e "$lockfile" ]
+ then
+ log_error "couldn't delete $lockfile" 1
+ fi
+}
+
+function _trap () {
+#
+# this function is called if the queuehandler is killed
+#
+ if [ "$debug" = "0" ]; then cleanup; fi
+ log_error "queuehandler was killed !"
+ vdrecho "queuehandler was killed !"
+}
+
+
+#
+# this is the main part
+#
+
+trap "_trap; exit" 2 9 15
+
+initialize "$1" "$2" "$3" # make initial checks
+cleanup # delete old temp-files
+
+while [ true ]
+do
+ read_queue # read the first line from the queuefile
+ pre_check # make some checks before the encoding
+ calc_steps # calc the number of encoding-steps
+ preview # get the preview values
+ prepare # prepares the encoding
+ encode # encodes the movie
+ merge_ogm_mkv # merge ogm/mkv-files
+ split # splits the encoded movie
+
+ if [ ! "$error" ]
+ then
+ mess="movie $shortname encoded"
+ log_info "$mess"
+ vdrecho "$mess"
+ else
+ mess="couldn't encode movie $shortname"
+ log_info "$mess"
+ vdrecho "$mess"
+ fi
+
+ rename # rename dir-name of the vdr-recording
+ del_queue # delete first line from the queuefile
+ cleanup # delete temp-files
+done
diff --git a/scripts/queuehandler.sh.conf b/scripts/queuehandler.sh.conf
new file mode 100755
index 0000000..37fed90
--- /dev/null
+++ b/scripts/queuehandler.sh.conf
@@ -0,0 +1,71 @@
+#
+# queuehandler.sh.conf:
+# this is the configuration-file of queuehandler.sh
+#
+ qh_conf_ver="0.3.0"
+
+ # set this to 1 to get debug-informations in the syslog and
+ # exit-messages of the queuehandler on the osd:
+ debug=0
+
+ # set this to 1 to see stdout while the queuehandler is executing an
+ # external programm
+ stdout=0
+
+ # resulting length (in seconds) of movies if the queuehandler is
+ # started in the preview-mode
+ previewlength=60
+
+ # check for new entries in queuefile (in seconds)
+ check=30
+
+ # check for unlocked queuefile (in seconds)
+ lock=5
+
+
+
+ # if you have set the setup-option "rename after encodings"
+ # to yes, this string will be appended to the recording-name
+ # after the movie is encoded.
+ append_string="_-_CONVERTED"
+
+
+
+ # this pathes are used for the encoding of vdr-recordings & dvd's.
+ # they _must_ point to an unpatched mencoder & mplayer
+ mencoder="/usr/local/bin/mencoder"
+ mplayer="/usr/local/bin/mplayer"
+
+ # this pathes are only used for encoding a vdr-recording with
+ # selected ac3-stream.
+ # they _must_ point to an ac3-patched mencoder & mplayer.
+ # if you don't use this feature you should deactivate the option
+ # AC3 Support (MPlayer-patch inst.) in the plugins setup-menu.
+ mencoder_ac3="/usr/local/bin/mencoder_ac3"
+ mplayer_ac3="/usr/local/bin/mplayer_ac3"
+
+
+ # this string is added to the mencoder-command in the
+ # queuehandler
+ useropts=""
+
+
+
+ # optional tools (only needed for ogm/matroska-container)
+ vdrsync="/usr/local/bin/vdrsync.pl"
+ ffmpeg="/usr/local/bin/ffmpeg"
+ ogmmerge="/usr/local/bin/ogmmerge"
+ ogmsplit="/usr/local/bin/ogmsplit"
+ mkvmerge="/usr/local/bin/mkvmerge"
+
+
+
+ # This (optional) command is used to display some informations
+ # from the queuehandler on your tv.
+ # You have to specify only $svdrpsend or $netcat.
+ # $netcat is only recommend, if perl isn't installed.
+ svdrpsend="/usr/local/bin/svdrpsend.pl"
+ #netcat=""
+
+ vdrhostname="localhost"
+
diff --git a/scripts/sleephalt.sh b/scripts/sleephalt.sh
new file mode 100755
index 0000000..d154160
--- /dev/null
+++ b/scripts/sleephalt.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+#
+# This script is called by vdrshutdown.sh
+#
+# It is written by herbert attenberger <herbsl@a-land.de>
+#
+
+#
+# initial definitions
+#
+
+pgrep="/usr/bin/pgrep"
+nvramwakeup="/usr/local/bin/nvram-wakeup"
+netcat="/usr/bin/netcat"
+
+pluginsdir="/etc/vdrtmpfs/plugins"
+
+scriptname=`basename $0`
+
+# reboot needed for nvram-wakeup (yes/no) ?
+nvramreboot="yes"
+
+
+vdrecho () {
+#
+# echo $1 in the vdr-infobar (or console)
+#
+
+if [ -x "$netcat" ]
+then
+ echo "MESG $1" | $netcat -q 1 localhost 2001
+else
+ echo $1
+fi
+
+}
+
+#
+# this is the main part
+#
+
+if [ -e "$pluginsdir/encode.vdrrip" ]
+then
+ # check, if there is already an active shutdown-procedure:
+ pids=`"$pgrep" -d" " "$scriptname"`
+ pid1=`echo "$pids" | cut -d" " -f1`
+ pid2=`echo "$pids" | cut -d" " -f3`
+
+ if [ "$pid1" != "$pid2" ]
+ then
+ vdrecho "a shutdown-procedure is already active"
+ exit
+ else
+ vdrecho "shutdown after vdrrip-encoding is finished"
+ while [ -e "$pluginsdir/encode.vdrrip" ]
+ do
+ sleep 60
+ done
+
+ # shutdown vdr with the power-key and exit the script
+ echo "HITK Power" | $netcat -q 1 localhost 2001
+ exit
+ fi
+else
+ if [ -x "$nvramwakeup" -a "$1" != "0" ]
+ then
+ if [ "$nvramreboot" = "yes" ]
+ then
+ # shutdown with reboot
+ $nvramwakeup -ls $1
+ lilo -R PowerOff
+ reboot
+ else
+ # shutdown without reboot
+ $nvramwakeup -ls $1
+ halt
+ fi
+ else
+ # shutdown without nvram-wakeup
+ halt
+ fi
+fi
diff --git a/scripts/vdrshutdown.sh b/scripts/vdrshutdown.sh
new file mode 100755
index 0000000..e63e2ac
--- /dev/null
+++ b/scripts/vdrshutdown.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+#
+# This script executes the script $sleephalt in the backgroud
+# an gives the control back to vdr
+#
+# $sleephalt handles the shutdown with or without nvram-wakeup
+# and waits until <plugins-dir>/encode.vdrrip is deleted
+#
+# It is written by herbert attenberger <herbsl@a-land.de>
+#
+
+sleephalt="/usr/local/bin/sleephalt.sh"
+
+if [ -x $sleephalt ]
+then
+ $sleephalt $1 &
+else
+ echo
+ echo "script $sleephalt not found"
+ echo
+fi
+
+exit
diff --git a/scripts/vdrsync.pl b/scripts/vdrsync.pl
new file mode 100755
index 0000000..bae489e
--- /dev/null
+++ b/scripts/vdrsync.pl
@@ -0,0 +1,2806 @@
+#!/usr/bin/perl
+
+#
+# vdrsync (c) 2003 by Dr. Peter Sebbel, a perl script to demux VDR recordings and
+# correcting for missing/additional Audio frames to ensure sync of audio and
+# video streams. Contact: peter@vdr-portal.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License
+#
+# 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
+
+
+
+use strict;
+use warnings;
+
+
+
+my $debug = 0;
+my $path_param = "./";
+my @parameter_list = @ARGV;
+my $tcmplex = "";
+my $tcmplex_panteltje= "";
+my $panteltje = 0; #uses tcmplex-panteltje instead of tcmplex
+my $mplex = 0;
+my $mpeg2 = 0;
+my $transcode = 0;
+my $info = 0;
+my $remuxfilename = "";
+my @ignore_streams;
+my $dump_packets = 0;
+my $dump_payload = 0;
+my $stop_flag = 0;
+my $audio_only = 0;
+my $script_output = 0;
+my $divx = 0;
+my $divxac3 = 0;
+my $divx_param = " -V -y divx4 -w 1000 "; #enter additional parameters for divx here
+my $divx_ac3_param = " -V -y divx4 -b 256 -w 1000 "; #enter additional parameters for divx with ac3 sound here
+my $master_dvd = 0;
+my $master_dvd_param = "-c 0,10:00,20:00,30:00,40:00,50:00,01:00:00,01:10:00,01:20:00,01:30:00,01:40:00,01:50:00,02:00:00,02:10:00,02:20:00,02:30:00,02:40:00,02:50:00,03:00:00";
+my $show_drift = 0;
+my $postexec = 0;
+my $dump_buffer = 0;
+my $mkiso = 0;
+
+
+$|=1; # prevent line buffering
+if (-e "/usr/bin/tcmplex") {
+ $tcmplex = "/usr/bin/tcmplex";
+}
+elsif (-e "/usr/local/bin/tcmplex") {
+ $tcmplex = "/usr/local/bin/tcmplex";
+}
+if (-e "/vdr/bin/tcmplex-panteltje"){
+ $tcmplex_panteltje = "/vdr/bin/tcmplex-panteltje";
+}
+elsif (-e "/usr/local/bin/tcmplex-panteltje") {
+ $tcmplex_panteltje = "/usr/local/bin/tcmplex-panteltje";
+}
+elsif (-e "/usr/bin/tcmplex-panteltje") {
+ $tcmplex_panteltje = "/usr/bin/tcmplex-panteltje";
+}
+
+if (-e "/usr/bin/transcode") {
+ $transcode = "/usr/bin/transcode";
+}
+elsif (-e "/usr/local/bin/transcode") {
+ $transcode = "/usr/local/bin/transcode";
+}
+
+
+sub parse_parameters {
+ my $parameter = shift;
+ if ($parameter eq "-d") {
+ $debug = 1;
+ }
+ elsif ($parameter eq "-o") {
+ $path_param = shift @parameter_list;
+ if (!($path_param =~ /\/$/)) {
+ $path_param .= "/";
+ }
+ }
+ elsif ($parameter eq "-m") {
+ $mplex = 1;
+ if ($parameter_list[0] && ($parameter_list[0] eq "panteltje")){
+ $panteltje = (shift @parameter_list);
+ }
+ }
+ elsif ($parameter eq "-mpeg2") {
+ $mpeg2 = 1;
+ $master_dvd = 0;
+ $mplex = 1;
+ $mkiso = 0;
+ }
+ elsif ($parameter eq "-i") {
+ $info = 1;
+ }
+ elsif ($parameter eq "-ignore") {
+ @ignore_streams = split /,/,(shift @parameter_list);
+ }
+ elsif ($parameter eq "-dump-packets"){
+ $dump_packets = (shift @parameter_list);
+ }
+ elsif ($parameter eq "-show-time-drift"){
+ $show_drift = 1;
+ }
+ elsif ($parameter eq "-dump-buffer-on-error"){
+ $dump_buffer = 1;
+ }
+ elsif ($parameter eq "-dump-payload"){
+ $dump_payload = (shift @parameter_list);
+ }
+ elsif ($parameter eq "-audio-only") {
+ $audio_only = 1;
+ }
+ elsif ($parameter eq "-script-output") {
+ $script_output = 1;
+ }
+ elsif ($parameter eq "-divx") {
+ $divx = 1;
+ if ($parameter_list[0] eq "ac3"){
+ $divxac3 = (shift @parameter_list);
+ }
+ }
+ elsif ($parameter eq "-master-dvd"){
+ $master_dvd = 1;
+ $mplex = 1;
+ if ( ! $parameter_list[0] =~/^-/ ){
+ $master_dvd_param = (shift @parameter_list);
+ }
+ }
+ elsif ($parameter eq "-mkiso"){
+ $mkiso = 1;
+ $mplex = 1;
+ $master_dvd = 1;
+ }
+ elsif ($parameter eq "-postexec"){
+ $postexec = (shift @parameter_list);
+ }
+ else {
+ print "Unknown parameter $parameter\n";
+ exit;
+ }
+}
+
+my @files;
+if (scalar(@ARGV) == 0)
+ {
+ print "\nVDRsync Version 0.1.2.2\n";
+ print "\nUsage: vdrsync.pl /path/to/vdr/recording/\n";
+ print "or : vdrsync.pl vdr-file1 .... vdr-fileN\n\n";
+ print "Optional -d print strange debug messages\n";
+ print "Optional -o output_dir sets the directory where the result files\n";
+ print " are written to\n";
+ print "Optional -m tries to multiplex the demuxed streams into a dvd compatible\n";
+ print " stream (uses tcmplex)\n";
+ print "Optional -m panteltje uses tcmplex-panteltje instead of tcmplex\n";
+ print "Optional -i just tries to analyse the .vdr file and exits. -m is ignored\n";
+ print "Optional -ingore stream1[,stream2]... tells the script to ignore stream1..n \n";
+ print " Useful for deliberately omitting streams (like AC3) or if you have \n";
+ print " trouble with one stream\n";
+ print "Optional -divx tries to transcode the demuxed streams into a divx movie\n";
+ print " For DIVX with AC3 (if present in the recording) type -divx ac3\n";
+ print " (uses transcode, adjust transcode settings at the beginning of\n";
+ print " vdrsync.pl)\n";
+ print "Optional -dump-packets NNNN tells the script to dump the first NNNN\n";
+ print " full PES-packets (in file STREAM_ID.pes_dump) Useful for debugging \n";
+ print " (if you want to extract a stream that does not work and mail it to me)\n";
+ print "Optional -dump-payload NNNN tells the script to dump the raw payload of the \n";
+ print " first NNNN PES-packets (in file STREAM_ID.dump) Useful for debugging\n";
+ print " (if you want to extract a stream-payload that does not work and \n";
+ print " test it with other tools)\n";
+ print "Optional -postexec executes the command specified after finishing\n";
+ #print " some Dummy variables like VSlength are replaced by actual values \n";
+ print "Optional -master-dvd creates a DVD structure in a subdirectory of outputpath\n";
+ print "Optional -audio-only discards all video streams and just writes audio\n";
+ print "Optional -script-output writes a special output format about the movie at\n";
+ print " the end of the vdrsync run. Useful for scripting, contains corrected \n";
+ print " info about the streams\n";
+ print "Optional -show-time-drift prints information about the difference between\n";
+ print " timestamps and actual video / audio data found in the recording\n";
+ print "Optional -dump-debug-buffer in case of a problem with one of the streams 3 MB\n";
+ print " of the recording are dumped to the file debug.buffer\n";
+ print "Optional -mkiso creates an ISO Image suitable for burning a DVD\n";
+ print "Optional -mpeg2 creates a generic MPEG2 File (tcmplex -m 2)\n";
+ exit;
+ }
+
+
+while (my $param = shift(@parameter_list)) { # check whether all files hat we got as parameters exist
+ print "Got parameter $param\n";
+ if ($param =~ /^-/) {parse_parameters($param); next}
+ if (-d $param) {
+ print "got a directory on the command line\n";
+ my @dir_files = @{ get_file_list($param) };
+ foreach (@dir_files) {
+ push @files, "$param/$_";
+ }
+ next;
+ }
+ push @files, $param;
+}
+
+print "Output files will be stored in $path_param\n" if $debug;
+
+if (!(-e $path_param)) {print "Output Directory $path_param does not exist\n"; exit 1}
+
+
+
+print "Found " . (scalar(@ignore_streams)) ." to ignore\n" if $debug;
+
+my %ignore_hash;
+foreach (@ignore_streams) {
+ $ignore_hash{$_} = 1;
+}
+
+
+my $PES_Obj = MPEGSTREAM->new
+ (
+ streamcode =>"PES_stream",
+ debug =>$debug,
+ outputpath =>$path_param,
+ files =>\@files,
+ ignore_streams => \%ignore_hash,
+ dump_packets => $dump_packets,
+ dump_payload => $dump_payload,
+ audio_only => $audio_only,
+ show_drift => $show_drift,
+ script_output => $script_output,
+ dump_buffer => $dump_buffer,
+ );
+
+if (!($PES_Obj)) {
+ print "could not create the PES Stream Obj\n";
+ exit 1;
+}
+if ($info) {
+ $PES_Obj->print_stats();
+ exit;
+}
+
+
+$PES_Obj->process_PES_packets();
+
+
+if ((!$mplex) && (!$divx ) && (! $postexec) && (! $master_dvd)) {exit}
+
+my @filestomux = @{$PES_Obj->output_files()};
+
+print "Got " . scalar(@filestomux) ." files back\n" if $debug;
+
+my @basename_list;
+foreach (@filestomux) {
+ my $base_name = (split /\//,$_)[-1];
+ $base_name =~ s/\.//;
+ push @basename_list, $base_name;
+}
+
+if ($divx == 1) {
+ if (scalar(@filestomux) < 2) {print "Need at least two streams for multiplexing\n";exit}
+ if (($filestomux[1] =~ /.ac3$/) && ($divxac3)) {
+ #transcode -i e0.mpv -A -N 0x2000 -p bd.ac3 -y divx4 -o test.avi
+ my $command = "nice -19 $transcode -i $filestomux[0] -A -N 0x2000 -p $filestomux[1] ";
+ $remuxfilename .= $path_param . "/$basename_list[0]_$basename_list[1]_";
+ $command .= " $divx_ac3_param -o $remuxfilename" . "divx.avi";
+ print "executeing $command\n";
+ system $command;
+ exit;
+ }
+ else {
+ #transcode -i e0.mpv -p c0.mpa -y divx4 -o test.avi
+ my $command = "nice -19 $transcode -i $filestomux[0] -p $filestomux[1] ";
+ $remuxfilename .= $path_param . "/$basename_list[0]_$basename_list[1]_";
+ $command .= " $divx_param -o $remuxfilename" . "divx.avi";
+ print "executeing $command\n";
+ system $command;
+ exit;
+ }
+}
+
+my $mplex_command;
+
+if ($mplex == 1) {
+ if (scalar(@filestomux) < 2) {print "Need at least two streams for multiplexing\n";exit}
+ if (! $panteltje){
+ $mplex_command = "nice -19 $tcmplex -i $filestomux[0] -p $filestomux[1]";
+ }
+ else {
+ $mplex_command = "nice -19 $tcmplex_panteltje -i $filestomux[0] -0 $filestomux[1]";
+ }
+ $remuxfilename .= $path_param . "/$basename_list[0]_$basename_list[1]_";
+
+ if (scalar(@filestomux) > 2) {
+ if (! $panteltje){
+ $mplex_command .= " -s $filestomux[2]";
+ $remuxfilename .= "$basename_list[2]_";
+ }
+ else {
+ print "Mplexing using tcmplex-panteltje\n";
+ my $counter = 2;
+ while (scalar(@filestomux) > $counter) {
+ print "adding to $counter $filestomux[$counter]\n";
+ $mplex_command .= " -" . ($counter-1) . " $filestomux[$counter]";
+ $remuxfilename .= "$basename_list[$counter]_";
+ $counter++;
+ }
+ }
+ }
+ $remuxfilename .= "remux.mpg";
+
+ if ($mpeg2) {
+ $mplex_command .= " -m 2 ";
+ }
+ else {
+ $mplex_command .= " -m d ";
+ }
+
+ print "$remuxfilename as outputname\n";
+
+ if (! $master_dvd) {
+ $mplex_command .= "-o $remuxfilename";
+ print "executeing $mplex_command\n";
+ system $mplex_command;
+ }
+}
+
+if ($master_dvd) {
+ print "we got a the master_dvd parameter\n";
+ create_dvd_image();
+}
+
+
+if ($postexec) {
+ print "Executing: $postexec\n";
+ if ($postexec =~ /VSlength/) {
+ my $length = $PES_Obj->get_movie_length();
+ $postexec =~ s/VSlength/$length/g;
+ }
+ exec $postexec;
+}
+
+if ($mplex) {
+ clean_up();
+}
+
+
+exit;
+
+sub create_dvd_image {
+ my $pid;
+ my $result = system "mkfifo $path_param"."remuxfifo";
+ print "the attempt to create FIFO returnd $result\n";
+ my $asp_ratio = $PES_Obj->get_aspect_ratio();
+
+ if ($pid = fork) {
+ my $command = "dvdauthor -v $asp_ratio $master_dvd_param -o $path_param" . "/DVD $path_param" . "remuxfifo";
+ print "starting $command\n";
+ system $command;
+ $command = "dvdauthor -T -o $path_param" . "/DVD";
+ print "starting $command\n";
+ system $command;
+ sleep 1;
+ }
+ else {
+ print "mplexing file to fifo\n";
+ print "should execute $mplex_command and put it to the fifo\n";
+ $mplex_command .= " -o $path_param" . "remuxfifo";
+ print "now the command is $mplex_command\n";
+ system $mplex_command;
+ print "finished mplexing\n";
+ exit;
+ }
+ if (! $mkiso) {
+ print "***********************************************************\n";
+ print "vdrsync finished\n";
+ print "***********************************************************\n";
+ print "now you can burn the Image to a DVD-R(W) using the command:\n\n";
+ print "mkisofs -dvd-video $path_param" . '/DVD | dvdrecord tsize=$(echo "`mkisofs -dvd-video --print-size ' .$path_param . '/DVD 2>/dev/null`*2048" | bc -l ) dev=1,0,0 -v -dao -' . "\n";
+ print "NOTE: Of course you have to adjust the dev=N,N,N parameter to match your device settings\n\n";
+ print "NOTE: It might be a good idea to check it first with:\n\n";
+ print "mplayer -dvd 1 -dvd-device $path_param" . "/DVD\n\n";
+ }
+ else {
+ my $command = "mkisofs -dvd-video $path_param" . '/DVD > ' . " $path_param/DVDimage.iso\n";
+ system $command;
+ print "***********************************************************\n";
+ print "vdrsync finished\n";
+ print "***********************************************************\n";
+ print "now you can burn the Image to a DVD-R(W) using the command:\n\n";
+ print "dvdrecord dev=1,0,0 -v -dao $path_param" . "DVDimage.iso\n";
+ print "NOTE: Of course you have to adjust the dev=N,N,N parameter to match your device settings\n\n";
+ }
+}
+
+sub clean_up {
+ print "Deleting temp files\n";
+ for my $delfile (@filestomux) {
+ if (-e $delfile){
+ print "$delfile\n";
+ unlink($delfile);
+ }
+ }
+ if (-e "$path_param"."remuxfifo") {
+ unlink ("$path_param"."remuxfifo");
+ }
+ if ($mkiso) {
+ my $command = "rm -r $path_param" . "DVD";
+ print "Deleting DVD Files with: $command\n";
+ system $command;
+
+ }
+}
+
+sub get_file_list {
+ my $indir = shift;
+ my $DIR;
+ opendir $DIR, $indir || die "Can not open $indir $!\n";
+ print "trying to open $indir\n";
+ if (! $DIR){
+ die "did not get a handle back\n";
+ }
+ my @allfiles = grep { ! /^\./ } readdir $DIR;
+ my @vdrfiles = sort (grep { /\d{3}.vdr$/ } @allfiles);
+ return \@vdrfiles;
+ #$summary_file = $indir . "summary.vdr" if (-e "$indir/summary.vdr");
+ #$marks_file = $indir . "marks.vdr" if (-e "$indir/marks.vdr");
+ #$index_file = $indir . "index.vdr" if (-e "$indir/index.vdr");
+}
+
+
+
+BEGIN
+{
+package MPEGSTREAM;
+require Exporter;
+# A place available to all instances for storing the cuts in the file...
+our @cutlist;
+our $kill_me = "";
+our $total_size = 0;
+our $bytes_read = 0;
+our %bitrates = (
+ MPEG1_Layer_1 => {
+ "0001" => "32",
+ "0010" => "64",
+ "0011" => "96",
+ "0100" => "128",
+ "0101" => "160",
+ "0110" => "192",
+ "0111" => "224",
+ "1000" => "256",
+ "1001" => "288",
+ "1010" => "320",
+ "1011" => "352",
+ "1100" => "384",
+ "1101" => "416",
+ "1110" => "448",
+ },
+ MPEG1_Layer_2 => {
+ "0001" => "32",
+ "0010" => "48",
+ "0011" => "56",
+ "0100" => "64",
+ "0101" => "80",
+ "0110" => "96",
+ "0111" => "112",
+ "1000" => "128",
+ "1001" => "160",
+ "1010" => "192",
+ "1011" => "224",
+ "1100" => "256",
+ "1101" => "320",
+ "1110" => "384",
+ },
+ MPEG1_Layer_3 => {
+ "0001" => "32",
+ "0010" => "40",
+ "0011" => "48",
+ "0100" => "56",
+ "0101" => "64",
+ "0110" => "80",
+ "0111" => "96",
+ "1000" => "112",
+ "1001" => "128",
+ "1010" => "160",
+ "1011" => "192",
+ "1100" => "224",
+ "1101" => "256",
+ "1110" => "320",
+ },
+ MPEG2_Layer_1 => {
+ "0001" => "32",
+ "0010" => "64",
+ "0011" => "96",
+ "0100" => "128",
+ "0101" => "160",
+ "0110" => "192",
+ "0111" => "224",
+ "1000" => "256",
+ "1001" => "288",
+ "1010" => "320",
+ "1011" => "352",
+ "1100" => "384",
+ "1101" => "416",
+ "1110" => "448",
+ },
+ MPEG2_Layer_2 => {
+ "0001" => "32",
+ "0010" => "48",
+ "0011" => "56",
+ "0100" => "64",
+ "0101" => "80",
+ "0110" => "96",
+ "0111" => "112",
+ "1000" => "128",
+ "1001" => "160",
+ "1010" => "192",
+ "1011" => "224",
+ "1100" => "256",
+ "1101" => "320",
+ "1110" => "384",
+ },
+ MPEG2_Layer_3 => {
+ "0001" => "8",
+ "0010" => "16",
+ "0011" => "24",
+ "0100" => "32",
+ "0101" => "64",
+ "0110" => "80",
+ "0111" => "56",
+ "1000" => "64",
+ "1001" => "128",
+ "1010" => "160",
+ "1011" => "112",
+ "1100" => "128",
+ "1101" => "256",
+ "1110" => "320",
+ },
+);
+our %freqs =(
+ MPEG1 => {
+ "00" => "44100",
+ "01" => "48000",
+ "10" => "32000",
+ },
+ MPEG2 => {
+ "00" => "22050",
+ "01" => "24000",
+ "10" => "16000",
+ },
+);
+
+our %AC3_frame_info = (
+ "32000" => {
+ "000000" => "192",
+ "000001" => "192",
+ "000010" => "240",
+ "000011" => "240",
+ "000100" => "288",
+ "000101" => "288",
+ "000110" => "336",
+ "000111" => "336",
+ "001000" => "384",
+ "001001" => "384",
+ "001010" => "480",
+ "001011" => "480",
+ "001100" => "576",
+ "001101" => "576",
+ "001110" => "672",
+ "001111" => "672",
+ "010000" => "768",
+ "010001" => "768",
+ "010010" => "960",
+ "010011" => "960",
+ "010100" => "1152",
+ "010101" => "1152",
+ "010110" => "1344",
+ "010111" => "1344",
+ "011000" => "1536",
+ "011001" => "1536",
+ "011010" => "1920",
+ "011011" => "1920",
+ "011100" => "2304",
+ "011101" => "2304",
+ "011110" => "2688",
+ "011111" => "2688",
+ "100000" => "3072",
+ "100001" => "3072",
+ "100010" => "3456",
+ "100011" => "3456",
+ "100100" => "3840",
+ "100101" => "3840",
+ },
+ "44100" => {
+ "000000" => "138",
+ "000001" => "140",
+ "000010" => "194",
+ "000011" => "196",
+ "000100" => "208",
+ "000101" => "210",
+ "000110" => "242",
+ "000111" => "244",
+ "001000" => "278",
+ "001001" => "280",
+ "001010" => "348",
+ "001011" => "350",
+ "001100" => "416",
+ "001101" => "418",
+ "001110" => "486",
+ "001111" => "488",
+ "010000" => "556",
+ "010001" => "558",
+ "010010" => "696",
+ "010011" => "698",
+ "010100" => "834",
+ "010101" => "836",
+ "010110" => "974",
+ "010111" => "976",
+ "011000" => "1114",
+ "011001" => "1116",
+ "011010" => "1392",
+ "011011" => "1394",
+ "011100" => "1670",
+ "011101" => "1672",
+ "011110" => "1950",
+ "011111" => "1952",
+ "100000" => "2228",
+ "100001" => "2230",
+ "100010" => "2506",
+ "100011" => "2508",
+ "100100" => "2786",
+ "100101" => "2788",
+ },
+ "48000" => {
+ "000000" => "128",
+ "000001" => "120",
+ "000010" => "160",
+ "000011" => "160",
+ "000100" => "192",
+ "000101" => "192",
+ "000110" => "224",
+ "000111" => "224",
+ "001000" => "256",
+ "001001" => "256",
+ "001010" => "320",
+ "001011" => "320",
+ "001100" => "384",
+ "001101" => "384",
+ "001110" => "448",
+ "001111" => "448",
+ "010000" => "512",
+ "010001" => "512",
+ "010010" => "640",
+ "010011" => "640",
+ "010100" => "768",
+ "010101" => "768",
+ "010110" => "896",
+ "010111" => "896",
+ "011000" => "1024",
+ "011001" => "1024",
+ "011010" => "1280",
+ "011011" => "1280",
+ "011100" => "1336",
+ "011101" => "1336",
+ "011110" => "1792",
+ "011111" => "1792",
+ "100000" => "2048",
+ "100001" => "2048",
+ "100010" => "2304",
+ "100011" => "2304",
+ "100100" => "2560",
+ "100101" => "2560",
+ },
+ "bitrate" => {
+ "000000" => "32000",
+ "000001" => "32000",
+ "000010" => "40000",
+ "000011" => "40000",
+ "000100" => "48000",
+ "000101" => "48000",
+ "000110" => "56000",
+ "000111" => "56000",
+ "001000" => "64000",
+ "001001" => "64000",
+ "001010" => "80000",
+ "001011" => "80000",
+ "001100" => "96000",
+ "001101" => "96000",
+ "001110" => "112000",
+ "001111" => "112000",
+ "010000" => "128000",
+ "010001" => "128000",
+ "010010" => "160000",
+ "010011" => "160000",
+ "010100" => "192000",
+ "010101" => "192000",
+ "010110" => "224000",
+ "010111" => "224000",
+ "011000" => "256000",
+ "011001" => "256000",
+ "011010" => "320000",
+ "011011" => "320000",
+ "011100" => "384000",
+ "011101" => "384000",
+ "011110" => "448000",
+ "011111" => "448000",
+ "100000" => "512000",
+ "100001" => "512000",
+ "100010" => "576000",
+ "100011" => "576000",
+ "100100" => "640000",
+ "100101" => "640000",
+ },
+);
+
+our $mp2_regex =
+ #(pack ("B16", "1111111111110000")) . "|" .
+ #(pack ("B16", "1111111111110001")) . "|" .
+ #(pack ("B16", "1111111111110010")) . "|" .
+ #(pack ("B16", "1111111111110011")) . "|" . These are Mpeg 2 Audio Headers,
+ #(pack ("B16", "1111111111110100")) . "|" . They should not occur
+ #(pack ("B16", "1111111111110101")) . "|" .
+ #(pack ("B16", "1111111111110110")) . "|" .
+ #(pack ("B16", "1111111111110111")) . "|" .
+
+ #(pack ("B16", "1111111111111000")) . "|" .
+ #(pack ("B16", "1111111111111001")) . "|" .
+ #(pack ("B16", "1111111111111010")) . "|" . These are Layer I and III headers
+ #(pack ("B16", "1111111111111011")) . "|" .
+ #(pack ("B16", "1111111111111110")) . "|" .
+ #(pack ("B16", "1111111111111111")) . "|" .
+
+ (pack ("B16", "1111111111111100")) . "|" .
+ (pack ("B16", "1111111111111101"))
+ ;
+
+$mp2_regex = qr/$mp2_regex/;
+
+our $AC3_regex =
+ (pack("B16", "0000101101110111")); # AC3 Frames always have this 16 Bit Syncword at the beginning
+
+$AC3_regex = qr/$AC3_regex/;
+
+
+sub get_cutlist { return @cutlist; }
+
+our @ISA = qw(Exporter);
+our @EXPORT = qw( add_PES_packet
+ bitrate
+ streamtype
+ streamcode
+ print_stats
+ output_files
+ process_PES_packets
+ );
+
+our $VERSION = 0.1.2.2; # Version number
+
+
+
+
+sub new {
+ my $invocant = shift;
+ my $class = ref($invocant) || $invocant;
+
+ my $self = {
+ streamcode => "PES_stream", #will be overridden
+ streamtype => undef, #
+ bitrate => undef, # only for Audio
+ freq => undef, # only for Audio
+ copyright => undef, # only for Audio
+ frame_bytes => undef, # only for Audio
+ frame_ticks => undef, # one tick is 1 / 90000 of a second
+ frameno => 0, # READ frames counter, not written frames
+ GOPno => 0, # just for video stats
+ packet_start => undef, # a signature that is found a the beginning of a frame, should read frame_start
+ packet_rest => "", # only audio, if a frame does not finish in a PES-Packet, the first part of the frame is stored here
+ check_frames => undef, # a placeholder for the sub that actually manages the frames of a given type (mp2 / ac3 / mpv)
+ analyse_frames => undef, # a placeholder for the sub that actually analyses the frames of a given type (mp2 / ac3 )
+ masterstream => "", # here the stream_id of the videostream is stored (it is not always e0 as I thought first)
+ outputpath => "./", # where to store the result files
+ outfilename => "", # The name of the output file
+ cutcounter => 0, # used as an index to the cuts list (see below), for sync we need the current and the previous cut
+ last_ts => 0, # last timestamp that was read
+ final_desync => [],
+ GOP_buffer => "", # A GOP is buffered here before analysed and written
+ GOP_ts => 0, # Here we store the first GOP ts, for the strrange recordings that have no ts at GOP start
+ frame_buffer => [], # an array that holds the buffered audio frames
+ frame_times => [], # an array that holds the timestamp for each audio frame
+ frame_lengths => [], # an array that holds the length for each audio frame
+ frames_written => 0, # used only for stats
+ timestamps => [], # all timesstamps are stored here, probably a waste of memory, but maybe used for stricter checks
+ written_chunks => [], # an array of scalars for debugging, from where to where were Audio STreams written?
+ final_desync => 0, # how many ticks desync after correction? Used in the next sync attempt
+ show_drift => 0, # if set to 1, info about timedrift will be printed
+ time_drift => 0, # The current mismatch between TS and actual Pakets found
+ audio_only => 0, # if this is set, all video Streams are discarded and audio ist just written out
+ script_output => 0,
+ Unit_analysis_counter => 0,
+ Unit_analysis_hash => {}, # Here the different settings for apsepect_ratio etc are collected for later print
+ first_flush => 1, # This flag indicates that it is the first time that the audio buffer is flushrd, an a start sync is needed
+ @_, # Override previous attributes
+ };
+ if ($self->{streamcode} eq "PES_stream") {
+
+ if (scalar(@{$self->{files}}) == 0) {
+ print "No input files specified, exiting\n"; exit 1 ;
+ }
+
+ foreach (@{$self->{files}}) {# check whether all files that we got as parameters exist
+ if (!(-e $_)) {print "Input file $_ not found\n"; exit 1 }
+ }
+ $self->{packets_before_sync} = 0;
+ print "dump only the first $self->{dump_packets} packets\n" if $self->{dump_packets};
+ foreach (keys (%{$self->{ignore_streams}})) {print "Ignoring stream $_\n";}
+ print "Lots of debug stuff will be printed\n" if $self->{debug};
+ print "Printing Information about the time drift\n" if $self->{show_drift};
+ init_PES_stream($self);
+ foreach(@{$self->{files}}) {
+ $total_size += -s $_;
+ }
+ print "Total Input Size is $total_size\n";# if $self->{debug};
+ }
+ return bless $self, $class;
+}
+
+
+sub init_stream {
+ my $self = shift;
+ my $payload = shift;
+ my %pes_header = %{shift @_};
+ my $decimal_code = hex($pes_header{stream_id});
+ print "we got the decimal code $decimal_code for $pes_header{stream_id}\n"if $self->{debug};
+ if (($decimal_code > 191) && ($decimal_code < 224)) {
+ print "we got the stream $decimal_code ($pes_header{stream_id}), checking Audio\n"if $self->{debug};
+ analyse_audio_stream($self, $payload, \%pes_header);
+ #$self->{streamtype} = "audio";
+ }
+ elsif (($decimal_code > 223) && ($decimal_code < 240)) {
+ print "we got the stream $decimal_code ($pes_header{stream_id}), checking Video\n"if $self->{debug};
+ analyse_video_stream($self, $payload, \%pes_header);
+ $self->{streamtype} = "video";
+ }
+ elsif ($decimal_code == 189) {
+ analyse_ac3_stream($self, $payload, \%pes_header);
+ $self->{streamtype} = "AC3_audio";
+ }
+ else {
+ print "unknown stream type found, skipping contents of stream $pes_header{stream_id}\n";
+ }
+}
+
+
+sub output_files {
+ my $self = shift;
+
+ if ($self->{streamcode} ne "PES_stream") {return}
+
+ my @audiofiles;
+ my $moviefile;
+ my @filelist;
+
+ foreach(keys(%{$self->{streams}})) {
+ if ($self->{ignore_streams}{$_}){
+ next;
+ }
+ if ( $_ =~ /(c|b)/ ) {
+ push @audiofiles, $self->{streams}{$_}{outfilename};
+ }
+ else {
+ $moviefile = $self->{streams}{$_}{outfilename};
+ }
+ }
+ @audiofiles = sort(@audiofiles);
+ @filelist = ($moviefile, @audiofiles);
+ return \@filelist;
+}
+
+sub analyse_ac3_stream {
+ my $self = shift;
+ my $payload = shift;
+ my %pes_header = %{shift @_};
+ $self->{frame_regex} = $AC3_regex;
+ ($payload, my %frame_info) = analyse_ac3_frame($self, $payload);
+ if ($payload eq "-1") {
+ print "AC3 Packet could not be analysed, skipping\n";
+ return;
+ }
+
+ $self->{packet_start} = substr($payload,0,2);
+
+
+ $self->{freq} = $frame_info{freq};
+
+ $self->{frame_bytes} = $frame_info{frame_bytes};
+ $self->{bitrate} = $frame_info{bitrate};
+ $self->{mode} = $frame_info{mode};
+
+ ##################################################################
+ ############ ONE FRAME is 32 ms
+ ##################################################################
+
+ $self->{frame_ticks} = $frame_info{frame_ticks};
+
+
+ $self->{outfilename} = "$self->{outputpath}/$self->{streamcode}.ac3";
+ open $self->{outfile}, ">$self->{outputpath}/$self->{streamcode}.ac3" || die "Can not open file for ac3: $!\n" if (!($self->{outfile}));
+ binmode $self->{outfile};
+ $self->{check_frames} = \&check_audio_frames;
+ $self->{analyse_frames} = \&analyse_ac3_frame;
+ $self->{frame_regex} = $AC3_regex;
+}
+
+sub analyse_ac3_frame {
+ my $self = shift;
+ my $payload = shift;
+ my $bits = unpack("B64", substr($payload, 0, 8));
+ my %frame_info;
+ if (!(substr($payload, 0, 2) =~ /^$AC3_regex$/)) {
+ #if (substr($bits,0,16) ne "0000101101110111") {
+ print "No Audio syncword found for stream $self->{streamcode}, searching for audio sync\n" if $self->{debug};
+ print substr($bits,0,16) . " found, 0000101101110111 expected\n" if $self->{debug};
+ if ($payload =~ /$AC3_regex/g) {
+ print "\n AC3 regex matched at " . pos($payload) . "\n" if $self->{debug};
+ $payload = substr($payload, (pos($payload)-2));
+ }
+ else {
+ print "No audio frame found in this paket\n";
+ return -1;
+ }
+ $bits = unpack("B64", substr($payload, 0, 8));
+ }
+
+ my $fscod = substr($bits,32,2);
+
+ if ($fscod == "00") {$frame_info{freq} = 48000}
+ elsif ($fscod == "01") {$frame_info{freq} = 44100}
+ elsif ($fscod == "11") {$frame_info{freq} = 32000}
+ elsif ($fscod == "10") {print "Illeagal AC3 freq\n"; return -1}
+
+ my $frmsizecod = substr($bits,34,6);
+ $frame_info{frame_bytes} = $AC3_frame_info{$frame_info{freq}}{$frmsizecod};
+ $frame_info{bitrate} = $AC3_frame_info{bitrate}{$frmsizecod};
+
+ my $acmod = substr($bits, 48, 3);
+ if ($acmod == "000") {$frame_info{mode} = "1+1"}
+ elsif ($acmod == "001") {$frame_info{mode} = "1/0"}
+ elsif ($acmod == "010") {$frame_info{mode} = "2/0"}
+ elsif ($acmod == "011") {$frame_info{mode} = "3/0"}
+ elsif ($acmod == "100") {$frame_info{mode} = "2/1"}
+ elsif ($acmod == "101") {$frame_info{mode} = "3/1"}
+ elsif ($acmod == "110") {$frame_info{mode} = "2/2"}
+ elsif ($acmod == "111") {$frame_info{mode} = "3/2"}
+
+ ##################################################################
+ ############ ONE FRAME is 32 ms
+ ##################################################################
+ if ($fscod ne "00") {print "not an 48 KHz stream, exiting\n"; return -1}
+ $frame_info{frame_ticks} = 8 * $frame_info{frame_bytes} * 90000 / $frame_info{bitrate};
+ $frame_info{streamtype} = "AC3_Audio";
+ if ($self->{Unit_analysis_counter}++ > 20) {
+ $self->{Unit_analysis_hash}{mode}{$frame_info{mode}}++;
+ }
+
+
+ return $payload, %frame_info;
+}
+
+sub check_audio_frames {
+ my $self = shift;
+ my $payload = shift;
+ my %pes_header = %{shift @_};
+ my $counter = 0;
+ my $FH = $self->{outfile};
+
+
+ if ($self->{change_message}) {return}
+
+ if ($self->{dump_payload}) {
+ print "Dumping payload of stream $self->{streamcode}, ($self->{dump_payload} to dump left)\n" if $self->{debug};
+ my $DUMPFH;
+ if (! $self->{"$self->{streamcode}.dump"}) {
+ print "Trying to open dumpfile\n";
+ open $DUMPFH, ">$self->{streamcode}.dump" || die "Can not open dumpfile: $!\n";
+ binmode $DUMPFH;
+ $self->{"$self->{streamcode}.dump"} = $DUMPFH;
+ print "opened dumpfile\n";
+ }
+ $DUMPFH = $self->{"$self->{streamcode}.dump"};
+ print $DUMPFH $payload;
+ if ($self->{dump_payload}-- == 1) {
+ exit;
+ }
+ return;
+ }
+
+ $payload = $self->{packet_rest} . $payload;
+
+ ($payload, my %frame_info) = &{$self->{analyse_frames}}($self, $payload) ;
+ if (!$frame_info{frame_ticks}) {
+ print "Analysis failed in audio stream $self->{streamcode}, returning from check_audio_frames\n" if $self->{debug};
+ return;
+ }
+ if ((!($self->{frame_bytes} eq $frame_info{frame_bytes}) || (!($self->{bitrate} eq $frame_info{bitrate}))) && ($self->{streamcode} ne "bd")) {
+ if ($self->{audio_only}){
+ $self->{copyright} = $frame_info{copyright};
+ $self->{bitrate} = $frame_info{bitrate};
+ $self->{freq} = $frame_info{freq};
+ $self->{padding_bit} = $frame_info{padding_bit};
+ $self->{streamtype} = $frame_info{streamtype};
+ $self->{frame_bytes} = $frame_info{frame_bytes};
+ $self->{frame_ticks} = $frame_info{frame_ticks};
+ $self->{mode} = $frame_info{mode};
+ print "\nAudio Format Changed:\n";
+ print "\naudio stream $self->{streamcode} info ($self->{streamtype}):\n";
+ print "Sample frequency: $self->{freq}\n"; # only for Audio
+ print "Bitrate: $self->{bitrate}\n"; # only for Audio
+ print "Mode: $self->{mode}\n"; # only for Audio
+ print "Copyright: $self->{copyright}\n" if $self->{copyright}; # only for Audio
+ print "Frame length (bytes) $self->{frame_bytes}\n"; # only for Audio
+ print "Frame length (ticks) $self->{frame_ticks} (90000 / sec)\n\n\n"; # one tick is 1 / 90000 of a second
+ }
+
+
+ elsif (!$self->{frames_written}) {
+ @{$self->{frame_times}} = ();
+ $self->{frame_times}[0] = 0;
+ @{$self->{frame_buffer}} = ();
+ @{$self->{frame_length}} = ();
+ $self->{frameno} = 0;
+ $self->{copyright} = $frame_info{copyright};
+ $self->{bitrate} = $frame_info{bitrate};
+ $self->{freq} = $frame_info{freq};
+ $self->{padding_bit} = $frame_info{padding_bit};
+ $self->{streamtype} = $frame_info{streamtype};
+ $self->{frame_bytes} = $frame_info{frame_bytes};
+ $self->{frame_ticks} = $frame_info{frame_ticks};
+ $self->{mode} = $frame_info{mode};
+
+ $self->{single_frame} = get_silent_frame($self, \%frame_info);
+ if ($self->{single_frame} eq "-1") {
+ $self->{single_frame} = substr($payload, 0, $frame_info{frame_bytes});
+ print "Defined first audio frame as single frame for later sync in stream $self->{streamcode}\n" if $self->{debug};
+ print "Frame has a length of " . length($self->{single_frame}) . "\n" if $self->{debug};
+ }
+
+ print "\nAUDIO FORMAT CHANGED, new parameters:\n";
+ print "\naudio stream $self->{streamcode} info ($self->{streamtype}):\n";
+ print "Sample frequency: $self->{freq}\n"; # only for Audio
+ print "Bitrate: $self->{bitrate}\n"; # only for Audio
+ print "Mode: $self->{mode}\n"; # only for Audio
+ print "Copyright: $self->{copyright}\n" if $self->{copyright}; # only for Audio
+ print "Frame length (bytes) $self->{frame_bytes}\n"; # only for Audio
+ print "Frame length (ticks) $self->{frame_ticks} (90000 / sec)\n\n\n";
+ }
+ elsif ($total_size - $bytes_read < 10000000) {
+ if (! $self->{change_message}) {
+ print "\nAudio Format changed " . int(($total_size - $bytes_read)/1000000) ." MBytes before end, continuing...\n";
+ $self->{change_message} = 1;
+ }
+ return;
+ }
+ else {
+ print "Change in Audio Mode from $self->{mode} to $frame_info{mode}, this will not work during remux, stopping!\n";
+ print "Change in Audio bitrate from $self->{bitrate} to $frame_info{bitrate}, this will not work during remux, stopping!\n";
+ print "You should cut the movie at this position and process the pieces independently\n";
+ my $frame_number = $self->{frames_written} + scalar(@{$self->{frame_buffer}});
+ my $seconds = $frame_number * $self->{frame_ticks} / 90000; #/
+ print "Current position: $seconds sec.\n";
+ $kill_me = $self->{streamcode};
+ }
+ }
+
+ if ((! $self->{frame_times}[0]) && ( $pes_header{PTS_decimal}) && ($self->{frameno} > 0)){
+ print "\nFirst audio timestamp at $self->{frameno} for stream $self->{streamcode}\n" if $self->{debug};
+ print "First Audio Timestamp is $pes_header{PTS_decimal}\n" if $self->{debug};
+ for (my $i = 1; $i <= $self->{frameno}; $i++) {
+ $self->{frame_times}[$self->{frameno} - $i] = $pes_header{PTS_decimal} - ($i * $self->{frame_ticks});
+ }
+ print "\nAudio now starting at $self->{frame_times}[0]\n" if $self->{debug};
+ }
+
+ my $first_timestamp = 0;
+
+ if ($pes_header{PTS_decimal}) {
+ $first_timestamp = $pes_header{PTS_decimal};
+ }
+ else {
+ $first_timestamp = ${$self->{frame_times}}[-1] + $frame_info{frame_ticks} if (${$self->{frame_times}}[-1]);
+ }
+
+ if (!($self->{single_frame})) {
+
+ $self->{single_frame} = get_silent_frame($self, \%frame_info);
+ if ($self->{single_frame} eq "-1") {
+ $self->{single_frame} = substr($payload, 0, $frame_info{frame_bytes});
+ print "\nDefined first audio frame as single frame for later sync in stream $self->{streamcode}\n" if $self->{debug};
+ print "Frame has a length of " . length($self->{single_frame}) . "\n" if $self->{debug};
+ }
+ }
+
+ my $packet_offset = 0;
+ while ($packet_offset + $frame_info{frame_bytes} +2 <= (length($payload))) {
+
+ if ((substr($payload, $packet_offset, 2) =~ /^$self->{frame_regex}$/)) {
+ push @{$self->{frame_buffer}}, substr($payload, $packet_offset, $frame_info{frame_bytes});
+
+ push @{$self->{frame_times}}, $first_timestamp + $counter * $frame_info{frame_ticks};
+ push @{$self->{frame_length}}, $frame_info{frame_ticks};
+ $packet_offset += $frame_info{frame_bytes};
+ $counter++;
+ $self->{frameno}++;
+ }
+ else {
+ print "\n$self->{frame_regex} did not match against " . (substr($payload,$packet_offset,2)) . "\n" if $self->{debug};
+ if ($counter == 0) {
+ $payload = search_audio_sync($self, substr($payload, $packet_offset));
+ $self->{packet_rest} = "";
+ $packet_offset = 0;
+ }
+ else {
+ print "\nAudio Format change within packet, skipping \n" if $self->{debug};
+ $self->{packet_rest} ="";
+ return;
+ }
+ }
+ }
+
+ if ($packet_offset < (length($payload))) {
+ $self->{packet_rest} = substr($payload, $packet_offset);
+ }
+ else {
+ $self->{packet_rest} = "";
+ }
+ if (scalar(@{$self->{frame_times}}) < 100) {
+ return;
+ }
+ new_flush($self);
+ return;
+}
+
+sub new_flush {
+ my $self = shift;
+ my $FH = $self->{outfile};
+
+ if ($self->{audio_only}) {
+ while (scalar(@{$self->{frame_times}}) > 50) {
+ $self->{last_frame_time} = shift @{$self->{frame_times}};
+ shift @{$self->{frame_length}};
+ print $FH shift @{$self->{frame_buffer}};
+ $self->{frames_written} ++;
+ }
+ return;
+ }
+
+ my ($chunk_start, $chunk_end, $video_frameno) = split /::/,$cutlist[$self->{cutcounter}];
+ if ($self->{first_flush}){
+ sync_audio_start($self, $chunk_start);
+ $self->{first_flush} = 0;
+ }
+
+ #
+ # Here the new time drift correction is performed. Note that this is performed wthe the beginning of a Aufio flush NOT when it occurs
+ # This should be ok, since a) The shift builds up very slowly and b) a buffer flush is only 60 Frames (max 1,8 sec) long
+ #
+ if (abs($self->{time_drift}) > ($self->{frame_ticks} * 1.5)) {
+ if (abs($self->{time_drift}) > 900000) {
+ print "Timedrift bigger than 10 Seconds, killing stream $self->{streamcode}\n";
+ $kill_me = $self->{streamcode};
+ return;
+ }
+ print "Timedrift is too big, trying to correct $self->{time_drift} ticks\n";
+ #sleep 1;
+ if ($self->{time_drift} < 0) {
+ while ($self->{time_drift} < ($self->{frame_ticks} * -1.5)) {
+ shift @{$self->{frame_buffer}};
+ shift @{$self->{frame_times}};
+ $self->{time_drift} += shift @{$self->{frame_length}};
+ print "Dropped frame to correct time drift EXPERIMENTAL!!!\n";
+ if (@{$self->{frame_buffer}} == 0) {
+ print "could not drop enough Audio frames in stream $self->{streamcode}to compensate for timedrift, still $self->{time_drift} left\nContinuing anyway...\n";
+ # sleep 1;
+ if ($self->{dump_buffer}) {$kill_me = "all"}
+ return;
+ }
+ }
+ }
+ else {
+ my $ins_frames = insert_frames($self, $self->{time_drift});
+ my $ins_time = $ins_frames * $self->{frame_ticks};
+ print "Inserted $ins_frames Audio Frames ($ins_time ticks) to correct a drift of $self->{time_drift}. EXPERIMENTAL\n";
+ $self->{time_drift} -= $ins_time;
+ }
+ }
+
+ #
+ #If the currenct chunk's end has not been determined yet, then we just flush 60 frames and calculate the timedrift
+ #
+
+ if (! $chunk_end) {
+ #my $frame;
+ #my $time;
+ #print "No Chunk end, just flushing\n";
+ my $counter = 0;
+ my $bufferstart = ${$self->{frame_times}}[0];
+ my $drift;
+ my $calc_end = $bufferstart;
+ while (scalar(@{$self->{frame_times}}) > 40) {
+ $self->{last_frame_time} = shift @{$self->{frame_times}};
+ $calc_end += shift @{$self->{frame_length}};
+ print $FH shift @{$self->{frame_buffer}};
+ $counter++;
+ $self->{frames_written}++;
+ }
+ $drift = $self->{last_frame_time} - $calc_end + $self->{frame_ticks};
+
+ #This should not be necessary, since a PTS Overflow will be treated as a cut...
+ #
+ #if ($drift < -8000000000) {
+ # print "Time drift indicates a PTS overflow, correcting\n";
+ # $drift += 8589934592;
+ # print "Now time drift will be " . ($self->{time_drift} + $drift) . "\n";
+ #}
+ $self->{time_drift} += $drift;
+ if ($self->{show_drift} && (abs($drift) > 0)) {
+ print "\nAUDIO TIMEDRIFT for stream $self->{streamcode}: $self->{time_drift}\n" if (abs($self->{time_drift}) > 100);
+ }
+ return;
+ }
+
+ #
+ #If the currenct chunk's end has been determined, but is at the end of the buffer, only 20 Frames are flushed to "move" the cut to the middle of the buffer
+ #Thereby we ensure that enough Audioframes for syncing are in the buffer before AND after the cut
+ #
+ my $cut_diff = $chunk_end - $self->{last_frame_time};
+
+ if (60 * ${$self->{frame_length}}[0] + $self->{last_frame_time} < $chunk_end) {
+
+ print "delaying sync to next run, chunk_end is $chunk_end\n" if $self->{debug};
+ my $calc = 60 * ${$self->{frame_length}}[0] + $self->{last_frame_time};
+ while (scalar(@{$self->{frame_times}}) > 80) {
+ $self->{last_frame_time} = shift @{$self->{frame_times}};
+ shift @{$self->{frame_length}};
+ print $FH shift @{$self->{frame_buffer}};
+ $self->{frames_written}++;
+ }
+ return;
+ }
+
+ # Then we test wether the cut is no cut but a PTS overflow .... If yes, we just dump the buffer, increase the cutcount and continue.
+ # No Timedrift is computed for this buffer
+ if ($chunk_end > 8589889595) {
+ print "syncing at PTS Overflow, special care is taken!\n";
+ while (scalar(@{$self->{frame_times}}) > 20) {
+ $self->{last_frame_time} = shift @{$self->{frame_times}};
+ shift @{$self->{frame_length}};
+ print $FH shift @{$self->{frame_buffer}};
+ $self->{frames_written}++;
+ }
+ $self->{cutcounter}++;
+ return;
+ }
+
+
+ #
+ # Finally we sync the end of the Audio chunk
+ #
+
+
+ sync_audio_end($self, $chunk_end, $video_frameno);
+ $self->{cutcounter}++;
+ # Extract the beginning of the next chunk
+ ($chunk_start, $chunk_end) = split /::/,$cutlist[$self->{cutcounter}];
+ if (! $chunk_start) {
+ print "Could not extract chunk start from $cutlist[$self->{cutcounter}]\n";
+ $kill_me = $self->{streamcode};
+ }
+ # And sync the start of the next chunk
+ sync_audio_start($self, $chunk_start);
+}
+
+sub sync_audio_end {
+ my $self = shift;
+ my $chunk_end = shift;
+ my $video_frameno = shift;
+
+ my $FH = $self->{outfile};
+ my $counter = 0;
+ my $cut_frame = 0;
+
+ for (my $i = 0; $i < scalar(@{$self->{frame_times}}); $i++) {
+ if (abs(${$self->{frame_times}}[$i + 1] - ${$self->{frame_times}}[$i]) > 90000) {
+ $cut_frame = $i;
+ #print "The end of the chunk is at frame $cut_frame of the buffer\n";
+ last;
+ }
+ }
+ print "\nsyncing end of chunk in stream $self->{streamcode}...\n" if $self->{debug};
+ my $bufferstart = ${$self->{frame_times}}[0];
+ my $calc_end = $bufferstart;
+ while ((${$self->{frame_times}}[0] < $chunk_end - $self->{final_desync} + ($self->{frame_ticks} * 0.5))
+ && ($counter < $cut_frame)){
+
+ $self->{last_frame_time} = shift @{$self->{frame_times}};
+ $calc_end += shift @{$self->{frame_length}};
+ print $FH shift @{$self->{frame_buffer}};
+ $self->{frames_written}++;
+ $counter++;
+ if (scalar(@{$self->{frame_times}}) == 0) {
+ print "syncing failed for stream $self->{streamcode} while trying to write Frames until $chunk_end\n";
+ print "time of last frame written was $self->{last_frame_time}\n";
+ $kill_me = $self->{streamcode};
+ }
+ }
+ print "written $self->{frames_written} frames, time $self->{last_frame_time}\n"if $self->{debug};
+ #
+ # We dont need a timedrift calc at the end of a cunk, it is not corrected anyway...At the end the real length correction is performed
+ #
+ #my $drift = $self->{last_frame_time} - $calc_end + ${$self->{frame_length}}[0];
+ #if ($drift < -8000000000) {
+ # print "Time drift indicates a PTS overflow, correcting\n";
+ # $drift += 8589934592;
+ # print "Now time drift will be " . ($self->{time_drift} + $drift) . "\n";
+ #}
+ #$self->{time_drift} += $drift;
+ #if ($self->{show_drift} && (abs($drift) > 0)) {
+ # print "\nAUDIO TIMEDRIFT for stream $self->{streamcode}: $self->{time_drift}\n" if (abs($self->{time_drift}) > 100);
+ #}
+ #my $diff = $chunk_end - ($self->{last_frame_time} + $self->{frame_ticks});
+ my $vid_time = $video_frameno * 3600;
+ my $aud_time = $self->{frames_written} * $self->{frame_ticks};
+ my $frame_diff = $vid_time - $aud_time;
+ print "For the end sync $self->{cutcounter} of $self->{streamcode} frames were printed up to $self->{last_frame_time} to match $chunk_end of chunk $self->{cutcounter} leaving: $frame_diff)\n"if $self->{debug};
+ my $ins_frames = insert_frames($self, $frame_diff);
+ $self->{frames_written} += $ins_frames;
+ $aud_time = $self->{frames_written} * $self->{frame_ticks};
+ $self->{final_desync} = $vid_time - $aud_time;
+ $self->{time_drift} = 0;
+ $self->{written_chunks}[$self->{cutcounter}] .= ($self->{last_frame_time} + $self->{frame_ticks} * ($ins_frames+1));
+}
+
+sub sync_audio_start {
+ my $self = shift;
+ my $chunk_start = shift;
+ print "\nFirst packet ts for stream $self->{streamcode} in buffer $self->{frame_times}[0] last:$self->{frame_times}[-1]\n" if $self->{debug};
+ print "\nIn stream $self->{streamcode}: new start $chunk_start\n" if $self->{debug};
+ my $counter = 0;
+ while ((${$self->{frame_times}}[0] < $chunk_start - $self->{frame_ticks} * 0.5)
+ || ( (${$self->{frame_times}}[0] - $chunk_start) > 90000 )) { # For PTS overflows and "catted" movies
+ #print "\ndropping frame with time ${$self->{frame_times}}[$counter]\n" if $self->{debug};
+ shift @{$self->{frame_times}};
+ shift @{$self->{frame_buffer}};
+ shift @{$self->{frame_length}};
+ $counter++;
+ if (scalar(@{$self->{frame_times}}) == 0) {
+ print "\nsyncing failed for stream $self->{streamcode} while trying to drop Frames until $chunk_start\n";
+ #print "time of last frame dropped was $time_drop\n";
+ $kill_me = $self->{streamcode};
+ }
+ }
+ my $diff = $chunk_start - ${$self->{frame_times}}[0];
+ my $ins_frames = insert_frames($self, $diff);
+ print "IN SYNC AUDIO START ($self->{streamcode}): diff is now: $diff\n" if $self->{debug};
+ $self->{frames_written} += $ins_frames;
+ $self->{last_frame_time} = ${$self->{frame_times}}[0];
+ $self->{written_chunks}[$self->{cutcounter}] = (${$self->{frame_times}}[0] - $self->{frame_ticks} * $ins_frames) . "::";
+ print "\nCHUNKSTART: dropped $counter frames at the beginning of $self->{streamcode}, start is now ${$self->{frame_times}}[0] matching $chunk_start leaving $diff\n" if $self->{debug};
+}
+
+
+
+sub insert_frames {
+ my $self = shift;
+ my $diff = shift;
+
+ $diff += $self->{final_desync};
+ my $FH = $self->{outfile};
+ my $abs_diff = abs($diff);
+
+ my $counter = 0;
+ if ($abs_diff > 900000) {
+ print "more than 10 seconds auf Audio missing, killing stream $self->{streamcode}\n";
+ $kill_me = $self->{streamcode};
+ return;
+ }
+ while ($abs_diff > ($self->{frame_ticks} * 0.5 )) {
+ print $FH $self->{single_frame};
+ $abs_diff -= $self->{frame_ticks};
+ $counter++;
+ }
+ if ($diff < 0) {$abs_diff *= -1}
+ print "INSERT FRAMES:wrote additional $counter frames to close $diff ticks, leaving $abs_diff\n" if $self->{debug};
+ $self->{final_desync} = $abs_diff;
+ #print "Final desync is now $self->{final_desync}\n";
+ return $counter;
+}
+
+sub analyse_video_stream {
+ my $self = shift;
+ my $payload = shift;
+ my %pes_header = %{shift @_};
+
+ $self->{packet_start} = pack("H8", "00000100");
+ my $seqstart = pack("H8", "000001b3");
+ if (!($payload =~ /$seqstart(.{8})/s)) {print "No SeqHeader in the first Frame, exiting\n"; $kill_me = "all"}
+
+ # Here we used to kill the stream if no PTS is found, that changed... We kill the strream if we find a GOP withou ANY ts
+ $self->{check_frames} = \&check_GOPs;
+
+ my $bitview = unpack("B64", $1);
+ print "Matched: $& at $-[0] bitview of the header\n$bitview \n" if $self->{debug};
+ my $hor_size = "0b" . substr($bitview,0,12);
+ $self->{horizontal_size} = oct $hor_size;
+ my $ver_size = "0b" . substr($bitview,12,12);
+ $self->{vertical_size} = oct $ver_size;
+ my $asp_ratio = substr($bitview,24,4);
+
+ if ($asp_ratio eq "0001"){
+ $self->{aspect_ratio} = "1:1";
+ }
+ elsif ($asp_ratio eq "0010") {
+ $self->{aspect_ratio} = "4:3";
+ }
+ elsif ($asp_ratio eq "0011") {
+ $self->{aspect_ratio} = "16:9";
+ }
+ elsif ($asp_ratio eq "0111") {
+ $self->{aspect_ratio} = "2.21:1";
+ }
+ else {
+ $self->{aspect_ratio} = "$asp_ratio";
+ }
+
+ my $fps = substr($bitview,28,4);
+ if ($fps eq "0001") {
+ $self->{fps} = 23.967;
+ }
+ elsif ($fps eq "0010") {
+ $self->{fps} = 24;
+ }
+ elsif ($fps eq "0011") {
+ $self->{fps} = 25;
+ }
+ elsif ($fps eq "0100") {
+ $self->{fps} = 29.97;
+ }
+ elsif ($fps eq "0101") {
+ $self->{fps} = 30.97;
+ }
+
+ $self->{bitrate_value} = 400 * ( oct ("0b" . substr($bitview,32, 18)));
+ my $marker_bit = substr($bitview,50, 1);
+ print "we got for fps: $fps\n" if $self->{debug};
+ $self->{frame_ticks} = 90000 / $self->{fps};
+ $self->{outfilename} = "$self->{outputpath}/$self->{streamcode}.mpv";
+ open $self->{outfile}, ">$self->{outputpath}/$self->{streamcode}.mpv" || die "Can not open file for m2v: $!\n";
+ binmode $self->{outfile};
+}
+
+
+sub analyse_GOP {
+ my $self = shift;
+
+
+ my %GOP_info;
+ my $seqstart = pack("H8", "000001b3");
+ if (!($self->{GOP_buffer} =~ /$seqstart(.{8})/s)) {
+
+ if (! $self->{GOPno}) {
+ print "\nNo Seq Header in the GOP, exiting\n";
+ $kill_me = "all";
+ }
+ else {
+ print "\nA GOP without Sequence Header. Weird recording\n";
+ open DFH, ">./strange_gop.mpg";
+ print DFH $self->{GOP_buffer};
+ close DFH;
+ return;
+ }
+ }
+
+ my $bitview = unpack("B64", $1);
+ my $hor_size = "0b" . substr($bitview,0,12);
+ $GOP_info{horizontal_size} = oct $hor_size;
+ $self->{Unit_analysis_hash}{horizontal_size}{$GOP_info{horizontal_size}}++;
+ my $ver_size = "0b" . substr($bitview,12,12);
+ $GOP_info{vertical_size} = oct $ver_size;
+ $self->{Unit_analysis_hash}{vertical_size}{$GOP_info{vertical_size}}++;
+ my $asp_ratio = substr($bitview,24,4);
+
+ if ($asp_ratio eq "0001"){
+ $GOP_info{aspect_ratio} = "1:1";
+ }
+ elsif ($asp_ratio eq "0010") {
+ $GOP_info{aspect_ratio} = "4:3";
+ }
+ elsif ($asp_ratio eq "0011") {
+ $GOP_info{aspect_ratio} = "16:9";
+ }
+ elsif ($asp_ratio eq "0111") {
+ $GOP_info{aspect_ratio} = "2.21:1";
+ }
+ else {
+ $GOP_info{aspect_ratio} = "$asp_ratio";
+ }
+
+
+ my $fps = substr($bitview,28,4);
+ if ($fps eq "0001") {
+ $GOP_info{fps} = 23.967;
+ }
+ elsif ($fps eq "0010") {
+ $GOP_info{fps} = 24;
+ }
+ elsif ($fps eq "0011") {
+ $GOP_info{fps} = 25;
+ }
+ elsif ($fps eq "0100") {
+ $GOP_info{fps} = 29.97;
+ }
+ elsif ($fps eq "0101") {
+ $GOP_info{fps} = 30.97;
+ }
+
+
+ $GOP_info{bitrate_value} = 400 * ( oct ("0b" . substr($bitview,32, 18)));
+ $self->{Unit_analysis_hash}{bitrate_value}{$GOP_info{bitrate_value}}++;
+ $self->{Unit_analysis_hash}{aspect_ratio}{$GOP_info{aspect_ratio}}++;
+ $self->{Unit_analysis_hash}{fps}{$GOP_info{fps}}++;
+
+}
+
+
+sub check_GOPs {
+ my $self = shift;
+ my $payload = shift;
+ my %pes_header = %{shift @_};
+ my $FH = $self->{outfile};
+ my $gopstart = pack("H8", "000001b8");
+ # First we just grep for the GOP start sequence
+ if ((! $self->{GOPno}) && (! $self->{GOP_buffer} )) {
+ $cutlist[$self->{cutcounter}] = "$pes_header{PTS_decimal}";
+ push @{$self->{timestamps}}, $pes_header{PTS_decimal};
+ my $seqstart = pack("H8", "000001b3");
+ $payload =~ /$seqstart/g;
+ if (pos($payload)-4 != 0) {
+ print "The very first GOP did not start at 0, but at " . (pos($payload)-4) ."\n";
+ $payload = substr($payload, (pos($payload)-4));
+ }
+ else {
+ print "Yes, it did start at 0\n" if $self->{debug};
+ }
+ $self->{GOP_buffer} .= $payload;
+ return;
+ }
+
+ if (! ($payload =~ /$gopstart/gm) ){
+ $self->{GOP_buffer} .= $payload;
+ #print "no GOPstart found, returning\n";
+ return;
+ }
+
+ $self->{GOPno}++;
+
+ my @pics = $self->{GOP_buffer} =~ /$self->{packet_start}/gm;
+ my $frames_in_GOP = scalar(@pics);
+
+
+ $self->{frameno} += $frames_in_GOP;
+
+ if ($self->{Unit_analysis_counter}++ > 9) {
+ $self->{Unit_analysis_counter} = 1;
+ analyse_GOP($self);
+ }
+
+
+ if (! $pes_header{PTS_decimal}) {die "Found no ts at GOP start\n";}
+
+ push @{$self->{timestamps}}, $pes_header{PTS_decimal};
+
+ my $pts_diff = ${$self->{timestamps}}[-1] - ${$self->{timestamps}}[-2];
+ my $calc = $self->{frame_ticks} * $frames_in_GOP;
+ #print "Timestamp diff is $pts_diff and frame time is $calc\n";
+
+ if ($calc != $pts_diff) {
+ my $ts_shift = $pts_diff - $calc;
+ #print "TS not as expected, diff is $ts_shift\n";
+ if (abs($ts_shift) > 90000) {
+ my $chunk_end = ${$self->{timestamps}}[-2] + $frames_in_GOP * $self->{frame_ticks};
+ if ($ts_shift > 0) {
+ print "\nCut detected in Video at $chunk_end\n";
+ }
+ else {
+ print "\nCut detected at $chunk_end, possibly a PTS Overflow\n";
+ }
+ $cutlist[$self->{cutcounter}] .= "::$chunk_end" . "::$self->{frameno}";
+ print "Chunk entry is $cutlist[$self->{cutcounter}]\n"if $self->{debug};
+ $self->{cutcounter}++;
+ $cutlist[$self->{cutcounter}] = "$pes_header{PTS_decimal}";
+ $self->{time_drift} = 0;
+ }
+ else {
+ #print "shift is too small for a cut, storing the shift for later use\n";
+ $self->{time_drift} += $ts_shift;
+ if (abs($self->{time_drift}) > 1000) {
+ print "\nTime Drift in VIDEO is now $self->{time_drift}, ts: ${$self->{timestamps}}[-2] and ${$self->{timestamps}}[-1] \n" if $self->{show_drift};
+ }
+ }
+ }
+ print $FH $self->{GOP_buffer};
+ $self->{GOP_buffer} = $payload;
+}
+
+
+sub search_audio_sync {
+
+ my $self = shift;
+ my $payload = shift;
+ my $new_offset = -1;
+ print "Searching for audio sync\n"if $self->{debug};
+ while ($payload =~ /$self->{frame_regex}/g) {
+ my $potential_start = (pos($payload)-2);
+ print "\tFound a potential audio syncword at $potential_start: " . unpack("H*" ,substr($payload,$potential_start,3)) . "\n" if $self->{debug};
+ (my $dummy_payload, my %frame_info) = analyse_audio_frame($self, substr($payload,$potential_start));
+ if (($potential_start + $frame_info{frame_bytes}) < length($payload)) {
+ print "\twe should have enough payload left to verify...\n" if $self->{debug};
+ #(my $dummy_payload, my %frame_info) = analyse_audio_frame($self, substr($payload,$potential_start));
+
+ print "\tchecking " . unpack("H4",substr($payload,($potential_start + $frame_info{frame_bytes}),2)) ."\n" if $self->{debug};
+
+ if ($frame_info{packet_start} eq substr($payload,($potential_start + $frame_info{frame_bytes}),2)) {
+ print "\tfound an additional audio sync in the right distance\n\tAll should be fine\n" if $self->{debug};
+ $new_offset = $potential_start;
+ print "\tNew attempt will be started at $new_offset\n" if $self->{debug};
+ $self->{packet_rest} ="";
+ last;
+ }
+ else {
+ print "\tNext audio start not found, continuing to check...\n" if $self->{debug};
+ }
+ }
+ else {
+ print "\tnot enough payload left to verify\n\tGood Luck\n\tSkipping to next packet\n" if $self->{debug};
+ last;
+ }
+ }
+
+ if ($new_offset != -1) {
+ return (substr($payload,$new_offset));
+ # &{$self->{check_frames}} ($self, substr($payload,$new_offset), \%pes_header);
+ }
+ else {
+ print "\tCould not find anything usefull in this packet, contents dropped, maybe next packet?\n" if $self->{debug};
+ return (-1);
+ }
+}
+
+sub print_stats {
+ my $self = shift;
+
+ foreach (keys(%{$self->{streams}})) {
+ print "$self->{streams}{$_}{streamtype} for stream $_\n" if $self->{debug};
+ if ($self->{ignore_streams}{$_}) {
+ print "Ignoring stream $_\n";
+ next;
+ }
+
+ if (($self->{streams}{$_}{streamtype} =~ /audio/) || ($self->{streams}{$_}{streamtype} =~ /Layer/)) {
+ print "\naudio stream $_ info ($self->{streams}{$_}{streamtype}):\n";
+ print "Sample frequency: $self->{streams}{$_}->{freq}\n"; # only for Audio
+ print "Bitrate: $self->{streams}{$_}->{bitrate}\n"; # only for Audio
+ print "Mode: $self->{streams}{$_}->{mode}\n"; # only for Audio
+ print "Copyright: $self->{streams}{$_}->{copyright}\n" if $self->{streams}{$_}->{copyright}; # only for Audio
+ print "Frame length (bytes) $self->{streams}{$_}->{frame_bytes}\n"; # only for Audio
+ print "Frame length (ticks) $self->{streams}{$_}->{frame_ticks} (90000 / sec)\n\n\n"; # one tick is 1 / 90000 of a second
+ }
+ if ($self->{streams}{$_}{streamtype} eq "video") {
+ print "video stream $_ info:\n";
+ print "Frame length (ticks) $self->{streams}{$_}->{frame_ticks} (90000 / sec)\n"; # one tick is 1 / 90000 of a second
+ print "Aspect ratio $self->{streams}{$_}->{aspect_ratio}\n";
+ print "Horizontal size $self->{streams}{$_}->{horizontal_size} \n";
+ print "Vertical size $self->{streams}{$_}->{vertical_size} \n";
+ print "Frames per Second $self->{streams}{$_}->{fps} \n";
+ print "Bitrate: $self->{streams}{$_}{bitrate_value}\n\n\n";
+ }
+ }
+}
+
+sub analyse_audio_stream {
+ my $self = shift;
+ my $payload = shift;
+ my %pes_header = %{shift @_};
+
+ #$self->{cuts}[0] = "new start: $self->{first_ts} at 0\t"; #{frameno} : $pes_header{PTS_decimal} : -1 : -1 : $self->{streamcode} : ";
+
+ $self->{frame_regex} = $mp2_regex;
+
+ ($payload, my %frame_info) = analyse_audio_frame($self, $payload);
+
+ if ($payload eq "-1") {
+ print "Audio Packet could not be analysed, skipping\n" if $self->{debug};
+ return;
+ }
+ $self->{copyright} = $frame_info{copyright};
+ $self->{bitrate} = $frame_info{bitrate};
+ $self->{freq} = $frame_info{freq};
+ $self->{padding_bit} = $frame_info{padding_bit};
+ $self->{streamtype} = $frame_info{streamtype};
+ $self->{frame_bytes} = $frame_info{frame_bytes};
+ $self->{frame_ticks} = $frame_info{frame_ticks};
+ $self->{mode} = $frame_info{mode};
+ print "streamtype is: $self->{streamtype}\nbitrate is $self->{bitrate}\nfreq is $self->{freq}\ncopyright is $self->{copyright}\nframelength in byte is $self->{frame_bytes}\nin sec: " . ($self->{frame_ticks}/90000) . "\n" if $self->{debug};#/
+
+ if ($self->{streamtype} eq "MPEG1_Layer_2") {
+ $self->{check_frames} = \&check_audio_frames;
+ $self->{analyse_frames} = \&analyse_audio_frame;
+ $self->{frame_regex} = $mp2_regex;
+ }
+ $self->{outfilename} = "$self->{outputpath}/$self->{streamcode}.mpa";
+ open $self->{outfile}, ">$self->{outputpath}/$self->{streamcode}.mpa" || die "Can not open file for mpa: $!\n";
+ binmode $self->{outfile};
+}
+
+sub analyse_audio_frame {
+ my $self = shift;
+ my $frame = shift;
+ #my %pes_header = %{shift @_};
+
+ my %frame_info;
+ my $streamtype = "";
+ if (!(substr($frame, 0, 2) =~ /^$mp2_regex$/)) {
+ print "No Audio syncword at the beginning of the frame, searching\n" if $self->{debug};
+ if ($frame =~ /$mp2_regex/g) {
+ $frame = substr($frame, (pos($frame) - 2))
+ }
+ else {
+ print "No Audio Sync found, returning -1\n" if $self->{debug};
+ return -1;
+ }
+ print "found sync for mp2 stream $self->{streamcode}\n" if $self->{debug};
+ }
+ if (length($frame) < 8) {print "Frame too small to analyse, returning for stream $self->{streamcode}\n"; return;}
+ my $BITS = unpack("B32", $frame);
+ if (substr($BITS,12,1) == 1) {$streamtype = "MPEG1"} else {$streamtype = "MPEG2"}
+
+ if (substr($BITS,13,2) eq "01") {$streamtype .= "_Layer_3"}
+ elsif (substr($BITS,13,2) eq "10") {$streamtype .= "_Layer_2"}
+ elsif (substr($BITS,13,2) eq "11") {$streamtype .= "_Layer_1"}
+ else {print "Streamtype invalid, returning -1\n"; return -1}
+
+ $frame_info{copyright} = substr($BITS,15,1);
+ if ($bitrates{$streamtype}{substr($BITS,16,4)}) {
+ $frame_info{bitrate} = $bitrates{$streamtype}{substr($BITS,16,4)} . "000"
+ }
+ else {
+ print "\nBitrate of the audio stream $self->{streamcode} could not be determined, skipping packet and trying again later\n";
+ print "Bitrate bits are:" . substr($BITS,14,4) . "\n" if $self->{debug};
+ return -1;
+ }
+
+ $frame_info{freq} = $freqs{substr($streamtype,0,5)}{substr($BITS,20,2)};
+ if (! $frame_info{freq}) {
+ print "\nFrequence of the audio stream $self->{streamcode} could not be determined, skipping packet and trying again later\n";
+ print "Freq bits are:" . substr($BITS,20,2) . "\n" if $self->{debug};
+ return -1;
+ }
+ $frame_info{padding_bit} = substr($BITS,22,1);
+
+ $frame_info{streamtype} = $streamtype;
+
+
+ if (substr($BITS,24,2) eq "00") {$frame_info{mode} = "stereo"}
+ elsif (substr($BITS,24,2) eq "01") {$frame_info{mode} = "joint_stereo"}
+ elsif (substr($BITS,24,2) eq "10") {$frame_info{mode} = "dual_channel"}
+ elsif (substr($BITS,24,2) eq "11") {$frame_info{mode} = "mono"}
+ #print "Mode: $frame_info{mode}\nbitrate: $frame_info{bitrate}, freq: $frame_info{freq}" if $self->{debug};
+
+
+ $frame_info{frame_bytes} = ($frame_info{bitrate} * 144 / $frame_info{freq}) + $frame_info{padding_bit};
+ $frame_info{frame_ticks} = 8 * $frame_info{frame_bytes} * 90000 / $frame_info{bitrate};
+
+ #print "Mode: $frame_info{mode}\nbytes: $frame_info{frame_bytes}\nticks: $frame_info{frame_ticks}\nbitrate: $frame_info{bitrate}\n";
+ $frame_info{packet_start} = substr($frame,0,2);
+ #print "The start of the packet is: $frame_info{packet_start}\n";
+ return ($frame, %frame_info);
+ #print "frame analysed\n";
+}
+
+sub find_next_pes_packet {
+ my $self = shift;
+ my $buffer = shift;
+ my $old_offset = shift;
+ my $search_buffer;
+ if ($old_offset > 0) {
+ $search_buffer = substr($buffer, $old_offset);
+ }
+ else {
+ $search_buffer = $buffer;
+ }
+ my $packet_start = pack("H6", "000001");
+ print "TRYING TO FIND A NEW PES PACKET START AFTER $old_offset\n";
+ print "Got a buffer of length " . length($buffer) . " to match against\n";
+ open DOF, ">./debug_buffer.vdr" || die "Can not open File to dump buffer\n";
+ binmode DOF;
+ print DOF $buffer;
+ close DOF;
+ my $counter = 0;
+ while ($search_buffer =~ /$packet_start/g) {
+
+ print "Now we found the new start at " . (pos($search_buffer)-3) . " \n";
+ return (pos($search_buffer) - 3 + (length($buffer) - length($search_buffer)));
+ }
+
+ print "did not find a new start\n";
+ return -1;
+}
+
+sub final_flush {
+ my $self = shift;
+ my $FH = $self->{outfile};
+ print "should do the final flush for stream $self->{streamcode}\n"if $self->{debug};
+ if ($self->{streamcode} eq $self->{masterstream}) {
+ print "Flushing Video Buffer, " . (length($self->{GOP_buffer})) . " bytes left\n"if $self->{debug};
+ my @pics = $self->{GOP_buffer} =~ /$self->{packet_start}/gm;
+ print "The last GOP contains " . (scalar(@pics)) . " pics\n"if $self->{debug};
+ print $FH $self->{GOP_buffer};
+ $self->{GOP_buffer} = "";
+ $self->{frameno} += scalar(@pics);
+ my $chunk_end = ${$self->{timestamps}}[-1] + (scalar(@pics)) * $self->{frame_ticks};
+ $cutlist[$self->{cutcounter}] .= "::$chunk_end" . "::$self->{frameno}";
+ if ($self->{debug}) {
+ foreach(@cutlist) {print "FINAL: $_\n";}
+ }
+ $self->{frames_written} = $self->{frameno};
+ return;
+ }
+ print $FH @{$self->{frame_buffer}};
+ $self->{frames_written} += scalar(@{$self->{frame_buffer}});
+ @{$self->{frame_buffer}} = "";
+ if (! $self->{audio_only}) {
+ my ($chunk_start, $chunk_end, $video_frameno) = split /::/,$cutlist[-1];
+ my $vid_time = $video_frameno * 3600;
+ my $aud_time = $self->{frames_written} * $self->{frame_ticks};
+ my $diff = $vid_time - $aud_time;
+ $self->{frames_written} += insert_frames($self, $diff);
+ }
+}
+
+
+sub process_PES_packets {
+ my $self = shift;
+ my $limit = shift;
+ my $offset = 0; # stores the position we are at in the current buffer
+ $self->{IFH} = undef; # Stores the filehandle for the current file
+ $self->{EOF} = 0; # All files processed ?
+ $self->{total_input} = 0;
+ my $lengthcounter = 0;
+ my $packetcounter = 0;
+
+ my %pes_header;
+ my $head_tmpl = 'H6 H2 n1 B8 B8 C1 B40';
+ my $dts_tmpl = 'B40';
+
+ my $buffer = ${ readNextChunk($self) }; # First we read the first chunk of data
+
+ ( $pes_header{startcode}, $pes_header{stream_id},
+ $pes_header{PES_packet_length}, $pes_header{eflags1},
+ $pes_header{eflags2}, $pes_header{header_length},
+ $pes_header{PTS_raw_bits})
+ = unpack ( $head_tmpl, substr($buffer, 0, 12) );
+
+ while (($self->{EOF} eq 0 || $offset + $pes_header{PES_packet_length} + 1) < (length($buffer))) {
+ if ($kill_me) {
+ my @kill_list;
+ if ($kill_me eq "all") { @kill_list = keys(% {$self->{streams} })}
+ else { push @kill_list, $kill_me }
+ if ($self->{dump_buffer}) {
+ print "Something nasty happend, dumping debug.buffer and exit\n";
+ my $start = 0;
+ if ($offset < 10000) {
+ print "Unfortunately the nasty thing happend at the start of a buffer \n";
+ print "offset is only $offset; Dumping anyway...\n";
+ }
+ if ((length($buffer) - $offset )< 1000000) {
+ print "Unfortunately the nasty thing happend at the end of a buffer \n";
+ print "offset is already $offset Dumping anyway...\n";
+ }
+ if ($offset > 1000000) {$start = $offset - 1000000}
+ open DFH, ">./debug.buffer";
+ binmode DFH;
+ print DFH substr($buffer, $start, $start + 2000000);
+ close DFH;
+ print "please mail the file and a short description of the recording to \n";
+ print "vdrsync\@gmx.net, then I will try to fix the bug\n";
+ exit 1;dump_buffer($self)
+ }
+ print "got the kill list @kill_list\n";
+ foreach (@kill_list) {
+ $self->{ignore_streams}{$_} = 1;
+ my $FH = $self->{streams}{$_}->{outfile};
+ close $FH;
+ unlink $self->{streams}{$_}->{outfilename};
+ print "Stream $_ was killed due to an error\n";
+ }
+ if ($kill_me eq "all") {die "Skript stopped due to an error\n";}
+ $kill_me="";
+
+ }
+
+
+ ( $pes_header{startcode}, $pes_header{stream_id},
+ $pes_header{PES_packet_length}, $pes_header{eflags1},
+ $pes_header{eflags2}, $pes_header{header_length},
+ $pes_header{PTS_raw_bits})
+ = unpack ( $head_tmpl, substr($buffer, $offset, 14) );
+
+ if ($pes_header{startcode} ne "000001") {
+ print "No 0x000001 found at current packet, found $pes_header{startcode} instead\noffset is $offset\n";
+ $offset = find_next_pes_packet($self, $buffer, $offset);
+
+ next;
+ }
+ my $decimal_code = hex($pes_header{stream_id});
+ if ((!(191 < $decimal_code ) && (240 > $decimal_code)) && (! $decimal_code == 189)) {
+ print "unknown Streamtype $pes_header{stream_id}, decimal $decimal_code ignoring\n" if $self->{debug};
+ $offset += $pes_header{PES_packet_length} + 6;
+ next;
+ }
+ # MPEG2 Audio and Video must have an extended Header as well as AC3
+ $pes_header{payload_start} = (9 + $pes_header{header_length});
+ # We check whether a TimeStamp is present:
+ $pes_header{PTS_DTS_flags} = substr($pes_header{eflags2}, 0, 2);
+
+ #FIXME: overflow of PTS not checked
+ if (($pes_header{PTS_DTS_flags} eq "10") || ($pes_header{PTS_DTS_flags} eq "11")) {
+ $pes_header{PTS_value_bits} = substr($pes_header{PTS_raw_bits},4,3) . substr($pes_header{PTS_raw_bits},8,15) . substr($pes_header{PTS_raw_bits},24,15);
+ # decode the timestamp
+ $pes_header{PTS_decimal} = oct("0b" . substr($pes_header{PTS_value_bits},1));
+ $pes_header{PTS_decimal} += 4294967296 if (substr($pes_header{PTS_value_bits},0,1) == 1);
+ }
+ else {
+ $pes_header{PTS_decimal} = 0;
+ }
+ $pes_header{data_align} = substr($pes_header{eflags1},6,1);
+
+ if ((($offset + $pes_header{PES_packet_length} + 150) > (length($buffer))) && ($self->{EOF} == 0)) {
+ my $helpbuffer = substr($buffer, $offset);
+ $buffer = $helpbuffer . ${ readNextChunk($self) };
+ $offset = 0;
+ }
+
+ my $packet = substr($buffer, $offset, $pes_header{PES_packet_length} + 6);
+ $offset += $pes_header{PES_packet_length} + 6;
+ $packetcounter++;
+ $lengthcounter += ($pes_header{PES_packet_length} + 6);
+
+
+ if ($self->{ignore_streams}{$pes_header{stream_id}}) {
+ print "ignoring packet for stream $pes_header{stream_id}\n" if $self->{debug};
+ next;
+ }
+ if (!($self->{streams}{$pes_header{stream_id}})) {
+ print "\nNew Stream with id $pes_header{stream_id}. Ignoring the stream\n" if (! $self->{audio_only});
+ $self->{ignore_streams}{$pes_header{stream_id}} = 1;
+ next;
+ }
+ if ($self->{dump_packets}) {
+ print "Dumping packet of stream $pes_header{stream_id} ($self->{dump_packets} to dump left)\n";
+ my $DUMPFH;
+ if (! $self->{"$pes_header{stream_id}.pes_dump"}) {
+ open $DUMPFH, ">$pes_header{stream_id}.pes_dump" || die "Can not open dumpfile: $!\n";
+ binmode $DUMPFH;
+ $self->{"$pes_header{stream_id}.pes_dump"} = $DUMPFH;
+ }
+ $DUMPFH = $self->{"$pes_header{stream_id}.pes_dump"};
+ print $DUMPFH $packet;
+ if ($self->{dump_packets}-- == 1) {
+ exit;
+ }
+ next;
+ }
+ &{$self->{streams}{$pes_header{stream_id}}->{check_frames}} (
+ $self->{streams}{$pes_header{stream_id}},
+ substr($packet,$pes_header{payload_start}),
+ \%pes_header
+ );
+ }
+
+ print "\n $packetcounter PES packets processed\n";
+
+
+ if (! $self->{audio_only}) {
+ $self->{streams}{$self->{masterstream}}->final_flush($self->{streams}{$self->{masterstream}});
+ }
+ foreach (keys (%{$self->{streams}})) {
+ if ($self->{ignore_streams}{$_}) {next}
+ if (! ($self->{masterstream} eq $_)) {
+ print "Final flush for stream $_\n"if $self->{debug};
+ $self->{streams}{$_}->final_flush($self->{streams}{$_});
+ }
+ my $seconds = $self->{streams}{$_}{frames_written} * $self->{streams}{$_}{frame_ticks} / 90000; #/
+ print "$self->{streams}{$_}{frames_written} frames written for stream $_ ($seconds sec) \n";
+ next;
+ }
+ print_script_output($self);
+ if (! $self->{script_output}){print_stats($self)};
+
+
+}
+
+sub print_script_output {
+ my $self = shift;
+
+ my %final_properties;
+ my $master = $self->{streams}{$self->{masterstream}};
+ my $max = 0;
+
+ foreach my $movie_property(keys(%{$master->{Unit_analysis_hash}})) {
+ print "found key $movie_property\n" if $self->{debug};
+ foreach my $subkey (keys(%{$master->{Unit_analysis_hash}{$movie_property}})) {
+ print "found subkey $subkey with value $master->{Unit_analysis_hash}{$movie_property}{$subkey}\n" if $self->{debug};
+ if ((!$final_properties{$movie_property}) || $max < $master->{Unit_analysis_hash}{$movie_property}{$subkey}) {
+ $final_properties{$movie_property} = $subkey;
+ $max = $master->{Unit_analysis_hash}{$movie_property}{$subkey};
+ }
+
+ }
+ }
+ $max = 0;
+ if ($self->{streams}{bd}) {
+ my $ac3_audio= $self->{streams}{bd};
+ foreach my $ac3_property(keys(%{$ac3_audio->{Unit_analysis_hash}})) {
+ print "found key $ac3_property\n" if $self->{debug};
+ foreach my $subkey (keys(%{$ac3_audio->{Unit_analysis_hash}{$ac3_property}})) {
+ print "found subkey $subkey with value $ac3_audio->{Unit_analysis_hash}{$ac3_property}{$subkey}\n" if $self->{debug};
+ if ((!$final_properties{$ac3_property}) || $max < $ac3_audio->{Unit_analysis_hash}{$ac3_property}{$subkey}) {
+ $final_properties{$ac3_property} = $subkey;
+ $max = $ac3_audio->{Unit_analysis_hash}{$ac3_property}{$subkey};
+ }
+ }
+ }
+ }
+
+
+ foreach (keys(%final_properties)) {
+ print "Property $_ is $final_properties{$_}\n" if $self->{debug};
+ $self->{streams}{$self->{masterstream}}->{$_} = $final_properties{$_};
+ }
+ if (! $self->{script_output}) {
+ return
+ }
+
+
+ print "*" x 45 ."\n";
+ foreach (keys(%{$self->{streams}})) {
+ print "$self->{streams}{$_}{streamtype} for stream $_\n" if $self->{debug};
+ if ($self->{ignore_streams}{$_}) {
+ print "Ignoring stream $_\n" if $self->{debug};
+ next;
+ }
+
+ if (($self->{streams}{$_}{streamtype} =~ /audio/) || ($self->{streams}{$_}{streamtype} =~ /Layer/)) {
+
+ my $seconds = $self->{streams}{$_}->{frames_written} * $self->{streams}{$_}->{frame_ticks} / 90000; #/
+ print "$_" . "_Audio_stream=yes\n";
+ print "$_" . "_Audio_type=$self->{streams}{$_}{streamtype}\n";
+ print "$_" . "_Sample_frequency=$self->{streams}{$_}->{freq}\n"; # only for Audio
+ print "$_" . "_Bitrate=$self->{streams}{$_}->{bitrate}\n"; # only for Audio
+ print "$_" . "_Mode=$self->{streams}{$_}->{mode}\n"; # only for Audio
+ print "$_" . "_Copyright=$self->{streams}{$_}->{copyright}\n" if $self->{streams}{$_}->{copyright}; # only for Audio
+ print "$_" . "_Bytes_per_frame=$self->{streams}{$_}->{frame_bytes}\n"; # only for Audio
+ print "$_" . "_Ticks_per_frame=$self->{streams}{$_}->{frame_ticks}\n"; # one tick is 1 / 90000 of a second
+ print "$_" . "_Total_frames=$self->{streams}{$_}->{frames_written}\n";
+ print "$_" . "_Total_time=$seconds\n\n";
+
+ }
+ if ($self->{streams}{$_}{streamtype} eq "video") {
+
+ my $seconds = $self->{streams}{$_}->{frames_written} * $self->{streams}{$_}->{frame_ticks} / 90000; #/
+ print "$_" . "_Video_stream=yes\n";
+ print "$_" . "_Aspect_ratio=$self->{streams}{$_}->{aspect_ratio}\n";
+ print "$_" . "_Horizontal_size=$self->{streams}{$_}->{horizontal_size}\n";
+ print "$_" . "_Vertical_size=$self->{streams}{$_}->{vertical_size}\n";
+ print "$_" . "_Frames_per_Second=$self->{streams}{$_}->{fps}\n";
+ print "$_" . "_Bitrate=$self->{streams}{$_}{bitrate_value}\n";
+ print "$_" . "_Ticks_per_frame=$self->{streams}{$_}->{frame_ticks}\n";
+ print "$_" . "_Total_frames=$self->{streams}{$_}->{frames_written}\n";
+ print "$_" . "_Total_time=$seconds\n\n";
+
+ }
+ }
+}
+
+sub init_PES_stream {
+ my $self = shift;
+ my $limit = shift;
+ my $offset = 0; # stores the position we are at in the current buffer
+ my $plength = 0;
+ $self->{IFH} = undef; # Stores the filehandle for the current file
+ $self->{EOF} = 0; # All files processed ?
+ $self->{total_input} = 0;
+ my %pes_header;
+ $pes_header{packet_length} = 0;
+ my $head_tmpl = 'H6 H2 n1 B8 B8 C1 B40';
+
+
+
+ my $packetcounter = 0;
+
+ print "Initialising and analysing the streams....\n";
+ my @save_file_list = @{$self->{files}};
+
+ my $buffer = ${ readNextChunk($self) }; # First we read the first chunk of data
+
+ while ((($self->{EOF} eq 0 || $offset + $pes_header{packet_length} + 1) < (length($buffer))) && ($packetcounter < 2000)) {
+ ( $pes_header{startcode}, $pes_header{stream_id},
+ $pes_header{PES_packet_length}, $pes_header{eflags1},
+ $pes_header{eflags2}, $pes_header{header_length},
+ $pes_header{PTS_raw_bits})
+ = unpack ( $head_tmpl, substr($buffer, $offset, 12) );
+
+ $pes_header{payload_start} = (9 + $pes_header{header_length});
+ # there are at leat six bytes of header at the beginning of a PES packet
+ if ( $pes_header{startcode} ne "000001") {
+ print "No 0x000001 found at current packet, searching for next Packet start\n";
+ $offset = find_next_pes_packet($self, $buffer, $offset);
+ if ($offset == -1) {$kill_me = "all"}
+ next;
+ }
+ # We check whether a TimeStamp is present:
+ $pes_header{PTS_DTS_flags} = substr($pes_header{eflags2}, 0, 2);
+ if (($pes_header{PTS_DTS_flags} eq "10") || ($pes_header{PTS_DTS_flags} eq "11")) {
+ $pes_header{PTS_value_bits} = substr($pes_header{PTS_raw_bits},4,3) . substr($pes_header{PTS_raw_bits},8,15) . substr($pes_header{PTS_raw_bits},24,15);
+ # decode the timestamp
+ $pes_header{PTS_decimal} = unpack("N", (pack ("B32", substr($pes_header{PTS_value_bits},1))));
+ $pes_header{PTS_decimal} += 4294967296 if (substr($pes_header{PTS_value_bits},0,1) == 1);
+ }
+ else {
+ $pes_header{PTS_decimal} = 0;
+ }
+ if ((($offset + $pes_header{PES_packet_length} + 150) > (length($buffer))) && ($self->{EOF} == 0)) {
+ my $helpbuffer = substr($buffer, $offset);
+ $buffer = $helpbuffer . ${ readNextChunk($self) };
+ $offset = 0;
+ }
+
+ my $packet = substr($buffer, $offset, ($pes_header{PES_packet_length} + 6));
+ $offset += $pes_header{PES_packet_length} + 6;
+ $packetcounter++;
+
+ #print "analysed the first $packetcounter packets...\n" if $self->{debug};
+ if (!$self->{streams}{$pes_header{stream_id}}) {
+ if ($self->{ignore_streams}{$pes_header{stream_id}}){
+ next;
+ }
+
+ my $decimal_code = hex($pes_header{stream_id});
+ if ((223 < $decimal_code ) && (240 > $decimal_code)){
+ if ($self->{audio_only}) {
+ $self->{ingnore_streams}{$pes_header{stream_id}} = 1;
+ next;
+ }
+
+ if ($self->{masterstream}){
+ print "Video stream already defined, but found stream $pes_header{stream_id} in addition. Ingnoring stream $pes_header{stream_id}\n";
+ $self->{ingnore_streams}{$pes_header{stream_id}} = 1;
+ next;
+ }
+ else {
+ $self->{streams}{$pes_header{stream_id}} = MPEGSTREAM->new
+ (
+ streamcode => $pes_header{stream_id},
+ outputpath => $self->{outputpath},
+ masterstream => $pes_header{stream_id},
+ debug => $self->{debug},
+ dump_payload => $self->{dump_payload},
+ show_drift => $self->{show_drift},
+ dump_buffer => $self->{dump_buffer},
+ );
+ $self->{masterstream} = $pes_header{stream_id};
+ print "\nCreated new MPEG stream object for stream $pes_header{stream_id}, master video stream\n";
+ }
+ }
+ else {
+ $self->{streams}{$pes_header{stream_id}} = MPEGSTREAM->new
+ (
+ streamcode => $pes_header{stream_id},
+ masterstream => $self->{masterstream},
+ outputpath => $self->{outputpath},
+ debug => $self->{debug},
+ dump_payload => $self->{dump_payload},
+ audio_only => $self->{audio_only},
+ show_drift => $self->{show_drift},
+ dump_buffer => $self->{dump_buffer},
+ );
+ print "\nCreated new MPEG stream object for stream $pes_header{stream_id} \n";
+ }
+
+ }
+
+ if (!($self->{streams}{$pes_header{stream_id}}{check_frames}))
+ {
+ print "sending frame number $packetcounter for analysis of stream $pes_header{stream_id}\n" if $self->{debug};
+ init_stream($self->{streams}{$pes_header{stream_id}}, substr($packet, $pes_header{payload_start}), \%pes_header);
+ }
+ }
+
+
+ @{$self->{files}} = @save_file_list;
+ print "analysed the first $packetcounter packets...\n";
+ my $IFH = $self->{IFH};
+ close $IFH;
+
+ if (!($self->{masterstream}))
+ {
+ die "No video stream could be found within the first 2000 packets, exiting\n" if (! $self->{ignore_streams});
+ }
+
+ foreach (keys(%{$self->{streams}}))
+ {
+ $self->{streams}{$_}{masterstream} = $self->{masterstream};
+
+ if ((!($self->{streams}{$_}{check_frames})) && (!($self->{ignore_streams}{$_})))
+ {
+ print "The contents of stream $_ could not be identified, the stream will be skipped!\n";
+ $self->{ignore_streams}{$_} = 1;
+ }
+ }
+
+ print_stats($self) if $self->{debug};
+ return;
+}
+
+
+
+sub get_aspect_ratio {
+ my $self = shift;
+ return $self->{streams}{$self->{masterstream}}->{aspect_ratio};
+}
+
+sub readNextChunk {
+ my $self = shift;
+ my $IFH = $self->{IFH};
+
+
+ if (!($self->{IFH})) {
+ my $firstfile = shift @{$self->{files}};
+ print "trying to open $firstfile\n" if $self->{debug};
+ open $IFH, $firstfile || die "$! happend while opening $firstfile\n";
+ binmode $IFH;
+ $self->{IFH} = $IFH;
+ }
+
+ my $rbuffer;
+ my $rbytes = sysread $IFH, $rbuffer, 10000000, 0;
+
+ if ($rbytes != 10000000 ) {
+ if ((scalar(@{$self->{files}}))== 0) {
+ print "\nall Input files processed\n";
+ print "EOF reached\n";
+ $self->{EOF} = 1;
+ }
+ else {
+ my $nextf = shift @{$self->{files}};
+ print "$nextf is the next file\n";
+ close $IFH;
+ open $IFH, $nextf || die "$! happend while opening $nextf\n";
+ binmode $IFH;
+ $self->{IFH} = $IFH;
+ my $helpbuffer;
+ my $helprbytes = sysread $self->{IFH}, $helpbuffer, (10000000 - length($rbuffer)), 0;
+ $rbuffer .= $helpbuffer;
+ $rbytes += $helprbytes;
+ }
+ }
+ $self->{total_input} += $rbytes;
+ my $status = sprintf ("%4d", ($self->{total_input} / 1000000));#/
+ $bytes_read = $self->{total_input};
+ print "\r$status Mbytes of " . int($total_size/1000000) . " read"; #if $self->{debug}; f
+ return \$rbuffer;
+}
+
+
+
+sub get_silent_frame {
+ my $self = shift;
+ my %info = % { shift @_ };
+ my $frame;
+ my $function;
+
+ if ($info{streamtype} eq "MPEG1_Layer_2") {
+ $function = "get_$info{mode}_" . "$info{bitrate}";
+ }
+ elsif ($info{streamtype} eq "AC3_Audio") {
+ $info{mode} =~ s/\//_/;
+ $function = "get_ac3_$info{mode}_" . "$info{bitrate}";
+ }
+ else {
+ print "Can not understand Format $info{streamtype}, no silent frame available\n" if $self->{debug}; return -1;
+ }
+
+ my $uu_frame = eval $function ;
+ if (! $uu_frame) {print "No silent frame available for $function\n" if $self->{debug}; return -1}
+ foreach (split "\n", $uu_frame) {
+ last if /^end/;
+ next if /[a-z]/;
+ next unless int((((ord() - 32) & 077) + 2) / 3) == int(length() / 4);
+ $frame .= unpack "u", $_;
+ }
+
+ return $frame;
+}
+
+
+
+sub get_mono_32000 {
+my $frame = <<'End_FRAME';
+M__T4P!%)I&JJOOOOOOOOFM?/EL?/FM:^?+8^?-:U\^6Q\^:UKY\MCY\UK7SY
+M;'SYK6OGRV/GS6M?/EL?/FM:^?+8^?-:U\^6Q\^:UKY\MCY\UK7SY;'SYK6O
+&GRV/GS0`
+end
+End_FRAME
+return $frame;
+}
+
+sub get_mono_48000 {
+my $frame = <<'End_FRAME';
+M__TDP#-R-NJJOOOOOOOOEL6Q;'=W=UL6Q;%L6Q;'=W=UL6Q;%L6Q;'=W=UL6
+MQ;%L6Q;'=W=UL6Q;%L6Q;'=W=UL6Q;%L6Q;'=W=UL6Q;%L6Q;'=W=UL6Q;%L
+M6Q;'=W=UL6Q;%L6Q;'=W=UL6Q;%L6Q;'=W=UL6Q;%L6Q;'=W=UL6Q;%L6Q;'
+)=W=UL6Q;````
+end
+End_FRAME
+return $frame;
+}
+
+sub get_mono_56000 {
+
+my $frame = <<'End_FRAME';
+M__TTP!(C,R(B$D``````JJJJOOOOOOOOOOOOOFMMMMMMMM\^?/FM:UMMMMMM
+MMOGSY\UK6MMMMMMMM\^?/FM:UMMMMMMMOGSY\UK6MMMMMMMM\^?/FM:UMMMM
+MMMMOGSY\UK6MMMMMMMM\^?/FM:UMMMMMMMOGSY\UK6MMMMMMMM\^?/FM:UMM
+AMMMMMOGSY\UK6MMMMMMMM\^?/FM:UMMMMMMMOGSY\UK0
+end
+End_FRAME
+
+return $frame;
+}
+
+sub get_mono_64000 {
+my $frame = <<'End_FRAME';
+M__U$P"(D1$,B)$``````JJJJOOOOOOOOOOOOOFVVVVMBV+8MC;?/GSYK;;;;
+M6Q;%L6QMOGSY\UMMMMK8MBV+8VWSY\^:VVVVUL6Q;%L;;Y\^?-;;;;:V+8MB
+MV-M\^?/FMMMMM;%L6Q;&V^?/GS6VVVVMBV+8MC;?/GSYK;;;;6Q;%L6QMOGS
+MY\UMMMMK8MBV+8VWSY\^:VVVVUL6Q;%L;;Y\^?-;;;;:V+8MBV-M\^?/FMMM
+,MM;%L6Q;&V^?/GS0
+end
+End_FRAME
+return $frame;
+}
+
+
+sub get_mono_80000 {
+my $frame = <<'End_FRAME';
+M__U4P"(U541#-HD`````JJJJJ^^^^^^^^^^^^^^^;;;=W=W=W=W6Q;%L;;;;
+M;YK6VVW=W=W=W=UL6Q;&VVVV^:UMMMW=W=W=W=;%L6QMMMMOFM;;;=W=W=W=
+MW6Q;%L;;;;;YK6VVW=W=W=W=UL6Q;&VVVV^:UMMMW=W=W=W=;%L6QMMMMOFM
+M;;;=W=W=W=W6Q;%L;;;;;YK6VVW=W=W=W=UL6Q;&VVVV^:UMMMW=W=W=W=;%
+ML6QMMMMOFM;;;=W=W=W=W6Q;%L;;;;;YK6VVW=W=W=W=UL6Q;&VVVV^:UMMM
+/W=W=W=W=;%L6QMMMMOFM
+end
+End_FRAME
+return $frame;
+}
+
+sub get_mono_96000 {
+my $frame = <<'End_FRAME';
+M__UDP#,V9E5$2-$@````JJJJJOOOOOOOOOOOOOOOOG=W=W=WO>][WO>[N[NM
+MBV+8MC;?-:[N[N[N][WO>][W=W=UL6Q;%L;;YK7=W=W=WO>][WO>[N[NMBV+
+M8MC;?-:[N[N[N][WO>][W=W=UL6Q;%L;;YK7=W=W=WO>][WO>[N[NMBV+8MC
+M;?-:[N[N[N][WO>][W=W=UL6Q;%L;;YK7=W=W=WO>][WO>[N[NMBV+8MC;?-
+M:[N[N[N][WO>][W=W=UL6Q;%L;;YK7=W=W=WO>][WO>[N[NMBV+8MC;?-:[N
+M[N[N][WO>][W=W=UL6Q;%L;;YK7=W=W=WO>][WO>[N[NMBV+8MC;?-:[N[N[
+2N][WO>][W=W=UL6Q;%L;;YK0
+end
+End_FRAME
+return $frame;
+}
+
+sub get_mono_112000 {
+my $frame = <<'End_FRAME';
+M__UTP#-&=F956R(D````JJJJJK[[[[[[[[[[[[[[[[YW=W=[WO>]]]][WO>]
+M[WN[N[N[N[K8MCYK7=W=WO>][WWWWO>][WO>[N[N[N[NMBV/FM=W=W>][WO?
+M??>][WO>][N[N[N[NZV+8^:UW=W=[WO>]]]][WO>][WN[N[N[N[K8MCYK7=W
+M=WO>][WWWWO>][WO>[N[N[N[NMBV/FM=W=W>][WO???>][WO>][N[N[N[NZV
+M+8^:UW=W=[WO>]]]][WO>][WN[N[N[N[K8MCYK7=W=WO>][WWWWO>][WO>[N
+M[N[N[NMBV/FM=W=W>][WO???>][WO>][N[N[N[NZV+8^:UW=W=[WO>]]]][W
+MO>][WN[N[N[N[K8MCYK7=W=WO>][WWWWO>][WO>[N[N[N[NMBV/FM=W=W>][
+5WO???>][WO>][N[N[N[NZV+8^:T`
+end
+End_FRAME
+return $frame;
+}
+
+sub get_mono_128000 {
+my $frame = <<'End_FRAME';
+M__V$P$17=V9F:V-D````JJJJJK[[[[[[[[[[[[[[[[Y[WO>]]]]]]]]]]]]]
+M[WO>][WO>][WN[N[K8VVVU[WO>]]]]]]]]]]]]][WO>][WO>][WN[N[K8VVV
+MU[WO>]]]]]]]]]]]]][WO>][WO>][WN[N[K8VVVU[WO>]]]]]]]]]]]]][WO
+M>][WO>][WN[N[K8VVVU[WO>]]]]]]]]]]]]][WO>][WO>][WN[N[K8VVVU[W
+MO>]]]]]]]]]]]]][WO>][WO>][WN[N[K8VVVU[WO>]]]]]]]]]]]]][WO>][
+MWO>][WN[N[K8VVVU[WO>]]]]]]]]]]]]][WO>][WO>][WN[N[K8VVVU[WO>]
+M]]]]]]]]]]]][WO>][WO>][WN[N[K8VVVU[WO>]]]]]]]]]]]]][WO>][WO>
+M][WN[N[K8VVVU[WO>]]]]]]]]]]]]][WO>][WO>][WN[N[K8VVVU[WO>]]]]
+8]]]]]]]]][WO>][WO>][WN[N[K8VVVT`
+end
+End_FRAME
+return $frame;
+}
+
+sub get_mono_160000 {
+my $frame = <<'End_FRAME';
+M__V4P%5HF(=W?;60@```JJJJJJ^^^^^^^^^^^^^^^^^^???????OW[]^_?W]
+M_?OW[]^_????????????>][WO>][NZV+8U]]]]]]^_?OW[]_?W]^_?OW[]]]
+M]]]]]]]]]][WO>][WN[K8MC7WWWWWW[]^_?OW]_?W[]^_?OWWWWWWWWWWWWW
+MO>][WO>[NMBV-???????OW[]^_?W]_?OW[]^_????????????>][WO>][NZV
+M+8U]]]]]]^_?OW[]_?W]^_?OW[]]]]]]]]]]]]][WO>][WN[K8MC7WWWWWW[
+M]^_?OW]_?W[]^_?OWWWWWWWWWWWWWO>][WO>[NMBV-???????OW[]^_?W]_?
+MOW[]^_????????????>][WO>][NZV+8U]]]]]]^_?OW[]_?W]^_?OW[]]]]]
+M]]]]]]]][WO>][WN[K8MC7WWWWWW[]^_?OW]_?W[]^_?OWWWWWWWWWWWWWO>
+M][WO>[NMBV-???????OW[]^_?W]_?OW[]^_????????????>][WO>][NZV+8
+MU]]]]]]^_?OW[]_?W]^_?OW[]]]]]]]]]]]]][WO>][WN[K8MC7WWWWWW[]^
+>_?OW]_?W[]^_?OWWWWWWWWWWWWWO>][WO>[NMBV-
+end
+End_FRAME
+return $frame;
+}
+
+sub get_mono_192000 {
+my $frame = <<'End_FRAME';
+M__VDP%9IF8B(?[:Q$```JJJJJJOOOOOOOOOOOOOOOOOOOGWWW[]^_?OW]_?W
+M]_?W]_?W[]^_?OW[]^_?OWWWW__?_]__WO>][WO>[NMCYK[[[]^_?OW[^_O[
+M^_O[^_O[]^_?OW[]^_?OW[[[[__O_^__[WO>][WO=W6Q\U]]]^_?OW[]_?W]
+M_?W]_?W]^_?OW[]^_?OW[]]]]__W__?_][WO>][WN[K8^:^^^_?OW[]^_O[^
+M_O[^_O[^_?OW[]^_?OW[]^^^^__[__O_^][WO>][W=UL?-????OW[]^_?W]_
+M?W]_?W]_?OW[]^_?OW[]^_????_]__W__>][WO>][NZV/FOOOOW[]^_?O[^_
+MO[^_O[^_OW[]^_?OW[]^_?OOOO_^__[__O>][WO>]W=;'S7WWW[]^_?OW]_?
+MW]_?W]_?W[]^_?OW[]^_?OWWWW__?_]__WO>][WO>[NMCYK[[[]^_?OW[^_O
+M[^_O[^_O[]^_?OW[]^_?OW[[[[__O_^__[WO>][WO=W6Q\U]]]^_?OW[]_?W
+M]_?W]_?W]^_?OW[]^_?OW[]]]]__W__?_][WO>][WN[K8^:^^^_?OW[]^_O[
+M^_O[^_O[^_?OW[]^_?OW[]^^^^__[__O_^][WO>][W=UL?-????OW[]^_?W]
+M_?W]_?W]_?OW[]^_?OW[]^_????_]__W__>][WO>][NZV/FOOOOW[]^_?O[^
+D_O[^_O[^_OW[]^_?OW[]^_?OOOO_^__[__O>][WO>]W=;'S0
+end
+End_FRAME
+return $frame;
+}
+
+
+sub get_stereo_48000 {
+my $frame = <<'End_FRAME';
+M__TD```1)22)))JJJJK[[[[[[[[[[[[[YK6M?/GSYK6M:UK6M?/GSYK6M:UK
+M6M?/GSYK6M:UK6M?/GSYK6M:UK6M?/GSYK6M:UK6M?/GSYK6M:UK6M?/GSYK
+M6M:UK6M?/GSYK6M:UK6M?/GSYK6M:UK6M?/GSYK6M:UK6M?/GSYK6M:UK6M?
+)/GSYK6M:T```
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_56000{
+my $frame = <<'End_FRAME';
+M__TT`!$11222))JJJJJOOOOOOOOOOOOOOOOFM:U\U\^?/GSYK6M:UK7S7SY\
+M^?/FM:UK6M?-?/GSY\^:UK6M:U\U\^?/GSYK6M:UK7S7SY\^?/FM:UK6M?-?
+M/GSY\^:UK6M:U\U\^?/GSYK6M:UK7S7SY\^?/FM:UK6M?-?/GSY\^:UK6M:U
+A\U\^?/GSYK6M:UK7S7SY\^?/FM:UK6M?-?/GSY\^:UK0
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_64000 {
+my $frame = <<'End_FRAME';
+M__U$`!$12;;21)JJJJJOOOOOOOOOOOOOOOOFM:U\^6Q;%L6Q\^?-:UK6M?/E
+ML6Q;%L?/GS6M:UK7SY;%L6Q;'SY\UK6M:U\^6Q;%L6Q\^?-:UK6M?/EL6Q;%
+ML?/GS6M:UK7SY;%L6Q;'SY\UK6M:U\^6Q;%L6Q\^?-:UK6M?/EL6Q;%L?/GS
+M6M:UK7SY;%L6Q;'SY\UK6M:U\^6Q;%L6Q\^?-:UK6M?/EL6Q;%L?/GS6M:UK
+,7SY;%L6Q;'SY\UK0
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_80000{
+my $frame = <<'End_FRAME';
+M__U4`"(B;;;;;2JJJJJOOOOOOOOOOOOOOOOGSY\^6Q;%L6Q;%L6Q;%L6Q\^?
+M/GSY;%L6Q;%L6Q;%L6Q;'SY\^?/EL6Q;%L6Q;%L6Q;%L?/GSY\^6Q;%L6Q;%
+ML6Q;%L6Q\^?/GSY;%L6Q;%L6Q;%L6Q;'SY\^?/EL6Q;%L6Q;%L6Q;%L?/GSY
+M\^6Q;%L6Q;%L6Q;%L6Q\^?/GSY;%L6Q;%L6Q;%L6Q;'SY\^?/EL6Q;%L6Q;%
+ML6Q;%L?/GSY\^6Q;%L6Q;%L6Q;%L6Q\^?/GSY;%L6Q;%L6Q;%L6Q;'SY\^?/
+/EL6Q;%L6Q;%L6Q;%L?/@
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_96000{
+my $frame = <<'End_FRAME';
+M__UD`#,SCDDD;;JJJJJOOOOOOOOOOOOOOOOEL6Q;%L=W6QW=W=W=W=W=W=;%
+ML6Q;%L6Q;%L=W6QW=W=W=W=W=W=;%L6Q;%L6Q;%L=W6QW=W=W=W=W=W=;%L6
+MQ;%L6Q;%L=W6QW=W=W=W=W=W=;%L6Q;%L6Q;%L=W6QW=W=W=W=W=W=;%L6Q;
+M%L6Q;%L=W6QW=W=W=W=W=W=;%L6Q;%L6Q;%L=W6QW=W=W=W=W=W=;%L6Q;%L
+M6Q;%L=W6QW=W=W=W=W=W=;%L6Q;%L6Q;%L=W6QW=W=W=W=W=W=;%L6Q;%L6Q
+M;%L=W6QW=W=W=W=W=W=;%L6Q;%L6Q;%L=W6QW=W=W=W=W=W=;%L6Q;%L6Q;%
+2L=W6QW=W=W=W=W=W=;%L6Q;`
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_112000{
+my $frame = <<'End_FRAME';
+M__UT`!$B(C-#,S(B(B(1))````````````"JJJJJJJJOOOOOOOOOOOOOOOOO
+MOOOOOOOOOFM;;;;;;;;;6QMMMMMM\^?/GSY\UK6M:UK;;;;;;;;:V-MMMMMO
+MGSY\^?/FM:UK6M;;;;;;;;;6QMMMMMM\^?/GSY\UK6M:UK;;;;;;;;:V-MMM
+MMMOGSY\^?/FM:UK6M;;;;;;;;;6QMMMMMM\^?/GSY\UK6M:UK;;;;;;;;:V-
+MMMMMMOGSY\^?/FM:UK6M;;;;;;;;;6QMMMMMM\^?/GSY\UK6M:UK;;;;;;;;
+M:V-MMMMMOGSY\^?/FM:UK6M;;;;;;;;;6QMMMMMM\^?/GSY\UK6M:UK;;;;;
+M;;;:V-MMMMMOGSY\^?/FM:UK6M;;;;;;;;;6QMMMMMM\^?/GSY\UK6M:UK;;
+5;;;;;;:V-MMMMMOGSY\^?/FM:UK0
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_128000{
+my $frame = <<'End_FRAME';
+M__V$`"(B(D1$1#,R(B(B)))```````````"JJJJJJJJJ^^^^^^^^^^^^^^^^
+M^^^^^^^^^^^^;;;;;;;;;6Q;%L6Q;%L;;;;;Y\^?/GSYK6M:UMMMMMMMMM;%
+ML6Q;%L6QMMMMOGSY\^?/FM:UK6VVVVVVVVUL6Q;%L6Q;&VVVV^?/GSY\^:UK
+M6M;;;;;;;;;6Q;%L6Q;%L;;;;;Y\^?/GSYK6M:UMMMMMMMMM;%L6Q;%L6QMM
+MMMOGSY\^?/FM:UK6VVVVVVVVUL6Q;%L6Q;&VVVV^?/GSY\^:UK6M;;;;;;;;
+M;6Q;%L6Q;%L;;;;;Y\^?/GSYK6M:UMMMMMMMMM;%L6Q;%L6QMMMMOGSY\^?/
+MFM:UK6VVVVVVVVUL6Q;%L6Q;&VVVV^?/GSY\^:UK6M;;;;;;;;;6Q;%L6Q;%
+ML;;;;;Y\^?/GSYK6M:UMMMMMMMMM;%L6Q;%L6QMMMMOGSY\^?/FM:UK6VVVV
+8VVVVUL6Q;%L6Q;&VVVV^?/GSY\^:UK6M
+end
+End_FRAME
+return $frame;
+}
+
+
+sub get_stereo_160000{
+my $frame = <<'End_FRAME';
+M__V4`"(R,U55541$0S,S;2))``````````"JJJJJJJJJK[[[[[[[[[[[[[[[
+M[[[[[[[[[[[[[[YMMMW=MN[N[N[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?/FM
+M:UMMMW=MN[N[N[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?/FM:UMMMW=MN[N[N
+M[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?/FM:UMMMW=MN[N[N[N[N[N[N[N[K8
+MMBV+8MC;;;;;;;;;;?/FM:UMMMW=MN[N[N[N[N[N[N[N[K8MBV+8MC;;;;;;
+M;;;;?/FM:UMMMW=MN[N[N[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?/FM:UMMM
+MW=MN[N[N[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?/FM:UMMMW=MN[N[N[N[N[
+MN[N[N[K8MBV+8MC;;;;;;;;;;?/FM:UMMMW=MN[N[N[N[N[N[N[N[K8MBV+8
+MMC;;;;;;;;;;?/FM:UMMMW=MN[N[N[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?
+M/FM:UMMMW=MN[N[N[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?/FM:UMMMW=MN[
+>N[N[N[N[N[N[N[K8MBV+8MC;;;;;;;;;;?/FM:T`
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_192000{
+my $frame = <<'End_FRAME';
+M__VD`#,S,V9F9E551$1$DC21)`````````"JJJJJJJJJJOOOOOOOOOOOOOOO
+MOOOOOOOOOOOOOOOOOG=W=W=W=W=W=WO>][WO>][WO>][W=W=W=W=UL6Q;%L6
+MQ;%L6Q;&V^?/FM:[N[N[N[N[N[N][WO>][WO>][WO>[N[N[N[NMBV+8MBV+8
+MMBV+8VWSY\UK7=W=W=W=W=W=WO>][WO>][WO>][W=W=W=W=UL6Q;%L6Q;%L6
+MQ;&V^?/FM:[N[N[N[N[N[N][WO>][WO>][WO>[N[N[N[NMBV+8MBV+8MBV+8
+MVWSY\UK7=W=W=W=W=W=WO>][WO>][WO>][W=W=W=W=UL6Q;%L6Q;%L6Q;&V^
+M?/FM:[N[N[N[N[N[N][WO>][WO>][WO>[N[N[N[NMBV+8MBV+8MBV+8VWSY\
+MUK7=W=W=W=W=W=WO>][WO>][WO>][W=W=W=W=UL6Q;%L6Q;%L6Q;&V^?/FM:
+M[N[N[N[N[N[N][WO>][WO>][WO>[N[N[N[NMBV+8MBV+8MBV+8VWSY\UK7=W
+M=W=W=W=W=WO>][WO>][WO>][W=W=W=W=UL6Q;%L6Q;%L6Q;&V^?/FM:[N[N[
+MN[N[N[N][WO>][WO>][WO>[N[N[N[NMBV+8MBV+8MBV+8VWSY\UK7=W=W=W=
+MW=W=WO>][WO>][WO>][W=W=W=W=UL6Q;%L6Q;%L6Q;&V^?/FM:[N[N[N[N[N
+D[N][WO>][WO>][WO>[N[N[N[NMBV+8MBV+8MBV+8VWSY\UK0
+end
+End_FRAME
+return $frame;
+}
+
+
+sub get_stereo_224000{
+my $frame = <<'End_FRAME';
+M__VT`#,S1'=W9F9F5555MD;2))````````"JJJJJJJJJJJ^^^^^^^^^^^^^^
+M^^^^^^^^^^^^^^^^^^^^=W=W=W=W>][WO????????????>][WO>][WO>][WO
+M=W=W=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W>][WO????????????>][WO>]
+M[WO>][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W>][WO???????????
+M?>][WO>][WO>][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W>][WO???
+M?????????>][WO>][WO>][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W
+M>][WO????????????>][WO>][WO>][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M
+M=W=W=W=W>][WO????????????>][WO>][WO>][WO=W=W=W=W=W=W=W=W6Q;&
+MVVWSYK6M=W=W=W=W>][WO????????????>][WO>][WO>][WO=W=W=W=W=W=W
+M=W=W6Q;&VVWSYK6M=W=W=W=W>][WO????????????>][WO>][WO>][WO=W=W
+M=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W>][WO????????????>][WO>][WO>
+M][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W>][WO????????????>][
+MWO>][WO>][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W>][WO???????
+M?????>][WO>][WO>][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M=W=W=W=W>][W
+JO????????????>][WO>][WO>][WO=W=W=W=W=W=W=W=W6Q;&VVWSYK6M
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_256000{
+my $frame = <<'End_FRAME';
+M__W$`$1$57=W=V9F9F9FVMD;:)````````"JJJJJJJJJJJ^^^^^^^^^^^^^^
+M^^^^^^^^^^^^^^^^^^^^>][WO>][WO????????????????????????>][WO>
+M][WO>][WO>][WO>][WO>][WO=W=W6Q;&VVVV^:U[WO>][WO>]]]]]]]]]]]]
+M]]]]]]]]]]]]][WO>][WO>][WO>][WO>][WO>][WO>]W=W=;%L;;;;;YK7O>
+M][WO>][WWWWWWWWWWWWWWWWWWWWWWWWWO>][WO>][WO>][WO>][WO>][WO>]
+M[W=W=UL6QMMMMOFM>][WO>][WO????????????????????????>][WO>][WO
+M>][WO>][WO>][WO>][WO=W=W6Q;&VVVV^:U[WO>][WO>]]]]]]]]]]]]]]]]
+M]]]]]]]]][WO>][WO>][WO>][WO>][WO>][WO>]W=W=;%L;;;;;YK7O>][WO
+M>][WWWWWWWWWWWWWWWWWWWWWWWWWO>][WO>][WO>][WO>][WO>][WO>][W=W
+M=UL6QMMMMOFM>][WO>][WO????????????????????????>][WO>][WO>][W
+MO>][WO>][WO>][WO=W=W6Q;&VVVV^:U[WO>][WO>]]]]]]]]]]]]]]]]]]]]
+M]]]]][WO>][WO>][WO>][WO>][WO>][WO>]W=W=;%L;;;;;YK7O>][WO>][W
+MWWWWWWWWWWWWWWWWWWWWWWWWO>][WO>][WO>][WO>][WO>][WO>][W=W=UL6
+MQMMMMOFM>][WO>][WO????????????????????????>][WO>][WO>][WO>][
+MWO>][WO>][WO=W=W6Q;&VVVV^:U[WO>][WO>]]]]]]]]]]]]]]]]]]]]]]]]
+M][WO>][WO>][WO>][WO>][WO>][WO>]W=W=;%L;;;;;YK7O>][WO>][WWWWW
+MWWWWWWWWWWWWWWWWWWWWO>][WO>][WO>][WO>][WO>][WO>][W=W=UL6QMMM
+#MOFM
+end
+End_FRAME
+return $frame;
+}
+
+sub get_stereo_320000{
+my $frame = <<'End_FRAME';
+M__W4`%559IB9B(AW=W=WVVVMDC)```````"JJJJJJJJJJJK[[[[[[[[[[[[[
+M[[[[[[[[[[[[[[[[[[[[[[Y]]]]]]]]]]]]^_?OW[]_?W]^_?O[^_O[^_OW[
+M]^_?OW[]^_?OOOOOOOOOOOOOOOOOOOOOOOOO>][WO>][WO>][WN[N[K8MBV-
+MMK7WWWWWWWWWWWW[]^_?OW]_?W[]^_O[^_O[^_?OW[]^_?OW[]^^^^^^^^^^
+M^^^^^^^^^^^^^^^][WO>][WO>][WO>[N[NMBV+8VVM?????????????OW[]^
+M_?W]_?OW[^_O[^_O[]^_?OW[]^_?OW[[[[[[[[[[[[[[[[[[[[[[[[[WO>][
+MWO>][WO>][N[NZV+8MC;:U]]]]]]]]]]]]^_?OW[]_?W]^_?O[^_O[^_OW[]
+M^_?OW[]^_?OOOOOOOOOOOOOOOOOOOOOOOOO>][WO>][WO>][WN[N[K8MBV-M
+MK7WWWWWWWWWWWW[]^_?OW]_?W[]^_O[^_O[^_?OW[]^_?OW[]^^^^^^^^^^^
+M^^^^^^^^^^^^^^][WO>][WO>][WO>[N[NMBV+8VVM?????????????OW[]^_
+M?W]_?OW[^_O[^_O[]^_?OW[]^_?OW[[[[[[[[[[[[[[[[[[[[[[[[[WO>][W
+MO>][WO>][N[NZV+8MC;:U]]]]]]]]]]]]^_?OW[]_?W]^_?O[^_O[^_OW[]^
+M_?OW[]^_?OOOOOOOOOOOOOOOOOOOOOOOOO>][WO>][WO>][WN[N[K8MBV-MK
+M7WWWWWWWWWWWW[]^_?OW]_?W[]^_O[^_O[^_?OW[]^_?OW[]^^^^^^^^^^^^
+M^^^^^^^^^^^^^][WO>][WO>][WO>[N[NMBV+8VVM?????????????OW[]^_?
+MW]_?OW[^_O[^_O[]^_?OW[]^_?OW[[[[[[[[[[[[[[[[[[[[[[[[[WO>][WO
+M>][WO>][N[NZV+8MC;:U]]]]]]]]]]]]^_?OW[]_?W]^_?O[^_O[^_OW[]^_
+M?OW[]^_?OOOOOOOOOOOOOOOOOOOOOOOOO>][WO>][WO>][WN[N[K8MBV-MK7
+MWWWWWWWWWWWW[]^_?OW]_?W[]^_O[^_O[^_?OW[]^_?OW[]^^^^^^^^^^^^^
+M^^^^^^^^^^^^][WO>][WO>][WO>[N[NMBV+8VVM?????????????OW[]^_?W
+M]_?OW[^_O[^_O[]^_?OW[]^_?OW[[[[[[[[[[[[[[[[[[[[[[[[[WO>][WO>
+/][WO>][N[NZV+8MC;:T`
+end
+End_FRAME
+return $frame;
+}
+
+
+sub get_stereo_384000 {
+my $frame = <<'End_FRAME';
+M__WD`%5F9IF9F8B(AW=W_^VML;2```````"JJJJJJJJJJJK[[[[[[[[[[[[[
+M[[[[[[[[[[[[[[[[[[[[[[Y]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?W]_?W]_
+M?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[__O_^__
+M[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?W]_?W]
+M_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[__O_^_
+M_[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?W]_?W
+M]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[__O_^
+M__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?W]_?
+MW]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[__O_
+M^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?W]_
+M?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[__O
+M_^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?W]
+M_?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[__
+MO_^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?W
+M]_?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[_
+M_O_^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_?
+MW]_?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__[
+M__O_^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]_
+M?W]_?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^__
+M[__O_^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W]
+M_?W]_?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^_
+M_[__O_^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?W
+M]_?W]_?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_^
+M__[__O_^__[__O>][WO>]W=W=W=;&VVWSY]]]]]]^_?OW[]^_?OW[]_?W]_?
+MW]_?W]_?W]_?W]_?W]^_?OW[]^_?OW[]^_?OOOOOOOOOOOOOOOO_^__[__O_
+;^__[__O_^__[__O>][WO>]W=W=W=;&VVWSX`
+end
+End_FRAME
+return $frame;
+}
+
+
+sub get_ac3_2_0_448000 {
+my $frame = <<'End_FRAME';
+M"W>KMQY`0W_X2P:@N&'_.KY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^
+M?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^??_.KY\^?/GSY\^?/G
+MSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^
+M?/GSY\^?>4^D($``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````\>/
+M'CQX\>/'CQX`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````'CQX\>/
+M'CQX\>/#````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````'CQX\>/'
+MCQX\>/``````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````\>/'CQX\>/'
+MCQX8````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````\>/'CQX\>/'C
+MQX``````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````'CQX\>/'CQX\>/#`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````'CQX\>/'CQX\>/```
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````\>/'CQX\>/'CQX8`0>`7
+M9',I_X0C2.]?[C,4O>``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M'CQX\>/'CQX\>/``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````\>/
+M'CQX\>/'CQX8`0X`1GEVD"Z"X6#I04H";@OIC#8Z]Q8X)BNY;28^@```````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````!X\>/'CQX\>/'CP```````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+E```````````````````````````````/'CQX\>/'CQX\>``C>@``
+end
+End_FRAME
+return $frame;
+}
+
+sub get_ac3_3_2_448000 {
+my $frame = <<'End_FRAME';
+M"W>9&!Y`X=_^$L`^_UE_P\/X>'\/#^'A_#P55X^?/GSY\^?/GSY\^?/GSY\^
+M??\ZOGSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?
+M/GW_SJ^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GS
+MY\^??_.KY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^
+M?/GSY]_\ZOGSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/G
+MSY\^?/GW_SJ^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\^?/GSY\
+M^?/GSY\^??_.N4^&)$B1(D2)``````&^;;;;;;;;>/'CN[N[N[N[N[N[N[N[
+MN[QX\;;;?/FM:UK6M:UK6M:UK6M:UK0````&VVVVVVVV\>/'=W=W=W=W=W=W
+M=W=W=WCQXVVV^?-:UK6M:UK6M:UK6M:UK6@````-MMMMMMMMX\>.[N[N[N[N
+M[N[N[N[N[O'CQMMM\^:UK6M:UK6M:UK6M:UK6M`````;YMMMMMMMMX\>.[N[
+MN[N[N[N[N[N[N[O'CQMMM\^:UK6M:UK6M:UK6M:UK6M`````;;;;;;;;;QX\
+M=W=W=W=W=W=W=W=W=W>/'C;;;Y\UK6M:UK6M:UK6M:UK6M:`````V#X`````
+M```!OFVVVVVVVWCQX[N[N[N[N[N[N[N[N[N\>/&VVWSYK6M:UK6M:UK6M:UK
+M6M:T````!MMMMMMMMO'CQW=W=W=W=W=W=W=W=W=X\>-MMOGS6M:UK6M:UK6M
+M:UK6M:UH````#;;;;;;;;>/'CN[N[N[N[N[N[N[N[N[QX\;;;?/FM:UK6M:U
+MK6M:UK6M:UK0````&^;;;;;;;;>/'CN[N[N[N[N[N[N[N[N[QX\;;;?/FM:U
+MK6M:UK6M:UK6M:UK0````&VVVVVVVV\>/'=W=W=W=W=W=W=W=W=WCQXVVV^?
+M-:UK6M:UK6M:UK6M:UK6@````-@^`````````;YMMMMMMMMX\>.[N[N[N[N[
+MN[N[N[N[O'CQMMM\^:UK6M:UK6M:UK6M:UK6M`````;;;;;;;;;QX\=W=W=W
+M=W=W=W=W=W=W>/'C;;;Y\UK6M:UK6M:UK6M:UK6M:`````VVVVVVVVWCQX[N
+M[N[N[N[N[N[N[N[N\>/&VVWSYK6M:UK6M:UK6M:UK6M:T````!OFVVVVVVVW
+MCQX[N[N[N[N[N[N[N[N[N\>/&VVWSYK6M:UK6M:UK6M:UK6M:T````!MMMMM
+MMMMO'CQW=W=W=W=W=W=W=W=W=X\>-MMOGS6M:UK6M:UK6M:UK6M:UH````#8
+M/@````````&^;;;;;;;;>/'CN[N[N[N[N[N[N[N[N[QX\;;;?/FM:UK6M:UK
+M6M:UK6M:UK0````&VVVVVVVV\>/'=W=W=W=W=W=W=W=W=WCQXVVV^?-:UK6M
+M:UK6M:UK6M:UK6@````-MMMMMMMMX\>.[N[N[N[N[N[N[N[N[O'CQMMM\^:U
+MK6M:UK6M:UK6M:UK6M`````;YMMMMMMMMX\>.[N[N[N[N[N[N[N[N[O'CQMM
+MM\^:UK6M:UK6M:UK6M:UK6M`````;;;;;;;;;QX\=W=W=W=W=W=W=W=W=W>/
+M'C;;;Y\UK6M:UK6M:UK6M:UK6M:`````V#X````````!OFVVVVVVVWCQX[N[
+MN[N[N[N[N[N[N[N\>/&VVWSYK6M:UK6M:UK6M:UK6M:T````!MMMMMMMMO'C
+MQW=W=W=W=W=W=W=W=W=X\>-MMOGS6M:UK6M:UK6M:UK6M:UH````#;;;;;;;
+M;>/'CN[N[N[N[N[N[N[N[N[QX\;;;?/FM:UK6M:UK6M:UK6M:UK0````&^;;
+M;;;;;;>/'CN[N[N[N[N[N[N[N[N[QX\;;;?/FM:UK6M:UK6M:UK6M:UK0```
+M`&VVVVVVVV\>/'=W=W=W=W=W=W=W=W=WCQXVVV^?-:UK6M:UK6M:UK6M:UK6
+M@````-@^```!`@!=D<R`````WS;;;;;;;;QX\=W=W=W=W=W=W=W=W=W>/'C;
+M;;Y\UK6M:UK6M:UK6M:UK6M:`````VVVVVVVVWCQX[N[N[N[N[N[N[N[N[N\
+M>/&VVWSYK6M:UK6M:UK6M:UK6M:T````!MMMMMMMMO'CQW=W=W=W=W=W=W=W
+M=W=X\>-MMOGS6M:UK6M:UK6M:UK6M:UH````#?-MMMMMMMO'CQW=W=W=W=W=
+MW=W=W=W=X\>-MMOGS6M:UK6M:UK6M:UK6M:UH````#;;;;;;;;>/'CN[N[N[
+EN[N[N[N[N[N[QX\;;;?/FM:UK6M:UK6M:UK6M:UK0````&PK$```
+end
+End_FRAME
+return $frame;
+}
+
+}
diff --git a/templates.c b/templates.c
new file mode 100755
index 0000000..125ca0c
--- /dev/null
+++ b/templates.c
@@ -0,0 +1,289 @@
+// templates.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vdr/plugin.h>
+
+#include "templates.h"
+#include "codecs.h"
+#include "a-tools.h"
+
+
+cTemplate::cTemplate() {
+ C = NULL;
+ T = NULL;
+ TNames = NULL;
+
+ C = new cCodecs();
+ Load();
+}
+
+cTemplate::~cTemplate() {
+ for (int c = 0; c < NumTemplates; c++) {FREE(T[c].Name);}
+ FREE(T);
+ FREE(TNames);
+
+ DELETE(C);
+}
+
+void cTemplate::Load() {
+ char *buf = NULL;
+ size_t i = 0;
+ bool d = false;
+ int c = 0;
+
+ FILE *f = fopen(AddDirectory(cPlugin::ConfigDirectory(), TEMPLATESFILE), "r");
+ if (f) {
+ // read Template-Data
+ while (getline(&buf, &i, f) != -1) {
+ // reserve memory for templates
+ T = (struct TemplateData*)realloc(T, (c + 1) * sizeof(struct TemplateData));
+ T[c].Name = strcol(buf, ";", 1);
+ T[c].FileSize = atoi(strcol(buf, ";", 2));
+ T[c].FileNumbers = atoi(strcol(buf, ";", 3));
+ T[c].BitrateVideo = atoi(strcol(buf, ";", 4));
+ T[c].BitrateAudio = atoi(strcol(buf, ";", 5));
+ T[c].VCodec = C->getNumVCodec(strcol(buf, ";", 6));
+ T[c].ACodec = C->getNumACodec(strcol(buf, ";", 7));
+ // migrate from version 0.0.9
+ char *s = NULL;
+ s = strcol(buf, ";", 8);
+ if (s) {T[c].ScaleType = atoi(s);
+ } else {T[c].ScaleType = 0;}
+ FREE(s);
+ s = strcol(buf, ";", 9);
+ if (s) {T[c].Bpp = atoi(s);
+ } else {T[c].Bpp = 20;}
+ FREE(s);
+ // migrate from version 0.1.1
+ s = strcol(buf, ";", 10);
+ if (s) {T[c].Container = C->getNumContainer(s);
+ } else {T[c].Container = C->getNumContainer("avi");}
+ FREE(s);
+
+ // search for default Templates
+ if (strcmp(T[c].Name, TDEFAULT) == 0) {d = true;}
+
+ FREE(buf);
+ c++;
+ }
+ fclose(f);
+ } else {
+ dsyslog("[vdrrip] could not open file %s !", TEMPLATESFILE);
+ isyslog("[vdrrip] try to create %s with default settings !", TEMPLATESFILE);
+ }
+
+ NumTemplates = c;
+
+ //create default Templates
+ if (! d) {New(TDEFAULT);}
+}
+
+void cTemplate::Save() {
+ FILE *f;
+
+ f = fopen(AddDirectory(cPlugin::ConfigDirectory(), TEMPLATESFILE), "w");
+ if (f) {
+ for (int c = 0; c < NumTemplates; c++) {
+ if (strcmp(T[c].Name, "delete") != 0) {
+ fprintf(f, "%s;%i;%i;%i;%i;%s;%s;%i;%i;%s\n", T[c].Name,
+ T[c].FileSize, T[c].FileNumbers, T[c].BitrateVideo,
+ T[c].BitrateAudio, C->getVCodec(T[c].VCodec),
+ C->getACodec(T[c].ACodec), T[c].ScaleType, T[c].Bpp,
+ C->getContainer(T[c].Container));
+ }
+ }
+ fclose(f);
+ Load();
+
+ } else {
+ dsyslog("[vdrrip] could not save %s !", TEMPLATESFILE);
+ }
+}
+
+int cTemplate::getNumTemplates() {return NumTemplates;}
+
+int cTemplate::getNumTemplate(char *t) {
+ int c;
+
+ if (t) {
+ for (c = 0; c < NumTemplates; c++) {
+ if (strcmp(T[c].Name, t) == 0) return c;
+ }
+ }
+ return -1;
+}
+
+char **cTemplate::getTNames() {
+ int c;
+
+ TNames = (char **)malloc(NumTemplates * sizeof(char *));
+ for (c = 0; c < NumTemplates; c++) {
+ TNames[c] = T[c].Name;
+ }
+ return TNames;
+}
+
+int cTemplate::New(char *n) {
+ T = (struct TemplateData*)realloc(T, ((NumTemplates + 1) * sizeof(struct TemplateData)));
+ T[NumTemplates].Name = strdup(n);
+ T[NumTemplates].FileSize = 700;
+ T[NumTemplates].FileNumbers = 1;
+ T[NumTemplates].BitrateVideo = -1;
+ T[NumTemplates].Container = C->getNumContainer("avi");
+ T[NumTemplates].VCodec = C->getNumVCodec("lavc");
+ T[NumTemplates].ACodec = C->getNumACodec("copy");
+ T[NumTemplates].ScaleType = 0;
+ T[NumTemplates].Bpp = 20;
+ T[NumTemplates].BitrateAudio = 96;
+
+ NumTemplates++;
+ Save();
+
+ return NumTemplates - 1;
+}
+
+void cTemplate::Del(int i) {
+ if (i >= 0 && i < NumTemplates) {
+ isyslog("add delete flag on template %s", T[i].Name);
+ T[i].Name = strdup("delete");
+ Save();
+ }
+}
+
+void cTemplate::setName(int i, char *n) {
+ if (i >= 0 && i < NumTemplates) {
+ T[i].Name = strdup(n);
+ Save();
+ }
+}
+
+void cTemplate::setFileSize(int i, int fs, int fn) {
+ if (i >= 0 && i < NumTemplates) {
+ T[i].FileSize = fs;
+ T[i].FileNumbers = fn;
+ T[i].BitrateVideo = -1;
+ Save();
+ }
+}
+
+void cTemplate::setBitrate(int i, int v, int a) {
+ if (i >= 0 && i < NumTemplates) {
+ T[i].BitrateVideo = v;
+ T[i].BitrateAudio = a;
+ if (! (T[i].BitrateVideo == -1)) {T[i].FileSize = -1;}
+ Save();
+ }
+}
+
+void cTemplate::setContainer(int i, int c) {
+ if (i >= 0 && i < NumTemplates) {
+ if (c >= 0 && c < C->getNumContainers()) {T[i].Container = c;
+ } else {
+ dsyslog("[vdrrip] unknown container, falling back to avi !");
+ T[i].Container = C->getNumContainer("avi");
+ }
+ Save();
+ }
+}
+
+void cTemplate::setCodecs(int i, int v, int a) {
+ if (i >= 0 && i < NumTemplates) {
+ // validate video codec
+ if (v >= 0 && v < C->getNumVCodecs()) {T[i].VCodec = v;
+ } else {
+ dsyslog("[vdrrip] unknown video codec, falling back to %s !",
+ C->getVCodec(0));
+ T[i].VCodec = 0;
+ }
+
+ // validate audio codec
+ if (a >= 0 && a < C->getNumACodecs()) {
+ if (strcmp(C->getContainer(T[i].Container), "avi") == 0 && strcmp(C->getACodec(a), "ogg-vorbis") == 0) {
+ dsyslog("[vdrrip] avi couldn't contain ogg-vorbis audio, falling back to copy !");
+ T[i].ACodec = C->getNumACodec("copy");
+ } else {T[i].ACodec = a;}
+ } else {
+ dsyslog("[vdrrip] unknown audio codec, falling back to copy !"),
+ T[i].ACodec = C->getNumACodec("copy");
+ }
+
+ Save();
+ }
+}
+
+void cTemplate::setBpp(int i, int b) {
+ if (i >= 0 && i < NumTemplates) {
+ T[i].Bpp = b;
+ Save();
+ }
+}
+
+void cTemplate::setScaleType(int i, int t) {
+ if (i >= 0 && i < NumTemplates) {
+ T[i].ScaleType = t;
+ Save();
+ }
+}
+
+char *cTemplate::getName(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].Name;
+ } else {return NULL;}
+}
+
+char *cTemplate::getShortname(int i) {
+ if (i >= 0 && i < NumTemplates) {
+ if (strlen(T[i].Name) > 20) {
+ char *s, *s1;
+ s = strsub(T[i].Name,1 , 17);
+ asprintf(&s1, "%s...", s);
+ return s1;
+ } else {return T[i].Name;}
+ } else {return NULL;}
+}
+
+int cTemplate::getFileSize(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].FileSize;
+ } else {return 0;}
+}
+
+int cTemplate::getFileNumbers(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].FileNumbers;
+ } else {return 0;}
+}
+
+int cTemplate::getBitrateVideo(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].BitrateVideo;
+ } else {return 0;}
+}
+
+int cTemplate::getBitrateAudio(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].BitrateAudio;
+ } else {return 0;}
+}
+
+int cTemplate::getContainer(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].Container;
+ } else {return 0;}
+}
+
+int cTemplate::getVCodec(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].VCodec;
+ } else {return 0;}
+}
+
+int cTemplate::getACodec(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].ACodec;
+ } else {return 0;}
+}
+
+int cTemplate::getScaleType(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].ScaleType;
+ } else {return 0;}
+}
+
+int cTemplate::getBpp(int i) {
+ if (i >= 0 && i < NumTemplates) {return T[i].Bpp;
+ } else {return 1;}
+}
+
diff --git a/templates.h b/templates.h
new file mode 100755
index 0000000..616e8e2
--- /dev/null
+++ b/templates.h
@@ -0,0 +1,67 @@
+//
+// templates.h
+//
+
+#ifndef __TEMPLATES_H
+#define __TEMPLATES_H
+
+#include "codecs.h"
+
+#define TEMPLATESFILE "templates.vdrrip"
+#define TDEFAULT "default"
+
+struct TemplateData {
+ char *Name;
+ int FileSize;
+ int FileNumbers;
+ int Bitrate;
+ int BitrateVideo;
+ int BitrateAudio;
+ int Container;
+ int VCodec;
+ int ACodec;
+ int ScaleType;
+ int Bpp;
+};
+
+class cTemplate {
+ private:
+ struct TemplateData *T;
+ char **TNames;
+ int NumTemplates;
+
+ void Load();
+
+ public:
+ cTemplate();
+ ~cTemplate();
+
+ cCodecs *C;
+
+ void Save();
+ int New(char *n);
+ void Del(int i);
+ void setName(int i, char *n);
+ void setFileSize(int i, int fs, int fn);
+ void setBitrate(int i, int v, int a);
+ int getContainer(int i);
+ void setContainer(int i, int c);
+ void setCodecs(int i, int v, int a);
+ int getVCodec(int i);
+ int getACodec(int i);
+ void setBpp(int i, int b);
+ void setScaleType(int i, int t);
+ int getNumTemplate(char *n);
+ int getNumTemplates();
+ char *getName(int i);
+ char *getShortname(int i);
+ char **getTNames();
+ int getFileSize(int i);
+ int getFileNumbers(int i);
+ int getBitrateVideo(int i);
+ int getBitrateAudio(int i);
+ int getScaleType(int i);
+ int getBpp(int i);
+};
+
+#endif // __TEMPLATES_H
diff --git a/vdrrip.c b/vdrrip.c
new file mode 100755
index 0000000..69fbfee
--- /dev/null
+++ b/vdrrip.c
@@ -0,0 +1,159 @@
+/*
+ * vdrrip.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include <unistd.h>
+
+#include <getopt.h>
+#include <vdr/plugin.h>
+#include <vdr/menu.h>
+#include "menu-vdrrip.h"
+#include "movie.h"
+#include "i18n.h"
+#include "a-tools.h"
+
+static const char *VERSION = "0.3.0";
+static const char *DESCRIPTION = "A MPlayer using movie encoder";
+static const char *MAINMENUENTRY = "Vdrrip";
+
+const char *MPlayer = "/usr/local/bin/mplayer";
+const char *MEncoder = "/usr/local/bin/mencoder";
+const char *DVD = "/dev/dvd";
+
+class cPluginVdrrip : public cPlugin {
+private:
+ // Add any member variables or functions you may need here.
+public:
+ cPluginVdrrip(void);
+ virtual ~cPluginVdrrip();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return DESCRIPTION; }
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual bool Initialize(void);
+ virtual bool Start(void);
+ virtual void Housekeeping(void);
+ virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; }
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ };
+
+cPluginVdrrip::cPluginVdrrip(void)
+{
+ // Initialize any member variables here.
+ // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
+ // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
+}
+
+cPluginVdrrip::~cPluginVdrrip()
+{
+ // Clean up after yourself!
+}
+
+const char *cPluginVdrrip::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ char *s = NULL;
+ asprintf(&s, " -p LOC, --MPlayer=LOC use LOC as location of MPlayer\n"
+ " (default is %s)\n"
+ " -e LOC, --MEncoder=LOC use LOC as location of MEncoder\n"
+ " (default is %s)\n"
+#ifdef VDRRIP_DVD
+ " -d DEV, --DVD=DEV use DEV as your DVD-device\n"
+ " (default is %s)\n"
+#endif // VDRRIP_DVD
+ , MPlayer, MEncoder
+#ifdef VDRRIP_DVD
+ , DVD
+#endif // VDRRIP_DVD
+ );
+ return s;
+}
+
+bool cPluginVdrrip::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+ static struct option long_options[] = {
+ { "MPlayer", required_argument, NULL, 'p' },
+ { "MEncoder", required_argument, NULL, 'e' },
+ { "DVD", required_argument, NULL, 'd' },
+ { NULL }
+ };
+
+ int c, option_index = 0;
+ while ((c = getopt_long(argc, argv, "p:e:d:", long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'p':
+ MPlayer = optarg;
+ break;
+
+ case 'e':
+ MEncoder = optarg;
+ break;
+
+ case 'd':
+ DVD = optarg;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cPluginVdrrip::Initialize(void)
+{
+ // Initialize any background activities the plugin shall perform.
+ return true;
+}
+
+bool cPluginVdrrip::Start(void)
+{
+ // Start any background activities the plugin shall perform.
+ RegisterI18n(Phrases);
+ return true;
+}
+
+void cPluginVdrrip::Housekeeping(void)
+{
+ // Perform any cleanup or other regular tasks.
+}
+
+cOsdObject *cPluginVdrrip::MainMenuAction(void)
+{
+ // Perform the action when selected from the main VDR menu.
+ if (access(MPlayer, X_OK) == -1) {
+ char *s = NULL;
+ asprintf(&s, "%s doesn't exist or isn't a executable !", MPlayer);
+ Interface->Error(s);
+ FREE(s);
+ return NULL;
+ } else if (access(MEncoder, X_OK) == -1) {
+ char *s = NULL;
+ asprintf(&s, "%s doesn't exist or isn't a executable !", MEncoder);
+ Interface->Error(s);
+ FREE(s);
+ return NULL;
+ } else return new cMenuVdrrip();
+}
+
+cMenuSetupPage *cPluginVdrrip::SetupMenu(void)
+{
+ // Return a setup menu in case the plugin supports one.
+ return new cMenuVdrripSetup();
+}
+
+bool cPluginVdrrip::SetupParse(const char *Name, const char *Value)
+{
+ // Parse your own setup parameters and store their values.
+ return VdrripSetup.SetupParse(Name, Value);
+}
+
+VDRPLUGINCREATOR(cPluginVdrrip); // Don't touch this!
diff --git a/vdrriprecordings.c b/vdrriprecordings.c
new file mode 100755
index 0000000..b63a780
--- /dev/null
+++ b/vdrriprecordings.c
@@ -0,0 +1,87 @@
+//
+// vdrriprecordings.c
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vdr/videodir.h>
+#include <vdr/tools.h>
+
+#include "vdrriprecordings.h"
+#include "a-tools.h"
+
+#define FINDRECCMD "find %s -follow -type d -regex '.*rec$'"
+
+// --- cVdrripRecordings -----------------------
+
+cVdrripRecordings::cVdrripRecordings() {
+ Name = Date = Path = NULL;
+ NumRec = 0;
+ ReadRec();
+}
+
+cVdrripRecordings::~cVdrripRecordings() {
+ FREE(Name);
+ FREE(Date);
+ FREE(Path);
+}
+
+void cVdrripRecordings::ReadRec() {
+ char *cmd = NULL, *buf = NULL;
+ size_t i = 0;
+
+ int colv = strnumcol(VideoDirectory, "/");
+
+ asprintf(&cmd, FINDRECCMD, VideoDirectory);
+ FILE *p = popen(cmd, "r");
+ if (p) {
+ while (getline(&buf, &i, p) != -1) {
+ int colg;
+
+ // search the c from *.rec and terminate the string
+ int l = strlen(buf);
+ while (buf[l] != 'c') {l--;}
+ buf[l+1] = '\0';
+
+ // allocate memory for Name, Date & Path - arrays
+ Name = (char **)realloc(Name, ((NumRec + 1) * sizeof(char *)));
+ Date = (char **)realloc(Date, ((NumRec + 1) * sizeof(char *)));
+ Path = (char **)realloc(Path, ((NumRec + 1) * sizeof(char *)));
+
+ colg = strnumcol(buf, "/");
+ if ( colg - colv >= 3) {
+ // this is recording with a subdir
+ asprintf(&Name[NumRec], "%s_-_%s", strcol(buf, "/", colg - 2), strcol(buf, "/", colg - 1));
+ } else {
+ Name[NumRec] = strcol(buf, "/", colg - 1);
+ }
+
+ Date[NumRec] = strcol(strcol(buf, "/", colg), ".", 1);
+ Path[NumRec] = strdup(buf);
+ FREE(buf);
+
+ NumRec++;
+ }
+ } else {
+ dsyslog("[vdrrip] could not open pipe to %s !", cmd);
+ }
+ pclose(p);
+ FREE(cmd);
+}
+
+int cVdrripRecordings::getNumRec() {return NumRec;}
+
+char *cVdrripRecordings::getName(int i) {
+ if (i >= 0 && i < NumRec) {return Name[i];
+ } else {return NULL;}
+}
+
+char *cVdrripRecordings::getDate(int i) {
+ if (i >= 0 && i < NumRec) {return Date[i];
+ } else {return NULL;}
+}
+
+char *cVdrripRecordings::getPath(int i) {
+ if (i >= 0 && i < NumRec) {return Path[i];
+ } else {return NULL;}
+}
diff --git a/vdrriprecordings.h b/vdrriprecordings.h
new file mode 100755
index 0000000..6f22095
--- /dev/null
+++ b/vdrriprecordings.h
@@ -0,0 +1,27 @@
+//
+// vdrriprecordings.h
+//
+
+#ifndef __VDRRIPRECORDINGS_H
+#define __VDRRIPRECORDINGS_H
+
+class cVdrripRecordings {
+ private:
+ char **Name;
+ char **Date;
+ char **Path;
+
+ int NumRec;
+
+ public:
+ cVdrripRecordings();
+ ~cVdrripRecordings();
+
+ void ReadRec();
+ int getNumRec();
+ char *getName(int i);
+ char *getDate(int i);
+ char *getPath(int i);
+};
+
+#endif // __VDRRIPRECORDINGS_H
diff --git a/xaver.jpg b/xaver.jpg
new file mode 100755
index 0000000..3d1a250
--- /dev/null
+++ b/xaver.jpg
Binary files differ