mp3-0.10.2/0040755000000000000000000000000011316352211010766 5ustar rootrootmp3-0.10.2/COPYING0100644000000000000000000004313110735452037012033 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mp3-0.10.2/HISTORY0100644000000000000000000006065011316351574012071 0ustar rootrootVDR Plugin Revision History --------------------------- 29.12.2009: Version 0.10.2 (vdr 1.6.0-2) - Fixed a segfault while direct song selection. Thanks to Halim Sahin for reporting. - Fixed possible division by zero in libsndfile decoder. - Fixed varoius warnings with never gcc versions. - Added commandline option for a user defined default background image. - Added OGG streaming support. Implemented by Manuel Reimer. - Made the handling of song information (e.g. ID3) UTF-8 aware. The infocache file is kept in UTF-8 format now. - Ignore errors while scaning recursive directories. Patch provided by Steffen Kaiser. - Map audio-button to "switch_audio" and next/prev-button to "seek_chapter" slave command in MPlayer replay. Suggested by Martin Dauskardt. - Set the environment variable DVB_DEVICE with the number of the primary device before calling mplayer.sh. Based on a patch from Marco Schinkel. - Use blocking IO for OSS output for improved compatibility. Suggested by Martin Dauskardt. - Backward compatible on-the-fly creation of the i18n.c file using Udo Richter's po2i18n package. - Removed compatibility with VDR versions < 1.4.5. - Added italian translations. - Updated french and russian translations. - For detailed changes please refer to the HG history. 27.08.2007: Version 0.10.1 (vdr 1.4.7 / 1.5.9) - Fixed segfault in MP3 infocache purge on plugin exit. - Added support for VDR 1.5.7+ gettext internationalization. 17.06.2007: Version 0.10.0 (vdr 1.4.7 / 1.5.2) - Fixed directory scaning in file browser if remembered directory has been removed meanwhile. Reported by Halim Sahin. - Added processing of kNext/kPrev to skip songs. Patch provided by Peter Pinnau. - Made subsampling mode selection for ppmtoy4m call in example image convert script backward compatible. Suggested by C.Y.M. - Fixed a missing include in mplayer.c. Reported by Dirk Vornheder. - Now closing all unused filedescriptors in MPlayer child thread. Suggested by Anssi Hannula. - Now defaults to slavemode enabled in MPlayer plugin. - Adapted to the API changes in vdr 1.5.0+. - Documentation updates. ---------------------------------------------------------------------- 21.09.2006: Version 0.9.15 development (vdr 1.4.1-4) - NOTE: This version has been tested with VDR 1.4.x only. It might be still compatible with VDR 1.2.x or 1.3.x, but this wasn't verified. - In MPlayer filebrowser you can display a summary text file with key "0". Filename convention: video filename extended with ".summary", e.g. "somefile.avi" -> "somefile.avi.summary". Summary files are not shown in the browsers filelist. (was in 0.9.14 already, but was missing in history) - Using ".txt" and ".nfo" as alternative extention for MPlayer summary file display. Suggested by Soeren Sonnenburg. - Additionaly searching for a MPlayer summary file with the video filename extention stripped of (e.g. "somefile.summary"). - Added SVDR and service support to MP3 and MPlayer plugin. Based on a patches provided by Olivier Jacques and Holger Brunn. - Added setup option to reverse title/artist display in MP3 plugin. - Added support for basic HTTP authorization in MP3 streaming. - Now passing correct name & path to VDR's status class during MPlayer playback. - Added commandline option to specify a subdirectory to load sources file from. Suggested by Ronny Kornexl. - Added commandline option to specify a directory for the global MPlayer resume file. Suggested by Ronny Kornexl. - Added -S option to ppmtoy4m call in example image convert script. Suggested by Thorsten Gehrig. - Replaced leftover usleep() calls. Thanks to Malte Schrіder. - Moved cleanup of ID3 cache to a seperate thread to prevent watchdog timeout. Suggested by Peter Holik. - Fixed browser excludes taking effect only after the first directory change. Reported by Soeren Sonnenburg. - Fixed parsing the filename from MPlayer output. Based on a fix from TomG. - Fixed MPlayer volume changes. Take non-linear changes in VDR into account. Reported by Daniel Karsubka. - Fixed delay when MPlayer process exits at EOF. Reported by Daniel Karsubka. - Fixed MPlayer volumen handling for VDR 1.4.1-2. Note that the current code doesn't work with VDR 1.4.1 and 1.4.1-1. - Fixed button translations with vdr 1.3.38+. Thanks to Ville Skyttф. - Fixed some gcc 4.1 issues. Thanks to Ville Skyttф. - Removed explizit libz dependency from Makefile. Suggested by Ville Skyttф. - Updated Makefile according to changes in VDR 1.3.47 & 1.4.1. - Updated finish translations. Provided by Rolf Ahrenberg. 08.01.2006: Version 0.9.14 development (vdr 1.2.6/1.3.38) - Fixed VDR hanging for some seconds when skipping songs and fixed pause mode freezing live background when using OSS output. Reported by Andy Grobb. - Now muting DVB audio while using OSS output. - Finaly restored the function of the back key (jumps directly to plugin main menu) (vdr >= 1.3.32 only). Thanks to Sascha Volkenandt for the hint. - During MPlayer playback, the name of the current videofile is now parsed from the MPlayer output. If you're using some kind of playlist hack, the MPlayer plugin will now report the correct filename. Based on suggestions from Ronny Kornexl. - Extended the example mplayer.sh file to show how a playlist can be passed to MPLayer. - Fixed segfault in progress display with skincurses. Thanks to Pasi Juppo for reporting. - Adapted to the API changes in vdr 1.3.38. 31.07.2005: Version 0.9.13 development (vdr 1.2.6/1.3.24) - Moved OSD position selection to plugin setup menu (as before this works for non-skined vdr <1.3.7 only). - Removed DVD navigation from MPlayer slavemode. - Added support for configurable keys (0-9) in MPlayer slavemode. The slave command can be entered in the plugin setup menu and is sent to MPlayer during playback if the key is pressed. - Added support to display a summary file (plain ascii) in the MPlayer browser. If you are on a video file, press '0' to display the summary. The summary file has to be named like the video file but with ".summary" appended (e.g. video.mpeg -> video.mpeg.summary). - New MP3 plugin setup option to keep the selection menu opened after selection. Suggested by Mikko Mфkinen. - Fixed ringbuffer timeouts in network code. - Fixed ID3 V2 tag handling. Unusual big tags caused the ID3 scanner to mark the file as bad. Now correctly skipping ID3 tags during playback too. Reported by Olaf Henkel. - Prevent writing to a broken pipe in mplayer slave control. Reported by Gerhard Steiner. - Fixed passing AID 0 to mplayer.sh. To allow MPlayer autoselect the audio stream, set AID to -1 (this can only be achieved by entering 0 and than pressing left). - Improved creation of LPCM frames. Based on the changes in muggle 0.1.8. - Updated french translations. Provided by Jerome Rousset. 17.03.2005: Version 0.9.12 development (vdr 1.2.6/1.3.22) - Fixed background image convert hanging a long time and some other oddities. - Now filtering image files in the song browser display. - Extended include field in mp3sources.conf to allow multiple patterns seperated by '/' e.g. *.mp3/*.ogg/*.txt - Enhanced image convert script for NTSC format. Thanks to Cym. - Fixed list sorting for vdr versions before 1.3.15. - Fixed MPlayer slavemode progress display reappearing on user requested close. - Now explicitly setting C locale in example image convert script. Thanks to Tobias Grimm. - Changed the location where cStatus::MsgReplaying is called. Helps to prevent a crash in graphlcd. In my opinion cControl API should be called from the foreground thread only. Reported by Wolfgang Fritz. - Fixed a huge bunch of typos in the documentation. Thanks to Ville Skyttф. - Updated finish translations. Provided by Rolf Ahrenberg & Ville Skyttф. 20.02.2005: Version 0.9.11 development (vdr 1.2.6/1.3.21) - Now using propper readdir() to scan directory contents rather than the external find & sort tools. - Added cover image display during MP3 replay. See the README on how this has to be configured. If you was using the old image patch, be aware that there are now new commandline options and that the layout of the cache directory has changed. Initial patch made by Eloy, currently maintained by Tobias Grimm for ctvdr-debian package. 06.02.2005: Version 0.9.10 development (vdr 1.2.6/1.3.20) - Fixed MPlayer resume for filenames/directories containing whitespace characters. - Fixed vdr 1.3.18+ compatibility with BROKEN_PCM=1. - Fixed MP3 replay with vdr 1.3.19+. Thanks to Tobias Grimm. - Fixed huge memory leak in song/decoder handling (approx 22kB/song). Thanks to the great valgrind tool. - Fixed some mismatched new[]/delete calls. - Reduced MP3 decoder memory footprint (stopped state, from 22k to 308). - Fixed crashes on status display from background threads (e.g. connect to streamserver). An asyncronous status display was added. - Updated finnish translations. Provided by Rolf Ahrenberg. - Updated recommended library versions to libmad/libid3tag 0.15.1b and libsndfile 1.0.11. - Updated patch for cdfs 0.5c. Correct tracksize for last audio track if a data track follows. Thanks to Merten Falk. 10.01.2005: Version 0.9.9 development (vdr 1.2.6/1.3.18) - Added global MPlayer resume file. This is used if the directory of the video file is not writeable. The global resume file is located in the video directory. - Added DVD navigation to MPlayer slavemode. Due to this some other functions have been moved to new keys. See MANUAL file. - Added some glue for vdr 1.3.18. - Fixed saving of MPlayer setup option "ResumeMode". You can select if you want "local/global" or "global only" resume files too. - Fixed thread deadlock in playmanager and non-blocking libsndfile reader (appearently only with some pthread versions) and high cpu usage of background scan thread when using libsndfile decoder. Thanks to Tobias Grimm for debugging. - Removed workarounds for broken PCM handling in firmware (PCM pause & samplerate changes). This requires DVB firmware 261d-rc6 or newer. If you prefer to use an older firmware, you can use the make commandline option BROKEN_PCM=1 to enable old behaviour. - Fixed handling of sym-links in source base path and playlists. - Fixed path generation for "wide" sym-links. - Replaced non-reentrant glibc functions with reentrant versions. - Updated finnish translations. Provided by Rolf Ahrenberg. 28.11.2004: Version 0.9.8 development (vdr 1.2.6/1.3.14) - Added MPlayer audiostream selection. Audiostream is selected with the blue key in the MPlayer menu. The selected stream is passed to the mplayer.sh script as "AID x" where x is the stream number. For compatibility reasons the AID parameter is passed after the SLAVE parameter. Due to this, parameter positions aren't fixed any more. You have to implement a flexible parameter parsing in mplayer.sh. See the example file how this can be done. Based on a patch from VDR-Portal. - Fixed segfault in shuffle code when adding a single song to the current playlist. Reported by Malte Schrіder. - Fixed segfault in network code (pthread_cancel). Reported by Malte Schrіder. - Fixed mounting/unmounting sources in MPlayer plugin. Reported by Guy Roussin. - Fixed status display with open (classic) progress display for vdr 1.3.7+. - Added russian translations (vdr >= 1.3.2). Provided by Vyacheslav Dikonov. 24.09.2004: Version 0.9.7 development (vdr 1.2.6/1.3.12) - Added non-blocking reader thread to libsndfile decoder. - Fixed backward skip and progress display. Reported by Burkhardt Petermann. - Fixed some locking problems in play manager. - Fixed handling of samplerate changes for DVB & OSS output. 13.09.2004: Version 0.9.6 development (vdr 1.2.6/1.3.12) - Changed the way how the player maintains the ringbuffer to prevent audio dropouts while background scan is active. - Increased player ringbuffer size and take care of ringbuffer contents when skipping forward. - Prevent full file scan on MP3 decoder check. - Flushing playlist on playback abort to unblock removable sources. This also prevents the background scanner to continue after playback was aborted. - Removed a buffer-to-buffer copy in DVB output. - Fixed several race conditions where the play manager could discard the currently played or scanned song. - Added a patch for cdfs 0.5c to correct discid calculation (applies to cdfs 2.4.20 as well). 07.09.2004: Version 0.9.5 development (vdr 1.2.6/1.3.12) - Resolved several oddities in progress display if the player is idle. - Now removing trailing '/' from source definitions in *sources.conf and warn the user about this. - Outdated entries in the MPlayer resume file are removed now. - Fixed playback start delay in case the background scanner is working on the current song. - Fixed progress display for net streams. Reported by Wolfgang Fritz. - Fixed MPlayer rewind button (broken by sources fix in 0.9.4). Reported by Sebastian Kemper. - Updated finnish translations. Provided by Rolf Ahrenberg. - Added a patch that prevents the VDR core from aborting the MP3 player in black background mode (see patches subdirectory). 03.09.2004: Version 0.9.4 development (vdr 1.2.6/1.3.12) - Added a queue manager. During playback you can add new songs to the playlist by selecting them from the MP3 menu/browser. To flush the playlist you have to stop the player for now. You can add new songs even if the player is kept idle (see below). - Replaced setup option "mute at end of list" with "abort player at end of list". If you set this option to "no" and the end of playlist is reached, the player is kept idle. To restart playback select a song to restart from there or "up" to restart from the begining. - Background scan (formerly known as ID3 prescan) now also can determine the song level. Note that level scan requires to decode the complete song. This is done on a seperate thread with nice 5 but nevertheless it needs CPU cycles. If your system crawls, you can set background scan to "ID3 only" in the plugin setup menu. - Added commanline option -C to specify the directory to place the id3cache file. The default is to place the file into the video directory. - MPlayer resume feature can now be disabled in the plugin setup menu. No resume file is created in this case. - Another fix to the OSS output. Now using little-endian samples only (which should be supported by all soundcard drivers). - Fixed mounting/unmounting of MPlayer sources (Bug introduced in 0.9.2). Thanks to Bill Blough for spotting this one. - Updated finnish translations. Provided by Rolf Ahrenberg. 03.07.2004: Version 0.9.3 development (vdr 1.2.6/1.3.11) - If a (single) selected file in the MP3 browser is actualy a playlist (*.m3u), load the playlist rather than trying to play the file. This allows to have playlists in subdirectories (by now only selectable from the browser not from the main menu). Note that song paths must be either absolute or relative to the location of the playlist file. Suggested by Helmut Auer. - Now returning replay mode information in MP3 replay. Suggested by Sascha Volkenandt. - Now paying attention to values returned by OSS ioctl's. This fixes playback for sound drivers which doesn't support big-endian samples. Thanks to Antti-Pekka Liedes for reporting and testing the fix. - Added setup option to hide the mainmenu entry. - Updated finnish translations. Provided by Rolf Ahrenberg. - Fixed VDR 1.2.x compile issues. - Fixed crash on status message display while the classic replay display is open. 24.06.2004: Version 0.9.2 development (vdr 1.2.6/1.3.11) - Added a setup option to toggle MP3 replay display between classic and skin version. Note that the big playlist display isn't available in skin mode. - Added rewind button to MPlayer menu. Suggested by Sebastian Kemper. - Updated finnish translations. Provided by Rolf Ahrenberg. - Fixed current play time calculation for MPlayer without slave-patch. Reported by Uwe Scheffler. - Fixed status messages which were displayed for ever. Reported by Sascha Volkenandt. 05.06.2004: Version 0.9.1 development (vdr 1.2.6/1.3.9) - Added finnish translations. Provided by Rolf Ahrenberg. - Adapted to the changes in VDR 1.3.7+. Based on patches provided by Sascha Volkenandt & Sven Goethel. - Fixed long standing bug in ID3 tag parsing, when the file contains an incomplete ID3 tag at the end of file. Thanks to Matt Tovey for debugging. - Better german translations. Suggested by Andreas Brachold. - Now ignoring dot-files in file browser. Suggested by Patrick Cernko. - Now showing total play time in MPlayer progress display. The value may be inaccurate. Suggested by Patrick Cernko. - Added resume capability for MPlayer. The resume position is stored in a file called ".mplayer.resume" in the directory of the MPlayer file. Based on a patch provided by Patrick Cernko. - Added a setup option to mute audio at end of playlist. Based on a patch provided by Christoph Gohle. - Now accepting absolute paths in playlists, even though the path must point to somewhere inside the defined source directory. Suggested by Niklaus Stutz. 08.05.2004: Version 0.9.0 development (vdr 1.2.6/1.3.1) - Added OSS soundcard output. Use make option WITH_OSS_OUTPUT=1 to compile support, commandline option -D to change DSP device and plugin setup menu to select output mode. Thanks to Gunnar Roth. - Added shoutcast/icecast metadata parsing. Thanks to Andreas Brachold. - Now restoring locale settings in MPlayer plugin. - Fixed MPlayer exit problem while paused. - Fixed showing outdated song name shortly after start of a new song. ---------------------------------------------------------------------- 16.01.2004: Version 0.8.3 (vdr 1.2.6/1.3.1) - Fixed shutting down network connection (race condition). - Added a pointer to Juri's mplayer.sh in the README. - Fixed compilation problem with VDR 1.3.x and Beauty-Patch. 16.11.2003: Version 0.8.2 (vdr 1.2.6) - Fixed quoting special shell characters when calling MPlayer. - Now sending a "quit" to MPlayer when in slave mode rather than killing the process. - Updated recommended library versions to libmad/libid3tag 0.15.0b and libsndfile 1.0.5. 08.08.2003: Version 0.8.1 (vdr 1.2.2) - Fixed network code for DOS-style \r\n (Thanks to Roland Praml). 01.06.2003: Version 0.8.0 (vdr 1.2.0) - Fixed thread cancelation in network code (valgrind hits). - Stable release 0.8.0. ---------------------------------------------------------------------- 25.05.2003: Version 0.7.15 plugin development (vdr 1.1.33) - Adapted to the changes in vdr 1.1.33. - Corrected the README about the fact that the plugins require vdr 1.1.29+. - Added Spanish & Catalan translations. Thanks to Ramon Roca. 18.05.2003: Version 0.7.14 plugin development (vdr 1.1.32) - Fixed ringbuffer handling for changes in vdr 1.1.31/32. - MPlayer progressbar can be moved up/down now. Use keys 6/9 while the progressbar is displayed. - Added Swedish translations. Thanks to Jan Ekholm. 27.04.2003: Version 0.7.13 plugin development (vdr 1.1.29) - Fixed compile error due to changes in vdr 1.1.29. - Fixed VDR version check. 18.04.2003: Version 0.7.12 plugin development (vdr 1.1.27) - Added support for MPlayers slave commands "get_percent_pos" & "get_time_length". Gives better results for the progressbar. The slavemode patch for MPlayer is still needed as not all video formats provide information through these slave commands. - Fixed s/ms mixup in remote CDDB connect. - Fixed possible deadlock-race in mp3 & snd decoder. - Added OggVorbis decoder. libvorbis & libvorbisfile needed. - Updated French translations. Thanks to Pierre-Henri Beguin. - Added VDR version check. 27.03.2003: Version 0.7.11 plugin development (vdr 1.1.26) - Fixed MPlayer AudioDelay(). Thanks to Sven Goethel. - Fixed MPlayer key repeat. Thanks to Reinhard Walter Buchner. - Added yellow/green key to MPlayer control to skip back/forward a minute. Key assignment may change in future for these keys. - Fixed Makefile for DVB includes. - Fixed creation of cMPlayerStatus according to the rules. - Fixed pipe reading and parse code. Caused all kind of weird behaviour. - Some changes to the MPlayer pipe handling. - Changed the network ringbuffer handling. You should use VDR version 1.1.25+ or you may suffer from high cpu load during network streaming. - Added a console message if a plugin fails to start due to a missing sources.conf. 03.02.2003: Version 0.7.10 plugin development (vdr 1.1.23) - Added patches for MPlayer 0.90rc1 (contributed by Beppe on the VDR ML). - Adapted to the API changes in vdr 1.1.22. - Removed speed drift detection. Makes not much sense with HEAD driver, as this supports non-48kHz modes anyways. 18.12.2002: Version 0.7.9 plugin development (vdr 1.1.20) - Added commandline option to specify a script which is called before & after network access (e.g. for dial-up networking) (suggested by Matthias Raus). - Fixed playback speed check for (partly) corrupted files. - Fixed blocking frontend thread during possibly slow playback startup. - Added support for shoutcast/icecast streams. See MANUAL for URL file format and setup menu options. 24.11.2002: Version 0.7.8 plugin development (vdr 1.1.16) - Speed up local CDDB database search with huge databases. Due to this, only one subdirectory level is allowed in the database directory (usually the category name). This follows the common xmcd database layout. - Added code for remote CDDB lookups. cddb.sh script is no longer needed. Please note, that the commandline options have changed. - Added some status output while scanning/loading playlists to inform the user. 13.11.2002: Version 0.7.7 plugin development (vdr 1.1.16) - Updated Makefile to support Make.config. - Removed a deadlock together with the rt-patch. - Added support for the new remote keys (play,pause,fastfwd/rwd). 06.10.2002: Version 0.7.6 plugin development (vdr 1.1.12) - Removed a class name conflict (cSource) introduced with the changes in vdr 1.1.12. - Added a field to the sources.conf files to specify which kind of files should be used on a source (see mp3sources.conf.example). 06.09.2002: Version 0.7.5 plugin development (vdr 1.1.8) - Fixed bug in new status string code, which crashed VDR if a song without artist tag was played. - Fixed parsing error of MPlayer output in slavemode if "C" is not the current locale. - Fixed jump to minute in MPlayer slavemode. - If you have installed the "replay mode beauty patch" the new symbols are used for MPlayer progressbar too. This feature is auto-detected in the Makefile. 01.09.2002: Version 0.7.4 plugin development (vdr 1.1.8) - Changed the status string to show the loop/shuffle state too. - Fixed replay problem with background mode "black". With vdr 1.1.8 you must apply the included patch to the base source. - Changed the way mplayer.sh is called. Now it shouldn't be necessary to give the full path to the script if the script is in the current PATH. - Added MANUAL a file. - New setup option SlaveMode for MPlayer. With SlaveMode enabled you can control MPlayer via VDR. A progress display is available too. See MANUAL for details (thanks to Dariush Forouher). 23.08.2002: Version 0.7.3 plugin development (vdr 1.1.7) - Now using libsndfile 1.x.x. You must update you system. The plugin won't compile with version 0.0.x. - Fixed detection if MPlayer is still running. - Fixed GetIndex() to return frames rather than seconds (thanks to Martin Hammerschmidt). - The last second of the last song in a playlist wasn't played. Now waiting until the ringbuffer is really empty. 16.08.2002: Version 0.7.2 plugin development (vdr 1.1.7) - Fixed gcc 2.96 compiling error due to variable name "not". - Fixed a undefined symbol error when compiling without libsndfile. - Fixed a deadlock in the MP3 player. - Removed old stale LCD code parts. - Now using free() on all strings. - Adapted to the API changes in vdr 1.1.7. 11.08.2002: Version 0.7.1 plugin development (vdr 1.1.6) - Added some calls to the status monitor. - Fixed internationalization (thanks to David Spiller). - Fixed jump to the next song at the end of current song (thanks to David Spiller). - Replaced all busy usleep wait loops with proper condition variables. - Removed one thread level in the MPlayer plugin. 08.08.2002: Version 0.7.0 plugin development (vdr 1.1.6) - Updated the source base to release version 0.6.2. - Added MPlayer plugin. - MP3 playback now functionaly. 13.05.2002: Version 0.0.2 plugin development (vdr 1.1.2) - Added setup menu page and saving of setup options. - Adding to playlist and playlist rename now functional. Beside playback all menus are (better should be) working. - Now using confdir/plugins/mp3sources.conf for sources config. 10.05.2002: Version 0.0.1 plugin development (vdr 1.1.1) - Initial revision. mp3-0.10.2/MANUAL0100644000000000000000000005326410735452037011710 0ustar rootroot This is a dual-plugin for VDR. The "MP3-Plugin" allows playback of MP3 and other audio files. The "MPlayer-Plugin" is used to call MPlayer for playback of video files (e.g. DivX) Written by: Stefan Hќlswitt Project's homepage: http://www.muempf.de/ Latest version available at: http://www.muempf.de/down/ See the file COPYING for license information. ---------------------------------------------------------------------- For install instructions see the README file. For MPlayer plugin documentation skip to the end this file. **** **** **** MP3 plugin **** **** The basic concept of the MP3 plugin is to use playlists for the songs you want to play. So most things designed toward playlists, but you can play directories and single files as well. Available audio codecs: libmad Supports MPEG-1/2/2.5 with layers 1/2/3. libsndfile Supports MS WAV/A-law/u-law; Apple/SGI AIFF/AIFC; Sun/NeXT AU/SND; Amiga IFF/8SVX/16SV and more. libvorbis Supports OGG. The starting point for all MP3 actions (or more generally: all song actions) is the MP3 menu. Select the MP3 entry from VDR's main menu to enter this menu. The MP3 menu: ------------- A list of available playlists is displayed (only playlists in your base directory of the selected source are displayed, there is no recursive scanning for playlists). Select the a playlist with "up" and "down". Press "OK" to start playback with the selected playlist. Press the "blue" key to see a second level of buttons. If you are on the second level, press the "red" button to return to the first level. If you are on the first level, press "red" to enter the playlist editor with the selected playlist (see Playlist editor). Press "green" to enter the source selector (see Sources). Press "yellow" to enter the file browser (see Browsing and instant playlists). On the second level, press "green" to create a new, empty playlist and enter the playlist editor. The new playlist will be named "unnamed" followed by a number. Press "yellow" to delete a playlist. There is a double confirmation needed to really delete the playlist. Press "blue" to rename a playlist. You are prompted for a new name. Press "back" to abort renaming. During playback: ---------------- During playback you will see the channel which was tuned last or a black screen depending on what you choose in setup (see Setup options). You can use some keys to control playback: Down skips back to the start of current song or to previous song if you are at the beginning of current song. Up skips forward to the start of next song. Right/Left skips back/forward 3 seconds in current song. Hold key to scan through song. Red enters jump mode. Enter the number of minutes/seconds you want to jump with the number keys. Press "left" to jump backwards, "right" to jump forward and "up" to jump to the absolute position. Press "blue" to toggle the jump unit between minute (m) and seconds (s). Any other key cancels jump mode. Note: jumping forward requires to scan all frame headers until the new position. On slow media or with long jumps this may be visible in the progress display. Green toggles loop and shuffle mode. Press once to enable loop, twice for loop and shuffle and three times for shuffle only. To disable shuffle, wait >4 seconds and press again. Yellow is pause/unpause. Blue aborts playback. Back aborts playback and returns to MP3 menu. Ok toggles progress display. If "ok" is pressed again within 4 seconds, the playlist window is opened (playlist window is available with classic progress display mode only). The color bar marks the current song. If the playlist window is open, you can page through the playlist with "left" and "right". If available title/artist is displayed. This is true for songs already played or which have been scanned in background (see Setup options). Menu enters VDR's main menu. 0-9 direct song selection. Selection timeout is 1 second. The progress display shows various information bits which are flipped every few seconds. You can adjust which information is shown (see Setup options). The playlist editor: -------------------- In the playlist editor you can add and remove files and shuffle them around. Press "red" to add songs to the playlist. A directory browser is started. You will see the directories and files you created beneath you the base directory of the current source. The entries surrounded by [ ] are directories. If you press "ok" on a directory, you will decent to this directory. Press "red" to add the current file/directory to the playlist. Selecting a directory adds recursively all files from the directory and subdirectories. If you have selected more than one file, you have to confirm the action. The new file(s) will be inserted below the currently selected file in the playlist. Press "green" to toggle between display of filenames and titles/artists (if available). The initial display of title/artist may take some time as all the files have to be scanned. You can configure if the editor is started with title/artist or filename display (see Setup options). Press "ok" over an entry to display a information page for this file. Song information which have been scanned in the playlist editor or during playback are saved to a file called "id3info.cache" located in the video directory. This file is used to speed up display of title/artist for files you already touched. The file is loaded on startup and saved regularly while VDR is running. Press "yellow" to remove a song from the playlist (the file IS NOT removed from disk, of course). Press "blue" to reorder the songs in the playlist. Browsing and instant playlists: ------------------------------- If you enter the browser you can browser through your song files. You can start playback for individual files, playlists and whole directories from here too. Position on a file or directory and select "red" to start playback. A "instant" playlist is created which contains either the selected file or all files from the selected directory and its subdirectories. When scanning directories, all files matching "*.m3u" (playlists) are ignored. The "instant" playlist is deleted if you stop playback. In the basedir you can press "yellow" to play all files in all directories. Press "blue" over an entry to display the song information page. Sources and playlists: ---------------------- It's fine to have all your songs on harddisk, but may be you have some CDROM's with song files on them and you want to play them directly from CDROM? Then this is what you are looking for! You can define multiple sources from which your songs could be played. At runtime you can select which source to use, you can mount, unmount and eject the source at runtime, too. This is done through a config file and a simple shell script. First you have to create a config file named "mp3sources.conf" located in the "plugins" subdirectory of the directory where you keep the other config files for VDR (e.g. if your VDR configfiles are in "/video" you must create the files as "/video/plugins/mp3sources.conf"). Every line defines a source (see the example config file which comes with the archive). You need three information for a source: the base directory, a description and a flag which determines if a mount/unmount/eject command is applicable to this source. Optionally you can give a fourth information to specify which kind of files should be used on this source. The fields must be separated by a semicolon. The basedir must be a real directory. Using a symlink to a directory will not work. So a valid line could be: /mp3;Local files;0 This means that the base directory is /mp3, the description say that these are local files and mount/unmount/eject commands can not be applied here. If you want to ignore all files without the ".mp3" extension, you could use: /mp3;Local files;0;*.mp3 You can give multiple patterns separated with a slash: /mp3;Local files;0;*.mp3/*.ogg/*.wav Another useful one: /cdrom;CDROM;1 This means that the base directory is /cdrom, which is obviously a CDROM drive and mount/unmount/eject commands can be applied here. Note some important things for using mount/unmount/eject commands here: - You must have defined an entry in your /etc/fstab for the base directory. - The user running VDR must have permission to mount/unmount the device (e.g. add "users" to the options in /etc/fstab). - You must have a mount script which can be called from VDR (see below). The actual mount/unmount/eject action is done with a script. See the README file and the example "mount.sh" which comes with the archive. You can create arbitrary directories below the base directory to group your songs. BUT all playlists have to be located in the base directory (the tree is not scanned recursively for playlists). A playlist is a simple text file which contains the paths of the songs to play. One path/filename on every line. The paths must be relative to the base directory (e.g. if you have a MP3 file /mp3/rock/bon_jovi/sample.mp3 a proper line in a playlist would be rock/bon_jovi/sample.mp3). All playlist must have the extension ".m3u". You also can load WinAmp-style playlists, this means that comment lines starting with "#" are ignored and if a line "#EXTM3U" is found, the pathnames are converted from DOS-style to UNIX-style (changing "\" to "/"). The DOS-style pathnames must not contain "/" for proper conversion. The sources menu: ----------------- If you enter this menu, you will get the list of the sources which you have defined in "mp3sources.conf". Entries marked with ">" can be mounted/unmounted. An entry marked with "*" is currently mounted. Use the "red" key to select a source. All playback and editing functions will refer only to the selected source. Press "green" to mount the source, "yellow" to unmount and "blue" to eject the media. Setup options: -------------- There are various configuration options which can be changed from the plugin setup menu. Select VDR's setup menu, select "Plugins" and select "mp3" to enter the setup menu. Audio output mode: The MP3 plugin supports alternative sound output modes (if activated at compile time). Use this option to select the desired output mode. Audio mode: The MP3 decoder of libmad delivers 24bit data which must be scaled to 16bit for output. You can select how this is done. "round" simply cuts of the LSB bits, while "dither" implements a error diffusion strategy. "dither" takes slightly more CPU power (about 1% on my 400Mhz Celeron). Use 48kHz mode only: Forces the plugin to use the default DVB samplerate of 48kHz only. All other are resampled to this value. Display mode: Choose which information is shown in the progress display: 1 - shows only title and artist. 2 - additionally shows album and year. 3 - additionally shows samplerate, bitrate and number of channels. Background mode: Choose what you want to see during playback: Black - a black screen Live - live video from the last tuned channel Images - display cover images (if available) Initial loop mode: Choose if loop mode should be enabled by default. Initial shuffle mode: Choose if shuffle mode should be enabled by default. Abort player at end of list: If you set this option to "no" and the end of playlist is reached, the player is kept idle. To restart playback select a song to restart from there or "up" to restart from the beginning. Background mode: Choose if the background scanner is enabled during playback. In the playlist window, title/artist is shown only for songs already played or which have been scanned in background. There are two scan modes: "ID3 only" gathers information from ID3 tags only, while "ID3 & Level" pre-calculates the level for the normalizer as well. Note that level scan requires to decode the complete song. This is done on a separate thread with nice 5 but nevertheless it needs CPU cycles. If you have a slow CPU your system may crawl. Editor display mode: Choose if the playlist editor shows title/artist or filenames by default. Be warned: the initial display of the title/artist may take some time, as all the files in the playlist have to be scanned. This is specially true for slower storage media. Main menu mode: Choose if you want to see your playlists or if you want to jump to the directory browser when entering the MP3 menu. Normalizer level: The volume level for the normalizer. Allowed range is 0-50. If set to zero the normalizer is disabled (see The normalizer). Limiter level: The volume level for the limiter. Samples above this level are limited. Allowed range is 25-100. If set to 100 the limiter is disabled (see The normalizer). Use HTTP proxy: Enables use of a HTTP proxy server when playing Shoutcast/Icecast streams. HTTP proxy host: The hostname of the HTTP proxy (used only if you have enabled HTTP proxy option above). HTTP proxy port: The port number to use on the HTTP proxy server (used only if you have enabled HTTP proxy option above). CDDB for CD-Audio: Enables lookups to the CDDB database if cd-audio is played via cdfs. You can choose between local only and local&remote lookups. CDDB server: The hostname of the CDDB server (used only if you have enabled remote lookups above). CDDB port: The port number to use on the CDDB server (used only if you have enabled remote lookups above). Playing Shoutcast/Icecast streams: ---------------------------------- The plugin is able to play Shoutcast and Icecast streams (which in fact are just streamed MP3's). This feature needs some special setup: First, your VDR machine must have a connection to the internet (either directly or through a proxy). Second, you have to create a simple text file in any of your MP3 source directories for every stream you want to play. The file must contain a single line of text with the complete URL of the stream. E.g. the file could contain (no guarantee that this link still works): http://152.163.134.164:80/stream/1012 The link must point to the stream itself and not to any kind of playlist. To play the stream, add the text file to a playlist or select the file from the browser. You cannot pause, FWD or REW a stream. Note: - If you internet connection doesn't provides the bandwidth the stream requires, playback will be distorted. - Any network operation has a timeout of 30 seconds (in case the stream server stalls). You should not set VDR's watchdog timer below this value. - If the stream server provides special Icecast headers or metadata, these values are displayed in the progress display. The normalizer: --------------- Very often songs from different albums are recorded at different volume levels. If you have playlists with songs from different albums, it's very likely that you keep adjusting the volume at you amplifier all the time. This is why the MP3 plugin has a function to normalize the volume level of all songs to a common level. The algorithm to calculate and to adjust the volume level was taken from the normalize project (version 0.7) from Chris Vaill. Basically the song is divided into chunks, for which the peak level is calculated. From the peak level a moving average value is calculated and the maximum of this is considered a measure for the perceived volume. Please refer to the normalize homepage for more details. This approach has one drawback: you must first decode the complete file to calculate the volume level. For this reason, the normalize function can not be applied if you are listening a song for the very first time. In this case the volume level is calculated and stored to the song cache file. If you are listening to the same songs again, the volume level is read back and the normalize function is applied. There are two parameters for the normalize function which can be changed via setup menu: The "target level": this is the volume level to which all songs are normalized. The allowed range is 0-50, while useful values are between 25 and 30. Setting the target level to zero disables the normalize function. You shouldn't use this parameter as a volume adjustment (volume adjustment should be done at your amplifier). You should set this parameter slightly above the average volume level of your songs (in my case this is 27). You can use the normalize tool from to calculate the volume level for all your songs (if invoked with --fractions, normalize returns a volume level which must be multiplied with 100 to be comparable). The "limiter level": this is the volume level for the limiter function. When boosting up the volume of a songs, it may very well happen that individual samples exceed the allowed range. In this case, one could simply clip the sample to the allowed range, but this would remove too much information from the audio data. So a kind of dynamic compression is applied to the exceeding samples to bring them back to the allowed range without loosing to much. The dynamic compression is applied to all sample above the limiter level. The allowed range is 25-100. Setting the limiter level to 100 disables the dynamic compression and returns to clipping. I'm not sure about the useful range of this parameter. While normalize uses 25, I prefer 70 as this leaves much more audio data untouched. **** **** **** MPlayer plugin **** **** The MPlayer plugin is basically a front-end to MPlayer . You can select a video file from a browser which then is replayed with MPlayer. The MPlayer menu: ----------------- The MPlayer menu is very similar to the the directory browser of the MP3 plugin. You will see the directories and files you created beneath you the base directory of the current source (how to define sources is explained in "Sources and playlists" in the MP3 plugin section, but the config file is named "mplayersources.conf"). The entries surrounded by [ ] are directories. If you press "ok" on a directory, you will descend to this directory. Press "green" to return to the parent directory. Use "yellow" to select a different source (see "The sources menu" in the MP3 plugin section). Press "red" to start replay of the current file. MPlayer will be started with this file through a shell script (see README file). There are two different ways to control MPlayer during replay. The control mode is selected from the MPlayer plugin setup menu. The traditional mode: --------------------- In traditional mode, only "blue" from VDR's remote is active to abort the replay. No other action is passed to MPlayer. It's up to you to configure MPlayer to use whatever control device you want (e.g. LIRC, keyboard). The slave mode: --------------- In slave mode the MPlayer plugin acts as a control frontend to MPlayer. All important actions are passed from VDR's remote to MPlayer (see README file on how to setup your mplayer.sh script for this mode). You can use the following keys to control playback: Down is pause/unpause. Up returns to normal replay. Right/Left skips back/forward 10 seconds. Red enters jump mode. Enter the number of minutes/percent you want to jump with the number keys. Press "left" to jump backwards, "right" to jump forward and "up" to jump to the absolute position. Press "blue" to toggle the jump unit between minute (m) and percent (%). Any other key cancels jump mode. Green skips back 60 seconds. Yellow skips forward 60 seconds. Blue/Back aborts playback. Ok toggles progress display. 0-9 send MPlayer slave command (configurable in plugin setup menu). In addition the "Volume+","Volume-" and "Mute" keys are routed to MPlayer. Setup options: -------------- There are some configuration options which can be changed from the plugin setup menu. Select VDR's setup menu, select "Plugins" and select "mplayer" to enter the setup menu. Control mode: The MPlayer plugin supports two control modes during replay: traditional and slave (see description above). Resume mode: Selects the mode for resuming playback. "local first" means that the plugin first tries to use a resume file in the directory of the video file. Only if this directory is non-writeable the global resume file is used. "global only" will use the global file only and "disabled" disables resume completely. Slave command key: Customize the slave commands which are send to MPlayer when the remote keys "0" to "9" are pressed. Hide main menu entry: Hides the MPlayer menu entry from the main menu. mp3-0.10.2/Makefile0100644000000000000000000001626311277241323012442 0ustar rootroot# # MP3/MPlayer plugin to VDR # # (C) 2001-2009 Stefan Huelswitt # # This code 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 code is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Or, point your browser to http://www.gnu.org/copyleft/gpl.html # You can change the compile options here or create a Make.config # in the VDR directory an set them there. ### uncomment one of these lines, if you don't want one of the plugins #WITHOUT_MP3=1 #WITHOUT_MPLAYER=1 ### uncomment the following line, if you don't have libsndfile installed #WITHOUT_LIBSNDFILE=1 ### uncomment the following line, if you don't have libvorbisfile installed #WITHOUT_LIBVORBISFILE=1 ### uncomment the following line, if you want OSS sound output #WITH_OSS_OUTPUT=1 ### uncomment the following line, if you want to include debug symbols #DBG=1 ### The C++ compiler and options: CXX ?= g++ CXXFLAGS ?= -O2 -fPIC -Wall -Woverloaded-virtual ############################################### ############################################### # # no user configurable options below this point # ############################################### ############################################### ### The directory environment: VDRDIR = ../../.. LIBDIR = ../../lib TMPDIR = /tmp # 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 = mp3 PLUGIN2 = mplayer ### Allow user defined options to overwrite defaults: -include $(VDRDIR)/Make.config -include Make.config ### The version number of this plugin: HGARCHIVE = .hg_archival.txt RELEASE := $(shell grep 'define PLUGIN_RELEASE' version.h | awk '{ print $$3 }' | sed -e 's/[";]//g') RELSTR := $(shell if test -d .hg; then \ echo -n "-"; (hg identify 2>/dev/null || echo -n "Unknown") | sed -e 's/ .*//'; \ elif test -r $(HGARCHIVE); then \ echo -n "-"; grep "^node" $(HGARCHIVE) | awk '{ printf "%.12s",$$2 }'; \ fi) VERSION := $(RELEASE)$(RELSTR) ### The version number of VDR (taken from VDR's "config.h"): VDRVERSION := $(shell sed -ne '/define VDRVERSION/ s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/include/vdr/config.h) APIVERSION := $(shell sed -ne '/define APIVERSION/ s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/include/vdr/config.h) ifeq ($(strip $(APIVERSION)),) APIVERSION = $(VDRVERSION) endif VDRVERSNUM := $(shell sed -ne '/define VDRVERSNUM/ s/^.[a-zA-Z ]*\([0-9]*\) .*$$/\1/p' $(VDRDIR)/include/vdr/config.h) APIVERSNUM := $(shell sed -ne '/define APIVERSNUM/ s/^.[a-zA-Z ]*\([0-9]*\) .*$$/\1/p' $(VDRDIR)/include/vdr/config.h) ifeq ($(strip $(APIVERSNUM)),) APIVERSNUM = $(VDRVERSNUM) endif ### The name of the distribution archive: ARCHIVE = $(PLUGIN)-$(RELEASE) PACKAGE = vdr-$(ARCHIVE) ### Includes and Defines (add further entries here): INCLUDES += -I$(VDRDIR)/include DEFINES += -D_GNU_SOURCE -DAPIVERSNUM=$(APIVERSNUM) ### The object files (add further files here): COM_OBJS = data.o menu.o version.o OBJS = $(PLUGIN).o $(COM_OBJS)\ data-mp3.o setup-mp3.o player-mp3.o stream.o network.o\ decoder.o decoder-mp3.o decoder-mp3-stream.o decoder-snd.o \ decoder-ogg.o decoder-ogg-stream.o compat.o LIBS = -lmad -lid3tag ifndef WITHOUT_LIBSNDFILE LIBS += -lsndfile DEFINES += -DHAVE_SNDFILE endif ifndef WITHOUT_LIBVORBISFILE LIBS += -lvorbisfile -lvorbis DEFINES += -DHAVE_VORBISFILE endif ifdef WITH_OSS_OUTPUT DEFINES += -DWITH_OSS endif ifdef BROKEN_PCM DEFINES += -DBROKEN_PCM endif OBJS2 = $(PLUGIN2).o $(COM_OBJS)\ setup-mplayer.o player-mplayer.o LIBS2 = ifdef DBG CXXFLAGS += -g endif ifneq ($(shell if test $(APIVERSNUM) -ge 010703; then echo "*"; fi),) DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE endif ### Internationalization (I18N): PODIR = po I18Npot = $(PODIR)/mp3-mplayer.pot I18Npots := $(notdir $(foreach file, $(wildcard $(PODIR)/*.po), $(basename $(file)))) ifeq ($(strip $(APIVERSION)),1.5.7) I18Nmo = $(PLUGIN).mo I18Nmo2 = $(PLUGIN2).mo else I18Nmo = vdr-$(PLUGIN).mo I18Nmo2 = vdr-$(PLUGIN2).mo endif LOCALEDIR = $(VDRDIR)/locale I18Nmsgs := $(addprefix $(LOCALEDIR)/,$(addsuffix /LC_MESSAGES/$(I18Nmo),$(I18Npots))) I18Nmsgs2 := $(addprefix $(LOCALEDIR)/,$(addsuffix /LC_MESSAGES/$(I18Nmo2),$(I18Npots))) HASLOCALE = $(shell grep -l 'I18N_DEFAULT_LOCALE' $(VDRDIR)/include/vdr/i18n.h) ifeq ($(strip $(HASLOCALE)),) COM_OBJS += i18n.o endif ### Targets: ifndef WITHOUT_MP3 ALL += libvdr-$(PLUGIN).so ifneq ($(strip $(HASLOCALE)),) ALL += i18n-$(PLUGIN) endif endif ifndef WITHOUT_MPLAYER ALL += libvdr-$(PLUGIN2).so ifneq ($(strip $(HASLOCALE)),) ALL += i18n-$(PLUGIN2) endif endif all: $(ALL) .PHONY: i18n-$(PLUGIN) i18n-$(PLUGIN2) # Dependencies: MAKEDEP = g++ -MM -MG DEPFILE = .dependencies DEPFILES = $(subst i18n.c,,$(subst version.c,,$(OBJS:%.o=%.c) $(OBJS2:%.o=%.c))) $(DEPFILE): Makefile $(DEPFILES) $(wildcard *.h) @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(DEPFILES) > $@ -include $(DEPFILE) # Rules %.o: %.c $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< libvdr-$(PLUGIN).so: $(OBJS) $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@ @cp $@ $(LIBDIR)/$@.$(APIVERSION) libvdr-$(PLUGIN2).so: $(OBJS2) $(CXX) $(CXXFLAGS) -shared $(OBJS2) $(LIBS2) -o $@ @cp $@ $(LIBDIR)/$@.$(APIVERSION) $(I18Npot): $(shell grep -rl '\(tr\|trNOOP\)(\".*\")' *.c ) xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='' -o $@ $^ %.po: $(I18Npot) msgmerge -U --no-wrap --no-location --backup=none -q $@ $< @touch $@ %.mo: %.po msgfmt -c -o $@ $< $(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/$(I18Nmo): $(PODIR)/%.mo @mkdir -p $(dir $@) cp $< $@ i18n-$(PLUGIN): $(I18Nmsgs) $(I18Nmsgs2): $(LOCALEDIR)/%/LC_MESSAGES/$(I18Nmo2): $(PODIR)/%.mo @mkdir -p $(dir $@) cp $< $@ i18n-$(PLUGIN2): $(I18Nmsgs2) i18n.c: $(PODIR)/*.po i18n-template.c po2i18n.pl perl ./po2i18n.pl i18n.c version.c: FORCE @echo >$@.new "/* this file will be overwritten without warning */"; \ echo >>$@.new 'const char *PluginVersion =' '"'$(VERSION)'";'; \ diff $@.new $@ >$@.diff 2>&1; \ if test -s $@.diff; then mv -f $@.new $@; fi; \ rm -f $@.new $@.diff; dist: clean @-rm -rf $(TMPDIR)/$(ARCHIVE) @mkdir $(TMPDIR)/$(ARCHIVE) @cp -a * $(TMPDIR)/$(ARCHIVE) @tar czf $(PACKAGE).tar.gz -C $(TMPDIR) $(ARCHIVE) @-rm -rf $(TMPDIR)/$(ARCHIVE) @echo Distribution package created as $(PACKAGE).tar.gz clean: @-rm -f $(OBJS) $(OBJS2) $(DEPFILE) libvdr-*.so $(PACKAGE).tar.gz core* *~ @-rm -f version.c i18n.c @-rm -f $(PODIR)/*.mo FORCE: mp3-0.10.2/README0100644000000000000000000002410111270456403011650 0ustar rootroot This is a dual-plugin for VDR. The "MP3-Plugin" allows playback of MP3 and other audio files. The "MPlayer-Plugin" is used to call MPlayer for playback of video files (e.g. DivX) Written by: Stefan Hќlswitt Project's homepage: http://www.muempf.de/ Latest version available at: http://www.muempf.de/down/ See the file COPYING for license information. ---------------------------------------------------------------------- For the user manual see the MANUAL file. Installing: ----------- By default the Makefile builds both plugins. If you want to use only one of them, you can add one of "WITHOUT_MP3=1" or "WITHOUT_MPLAYER=1" to your Make.config. In the past month the plugins only have been tested with VDR 1.4.x and 1.5.x. While the plugins probably can be compiled with VDR down to version 1.1.29, this is not tested nor supported. By default any mentioned plugin config file should be located in the "plugins" subdirectory of your VDR config directory (see commandline option -S to specify an plugin specific subdirectory). For a complete description of the config files, see the MANUAL file. The MP3 plugin needs some external libraries (some optionally): You must have installed libmad and libid3tag from for decoding MP3 and ID3 support. Recommended version is 0.15.1b. To compile and install I suggest the following sequence from the source directory (libmad and libid3tag are installed separately, so you must execute this once for each directory): > configure > make > make install > ldconfig For playback of WAV and other sound files you must have installed libsndfile on your system. Recommended version is 1.0.11 or newer. The old 0.0.x series doesn't work due to some API changes. To compile and install libsndfile I suggest the following sequence from the libsndfile source directory: > configure > make > make install > ldconfig If you don't want to install libsndfile, you must add "WITHOUT_LIBSNDFILE=1" to your Make.config. If you want to listen to CD audio, you can use cdfs (version 0.5c suggested). I suggest that you create a new entry in /etc/fstab and mp3sources.conf for cdfs. The /etc/fstab entry could look like: /dev/hdc /mnt/cdfs cdfs ro,noauto,user 0 0 The entry for mp3sources.conf could look like: /mnt/cdfs;CD-Audio;1 Or if you want only WAV files to be displayed: /mnt/cdfs;CD-Audio;1;*.wav If you don't like cdfs, you could use any other filesystems which allows to access the CD audio data as WAV files. For playback of OGG files you must have installed libvorbis and libvorbisfile on your system. Most Linux distributions include packages for this. If you don't want to install the vorbis libraries, you must add "WITHOUT_LIBVORBISFILE=1" to your Make.config. The MP3 plugin can output the sound to an OSS soundcard. To compile this support add "WITH_OSS_OUTPUT=1" to your Make.config. The output device defaults to "/dev/dsp" (see commandline option -D too). Don't forget to enable OSS output in the plugin setup menu. Before compiling the plugin, you could have a look at "mp3-config.h". This file includes a number of defines to set options and values at compile time. You should only change defines, if you have understand the source code parts which deal with the define. Improper settings can make the MP3 plugin to fail or to operate unsmoothly. So you should know what you are doing. To build the plugin(s) type: "make plugins" from the VDR source directory. To make the progressbar work with the MPlayer plugin and slave mode you need to apply a small patch to mplayer. Select an appropriate patch file for your MPlayer version from the patches subdirectory. Apply the patch and recompile MPlayer. Early 0.90rc versions of MPlayer need a patch to enabled HEAD driver support too. You will find one for 0.90rc1 in the patches subdirectory. Probably you'll have to point configure to the new DVB include files with --with-extraincdir=/usr/local/src/DVB/include or where ever you have stored the files. MPlayer versions later as 0.90rc5 allow to select HEAD support with a configure option or even detect this automatically. Commandline options: -------------------- For both plugins it's possible to give an additional configuration subdirectory with commandline option -S/--sources, i.e. the given directory name is appended to the default plugin config directory path. Both plugins have a commandline option -m/--mount to define the name and location of the mount script. The default mount script is "mount.sh". This script is called from the plugin with 2 options on the commandline. The first is one of mount/unmount/eject/status and gives the action to perform. The second one is the base directory as defined in "mp3sources.conf" or "mplayersources.conf". The script must return the exit code 0 if the action was successful and 1 if the action failed (see the comments in the example "mount.sh" script which comes with the archive). The MP3 plugin maintains a cache for information scanned from song files (e.g. ID3 tags). This information is saved to the id3info.cache file by default located in the video directory. You can use commandline option -C/--cache to specify a different directory for this file. If you are using cdfs, the MP3 plugin is able to query a CDDB database for the song information (like title, artist). Local CDDB lookups can be enable from the setup menu and you must give the path to your local CDDB files with commandline option -B/--cddb. The database layout follows the xmcd standard (one subdirectory level for the categories, individual files for every disc). The settings for remote CDDB lookups can be found in the setup menu, too. Any information retrieved from a remote host is stored to your local CDDB database, so the user running VDR needs write access to this directory. If you are using any of the networking capabilities and you have a dial-up network, you can use the commandline option -n/--network to give a script name. This script is called before and after any network access and receives one option on commandline. This can either be "up" or "down", depending on if it's before or after the network access. In the "up" case the script should not return before the network is connected and useable. By default the plugin assumes that network access can be done at any time without prior action. If you want to use the OSS output capability but your soundcard device is not "/dev/dsp" (which is the default) you can use the commandline option -D/--dsp to give an alternative soundcard device. If you want to use the cover image display, you have to provide an image converting script. Usually your covers are in a common image format like e.g. JPEG or PNG, but the MP3 plugin can only display MPEG (still) frames. The conversion is done by the script, which takes two arguments: first the filename of the image file and second the filename or the resulting MPEG file. The script also has to take care that any needed subdirectories in the cache are created e.g. mkdir -p. You will find an example script in the examples subdirectory. By default the script is called "image_convert.sh", but you can use the commandline option -i/--iconv to change the name and location of the script. To speed up consecutive accesses to the same image, the converted frames are cached on disk. The default cache directory is "/var/cache/images/mp3". You can change this location with the commandline option -c/--icache. Don't forget to enable the image display in the plugin setup menu. The search order for images is: - An image in the same directory as the song, named like the song but with the song extension replaced with the image format extension e.g. test.mp3 -> test.jpg - An image named "cover" with the image format extension in the same directory as the song (album cover). e.g. cover.gif - An image named "artist" with the image format extension in the parent directory of the song (artist image). e.g. artist.png - An image named "background" with the image format extension in the base directory of the MP3 source. For all locations the extensions "jpg", "png" & "gif" are checked (in that order). If no image can be found, a full screen black image is displayed (this is included statically in the plugin). MPlayer is called through a script called "mplayer.sh" with the filename to play as first argument and the phrase SLAVE as second argument if slave mode is enabled. Additional the environment variable DVB_DEVICE will be set with the number of the DVB card which VDR uses as primary display. You can use the commandline option -M/--mplayer to change the name and location of the mplayer script. The script has to call MPlayer with all the necessary options. The script should parse the SLAVE keyword too and give appropriate options to MPlayer. To enable slave mode you must give at least the "-slave" option, while I suggest "-slave -nolirc -quiet". You can use the mplayer.sh.example file, which comes with the archive, as a starting point. Juri Haberland maintains a full featured mplayer.sh file which is available at . For the MPlayer plugin you can give a location for the global resume file with commandline option -R/--resume. Summary of commandline options: ------------------------------- MP3 Plugin: -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources -n CMD, --network=CMD execute CMD before & after network access -B DIR, --cddb=DIR search CDDB files in DIR -C DIR, --cache=DIR store ID3 cache file in DIR -D DIR, --dsp=DIR device for OSS output -i CMD, --iconv=CMD use CMD to convert background images -I IMG, --defimage=IMG use IMG as default background image -c DIR, --icache=DIR cache converted images in DIR -S SUB, --sources=SUB search sources config in SUB subdirectory MPlayer plugin: -m CMD, --mount=CMD use CMD to mount/unmount/eject mplayer sources -M CMD, --mplayer=CMD use CMD when calling MPlayer -S SUB, --sources=SUB search sources config in SUB subdirectory -R DIR, --resume=DIR store global resume file in DIR mp3-0.10.2/README.po2i18n0100644000000000000000000000341610735452037013061 0ustar rootroot po2i18n - Converter for po files Written by: Udo Richter Project's homepage: http://www.udo-richter.de/vdr/scripts.html#po2i18n http://www.udo-richter.de/vdr/scripts.en.html#po2i18n About -------------------------------------------------------------------------- po2i18n is a perl script that generates an i18n.c file compatible to the i18n system of VDR 1.2.0 - VDR 1.5.6, based on the .po files of VDR 1.5.7. This allows plugins to transit to the translation system of VDR 1.5.7 while maintaining compatibility to earlier versions. The script can be used manually or automatically as part of the Makefile. Use -------------------------------------------------------------------------- po2i18n.pl is a filter and can be used manually like this: ./po2i18n.pl < i18n-template.c > i18n.c The filter reads all relevant ./po/*.po files and writes the i18n strings into the template file. Strings will be added between the following two lines: // START I18N // END I18N See also the sample i18n.h and i18n-template.c file. Note that the phrases data structure is encapsulated in #if VDRVERSNUM < 10507, so the i18n strings won't be in the plugin file after 1.5.7. The call to RegisterI18n() of your plugin should also be encapsulated like this. po2i18n can also generate the i18n.c file on the fly while compiling. The changes to the Makefile are demonstrated by the included Makefile.diff sample. With these changes, the i18n.c file will be generated on VDR up to 1.5.6, and the whole gettext conversion is skipped. From 1.5.7 on, the i18n-template.c file will be simply copied as a dummy, and the new locale system will run. As a drawback, the automatic .dependencies for i18n.c won't work. mp3-0.10.2/common.h0100644000000000000000000000224611145023367012437 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___COMMON_H #define ___COMMON_H #ifndef PLUGIN_NAME_I18N #define PLUGIN_NAME_I18N "dummy" #endif #ifndef APIVERSNUM #include #endif #include "config.h" #include "compat.h" #if !defined(NO_DEBUG) && defined(DEBUG) #define d(x) { (x); } #else #define d(x) ; #endif #endif //___COMMON_H mp3-0.10.2/compat.c0100644000000000000000000000673611145022673012434 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #if APIVERSNUM < 10503 #include #include #include "common.h" // --- cCharSetConv ---------------------------------------------------------- char *cCharSetConv::systemCharacterTable = NULL; cCharSetConv::cCharSetConv(const char *FromCode, const char *ToCode) { if (!FromCode) FromCode = systemCharacterTable; if (!ToCode) ToCode = "UTF-8"; cd = (FromCode && ToCode) ? iconv_open(ToCode, FromCode) : (iconv_t)-1; result = NULL; length = 0; } cCharSetConv::~cCharSetConv() { free(result); iconv_close(cd); } void cCharSetConv::SetSystemCharacterTableX(const char *CharacterTable) { free(systemCharacterTable); systemCharacterTable = NULL; if (!strcasestr(CharacterTable, "UTF-8")) { systemCharacterTable = strdup(CharacterTable); } } const char *cCharSetConv::Convert(const char *From, char *To, size_t ToLength) { if (cd != (iconv_t)-1 && From && *From) { char *FromPtr = (char *)From; size_t FromLength = strlen(From); char *ToPtr = To; if (!ToPtr) { length = max(length, FromLength * 2); // some reserve to avoid later reallocations result = (char *)realloc(result, length); ToPtr = result; ToLength = length; } else if (!ToLength) return From; // can't convert into a zero sized buffer ToLength--; // save space for terminating 0 char *Converted = ToPtr; while (FromLength > 0) { if (iconv(cd, &FromPtr, &FromLength, &ToPtr, &ToLength) == size_t(-1)) { if (errno == E2BIG || errno == EILSEQ && ToLength < 1) { if (To) break; // caller provided a fixed size buffer, but it was too small // The result buffer is too small, so increase it: size_t d = ToPtr - result; size_t r = length / 2; length += r; Converted = result = (char *)realloc(result, length); ToLength += r; ToPtr = result + d; } if (errno == EILSEQ) { // A character can't be converted, so mark it with '?' and proceed: FromPtr++; FromLength--; *ToPtr++ = '?'; ToLength--; } else if (errno != E2BIG) return From; // unknown error, return original string } } *ToPtr = 0; return Converted; } return From; } #endif mp3-0.10.2/compat.h0100644000000000000000000000272111145023340012417 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___COMPAT_H #define ___COMPAT_H #ifndef APIVERSNUM #include #endif #if APIVERSNUM < 10503 #include class cCharSetConv { private: iconv_t cd; char *result; size_t length; static char *systemCharacterTable; public: cCharSetConv(const char *FromCode = NULL, const char *ToCode = NULL); ~cCharSetConv(); const char *Convert(const char *From, char *To = NULL, size_t ToLength = 0); static const char *SystemCharacterTable(void) { return systemCharacterTable; } static void SetSystemCharacterTableX(const char *CharacterTable); }; #endif #endif //___COMPAT_H mp3-0.10.2/config.h0100644000000000000000000000426010735452037012416 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ // This files contains some option switches/values for compile time // configuration of the MP3/MPlayer plugin. You should only alter // this file, if you have understand the source code parts which deal // with the changed value. // After changing this file you should do a "make plugins-clean ; make plugins" // to recompile vdr. #ifndef ___CONFIG_H #define ___CONFIG_H // Uncomment to enable generic debugging messages to the console. This may slow // down operation in some cases. #define DEBUG //#define NO_DEBUG // Defines the filename extention to use for playlist files. #define PLAYLISTEXT ".m3u" // Defines the text to identify WinAmp-Style playlists. #define WINAMPEXT "#EXTM3U" // Defines the timeout in seconds for functions which use a single key // (e.g. openning the playlist window). If the key is repressed during // the timeout, the secondary function is activated. #define MULTI_TIMEOUT 3 // Defines the timeout in ms for entering the single digits in direct song // selection. #define SELECT_TIMEOUT 1000 // If the progress display is closed on direct song selection, the display // is opend temporarily. This defines the time in seconds after the display // is closed again. #define SELECTHIDE_TIMEOUT 3 // Defines the time in seconds to jump inside a song with left/right. #define JUMPSIZE 3 #endif //___CONFIG_H mp3-0.10.2/data-mp3-image.c0100644000000000000000000012533610735452037013642 0ustar rootrootunsigned char defaultImage[]={ 0x00,0x00,0x01,0xb3,0x2c,0x02,0x40,0x23,0x06,0x1a,0xa3,0x70,0x00,0x00,0x01,0xb5, 0x14,0x82,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0xb5,0x23,0x05,0x05,0x05,0x0b,0x02, 0x12,0x00,0x00,0x00,0x01,0xb8,0x00,0x08,0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x0f, 0xff,0xf8,0x00,0x00,0x01,0xb5,0x8f,0xff,0xf7,0xdd,0x80,0x00,0x00,0x01,0x01,0x33, 0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1a,0x96,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xa9,0x23,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xa3,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6a,0x28,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xa8,0x63,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0x00,0x00,0x01,0x02, 0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x03,0x0b,0xfc, 0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x04,0x0b,0xfc,0x3e,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x05,0x0b,0xfc,0x3e,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x06,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0x80,0x00,0x00,0x01,0x07,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80, 0x00,0x00,0x01,0x08,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00, 0x01,0x09,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x0a, 0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x0b,0x0b,0xfc, 0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x0c,0x0b,0xfc,0x3e,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x0d,0x0b,0xfc,0x3e,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x0e,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0x80,0x00,0x00,0x01,0x0f,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80, 0x00,0x00,0x01,0x10,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00, 0x01,0x11,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x12, 0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x13,0x0b,0xfc, 0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x14,0x0b,0xfc,0x3e,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x15,0x0b,0xfc,0x3e,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x16,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0x80,0x00,0x00,0x01,0x17,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80, 0x00,0x00,0x01,0x18,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00, 0x01,0x19,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x1a, 0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x1b,0x0b,0xfc, 0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x1c,0x0b,0xfc,0x3e,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x1d,0x0b,0xfc,0x3e,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x1e,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0x80,0x00,0x00,0x01,0x1f,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80, 0x00,0x00,0x01,0x20,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00, 0x01,0x21,0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x22, 0x0b,0xfc,0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x23,0x0b,0xfc, 0x3e,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b, 0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e, 0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8, 0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3, 0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d, 0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34, 0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0x24,0x0b,0xfc,0x3e,0xd1, 0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46, 0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a, 0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68, 0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3, 0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d, 0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34, 0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1, 0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46, 0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18, 0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61, 0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86, 0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61,0xb8,0xd1,0xa3,0x46,0x18, 0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86,0xe3,0x46,0x8d,0x18,0x61, 0xb8,0xd1,0xa3,0x46,0x18,0x6e,0x34,0x68,0xd1,0x86,0x1b,0x8d,0x1a,0x34,0x61,0x86, 0xe3,0x46,0x8d,0x18,0x61,0x80,0x00,0x00,0x01,0xb7}; mp3-0.10.2/data-mp3.c0100644000000000000000000002773611304362361012560 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include "common.h" #include "data-mp3.h" #include "data.h" #include "decoder.h" #define DEBUG_IMAGE #ifdef DEBUG_IMAGE #define di(x) { (x); } #else #define di(x) ; #endif const char *imagecache = "/var/cache/images/mp3"; const char *imageconv = "image_convert.sh"; const char *def_usr_img = 0; // image suffixes to search const char *img_suff[] = { "jpg","png","gif",0 }; // exclude list for instant playlist creation const char *excl_pl[] = { "*"PLAYLISTEXT,"*.jpg","*.gif","*.png",0 }; // exclude list for song browser const char *excl_br[] = { ".*","*.jpg","*.gif","*.png",0 }; // --- cImageConvert ----------------------------------------------------------- class cImageConvert : private cThread { private: char *image; enum eStatus { stNone, stRun, stFin }; eStatus status; protected: virtual void Action(void); public: cImageConvert(void); ~cImageConvert(); bool Convert(const char *Image); bool Status(void); }; cImageConvert::cImageConvert(void) { image=0; status=stNone; } cImageConvert::~cImageConvert() { if(status==stRun) Cancel(10); free(image); } bool cImageConvert::Convert(const char *Image) { if(status==stNone) { image=strdup(Image); status=stRun; Start(); return true; } return false; } bool cImageConvert::Status(void) { if(status==stRun && !Active()) status=stFin; return status==stFin; } void cImageConvert::Action(void) { if(nice(3)<0); char *qp, *qm; char *m=aprintf("%s%s.mpg",imagecache,image); di(printf("image: convert started %s -> %s\n",image,m)) char *cmd=aprintf("%s \"%s\" \"%s\"",imageconv,qp=Quote(image),qm=Quote(m)); int r=system(cmd); if(r!=0) di(printf("image: convert returned with code %d. Failed?\n",r)) free(cmd); free(qp); free(qm); free(m); di(printf("image: convert finished\n")) status=stFin; } // --- cSong ------------------------------------------------------------------- cSong::cSong(cFileObj *Obj) { obj=new cFileObj(Obj); Init(); } cSong::cSong(cFileSource *Source, const char *Subdir, const char *Name) { obj=new cFileObj(Source,Subdir,Name,otFile); Init(); } cSong::cSong(cSong *Song) { obj=new cFileObj(Song->obj); Init(); } cSong::~cSong() { delete conv; delete decoder; obj->Source()->Unblock(); delete obj; free((char *)image); } void cSong::Init(void) { decoder=0; user=0; image=0; conv=0; queueStat=0; fromDOS=decoderFailed=false; obj->Source()->Block(); } int cSong::Compare(const cListObject &ListObject) const { cSong *song=(cSong *)&ListObject; return strcasecmp(obj->Path(),song->obj->Path()); } cSongInfo *cSong::Info(bool get) { Decoder(); cSongInfo *si=0; if(decoder) si=decoder->SongInfo(get); return si; } cDecoder *cSong::Decoder(void) { decLock.Lock(); if(!decoder && !decoderFailed) { decoder=cDecoders::FindDecoder(obj); if(!decoder) decoderFailed=true; } decLock.Unlock(); return decoder; } void cSong::Convert(void) { char *Name=Convert2Unix(obj->Name()); obj->SetName(Name); fromDOS=true; free(Name); } char *cSong::Convert2Unix(const char *name) const { char *Name=strdup(name); char *p=Name; while(*p) { if(*p=='/') *p='?'; if(*p=='\\') *p='/'; p++; } return Name; } /* char *cSong::Convert2Dos(const char *name) { char *Name=strdup(name); char *p=Name; while(*p) { if(*p=='\\') *p='?'; if(*p=='/') *p='\\'; p++; } return Name; } */ bool cSong::Parse(char *s, const char *reldir) const { s=skipspace(stripspace(s)); if(*s) { if(s[0]=='/' || !reldir) obj->SplitAndSet(s); else { s=AddPath(reldir,s); obj->SplitAndSet(s); free(s); } return true; } return false; } bool cSong::Save(FILE *f, const char *reldir) const { const char *path=obj->Path(); if(reldir) { int l=strlen(reldir); if(!strncasecmp(path,reldir,l)) path+=l+1; } return fprintf(f,"%s\n",path)>0; } bool cSong::FindImage(void) { if(image) return true; char base[strlen(obj->Path())+32]; strcpy(base,obj->Path()); di(printf("image: checking image for %s\n",obj->Path())) // song specific image char *m=rindex(base,'.'); if(m) *m=0; if((image=CheckImage(base))) return true; // album specific image in song directory if(!(m=rindex(base,'/'))) m=base-1; strcpy(m+1,"cover"); if((image=CheckImage(base))) return true; // artist specific image in parent directory if((m=rindex(base,'/'))) { *m=0; if(!(m=rindex(base,'/'))) m=base-1; strcpy(m+1,"artist"); if((image=CheckImage(base))) return true; } // default image in source basedir if((image=CheckImage("background"))) return true; // default user supplied image if(def_usr_img && (image=strdup(def_usr_img))) return true; di(printf("image: no image for %s\n",obj->Path())) return false; } const char *cSong::CheckImage(const char *base) const { int n; char *p=aprintf("%s/%s.%n ",obj->Source()->BaseDir(),base,&n); for(const char **s=img_suff; *s; s++) { #ifdef DEBUG if(strlen(*s)>5) printf("ERROR: buffer overflow in CheckImage ext=%s\n",*s); #endif strcpy(&p[n],*s); di(printf("image: check %s\n",p)) if(!access(p,R_OK)) { di(printf("image: found\n")) return p; } } free(p); return 0; } #include "data-mp3-image.c" extern void PropagateImage(const char *image); bool cSong::Image(unsigned char * &mem, int &len) { mem=0; if(queueStat>0) { if(!conv->Status()) { di(printf("image: still queued\n")) return false; } queueStat=-1; delete conv; conv=0; } int res=0; if(image || FindImage()) { di(printf("image: loading image %s\n",image)) char *m=aprintf("%s%s.mpg",imagecache,image); if(access(m,R_OK)) { di(printf("image: not cached\n")) if(queueStat<0) { di(printf("image: obviously convert failed...\n")) } else { if(!conv) conv=new cImageConvert; if(conv && conv->Convert(image)) { di(printf("image: convert queued\n")) queueStat=1; res=-1; } else { di(printf("image: queueing failed\n")) queueStat=-1; } } } else { di(printf("image: cached\n")) int f=open(m,O_RDONLY); if(f>=0) { struct stat64 st; fstat64(f,&st); len=st.st_size; mem=MALLOC(unsigned char,len); if(mem) { if(read(f,mem,len)==len) res=1; else free(mem); } close(f); } } free(m); } PropagateImage(res==1 ? image : 0); if(res<=0) { di(printf("image: using static default image\n")) len=sizeof(defaultImage); mem=MALLOC(unsigned char,len); if(mem) { memcpy(mem,defaultImage,len); } } return res>=0; } // -- cPlayList -------------------------------------------------------------- cPlayList::cPlayList(cFileObj *Obj) { obj=new cFileObj(Obj); Init(); } cPlayList::cPlayList(cFileSource *Source, const char *Subdir, const char *Name) { obj=new cFileObj(Source,Subdir,Name,otFile); Init(); } cPlayList::cPlayList(cPlayList *List) { obj=new cFileObj(List->obj); Init(); } cPlayList::~cPlayList() { free(basename); free(extbuffer); obj->Source()->Unblock(); delete obj; } void cPlayList::Init(void) { extbuffer=basename=0; isWinAmp=false; obj->Source()->Block(); Set(); } void cPlayList::Set(void) { free(basename); basename=0; if(obj->Name()) { basename=strdup(obj->Name()); int l=strlen(basename)-strlen(PLAYLISTEXT); if(l>0 && !strcasecmp(basename+l,PLAYLISTEXT)) basename[l]=0; } } int cPlayList::Compare(const cListObject &ListObject) const { cPlayList *list=(cPlayList *)&ListObject; return strcasecmp(obj->Name(),list->obj->Name()); } bool cPlayList::Load(void) { Clear(); bool result=false; FILE *f=fopen(obj->FullPath(),"r"); if(f) { char buffer[512]; result=true; while(fgets(buffer,sizeof(buffer),f)>0) { if(buffer[0]=='#') { if(!strncmp(buffer,WINAMPEXT,strlen(WINAMPEXT))) { d(printf("mp3: detected WinAmp style playlist\n")) isWinAmp=true; } continue; } if(!isempty(buffer)) { cSong *song=new cSong(obj->Source(),0,0); if(song->Parse(buffer,obj->Subdir())) Add(song); else { esyslog("error loading playlist %s\n",obj->FullPath()); delete song; result=false; break; } } } fclose(f); } else LOG_ERROR_STR(obj->FullPath()); if(result && isWinAmp) { cSong *song=First(); while(song) { // if this is a WinAmp playlist, convert \ to / song->Convert(); song=cList::Next(song); } } return result; } bool cPlayList::Save(void) { bool result=true; cSafeFile f(obj->FullPath()); if(f.Open()) { cSong *song=First(); while(song) { if(!song->Save(f,obj->Subdir())) { result=false; break; } song=cList::Next(song); } if(!f.Close()) result=false; } else result=false; return result; } bool cPlayList::Exists(void) { return obj->Exists(); } bool cPlayList::TestName(const char *newName) { return obj->TestName(AddExt(newName,PLAYLISTEXT)); } bool cPlayList::Rename(const char *newName) { bool r=obj->Rename(AddExt(newName,PLAYLISTEXT)); if(r) Set(); return r; } bool cPlayList::Create(const char *newName) { bool r=obj->Create(AddExt(newName,PLAYLISTEXT)); if(r) { Set(); r=Load(); } return r; } bool cPlayList::Delete(void) { return obj->Delete(); } const char *cPlayList::AddExt(const char *FileName, const char *Ext) { free(extbuffer); extbuffer=aprintf("%s%s",FileName,Ext); return extbuffer; } // -- cInstantPlayList ------------------------------------------------------ cInstantPlayList::cInstantPlayList(cFileObj *Obj) :cPlayList(Obj) { if(!Obj->Name()) Obj->SetName("instant"); } bool cInstantPlayList::Load(void) { bool res=false; Clear(); switch(obj->Type()) { case otFile: d(printf("instant: file %s\n",obj->Name())) if(strcasecmp(obj->Name(),basename)) { d(printf("instant: detected as playlist\n")) res=cPlayList::Load(); } else { Add(new cSong(obj)); res=true; } break; case otDir: { d(printf("instant: dir %s\n",obj->Name())) res=ScanDir(obj->Source(),obj->Path(),stFile,obj->Source()->Include(),excl_pl,true); Sort(); break; } case otBase: d(printf("instant: base\n")) res=ScanDir(obj->Source(),0,stFile,obj->Source()->Include(),excl_pl,true); Sort(); break; default: break; } return res; } void cInstantPlayList::DoItem(cFileSource *src, const char *subdir, const char *name) { Add(new cSong(src,subdir,name)); } // -- cPlayLists -------------------------------------------------------------- bool cPlayLists::Load(cFileSource *Source) { static const char *spec[] = { "*"PLAYLISTEXT,0 }; Clear(); bool res=ScanDir(Source,0,stFile,spec,0,false); Sort(); return res; } void cPlayLists::DoItem(cFileSource *src, const char *subdir, const char *name) { Add(new cPlayList(src,subdir,name)); } mp3-0.10.2/data-mp3.h0100644000000000000000000000730611141713426012555 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DATA_MP3_H #define ___DATA_MP3_H #include #include #include "data.h" // ---------------------------------------------------------------- class cDecoder; class cSongInfo; class cImageConvert; extern const char *imagecache, *imageconv, *def_usr_img; extern const char *img_suff[], *excl_pl[], *excl_br[]; // ---------------------------------------------------------------- class cSong : public cListObject { public: int user; private: cFileObj *obj; bool fromDOS, decoderFailed; cDecoder *decoder; cMutex decLock; // const char *image; cImageConvert *conv; int queueStat; // void Init(void); char *Convert2Unix(const char *name) const; bool FindImage(void); const char *CheckImage(const char *base) const; public: cSong(cFileObj *Obj); cSong(cFileSource *Source, const char *Subdir, const char *Name); cSong(cSong *Song); ~cSong(); virtual int Compare(const cListObject &ListObject) const; bool Parse(char *s, const char *reldir) const; bool Save(FILE *f, const char *reldir) const; void Convert(void); cSongInfo *Info(bool get=true); cDecoder *Decoder(void); bool Image(unsigned char * &mem, int &len); inline const char *Name(void) const { return obj->Name(); } inline const char *FullPath(void) const { return obj->FullPath(); } }; // ---------------------------------------------------------------- class cPlayList : public cList, public cListObject { private: bool isWinAmp; char *extbuffer; // void Init(void); void Set(void); const char *AddExt(const char *Name, const char *Ext); protected: cFileObj *obj; char *basename; public: cPlayList(cFileObj *Obj); cPlayList(cFileSource *Source, const char *Subdir, const char *Name); cPlayList(cPlayList *List); ~cPlayList(); virtual bool Load(void); virtual bool Save(void); virtual int Compare(const cListObject &ListObject) const; // bool Rename(const char *newName); bool Delete(void); bool Create(const char *newName); bool Exists(void); bool TestName(const char *newName); // inline const char *Name(void) const { return obj->Name(); } inline const char *BaseName(void) const { return basename; } inline bool IsWinAmp(void) const { return isWinAmp; } }; // ---------------------------------------------------------------- class cInstantPlayList : public cScanDir, public cPlayList { protected: virtual void DoItem(cFileSource *src, const char *subdir, const char *name); public: cInstantPlayList(cFileObj *Obj); virtual bool Load(void); virtual bool Save(void) { return false; } }; // ---------------------------------------------------------------- class cPlayLists : public cScanDir, public cList { protected: virtual void DoItem(cFileSource *src, const char *subdir, const char *name); public: bool Load(cFileSource *Source); }; #endif //___DATA_MP3_H mp3-0.10.2/data-src.h0100644000000000000000000000253710735452037012654 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DATA_SRC_H #define ___DATA_SRC_H #include #include "data.h" // ---------------------------------------------------------------- class cFileSources : public cConfig { private: cFileSource *current; public: virtual bool Load(const char *filename, bool dummy=false); void SetSource(cFileSource *source) { current=source; } cFileSource *GetSource(void) { return current; } cFileSource *FindSource(const char *filename); }; #endif //___DATA_SRC_H mp3-0.10.2/data.c0100644000000000000000000003370611304457026012060 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "data.h" #include "data-src.h" // ---------------------------------------------------------------- const char *mountscript = "mount.sh"; char *Quote(const char *str) { char *nstr=MALLOC(char,strlen(str)*2); char *p=nstr; while(*str) { switch(*str) { case '$': // dollar case '\\': // backslash case '\"': // double quote case '`': // back tick *p++='\\'; break; } *p++=*str++; } *p=0; return nstr; } char *AddPath(const char *dir, const char *filename) { char *name=aprintf("%s/%s",dir,filename); return name; } bool CheckVDRVersion(int Version, int Major, int Minor, const char *text) { static char vv[] = VDRVERSION; int version, major, minor; if(sscanf(vv,"%d.%d.%d",&version,&major,&minor)==3) { if(versionBaseDir(),subdir); DIR *d=opendir(dir); if(d) { struct dirent64 *e; while((e=readdir64(d))) { if(!strcmp(e->d_name,".") || !strcmp(e->d_name,"..")) continue; free(f); if(!(f=AddPath(dir,e->d_name))) continue; struct stat64 st; if(stat64(f,&st)<0) { esyslog("ERROR: stat(1) %s: %s",f,strerror(errno)); continue; } if(S_ISLNK(st.st_mode)) { char *of=f; f=ReadLink(of); free(of); if(!f) continue; if(stat64(f,&st)<0) { esyslog("ERROR: stat(2) %s: %s",f,strerror(errno)); continue; } } if(S_ISDIR(st.st_mode)) { if(type==stFile && recursiv) { char *s=aprintf(subdir ? "%2$s/%1$s":"%s",e->d_name,subdir); ScanDir(src,s,type,spec,excl,recursiv); free(s); continue; } if(type!=stDir) continue; } if(S_ISREG(st.st_mode)) { if(type!=stFile) continue; if(spec) { bool ok=false; for(const char * const *m=spec; *m; m++) { int n=fnmatch(*m,e->d_name,FNM_CASEFOLD); if(n==0) { ok=true; break; } if(n!=FNM_NOMATCH) esyslog("ERROR: fnmatch(1) %s: %s",*m,strerror(errno)); } if(!ok) continue; } if(excl) { bool ok=true; for(const char * const *m=excl; *m; m++) { int n=fnmatch(*m,e->d_name,FNM_CASEFOLD); if(n==0) { ok=false; break; } if(n!=FNM_NOMATCH) esyslog("ERROR: fnmatch(2) %s: %s",*m,strerror(errno)); } if(!ok) continue; } } DoItem(src,subdir,e->d_name); } closedir(d); } else { esyslog("ERROR: opendir %s: %s",dir,strerror(errno)); res=false; } free(dir); free(f); return res; } // -- cFileObj -------------------------------------------------------------- cFileObj::cFileObj(cFileSource *Source, const char *Subdir, const char *Name, const eObjType Type) { path=fpath=0; source=Source; subdir=Subdir ? strdup(Subdir):0; name=Name ? strdup(Name):0; type=Type; Set(); } cFileObj::cFileObj(const cFileObj *obj) { path=fpath=0; source=obj->source; subdir=obj->subdir ? strdup(obj->subdir):0; name=obj->name ? strdup(obj->name):0; type=obj->type; Set(); } cFileObj::~cFileObj() { free(name); free(subdir); free(path); free(fpath); } int cFileObj::Compare(const cListObject &ListObject) const { cFileObj *obj=(cFileObj *)&ListObject; if(type==otParent) return obj->type==otParent ? 0:-1; if(obj->type==otParent) return 1; if(type==otBase) return obj->type==otBase ? 0:1; if(obj->type==otBase) return -1; if(type!=obj->type) { if(type==otFile) return 1; return -1; } return strcasecmp(path,obj->path); } void cFileObj::SplitAndSet(const char *Path) { free(subdir); subdir=0; const char *p=Path; if(Path[0]=='/') { int l=strlen(source->BaseDir()); if(!strncasecmp(Path,source->BaseDir(),l)) p+=l+1; else { l=strlen(source->RealBaseDir()); if(!strncasecmp(Path,source->RealBaseDir(),l)) p+=l+1; else { char buff[strlen(Path)+5]; strcpy(buff,"/"); p++; while(1) { char real[PATH_MAX+1]; if(!realpath(buff,real)) { if(errno!=ENOENT && errno!=ENOTDIR) esyslog("ERROR: realpath: %s: %s",buff,strerror(errno)); p=Path+1; break; } if(!strncasecmp(real,source->RealBaseDir(),l)) break; const char *r=index(p,'/'); if(!r) { esyslog("ERROR: can't find source basedir in '%s'. Outside source?",Path); p=Path+1; break; } strn0cpy(buff,Path,r-Path+1); p=r+1; } } } } const char *s=rindex(p,'/'); if(s) { const int l=s-p+1; subdir=MALLOC(char,l); if(subdir) strn0cpy(subdir,p,l); SetName(s+1); } else SetName(p); } void cFileObj::SetName(const char *Name) { free(name); name=Name ? strdup(Name):0; Set(); } void cFileObj::Set(void) { free(path); path=aprintf(subdir ? "%2$s/%1$s":"%s",name,subdir); free(fpath); fpath=0; MakeFullName(&fpath,name); } void cFileObj::MakeFullName(char **fp, const char *Name) { *fp=aprintf(subdir ? "%1$s/%3$s/%2$s":"%s/%s",source->BaseDir(),Name,subdir); } bool cFileObj::GuessType(void) { struct stat64 ds; if(!stat64(fpath,&ds)) { if(S_ISREG(ds.st_mode)) type=otFile; else if(S_ISDIR(ds.st_mode)) type=subdir ? otDir:otBase; else return false; return true; } return false; } bool cFileObj::Exists(void) { if(type==otFile) { struct stat64 ds; if(!stat64(fpath,&ds) && S_ISREG(ds.st_mode) && !access(fpath,R_OK)) return true; } return false; } bool cFileObj::TestName(const char *newName) { bool r=false; if(type==otFile) { char *fname; MakeFullName(&fname,newName); if(access(fname,F_OK)==0) r=true; free(fname); } return r; } bool cFileObj::Rename(const char *newName) { bool r=false; if(type==otFile) { char *fname; MakeFullName(&fname,newName); if(access(fname,F_OK) && (!rename(fpath,fname))) { SetName(newName); r=true; } free(fname); } return r; } bool cFileObj::Create(const char *newName) { bool r=false; if(type==otFile) { char *fname; MakeFullName(&fname,newName); FILE *newf; if(access(fname,F_OK) && (newf=fopen(fname,"w"))) { fclose(newf); SetName(newName); r=true; } free(fname); } return r; } bool cFileObj::Delete(void) { if(type==otFile && !unlink(fpath)) return true; return false; } // -- cDirList -------------------------------------------------------------- bool cDirList::Load(cFileSource *src, const char *subdir, const char * const *excl) { static const char *excl_s[] = { ".*",0 }; bool res=false; Clear(); if(subdir) Add(new cFileObj(src,subdir,"..",otParent)); otype=otDir; if(ScanDir(src,subdir,stDir,0,0,false)) { otype=otFile; if(!excl) excl=excl_s; if(ScanDir(src,subdir,stFile,src->Include(),excl,false)) res=true; } Sort(); return res; } void cDirList::DoItem(cFileSource *src, const char *subdir, const char *name) { Add(new cFileObj(src,subdir,name,otype)); } // -- cFileSource -------------------------------------------------------------- cFileSource::cFileSource(void) { browsedir=browseparent=0; basedir=realbasedir=description=0; useCount=0; needsmount=false; include=0; incCount=0; } cFileSource::cFileSource(const char *Basedir, const char *Description, const bool NeedsMount, const char *Include) { browsedir=browseparent=0; basedir=realbasedir=description=0; useCount=0; include=0; incCount=0; Set(Basedir,Description,NeedsMount,Include); } cFileSource::~cFileSource() { ClearRemember(); Clear(); } void cFileSource::Clear(void) { free(basedir); basedir=0; free(realbasedir); realbasedir=0; free(description); description=0; for(int i=0; i0); } #ifdef DEBUG if(include) { printf("sources: filesource %s includes (count=%d):",basedir,incCount); for(int i=0; i=3) { char *base2=skipspace(stripspace(base)); int l=strlen(base2); while(l>0 && base2[l-1]=='/') { esyslog("WARNING: removing trailing '/' from base %s",base2); base2[l-1]=0; l--; } Set(base2,skipspace(stripspace(des)),needsmount!=0,n>3?skipspace(stripspace(incl)):0); // do some checking of the basedir and issue a warning if apropriate if(access(realbasedir,R_OK)) { esyslog("WARNING: source base %s not found/permission denied",realbasedir); } else { struct stat64 ds; if(lstat64(realbasedir,&ds)) { esyslog("WARNING: can't stat source base %s",realbasedir); } else if(!S_ISDIR(ds.st_mode)) { esyslog("WARNING: source base %s is not a directory",realbasedir); } } return true; } return false; } bool cFileSource::Action(eAction act) { static const char *str[] = { "mount","unmount","eject","status" }; char *cmd=aprintf("%s %s %s",mountscript,str[act],basedir); bool res=(system(cmd)==0); free(cmd); return res; } bool cFileSource::Mount(void) { bool res=false; if(needsmount && (res=Action(acMount))) ClearRemember(); return res; } bool cFileSource::Unmount(void) { bool res=false; if(needsmount) { if(!useCount && (res=Action(acUnmount))) ClearRemember(); } return res; } bool cFileSource::Eject(void) { bool res=false; if(needsmount) { if(!useCount && (res=Action(acEject))) ClearRemember(); } return res; } bool cFileSource::Status(void) { if(needsmount) return Action(acStatus); return true; } // -- cFileSources -------------------------------------------------------------- bool cFileSources::Load(const char *filename, bool dummy) { if(cConfig::Load(filename,true)) { SetSource(First()); return true; } return false; } cFileSource *cFileSources::FindSource(const char *filename) { cFileSource *src=First(); while(src) { if(startswith(filename,src->RealBaseDir())) return src; src=Next(src); } return 0; } mp3-0.10.2/data.h0100644000000000000000000001062111242237270012052 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DATA_H #define ___DATA_H #include // ---------------------------------------------------------------- class cFileSource; extern char *Quote(const char *str); extern char *AddPath(const char *dir, const char *filename); extern bool CheckVDRVersion(int Version, int Major, int Minor, const char *text=0); extern char *aprintf(const char *fmt, ...) __attribute__ ((format (printf,1,2))); // ---------------------------------------------------------------- class cScanDir { protected: enum eScanType { stFile, stDir }; virtual void DoItem(cFileSource *src, const char *subdir, const char *name)=0; public: virtual ~cScanDir() {} bool ScanDir(cFileSource *src, const char *subdir, eScanType type, const char * const *spec, const char * const *excl, bool recursiv); }; // ---------------------------------------------------------------- enum eObjType { otDir, otParent, otFile, otBase }; class cFileObj : public cListObject { private: cFileSource *source; char *subdir, *name, *path, *fpath; eObjType type; // void Set(void); void MakeFullName(char **fp, const char *Name); public: cFileObj(cFileSource *Source, const char *Subdir, const char *Name, const eObjType Type); cFileObj(const cFileObj *obj); virtual ~cFileObj(); virtual int Compare(const cListObject &ListObject) const; void SetName(const char *Name); void SplitAndSet(const char *Path); bool GuessType(void); // bool Exists(void); bool TestName(const char *newName); bool Rename(const char *newName); bool Create(const char *newName); bool Delete(void); // inline const char *Name(void) const { return name; } inline const char *Subdir(void) const { return subdir; } inline cFileSource *Source(void) const { return source; } inline eObjType Type(void) const { return type; } inline const char *Path(void) const { return path; } inline const char *FullPath(void) const { return fpath; } }; // ---------------------------------------------------------------- class cDirList : public cScanDir, public cList { private: eObjType otype; protected: virtual void DoItem(cFileSource *src, const char *subdir, const char *name); public: bool Load(cFileSource *src, const char *subdir, const char * const *excl=0); }; // ---------------------------------------------------------------- class cFileSource : public cListObject { private: enum eAction { acMount, acUnmount, acEject, acStatus }; char *basedir, *realbasedir; char *description; char **include; bool needsmount; int useCount, incCount; // remember last browse position char *browsedir, *browseparent; // void Set(const char *Basedir, const char *Description, const bool NeedsMount, const char *Include); bool Action(eAction act); void ClearRemember(void); void Clear(void); public: cFileSource(void); cFileSource(const char *Basedir, const char *Description, const bool NeedsMount, const char *Include=0); ~cFileSource(); bool Parse(char *s); bool Mount(void); bool Unmount(void); bool Eject(void); bool Status(void); void Block(void) { useCount++; } void Unblock(void) { useCount--; } void SetRemember(const char *dir, const char *parent); bool GetRemember(char * &dir, char * &parent); inline const char *BaseDir(void) const { return basedir; } inline const char *RealBaseDir(void) const { return realbasedir; } inline const char *Description(void) const { return description; } inline const char * const * Include(void) const { return include; } inline bool NeedsMount(void) const { return needsmount; } }; #endif //___DATA_H mp3-0.10.2/decoder-core.h0100644000000000000000000000357411144671103013503 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DECODER_CORE_H #define ___DECODER_CORE_H #include "decoder.h" #define DEC_ID(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) // ---------------------------------------------------------------- enum eDecodeStatus { dsOK=0, dsPlay, dsSkip, dsEof, dsError, dsSoftError }; struct Decode { eDecodeStatus status; int index; struct mad_pcm *pcm; }; // ---------------------------------------------------------------- #define CACHE_VERSION 8 class cCacheData : public cSongInfo, public cFileInfo, public cListObject { friend class cInfoCache; private: int hash, version; time_t touch; cMutex lock; // bool Check8bit(const char *str); protected: bool Save(FILE *f); bool Load(FILE *f); bool Upgrade(void); void Touch(void); bool Purge(void); void Create(cFileInfo *fi, cSongInfo *si, bool update); public: cCacheData(void); void Lock(void) { lock.Lock(); } void Unlock(void) { lock.Unlock(); } }; // ---------------------------------------------------------------- #endif //___DECODER_CORE_H mp3-0.10.2/decoder-mp3-stream.c0100644000000000000000000000560110735452037014537 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include "common.h" #include "decoder-mp3-stream.h" #include "stream.h" // --- cNetScanID3 ------------------------------------------------------------- class cNetScanID3 : public cScanID3 { private: cNetStream *nstr; // void IcyInfo(void); public: cNetScanID3(cNetStream *Str, bool *Urgent); virtual bool DoScan(bool KeepOpen=false); virtual void InfoHook(struct mad_header *header); }; cNetScanID3::cNetScanID3(cNetStream *Str, bool *Urgent) :cScanID3(Str,Urgent) { nstr=Str; } bool cNetScanID3::DoScan(bool KeepOpen) { Clear(); IcyInfo(); if(!Title) FakeTitle(nstr->Filename); Total=0; ChMode=3; DecoderID=DEC_MP3S; InfoDone(); return true; } void cNetScanID3::InfoHook(struct mad_header *header) { if(nstr->IcyChanged()) IcyInfo(); SampleFreq=header->samplerate; Channels=MAD_NCHANNELS(header); ChMode=header->mode; int br=header->bitrate; if(Bitrate<0) Bitrate=br; else if(Bitrate!=br) { if(MaxBitrate<0) { if(BitrateMaxBitrate) MaxBitrate=br; if(brIcyTitle(); const char *a; if(t) { a=nstr->IcyName(); if(!a) a=nstr->IcyUrl(); } else { t=nstr->IcyName(); a=nstr->IcyUrl(); } if(t && (!Title || strcmp(t,Title))) { free(Title); Title=strdup(t); } if(a && (!Album || strcmp(a,Album))) { free(Album); Album=strdup(a); } } // --- cMP3StreamDecoder ------------------------------------------------------- cMP3StreamDecoder::cMP3StreamDecoder(const char *Filename) :cMP3Decoder(Filename,false) { nstr=new cNetStream(filename); str=nstr; nscan=new cNetScanID3(nstr,&urgentLock); scan=nscan; isStream=true; } bool cMP3StreamDecoder::Valid(void) { bool res=false; if(TryLock()) { if(nstr->Valid()) res=true; Unlock(); } return res; } mp3-0.10.2/decoder-mp3-stream.h0100644000000000000000000000260510735452037014545 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DECODER_MP3_STREAM_H #define ___DECODER_MP3_STREAM_H #define DEC_MP3S DEC_ID('M','P','3','S') #define DEC_MP3S_STR "MP3S" #include "decoder-mp3.h" class cNetStream; class cNetScanID3; // ---------------------------------------------------------------- class cMP3StreamDecoder : public cMP3Decoder { private: cNetStream *nstr; cNetScanID3 *nscan; public: cMP3StreamDecoder(const char *Filename); virtual bool Valid(void); virtual bool IsStream(void) { return true; } }; #endif //___DECODER_MP3_STREAM_H mp3-0.10.2/decoder-mp3.c0100644000000000000000000004350711144671122013246 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include "common.h" #include "data-mp3.h" #include "decoder-mp3.h" #include "stream.h" #define MAX_FRAME_ERR 10 // ---------------------------------------------------------------- int MadStream(struct mad_stream *stream, cStream *str) { unsigned char *data; unsigned long len; if(str->Stream(data,len,stream->next_frame)) { if(len>0) mad_stream_buffer(stream, data, len); return len; } return -1; } // --- cMP3Decoder ------------------------------------------------------------- cMP3Decoder::cMP3Decoder(const char *Filename, bool preinit) :cDecoder(Filename) { str=0; scan=0; isStream=false; if(preinit) { //d(printf("mp3: preinit\n")) str=new cStream(filename); scan=new cScanID3(str,&urgentLock); } fi=0; stream=0; frame=0; synth=0; } cMP3Decoder::~cMP3Decoder() { Clean(); delete scan; delete str; } bool cMP3Decoder::Valid(void) { bool res=false; if(TryLock()) { struct mad_stream stream; struct mad_header header; mad_stream_init(&stream); mad_stream_options(&stream,MAD_OPTION_IGNORECRC); mad_header_init(&header); if(str->Open() && str->Seek()) { int count=10; do { if(mad_header_decode(&header,&stream)<0) { if(stream.error==MAD_ERROR_BUFLEN || stream.error==MAD_ERROR_BUFPTR) { if(MadStream(&stream,str)<=0) break; } else if(!MAD_RECOVERABLE(stream.error)) break; count++; } } while(--count); if(!count) res=true; } mad_header_finish(&header); mad_stream_finish(&stream); str->Close(); Unlock(); } return res; } cFileInfo *cMP3Decoder::FileInfo(void) { cFileInfo *fi=0; if(str->HasInfo()) fi=str; else if(TryLock()){ if(str->Open()) { fi=str; str->Close(); } Unlock(); } return fi; } cSongInfo *cMP3Decoder::SongInfo(bool get) { cSongInfo *si=0; if(scan->HasInfo()) si=scan; else if(get && TryLock()) { if(scan->DoScan()) si=scan; Unlock(); } return si; } cPlayInfo *cMP3Decoder::PlayInfo(void) { if(playing) { pi.Index=mad_timer_count(playtime,MAD_UNITS_SECONDS); pi.Total=scan->Total; return π } return 0; } void cMP3Decoder::Init(void) { Clean(); stream=new struct mad_stream; mad_stream_init(stream); mad_stream_options(stream,MAD_OPTION_IGNORECRC); frame=new struct mad_frame; mad_frame_init(frame); synth=new struct mad_synth; mad_synth_init(synth); playtime=mad_timer_zero; skiptime=mad_timer_zero; framenum=framemax=0; mute=errcount=0; } void cMP3Decoder::Clean(void) { playing=false; if(synth) { mad_synth_finish(synth); delete synth; synth=0; } if(frame) { mad_frame_finish(frame); delete frame; frame=0; } if(stream) { mad_stream_finish(stream); delete stream; stream=0; } delete[] fi; fi=0; } bool cMP3Decoder::Start(void) { Lock(true); Init(); playing=true; if(str->Open() && scan->DoScan(true)) { if(!isStream) { str->Seek(); framemax=scan->Frames+20; fi=new struct FrameInfo[framemax]; if(!fi) esyslog("ERROR: no memory for frame index, rewinding disabled"); } Unlock(); return true; } str->Close(); Clean(); Unlock(); return false; } bool cMP3Decoder::Stop(void) { Lock(); if(playing) { str->Close(); Clean(); } Unlock(); return true; } struct Decode *cMP3Decoder::Done(eDecodeStatus status) { ds.status=status; ds.index=mad_timer_count(playtime,MAD_UNITS_MILLISECONDS); ds.pcm=&synth->pcm; Unlock(); // release the lock from Decode() return &ds; } eDecodeStatus cMP3Decoder::DecodeError(bool hdr) { if(stream->error==MAD_ERROR_BUFLEN || stream->error==MAD_ERROR_BUFPTR) { int s=MadStream(stream,str); if(s<0) return dsError; if(s==0) return dsEof; } else if(!MAD_RECOVERABLE(stream->error)) { d(printf("mad: decode %sfailed, frame=%d: %s\n",hdr?"hdr ":"",framenum,mad_stream_errorstr(stream))) return dsError; } else { if(stream->error==MAD_ERROR_LOSTSYNC) { // check for ID3 tags #ifdef DEBUG char buf[10]; int buf2[3]; memcpy(buf,stream->this_frame,8); buf[8]=0; memcpy(buf2,stream->this_frame,8); printf("mad: lost sync %08x %08x %s\n",buf2[0],buf2[1],buf); #endif id3_length_t count=stream->bufend-stream->this_frame; id3_length_t tagsize=id3_tag_query(stream->this_frame,count); if(tagsize>0) { d(printf("mad: skipping over ID3 tag\n")) if(count>tagsize) count=tagsize; mad_stream_skip(stream,count); while(countStream(sdata,slen)) return dsError; if(slen<=0) return dsEof; unsigned long len=min(tagsize-count,slen); count+=len; sdata+=len; slen-=len; if(slen>0) mad_stream_buffer(stream,sdata,slen); } return dsOK; } } errcount+=hdr?1:100; d(printf("mad: decode %serror, frame=%d count=%d: %s\n",hdr?"hdr ":"",framenum,errcount,mad_stream_errorstr(stream))) } return dsOK; } struct Decode *cMP3Decoder::Decode(void) { Lock(); // this is released in Done() eDecodeStatus r; while(playing) { if(errcount>=MAX_FRAME_ERR*100) { esyslog("ERROR: excessive decoding errors, aborting file %s",filename); return Done(dsError); } if(mad_header_decode(&frame->header,stream)<0) { if((r=DecodeError(true))) return Done(r); } else { if(!isStream) { #ifdef DEBUG if(framenum>=framemax) printf("mp3: framenum >= framemax!!!!\n"); #endif if(fi && framenumBufferPos() + (stream->this_frame-stream->buffer); fi[framenum].Time=playtime; } } mad_timer_add(&playtime,frame->header.duration); framenum++; if(mad_timer_compare(playtime,skiptime)>=0) skiptime=mad_timer_zero; else return Done(dsSkip); // skipping, decode next header if(mad_frame_decode(frame,stream)<0) { if((r=DecodeError(false))) return Done(r); } else { errcount=0; scan->InfoHook(&frame->header); mad_synth_frame(synth,frame); if(mute) { mute--; return Done(dsSkip); } return Done(dsPlay); } } } return Done(dsError); } void cMP3Decoder::MakeSkipTime(mad_timer_t *skiptime, mad_timer_t playtime, int secs, float bsecs) { mad_timer_t time; *skiptime=playtime; mad_timer_set(&time,abs(secs),0,0); if(secs<0) mad_timer_negate(&time); mad_timer_add(skiptime,time); int full=(int)bsecs; bsecs-=(float)full; mad_timer_set(&time,full,(int)(bsecs*1000.0),1000); mad_timer_negate(&time); mad_timer_add(skiptime,time); d(printf("mp3: skip: playtime=%ld secs=%d full=%d bsecs=%f skiptime=%ld\n", mad_timer_count(playtime,MAD_UNITS_MILLISECONDS),secs,full,bsecs,mad_timer_count(*skiptime,MAD_UNITS_MILLISECONDS))) } bool cMP3Decoder::Skip(int Seconds, float bsecs) { Lock(); bool res=false; if(playing && !isStream) { if(!mad_timer_compare(skiptime,mad_timer_zero)) { // allow only one skip at any time mad_timer_t time; MakeSkipTime(&time,playtime,Seconds,bsecs); if(mad_timer_compare(playtime,time)<=0) { // forward skip #ifdef DEBUG int i=mad_timer_count(time,MAD_UNITS_SECONDS); printf("mp3: forward skipping to %02d:%02d\n",i/60,i%60); #endif skiptime=time; mute=1; res=true; } else { // backward skip if(fi) { #ifdef DEBUG int i=mad_timer_count(time,MAD_UNITS_SECONDS); printf("mp3: rewinding to %02d:%02d\n",i/60,i%60); #endif while(framenum && mad_timer_compare(time,fi[--framenum].Time)<0) ; mute=2; if(framenum>=2) framenum-=2; playtime=fi[framenum].Time; str->Seek(fi[framenum].Pos); mad_stream_finish(stream); // reset stream buffer mad_stream_init(stream); #ifdef DEBUG i=mad_timer_count(playtime,MAD_UNITS_MILLISECONDS); printf("mp3: new playtime=%d framenum=%d filepos=%lld\n",i,framenum,fi[framenum].Pos); #endif res=true; } } } } Unlock(); return res; } // --- cScanID3 ---------------------------------------------------------------- // This function was adapted from mad_timer, from the // libmad distribution #define MIN_SCAN_FRAMES 200 // min. number of frames to scan cScanID3::cScanID3(cStream *Str, bool *Urgent) { str=Str; urgent=Urgent; } bool cScanID3::Abort(bool result) { if(!keepOpen) str->Close(); return result; } bool cScanID3::DoScan(bool KeepOpen) { mad_timer_t duration=mad_timer_zero; unsigned int bitrate=0, minrate=~0, maxrate=0; int xframes=0; unsigned int id3_vers=0; bool is_vbr=false, has_id3=false; keepOpen=KeepOpen; if(!str->Open()) return Abort(false); if(HasInfo()) return Abort(true); // check the infocache cCacheData *dat=InfoCache.Search(str); if(dat) { Set(dat); dat->Unlock(); ConvertToSys(); if(!DecoderID) { DecoderID=DEC_MP3; InfoCache.Cache(this,str); } return Abort(true); } Clear(); // do a initial check for a ID3v1 tag at the end of the file // to speed up the following scan if(str->Filesize>=128 && str->Seek(str->Filesize-128)) { unsigned char *data; unsigned long len; if(str->Stream(data,len)) { struct id3_tag *tag=id3_tag_parse(data,len); if(tag) { d(printf("id3-scan: initialy found ID3 V1 tag at EOF\n")) ParseID3(tag); has_id3=true; id3_vers=tag->version; id3_tag_delete(tag); } } } if(!str->Seek()) return Abort(false); // There are three ways of calculating the length of an mp3: // 1) Constant bitrate: One frame can provide the information // needed: # of frames and duration. Just see how long it // is and do the division. // 2) Variable bitrate: Xing tag. It provides the number of // frames. Each frame has the same number of samples, so // just use that. // 3) All: Count up the frames and duration of each frames // by decoding each one. We do this if we've no other // choice, i.e. if it's a VBR file with no Xing tag. struct mad_stream stream; struct mad_header header; mad_stream_init(&stream); mad_stream_options(&stream,MAD_OPTION_IGNORECRC); mad_header_init(&header); bool res=true; int errcount=0; while(1) { if(*urgent) { d(printf("id3-scan: urgent request, aborting!\n")) res=false; break; // abort scan if there is an urgent request for the decoder lock } if(mad_header_decode(&header,&stream)<0) { if(stream.error==MAD_ERROR_BUFLEN || stream.error==MAD_ERROR_BUFPTR) { int s=MadStream(&stream,str); if(s>0) continue; if(s<0) res=false; break; } else if(stream.error==MAD_ERROR_LOSTSYNC) { // check for ID3 tags #ifdef DEBUG char buf[10]; int buf2[3]; memcpy(buf,stream.this_frame,8); buf[8]=0; memcpy(buf2,stream.this_frame,8); printf("id3-scan: lost sync %08x %08x %s\n",buf2[0],buf2[1],buf); #endif id3_length_t tagsize=id3_tag_query(stream.this_frame,stream.bufend-stream.this_frame); if(tagsize>0) { struct id3_tag *tag=GetID3(&stream,tagsize); if(tag) { unsigned int vers=id3_tag_version(tag); d(printf("id3-scan: found ID3 %s tag (%d.%d)\n",vers==0x100?"V1":"V2",ID3_TAG_VERSION_MAJOR(vers),ID3_TAG_VERSION_MINOR(vers))) if(!has_id3 || vers>id3_vers) { ParseID3(tag); has_id3=true; id3_vers=vers; } id3_tag_delete(tag); } } continue; } else { d(printf("id3-scan: decode header error (frame %d): %s\n",Frames,mad_stream_errorstr(&stream))) errcount++; if(errcountmaxrate) maxrate=header.bitrate; if(header.bitrate=0) { is_vbr=true; } } // Test the first n frames to see if this is a VBR file if(!is_vbr && FramesFilesize * 8.0) / (header.bitrate); // time in seconds long nsamples = 32 * MAD_NSBSAMPLES(&header); // samples per frame Frames = (long)(time * header.samplerate / nsamples); Total = (long)time; Bitrate= (int)bitrate; } else if(xframes>0) { d(printf("mad: vbr, but has Xing frame\n")) mad_timer_multiply(&header.duration, xframes); Frames = xframes; Total = mad_timer_count(header.duration,MAD_UNITS_SECONDS); } else { // the durations have been added up, and the number of frames counted. We do nothing here. d(printf("mad: vbr detected\n")) Total = mad_timer_count(duration,MAD_UNITS_SECONDS); Bitrate = (int)minrate; MaxBitrate = (int)maxrate; } if(!has_id3 || !Title) FakeTitle(str->Filename,".mp3"); InfoCache.Cache(this,str); ConvertToSys(); } } return Abort(res); } // This function was adapted from player.c, from the // libmad distribution struct id3_tag *cScanID3::GetID3(struct mad_stream *stream, id3_length_t tagsize) const { struct id3_tag *tag=0; const id3_byte_t *data; id3_byte_t *allocated=0; id3_length_t count=stream->bufend-stream->this_frame; if(count>=tagsize) { data=stream->this_frame; mad_stream_skip(stream,tagsize); } else { if(!(allocated=(id3_byte_t *)malloc(tagsize))) { esyslog("ERROR: not enough memory for id3 tag buffer"); return 0; } memcpy(allocated,stream->this_frame,count); mad_stream_skip(stream,count); while(countStream(sdata,slen) || !slen) { d(printf("mad: error or eof on ID3 tag parse\n")) free(allocated); return 0; } len=tagsize-count; if(len>slen) len=slen; memcpy(allocated+count,sdata,len); count+=len; sdata+=len; slen-=len; if(slen) mad_stream_buffer(stream,sdata,slen); } data=allocated; } tag=id3_tag_parse(data,tagsize); if(allocated) free(allocated); return tag; } void cScanID3::ParseID3(const struct id3_tag *tag) { d(printf("id3-scan: parsing ID3 tag\n")) ParseStr(tag,ID3_FRAME_TITLE,Title); ParseStr(tag,ID3_FRAME_ARTIST,Artist); ParseStr(tag,ID3_FRAME_ALBUM,Album); char *data=0; ParseStr(tag,ID3_FRAME_YEAR,data); if(data) Year=atol(data); free(data); //ParseStr(tag,ID3_FRAME_TRACK,Track); //ParseStr(tag,ID3_FRAME_GENRE,Genre); } /* void cScanID3::ParsePic(const struct id3_tag *tag, const char *id, char * &name) { const struct id3_frame *frame=id3_tag_findframe(tag,id,0); if(frame) { id3_length_t len; const id3_byte_t *data=id3_field_getbinarydata(&frame->fields[1],&len); if(data && len>0) { static const char salt[] = { "$1$id3__pic$" }; } } } */ // This function was adapted from player.c, from the // libmad distribution void cScanID3::ParseStr(const struct id3_tag *tag, const char *id, char * &data) { const struct id3_frame *frame=id3_tag_findframe(tag,id,0); if(!frame) return; free(data); data=0; const union id3_field *field=&frame->fields[1]; if(id3_field_getnstrings(field)>0) { const id3_ucs4_t *ucs4=id3_field_getstrings(field,0); if(!ucs4) return; if(!strcmp(id,ID3_FRAME_GENRE)) ucs4=id3_genre_name(ucs4); data=(char *)id3_ucs4_utf8duplicate(ucs4); } } // XING parsing was adapted from the MAD winamp input plugin, // from the libmad distribution #define XING_MAGIC (('X'<<24) | ('i'<<16) | ('n'<<8) | 'g') #define XING_FRAMES 0x0001 // #define XING_BYTES 0x0002 // #define XING_TOC 0x0004 // #define XING_SCALE 0x0008 int cScanID3::ParseXing(struct mad_bitptr *ptr, unsigned int bitlen) const { if(bitlen>=64 && mad_bit_read(ptr,32)==XING_MAGIC) { int flags=mad_bit_read(ptr, 32); bitlen-=64; return (bitlen>=32 && (flags & XING_FRAMES)) ? mad_bit_read(ptr,32) : 0; } return -1; } mp3-0.10.2/decoder-mp3.h0100644000000000000000000000564110735452037013257 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DECODER_MP3_H #define ___DECODER_MP3_H #define DEC_MP3 DEC_ID('M','P','3',' ') #define DEC_MP3_STR "MP3" #include #include #include "decoder.h" #include "decoder-core.h" #if MAD_F_FRACBITS != 28 #warning libmad with MAD_F_FRACBITS != 28 not tested #endif class cStream; // ---------------------------------------------------------------- class cScanID3 : public cSongInfo { private: bool keepOpen, *urgent; // bool Abort(bool result); struct id3_tag *GetID3(struct mad_stream *stream, id3_length_t tagsize) const; void ParseID3(const struct id3_tag *tag); void ParseStr(const struct id3_tag *tag, const char *id, char * &data); void ParsePic(const struct id3_tag *tag, const char *id, char * &name); int ParseXing(struct mad_bitptr *ptr, unsigned int bitlen) const; protected: cStream *str; public: cScanID3(cStream *Str, bool *Urgent); virtual ~cScanID3() {} virtual bool DoScan(bool KeepOpen=false); virtual void InfoHook(struct mad_header *header) {} }; // ---------------------------------------------------------------- class cMP3Decoder : public cDecoder { private: struct Decode ds; // struct mad_stream *stream; struct mad_frame *frame; struct mad_synth *synth; mad_timer_t playtime, skiptime; // struct FrameInfo { unsigned long long Pos; mad_timer_t Time; } *fi; int framenum, framemax, errcount, mute; // void Init(void); void Clean(void); struct Decode *Done(eDecodeStatus status); eDecodeStatus DecodeError(bool hdr); void MakeSkipTime(mad_timer_t *skiptime, mad_timer_t playtime, int secs, float bsecs); protected: cStream *str; cScanID3 *scan; bool isStream; public: cMP3Decoder(const char *Filename, bool preinit=true); virtual ~cMP3Decoder(); virtual bool Valid(void); virtual cFileInfo *FileInfo(void); virtual cSongInfo *SongInfo(bool get); virtual cPlayInfo *PlayInfo(void); virtual bool Start(void); virtual bool Stop(void); virtual bool Skip(int Seconds, float bsecs); virtual struct Decode *Decode(void); }; #endif //___DECODER_MP3_H mp3-0.10.2/decoder-ogg-stream.c0100644000000000000000000000751211277241323014613 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * OGG stream support initialy developed by Manuel Reimer * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include "common.h" #include "decoder-ogg-stream.h" #include "stream.h" // --- Ogg callbacks ----------------------------------------------------------- static size_t callback_read(void *ptr, size_t size, size_t nmemb, void *datasource) { cNetStream *nstr=(cNetStream*)datasource; unsigned char *sdata; unsigned long slen=0; // Read in loop until we either get data or function "Stream" fails do { if(!nstr->Stream(sdata,slen)) { d(printf("oggstream-callback-read: EOF?\n")) return 0; } } while(slen==0); size_t read_size=size*nmemb; if(slen>read_size) { // If someone ever gets this message, buffer handling has to be improved... d(printf("oggstream-callback-read: buffer size too small...\n")) slen=read_size; } memcpy(ptr,sdata,slen); return slen/size; } static int callback_close(void *datasource) { cNetStream *nstr=(cNetStream*)datasource; nstr->Close(); return 0; } static const ov_callbacks callbacks = { callback_read, NULL, callback_close, NULL }; // --- cNetOggFile ------------------------------------------------------------- cNetOggFile::cNetOggFile(const char *Filename) :cOggFile(Filename) { nstr=new cNetStream(Filename); } bool cNetOggFile::Open(bool log) { if(opened) return true; if(!nstr->Open(log)) return false; int r=ov_open_callbacks(nstr,&vf,NULL,0,callbacks); if(!r) opened=true; else { nstr->Close(); if(log) Error("open",r); } return opened; } // --- cNetOggInfo ------------------------------------------------------------- cNetOggInfo::cNetOggInfo(cNetOggFile *File) :cOggInfo(File) { nfile=File; nstr=nfile->nstr; } bool cNetOggInfo::DoScan(bool KeepOpen) { Clear(); IcyInfo(); if(!Title) FakeTitle(nstr->Filename); Total=0; ChMode=3; DecoderID=DEC_OGGS; InfoDone(); return true; } void cNetOggInfo::InfoHook() { if(nstr->IcyChanged()) IcyInfo(); vorbis_info *vi=ov_info(&nfile->vf,-1); if(!vi) return; Channels=vi->channels; ChMode=Channels>1 ? 3:0; SampleFreq=vi->rate; if(vi->bitrate_upper>0 && vi->bitrate_lower>0) { Bitrate=vi->bitrate_lower; MaxBitrate=vi->bitrate_upper; } else Bitrate=vi->bitrate_nominal; Total=(int)ov_time_total(&nfile->vf,-1); Frames=-1; } void cNetOggInfo::IcyInfo(void) { const char *t=nstr->IcyTitle(); const char *a; if(t) { a=nstr->IcyName(); if(!a) a=nstr->IcyUrl(); } else { t=nstr->IcyName(); a=nstr->IcyUrl(); } if(t && (!Title || strcmp(t,Title))) { free(Title); Title=strdup(t); } if(a && (!Album || strcmp(a,Album))) { free(Album); Album=strdup(a); } } // --- cOggStreamDecoder ------------------------------------------------------- cOggStreamDecoder::cOggStreamDecoder(const char *Filename) :cOggDecoder(Filename,false) { nfile=new cNetOggFile(Filename); file=nfile; info=new cNetOggInfo(nfile); } mp3-0.10.2/decoder-ogg-stream.h0100644000000000000000000000367611277241323014627 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * OGG stream support initialy developed by Manuel Reimer * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DECODER_OGG_STREAM_H #define ___DECODER_OGG_STREAM_H #define DEC_OGGS DEC_ID('O','G','G','S') #define DEC_OGGS_STR "OGGS" #include "decoder-ogg.h" class cNetStream; // ---------------------------------------------------------------- class cNetOggFile : public cOggFile { friend class cNetOggInfo; private: cNetStream *nstr; public: cNetOggFile(const char *Filename); virtual bool Open(bool log=true); }; // ---------------------------------------------------------------- class cNetOggInfo : public cOggInfo { private: cNetOggFile *nfile; cNetStream *nstr; void IcyInfo(void); public: cNetOggInfo(cNetOggFile *File); virtual bool DoScan(bool KeepOpen=false); virtual void InfoHook(void); }; // ---------------------------------------------------------------- class cOggStreamDecoder : public cOggDecoder { private: cNetOggFile *nfile; public: cOggStreamDecoder(const char *Filename); virtual bool IsStream(void) { return true; } }; #endif //___DECODER_OGG_STREAM_H mp3-0.10.2/decoder-ogg.c0100644000000000000000000002136711306462552013330 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifdef HAVE_VORBISFILE #include #include #include #include "common.h" #include "decoder-ogg.h" // --- cOggFile ---------------------------------------------------------------- cOggFile::cOggFile(const char *Filename) :cFileInfo(Filename) { canSeek=opened=false; } cOggFile::~cOggFile() { Close(); } bool cOggFile::Open(bool log) { if(opened) { if(canSeek) return (Seek()>=0); return true; } if(FileInfo(log)) { FILE *f=fopen(Filename,"r"); if(f) { int r=ov_open(f,&vf,0,0); if(!r) { canSeek=(ov_seekable(&vf)!=0); opened=true; } else { fclose(f); if(log) Error("open",r); } } else if(log) { esyslog("ERROR: failed to open file %s: %s",Filename,strerror(errno)); } } return opened; } void cOggFile::Close(void) { if(opened) { ov_clear(&vf); opened=false; } } void cOggFile::Error(const char *action, const int err) { const char *errstr; switch(err) { case OV_FALSE: errstr="false/no data available"; break; case OV_EOF: errstr="EOF"; break; case OV_HOLE: errstr="missing or corrupted data"; break; case OV_EREAD: errstr="read error"; break; case OV_EFAULT: errstr="internal error"; break; case OV_EIMPL: errstr="unimplemented feature"; break; case OV_EINVAL: errstr="invalid argument"; break; case OV_ENOTVORBIS: errstr="no Ogg Vorbis stream"; break; case OV_EBADHEADER: errstr="corrupted Ogg Vorbis stream"; break; case OV_EVERSION: errstr="unsupported bitstream version"; break; case OV_ENOTAUDIO: errstr="ENOTAUDIO"; break; case OV_EBADPACKET: errstr="EBADPACKET"; break; case OV_EBADLINK: errstr="corrupted link"; break; case OV_ENOSEEK: errstr="stream not seekable"; break; default: errstr="unspecified error"; break; } esyslog("ERROR: vorbisfile %s failed on %s: %s",action,Filename,errstr); } long long cOggFile::IndexMs(void) { double p=ov_time_tell(&vf); if(p<0.0) p=0.0; return (long long)(p*1000.0); } long long cOggFile::Seek(long long posMs, bool relativ) { if(relativ) posMs+=IndexMs(); int r=ov_time_seek(&vf,(double)posMs/1000.0); if(r) { Error("seek",r); return -1; } posMs=IndexMs(); return posMs; } int cOggFile::Stream(short *buffer, int samples) { int n; do { int stream; n=ov_read(&vf,(char *)buffer,samples*2,0,2,1,&stream); } while(n==OV_HOLE); if(n<0) Error("read",n); return (n/2); } // --- cOggInfo ---------------------------------------------------------------- cOggInfo::cOggInfo(cOggFile *File) { file=File; } bool cOggInfo::Abort(bool result) { if(!keepOpen) file->Close(); return result; } bool cOggInfo::DoScan(bool KeepOpen) { keepOpen=KeepOpen; if(!file->Open()) return Abort(false); if(HasInfo()) return Abort(true); // check the infocache cCacheData *dat=InfoCache.Search(file); if(dat) { Set(dat); dat->Unlock(); ConvertToSys(); if(!DecoderID) { DecoderID=DEC_OGG; InfoCache.Cache(this,file); } return Abort(true); } Clear(); vorbis_comment *vc=ov_comment(&file->vf,-1); if(vc) { for(int i=0 ; icomments ; i++) { const char *cc=vc->user_comments[i]; d(printf("ogg: comment%d='%s'\n",i,cc)) const char *p=strchr(cc,'='); if(p) { const int len=p-cc; p++; if(!strncasecmp(cc,"TITLE",len)) { if(!Title) Title=strdup(p); } else if(!strncasecmp(cc,"ARTIST",len)) { if(!Artist) Artist=strdup(p); } else if(!strncasecmp(cc,"ALBUM",len)) { if(!Album) Album=strdup(p); } else if(!strncasecmp(cc,"YEAR",len)) { if(Year<0) { Year=atoi(p); if(Year<1800 || Year>2100) Year=-1; } } } } } if(!Title) FakeTitle(file->Filename); vorbis_info *vi=ov_info(&file->vf,-1); if(!vi) Abort(false); d(printf("ogg: info ch=%d srate=%ld brate_low=%ld brate_high=%ld brate_avg=%ld\n", vi->channels,vi->rate,vi->bitrate_lower,vi->bitrate_upper,vi->bitrate_nominal)) Channels=vi->channels; ChMode=Channels>1 ? 3:0; SampleFreq=vi->rate; if(vi->bitrate_upper>0 && vi->bitrate_lower>0) { Bitrate=vi->bitrate_lower; MaxBitrate=vi->bitrate_upper; } else Bitrate=vi->bitrate_nominal; Total=(int)ov_time_total(&file->vf,-1); Frames=-1; DecoderID=DEC_OGG; InfoDone(); InfoCache.Cache(this,file); ConvertToSys(); return Abort(true); } // --- cOggDecoder ------------------------------------------------------------- cOggDecoder::cOggDecoder(const char *Filename, bool preinit) :cDecoder(Filename) { file=0; info=0; pcm=0; if(preinit) { file=new cOggFile(Filename); info=new cOggInfo(file); } } cOggDecoder::~cOggDecoder() { Clean(); delete info; delete file; } bool cOggDecoder::Valid(void) { bool res=false; if(TryLock()) { if(file->Open(false)) res=true; Unlock(); } return res; } cFileInfo *cOggDecoder::FileInfo(void) { cFileInfo *fi=0; if(file->HasInfo()) fi=file; else if(TryLock()){ if(file->Open()) { fi=file; file->Close(); } Unlock(); } return fi; } cSongInfo *cOggDecoder::SongInfo(bool get) { cSongInfo *si=0; if(info->HasInfo()) si=info; else if(get && TryLock()) { if(info->DoScan(false)) si=info; Unlock(); } return si; } cPlayInfo *cOggDecoder::PlayInfo(void) { if(playing) { pi.Index=index/1000; pi.Total=info->Total; return π } return 0; } void cOggDecoder::Init(void) { Clean(); pcm=new struct mad_pcm; index=0; } bool cOggDecoder::Clean(void) { playing=false; delete pcm; pcm=0; file->Close(); return false; } #define SF_SAMPLES (sizeof(pcm->samples[0])/sizeof(mad_fixed_t)) bool cOggDecoder::Start(void) { Lock(true); Init(); playing=true; if(file->Open() && info->DoScan(true)) { d(printf("ogg: open rate=%d channels=%d seek=%d\n", info->SampleFreq,info->Channels,file->CanSeek())) if(info->Channels<=2) { Unlock(); return true; } else esyslog("ERROR: cannot play ogg file %s: more than 2 channels",filename); } Clean(); Unlock(); return false; } bool cOggDecoder::Stop(void) { Lock(); if(playing) Clean(); Unlock(); return true; } struct Decode *cOggDecoder::Done(eDecodeStatus status) { ds.status=status; ds.index=index; ds.pcm=pcm; Unlock(); // release the lock from Decode() return &ds; } struct Decode *cOggDecoder::Decode(void) { Lock(); // this is released in Done() if(playing) { short framebuff[2*SF_SAMPLES]; int n=file->Stream(framebuff,SF_SAMPLES); if(n<0) return Done(dsError); if(n==0) return Done(dsEof); pcm->samplerate=info->SampleFreq; pcm->channels=info->Channels; n/=pcm->channels; pcm->length=n; index=file->IndexMs(); short *data=framebuff; mad_fixed_t *sam0=pcm->samples[0], *sam1=pcm->samples[1]; const int s=MAD_F_FRACBITS+1-(sizeof(short)*8); // shift value for mad_fixed conversion if(pcm->channels>1) { for(; n>0 ; n--) { *sam0++=(*data++) << s; *sam1++=(*data++) << s; } } else { for(; n>0 ; n--) *sam0++=(*data++) << s; } info->InfoHook(); return Done(dsPlay); } return Done(dsError); } bool cOggDecoder::Skip(int Seconds, float bsecs) { Lock(); bool res=false; if(playing && file->CanSeek()) { float fsecs=(float)Seconds - bsecs; long long newpos=file->IndexMs()+(long long)(fsecs*1000.0); if(newpos<0) newpos=0; d(printf("ogg: skip: secs=%d fsecs=%f current=%lld new=%lld\n",Seconds,fsecs,file->IndexMs(),newpos)) newpos=file->Seek(newpos,false); if(newpos>=0) { index=file->IndexMs(); #ifdef DEBUG int i=index/1000; printf("ogg: skipping to %02d:%02d\n",i/60,i%60); #endif res=true; } } Unlock(); return res; } #endif //HAVE_VORBISFILE mp3-0.10.2/decoder-ogg.h0100644000000000000000000000545211316351073013326 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DECODER_OGG_H #define ___DECODER_OGG_H #define DEC_OGG DEC_ID('O','G','G',' ') #define DEC_OGG_STR "OGG" #ifdef HAVE_VORBISFILE #include #include #include "decoder.h" #include "decoder-core.h" // ---------------------------------------------------------------- class cOggInfo; class cOggFile : public cFileInfo { friend class cOggInfo; private: bool canSeek; protected: bool opened; OggVorbis_File vf; // void Error(const char *action, const int err); public: cOggFile(const char *Filename); virtual ~cOggFile(); virtual bool Open(bool log=true); void Close(void); long long Seek(long long posMs=0, bool relativ=false); int Stream(short *buffer, int samples); bool CanSeek(void) { return canSeek; } long long IndexMs(void); }; // ---------------------------------------------------------------- class cOggInfo : public cSongInfo { private: cOggFile *file; bool keepOpen; // bool Abort(bool result); public: cOggInfo(cOggFile *File); virtual ~cOggInfo() {} virtual bool DoScan(bool KeepOpen=false); virtual void InfoHook(void) {}; }; // ---------------------------------------------------------------- class cOggDecoder : public cDecoder { private: struct Decode ds; struct mad_pcm *pcm; unsigned long long index; // void Init(void); bool Clean(void); bool GetInfo(bool keepOpen); struct Decode *Done(eDecodeStatus status); protected: cOggFile *file; cOggInfo *info; public: cOggDecoder(const char *Filename, bool preinit=true); ~cOggDecoder(); virtual bool Valid(void); virtual cFileInfo *FileInfo(void); virtual cSongInfo *SongInfo(bool get); virtual cPlayInfo *PlayInfo(void); virtual bool Start(void); virtual bool Stop(void); virtual bool Skip(int Seconds, float bsecs); virtual struct Decode *Decode(void); }; // ---------------------------------------------------------------- #endif //HAVE_VORBISFILE #endif //___DECODER_OGG_H mp3-0.10.2/decoder-snd.c0100644000000000000000000005362411305370261013333 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifdef TEST_MAIN #define HAVE_SNDFILE #define REMOTE_LIRC #define _GNU_SOURCE #define DEBUG #endif #ifdef HAVE_SNDFILE #include #include #include #include #include #include #include #include #include "common.h" #include "setup-mp3.h" #include "decoder-snd.h" #include "data.h" #include "network.h" #include "menu-async.h" #include "i18n.h" #include "version.h" #ifndef SNDFILE_1 #error You must use libsndfile version 1.x.x #endif #define CDFS_TRACK_OFF 150 #define CDFS_PROC "/proc/cdfs" #define CDFS_MARK_ID "CD (discid=%x) contains %d tracks:" #define CDFS_MARK_TR "%*[^[][ %d - %d" #define CDFS_TRACK "track-" #define CDDB_PROTO 5 // used protocol level #define CDDB_TOUT 30*1000 // connection timeout (ms) #define CDDB_CHARSET "ISO8859-1" // data charset const char *cddbpath="/var/lib/cddb"; // default local cddb path #define CDDB_DEBUG // debug cddb queries //#define DEBUG_CDFS // debug cdfs parsing //#define GUARD_DEBUG // enable framebuffer guard #if !defined(NO_DEBUG) && defined(DEBUG_CDFS) #define dc(x) { (x); } #else #define dc(x) ; #endif #ifndef TEST_MAIN // --- cSndDecoder ------------------------------------------------------------- #define SF_SAMPLES (sizeof(pcm->samples[0])/sizeof(mad_fixed_t)) cSndDecoder::cSndDecoder(const char *Filename) :cDecoder(Filename) ,file(Filename) ,info(&file) { pcm=0; framebuff=0; playing=ready=false; } cSndDecoder::~cSndDecoder() { Clean(); } bool cSndDecoder::Valid(void) { bool res=false; if(TryLock()) { if(file.Open(false)) res=true; cDecoder::Unlock(); } return res; } cFileInfo *cSndDecoder::FileInfo(void) { cFileInfo *fi=0; if(file.HasInfo()) fi=&file; else if(TryLock()){ if(file.Open()) { fi=&file; file.Close(); } cDecoder::Unlock(); } return fi; } cSongInfo *cSndDecoder::SongInfo(bool get) { cSongInfo *si=0; if(info.HasInfo()) si=&info; else if(get && TryLock()) { if(info.DoScan(false)) si=&info; cDecoder::Unlock(); } return si; } cPlayInfo *cSndDecoder::PlayInfo(void) { if(playing) { pi.Index=index/info.SampleFreq; pi.Total=info.Total; return π } return 0; } void cSndDecoder::Init(void) { Clean(); pcm=new struct mad_pcm; framebuff=MALLOC(int,2*SF_SAMPLES+8); #ifdef GUARD_DEBUG for(int i=0; i<8; i++) framebuff[i+(SF_SAMPLES*2)-4]=0xdeadbeaf; #endif index=0; } bool cSndDecoder::Clean(void) { playing=false; buffMutex.Lock(); run=false; bgCond.Broadcast(); buffMutex.Unlock(); cThread::Cancel(3); buffMutex.Lock(); if(!ready) { deferedN=-1; ready=true; } fgCond.Broadcast(); buffMutex.Unlock(); delete pcm; pcm=0; #ifdef GUARD_DEBUG if(framebuff) { printf("snd: bufferguard"); for(int i=0; i<8; i++) printf(" %08x",framebuff[i+(SF_SAMPLES*2)-4]); printf("\n"); } #endif free(framebuff); framebuff=0; file.Close(); return false; } bool cSndDecoder::Start(void) { cDecoder::Lock(true); Init(); playing=true; if(file.Open() && info.DoScan(true)) { d(printf("snd: open rate=%d frames=%lld channels=%d format=0x%x seek=%d\n", file.sfi.samplerate,file.sfi.frames,file.sfi.channels,file.sfi.format,file.sfi.seekable)) if(file.sfi.channels<=2) { ready=false; run=true; softCount=0; cThread::Start(); cDecoder::Unlock(); return true; } else esyslog("ERROR: cannot play sound file %s: more than 2 channels",filename); } cDecoder::Unlock(); return Clean(); } bool cSndDecoder::Stop(void) { cDecoder::Lock(); if(playing) Clean(); cDecoder::Unlock(); return true; } void cSndDecoder::Action(void) { buffMutex.Lock(); while(run) { if(ready) bgCond.Wait(buffMutex); if(!ready) { buffMutex.Unlock(); deferedN=file.Stream(framebuff,SF_SAMPLES); buffMutex.Lock(); ready=true; fgCond.Broadcast(); } } buffMutex.Unlock(); } struct Decode *cSndDecoder::Done(eDecodeStatus status) { ds.status=status; ds.index=index*1000/info.SampleFreq; ds.pcm=pcm; cDecoder::Unlock(); // release the lock from Decode() return &ds; } struct Decode *cSndDecoder::Decode(void) { cDecoder::Lock(); // this is released in Done() if(playing) { cMutexLock lock(&buffMutex); while(!ready) if(!softCount || !fgCond.TimedWait(buffMutex,softCount*5)) { if(softCount<20) softCount++; return Done(dsSoftError); } softCount=0; ready=false; bgCond.Broadcast(); int n=deferedN; if(n<0) return Done(dsError); if(n==0) return Done(dsEof); pcm->samplerate=file.sfi.samplerate; pcm->channels=file.sfi.channels; pcm->length=n; index+=n; int *data=framebuff; mad_fixed_t *sam0=pcm->samples[0], *sam1=pcm->samples[1]; const int s=(sizeof(int)*8)-1-MAD_F_FRACBITS; // shift value for mad_fixed conversion if(pcm->channels>1) { for(; n>0 ; n--) { *sam0++=(*data++) >> s; *sam1++=(*data++) >> s; } } else { for(; n>0 ; n--) *sam0++=(*data++) >> s; } return Done(dsPlay); } return Done(dsError); } bool cSndDecoder::Skip(int Seconds, float bsecs) { cDecoder::Lock(); bool res=false; if(playing && file.sfi.seekable) { float fsecs=(float)Seconds-bsecs; sf_count_t frames=(sf_count_t)(fsecs*(float)file.sfi.samplerate); sf_count_t newpos=file.Seek(0,true)+frames; if(newpos>file.sfi.frames) newpos=file.sfi.frames-1; if(newpos<0) newpos=0; d(printf("snd: skip: secs=%d fsecs=%f frames=%lld current=%lld new=%lld\n",Seconds,fsecs,frames,file.Seek(0,true),newpos)) buffMutex.Lock(); frames=file.Seek(newpos,false); ready=false; bgCond.Broadcast(); buffMutex.Unlock(); if(frames>=0) { index=frames; #ifdef DEBUG int i=frames/file.sfi.samplerate; printf("snd: skipping to %02d:%02d (frame %lld)\n",i/60,i%60,frames); #endif res=true; } } cDecoder::Unlock(); return res; } #endif //TEST_MAIN // --- cDiscID ------------------------------------------------------------------- class cDiscID { public: int discid, ntrks, nsecs; int *offsets; // cDiscID(void); ~cDiscID(); bool Get(void); }; cDiscID::cDiscID(void) { offsets=0; discid=ntrks=0; } cDiscID::~cDiscID() { delete offsets; } bool cDiscID::Get(void) { bool res=false; FILE *f=fopen(CDFS_PROC,"r"); if(f) { char line[256]; bool state=false; int tr=0; while(fgets(line,sizeof(line),f)) { if(!state) { int id, n; if(sscanf(line,CDFS_MARK_ID,&id,&n)==2) { d(printf("discid: found id=%08x n=%d\n",id,n)) if(discid==id && ntrks==n) { res=true; break; } else { discid=id; ntrks=n; delete offsets; offsets=new int[ntrks]; state=true; } } } else { int off, end; if(sscanf(line,CDFS_MARK_TR,&off,&end)==2) { dc(printf("discid: found offset=%d end=%d for track %d\n",off,end,tr+1)) offsets[tr]=off+CDFS_TRACK_OFF; if(++tr==ntrks) { nsecs=(end+1)/75; dc(printf("discid: nsecs=%d / 0x%x\n",nsecs,nsecs)) res=true; break; } } } } fclose(f); } return res; } // --- cCDDBSong --------------------------------------------------------------- // The CDDB code is loosely based on the implementation in mp3c 0.27 which is // (C) 1999-2001 WSPse, Matthias Hensler, class cCDDBSong : public cListObject { public: cCDDBSong(void); ~cCDDBSong(); // int Track; char *TTitle, *ExtT; char *Title, *Artist; }; cCDDBSong::cCDDBSong(void) { Title=Artist=0; TTitle=ExtT=0; } cCDDBSong::~cCDDBSong() { free(Title); free(Artist); free(TTitle); free(ExtT); } // --- cCDDBDisc --------------------------------------------------------------- const char *sampler[] = { // some artist names to identify sampler discs "various", "varios", "variщtщ", "compilation", "sampler", "mixed", "divers", "v.a.", "VA", "misc", "none", 0 }; class cCDDBDisc : public cList { private: int DiscID; // bool isSampler; char *DTitle, *ExtD; // cCDDBSong *GetTrack(const char *name, unsigned int pos); cCDDBSong *FindTrack(int tr); void Strcat(char * &store, const char *value); bool Split(const char *source, char div, char * &first, char * &second, bool only3=false); void Put(const char *from, char * &to); void Clean(void); public: cCDDBDisc(void); ~cCDDBDisc(); bool Load(cDiscID *id, const char *filename); bool Cached(cDiscID *id) { return DiscID==id->discid; } bool TrackInfo(int tr, cSongInfo *si); // char *Album, *Artist; int Year; }; cCDDBDisc::cCDDBDisc(void) { Album=Artist=0; DTitle=ExtD=0; DiscID=0; } cCDDBDisc::~cCDDBDisc() { Clean(); } void cCDDBDisc::Clean(void) { free(DTitle); DTitle=0; free(ExtD); ExtD=0; free(Artist); Artist=0; free(Album); Album=0; Year=-1; DiscID=0; isSampler=false; } bool cCDDBDisc::TrackInfo(int tr, cSongInfo *si) { cCDDBSong *s=FindTrack(tr); if(s) { Put(s->Title,si->Title); if(s->Artist) Put(s->Artist,si->Artist); else Put(Artist,si->Artist); Put(Album,si->Album); if(Year>0) si->Year=Year; return true; } return false; } void cCDDBDisc::Put(const char *from, char * &to) { free(to); to=from ? strdup(from):0; } bool cCDDBDisc::Load(cDiscID *id, const char *filename) { char *p; Clean(); Clear(); d(printf("cddb: loading discid %08x from %s\n",id->discid,filename)) DiscID=id->discid; FILE *f=fopen(filename,"r"); if(f) { cCharSetConv csc(CDDB_CHARSET); char buff[1024]; while(fgets(buff,sizeof(buff),f)) { int i=strlen(buff); while(i && (buff[i-1]=='\n' || buff[i-1]=='\r')) buff[--i]=0; if(buff[0]=='#') { // special comment line handling } else { p=strchr(buff,'='); if(p) { *p=0; char *name =compactspace(buff); const char *value=csc.Convert(compactspace(p+1)); if(*name && *value) { if(!strcasecmp(name,"DTITLE")) Strcat(DTitle,value); else if(!strcasecmp(name,"EXTD")) Strcat(ExtD,value); else if(!strcasecmp(name,"DYEAR")) Year=atoi(value); else if(!strncasecmp(name,"TTITLE",6)) { cCDDBSong *s=GetTrack(name,6); if(s) Strcat(s->TTitle,value); } else if(!strncasecmp(name,"EXTT",4)) { cCDDBSong *s=GetTrack(name,4); if(s) Strcat(s->ExtT,value); } } } } } fclose(f); // read all data, now post-processing if(Count()>0) { if(DTitle) { if(Split(DTitle,'/',Artist,Album)) { for(int n=0 ; sampler[n] ; n++) if(!strncasecmp(Artist,sampler[n],strlen(sampler[n]))) { isSampler=true; break; } } else { Album=strdup(DTitle); isSampler=true; } } d(printf("cddb: found artist='%s' album='%s' isSampler=%d\n",Artist,Album,isSampler)) free(DTitle); DTitle=0; if(!isSampler && Artist && Album && !strncmp(Album,Artist,strlen(Artist))) { d(printf("cddb: detecting sampler from Artist==Album\n")) isSampler=true; } if(!isSampler) { int nofail1=0, nofail2=0; cCDDBSong *s=First(); while(s) { if(s->TTitle) { if(strstr(s->TTitle," / ")) nofail1++; //if(strstr(s->TTitle," - ")) nofail2++; } s=Next(s); } if(nofail1==Count() || nofail2==Count()) { d(printf("cddb: detecting sampler from nofail\n")) isSampler=true; } } if(Year<0 && ExtD && (p=strstr(ExtD,"YEAR:"))) Year=atoi(p+5); free(ExtD); ExtD=0; d(printf("cddb: found year=%d\n",Year)) cCDDBSong *s=First(); while(s) { if(s->TTitle) { if(isSampler) { if(!Split(s->TTitle,'/',s->Artist,s->Title) && !Split(s->TTitle,'-',s->Artist,s->Title,true)) { s->Title=compactspace(strdup(s->TTitle)); if(s->ExtT) s->Artist=compactspace(strdup(s->ExtT)); } } else { s->Title=compactspace(strdup(s->TTitle)); if(Artist) s->Artist=strdup(Artist); } } else s->Title=strdup(tr("unknown")); free(s->TTitle); s->TTitle=0; free(s->ExtT); s->ExtT=0; d(printf("cddb: found track %d title='%s' artist='%s'\n",s->Track,s->Title,s->Artist)) s=Next(s); } return true; } } return false; } bool cCDDBDisc::Split(const char *source, char div, char * &first, char * &second, bool only3) { int pos=-1, n=0; const char *p; char l[4]={ ' ',div,' ',0 }; if ((p=strstr(source,l))) { pos=p-source; n=3; } else if(!only3 && (p=strchr(source,div))) { pos=p-source; n=1; } if(pos>=0) { free(first); first=strdup(source); first[pos]=0; compactspace(first); free(second); second=strdup(source+pos+n); compactspace(second); return true; } return false; } void cCDDBDisc::Strcat(char * &store, const char *value) { if(store) { char *n=MALLOC(char,strlen(store)+strlen(value)+1); if(n) { strcpy(n,store); strcat(n,value); free(store); store=n; } } else store=strdup(value); } cCDDBSong *cCDDBDisc::GetTrack(const char *name, unsigned int pos) { cCDDBSong *s=0; if(strlen(name)>pos) { int tr=atoi(&name[pos]); s=FindTrack(tr); if(!s) { s=new cCDDBSong; Add(s); s->Track=tr; } } return s; } cCDDBSong *cCDDBDisc::FindTrack(int tr) { cCDDBSong *s=First(); while(s) { if(s->Track==tr) break; s=Next(s); } return s; } #ifndef TEST_MAIN // --- cCDDB ------------------------------------------------------------------- class cCDDB : public cScanDir, cMutex { private: cCDDBDisc cache; cFileSource *src; cFileObj *file; cNet *net; char searchID[10], cddbstr[256]; // virtual void DoItem(cFileSource *src, const char *subdir, const char *name); bool LocalQuery(cDiscID *id); bool RemoteGet(cDiscID *id); bool GetLine(char *buff, int size, bool log=true); int GetCddbResponse(void); int DoCddbCmd(const char *format, ...); public: cCDDB(void); virtual ~cCDDB(); bool Lookup(cDiscID *id, int track, cSongInfo *si); }; cCDDB cddb; cCDDB::cCDDB(void) { src=0; file=0; net=0; } cCDDB::~cCDDB() { delete file; delete src; delete net; } bool cCDDB::Lookup(cDiscID *id, int track, cSongInfo *si) { bool res=false; Lock(); if(!cache.Cached(id)) { if(LocalQuery(id) || (MP3Setup.UseCddb>1 && RemoteGet(id) && LocalQuery(id))) cache.Load(id,file->FullPath()); } if(cache.Cached(id) && cache.TrackInfo(track,si)) res=true; Unlock(); return res; } bool cCDDB::LocalQuery(cDiscID *id) { bool res=false; delete file; file=0; if(!src) src=new cFileSource(cddbpath,"CDDB database",false); if(src) { snprintf(searchID,sizeof(searchID),"%08x",id->discid); if(ScanDir(src,0,stDir,0,0,false) && file) res=true; } return res; } void cCDDB::DoItem(cFileSource *src, const char *subdir, const char *name) { if(!file) { file=new cFileObj(src,name,searchID,otFile); if(access(file->FullPath(),R_OK)) { delete file; file=0; } } } bool cCDDB::RemoteGet(cDiscID *id) { bool res=false; asyncStatus.Set(tr("Remote CDDB lookup...")); delete net; net=new cNet(16*1024,CDDB_TOUT,CDDB_TOUT); if(net->Connect(MP3Setup.CddbHost,MP3Setup.CddbPort)) { int code=GetCddbResponse(); if(code/100==2) { const char *host=getenv("HOSTNAME"); if(!host) host="unknown"; const char *user=getenv("USER"); if(!user) user="nobody"; code=DoCddbCmd("cddb hello %s %s %s %s\n",user,host,PLUGIN_NAME,PluginVersion); if(code/100==2) { code=DoCddbCmd("proto %d\n",CDDB_PROTO); if(code>0) { char off[1024]; off[0]=0; for(int i=0 ; intrks ; i++) sprintf(&off[strlen(off)]," %d",id->offsets[i]); code=DoCddbCmd("cddb query %08x %d %s %d\n",id->discid,id->ntrks,off,id->nsecs); if(code/100==2) { char *cat=0; if(code==200) cat=strdup(cddbstr); else if(code==210) { if(GetLine(off,sizeof(off))) { cat=strdup(off); while(GetLine(off,sizeof(off)) && off[0]!='.'); } } if(cat) { char *s=index(cat,' '); if(s) *s=0; code=DoCddbCmd("cddb read %s %08x\n",cat,id->discid); if(code==210) { char *name=aprintf("%s/%s/%08x",cddbpath,cat,id->discid); if(MakeDirs(name,false)) { FILE *out=fopen(name,"w"); if(out) { while(GetLine(off,sizeof(off),false) && off[0]!='.') fputs(off,out); fclose(out); res=true; } else esyslog("fopen() failed: %s",strerror(errno)); } free(name); } else if(code>0) esyslog("server read error: %d %s",code,cddbstr); free(cat); } } else if(code>0) esyslog("server query error: %d %s",code,cddbstr); } else esyslog("server proto error: %d %s",code,cddbstr); } else if(code>0) esyslog("server hello error: %d %s",code,cddbstr); } else if(code>0) esyslog("server sign-on error: %d %s",code,cddbstr); } delete net; net=0; asyncStatus.Set(0); return res; } bool cCDDB::GetLine(char *buff, int size, bool log) { if(net->Gets(buff,size)>0) { #ifdef CDDB_DEBUG if(log) printf("cddb: <- %s",buff); #endif return true; } return false; } int cCDDB::GetCddbResponse(void) { char buf[1024]; if(GetLine(buf,sizeof(buf))) { int code; if(sscanf(buf,"%d %255[^\n]",&code,cddbstr)==2) return code; else esyslog("Unexpected server response: %s",buf); } return -1; } int cCDDB::DoCddbCmd(const char *format, ...) { va_list ap; va_start(ap,format); char *buff=0; if(vasprintf(&buff,format,ap)<0); va_end(ap); #ifdef CDDB_DEBUG printf("cddb: -> %s",buff); #endif int r=net->Puts(buff); free(buff); if(r<0) return -1; return GetCddbResponse(); } // --- cSndInfo ---------------------------------------------------------------- cSndInfo::cSndInfo(cSndFile *File) { file=File; id=new cDiscID; } cSndInfo::~cSndInfo() { delete id; } bool cSndInfo::Abort(bool result) { if(!keepOpen) file->Close(); return result; } bool cSndInfo::DoScan(bool KeepOpen) { keepOpen=KeepOpen; if(!file->Open()) return Abort(false); if(HasInfo()) return Abort(true); // check the infocache cCacheData *dat=InfoCache.Search(file); if(dat) { Set(dat); dat->Unlock(); ConvertToSys(); if(!DecoderID) { DecoderID=DEC_SND; InfoCache.Cache(this,file); } return Abort(true); } Clear(); if(file->FsType!=CDFS_MAGIC || !MP3Setup.UseCddb || !CDDBLookup(file->Filename)) FakeTitle(file->Filename); Frames=file->sfi.frames; SampleFreq=file->sfi.samplerate; Channels=file->sfi.channels; ChMode=Channels>1 ? 3:0; Total=Frames/SampleFreq; Bitrate=Total ? file->Filesize*8/Total : 0; //XXX SampleFreq*Channels*file->sfi.pcmbitwidth; DecoderID=DEC_SND; InfoDone(); InfoCache.Cache(this,file); ConvertToSys(); return Abort(true); } bool cSndInfo::CDDBLookup(const char *filename) { if(id->Get()) { int tr; const char *s=strstr(filename,CDFS_TRACK); if(s && sscanf(s+strlen(CDFS_TRACK),"%d",&tr)==1) { d(printf("snd: looking up disc id %08x track %d\n",id->discid,tr)) return cddb.Lookup(id,tr-1,this); } } return false; } // --- cSndFile ---------------------------------------------------------------- cSndFile::cSndFile(const char *Filename) :cFileInfo(Filename) { sf=0; } cSndFile::~cSndFile() { Close(); } bool cSndFile::Open(bool log) { if(sf) return (Seek()>=0); if(FileInfo(log)) { sf=sf_open(Filename,SFM_READ,&sfi); if(!sf && log) Error("open"); } return (sf!=0); } void cSndFile::Close(void) { if(sf) { sf_close(sf); sf=0; } } void cSndFile::Error(const char *action) { char buff[128]; sf_error_str(sf,buff,sizeof(buff)); esyslog("ERROR: sndfile %s failed on %s: %s",action,Filename,buff); } sf_count_t cSndFile::Seek(sf_count_t frames, bool relativ) { int dir=SEEK_CUR; if(!relativ) dir=SEEK_SET; int n=sf_seek(sf,frames,dir); if(n<0) Error("seek"); return n; } sf_count_t cSndFile::Stream(int *buffer, sf_count_t frames) { sf_count_t n=sf_readf_int(sf,buffer,frames); if(n<0) Error("read"); return n; } #endif //TEST_MAIN #endif //HAVE_SNDFILE #ifdef TEST_MAIN // // to compile: // g++ -g -DTEST_MAIN -o test mp3-decoder-snd.c tools.o thread.o -lpthread // // calling: // test // extern const char *tr(const char *test) { return test; } int main (int argc, char *argv[]) { cCDDBDisc cddb; cddb.Load(1,argv[1]); return 0; } #endif mp3-0.10.2/decoder-snd.h0100644000000000000000000000556710735452037013353 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DECODER_SND_H #define ___DECODER_SND_H #define DEC_SND DEC_ID('S','N','D',' ') #define DEC_SND_STR "SND" #ifdef HAVE_SNDFILE #include #include #include #include #include "decoder.h" #include "decoder-core.h" #define CDFS_MAGIC 0xCDDA // cdfs filesystem-ID class cDiscID; // ---------------------------------------------------------------- class cSndFile : public cFileInfo { private: SNDFILE *sf; // void Error(const char *action); public: SF_INFO sfi; // cSndFile(const char *Filename); ~cSndFile(); bool Open(bool log=true); void Close(void); sf_count_t Seek(sf_count_t frames=0, bool relativ=false); sf_count_t Stream(int *buffer, sf_count_t frames); }; // ---------------------------------------------------------------- class cSndInfo : public cSongInfo { private: cSndFile *file; cDiscID *id; bool keepOpen; // bool Abort(bool result); bool CDDBLookup(const char *filename); public: cSndInfo(cSndFile *File); ~cSndInfo(); bool DoScan(bool KeepOpen=false); }; // ---------------------------------------------------------------- class cSndDecoder : public cDecoder, public cThread { private: cSndFile file; cSndInfo info; struct Decode ds; struct mad_pcm *pcm; unsigned long long index; // cMutex buffMutex; cCondVar fgCond, bgCond; bool run, ready; int *framebuff, deferedN, softCount; // void Init(void); bool Clean(void); bool GetInfo(bool keepOpen); struct Decode *Done(eDecodeStatus status); protected: virtual void Action(void); public: cSndDecoder(const char *Filename); ~cSndDecoder(); virtual bool Valid(void); virtual cFileInfo *FileInfo(void); virtual cSongInfo *SongInfo(bool get); virtual cPlayInfo *PlayInfo(void); virtual bool Start(void); virtual bool Stop(void); virtual bool Skip(int Seconds, float bsecs); virtual struct Decode *Decode(void); }; // ---------------------------------------------------------------- #endif //HAVE_SNDFILE #endif //___DECODER_SND_H mp3-0.10.2/decoder.c0100644000000000000000000004462111304362771012554 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include "common.h" #include "data-mp3.h" #include "data-src.h" #include "decoder.h" #include "decoder-core.h" #include "decoder-mp3.h" #include "decoder-mp3-stream.h" #include "decoder-snd.h" #include "decoder-ogg.h" #include "decoder-ogg-stream.h" #define CACHEFILENAME "id3info.cache" #define CACHESAVETIMEOUT 120 // secs #define CACHEPURGETIMEOUT 120 // days extern cFileSources MP3Sources; cInfoCache InfoCache; char *cachedir=0; int MakeHashBuff(const char *buff, int len) { int h=len; while(len--) h=(h*13 + *buff++) & 0x7ff; return h; } // --- cStrConv ---------------------------------------------------------------- class cStrConv : private cMutex { private: cCharSetConv toSys; public: cStrConv(void):toSys("UTF-8",cCharSetConv::SystemCharacterTable()) {} char *ToSys(char *from); }; static cStrConv *strconv; char *cStrConv::ToSys(char *from) { if(from) { Lock(); const char *r=toSys.Convert(from); Unlock(); if(r!=from) { char *n=strdup(r); if(n) { free(from); return n; } } } return from; } // --- cSongInfo --------------------------------------------------------------- cSongInfo::cSongInfo(void) { Title=Artist=Album=0; Clear(); } cSongInfo::~cSongInfo() { Clear(); } void cSongInfo::Clear(void) { Frames=0; Total=-1; DecoderID=0; SampleFreq=Channels=Bitrate=MaxBitrate=ChMode=-1; free(Title); Title=0; free(Artist); Artist=0; free(Album); Album=0; Year=-1; Level=Peak=0.0; infoDone=false; utf8clean=true; } void cSongInfo::Set(cSongInfo *si, bool update) { if(!update || si->Utf8Clean()) { Clear(); Title=si->Title ? strdup(si->Title):0; Artist=si->Artist ? strdup(si->Artist):0; Album=si->Album ? strdup(si->Album):0; utf8clean=si->utf8clean; } Frames=si->Frames; Total=si->Total; SampleFreq=si->SampleFreq; Channels=si->Channels; Bitrate=si->Bitrate; MaxBitrate=si->MaxBitrate; ChMode=si->ChMode; Year=si->Year; if(si->Level>0.0) { // preserve old level Level=si->Level; Peak=si->Peak; } DecoderID=si->DecoderID; InfoDone(); } void cSongInfo::FakeTitle(const char *filename, const char *extention) { // if no title, try to build a reasonable from the filename if(!Title && filename) { const char *s=rindex(filename,'/'); if(s && *s=='/') { s++; Title=strdup(s); strreplace(Title,'_',' '); if(extention) { // strip given extention int l=strlen(Title)-strlen(extention); if(l>0 && !strcasecmp(Title+l,extention)) Title[l]=0; } else { // strip any extention char *e=rindex(Title,'.'); if(e && *e=='.' && strlen(e)<=5) *e=0; } d(printf("mp3: faking title '%s' from filename '%s'\n",Title,filename)) } } } void cSongInfo::ConvertToSys(void) { if(cCharSetConv::SystemCharacterTable()) { Title=strconv->ToSys(Title); Artist=strconv->ToSys(Artist); Album=strconv->ToSys(Album); utf8clean=false; } } // --- cFileInfo --------------------------------------------------------------- cFileInfo::cFileInfo(void) { Filename=FsID=0; Clear(); } cFileInfo::cFileInfo(const char *Name) { Filename=FsID=0; Clear(); Filename=strdup(Name); } cFileInfo::~cFileInfo() { Clear(); } void cFileInfo::Clear(void) { free(Filename); Filename=0; free(FsID); FsID=0; Filesize=0; CTime=0; FsType=0; removable=-1; infoDone=false; } bool cFileInfo::Removable(void) { if(removable<0 && Filename) { cFileSource *src=MP3Sources.FindSource(Filename); if(src) removable=src->NeedsMount(); else removable=1; } return (removable!=0); } void cFileInfo::Set(cFileInfo *fi) { Clear(); InfoDone(); Filename=fi->Filename ? strdup(fi->Filename):0; FsID=fi->FsID ? strdup(fi->FsID):0; Filesize=fi->Filesize; CTime=fi->CTime; } bool cFileInfo::FileInfo(bool log) { if(Filename) { struct stat64 ds; if(!stat64(Filename,&ds)) { if(S_ISREG(ds.st_mode)) { free(FsID); FsID=0; FsType=0; struct statfs64 sfs; if(!statfs64(Filename,&sfs)) { if(Removable()) FsID=aprintf("%llx:%llx",sfs.f_blocks,sfs.f_files); FsType=sfs.f_type; } else if(errno!=ENOSYS && log) { esyslog("ERROR: can't statfs %s: %s",Filename,strerror(errno)); } Filesize=ds.st_size; CTime=ds.st_ctime; #ifdef CDFS_MAGIC if(FsType==CDFS_MAGIC) CTime=0; // CDFS returns mount time as ctime #endif InfoDone(); return true; } else if(log) { esyslog("ERROR: %s is not a regular file",Filename); } } else if(log) { esyslog("ERROR: can't stat %s: %s",Filename,strerror(errno)); } } return false; } // --- cDecoders --------------------------------------------------------------- cDecoder *cDecoders::FindDecoder(cFileObj *Obj) { const char *full=Obj->FullPath(); cFileInfo fi(full); cCacheData *dat; cDecoder *decoder=0; if(fi.FileInfo(false) && (dat=InfoCache.Search(&fi))) { if(dat->DecoderID) { //d(printf("mp3: found DecoderID '%s' for %s from cache\n",cDecoders::ID2Str(dat->DecoderID),Filename)) switch(dat->DecoderID) { case DEC_MP3: decoder=new cMP3Decoder(full); break; case DEC_MP3S: decoder=new cMP3StreamDecoder(full); break; #ifdef HAVE_SNDFILE case DEC_SND: decoder=new cSndDecoder(full); break; #endif #ifdef HAVE_VORBISFILE case DEC_OGG: decoder=new cOggDecoder(full); break; case DEC_OGGS: decoder=new cOggStreamDecoder(full); break; #endif default: esyslog("ERROR: bad DecoderID '%s' from info cache: %s",cDecoders::ID2Str(dat->DecoderID),full); break; } } dat->Unlock(); } if(!decoder || !decoder->Valid()) { // no decoder in cache or cached decoder doesn't matches. // try to detect a decoder delete decoder; decoder=0; #ifdef HAVE_SNDFILE if(!decoder) { decoder=new cSndDecoder(full); if(!decoder || !decoder->Valid()) { delete decoder; decoder=0; } } #endif #ifdef HAVE_VORBISFILE if(!decoder) { decoder=new cOggDecoder(full); if(!decoder || !decoder->Valid()) { delete decoder; decoder=0; } } if(!decoder) { decoder=new cOggStreamDecoder(full); if(!decoder || !decoder->Valid()) { delete decoder; decoder=0; } } #endif if(!decoder) { decoder=new cMP3StreamDecoder(full); if(!decoder || !decoder->Valid()) { delete decoder; decoder=0; } } if(!decoder) { decoder=new cMP3Decoder(full); if(!decoder || !decoder->Valid()) { delete decoder; decoder=0; } } if(!decoder) esyslog("ERROR: no decoder found for %s",Obj->Name()); } return decoder; } const char *cDecoders::ID2Str(int id) { switch(id) { case DEC_MP3: return DEC_MP3_STR; case DEC_MP3S: return DEC_MP3S_STR; case DEC_SND: return DEC_SND_STR; case DEC_OGG: return DEC_OGG_STR; case DEC_OGGS: return DEC_OGGS_STR; } return 0; } int cDecoders::Str2ID(const char *str) { if (!strcmp(str,DEC_MP3_STR )) return DEC_MP3; else if(!strcmp(str,DEC_MP3S_STR)) return DEC_MP3S; else if(!strcmp(str,DEC_SND_STR )) return DEC_SND; else if(!strcmp(str,DEC_OGG_STR )) return DEC_OGG; else if(!strcmp(str,DEC_OGGS_STR)) return DEC_OGGS; return 0; } // --- cDecoder ---------------------------------------------------------------- cDecoder::cDecoder(const char *Filename) { filename=strdup(Filename); locked=0; urgentLock=playing=false; } cDecoder::~cDecoder() { free(filename); } void cDecoder::Lock(bool urgent) { locklock.Lock(); if(urgent && locked) urgentLock=true; // signal other locks to release quickly locked++; locklock.Unlock(); // don't hold the "locklock" when locking "lock", may cause a deadlock lock.Lock(); urgentLock=false; } void cDecoder::Unlock(void) { locklock.Lock(); locked--; lock.Unlock(); locklock.Unlock(); } bool cDecoder::TryLock(void) { bool res=false; locklock.Lock(); if(!locked && !playing) { Lock(); res=true; } locklock.Unlock(); return res; } // --- cCacheData ----------------------------------------------------- cCacheData::cCacheData(void) { touch=0; version=0; } void cCacheData::Touch(void) { touch=time(0); } #define SECS_PER_DAY (24*60*60) bool cCacheData::Purge(void) { time_t now=time(0); //XXX does this realy made sense? //if(touch+CACHEPURGETIMEOUT*SECS_PER_DAY < now) { // d(printf("cache: purged: timeout %s\n",Filename)) // return true; // } if(touch+CACHEPURGETIMEOUT*SECS_PER_DAY/10 < now) { if(!Removable()) { // is this a permant source? struct stat64 ds; // does the file exists? if not, purge if(stat64(Filename,&ds) || !S_ISREG(ds.st_mode) || access(Filename,R_OK)) { d(printf("cache: purged: file not found %s\n",Filename)) return true; } } } return false; } bool cCacheData::Check8bit(const char *str) { if(str) while(*str) if(*str++ & 0x80) return true; return false; } bool cCacheData::Upgrade(void) { if(version<8) { if(Check8bit(Title) || Check8bit(Artist) || Check8bit(Album)) return false; // Trash entries not 7bit clean } if(version<7) { if(DecoderID==DEC_SND || (Title && startswith(Title,"track-"))) return false; // Trash older SND entries (incomplete) if(Removable()) { if(!FsID) FsID=strdup("old"); // Dummy entry, will be replaced in InfoCache::Search() } else { free(FsID); FsID=0; } } if(version<4) { Touch(); // Touch entry } if(version<3 && !Title) { FakeTitle(Filename,".mp3"); // Fake title } if(version<2 && Bitrate<=0) { return false; // Trash entry without bitrate } return true; } void cCacheData::Create(cFileInfo *fi, cSongInfo *si, bool update) { cFileInfo::Set(fi); cSongInfo::Set(si,update); hash=MakeHash(Filename); Touch(); } bool cCacheData::Save(FILE *f) { fprintf(f,"##BEGIN\n" "Filename=%s\n" "Filesize=%lld\n" "Timestamp=%ld\n" "Touch=%ld\n" "Version=%d\n" "Frames=%d\n" "Total=%d\n" "SampleFreq=%d\n" "Channels=%d\n" "Bitrate=%d\n" "MaxBitrate=%d\n" "ChMode=%d\n" "Year=%d\n" "Level=%.4f\n" "Peak=%.4f\n", Filename,Filesize,CTime,touch,CACHE_VERSION,Frames,Total,SampleFreq,Channels,Bitrate,MaxBitrate,ChMode,Year,Level,Peak); if(Title) fprintf(f,"Title=%s\n" ,Title); if(Artist) fprintf(f,"Artist=%s\n" ,Artist); if(Album) fprintf(f,"Album=%s\n" ,Album); if(DecoderID) fprintf(f,"DecoderID=%s\n",cDecoders::ID2Str(DecoderID)); if(FsID) fprintf(f,"FsID=%s\n" ,FsID); fprintf(f,"##END\n"); return ferror(f)==0; } bool cCacheData::Load(FILE *f) { static const char delimiters[] = { "=\n" }; char buf[1024]; cFileInfo::Clear(); cSongInfo::Clear(); while(fgets(buf,sizeof(buf),f)) { char *ptrptr; char *name =strtok_r(buf ,delimiters,&ptrptr); char *value=strtok_r(0,delimiters,&ptrptr); if(name) { if(!strcasecmp(name,"##END")) break; if(value) { if (!strcasecmp(name,"Filename")) Filename =strdup(value); else if(!strcasecmp(name,"Filesize") || !strcasecmp(name,"Size")) Filesize =atoll(value); else if(!strcasecmp(name,"FsID")) FsID =strdup(value); else if(!strcasecmp(name,"Timestamp")) CTime =atol(value); else if(!strcasecmp(name,"Touch")) touch =atol(value); else if(!strcasecmp(name,"Version")) version =atoi(value); else if(!strcasecmp(name,"DecoderID")) DecoderID =cDecoders::Str2ID(value); else if(!strcasecmp(name,"Frames")) Frames =atoi(value); else if(!strcasecmp(name,"Total")) Total =atoi(value); else if(!strcasecmp(name,"SampleFreq")) SampleFreq=atoi(value); else if(!strcasecmp(name,"Channels")) Channels =atoi(value); else if(!strcasecmp(name,"Bitrate")) Bitrate =atoi(value); else if(!strcasecmp(name,"MaxBitrate")) MaxBitrate=atoi(value); else if(!strcasecmp(name,"ChMode")) ChMode =atoi(value); else if(!strcasecmp(name,"Year")) Year =atoi(value); else if(!strcasecmp(name,"Title")) Title =strdup(value); else if(!strcasecmp(name,"Artist")) Artist =strdup(value); else if(!strcasecmp(name,"Album")) Album =strdup(value); else if(!strcasecmp(name,"Level")) Level =atof(value); else if(!strcasecmp(name,"Peak")) Peak =atof(value); else d(printf("cache: ignoring bad token '%s' from cache file\n",name)) } } } if(ferror(f) || !Filename) return false; hash=MakeHash(Filename); return true; } // --- cInfoCache ---------------------------------------------------- cInfoCache::cInfoCache(void) { lasttime=0; modified=false; lastpurge=time(0)-(50*60); } void cInfoCache::Shutdown(void) { Cancel(10); Save(true); } void cInfoCache::Cache(cSongInfo *info, cFileInfo *file) { lock.Lock(); cCacheData *dat=Search(file); if(dat) { dat->Create(file,info,true); Modified(); dat->Unlock(); d(printf("cache: updating infos for %s\n",file->Filename)) } else { dat=new cCacheData; dat->Create(file,info,false); AddEntry(dat); d(printf("cache: caching infos for %s\n",file->Filename)) } lock.Unlock(); } cCacheData *cInfoCache::Search(cFileInfo *file) { int hash=MakeHash(file->Filename); lock.Lock(); cCacheData *dat=FirstEntry(hash); while(dat) { if(dat->hash==hash && !strcmp(dat->Filename,file->Filename) && dat->Filesize==file->Filesize) { dat->Lock(); if(file->FsID && dat->FsID && !strcmp(dat->FsID,"old")) { // duplicate FsID for old entries dat->FsID=strdup(file->FsID); dat->Touch(); Modified(); //d(printf("adding FsID for %s\n",dat->Filename)) } if((!file->FsID && !dat->FsID) || (file->FsID && dat->FsID && !strcmp(dat->FsID,file->FsID))) { //d(printf("cache: found cache entry for %s\n",dat->Filename)) dat->Touch(); Modified(); if(dat->CTime!=file->CTime) { d(printf("cache: ctime differs, removing from cache: %s\n",dat->Filename)) DelEntry(dat); dat=0; } break; } dat->Unlock(); } dat=(cCacheData *)dat->Next(); } lock.Unlock(); return dat; } void cInfoCache::AddEntry(cCacheData *dat) { lists[dat->hash%CACHELINES].Add(dat); Modified(); } void cInfoCache::DelEntry(cCacheData *dat) { dat->Lock(); lists[dat->hash%CACHELINES].Del(dat); Modified(); } cCacheData *cInfoCache::FirstEntry(int hash) { return lists[hash%CACHELINES].First(); } bool cInfoCache::Purge(void) { time_t now=time(0); if(now-lastpurge>(60*60)) { isyslog("cleaning up id3 cache"); Start(); lastpurge=now; } return Active(); } void cInfoCache::Action(void) { d(printf("cache: id3 cache purge thread started (pid=%d)\n",getpid())) if(nice(3)<0); lock.Lock(); for(int i=0,n=0 ; iNext(); if(dat->Purge()) DelEntry(dat); dat=ndat; if(++n>30) { lastmod=false; n=0; lock.Unlock(); lock.Lock(); // give concurrent thread an access chance if(lastmod) dat=FirstEntry(i); // restart line, if cache changed meanwhile } } } lock.Unlock(); d(printf("cache: id3 cache purge thread ended (pid=%d)\n",getpid())) } char *cInfoCache::CacheFile(void) { return AddPath(cachedir?cachedir:VideoDirectory,CACHEFILENAME); } void cInfoCache::Save(bool force) { if(modified && (force || (!Purge() && time(0)>lasttime))) { char *name=CacheFile(); cSafeFile f(name); free(name); if(f.Open()) { lock.Lock(); fprintf(f,"## This is a generated file. DO NOT EDIT!!\n" "## This file will be OVERWRITTEN WITHOUT WARNING!!\n"); for(int i=0 ; iSave(f)) { i=CACHELINES+1; break; } dat=(cCacheData *)dat->Next(); } } lock.Unlock(); f.Close(); modified=false; lasttime=time(0)+CACHESAVETIMEOUT; d(printf("cache: saved cache to file\n")) } } } void cInfoCache::Load(void) { if(!strconv) strconv=new cStrConv; char *name=CacheFile(); if(access(name,F_OK)==0) { isyslog("loading id3 cache from %s",name); FILE *f=fopen(name,"r"); if(f) { char buf[256]; bool mod=false; lock.Lock(); for(int i=0 ; iLoad(f)) { if(dat->version!=CACHE_VERSION) { if(dat->Upgrade()) mod=true; else { delete dat; continue; } } AddEntry(dat); } else { delete dat; if(ferror(f)) { esyslog("ERROR: failed to load id3 cache"); break; } } } } lock.Unlock(); fclose(f); modified=false; if(mod) Modified(); } else LOG_ERROR_STR(name); } free(name); } mp3-0.10.2/decoder.h0100644000000000000000000001016611144545240012552 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DECODER_H #define ___DECODER_H #include #include // ---------------------------------------------------------------- class cCacheData; class cFileObj; extern int MakeHashBuff(const char *buff, int len); #define MakeHash(str) MakeHashBuff((str),strlen(str)) // ---------------------------------------------------------------- class cSongInfo { private: bool infoDone, utf8clean; protected: void Clear(void); void Set(cSongInfo *si, bool update=false); void FakeTitle(const char *filename, const char *extention=0); void InfoDone(void) { infoDone=true; } public: cSongInfo(void); ~cSongInfo(); bool HasInfo(void) { return infoDone; } bool Utf8Clean(void) { return utf8clean; } void ConvertToSys(void); // Song char *Title, *Artist, *Album; int Year, Frames, Total; int SampleFreq, Channels, Bitrate, MaxBitrate, ChMode; // Normalize double Level, Peak; // Decoder int DecoderID; }; // ---------------------------------------------------------------- class cFileInfo { private: bool infoDone; int removable; protected: void Clear(void); void Set(cFileInfo *fi); void InfoDone(void) { infoDone=true; } public: cFileInfo(void); cFileInfo(const char *Name); ~cFileInfo(); bool FileInfo(bool log=true); bool HasInfo(void) { return infoDone; } bool Removable(void); // char *Filename, *FsID; unsigned long long Filesize; time_t CTime; long FsType; }; // ---------------------------------------------------------------- class cPlayInfo { public: int Index, Total; }; // ---------------------------------------------------------------- class cDecoder { protected: char *filename; cMutex lock, locklock; int locked; bool urgentLock; // cPlayInfo pi; bool playing; // void Lock(bool urgent=false); void Unlock(void); bool TryLock(void); public: cDecoder(const char *Filename); virtual ~cDecoder(); // virtual cFileInfo *FileInfo(void) { return 0; } virtual cSongInfo *SongInfo(bool get) { return 0; } virtual cPlayInfo *PlayInfo(void) { return 0; } // virtual bool Valid(void)=0; virtual bool IsStream(void) { return false; } virtual bool Start(void)=0; virtual bool Stop(void)=0; virtual bool Skip(int Seconds, float bsecs) { return false; } virtual struct Decode *Decode(void)=0; }; // ---------------------------------------------------------------- class cDecoders { public: static cDecoder *FindDecoder(cFileObj *Obj); static const char *ID2Str(int id); static int Str2ID(const char *str); }; // ---------------------------------------------------------------- #define CACHELINES 32 class cInfoCache : public cThread { private: cMutex lock; cList lists[CACHELINES]; time_t lasttime, lastpurge; bool modified, lastmod; // char *CacheFile(void); void AddEntry(cCacheData *dat); void DelEntry(cCacheData *dat); cCacheData *FirstEntry(int hash); void Modified(void) { modified=lastmod=true; } protected: virtual void Action(void); public: cInfoCache(void); void Shutdown(void); void Save(bool force=false); void Load(void); bool Purge(void); void Cache(cSongInfo *info, cFileInfo *file); cCacheData *Search(cFileInfo *file); }; extern cInfoCache InfoCache; extern char *cachedir; #endif //___DECODER_H mp3-0.10.2/examples/0040755000000000000000000000000011307500171012604 5ustar rootrootmp3-0.10.2/examples/image_convert.sh.example0100644000000000000000000000331410735452037017425 0ustar rootroot#!/bin/bash # # requires: ...topnm, pnmscale, pnmcomp, ppmntsc, ppmtoy4m, mpeg2enc # # video format. pal or ntsc FORMAT=pal # target image width/height (taking into account visible screen area) if [ "$FORMAT" = "ntsc" ]; then TW=600 TH=420 else TW=632 TH=512 fi TMP=/tmp/image_convert.$$.pnm IMG=$1 MPG=$2 DIR=`dirname "$MPG"` if [ ! -d "$DIR" ]; then mkdir -p "$DIR" fi # # get the file type and set the according converter to PNM # FILE_TYPE=`file -i -L -b "$IMG" 2>/dev/null | cut -f2 -d/` case "$FILE_TYPE" in jpg | jpeg) TO_PNM=jpegtopnm ;; tiff) TO_PNM=tifftopnm ;; bmp | x-bmp) TO_PNM=bmptoppm ;; png | x-png) TO_PNM=pngtopnm ;; Netpbm | pnm | x-portable-pixmap) TO_PNM=cat ;; gif) TO_PNM=giftopnm ;; *) echo "filetype '$FILE_TYPE' is not supported" exit 1 ;; esac # # 'chroma subsampling mode' mjpegtools >= 1.8.0 # SUBSAMPLINGMODE="" if ppmtoy4m -h | egrep -q "'420mpeg2'"; then SUBSAMPLINGMODE="-S 420mpeg2" fi # # extract the image size & compute scale value # LANG=C # get the decimal point right $TO_PNM "$IMG" >$TMP 2>/dev/null S=`pnmfile $TMP | awk '{ printf "%d %d ",$4,$6 }'` S=`echo $S $TW $TH | awk '{ sw=$3/$1; sh=$4/$2; s=(sw1)?1.0:s; }'` # # now run the conversion # if [ "$FORMAT" = "ntsc" ]; then pnmscale $S $TMP | \ pnmpad -black -width 704 -height 480 | \ ppmntsc | \ ppmtoy4m -v 0 -n 1 -r -F 30000:1001 $SUBSAMPLINGMODE | \ mpeg2enc -f 7 -T 90 -F 4 -nn -a 2 -v 0 -o "$MPG" else pnmscale $S $TMP | \ pnmpad -black -width 704 -height 576 | \ ppmntsc --pal | \ ppmtoy4m -v 0 -n 1 -r -F 25:1 $SUBSAMPLINGMODE | \ mpeg2enc -f 7 -T 90 -F 3 -np -a 2 -v 0 -o "$MPG" fi # # cleanup # rm $TMP mp3-0.10.2/examples/mount.sh.example0100644000000000000000000000135410735452037015747 0ustar rootroot#!/bin/bash # # This script is called from VDR to mount/unmount/eject # the sources for MP3 play. # # argument 1: wanted action, one of mount,unmount,eject,status # argument 2: mountpoint to act on # # mount,unmount,eject must return 0 if succeeded, 1 if failed # status must return 0 if device is mounted, 1 if not # action="$1" path="$2" case "$action" in mount) eject -t "$path" || exit 1 # close the tray mount "$path" || exit 1 # mount it ;; unmount) umount "$path" || exit 1 # unmount it ;; eject) eject "$path" || exit 1 # eject disk ;; status) cat /proc/mounts | grep -q "$path" # check if mounted if [ $? -ne 0 ]; then # not mounted ... exit 1 fi esac exit 0 mp3-0.10.2/examples/mp3sources.conf.example0100644000000000000000000000015710735452037017223 0ustar rootroot/mp3;Locale Platte;0;*.mp3/*.ogg/*.wav /mnt/nfs/mp3;Remote NFS;0 /mnt/cdrom;CDROM;1 /mnt/cdfs;CD-Audio;1;*.wav mp3-0.10.2/examples/mplayer.sh.example0100644000000000000000000000212311270457040016243 0ustar rootroot#!/bin/bash # # This script is called from VDR to start MPlayer # # argument 1: the file to play # argument 2: (optional) the phrase SLAVE if SlaveMode is enabled # argument 3: (optional) the phrase AID x to select audio stream x # where to find mplayer MPLAYER="mplayer" # mplayer options, -vc will be added below # add "-lircconf " to enable LIRC support OPTS="-vo mpegpes" if [ "aa$DVB_DEVICE" != "aa" ]; then OPTS="-vo mpegpes:card=$DVB_DEVICE -ao mpegpes:card=$DVB_DEVICE" fi # mplayer options for SlaveMode SLAVE="-slave -quiet -nolirc" ##################### FILE=$1 case "$FILE" in *.pls | *.m3u) popt="-playlist" first=`grep -v -m1 "^#" $FILE` type=`file "$first"` ;; *) type=`file "$FILE"` ;; esac while shift; do if [ "$1" = "SLAVE" ]; then sopt=$SLAVE elif [ "$1" = "AID" ]; then aopt="-aid $2" shift fi done case "$type" in *AVI*) VC="ffdivx" ;; *MPEG*) VC="mpegpes" ;; *) echo "Unknown video file format $type" echo "Edit mplayer.sh to support this file type" exit 1 ;; esac exec $MPLAYER $OPTS -vc $VC $sopt $aopt $popt "$FILE" mp3-0.10.2/examples/network.sh.example0100644000000000000000000000034710735452037016277 0ustar rootroot#!/bin/bash # # This script is called from VDR before & after network access # # argument 1: wanted action, one of up,down # action="$1" case "$action" in up) echo "starting dialin" ;; down) echo "hangup" ;; esac exit 0 mp3-0.10.2/i18n-template.c0100644000000000000000000000043010735452037013527 0ustar rootroot/* * Auto generated file, do not edit * Will be overwritten/deleted without warning * * Edit the .po files if you want to update translations!! */ #include "i18n.h" #if VDRVERSNUM < 10507 const tI18nPhrase Phrases[] = { // START I18N // END I18N { NULL } }; #endif mp3-0.10.2/i18n.h0100644000000000000000000000225710735452037011734 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2007 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___I18N_H #define ___I18N_H #include extern const char *i18n_name; #if APIVERSNUM < 10507 extern const tI18nPhrase Phrases[]; #endif #undef tr #define tr(s) I18nTranslate(s, i18n_name) #ifndef trNOOP #define trNOOP(s) (s) #endif #ifndef trVDR #define trVDR(s) tr(s) #endif #endif //___I18N_H mp3-0.10.2/menu-async.h0100644000000000000000000000247110735452037013232 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___MENU_ASYNC_H #define ___MENU_ASYNC_H #include // ---------------------------------------------------------------- class cAsyncStatus : private cMutex { private: const char *text; bool changed; public: cAsyncStatus(void); ~cAsyncStatus(); void Set(const char *Text); bool Changed(void) { return changed; } const char *Begin(void); void Finish(void); }; extern cAsyncStatus asyncStatus; #endif //___MENU_ASYNC_H mp3-0.10.2/menu.c0100644000000000000000000002116711242240773012111 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include "common.h" #include "menu.h" #include "data.h" #include "data-src.h" #include "i18n.h" // ----------------------------------------------------------------------------- void Status(const char *text) { Skins.Message(mtStatus,text); } void Error(const char *text) { Skins.Message(mtError,text); } void Info(const char *text) { Skins.Message(mtInfo,text); } // --- cMenuBrowseItem --------------------------------------------------------- class cMenuBrowseItem : public cOsdItem { private: cFileObj *item; virtual void Set(void); public: cMenuBrowseItem(cFileObj *Item); cFileObj *Item(void) { return item; } }; cMenuBrowseItem::cMenuBrowseItem(cFileObj *Item) { item = Item; Set(); } void cMenuBrowseItem::Set(void) { char *buffer=aprintf(item->Type()==otFile?"%s":"[%s]",item->Name()); SetText(buffer,false); } // --- cMenuBrowse ------------------------------------------------------ cFileObj *cMenuBrowse::lastselect=0; cMenuBrowse::cMenuBrowse(cFileSource *Source, bool Dirselect, bool WithID3, const char *title, const char * const *Excl) :cOsdMenu(title) { currentdir=parent=0; delete lastselect; lastselect=0; list=new cDirList; dirselectable=Dirselect; withID3=WithID3; excl=Excl; SetSource(Source); NewDir(currentdir); } cMenuBrowse::~cMenuBrowse() { free(parent); free(currentdir); delete list; } cFileObj *cMenuBrowse::CurrentItem(void) { cMenuBrowseItem *item = (cMenuBrowseItem *)Get(Current()); return item ? item->Item():0; } void cMenuBrowse::SetButtons(void) { SetHelp(tr("Select"), currentdir?tr("Parent"):0, 0, withID3?tr("ID3 info"):0); Display(); } void cMenuBrowse::SetSource(cFileSource *Source) { source=Source; free(currentdir); currentdir=0; free(parent); parent=0; source->GetRemember(currentdir,parent); } bool cMenuBrowse::LoadDir(const char *dir) { Clear(); Status(tr("Scanning directory...")); bool res=list->Load(source,dir,excl); if(res) { cFileObj *item=list->First(); while(item) { Add(new cMenuBrowseItem(item),(parent && !strcmp(item->Name(),parent))); item=list->Next(item); } } Status(0); return res; } bool cMenuBrowse::NewDir(const char *dir) { char *ncur=dir ? strdup(dir):0; bool r=LoadDir(ncur); if(!r && ncur) { free(ncur); ncur=0; r=LoadDir(ncur); } if(r) { free(currentdir); currentdir=ncur; cFileObj *item=CurrentItem(); source->SetRemember(currentdir,item?item->Name():0); SetButtons(); return true; } free(ncur); Error(tr("Error scanning directory!")); return false; } eOSState cMenuBrowse::Parent(void) { eOSState res=osContinue; if(currentdir) { free(parent); char *ss=strrchr(currentdir,'/'); if(ss) { *ss++=0; parent=strdup(ss); ss=currentdir; } else parent=strdup(currentdir); if(!NewDir(ss)) res=osEnd; } return res; } eOSState cMenuBrowse::Select(bool isred) { eOSState res=osContinue; cFileObj *item; if((item=CurrentItem())) { switch(item->Type()) { case otParent: if(!isred || !dirselectable) res=Parent(); break; case otDir: if(!isred || !dirselectable) { if(!NewDir(item->Path())) res=osEnd; break; } // fall through to otFile case otFile: lastselect=new cFileObj(item); res=osBack; break; default: break; } } return res; } eOSState cMenuBrowse::ID3Info(void) { return osContinue; } eOSState cMenuBrowse::ProcessStdKey(eKeys Key, eOSState state) { if(state==osUnknown) { switch (Key) { case kOk: state=Select(false); break; case kRed: state=Select(true); break; case kGreen: state=Parent(); break; case kBlue: if(withID3) state=ID3Info(); break; //case kMenu: state=osEnd; break; default: break; } } if(state==osEnd || state==osBack) { cFileObj *item=CurrentItem(); if(item) source->SetRemember(currentdir,item->Name()); } return state; } // --- cMenuSourceItem ---------------------------------------------------------- class cMenuSourceItem : public cOsdItem { private: cFileSource *source; virtual void Set(void); public: cMenuSourceItem(cFileSource *Source); cFileSource *Source(void) { return source; } }; cMenuSourceItem::cMenuSourceItem(cFileSource *Source) { source=Source; Set(); } void cMenuSourceItem::Set(void) { char *buffer=aprintf("%s\t%s\t%s", source->NeedsMount()?(source->Status()?"*":">"):"", source->Description(), source->BaseDir()); SetText(buffer,false); } // --- cMenuSource -------------------------------------------------- cFileSource *cMenuSource::selected=0; cMenuSource::cMenuSource(cFileSources *Sources, const char *title) :cOsdMenu(title,2,20) { selected=0; current=Sources->GetSource(); cFileSource *source=Sources->First(); while(source) { cOsdMenu::Add(new cMenuSourceItem(source),source==current); source=Sources->Next(source); } SetHelp(tr("Select"), tr("Mount"), tr("Unmount"), tr("Eject")); Display(); } bool cMenuSource::DoMount(cFileSource *src) { bool res=src->Mount(); RefreshCurrent(); DisplayCurrent(true); return res; } bool cMenuSource::CheckMount(void) { cFileSource *src=selected ? selected:current; if(src->NeedsMount() && !src->Status()) { Error(tr("Selected source is not mounted!")); return false; } return true; } eOSState cMenuSource::Select(void) { if(HasSubMenu() || Count() == 0) return osContinue; cFileSource *src = ((cMenuSourceItem *)Get(Current()))->Source(); if(src->NeedsMount() && !src->Status()) { if(!DoMount(src)) Error(tr("Mount failed!")); } if(!src->NeedsMount() || src->Status()) { selected=src; return osBack; } return osContinue; } eOSState cMenuSource::Mount(void) { if(HasSubMenu() || Count() == 0) return osContinue; cFileSource *src = ((cMenuSourceItem *)Get(Current()))->Source(); if(src->NeedsMount() && !src->Status()) { if(DoMount(src)) Info(tr("Mount succeeded")); else Error(tr("Mount failed!")); } return osContinue; } eOSState cMenuSource::Unmount(void) { if(HasSubMenu() || Count() == 0) return osContinue; cFileSource *src = ((cMenuSourceItem *)Get(Current()))->Source(); if(src->NeedsMount() && src->Status()) { bool res=src->Unmount(); RefreshCurrent(); DisplayCurrent(true); if(res) Info(tr("Unmount succeeded")); else Error(tr("Unmount failed!")); } return osContinue; } eOSState cMenuSource::Eject(void) { if(HasSubMenu() || Count() == 0) return osContinue; cFileSource *src = ((cMenuSourceItem *)Get(Current()))->Source(); if(src->NeedsMount()) { bool res=src->Eject(); RefreshCurrent(); DisplayCurrent(true); if(!res) Error(tr("Eject failed!")); } return osContinue; } eOSState cMenuSource::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if(state==osBack && !CheckMount()) state=osContinue; if(state==osUnknown) { switch(Key) { case kOk: case kRed: return Select(); case kGreen: return Mount(); case kYellow: return Unmount(); case kBlue: return Eject(); case kMenu: CheckMount(); return osEnd; default: break; } } return state; } // --- cProgressBar ------------------------------------------------------------ cProgressBar::cProgressBar(int Width, int Height, int Current, int Total) :cBitmap(Width, Height, 2) { if(Total > 0) { int p = Current * Width / Total;; DrawRectangle(0, 0, p, Height - 1, clrGreen); DrawRectangle(p + 1, 0, Width - 1, Height - 1, clrWhite); } } mp3-0.10.2/menu.h0100644000000000000000000000534711141751117012115 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___MENU_H #define ___MENU_H #include "common.h" #include // ---------------------------------------------------------------- void Status(const char *text); void Error(const char *text); void Info(const char *text); // ---------------------------------------------------------------- class cFileSources; class cFileSource; class cFileObj; class cDirList; // ---------------------------------------------------------------- class cMenuBrowse : public cOsdMenu { private: eOSState Select(bool isred); eOSState Parent(void); bool LoadDir(const char *dir); protected: static cFileObj *lastselect; // cDirList *list; cFileSource *source; bool dirselectable, withID3; char *currentdir, *parent; const char * const *excl; // bool NewDir(const char *dir); void SetSource(cFileSource *Source); cFileObj *CurrentItem(void); virtual void SetButtons(void); virtual eOSState ID3Info(void); virtual eOSState ProcessStdKey(eKeys Key, eOSState state); public: cMenuBrowse(cFileSource *Source, bool Dirselect, bool WithID3, const char *title, const char * const *Excl); ~cMenuBrowse(); static cFileObj *GetSelected(void) { return lastselect; } }; // ---------------------------------------------------------------- class cMenuSource : public cOsdMenu { private: static cFileSource *selected; cFileSource *current; // eOSState Mount(void); eOSState Unmount(void); eOSState Eject(void); eOSState Select(void); bool DoMount(cFileSource *src); bool CheckMount(void); public: cMenuSource(cFileSources *Sources, const char *title); virtual eOSState ProcessKey(eKeys Key); static cFileSource *GetSelected(void) { return selected; } }; // ---------------------------------------------------------------- class cProgressBar : public cBitmap { public: cProgressBar(int Width, int Height, int Current, int Total); }; #endif //___MENU_H mp3-0.10.2/mp3.c0100644000000000000000000014160211304361717011642 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include "common.h" #include #include #include #include #include #include "setup.h" #include "setup-mp3.h" #include "data-mp3.h" #include "data-src.h" #include "player-mp3.h" #include "menu.h" #include "menu-async.h" #include "decoder.h" #include "i18n.h" #include "version.h" #include "service.h" #ifdef DEBUG #include #endif const char *sourcesSub=0; cFileSources MP3Sources; static const char *plugin_name=0; const char *i18n_name=0; // --- cMenuSetupMP3 -------------------------------------------------------- class cMenuSetupMP3 : public cMenuSetupPage { private: cMP3Setup data; // const char *cddb[3], *disp[2], *scan[3], *bgr[3]; const char *aout[AUDIOOUTMODES]; int amode, amodes[AUDIOOUTMODES]; protected: virtual void Store(void); public: cMenuSetupMP3(void); }; cMenuSetupMP3::cMenuSetupMP3(void) { static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789-_" }; int numModes=0; aout[numModes]=trVDR("DVB"); amodes[numModes]=AUDIOOUTMODE_DVB; numModes++; #ifdef WITH_OSS aout[numModes]=tr("OSS"); amodes[numModes]=AUDIOOUTMODE_OSS; numModes++; #endif data=MP3Setup; amode=0; for(int i=0; iHalt(); mgr->Flush(); //XXX remove later } bool cMP3Control::SetPlayList(cPlayList *plist) { bool res; cControl *control=cControl::Control(); // is there a running MP3 player? if(control && typeid(*control)==typeid(cMP3Control)) { // add songs to running playlist if(!MP3Setup.EnqueueSongs) mgr->Flush(); mgr->Add(plist); res=true; } else { mgr->Flush(); mgr->Add(plist); cControl::Launch(new cMP3Control); res=false; } delete plist; return res; } void cMP3Control::ShowTimed(int Seconds) { if(!visible) { ShowProgress(true); timeoutShow=(Seconds>0) ? time(0)+Seconds : 0; } } void cMP3Control::Hide(void) { HideStatus(); timeoutShow=0; if(visible) { delete osd; osd=0; delete disp; disp=0; visible=bigwin=false; #if APIVERSNUM >= 10500 SetNeedsFastResponse(false); #else needsFastResponse=false; #endif } } void cMP3Control::ShowStatus(bool force) { if((asyncStatus.Changed() || (force && !statusActive)) && !jumpactive) { const char *text=asyncStatus.Begin(); if(text) { if(MP3Setup.ReplayDisplay || !osd) { if(statusActive) Skins.Message(mtStatus,0); Skins.Message(mtStatus,text); } else { if(!statusActive) osd->SaveRegion(0,bh-2*fh,bw-1,bh-fh-1); osd->DrawText(0,bh-2*fh,text,clrBlack,clrCyan,font,bw,fh,taCenter); osd->Flush(); } statusActive=true; } else HideStatus(); asyncStatus.Finish(); } } void cMP3Control::HideStatus(void) { if(statusActive) { if(MP3Setup.ReplayDisplay || !osd) Skins.Message(mtStatus,0); else { osd->RestoreRegion(); osd->Flush(); } } statusActive=false; } #define CTAB 11 // some tabbing values for the progress display #define CTAB2 5 void cMP3Control::Write(int x, int y, int w, const char *text, int fg, int bg) { if(osd) { x*=fw; if(x<0) x+=bw; y*=fh; if(y<0) y+=bh; osd->DrawText(x,y,text,fg,bg,font,w*fw); } } void cMP3Control::Fill(int x, int y, int w, int h, int fg) { if(osd) { x*=fw; if(x<0) x+=bw; y*=fh; if(y<0) y+=bh; osd->DrawRectangle(x,y,x+w*fw-1,y+h*fh-1,fg); } } void cMP3Control::Flush(void) { if(MP3Setup.ReplayDisplay) Skins.Flush(); else if(osd) osd->Flush(); } void cMP3Control::ShowProgress(bool open, bool bigWin) { int index, total; if(player->GetIndex(index,total) && total>=0) { if(!visible && open) { HideStatus(); if(MP3Setup.ReplayDisplay) { disp=Skins.Current()->DisplayReplay(false); if(!disp) return; bigWin=false; } else { int bt, bp; fw=font->Width(' ')*2; fh=font->Height(); if(bigWin) { bw=Setup.OSDWidth; bh=Setup.OSDHeight; bt=0; bp=2*fh; rows=(bh-bp-fh/3)/fh; } else { bw=Setup.OSDWidth; bh=bp=2*fh; bt=Setup.OSDHeight-bh; rows=0; } bwc=bw/fw+1; //d(printf("mp3: bw=%d bh=%d bt=%d bp=%d bwc=%d rows=%d fw=%d fh=%d\n", // bw,bh,bt,bp,bwc,rows,fw,fh)) osd=cOsdProvider::NewOsd(Setup.OSDLeft,Setup.OSDTop+bt); if(!osd) return; if(bigWin) { tArea Areas[] = { { 0,0,bw-1,bh-bp-1,2 }, { 0,bh-bp,bw-1,bh-1,4 } }; osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea)); } else { tArea Areas[] = { { 0,0,bw-1,bh-1,4 } }; osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea)); } osd->DrawRectangle(0,0,bw-1,bh-1,clrGray50); osd->Flush(); } ShowStatus(true); bigwin=bigWin; visible=true; #if APIVERSNUM >= 10500 SetNeedsFastResponse(true); #else needsFastResponse=true; #endif fliptime=listtime=0; flipint=0; flip=-1; top=lastTop=-1; lastIndex=lastTotal=-1; delete lastMode; lastMode=0; } cMP3PlayInfo *mode=new cMP3PlayInfo; bool valid=mgr->Info(-1,mode); bool changed=(!lastMode || mode->Hash!=lastMode->Hash); if(changed) { d(printf("mp3-ctrl: mode change detected\n")) } if(valid) { // send progress to status monitor if(changed || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle) cStatus::MsgReplaying(this,cString::sprintf("[%c%c] (%d/%d) %s",mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,*TitleArtist(mode->Title,mode->Artist)),mode->Filename[0]?mode->Filename:0,true); } if(visible) { // refresh the OSD progress display bool flush=false; if(MP3Setup.ReplayDisplay) { if(!statusActive) { if(total>0) disp->SetProgress(index,total); disp->SetCurrent(IndexToHMSF(index)); disp->SetTotal(IndexToHMSF(total)); bool Play, Forward; int Speed; if(GetReplayMode(Play,Forward,Speed)) disp->SetMode(Play, Forward, Speed); flush=true; } } else { if(!selecting && changed && !statusActive) { Write(0,-2,CTAB,cString::sprintf("(%d/%d)",mode->Num,mode->MaxNum)); flush=true; } if(!lastMode || mode->Loop!=lastMode->Loop) { if(mode->Loop) Write(-4,-1,0,"L",clrBlack,clrYellow); else Fill(-4,-1,2,1,clrGray50); flush=true; } if(!lastMode || mode->Shuffle!=lastMode->Shuffle) { if(mode->Shuffle) Write(-2,-1,0,"S",clrWhite,clrRed); else Fill(-2,-1,2,1,clrGray50); flush=true; } index/=framesPerSecond; total/=framesPerSecond; if(index!=lastIndex || total!=lastTotal) { if(total>0) { cProgressBar ProgressBar(bw-(CTAB+CTAB2)*fw,fh,index,total); osd->DrawBitmap(CTAB*fw,bh-fh,ProgressBar); } Write(0,-1,11,cString::sprintf(total?"%02d:%02d/%02d:%02d":"%02d:%02d",index/60,index%60,total/60,total%60)); flush=true; } } if(!jumpactive) { bool doflip=false; if(MP3Setup.ReplayDisplay && (!lastMode || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle)) doflip=true; if(!valid || changed) { fliptime=time(0); flip=0; doflip=true; } else if(time(0)>fliptime+flipint) { fliptime=time(0); flip++; if(flip>=MP3Setup.DisplayMode) flip=0; doflip=true; } if(doflip) { cString buff; switch(flip) { default: flip=0; // fall through case 0: buff=TitleArtist(mode->Title,mode->Artist); flipint=6; break; case 1: if(mode->Album[0]) { buff=cString::sprintf(mode->Year>0?"from: %s (%d)":"from: %s",mode->Album,mode->Year); flipint=4; break; } flip++; // fall through case 2: if(mode->MaxBitrate>0) buff=cString::sprintf("%.1f kHz, %d-%d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->MaxBitrate/1000,mode->SMode); else buff=cString::sprintf("%.1f kHz, %d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->SMode); flipint=3; break; } if(MP3Setup.ReplayDisplay) { disp->SetTitle(cString::sprintf("[%c%c] (%d/%d) %s",mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,*buff)); flush=true; } else { if(!statusActive) { DisplayInfo(buff); flush=true; } else { d(printf("mp3-ctrl: display info skip due to status active\n")) } } } } if(bigwin) { bool all=(top!=lastTop || changed); if(all || time(0)>listtime+2) { int num=(top>0 && mode->Num==lastMode->Num) ? top : mode->Num - rows/2; if(num+rows>mode->MaxNum) num=mode->MaxNum-rows+1; if(num<1) num=1; top=num; for(int i=0 ; iMaxNum ; i++,num++) { cMP3PlayInfo pi; mgr->Info(num,&pi); if(!pi.Title[0]) break; cString buff=cString::sprintf("%d.\t%s",num,*TitleArtist(pi.Title,pi.Artist)); int fg=clrWhite, bg=clrGray50; int hash=MakeHash(buff); if(num==mode->Num) { fg=clrBlack; bg=clrCyan; hash=(hash^77) + 23; } if(all || hash!=hashlist[i]) { const char *s=rindex(buff,'\t'); if(s) { Write(5,i,bwc-5,s,fg,bg); buff.Truncate(s-buff); Write(0,i,5,buff,fg,bg); } else Write(0,i,bwc,buff,fg,bg); flush=true; hashlist[i]=hash; } } listtime=time(0); lastTop=top; } } if(flush) Flush(); } lastIndex=index; lastTotal=total; delete lastMode; lastMode=mode; } } void cMP3Control::DisplayInfo(const char *s) { if(s) Write(CTAB,-2,bwc-CTAB,s); else Fill(CTAB,-2,bwc-CTAB,1,clrGray50); } void cMP3Control::JumpDisplay(void) { char buf[64]; const char *j=trVDR("Jump: "), u=jumpsecs?'s':'m'; if(!jumpmm) sprintf(buf,"%s- %c", j,u); else sprintf(buf,"%s%d- %c",j,jumpmm,u); if(MP3Setup.ReplayDisplay) { disp->SetJump(buf); } else { DisplayInfo(buf); } } void cMP3Control::JumpProcess(eKeys Key) { int n=Key-k0, d=jumpsecs?1:60; switch (Key) { case k0 ... k9: if(jumpmm*10+n <= lastTotal/d) jumpmm=jumpmm*10+n; JumpDisplay(); break; case kBlue: jumpsecs=!jumpsecs; JumpDisplay(); break; case kPlay: case kUp: jumpmm-=lastIndex/d; // fall through case kFastRew: case kFastFwd: case kLeft: case kRight: player->SkipSeconds(jumpmm*d * ((Key==kLeft || Key==kFastRew) ? -1:1)); // fall through default: jumpactive=false; break; } if(!jumpactive) { if(jumphide) Hide(); else if(MP3Setup.ReplayDisplay) disp->SetJump(0); } } void cMP3Control::Jump(void) { jumpmm=0; jumphide=jumpsecs=false; if(!visible) { ShowTimed(); if(!visible) return; jumphide=true; } JumpDisplay(); jumpactive=true; fliptime=0; flip=-1; } eOSState cMP3Control::ProcessKey(eKeys Key) { if(!player->Active()) return osEnd; if(timeoutShow && time(0)>timeoutShow) Hide(); ShowProgress(); ShowStatus(Key==kNone && !Skins.IsOpen()); if(jumpactive && Key!=kNone) { JumpProcess(Key); return osContinue; } switch(Key) { case kUp: case kUp|k_Repeat: case kNext: case kNext|k_Repeat: mgr->Next(); player->Play(); break; case kDown: case kDown|k_Repeat: case kPrev: case kPrev|k_Repeat: if(!player->PrevCheck()) mgr->Prev(); player->Play(); break; case kLeft: case kLeft|k_Repeat: if(bigwin) { if(top>0) { top-=rows; if(top<1) top=1; } break; } // fall through case kFastRew: case kFastRew|k_Repeat: if(!player->IsStream()) player->SkipSeconds(-JUMPSIZE); break; case kRight: case kRight|k_Repeat: if(bigwin) { if(top>0) top+=rows; break; } // fall through case kFastFwd: case kFastFwd|k_Repeat: if(!player->IsStream()) player->SkipSeconds(JUMPSIZE); break; case kRed: if(!player->IsStream()) Jump(); break; case kGreen: if(lastMode) { if(time(0)>greentime) { if(lastMode->Loop || (!lastMode->Loop && !lastMode->Shuffle)) mgr->ToggleLoop(); if(lastMode->Shuffle) mgr->ToggleShuffle(); } else { if(!lastMode->Loop) mgr->ToggleLoop(); else if(!lastMode->Shuffle) mgr->ToggleShuffle(); else mgr->ToggleLoop(); } greentime=time(0)+MULTI_TIMEOUT; } break; case kPlay: player->Play(); break; case kPause: case kYellow: if(!player->IsStream()) player->Pause(); break; case kStop: case kBlue: Hide(); Stop(); return osEnd; case kBack: Hide(); cRemote::CallPlugin(plugin_name); return osBack; case k0 ... k9: number=number*10+Key-k0; if(lastMode && number>0 && number<=lastMode->MaxNum) { if(!visible) ShowTimed(SELECTHIDE_TIMEOUT); else if(timeoutShow>0) timeoutShow=time(0)+SELECTHIDE_TIMEOUT; selecting=true; lastkeytime.Set(SELECT_TIMEOUT); char buf[32]; if(MP3Setup.ReplayDisplay) { snprintf(buf,sizeof(buf),"%s%d-/%d",trVDR("Jump: "),number,lastMode->MaxNum); disp->SetJump(buf); } else { snprintf(buf,sizeof(buf),"(%d-/%d)",number,lastMode->MaxNum); Write(0,-2,CTAB,buf); } Flush(); break; } number=0; lastkeytime.Set(); // fall through case kNone: if(selecting && lastkeytime.TimedOut()) { if(number>0) { mgr->Goto(number); player->Play(); } if(lastMode) lastMode->Hash=-1; number=0; selecting=false; if(MP3Setup.ReplayDisplay && disp) disp->SetJump(0); } break; case kOk: if(time(0)>oktime || MP3Setup.ReplayDisplay) { visible ? Hide() : ShowTimed(); } else { if(visible && !bigwin) { Hide(); ShowProgress(true,true); } else { Hide(); ShowTimed(); } } oktime=time(0)+MULTI_TIMEOUT; ShowStatus(true); break; default: return osUnknown; } return osContinue; } // --- cMenuID3Info ------------------------------------------------------------ class cMenuID3Info : public cOsdMenu { private: cOsdItem *Item(const char *name, const char *text); cOsdItem *Item(const char *name, const char *format, const float num); void Build(cSongInfo *info, const char *name); public: cMenuID3Info(cSong *song); cMenuID3Info(cSongInfo *si, const char *name); virtual eOSState ProcessKey(eKeys Key); }; cMenuID3Info::cMenuID3Info(cSong *song) :cOsdMenu(tr("ID3 information"),12) { Build(song->Info(),song->Name()); } cMenuID3Info::cMenuID3Info(cSongInfo *si, const char *name) :cOsdMenu(tr("ID3 information"),12) { Build(si,name); } void cMenuID3Info::Build(cSongInfo *si, const char *name) { if(si) { Item(tr("Filename"),name); if(si->HasInfo() && si->Total>0) { char *buf=aprintf("%02d:%02d",si->Total/60,si->Total%60); Item(tr("Length"),buf); free(buf); Item(tr("Title"),si->Title); Item(tr("Artist"),si->Artist); Item(tr("Album"),si->Album); Item(tr("Year"),0,(float)si->Year); Item(tr("Samplerate"),"%.1f kHz",si->SampleFreq/1000.0); Item(tr("Bitrate"),"%.f kbit/s",si->Bitrate/1000.0); Item(trVDR("Channels"),0,(float)si->Channels); } Display(); } } cOsdItem *cMenuID3Info::Item(const char *name, const char *format, const float num) { cOsdItem *item; if(num>=0.0) { char *buf=aprintf(format?format:"%.f",num); item=Item(name,buf); free(buf); } else item=Item(name,""); return item; } cOsdItem *cMenuID3Info::Item(const char *name, const char *text) { char *buf=aprintf("%s:\t%s",name,text?text:""); cOsdItem *item = new cOsdItem(buf,osBack); item->SetSelectable(false); free(buf); Add(item); return item; } eOSState cMenuID3Info::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if(state==osUnknown) { switch(Key) { case kRed: case kGreen: case kYellow: case kBlue: return osContinue; case kMenu: return osEnd; default: break; } } return state; } // --- cMenuInstantBrowse ------------------------------------------------------- class cMenuInstantBrowse : public cMenuBrowse { private: const char *selecttext, *alltext; virtual void SetButtons(void); virtual eOSState ID3Info(void); public: cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext); virtual eOSState ProcessKey(eKeys Key); }; cMenuInstantBrowse::cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext) :cMenuBrowse(Source,true,true,tr("Directory browser"),excl_br) { selecttext=Selecttext; alltext=Alltext; SetButtons(); } void cMenuInstantBrowse::SetButtons(void) { SetHelp(selecttext, currentdir?tr("Parent"):0, currentdir?0:alltext, tr("ID3 info")); Display(); } eOSState cMenuInstantBrowse::ID3Info(void) { cFileObj *item=CurrentItem(); if(item && item->Type()==otFile) { cSong *song=new cSong(item); cSongInfo *si; if(song && (si=song->Info())) { AddSubMenu(new cMenuID3Info(si,item->Path())); } delete song; } return osContinue; } eOSState cMenuInstantBrowse::ProcessKey(eKeys Key) { eOSState state=cOsdMenu::ProcessKey(Key); if(state==osUnknown) { switch (Key) { case kYellow: lastselect=new cFileObj(source,0,0,otBase); return osBack; default: break; } } if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state); return state; } // --- cMenuPlayListItem ------------------------------------------------------- class cMenuPlayListItem : public cOsdItem { private: bool showID3; cSong *song; public: cMenuPlayListItem(cSong *Song, bool showid3); cSong *Song(void) { return song; } virtual void Set(void); void Set(bool showid3); }; cMenuPlayListItem::cMenuPlayListItem(cSong *Song, bool showid3) { song=Song; Set(showid3); } void cMenuPlayListItem::Set(bool showid3) { showID3=showid3; Set(); } void cMenuPlayListItem::Set(void) { char *buffer; cSongInfo *si=song->Info(false); if(showID3 && !si) si=song->Info(); if(showID3 && si && si->Title) buffer=aprintf("%d.\t%s",song->Index()+1,*TitleArtist(si->Title,si->Artist)); else buffer=aprintf("%d.\t<%s>",song->Index()+1,song->Name()); SetText(buffer,false); } // --- cMenuPlayList ------------------------------------------------------ class cMenuPlayList : public cOsdMenu { private: cPlayList *playlist; bool browsing, showid3; void Buttons(void); void Refresh(bool all = false); void Add(void); virtual void Move(int From, int To); eOSState Remove(void); eOSState ShowID3(void); eOSState ID3Info(void); public: cMenuPlayList(cPlayList *Playlist); virtual eOSState ProcessKey(eKeys Key); }; cMenuPlayList::cMenuPlayList(cPlayList *Playlist) :cOsdMenu(tr("Playlist editor"),4) { browsing=showid3=false; playlist=Playlist; if(MP3Setup.EditorMode) showid3=true; cSong *mp3 = playlist->First(); while(mp3) { cOsdMenu::Add(new cMenuPlayListItem(mp3,showid3)); mp3 = playlist->cList::Next(mp3); } Buttons(); Display(); } void cMenuPlayList::Buttons(void) { SetHelp(tr("Add"), showid3?tr("Filenames"):tr("ID3 names"), tr("Remove"), trVDR("Button$Mark")); } void cMenuPlayList::Refresh(bool all) { cMenuPlayListItem *cur=(cMenuPlayListItem *)((all || Count()<2) ? First() : Get(Current())); while(cur) { cur->Set(showid3); cur=(cMenuPlayListItem *)Next(cur); } } void cMenuPlayList::Add(void) { cFileObj *item=cMenuInstantBrowse::GetSelected(); if(item) { Status(tr("Scanning directory...")); cInstantPlayList *newpl=new cInstantPlayList(item); if(newpl->Load()) { if(newpl->Count()) { if(newpl->Count()==1 || Interface->Confirm(tr("Add recursivly?"))) { cSong *mp3=newpl->First(); while(mp3) { cSong *n=new cSong(mp3); if(Count()>0) { cMenuPlayListItem *current=(cMenuPlayListItem *)Get(Current()); playlist->Add(n,current->Song()); cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true,current); } else { playlist->Add(n); cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true); } mp3=newpl->cList::Next(mp3); } playlist->Save(); Refresh(); Display(); } } else Error(tr("Empty directory!")); } else Error(tr("Error scanning directory!")); delete newpl; Status(0); } } void cMenuPlayList::Move(int From, int To) { playlist->Move(From,To); playlist->Save(); cOsdMenu::Move(From,To); Refresh(true); Display(); } eOSState cMenuPlayList::ShowID3(void) { showid3=!showid3; Buttons(); Refresh(true); Display(); return osContinue; } eOSState cMenuPlayList::ID3Info(void) { if(Count()>0) { cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current()); AddSubMenu(new cMenuID3Info(current->Song())); } return osContinue; } eOSState cMenuPlayList::Remove(void) { if(Count()>0) { cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current()); if(Interface->Confirm(tr("Remove entry?"))) { playlist->Del(current->Song()); playlist->Save(); cOsdMenu::Del(Current()); Refresh(); Display(); } } return osContinue; } eOSState cMenuPlayList::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if(browsing && !HasSubMenu() && state==osContinue) { Add(); browsing=false; } if(state==osUnknown) { switch(Key) { case kOk: return ID3Info(); case kRed: browsing=true; return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),tr("Add"),tr("Add all"))); case kGreen: return ShowID3(); case kYellow: return Remove(); case kBlue: Mark(); return osContinue; case kMenu: return osEnd; default: break; } } return state; } // --- cPlaylistRename -------------------------------------------------------- class cPlaylistRename : public cOsdMenu { private: static char *newname; const char *oldname; char data[64]; public: cPlaylistRename(const char *Oldname); virtual eOSState ProcessKey(eKeys Key); static const char *GetNewname(void) { return newname; } }; char *cPlaylistRename::newname = NULL; cPlaylistRename::cPlaylistRename(const char *Oldname) :cOsdMenu(tr("Rename playlist"), 15) { free(newname); newname=0; oldname=Oldname; char *buf=aprintf("%s\t%s",tr("Old name:"),oldname); cOsdItem *old = new cOsdItem(buf,osContinue); old->SetSelectable(false); Add(old); free(buf); data[0]=0; Add(new cMenuEditStrItem( tr("New name"), data, sizeof(data)-1, tr(FileNameChars)),true); } eOSState cPlaylistRename::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { case kOk: if(data[0] && strcmp(data,oldname)) newname=strdup(data); return osBack; case kRed: case kGreen: case kYellow: case kBlue: return osContinue; default: break; } } return state; } // --- cMenuMP3Item ----------------------------------------------------- class cMenuMP3Item : public cOsdItem { private: cPlayList *playlist; virtual void Set(void); public: cMenuMP3Item(cPlayList *PlayList); cPlayList *List(void) { return playlist; } }; cMenuMP3Item::cMenuMP3Item(cPlayList *PlayList) { playlist=PlayList; Set(); } void cMenuMP3Item::Set(void) { char *buffer=aprintf(" %s",playlist->BaseName()); SetText(buffer,false); } // --- cMenuMP3 -------------------------------------------------------- class cMenuMP3 : public cOsdMenu { private: cPlayLists *lists; bool renaming, sourcing, instanting; int buttonnum; eOSState Play(void); eOSState Edit(void); eOSState New(void); eOSState Delete(void); eOSState Rename(bool second); eOSState Source(bool second); eOSState Instant(bool second); void ScanLists(void); eOSState SetButtons(int num); public: cMenuMP3(void); ~cMenuMP3(void); virtual eOSState ProcessKey(eKeys Key); }; cMenuMP3::cMenuMP3(void) :cOsdMenu(tr("MP3")) { renaming=sourcing=instanting=false; lists=new cPlayLists; ScanLists(); SetButtons(1); if(MP3Setup.MenuMode) Instant(false); } cMenuMP3::~cMenuMP3(void) { delete lists; } eOSState cMenuMP3::SetButtons(int num) { switch(num) { case 1: SetHelp(trVDR("Button$Edit"), tr("Source"), tr("Browse"), ">>"); break; case 2: SetHelp("<<", trVDR("Button$New"), trVDR("Button$Delete"), tr("Rename")); break; } buttonnum=num; Display(); return osContinue; } void cMenuMP3::ScanLists(void) { Clear(); Status(tr("Scanning playlists...")); bool res=lists->Load(MP3Sources.GetSource()); Status(0); if(res) { cPlayList *plist=lists->First(); while(plist) { Add(new cMenuMP3Item(plist)); plist=lists->Next(plist); } } else Error(tr("Error scanning playlists!")); } eOSState cMenuMP3::Delete(void) { if(Count()>0) { if(Interface->Confirm(tr("Delete playlist?")) && Interface->Confirm(tr("Are you sure?")) ) { cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); if(plist->Delete()) { lists->Del(plist); cOsdMenu::Del(Current()); Display(); } else Error(tr("Error deleting playlist!")); } } return osContinue; } eOSState cMenuMP3::New(void) { cPlayList *plist=new cPlayList(MP3Sources.GetSource(),0,0); char name[32]; int i=0; do { if(i) sprintf(name,"%s%d",tr("unnamed"),i++); else { strcpy(name,tr("unnamed")); i++; } } while(plist->TestName(name)); if(plist->Create(name)) { lists->Add(plist); Add(new cMenuMP3Item(plist), true); isyslog("MP3: playlist %s added", plist->Name()); return AddSubMenu(new cMenuPlayList(plist)); } Error(tr("Error creating playlist!")); delete plist; return osContinue; } eOSState cMenuMP3::Rename(bool second) { if(HasSubMenu() || Count() == 0) return osContinue; cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); if(!second) { renaming=true; return AddSubMenu(new cPlaylistRename(plist->BaseName())); } renaming=false; const char *newname=cPlaylistRename::GetNewname(); if(newname) { if(plist->Rename(newname)) { RefreshCurrent(); DisplayCurrent(true); } else Error(tr("Error renaming playlist!")); } return osContinue; } eOSState cMenuMP3::Edit(void) { if(HasSubMenu() || Count() == 0) return osContinue; cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); if(!plist->Load()) Error(tr("Error loading playlist!")); else if(!plist->IsWinAmp()) { isyslog("MP3: editing playlist %s", plist->Name()); return AddSubMenu(new cMenuPlayList(plist)); } else Error(tr("Can't edit a WinAmp playlist!")); return osContinue; } eOSState cMenuMP3::Play(void) { if(HasSubMenu() || Count() == 0) return osContinue; Status(tr("Loading playlist...")); cPlayList *newpl=new cPlayList(((cMenuMP3Item *)Get(Current()))->List()); if(newpl->Load() && newpl->Count()) { isyslog("mp3: playback started with playlist %s", newpl->Name()); cMP3Control::SetPlayList(newpl); if(MP3Setup.KeepSelect) { Status(0); return osContinue; } return osEnd; } Status(0); delete newpl; Error(tr("Error loading playlist!")); return osContinue; } eOSState cMenuMP3::Source(bool second) { if(HasSubMenu()) return osContinue; if(!second) { sourcing=true; return AddSubMenu(new cMenuSource(&MP3Sources,tr("MP3 source"))); } sourcing=false; cFileSource *src=cMenuSource::GetSelected(); if(src) { MP3Sources.SetSource(src); ScanLists(); Display(); } return osContinue; } eOSState cMenuMP3::Instant(bool second) { if(HasSubMenu()) return osContinue; if(!second) { instanting=true; return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),trVDR("Button$Play"),tr("Play all"))); } instanting=false; cFileObj *item=cMenuInstantBrowse::GetSelected(); if(item) { Status(tr("Building playlist...")); cInstantPlayList *newpl = new cInstantPlayList(item); if(newpl->Load() && newpl->Count()) { isyslog("mp3: playback started with instant playlist %s", newpl->Name()); cMP3Control::SetPlayList(newpl); if(MP3Setup.KeepSelect) { Status(0); return Instant(false); } return osEnd; } Status(0); delete newpl; Error(tr("Error building playlist!")); } return osContinue; } eOSState cMenuMP3::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if(!HasSubMenu() && state==osContinue) { // eval the return value from submenus if(renaming) return Rename(true); if(sourcing) return Source(true); if(instanting) return Instant(true); } if(state == osUnknown) { switch(Key) { case kOk: return Play(); case kRed: return (buttonnum==1 ? Edit() : SetButtons(1)); case kGreen: return (buttonnum==1 ? Source(false) : New()); case kYellow: return (buttonnum==1 ? Instant(false) : Delete()); case kBlue: return (buttonnum==1 ? SetButtons(2) : Rename(false)); case kMenu: return osEnd; default: break; } } return state; } // --- PropagateImage ---------------------------------------------------------- void PropagateImage(const char *image) { cPlugin *graphtft=cPluginManager::GetPlugin("graphtft"); if(graphtft) graphtft->SetupParse("CoverImage",image ? image:""); } // --- cPluginMP3 -------------------------------------------------------------- static const char *DESCRIPTION = trNOOP("A versatile audio player"); static const char *MAINMENUENTRY = "MP3"; class cPluginMp3 : public cPlugin { private: bool ExternalPlay(const char *path, bool test); public: cPluginMp3(void); virtual ~cPluginMp3(); virtual const char *Version(void) { return PluginVersion; } virtual const char *Description(void) { return tr(DESCRIPTION); } virtual const char *CommandLineHelp(void); virtual bool ProcessArgs(int argc, char *argv[]); virtual bool Initialize(void); virtual void Housekeeping(void); virtual const char *MainMenuEntry(void); virtual cOsdObject *MainMenuAction(void); virtual cMenuSetupPage *SetupMenu(void); virtual bool SetupParse(const char *Name, const char *Value); virtual bool Service(const char *Id, void *Data); virtual const char **SVDRPHelpPages(void); virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); }; cPluginMp3::cPluginMp3(void) { // Initialize any member varaiables here. // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! } cPluginMp3::~cPluginMp3() { InfoCache.Shutdown(); delete mgr; } const char *cPluginMp3::CommandLineHelp(void) { static char *help_str=0; free(help_str); // for easier orientation, this is column 80| help_str=aprintf( " -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n" " (default: %s)\n" " -n CMD, --network=CMD execute CMD before & after network access\n" " (default: %s)\n" " -C DIR, --cache=DIR store ID3 cache file in DIR\n" " (default: %s)\n" " -B DIR, --cddb=DIR search CDDB files in DIR\n" " (default: %s)\n" " -D DEV, --dsp=DEV device for OSS output\n" " (default: %s)\n" " -i CMD, --iconv=CMD use CMD to convert background images\n" " (default: %s)\n" " -I IMG, --defimage=IMG use IMG as default background image\n" " (default: none)\n" " -c DIR, --icache=DIR cache converted images in DIR\n" " (default: %s)\n" " -S SUB, --sources=SUB search sources config in SUB subdirectory\n" " (default: %s)\n", mountscript, netscript ? netscript:"none", cachedir ? cachedir:"video dir", #ifdef HAVE_SNDFILE cddbpath, #else "none", #endif #ifdef WITH_OSS dspdevice, #else "none", #endif imageconv, imagecache, sourcesSub ? sourcesSub:"empty" ); return help_str; } bool cPluginMp3::ProcessArgs(int argc, char *argv[]) { static struct option long_options[] = { { "mount", required_argument, NULL, 'm' }, { "network", required_argument, NULL, 'n' }, { "cddb", required_argument, NULL, 'B' }, { "dsp", required_argument, NULL, 'D' }, { "cache", required_argument, NULL, 'C' }, { "icache", required_argument, NULL, 'c' }, { "iconv", required_argument, NULL, 'i' }, { "defimage", required_argument, NULL, 'I' }, { "sources", required_argument, NULL, 'S' }, { NULL } }; int c, option_index = 0; while((c=getopt_long(argc,argv,"c:i:m:n:B:C:D:S:",long_options,&option_index))!=-1) { switch (c) { case 'i': imageconv=optarg; break; case 'c': imagecache=optarg; break; case 'm': mountscript=optarg; break; case 'n': netscript=optarg; break; case 'C': cachedir=optarg; break; case 'I': def_usr_img=optarg; break; case 'S': sourcesSub=optarg; break; case 'B': #ifdef HAVE_SNDFILE cddbpath=optarg; break; #else fprintf(stderr, "mp3: libsndfile support has not been compiled in!\n"); return false; #endif case 'D': #ifdef WITH_OSS dspdevice=optarg; break; #else fprintf(stderr, "mp3: OSS output has not been compiled in!\n"); return false; #endif default: return false; } } return true; } bool cPluginMp3::Initialize(void) { if(!CheckVDRVersion(1,4,5,"mp3")) return false; plugin_name="mp3"; #if APIVERSNUM < 10507 i18n_name="mp3"; #else i18n_name="vdr-mp3"; #endif MP3Sources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mp3sources.conf")); if(MP3Sources.Count()<1) { esyslog("ERROR: you should have defined at least one source in mp3sources.conf"); fprintf(stderr,"No source(s) defined in mp3sources.conf\n"); return false; } InfoCache.Load(); #if APIVERSNUM < 10507 RegisterI18n(Phrases); #endif #if APIVERSNUM < 10503 cCharSetConv::SetSystemCharacterTableX(I18nCharSets()[Setup.OSDLanguage]); #endif mgr=new cPlayManager; if(!mgr) { esyslog("ERROR: creating playmanager failed"); fprintf(stderr,"Creating playmanager failed\n"); return false; } d(printf("mp3: using %s\n",mad_version)) d(printf("mp3: compiled with %s\n",MAD_VERSION)) return true; } void cPluginMp3::Housekeeping(void) { InfoCache.Save(); } const char *cPluginMp3::MainMenuEntry(void) { return MP3Setup.HideMainMenu ? 0 : tr(MAINMENUENTRY); } cOsdObject *cPluginMp3::MainMenuAction(void) { return new cMenuMP3; } cMenuSetupPage *cPluginMp3::SetupMenu(void) { return new cMenuSetupMP3; } bool cPluginMp3::SetupParse(const char *Name, const char *Value) { if (!strcasecmp(Name, "InitLoopMode")) MP3Setup.InitLoopMode = atoi(Value); else if (!strcasecmp(Name, "InitShuffleMode")) MP3Setup.InitShuffleMode = atoi(Value); else if (!strcasecmp(Name, "AudioMode")) MP3Setup.AudioMode = atoi(Value); else if (!strcasecmp(Name, "BgrScan")) MP3Setup.BgrScan = atoi(Value); else if (!strcasecmp(Name, "EditorMode")) MP3Setup.EditorMode = atoi(Value); else if (!strcasecmp(Name, "DisplayMode")) MP3Setup.DisplayMode = atoi(Value); else if (!strcasecmp(Name, "BackgrMode")) MP3Setup.BackgrMode = atoi(Value); else if (!strcasecmp(Name, "MenuMode")) MP3Setup.MenuMode = atoi(Value); else if (!strcasecmp(Name, "TargetLevel")) MP3Setup.TargetLevel = atoi(Value); else if (!strcasecmp(Name, "LimiterLevel")) MP3Setup.LimiterLevel = atoi(Value); else if (!strcasecmp(Name, "Only48kHz")) MP3Setup.Only48kHz = atoi(Value); else if (!strcasecmp(Name, "UseProxy")) MP3Setup.UseProxy = atoi(Value); else if (!strcasecmp(Name, "ProxyHost")) strn0cpy(MP3Setup.ProxyHost,Value,MAX_HOSTNAME); else if (!strcasecmp(Name, "ProxyPort")) MP3Setup.ProxyPort = atoi(Value); else if (!strcasecmp(Name, "UseCddb")) MP3Setup.UseCddb = atoi(Value); else if (!strcasecmp(Name, "CddbHost")) strn0cpy(MP3Setup.CddbHost,Value,MAX_HOSTNAME); else if (!strcasecmp(Name, "CddbPort")) MP3Setup.CddbPort = atoi(Value); else if (!strcasecmp(Name, "AbortAtEOL")) MP3Setup.AbortAtEOL = atoi(Value); else if (!strcasecmp(Name, "AudioOutMode")) { MP3Setup.AudioOutMode = atoi(Value); #ifndef WITH_OSS if(MP3Setup.AudioOutMode==AUDIOOUTMODE_OSS) { esyslog("WARNING: AudioOutMode OSS not supported, falling back to DVB"); MP3Setup.AudioOutMode=AUDIOOUTMODE_DVB; } #endif } else if (!strcasecmp(Name, "ReplayDisplay")) MP3Setup.ReplayDisplay = atoi(Value); else if (!strcasecmp(Name, "HideMainMenu")) MP3Setup.HideMainMenu = atoi(Value); else if (!strcasecmp(Name, "KeepSelect")) MP3Setup.KeepSelect = atoi(Value); else if (!strcasecmp(Name, "TitleArtistOrder")) MP3Setup.TitleArtistOrder = atoi(Value); else return false; return true; } bool cPluginMp3::ExternalPlay(const char *path, bool test) { char real[PATH_MAX+1]; if(realpath(path,real)) { cFileSource *src=MP3Sources.FindSource(real); if(src) { cFileObj *item=new cFileObj(src,0,0,otFile); if(item) { item->SplitAndSet(real); if(item->GuessType()) { if(item->Exists()) { cInstantPlayList *pl=new cInstantPlayList(item); if(pl && pl->Load() && pl->Count()) { if(!test) cMP3Control::SetPlayList(pl); else delete pl; delete item; return true; } else dsyslog("MP3 service: error building playlist"); delete pl; } else dsyslog("MP3 service: cannot play '%s'",path); } else dsyslog("MP3 service: GuessType() failed for '%s'",path); delete item; } } else dsyslog("MP3 service: cannot find source for '%s', real '%s'",path,real); } else if(errno!=ENOENT && errno!=ENOTDIR) esyslog("ERROR: realpath: %s: %s",path,strerror(errno)); return false; } bool cPluginMp3::Service(const char *Id, void *Data) { if(!strcasecmp(Id,"MP3-Play-v1")) { if(Data) { struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; msd->result=ExternalPlay(msd->data.filename,false); } return true; } else if(!strcasecmp(Id,"MP3-Test-v1")) { if(Data) { struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; msd->result=ExternalPlay(msd->data.filename,true); } return true; } return false; } const char **cPluginMp3::SVDRPHelpPages(void) { static const char *HelpPages[] = { "PLAY \n" " Triggers playback of file 'filename'.", "TEST \n" " Tests is playback of file 'filename' is possible.", "CURR\n" " Returns filename of song currently being replayed.", NULL }; return HelpPages; } cString cPluginMp3::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) { if(!strcasecmp(Command,"PLAY")) { if(*Option) { if(ExternalPlay(Option,false)) return "Playback triggered"; else { ReplyCode=550; return "Playback failed"; } } else { ReplyCode=501; return "Missing filename"; } } else if(!strcasecmp(Command,"TEST")) { if(*Option) { if(ExternalPlay(Option,true)) return "Playback possible"; else { ReplyCode=550; return "Playback not possible"; } } else { ReplyCode=501; return "Missing filename"; } } else if(!strcasecmp(Command,"CURR")) { cControl *control=cControl::Control(); if(control && typeid(*control)==typeid(cMP3Control)) { cMP3PlayInfo mode; if(mgr->Info(-1,&mode)) return mode.Filename; else return ""; } else { ReplyCode=550; return "No running playback"; } } return NULL; } VDRPLUGINCREATOR(cPluginMp3); // Don't touch this! mp3-0.10.2/mplayer.c0100644000000000000000000005124711242240217012611 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include "common.h" #include #include #include #include #include #include #include #include #include #include "setup.h" #include "setup-mplayer.h" #include "menu.h" #include "player-mplayer.h" #include "data.h" #include "data-src.h" #include "i18n.h" #include "version.h" #include "service.h" const char *sourcesSub=0; cFileSources MPlaySources; static const char *plugin_name=0; const char *i18n_name=0; // --- cMenuSetupMPlayer -------------------------------------------------------- class cMenuSetupMPlayer : public cMenuSetupPage { private: cMPlayerSetup data; const char *res[3]; protected: virtual void Store(void); public: cMenuSetupMPlayer(void); }; cMenuSetupMPlayer::cMenuSetupMPlayer(void) { data=MPlayerSetup; SetSection(tr("MPlayer")); Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Control mode"), &data.SlaveMode, tr("Traditional"), tr("Slave"))); res[0]=tr("disabled"); res[1]=tr("global only"); res[2]=tr("local first"); Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"), &data.ResumeMode, 3, res)); Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu)); for(int i=0; i<10; i++) { char name[32]; snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i); static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"Ї$%&/()=?{}[]\\+*~#',;.:-_<>|@Д`^А" }; Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed)); } } void cMenuSetupMPlayer::Store(void) { MPlayerSetup=data; SetupStore("ControlMode", MPlayerSetup.SlaveMode); SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu); SetupStore("ResumeMode", MPlayerSetup.ResumeMode); for(int i=0; i<10; i++) { char name[16]; snprintf(name,sizeof(name),"KeyCmd%d",i); SetupStore(name,MPlayerSetup.KeyCmd[i]); } } // --- cMPlayerControl --------------------------------------------------------- class cMPlayerControl : public cControl { private: static cFileObj *file; static bool rewind; cMPlayerPlayer *player; cSkinDisplayReplay *display; bool visible, modeOnly; time_t timeoutShow; int lastCurrent, lastTotal; char *lastReplayMsg; // bool jumpactive, jumphide, jumpmode; int jumpval; // void Stop(void); void ShowTimed(int Seconds=0); void ShowProgress(void); void ShowMode(void); void ShowTitle(void); void Jump(void); void JumpProcess(eKeys Key); void JumpDisplay(void); public: cMPlayerControl(void); virtual ~cMPlayerControl(); virtual eOSState ProcessKey(eKeys Key); virtual void Show(void) { ShowTimed(); } virtual void Hide(void); static void SetFile(const cFileObj *File, bool Rewind); }; cFileObj *cMPlayerControl::file=0; bool cMPlayerControl::rewind=false; cMPlayerControl::cMPlayerControl(void) :cControl(player=new cMPlayerPlayer(file,rewind)) { visible=modeOnly=jumpactive=false; lastReplayMsg=0; display=0; ShowTitle(); } cMPlayerControl::~cMPlayerControl() { Stop(); cStatus::MsgReplaying(this,0,0,false); free(lastReplayMsg); } void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind) { delete file; file=File ? new cFileObj(File) : 0; rewind=Rewind; } void cMPlayerControl::Stop(void) { delete player; player=0; } void cMPlayerControl::ShowTimed(int Seconds) { if(modeOnly) Hide(); if(!visible) { ShowProgress(); timeoutShow = Seconds>0 ? time(0)+Seconds : 0; } } void cMPlayerControl::Hide(void) { if(visible) { delete display; display=0; visible=modeOnly=false; #if APIVERSNUM >= 10500 SetNeedsFastResponse(false); #else needsFastResponse=false; #endif } } void cMPlayerControl::ShowTitle(void) { const char *path=0; bool release=true; if(player) path=player->GetCurrentName(); if(!path) { path=file->FullPath(); release=false; } if(path) { const char *name=rindex(path,'/'); if(name) name++; else name=path; if(!lastReplayMsg || strcmp(lastReplayMsg,path)) { cStatus::MsgReplaying(this,name,path,true); free(lastReplayMsg); lastReplayMsg=strdup(path); } if(visible) { if(display) display->SetTitle(name); } } if(release) free((void *)path); } void cMPlayerControl::ShowProgress(void) { int Current, Total; if(GetIndex(Current,Total) && Total>0) { bool flush=false; if(!visible) { display=Skins.Current()->DisplayReplay(false); visible=true; modeOnly=false; #if APIVERSNUM >= 10500 SetNeedsFastResponse(true); #else needsFastResponse=true; #endif lastCurrent=lastTotal=-1; flush=true; } if(abs(Current-lastCurrent)>12) { if(Total>0) display->SetProgress(Current, Total); display->SetCurrent(IndexToHMSF(Current)); display->SetTotal(IndexToHMSF(Total)); bool Play, Forward; int Speed; if(GetReplayMode(Play,Forward,Speed)) display->SetMode(Play, Forward, Speed); ShowTitle(); flush=true; lastCurrent=Current; lastTotal=Total; } if(flush) Skins.Flush(); ShowMode(); } } void cMPlayerControl::ShowMode(void) { if(Setup.ShowReplayMode && !jumpactive) { bool Play, Forward; int Speed; if(GetReplayMode(Play, Forward, Speed)) { bool NormalPlay = (Play && Speed == -1); if(!visible) { if(NormalPlay) return; display = Skins.Current()->DisplayReplay(true); visible=modeOnly=true; } if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT; display->SetMode(Play, Forward, Speed); } } } void cMPlayerControl::JumpDisplay(void) { char buf[64]; const char *j=trVDR("Jump: "), u=jumpmode?'%':'m'; if(!jumpval) sprintf(buf,"%s- %c", j,u); else sprintf(buf,"%s%d- %c",j,jumpval,u); display->SetJump(buf); } void cMPlayerControl::JumpProcess(eKeys Key) { const int n=Key-k0; switch (Key) { case k0 ... k9: { const int max=jumpmode?100:lastTotal; if(jumpval*10+n <= max) jumpval=jumpval*10+n; JumpDisplay(); } break; case kBlue: jumpmode=!jumpmode; jumpval=0; JumpDisplay(); break; case kPlay: case kUp: player->Goto(jumpval*(jumpmode?1:60),jumpmode,false); jumpactive=false; break; case kFastRew: case kFastFwd: case kLeft: case kRight: if(!jumpmode) { player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1)); jumpactive=false; } break; default: jumpactive=false; break; } if(!jumpactive) { if(jumphide) Hide(); else display->SetJump(0); } } void cMPlayerControl::Jump(void) { jumpval=0; jumphide=jumpmode=false; if(!visible) { ShowTimed(); if(!visible) return; jumphide=true; } JumpDisplay(); jumpactive=true; } eOSState cMPlayerControl::ProcessKey(eKeys Key) { if(!player->Active()) { Hide(); Stop(); return osEnd; } if(!player->SlaveMode()) { if(Key==kBlue) { Hide(); Stop(); return osEnd; } } else { if(visible) { if(timeoutShow && time(0)>timeoutShow) { Hide(); ShowMode(); timeoutShow = 0; } else { if(modeOnly) ShowMode(); else ShowProgress(); } } else ShowTitle(); if(jumpactive && Key != kNone) { JumpProcess(Key); return osContinue; } bool DoShowMode = true; switch (Key) { case kPlay: case kUp: player->Play(); break; case kPause: case kDown: player->Pause(); break; case kFastRew|k_Repeat: case kFastRew: case kLeft|k_Repeat: case kLeft: player->SkipSeconds(-10); break; case kFastFwd|k_Repeat: case kFastFwd: case kRight|k_Repeat: case kRight: player->SkipSeconds(10); break; case kRed: Jump(); break; case kGreen|k_Repeat: // temporary use case kGreen: player->SkipSeconds(-60); break; case kYellow|k_Repeat: case kYellow: player->SkipSeconds(60); break; // case kGreen|k_Repeat: // reserved for future use // case kGreen: player->SkipPrev(); break; // case kYellow|k_Repeat: // case kYellow: player->SkipNext(); break; case kBack: Hide(); cRemote::CallPlugin(plugin_name); return osBack; case kStop: case kBlue: Hide(); Stop(); return osEnd; default: DoShowMode = false; switch(Key) { case kOk: if(visible && !modeOnly) { Hide(); DoShowMode=true; } else ShowTimed(); break; case kAudio: player->KeyCmd("switch_audio"); break; case kNext: player->KeyCmd("seek_chapter +1"); break; case kPrev: player->KeyCmd("seek_chapter -1"); break; case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: { const char *cmd=MPlayerSetup.KeyCmd[Key-k0]; if(cmd[0]) player->KeyCmd(cmd); } break; default: break; } break; } if(DoShowMode) ShowMode(); } return osContinue; } // --- cMenuMPlayAid ----------------------------------------------------------- class cMenuMPlayAid : public cOsdMenu { public: cMenuMPlayAid(void); virtual eOSState ProcessKey(eKeys Key); }; cMenuMPlayAid::cMenuMPlayAid(void) :cOsdMenu(tr("MPlayer Audio ID"),20) { Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255)); Display(); } eOSState cMenuMPlayAid::ProcessKey(eKeys Key) { eOSState state=cOsdMenu::ProcessKey(Key); if(state==osUnknown) { switch(Key) { case kOk: state=osBack; break; default: break; } } return state; } // --- cMenuMPlayBrowse --------------------------------------------------------- class cMenuMPlayBrowse : public cMenuBrowse { private: bool sourcing, aidedit; eOSState Source(bool second); eOSState Summary(void); protected: virtual void SetButtons(void); public: cMenuMPlayBrowse(void); virtual eOSState ProcessKey(eKeys Key); }; static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 }; cMenuMPlayBrowse::cMenuMPlayBrowse(void) :cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum) { sourcing=aidedit=false; SetButtons(); } void cMenuMPlayBrowse::SetButtons(void) { static char blue[12]; snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid); SetHelp(trVDR("Button$Play"), MPlayerSetup.ResumeMode ? trVDR("Button$Rewind"):0, tr("Source"), blue); Display(); } eOSState cMenuMPlayBrowse::Source(bool second) { if(HasSubMenu()) return osContinue; if(!second) { sourcing=true; return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source"))); } sourcing=false; cFileSource *src=cMenuSource::GetSelected(); if(src) { MPlaySources.SetSource(src); SetSource(src); NewDir(0); } return osContinue; } eOSState cMenuMPlayBrowse::Summary(void) { cFileObj *item=CurrentItem(); if(item && item->Type()==otFile) { static const char *exts[] = { ".summary",".txt",".nfo",0 }; for(int i=0; exts[i]; i++) { char buff[4096]; strn0cpy(buff,item->FullPath(),sizeof(buff)-20); char *e=&buff[strlen(buff)]; strn0cpy(e,exts[i],20); int fd=open(buff,O_RDONLY); *e=0; if(fd<0 && (e=rindex(buff,'.'))) { strn0cpy(e,exts[i],20); fd=open(buff,O_RDONLY); } if(fd>=0) { int r=read(fd,buff,sizeof(buff)-1); close(fd); if(r>0) { buff[r]=0; return AddSubMenu(new cMenuText(tr("Summary"),buff)); } } } } return osContinue; } eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key) { eOSState state=cOsdMenu::ProcessKey(Key); if(state==osContinue && !HasSubMenu()) { if(sourcing) return Source(true); if(aidedit) { aidedit=false; SetButtons(); } } bool rew=false; if(state==osUnknown) { switch(Key) { case kGreen: { cFileObj *item=CurrentItem(); if(item && item->Type()==otFile) { lastselect=new cFileObj(item); state=osBack; rew=true; } else state=osContinue; break; } case kYellow: state=Source(false); break; case kBlue: aidedit=true; state=AddSubMenu(new cMenuMPlayAid); break; case k0: state=Summary(); break; default: break; } } if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state); if(state==osBack && lastselect) { cMPlayerControl::SetFile(lastselect,rew); cControl::Launch(new cMPlayerControl); return osEnd; } return state; } // --- cPluginMPlayer ---------------------------------------------------------- static const char *DESCRIPTION = trNOOP("Media replay via MPlayer"); static const char *MAINMENUENTRY = "MPlayer"; class cPluginMPlayer : public cPlugin { private: bool ExternalPlay(const char *path, bool test); public: cPluginMPlayer(void); virtual ~cPluginMPlayer(); virtual const char *Version(void) { return PluginVersion; } virtual const char *Description(void) { return tr(DESCRIPTION); } virtual const char *CommandLineHelp(void); virtual bool ProcessArgs(int argc, char *argv[]); virtual bool Initialize(void); virtual const char *MainMenuEntry(void); virtual cOsdMenu *MainMenuAction(void); virtual cMenuSetupPage *SetupMenu(void); virtual bool SetupParse(const char *Name, const char *Value); virtual bool Service(const char *Id, void *Data); virtual const char **SVDRPHelpPages(void); virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); }; cPluginMPlayer::cPluginMPlayer(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! status=0; } cPluginMPlayer::~cPluginMPlayer() { delete status; } const char *cPluginMPlayer::CommandLineHelp(void) { static char *help_str=0; free(help_str); // for easier orientation, this is column 80| help_str=aprintf( " -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n" " (default: %s)\n" " -M CMD, --mplayer=CMD use CMD when calling MPlayer\n" " (default: %s)\n" " -S SUB, --sources=SUB search sources config in SUB subdirectory\n" " (default: %s)\n" " -R DIR, --resume=DIR store global resume file in DIR\n" " (default: %s)\n", mountscript, MPlayerCmd, sourcesSub ? sourcesSub:"none", globalResumeDir ? globalResumeDir:"video dir" ); return help_str; } bool cPluginMPlayer::ProcessArgs(int argc, char *argv[]) { static struct option long_options[] = { { "mount", required_argument, NULL, 'm' }, { "mplayer", required_argument, NULL, 'M' }, { "sources", required_argument, NULL, 'S' }, { "resume", required_argument, NULL, 'R' }, { NULL } }; int c, option_index = 0; while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) { switch (c) { case 'm': mountscript=optarg; break; case 'M': MPlayerCmd=optarg; break; case 'S': sourcesSub=optarg; break; case 'R': globalResumeDir=optarg; break; default: return false; } } return true; } bool cPluginMPlayer::Initialize(void) { if(!CheckVDRVersion(1,4,5,"mplayer")) return false; plugin_name="mplayer"; #if APIVERSNUM < 10507 i18n_name="mplayer"; #else i18n_name="vdr-mplayer"; #endif MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf")); if(MPlaySources.Count()<1) { esyslog("ERROR: you must have defined at least one source in mplayersources.conf"); fprintf(stderr,"No source(s) defined in mplayersources.conf\n"); return false; } #if APIVERSNUM < 10507 RegisterI18n(Phrases); #endif if(!(status=new cMPlayerStatus)) return false; return true; } const char *cPluginMPlayer::MainMenuEntry(void) { return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY); } cOsdMenu *cPluginMPlayer::MainMenuAction(void) { return new cMenuMPlayBrowse; } cMenuSetupPage *cPluginMPlayer::SetupMenu(void) { return new cMenuSetupMPlayer; } bool cPluginMPlayer::SetupParse(const char *Name, const char *Value) { if( !strcasecmp(Name, "ControlMode")) MPlayerSetup.SlaveMode = atoi(Value); else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value); else if (!strcasecmp(Name, "ResumeMode")) MPlayerSetup.ResumeMode = atoi(Value); else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6])) strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0])); else return false; return true; } bool cPluginMPlayer::ExternalPlay(const char *path, bool test) { char real[PATH_MAX+1]; if(realpath(path,real)) { cFileSource *src=MPlaySources.FindSource(real); if(src) { cFileObj *item=new cFileObj(src,0,0,otFile); if(item) { item->SplitAndSet(real); if(item->GuessType()) { if(item->Exists()) { if(!test) { cMPlayerControl::SetFile(item,true); cControl::Launch(new cMPlayerControl); cControl::Attach(); } delete item; return true; } else dsyslog("MPlayer service: cannot play '%s'",path); } else dsyslog("MPlayer service: GuessType() failed for '%s'",path); delete item; } } else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real); } else if(errno!=ENOENT && errno!=ENOTDIR) esyslog("ERROR: realpath: %s: %s",path,strerror(errno)); return false; } bool cPluginMPlayer::Service(const char *Id, void *Data) { if(!strcasecmp(Id,"MPlayer-Play-v1")) { if(Data) { struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; msd->result=ExternalPlay(msd->data.filename,false); } return true; } else if(!strcasecmp(Id,"MPlayer-Test-v1")) { if(Data) { struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; msd->result=ExternalPlay(msd->data.filename,true); } return true; } return false; } const char **cPluginMPlayer::SVDRPHelpPages(void) { static const char *HelpPages[] = { "PLAY \n" " Triggers playback of file 'filename'.", "TEST \n" " Tests is playback of file 'filename' is possible.", NULL }; return HelpPages; } cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) { if(!strcasecmp(Command,"PLAY")) { if(*Option) { if(ExternalPlay(Option,false)) return "Playback triggered"; else { ReplyCode=550; return "Playback failed"; } } else { ReplyCode=501; return "Missing filename"; } } else if(!strcasecmp(Command,"TEST")) { if(*Option) { if(ExternalPlay(Option,true)) return "Playback possible"; else { ReplyCode=550; return "Playback not possible"; } } else { ReplyCode=501; return "Missing filename"; } } return NULL; } VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this! mp3-0.10.2/network.c0100644000000000000000000001741411242241110012620 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "setup-mp3.h" #include "network.h" #include "data.h" #define CON_TIMEOUT 30*1000 // default timeout (ms) for connect operation #define RW_TIMEOUT 30*1000 // default timeout (ms) for read/write operations #define BUFFERSIZE 128*1024 // default ringbuffer size (bytes) for async read #define NETDOWN_TIMEOUT 30 // timeout (s) for shutting down network const char *netscript=0; // ----------------------------------------------------------------------------- int RunCommand(const char *cmd, const char *State, const char *Name=0) { int res=-1; if(cmd) { char *tmp; if(Name) tmp=aprintf("%s %s \"%s\"",cmd,State,*strescape(Name,"\"$")); else tmp=aprintf("%s %s",cmd,State); d(printf("run: executing '%s'\n",tmp)) res=SystemExec(tmp); free(tmp); } return res; } // -- cNetScript --------------------------------------------------------------- class cNetScript : public cThread { private: int count; bool pending; protected: virtual void Action(void); public: cNetScript(void); ~cNetScript(); void Up(void); void Down(void); }; cNetScript ns; cNetScript::cNetScript(void) { count=0; pending=false; } cNetScript::~cNetScript() { if(pending) Cancel(0); } void cNetScript::Up(void) { Lock(); if(netscript) { if(pending) { Cancel(0); pending=false; } RunCommand(netscript,"up"); count++; } Unlock(); } void cNetScript::Down(void) { Lock(); if(netscript) { if(--count==0) { Start(); pending=true; } } Unlock(); } void cNetScript::Action(void) { d(printf("net: netscript down delay\n")) sleep(NETDOWN_TIMEOUT); Lock(); RunCommand(netscript,"down"); Unlock(); } // -- cNetConnect -------------------------------------------------------------- class cNetConnect : public cThread { private: int fd; const char *hostname; int port; cMutex conMutex; cCondVar conCond; int result; protected: virtual void Action(void); void Done(int res); public: cNetConnect(int Fd, const char *Hostname, int Port); ~cNetConnect(); int Wait(int timeoutMs); }; cNetConnect::cNetConnect(int Fd, const char *Hostname, int Port) { fd=Fd; hostname=Hostname; port=Port; result=0; Start(); } cNetConnect::~cNetConnect() { Cancel(1); } int cNetConnect::Wait(int timeoutMs) { conMutex.Lock(); if(!result) conCond.TimedWait(conMutex,timeoutMs); conMutex.Unlock(); return result; } void cNetConnect::Done(int res) { conMutex.Lock(); result=res; conCond.Broadcast(); conMutex.Unlock(); } void cNetConnect::Action(void) { d(printf("net: name lookup %s\n",hostname)) struct hostent *hp=gethostbyname(hostname); if(hp) { struct sockaddr_in sin; sin.sin_port=htons(port); sin.sin_family=AF_INET; memcpy((char *)&sin.sin_addr,hp->h_addr,hp->h_length); d(printf("net: connecting to %s:%d\n",hostname,port)) if(connect(fd,(struct sockaddr *)&sin,sizeof(sin))==0) { d(printf("net: connected\n")) Done(1); } else { esyslog("connect() failed: %s",strerror(errno)); Done(-1); } } else { esyslog("Unknown host '%s'",hostname); Done(-1); } } // -- cNet --------------------------------------------------------------------- cNet::cNet(int size, int ConTimeoutMs, int RwTimeoutMs) :cRingBufferLinear(size>0?size:BUFFERSIZE,1,false) { fd=-1; deferedErrno=0; count=0; connected=netup=false; rwTimeout =RwTimeoutMs ? RwTimeoutMs :RW_TIMEOUT; conTimeout=ConTimeoutMs ? ConTimeoutMs:CON_TIMEOUT; SetTimeouts(50,50); } cNet::~cNet() { Disconnect(); } void cNet::Close(void) { if(connected) { connected=false; Cancel(2); deferedErrno=0; } if(fd>=0) { close(fd); fd=-1; } Clear(); count=0; } void cNet::Disconnect(void) { Close(); if(netup) { ns.Down(); netup=false; } } bool cNet::Connect(const char *hostname, const int port) { Close(); fd=socket(AF_INET,SOCK_STREAM,0); if(fd>=0) { ns.Up(); netup=true; cNetConnect *con=new cNetConnect(fd,hostname,port); int res=con->Wait(conTimeout); delete con; if(res>0) { if(fcntl(fd,F_SETFL,O_NONBLOCK)>=0) { deferedErrno=0; connected=true; Start(); return(true); } else esyslog("fnctl() failed: %s",strerror(errno)); } else if(res==0) esyslog("Connection timed out"); } else esyslog("socket() failed: %s",strerror(errno)); Disconnect(); return false; } void cNet::CopyFromBuff(unsigned char *dest, int n) { memcpy(dest,lineBuff,n); count-=n; if(count>0) memmove(lineBuff,lineBuff+n,count); } int cNet::Gets(char *dest, int len) { len--; // let room for trailing zero int c=0; while(c0) { c=count; if(c>len) c=len; CopyFromBuff(dest,c); } else { c=RingRead(dest,len); } return c; } int cNet::Write(unsigned char *dest, int len) { int t=0, r; cPoller poll(fd,true); do { if(poll.Poll(rwTimeout)) { r=write(fd,dest,len); if(r<0 && errno!=EAGAIN) { esyslog("write() failed: %s",strerror(errno)); break; } dest+=r; len-=r; t+=r; } else { esyslog("Write timed out"); break; } } while(len>0); return t; } int cNet::Puts(char *dest) { return Write((unsigned char *)dest,strlen(dest)); } int cNet::RingRead(unsigned char *dest, int len) { int r=0; const uchar *rd; for(;;) { if(!Available() && deferedErrno) { d(printf("net: ringbuffer empty, async read bailed out\n")) return -1; } rd=Get(r); if(rd && r>0) { if(r>len) r=len; memcpy(dest,rd,r); Del(r); return r; } } } void cNet::Action(void) { d(printf("net: async read started\n")) cPoller poll(fd,false); while(connected) { if(poll.Poll(rwTimeout)) { unsigned char buff[8192]; int r=read(fd,buff,sizeof(buff)); if(r>0) { int d=0; do { d+=Put(buff+d,r-d); } while(d * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___NETWORK_H #define ___NETWORK_H #include #include class cRingBufferLinear; // ---------------------------------------------------------------- class cNet : public cRingBufferLinear, cThread { private: int fd; bool connected, netup; int deferedErrno; int rwTimeout, conTimeout; unsigned char lineBuff[4096]; int count; // void Close(void); int RingRead(unsigned char *dest, int len); void CopyFromBuff(unsigned char *dest, int n); protected: virtual void Action(void); public: cNet(int size, int ConTimeoutMs, int RwTimeoutMs); ~cNet(); bool Connect(const char *hostname, const int port); void Disconnect(void); bool Connected(void) { return connected; } int Gets(char *dest, int len); int Puts(char *dest); int Read(unsigned char *dest, int len); int Write(unsigned char *dest, int len); }; #endif //___NETWORK_H mp3-0.10.2/patches/0040755000000000000000000000000010735452037012430 5ustar rootrootmp3-0.10.2/patches/cdfs-0.5c-discid-1.diff0100644000000000000000000000141210735452037016232 0ustar rootroot--- discid.c.orig Thu Dec 27 19:48:57 2001 +++ discid.c Mon Feb 23 20:18:44 2004 @@ -5,14 +5,18 @@ unsigned long discid(cd * this_cd) { - unsigned int i=0, t, n = 0; + unsigned int i=0, t, n = 0, trks=0, l=0; for (i=0; i< this_cd->tracks; i++) - n += cddb_sum((this_cd->track[T2I(i)].start_lba+CD_MSF_OFFSET)/CD_FRAMES); + if(this_cd->track[T2I(i)].type==AUDIO) { + n += cddb_sum((this_cd->track[T2I(i)].start_lba+CD_MSF_OFFSET)/CD_FRAMES); + trks++; l=i; + } - t = this_cd->track[T2I(this_cd->tracks-1)].stop_lba/CD_FRAMES; + t = (this_cd->track[T2I(l+1)].start_lba- + this_cd->track[T2I(0)].start_lba)/CD_FRAMES; - return (((n % 0xFF) << 24) | (t << 8) | this_cd->tracks); + return (((n % 0xFF) << 24) | (t << 8) | trks); } mp3-0.10.2/patches/cdfs-0.5c-discid-2.diff0100644000000000000000000000304010735452037016232 0ustar rootroot--- discid.c.orig 2001-12-27 19:48:57.000000000 +0100 +++ discid.c 2004-02-23 20:18:45.000000000 +0100 @@ -5,14 +5,18 @@ unsigned long discid(cd * this_cd) { - unsigned int i=0, t, n = 0; + unsigned int i=0, t, n = 0, trks=0, l=0; for (i=0; i< this_cd->tracks; i++) - n += cddb_sum((this_cd->track[T2I(i)].start_lba+CD_MSF_OFFSET)/CD_FRAMES); + if(this_cd->track[T2I(i)].type==AUDIO) { + n += cddb_sum((this_cd->track[T2I(i)].start_lba+CD_MSF_OFFSET)/CD_FRAMES); + trks++; l=i; + } - t = this_cd->track[T2I(this_cd->tracks-1)].stop_lba/CD_FRAMES; + t = (this_cd->track[T2I(l+1)].start_lba- + this_cd->track[T2I(0)].start_lba)/CD_FRAMES; - return (((n % 0xFF) << 24) | (t << 8) | this_cd->tracks); + return (((n % 0xFF) << 24) | (t << 8) | trks); } --- root.c.orig 2002-04-07 18:31:39.000000000 +0200 +++ root.c 2005-02-05 17:27:48.000000000 +0100 @@ -146,6 +146,10 @@ this_cd->track[i].type = AUDIO; this_cd->track[i].time = CURRENT_TIME; this_cd->track[i].iso_size = 0; + if ((t!=(this_cd->tracks - 1)) && t > 0 && (this_cd->track[i + 1].type!=AUDIO)) { + this_cd->track[i].track_size = this_cd->track[i].track_size - 11400; + this_cd->track[i].stop_lba = this_cd->track[i].stop_lba -11400; + } this_cd->track[i].track_size = this_cd->track[i].track_size * CD_FRAMESIZE_RAW + ((this_cd->raw_audio==0)?WAV_HEADER_SIZE:0); this_cd->track[i].size = this_cd->track[i].track_size; this_cd->track[i].avi = 0; mp3-0.10.2/patches/mplayer-0.90rc1-head.diff0100644000000000000000000000262110735452037016622 0ustar rootrootdiff -ruN ./libao2/ao_mpegpes.c /usr/src/MPlayer-0.90rc1/libao2/ao_mpegpes.c --- ./libao2/ao_mpegpes.c Sun Oct 6 03:08:04 2002 +++ /usr/src/MPlayer-0.90rc1/libao2/ao_mpegpes.c Wed Dec 11 15:47:20 2002 @@ -15,7 +15,7 @@ #include "../mp_msg.h" #ifdef HAVE_DVB -#include -audioMixer_t dvb_mixer={255,255}; +#include +audio_mixer_t dvb_mixer={255,255}; #endif extern int vo_mpegpes_fd; diff -ruN ./libvo/vo_mpegpes.c /usr/src/MPlayer-0.90rc1/libvo/vo_mpegpes.c --- ./libvo/vo_mpegpes.c Mon Nov 11 16:20:26 2002 +++ /usr/src/MPlayer-0.90rc1/libvo/vo_mpegpes.c Wed Dec 11 15:54:49 2002 @@ -35,12 +35,14 @@ #include #include -#include -#include -#include -#include -#include - +#include +#include +#ifndef true +#define true 1 +#endif +#ifndef false +#define false 0 +#endif #endif #include "config.h" @@ -86,11 +88,11 @@ #ifdef HAVE_DVB if(!arg){ //|O_NONBLOCK - if((vo_mpegpes_fd = open("/dev/ost/video",O_RDWR)) < 0){ + if((vo_mpegpes_fd = open("/dev/dvb/adapter0/video0",O_RDWR)) < 0){ perror("DVB VIDEO DEVICE: "); return -1; } - if((vo_mpegpes_fd2 = open("/dev/ost/audio",O_RDWR|O_NONBLOCK)) < 0){ + if((vo_mpegpes_fd2 = open("/dev/dvb/adapter0/audio0",O_RDWR|O_NONBLOCK)) < 0){ perror("DVB AUDIO DEVICE: "); return -1; } mp3-0.10.2/patches/mplayer-0.90rc1-slavemode.diff0100644000000000000000000000175710735452037017711 0ustar rootrootdiff -ruN ./mplayer.c /usr/src/MPlayer-0.90rc1/mplayer.c --- ./mplayer.c Thu Dec 5 01:18:56 2002 +++ /usr/src/MPlayer-0.90rc1/mplayer.c Wed Dec 11 15:49:50 2002 @@ -2682,6 +2682,25 @@ current_module=NULL; } +#if 1 + if(slave_mode){ + float position=0.0; + float time=0.0; + if(demuxer->file_format==DEMUXER_TYPE_AVI && sh_video->video.dwLength>2) { + // get pos from frame number / total frames + position=(float)d_video->pack_no*100.0/(float)sh_video->video.dwLength; + } + else { + off_t len = ( demuxer->movi_end - demuxer->movi_start ); + off_t pos = ( demuxer->file_format == DEMUXER_TYPE_AUDIO?stream->pos:demuxer->filepos ); + if(len>0) position=( pos - demuxer->movi_start ) * 100.0 / len; + } + if(sh_video) time=d_video->pts; + else if(sh_audio) time=sh_audio->delay; + mp_msg(MSGT_OSD,MSGL_ERR,"SLAVE: time=%.2f position=%.2f\r",time,position); + } +#endif + #ifdef HAVE_NEW_GUI if(use_gui){ guiEventHandling(); mp3-0.10.2/patches/mplayer-0.90rc5-slavemode.diff0100644000000000000000000000165610735452037017713 0ustar rootroot--- mplayer.c.orig 2003-03-10 15:02:18.000000000 +0100 +++ mplayer.c 2003-03-29 14:58:17.000000000 +0100 @@ -3114,6 +3114,25 @@ loop_seek=0; } +#if 1 + if(slave_mode){ + float position=0.0; + float time=0.0; + if(demuxer->file_format==DEMUXER_TYPE_AVI && sh_video->video.dwLength>2) { + // get pos from frame number / total frames + position=(float)d_video->pack_no*100.0/(float)sh_video->video.dwLength; + } + else { + off_t len = ( demuxer->movi_end - demuxer->movi_start ); + off_t pos = ( demuxer->file_format == DEMUXER_TYPE_AUDIO?stream->pos:demuxer->filepos ); + if(len>0) position=( pos - demuxer->movi_start ) * 100.0 / len; + } + if(sh_video) time=d_video->pts; + else if(sh_audio) time=sh_audio->delay; + mp_msg(MSGT_OSD,MSGL_ERR,"SLAVE: time=%.2f position=%.2f\r",time,position); + } +#endif + #ifdef HAVE_NEW_GUI if(use_gui){ guiEventHandling(); mp3-0.10.2/patches/mplayer-1.0cvs20070302-slavemode.diff0100644000000000000000000000204510735452037020534 0ustar rootroot--- mplayer/mplayer.c.orig 2007-03-02 13:20:05.000000000 -0800 +++ mplayer/mplayer.c 2007-03-02 13:20:39.000000000 -0800 @@ -3549,6 +3549,25 @@ edl_decision = 0; } +#if 1 + if(slave_mode){ + float position=0.0; + float time=0.0; + if(mpctx->demuxer->file_format==DEMUXER_TYPE_AVI && mpctx->sh_video->video.dwLength>2) { + // get pos from frame number / total frames + position=(float)mpctx->d_video->pack_no*100.0/(float)mpctx->sh_video->video.dwLength; + } + else { + off_t len = ( mpctx->demuxer->movi_end - mpctx->demuxer->movi_start ); + off_t pos = ( mpctx->demuxer->file_format == DEMUXER_TYPE_AUDIO?mpctx->stream->pos:mpctx->demuxer->filepos ); + if(len>0) position=( pos - mpctx->demuxer->movi_start ) * 100.0 / len; + } + if(mpctx->sh_video) time=mpctx->d_video->pts; + else if(mpctx->sh_audio) time=mpctx->sh_audio->delay; + mp_msg(MSGT_OSD,MSGL_ERR,"SLAVE: time=%.2f position=%.2f\r",time,position); + } +#endif + #ifdef HAVE_NEW_GUI if(use_gui){ guiEventHandling(); mp3-0.10.2/patches/mplayer-1.0pre2-slavemode.diff0100644000000000000000000000165610735452037020002 0ustar rootroot--- mplayer.c.orig 2003-10-04 03:24:50.000000000 +0200 +++ mplayer.c 2003-11-01 16:17:37.000000000 +0100 @@ -3444,6 +3444,25 @@ loop_seek=0; } +#if 1 + if(slave_mode){ + float position=0.0; + float time=0.0; + if(demuxer->file_format==DEMUXER_TYPE_AVI && sh_video->video.dwLength>2) { + // get pos from frame number / total frames + position=(float)d_video->pack_no*100.0/(float)sh_video->video.dwLength; + } + else { + off_t len = ( demuxer->movi_end - demuxer->movi_start ); + off_t pos = ( demuxer->file_format == DEMUXER_TYPE_AUDIO?stream->pos:demuxer->filepos ); + if(len>0) position=( pos - demuxer->movi_start ) * 100.0 / len; + } + if(sh_video) time=d_video->pts; + else if(sh_audio) time=sh_audio->delay; + mp_msg(MSGT_OSD,MSGL_ERR,"SLAVE: time=%.2f position=%.2f\r",time,position); + } +#endif + #ifdef HAVE_NEW_GUI if(use_gui){ guiEventHandling(); mp3-0.10.2/patches/mplayer-1.0rc2-slavemode.diff0100644000000000000000000000155710735452037017620 0ustar rootroot--- mplayer.c.orig 2007-10-07 21:49:33.000000000 +0200 +++ mplayer.c 2007-10-28 14:13:54.000000000 +0100 @@ -3543,6 +3543,22 @@ edl_decision = 0; } +#if 1 + if(slave_mode){ + float position=0.0; + float time=0.0; + if(mpctx->demuxer->file_format==DEMUXER_TYPE_AVI && mpctx->sh_video && mpctx->sh_video->video.dwLength>2){ + // get pos from frame number / total frames + position=(float)mpctx->d_video->pack_no*100.0f/mpctx->sh_video->video.dwLength; + } else { + position=demuxer_get_percent_pos(mpctx->demuxer); + } + if(mpctx->sh_video) time=mpctx->sh_video->pts; + else if(mpctx->sh_audio) time=playing_audio_pts(mpctx->sh_audio, mpctx->d_audio, mpctx->audio_out); + mp_msg(MSGT_OSD,MSGL_ERR,"SLAVE: time=%.2f position=%.2f\r",time,position); + } +#endif + #ifdef HAVE_NEW_GUI if(use_gui){ guiEventHandling(); mp3-0.10.2/patches/vdr-1.3.10-nostop.diff0100644000000000000000000000115310735452037016110 0ustar rootroot--- vdr-1.3.10-orig/dvbdevice.c 2004-06-06 13:28:28.000000000 +0200 +++ vdr-1.3.10/dvbdevice.c 2004-09-06 17:32:09.000000000 +0200 @@ -856,10 +890,9 @@ CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); break; case pmAudioVideo: + case pmAudioOnlyBlack: if (playMode == pmNone) TurnOffLiveMode(); - // continue with next... - case pmAudioOnlyBlack: CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo)); mp3-0.10.2/player-mp3-sample.c0100644000000000000000000002643610735452037014425 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ static const unsigned char testAudio[] = { 0x00,0x00,0x01,0xc0,0x07,0xfa,0x87,0x80,0x05,0x2f,0x46,0x05,0x80,0xcf,0xff,0xfc, 0xa4,0x00,0xd2,0x6c,0x36,0x22,0x12,0x11,0x11,0x21,0x11,0x11,0x11,0x43,0x33,0xd5, 0xa4,0x6b,0xac,0x92,0x49,0x24,0x90,0x00,0x00,0x00,0x12,0x32,0x23,0x23,0x22,0x22, 0x22,0x22,0x32,0x23,0x35,0x51,0x54,0xe3,0x1c,0x71,0xa6,0x1c,0x75,0xc7,0x99,0x75, 0xf7,0xda,0x71,0xd7,0x5c,0x65,0xd6,0xd9,0x71,0x97,0x1c,0x75,0xc7,0x5b,0x65,0xc6, 0xdc,0x6d,0xb5,0xd9,0x5d,0x95,0xd7,0x61,0x84,0x13,0x51,0x36,0x1b,0x69,0xb6,0x5b, 0x6d,0xd4,0xd3,0x5d,0x75,0x55,0x4d,0x76,0x9c,0x75,0xc7,0xdf,0x71,0xe6,0xdb,0x75, 0xd7,0x5c,0x79,0xc6,0xdd,0x75,0xd7,0xdd,0x82,0xf2,0xf4,0x60,0xcc,0xdb,0x95,0x96, 0x16,0xd5,0x4d,0xb5,0xac,0xd3,0x49,0x8e,0xbd,0xb1,0x6e,0x65,0x34,0xaa,0x69,0x40, 0x42,0x9a,0x5c,0x54,0x69,0xde,0x36,0x52,0xd1,0x88,0x89,0xdb,0x08,0x31,0xb5,0xac, 0x5e,0x6e,0xe7,0xb5,0x05,0x53,0x82,0x45,0xcb,0x54,0xeb,0xbd,0xb5,0x0b,0x98,0xc9, 0xaa,0xdb,0x12,0x65,0x41,0x1a,0x87,0xda,0xd4,0xa4,0xac,0x4d,0x45,0x51,0xe9,0x38, 0x88,0xe6,0x41,0xaa,0x6b,0x46,0xfc,0xed,0xcb,0x7a,0xda,0x0c,0xb4,0x94,0x42,0x44, 0x45,0x2f,0x69,0x1a,0xf6,0x49,0x86,0xb4,0x49,0x88,0x93,0x68,0xf8,0x85,0xd0,0x21, 0x8d,0x14,0xb2,0xea,0xa5,0xc3,0x71,0x34,0xc4,0x6e,0x2d,0x08,0x24,0xd0,0xcd,0x21, 0xe3,0x92,0x19,0x6d,0x54,0xb2,0x12,0xcd,0x64,0xc4,0xb2,0x6d,0x20,0x06,0x62,0x12, 0x11,0x16,0x96,0xd5,0x22,0x6e,0x8b,0xdc,0xba,0x95,0xe3,0x70,0xf1,0x23,0xcd,0x67, 0x06,0x85,0xb2,0x71,0xd9,0x55,0x8a,0x54,0xbb,0x37,0x98,0x63,0x60,0x6a,0x9a,0xc6, 0x00,0x5d,0x5f,0x0a,0x8a,0xc8,0x90,0xd2,0x4c,0x4c,0x81,0x44,0x00,0x90,0x01,0x82, 0x45,0x25,0x9d,0xe5,0xb6,0xa5,0x66,0x0d,0x65,0x6b,0x02,0x98,0x82,0x95,0x09,0x2e, 0x59,0xc8,0x46,0xa6,0xd6,0x32,0x29,0xdb,0x0a,0x3a,0xca,0x17,0x09,0x4a,0x34,0xd1, 0xa3,0x04,0x78,0xb2,0x57,0xa3,0x84,0x85,0x31,0x05,0x51,0x92,0x0d,0x83,0x5c,0x18, 0xb9,0xce,0x02,0x53,0x08,0xd7,0xb6,0x5c,0x4d,0x71,0x3d,0x8d,0x6d,0xc6,0xb5,0xa5, 0x99,0xda,0x8c,0xa6,0xe3,0xb5,0xb2,0x37,0xac,0xf5,0x65,0xae,0xe1,0x52,0x3b,0x05, 0x63,0xc4,0xa9,0x86,0xd6,0xb6,0x09,0x52,0x9a,0xac,0xa9,0x0f,0x1d,0x2d,0x43,0x20, 0xa5,0x6b,0x54,0xbb,0x96,0xbc,0x58,0xf9,0x4d,0x88,0x71,0xbd,0x1b,0xb0,0x93,0x1d, 0x9c,0xd0,0xc1,0x70,0xd2,0xc5,0x42,0x89,0x88,0xdb,0x66,0x0d,0x93,0x42,0xaa,0xd8, 0x85,0x13,0xa0,0x34,0x96,0x4d,0x6a,0xd4,0xe7,0x1b,0x22,0x16,0x45,0x34,0xe4,0x6b, 0x8f,0x1c,0xdb,0x4c,0xcf,0xaa,0xb5,0x36,0x0e,0xeb,0xc1,0xc8,0xeb,0x51,0x1e,0x0c, 0x99,0x51,0x2c,0xd6,0xa9,0x56,0xba,0xba,0x94,0x20,0x2c,0x4a,0xdd,0x53,0x12,0x2c, 0x6b,0x55,0x41,0xa3,0x6a,0xb2,0xd8,0x86,0xcb,0x2c,0x6e,0x26,0x8e,0x7a,0x6a,0x1b, 0x35,0x35,0xa0,0xa8,0xa3,0xa6,0x35,0x16,0x67,0x35,0xb0,0x5d,0x33,0x15,0x11,0x1a, 0x38,0xa3,0x95,0xa7,0x06,0x51,0x61,0x6a,0x88,0x20,0x54,0xa5,0xce,0xd3,0xed,0xb2, 0xa7,0x1b,0x63,0x4c,0xee,0xa4,0x66,0xa8,0x5a,0x4e,0x49,0x91,0xd2,0x38,0x69,0xef, 0x68,0x48,0xea,0x34,0x40,0x28,0x70,0xf1,0xf6,0x9c,0x80,0x05,0x28,0x5a,0xad,0x0c, 0x4b,0x3a,0x0f,0x4c,0xe3,0x49,0x6a,0x69,0x47,0x7e,0x12,0xa1,0x73,0x91,0x5e,0xb7, 0x4e,0xeb,0x93,0x29,0x59,0x08,0xac,0xd8,0x35,0xaa,0x6b,0x80,0x00,0x00,0xff,0xfc, 0xa4,0x00,0x17,0xc7,0x46,0x22,0x12,0x11,0x11,0x11,0x11,0x11,0x21,0x43,0x42,0xad, 0xa4,0x63,0xac,0x92,0x49,0x24,0x90,0x00,0x00,0x00,0xbb,0xbb,0x88,0x88,0x88,0x00, 0x00,0x00,0x00,0x00,0x04,0x50,0x29,0xb6,0x5a,0x75,0xd6,0x9e,0x79,0xb7,0x5b,0x7d, 0xc6,0xdc,0x71,0xd7,0x5e,0x7a,0x07,0x5c,0x71,0xd6,0x9d,0x71,0xc5,0xd9,0x65,0xa5, 0x9b,0x61,0xa7,0x1a,0x55,0x45,0x97,0x61,0x86,0x5b,0x5d,0xd6,0xdb,0x6d,0xc7,0x1e, 0x79,0xd5,0x54,0x61,0x86,0x5c,0x55,0x55,0x58,0x69,0xa7,0x9d,0x7e,0x08,0x1f,0x8e, 0x08,0xa0,0x86,0x07,0xe1,0x89,0xf8,0xe3,0x79,0xf8,0x1f,0x86,0x18,0xde,0x86,0x18, 0x60,0x74,0x22,0x14,0x61,0x16,0xcb,0x4d,0xb9,0x4a,0xd6,0xd6,0x6b,0x8a,0xe2,0x35, 0xc4,0x9d,0x0b,0x18,0x28,0x33,0x60,0x71,0x4d,0xa7,0x18,0x0c,0xa9,0xc2,0x9e,0xc6, 0x42,0xf8,0x11,0xa5,0x70,0x1b,0xa8,0x5b,0x7a,0x5d,0x3e,0xf3,0x26,0xa7,0x67,0x33, 0x40,0x74,0x11,0xae,0xce,0x6c,0xfa,0x6b,0x63,0x6d,0x58,0x3c,0xab,0xd5,0x32,0x93, 0x2b,0xb8,0x45,0x2a,0x9c,0x59,0x8d,0x0a,0xa6,0xdc,0x32,0x11,0x81,0x37,0xbb,0x68, 0xb7,0x0f,0x37,0xa2,0xb3,0x26,0xb6,0x33,0x08,0x62,0x29,0xad,0xaf,0x34,0x6d,0xb4, 0x5e,0x9e,0x44,0xa5,0x25,0x52,0x19,0xf9,0xa8,0x13,0x21,0xb6,0x31,0xe6,0xa0,0xc3, 0x54,0xfc,0xb2,0xd4,0x9c,0xa4,0x54,0x9b,0x9b,0x6e,0xb6,0x32,0xa2,0x3e,0x0c,0x7b, 0x5a,0x52,0x8e,0xb0,0xb4,0x01,0x44,0x5c,0xd0,0xb2,0x4f,0x37,0x65,0xb2,0xd6,0x96, 0xeb,0x3c,0xb6,0xdb,0x78,0x65,0x8e,0x64,0xc4,0xe8,0xd2,0x70,0x23,0x4d,0x4a,0x24, 0x94,0xe2,0xc3,0x5a,0x66,0xca,0xe4,0x1a,0x26,0xc8,0xac,0x41,0x2b,0x3b,0x6e,0x2d, 0xdd,0x03,0x73,0x9e,0x6b,0xaa,0xac,0x78,0xce,0x36,0x74,0xd7,0x68,0x34,0xad,0x54, 0x21,0x0a,0x76,0xb1,0x96,0x9d,0x4d,0x05,0x11,0x4f,0x1d,0xe1,0x55,0x40,0x2f,0xd8, 0x5f,0xa4,0xaa,0x03,0xd1,0x00,0x91,0x6d,0xbe,0x72,0xa6,0xae,0x0b,0x43,0xd4,0x65, 0xae,0xad,0x69,0xd2,0x9b,0x5a,0x55,0xc6,0xbe,0x1c,0x95,0x2e,0x46,0xc9,0x64,0xc5, 0x28,0x2c,0x56,0x86,0x47,0x53,0x14,0x89,0x33,0x35,0xca,0xc5,0xcc,0xbd,0x24,0xb3, 0x4a,0x58,0xaa,0x29,0x64,0x62,0x23,0x77,0x5a,0xb9,0x83,0x9d,0x8b,0xdb,0x9f,0x6e, 0x72,0xc8,0xd9,0xda,0x8e,0x75,0x5e,0xf6,0xc1,0xae,0x1b,0xb9,0xaa,0xe9,0xb7,0x97, 0x0c,0x9d,0xc5,0x81,0x27,0x86,0x01,0x55,0xc0,0xca,0x3b,0x31,0xa5,0x58,0x42,0x1b, 0x15,0x41,0xac,0xa1,0xa7,0x15,0x97,0x22,0x9b,0x32,0xb0,0x35,0x11,0xd6,0x5d,0x0d, 0x65,0x39,0x10,0x84,0xdc,0x1f,0x76,0xee,0xdc,0x60,0x90,0x04,0x40,0x77,0xba,0xa1, 0x1d,0x28,0xd4,0xad,0x69,0x2b,0x40,0x17,0x31,0x4b,0x9d,0x1a,0x24,0x11,0x1b,0x60, 0xa4,0x21,0x68,0x26,0x4a,0x3b,0xf2,0x81,0x30,0xb4,0xb9,0xc4,0x84,0x25,0x86,0x37, 0x24,0x48,0x2f,0x48,0x93,0x70,0xd2,0x5b,0xca,0x84,0xe8,0xd6,0x56,0x8e,0x54,0x83, 0xc4,0x7c,0xfe,0x29,0x2b,0xb3,0x4c,0xa5,0x1b,0x60,0x72,0x4f,0x4d,0x56,0x47,0x6e, 0xc8,0x36,0x9f,0x4b,0xa5,0x23,0xad,0x72,0x56,0xa2,0x2d,0x25,0xa2,0x51,0x46,0x13, 0x9d,0xb2,0xd6,0x55,0x86,0x31,0x5e,0x39,0x76,0xd6,0x2f,0x16,0x33,0x69,0x90,0x8e, 0x69,0x02,0x23,0x91,0x63,0x8f,0x13,0x1b,0x11,0xec,0xae,0x6d,0x46,0xf6,0x5b,0x1e, 0xdc,0x6f,0x0d,0x51,0x2d,0x68,0x36,0x2d,0x21,0x2e,0xd0,0x00,0x00,0x00,0xff,0xfc, 0xa4,0x00,0x61,0x12,0x47,0x22,0x12,0x12,0x11,0x11,0x11,0x22,0x23,0x42,0x31,0x8d, 0x92,0x5a,0x88,0x92,0x49,0x24,0x90,0x00,0x00,0x00,0xa5,0xab,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x04,0x4a,0x71,0xa7,0x19,0x6d,0x97,0x9a,0x72,0x07,0xdb,0x71, 0xf7,0x1c,0x7d,0xd6,0xde,0x76,0x08,0x1a,0x7a,0x07,0xdd,0x69,0xa6,0xdc,0x69,0xf7, 0x18,0x6d,0xc5,0xd7,0x65,0x86,0x9b,0x6d,0x96,0x5a,0x71,0xc7,0x57,0x55,0x76,0x9a, 0x65,0xa6,0x19,0x6d,0xc7,0x1b,0x79,0xa7,0x5f,0x71,0x76,0x18,0x65,0xa7,0x19,0x5d, 0x86,0xdd,0x6d,0xf8,0x60,0x86,0x18,0x62,0x91,0xe8,0xa2,0x86,0x18,0xde,0x8a,0x38, 0x61,0x91,0xa8,0xa5,0x76,0x28,0xdd,0x92,0x67,0xd0,0x74,0xbe,0xbe,0x3e,0xa6,0xee, 0xad,0x52,0x2a,0xb5,0x22,0xe6,0xd5,0xf1,0x15,0x23,0x12,0x18,0x2e,0x4a,0x6a,0x5b, 0x49,0xc5,0x20,0x56,0xab,0x05,0xcd,0xdd,0x26,0x86,0xaa,0x8a,0x1a,0xa5,0x5d,0xcf, 0x93,0xe3,0xc3,0x69,0x8a,0x46,0xd2,0x96,0x2e,0x1c,0x84,0x6d,0x2d,0xa5,0xec,0x95, 0x18,0xcc,0x95,0xd6,0xc6,0x45,0x37,0x1a,0x6b,0x5b,0x0b,0x43,0x27,0x52,0x63,0x1f, 0x64,0x92,0x64,0x12,0xe9,0x38,0xb3,0x2b,0x28,0xb8,0xa4,0x0d,0xb1,0x28,0xe3,0xa1, 0x26,0x29,0x29,0xa5,0x39,0x04,0x14,0x4c,0x9c,0x64,0x3d,0x02,0x8e,0x26,0x17,0x36, 0xb8,0x90,0xa2,0xd2,0x95,0x8c,0xd3,0x94,0x44,0x86,0x2c,0x3a,0x61,0xe1,0x6d,0x82, 0x41,0x17,0x15,0x9e,0x59,0x79,0xb3,0x72,0x99,0xca,0x88,0xdb,0x8d,0x5a,0xac,0x93, 0x56,0x43,0x00,0x2b,0x5d,0x0c,0x41,0x52,0xbd,0xad,0x5a,0xd0,0x05,0xae,0x73,0x4a, 0x60,0x8d,0x88,0x86,0x54,0xad,0x2d,0x49,0x10,0x61,0x43,0x08,0x69,0x11,0x22,0x3d, 0x10,0xb5,0x94,0x9e,0xcd,0x5e,0x8d,0x5a,0xa8,0xd9,0x8e,0x48,0x69,0x91,0x01,0x06, 0x2d,0x65,0x40,0xd4,0xb4,0x44,0x28,0xb0,0xf1,0x13,0x49,0x36,0xd4,0x53,0x5c,0xb7, 0x57,0x6b,0x9a,0xfd,0x35,0x72,0x9a,0x8e,0x6a,0xa8,0xa4,0xd1,0x48,0xc9,0x39,0x27, 0x50,0x1c,0xda,0x53,0xd5,0xac,0xc8,0xe6,0x6a,0x6b,0x93,0x18,0x91,0x16,0x1b,0xc7, 0x52,0x6c,0x8d,0x9d,0x30,0x8a,0x52,0x0e,0x0f,0x92,0xb0,0x6a,0xd8,0x57,0x23,0x70, 0x5b,0x23,0xb1,0xb6,0xae,0x72,0x15,0xe9,0x23,0x68,0x3d,0xcc,0x6b,0x54,0xd5,0x96, 0x31,0x8a,0x22,0x7a,0xd9,0x55,0x9a,0x47,0x49,0xcf,0x46,0x35,0x9e,0xa6,0x68,0xd7, 0x6b,0x24,0x47,0x85,0x52,0xa6,0xd4,0xdd,0x0a,0x0b,0x1e,0xea,0x57,0x02,0xeb,0x6b, 0x9c,0x46,0xa0,0x87,0x63,0xe5,0x6a,0xb3,0x3a,0x3e,0x26,0xcb,0x89,0x51,0x2a,0x9b, 0x94,0xe6,0x30,0xd8,0xae,0xd3,0x6a,0x3c,0x52,0x31,0xad,0x54,0x98,0x56,0xb2,0xb0, 0x0a,0x98,0x29,0x94,0x1c,0xe5,0xb5,0x6c,0x1a,0xd6,0xb6,0x73,0xc4,0x14,0x6c,0xb9, 0x91,0x98,0xd6,0xda,0xa7,0xb8,0xa8,0x2b,0x83,0x35,0xad,0x88,0xea,0x4c,0x95,0xc0, 0x77,0xf5,0xe4,0xe2,0x43,0x5c,0xa5,0xf0,0xba,0x56,0x21,0x1a,0xcb,0x35,0xad,0x6b, 0x71,0xac,0xcf,0xd5,0x55,0xbc,0x9e,0x36,0x42,0xcb,0x23,0x48,0xa5,0x44,0xb8,0xf1, 0xbe,0x8e,0x23,0x50,0xd1,0x04,0x4b,0x63,0x0d,0x36,0xb5,0xa1,0xba,0xa4,0xd1,0x4c, 0xb4,0x8c,0x6b,0x5a,0xd6,0xb7,0x17,0xc5,0x55,0x9d,0xac,0x90,0x9a,0x44,0xc8,0xd5, 0x65,0xd4,0xbe,0x70,0xf9,0x37,0x78,0xf2,0x0e,0x06,0x24,0xea,0xba,0x6a,0x83,0x52, 0x94,0x92,0x4a,0x6d,0xa0,0xbe,0xb1,0x82,0xa2,0xb8,0x42,0x00,0x00,0x00,0xff,0xfc, 0xa4,0x00,0x63,0x29,0x45,0x23,0x22,0x34,0x33,0x33,0x23,0x23,0x33,0x23,0x23,0x6d, 0x22,0x51,0x45,0x22,0x49,0x24,0x90,0x00,0x00,0x00,0xaa,0x7e,0xbb,0x6a,0xaa,0xea, 0xaa,0xeb,0xaa,0xae,0x23,0x4a,0x4d,0x25,0x18,0x49,0x44,0x95,0x4d,0x44,0x95,0x55, 0x25,0xd5,0x69,0x55,0x55,0x59,0x45,0x93,0x61,0x55,0x94,0x55,0x45,0x99,0x61,0xb5, 0x57,0x5d,0x76,0x56,0x5d,0x75,0xd9,0x61,0xa5,0xd9,0x69,0x66,0xd7,0x73,0xeb,0x6d, 0xfa,0x55,0x25,0xa0,0xb6,0xdb,0x61,0xab,0x54,0x06,0x99,0x49,0xb6,0x9a,0x36,0x65, 0x25,0x6c,0x8d,0xd2,0x6d,0xb8,0x69,0x44,0x5b,0x70,0xdf,0x39,0xa2,0x5a,0xa9,0xb5, 0xeb,0xdd,0xa4,0x23,0x2a,0x72,0x63,0x32,0xc7,0x4e,0xdc,0x56,0xb2,0xb4,0x46,0x39, 0x29,0xaa,0x9d,0xc1,0x8c,0xdd,0xd9,0x32,0x73,0x26,0x70,0x35,0x24,0x3a,0x83,0x36, 0x9d,0x89,0xc7,0xaf,0x9c,0xd9,0x56,0xcf,0x33,0xe2,0xdb,0x77,0x38,0xed,0x53,0x4e, 0x41,0x71,0xde,0x0a,0x15,0x83,0x4c,0x09,0x59,0x86,0xea,0x99,0xb7,0x35,0x7a,0x43, 0x68,0xb9,0x32,0x16,0xe4,0xc8,0xd9,0x5c,0x1d,0xa5,0x24,0x53,0xfa,0xed,0x65,0x96, 0xba,0x2b,0xea,0x2e,0x2a,0x96,0xb7,0x22,0x70,0xa6,0x62,0x8e,0x28,0x1a,0xaa,0xd0, 0x9b,0x6e,0x24,0x43,0x08,0x9b,0x8d,0xc7,0x27,0xb3,0x61,0xbb,0x8c,0x4e,0x29,0x89, 0x24,0xf9,0x39,0x95,0xac,0x58,0xc5,0x39,0xfb,0x52,0xad,0x42,0xe6,0xba,0x0f,0x6a, 0xda,0xec,0x30,0xd6,0x67,0xb0,0x71,0x99,0xed,0xd2,0xc2,0xa2,0x6c,0xe2,0x75,0x02, 0xcb,0x48,0x1d,0x37,0x1d,0x82,0x26,0xd5,0x87,0x1d,0xb2,0xe9,0x8d,0xd7,0x73,0xc8, 0x48,0x99,0xd3,0x1b,0x12,0x24,0x20,0xe7,0x46,0x2c,0x69,0x92,0x7e,0xf7,0xb5,0xd8, 0xb3,0x29,0x36,0x6c,0xcc,0xcc,0x65,0xb7,0x0c,0x2f,0x14,0x72,0x28,0x4e,0x12,0xe2, }; mp3-0.10.2/player-mp3.c0100644000000000000000000014776511242241354013147 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #ifdef WITH_OSS #include #endif #include #include #include #include #include #include #include "common.h" #include "setup-mp3.h" #include "player-mp3.h" #include "data-mp3.h" #include "decoder.h" #include "decoder-core.h" #ifndef NO_DEBUG //#define DEBUG_MODE // debug playmode changes #define DEBUG_BGR // debug backround scan thread #define DEBUG_DELAY 300 // debug write/decode delays //#define ACC_DUMP // dump limiter lookup table to /tmp/limiter #endif #if !defined(NO_DEBUG) && defined(DEBUG_MODE) #define dm(x) { (x); } #else #define dm(x) ; #endif #if !defined(NO_DEBUG) && defined(DEBUG_BGR) #define db(x) { (x); } #else #define db(x) ; #endif // ---------------------------------------------------------------- #define MP3BUFSIZE (1024*1024) // output ringbuffer size #define OUT_BITS 16 // output 16 bit samples to DVB driver #define OUT_FACT (OUT_BITS/8*2) // output factor is 16 bit & 2 channels -> 4 bytes // cResample #define MAX_NSAMPLES (1152*7) // max. buffer for resampled frame // cNormalize #define MIN_GAIN 0.03 // min. gain required to launch the normalizer #define MAX_GAIN 3.0 // max. allowed gain #define USE_FAST_LIMITER #define LIM_ACC 12 // bit, accuracy for lookup table #define F_LIM_MAX (mad_fixed_t)((1<<(MAD_F_FRACBITS+2))-1) // max. value covered by lookup table #define LIM_SHIFT (MAD_F_FRACBITS-LIM_ACC) // shift value for table lookup #define F_LIM_JMP (mad_fixed_t)(1<newrate*6) { // out of range esyslog("WARNING: samplerate %d out of range 8000-%d\n",oldrate,newrate*6); return 0; } ratio=mad_f_tofixed((double)oldrate/(double)newrate); step=0; last=0; #ifdef DEBUG static mad_fixed_t oldratio=0; if(oldratio!=ratio) { printf("mad: new resample ratio %f (from %d kHz to %d kHz)\n",mad_f_todouble(ratio),oldrate,newrate); oldratio=ratio; } #endif return ratio!=MAD_F_ONE; } unsigned int cResample::ResampleBlock(unsigned int nsamples, const mad_fixed_t *old) { // This resampling algorithm is based on a linear interpolation, which is // not at all the best sounding but is relatively fast and efficient. // // A better algorithm would be one that implements a bandlimited // interpolation. mad_fixed_t *nsam=resampled; const mad_fixed_t *end=old+nsamples; const mad_fixed_t *begin=nsam; if(step < 0) { step = mad_f_fracpart(-step); while (step < MAD_F_ONE) { *nsam++ = step ? last+mad_f_mul(*old-last,step) : last; step += ratio; if(((step + 0x00000080L) & 0x0fffff00L) == 0) step = (step + 0x00000080L) & ~0x0fffffffL; } step -= MAD_F_ONE; } while (end - old > 1 + mad_f_intpart(step)) { old += mad_f_intpart(step); step = mad_f_fracpart(step); *nsam++ = step ? *old + mad_f_mul(old[1] - old[0], step) : *old; step += ratio; if (((step + 0x00000080L) & 0x0fffff00L) == 0) step = (step + 0x00000080L) & ~0x0fffffffL; } if (end - old == 1 + mad_f_intpart(step)) { last = end[-1]; step = -step; } else step -= mad_f_fromint(end - old); return nsam-begin; } // --- cLevel ---------------------------------------------------------------- // The normalize algorithm and parts of the code has been adapted from the // Normalize 0.7 project. (C) 1999-2002, Chris Vaill // A little background on how normalize computes the volume // of a wav file, in case you want to know just how your // files are being munged: // // The volumes calculated are RMS amplitudes, which corre­ // spond (roughly) to perceived volume. Taking the RMS ampli­ // tude of an entire file would not give us quite the measure // we want, though, because a quiet song punctuated by short // loud parts would average out to a quiet song, and the // adjustment we would compute would make the loud parts // excessively loud. // // What we want is to consider the maximum volume of the // file, and normalize according to that. We break up the // signal into 100 chunks per second, and get the signal // power of each chunk, in order to get an estimation of // "instantaneous power" over time. This "instantaneous // power" signal varies too much to get a good measure of the // original signal's maximum sustained power, so we run a // smoothing algorithm over the power signal (specifically, a // mean filter with a window width of 100 elements). The max­ // imum point of the smoothed power signal turns out to be a // good measure of the maximum sustained power of the file. // We can then take the square root of the power to get maxi­ // mum sustained RMS amplitude. class cLevel { private: double maxpow; mad_fixed_t peak; struct Power { // smooth int npow, wpow; double powsum, pows[POW_WIN]; // sum unsigned int nsum; double sum; } power[2]; // inline void AddPower(struct Power *p, double pow); public: void Init(void); void GetPower(struct mad_pcm *pcm); double GetLevel(void); double GetPeak(void); }; void cLevel::Init(void) { for(int l=0 ; l<2 ; l++) { struct Power *p=&power[l]; p->sum=p->powsum=0.0; p->wpow=p->npow=p->nsum=0; for(int i=POW_WIN-1 ; i>=0 ; i--) p->pows[i]=0.0; } maxpow=0.0; peak=0; } void cLevel::GetPower(struct mad_pcm *pcm) { for(int i=0 ; ichannels ; i++) { struct Power *p=&power[i]; mad_fixed_t *data=pcm->samples[i]; for(int n=pcm->length ; n>0 ; n--) { if(*data < -peak) peak = -*data; if(*data > peak) peak = *data; double s=mad_f_todouble(*data++); p->sum+=(s*s); if(++(p->nsum)>=pcm->samplerate/100) { AddPower(p,p->sum/(double)p->nsum); p->sum=0.0; p->nsum=0; } } } } void cLevel::AddPower(struct Power *p, double pow) { p->powsum+=pow; if(p->npow>=POW_WIN) { if(p->powsum>maxpow) maxpow=p->powsum; p->powsum-=p->pows[p->wpow]; } else p->npow++; p->pows[p->wpow]=pow; p->wpow=(p->wpow+1) % POW_WIN; } double cLevel::GetLevel(void) { if(maxpowmaxpow) maxpow=power[0].powsum; if(power[1].powsum>maxpow) maxpow=power[1].powsum; } double level=sqrt(maxpow/(double)POW_WIN); // adjust for the smoothing window size and root d(printf("norm: new volumen level=%f peak=%f\n",level,mad_f_todouble(peak))) return level; } double cLevel::GetPeak(void) { return mad_f_todouble(peak); } // --- cNormalize ------------------------------------------------------------ class cNormalize { private: mad_fixed_t gain; double d_limlvl, one_limlvl; mad_fixed_t limlvl; bool dogain, dolimit; #ifdef DEBUG // stats unsigned long limited, clipped, total; mad_fixed_t peak; #endif // limiter #ifdef USE_FAST_LIMITER mad_fixed_t *table, tablestart; int tablesize; inline mad_fixed_t FastLimiter(mad_fixed_t x); #endif inline mad_fixed_t Limiter(mad_fixed_t x); public: cNormalize(void); ~cNormalize(); void Init(double Level, double Peak); void Stats(void); void AddGain(struct mad_pcm *pcm); }; cNormalize::cNormalize(void) { d_limlvl=(double)MP3Setup.LimiterLevel/100.0; one_limlvl=1-d_limlvl; limlvl=mad_f_tofixed(d_limlvl); d(printf("norm: lim_lev=%f lim_acc=%d\n",d_limlvl,LIM_ACC)) #ifdef USE_FAST_LIMITER mad_fixed_t start=limlvl & ~(F_LIM_JMP-1); tablestart=start; tablesize=(unsigned int)(F_LIM_MAX-start)/F_LIM_JMP + 2; table=new mad_fixed_t[tablesize]; if(table) { d(printf("norm: table size=%d start=%08x jump=%08x\n",tablesize,start,F_LIM_JMP)) for(int i=0 ; i=limlvl ; x-=mad_f_tofixed(1e-4)) { mad_fixed_t diff=mad_f_abs(Limiter(x)-FastLimiter(x)); if(diff>maxdiff) maxdiff=diff; #ifdef ACC_DUMP fprintf(out,"%0.10f\t%0.10f\t%0.10f\t%0.10f\t%0.10f\n", mad_f_todouble(x),mad_f_todouble(Limiter(x)),mad_f_todouble(FastLimiter(x)),mad_f_todouble(diff),mad_f_todouble(maxdiff)); if(ferror(out)) break; #endif } #ifdef ACC_DUMP fclose(out); #endif d(printf("norm: accuracy %.12f\n",mad_f_todouble(maxdiff))) if(mad_f_todouble(maxdiff)>1e-6) { esyslog("ERROR: accuracy check failed, normalizer disabled"); delete table; table=0; } } else esyslog("ERROR: no memory for lookup table, normalizer disabled"); #endif // USE_FAST_LIMITER } cNormalize::~cNormalize() { #ifdef USE_FAST_LIMITER delete[] table; #endif } void cNormalize::Init(double Level, double Peak) { double Target=(double)MP3Setup.TargetLevel/100.0; double dgain=Target/Level; if(dgain>MAX_GAIN) dgain=MAX_GAIN; gain=mad_f_tofixed(dgain); // Check if we actually need to apply a gain dogain=(Target>0.0 && fabs(1-dgain)>MIN_GAIN); #ifdef USE_FAST_LIMITER if(!table) dogain=false; #endif // Check if we actually need to do limiting: // we have to if limiter is enabled, if gain>1 and if the peaks will clip. dolimit=(d_limlvl<1.0 && dgain>1.0 && Peak*dgain>1.0); #ifdef DEBUG printf("norm: gain=%f dogain=%d dolimit=%d (target=%f level=%f peak=%f)\n",dgain,dogain,dolimit,Target,Level,Peak); limited=clipped=total=0; peak=0; #endif } void cNormalize::Stats(void) { #ifdef DEBUG if(total) printf("norm: stats tot=%ld lim=%ld/%.3f%% clip=%ld/%.3f%% peak=%.3f\n", total,limited,(double)limited/total*100.0,clipped,(double)clipped/total*100.0,mad_f_todouble(peak)); #endif } mad_fixed_t cNormalize::Limiter(mad_fixed_t x) { // Limiter function: // // / x (for x <= lev) // x' = | // \ tanh((x - lev) / (1-lev)) * (1-lev) + lev (for x > lev) // // call only with x>=0. For negative samples, preserve sign outside this function // // With limiter level = 0, this is equivalent to a tanh() function; // with limiter level = 1, this is equivalent to clipping. if(x>limlvl) { #ifdef DEBUG if(x>MAD_F_ONE) clipped++; limited++; #endif x=mad_f_tofixed(tanh((mad_f_todouble(x)-d_limlvl) / one_limlvl) * one_limlvl + d_limlvl); } return x; } #ifdef USE_FAST_LIMITER mad_fixed_t cNormalize::FastLimiter(mad_fixed_t x) { // The fast algorithm is based on a linear interpolation between the // the values in the lookup table. Relays heavly on libmads fixed point format. if(x>limlvl) { int i=(unsigned int)(x-tablestart)/F_LIM_JMP; #ifdef DEBUG if(x>MAD_F_ONE) clipped++; limited++; if(i>=tablesize) printf("norm: overflow x=%f x-ts=%f i=%d tsize=%d\n", mad_f_todouble(x),mad_f_todouble(x-tablestart),i,tablesize); #endif mad_fixed_t r=x & (F_LIM_JMP-1); x=MAD_F_ONE; if(i>MAD_F_FRACBITS // which is senseless in the case of following <>LIM_SHIFT; // better, don't know if works on all machines } } return x; } #endif #ifdef USE_FAST_LIMITER #define LIMITER_FUNC FastLimiter #else #define LIMITER_FUNC Limiter #endif void cNormalize::AddGain(struct mad_pcm *pcm) { if(dogain) { for(int i=0 ; ichannels ; i++) { mad_fixed_t *data=pcm->samples[i]; #ifdef DEBUG total+=pcm->length; #endif if(dolimit) { for(int n=pcm->length ; n>0 ; n--) { mad_fixed_t s=mad_f_mul(*data,gain); if(s<0) { s=-s; #ifdef DEBUG if(s>peak) peak=s; #endif s=LIMITER_FUNC(s); s=-s; } else { #ifdef DEBUG if(s>peak) peak=s; #endif s=LIMITER_FUNC(s); } *data++=s; } } else { for(int n=pcm->length ; n>0 ; n--) { mad_fixed_t s=mad_f_mul(*data,gain); #ifdef DEBUG if(s>peak) peak=s; else if(-s>peak) peak=-s; #endif if(s>MAD_F_ONE) s=MAD_F_ONE; // do clipping if(s<-MAD_F_ONE) s=-MAD_F_ONE; *data++=s; } } } } } // --- cScale ---------------------------------------------------------------- // The dither code has been adapted from the madplay project // (audio.c) found in the libmad distribution enum eAudioMode { amRoundBE, amDitherBE, amRoundLE, amDitherLE }; class cScale { private: enum { MIN=-MAD_F_ONE, MAX=MAD_F_ONE - 1 }; #ifdef DEBUG // audio stats unsigned long clipped_samples; mad_fixed_t peak_clipping; mad_fixed_t peak_sample; #endif // dither struct dither { mad_fixed_t error[3]; mad_fixed_t random; } leftD, rightD; // inline mad_fixed_t Clip(mad_fixed_t sample, bool stats=true); inline unsigned long Prng(unsigned long state); signed long LinearRound(mad_fixed_t sample); signed long LinearDither(mad_fixed_t sample, struct dither *dither); public: void Init(void); void Stats(void); unsigned int ScaleBlock(unsigned char *data, unsigned int size, unsigned int &nsamples, const mad_fixed_t * &left, const mad_fixed_t * &right, eAudioMode mode); }; void cScale::Init(void) { #ifdef DEBUG clipped_samples=0; peak_clipping=peak_sample=0; #endif memset(&leftD,0,sizeof(leftD)); memset(&rightD,0,sizeof(rightD)); } void cScale::Stats(void) { #ifdef DEBUG printf("mp3: scale stats clipped=%ld peak_clip=%f peak=%f\n", clipped_samples,mad_f_todouble(peak_clipping),mad_f_todouble(peak_sample)); #endif } // gather signal statistics while clipping mad_fixed_t cScale::Clip(mad_fixed_t sample, bool stats) { #ifndef DEBUG if (sample > MAX) sample = MAX; if (sample < MIN) sample = MIN; #else if(!stats) { if (sample > MAX) sample = MAX; if (sample < MIN) sample = MIN; } else { if (sample >= peak_sample) { if (sample > MAX) { ++clipped_samples; if (sample - MAX > peak_clipping) peak_clipping = sample - MAX; sample = MAX; } peak_sample = sample; } else if (sample < -peak_sample) { if (sample < MIN) { ++clipped_samples; if (MIN - sample > peak_clipping) peak_clipping = MIN - sample; sample = MIN; } peak_sample = -sample; } } #endif return sample; } // generic linear sample quantize routine signed long cScale::LinearRound(mad_fixed_t sample) { // round sample += (1L << (MAD_F_FRACBITS - OUT_BITS)); // clip sample=Clip(sample); // quantize and scale return sample >> (MAD_F_FRACBITS + 1 - OUT_BITS); } // 32-bit pseudo-random number generator unsigned long cScale::Prng(unsigned long state) { return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; } // generic linear sample quantize and dither routine signed long cScale::LinearDither(mad_fixed_t sample, struct dither *dither) { // noise shape sample += dither->error[0] - dither->error[1] + dither->error[2]; dither->error[2] = dither->error[1]; dither->error[1] = dither->error[0] / 2; // bias mad_fixed_t output = sample + (1L << (MAD_F_FRACBITS + 1 - OUT_BITS - 1)); const int scalebits = MAD_F_FRACBITS + 1 - OUT_BITS; const mad_fixed_t mask = (1L << scalebits) - 1; // dither const mad_fixed_t random = Prng(dither->random); output += (random & mask) - (dither->random & mask); dither->random = random; // clip output=Clip(output); sample=Clip(sample,false); // quantize output &= ~mask; // error feedback dither->error[0] = sample - output; // scale return output >> scalebits; } #define PUT_BE(data,sample) { *data++=(sample)>>8; *data++=(sample)>>0; } #define PUT_LE(data,sample) { *data++=(sample)>>0; *data++=(sample)>>8; } // write a block of signed 16-bit PCM samples unsigned int cScale::ScaleBlock(unsigned char *data, unsigned int size, unsigned int &nsamples, const mad_fixed_t * &left, const mad_fixed_t * &right, eAudioMode mode) { unsigned int len=size/OUT_FACT; if(len>nsamples) { len=nsamples; size=len*OUT_FACT; } nsamples-=len; switch(mode) { case amRoundBE: while(len--) { signed int sample=LinearRound(*left++); PUT_BE(data,sample); if(right) sample=LinearRound(*right++); PUT_BE(data,sample); } break; case amDitherBE: while(len--) { signed int sample=LinearDither(*left++,&leftD); PUT_BE(data,sample); if(right) sample=LinearDither(*right++,&rightD); PUT_BE(data,sample); } break; case amRoundLE: while(len--) { signed int sample=LinearRound(*left++); PUT_LE(data,sample); if(right) sample=LinearRound(*right++); PUT_LE(data,sample); } break; case amDitherLE: while(len--) { signed int sample=LinearDither(*left++,&leftD); PUT_LE(data,sample); if(right) sample=LinearDither(*right++,&rightD); PUT_LE(data,sample); } break; } return size; } // --- cShuffle ---------------------------------------------------------------- class cShuffle { private: int *shuffle, max; unsigned int seed; // int Index(int pos); public: cShuffle(void); ~cShuffle(); void Shuffle(int num, int curr); void Del(int pos); void Flush(void); int First(void); int Next(int curr); int Prev(int curr); int Goto(int pos, int curr); }; cShuffle::cShuffle(void) { shuffle=0; max=0; seed=time(0); } cShuffle::~cShuffle(void) { Flush(); } void cShuffle::Flush(void) { delete shuffle; shuffle=0; max=0; } int cShuffle::Index(int pos) { if(pos>=0) for(int i=0; imax) { memcpy(ns,shuffle,max*sizeof(int)); oldmax=max; } delete shuffle; } shuffle=ns; max=num; } if(!oldmax) curr=-1; for(int i=oldmax ; i=2) { for(int i=in ; i= i); int t=shuffle[i]; shuffle[i]=shuffle[ran+in]; shuffle[ran+in]=t; } } #ifdef DEBUG printf("shuffle: order (%d , %d -> %d) ",num,curr,in); for(int i=0 ; i=0) { if(i+1=0 && i+10) ? shuffle[i-1] : -1; } int cShuffle::Goto(int pos, int curr) { int i=Index(curr); int g=Index(pos); if(g>=0) { if(gi) { for(int l=g; l>i+1; l--) shuffle[l]=shuffle[l-1]; shuffle[i+1]=pos; } #ifdef DEBUG printf("shuffle: goto order (%d -> %d , %d -> %d) ",pos,g,curr,i); for(int i=0 ; i0); shuffleMode=(MP3Setup.InitShuffleMode>0); } cPlayManager::~cPlayManager() { Flush(); Release(); listMutex.Lock(); stopscan=true; bgCond.Broadcast(); listMutex.Unlock(); Cancel(2); delete shuffle; } void cPlayManager::ThrottleWait(void) { while(!stopscan && !release && throttle) { db(printf("mgr: background scan throttled\n")) bgCond.Wait(listMutex); db(printf("mgr: background scan throttle wakeup\n")) } } void cPlayManager::Action(void) { db(printf("mgr: background scan thread started (pid=%d)\n", getpid())) if(nice(5)<0); listMutex.Lock(); while(!stopscan) { for(scan=list.First(); !stopscan && !release && scan; scan=list.Next(scan)) { ThrottleWait(); listMutex.Unlock(); if(!(scan->user & SCANNED_ID3)) { db(printf("mgr: scanning (id3) %s\n",scan->Name())) cSongInfo *si=scan->Info(true); if(si && si->Level>0.0) scan->user|=SCANNED_LVL; scan->user|=SCANNED_ID3; } listMutex.Lock(); } if(MP3Setup.BgrScan>1) { pass2=true; for(scan=list.First(); !stopscan && !release && scan; scan=list.Next(scan)) { if(scan==curr) continue; ThrottleWait(); listMutex.Unlock(); if(!(scan->user & SCANNED_LVL)) { cDecoder *dec=scan->Decoder(); if(dec) { cSongInfo *si=scan->Info(false); if(!dec->IsStream() && (!si || si->Level<=0.0) && dec->Start()) { db(printf("mgr: scanning (lvl) %s\n",scan->Name())) cLevel level; level.Init(); bool go=true; while(go && !release) { if(throttle) { listMutex.Lock(); ThrottleWait(); listMutex.Unlock(); continue; } struct Decode *ds=dec->Decode(); switch(ds->status) { case dsPlay: level.GetPower(ds->pcm); break; case dsSkip: case dsSoftError: break; case dsEof: { double l=level.GetLevel(); if(l>0.0) { cSongInfo *si=dec->SongInfo(false); cFileInfo *fi=dec->FileInfo(); if(si && fi) { si->Level=l; si->Peak=level.GetPeak(); InfoCache.Cache(si,fi); } } } //fall through case dsOK: case dsError: scan->user|=SCANNED_LVL; go=false; break; } } } else scan->user|=SCANNED_LVL; dec->Stop(); } } listMutex.Lock(); } pass2=false; } do { scan=0; release=false; fgCond.Broadcast(); db(printf("mgr: background scan idle\n")) bgCond.Wait(listMutex); db(printf("mgr: background scan idle wakeup\n")) } while(!stopscan && (release || throttle)); } listMutex.Unlock(); db(printf("mgr: background scan thread ended (pid=%d)\n", getpid())) } void cPlayManager::Throttle(bool thr) { if(MP3Setup.BgrScan) { if(!thr && throttle) { db(printf("mgr: bgr-scan -> run (%llu)\n",cTimeMs::Now())) listMutex.Lock(); throttle=false; bgCond.Broadcast(); listMutex.Unlock(); } if(thr && !throttle) { db(printf("mgr: bgr-scan -> throttle (%llu)\n",cTimeMs::Now())) throttle=true; } } } void cPlayManager::ToggleShuffle(void) { shuffleMode=!shuffleMode; d(printf("mgr: shuffle mode toggled : %d\n",shuffleMode)) if(shuffleMode && !eol) { curr=0; currIndex=-1; shuffle->Shuffle(maxIndex+1,-1); Next(); } } void cPlayManager::ToggleLoop(void) { loopMode=!loopMode; d(printf("mgr: loop mode toggled : %d\n",loopMode)) } bool cPlayManager::Info(int num, cMP3PlayInfo *pi) { cSong *s; int idx=num-1; if(idx<0) { idx=currIndex; s=curr; } else { s=list.Get(idx); } memset(pi,0,sizeof(*pi)); pi->Num=idx+1; pi->MaxNum=maxIndex+1; pi->Loop=loopMode; pi->Shuffle=shuffleMode; bool res=false; if(s) { strn0cpy(pi->Title,s->Name(),sizeof(pi->Title)); strn0cpy(pi->Filename,s->FullPath(),sizeof(pi->Filename)); cSongInfo *si=s->Info(false); if(si && si->HasInfo()) { static const char *modestr[] = { "Mono","Dual","Joint-Stereo","Stereo" }; if(si->Title) strn0cpy(pi->Title,si->Title,sizeof(pi->Title)); if(si->Artist) strn0cpy(pi->Artist,si->Artist,sizeof(pi->Artist)); if(si->Album) strn0cpy(pi->Album,si->Album,sizeof(pi->Album)); strn0cpy(pi->SMode,modestr[si->ChMode],sizeof(pi->SMode)); pi->Year=si->Year; pi->SampleFreq=si->SampleFreq; pi->Bitrate=si->Bitrate; pi->MaxBitrate=si->MaxBitrate; res=true; } } pi->Hash=MakeHashBuff((char *)pi,(char *)&pi->Loop-(char *)pi); return res; } void cPlayManager::Add(cPlayList *pl) { cMutexLock lock(&listMutex); bool real=false; for(cSong *song=pl->First(); song; song=pl->cList::Next(song)) { cSong *ns=new cSong(song); list.Add(ns); real=true; } if(real) { if(MP3Setup.BgrScan) { stopscan=false; if(!Active()) Start(); } else stopscan=true; bgCond.Broadcast(); maxIndex=list.Count()-1; if(shuffleMode) shuffle->Shuffle(maxIndex+1,currIndex); if(!curr) Next(); } } void cPlayManager::Flush(void) { cMutexLock lock(&listMutex); Halt(); list.Clear(); shuffle->Flush(); } void cPlayManager::Halt(void) { cMutexLock lock(&listMutex); curr=0; currIndex=-1; playNew=true; stopscan=true; bgCond.Broadcast(); NoScan(0); NoPlay(0); } void cPlayManager::NoScan(cSong *nono) { // call with listMutex locked!! while((nono && pass2 && scan==nono) || (!nono && scan)) { release=true; bgCond.Broadcast(); d(printf("mgr: waiting for bgr release ... (pass2=%d nono=%p scan=%p)\n",pass2,nono,scan)) fgCond.Wait(listMutex); } } void cPlayManager::NoPlay(cSong *nono) { // call with listMutex locked!! while((nono && play==nono) || (!nono && play)) { playNew=true; fgCond.Wait(listMutex); } } bool cPlayManager::Next(void) { cMutexLock lock(&listMutex); int ni; cSong *n; if(shuffleMode) { if(curr) { ni=shuffle->Next(currIndex); if(ni<0) { if(loopMode || eol) { shuffle->Shuffle(maxIndex+1,-1); ni=shuffle->First(); } else eol=true; } } else ni=shuffle->First(); n=(ni>=0) ? list.Get(ni) : 0; } else { if(curr) { n=list.cList::Next(curr); if(!n) { if(loopMode || eol) n=list.First(); else eol=true; } } else n=list.First(); ni=n ? n->Index() : -1; } if(n) { curr=n; currIndex=ni; playNew=true; eol=false; d(printf("mgr: next -> %d\n",currIndex)) return true; } return false; } bool cPlayManager::Prev(void) { cMutexLock lock(&listMutex); int ni; cSong *n; if(shuffleMode) { ni=shuffle->Prev(currIndex); n=(ni>=0) ? list.Get(ni) : 0; } else { n=list.cList::Prev(curr); ni=n ? n->Index() : -1; } if(n) { curr=n; currIndex=ni; playNew=true; eol=false; d(printf("mgr: prev -> %d\n",currIndex)) return true; } return false; } void cPlayManager::Goto(int num) { cMutexLock lock(&listMutex); if(num>0 && num<=maxIndex+1) { int idx=num-1; if(shuffleMode) { if(eol) { shuffle->Shuffle(maxIndex+1,-1); currIndex=shuffle->Goto(idx,-1); } else currIndex=shuffle->Goto(idx,currIndex); } else currIndex=idx; curr=(currIndex>=0) ? list.Get(currIndex) : 0; playNew=true; eol=false; d(printf("mgr: goto -> %d\n",currIndex)) } } cSong *cPlayManager::Current(void) { cMutexLock lock(&listMutex); if(!play) { NoScan(curr); play=curr; playNew=false; if(play) d(printf("mgr: playing %s\n",play->Name())) else d(printf("mgr: nothing to play\n")) fgCond.Broadcast(); } return play; } bool cPlayManager::NextCurrent(void) { cMutexLock lock(&listMutex); return (!eol && (playNew || Next())); } bool cPlayManager::NewCurrent(void) { return playNew; } void cPlayManager::Release(void) { cMutexLock lock(&listMutex); play=0; fgCond.Broadcast(); } // --- cOutput ----------------------------------------------------------------- struct FrameHeader { unsigned int samplerate; }; #define FHS sizeof(struct FrameHeader) class cOutput { protected: cMP3Player *player; cScale scale; public: cOutput(cMP3Player *Player); virtual ~cOutput() {} virtual void Init(void); virtual unsigned int SampleRate(unsigned int PcmSampleRate)=0; virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr)=0; virtual int Output(const unsigned char *Data, int Len, bool SOF)=0; virtual bool Poll(void)=0; virtual void Play(void)=0; virtual void Pause(void)=0; #ifdef DEBUG virtual void Stats(void); #endif }; cOutput::cOutput(cMP3Player *Player) { player=Player; } void cOutput::Init(void) { scale.Init(); } #ifdef DEBUG void cOutput::Stats(void) { scale.Stats(); } #endif // --- cOutputDvb -------------------------------------------------------------- /* struct LPCMHeader { int id:8; // id int frame_count:8; // number of frames int access_ptr:16; // first acces unit pointer, i.e. start of audio frame bool emphasis:1; // audio emphasis on-off bool mute:1; // audio mute on-off bool reserved:1; // reserved int frame_number:5; // audio frame number int quant_wlen:2; // quantization word length int sample_freq:2; // audio sampling frequency (48khz=0, 96khz=1, 44,1khz=2, 32khz=3) bool reserved2:1; // reserved int chan_count:3; // number of audio channels - 1 (e.g. stereo = 1) int dyn_range_ctrl:8; // dynamic range control (0x80 if off) }; */ #define FRAMESIZE 2048 // max. frame size allowed for DVB driver class cOutputDvb : public cOutput { private: cPoller poll; unsigned int outSr; bool only48khz; public: cOutputDvb(cMP3Player *Player); virtual unsigned int SampleRate(unsigned int PcmSampleRate); virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr); virtual int Output(const unsigned char *Data, int Len, bool SOF); virtual bool Poll(void); virtual void Play(void); virtual void Pause(void); }; cOutputDvb::cOutputDvb(cMP3Player *Player) :cOutput(Player) { only48khz=MP3Setup.Only48kHz; outSr=0; cDevice::PrimaryDevice()->SetCurrentAudioTrack(ttAudio); d(printf("mp3-dvb: using DVB output\n")) } unsigned int cOutputDvb::SampleRate(unsigned int PcmSampleRate) { unsigned int samplerate=48000; if(!only48khz) { switch(PcmSampleRate) { // If one of the supported frequencies, do it without resampling. case 96000: // Select a "even" upsampling frequency if possible, too. samplerate=96000; break; //case 48000: // this is already the default ... // samplerate=48000; // break; case 11025: case 22050: case 44100: samplerate=44100; break; case 8000: case 16000: case 32000: samplerate=32000; break; } } return samplerate; } cFrame *cOutputDvb::MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr) { static const unsigned char header[] = { 0x00, // PES header 0x00, 0x01, 0xBD, // private stream 0x00, 0x00, 0x87, // mpeg2, aligned, copyright, original 0x00, // no pts/dts 0x00, // PES header data len 0xA0, // aLPCM header 0xFF, 0x00, 0x04, 0x00, 0x01, // 2-channel stereo (n-1) 0x80 // neutral dynamic range }; cFrame *f=0; unsigned char *buff=MALLOC(uchar,FRAMESIZE); if(buff) { struct FrameHeader *fh=(struct FrameHeader *)buff; fh->samplerate=sr; memcpy(buff+FHS,header,sizeof(header)); int srMode; switch(sr) { default: case 48000: srMode=0<<4; break; case 96000: srMode=1<<4; break; case 44100: srMode=2<<4; break; case 32000: srMode=3<<4; break; } buff[14+FHS]|=srMode; unsigned int outlen=scale.ScaleBlock(buff+sizeof(header)+FHS,FRAMESIZE-sizeof(header)-FHS,Samples,Data[0],Data[1],MP3Setup.AudioMode?amDitherBE:amRoundBE); if(outlen) { // lPCM has 600 fps which is 80 samples at 48kHz per channel // Frame size = (sample_rate * quantization * channels)/4800 buff[10+FHS]=outlen*(4800/16/2)/sr; outlen+=(sizeof(header)-6); buff[4+FHS]=outlen>>8; buff[5+FHS]=outlen; f=new cFrame(buff,-(outlen+6+FHS),ftUnknown,index); } if(!f) free(buff); } return f; } #ifdef BROKEN_PCM #include "player-mp3-sample.c" #endif int cOutputDvb::Output(const unsigned char *Data, int Len, bool SOF) { int n=0; if(SOF) { #ifdef BROKEN_PCM struct FrameHeader *fh=(struct FrameHeader *)Data; if(fh->samplerate!=outSr) { if(outSr) { // at this point we would need access to AUDIO_STOP/AUDIO_PLAY // ioctl, but unfortunaly VDR's API doesn't provides this. // So we have to do magic to make the driver switch samplerate. const unsigned char *p=testAudio; int pc=sizeof(testAudio); int r; do { r=player->PlayPes(p,pc); if(r>0) { p+=r; pc-=r; } if(r==0) Poll(); } while(r>=0 && pc>0); } outSr=fh->samplerate; d(printf("mp3-dvb: output samplerate now %d\n",outSr)) } #endif n=FHS; Data+=n; Len-=n; } int r=player->PlayPes(Data,Len); return (r>=0 ? r+n : -1); } bool cOutputDvb::Poll(void) { return player->DevicePoll(poll,500); } void cOutputDvb::Play(void) { #ifndef BROKEN_PCM player->DevicePlay(); #endif } void cOutputDvb::Pause(void) { #ifndef BROKEN_PCM player->DeviceFreeze(); #endif } // --- cOutputOss -------------------------------------------------------------- #ifdef WITH_OSS const char *dspdevice="/dev/dsp"; class cOutputOss : public cOutput { private: int fd; cPoller poll; unsigned int outSr; unsigned char buff[8192]; // bool Reset(unsigned int sr); public: cOutputOss(cMP3Player *Player); virtual ~cOutputOss(); virtual void Init(void); virtual unsigned int SampleRate(unsigned int PcmSampleRate); virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr); virtual int Output(const unsigned char *Data, int Len, bool SOF); virtual bool Poll(void); virtual void Play(void); virtual void Pause(void); }; cOutputOss::cOutputOss(cMP3Player *Player) :cOutput(Player) { fd=-1; outSr=0; d(printf("mp3-oss: using OSS output\n")) } cOutputOss::~cOutputOss() { if(fd>=0) close(fd); } void cOutputOss::Init(void) { if(fd<0) { fd=open(dspdevice,O_WRONLY|O_NONBLOCK); if(fd>=0) { if(fcntl(fd,F_SETFL,0)==0) poll.Add(fd,true); else { esyslog("ERROR: Cannot make dsp device '%s' blocking: %s!",dspdevice,strerror(errno)); close(fd); fd=-1; } } else esyslog("ERROR: Cannot open dsp device '%s': %s!",dspdevice,strerror(errno)); } cOutput::Init(); } bool cOutputOss::Reset(unsigned int sr) { if(fd>=0) { CHECK(ioctl(fd,SNDCTL_DSP_SYNC,0)); int format=AFMT_S16_LE; CHECK(ioctl(fd,SNDCTL_DSP_SETFMT,&format)); if(format==AFMT_S16_LE) { int channels=2; CHECK(ioctl(fd,SNDCTL_DSP_CHANNELS,&channels)); if(channels==2) { int real=sr; CHECK(ioctl(fd,SNDCTL_DSP_SPEED,&real)); d(printf("oss: DSP samplerate now %d\n",real)) if((unsigned int)abs(real-sr)samplerate=sr; cFrame *f=0; unsigned int outlen=scale.ScaleBlock(buff+FHS,sizeof(buff)-FHS,Samples,Data[0],Data[1],MP3Setup.AudioMode?amDitherLE:amRoundLE); if(outlen) f=new cFrame(buff,outlen+FHS,ftUnknown,index); return f; } int cOutputOss::Output(const unsigned char *Data, int Len, bool SOF) { if(fd>=0) { int n=0; if(SOF) { struct FrameHeader *fh=(struct FrameHeader *)Data; if(fh->samplerate!=outSr) Reset(fh->samplerate); n=FHS; Data+=n; Len-=n; } if(poll.Poll(0)) { int r=write(fd,Data,Len); if(r<0 && FATALERRNO) return -1; if(r>0) n+=r; } return n; } return -1; } bool cOutputOss::Poll(void) { return fd>=0 ? poll.Poll(500) : false; } void cOutputOss::Play(void) { } void cOutputOss::Pause(void) { CHECK(ioctl(fd,SNDCTL_DSP_POST,0)); } #endif // --- cMP3Player -------------------------------------------------------------- cMP3Player::cMP3Player() :cPlayer(MP3Setup.BackgrMode==1 ? pmAudioOnly : pmAudioOnlyBlack) { active=true; started=false; isStream=false; ringBuffer=new cRingBufferFrame(MP3BUFSIZE); rframe=0; pframe=0; decoder=0; output=0; playMode=pmStartup; state=msStop; playindex=total=0; } cMP3Player::~cMP3Player() { Detach(); delete ringBuffer; } void cMP3Player::Activate(bool On) { if(On) { d(printf("mp3: player active true requested...\n")) if(!started) { playMode=pmStartup; Start(); started=true; playModeMutex.Lock(); WaitPlayMode(pmStartup,true); // wait for the decoder to become ready playModeMutex.Unlock(); Lock(); Play(); Unlock(); } d(printf("mp3: player active true done\n")) } else if(started && active) { d(printf("mp3: player active false requested...\n")) Lock(); StopPlay(); Unlock(); active=false; SetPlayMode(pmStartup); Cancel(2); d(printf("mp3: player active false done\n")) } } void cMP3Player::SetPlayMode(ePlayMode mode) { playModeMutex.Lock(); if(mode!=playMode) { playMode=mode; dm(printf("mp3: setting mode=%d (pid=%d)\n",mode,getpid())) playModeCond.Broadcast(); } playModeMutex.Unlock(); } void cMP3Player::WaitPlayMode(ePlayMode mode, bool inv) { // must be called with playModeMutex LOCKED !!! while(active && ((!inv && mode!=playMode) || (inv && mode==playMode))) { dm(printf("mp3: entering wait for mode%s%d with mode=%d (pid=%d)\n",inv?"!=":"==",mode,playMode,getpid())) playModeCond.Wait(playModeMutex); dm(printf("mp3: returning from wait with mode=%d (pid=%d)\n",playMode,getpid())) } } void cMP3Player::Action(void) { cSong *playing=0; struct mad_pcm *pcm=0; cResample resample[2]; unsigned int nsamples[2]; const mad_fixed_t *data[2]; cLevel level; cNormalize norm; bool haslevel=false; const unsigned char *p=0; int pc=0, readindex=0; bool imageValid=true; cTimeMs imageCheck; #ifdef DEBUG int beat=0; #endif #ifdef DEBUG_DELAY cTimeMs lastwrite(2000000); #endif dsyslog("mp3: player thread started (pid=%d)", getpid()); state=msStop; SetPlayMode(pmStopped); delete output; output=0; #ifdef WITH_OSS if(MP3Setup.AudioOutMode==AUDIOOUTMODE_OSS) output=new cOutputOss(this); #endif if(MP3Setup.AudioOutMode==AUDIOOUTMODE_DVB) output=new cOutputDvb(this); if(!output) { d(printf("mp3: audiooutmode mismatch or no output driver\n")) esyslog("ERROR: no audio output driver. balling out"); goto abort; } while(active) { #ifdef DEBUG { int now=time(0); if(now>=beat) { int avail=ringBuffer->Available(); printf("mp3: heartbeat buffer=%d now=%d\n",avail,now&4095); //output->Stats(); if(haslevel) norm.Stats(); beat=now+(avail>(MP3BUFSIZE*10/100) ? (avail<(MP3BUFSIZE*50/100) ? 2 : 20) : 1); } } #endif Lock(); next: if(!pframe && playing && !imageValid && imageCheck.Elapsed()) { unsigned char *mem; int len; imageCheck.Set(250); imageValid=playing->Image(mem,len); if(mem) { if(playindex) cCondWait::SleepMs(80); // stillpicture ioctl freezes without this DeviceStillPicture(mem,len); free(mem); } } bool SOF=false; if(!pframe && playMode==pmPlay) { pframe=ringBuffer->Get(); if(pframe) { playindex=pframe->Index(); p=pframe->Data(); pc=pframe->Count(); SOF=true; } } if(pframe) { #ifdef DEBUG_DELAY { if(lastwrite.TimedOut()) printf("mp3: write delayed %llu ms\n",lastwrite.Elapsed()); lastwrite.Set(DEBUG_DELAY+50); } #endif int w=output->Output(p,pc,SOF); if(w>0) { p+=w; pc-=w; if(pc<=0) { ringBuffer->Drop(pframe); pframe=0; goto next; } } else if(w<0 && FATALERRNO) { LOG_ERROR; d(printf("mp3: output failed: %s\n",strerror(errno))) Unlock(); goto abort; } } if(mgr->NewCurrent() && playMode==pmPlay && state!=msStart) { Empty(); state=msRestart; d(printf("mp3: stale song change, restart.\n")) } if(!rframe && playMode==pmPlay) { switch(state) { case msStart: d(printf("mp3: starting play\n")) mgr->Throttle(true); playindex=readindex=total=0; playing=mgr->Current(); if(playing) { if((decoder=playing->Decoder()) && decoder->Start()) { isStream=decoder->IsStream(); levelgood=!isStream; haslevel=false; cSongInfo *si=playing->Info(true); if(si) { if(si->Level>0.0) { d(printf("mp3: found song level=%f peak=%f\n",si->Level,si->Peak)) haslevel=true; norm.Init(si->Level,si->Peak); } if(si->HasInfo()) total=SecondsToFrames(si->Total); } d(printf("mp3: isStream=%d levelgood=%d haslevel=%d\n",isStream,levelgood,haslevel)) output->Init(); level.Init(); if(MP3Setup.BackgrMode==2) imageValid=false; state=msDecode; break; } else esyslog("ERROR: playlist entry %s is not a valid file",playing->Name()); } else d(printf("mp3: no current on start play\n")) state=msEof; break; case msDecode: { #ifdef DEBUG_DELAY cTimeMs check(DEBUG_DELAY); #endif struct Decode *ds=decoder->Decode(); #ifdef DEBUG_DELAY if(check.TimedOut()) printf("mp3: decode delayed %llu ms\n",check.Elapsed()); #endif switch(ds->status) { case dsPlay: pcm=ds->pcm; readindex=ds->index; state=msNormalize; break; case dsSkip: case dsSoftError: // skipping, state unchanged, next decode break; case dsEof: if(!haslevel && levelgood) { // save level & peak to infocache on eof double l=level.GetLevel(); if(l>0.0) { cSongInfo *si=decoder->SongInfo(false); cFileInfo *fi=decoder->FileInfo(); if(si && fi) { si->Level=l; si->Peak=level.GetPeak(); InfoCache.Cache(si,fi); } } } state=msEof; break; case dsOK: case dsError: state=msError; break; } break; } case msNormalize: if(!haslevel) { if(levelgood) level.GetPower(pcm); } else norm.AddGain(pcm); state=msResample; break; case msResample: #ifdef DEBUG { static unsigned int oldrate=0; if(oldrate!=pcm->samplerate) { printf("mp3: new input sample rate %d\n",pcm->samplerate); oldrate=pcm->samplerate; } } #endif nsamples[0]=nsamples[1]=pcm->length; data[0]=pcm->samples[0]; data[1]=pcm->channels>1 ? pcm->samples[1]:0; dvbSampleRate=output->SampleRate(pcm->samplerate); if(dvbSampleRate!=pcm->samplerate) { if(resample[0].SetInputRate(pcm->samplerate,dvbSampleRate)) { nsamples[0]=resample[0].ResampleBlock(nsamples[0],data[0]); data[0] =resample[0].Resampled(); } if(data[1] && resample[1].SetInputRate(pcm->samplerate,dvbSampleRate)) { nsamples[1]=resample[1].ResampleBlock(nsamples[1],data[1]); data[1] =resample[1].Resampled(); } } state=msOutput; break; case msOutput: if(nsamples[0]>0) rframe=output->MakeFrame(nsamples[0],data,readindex,dvbSampleRate); else state=msDecode; break; case msError: case msEof: d(printf("mp3: eof or error\n")) state=msWait; // fall through case msRestart: case msStop: d(printf("mp3: stopping play\n")) if(decoder) { decoder->Stop(); decoder=0; } mgr->Release(); playing=0; imageValid=true; levelgood=false; #ifdef DEBUG output->Stats(); if(haslevel) norm.Stats(); #endif if(state==msStop) SetPlayMode(pmStopped); if(state==msRestart) state=msStart; break; case msWait: if(ringBuffer->Available()==0) { if(mgr->NextCurrent()) { d(printf("mp3: playing next\n")) state=msStart; } else { d(printf("mp3: end of playlist\n")) if(MP3Setup.AbortAtEOL) { active=false; d(printf("mp3: aborting player...\n")) } else d(printf("mp3: player idle...\n")) SetPlayMode(pmStopped); } } break; } } if(rframe && ringBuffer->Put(rframe)) rframe=0; Unlock(); if((rframe || state==msWait) && pframe) { mgr->Throttle(false); output->Poll(); } else if(playMode!=pmPlay) { mgr->Throttle(false); if(!imageValid) cCondWait::SleepMs(100); else { playModeMutex.Lock(); if(playMode!=pmPlay) WaitPlayMode(playMode,true); playModeMutex.Unlock(); } #ifdef DEBUG_DELAY lastwrite.Set(2000000); #endif } else if(state!=msWait && ringBuffer->Available()<(MP3BUFSIZE*50/100)) { mgr->Throttle(true); } } abort: Lock(); delete rframe; delete output; output=0; if(decoder) { decoder->Stop(); decoder=0; } mgr->Release(); playing=0; SetPlayMode(pmStopped); Unlock(); active=false; dsyslog("mp3: player thread ended (pid=%d)", getpid()); } void cMP3Player::Empty(void) { Lock(); delete rframe; rframe=0; pframe=0; ringBuffer->Clear(); DeviceClear(); Unlock(); } void cMP3Player::StopPlay(void) // StopPlay() must be called in locked state!!! { if(playMode!=pmStopped) { Empty(); state=msStop; SetPlayMode(pmPlay); Unlock(); // let the decode thread process the stop signal playModeMutex.Lock(); WaitPlayMode(pmStopped,false); playModeMutex.Unlock(); Lock(); } } void cMP3Player::Pause(void) { Lock(); if(playMode==pmPaused) Play(); else if(playMode==pmPlay && !isStream) { d(printf("mp3: pause\n")) if(output) output->Pause(); SetPlayMode(pmPaused); } Unlock(); } void cMP3Player::Play(void) { Lock(); if(playMode!=pmPlay) { d(printf("mp3: play\n")) if(playMode==pmStopped) state=msStart; if(output) output->Play(); SetPlayMode(pmPlay); } Unlock(); } bool cMP3Player::PrevCheck(void) { bool res=false; Lock(); if(playindex>=2000 && !isStream) { state=msRestart; res=true; Empty(); d(printf("mp3: skip to start of song\n")) } Unlock(); return res; } void cMP3Player::SkipSeconds(int secs) { if(playMode!=pmStopped && !isStream) { Lock(); d(printf("mp3: skip secs %d\n",secs)) if(playMode==pmPaused) SetPlayMode(pmPlay); float bufsecs=(float)ringBuffer->Available() / (float)(dvbSampleRate*OUT_FACT); d(printf("mp3: ringbuffer available %f secs\n",bufsecs)) if(secs>0 && bufsecs>=(float)secs) { // clear intermediate queue if(pframe) { ringBuffer->Drop(pframe); pframe=0; } DeviceClear(); // skip inside ringbuffer int skipindex=playindex+secs*1000; d(printf("mp3: skipping play=%d skip=%d ...",playindex,skipindex)) cFrame *f; do { f=ringBuffer->Get(); if(f) { playindex=f->Index(); ringBuffer->Drop(f); d(printf("*")) } } while(f && playindexSkip(secs,bufsecs)) levelgood=false; Empty(); } Unlock(); } } bool cMP3Player::GetIndex(int &Current, int &Total, bool SnapToIFrame) { Current=SecondsToFrames(playindex/1000); Total=total; return total>=0; } bool cMP3Player::GetReplayMode(bool &Play, bool &Forward, int &Speed) { Play=(playMode==pmPlay); Forward=true; Speed=-1; return true; } mp3-0.10.2/player-mp3.h0100644000000000000000000000732010735452037013142 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DVB_MP3_H #define ___DVB_MP3_H #include #include // ------------------------------------------------------------------- class cRingBufferFrame; class cFrame; class cPlayList; class cSong; class cSongInfo; class cBackgroundScan; class cDecoder; class cOutput; class cOutputDvb; class cShuffle; // ------------------------------------------------------------------- class cMP3PlayInfo { public: char Title[64], Artist[64], Album[64], SMode[32], Filename[256]; int Year, SampleFreq, Bitrate, MaxBitrate; int Num, MaxNum; // not in hash bool Loop, Shuffle; int Hash; }; // ------------------------------------------------------------------- class cPlayManager : public cThread { private: cMutex listMutex; cCondVar fgCond, bgCond; cList list; cSong *curr; int currIndex, maxIndex; // cSong *play; bool playNew, eol; // cShuffle *shuffle; bool shuffleMode, loopMode; // cSong *scan; bool stopscan, throttle, pass2, release; // virtual void Action(void); void NoScan(cSong *nono); void NoPlay(cSong *nono); void ThrottleWait(void); public: cPlayManager(void); ~cPlayManager(); // Control interface (to be called from frontend thread only!) void Flush(void); void Add(cPlayList *pl); bool Next(void); bool Prev(void); void Goto(int num); void ToggleShuffle(void); void ToggleLoop(void); bool Info(int num, cMP3PlayInfo *info); void Halt(void); // Player interface (to be called from player thread only!) cSong *Current(void); bool NewCurrent(void); bool NextCurrent(void); void Release(void); void Throttle(bool thr); }; extern cPlayManager *mgr; // ------------------------------------------------------------------- class cMP3Player : public cPlayer, cThread { friend class cOutputDvb; private: bool active, started; cRingBufferFrame *ringBuffer; cMutex playModeMutex; cCondVar playModeCond; // int playindex, total; cDecoder *decoder; cOutput *output; cFrame *rframe, *pframe; enum ePlayMode { pmPlay, pmStopped, pmPaused, pmStartup }; ePlayMode playMode; enum eState { msStart, msStop, msDecode, msNormalize, msResample, msOutput, msError, msEof, msWait, msRestart }; eState state; bool levelgood, isStream; unsigned int dvbSampleRate; // void Empty(void); void StopPlay(void); void SetPlayMode(ePlayMode mode); void WaitPlayMode(ePlayMode mode, bool inv); protected: virtual void Activate(bool On); virtual void Action(void); public: cMP3Player(void); virtual ~cMP3Player(); void Pause(void); void Play(void); bool PrevCheck(void); void SkipSeconds(int secs); virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false); virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); bool Active(void) { return active; } bool IsStream(void) { return isStream; } }; #endif //___DVB_MP3_H mp3-0.10.2/player-mplayer.c0100644000000000000000000004342111265176252014112 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "data.h" #include "player-mplayer.h" #include "setup-mplayer.h" //#define DEBUG_SLAVE #define MPLAYER_VOL_STEP 3.0 const char *MPlayerCmd = "mplayer.sh"; int MPlayerAid=-1; const char *globalResumeDir = 0; // -- cMPlayerStatus ----------------------------------------------------------- cMPlayerStatus *status; cMPlayerStatus::cMPlayerStatus(void) { mute=changed=false; volume=0; } bool cMPlayerStatus::GetVolume(int &Volume, bool &Mute) { Lock(); bool r=changed; // convert according cDvbDevice::SetVolumeDevice(); // take into account that VDR does non-linear changes, while // MPlayer does linear volume changes. Volume=((2*volume-volume*volume/255)*100+128)/256; Mute=mute; changed=false; Unlock(); return r; } void cMPlayerStatus::SetVolume(int Volume, bool Absolute) { Lock(); if(Absolute && Volume==0) mute=true; else { if(!Absolute) volume+=Volume; else volume=Volume; if(volume>0) mute=false; } d(printf("status: volume=%d mute=%d\n",volume,mute)) changed=true; Unlock(); } // --- cResumeEntry ------------------------------------------------------------ class cResumeEntry : public cListObject { public: char *name; float pos; // cResumeEntry(void); ~cResumeEntry(); }; cResumeEntry::cResumeEntry(void) { name=0; } cResumeEntry::~cResumeEntry() { free(name); } // --- cMPlayerResume ---------------------------------------------------------- #define RESUME_FILE ".mplayer.resume" #define GLOBAL_RESUME_FILE "global.mplayer.resume" class cMPlayerResume : public cList { private: char *resfile; bool modified, global; cFileObj *resobj; // bool OpenResume(const cFileObj *file); bool SaveResume(void); void Purge(void); cResumeEntry *FindResume(const cFileObj *file); public: cMPlayerResume(void); ~cMPlayerResume(); void SetResume(const cFileObj *file, float pos); bool GetResume(const cFileObj *file, float &pos); }; cMPlayerResume::cMPlayerResume(void) { resfile=0; resobj=0; } cMPlayerResume::~cMPlayerResume() { SaveResume(); free(resfile); delete resobj; } void cMPlayerResume::SetResume(const cFileObj *file, float pos) { if(pos<0.001) pos=0.0; else if(pos>99.0) pos=99.0; cResumeEntry *re; if(OpenResume(file) && (re=FindResume(file))) { d(printf("resume: setting resume %f (update)\n",pos)) } else { re=new cResumeEntry; re->name=strdup(global ? file->FullPath() : file->Name()); Add(re); d(printf("resume: setting resume %f (new)\n",pos)) } re->pos=pos; modified=true; } bool cMPlayerResume::GetResume(const cFileObj *file, float &pos) { cResumeEntry *re; if(OpenResume(file) && (re=FindResume(file))) { pos=re->pos; return true; } return false; } bool cMPlayerResume::OpenResume(const cFileObj *file) { if(!resfile) { Clear(); modified=global=false; free(resfile); resfile=0; delete resobj; resobj=new cFileObj(file); char *s=aprintf(file->Subdir() ? "%s/%s":"%s",file->Source()->BaseDir(),file->Subdir()); if(MPlayerSetup.ResumeMode==1 || (access(s,W_OK) && (errno==EACCES || errno==EROFS))) { global=true; resfile=AddPath(globalResumeDir?globalResumeDir:VideoDirectory,GLOBAL_RESUME_FILE); d(printf("resume: using global file\n")) } else { resfile=AddPath(s,RESUME_FILE); } free(s); d(printf("resume: resume file is '%s'\n",resfile)) FILE *f=fopen(resfile,"r"); if(f) { d(printf("resume: successfully opened resume file\n")) char line[768]; while(fgets(line,sizeof(line),f)) { char name[512]; float p; if(sscanf(line,"%f:%511[^\n]",&p,name)==2) { cResumeEntry *re=new cResumeEntry; re->name=strdup(name); re->pos=p; Add(re); } } fclose(f); return true; } else { d(printf("resume: assuming empty resume file\n")) return false; } } return true; } bool cMPlayerResume::SaveResume(void) { if(resfile && modified) { Purge(); d(printf("resume: saving resume file\n")) cSafeFile f(resfile); if(f.Open()) { for(cResumeEntry *re=First(); re; re=Next(re)) fprintf(f,"%06.2f:%s\n",re->pos,re->name); f.Close(); return true; } else d(printf("resume: failed to save resume file\n")) } return false; } void cMPlayerResume::Purge(void) { d(printf("resume: purging from resume file\n")) for(cResumeEntry *re=First(); re;) { bool del=false; if(re->pos<1.0 || re->pos>99.0) { del=true; d(printf("resume: purging due to position: %s\n",re->name)) } else if(!global) { resobj->SetName(re->name); if(access(resobj->FullPath(),F_OK)<0) { del=true; d(printf("resume: purging due to access: %s\n",re->name)) } } if(del) { cResumeEntry *n=Next(re); Del(re); modified=true; re=n; } else re=Next(re); } } cResumeEntry *cMPlayerResume::FindResume(const cFileObj *file) { if(resfile) { d(printf("resume: searching resume position for '%s'\n",file->Name())) const char *s=global ? file->FullPath() : file->Name(); for(cResumeEntry *re=First(); re; re=Next(re)) if(!strcasecmp(re->name,s)) { d(printf("resume: found resume position %.1f%%\n",re->pos)) return re; } } d(printf("resume: no resume position found\n")) return 0; } // --- cMPlayerPlayer ---------------------------------------------------------- cMPlayerPlayer::cMPlayerPlayer(const cFileObj *File, bool Rewind) :cPlayer(pmExtern_THIS_SHOULD_BE_AVOIDED) { started=slave=brokenPipe=false; run=true; pid=-1; pipefl=0; playMode=pmPlay; index=saveIndex=total=-1; nextTime=nextPos=0; currentName=0; file=new cFileObj(File); rewind=Rewind; resume=MPlayerSetup.ResumeMode ? new cMPlayerResume : 0; } cMPlayerPlayer::~cMPlayerPlayer() { Detach(); ClosePipe(); delete file; delete resume; free(currentName); } void cMPlayerPlayer::ClosePipe(void) { if(pipefl&1) close(inpipe[0]); if(pipefl&2) close(inpipe[1]); if(pipefl&4) close(outpipe[0]); if(pipefl&8) close(outpipe[1]); pipefl=0; } void cMPlayerPlayer::Activate(bool On) { if(On) { if(file && !started) { if(Fork()) started=true; } } else if(started) { run=false; if(Active()) { if(slave) { Play(); // MPlayer ignores "quit" while paused MPlayerControl("quit"); cTimeMs until(3000); // wait some time until MPlayer is gone d(printf("mplayer: waiting for child exit")) while(Active()) { if(until.TimedOut()) { kill(pid,SIGKILL); // kill it anyways d(printf(" SIGKILL")) break; } cCondWait::SleepMs(250); d(printf(".")) d(fflush(stdout)) } d(printf("\n")) } else { kill(pid,SIGTERM); d(printf("mplayer: waiting for child exit (non-slave)\n")) } waitpid(pid,0,0); } ClosePipe(); Cancel(2); started=slave=false; } } bool cMPlayerPlayer::Active(void) { return waitpid(pid,0,WNOHANG)==0; } bool cMPlayerPlayer::Fork(void) { if(MPlayerSetup.SlaveMode) { if(pipe(inpipe)==-1) { esyslog("ERROR: pipe failed for inpipe: (%d) %s",errno,strerror(errno)); return false; } pipefl|=1+2; if(pipe(outpipe)==-1) { esyslog("ERROR: pipe failed for outpipe: (%d) %s",errno,strerror(errno)); return false; } pipefl|=4+8; brokenPipe=false; } pid=fork(); if(pid==-1) { esyslog("ERROR: fork failed: (%d) %s",errno,strerror(errno)); return false; } if(pid==0) { // child dsyslog("mplayer: mplayer child started (pid=%d)", getpid()); if(MPlayerSetup.SlaveMode) { if(dup2(inpipe[0],STDIN_FILENO)<0 || dup2(outpipe[1],STDOUT_FILENO)<0 || dup2(outpipe[1],STDERR_FILENO)<0) { esyslog("ERROR: dup2() failed in MPlayer child: (%d) %s",errno,strerror(errno)); exit(127); } } else { int nfd=open("/dev/null",O_RDONLY); if(nfd<0 || dup2(nfd,STDIN_FILENO)<0) esyslog("ERROR: redirect of STDIN failed in MPlayer child: (%d) %s",errno,strerror(errno)); } for(int i=getdtablesize()-1; i>STDERR_FILENO; i--) close(i); char cmd[64+PATH_MAX*2], aid[20]; char *fname=Quote(file->FullPath()); if(MPlayerAid>=0) snprintf(aid,sizeof(aid)," AID %d",MPlayerAid); else aid[0]=0; snprintf(cmd,sizeof(cmd),"%s \"%s\" %s%s",MPlayerCmd,fname,MPlayerSetup.SlaveMode?"SLAVE":"",aid); free(fname); // give index of primary dvb adapter device to mplayer via environment variable char dvb[4]; snprintf(dvb,sizeof(dvb),"%d",cDevice::PrimaryDevice()->CardIndex()+1); setenv("DVB_DEVICE",dvb,1); execle("/bin/sh","sh","-c",cmd,(char *)0,environ); esyslog("ERROR: exec failed for %s: (%d) %s",cmd,errno,strerror(errno)); exit(127); } if(MPlayerSetup.SlaveMode) { close(inpipe[0]); pipefl&=~1; close(outpipe[1]); pipefl&=~8; fcntl(outpipe[0],F_SETFL,O_NONBLOCK); run=slave=true; mpVolume=100; // MPlayer startup defaults mpMute=false; Start(); } return true; } #define BSIZE 1024 #define TIME_INT 20 #define POS_INT 1 void cMPlayerPlayer::Action(void) { dsyslog("mplayer: player thread started (pid=%d)", getpid()); // set locale for correct parsing of MPlayer output. // I don't know if this affects other parts of VDR. const char * const oldLocale=setlocale(LC_NUMERIC,"C"); pollfd pfd[1]; pfd[0].fd=outpipe[0]; pfd[0].events=POLLIN; float curPos=-1.0, resPos=-1.0; if(resume && !rewind) resume->GetResume(file,resPos); char buff[BSIZE+2]; // additional space for fake newline int c=0; bool force=true, slavePatch=false, trustedTotal=false, playBack=false; while(run) { if(playMode==pmPlay && playBack) { int t=time(0); if(t>=nextTime) { MPlayerControl("get_time_length"); nextTime=t+(total>0 ? TIME_INT : POS_INT); } if(t>=nextPos) { if(!slavePatch) MPlayerControl("get_percent_pos"); nextPos=t+POS_INT; } } poll(pfd,1,300); int r=read(outpipe[0],buff+c,BSIZE-c); if(r>0) c+=r; if(c>0) { buff[c]=0; // make sure buffer is NULL terminated char *p; do { p=strpbrk(buff,"\n\r"); if(!p && c==BSIZE) { // Full buffer, but no newline found. p=&buff[c]; // Have to fake one. buff[c]='\n'; c++; buff[c]=0; } if(p) { #ifdef DEBUG char cc=*p; #endif *p++=0; float ftime=-1.0, fpos=-1.0; int itime; if(strncmp(buff,"Starting playback",17)==0 || strncmp(buff,"Starte Wiedergabe",17)==0) { if(!playBack) { playBack=true; nextTime=nextPos=0; d(printf("PLAYBACK STARTED\n")) if(resPos>=0.0) { if(!currentName || !strcmp(currentName,file->FullPath()) || !strcmp(currentName,file->Path())) MPlayerControl("seek %.1f 1",resPos); else d(printf("mplayer: no resume, seems to be playlist\n")) } } } else if(strncmp(buff,"Playing ",8)==0 || strncmp(buff,"Spiele ",7)==0) { nextTime=nextPos=0; index=saveIndex=total=-1; trustedTotal=false; LOCK_THREAD; free(currentName); currentName=strdup(::index(buff,' ')+1); if(currentName[0]) { int l=strlen(currentName); if(currentName[l-1]=='.') currentName[l-1]=0; // skip trailing dot } d(printf("PLAYING %s\n",currentName)) } else if(sscanf(buff,"ANS_LENGTH=%d",&itime)==1) { if(itime>0) { total=SecondsToFrames(itime); trustedTotal=true; #ifdef DEBUG_SLAVE printf("sl: ANS_LENGTH=%s (%s)\n",IndexToHMSF(total),buff); #endif } } else if(sscanf(buff,"ANS_PERCENT_POSITION=%d",&itime)==1) { if(itime>0) { curPos=itime; if(total>=0) { index=total*itime/100; #ifdef DEBUG_SLAVE printf("sl: ANS_PERCENT_POS=%s (%s)\n",IndexToHMSF(index),buff); #endif } } } else if(sscanf(buff,"SLAVE: time=%f position=%f",&ftime,&fpos)==2) { curPos=fpos; const float fr=(float)SecondsToFrames(1); itime=(int)(ftime*fr); if(saveIndex<0 || itime>saveIndex) { // prevent index jump-back saveIndex=index=itime; if(!trustedTotal) total=(int)(ftime*fr*100.0/fpos); #ifdef DEBUG_SLAVE printf("sl: SLAVE=%s/%s [%d] (%s)\n",IndexToHMSF(index),IndexToHMSF(total),trustedTotal,buff); #endif } slavePatch=playBack=true; } #ifdef DEBUG else printf("%s%c",buff,cc); #endif c-=(p-buff); memmove(buff,p,c+1); } } while(c>0 && p); } if(playBack) { SetMPlayerVolume(force); force=false; } } if(resume && curPos>=0.0) resume->SetResume(file,curPos); // restore old locale if(oldLocale) setlocale(LC_NUMERIC,oldLocale); dsyslog("mplayer: player thread ended (pid=%d)", getpid()); } void cMPlayerPlayer::SetMPlayerVolume(bool force) { int volume; bool mute; Lock(); if(status->GetVolume(volume,mute) || force) { if(mute) { if(!mpMute) { MPlayerControl("mute"); mpMute=true; } } else { if(mpMute) { MPlayerControl("mute"); mpMute=false; } if(volume!=mpVolume) { MPlayerControl("volume %d 1",volume); mpVolume=volume; } } d(printf("mplayer: volume=%d mpVolume=%d mpMute=%d\n",volume,mpVolume,mpMute)) } Unlock(); } void cMPlayerPlayer::MPlayerControl(const char *format, ...) { if(slave) { va_list ap; va_start(ap,format); char *buff=0; if(vasprintf(&buff,format,ap)<0); Lock(); // check for writeable pipe i.e. prevent broken pipe signal if(!brokenPipe) { struct pollfd pfd; pfd.fd=inpipe[1]; pfd.events=POLLOUT; pfd.revents=0; int r=poll(&pfd,1,50); if(r>0) { if(pfd.revents & ~POLLOUT) { d(printf("mplayer: %s%s%s%sin MPlayerControl\n",pfd.revents&POLLOUT?"POLLOUT ":"",pfd.revents&POLLERR?"POLLERR ":"",pfd.revents&POLLHUP?"POLLHUP ":"",pfd.revents&POLLNVAL?"POLLNVAL ":"")) brokenPipe=true; } else if(pfd.revents & POLLOUT) { r=write(inpipe[1],buff,strlen(buff)); if(r<0) { d(printf("mplayer: pipe write(1) failed: %s\n",strerror(errno))) brokenPipe=true; } else { r=write(inpipe[1],"\n",1); if(r<0) { d(printf("mplayer: pipe write(2) failed: %s\n",strerror(errno))) brokenPipe=true; } } } } else if(r==0) d(printf("mplayer: poll timed out in MPlayerControl (hugh?)\n")) else d(printf("mplayer: poll failed in MPlayerControl: %s\n",strerror(errno))) } else d(printf("mplayer: cmd pipe is broken\n")) Unlock(); d(printf("mplayer: slave cmd: %s\n",buff)) free(buff); va_end(ap); } } void cMPlayerPlayer::Pause(void) { if(slave) { if(playMode==pmPaused) Play(); else if(playMode==pmPlay) { playMode=pmPaused; MPlayerControl("pause"); } } } void cMPlayerPlayer::Play(void) { if(slave) { if(playMode==pmPaused) { playMode=pmPlay; MPlayerControl("pause"); } } } void cMPlayerPlayer::Goto(int Index, bool percent, bool still) { if(slave) { if(playMode==pmPaused) Play(); if(percent) MPlayerControl("seek %d 1",Index); else MPlayerControl("seek %+d 0",Index-(index/SecondsToFrames(1))); if(still) Pause(); saveIndex=-1; } } void cMPlayerPlayer::SkipSeconds(int secs) { if(slave) { bool p=false; if(playMode==pmPaused) { Play(); p=true; } MPlayerControl("seek %+d 0",secs); if(p) Pause(); saveIndex=-1; } } void cMPlayerPlayer::KeyCmd(const char *cmd) { if(slave) MPlayerControl(cmd); } bool cMPlayerPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame) { Current=index; Total=total; return true; } bool cMPlayerPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) { Play=(playMode==pmPlay); Forward=true; Speed=-1; return true; } char *cMPlayerPlayer::GetCurrentName(void) { LOCK_THREAD; return currentName ? strdup(currentName) : 0; } mp3-0.10.2/player-mplayer.h0100644000000000000000000000515610735452037014121 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2006 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___DVB_MPLAYER_H #define ___DVB_MPLAYER_H #include #include #include // ---------------------------------------------------------------- class cFileObj; class cMPlayerResume; // ---------------------------------------------------------------- class cMPlayerStatus : public cStatus, cMutex { private: int volume; bool mute, changed; protected: virtual void SetVolume(int Volume, bool Absolute); public: cMPlayerStatus(void); bool GetVolume(int &Volume, bool &Mute); }; extern cMPlayerStatus *status; // ---------------------------------------------------------------- class cMPlayerPlayer : public cPlayer, cThread { private: cFileObj *file; bool rewind; cMPlayerResume *resume; bool started, slave, run; int pid, inpipe[2], outpipe[2], pipefl; bool brokenPipe; enum ePlayMode { pmPlay, pmPaused }; ePlayMode playMode; int index, total, saveIndex; int nextTime, nextPos; int mpVolume; bool mpMute; char *currentName; // bool Fork(void); void ClosePipe(void); void MPlayerControl(const char *format, ...); void SetMPlayerVolume(bool force); protected: virtual void Activate(bool On); virtual void Action(void); public: cMPlayerPlayer(const cFileObj *File, bool Rewind); virtual ~cMPlayerPlayer(); bool Active(void); bool SlaveMode(void) const { return slave; } void Pause(void); void Play(void); void Goto(int Index, bool percent, bool still); void SkipSeconds(int secs); void KeyCmd(const char *cmd); char *GetCurrentName(void); virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame); virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); }; extern int MPlayerAid; extern const char *globalResumeDir; #endif //___DVB_MPLAYER_H mp3-0.10.2/po/0040755000000000000000000000000011316352211011404 5ustar rootrootmp3-0.10.2/po/ca_ES.po0100644000000000000000000001370711307515470012733 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Ramon Roca # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "desconegut" msgid "Remote CDDB lookup..." msgstr "Consultant CDDB..." msgid "Select" msgstr "Escollir" msgid "Parent" msgstr "Anterior" msgid "ID3 info" msgstr "ID3 info" msgid "Scanning directory..." msgstr "Revisant les carpetes.." msgid "Error scanning directory!" msgstr "Error al llegir una carpeta!" msgid "Mount" msgstr "Mount" msgid "Unmount" msgstr "Unmount" msgid "Eject" msgstr "" msgid "Selected source is not mounted!" msgstr "l'Origen sel.leccionat no estр muntat!" msgid "Mount failed!" msgstr "No he pogut muntar!" msgid "Mount succeeded" msgstr "mount correcte" msgid "Unmount succeeded" msgstr "unmount amb шxit" msgid "Unmount failed!" msgstr "No puc desmontar!" msgid "Eject failed!" msgstr "No puc expulsar!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "" msgid "Setup.MP3$Audio mode" msgstr "Mode d'audio" msgid "Round" msgstr "Arrodonir" msgid "Dither" msgstr "Compactar" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Nomщs mode 48kHz" msgid "classic" msgstr "" msgid "via skin" msgstr "" msgid "Setup.MP3$Replay display" msgstr "" msgid "Setup.MP3$Display mode" msgstr "Mode de visualitzaciѓ" msgid "Black" msgstr "Negre" msgid "Live" msgstr "Imatge" msgid "Images" msgstr "" msgid "Setup.MP3$Background mode" msgstr "Execuciѓ de fons" msgid "Setup.MP3$Initial loop mode" msgstr "Mode de repeticiѓ inicial" msgid "Setup.MP3$Initial shuffle mode" msgstr "Lectura aleatђria inicial" msgid "Setup.MP3$Abort player at end of list" msgstr "" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "desactivat" msgid "ID3 only" msgstr "" msgid "ID3 & Level" msgstr "" msgid "Setup.MP3$Background scan" msgstr "" msgid "Setup.MP3$Editor display mode" msgstr "Mode de visualitzaciѓ del editor" msgid "Filenames" msgstr "Nom dels arxius" msgid "ID3 names" msgstr "Nom ID3" msgid "Setup.MP3$Mainmenu mode" msgstr "Menњ Principal" msgid "Playlists" msgstr "Llista a reproduяr" msgid "Browser" msgstr "Navegador" msgid "Setup.MP3$Keep selection menu" msgstr "" msgid "Setup.MP3$Title/Artist order" msgstr "" msgid "Normal" msgstr "" msgid "Reversed" msgstr "" msgid "Hide mainmenu entry" msgstr "" msgid "Setup.MP3$Normalizer level" msgstr "Nivell de normalitzaciѓ" msgid "Setup.MP3$Limiter level" msgstr "Limitador del nivell" msgid "Setup.MP3$Use HTTP proxy" msgstr "UtilЗlitzar proxy HTTP" msgid "Setup.MP3$HTTP proxy host" msgstr "Nom del proxy HTTP" msgid "Setup.MP3$HTTP proxy port" msgstr "Port del proxy HTTP" msgid "local only" msgstr "solsament local" msgid "local&remote" msgstr "local i remot" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB per al Audio-CD" msgid "Setup.MP3$CDDB server" msgstr "Servidor CDDB" msgid "Setup.MP3$CDDB port" msgstr "Port CDDB" msgid "ID3 information" msgstr "Informaciѓ ID3" msgid "Filename" msgstr "Nom de l'arxiu" msgid "Length" msgstr "Durada" msgid "Title" msgstr "Tэtol" msgid "Artist" msgstr "Intшrpret" msgid "Album" msgstr "Рlbum" msgid "Year" msgstr "Any" msgid "Samplerate" msgstr "Freqќшncia" msgid "Bitrate" msgstr "Bitrate" msgid "Directory browser" msgstr "Navegar per les carpetes" msgid "Playlist editor" msgstr "Editor de llistes de reproducciѓ" msgid "Add" msgstr "Afegir" msgid "Remove" msgstr "Esborrar" msgid "Add recursivly?" msgstr "Afegir recursivament?" msgid "Empty directory!" msgstr "Carpeta buida!" msgid "Remove entry?" msgstr "Esborrar la entrada?" msgid "Add all" msgstr "Afegir-ho tot" msgid "Rename playlist" msgstr "Reanomenar la llista de repr." msgid "Old name:" msgstr "Nom anterior:" msgid "New name" msgstr "Nou nom" msgid "Source" msgstr "Orэgen" msgid "Browse" msgstr "Explorar" msgid "Rename" msgstr "Reanomenar" msgid "Scanning playlists..." msgstr "Llegint les llistes de reproducciѓ..." msgid "Error scanning playlists!" msgstr "Error al llegir les llistes!" msgid "Delete playlist?" msgstr "Esborrar la Llista?" msgid "Are you sure?" msgstr "N'esteu segur?" msgid "Error deleting playlist!" msgstr "Error al esborrar una llista!" msgid "unnamed" msgstr "sense nom" msgid "Error creating playlist!" msgstr "Error al crear una llista!" msgid "Error renaming playlist!" msgstr "Error al reanomenar la llista!" msgid "Error loading playlist!" msgstr "Error al carregar la llista de reproducciѓ!" msgid "Can't edit a WinAmp playlist!" msgstr "No puc editar una llista del WinAmp!" msgid "Loading playlist..." msgstr "Carregant la llista de reproducciѓ..." msgid "MP3 source" msgstr "Orэgen MP3" msgid "Play all" msgstr "Escoltar-ho tot" msgid "Building playlist..." msgstr "Construяnt la llista de reproducciѓ..." msgid "Error building playlist!" msgstr "Error al consstruir la llista de reproducciѓ!" msgid "A versatile audio player" msgstr "" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "Mode de control" msgid "Traditional" msgstr "Tradicional" msgid "Slave" msgstr "Esclau" msgid "global only" msgstr "" msgid "local first" msgstr "" msgid "Setup.MPlayer$Resume mode" msgstr "" msgid "Setup.MPlayer$Slave command key" msgstr "" msgid "MPlayer Audio ID" msgstr "" msgid "Audiostream ID" msgstr "" msgid "MPlayer browser" msgstr "Navegador del MPlayer" msgid "MPlayer source" msgstr "Orэgen del MPlayer" msgid "Summary" msgstr "" msgid "Media replay via MPlayer" msgstr "" msgid "Connecting to stream server ..." msgstr "Connectant al servidor..." mp3-0.10.2/po/de_DE.po0100644000000000000000000001460311307515470012715 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Stefan Huelswitt , 2006 # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "unbekannt" msgid "Remote CDDB lookup..." msgstr "Remote CDDB Abfrage..." msgid "Select" msgstr "Auswфhlen" msgid "Parent" msgstr "Zurќck" msgid "ID3 info" msgstr "ID3 Info" msgid "Scanning directory..." msgstr "Durchsuche Verzeichnis..." msgid "Error scanning directory!" msgstr "Fehler beim Lesen des Verzeichnisses!" msgid "Mount" msgstr "Einbinden" msgid "Unmount" msgstr "Aushфngen" msgid "Eject" msgstr "Auswerfen" msgid "Selected source is not mounted!" msgstr "Ausgewфhlte Datentrфger ist nicht eingebunden!" msgid "Mount failed!" msgstr "Einbinden fehlgeschlagen!" msgid "Mount succeeded" msgstr "Einbinden erfolgreich" msgid "Unmount succeeded" msgstr "Aushфngen erfolgreich" msgid "Unmount failed!" msgstr "Aushфngen fehlgeschlagen!" msgid "Eject failed!" msgstr "Auswerfen fehlgeschlagen!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "Audio Ausgabe Modus" msgid "Setup.MP3$Audio mode" msgstr "Audio Modus" msgid "Round" msgstr "Runden" msgid "Dither" msgstr "Streuen" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Nur 48kHz Modus benutzen" msgid "classic" msgstr "klassisch" msgid "via skin" msgstr "ќber Skin" msgid "Setup.MP3$Replay display" msgstr "Wiedergabe Anzeige" msgid "Setup.MP3$Display mode" msgstr "Anzeige Modus" msgid "Black" msgstr "Schwarz" msgid "Live" msgstr "Live" msgid "Images" msgstr "Bilder" msgid "Setup.MP3$Background mode" msgstr "Hintergrund Modus" msgid "Setup.MP3$Initial loop mode" msgstr "Default Loop Modus" msgid "Setup.MP3$Initial shuffle mode" msgstr "Default Shuffle Modus" msgid "Setup.MP3$Abort player at end of list" msgstr "Abspieler am Listenende beenden" msgid "Setup.MP3$Enqueue to running playlist" msgstr "Zur laufenden Wiedergabe hinzufќgen" msgid "disabled" msgstr "aus" msgid "ID3 only" msgstr "nur ID3" msgid "ID3 & Level" msgstr "ID3 & Pegel" msgid "Setup.MP3$Background scan" msgstr "Hintergrund Scan" msgid "Setup.MP3$Editor display mode" msgstr "Editor Anzeige Modus" msgid "Filenames" msgstr "Dateinamen" msgid "ID3 names" msgstr "ID3 Namen" msgid "Setup.MP3$Mainmenu mode" msgstr "Hauptmenu Modus" msgid "Playlists" msgstr "Abspiellisten" msgid "Browser" msgstr "Verz.anzeige" msgid "Setup.MP3$Keep selection menu" msgstr "Auswahlmenu geіffnet lassen" msgid "Setup.MP3$Title/Artist order" msgstr "Title/Artist Reihenfolge" msgid "Normal" msgstr "Normal" msgid "Reversed" msgstr "Umgedreht" msgid "Hide mainmenu entry" msgstr "Hauptmenќeintrag verstecken" msgid "Setup.MP3$Normalizer level" msgstr "Normalisierer Pegel" msgid "Setup.MP3$Limiter level" msgstr "Begrenzer Pegel" msgid "Setup.MP3$Use HTTP proxy" msgstr "HTTP Proxy benutzen" msgid "Setup.MP3$HTTP proxy host" msgstr "HTTP Proxy Name" msgid "Setup.MP3$HTTP proxy port" msgstr "HTTP Proxy Port" msgid "local only" msgstr "nur lokal" msgid "local&remote" msgstr "lokal und entfernt" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB fќr CD-Audio" msgid "Setup.MP3$CDDB server" msgstr "CDDB Server" msgid "Setup.MP3$CDDB port" msgstr "CDDB Port" msgid "ID3 information" msgstr "ID3 Information" msgid "Filename" msgstr "Dateiname" msgid "Length" msgstr "Lфnge" msgid "Title" msgstr "Titel" msgid "Artist" msgstr "Interpret" msgid "Album" msgstr "Album" msgid "Year" msgstr "Jahr" msgid "Samplerate" msgstr "Sample Rate" msgid "Bitrate" msgstr "Bit Rate" msgid "Directory browser" msgstr "Verzeichnisanzeige" msgid "Playlist editor" msgstr "Abspielliste bearbeiten" msgid "Add" msgstr "Hinzufќgen" msgid "Remove" msgstr "Entfernen" msgid "Add recursivly?" msgstr "Recursiv hinzufќgen?" msgid "Empty directory!" msgstr "Leeres Verzeichnis!" msgid "Remove entry?" msgstr "Eintrag entfernen?" msgid "Add all" msgstr "Alle hinzufќgen" msgid "Rename playlist" msgstr "Abspielliste umbenennen" msgid "Old name:" msgstr "Alter Name:" msgid "New name" msgstr "Neuer Name" msgid "Source" msgstr "Datentrфger" msgid "Browse" msgstr "Blфttern" msgid "Rename" msgstr "Umbenennen" msgid "Scanning playlists..." msgstr "Durchsuche Abspiellisten..." msgid "Error scanning playlists!" msgstr "Fehler beim Einlesen der Abspiellisten!" msgid "Delete playlist?" msgstr "Abspielliste lіschen?" msgid "Are you sure?" msgstr "Wirklich lіschen?" msgid "Error deleting playlist!" msgstr "Fehler beim Lіschen der Abspielliste!" msgid "unnamed" msgstr "unbenannt" msgid "Error creating playlist!" msgstr "Fehler beim Erstellen der Abspielliste!" msgid "Error renaming playlist!" msgstr "Fehler beim Umbenennen der Abspielliste!" msgid "Error loading playlist!" msgstr "Fehler beim Lesen der Abspielliste!" msgid "Can't edit a WinAmp playlist!" msgstr "Editieren von WinAmp Abspiellisten nicht mіglich!" msgid "Loading playlist..." msgstr "Lade Abspielliste..." msgid "MP3 source" msgstr "MP3 Datentrфger" msgid "Play all" msgstr "Alle abspielen" msgid "Building playlist..." msgstr "Baue Abspielliste auf..." msgid "Error building playlist!" msgstr "Fehler beim Aufbau der Abspielliste!" msgid "A versatile audio player" msgstr "Ein vielseitiger Audio-Player" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "Kontroll Modus" msgid "Traditional" msgstr "Traditionell" msgid "Slave" msgstr "Slave" msgid "global only" msgstr "nur global" msgid "local first" msgstr "zuerst local" msgid "Setup.MPlayer$Resume mode" msgstr "Modus fќr Wiederaufnahme" msgid "Setup.MPlayer$Slave command key" msgstr "Slave Kommando Taste" msgid "MPlayer Audio ID" msgstr "MPlayer Audio ID" msgid "Audiostream ID" msgstr "Tonspur ID" msgid "MPlayer browser" msgstr "MPlayer Verzeichnisanzeige" msgid "MPlayer source" msgstr "MPlayer Datentrфger" msgid "Summary" msgstr "Zusammenfassung" msgid "Media replay via MPlayer" msgstr "Medien Wiedergabe ќber MPlayer" msgid "Connecting to stream server ..." msgstr "Verbinde mit Stream Server..." mp3-0.10.2/po/el_GR.po0100644000000000000000000001262011307515470012742 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Dimitrios Dimitrakos # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-7\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "" msgid "Remote CDDB lookup..." msgstr "" msgid "Select" msgstr "Epilogi" msgid "Parent" msgstr "Piso" msgid "ID3 info" msgstr "ID3 pliroforia" msgid "Scanning directory..." msgstr "" msgid "Error scanning directory!" msgstr "Lathos stin sarosi tou fakelou!" msgid "Mount" msgstr "Sindesi" msgid "Unmount" msgstr "Aposindesi" msgid "Eject" msgstr "" msgid "Selected source is not mounted!" msgstr "Epilegmeni Pigi den ine sindemeni!" msgid "Mount failed!" msgstr "I sindesi apetixe!" msgid "Mount succeeded" msgstr "I sindesi petixe" msgid "Unmount succeeded" msgstr "I aposindesi itan epitixisi" msgid "Unmount failed!" msgstr "I aposindesi den itan epitixis!" msgid "Eject failed!" msgstr "I apovoli apetixe!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "" msgid "Setup.MP3$Audio mode" msgstr "Katastasi audio" msgid "Round" msgstr "Kikli" msgid "Dither" msgstr "" msgid "Setup.MP3$Use 48kHz mode only" msgstr "" msgid "classic" msgstr "" msgid "via skin" msgstr "" msgid "Setup.MP3$Replay display" msgstr "" msgid "Setup.MP3$Display mode" msgstr "" msgid "Black" msgstr "Mavro" msgid "Live" msgstr "Zontana" msgid "Images" msgstr "" msgid "Setup.MP3$Background mode" msgstr "" msgid "Setup.MP3$Initial loop mode" msgstr "" msgid "Setup.MP3$Initial shuffle mode" msgstr "" msgid "Setup.MP3$Abort player at end of list" msgstr "" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "" msgid "ID3 only" msgstr "" msgid "ID3 & Level" msgstr "" msgid "Setup.MP3$Background scan" msgstr "" msgid "Setup.MP3$Editor display mode" msgstr "" msgid "Filenames" msgstr "Onomata arxeion" msgid "ID3 names" msgstr "ID3 onomata" msgid "Setup.MP3$Mainmenu mode" msgstr "" msgid "Playlists" msgstr "Listes peksimatos" msgid "Browser" msgstr "" msgid "Setup.MP3$Keep selection menu" msgstr "" msgid "Setup.MP3$Title/Artist order" msgstr "" msgid "Normal" msgstr "" msgid "Reversed" msgstr "" msgid "Hide mainmenu entry" msgstr "" msgid "Setup.MP3$Normalizer level" msgstr "" msgid "Setup.MP3$Limiter level" msgstr "" msgid "Setup.MP3$Use HTTP proxy" msgstr "" msgid "Setup.MP3$HTTP proxy host" msgstr "" msgid "Setup.MP3$HTTP proxy port" msgstr "" msgid "local only" msgstr "" msgid "local&remote" msgstr "" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "" msgid "Setup.MP3$CDDB server" msgstr "" msgid "Setup.MP3$CDDB port" msgstr "" msgid "ID3 information" msgstr "Plirofories ID3" msgid "Filename" msgstr "Onoma arxeiou" msgid "Length" msgstr "Megethos" msgid "Title" msgstr "Titlos" msgid "Artist" msgstr "Ermineftis" msgid "Album" msgstr "Album" msgid "Year" msgstr "Etos" msgid "Samplerate" msgstr "Sixnotita" msgid "Bitrate" msgstr "Bitrate" msgid "Directory browser" msgstr "Endiski fakelou" msgid "Playlist editor" msgstr "Metatropes stin Playlista" msgid "Add" msgstr "Prosthesi" msgid "Remove" msgstr "Aferesi" msgid "Add recursivly?" msgstr "Prosthesi recursiv?" msgid "Empty directory!" msgstr "Adios fakelos!" msgid "Remove entry?" msgstr "Aferesi simiou?" msgid "Add all" msgstr "Prosthesi olon" msgid "Rename playlist" msgstr "Metonomasi tis Playlistas" msgid "Old name:" msgstr "Palio onoma:" msgid "New name" msgstr "Neo onoma" msgid "Source" msgstr "Pigi" msgid "Browse" msgstr "Selida" msgid "Rename" msgstr "Alagi Onomatos" msgid "Scanning playlists..." msgstr "" msgid "Error scanning playlists!" msgstr "Lathos stin sarosi tis Playlistas!" msgid "Delete playlist?" msgstr "Svisimo listas?" msgid "Are you sure?" msgstr "Ise sigouros?" msgid "Error deleting playlist!" msgstr "Lathos stin akirosi tis Playlistas!" msgid "unnamed" msgstr "xoris onoma" msgid "Error creating playlist!" msgstr "Lathos stin dimiourgia tis Playlistas!" msgid "Error renaming playlist!" msgstr "Latsos stin metonomasi tis Playlistas!" msgid "Error loading playlist!" msgstr "Lathos sto fortoma tis Playlistas!" msgid "Can't edit a WinAmp playlist!" msgstr "Den mporo na kano metatropes se WinAmp Playlista!" msgid "Loading playlist..." msgstr "" msgid "MP3 source" msgstr "Pigi MP3" msgid "Play all" msgstr "Peksimo olon" msgid "Building playlist..." msgstr "" msgid "Error building playlist!" msgstr "" msgid "A versatile audio player" msgstr "" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "" msgid "Traditional" msgstr "" msgid "Slave" msgstr "" msgid "global only" msgstr "" msgid "local first" msgstr "" msgid "Setup.MPlayer$Resume mode" msgstr "" msgid "Setup.MPlayer$Slave command key" msgstr "" msgid "MPlayer Audio ID" msgstr "" msgid "Audiostream ID" msgstr "" msgid "MPlayer browser" msgstr "Mplayer endiksi fakelon" msgid "MPlayer source" msgstr "Pigi MPlayer" msgid "Summary" msgstr "" msgid "Media replay via MPlayer" msgstr "" msgid "Connecting to stream server ..." msgstr "" mp3-0.10.2/po/es_ES.po0100644000000000000000000001373111307515470012754 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Ramon Roca # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "desconocido" msgid "Remote CDDB lookup..." msgstr "Consultando CDDB..." msgid "Select" msgstr "Seleccionar" msgid "Parent" msgstr "Predecesor" msgid "ID3 info" msgstr "ID3 info" msgid "Scanning directory..." msgstr "Leyendo las carpetas.." msgid "Error scanning directory!" msgstr "ЁError al leer una carpeta!" msgid "Mount" msgstr "Mount" msgid "Unmount" msgstr "Unmount" msgid "Eject" msgstr "" msgid "Selected source is not mounted!" msgstr "ЁEl origen deseado no estр montado!" msgid "Mount failed!" msgstr "ЁNo he podido montar!" msgid "Mount succeeded" msgstr "mount correcto" msgid "Unmount succeeded" msgstr "Щxito al unmount" msgid "Unmount failed!" msgstr "ЁNo puedo desmontar!" msgid "Eject failed!" msgstr "ЁNo puedo expulsar!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "" msgid "Setup.MP3$Audio mode" msgstr "Modo de audio" msgid "Round" msgstr "Redondear" msgid "Dither" msgstr "Compactar" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Solo modo 48kHz" msgid "classic" msgstr "" msgid "via skin" msgstr "" msgid "Setup.MP3$Replay display" msgstr "" msgid "Setup.MP3$Display mode" msgstr "Modo de Visualizaciѓn" msgid "Black" msgstr "Negra" msgid "Live" msgstr "En vivo" msgid "Images" msgstr "" msgid "Setup.MP3$Background mode" msgstr "Ejecutar al fondo" msgid "Setup.MP3$Initial loop mode" msgstr "Modo de repeticiѓn inicial" msgid "Setup.MP3$Initial shuffle mode" msgstr "Lectura aleatѓria inicial" msgid "Setup.MP3$Abort player at end of list" msgstr "" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "desactivado" msgid "ID3 only" msgstr "" msgid "ID3 & Level" msgstr "" msgid "Setup.MP3$Background scan" msgstr "" msgid "Setup.MP3$Editor display mode" msgstr "Modo de visualizaciѓn del editor" msgid "Filenames" msgstr "Nombre de los archivos" msgid "ID3 names" msgstr "Nombre ID3" msgid "Setup.MP3$Mainmenu mode" msgstr "Menњ Principal" msgid "Playlists" msgstr "Lista de reproducciѓn" msgid "Browser" msgstr "Navegador" msgid "Setup.MP3$Keep selection menu" msgstr "" msgid "Setup.MP3$Title/Artist order" msgstr "" msgid "Normal" msgstr "" msgid "Reversed" msgstr "" msgid "Hide mainmenu entry" msgstr "" msgid "Setup.MP3$Normalizer level" msgstr "Nivel de normalizaciѓn" msgid "Setup.MP3$Limiter level" msgstr "Limitador del nivel" msgid "Setup.MP3$Use HTTP proxy" msgstr "Utilizar proxy HTTP" msgid "Setup.MP3$HTTP proxy host" msgstr "Nombre del puerto HTTP" msgid "Setup.MP3$HTTP proxy port" msgstr "Puerto del Proxy HTTP" msgid "local only" msgstr "solo local" msgid "local&remote" msgstr "local y remoto" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB para el Aidio-CD" msgid "Setup.MP3$CDDB server" msgstr "Servidor CDDB" msgid "Setup.MP3$CDDB port" msgstr "Puerto CDDB" msgid "ID3 information" msgstr "Informaciѓn ID3" msgid "Filename" msgstr "Nombre del archivo" msgid "Length" msgstr "Duraciѓn" msgid "Title" msgstr "Tэtulo" msgid "Artist" msgstr "Artista" msgid "Album" msgstr "Album" msgid "Year" msgstr "" msgid "Samplerate" msgstr "Frecuencia" msgid "Bitrate" msgstr "Bitrate" msgid "Directory browser" msgstr "Explorar carpetes" msgid "Playlist editor" msgstr "Editor de listas de reproducciѓn" msgid "Add" msgstr "Aёadir" msgid "Remove" msgstr "Borrar" msgid "Add recursivly?" msgstr "ПAёadir recursivamente?" msgid "Empty directory!" msgstr "ЁCarpeta vacэa!" msgid "Remove entry?" msgstr "ПBorrar la entrada?" msgid "Add all" msgstr "Aёadir todo" msgid "Rename playlist" msgstr "Renombrar la lista de reproducciѓn" msgid "Old name:" msgstr "Nombre anterior:" msgid "New name" msgstr "Nombre nuevo" msgid "Source" msgstr "Origen" msgid "Browse" msgstr "Explorar" msgid "Rename" msgstr "Renombrar" msgid "Scanning playlists..." msgstr "Leyendo las listas de reproducciѓn..." msgid "Error scanning playlists!" msgstr "ЁError al leer las listas!" msgid "Delete playlist?" msgstr "ПBorrar la lista?" msgid "Are you sure?" msgstr "ПEstс seguro?" msgid "Error deleting playlist!" msgstr "ЁError al borrar una lista!" msgid "unnamed" msgstr "sin nombre" msgid "Error creating playlist!" msgstr "ЁError al crear una lista!" msgid "Error renaming playlist!" msgstr "ЁErrir al renombrar la lista!" msgid "Error loading playlist!" msgstr "ЁError al cargar la lista de reproducciѓn!" msgid "Can't edit a WinAmp playlist!" msgstr "ЁNo puedo editar una lista del WinAmp!" msgid "Loading playlist..." msgstr "Cargando la lista de reproducciѓn..." msgid "MP3 source" msgstr "Origen MP3" msgid "Play all" msgstr "Reproducirlo todo" msgid "Building playlist..." msgstr "Construyendo la lista de reproducciѓn..." msgid "Error building playlist!" msgstr "ЁError al construir la lista de reproducciѓn!" msgid "A versatile audio player" msgstr "" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "Modo de control" msgid "Traditional" msgstr "Tradicional" msgid "Slave" msgstr "Esclavo" msgid "global only" msgstr "" msgid "local first" msgstr "" msgid "Setup.MPlayer$Resume mode" msgstr "" msgid "Setup.MPlayer$Slave command key" msgstr "" msgid "MPlayer Audio ID" msgstr "" msgid "Audiostream ID" msgstr "" msgid "MPlayer browser" msgstr "Navegador del MPlayer" msgid "MPlayer source" msgstr "" msgid "Summary" msgstr "" msgid "Media replay via MPlayer" msgstr "" msgid "Connecting to stream server ..." msgstr "Conectando con el servidor..." mp3-0.10.2/po/fi_FI.po0100644000000000000000000001462611307515470012736 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Rolf Ahrenberg # Ville Skyttф # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "tuntematon" msgid "Remote CDDB lookup..." msgstr "Kysytффn CDDB-tietoja..." msgid "Select" msgstr "Valitse" msgid "Parent" msgstr "Takaisin" msgid "ID3 info" msgstr "ID3-info" msgid "Scanning directory..." msgstr "Selataan hakemistoa..." msgid "Error scanning directory!" msgstr "Hakemiston avaaminen epфonnistui!" msgid "Mount" msgstr "Kiinnitф" msgid "Unmount" msgstr "Irrota" msgid "Eject" msgstr "Avaa" msgid "Selected source is not mounted!" msgstr "Valittu lфhde ei ole kiinnitetty!" msgid "Mount failed!" msgstr "Kiinnittфminen epфonnistui!" msgid "Mount succeeded" msgstr "Kiinnittфminen onnistui" msgid "Unmount succeeded" msgstr "Irrottaminen onnistui" msgid "Unmount failed!" msgstr "Irrottaminen epфonnistui!" msgid "Eject failed!" msgstr "Aseman avaaminen epфonnistui!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3-soitin" msgid "Setup.MP3$Audio output mode" msgstr "Ффnen ulostulomoodi" msgid "Setup.MP3$Audio mode" msgstr "Ффnimoodi" msgid "Round" msgstr "pyіristetty" msgid "Dither" msgstr "ditteroitu" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Kфytф vain 48kHz moodia" msgid "classic" msgstr "klassinen" msgid "via skin" msgstr "ulkoasun mukaan" msgid "Setup.MP3$Replay display" msgstr "Toistotilan nфyttіmoodi" msgid "Setup.MP3$Display mode" msgstr "Nфyttіmoodi" msgid "Black" msgstr "musta" msgid "Live" msgstr "live" msgid "Images" msgstr "kansikuva" msgid "Setup.MP3$Background mode" msgstr "Taustamoodi" msgid "Setup.MP3$Initial loop mode" msgstr "Jatkuva soitto oletuksena" msgid "Setup.MP3$Initial shuffle mode" msgstr "Satunnaissoitto oletuksena" msgid "Setup.MP3$Abort player at end of list" msgstr "Keskeytф soittolistan loputtua" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "pois" msgid "ID3 only" msgstr "vain ID3" msgid "ID3 & Level" msgstr "ID3 & taso" msgid "Setup.MP3$Background scan" msgstr "Taustaskannaus" msgid "Setup.MP3$Editor display mode" msgstr "Muokkaustilan nфyttіmoodi" msgid "Filenames" msgstr "tiedostonimet" msgid "ID3 names" msgstr "ID3-nimet" msgid "Setup.MP3$Mainmenu mode" msgstr "Pффvalikon tila" msgid "Playlists" msgstr "soittolistat" msgid "Browser" msgstr "selain" msgid "Setup.MP3$Keep selection menu" msgstr "Pidф valintaikkunaa auki" msgid "Setup.MP3$Title/Artist order" msgstr "Nфytф kappale ja esittфjф" msgid "Normal" msgstr "normaalisti" msgid "Reversed" msgstr "kффnnettynф" msgid "Hide mainmenu entry" msgstr "Piilota valinta pффvalikosta" msgid "Setup.MP3$Normalizer level" msgstr "Normalisoinnin taso" msgid "Setup.MP3$Limiter level" msgstr "Rajoittimen taso" msgid "Setup.MP3$Use HTTP proxy" msgstr "Kфytф HTTP-vфlityspalvelinta" msgid "Setup.MP3$HTTP proxy host" msgstr "HTTP-vфlityspalvelimen osoite" msgid "Setup.MP3$HTTP proxy port" msgstr "HTTP-vфlityspalvelimen portti" msgid "local only" msgstr "vain paikallinen" msgid "local&remote" msgstr "paikallinen & etф" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB-tietokanta" msgid "Setup.MP3$CDDB server" msgstr "CDDB-palvelin" msgid "Setup.MP3$CDDB port" msgstr "CDDB-palvelimen portti" msgid "ID3 information" msgstr "ID3-informaatio" msgid "Filename" msgstr "Tiedostonimi" msgid "Length" msgstr "Pituus" msgid "Title" msgstr "Kappale" msgid "Artist" msgstr "Esittфjф" msgid "Album" msgstr "Albumi" msgid "Year" msgstr "Vuosi" msgid "Samplerate" msgstr "Nфytteenottotaajuus" msgid "Bitrate" msgstr "Bittinopeus" msgid "Directory browser" msgstr "Hakemistoselain" msgid "Playlist editor" msgstr "Soittolistan muokkaus" msgid "Add" msgstr "Lisфф" msgid "Remove" msgstr "Poista" msgid "Add recursivly?" msgstr "Lisфф rekursiivisesti?" msgid "Empty directory!" msgstr "Hakemisto on tyhjф!" msgid "Remove entry?" msgstr "Poistetaanko merkintф?" msgid "Add all" msgstr "Lisфф kaikki" msgid "Rename playlist" msgstr "Nimeф soittolista" msgid "Old name:" msgstr "Vanha nimi" msgid "New name" msgstr "Uusi nimi" msgid "Source" msgstr "Lфhde" msgid "Browse" msgstr "Selaa" msgid "Rename" msgstr "Nimeф" msgid "Scanning playlists..." msgstr "Selataan soittolistoja..." msgid "Error scanning playlists!" msgstr "Soittolistojen lukeminen epфonnistui!" msgid "Delete playlist?" msgstr "Poistetaanko soittolista?" msgid "Are you sure?" msgstr "Oletko varma?" msgid "Error deleting playlist!" msgstr "Soittolistan poistaminen epфonnistui!" msgid "unnamed" msgstr "nimetіn" msgid "Error creating playlist!" msgstr "Soittolistan luominen epфonnistui!" msgid "Error renaming playlist!" msgstr "Soittolistan uudelleennimeфminen epфonnistui!" msgid "Error loading playlist!" msgstr "Soittolistan avaaminen epфonnistui!" msgid "Can't edit a WinAmp playlist!" msgstr "WinAmp-soittolistaa ei voida muokata!" msgid "Loading playlist..." msgstr "Avataan soittolistaa..." msgid "MP3 source" msgstr "MP3-lфhde" msgid "Play all" msgstr "Soita kaikki" msgid "Building playlist..." msgstr "Muodostetaan soittolistaa..." msgid "Error building playlist!" msgstr "Soittolistan muodostaminen epфonnistui!" msgid "A versatile audio player" msgstr "Monipuolinen audiosoitin" msgid "MPlayer" msgstr "MPlayer-mediasoitin" msgid "Setup.MPlayer$Control mode" msgstr "Komentotila" msgid "Traditional" msgstr "perinteinen" msgid "Slave" msgstr "orja" msgid "global only" msgstr "globaali" msgid "local first" msgstr "paikallinen" msgid "Setup.MPlayer$Resume mode" msgstr "Resume-toiminto" msgid "Setup.MPlayer$Slave command key" msgstr "Orjakomento nфppфimelle" msgid "MPlayer Audio ID" msgstr "MPlayerin ффniraidan valinta" msgid "Audiostream ID" msgstr "Ффniraidan ID" msgid "MPlayer browser" msgstr "MPlayer-hakemistoselain" msgid "MPlayer source" msgstr "MPlayer-lфhde" msgid "Summary" msgstr "" msgid "Media replay via MPlayer" msgstr "MPlayeriin perustuva mediasoitin" msgid "Connecting to stream server ..." msgstr "Yhdistetффn palvelimeen..." mp3-0.10.2/po/fr_FR.po0100644000000000000000000001443111307515470012752 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Maxime Guilbot # Pierre-Henri Beguin # Jerome Rousset # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "inconnu" msgid "Remote CDDB lookup..." msgstr "Consultation CDDB..." msgid "Select" msgstr "Sщlectionner" msgid "Parent" msgstr "Parent" msgid "ID3 info" msgstr "Info ID3" msgid "Scanning directory..." msgstr "Scanne le repertoire..." msgid "Error scanning directory!" msgstr "Erreur de parcours du rщpertoire!" msgid "Mount" msgstr "Monter" msgid "Unmount" msgstr "Dщmonter" msgid "Eject" msgstr "Eject" msgid "Selected source is not mounted!" msgstr "Source sщlectionnщe non montщe!" msgid "Mount failed!" msgstr "Echec du montage!" msgid "Mount succeeded" msgstr "Montage rщussi" msgid "Unmount succeeded" msgstr "Dщmontage rщussi" msgid "Unmount failed!" msgstr "Echec du dщmontage!" msgid "Eject failed!" msgstr "Echec de l'щjection!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "Mode de sortie audio" msgid "Setup.MP3$Audio mode" msgstr "Mode audio" msgid "Round" msgstr "Arrondir" msgid "Dither" msgstr "Lisser" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Mode 48kHz uniquement" msgid "classic" msgstr "Classique" msgid "via skin" msgstr "Par skin" msgid "Setup.MP3$Replay display" msgstr "Affichage relecture" msgid "Setup.MP3$Display mode" msgstr "Mode d'affichage" msgid "Black" msgstr "Noir" msgid "Live" msgstr "Live" msgid "Images" msgstr "Images" msgid "Setup.MP3$Background mode" msgstr "Arriшre plan" msgid "Setup.MP3$Initial loop mode" msgstr "Mode de rщpщtition initial" msgid "Setup.MP3$Initial shuffle mode" msgstr "Mode de lecture alщatoire initial" msgid "Setup.MP3$Abort player at end of list" msgstr "Stopper le lecteur р la fin de la liste" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "dщsactiver" msgid "ID3 only" msgstr "Seulement ID3" msgid "ID3 & Level" msgstr "ID3 et niveau" msgid "Setup.MP3$Background scan" msgstr "Scan en tache de fond" msgid "Setup.MP3$Editor display mode" msgstr "Mode d'affichage de l'щditeur" msgid "Filenames" msgstr "Noms de fichiers" msgid "ID3 names" msgstr "Nom ID3" msgid "Setup.MP3$Mainmenu mode" msgstr "Menu principal" msgid "Playlists" msgstr "Playlists" msgid "Browser" msgstr "Navigateur" msgid "Setup.MP3$Keep selection menu" msgstr "Afficher le menu de selection" msgid "Setup.MP3$Title/Artist order" msgstr "Trier par Titre/Artiste" msgid "Normal" msgstr "Normal" msgid "Reversed" msgstr "Inversщ" msgid "Hide mainmenu entry" msgstr "Cacher l entrщe du menu" msgid "Setup.MP3$Normalizer level" msgstr "Niveau de normalisation" msgid "Setup.MP3$Limiter level" msgstr "Niveau limite" msgid "Setup.MP3$Use HTTP proxy" msgstr "Utiliser un Proxy HTTP" msgid "Setup.MP3$HTTP proxy host" msgstr "Nom du Proxy HTTP" msgid "Setup.MP3$HTTP proxy port" msgstr "Port du proxy HTTP" msgid "local only" msgstr "local uniquement" msgid "local&remote" msgstr "local et distant" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB pour CD-Audio" msgid "Setup.MP3$CDDB server" msgstr "Serveur CDDB" msgid "Setup.MP3$CDDB port" msgstr "Port CDDB" msgid "ID3 information" msgstr "Information ID3" msgid "Filename" msgstr "Nom du fichier" msgid "Length" msgstr "Longueur" msgid "Title" msgstr "Titre" msgid "Artist" msgstr "Artiste" msgid "Album" msgstr "Album" msgid "Year" msgstr "Annщe" msgid "Samplerate" msgstr "Frщquence" msgid "Bitrate" msgstr "Bitrate" msgid "Directory browser" msgstr "Navigateur" msgid "Playlist editor" msgstr "Editeur de liste de lecture" msgid "Add" msgstr "Ajouter" msgid "Remove" msgstr "Enlever" msgid "Add recursivly?" msgstr "Ajouter rщcursivement?" msgid "Empty directory!" msgstr "Rщpertoire vide!" msgid "Remove entry?" msgstr "Enlever titre?" msgid "Add all" msgstr "Ajouter tous" msgid "Rename playlist" msgstr "Renommer la liste" msgid "Old name:" msgstr "Ancien nom:" msgid "New name" msgstr "Nouveau nom" msgid "Source" msgstr "Source" msgid "Browse" msgstr "Parcourir" msgid "Rename" msgstr "Renommer" msgid "Scanning playlists..." msgstr "Scanne playlists..." msgid "Error scanning playlists!" msgstr "Erreur de parcours de la liste!" msgid "Delete playlist?" msgstr "Effacer liste?" msgid "Are you sure?" msgstr "Etes-vous sћr?" msgid "Error deleting playlist!" msgstr "Erreur d'effacement de la liste!" msgid "unnamed" msgstr "sansnom" msgid "Error creating playlist!" msgstr "Erreur de crщation de la liste!" msgid "Error renaming playlist!" msgstr "Erreur pour renommer la liste!" msgid "Error loading playlist!" msgstr "Erreur de chargement de la playlist!" msgid "Can't edit a WinAmp playlist!" msgstr "Ne peut pas щditer une liste WinAmp!" msgid "Loading playlist..." msgstr "Chargement playlist..." msgid "MP3 source" msgstr "Source MP3" msgid "Play all" msgstr "Jouer tous" msgid "Building playlist..." msgstr "Construit la playlist..." msgid "Error building playlist!" msgstr "Erreur construction playlist!" msgid "A versatile audio player" msgstr "Lecteur multiformats" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "Mode de controle" msgid "Traditional" msgstr "Traditionnel" msgid "Slave" msgstr "Esclave" msgid "global only" msgstr "Global seulement" msgid "local first" msgstr "Local en premier" msgid "Setup.MPlayer$Resume mode" msgstr "Reprise" msgid "Setup.MPlayer$Slave command key" msgstr "Commande esclave" msgid "MPlayer Audio ID" msgstr "Mplayer piste audio" msgid "Audiostream ID" msgstr "Canal audio" msgid "MPlayer browser" msgstr "Navigateur MPlayer" msgid "MPlayer source" msgstr "Source MPlayer" msgid "Summary" msgstr "Rщsumщ" msgid "Media replay via MPlayer" msgstr "Lecture par MPlayer" msgid "Connecting to stream server ..." msgstr "Connexion au Serveur Stream..." mp3-0.10.2/po/it_IT.po0100644000000000000000000001447111307515470012770 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Diego Pierotto # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2008-06-25 23:37+0100\n" "Last-Translator: Diego Pierotto \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "sconosciuto" msgid "Remote CDDB lookup..." msgstr "Verifica CDDB remoto..." msgid "Select" msgstr "Seleziona" msgid "Parent" msgstr "Precedente" msgid "ID3 info" msgstr "Info ID3" msgid "Scanning directory..." msgstr "Scansione directory..." msgid "Error scanning directory!" msgstr "Errore scansione directory!" msgid "Mount" msgstr "Monta" msgid "Unmount" msgstr "Smonta" msgid "Eject" msgstr "Espelli" msgid "Selected source is not mounted!" msgstr "La fonte selezionata non ш montata!" msgid "Mount failed!" msgstr "Montaggio fallito!" msgid "Mount succeeded" msgstr "Montaggio riuscito" msgid "Unmount succeeded" msgstr "Smontaggio riuscito" msgid "Unmount failed!" msgstr "Smontaggio fallito!" msgid "Eject failed!" msgstr "Espulsione fallita!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "Mod. uscita audio" msgid "Setup.MP3$Audio mode" msgstr "Mod. audio" msgid "Round" msgstr "Arrotonda" msgid "Dither" msgstr "Compatta" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Usa solo mod. 48kHz" msgid "classic" msgstr "classica" msgid "via skin" msgstr "con interfaccia" msgid "Setup.MP3$Replay display" msgstr "Mostra riproduzione" msgid "Setup.MP3$Display mode" msgstr "Mod. visualizzazione" msgid "Black" msgstr "Nero" msgid "Live" msgstr "Dal vivo" msgid "Images" msgstr "Immagini" msgid "Setup.MP3$Background mode" msgstr "Mod. sottofondo" msgid "Setup.MP3$Initial loop mode" msgstr "Mod. ripetizione iniziale" msgid "Setup.MP3$Initial shuffle mode" msgstr "Lettura casuale iniziale" msgid "Setup.MP3$Abort player at end of list" msgstr "Ferma lettore alla fine della lista" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "disabilitato" msgid "ID3 only" msgstr "Solo ID3" msgid "ID3 & Level" msgstr "ID3 & livello" msgid "Setup.MP3$Background scan" msgstr "Scansione in sottofondo" msgid "Setup.MP3$Editor display mode" msgstr "Mod. visualizzazione editor" msgid "Filenames" msgstr "Nomi dei file" msgid "ID3 names" msgstr "Nome ID3" msgid "Setup.MP3$Mainmenu mode" msgstr "Menu principale" msgid "Playlists" msgstr "Lista esecuzione" msgid "Browser" msgstr "Sfoglia" msgid "Setup.MP3$Keep selection menu" msgstr "Mantieni selezione menu" msgid "Setup.MP3$Title/Artist order" msgstr "Ordine Titolo/Artista" msgid "Normal" msgstr "Normale" msgid "Reversed" msgstr "Invertito" msgid "Hide mainmenu entry" msgstr "Nascondi voce menu principale" msgid "Setup.MP3$Normalizer level" msgstr "Livello normalizzazione" msgid "Setup.MP3$Limiter level" msgstr "Livello limitatore" msgid "Setup.MP3$Use HTTP proxy" msgstr "Usa proxy HTTP" msgid "Setup.MP3$HTTP proxy host" msgstr "Nome proxy HTTP" msgid "Setup.MP3$HTTP proxy port" msgstr "Porta proxy HTTP" msgid "local only" msgstr "solo locale" msgid "local&remote" msgstr "locale e remoto" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB per Audio-CD" msgid "Setup.MP3$CDDB server" msgstr "Server CDDB" msgid "Setup.MP3$CDDB port" msgstr "Porta CDDB" msgid "ID3 information" msgstr "Informazione ID3" msgid "Filename" msgstr "Nome file" msgid "Length" msgstr "Durata" msgid "Title" msgstr "Titolo" msgid "Artist" msgstr "Artista" msgid "Album" msgstr "Album" msgid "Year" msgstr "Anno" msgid "Samplerate" msgstr "Frequenza" msgid "Bitrate" msgstr "Bitrate" msgid "Directory browser" msgstr "Sfoglia directory" msgid "Playlist editor" msgstr "Editor lista esecuzione" msgid "Add" msgstr "Aggiungi" msgid "Remove" msgstr "Rimuovi" msgid "Add recursivly?" msgstr "Aggiungere ricorsivamente?" msgid "Empty directory!" msgstr "Svuota directory!" msgid "Remove entry?" msgstr "Rimuovere voce?" msgid "Add all" msgstr "Aggiungi tutti" msgid "Rename playlist" msgstr "Rinomina lista esecuzione" msgid "Old name:" msgstr "Vecchio nome:" msgid "New name" msgstr "Nuovo nome" msgid "Source" msgstr "Fonte" msgid "Browse" msgstr "Sfoglia" msgid "Rename" msgstr "Rinomina" msgid "Scanning playlists..." msgstr "Scansione liste esecuzione..." msgid "Error scanning playlists!" msgstr "Errore scansione liste esecuzione!" msgid "Delete playlist?" msgstr "Eliminare lista esecuzione?" msgid "Are you sure?" msgstr "Sei sicuro?" msgid "Error deleting playlist!" msgstr "Errore eliminazione lista esecuzione!" msgid "unnamed" msgstr "senza nome" msgid "Error creating playlist!" msgstr "Errore creazione lista esecuzione!" msgid "Error renaming playlist!" msgstr "Errore ridenominazione lista esecuzione" msgid "Error loading playlist!" msgstr "Errore caricamento lista esecuzione!" msgid "Can't edit a WinAmp playlist!" msgstr "Non posso modificare un lista esecuzione di Winamp!" msgid "Loading playlist..." msgstr "Caricamento lista esecuzione..." msgid "MP3 source" msgstr "Fonte MP3" msgid "Play all" msgstr "Esegui tutti" msgid "Building playlist..." msgstr "Creazione lista esecuzione..." msgid "Error building playlist!" msgstr "Errore creazione lista esecuzione!" msgid "A versatile audio player" msgstr "Un lettore audio versatile" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "Mod. controllo" msgid "Traditional" msgstr "Tradizionale" msgid "Slave" msgstr "Esclavo" msgid "global only" msgstr "solo globale" msgid "local first" msgstr "prima locale" msgid "Setup.MPlayer$Resume mode" msgstr "Mod. ripristino" msgid "Setup.MPlayer$Slave command key" msgstr "Tasto comando slave" msgid "MPlayer Audio ID" msgstr "ID audio MPlayer" msgid "Audiostream ID" msgstr "ID canale audio" msgid "MPlayer browser" msgstr "Navigatore MPlayer" msgid "MPlayer source" msgstr "Fonte MPlayer" msgid "Summary" msgstr "Sommario" msgid "Media replay via MPlayer" msgstr "Riproduci media con MPlayer" msgid "Connecting to stream server ..." msgstr "Connessione al server stream..." mp3-0.10.2/po/ru_RU.po0100644000000000000000000001464111307515470013013 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Vyacheslav Dikonov # Alexander , 2008. # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2008-03-12 19:50+0100\n" "Last-Translator: Alexander \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-5\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" msgid "unknown" msgstr "неизвестный" msgid "Remote CDDB lookup..." msgstr "Запрос к удалённой базе CDDB..." msgid "Select" msgstr "Выбрать" msgid "Parent" msgstr "Вверх" msgid "ID3 info" msgstr "данные ID3" msgid "Scanning directory..." msgstr "Сканирование каталогов..." msgid "Error scanning directory!" msgstr "Ошибка сканирования каталога!" msgid "Mount" msgstr "Подключить" msgid "Unmount" msgstr "Отключить" msgid "Eject" msgstr "Извлечь" msgid "Selected source is not mounted!" msgstr "Выбранный диск не подключен!" msgid "Mount failed!" msgstr "Ошибка подключения диска!" msgid "Mount succeeded" msgstr "Диск подключен" msgid "Unmount succeeded" msgstr "Диск отключен" msgid "Unmount failed!" msgstr "Ошибка отключения диска!" msgid "Eject failed!" msgstr "Ошибка извлечения диска!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "Проигрыватель MP3" msgid "Setup.MP3$Audio output mode" msgstr "Режим вывода звука" msgid "Setup.MP3$Audio mode" msgstr "Режим переоцифровки звука" msgid "Round" msgstr "приближение" msgid "Dither" msgstr "сглаживание" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Только 48 кГц" msgid "classic" msgstr "классический" msgid "via skin" msgstr "согласно теме" msgid "Setup.MP3$Replay display" msgstr "Интерфейс в режиме воспроизведения" msgid "Setup.MP3$Display mode" msgstr "Режим интерфейса" msgid "Black" msgstr "чёрный экран" msgid "Live" msgstr "телевидение" msgid "Images" msgstr "Изображения" msgid "Setup.MP3$Background mode" msgstr "Режим фона" msgid "Setup.MP3$Initial loop mode" msgstr "Режим повтора по умолчанию" msgid "Setup.MP3$Initial shuffle mode" msgstr "Режим случайн. выбора по умолчанию" msgid "Setup.MP3$Abort player at end of list" msgstr "Выход в конце списка песен" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "выкл" msgid "ID3 only" msgstr "Только ID3" msgid "ID3 & Level" msgstr "ID3 и уровень" msgid "Setup.MP3$Background scan" msgstr "Фоновое сканирование" msgid "Setup.MP3$Editor display mode" msgstr "Режим редактора списков" msgid "Filenames" msgstr "имена файлов" msgid "ID3 names" msgstr "ID3-имена" msgid "Setup.MP3$Mainmenu mode" msgstr "Режим главного меню" msgid "Playlists" msgstr "списки песен" msgid "Browser" msgstr "каталоги" msgid "Setup.MP3$Keep selection menu" msgstr "Оставить меню открытым" msgid "Setup.MP3$Title/Artist order" msgstr "Последовательность названия/исполнителя" msgid "Normal" msgstr "Нормально" msgid "Reversed" msgstr "Реверсед" msgid "Hide mainmenu entry" msgstr "Скрыть команду в меню" msgid "Setup.MP3$Normalizer level" msgstr "Уровень нормализации" msgid "Setup.MP3$Limiter level" msgstr "Порог ограничителя пиков" msgid "Setup.MP3$Use HTTP proxy" msgstr "Использовать HTTP прокси" msgid "Setup.MP3$HTTP proxy host" msgstr "Сервер HTTP прокси" msgid "Setup.MP3$HTTP proxy port" msgstr "Порт HTTP прокси" msgid "local only" msgstr "только локальн." msgid "local&remote" msgstr "локальн. и удалён." msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB для аудио-CD" msgid "Setup.MP3$CDDB server" msgstr "Сервер CDDB" msgid "Setup.MP3$CDDB port" msgstr "Порт CDDB" msgid "ID3 information" msgstr "ID3-метки" msgid "Filename" msgstr "Имя файла" msgid "Length" msgstr "Длина" msgid "Title" msgstr "Название" msgid "Artist" msgstr "Исполнитель" msgid "Album" msgstr "Альбом" msgid "Year" msgstr "Год" msgid "Samplerate" msgstr "Частота" msgid "Bitrate" msgstr "Поток" msgid "Directory browser" msgstr "Просмотр каталогов" msgid "Playlist editor" msgstr "Редактор списка песен" msgid "Add" msgstr "Добавить" msgid "Remove" msgstr "Удалить" msgid "Add recursivly?" msgstr "Добавить рекурсивно?" msgid "Empty directory!" msgstr "Пустой каталог!" msgid "Remove entry?" msgstr "Удалить запись?" msgid "Add all" msgstr "Добавить всё" msgid "Rename playlist" msgstr "Переименовать список песен" msgid "Old name:" msgstr "Старое имя:" msgid "New name" msgstr "Новое имя:" msgid "Source" msgstr "Диск" msgid "Browse" msgstr "Каталоги" msgid "Rename" msgstr "Переименовать" msgid "Scanning playlists..." msgstr "Поиск списков песен..." msgid "Error scanning playlists!" msgstr "Ошибка поиска списков песен!" msgid "Delete playlist?" msgstr "Удалить список" msgid "Are you sure?" msgstr "Вы уверены?" msgid "Error deleting playlist!" msgstr "Ошибка удаления списка песен!" msgid "unnamed" msgstr "безымянный" msgid "Error creating playlist!" msgstr "Ошибка создания списка песен!" msgid "Error renaming playlist!" msgstr "Ошибка переименования списка!" msgid "Error loading playlist!" msgstr "Ошибка чтения списка песен!" msgid "Can't edit a WinAmp playlist!" msgstr "Невозможно редактировать список WinAmp!" msgid "Loading playlist..." msgstr "Чтение списка песен..." msgid "MP3 source" msgstr "Диск MP3" msgid "Play all" msgstr "Воспроизвести всё" msgid "Building playlist..." msgstr "Построение списка песен..." msgid "Error building playlist!" msgstr "Ошибка построения списка песен!" msgid "A versatile audio player" msgstr "Проигрыватель аудиофайлов" msgid "MPlayer" msgstr "Проигрыватель видео" msgid "Setup.MPlayer$Control mode" msgstr "Режим управления" msgid "Traditional" msgstr "обычный" msgid "Slave" msgstr "расширенный" msgid "global only" msgstr "только глобально" msgid "local first" msgstr "сначало локально" msgid "Setup.MPlayer$Resume mode" msgstr "Режим возобновления" msgid "Setup.MPlayer$Slave command key" msgstr "Slave команда кнопки" msgid "MPlayer Audio ID" msgstr "MPlayer аудио ID" msgid "Audiostream ID" msgstr "ID звуковой дорожки" msgid "MPlayer browser" msgstr "Просмотр каталогов MPlayer" msgid "MPlayer source" msgstr "Источник видео MPlayer" msgid "Summary" msgstr "Резюме" msgid "Media replay via MPlayer" msgstr "Проигрыватель видеофайлов" msgid "Connecting to stream server ..." msgstr "Подключение к серверу потоков..." mp3-0.10.2/po/sl_SI.po0100644000000000000000000001264711307515470012774 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Matjaz Thaler # msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-2\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "" msgid "Remote CDDB lookup..." msgstr "" msgid "Select" msgstr "Izberi" msgid "Parent" msgstr "Nazaj" msgid "ID3 info" msgstr "ID3 info" msgid "Scanning directory..." msgstr "" msgid "Error scanning directory!" msgstr "Napaka pri pregledovanju direktorija!" msgid "Mount" msgstr "Priklopi" msgid "Unmount" msgstr "Izklopi" msgid "Eject" msgstr "" msgid "Selected source is not mounted!" msgstr "Izbran izvor ni prikljucen!" msgid "Mount failed!" msgstr "Napaka pri priklopu!" msgid "Mount succeeded" msgstr "Priklop izveden" msgid "Unmount succeeded" msgstr "Izklop izveden" msgid "Unmount failed!" msgstr "Napaka pri izklopu!" msgid "Eject failed!" msgstr "Napaka pri izmetu!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "" msgid "Setup.MP3$Audio mode" msgstr "Avdio nacin" msgid "Round" msgstr "Zaokrozeni" msgid "Dither" msgstr "Raztrosni" msgid "Setup.MP3$Use 48kHz mode only" msgstr "" msgid "classic" msgstr "" msgid "via skin" msgstr "" msgid "Setup.MP3$Replay display" msgstr "" msgid "Setup.MP3$Display mode" msgstr "Nacin prikaza" msgid "Black" msgstr "Crnina" msgid "Live" msgstr "Slika" msgid "Images" msgstr "" msgid "Setup.MP3$Background mode" msgstr "Ozadje" msgid "Setup.MP3$Initial loop mode" msgstr "Osnovni nacin ponavljanje" msgid "Setup.MP3$Initial shuffle mode" msgstr "Osnovni nacin mesano" msgid "Setup.MP3$Abort player at end of list" msgstr "" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "" msgid "ID3 only" msgstr "" msgid "ID3 & Level" msgstr "" msgid "Setup.MP3$Background scan" msgstr "" msgid "Setup.MP3$Editor display mode" msgstr "Nacin prikaza urejevalnika" msgid "Filenames" msgstr "Imena datotek" msgid "ID3 names" msgstr "ID3 imena" msgid "Setup.MP3$Mainmenu mode" msgstr "Nacin glavnega menija" msgid "Playlists" msgstr "Lista" msgid "Browser" msgstr "Navigator" msgid "Setup.MP3$Keep selection menu" msgstr "" msgid "Setup.MP3$Title/Artist order" msgstr "" msgid "Normal" msgstr "" msgid "Reversed" msgstr "" msgid "Hide mainmenu entry" msgstr "" msgid "Setup.MP3$Normalizer level" msgstr "Normalni nivo" msgid "Setup.MP3$Limiter level" msgstr "Limitni nivo" msgid "Setup.MP3$Use HTTP proxy" msgstr "" msgid "Setup.MP3$HTTP proxy host" msgstr "" msgid "Setup.MP3$HTTP proxy port" msgstr "" msgid "local only" msgstr "" msgid "local&remote" msgstr "" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "" msgid "Setup.MP3$CDDB server" msgstr "" msgid "Setup.MP3$CDDB port" msgstr "" msgid "ID3 information" msgstr "ID3 informacija" msgid "Filename" msgstr "Ime datoteke" msgid "Length" msgstr "Dolzina" msgid "Title" msgstr "Naslov" msgid "Artist" msgstr "Avtor" msgid "Album" msgstr "Album" msgid "Year" msgstr "Leto" msgid "Samplerate" msgstr "Vzorcenje" msgid "Bitrate" msgstr "Bitna hitrost" msgid "Directory browser" msgstr "Navigator" msgid "Playlist editor" msgstr "Urejevalnik liste" msgid "Add" msgstr "Dodaj" msgid "Remove" msgstr "Odstrani" msgid "Add recursivly?" msgstr "Rekurzivno dodaj?" msgid "Empty directory!" msgstr "Direktorij prazen!" msgid "Remove entry?" msgstr "Odstrani izbrano?" msgid "Add all" msgstr "Dodaj vse" msgid "Rename playlist" msgstr "Preimenuj listo" msgid "Old name:" msgstr "Staro ime:" msgid "New name" msgstr "Novo ime" msgid "Source" msgstr "Izvor" msgid "Browse" msgstr "Isci" msgid "Rename" msgstr "Preimenuj" msgid "Scanning playlists..." msgstr "" msgid "Error scanning playlists!" msgstr "Napaka pri pregledovanju liste!" msgid "Delete playlist?" msgstr "Odstrani listo?" msgid "Are you sure?" msgstr "Ste prepricani?" msgid "Error deleting playlist!" msgstr "Napaka pri odstranjevanju liste!" msgid "unnamed" msgstr "neimenovan" msgid "Error creating playlist!" msgstr "Napaka pri kreiranju liste!" msgid "Error renaming playlist!" msgstr "Napaka pri preimenovanju liste!" msgid "Error loading playlist!" msgstr "Napaka pri nalaganju liste!" msgid "Can't edit a WinAmp playlist!" msgstr "Ne morem vnesti liste od WinAmp-a!" msgid "Loading playlist..." msgstr "" msgid "MP3 source" msgstr "MP3 izvor" msgid "Play all" msgstr "Predvajaj vse" msgid "Building playlist..." msgstr "" msgid "Error building playlist!" msgstr "" msgid "A versatile audio player" msgstr "" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "" msgid "Traditional" msgstr "" msgid "Slave" msgstr "" msgid "global only" msgstr "" msgid "local first" msgstr "" msgid "Setup.MPlayer$Resume mode" msgstr "" msgid "Setup.MPlayer$Slave command key" msgstr "" msgid "MPlayer Audio ID" msgstr "" msgid "Audiostream ID" msgstr "" msgid "MPlayer browser" msgstr "MPlayer navigator" msgid "MPlayer source" msgstr "MPlayer izvor" msgid "Summary" msgstr "" msgid "Media replay via MPlayer" msgstr "" msgid "Connecting to stream server ..." msgstr "" mp3-0.10.2/po/sv_SE.po0100644000000000000000000001340211307515470012770 0ustar rootroot# VDR plugin language source file. # Copyright (C) 2007 Stefan Huelswitt # This file is distributed under the same license as the VDR package. # Jan Ekholm \n" "POT-Creation-Date: 2009-08-17 09:00-0400\n" "PO-Revision-Date: 2007-08-27 16:33+0200\n" "Last-Translator: Stefan Huelswitt \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "okфnd" msgid "Remote CDDB lookup..." msgstr "Fjфrrfіrfrхgan till CDDB..." msgid "Select" msgstr "Vфlj" msgid "Parent" msgstr "Tillbaka" msgid "ID3 info" msgstr "ID3 info" msgid "Scanning directory..." msgstr "Sіker igenom katalog..." msgid "Error scanning directory!" msgstr "Kunde inte lфsa katalogen!" msgid "Mount" msgstr "Montera" msgid "Unmount" msgstr "Avmontera" msgid "Eject" msgstr "" msgid "Selected source is not mounted!" msgstr "Den valda kфllan фr inte monterad!" msgid "Mount failed!" msgstr "Monteringen misslyckades!" msgid "Mount succeeded" msgstr "Monteringen lyckades" msgid "Unmount succeeded" msgstr "Avmonteringen lyckades" msgid "Unmount failed!" msgstr "Avmonteringen misslyckades!" msgid "Eject failed!" msgstr "Mata ut!" msgid "OSS" msgstr "OSS" msgid "MP3" msgstr "MP3" msgid "Setup.MP3$Audio output mode" msgstr "" msgid "Setup.MP3$Audio mode" msgstr "Audiolфge" msgid "Round" msgstr "Avrunda" msgid "Dither" msgstr "" msgid "Setup.MP3$Use 48kHz mode only" msgstr "Anvфnd endast 48Khz-lфge" msgid "classic" msgstr "" msgid "via skin" msgstr "" msgid "Setup.MP3$Replay display" msgstr "" msgid "Setup.MP3$Display mode" msgstr "Visuellt lфge" msgid "Black" msgstr "Svart" msgid "Live" msgstr "Live" msgid "Images" msgstr "" msgid "Setup.MP3$Background mode" msgstr "Bakgrundslфge" msgid "Setup.MP3$Initial loop mode" msgstr "Normalt upprepningslфge" msgid "Setup.MP3$Initial shuffle mode" msgstr "Normalt blandlфge" msgid "Setup.MP3$Abort player at end of list" msgstr "" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "avstфngd" msgid "ID3 only" msgstr "" msgid "ID3 & Level" msgstr "" msgid "Setup.MP3$Background scan" msgstr "" msgid "Setup.MP3$Editor display mode" msgstr "Redigerarens visuella lфge" msgid "Filenames" msgstr "Filnamn" msgid "ID3 names" msgstr "ID3 namn" msgid "Setup.MP3$Mainmenu mode" msgstr "Huvudmenylфge" msgid "Playlists" msgstr "Spellistor" msgid "Browser" msgstr "Blфddra" msgid "Setup.MP3$Keep selection menu" msgstr "" msgid "Setup.MP3$Title/Artist order" msgstr "" msgid "Normal" msgstr "" msgid "Reversed" msgstr "" msgid "Hide mainmenu entry" msgstr "" msgid "Setup.MP3$Normalizer level" msgstr "Normaliseringsnivх" msgid "Setup.MP3$Limiter level" msgstr "Begrфnsningsnivх" msgid "Setup.MP3$Use HTTP proxy" msgstr "Anvфnd en HTTP-proxy" msgid "Setup.MP3$HTTP proxy host" msgstr "HTTP-proxyns namn" msgid "Setup.MP3$HTTP proxy port" msgstr "HTTP-proxyns port" msgid "local only" msgstr "" msgid "local&remote" msgstr "" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "CDDB fіr CD-audio" msgid "Setup.MP3$CDDB server" msgstr "CDDB server" msgid "Setup.MP3$CDDB port" msgstr "CDDB port" msgid "ID3 information" msgstr "ID3 information" msgid "Filename" msgstr "Filnamn" msgid "Length" msgstr "Lфngd" msgid "Title" msgstr "Tittel" msgid "Artist" msgstr "Artist" msgid "Album" msgstr "Album" msgid "Year" msgstr "Хr" msgid "Samplerate" msgstr "Samplingshastighet" msgid "Bitrate" msgstr "Bithastighet" msgid "Directory browser" msgstr "Katalogblфddrare" msgid "Playlist editor" msgstr "Spellisteditor" msgid "Add" msgstr "Lфgg till" msgid "Remove" msgstr "Radera" msgid "Add recursivly?" msgstr "Lфgg till rekursivt?" msgid "Empty directory!" msgstr "Tom katalog!" msgid "Remove entry?" msgstr "Radera post?" msgid "Add all" msgstr "Lфgg till alla" msgid "Rename playlist" msgstr "Dіp om spellistan" msgid "Old name:" msgstr "Gammalt namn:" msgid "New name" msgstr "Nytt namn" msgid "Source" msgstr "Kфlla" msgid "Browse" msgstr "Blфddra" msgid "Rename" msgstr "Dіp om" msgid "Scanning playlists..." msgstr "Sіker spellistor..." msgid "Error scanning playlists!" msgstr "Fel uppstod dх spellistorna lфstes!" msgid "Delete playlist?" msgstr "Radera spellista?" msgid "Are you sure?" msgstr "Фr du sфker?" msgid "Error deleting playlist!" msgstr "Fel uppstod dх spellistan raderades!" msgid "unnamed" msgstr "namnlіs" msgid "Error creating playlist!" msgstr "Fel uppstod dх spellistan skapades!" msgid "Error renaming playlist!" msgstr "Fel uppstod dх spellistan dіptes om!" msgid "Error loading playlist!" msgstr "Fel uppstod dх spellistan lфstes in!" msgid "Can't edit a WinAmp playlist!" msgstr "Kan inte redigera en WinAmp-spellista!" msgid "Loading playlist..." msgstr "Lфser in spellista..." msgid "MP3 source" msgstr "MP3 kфlla" msgid "Play all" msgstr "Spela alla" msgid "Building playlist..." msgstr "Skapar en spellista..." msgid "Error building playlist!" msgstr "Fel uppstod dх spellistan skapades!" msgid "A versatile audio player" msgstr "" msgid "MPlayer" msgstr "MPlayer" msgid "Setup.MPlayer$Control mode" msgstr "Kontrollфge" msgid "Traditional" msgstr "Traditionell" msgid "Slave" msgstr "Slav" msgid "global only" msgstr "" msgid "local first" msgstr "" msgid "Setup.MPlayer$Resume mode" msgstr "" msgid "Setup.MPlayer$Slave command key" msgstr "" msgid "MPlayer Audio ID" msgstr "" msgid "Audiostream ID" msgstr "" msgid "MPlayer browser" msgstr "MPlayer-blфddrare" msgid "MPlayer source" msgstr "MPlayer kфlla" msgid "Summary" msgstr "" msgid "Media replay via MPlayer" msgstr "" msgid "Connecting to stream server ..." msgstr "Kontaktar stream-server..." mp3-0.10.2/po/mp3-mplayer.pot0100644000000000000000000001100611307515470014301 0ustar rootroot# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-12-08 19:30+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "unknown" msgstr "" msgid "Remote CDDB lookup..." msgstr "" msgid "Select" msgstr "" msgid "Parent" msgstr "" msgid "ID3 info" msgstr "" msgid "Scanning directory..." msgstr "" msgid "Error scanning directory!" msgstr "" msgid "Mount" msgstr "" msgid "Unmount" msgstr "" msgid "Eject" msgstr "" msgid "Selected source is not mounted!" msgstr "" msgid "Mount failed!" msgstr "" msgid "Mount succeeded" msgstr "" msgid "Unmount succeeded" msgstr "" msgid "Unmount failed!" msgstr "" msgid "Eject failed!" msgstr "" msgid "OSS" msgstr "" msgid "MP3" msgstr "" msgid "Setup.MP3$Audio output mode" msgstr "" msgid "Setup.MP3$Audio mode" msgstr "" msgid "Round" msgstr "" msgid "Dither" msgstr "" msgid "Setup.MP3$Use 48kHz mode only" msgstr "" msgid "classic" msgstr "" msgid "via skin" msgstr "" msgid "Setup.MP3$Replay display" msgstr "" msgid "Setup.MP3$Display mode" msgstr "" msgid "Black" msgstr "" msgid "Live" msgstr "" msgid "Images" msgstr "" msgid "Setup.MP3$Background mode" msgstr "" msgid "Setup.MP3$Initial loop mode" msgstr "" msgid "Setup.MP3$Initial shuffle mode" msgstr "" msgid "Setup.MP3$Abort player at end of list" msgstr "" msgid "Setup.MP3$Enqueue to running playlist" msgstr "" msgid "disabled" msgstr "" msgid "ID3 only" msgstr "" msgid "ID3 & Level" msgstr "" msgid "Setup.MP3$Background scan" msgstr "" msgid "Setup.MP3$Editor display mode" msgstr "" msgid "Filenames" msgstr "" msgid "ID3 names" msgstr "" msgid "Setup.MP3$Mainmenu mode" msgstr "" msgid "Playlists" msgstr "" msgid "Browser" msgstr "" msgid "Setup.MP3$Keep selection menu" msgstr "" msgid "Setup.MP3$Title/Artist order" msgstr "" msgid "Normal" msgstr "" msgid "Reversed" msgstr "" msgid "Hide mainmenu entry" msgstr "" msgid "Setup.MP3$Normalizer level" msgstr "" msgid "Setup.MP3$Limiter level" msgstr "" msgid "Setup.MP3$Use HTTP proxy" msgstr "" msgid "Setup.MP3$HTTP proxy host" msgstr "" msgid "Setup.MP3$HTTP proxy port" msgstr "" msgid "local only" msgstr "" msgid "local&remote" msgstr "" msgid "Setup.MP3$CDDB for CD-Audio" msgstr "" msgid "Setup.MP3$CDDB server" msgstr "" msgid "Setup.MP3$CDDB port" msgstr "" msgid "ID3 information" msgstr "" msgid "Filename" msgstr "" msgid "Length" msgstr "" msgid "Title" msgstr "" msgid "Artist" msgstr "" msgid "Album" msgstr "" msgid "Year" msgstr "" msgid "Samplerate" msgstr "" msgid "Bitrate" msgstr "" msgid "Directory browser" msgstr "" msgid "Playlist editor" msgstr "" msgid "Add" msgstr "" msgid "Remove" msgstr "" msgid "Add recursivly?" msgstr "" msgid "Empty directory!" msgstr "" msgid "Remove entry?" msgstr "" msgid "Add all" msgstr "" msgid "Rename playlist" msgstr "" msgid "Old name:" msgstr "" msgid "New name" msgstr "" msgid "Source" msgstr "" msgid "Browse" msgstr "" msgid "Rename" msgstr "" msgid "Scanning playlists..." msgstr "" msgid "Error scanning playlists!" msgstr "" msgid "Delete playlist?" msgstr "" msgid "Are you sure?" msgstr "" msgid "Error deleting playlist!" msgstr "" msgid "unnamed" msgstr "" msgid "Error creating playlist!" msgstr "" msgid "Error renaming playlist!" msgstr "" msgid "Error loading playlist!" msgstr "" msgid "Can't edit a WinAmp playlist!" msgstr "" msgid "Loading playlist..." msgstr "" msgid "MP3 source" msgstr "" msgid "Play all" msgstr "" msgid "Building playlist..." msgstr "" msgid "Error building playlist!" msgstr "" msgid "A versatile audio player" msgstr "" msgid "MPlayer" msgstr "" msgid "Setup.MPlayer$Control mode" msgstr "" msgid "Traditional" msgstr "" msgid "Slave" msgstr "" msgid "global only" msgstr "" msgid "local first" msgstr "" msgid "Setup.MPlayer$Resume mode" msgstr "" msgid "Setup.MPlayer$Slave command key" msgstr "" msgid "MPlayer Audio ID" msgstr "" msgid "Audiostream ID" msgstr "" msgid "MPlayer browser" msgstr "" msgid "MPlayer source" msgstr "" msgid "Summary" msgstr "" msgid "Media replay via MPlayer" msgstr "" msgid "Connecting to stream server ..." msgstr "" mp3-0.10.2/po2i18n.pl0100644000000000000000000000615410735452037012541 0ustar rootroot#!/usr/bin/perl # # po2i18n - Convert plugin po files in into i18n.c-format # # See the README file for copyright information and how to reach the author. # use strict; use warnings; my @LANGS = ( "en_US", "de_DE", "sl_SI", "it_IT", "nl_NL", "pt_PT", "fr_FR", "nn_NO", "fi_FI", "pl_PL", "es_ES", "el_GR", "sv_SE", "ro_RO", "hu_HU", "ca_ES", "ru_RU", "hr_HR", "et_EE", "da_DK", "cs_CZ", "tr_TR" ); my %VERS = ( "en_US" => 10200, "de_DE" => 10200, "sl_SI" => 10200, "it_IT" => 10200, "nl_NL" => 10200, "pt_PT" => 10200, "fr_FR" => 10200, "nn_NO" => 10200, "fi_FI" => 10200, "pl_PL" => 10200, "es_ES" => 10200, "el_GR" => 10200, "sv_SE" => 10200, "ro_RO" => 10200, "hu_HU" => 10200, "ca_ES" => 10200, "ru_RU" => 10302, "hr_HR" => 10307, "et_EE" => 10313, "da_DK" => 10316, "cs_CZ" => 10342, "tr_TR" => 10502 ); my %strings; foreach my $lang (@LANGS) { $strings{$lang} = { }; } sub LoadLanguage(*) { my ($lang) = @_; if (!open FILE, "<", "po/$lang.po") { return 0; } my $msgid = ""; my $msgstr = ""; my $last = 0; # 0=init, 1=msgid was last, 2=msgstr was last while () { chomp; my $line = $_; if ($line =~ /^msgid "(.*)"$/) { if ($last eq 2) { $strings{$lang}->{$msgid} = $msgstr; $strings{"en_US"}->{$msgid} = $msgid; } $msgid = $1; $last = 1; } elsif ($line =~ /^msgstr "(.*)"/) { $msgstr = $1; $last = 2; } elsif ($line =~ /^"(.*)"/) { if ($last eq 1) { $msgid = $msgid . $1; } elsif ($last eq 2) { $msgstr = $msgstr . $1; } } } if ($last eq 2) { $strings{$lang}->{$msgid} = $msgstr; $strings{"en_US"}->{$msgid} = $msgid; } close FILE; } foreach my $lang (@LANGS) { LoadLanguage($lang); } my @msgids = sort keys %{$strings{"en_US"}}; my $silent = 0; while (<>) { my $line = $_; if ($line =~ /^\/\/ START I18N/) { print "// START I18N - automatically generated by po2i18n.pl\n"; for my $msgid (@msgids) { next if $msgid eq ""; my $head = " { "; my $endif = ""; my $versnum = 10200; for my $lang (@LANGS) { if ($VERS{$lang} ne $versnum) { $versnum = $VERS{$lang}; print $endif; print "#if VDRVERSNUM >= $versnum\n"; $endif = "#endif\n"; } my $msgstr = $strings{$lang}->{$msgid}; $msgstr = "" if !defined $msgstr; print "$head\"$msgstr\",\n"; $head = " "; } print $endif; print " },\n"; } $silent = 1; } if (!$silent) { print $line; } if ($line =~ /^\/\/ END I18N/) { print "// END I18N - automatically generated by po2i18n.pl\n"; $silent = 0; } } mp3-0.10.2/service.h0100644000000000000000000000215310735452037012610 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2006 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___SERVICE_H #define ___SERVICE_H struct MP3ServiceData { int result; union { const char *filename; } data; }; struct MPlayerServiceData { int result; union { const char *filename; } data; }; #endif //___SERVICE_H mp3-0.10.2/setup-mp3.c0100644000000000000000000000310111242242763012767 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include "common.h" #include "setup-mp3.h" cMP3Setup MP3Setup; // --- cMP3Setup --------------------------------------------------------------- cMP3Setup::cMP3Setup(void) { InitLoopMode = 0; InitShuffleMode = 0; AudioMode = 1; BgrScan = 2; EditorMode = 1; DisplayMode = 3; BackgrMode = 1; MenuMode = 0; TargetLevel = DEFAULT_TARGET_LEVEL; LimiterLevel = DEFAULT_LIMITER_LEVEL; Only48kHz = 0; UseProxy = 0; strcpy(ProxyHost,"localhost"); ProxyPort = 8080; UseCddb = 1; strcpy(CddbHost,"freedb.freedb.org"); CddbPort = 888; AudioOutMode = 0; AbortAtEOL = 1; ReplayDisplay = 0; HideMainMenu = 0; KeepSelect = 0; TitleArtistOrder = 0; EnqueueSongs = 1; } mp3-0.10.2/setup-mp3.h0100644000000000000000000000361111242243005012770 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___SETUP_MP3_H #define ___SETUP_MP3_H extern const char *cddbpath; extern const char *netscript; #ifdef WITH_OSS extern const char *dspdevice; #endif // ---------------------------------------------------------------- #define DEFAULT_TARGET_LEVEL 25 #define MAX_TARGET_LEVEL 50 #define DEFAULT_LIMITER_LEVEL 70 #define MIN_LIMITER_LEVEL 25 #define MAX_HOSTNAME 128 #define AUDIOOUTMODES 2 #define AUDIOOUTMODE_DVB 0 #define AUDIOOUTMODE_OSS 1 class cMP3Setup { public: int InitLoopMode; int InitShuffleMode; int AudioMode; int BgrScan; int EditorMode; int DisplayMode; int BackgrMode; int MenuMode; int TargetLevel; int LimiterLevel; int Only48kHz; int UseProxy; char ProxyHost[MAX_HOSTNAME]; int ProxyPort; int UseCddb; char CddbHost[MAX_HOSTNAME]; int CddbPort; int AudioOutMode; int AbortAtEOL; int ReplayDisplay; int HideMainMenu; int KeepSelect; int TitleArtistOrder; int EnqueueSongs; public: cMP3Setup(void); }; extern cMP3Setup MP3Setup; #endif //___SETUP_MP3_H mp3-0.10.2/setup-mplayer.c0100644000000000000000000000242711141753367013760 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include "common.h" #include "setup-mplayer.h" cMPlayerSetup MPlayerSetup; // --- cMPlayerSetup ----------------------------------------------------------- cMPlayerSetup::cMPlayerSetup(void) { SlaveMode = 1; ResumeMode = 2; HideMainMenu = 0; memset(KeyCmd,0,sizeof(KeyCmd)); strcpy(KeyCmd[1],"audio_delay +0.1"); strcpy(KeyCmd[7],"audio_delay -0.1"); strcpy(KeyCmd[4],"switch_audio"); } mp3-0.10.2/setup-mplayer.h0100644000000000000000000000237211141753413013754 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___SETUP_MPLAYER_H #define ___SETUP_MPLAYER_H extern const char *MPlayerCmd; // ---------------------------------------------------------------- #define MAX_KEYCMD 32 class cMPlayerSetup { public: int SlaveMode; int ResumeMode; int HideMainMenu; char KeyCmd[10][MAX_KEYCMD]; public: cMPlayerSetup(void); }; extern cMPlayerSetup MPlayerSetup; #endif //___SETUP_MPLAYER_H mp3-0.10.2/setup.h0100644000000000000000000000171210735452037012310 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___SETUP_H #define ___SETUP_H extern const char *mountscript; #endif //___SETUP_H mp3-0.10.2/stream.c0100644000000000000000000003340111306577367012447 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include "common.h" #include "setup-mp3.h" #include "stream.h" #include "network.h" #include "data.h" #include "menu-async.h" #include "i18n.h" #include "version.h" #define USE_MMAP #define MAX_MMAP_SIZE (32*1024*1024) #define MP3FILE_BUFSIZE (32*1024) #ifdef USE_MMAP #include #endif #define DEFAULT_PORT 80 // default port for streaming (HTTP) //#define DUMP_HEAD "/var/tmp/headers" // --- cIO --------------------------------------------------------------------- #if 0 cIO::cIO(const char *Filename, bool Log) :cFileInfo(Filename) { log=Log; readpos=0; } cIO::~cIO() { } // --- cStreamIO --------------------------------------------------------------- cStreamIO::cStreamIO(void) { data=0; } cStreamIO::~cStreamIO() { StreamClear(true); } void cStreamIO::StreamClear(bool all) { if(all) { free(data); data=0; } fill=0; } unsigned char *cStreamIO::StreamInit(int Size) { StreamClear(true); size=Size; data=(unsigned char *)malloc(size); return data; } int cStreamIO::Stream(const unsigned char *rest) { if(rest && fill) { // copy remaining data to start of buffer fill-=(rest-data); memmove(data,rest,fill); } else fill=0; unsigned long r=Read(data+fill,size-fill); if(r>=0) { fill+=r; return fill; } return -1; } // --- cFileIO ----------------------------------------------------------------- cFileIO::cFileIO(const char *Filename, bool Log) :cIO(Filename,Log) { fd=-1; } cFileIO::~cFileIO() { Close(); } bool cFileIO::Open(void) { if(fd>=0) return Seek(0,SEEK_SET); if(FileInfo(log)) { if((fd=open(Filename,O_RDONLY))>=0) { StreamClear(false); readpos=0; return true; } else if(log) { esyslog("ERROR: open failed on %s: %s",Filename,strerror(errno)); } } Close(); return false; } void cFileIO::Close(void) { if(fd>=0) { close(fd); fd=-1; } } int cFileIO::Read(unsigned char *Data, int Size) { unsigned long r=read(fd,Data,Size); if(r>=0) readpos+=r; else if(log) { esyslog("ERROR: read failed in %s: %s",Filename,strerror(errno)); } return r; } bool cFileIO::Seek(unsigned long long pos, int whence) { if(pos>=0 && pos<=Filesize) { StreamClear(false); if((readpos=lseek64(fd,pos,whence))>=0) { if(readpos!=pos) { dsyslog("seek mismatch in %s, wanted %lld, got %lld",Filename,pos,readpos); } return true; } else if(log) { esyslog("ERROR: seek failed in %s: %s",Filename,strerror(errno)); } } else d(printf("mp3: bad seek call fd=%d pos=%lld name=%s\n",fd,pos,Filename)) return false; } #endif // --- cStream ----------------------------------------------------------------- cStream::cStream(const char *Filename) :cFileInfo(Filename) { fd=-1; ismmap=false; buffer=0; } cStream::~cStream() { Close(); } bool cStream::Open(bool log) { if(fd>=0) return Seek(); if(FileInfo(log)) { if((fd=open(Filename,O_RDONLY))>=0) { buffpos=readpos=0; fill=0; #ifdef USE_MMAP if(Filesize<=MAX_MMAP_SIZE) { buffer=(unsigned char *)mmap(0,Filesize,PROT_READ,MAP_SHARED,fd,0); if(buffer!=MAP_FAILED) { ismmap=true; return true; } else dsyslog("mmap() failed for %s: %s",Filename,strerror(errno)); } #endif buffer = new unsigned char[MP3FILE_BUFSIZE]; if(buffer) return true; else { esyslog("ERROR: not enough memory for buffer: %s",Filename); } } else if(log) { esyslog("ERROR: failed to open file %s: %s",Filename,strerror(errno)); } } Close(); return false; } void cStream::Close(void) { #ifdef USE_MMAP if(ismmap) { munmap(buffer,Filesize); buffer=0; ismmap=false; } else { #endif delete buffer; buffer=0; #ifdef USE_MMAP } #endif if(fd>=0) { close(fd); fd=-1; } } bool cStream::Seek(unsigned long long pos) { if(fd>=0 && pos>=0 && pos<=Filesize) { buffpos=0; fill=0; if(ismmap) { readpos=pos; return true; } else { if((readpos=lseek64(fd,pos,SEEK_SET))>=0) { if(readpos!=pos) { dsyslog("seek mismatch in %s, wanted %lld, got %lld",Filename,pos,readpos); } return true; } else { esyslog("ERROR: seeking failed in %s: %d,%s",Filename,errno,strerror(errno)); } } } else d(printf("mp3: bad seek call fd=%d pos=%lld name=%s\n",fd,pos,Filename)) return false; } bool cStream::Stream(unsigned char * &data, unsigned long &len, const unsigned char *rest) { if(fd>=0) { if(readpos=0) { buffpos=readpos-fill; readpos+=r; fill+=r; data=buffer; len=fill; return true; } else { esyslog("ERROR: read failed in %s: %d,%s",Filename,errno,strerror(errno)); } } } else { len=0; return true; } } return false; } // ----------------------------------------------------------------------------- #ifdef DUMP_HEAD void Dump(const char *name, char *buffer) { FILE *f=fopen(name,"a"); if(f) { fprintf(f,"<<<< %s\n",buffer); /* int n=strlen(buffer); for(int i=0 ; iConnect(MP3Setup.UseProxy ? MP3Setup.ProxyHost:host , MP3Setup.UseProxy ? MP3Setup.ProxyPort:port)) { d(printf("netstream: -> %s",buff)) if(net->Puts(buff)>0) res=GetHTTPResponse(); } if(cc--==1) asyncStatus.Set(0); return res; } bool cNetStream::ParseHeader(const char *buff, const char *name, char **value) { const char *s=index(buff,':'); if(s && !strncasecmp(buff,name,s-buff)) { s=skipspace(s+1); d(printf("netstream: found header '%s' contents '%s'\n",name,s)) free(*value); *value=strdup(s); return true; } return false; } bool cNetStream::GetHTTPResponse(void) { bool res=false; char buff[1024], text[128], *newurl=0; int code=-1, hcount=0; while(net->Gets(buff,sizeof(buff))>0) { stripspace(buff); #ifdef DUMP_HEAD Dump(DUMP_HEAD,buff); #endif d(printf("netstream: <- %s\n",buff)) hcount++; if(hcount==1) { // parse status line if(sscanf(buff,"%*[^ ] %d %128s",&code,text)!=2) { esyslog("Bad HTTP response '%s' from %s:%d",buff,host,port); goto out; } } else { // parse header lines if(buff[0]==0) { // headers finish if we receive a empty line switch(code) { case 200: // OK res=true; goto out; case 300: // MULTIPLE_CHOICES case 301: // MOVED_PERMANENTLY case 302: // MOVED_TEMPORARILY if(newurl) { if(ParseURL(newurl,true)) res=SendRequest(); } else esyslog("No location header for redirection from %s:%d",host,port); goto out; default: esyslog("Unhandled HTTP response '%d %s' from %s:%d",code,text,host,port); goto out; } } ParseHeader(buff,"Location",&newurl); ParseHeader(buff,"icy-name",&icyName); ParseHeader(buff,"icy-url",&icyUrl); char *meta=0; if(ParseHeader(buff,"icy-metaint",&meta)) { metaInt=metaCnt=atol(meta); d(printf("netstream: meta interval set to %d\n",metaInt)); } free(meta); } } out: free(newurl); return res; } bool cNetStream::Open(bool log) { if(net && net->Connected()) return true; if(!net) net=new cNet(0,0,0); net->Disconnect(); if(ParseURLFile(Filename,log)) { buffpos=readpos=0; fill=0; buffer = new unsigned char[MP3FILE_BUFSIZE]; if(buffer) { if(SendRequest()) { return true; } } else esyslog("Not enough memory for buffer"); } Close(); return false; } void cNetStream::Close(void) { delete buffer; buffer=0; delete net; net=0; } bool cNetStream::Seek(unsigned long long pos) { return false; } bool cNetStream::Stream(unsigned char * &data, unsigned long &len, const unsigned char *rest) { if(net && net->Connected()) { if(rest && fill) { // copy remaining data to start of buffer fill-=(rest-buffer); // remaing bytes memmove(buffer,rest,fill); } else fill=0; int r=MP3FILE_BUFSIZE-fill; if(metaInt && r>metaCnt) r=metaCnt; r=net->Read(buffer+fill,r); if(r>=0) { fill+=r; data=buffer; len=fill; metaCnt-=r; if(metaInt && metaCnt<=0) { ParseMetaData(); metaCnt=metaInt; } return true; } } return false; } char *cNetStream::ParseMetaString(char *buff, const char *name, char **value) { char *s=index(buff,'='); if(s && !strncasecmp(buff,name,s-buff)) { char *end=index(s+2,'\''); if(s[1]=='\'' && end) { *end=0; s=stripspace(skipspace(s+2)); if(strlen(s)>0) { d(printf("netstream: found metadata '%s' contents '%s'\n",name,s)) free(*value); *value=strdup(s); } //else d(printf("netstream: found empty metadata '%s'\n",name)) return end+1; } else d(printf("netstream: bad metadata format\n")) } return 0; } bool cNetStream::ParseMetaData(void) { unsigned char byte; int r=net->Read(&byte,1); if(r<=0) return false; int metalen=byte*16; if(metalen>0) { char data[metalen+1]; data[metalen]=0; int cnt=0; do { r=net->Read((unsigned char *)data+cnt,metalen-cnt); if(r<=0) return false; cnt+=r; } while(cnt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___STREAM_H #define ___STREAM_H #include "decoder.h" class cNet; // ---------------------------------------------------------------- #if 0 class cIO : public cFileInfo { protected: bool log; unsigned long long readpos; public: cIO(const char *Filename, bool Log); virtual ~cIO(); virtual bool Open(void)=0; virtual void Close(void)=0; virtual int Read(unsigned char *Data, int Size)=0; virtual unsigned char *StreamInit(int Size) { return 0; } virtual int Stream(const unsigned char *rest) { return -1; } virtual bool Seek(unsigned long long pos, int whence) { return -1; } virtual unsigned long long Tell(void) { return readpos; } }; // ---------------------------------------------------------------- class cStreamIO { private: int size, fill; unsigned char *data; protected: void StreamClear(bool all); public: cStreamIO(void); virtual ~cStreamIO(); virtual unsigned char *StreamInit(int Size); virtual int Stream(const unsigned char *rest); virtual int Read(unsigned char *Data, int Size)=0; }; // ---------------------------------------------------------------- class cFileIO : public cIO, public cStreamIO { protected: int fd; public: cFileIO(const char *Filename, bool Log); virtual ~cFileIO(); virtual bool Open(void); virtual void Close(void); virtual int Read(unsigned char *Data, int Size); virtual bool Seek(unsigned long long pos, int whence); }; #endif // ---------------------------------------------------------------- class cStream : public cFileInfo { private: int fd; bool ismmap; protected: unsigned char *buffer; unsigned long long readpos, buffpos; unsigned long fill; public: cStream(const char *Filename); virtual ~cStream(); virtual bool Open(bool log=true); virtual void Close(void); virtual bool Stream(unsigned char *&data, unsigned long &len, const unsigned char *rest=NULL); virtual bool Seek(unsigned long long pos=0); virtual unsigned long long BufferPos(void) { return buffpos; } }; // ---------------------------------------------------------------- class cNetStream : public cStream { private: cNet *net; char *host, *path, *auth; int port, cc; // char *icyName, *icyUrl, *icyTitle; int metaInt, metaCnt; bool icyChanged; // bool ParseURL(const char *line, bool log); bool ParseURLFile(const char *name, bool log); bool SendRequest(void); bool GetHTTPResponse(void); bool ParseHeader(const char *buff, const char *name, char **value); bool ParseMetaData(void); char *ParseMetaString(char *buff, const char *name, char **value); public: cNetStream(const char *Filename); virtual ~cNetStream(); virtual bool Open(bool log=true); virtual void Close(void); virtual bool Stream(unsigned char *&data, unsigned long &len, const unsigned char *rest=NULL); virtual bool Seek(unsigned long long pos=0); bool Valid(void) { return ParseURLFile(Filename,false); } const char *IcyName(void) const { return icyName; } const char *IcyUrl(void) const { return icyUrl; } const char *IcyTitle(void) const { return icyTitle; } bool IcyChanged(void); }; #endif //___STREAM_H mp3-0.10.2/version.h0100644000000000000000000000202411316351641012625 0ustar rootroot/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2009 Stefan Huelswitt * * This code 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 code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef ___VERSION_H #define ___VERSION_H #define PLUGIN_NAME "VDR-MP3" #define PLUGIN_RELEASE "0.10.2" extern const char *PluginVersion; #endif //___VERSION_H