diff options
127 files changed, 0 insertions, 47626 deletions
diff --git a/COPYING b/COPYING deleted file mode 100644 index f90922ee..00000000 --- a/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/HISTORY b/HISTORY deleted file mode 100644 index e12f5a52..00000000 --- a/HISTORY +++ /dev/null @@ -1,463 +0,0 @@ -VDR Plugin 'xineliboutput' Revision History -------------------------------------------- - -????-??-??: Version 1.1.0 - -- Fixed compilation with gcc-4.4.0 (invalid casts) -- Added --geometry option to vdr-sxfe -- Updated logo (Thanks to Stefan Wagner) -- Implemented demuxer with mpeg-ts support -- Initial support for vdr-1.7.7 -- Support for multilayer OSD -- Improved OSD scaling (OSD reacts now immediately to frame size changes) -- Fixed setting focus in vdr-sxfe fullscreen mode -- Added Gnome screensaver support to vdr-sxfe (Thanks to Alex Stansfield) -- Changed the default grab quality to match VDR's documentation. -- Added sharpness and noise reduction setup options for VDPAU. -- Added '-C'/'--config' command-line option to specify xine's configuration file. -- Replaced cIConv with VDR's cCharConv. -- Supports only for vdr-1.6.0 or later. -- Added an option to limit number of remote clients -- Implemented build-time configuration script -- Replaced build-time options INTERPRET_LIRC_KEYS and FE_TOGGLE_FULLSCREEN - with run-time option --hotkeys -- Added an option to adjust the stepping value that is used for - metronom live mode sync (Thanks to Andreas Auras) -- Added preliminary SVDRP interface (Thanks to Rolf Ahrenberg) -- Fixed aspect ratio problems when using ffmpeg mpeg2 decoder -- H.264 updates -- Added an option to use xine-lib DVB subtitles decoder - -2009-02-12: Version 1.0.4 (branch-1_0_x) -Backported bugfixes from CVS trunk: -- Updated Italian translations (Thanks to Diego Pierotto) -- Fixed default grab quality (Thanks to Jochen Dolze, patch #2454827) -- Added math library (-lm) to vdr-sxfe when building with - Xrender / HUD OSD support (Thanks to Anssi Hannula) -- Reduced H.264 logging -- Fixed CD track count query -- Fixed mrl backwards compability - -2008-10-24: Version 1.0.3 (branch-1_0_x) -Backported bugfixes from CVS trunk: -- Added missing sxfe display locks (Thanks to Antti Seppälä) -- Modified HUD OSD scaling parameters (Thanks to Rolf Ahrenberg) -- Fixes to HUD OSD drawing (Thanks to Rolf Ahrenberg) -- Fixed --aspect=auto:path_to_script option (Thanks to Armin Diedering) -- Fixed playing first track of audio CD (requires xine-lib 1.1.5) -- OS X build fixes (Thanks to Tero Siironen) -- Updated finnish translations (Thanks to Rolf Ahrenberg) -- Updated Italian translations (Thanks to Diego Pierotto) - -2008-10-04: Version 1.0.2 (branch-1_0_x) -Backported bugfixes from CVS trunk: -- Fixed segfault when committing uninitialized OSD (Thanks to Rolf Ahrenberg) -- Fixed buffer errors when switching from HD channel to SD channel -- Fixed selecting DVD subtitles language from DVD menus -- Fixed setting DVD subtitles preferred language -- Fixed missing VDR OSD while playing DVDs -- Fixed DVD menu navigation when menu is not in title 0 -- Fixed infinite loop when trying to replay unaccessible DVD -- Fixed infinite loop when trying to play only one unacessible or very short music file -- Fixed replaying images from network sources (http://, ...) (Thanks to Rolf Ahrenberg) -- Fixed segfault when media file meta info contains thumbnails (Thanks to Petri Helin) -- Fixed smooth trickspeed setup menu entry with VDR-1.5.10+ (Thanks to Timo Eskola) -- Fixed vdr-sxfe icon in 64-bit systems -- Fixed updating window title when protocol is part of mrl -- Fixed German translation for "Play DVD disc >>" (Thanks to Helmar Gerloni) -- Increased timeout when opening media files from network sources (Thanks to Tobias Grimm) -- OS X build fixes (Thanks to Tero Siironen) -- xine-lib 1.2 updates -- Added WM class hint ("VDR") to vdr-sxfe windows (Thanks to Rolf Ahrenberg) - -2008-05-07: Version 1.0.1 - -- Fixed freezes while zapping and/or seeking -- Added metainfo menu to media player (Petri Helin) - -2008-04-14: Version 1.0.0 -- Added Italian translations (Thanks to Diego Pierotto) -- Added Czech translations (Thanks to Maya) -- Added HUD OSD (Blend OSD using graphics hardware) and --hud command-line option. - (Thanks to Antti Seppälä and Rolf Ahrenberg) -- Added support for libextractor metadata parsing library (Petri Helin) -- Added service interface for launching media player (Suggested by Tobias Grimm) -- Added configuration options for unsharp and denoise3d post plugins (Petri Helin) -- Fixed the case when watching image files and the first one just flashes and - gets replaced by black image (Petri Helin) -- Added support for VDR 1.5.x and 1.6.0 -- Dropped legacy code for vdr-1.3.x -- Added support for xine-lib up to 1.1.11.1 -- Added support for xine-lib 1.2 hg branch -- Changed mrl syntax from xvdr[:proto]:// to xvdr[+proto]:// -- Added video softwarwe scaling support -- Added non-linear 4:3 -> 16:9 "smart" scaling -- Added configure option for video aspect ratio (Petri Helin) -- Added media player options for enabling or disabling metainfo types, metainfo - scanner and metainfo caching (Petri Helin) -- Added support for smooth fast forward (Thanks to Timo Eskola) -- Added setup option to limit trick speed -- Removed support for arts audio output -- Added setup option to change external subtitle (.sub/.srt) font size -- Added command-line option for binding to specific local interface address -- Initial support for H.264 video -- Support for HD-resolution OSD (Petri Helin). Requires patched vdr. -- Increased local frontend initialization timeout (Thanks to Mikko Vartiainen) -- Removed configuration option to disable OSD downscaling -- Improved media player playlist handling and menu (Petri Helin) -- Fixed DVD menu domain detection (Petri Helin) -- Fixed DVD title and chapter information shown on the OSD (Petri Helin) -- Improved key mappings for audio player (Petri Helin) -- Allow users to add single files to playlist as well as whole directories (Petri Helin) -- Fixed "TCP fifo full" problem -- Added hotkeys for audio delay (Thanks to Timo Eskola) -- Enabled streaming of external subtitle files for remote frontends -- Added support for multithreaded video decoding. Auto-detect number of CPUs. -- Show address of current VDR server in X title bar -- Added support to control HW aspect ratio with external script -- Added support to output video and OSD to existing X11 window -- Allow fine-tuning of SCR (should reduce frame drops/duplications and make video smoother) -- Support using ffmpeg mpeg2 video decoder instead of libmpeg2 decoder -- Improved PTS warp detection -- Restore DPMS state at exit -- Fixed sxfe window position when returning from fullscreen mode (Thanks to Timo Eskola) - -2007-05-17: Version 1.0.0rc2 - -- Workaround for xine-lib demux_mpeg_block PTS wrap issue - (this should fix daily picture freezes) -- Support for denoise3d and unsharp post plugins (Thanks to Petri Helin) -- Fixed media player random play kNext (next file) handling (Thanks to Petri Helin) -- Fixed media player MsgReplaying status messages (Thanks to Petri Helin) -- Fixed closing DVD player with Back key (Thanks to Petri Helin) -- Improved media player resume file creation -- Fixed UDP segfault -- Mac OS X build fixes (Thanks to Tero Siironen) -- Updated remote.conf example -- Added support for xine-lib software volume control - (useful with digital audio output) -- Removed (unused) decoder priority setting -- Fixed yuy2 frame grabbing -- Adapted for xine-lib 1.1.5 -- Added vdr-sxfe fullscreen and de-interlace toggling with lirc keys - "Fullscreen" and "Deinterlace" - -2007-03-17: Version 1.0.0rc1 - -- PLUGIN HOMEPAGE CHANGED - -- Fixed audio CD replay (cdda:/) -- Adapted for xine-lib 1.1.4 -- Adapted for vdr-1.5.1 (Thanks to Rolf Ahrenberg) -- Mac OS X compability fixes (Thanks to Tero Siironen) -- DXR3 added to list of output devices (experimental; Thanks to Ville Skyttä) -- Subtitle selection menu updated to use VDR audio menu skin -- New subtitle macro key handling (identical to VDR kAudio) -- Added preferred subtitle language selection for media player -- Updated trick speed modes and still image handling -- Remote mode can now survive longer network delays -- Fixed tvtime options (Thanks to Petri Helin) -- Fixed using video driver "none" -- Simple "slave mode" for remote frontends -- Added automatic re-connection to remote frontends (--reconnect option) -- Slow down DVD drive speed -- Initialize video size from stream info when playing slave streams, - (Thanks to Antti Seppälä) -- Makefile shell scripts modified to run in dash (Ubuntu). - (Thanks to realKano@directbox.com) -- Increased frame-based buffering time after channel changes -- Use iconv to translate id3 tags from utf8 to VDR charset -- Use /dev/dsp as OSS default device (Thanks to Ville Skyttä) -- Lot of small fixes and enhancements, complete log in CVS - -2007-01-07: Version 1.0.0pre7 - -- Added possibility to add files to playlist -- Added playlist menu to media player -- Added "Play Audio CD" / "Play remote Audio CD" entry to plugin menu -- Makefile modified to allow overriding default directory environment. - Using "install" to install files. (Thanks to Timo Weingärtner) -- Added metainfo caching to media player. Cached metainfo is stored to - ".xineliboutput-playlist.m3u" files by default. -- Added support for playlists inside playlists - (ex. http://.../?.pls entries in playlists) -- Added playlist HTTP download support to playlists (curl required) -- lirc forwarding updated (synced with vdr-1.4.3-2): added re-connecting to lircd. -- Lirc forwarding key repeat fixed (Thanks to Timo Ruottinen). -- Display metainfo (ID3 etc) instead of file name in (audio)player -- Fixed deadlock in audio post plugin loading and wiring - (in some cases plugins were loaded multiple times) -- Fixed buffer overflow problems in xineliboutput device polling -- Fixed buffer overflow problems in UDP packet scheduler queue -- Several new media file types added to media player -- Subtitle type .ssa added -- Parsing for .pls, .asx and .ram playlists added -- Eliminated some warnings when compiling to 64bit (Thanks to Anssi Hannula) -- Vidix(fb) added to supported video drivers (Thanks to Antti Seppälä) -- Media player/audio file browser does not anymore show video files -- When replaying music files, replay moves to next file automatically -- Decoder setup menu moved to Local setup menu - (decoder settings have effect on local frontend only) -- Implemented simple RTSP streaming support (rtsp://vdr-host:xineliboutput-port/) -- Implemented simple HTTP streaming support (http://vdr-host:xineliboutput-port/) -- Fixed control channel disconnection detection in frontend_svr.c -- Media player: Try to detect when navigating in DVD menus and change - functions of Up/Down/Left/Right/Ok/Back keys when in menus -- Added RFC2974 SAP (Session Announcement Protocol) implementation -- Now using RFC3550 RTP headers when multicasting - -2006-10-20: Version 1.0.0pre6 - -- Display Audio track languages when replaying DVDs -- Display DVD SPU track language names instead track numbers -- Improved shortcut key support -- Fixed garbage in bottom of image when using autocrop -- Fixed SCR tunning when only one TCP/PIPE client -- Fixed unscaled OSD scaling to display size when low-resolution video or - different aspect ratio -- Allow overriding default startup image -- German translations (Thanks to Udo Richter) -- Setup menu re-arranged -- Command-line given post plugin parameters are never changed at runtime -- Added string length checks to several places -- Added missing frame buffer device selection -- Support for ffmpeg post processing -- Easier configuration for tvtime post plugin in menu -- Autoplay list support for xine (patch from sf feature request #1561688) -- Removed busy loop from vdr-fbfe/vdr-sxfe when console was unavailable - -2006-09-17: Version 1.0.0pre5 - -- Allow overriding default no signal image -- Several fixes to post plugin handling -- Fixed --audio=driver:port parsing in vdr plugin -- Fixed overscan when image does not fill whole output window - (bug #1556912) -- Implemented simple MMX/SSE and YUY2 detection routines - to autocrop -- Main menu re-arranged (Thanks to Petri Helin) -- Fixed display blanking aspect ratio (bug #1554070) -- Lirc receiver accepts shorter LIRC commands (bug #1540896) -- Fixed immediate re-configuration when setup entries are - changed with repeated keys (Thanks to Petri Helin) -- Implemented audio channel selection as xine post plugin - (to select only left or right channel from stereo) -- Several minor fixes / enhancements to autocrop plugin - -2006-09-06: Version 1.0.0pre4 - -- WARNING: updated command-line options ! -- Support for HD (larger buffers with HD content) -- Simple playlist support to media player -- Fixed starting replay of new file while old file is still playing -- Fixed segfault in OSD downscaling -- Added SPU track selection for DVDs without menu -- Forcing order and location of video filter post plugins - autocrop and tvtime in post plugin chain -- Fixed replaying some older VDR recordings (video PID != 0xE0) - (Reported by Petri Helin) -- Fixed deadlock when closing xine input plugin and threads - in TCP mode (reported by Tobias Grimm) -- Fixed wrong XKeySym remote learning trigger when using fbfe - (reported by Voitto Tuomainen) -- Minor updates to playlists and file replay OSD handling -- Added trick speed modes (forward only) to DVD player -- Improved X11 fullscreen <-> window mode switching -- Improved display blanking: blank image is now generated using - last seen video frame size and aspect ratio. This should reduce - OSD resizings and re-positioning when switching channels. - -2006-08-25: Version 1.0.0pre3 - -- Fixed segfault when grabbing with remote-only frontends -- Configurable speaker configuration and spdif passthru -- Support for playlists (.m3u or whole directory) in media player -- Separate menu item for playing music -- Configuration options for letterbox cropping -- Added audio visualization support for media files - (originally supported only with DVB radio) -- Implemented image grabbing for remote frontends -- Fixed restoring primary device when using tcp transport -- Executing primary device switching in main thread context -- Added configurable overscan option (%) to crop frame borders - when using displays without overscan - -2006-08-16: Version 1.0.0pre2 - -- Xine plugins and frontends are not installed automatically. - (Suggested by Udo Richter). -- Added support for AC3 passthrough (thanks to Petri Helin) -- Automatic 4:3 letterbox to 16:9 cropping pre-version -- Added daemon mode to stand-alone frontends -- Removed possible busy loop from lirc receiver thread -- New localized texts -- Fixed local media player when remote server is active and there are no clients -- Option for audio-only playback (discards video) -- Fixed DVD navigation in local mode (Thanks to Petri Helin) -- Completed simple playlist support - (play all media files in folder ; play .m3u playlist) - -2006-07-23: Verson 1.0.0pre1 - -- Added DVD playback and navigation support to media player -- Added support for DVD subtitles in VDR recordings -- Fixed audio surround mode (Thanks to Petri Helin) -- Added option to disable keyboard input in vdr-fbfe and vdr-sxfe - (required when running as daemon) -- Fixed OSD updating, closing and re-scaling under high system load - -2006-07-05: Version 0.99 - -- Finished implementing audio stream switching -- Improved VDR server detection and refused connection handling -- Added option to close VDR when local frontend window is closed -- Added always-on-top mode, window title and icon to vdr-sxfe - -2006-06-12: Version 0.99rc5 -- OSD endian problems fixed -- More x64 fixes (Thanks to Anssi Hannula) -- Better TCP and PIPE disconnection detection -- Fixed possible race conditions in xine input plugin -- Fixed image player (reported by Petri Helin) -- Improved (?) X11 fullscreen mode -- X11 fullscreen mode can be toggled by double-clicking window - -2006-06-03: Version 0.99rc4 - -- Fixed missing audio after trick speed modes (thanks to Tero Saarni) -- Fixed fullscreen size detection with frame buffer / DirectFB -- Added unscaled OSD capability check for framebuffer / DirectFB - -2006-06-02: Version 0.99rc3 - -- OSD is scaled to display resolution instead of video resolution - when using unscaled OSD -- OSD is re-centered when resolution is slighty different from 720x576 -- Added configuration options for multicast parameters (address, port, TTL) -- Added option to set multicast transmission always on for third-party - clients (vlc, ...) -- Some new x64 fixes -- Several configuration menu fixes -- Fixed compilation problem with xine-lib < 1.1.2 -- Fixed missing audio after trick speed modes (thanks to Tero Saarni) - -2006-05-18: Version 0.99rc2 - -- Fixed control input deadlock when using xine-ui -- Experimental automatic primary device mode included -- Fixed remote frontend keyboard handling for escape sequences -- Added several new command-line options to stand-alone frontends -- Adapted for vdr 1.4.0 -- Fixed automatic server discovery -- Fixed fullscreen mode when screen resolution != 720x576 -- Fixed --local=none option (reported by Ulf Betlehem) -- Faster channel switching -- Fixed --post option -- Fixed several endian problems and byte ordering in network modes - (reported by Carsten Rietzschel) -- Fixed segmentation fault when frontend was executed from path - (reported by Carsten Rietzschel) -- Fixed amd64 compilation problems (reported by Voitto Tuomainen) -- Many finnish menu texts updated (patch provided by Rolf Ahrenberg) -- Socket option SO_REUSEADDR added to several places to speed - up VDR restart - -2006-04-08: Version 0.99rc - -- Fixed compilation problems with gcc 3.4.5 (timer.h, osd.c). - (reported by Gavin Hamill and Voitto Tuomainen) -- Suspend mode removed (it is now implemented only as separate plugin) -- Fixed X11 keyboard input handling -- Faster seeks and channel switches in udp and rtp streaming modes -- Fixed disconnection when playing to end of avi file -- Fixed multi-speed modes (reported by Vladimir Monchenko) -- Updated russian translations (thanks to Vladimir Monchenko) -- Pipe transport fixed - -2006-03-28: Version 0.99pre - -- Russian translations (thanks to Vladimir Monchenko) -- New de-interlacing methods and options -- Updated for vdr 1.3.43 -- Support for xine post-processing plugins -- Stand-alone frontends can now automatically find - vdr (xineliboutput) server from network. -- Makefile modified to auto-detect vdr. - If vdr is not installed, only stand-alone frontends and - xine plugin are compiled. - (use "make frontends" in plugin source directory) -- Xine plugin is automatically copied to xine's plugin directory - instead of statically linking it to frontends. - -> any xine frontend can be used. -- All logging goes to syslog and honors vdr's logging level - -2005-11-22: Version 0.4 - -- Updated for xine-lib 1.1.0 and 1.1.1 -- Framebuffer and DirectFB frontend is now tested and working. -- Remote frontends tested and working (TCP/UDP/RTP). -- README updated. -- Frontend is now loaded dynamically if needed. - VDR part of plugin is not anymore linked against xine-lib and X11. - -> plugin itself can be compiled and used without installing xine - and/or X11 to VDR machine. - Frontends still need X11 and/or xine-lib. -- Makefile modified to auto-detect xine-lib and X11. - If X11 is not installed, only framebuffer frontend is compiled. - If xine-lib is not installed, frontends are not compiled (-> only - remote frontends can be used). -- Updated for vdr 1.3.34 -- Stand-alone frontends (sxfe and fbfe) can now forward lirc keys to VDR. -- New command-line parameters: frontend type, video driver and audio driver. -- Command-line parameters now override saved configuration parameters. - -- Updated for xine-lib 1.0.1 - -2005-02-17: Version 0.3 - -- Updated for vdr 1.3.19 and xine-lib 1.0 -- Direct playback of all xine-supported media types - (+ automatic loading of external .srt/.sub subtitles) -- Support for http/rtsp network streams -- Image viewer -- New configuration options -- Improved OSD support for low-resolution video -- OSD performance optimizations -- Improved X server detection -- Support for xxmc output driver -- Support for DVB radio streams -- Support for audio visualization plugins - -2004-08-19: Version 0.2 - -- Tested with VDR versions 1.2.6, 1.3.7 and 1.3.12 -- Modified to compile with xine-lib 1.0.0 (rc4) -- New configuration options -- Decoder can be stopped manually or using inactivity timer -- Support for image grabbing -- Support for localization (i18n) - -2003-12-20: Version 0.1 - -- Modified to compile with xine-lib 1.0.0 (rc2) -- Support for Xshm, Xv and XvMC. -- Audio driver and port can be selected (alsa,oss,...) -- X11 display location configurable (in setup.conf, - OSD menu or usind DISPLAY environment variable) -- Support for unscaled OSD (requires XShape X server extension) -- Support for deinterlacing -- Multiple bug fixes -- Many new configuration options -- Support for DVD plugin (GetSTC) -- Support for VDR Make.config - -2003-09-10 - -- C Compilation problems fixed -- OSD scaling fixed - -2003-05-23: Version 0.0.0 - -- Initial revision. - - diff --git a/Makefile b/Makefile deleted file mode 100644 index d6467da8..00000000 --- a/Makefile +++ /dev/null @@ -1,416 +0,0 @@ -# -# Makefile for a Video Disk Recorder plugin -# -# See the main source file 'xineliboutput.c' for copyright information and -# how to reach the author. -# -# $Id: Makefile,v 1.86 2009-06-02 08:49:32 phintuka Exp $ -# - -# 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 = xineliboutput - -_default: all - - -# check for Apple Darwin -ARCH_APPLE_DARWIN = no -ifeq ($(shell gcc -dumpmachine | grep -q 'apple-darwin' && echo "1" || echo "0"), 1) - ARCH_APPLE_DARWIN = yes -endif - -# -# Override configuration here or in ../../../Make.config -# - -#NOSIGNAL_IMAGE_FILE=/usr/share/vdr/xineliboutput/nosignal.mpv -#STARTUP_IMAGE_FILE=/usr/share/vdr/xineliboutput/logodisplay.mpv -XINELIBOUTPUT_CONFIGURE_OPTS = - - -### -### The version number of this plugin (taken from the main source file): -### - -VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | cut -d'"' -f2) - - -### -### The C++ compiler and options: -### - -CXX ?= g++ -CC ?= gcc -OPTFLAGS ?= - -ifeq ($(ARCH_APPLE_DARWIN), yes) - CXXFLAGS ?= -O3 -pipe -Wall -Woverloaded-virtual -fPIC -g -fno-common -bundle -flat_namespace -undefined suppress - CFLAGS ?= -O3 -pipe -Wall -fPIC -g -fno-common -bundle -flat_namespace -undefined suppress - LDFLAGS_SO ?= -fvisibility=hidden -else - CXXFLAGS ?= -O3 -pipe -Wall -Woverloaded-virtual -fPIC -g - CFLAGS ?= -O3 -pipe -Wall -fPIC -g - LDFLAGS_SO ?= -shared -fvisibility=hidden -endif - -### -### The directory environment: -### - -VDRDIR ?= ../../.. -LIBDIR ?= ../../lib -TMPDIR ?= /tmp -BINDIR ?= /usr/bin -DESTDIR ?= / - -INSTALL ?= install - -VDRINCDIR ?= $(VDRDIR)/include - -### -### Allow user defined options to overwrite defaults: -### - --include $(VDRDIR)/Make.config --include Make.config - - -### -### check for VDR -### - -ifeq ($(ARCH_APPLE_DARWIN), yes) - VDRVERSION = $(shell sed -ne '/define VDRVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) - APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) -else - VDRVERSION = $(shell sed -ne '/define VDRVERSION/ { s/^.*"\(.*\)".*$$/\1/; p }' $(VDRDIR)/config.h) - APIVERSION = $(shell sed -ne '/define APIVERSION/ { s/^.*"\(.*\)".*$$/\1/; p }' $(VDRDIR)/config.h) -endif - -ifeq ($(strip $(VDRVERSION)),) - $(warning ********************************************************) - $(warning VDR not detected ! VDR plugin will not be compiled. ) - $(warning ********************************************************) - CONFIGURE_OPTS += --disable-vdr -else - ifeq ($(strip $(APIVERSION)),) - $(warning VDR APIVERSION missing, using VDRVERSION $(VDRVERSION) ) - APIVERSION = $(VDRVERSION) - endif - CONFIGURE_OPTS += --add-cflags=-I$(VDRDIR) -endif - - -### -### run configure script -### - -config.mak: Makefile configure - @echo Running configure - @sh configure --cc=$(CC) --cxx=$(CXX) $(CONFIGURE_OPTS) $(XINELIBOUTPUT_CONFIGURE_OPTS) --include config.mak - -### -### The name of the distribution archive: -### - -ARCHIVE = $(PLUGIN)-$(VERSION) -PACKAGE = vdr-$(ARCHIVE) - - -### -### The name of executable and libraries -### - -VDRPLUGIN = libvdr-$(PLUGIN).so -VDRPLUGIN_SXFE = lib$(PLUGIN)-sxfe.so -VDRPLUGIN_FBFE = lib$(PLUGIN)-fbfe.so -VDRSXFE = vdr-sxfe -VDRFBFE = vdr-fbfe -XINEINPUTVDR = xineplug_inp_xvdr.so -XINEPOSTAUTOCROP = xineplug_post_autocrop.so -XINEPOSTSWSCALE = xineplug_post_swscale.so -XINEPOSTAUDIOCHANNEL = xineplug_post_audiochannel.so - -### -### which programs and libs to build -### - -TARGETS_VDR = -TARGETS_FE = -TARGETS_XINE = -ifeq ($(XINELIBOUTPUT_VDRPLUGIN), yes) - TARGETS_VDR += $(VDRPLUGIN) -endif -ifeq ($(XINELIBOUTPUT_XINEPLUGIN), yes) - TARGETS_XINE += $(XINEINPUTVDR) $(XINEPOSTAUTOCROP) $(XINEPOSTSWSCALE) $(XINEPOSTAUDIOCHANNEL) -endif -ifeq ($(XINELIBOUTPUT_X11), yes) - TARGETS_FE += $(VDRSXFE) - ifeq ($(XINELIBOUTPUT_VDRPLUGIN), yes) - TARGETS_VDR += $(VDRPLUGIN_SXFE) - endif -endif -ifeq ($(XINELIBOUTPUT_FB), yes) - TARGETS_FE += $(VDRFBFE) - ifeq ($(XINELIBOUTPUT_VDRPLUGIN), yes) - TARGETS_VDR += $(VDRPLUGIN_FBFE) - endif -endif - - -### -### Includes and Defines (add further entries here): -### - -INCLUDES += -I$(VDRINCDIR) - -ifeq ($(ARCH_APPLE_DARWIN), yes) - INCLUDES += -I/sw/include - LIBDIRS += -L/sw/lib - LIBS += $(LIBDIRS) -else - LIBS += -lrt -endif - -DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \ - -D_REENTRANT -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \ - -DXINELIBOUTPUT_VERSION='"$(VERSION)"' - -ifdef NOSIGNAL_IMAGE_FILE - DEFINES += -DNOSIGNAL_IMAGE_FILE='"$(NOSIGNAL_IMAGE_FILE)"' -endif -ifdef STARTUP_IMAGE_FILE - DEFINES += -DSTARTUP_IMAGE_FILE='"$(STARTUP_IMAGE_FILE)"' -endif - - -### -### The object files (add further files here): -### - -# VDR plugin -OBJS = $(PLUGIN).o device.o frontend.o osd.o config.o menu.o setup_menu.o \ - menuitems.o media_player.o equalizer.o \ - frontend_local.o frontend_svr.o \ - tools/cxsocket.o tools/udp_pes_scheduler.o \ - tools/backgroundwriter.o tools/playlist.o tools/http.o \ - tools/vdrdiscovery.o tools/time_pts.o tools.o \ - tools/metainfo_menu.o logdefs.o tools/rle.o -OBJS_MPG = black_720x576.o nosignal_720x576.o vdrlogo_720x576.o - -# frontends -OBJS_FE_SO = xine_frontend.o logdefs.o \ - xine/post.o xine/vo_hook.o xine/vo_osdscaler.o xine/vo_osdreorder.o \ - tools/rle.o -OBJS_FE = $(OBJS_FE_SO) tools/vdrdiscovery.o xine_frontend_main.o xine_frontend_lirc.o - -OBJS_SXFE_SO = xine_sxfe_frontend.o $(OBJS_FE_SO) -OBJS_SXFE = xine_sxfe_frontend.o $(OBJS_FE) -OBJS_FBFE_SO = xine_fbfe_frontend.o $(OBJS_FE_SO) -OBJS_FBFE = xine_fbfe_frontend.o $(OBJS_FE) - -ifneq ($(HAVE_DBUS_GLIB_1), no) -OBJS_SXFE += tools/gnome_screensaver.o -OBJS_SXFE_SO += tools/gnome_screensaver.o -endif - -# xine plugins -OBJS_XINEINPUTVDR = xine_input_vdr.o xine/demux_xvdr.o \ - xine/ts2es.o xine/demux_xvdr_tsdata.o \ - xine/adjustable_scr.o xine/xvdr_metronom.o xine/osd_manager.o \ - tools/rle.o tools/ts.o tools/pes.o tools/mpeg.o tools/h264.o - -OBJS_XINE = $(OBJS_XINEINPUTVDR) xine_post_autocrop.o xine_post_swscale.o xine_post_audiochannel.o - -### -### Implicit rules: -### - -%.o: %.c - $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $(CFLAGS_VDR) -o $@ $< - - -### -### Dependencies: -### - -MAKEDEP = g++ -MM -MG -DEPFILE = .dependencies -$(DEPFILE): Makefile config.mak - @rm -f $@ - @for i in $(OBJS:%.o=%.c) $(OBJS_SXFE:%.o=%.c) $(OBJS_FBFE:%.o=%.c) $(OBJS_XINE:%.o=%.c) ; do \ - $(MAKEDEP) $(DEFINES) $(INCLUDES) -MT "`dirname $$i`/`basename $$i .c`.o" $$i >>$@ ; \ - done - --include $(DEPFILE) - -DEFINES += -Wall - - -### -### Rules: -### - -mpg2c: mpg2c.c - $(CC) mpg2c.c -o $@ - -# data -black_720x576.c: mpg2c black_720x576.mpg - @./mpg2c black black_720x576.mpg black_720x576.c -nosignal_720x576.c: mpg2c nosignal_720x576.mpg - @./mpg2c nosignal nosignal_720x576.mpg nosignal_720x576.c -vdrlogo_720x576.c: mpg2c vdrlogo_720x576.mpg - @./mpg2c vdrlogo vdrlogo_720x576.mpg vdrlogo_720x576.c - -# C code (xine plugins and frontends) -$(sort $(OBJS_SXFE) $(OBJS_FBFE) $(OBJS_XINE)): - $(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) $(CFLAGS_X11) $(OPTFLAGS) -o $@ $< - -### Internationalization (I18N): - -PODIR = po -LOCALEDIR ?= $(VDRDIR)/locale -I18Npo = $(wildcard $(PODIR)/*.po) -I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) -I18Npot = $(PODIR)/$(PLUGIN).pot - -%.mo: %.po - msgfmt -c -o $@ $< - -$(I18Npot): $(wildcard *.c) - xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<phintuka@users.sourceforge.net>' -o $@ $^ - -%.po: $(I18Npot) - msgmerge -U --no-wrap --no-location --backup=none -q $@ $< - @touch $@ - -$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo - @mkdir -p $(dir $@) - cp $< $@ - -.PHONY: i18n -i18n: $(I18Nmsgs) - -### -### targets -### - -XINELIBOUTPUT_INSTALL_MSG = \ - $(warning *********************** xineliboutput ***************************) \ - $(warning Xine plugins and frontends will not be installed automatically. ) \ - $(warning To install files execute "make install" in ) \ - $(warning $(shell echo `pwd`)) \ - $(warning *****************************************************************) - -install : XINELIBOUTPUT_INSTALL_MSG = - -.PHONY: all -all: config $(TARGETS_VDR) frontends i18n - -frontends: config $(TARGETS_FE) $(TARGETS_XINE) - $(XINELIBOUTPUT_INSTALL_MSG) - -config: config.mak - -.PHONY: config - -.PHONY: frontends install dist clean - -# -# VDR plugin -# - -$(VDRPLUGIN): $(OBJS) $(OBJS_MPG) - $(CXX) $(CXXFLAGS) $(LDFLAGS_SO) $(OBJS) $(OBJS_MPG) $(LIBS) $(LIBS_VDR) -o $@ - @-rm -rf $(LIBDIR)/$@.$(APIVERSION) - @cp $@ $(LIBDIR)/$@.$(APIVERSION) - -# -# vdr-sxfe -# - -$(VDRPLUGIN_SXFE): $(OBJS_SXFE_SO) - $(CC) $(CFLAGS) $(LDFLAGS_SO) $(OBJS_SXFE_SO) $(LIBS_X11) $(LIBS_XINE) -o $@ - @-rm -rf $(LIBDIR)/$(VDRPLUGIN_SXFE).$(VERSION) - @cp $@ $(LIBDIR)/$(VDRPLUGIN_SXFE).$(VERSION) -$(VDRSXFE): $(OBJS_SXFE) - $(CC) -g $(OBJS_SXFE) $(LIBS_X11) $(LIBS_XINE) -o $@ - -# -# vdr-fbfe -# - -$(VDRPLUGIN_FBFE): $(OBJS_FBFE_SO) - $(CC) $(CFLAGS) $(LDFLAGS_SO) $(OBJS_FBFE_SO) $(LIBS_XINE) -o $@ - @-rm -rf $(LIBDIR)/$(VDRPLUGIN_FBFE).$(VERSION) - @cp $@ $(LIBDIR)/$(VDRPLUGIN_FBFE).$(VERSION) -$(VDRFBFE): $(OBJS_FBFE) - $(CC) -g $(OBJS_FBFE) $(LIBS_XINE) -o $@ - -# -# xine plugins -# - -$(XINEINPUTVDR): $(OBJS_XINEINPUTVDR) - $(CC) $(CFLAGS) $(LDFLAGS_SO) $(LIBS_XINE) -o $@ $(OBJS_XINEINPUTVDR) -$(XINEPOSTAUTOCROP): xine_post_autocrop.o - $(CC) $(CFLAGS) $(LDFLAGS_SO) $(LIBS_XINE) -o $@ $< -$(XINEPOSTSWSCALE): xine_post_swscale.o - $(CC) $(CFLAGS) $(LDFLAGS_SO) $(LIBS_XINE) -o $@ $< -$(XINEPOSTAUDIOCHANNEL): xine_post_audiochannel.o - $(CC) $(CFLAGS) $(LDFLAGS_SO) $(LIBS_XINE) -o $@ $< - -# -# install -# - -install: all -ifeq ($(XINELIBOUTPUT_XINEPLUGIN), yes) - @mkdir -p $(DESTDIR)/$(XINEPLUGINDIR)/post - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEINPUTVDR) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEINPUTVDR) - @$(INSTALL) -m 0644 $(XINEINPUTVDR) $(DESTDIR)/$(XINEPLUGINDIR)/$(XINEINPUTVDR) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTAUTOCROP) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTAUTOCROP) - @$(INSTALL) -m 0644 $(XINEPOSTAUTOCROP) $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTAUTOCROP) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTSWSCALE) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTSWSCALE) - @$(INSTALL) -m 0644 $(XINEPOSTSWSCALE) $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTSWSCALE) - @echo Installing $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTAUDIOCHANNEL) - @-rm -rf $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTAUDIOCHANNEL) - @$(INSTALL) -m 0644 $(XINEPOSTAUDIOCHANNEL) $(DESTDIR)/$(XINEPLUGINDIR)/post/$(XINEPOSTAUDIOCHANNEL) -endif -ifeq ($(XINELIBOUTPUT_FB), yes) - @echo Installing $(DESTDIR)/$(BINDIR)/vdr-fbfe - @mkdir -p $(DESTDIR)/$(BINDIR) - @-rm -rf $(DESTDIR)/$(BINDIR)/vdr-fbfe - @$(INSTALL) -m 0755 vdr-fbfe $(DESTDIR)/$(BINDIR)/vdr-fbfe -endif -ifeq ($(XINELIBOUTPUT_X11), yes) - @echo Installing $(DESTDIR)/$(BINDIR)/vdr-sxfe - @mkdir -p $(DESTDIR)/$(BINDIR) - @-rm -rf $(DESTDIR)/$(BINDIR)/vdr-sxfe - @$(INSTALL) -m 0755 vdr-sxfe $(DESTDIR)/$(BINDIR)/vdr-sxfe -endif - -dist: clean - @-rm -rf $(TMPDIR)/$(ARCHIVE) - @mkdir $(TMPDIR)/$(ARCHIVE) - @cp -a * $(TMPDIR)/$(ARCHIVE) - @tar czf $(PACKAGE).tgz --exclude=CVS -C $(TMPDIR) $(ARCHIVE) - @-rm -rf $(TMPDIR)/$(ARCHIVE) - @echo Distribution package created as $(PACKAGE).tgz - - -clean: - @-rm -f $(DEPFILE) *.so* *.o *.tgz core* *~ *.flc *.bak \ - tools/*.o tools/*~ tools/*.flc xine/*.o xine/*~ \ - xine/*.flc $(VDR_FBFE) $(VDR_SXFE) mpg2c black_720x576.c \ - nosignal_720x576.c vdrlogo_720x576.c vdr-sxfe vdr-fbfe \ - $(PODIR)/*.mo $(PODIR)/*.pot \ - features.h config.mak configure.log - diff --git a/README b/README deleted file mode 100644 index d2d01f0b..00000000 --- a/README +++ /dev/null @@ -1,653 +0,0 @@ -This is a "plugin" for the Video Disk Recorder (VDR). - -Written by: Petri Hintukainen <phintuka@users.sourceforge.net> - -Project's homepage: http://www.sourceforge.net/projects/xineliboutput - -Latest version available at: http://prdownloads.sourceforge.net/xineliboutput/ - - -See the file COPYING for license information. - - -Description - - X11 and Linux framebuffer front-end for VDR. - Plugin displays video and OSD in X/Xv/XvMC window, - Linux framebuffer/DirectFB/vidixfb or DXR3 card. - - Support for local and remote frontends. - - Built-in image and media player supports playback of most known - media files (avi/mp3/divx/jpeg/...), DVDs and radio/video streams - (http, rtsp, ...) directly from VDR. - - -Requirements - - - vdr-1.6.0 or later (use "1.0.x" branch for older vdr versions) - (vdr is required only at server side) - - xine-lib 1.1.1 or later - (xine-lib is not required for server in network-only usage) - - Enough CPU power and memory to decode streams - (PII 400Mhz + 64M should be enough with Xv or DirectFB) - - Optional: - - - X server with Composite and Xrender extensions, - compositing window manager or composite manager (xcompmgr). - (Required for HUD OSD to blend high-quality OSD using graphics hardware) - - libextractor 0.5.20 or later (http://libextractor.sourceforge.net). - (used for media file metadata extraction in media player) - - libjpeg for grabbing in JPEG format - -WARNING - - Remote (network) mode should be used only in firewalled - environment; it gives anyone full control to VDR ! - - Full access is allowed to all hosts listed in svdrphosts.conf. - - Multicast streaming can flood your internet connection and/or - wireless LAN. If there is no router (or intelligent switch ?) - all multicast packets will be broadcasted to all network links. - This will flood slow network links: - - Internet connection if outgoing bandwith is < 10 Mbit/s - - Wireless LAN (11 or 54 Mbit/s). - By default multicast TTL is set to 1 so multicast packets should - be stopped to first router regardless of network configuration. - - -Public CVS - - Latest fixes are available from sourceforge.net public CVS - (http://sourceforge.net/cvs/?group_id=160063). - - CVS checkout command: - cvs -d:pserver:anonymous@xineliboutput.cvs.sourceforge.net:/cvsroot/xineliboutput co vdr-xineliboutput - - -Buildtime options - - VDR, X11 and xine-lib are auto-detected by the build system. - By default all possible plugins and executables are build. - - Default configuration can be overridden by running configure - script manually. List of all configurable features can be - acquired by running - - ./configure --help - - For long-time use it is preferred to set configure options - in Make.config file. Make.config is first read from VDR source - directory and then from xineliboutput plugin source directory. - - Basic Make.config entries: - - enable/disable building of VDR plugin: - XINELIBOUTPUT_CONFIGURE_OPTS += --enable-vdr / --disable-vdr - - enable/disable X11 frontends: - XINELIBOUTPUT_CONFIGURE_OPTS += --enable-x11 / --disable-x11 - - enable/disable framebuffer frontends: - XINELIBOUTPUT_CONFIGURE_OPTS += --enable-fb / --disable-fb - - enable/disable xine (input)plugin: - XINELIBOUTPUT_CONFIGURE_OPTS += --enable-libxine / --disable-libxine - - It is possible to compile only remote frontends with command - "make frontends". Building frontends is possible without VDR. - Only xine-lib and corresponding development package or headers - are required. - - -Installing - IMPORTANT - - XINE'S DYNAMIC LIBRARIES AND FRONTEND EXECUTABLES ARE NOT - INSTALLED AUTOMATICALLY. - - It is important to copy required libraries to right place - either by hand or by executing "make install" in plugin's - source directory. - Installing binaries and libraries usually requires root - permissions. - - PLUGIN WILL NOT WORK UNLESS ALL FILES HAVE BEEN INSTALLED ! - - To be able to use remote frontends each client's IP address - must be defined in VDR's svdrphosts.conf. - Full access is allowed to all hosts listed in svdrphosts.conf. - Connections from any other hosts are rejected. - - -Usage examples (VDR plugin) - - If no arguments are given, both X11 and framebuffer frontends are tried. - First working frontend is used with best available video driver. - Complete list of available command-line arguments can be obtained - with "vdr --help". - - Only local frontend, X11/Xv video, alsa audio: - vdr -P"xineliboutput --local=sxfe --video=xv --audio=alsa --remote=none" - - Only local frontend, (slow) X11 video, oss audio: - vdr -P"xineliboutput --local=sxfe --video=xshm --audio=oss --remote=none" - - Only local frontend, DirectFB: - vdr -P"xineliboutput --local=fbfe --video=DirectFB --remote=none" - - Only remote frontend(s): - vdr -P"xineliboutput --local=none --remote=37890" - - Local and remote frontends: - vdr -P"xineliboutput --local=sxfe --remote=37890" - or - vdr -P"xineliboutput --local=fbfe --remote=37890" - - -Using remote frontends - - Two remote frontends are included, vdr-fbfe for framebuffer and - vdr-sxfe for X11. - Complete list of available command-line arguments can be obtained - with "vdr-??fe --help". - - Frontend should find server automatically (from local subnet) - and negotiate best available transport. If frontend does not - find server (or specific transport should be used), mrl must - be given on command line. - - Examples: - - Search for VDR (xineliboutput) server, connect to it and - negotiate best available transport. Use best available audio - and video driver. - vdr-fbfe - or - vdr-sxfe - - Connect to 192.168.1.3 default port and negotiate best available transport - vdr-fbfe xvdr://192.168.1.3 - - Connect to 192.168.2.100, port 12550 and use TCP transport - vdr-fbfe xvdr+tcp://192.168.2.100:12550 - - Automatically search for VDR server and use UDP transport - vdr-fbfe xvdr+udp: - or - vdr-fbfe --udp - - Available transports for video/audio - pipe Use local pipe; server and front-end must be running on - same machine. - rtp Use RTP/UDP multicast for data and TCP for control. - Multiple frontends can receive same stream. - udp Use UDP unicast for data and TCP for control. - tcp Use TCP protocol for control and data. Both channels - use same server port and are opened by client. - - Forwarding lirc keys to server - Use option --lirc with optional lircd socket name to - forward LIRC commands from client to server. - - Audio driver - Use alsa: - vdr-fbfe --audio alsa - Use alsa (and specific card/sub-device): - vdr-fbfe --audio alsa:plughw:1,1 - - Video driver (and display / device): - With X11 frontend (vdr-sxfe): - vdr-sxfe --video [xshm | xv | xvmc | xxmc | vidix | vdpau | - XDirectFB | opengl | sdl | none [:display]] - Examples: - --video xv - --video xvmc:127.0.0.1:1.0 - - With framebuffer frontend (vdr-fbfe): - vdr-fbfe --video [fb | DirectFB | sdl | vidixfb | dxr3 | aadxr3 | none [:fb_device]] - Examples: - --video DirectFB - --video fb:/dev/fb/1 - --video vidixfb - --video aadxr3 - - De-interlacing - If deinterlacing post plugin options are not given at command line, - deinterlacing is controlled by VDR plugin configuration menu settings. - - De-interlacing can also be forced on or off with command-line option --post tvtime. - Examples: - vdr-sxfe --post tvtime:method=Linear,cheap_mode=1,pulldown=0,use_progressive_frame_flag=1 - vdr -P"xineliboutput --post=tvtime:method=Linear,cheap_mode=1,pulldown=0,use_progressive_frame_flag=1" - Disable deinterlacing: - vdr-sxfe --post tvtime:enable=0 - - -VDPAU - - All video scaling, cropping, and postprocessing options must be disabled - if the VDPAU output device is used. - De-interlacing can be enabled with command-line option --post tvtime: - Examples: - vdr-sxfe --video vdpau --post tvtime:method=use_vo_driver - vdr -P"xineliboutput --video=vdpau --post=tvtime:method=use_vo_driver" - - -HUD OSD - - HUD OSD implements high-quality OSD using modern graphics hardware. - OSD is scaled and blended using hardware, so it adds no extra CPU - overhead. OSD is always blended to output (display) resolution, - so it remains sharp and detailed even with low-resolution video. - - HUD OSD must be enabled with command-line option (--hud). Scaling - options can be configured in xineliboutput plugin setup menu, - OSD settings page. - - Requirements: - - X server with Composite and Xrender extensions. - Composite extension must be enabled in Xorg config. - - Composite window manager (compiz, beryl, or properly configured xfce4, metacity, ...) - or separate composite manager (xcompmgr). - - Compatible graphics hardware and drivers. - HUD OSD has been tested with: - nVidia GF FX5700LE (driver version 169.09) - Intel G965 (GMA-X3000) (driver version 2.2.1, textured XVideo) - - metacity 2.23.2 - xcompmgr 1.1.3 - - NOTE: - - Drawing video (even without OSD) may be slower when composite - extension is enabled. - - - Try to adjust OSD size and offsets to get rid of possible graphical - corruption. - - - For true HD-resolution OSD VDR needs to be patched. - - HUD OSD was contributed by Antti Seppälä and Rolf Ahrenberg. - - -Using with xine-ui (xine, fbxine, gxine, ...) - - Examples: - xine "xvdr://127.0.0.1#nocache" - xine "xvdr+tcp://127.0.0.1:37890#nocache" - xine "xvdr+udp://127.0.0.1:37890#nocache" - - "#nocache" should always be appended to end of mrl. - - Remote mode must be enabled in VDR plugin. - - Some configuration options are not available when using - third-party frontends. - - -Using with other media players (mplayer, vlc, ...) - - Primary device video and audio (without OSD or subtitles) - can be streamed from plugin control port to almost any media - player using http or rtsp. - - Session Announcement Protocol (SAP) compatible players - should detect stream automatically and add it to playlist - or bookmarks when RTP transmission is active (tested with vlc). - - Tested players: - - Linux: mplayer, vlc, xine - Windows: vlc - - Examples: - - mplayer http://192.168.1.3:37890 - vlc http://192.168.1.3:37890 - vlc rtsp://192.168.1.3:37890 - vlc rtp://@224.0.1.9:37890 - - -Controlling VDR - - With local frontend, vdr-sxfe and vdr-fbfe: - - Keyboard input from console is mapped to VDR keyboard input. - If VDR was compiled or configured without keyboard support, - console keyboard input does not work. - - Keyboard input from X11 window is mapped to XKeySym remote. - Keys are mapped to VDR keys in remote.conf file. Simple example - of X11 key mappings is included in examples directory. - - It should be possible to use VDR's remote controller learning - mode by pressing some key just after VDR has been started. - Learning mode does not work with remote frontends. - - Keyboard input can be disabled in configuration menu. There - are separate entries for local and remote frontends. - - With xine-ui: - - Keyboard shortcuts and remote events from xine menus are - automatically forwarded to VDR and translated to VDR keys. - Translation to VDR keys is static and defined in xine_input_vdr.c. - - -Frontend key bindings - - Esc Close frontend (vdr-fbfe / fdr-sxfe) - - Mouse left button double-click - Toggle between fullscreen / window mode (vdr-sxfe only) - - Mouse right button click - Toggle between normal window / always on top / - borderless window (vdr-sxfe only) - - Close Window - Close frontend (fdr-sxfe only) - - -Image viewer key bindings - - Left/Prev Previous image - Right/Next Next image - Up/Down Jump 5 images forward/backward - Yellow Delete current image - Back Return to image list - Stop/Blue Exit image viewer - Play Start slide show - Pause Stop slide show - FastFwd/FastRew Start slide show; Increase/decrease slide show speed; - Change slideshow direction - Ok Toggle replay display mode - -Media player key bindings for video files - - Back Return to file list - Red Open playlist if more than one file in the playlist, - otherwise jump to beginning of file - Green Jump 1 min back - Yellow Jump 1 min forward - Stop/Blue Stop replay - User7 Random play / normal play - 1, User8 Jump 20 s back - 3, User9 Jump 20 s forward - 2 Move subtitles up - 5 Move subtitles down - Down/Pause Pause replay - Up/Play Play - Ok Toggle replay display mode - Next Skip to next file when replaying playlist - Prev Skip to previous file when replaying playlist - FastRew/Left Play slower - FastFwd/Right Play faster - -Media player key bindings for audio files - - Back Return to file list - Red Open playlist - Green Jump 1 min back - Yellow Jump 1 min forward - Stop/Blue Stop replay - 0...9 Use to select a file from the playlist - according to its position on the playlist - Down/Pause Pause replay - Up/Play Play - Ok Toggle replay display mode - Next/Right Skip to next file - Prev/Left Skip to previous file or restart the currently playing file - if more than three seconds has been played back already - FastRew/FastFwd Play faster/slower - User7 Random play / normal play - - If media file includes multiple subtitles (DVD, .mkv file, ...), - subtitle language can be selected with VDR Subtitle key or from - DVD subtitle menu. - Plugin uses VDR's preferred subtitle language settings. - -DVD player key bindings - - Up/Down/Left/Right/Ok/Back DVD menu navigation when DVD menu is active - Red Access DVD menu(s) - Green Jump 1 min back - Yellow Jump 1 min forward - Stop/Blue/Back Stop replay - Ok / Info Toggle replay display mode - 1 / User8 Jump 20 s back - 3 / User9 Jump 20 s forward - Pause / Down Pause replay - Play / Up Play - 6 / Next, Next chapter - 4 / Prev Previous chapter - 9 Next title - 7 Previous title - Info Show progress display - FastRew/FastFwd, - Left/Right Play faster/slower - - -DVD playback - - DVD images - - Media player supports playing DVDs directly from hard disk. - Found DVD folders are marked with 'D' in media player - file list. - Plugin detects folders as DVDs if there is file - Name_Of_DVD/VIDEO_TS/VIDEO_TS.IFO. - - It is also possible to replay DVD as VDR recording by - creating empty recording directory and renaming or - symlinking .VOBs of selected title to 00?.vdr files. - DVD menus (VTS_??_0.VOB) should _not_ be copied. - Audio can be selected from main menu just as with normal - VDR recordings. - For seeking it is necessarily to create index.vdr file - with genindex or similar tool. - - DVD discs - - "Real" DVD discs (accessible from /dev/dvd) can be played - from xineliboutput plugin menu. - - In case of remote frontend (vdr-sxfe/vdr-fbfe) DVD drive - of _remote client_ is used. - - Audio track can be selected from VDR audio track menu - (keys "Menu" + "Green" or "Audio") or from DVD menu. - - DVD subtitle language can be selected with VDR Subtitle key or - from DVD subtitle menu. - Plugin uses VDR's preferred subtitle language settings. - - -Aspect ratio setting - - default Aspect ratio is calculated from display resolution. - - 4:3 4:3 video is scaled to fill whole window; - 16:9 video has black bars at top and bottom - - 16:9 16:9 video is scaled to fill whole window; - 4:3 video has black bars at left and right. - - 16:10 - - auto 4:3 and 16:9 are scaled to fill whole window. - (useful if TV can "smart scale" 4:3 video to 16:9) - - -Shortcut key macros - - It is possible to change some settings and execute actions with - user-defined key macros and VDR User? keys. - - Supported settings and corresponding key sequences in VDR - keymacros.conf format are: - - Start replaying DVD (User? @xineliboutput Red 0) - Start replaying Title 1 from DVD (User? @xineliboutput Red 1) - <reserved> (User? @xineliboutput Red 2) - Toggle aspect ratio (User? @xineliboutput Red 3) - Toggle letterbox -> 16:9 cropping (User? @xineliboutput Red 4) - Toggle stereo -> 5.1 upmix (User? @xineliboutput Red 5) - Toggle 5.1 -> surround downmix (User? @xineliboutput Red 6) - Toggle de-interlacing (User? @xineliboutput Red 7) - Toggle local frontend on/off (User? @xineliboutput Red 8) - Start replaying default playlist or file pointed by symlink - $(CONFDIR)/plugins/xineliboutput/default_playlist - (User? @xineliboutput Red 9) - Increase audio delay (User? @xineliboutput Red Up) - Decrease audio delay (User? @xineliboutput Red Down) - Toggle the video aspect ratio (User? @xineliboutput Red Right) - - -Special frontend control keys - - When frontend is started with --hotkeys command-line option, following - keyboard and LIRC keys are interpreted by vdr-sxfe/vdr-fbfe: - - Keyboard (console and X11 window) - f, F Toggle fullscreen state - d, D Toggle deinterlacing - - LIRC - Fullscreen Toggle fullscreen state - Deinterlace Toggle deinterlacing - Quit Close program - - [ this run-time option replaces old build-time options - INTERPRET_LIRC_KEYS and XINELIBOUTPUT_FE_FULLSCREEN_TOGGLE ] - - -Xine-specific settings - - All xine-specific settings can be changed by editing file - $(HOME)/.xine/config_xineliboutput. - - Default mpeg2 decoder (libmpeg2) can be switched to ffmpeg mpeg2 decoder - by increasing ffmpeg decoder priority: - - engine.decoder_priorities.ffmpegvideo:1 - - (ffmpeg decoder is slower but handles errors better). - - -Slave mode - - vdr-sxfe and vdr-fbfe implement simple slave mode. Slave mode is - activated with command-line option --slave. In slave mode program reads - CRLF-terminated commands from standard input instead of using keyboard - as VDR remote controller. Supported commands are: - - HITK <vdrkey> Send key press event to VDR - FULLSCREEN Toggle fullscreen state - DEINTERLACE Toggle deinterlacing - QUIT Close program - - Video can be drawn to existing X11 window with vdr-sxfe - option --wid=<x_window_id> - - -Distributed set-up - multiple clients and/or servers - - Simple multi-head setup - - When there is no need to watch different recordings / channels at - different clients at the same time, just running vdr-[sx/fb]fe at - each client is enough. In this case the same video + OSD is mirrored - to all clients and all clients control the same (shared) VDR. - - Real multi-user setup - - When there is a need to have multiple independently controlled - clients (each with separate video and OSD), running multiple - instances of VDR is required. - It doesn't matter if all VDR instances run at server or at each - client. However, there are some benefits when running all - instances of VDR on the same server: - - less maintenance: only one installation of VDR and plugins is required - - posibility to use simpler, diskless clients with less memory - - Faster cutting / DVD burning / ... as there is no - network between VDR and disks - - no need to export and mount /video to every client - - overall resource usage is lower - - ... - - It is preferred to allow recording only at the "master" vdr. - Recording the same timer on two VDR instances will most likely - corrupt the recording. Besides that, doing all recordings directly - from DVB card (no streamdev in middle) makes things simpler and less - error prone. It is probably even impossible to do several recordings - from different transponders using single streamdev instance. - - Timersync plugin disables recording on client VDRs. All timers - are still visible at each client and timers can be created/modified - at any client just as with the single VDR setup. - Timersync plugin synchronizes all timer modifications between VDR instances - and takes care that all recordings are made by the "master" vdr. - Still, all kind of autotimer plugins etc. that generate timers - should be activated only at server vdr (there shouldn't - be any reasons to run multiple instances of such plugins). - - Simplified example: - (xinelibout and streamdev plugins required) - - Start 3 VDRs at server: - - "Master" VDR: controls all DVB cards, does all recordings, - server for client 1 - - vdr -c /etc/vdr \ - -P"xineliboutput --local=none --remote=37890" \ - -Pstreamdev-server - - VDR server for client 2: - - vdr -c /etc/vdr2 \ - -D 10 -p 2102 \ - -P"xineliboutput --local=none --remote=37892" \ - -Pstreamdev-client - - VDR server for client 3 - - vdr -c /etc/vdr3 \ - -D 10 -p 2103 \ - -P"xineliboutput --local=none --remote=37894" \ - -Pstreamdev-client - - + all possible other options and plugins. - - - Using -D 10 option for client VDR instances "forces" all DVB - cards for master VDR. - - Each VDR instance must have its own configuration directory (-c option). - - Each xineliboutput server uses different port - - Streamdev plugin is used to provide live view for client - VDR's. It is not required to just watch recordings. - To correctly configure vdr-streamdev plugin, see - streamdev plugin's README. - - Using suspendoutput plugin with some proper timeout value - in VDR instances might be good idea - it releases - streamdev VTP connection and server-side DVB devices - for other use when the client is not in use. - - Starting clients: - - Client 1: vdr-sxfe - - Client 2: vdr-sxfe xvdr://<server ip>:37892 - - Client 3: vdr-sxfe xvdr://<server ip>:37894 - - - If RTP is used between vdr and vdr-sxfe, using separate - RTP address or port for each xineliboutput server - instance might be good idea. - - -VDR Logo - - The VDR logo was designed by Jan Grell. - diff --git a/black_720x576.mpg b/black_720x576.mpg Binary files differdeleted file mode 100644 index 1d466be0..00000000 --- a/black_720x576.mpg +++ /dev/null diff --git a/config.c b/config.c deleted file mode 100644 index 02556cb5..00000000 --- a/config.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - * config.c: User settings - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: config.c,v 1.82 2009-05-31 15:30:07 phintuka Exp $ - * - */ - -#include "features.h" - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - -#include <vdr/config.h> -#include <vdr/videodir.h> -#include <vdr/device.h> -#include <vdr/i18n.h> - -#include "logdefs.h" -#include "config.h" - -#define STRN0CPY(dst, src) \ - do { \ - strn0cpy(dst, src, sizeof(dst)); \ - if(strlen(src) >= sizeof(dst)) \ - LOGMSG("WARNING: Setting %s truncated to %s !", Name, dst); \ - } while(0) - - -#define DEFAULT_DEINTERLACE_OPTS "method=Linear,cheap_mode=1,pulldown=0,use_progressive_frame_flag=1" - -const int config_t::i_pesBufferSize[ PES_BUFFERS_count+1 ] = { - 0, 50, 250, 500, 1000, 2000, 500 -}; - -const char * const config_t::s_bufferSize[ PES_BUFFERS_count+1 ] = { - trNOOP("custom"), - trNOOP("tiny"), - trNOOP("small"), - trNOOP("medium"), - trNOOP("large"), - trNOOP("huge"), - NULL -}; - -const char * const config_t::s_aspects[ ASPECT_count+1 ] = { - trNOOP("automatic"), - trNOOP("default"), - "4:3", - "16:9", - "16:10", - trNOOP("Pan&Scan"), - trNOOP("CenterCutOut"), - NULL -}; - -const char * const config_t::s_vo_aspects[ VO_ASPECT_count+1 ] = { - trNOOP("automatic"), - trNOOP("square"), - "4:3", - trNOOP("anamorphic"), - trNOOP("DVB"), - NULL -}; - - -const char * const config_t::s_deinterlaceMethods[ DEINTERLACE_count+1 ] = { - "none", - "bob", - "weave", - "greedy", - "onefield", - "onefield_xv", - "linearblend", - "tvtime", - NULL -}; - -const char * const config_t::s_deinterlaceMethodNames[ DEINTERLACE_count+1 ] = { - trNOOP("off"), - "Bob", - "Weave", - "Greedy", - "One Field", - "One Field XV", - "Linear Blend", - "TvTime", - NULL -}; - -const char * const config_t::s_fieldOrder[ FIELD_ORDER_count+1 ] = { - trNOOP("normal"), - trNOOP("inverted"), - NULL -}; - -const char * const config_t::s_audioDrivers[ AUDIO_DRIVER_count+1 ] = { - "auto", "alsa", "oss", "none", "esd", "jack", - NULL -}; - -const char * const config_t::s_audioDriverNames[ AUDIO_DRIVER_count+1 ] = { - trNOOP("automatic"), - "Alsa", - "OSS", - trNOOP("no audio"), - "ESD", - "Jack", - NULL -}; - -const char * const config_t::s_videoDriversX11[ X11_DRIVER_count+1 ] = { - "auto", "xshm", "xv", "xvmc", "xxmc", "vidix", "XDirectFB", "opengl", "sdl", "none", - NULL -}; - -const char * const config_t::s_videoDriverNamesX11[ X11_DRIVER_count+1 ] = { - trNOOP("automatic"), - "XShm", - "Xv", - "XvMC", - "XvMC+VLD", - "Vidix", - "XDirectFB", - "OpenGL", - "SDL", - trNOOP("no video"), - NULL -}; - -const char * const config_t::s_videoDriversFB[ FB_DRIVER_count+1 ] = { - "auto", "fb", "DirectFB", "sdl", "vidixfb", "aadxr3", "none", - NULL -}; - -const char * const config_t::s_videoDriverNamesFB [ FB_DRIVER_count+1 ] = { - trNOOP("automatic"), - "Framebuffer", - "DirectFB", - "SDL", - "VidixFB", - "DXR3", - trNOOP("no video"), - NULL -}; - -const char * const config_t::s_frontends[ FRONTEND_count+1 ] = { - "sxfe", "fbfe", "none", - NULL -}; - -const char * const config_t::s_frontendNames[ FRONTEND_count+1 ] = { - "X11 (sxfe)", - "Framebuffer (fbfe)", - trNOOP("Off"), - NULL -}; - -const char * const config_t::s_frontend_files[ FRONTEND_count+1 ] = { - "lib" PLUGIN_NAME_I18N "-sxfe.so." XINELIBOUTPUT_VERSION, - "lib" PLUGIN_NAME_I18N "-fbfe.so." XINELIBOUTPUT_VERSION, - // example: libxineliboutput-sxfe.so.0.4.0 - "", - NULL -}; - -const char * const config_t::s_audioEqNames[ AUDIO_EQ_count+1 ] = { - "30 Hz", "60 Hz", "125 Hz", "250 Hz", "500 Hz", - "1 kHz", "2 kHz", "4 kHz", "8 kHz", "16 kHz", - NULL -}; - -const char * const config_t::s_audioVisualizations[ AUDIO_VIS_count+1 ] = { - "none", "goom", "oscope", "fftscope", "fftgraph", - NULL -}; - -const char * const config_t::s_audioVisualizationNames[ AUDIO_VIS_count+1 ] = { - trNOOP("Off"), - trNOOP("Goom"), - trNOOP("Oscilloscope"), - trNOOP("FFT Scope"), - trNOOP("FFT Graph"), - NULL -}; - -/* xine, audio_alsa_out.c */ -const char * const config_t::s_speakerArrangements[ SPEAKERS_count+1 ] = { - trNOOP("Mono 1.0"), trNOOP("Stereo 2.0"), trNOOP("Headphones 2.0"), trNOOP("Stereo 2.1"), - trNOOP("Surround 3.0"), trNOOP("Surround 4.0"), trNOOP("Surround 4.1"), - trNOOP("Surround 5.0"), trNOOP("Surround 5.1"), trNOOP("Surround 6.0"), - trNOOP("Surround 6.1"), trNOOP("Surround 7.1"), trNOOP("Pass Through"), - NULL -}; - -const char * const config_t::s_subtitleSizes[ SUBTITLESIZE_count+1 ] = { - trNOOP("default"), - trNOOP("tiny"), - trNOOP("small"), - trNOOP("medium"), - trNOOP("large"), - trNOOP("very large"), - trNOOP("huge"), - NULL -}; - -const char * const config_t::s_subExts[] = { - ".sub", ".srt", ".txt", ".ssa", - ".SUB", ".SRT", ".TXT", ".SSA", - NULL -}; - -const char * const config_t::s_osdBlendingMethods[] = { - trNOOP("Software"), - trNOOP("Hardware"), - NULL -}; - -const char * const config_t::s_osdMixers[] = { - trNOOP("no"), - trNOOP("grayscale"), // item [1] - trNOOP("transparent"), // item [2] - trNOOP("transparent grayscale"), // item [3] ([1 | 2]) - trNOOP("yes"), - NULL -}; - -const char * const config_t::s_osdScalings[] = { - trNOOP("no"), - trNOOP("nearest"), // item [1] - trNOOP("bilinear"), // item [2] - NULL -}; - -const char * const config_t::s_decoders_MPEG2[] = { - trNOOP("automatic"), - "libmpeg2", - "FFmpeg", - NULL -}; - -const char * const config_t::s_decoders_H264[] = { - trNOOP("automatic"), - "FFmpeg", - "CoreAVC", - NULL -}; - -const char * const config_t::s_ff_skip_loop_filters[] = { - trNOOP("automatic"), - trNOOP("default"), - trNOOP("none"), - trNOOP("nonref"), - trNOOP("bidir"), - trNOOP("nonkey"), - trNOOP("all"), - NULL -}; - -const char * const config_t::s_ff_speed_over_accuracy[] = { - trNOOP("automatic"), - trNOOP("yes"), - trNOOP("no"), -}; - -static const char exts_playlist[][4] = { - "asx", - "m3u", - "pls", - "ram", -}; - -static const char exts_audio[][8] = { - "ac3", - "asf", - "au", - "aud", - "flac", - "mpa", - "mpega", - "mp2", - "mp3", - "m4a", - "ogg", - "ogm", - "ra", - "spx", - "wav", - "wma", -}; - -static const char exts_video[][8] = { - "asf", - "avi", - "dat", - "divx", - "dv", - "fli", - "flv", - "iso", /* maybe dvd */ - "mkv", - "mov", - "mpeg", - "mpg", - "mpv", - "mp4", - "m2v", - "m2t", - "m2ts", - "m4v", - "mts", - "pes", - "rm", - "ts", - "vdr", - "vob", - "wmv", - "xvid", -}; - -static const char exts_image[][8] = { - "bmp", - "gif", - "jpeg", - "jpg", - "mng", - "png", - "tiff", -}; - -#define DEF_EXT_IS(TYPE) \ -static bool ext_is_ ## TYPE(const char *ext) \ -{ \ - for(unsigned int i=0; i<sizeof(exts_ ## TYPE)/sizeof(exts_ ## TYPE[0]); i++) \ - if(!strcasecmp(ext, exts_ ## TYPE[i])) \ - return true; \ - return false; \ -} -DEF_EXT_IS(playlist) -DEF_EXT_IS(audio) -DEF_EXT_IS(video) -DEF_EXT_IS(image) - -static const char *get_extension(const char *fname) -{ - if(fname) { - const char *pos = strrchr(fname, '.'); - if(pos) - return pos+1; - } - return NULL; -} - -static char *strcatrealloc(char *dest, const char *src) -{ - if (!src || !*src) - return dest; - - size_t l = (dest ? strlen(dest) : 0) + strlen(src) + 1; - if(dest) { - dest = (char *)realloc(dest, l); - strcat(dest, src); - } else { - dest = (char*)malloc(l); - strcpy(dest, src); - } - return dest; -} - - -bool config_t::IsPlaylistFile(const char *fname) -{ - const char *ext = get_extension(fname); - return ext && ext_is_playlist(ext); -} - -bool config_t::IsAudioFile(const char *fname) -{ - const char *ext = get_extension(fname); - return ext && (ext_is_audio(ext) || ext_is_playlist(ext)); -} - -bool config_t::IsVideoFile(const char *fname) -{ - const char *ext = get_extension(fname); - return ext && (ext_is_video(ext) || ext_is_audio(ext) || ext_is_playlist(ext)); -} - -bool config_t::IsImageFile(const char *fname) -{ - const char *ext = get_extension(fname); - return ext && (ext_is_image(ext) || ext_is_playlist(ext)); -} - -bool config_t::IsDvdImage(const char *fname) -{ - const char *ext = get_extension(fname); - return (ext && !strcasecmp(ext, "iso")) ? true : false; -} - -bool config_t::IsDvdFolder(const char *fname) -{ - struct stat st; - cString buf, folder; - - buf = cString::sprintf("%s/VIDEO_TS/", fname); - if (stat(buf, &st) == 0) { - folder = buf; - } else { - buf = cString::sprintf("%s/video_ts/", fname); - if (stat(buf, &st) == 0) - folder = buf; - else - return false; - } - - buf = cString::sprintf("%s/video_ts.ifo", *folder); - if (stat(buf, &st) == 0) - return true; - - buf = cString::sprintf("%s/VIDEO_TS.IFO", *folder); - if (stat(buf, &st) == 0) - return true; - - return false; -} - -cString config_t::AutocropOptions(void) -{ - if (!autocrop) - return NULL; - - return cString::sprintf("enable_autodetect=%d,soft_start=%d,stabilize=%d,enable_subs_detect=%d", - autocrop_autodetect, autocrop_soft, autocrop_fixedsize, autocrop_subs); -} - -cString config_t::SwScaleOptions(void) -{ - if (!swscale) - return NULL; - - return cString::sprintf("output_aspect=%s,output_width=%d,output_height=%d,no_downscaling=%d", - swscale_change_aspect ? "auto" : "0.0", - swscale_resize ? swscale_width : 0, - swscale_resize ? swscale_height : 0, - swscale_downscale ? 0 : 1 ); -} - -cString config_t::FfmpegPpOptions(void) -{ - if (!ffmpeg_pp) - return NULL; - - if(*ffmpeg_pp_mode) - return cString::sprintf("quality=%d,mode=%s", ffmpeg_pp_quality, ffmpeg_pp_mode); - - return cString::sprintf("quality=%d", ffmpeg_pp_quality); -} - -cString config_t::UnsharpOptions(void) -{ - if (!unsharp) - return NULL; - - return cString::sprintf("luma_matrix_width=%d,luma_matrix_height=%d,luma_amount=%1.1f," - "chroma_matrix_width=%d,chroma_matrix_height=%d,chroma_amount=%1.1f", - unsharp_luma_matrix_width, unsharp_luma_matrix_height, - ((float)unsharp_luma_amount)/10.0, - unsharp_chroma_matrix_width, unsharp_chroma_matrix_height, - ((float)unsharp_chroma_amount)/10.0); -} - -cString config_t::Denoise3dOptions(void) -{ - if (!denoise3d) - return NULL; - - return cString::sprintf("luma=%1.1f,chroma=%1.1f,time=%1.1f", - ((float)denoise3d_luma)/10.0, - ((float)denoise3d_chroma)/10.0, - ((float)denoise3d_time)/10.0); -} - -config_t::config_t() { - memset(this, 0, sizeof(config_t)); - - strn0cpy(local_frontend, s_frontends[FRONTEND_X11], sizeof(local_frontend)); - strn0cpy(video_driver , s_videoDriversX11[X11_DRIVER_XV], sizeof(video_driver)); - strn0cpy(video_port , "0.0", sizeof(video_port)); - strn0cpy(modeline , "", sizeof(modeline)); - - strn0cpy(audio_driver , s_audioDrivers[AUDIO_DRIVER_ALSA], sizeof(audio_driver)); - strn0cpy(audio_port , "default", sizeof(audio_port)); - speaker_type = SPEAKERS_STEREO; - - post_plugins = NULL; - config_file = NULL; - - audio_delay = 0; - audio_compression = 0; - memset(audio_equalizer,0,sizeof(audio_equalizer)); - strn0cpy(audio_visualization, "goom", sizeof(audio_visualization)); - strn0cpy(audio_vis_goom_opts, "fps:25,width:720,height:576", sizeof(audio_vis_goom_opts)); - - headphone = 0; - audio_upmix = 0; - audio_surround = 0; - sw_volume_control = 0; - - pes_buffers = i_pesBufferSize[PES_BUFFERS_SMALL_250]; - strn0cpy(deinterlace_method, s_deinterlaceMethods[DEINTERLACE_NONE], sizeof(deinterlace_method)); - strn0cpy(deinterlace_opts, DEFAULT_DEINTERLACE_OPTS, sizeof(deinterlace_opts)); - ffmpeg_pp = 0; - ffmpeg_pp_quality = 3; - strn0cpy(ffmpeg_pp_mode, "de", sizeof(ffmpeg_pp_mode)); - subtitle_vpos = 0; - - unsharp = 0; - unsharp_luma_matrix_width = 5; - unsharp_luma_matrix_height = 5; - unsharp_luma_amount = 0; - unsharp_chroma_matrix_width = 3; - unsharp_chroma_matrix_height = 3; - unsharp_chroma_amount = 0; - - denoise3d = 0; - denoise3d_luma = 40; - denoise3d_chroma = 30; - denoise3d_time = 60; - - display_aspect = 0; /* auto */ - - hide_main_menu = 0; - osd_mixer = OSD_MIXER_FULL; - osd_scaling = OSD_SCALING_NEAREST; - hud_osd = 0; - - osd_blending = OSD_BLENDING_SOFTWARE; - osd_blending_lowresvideo = OSD_BLENDING_HARDWARE; - - extsub_size = -1; - dvb_subtitles = 0; - - alpha_correction = 0; - alpha_correction_abs = 0; - - fullscreen = 0; - modeswitch = 1; - width = 720; - height = 576; - scale_video = 0; - field_order = 0; - autocrop = 0; - autocrop_autodetect = 1; - autocrop_soft = 1; - autocrop_fixedsize = 1; - autocrop_subs = 1; - - swscale = 0; // enable/disable - swscale_change_aspect = 0; // change video aspect ratio - swscale_resize = 0; // change video size - swscale_width = 720; // output video width - swscale_height = 576; // output video height - swscale_downscale = 0; // allow downscaling - - remote_mode = 0; - listen_port = LISTEN_PORT; - remote_keyboard = 1; - remote_max_clients = MAXCLIENTS; - remote_usetcp = 1; - remote_useudp = 1; - remote_usertp = 1; - remote_usepipe = 1; - remote_usebcast = 1; - remote_http_files = 1; /* allow http streaming of media files to xineliboutput clients - * (currently replayed media file from xineliboutput media player) - * - will be used if client can't access file directly (nfs etc.) */ - - strn0cpy(remote_rtp_addr, "224.0.1.9", sizeof(remote_rtp_addr)); - remote_rtp_port = (LISTEN_PORT) & (0xfffe); /* even ports only */ - remote_rtp_ttl = 1; - remote_rtp_always_on = 0; - remote_rtp_sap = 1; - - remote_use_rtsp = 1; // allow generic rtsp for primary device. needs enabled udp or rtp - remote_use_rtsp_ctrl = 0; // allow rtsp to control primary device (play/pause/seek...) - remote_use_http = 1; // allow generic http streaming (primary device output) - remote_use_http_ctrl = 0; // allow http to control primary device (play/pause/seek...) - - remote_local_if[0] = 0; // use only this interface - undefined -> any/all - remote_local_ip[0] = 0; // bind locally to this IP - undefined -> any/all - - use_x_keyboard = 1; - - // video settings - ibp_trickspeed = 1; - max_trickspeed = 12; - overscan = 0; - hue = -1; - saturation = -1; - contrast = -1; - brightness = -1; - sharpness = -1; - noise_reduction = -1; - vo_aspect_ratio = 0; - - live_mode_sync = 1; // Sync SCR to transponder clock in live mode - scr_tuning = 0; // Fine-tune xine egine SCR (to sync video to graphics output) - scr_hz = 90000; // Current SCR speed (Hz), default is 90000 - - decoder_mpeg2 = DECODER_MPEG2_auto; - decoder_h264 = DECODER_H264_auto; - ff_h264_speed_over_accurancy = FF_H264_SPEED_OVER_ACCURACY_auto; - ff_h264_skip_loop_filter = FF_H264_SKIP_LOOPFILTER_auto; - - strn0cpy(browse_files_dir, VideoDirectory, sizeof(browse_files_dir)); - strn0cpy(browse_music_dir, VideoDirectory, sizeof(browse_music_dir)); - strn0cpy(browse_images_dir, VideoDirectory, sizeof(browse_images_dir)); - cache_implicit_playlists = 1; - enable_id3_scanner = 1; - dvd_arrow_keys_control_playback = 1; - - main_menu_mode = ShowMenu; - force_primary_device = 0; -}; - -static uint8_t g_hidden_options[sizeof(config_t)] = {0}; -static uint8_t g_readonly_options[sizeof(config_t)] = {0}; -uint8_t *config_t::hidden_options = &g_hidden_options[0]; -uint8_t *config_t::readonly_options = &g_readonly_options[0]; - -cString config_t::m_ProcessedArgs; -bool config_t::ProcessArg(const char *Name, const char *Value) -{ - if(SetupParse(Name, Value)) { - m_ProcessedArgs = cString::sprintf("%s%s ", *m_ProcessedArgs ? *m_ProcessedArgs : " ", Name); - return true; - } - return false; -} - -bool config_t::ProcessArgs(int argc, char *argv[]) -{ - static const char short_options[] = "fDw:h:l:r:A:V:d:P:C:pc"; - - static const struct option long_options[] = { - { "fullscreen", no_argument, NULL, 'f' }, - { "hud", no_argument, NULL, 'D' }, - { "width", required_argument, NULL, 'w' }, - { "height", required_argument, NULL, 'h' }, - //{ "xkeyboard", no_argument, NULL, 'k' }, - //{ "noxkeyboard", no_argument, NULL, 'K' }, - { "local", required_argument, NULL, 'l' }, - //{ "modeline", required_argument, NULL, 'm' }, - { "remote", required_argument, NULL, 'r' }, - { "audio", required_argument, NULL, 'A' }, - { "video", required_argument, NULL, 'V' }, - { "display", required_argument, NULL, 'd' }, - { "post", required_argument, NULL, 'P' }, - { "config", required_argument, NULL, 'C' }, - { "primary", no_argument, NULL, 'p' }, - { "exit-on-close",no_argument, NULL, 'c' }, - { NULL } - }; - - int c; - while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { - switch (c) { - case 'd': ProcessArg("Video.Port", optarg); - break; - case 'f': ProcessArg("Fullscreen", "1"); - break; - case 'D': ProcessArg("X11.HUDOSD", "1"); -#ifndef HAVE_XRENDER - LOGMSG("HUD OSD not supported\n"); -#endif - break; - case 'w': ProcessArg("Fullscreen", "0"); - ProcessArg("X11.WindowWidth", optarg); - break; - case 'h': ProcessArg("Fullscreen", "0"); - ProcessArg("X11.WindowHeight", optarg); - break; - //case 'k': ProcessArg("X11.UseKeyboard", "1"); - // break; - //case 'K': ProcessArg("X11.UseKeyboard", "0"); - // break; - case 'l': ProcessArg("Frontend", optarg); - break; - //case 'm': ProcessArg("Modeline", optarg); - // break; - case 'r': if(strcmp(optarg, "none")) { - if(strchr(optarg, ':')) { - char *tmp = strdup(optarg); - char *pt = strchr(tmp,':'); - *pt++ = 0; - ProcessArg("Remote.ListenPort", pt); - ProcessArg("RemoteMode", listen_port>0 ? "1" : "0"); - ProcessArg("Remote.LocalIP", tmp); - free(tmp); - LOGMSG("Listening on address \'%s\' port %d", remote_local_ip, listen_port); - } else { - ProcessArg("Remote.ListenPort", optarg); - ProcessArg("RemoteMode", listen_port>0 ? "1" : "0"); - } - } else - ProcessArg("RemoteMode", "0"); - break; - case 'V': ProcessArg("Video.Driver", optarg); - break; - case 'A': if(strchr(optarg,':')) { - char *tmp = strdup(optarg); - char *pt = strchr(tmp,':'); - *pt = 0; - ProcessArg("Audio.Driver", tmp); - ProcessArg("Audio.Port", pt+1); - free(tmp); - } else - ProcessArg("Audio.Driver", optarg); - break; - case 'P': if(post_plugins) - post_plugins = strcatrealloc(post_plugins, ";"); - post_plugins = strcatrealloc(post_plugins, optarg); - break; - case 'C': config_file = strdup(optarg); - break; - case 'p': ProcessArg("ForcePrimaryDevice", "1"); - break; - case 'c': exit_on_close = 1; - break; - - default: return false; - } - } - return true; -} - -bool config_t::SetupParse(const char *Name, const char *Value) -{ - const char *pt; - if(*m_ProcessedArgs && NULL != (pt=strstr(m_ProcessedArgs+1, Name)) && - *(pt-1) == ' ' && *(pt+strlen(Name)) == ' ') { - LOGDBG("Skipping configuration entry %s=%s (overridden in command line)", Name, Value); - return true; - } - - if (!strcasecmp(Name, "Frontend")) STRN0CPY(local_frontend, Value); - else if (!strcasecmp(Name, "Modeline")) STRN0CPY(modeline, Value); - else if (!strcasecmp(Name, "VideoModeSwitching")) modeswitch = atoi(Value); - else if (!strcasecmp(Name, "Fullscreen")) fullscreen = atoi(Value); - else if (!strcasecmp(Name, "DisplayAspect")) display_aspect = strstra(Value, s_aspects, 0); - else if (!strcasecmp(Name, "ForcePrimaryDevice")) force_primary_device = atoi(Value); - - else if (!strcasecmp(Name, "X11.WindowWidth")) width = atoi(Value); - else if (!strcasecmp(Name, "X11.WindowHeight")) height = atoi(Value); - else if (!strcasecmp(Name, "X11.UseKeyboard")) use_x_keyboard = atoi(Value); - else if (!strcasecmp(Name, "X11.HUDOSD")) hud_osd = atoi(Value); - - else if (!strcasecmp(Name, "Audio.Driver")) STRN0CPY(audio_driver, Value); - else if (!strcasecmp(Name, "Audio.Port")) STRN0CPY(audio_port, Value); - else if (!strcasecmp(Name, "Audio.Speakers")) speaker_type = strstra(Value, s_speakerArrangements, - SPEAKERS_STEREO); - else if (!strcasecmp(Name, "Audio.Delay")) audio_delay = atoi(Value); - else if (!strcasecmp(Name, "Audio.Compression")) audio_compression = atoi(Value); - else if (!strcasecmp(Name, "Audio.Visualization.GoomOpts")) STRN0CPY(audio_vis_goom_opts, Value); - else if (!strcasecmp(Name, "Audio.Visualization")) STRN0CPY(audio_visualization, Value); - else if (!strcasecmp(Name, "Audio.Surround")) audio_surround = atoi(Value); - else if (!strcasecmp(Name, "Audio.Upmix")) audio_upmix = atoi(Value); - else if (!strcasecmp(Name, "Audio.Headphone")) headphone = atoi(Value); - else if (!strcasecmp(Name, "Audio.SoftwareVolumeControl")) sw_volume_control = atoi(Value); - - else if (!strcasecmp(Name, "OSD.HideMainMenu")) hide_main_menu = atoi(Value); - else if (!strcasecmp(Name, "OSD.LayersVisible")) osd_mixer = atoi(Value); - else if (!strcasecmp(Name, "OSD.Scaling")) osd_scaling = atoi(Value); - else if (!strcasecmp(Name, "OSD.Blending")) osd_blending = atoi(Value); - else if (!strcasecmp(Name, "OSD.BlendingLowRes")) osd_blending_lowresvideo = atoi(Value); -#if 1 - // < 1.0.1 - else if (!strcasecmp(Name, "OSD.UnscaledAlways")) osd_blending = atoi(Value); - else if (!strcasecmp(Name, "OSD.UnscaledLowRes")) osd_blending_lowresvideo = atoi(Value); -#endif - else if (!strcasecmp(Name, "OSD.AlphaCorrection")) alpha_correction = atoi(Value); - else if (!strcasecmp(Name, "OSD.AlphaCorrectionAbs")) alpha_correction_abs = atoi(Value); - - else if (!strcasecmp(Name, "OSD.ExtSubSize")) extsub_size = atoi(Value); - else if (!strcasecmp(Name, "OSD.DvbSubtitles")) dvb_subtitles = atoi(Value); - - else if (!strcasecmp(Name, "RemoteMode")) remote_mode = atoi(Value); - else if (!strcasecmp(Name, "Remote.ListenPort")) listen_port = atoi(Value); - else if (!strcasecmp(Name, "Remote.Keyboard")) remote_keyboard = atoi(Value); - else if (!strcasecmp(Name, "Remote.MaxClients")) remote_max_clients = atoi(Value); - else if (!strcasecmp(Name, "Remote.UseTcp")) remote_usetcp = atoi(Value); - else if (!strcasecmp(Name, "Remote.UseUdp")) remote_useudp = atoi(Value); - else if (!strcasecmp(Name, "Remote.UseRtp")) remote_usertp = atoi(Value); - else if (!strcasecmp(Name, "Remote.UsePipe")) remote_usepipe= atoi(Value); - else if (!strcasecmp(Name, "Remote.UseHttp")) remote_http_files = atoi(Value); - else if (!strcasecmp(Name, "Remote.UseBroadcast")) remote_usebcast = atoi(Value); - - else if (!strcasecmp(Name, "Remote.Rtp.Address")) STRN0CPY(remote_rtp_addr, Value); - else if (!strcasecmp(Name, "Remote.Rtp.Port")) remote_rtp_port = (atoi(Value)) & (0xfffe); - else if (!strcasecmp(Name, "Remote.Rtp.TTL")) remote_rtp_ttl = atoi(Value); - else if (!strcasecmp(Name, "Remote.Rtp.AlwaysOn")) remote_rtp_always_on = atoi(Value); - else if (!strcasecmp(Name, "Remote.Rtp.SapAnnouncements")) remote_rtp_sap = atoi(Value); - - else if (!strcasecmp(Name, "Remote.AllowRtsp")) remote_use_rtsp = atoi(Value); - else if (!strcasecmp(Name, "Remote.AllowRtspCtrl")) remote_use_rtsp_ctrl = atoi(Value); - else if (!strcasecmp(Name, "Remote.AllowHttp")) remote_use_http = atoi(Value); - else if (!strcasecmp(Name, "Remote.AllowHttpCtrl")) remote_use_http_ctrl = atoi(Value); - - else if (!strcasecmp(Name, "Remote.Iface")) STRN0CPY(remote_local_if, Value); - else if (!strcasecmp(Name, "Remote.LocalIP")) STRN0CPY(remote_local_ip, Value); - - else if (!strcasecmp(Name, "Decoder.PesBuffers")) pes_buffers=atoi(Value); - - else if (!strcasecmp(Name, "Video.Driver")) STRN0CPY(video_driver, Value); - else if (!strcasecmp(Name, "Video.Port")) STRN0CPY(video_port, Value); - else if (!strcasecmp(Name, "Video.Scale")) scale_video = atoi(Value); - else if (!strcasecmp(Name, "Video.DeinterlaceOptions")) STRN0CPY(deinterlace_opts, Value); - else if (!strcasecmp(Name, "Video.Deinterlace")) STRN0CPY(deinterlace_method, Value); - else if (!strcasecmp(Name, "Video.FieldOrder")) field_order=atoi(Value)?1:0; - - else if (!strcasecmp(Name, "Video.AutoCrop")) autocrop = atoi(Value); - else if (!strcasecmp(Name, "Video.AutoCrop.AutoDetect")) autocrop_autodetect = atoi(Value); - else if (!strcasecmp(Name, "Video.AutoCrop.SoftStart")) autocrop_soft = atoi(Value); - else if (!strcasecmp(Name, "Video.AutoCrop.FixedSize")) autocrop_fixedsize = atoi(Value); - else if (!strcasecmp(Name, "Video.AutoCrop.DetectSubs")) autocrop_subs = atoi(Value); - - else if (!strcasecmp(Name, "Video.SwScale")) swscale = atoi(Value); - else if (!strcasecmp(Name, "Video.SwScale.Aspect")) swscale_change_aspect = atoi(Value); - else if (!strcasecmp(Name, "Video.SwScale.Resize")) swscale_resize = atoi(Value); - else if (!strcasecmp(Name, "Video.SwScale.Downscale")) swscale_downscale = atoi(Value); - else if (!strcasecmp(Name, "Video.SwScale.Width")) swscale_width = atoi(Value); - else if (!strcasecmp(Name, "Video.SwScale.Height")) swscale_height = atoi(Value); - - else if (!strcasecmp(Name, "Video.HUE")) hue = atoi(Value); - else if (!strcasecmp(Name, "Video.Saturation")) saturation = atoi(Value); - else if (!strcasecmp(Name, "Video.Contrast")) contrast = atoi(Value); - else if (!strcasecmp(Name, "Video.Brightness")) brightness = atoi(Value); - else if (!strcasecmp(Name, "Video.Sharpness")) sharpness = atoi(Value); - else if (!strcasecmp(Name, "Video.NoiseReduction")) noise_reduction = atoi(Value); - else if (!strcasecmp(Name, "Video.Overscan")) overscan = atoi(Value); - else if (!strcasecmp(Name, "Video.IBPTrickSpeed")) ibp_trickspeed = atoi(Value); - else if (!strcasecmp(Name, "Video.MaxTrickSpeed")) max_trickspeed = atoi(Value); - else if (!strcasecmp(Name, "Video.AspectRatio")) vo_aspect_ratio = atoi(Value); - - else if (!strcasecmp(Name, "Video.Decoder.MPEG2")) decoder_mpeg2 = strstra(Value, s_decoders_MPEG2, 0); - else if (!strcasecmp(Name, "Video.Decoder.H264")) decoder_h264 = strstra(Value, s_decoders_H264, 0); - else if (!strcasecmp(Name, "Video.Decoder.H264.SpeedOverAccuracy")) ff_h264_speed_over_accurancy = strstra(Value, s_ff_speed_over_accuracy, 0); - else if (!strcasecmp(Name, "Video.Decoder.H264.SkipLoopFilter")) ff_h264_skip_loop_filter = strstra(Value, s_ff_skip_loop_filters, 0); - - else if (!strcasecmp(Name, "Post.pp.Enable")) ffmpeg_pp = atoi(Value); - else if (!strcasecmp(Name, "Post.pp.Quality")) ffmpeg_pp_quality = atoi(Value); - else if (!strcasecmp(Name, "Post.pp.Mode")) STRN0CPY(ffmpeg_pp_mode, Value); - - else if (!strcasecmp(Name, "Post.unsharp.Enable")) unsharp = atoi(Value); - else if (!strcasecmp(Name, "Post.unsharp.luma_matrix_width")) unsharp_luma_matrix_width = atoi(Value); - else if (!strcasecmp(Name, "Post.unsharp.luma_matrix_height")) unsharp_luma_matrix_height = atoi(Value); - else if (!strcasecmp(Name, "Post.unsharp.luma_amount")) unsharp_luma_amount = atoi(Value); - else if (!strcasecmp(Name, "Post.unsharp.chroma_matrix_width")) unsharp_chroma_matrix_width = atoi(Value); - else if (!strcasecmp(Name, "Post.unsharp.chroma_matrix_height")) unsharp_chroma_matrix_height = atoi(Value); - else if (!strcasecmp(Name, "Post.unsharp.chroma_amount")) unsharp_chroma_amount = atoi(Value); - - else if (!strcasecmp(Name, "Post.denoise3d.Enable")) denoise3d = atoi(Value); - else if (!strcasecmp(Name, "Post.denoise3d.luma")) denoise3d_luma = atoi(Value); - else if (!strcasecmp(Name, "Post.denoise3d.chroma")) denoise3d_chroma = atoi(Value); - else if (!strcasecmp(Name, "Post.denoise3d.time")) denoise3d_time = atoi(Value); - - else if (!strcasecmp(Name, "Media.BrowseFilesDir")) STRN0CPY(browse_files_dir, Value); - else if (!strcasecmp(Name, "Media.BrowseMusicDir")) STRN0CPY(browse_music_dir, Value); - else if (!strcasecmp(Name, "Media.BrowseImagesDir")) STRN0CPY(browse_images_dir, Value); - else if (!strcasecmp(Name, "Media.CacheImplicitPlaylists")) cache_implicit_playlists = atoi(Value); - else if (!strcasecmp(Name, "Media.EnableID3Scanner")) enable_id3_scanner = atoi(Value); - else if (!strcasecmp(Name, "Media.DVD.ArrowKeysControlPlayback")) dvd_arrow_keys_control_playback = atoi(Value); - - else if (!strcasecmp(Name, "Playlist.Tracknumber")) playlist_tracknumber = atoi(Value); - else if (!strcasecmp(Name, "Playlist.Artist")) playlist_artist = atoi(Value); - else if (!strcasecmp(Name, "Playlist.Album")) playlist_album = atoi(Value); - - else if (!strcasecmp(Name, "Advanced.LiveModeSync")) live_mode_sync = atoi(Value); - else if (!strcasecmp(Name, "Advanced.AdjustSCR")) scr_tuning = atoi(Value); - else if (!strcasecmp(Name, "Advanced.SCRSpeed")) scr_hz = atoi(Value); - - else if (!strcasecmp(Name, "Audio.Equalizer")) - sscanf(Value,"%d %d %d %d %d %d %d %d %d %d", - audio_equalizer ,audio_equalizer+1, - audio_equalizer+2,audio_equalizer+3, - audio_equalizer+4,audio_equalizer+5, - audio_equalizer+6,audio_equalizer+7, - audio_equalizer+8,audio_equalizer+9); - - else return false; - - return true; -} - -/* Global instance */ -config_t xc; - - diff --git a/config.h b/config.h deleted file mode 100644 index 86ce315d..00000000 --- a/config.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - * config.h: Global configuration and user settings - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: config.h,v 1.61 2009-05-31 15:30:07 phintuka Exp $ - * - */ - -#ifndef _XINELIB_CONFIG_H_ -#define _XINELIB_CONFIG_H_ - -#include "features.h" - -#include <string.h> -#include <stdint.h> - -#include <vdr/config.h> - -// Max number of remote clients -#define MAXCLIENTS 10 - -// Decoder buffer size -#define PES_BUFFERS_CUSTOM 0 -#define PES_BUFFERS_TINY_50 1 -#define PES_BUFFERS_SMALL_250 2 -#define PES_BUFFERS_MEDIUM_500 3 -#define PES_BUFFERS_LARGE_1000 4 -#define PES_BUFFERS_HUGE_2000 5 -#define PES_BUFFERS_count 6 - -// Output window aspect ratio -#define ASPECT_AUTO 0 -#define ASPECT_DEFAULT 1 -#define ASPECT_4_3 2 -#define ASPECT_16_9 3 -#define ASPECT_16_10 4 -#define ASPECT_PAN_SCAN 5 -#define ASPECT_CENTER_CUT_OUT 6 -#define ASPECT_count 7 - -// VIDEO OUTPUT ASPECT RATIO -#define VO_ASPECT_AUTO 0 -#define VO_ASPECT_SQUARE 1 /* 1:1 */ -#define VO_ASPECT_4_3 2 /* 4:3 */ -#define VO_ASPECT_ANAMORPHIC 3 /* 16:9 */ -#define VO_ASPECT_DVB 4 /* 2.11:1 */ -#define VO_ASPECT_count 5 - -// De-interlace method -#define DEINTERLACE_NONE 0 -#define DEINTERLACE_BOB 1 -#define DEINTERLACE_WEAVE 2 -#define DEINTERLACE_GREEDY 3 -#define DEINTERLACE_ONEFIELD 4 -#define DEINTERLACE_ONEFIELD_XV 5 -#define DEINTERLACE_LINEARLEND 6 -#define DEINTERLACE_TVTIME 7 -#define DEINTERLACE_count 8 - -#define FIELD_ORDER_NORMAL 0 -#define FIELD_ORDER_INVERTED 1 -#define FIELD_ORDER_count 2 - -// Audio driver -#define AUDIO_DRIVER_AUTO 0 -#define AUDIO_DRIVER_ALSA 1 -#define AUDIO_DRIVER_OSS 2 -#define AUDIO_DRIVER_NONE 3 -#define AUDIO_DRIVER_ESD 4 -#define AUDIO_DRIVER_JACK 5 -#define AUDIO_DRIVER_count 6 - -// Video driver -#define X11_DRIVER_AUTO 0 -#define X11_DRIVER_XSHM 1 -#define X11_DRIVER_XV 2 -#define X11_DRIVER_XVMC 3 -#define X11_DRIVER_XXMC 4 -#define X11_DRIVER_VIDIX 5 -#define X11_DRIVER_DIRECTFB 6 -#define X11_DRIVER_OPENGL 7 -#define X11_DRIVER_SDL 8 -#define X11_DRIVER_NONE 9 -#define X11_DRIVER_count 10 - -#define FB_DRIVER_AUTO 0 -#define FB_DRIVER_FB 1 -#define FB_DRIVER_DIRECTFB 2 -#define FB_DRIVER_SDL 3 -#define FB_DRIVER_VIDIXFB 4 -#define FB_DRIVER_DXR3 5 -#define FB_DRIVER_NONE 6 -#define FB_DRIVER_count 7 - -// Local frontend -#define FRONTEND_X11 0 -#define FRONTEND_FB 1 -#define FRONTEND_NONE 2 -#define FRONTEND_count 3 -#define DEFAULT_FRONTEND "sxfe" - -#define LISTEN_PORT 37890 -#define LISTEN_PORT_S "37890" -#define DISCOVERY_PORT 37890 - -#define AUDIO_EQ_30HZ 0 -#define AUDIO_EQ_60HZ 1 -#define AUDIO_EQ_125HZ 2 -#define AUDIO_EQ_250HZ 3 -#define AUDIO_EQ_500HZ 4 -#define AUDIO_EQ_1000HZ 5 -#define AUDIO_EQ_2000HZ 6 -#define AUDIO_EQ_4000HZ 7 -#define AUDIO_EQ_8000HZ 8 -#define AUDIO_EQ_16000HZ 9 -#define AUDIO_EQ_count 10 - -#define AUDIO_VIS_NONE 0 -#define AUDIO_VIS_GOOM 1 -#define AUDIO_VIS_count 5 - -/* speaker arrangements: xine, audio_out_alsa.c */ -#define SPEAKERS_MONO 0 -#define SPEAKERS_STEREO 1 -#define SPEAKERS_HEADPHONES 2 -#define SPEAKERS_SURROUND21 3 -#define SPEAKERS_SURROUND3 4 -#define SPEAKERS_SURROUND4 5 -#define SPEAKERS_SURROUND41 6 -#define SPEAKERS_SURROUND5 7 -#define SPEAKERS_SURROUND51 8 -#define SPEAKERS_SURROUND6 9 -#define SPEAKERS_SURROUND61 10 -#define SPEAKERS_SURROUND71 11 -#define SPEAKERS_A52_PASSTHRU 12 -#define SPEAKERS_count 13 - -#define SUBTITLESIZE_count 7 - -// OSD blending methods -#define OSD_BLENDING_SOFTWARE 0 // xine-lib "normal" osd -#define OSD_BLENDING_HARDWARE 1 // xine-lib "unscaled osd" -#define OSD_BLENDING_count 2 - -// OSD layers mixing -#define OSD_MIXER_NONE 0 -#define OSD_MIXER_GRAY 1 -#define OSD_MIXER_ALPHA 2 -#define OSD_MIXER_GRAYALPHA 3 // OSD_MIXER_GRAY | OSD_MIXER_ALPHA -#define OSD_MIXER_FULL 4 -#define OSD_MIXER_count 5 - -// OSD scaling modes -#define OSD_SCALING_NONE 0 -#define OSD_SCALING_NEAREST 1 -#define OSD_SCALING_BILINEAR 2 -#define OSD_SCALING_count 3 - -// Video decoder -#define DECODER_MPEG2_auto 0 /* use value from frontend config_xineliboutput */ -#define DECODER_MPEG2_LIBMPEG2 1 -#define DECODER_MPEG2_FFMPEG 2 -#define DECODER_MPEG2_count 3 - -#define DECODER_H264_auto 0 /* use value from frontend config_xineliboutput */ -#define DECODER_H264_FFMPEG 1 -#define DECODER_H264_COREAVC 2 -#define DECODER_H264_count 3 - -#define FF_H264_SKIP_LOOPFILTER_auto 0 /* use value from frontend config_xineliboutput */ -#define FF_H264_SKIP_LOOPFILTER_DEFAULT 1 -#define FF_H264_SKIP_LOOPFILTER_NONE 2 -#define FF_H264_SKIP_LOOPFILTER_NONREF 3 -#define FF_H264_SKIP_LOOPFILTER_BIDIR 4 -#define FF_H264_SKIP_LOOPFILTER_NONKEY 5 -#define FF_H264_SKIP_LOOPFILTER_ALL 6 -#define FF_H264_SKIP_LOOPFILTER_count 7 - -#define FF_H264_SPEED_OVER_ACCURACY_auto 0 /* use value from frontend config_xineliboutput */ -#define FF_H264_SPEED_OVER_ACCURACY_no 1 -#define FF_H264_SPEED_OVER_ACCURACY_yes 2 -#define FF_H264_SPEED_OVER_ACCURACY_count 3 - -#define HIDDEN_OPTION(opt) \ - (xc.IsOptionHidden(xc.opt)) -#define READONLY_OPTION(opt) \ - (xc.IsOptionReadOnly(xc.opt)) - -#define DEFAULT_POLL_SIZE 16 - -typedef enum { - ShowMenu = 0, - ShowEq = 1, - ShowFiles = 2, - ShowMusic = 3, - ShowImages = 4, - CloseOsd = 5 -} eMainMenuMode; - -class config_t { - public: - static const char * const s_bufferSize [PES_BUFFERS_count + 1]; - static const int i_pesBufferSize [PES_BUFFERS_count + 1]; - static const char * const s_aspects [ASPECT_count + 1]; - static const char * const s_vo_aspects [VO_ASPECT_count + 1]; - static const char * const s_deinterlaceMethods [DEINTERLACE_count + 1]; - static const char * const s_deinterlaceMethodNames [DEINTERLACE_count + 1]; - static const char * const s_fieldOrder [FIELD_ORDER_count + 1]; - static const char * const s_audioDriverNames [AUDIO_DRIVER_count + 1]; - static const char * const s_audioDrivers [AUDIO_DRIVER_count + 1]; - static const char * const s_videoDriverNamesX11 [X11_DRIVER_count + 1]; - static const char * const s_videoDriversX11 [X11_DRIVER_count + 1]; - static const char * const s_videoDriverNamesFB [FB_DRIVER_count + 1]; - static const char * const s_videoDriversFB [FB_DRIVER_count + 1]; - static const char * const s_frontendNames [FRONTEND_count + 1]; - static const char * const s_frontends [FRONTEND_count + 1]; - static const char * const s_frontend_files [FRONTEND_count + 1]; - static const char * const s_audioEqNames [AUDIO_EQ_count + 1]; - static const char * const s_audioVisualizations [AUDIO_VIS_count + 1]; - static const char * const s_audioVisualizationNames[AUDIO_VIS_count + 1]; - static const char * const s_speakerArrangements [SPEAKERS_count + 1]; - static const char * const s_subtitleSizes [SUBTITLESIZE_count + 1]; - static const char * const s_osdBlendingMethods [OSD_BLENDING_count + 1]; - static const char * const s_osdMixers [OSD_MIXER_count + 1]; - static const char * const s_osdScalings [OSD_SCALING_count + 1]; - static const char * const s_decoders_MPEG2 [DECODER_MPEG2_count + 1]; - static const char * const s_decoders_H264 [DECODER_H264_count + 1]; - static const char * const s_ff_skip_loop_filters [FF_H264_SKIP_LOOPFILTER_count + 1]; - static const char * const s_ff_speed_over_accuracy [FF_H264_SPEED_OVER_ACCURACY_count + 1]; - - static const char * const s_subExts[]; - - public: - - // Force xineliboutput to be the primary device - int force_primary_device; - - // local frontend settings - char local_frontend[64]; - char video_driver[32]; - char video_port[32]; // X11: DISPLAY=... - char audio_driver[32]; - char audio_port[64]; - char *post_plugins; // static post plugins from command line options - char *config_file; // config file from command line options - int pes_buffers; - - char modeline[64]; - int fullscreen; - int modeswitch; - int width; - int height; - int display_aspect; - int scale_video; - int field_order; - int exit_on_close; // Terminate VDR when local frontend is closed - int use_x_keyboard; // Use X11 keyboard to control VDR (console kbd is handled by VDR) - - // Audio settings - int speaker_type; - int audio_delay; // in ms - int audio_compression; // 100%(=off)...500% - int audio_equalizer[AUDIO_EQ_count]; - int audio_surround; // downmix multichannel audio to stereo surround - int headphone; // mix audio for headphones - int audio_upmix; // upmix stereo to 5.1 - int sw_volume_control; // software (xine-lib) or hardware (alsa) volume control and muting - - // Video settings - int ibp_trickspeed; - int max_trickspeed; - int overscan; // % - int hue; // 0...0xffff, -1 == off - int saturation; // 0...0xffff, -1 == off - int contrast; // 0...0xffff, -1 == off - int brightness; // 0...0xffff, -1 == off - int sharpness; // 0...0xffff, -1 == off - int noise_reduction; // 0...0xffff, -1 == off - int vo_aspect_ratio; - - // OSD settings - eMainMenuMode main_menu_mode; // used internally to open right sub-menu - int hide_main_menu; - int osd_mixer; // show multiple OSD layers - int osd_scaling; // OSD scaling mode: off, nearest, bilinear - int hud_osd; // head up display OSD - int osd_blending; // OSD blending method - int osd_blending_lowresvideo; // Use hardware blending for low-resolution video - int alpha_correction; - int alpha_correction_abs; - int extsub_size; // size of separate subtitles ( -1 = xine default ; 0...6 = { tiny small normal large very large huge } - int dvb_subtitles; // send DVB subtitles in data stream (decode+display using xine-lib or external media player) - - // Media player - char browse_files_dir[4096]; - char browse_music_dir[4096]; - char browse_images_dir[4096]; - int cache_implicit_playlists; // used in playlist.c - int enable_id3_scanner; // used in playlist.c - int subtitle_vpos; // used in media player. Not saved ! - int playlist_tracknumber; - int playlist_artist; - int playlist_album; - int dvd_arrow_keys_control_playback; - - // Audio visualization - char audio_visualization[64]; - char audio_vis_goom_opts[256]; - - // deinterlacing post plugin - char deinterlace_method[32]; - char deinterlace_opts[256]; - - // ffmpeg post processing - int ffmpeg_pp; // enable / disable - int ffmpeg_pp_quality; // 0...6 - char ffmpeg_pp_mode[256]; - - // automatic 4:3 letterbox -> 16:9 cropping post plugin - int autocrop; // enable / disable - int autocrop_autodetect; - int autocrop_soft; - int autocrop_fixedsize; - int autocrop_subs; - - // (video) software scaling - int swscale; // enable/disable - int swscale_change_aspect; // change video aspect ratio - int swscale_resize; // change video size - int swscale_width; // output video width - int swscale_height; // output video height - int swscale_downscale; // allow downscaling - - // sharpen / soften post plugin - int unsharp; // enable / disable - int unsharp_luma_matrix_width; // 3..11, should be an odd number - int unsharp_luma_matrix_height; // 3..11, should be an odd number - int unsharp_luma_amount; // Actually a double between -2.0 and 2.0, but handled as a int between -20 and 20 - int unsharp_chroma_matrix_width; // 3..11, should be an odd number - int unsharp_chroma_matrix_height; // 3..11, should be an odd number - int unsharp_chroma_amount; // Actually a double between -2.0 and 2.0, but handled as a int between -20 and 20 - - // 3D noise reduction post plugin - int denoise3d; // enable / disable - int denoise3d_luma; // Actually a double between 0.0 and 10.0, but handled as a int between 0 and 100 - int denoise3d_chroma; // Actually a double between 0.0 and 10.0, but handled as a int between 0 and 100 - int denoise3d_time; // Actually a double between 0.0 and 10.0, but handled as a int between 0 and 100 - - int volnorm; // enable/disable volnorm post plugin (normalize audio volume) - - // Remote server settings - int remote_mode; // Allow remote clients (vdr-sxfe, vdr-fbfe, ...) - int listen_port; // Port of remote server - char remote_local_if[32]; // Listen only on this interface - char remote_local_ip[32]; // Bind locally to this IP - int remote_keyboard; // Allow remote client to control VDR with keyboard, LIRC, etc. - int remote_max_clients; // Max. number of clients - - int remote_usebcast; // Use broadcasts to find servers automatically - int remote_usepipe; // enable local pipes for video transport - int remote_usertp; // enable RTP multicast for video transport - int remote_useudp; // enable UDP unicast for video transport - int remote_usetcp; // enable TCP streams for video transport - int remote_http_files; // allow http streaming of media files to xineliboutput clients - // (=currently replayed media file from xineliboutput media player) - // streaming is used only if client can't access file directly (nfs etc.) - int remote_use_rtsp; // allow generic rtsp for primary device. needs enabled udp or rtp - int remote_use_rtsp_ctrl;// allow rtsp to control primary device (play/pause/seek...) - int remote_use_http; // allow generic http streaming (primary device output) - int remote_use_http_ctrl;// allow http to control primary device (play/pause/seek...) - - // RTP parameters - char remote_rtp_addr[32]; //xxx.xxx.xxx.xxx\0 - int remote_rtp_port; - int remote_rtp_ttl; - int remote_rtp_always_on; - int remote_rtp_sap; - - // Advanced settings - int live_mode_sync; /* Sync SCR to transponder clock in live mode */ - int scr_tuning; /* Fine-tune xine egine SCR (to sync video to graphics output) */ - int scr_hz; /* Current SCR speed (Hz), default is 90000 */ - - int decoder_mpeg2; /* DECODER_MPEG2_... */ - int decoder_h264; /* DECODER_H264_... */ - int ff_h264_speed_over_accurancy; - int ff_h264_skip_loop_filter; /* FF_H264_SKIP_LOOPFILTER_* */ - - config_t(); - - bool SetupParse(const char *Name, const char *Value); - bool ProcessArgs(int argc, char *argv[]); - - bool IsImageFile(const char *); - bool IsAudioFile(const char *); - bool IsVideoFile(const char *); - bool IsPlaylistFile(const char *); - bool IsDvdFolder(const char *); - bool IsDvdImage(const char *); - - cString AutocropOptions(void); - cString SwScaleOptions(void); - cString FfmpegPpOptions(void); - cString UnsharpOptions(void); - cString Denoise3dOptions(void); - - template<typename T> bool IsOptionHidden(T & option) - { return hidden_options[(int)((long int)&option - (long int)this)];}; - template<typename T> bool IsOptionReadOnly(T & option) - { return readonly_options[(int)((long int)&option - (long int)this)];}; - - protected: - bool ProcessArg(const char *Name, const char *Value); - static cString m_ProcessedArgs; - - static uint8_t *hidden_options; - static uint8_t *readonly_options; - - template<typename T> void HideOption(T & option) - { hidden_options[(int)((long int)&option - (long int)this)] = 1;}; - template<typename T> void ReadOnlyOption(T & option) - { readonly_options[(int)((long int)&option - (long int)this)] = 1;}; -}; - -// Global instance -extern config_t xc; - -// Find index of string in array of strings -static inline int strstra(const char * const str, const char * const stra[], int def_index) -{ - if(str && stra) { - int i; - for(i=0; stra[i]; i++) - if(!strcmp(str,stra[i])) - return i; - } - return def_index; -} - -#endif //_XINELIB_CONFIG_H_ - diff --git a/configure b/configure deleted file mode 100755 index 76cb4956..00000000 --- a/configure +++ /dev/null @@ -1,450 +0,0 @@ -#!/bin/sh -# -# vdr-xinelibout configure script -# -# Copyright (c) Petri Hintukainen 2008 -# -# See the main source file 'xineliboutput.c' for copyright information and -# how to reach the author. -# -# * $Id: configure,v 1.18 2009-02-17 13:01:16 phintuka Exp $ -# - -PKG_CONFIG="pkg-config" -makefile="config.mak" -header="features.h" -logfile="configure.log" -debug=no - -CC="cc" -CXX="g++" -CFLAGS="" - -# -# tools -# - -toupper(){ - echo "$@" | tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_ -} - -die(){ - log "$@" - exit -1 -} - -log(){ - echo "$@" - echo "$@" >> $logfile -} - -logdbg(){ - [ x$debug = xyes ] && log "$@" || echo "$@" >> $logfile -} - -not_in_list(){ - key=$1 - shift - for item in $*; do - test $key = $item && return 1 - done - return 0 -} - -add_flag(){ - eval not_in_list $flag \$$flags_list || return 1 - logdbg "adding $flag to $flags_list" - eval $flags_list=\"\$${flags_list} ${flag}\" -} - -add_flags(){ - flags_list=$1 - shift - for flag in $*; do - add_flag $flags_list $flag - done -} - -# -# enable/disable -# - -set_opt(){ - eval HAVE_$(toupper $1)=$2 -} - -set_opts(){ - optvalue=$1 - shift - for optname in $*; do - set_opt $optname $optvalue - done -} - -enable(){ - set_opts yes $* -} - -disable(){ - set_opts no $* -} - -enabled(){ - ucfeature=$(toupper $1) - eval test "x\$HAVE_${ucfeature}" = "xyes" -} - -disabled(){ - ucfeature=$(toupper $1) - eval test "x\$HAVE_${ucfeature}" = "xno" -} - -# -# compile/link tests -# - -generate_test_c(){ - hdrname="$1" - subsys="$2" - func="$3" - if test x"$subsys" = xX11 ; then - cat <<EOF >testhdr.c -#include <X11/Xlib.h> -#include <$hdrname> -int main(int c, char **v) { - $func; - return 0; -} -EOF - else - cat <<EOF >testhdr.c -#include <stdio.h> -#include <$hdrname> -int main(int c, char **v) { - $func; -} -EOF - fi -} - -test_library_c(){ - - log -n "Checking for $libname ... " - generate_test_c "$hdr" "$subsys" "$func" - $CC -g testhdr.c -o testhdr $CFLAGS $inc $lib >> $logfile 2>&1 - err=$? - - if test $err = 0; then - log "yes" - add_flags LIBS_$subsys $lib - add_flags CFLAGS_$subsys $inc - else - log "no" - logdbg "--------" - logdbg "/* $CC -g testhdr.c -o testhdr $CFLAGS $inc $lib */" - logdbg `cat testhdr.c` - logdbg "--------" - fi - - rm -f testhdr.c testhdr - return $err -} - -# -# pkg-config tests -# - -test_pkgconfig(){ - disabled pkgconfig && return 1 - log -n "Checking for $PKG_CONFIG ... " - disable pkgconfig - $PKG_CONFIG --version>/dev/null && enable pkgconfig - log $HAVE_PKGCONFIG -} - -test_library_pc(){ - subsys="$1" - libname="$2" - - log -n "Checking for pkg-config $libname ... " - if $PKG_CONFIG --exists $libname; then - add_flags LIBS_$subsys \ - `pkg-config --libs-only-L $libname` \ - `pkg-config --libs-only-l $libname` - add_flags CFLAGS_$subsys `pkg-config --cflags-only-I $libname` - log "yes" - return 0 - fi - log "no" - return 1 -} - -# -# generic test -# - -test_library(){ - subsys="$1" - libname="$2" - hdr="$3" - lib="$4" - func="$5" - inc="$6" - feature=$(toupper $libname) - - # do not test if disabled from command-line - if disabled $feature; then - log "Not checking for $libname" - disable $feature - return 1 - fi - - disable $feature - - # try pkg-config first - if enabled pkgconfig; then - test_library_pc "$subsys" "$libname" && enable "$feature" - fi - - # compile/link test as fallback - if disabled $feature; then - test_library_c "$subsys" "$libname" "$hdr" "$lib" "$func" "$inc" && enable $feature - fi -} - -# -# configurable features -# - -SUBSYSTEMS=" - x11 - fb - vdr - libxine -" -FEATURES=" - $SUBSYSTEMS - libextractor - libavutil - libjpeg - dbus_glib_1 - xshm - xdpms - xinerama - xrandr - xrender - vdpau -" - -# set defaults - -enable x11 vdr fb xine - -# clear log file - -rm -f $logfile - -# -# Parse command-line arguments -# - -show_help(){ - echo "Usage: configure [options]" - echo "Options: [defaults in brackets after descriptions]" - echo - echo " --help print this message" - echo " --enable-x11 build X11 frontend (vdr-sxfe) [yes]" - echo " --enable-fb build framebuffer frontend (vdr-fbfe) [yes]" - echo " --enable-vdr build VDR plugin [yes]" - echo " --enable-libxine build xine plugins [yes]" - echo - echo " --disable-libextractor disable libextractor support (media file metainfo) [no]" - echo " --disable-libjpeg disable libjpeg support [no]" - echo " --disable-dbus-glib-1 disable dbus-glib support [no]" - echo " --disable-xshm disable XShm support [no]" - echo " --disable-xdpms disable Xdpms support [no]" - echo " --disable-xinerama disable Xinerama support [no]" - echo " --disable-xrandr disable Xrandr support (video mode switching) [no]" - echo " --disable-xrender disable Xrender support (HUD OSD) [no]" - echo " --disable-vdpau disable VDPAU support (X11) [no]" - echo - echo " --debug debug configure script" - echo " --disable-pkgconfig do not use pkg-config" - echo " --cc=CC select C compiler" - echo " --cxx=CXX select C++ compiler" - echo " --add-cflags=FLAGS add compiler flags" -} - -for opt do - optval="${opt#*=}" - logdbg "Command line: $opt [$optval]" - case "$opt" in - --help) - show_help && die - ;; - --debug) - debug=yes - logdbg "Debug mode" - ;; - --cc=?*) - CC=$optval - logdbg "C compiler: $CC" - ;; - --cxx=?*) - CXX=$optval - logdbg "C++ compiler: $CXX" - ;; - --add-cflags=?*) - CFLAGS="$CFLAGS $optval" - logdbg "CFLAGS: $CFLAGS" - ;; - --disable-pkgconfig) - disable pkgconfig - logdbg "Disabled pkg-config" - ;; - --enable-?*|--disable-?*) - eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'` - logdbg " $action $option" - not_in_list $option $FEATURES && die "unknown option $opt" - eval $action \${option} - ;; - -*) - die "unknown option $opt" - ;; - esac -done - -# -# maintain deps -# - -check_deps(){ - disabled libxine && disable x11 fb libavutil libjpeg - disabled x11 && disable xshm xrender xrandr xdpms xinerama vdpau - disabled x11 && disable dbus-glib-1 xshm xrender xrandr xdpms xinerama vdpau - disabled vdr && disable libextractor -} - -check_deps - -# -# Run the tests -# - -test_pkgconfig - -# fake test that should fail -[ $debug = yes ] && \ - test_library X11 do_error "none.h" "-lnolib" - -test_library VDR libextractor "extractor.h" "-lextractor" "EXTRACTOR_getKeywords(0,0)" -test_library XINE libxine "xine.h" "-lxine" "xine_init(0)" - -if enabled libxine; then - - log -n "Checking for xine plugin directory ..." - if enabled pkgconfig && $PKG_CONFIG libxine --atleast-version 1.1.90; then - XINEPLUGINDIR=`$PKG_CONFIG libxine --variable=plugindir` - else - XINEPLUGINDIR=`xine-config --plugindir` - fi - log " $XINEPLUGINDIR" - - test_library XINE libavutil "libavutil/mem.h" "-lavutil" "av_mallocz(1)" - test_library XINE libjpeg "jpeglib.h" "-ljpeg" "jpeg_create_compress(0)" - test_library X11 x11 "X11/X.h" "-lX11" "XInitThreads()" - if enabled x11; then - test_library X11 xext "X11/extensions/Xext.h" "-lXext" "" - test_library X11 xshm "X11/extensions/XShm.h" "-lXext" "XShmQueryExtension(0)" - test_library X11 xrender "X11/extensions/Xrender.h" "-lXrender" "XRenderQueryFormats(0)" - test_library X11 xrandr "X11/extensions/Xrandr.h" "-lXrandr" "XRRGetScreenInfo(0,0)" - test_library X11 xdpms "X11/extensions/dpms.h" "-lXext" "DPMSDisable(0)" - test_library X11 xinerama "X11/extensions/Xinerama.h" "-lXinerama" "XineramaQueryScreens(0,0)" - test_library X11 vdpau "vdpau/vdpau_x11.h" "-lvdpau" "vdp_device_create_x11(0,0,0,0)" - test_library X11 dbus-glib-1 \ - "dbus/dbus-glib.h" \ - "-ldbus-glib-1 -ldbus-1 -lgobject-2.0 -lglib-2.0" \ - "dbus_g_bus_get(0,0)" \ - "-I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include" - fi -fi - -check_deps - -# need -lm for ceil/floor in HUD OSD -enabled xrender && add_flags "LIBS_X11" "-lm" - -# -# Print results -# - -log -log "Enabled features:" -for feature in $FEATURES; do - enabled $feature && log " $feature" -done -log "Disabled features:" -for feature in $FEATURES; do - enabled $feature || log " $feature" -done -log - -# -# create features.h -# - -log "Creating $header ..." - -cat <<EOF >$header -/* Automatically generated by configure - do not modify! */ - -#ifndef XINELIBOUTPUT_FEATURES_H -#define XINELIBOUTPUT_FEATURES_H - -EOF - -for feature in $FEATURES; do - enabled $feature && - echo "#define HAVE_$(toupper $feature) 1">>$header || \ - echo "#undef HAVE_$(toupper $feature)">>$header -done - -echo "" >> $header -echo "#endif /* XINELIBOUTPUT_FEATURES_H */" >> $header - -# -# create features.mak -# - -log "Creating $makefile ..." - -echo "# Automatically generated by configure - do not modify!" > $makefile -echo >> $makefile - -# subsystems -echo "XINELIBOUTPUT_VDRPLUGIN=$HAVE_VDR" >> $makefile -echo "XINELIBOUTPUT_XINEPLUGIN=$HAVE_LIBXINE" >> $makefile -echo "XINELIBOUTPUT_X11=$HAVE_X11" >> $makefile -echo "XINELIBOUTPUT_FB=$HAVE_FB" >> $makefile -echo >> $makefile - -# features -for feature in $FEATURES; do - feature="`toupper $feature`" - enabled $feature && - echo "HAVE_$feature=yes">>$makefile || - echo "HAVE_$feature=no">>$makefile -done -echo >> $makefile - -# xine plugin dir -enabled libxine && echo "XINEPLUGINDIR=$XINEPLUGINDIR" >> $makefile && echo >> $makefile - -# cc/ld flags -echo "CFLAGS_XINE += $CFLAGS_XINE">>$makefile -echo "CFLAGS_VDR += $CFLAGS_VDR">>$makefile -echo "CFLAGS_X11 += $CFLAGS_X11">>$makefile -echo "LIBS_XINE += $LIBS_XINE">>$makefile -echo "LIBS_VDR += $LIBS_VDR">>$makefile -echo "LIBS_X11 += $LIBS_X11">>$makefile - diff --git a/device.c b/device.c deleted file mode 100644 index 0d797f92..00000000 --- a/device.c +++ /dev/null @@ -1,1640 +0,0 @@ -/* - * device.c: xine-lib output device for the Video Disk Recorder - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: device.c,v 1.84 2009-06-24 20:45:40 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS -#include <inttypes.h> - -#include <vdr/config.h> -#include <vdr/thread.h> -#include <vdr/dvbspu.h> -#include <vdr/channels.h> -#include <vdr/skins.h> -#include <vdr/status.h> -#include <vdr/remote.h> - -//#define XINELIBOUTPUT_DEBUG -//#define XINELIBOUTPUT_DEBUG_STDERR -//#define TRACK_EXEC_TIME -//#define FORWARD_DVD_SPUS -//#define DEBUG_SWITCHING_TIME -//#define LOG_TRICKSPEED - -#include "logdefs.h" -#include "config.h" -#include "osd.h" - -#include "tools/listiter.h" -#include "tools/mpeg.h" -#include "tools/pes.h" -#include "tools/ts.h" -#include "tools/functor.h" - -#include "frontend_local.h" -#include "frontend_svr.h" - -#include "device.h" - -#define STILLPICTURE_REPEAT_COUNT 3 -#define LOCAL_INIT_TIMEOUT 20 // seconds -#define SERVER_INIT_TIMEOUT 5 // seconds - -#ifdef LOG_TRICKSPEED -# define LOGTRICKSPEED(x...) LOGMSG("trs: " x) -#else -# define LOGTRICKSPEED(x...) -#endif - -//---------------------------- status monitor ------------------------------- - -class cXinelibStatusMonitor : public cStatus -{ - private: - cXinelibStatusMonitor(); - cXinelibStatusMonitor(cXinelibStatusMonitor&); - - public: - cXinelibStatusMonitor(cXinelibDevice& device, int cardIndex) : - m_Device(device), m_cardIndex(cardIndex) - { -#ifdef DEBUG_SWITCHING_TIME - switchtimeOff = 0LL; - switchtimeOn = 0LL; - switchingIframe = false; -#endif - }; - - protected: - virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); - virtual void Replaying(const cControl *Control, const char *Name, - const char *FileName, bool On); - - cXinelibDevice& m_Device; - int m_cardIndex; - -#ifdef DEBUG_SWITCHING_TIME - public: - int64_t switchtimeOff; - int64_t switchtimeOn; - bool switchingIframe; - - void IFrame(void) - { - if(!switchingIframe) { - int64_t now = cTimeMs::Now(); - switchingIframe = true; - LOGMSG("Channel switch: off -> on %" PRId64 " ms, " - "on -> 1. I-frame %" PRId64 " ms", - switchtimeOn-switchtimeOff, now-switchtimeOn); - } else { - int64_t now = cTimeMs::Now(); - LOGMSG("Channel switch: on -> 2. I-frame %" PRId64 " ms, " - "Total %" PRId64 " ms", - now-switchtimeOn, now-switchtimeOff); - switchtimeOff = 0LL; - switchtimeOn = 0LL; - switchingIframe = false; - } - } -#endif -}; - -void cXinelibStatusMonitor::ChannelSwitch(const cDevice *Device, - int ChannelNumber) -{ - TRACEF("cXinelibStatusMonitor::ChannelSwitch"); - TRACK_TIME(200); - - if (ChannelNumber) { - if (Device->CardIndex() == m_cardIndex) { -#ifdef DEBUG_SWITCHING_TIME - switchtimeOn = cTimeMs::Now(); -#endif - m_Device.SetTvMode(Channels.GetByNumber(ChannelNumber)); - TRACE("cXinelibStatusMonitor: Set to TvMode"); - } - } else { - if (Device->CardIndex() == m_cardIndex) { -#ifdef DEBUG_SWITCHING_TIME - switchtimeOff = cTimeMs::Now(); -#endif - m_Device.StopOutput(); - TRACE("cXinelibStatusMonitor: received stop"); - } - } -} - -void cXinelibStatusMonitor::Replaying(const cControl *Control, - const char *Name, - const char *FileName, bool On) -{ - TRACEF("cXinelibStatusMonitor::Replaying"); - - if (On /*&& Name != NULL*/) { - TRACE("cXinelibStatusMonitor: Replaying " << Name << "(" << FileName << ")"); - m_Device.SetReplayMode(); - } -} - -//----------------------------- device ---------------------------------------- - -// -// Singleton -// - -cXinelibDevice* cXinelibDevice::m_pInstance = NULL; - -cXinelibDevice& cXinelibDevice::Instance(void) -{ - TRACEF("cXinelibDevice::Instance"); - if (!m_pInstance) { - m_pInstance = new cXinelibDevice(); - TRACE("cXinelibDevice::Instance(): create, cardindex = " - << m_pInstance->CardIndex()); - } - - return *m_pInstance; -} - -void cXinelibDevice::Dispose(void) -{ - TRACEF("cXinelibDevice::Dispose"); - delete m_pInstance; - m_pInstance = NULL; -} - -// -// init and shutdown -// - -cXinelibDevice::cXinelibDevice() -{ - TRACEF("cXinelibDevice::cXinelibDevice"); - - m_statusMonitor = NULL; - m_spuDecoder = NULL; - - m_local = NULL; - m_server = NULL; - - m_OriginalPrimaryDevice = 0; - m_ForcePrimaryDeviceCnt = 0; - - if(*xc.local_frontend && strncmp(xc.local_frontend, "none", 4)) - m_clients.Add(m_local = new cXinelibLocal(xc.local_frontend)); - if(xc.remote_mode && xc.listen_port>0) - m_clients.Add(m_server = new cXinelibServer(xc.listen_port)); - - m_ac3Present = false; - m_spuPresent = false; - - memset(m_MetaInfo, 0, sizeof(m_MetaInfo)); - - m_PlayMode = pmNone; - m_AudioChannel = 0; - - m_liveMode = true; - m_TrickSpeed = -1; - m_TrickSpeedPts = 0; - m_TrickSpeedMode = 0; - m_TrickSpeedDelay = 0; - m_SkipAudio = false; - m_PlayingFile = pmNone; - m_StreamStart = true; - m_RadioStream = false; - m_AudioCount = 0; - m_FreeBufs = 0; - m_Cleared = true; - m_h264 = false; - - m_VideoSize = (video_size_t*)calloc(1, sizeof(video_size_t)); - - TsBufferClear(); -} - -cXinelibDevice::~cXinelibDevice() -{ - TRACEF("cXinelibDevice::~cXinelibDevice"); - - StopDevice(); - - m_pInstance = NULL; - - free (m_VideoSize); -} - -bool cXinelibDevice::StartDevice() -{ - TRACEF("cXinelibDevice::StartDevice"); - - if(m_local) - m_local->Start(); - if(m_server) - m_server->Start(); - - // if(dynamic_cast<cXinelibLocal*>(it)) - if(m_local) { - int timer = 0; - while(!m_local->IsReady()) { - cCondWait::SleepMs(100); - if(m_local->IsFinished()) { - LOGMSG("cXinelibDevice::Start(): Local frontend init failed"); - return false; - } - if(++timer >= LOCAL_INIT_TIMEOUT*10) { - LOGMSG("cXinelibDevice::Start(): Local frontend init timeout"); - return false; - } - } - if(xc.force_primary_device) - ForcePrimaryDevice(true); - } - - if(m_server) { - int timer = 0; - while(!m_server->IsReady()) { - cCondWait::SleepMs(100); - if(m_server->IsFinished()) { - LOGMSG("cXinelibDevice::Start(): Server init failed"); - return false; - } - if(++timer >= SERVER_INIT_TIMEOUT*10) { - LOGMSG("cXinelibDevice::Start(): Server init timeout"); - return false; - } - } - } - - ASSERT(m_statusMonitor == NULL, false); - m_statusMonitor = new cXinelibStatusMonitor(*this, CardIndex()); - - LOGDBG("cXinelibDevice::StartDevice(): Device started"); - return true; -} - -void cXinelibDevice::StopDevice(void) -{ - TRACEF("cXinelibDevice::StopDevice"); - LOGDBG("cXinelibDevice::StopDevice(): Stopping device ..."); - - if(m_statusMonitor) { - delete m_statusMonitor; - m_statusMonitor = NULL; - } - if (m_spuDecoder) { - delete m_spuDecoder; - m_spuDecoder = NULL; - } - - cXinelibThread *server = m_server; - cXinelibThread *local = m_local; - m_local = m_server = NULL; - - cControl::Shutdown(); - ForEach(m_clients, &cXinelibThread::SetLiveMode, false); - TrickSpeed(-1); - - if(local) m_clients.Del(local, false); - if(server) m_clients.Del(server, false); - - if(server) { - server->Stop(); - delete server; - } - if(local) { - local->Stop(); - delete local; - } - - m_clients.Clear(); -} - -// -// Primary device switching -// - -void cXinelibDevice::MakePrimaryDevice(bool On) -{ - TRACEF("cXinelibDevice::MakePrimaryDevice"); - - cDevice::MakePrimaryDevice(On); - - if(On) - new cXinelibOsdProvider(this); -} - -void cXinelibDevice::ForcePrimaryDevice(bool On) -{ - TRACEF("cXinelibDevice::ForcePrimaryDevice"); - - m_MainThreadLock.Lock(); - m_MainThreadFunctors.Add(CreateFunctor(this, &cXinelibDevice::ForcePrimaryDeviceImpl, On)); - m_MainThreadLock.Unlock(); -} - -void cXinelibDevice::ForcePrimaryDeviceImpl(bool On) -{ - TRACEF("cXinelibDevice::ForcePrimaryDeviceImpl"); - ASSERT(cThread::IsMainThread(), false); - - if(On) { - m_ForcePrimaryDeviceCnt++; - - if(xc.force_primary_device) { - if(cDevice::PrimaryDevice() && this != cDevice::PrimaryDevice()) { - m_OriginalPrimaryDevice = cDevice::PrimaryDevice()->DeviceNumber() + 1; - cControl::Shutdown(); - LOGMSG("Forcing primary device, original index = %d", m_OriginalPrimaryDevice); - if(cOsd::IsOpen()) { - LOGMSG("Forcing primary device, old OSD still open !"); - xc.main_menu_mode = CloseOsd; - cRemote::CallPlugin("xineliboutput"); - } - SetPrimaryDevice(DeviceNumber() + 1); - } - } - - } else /* Off */ { - m_ForcePrimaryDeviceCnt--; - - if(m_ForcePrimaryDeviceCnt < 0) - LOGMSG("ForcePrimaryDevice: Internal error (ForcePrimaryDevice < 0)"); - else if(m_ForcePrimaryDeviceCnt == 0) { - if(m_OriginalPrimaryDevice) { - LOGMSG("Restoring original primary device %d", m_OriginalPrimaryDevice); - cControl::Shutdown(); - if(cOsd::IsOpen()) { - LOGMSG("Restoring primary device, xineliboutput OSD still open !"); - xc.main_menu_mode = CloseOsd; /* will be executed in future by vdr main thread */ - cRemote::CallPlugin("xineliboutput"); - } - cChannel *channel = Channels.GetByNumber(CurrentChannel()); - cDevice::SetPrimaryDevice(m_OriginalPrimaryDevice); - PrimaryDevice()->SwitchChannel(channel, true); - m_OriginalPrimaryDevice = 0; - } - } - } -} - -// -// Execute functors in main thread context -// - -void cXinelibDevice::MainThreadHook(void) -{ - TRACEF("cXinelibDevice::MainThreadHook"); - - if(m_MainThreadFunctors.First()) { - cFunctor *f = NULL; - do { - m_MainThreadLock.Lock(); - if(f) - m_MainThreadFunctors.Del(f); - f = m_MainThreadFunctors.First(); - m_MainThreadLock.Unlock(); - - if(f) { - /*LOGDBG("cXinelibDevice::MainThreadHook: executing functor 0x%lx",(long)f);*/ - f->Execute(); - } - - } while(f); - } -} - -// -// Configuration -// - -void cXinelibDevice::ConfigurePostprocessing(const char *deinterlace_method, - int audio_delay, - int audio_compression, - const int *audio_equalizer, - int audio_surround, - int speaker_type) -{ - TRACEF("cXinelibDevice::ConfigurePostprocessing"); - - if(m_local) - m_local->ConfigurePostprocessing(deinterlace_method, audio_delay, - audio_compression, audio_equalizer, - audio_surround, speaker_type); - if(m_server) - m_server->ConfigurePostprocessing(deinterlace_method, audio_delay, - audio_compression, audio_equalizer, - audio_surround, speaker_type); -} - -void cXinelibDevice::ConfigurePostprocessing(const char *name, bool on, - const char *args) -{ - TRACEF("cXinelibDevice::ConfigurePostprocessing"); - - if(m_local) - m_local->ConfigurePostprocessing(name, on, args); - if(m_server) - m_server->ConfigurePostprocessing(name, on, args); -} - -void cXinelibDevice::ConfigureVideo(int hue, int saturation, int brightness, int sharpness, - int noise_reduction, int contrast, int overscan, int vo_aspect_ratio) -{ - TRACEF("cXinelibDevice::ConfigureVideo"); - - if(m_local) - m_local->ConfigureVideo(hue, saturation, brightness, sharpness, noise_reduction, contrast, overscan, vo_aspect_ratio); - if(m_server) - m_server->ConfigureVideo(hue, saturation, brightness, sharpness, noise_reduction, contrast, overscan, vo_aspect_ratio); -} - -void cXinelibDevice::ConfigureDecoder(int pes_buffers) -{ - TRACEF("cXinelibDevice::ConfigureDecoder"); - - if(m_local) - m_local->ConfigureDecoder(pes_buffers); - //if(m_server) - // m_server->ConfigureDecoder(pes_buffers); - - cXinelibOsdProvider::RefreshOsd(); -} - -void cXinelibDevice::ConfigureWindow(int fullscreen, int width, int height, - int modeswitch, const char *modeline, - int aspect, int scale_video, - int field_order) -{ - TRACEF("cXinelibDevice::ConfigureWindow"); - - if((!*xc.local_frontend || !strncmp(xc.local_frontend, "none", 4)) && m_local) { - cXinelibThread *tmp = m_local; - m_clients.Del(tmp, false); - m_local = NULL; - cCondWait::SleepMs(5); - tmp->Stop(); - cCondWait::SleepMs(5); - delete tmp; - if(xc.force_primary_device) - ForcePrimaryDevice(false); - } - - if(m_local) - m_local->ConfigureWindow(fullscreen, width, height, modeswitch, modeline, - aspect, scale_video, field_order); - - else if(*xc.local_frontend && strncmp(xc.local_frontend, "none", 4)) { - cXinelibThread *tmp = new cXinelibLocal(xc.local_frontend); - tmp->Start(); - m_clients.Add(m_local = tmp); - - cCondWait::SleepMs(25); - while(!m_local->IsReady() && !m_local->IsFinished()) - cCondWait::SleepMs(25); - - if(m_local->IsFinished()) { - m_local = NULL; - m_clients.Del(tmp, true); - Skins.QueueMessage(mtError, tr("Frontend initialization failed"), 10); - } else { - if(xc.force_primary_device) - ForcePrimaryDevice(true); - - m_local->ConfigureWindow(fullscreen, width, height, modeswitch, modeline, - aspect, scale_video, field_order); - } - } -} - -void cXinelibDevice::Listen(bool activate, int port) -{ - TRACEF("cXinelibDevice::Listen"); - - if(activate && port>0) { - if(!m_server) { - cXinelibThread *tmp = new cXinelibServer(port); - tmp->Start(); - m_clients.Add(m_server = tmp); - - cCondWait::SleepMs(10); - while(!m_server->IsReady() && !m_server->IsFinished()) - cCondWait::SleepMs(10); - - if(m_server->IsFinished()) { - Skins.QueueMessage(mtError, tr("Server initialization failed"), 10); - m_server = NULL; - m_clients.Del(tmp, true); - } - - } else { - if(! m_server->Listen(port)) - Skins.QueueMessage(mtError, tr("Server initialization failed"), 10); - } - } else if( /*((!activate) || port<=0) && */ m_server) { - cXinelibThread *tmp = m_server; - m_clients.Del(tmp, false); - m_server = NULL; - cCondWait::SleepMs(5); - tmp->Stop(); - cCondWait::SleepMs(5); - delete tmp; - } -} - -// -// OSD -// - -void cXinelibDevice::OsdCmd(void *cmd) -{ - TRACEF("cXinelibDevice::OsdCmd"); - TRACK_TIME(250); - - if(m_server) // call first server, local frontend modifies contents of the message ... - m_server->OsdCmd(cmd); - if(m_local) - m_local->OsdCmd(cmd); -} - -// -// Play mode control -// -void cXinelibDevice::StopOutput(void) -{ - TRACEF("cXinelibDevice::StopOutput"); - TRACK_TIME(250); - - m_RadioStream = false; - m_AudioCount = 0; - ForEach(m_clients, &cXinelibThread::SetLiveMode, false); - Clear(); - ForEach(m_clients, &cXinelibThread::QueueBlankDisplay); - ForEach(m_clients, &cXinelibThread::SetNoVideo, false); -} - -void cXinelibDevice::SetTvMode(cChannel *Channel) -{ - TRACEF("cXinelibDevice::SetTvMode"); - TRACK_TIME(250); - -#if VDRVERSNUM >= 10701 - m_PatPmtParser.Reset(); -#endif - - m_RadioStream = false; - if (Channel && !Channel->Vpid() && (Channel->Apid(0) || Channel->Apid(1))) - m_RadioStream = true; - if(m_PlayMode == pmAudioOnlyBlack) - m_RadioStream = true; - TRACE("cXinelibDevice::SetTvMode - isRadio = "<<m_RadioStream); - - m_StreamStart = true; - m_liveMode = true; - m_TrickSpeed = -1; - m_SkipAudio = false; - m_AudioCount = 0; - m_spuPresent = false; - - Clear(); - ForEach(m_clients, &cXinelibThread::SetNoVideo, m_RadioStream); - ForEach(m_clients, &cXinelibThread::SetLiveMode, true); - ForEach(m_clients, &cXinelibThread::ResumeOutput); -} - -void cXinelibDevice::SetReplayMode(void) -{ - TRACEF("cXinelibDevice::SetReplayMode"); - - m_RadioStream = true; // first seen replayed video packet resets this - m_AudioCount = 15; - m_StreamStart = true; - - ForEach(m_clients, &cXinelibThread::SetLiveMode, false); - Clear(); - ForEach(m_clients, &cXinelibThread::SetNoVideo, false /*m_RadioStream*/); - if(m_RadioStream && !m_liveMode) - ForEach(m_clients, &cXinelibThread::BlankDisplay); - ForEach(m_clients, &cXinelibThread::ResumeOutput); - - m_liveMode = false; -} - -bool cXinelibDevice::SetPlayMode(ePlayMode PlayMode) -{ - TRACEF("cXinelibDevice::SetPlayMode"); - -#ifdef XINELIBOUTPUT_DEBUG - switch (PlayMode) { - case pmNone: - TRACE("cXinelibDevice::SetPlayMode audio/video from decoder"); break; - case pmAudioVideo: - TRACE("cXinelibDevice::SetPlayMode audio/video from player"); break; - case pmVideoOnly: - TRACE("cXinelibDevice::SetPlayMode video from player, audio from decoder"); break; - case pmAudioOnly: - TRACE("cXinelibDevice::SetPlayMode audio from player, video from decoder"); break; - case pmAudioOnlyBlack: - TRACE("cXinelibDevice::SetPlayMode audio only from player, no video (black screen)"); break; - case pmExtern_THIS_SHOULD_BE_AVOIDED: - TRACE("cXinelibDevice::SetPlayMode this should be avoided"); break; - } -#endif - - m_ac3Present = false; - m_spuPresent = false; - - m_PlayMode = PlayMode; - - TrickSpeed(-1); - if (m_PlayMode == pmAudioOnlyBlack) { - TRACE("pmAudioOnlyBlack --> BlankDisplay, NoVideo"); - ForEach(m_clients, &cXinelibThread::BlankDisplay); - ForEach(m_clients, &cXinelibThread::SetNoVideo, true); - } else { - if(m_liveMode) - ForEach(m_clients, &cXinelibThread::SetNoVideo, m_RadioStream); - else - ForEach(m_clients, &cXinelibThread::SetNoVideo, - m_RadioStream && (m_AudioCount<1)); - Clear(); - } - - return true; -} - -// -// Playback control -// - -// m_TrickSpeedMode flags -#define trs_IPB_frames 0x01 // stream has all frame types -#define trs_I_frames 0x02 // stream has only I-frames -#define trs_PTS_recalc 0x04 // PTS must be re-calculated -#define trs_NoAudio 0x08 // no audio in trick speed mode -#define trs_PTS_check 0x80 // detect in PlayVideo if PTS must be recalculated - -void cXinelibDevice::TrickSpeed(int Speed) -{ - TRACEF("cXinelibDevice::TrickSpeed"); - - if(m_TrickSpeed != Speed) { - int RealSpeed = abs(Speed); - LOGTRICKSPEED("TrickSpeed changed from %d to %d [%d]", m_TrickSpeed, Speed, RealSpeed); - - m_TrickSpeedPts = 0; - m_TrickSpeed = Speed; - m_TrickSpeedDelay = 0; - - // Possible transitions: - // fast <-> play - // play <-> pause - // pause <-> slow - // _and_ from any mode to normal play and pause - - if(Speed == 8 || Speed == 4 || Speed == 2) { - LOGTRICKSPEED(" Slow forward (1/%d speed), IPB-frames", Speed); - - // do nothing - slow forward is just slow playback of complete stream - m_TrickSpeedMode = trs_IPB_frames; - - // previous state was slow forward or pause --> no need for clear - - // change decoder and UDP/RTP scheduler clock rates - ForEach(m_clients, &cXinelibThread::TrickSpeed, RealSpeed); - } - - else if(Speed == 63 || Speed == 48 || Speed == 24) { - RealSpeed = (Speed+11)/12; - LOGTRICKSPEED(" Slow backward (1/%d speed), I-frames only", RealSpeed); - - // previous state was slow backwards or pause --> clear if it was pause - // - //if(PrevSpeed == 0 && !(m_TrickSpeedMode & trs_PTS_recalc)) { - // LOGMSG(" -> Clear"); - // ForEach(m_clients, &cXinelibThread::Clear); - //} - - // only I-frames, backwards, pts must be re-generated - m_TrickSpeedMode = trs_I_frames | trs_PTS_recalc | trs_NoAudio; - - // change decoder and UDP/RTP scheduler clock rates - ForEach(m_clients, &cXinelibThread::TrickSpeed, RealSpeed); - } - - else if(Speed == 6 || Speed == 3 || Speed == 1) { - RealSpeed = 12/Speed; - LOGTRICKSPEED(" Fast (%dx speed), direction unknown", RealSpeed); - - if(RealSpeed > xc.max_trickspeed) { - RealSpeed = xc.max_trickspeed; - LOGTRICKSPEED(" Trick speed limited to %dx speed", RealSpeed); - } - - /* only I-frames, backwards, pts must be re-generated if playing backwards */ - m_TrickSpeedMode |= trs_PTS_check; - - /* backward/forward state is unknown until first PTS is seen - so, clear() must be done in PlayVideo. */ - /* previous trick speed state is not overwritten yet ... ! */ - - // change decoder and UDP/RTP scheduler clock rates - ForEach(m_clients, &cXinelibThread::TrickSpeed, -RealSpeed); - } - - else if(Speed==-1 || Speed == 0) { - LOGTRICKSPEED(" Play/Pause"); - - // change decoder and UDP/RTP scheduler clock rates - ForEach(m_clients, &cXinelibThread::TrickSpeed, RealSpeed); - - // returning from backward mode needs Clear - // - //if(Speed==-1 && (m_TrickSpeedMode & trs_PTS_recalc)) { - // LOGMSG(" -> Clear"); - // ForEach(m_clients, &cXinelibThread::Clear); - // m_TrickSpeedMode = 0; - //} - // returning from fast forward mode needs Clear - // because of DvbPlayer jumps few seconds back at mode change ... - // - //if(Speed==-1 && (m_TrickSpeedMode & trs_I_frames)) { - // LOGMSG(" -> Clear"); - // ForEach(m_clients, &cXinelibThread::Clear); - //} - m_TrickSpeedMode = 0; - } - - else { - LOGTRICKSPEED(" Unknown trickspeed %d !", Speed); - m_TrickSpeedMode = 0; - m_TrickSpeed = -1; - ForEach(m_clients, &cXinelibThread::TrickSpeed, -1); - } - } -} - -void cXinelibDevice::Clear(void) -{ - TRACEF("cXinelibDevice::Clear"); - TRACK_TIME(100); - - TsBufferClear(); - - if(m_Cleared && m_StreamStart && m_TrickSpeed == -1) { - //LOGMSG("************ Double Clear ***************"); - } else { - //LOGMSG("************ FIRST Clear ***************"); - m_Cleared = true; - m_StreamStart = true; - m_h264 = false; - m_FreeBufs = 0; - TrickSpeed(-1); - ForEach(m_clients, &cXinelibThread::Clear); - ForEach(m_clients, &cXinelibThread::SetStillMode, false); - } -} - -void cXinelibDevice::Play(void) -{ - TRACEF("cXinelibDevice::Play"); - - m_SkipAudio = false; - - ForEach(m_clients, &cXinelibThread::SetLiveMode, false); - TrickSpeed(-1); -} - -void cXinelibDevice::Freeze(void) -{ - TRACEF("cXinelibDevice::Freeze"); - - TsBufferFlush(); - TrickSpeed(0); -} - -int64_t cXinelibDevice::GetSTC(void) -{ - TRACEF("cXinelibDevice::GetSTC"); - - if(m_local) - return m_local->GetSTC(); - if(m_server) - return m_server->GetSTC(); - return cDevice::GetSTC(); -} - -bool cXinelibDevice::Flush(int TimeoutMs) -{ - TRACEF("cXinelibDevice::Flush"); - TRACK_TIME(500); - - TsBufferFlush(); - - if(m_TrickSpeed == 0) { - ForEach(m_clients, &cXinelibThread::SetLiveMode, false); - TrickSpeed(-1); - } - - bool r = ForEach(m_clients, &cXinelibThread::Flush, TimeoutMs, - &mand<bool>, true); - - return r; -} - - -// -// Playback of files and images -// - -int cXinelibDevice::PlayFileCtrl(const char *Cmd, int TimeoutMs) -{ - TRACEF("cXinelibDevice::PlayFile"); - int result = -1; - - /*if(m_PlayingFile != pmNone)*/ { - if(m_server) - result = m_server->PlayFileCtrl(Cmd, TimeoutMs); - if(m_local) - result = m_local->PlayFileCtrl(Cmd, TimeoutMs); - } - return result; -} - -bool cXinelibDevice::EndOfStreamReached(void) -{ - if(m_local && !m_local->EndOfStreamReached()) - return false; - if(m_server && !m_server->EndOfStreamReached()) - return false; - return true; -} - -bool cXinelibDevice::PlayFile(const char *FileName, int Position, - bool LoopPlay, ePlayMode PlayMode, - int TimeoutMs) -{ - TRACEF("cXinelibDevice::PlayFile"); - TRACE("cXinelibDevice::PlayFile(\"" << FileName << "\")"); - - bool result = true; - - if(FileName) { - if(m_PlayingFile == pmNone) { - m_PlayingFile = PlayMode; - if (!xc.IsImageFile(FileName)) - StopOutput(); - } - for(int i = 0; i < mi_Count; i++) - m_MetaInfo[i][0] = 0; - if(m_server) - result = m_server->PlayFile(FileName, Position, LoopPlay, PlayMode, TimeoutMs); - if(m_local) - result = m_local->PlayFile(FileName, Position, LoopPlay, PlayMode, TimeoutMs); - } else if(/*!FileName &&*/m_PlayingFile != pmNone) { - if(m_server) - result = m_server->PlayFile(NULL, 0, 0, pmNone, TimeoutMs); - if(m_local) - result = m_local->PlayFile(NULL, 0, 0, pmNone, TimeoutMs); - if(!m_liveMode) - SetReplayMode(); - else - SetTvMode(Channels.GetByNumber(cDevice::CurrentChannel())); - m_PlayingFile = pmNone; - } - - return result; -} - -// -// Data stream handling -// - -int cXinelibDevice::PlayTrickSpeed(const uchar *buf, int length) -{ -#if VDRVERSNUM >= 10705 - return 0; -#endif - if(abs(m_TrickSpeed) > 1 && (m_TrickSpeedMode & trs_I_frames)) { - uint8_t PictureType = pes_get_picture_type(buf, length); -#ifdef LOG_TRICKSPEED - if(PictureType != NO_PICTURE && PES_HAS_PTS(buf)) { - int64_t pts = pes_get_pts(buf, length); - LOGMSG(" TrickSpeed: frame %s pts %"PRId64, picture_type_str[PictureType], pts); - } -#endif - -#if 1 - // limit I-frame rate - if(PictureType == I_FRAME) { - static int64_t t0 = 0; - int64_t t1 = cTimeMs::Now(); - if((t1 - t0) < 1000) { - int fdelay = 40*12; // = 480 ms, time of one GOP in normal speed - switch(m_TrickSpeed) { - case 6: /* 2x ff */ fdelay /= min( 2, xc.max_trickspeed); break; - case 3: /* 4x ff */ fdelay /= min( 4, xc.max_trickspeed); break; - case 1: /* 12x ff */ fdelay /= min(12, xc.max_trickspeed); break; - case 63: /* 1/6x rew */ fdelay *= 6; break; - case 48: /* 1/4x rew */ fdelay *= 4; break; - case 24: /* 1/2x rew */ fdelay *= 2; break; - default: break; - } - /* wait if data is coming in too fast */ - if(fdelay - (t1-t0) >= 40) { - m_TrickSpeedDelay = 40; - return -1; - } - - t0 += fdelay; - - pes_change_pts((uchar*)buf, length, INT64_C(0)); - } else { - t0 = t1; - } - } -#endif - } - - // - // detecting trick speed mode ? - // - if( m_TrickSpeed > 0 && (m_TrickSpeedMode & trs_PTS_check) && IS_VIDEO_PACKET(buf)) { - int64_t pts; - if (PES_HAS_PTS(buf) && (pts = pes_get_pts(buf, length)) > 0) { - uint8_t PictureType = pes_get_picture_type(buf, length); - if(PictureType != I_FRAME && PictureType != NO_PICTURE) { - // --> must be fast worward with IBP frames. - // --> PTS check does not work (frames are sent in decoder order) ! */ - m_TrickSpeedPts = pts - 1; - LOGTRICKSPEED(" Detected fast forward mode, using IBP frames"); - } - if(m_TrickSpeedPts == 0) { - m_TrickSpeedMode |= trs_NoAudio; - m_TrickSpeedPts = pts; - LOGTRICKSPEED(" Seen video pts = %"PRId64, pts); - } else { - if(pts < m_TrickSpeedPts) { - /* -> playing fast backwards */ - LOGTRICKSPEED(" Detected fast backward mode. last %"PRId64" now %"PRId64, - m_TrickSpeedPts, pts); - //if(!(m_TrickSpeedMode & trs_PTS_recalc)) - // ForEach(m_clients, &cXinelibThread::Clear); - m_TrickSpeedMode = trs_I_frames | trs_PTS_recalc | trs_NoAudio; - } else { - LOGTRICKSPEED(" Detected fast forward mode"); - if(xc.ibp_trickspeed) - m_TrickSpeedMode = trs_IPB_frames; - else - m_TrickSpeedMode = trs_I_frames; - } - } - } - } - - // - // Trick speed mode with PTS re-calc - // - if( m_TrickSpeed > 0 && (m_TrickSpeedMode & trs_PTS_recalc) && - IS_VIDEO_PACKET(buf) && PES_HAS_PTS(buf)) { - int64_t pts = pes_get_pts(buf, length); - if (pts > 0) { - - /* m_TrickSpeedPts could be 0 in case of slow backwards */ - if(m_TrickSpeedPts == 0) - m_TrickSpeedPts = pts; - - LOGTRICKSPEED(" pts %"PRId64" -> %"PRId64" (diff %"PRId64") %"PRId64"", pts, - m_TrickSpeedPts + 40*12*90, m_TrickSpeedPts + 40*12*90 - pts, - (m_TrickSpeedPts + 40*12*90)^0x80000000); - pts = m_TrickSpeedPts = m_TrickSpeedPts + 40*12*90; /* 12 frames * 40ms -> pts units */ - pts ^= 0x80000000; /* discontinuity (when mode changes) forces re-syncing of all clocks */ - pes_change_pts((uchar*)buf, length, pts); - } - } - -#if 1 - else if (m_TrickSpeedMode & trs_I_frames) { - if (IS_VIDEO_PACKET(buf) && PES_HAS_PTS(buf)) { - int64_t pts = pes_get_pts(buf, length); - if (pts > 0) { - pts ^= 0x80000000; /* discontinuity (when mode changes) forces re-syncing of all clocks */ - pes_change_pts((uchar*)buf, length, pts); - } - } - } -#endif - - return 0; -} - -int cXinelibDevice::PlayAny(const uchar *buf, int length) -{ - TRACEF("cXinelibDevice::PlayAny"); - TRACK_TIME(100); - -#if 0 - if(m_PlayingFile) - return length; -#endif - - if (!buf || length <= 0) - return length; - - // - // Need to be sure Poll has been called for every frame: - // - cDevice can feed multiple frames after each poll from player/transfer. - // - If only part of frames are consumed, rest are fed again after next Poll. - // - If there are multiple clients it is possible first client(s) - // can queue more frames than last client(s). - // -> frame(s) are either lost immediately (last client(s)) - // or duplicated after next poll (first client(s)) - // - if(m_FreeBufs < 1) { - cPoller Poller; - if(!Poll(Poller,0)) { - errno = EAGAIN; - return 0; - } - } - - bool isMpeg1 = false; - if (DATA_IS_PES(buf)) { - isMpeg1 = pes_is_mpeg1(buf); - int len = pes_packet_len(buf, length); - if (len>0 && len != length) - LOGMSG("cXinelibDevice::PlayAny: invalid data !"); - } - - if(m_TrickSpeed > 0) { - if(PlayTrickSpeed(buf, length) < 0) - return 0; /* wait if data is coming in too fast */ - } else if(m_SkipAudio) { - /* needed for still images when moving cutting marks */ - if (DATA_IS_PES(buf)) - pes_change_pts((uchar*)buf, length, INT64_C(0)); - } - m_Cleared = false; - m_FreeBufs --; - - if(m_local) { - length = (isMpeg1 ? m_local->Play_Mpeg1_PES(buf,length) : - m_local->Play_PES(buf,length)); - } - if(m_server && length > 0) { - int length2 = isMpeg1 ? m_server->Play_Mpeg1_PES(buf, length) : - m_server->Play_PES(buf, length); - if(!m_local) - return length2; - } - - return length; -} - -#if VDRVERSNUM >= 10701 -/* - * hook to PlayTs() to get PAT and PMT - */ -int cXinelibDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly) -{ - if (Length > TS_SIZE) Length = TS_SIZE; - - if (Length == TS_SIZE && TsHasPayload(Data)) { - int PayloadOffset = TsPayloadOffset(Data); - if (PayloadOffset < Length) { - int Pid = TsPid(Data); - if (Pid == 0) { -#if VDRVERSNUM >= 10704 - m_PatPmtParser.ParsePat(Data, Length); -#else - m_PatPmtParser.ParsePat(Data + PayloadOffset, Length - PayloadOffset); -#endif - LOGMSG("Got PAT: PMT pid = %d", m_PatPmtParser.PmtPid()); - if (m_server) - m_server->SetHeader(Data, Length, true); - PlayTsAny(Data, Length); - } else if (Pid == m_PatPmtParser.PmtPid()) { -#if VDRVERSNUM >= 10704 - m_PatPmtParser.ParsePmt(Data, Length); -#else - m_PatPmtParser.ParsePmt(Data + PayloadOffset, Length - PayloadOffset); -#endif - m_h264 = (m_PatPmtParser.Vtype() == 0x1b); /* ISO_14496_PART10_VIDEO */ - LOGMSG("Got PMT packet, h264 = %d", m_h264?1:0); - if (m_server) - m_server->SetHeader(Data, Length); - PlayTsAny(Data, Length); - TsBufferFlush(); - } - } - } else if (!Data) { - TsBufferFlush(); - } - - return cDevice::PlayTs(Data, Length, VideoOnly); -} - -int cXinelibDevice::TsBufferFlush(void) -{ - if (m_TsBufSize) { - int n; - if ((n = PlayAny(m_TsBuf, m_TsBufSize)) == (int)m_TsBufSize) { - m_TsBufSize = 0; - return n; - } - if (n) - LOGMSG("cXinelibDevice::TsBufferFlush: error: cache not flushed (%d %d)", n, m_TsBufSize); - errno = EAGAIN; - } - return 0; -} - -int cXinelibDevice::PlayTsAny(const uchar *buf, int length) -{ - if (!DATA_IS_TS(buf)) - LOGMSG("PlayTsAny(): TS SYNC byte missing !"); - if (length != TS_SIZE) - LOGMSG("PlayTsAny(): length == %d !", length); - - // cache full ? try to flush it - if (m_TsBufSize >= 2048) - if (!TsBufferFlush()) - return 0; - - // add packet to cache - memcpy(m_TsBuf + m_TsBufSize, buf, length); - m_TsBufSize += length; - - // time to flush ? - if (m_TsBufSize >= 2048-TS_SIZE-1) - TsBufferFlush(); - - return length; -} - -int cXinelibDevice::PlayTsSubtitle(const uchar *Data, int Length) -{ - if (!xc.dvb_subtitles) - return cDevice::PlayTsSubtitle(Data, Length); - - return PlayTsAny(Data, Length); -} - -int cXinelibDevice::PlayTsAudio(const uchar *Data, int Length) -{ - return PlayTsAny(Data, Length); -} - -int cXinelibDevice::PlayTsVideo(const uchar *Data, int Length) -{ - return PlayTsAny(Data, Length); -} -#endif // VDRVERSNUM >= 10701 - -int cXinelibDevice::PlayVideo(const uchar *buf, int length) -{ - TRACEF("cXinelibDevice::PlayVideo"); - TRACK_TIME(100); - - if(m_PlayMode == pmAudioOnlyBlack) - return length; - - if (!DATA_IS_PES(buf)) { - LOGMSG("PlayVideo: data is not PES !"); - return length; - } - - if(m_RadioStream) { - m_RadioStream = false; - m_AudioCount = 0; - ForEach(m_clients, &cXinelibThread::SetNoVideo, m_RadioStream); - } - - if(m_StreamStart) { -#ifdef START_IFRAME - // Start with I-frame if stream has video - // wait for first I-frame - if (pes_get_picture_type(buf, length) == I_FRAME) { - m_StreamStart = false; - } else { - return length; - } -#endif - - if (!m_h264 && pes_is_frame_h264(buf, length)) { - LOGMSG("cXinelibDevice::PlayVideo: Detected H.264 video"); - m_h264 = true; - } - - if (pes_get_video_size(buf, length, m_VideoSize, m_h264 ? 1:0)) { - m_StreamStart = false; - LOGDBG("Detected video size %dx%d", m_VideoSize->width, m_VideoSize->height); - ForEach(m_clients, &cXinelibThread::SetHDMode, (m_VideoSize->width > 800)); - } - } - -#ifdef DEBUG_SWITCHING_TIME - if(m_statusMonitor->switchtimeOff && m_statusMonitor->switchtimeOn) { - if (pes_get_picture_type(buf, length) == I_FRAME) - m_statusMonitor->IFrame(); - } -#endif - - if(m_PlayingFile && (m_PlayingFile == pmAudioVideo || m_PlayingFile == pmVideoOnly)) - return length; - - return PlayAny(buf, length); -} - -void cXinelibDevice::StillPicture(const uchar *Data, int Length) -{ - TRACEF("cXinelibDevice::StillPicture"); - - // skip still images coming in too fast (ex. when moving cutting marks) - if(cRemote::HasKeys()) { - static int skipped = 0; - static uint64_t lastshow = 0; - uint64_t now = cTimeMs::Now(); - if(now - lastshow < 500) { - skipped++; - //LOGMSG("Skipping still image (coming in too fast)"); - return; - } - LOGDBG("Forcing still image - skipped %d images", skipped); - lastshow = now; - skipped = 0; - } - - bool isPes = DATA_IS_PES(Data) && ((Data[3] & 0xF0) == 0xE0); - bool isMpeg1 = isPes && ((Data[6] & 0xC0) != 0x80); - bool isH264 = isPes && pes_is_frame_h264(Data, Length); -#if VDRVERSNUM >= 10701 - bool isTs = DATA_IS_TS(Data); -#endif - - int i; - - if(m_PlayingFile && (m_PlayingFile == pmAudioVideo || m_PlayingFile == pmVideoOnly)) - return; - - TsBufferFlush(); - - ForEach(m_clients, &cXinelibThread::Clear); - ForEach(m_clients, &cXinelibThread::SetNoVideo, false); - ForEach(m_clients, &cXinelibThread::SetLiveMode, false); - ForEach(m_clients, &cXinelibThread::SetStillMode, true); - ForEach(m_clients, &cXinelibThread::TrickSpeed, 1); - - m_TrickSpeed = -1; // to make Poll work ... - m_SkipAudio = 1; // enables audio and pts stripping - - for(i=0; i<STILLPICTURE_REPEAT_COUNT; i++) - if(isMpeg1) { - ForEach(m_clients, &cXinelibThread::Play_Mpeg1_PES, Data, Length, - &mmin<int>, Length); - } else if(isPes) { - /*cDevice::*/PlayPes(Data, Length, m_SkipAudio); -#if VDRVERSNUM >= 10701 - } else if(isTs) { - /*cDevice::*/PlayTs(Data, Length, m_SkipAudio); -#endif - } else { - ForEach(m_clients, &cXinelibThread::Play_Mpeg2_ES, - Data, Length, VIDEO_STREAM, - &mand<bool>, true); - } - - if(!isH264) { - // creates empty video PES with pseudo-pts - ForEach(m_clients, &cXinelibThread::Play_Mpeg2_ES, - Data, 0, VIDEO_STREAM, - &mand<bool>, true); - } - - TsBufferFlush(); - - ForEach(m_clients, &cXinelibThread::Flush, 60, - &mand<bool>, true); - - m_TrickSpeed = 0; - m_SkipAudio = 0; -} - -int cXinelibDevice::PlayAudio(const uchar *buf, int length, uchar Id) -{ - TRACEF("cXinelibDevice::PlayAudio"); - TRACK_TIME(100); - - if(!buf || length < 6) - return length; - -#ifdef SKIP_AC3_AUDIO - // skip AC3 audio - if(((unsigned char *)buf)[3] == PRIVATE_STREAM1) { - TRACE("cXinelibDevice::PlayVideo: PRIVATE_STREAM1 discarded"); - return length; - } -#endif - - // strip audio in trick speed modes and when displaying still images - if(m_SkipAudio /*|| m_TrickSpeed > 0*/) - return length; - if(m_TrickSpeedMode & trs_NoAudio) - return length; - - if(m_RadioStream) { - if(m_AudioCount) { - m_AudioCount--; - if(!m_AudioCount) { - LOGDBG("PlayAudio detected radio stream"); - ForEach(m_clients, &cXinelibThread::SetNoVideo, m_RadioStream); - } - } - } - - if(m_PlayingFile && (m_PlayingFile == pmAudioVideo || m_PlayingFile == pmAudioOnly)) - return length; - - return PlayAny(buf, length); -} - -int cXinelibDevice::PlaySubtitle(const uchar *Data, int Length) -{ - if(!xc.dvb_subtitles) - return cDevice::PlaySubtitle(Data, Length); - return PlayAny(Data, Length); -} - -bool cXinelibDevice::Poll(cPoller &Poller, int TimeoutMs) -{ - TRACEF("cXinelibDevice::Poll"); - TRACK_TIME(400); - - if(m_PlayingFile == pmAudioVideo) - return true; - - if(m_TrickSpeed == 0) { - cCondWait::SleepMs(min(TimeoutMs, 20)); - return Poller.Poll(0); - } - - if(!m_local && !m_server) { - /* nothing to do... why do I exist ... ? */ - //cCondWait::SleepMs(TimeoutMs); - //return Poller.Poll(0); - return true; - } - - if(m_TrickSpeed > 1 && m_TrickSpeedDelay > 20) { - LOGTRICKSPEED(" Poll: m_TrickSpeedDelay=%d.", m_TrickSpeedDelay); - cCondWait::SleepMs(20); - m_TrickSpeedDelay -= 20; - return false; - } - - if(m_FreeBufs < 1) { - int result = DEFAULT_POLL_SIZE; - - if(m_local) - result = min(result, m_local->Poll(Poller, TimeoutMs)); - if(m_server) - result = min(result, m_server->Poll(Poller, TimeoutMs)); - - m_FreeBufs = max(result, 0); - } - - return m_FreeBufs > 0 /*|| Poller.Poll(0)*/; -} - -// -// Audio facilities -// - -void cXinelibDevice::SetVolumeDevice(int Volume) -{ - TRACEF("cXinelibDevice::SetVolumeDevice"); - - ForEach(m_clients, &cXinelibThread::SetVolume, Volume); -} - -void cXinelibDevice::SetAudioTrackDevice(eTrackType Type) -{ - TRACEF("cXinelibDevice::SetAudioTrackDevice"); - - // track changes are autodetected at xine side -} - -void cXinelibDevice::SetAudioChannelDevice(int AudioChannel) -{ - TRACEF("cXinelibDevice::SetAudioChannelDevice"); - - if(m_AudioChannel != AudioChannel) { - m_AudioChannel = AudioChannel; - //LOGDBG("cXinelibDevice::SetAudioChannelDevice --> %d", AudioChannel); -#if 0 - switch(AudioChannel) { - default: - //case 0: ConfigurePostprocessing("upmix_mono", false, NULL); - case 0: ConfigurePostprocessing("upmix_mono", true, "channel=-1"); - break; - case 1: ConfigurePostprocessing("upmix_mono", true, "channel=0"); - break; - case 2: ConfigurePostprocessing("upmix_mono", true, "channel=1"); - break; - } -#else - switch(AudioChannel) { - default: - case 0: ConfigurePostprocessing("audiochannel", false, NULL); - break; - case 1: ConfigurePostprocessing("audiochannel", true, "channel=0"); - break; - case 2: ConfigurePostprocessing("audiochannel", true, "channel=1"); - break; - } -#endif - } -} - -void cXinelibDevice::SetDigitalAudioDevice(bool On) -{ - TRACEF("cXinelibDevice::SetDigitalAudioDevice"); - - // track changes are autodetected at xine side -} - -// -// Video format facilities -// - -void cXinelibDevice::SetVideoFormat(bool VideoFormat16_9) -{ - TRACEF("cXinelibDevice::SetVideoFormat"); - cDevice::SetVideoFormat(VideoFormat16_9); - -#if 0 - // - // TODO - // - if(xc.aspect != ASPECT_AUTO && - xc.aspect != ASPECT_DEFAULT) { - if(VideoFormat16_9) - xc.aspect = ASPECT_16_9; - else if(xc.aspect == ASPECT_16_9) - xc.aspect = ASPECT_4_3; - ConfigureDecoder(,,,xc.aspect,,,); - } -#endif -} - -void cXinelibDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) -{ - TRACEF("cXinelibDevice::SetVideoDisplayFormat"); - cDevice::SetVideoDisplayFormat(VideoDisplayFormat); - -#if 0 - // - // TODO - // - // - set normal, pan&scan, letterbox (only for 4:3?) - // - if(xc.aspect != ASPECT_AUTO && - xc.aspect != ASPECT_DEFAULT) { - switch(VideoDisplayFormat) { - case vdfPanAndScan: - xc.aspect = ASPECT_PAN_SCAN; - break; - case vdfLetterBox: - xc.aspect = ASPECT_4_3; /* borders are added automatically if needed */ - break; - case vdfCenterCutOut: - xc.aspect = ASPECT_CENTER_CUT_OUT; - break; - } - ConfigureDecoder(,,,xc.aspect,,,); - } -#endif -} - -eVideoSystem cXinelibDevice::GetVideoSystem(void) -{ - TRACEF("cXinelibDevice::GetVideoSystem"); - return cDevice::GetVideoSystem(); -} - -#if VDRVERSNUM >= 10708 -void cXinelibDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect) -{ - Width = m_VideoSize->width; - Height = m_VideoSize->height; - VideoAspect = 1.0; - if (m_VideoSize->pixel_aspect.den) { - VideoAspect = (double)m_VideoSize->pixel_aspect.num / (double)m_VideoSize->pixel_aspect.den; - VideoAspect *= (double)Width / (double)Height; - } -} -#endif - -void cXinelibDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect) -{ - Width = 720; - Height = 576; - PixelAspect = 16.0 / 9.0 / (double)Width * (double)Height; -} - -// -// SPU decoder -// - -#ifdef FORWARD_DVD_SPUS -# include "spu_decoder.h" -#endif - -cSpuDecoder *cXinelibDevice::GetSpuDecoder(void) -{ - TRACEF("cXinelibDevice::GetSpuDecoder"); - if (!m_spuDecoder && IsPrimaryDevice()) { - // - // TODO - // - // - use own derived SpuDecoder with special cXinelibOsd - // -> always visible - // - -#ifdef FORWARD_DVD_SPUS - // forward DVD SPUs to xine without decoding - m_spuDecoder = new cFwdSpuDecoder(this); -#else - m_spuDecoder = new cDvbSpuDecoder(); -#endif - } - return m_spuDecoder; -} - -// -// Image Grabbing -// - -uchar *cXinelibDevice::GrabImage(int &Size, bool Jpeg, - int Quality, int SizeX, int SizeY) -{ - TRACEF("cXinelibDevice::GrabImage"); - - if(m_local) - return m_local->GrabImage(Size, Jpeg, Quality, SizeX, SizeY); - if(m_server) - return m_server->GrabImage(Size, Jpeg, Quality, SizeX, SizeY); - - return NULL; -} - - -// -// Available DVD SPU tracks -// - -void cXinelibDevice::SetSubtitleTrackDevice(eTrackType Type) -{ - if (m_PlayingFile == pmAudioVideo || m_PlayingFile == pmVideoOnly) - ForEach(m_clients, &cXinelibThread::SetSubtitleTrack, Type); -} - -// -// Metainfo -// - -const char *cXinelibDevice::GetMetaInfo(eMetainfoType Type) -{ - if(Type >= 0 && Type < mi_Count) { - if ((Type == miTitle) || - (Type == miTracknumber && xc.playlist_tracknumber == 1) || - (Type == miArtist && xc.playlist_artist == 1) || - (Type == miAlbum && xc.playlist_album == 1) || - (Type > miAlbum)) { - return m_MetaInfo[Type]; - } - return ""; - } - - LOGMSG("cXinelibDevice::GetMetaInfo: unknown metainfo type"); - return ""; -} - -void cXinelibDevice::SetMetaInfo(eMetainfoType Type, const char *Value) -{ - if(Type >= 0 && Type < mi_Count) { - /* set to 0 first, so if player is accessing string in middle of - copying it will always be 0-terminated (but truncated) */ - memset(m_MetaInfo[Type], 0, sizeof(m_MetaInfo[Type])); - strn0cpy(m_MetaInfo[Type], Value, MAX_METAINFO_LEN); - } else { - LOGMSG("cXinelibDevice::SetMetaInfo: unknown metainfo type"); - } -} - diff --git a/device.h b/device.h deleted file mode 100644 index 04f23f52..00000000 --- a/device.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * device.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: device.h,v 1.48 2009-06-24 20:43:45 phintuka Exp $ - * - */ - -#ifndef __XINELIB_DEVICE_H -#define __XINELIB_DEVICE_H - -#include <vdr/config.h> -#include <vdr/device.h> -#include <vdr/tools.h> - -class cXinelibStatusMonitor; -class cXinelibThread; -class cChannel; -class cFunctor; - -struct video_size_s; - -typedef enum { - miTitle = 0, - miTracknumber = 1, - miArtist = 2, - miAlbum = 3, - miDvdTitleNo = 4, - miDvdButtons = 5, - mi_Count = 6 -} eMetainfoType; - -# define ttXSubtitleNone (-2) -# define ttXSubtitleAuto (-1) - -#define MAX_METAINFO_LEN 63 - -class cXinelibDevice : public cDevice -{ - - // Singleton - - private: - static cXinelibDevice* m_pInstance; // singleton - cXinelibDevice(); // - cXinelibDevice(cXinelibDevice&); // no copy constructor - - public: - static cXinelibDevice& Instance(void); // singleton - static void Dispose(void); - - virtual ~cXinelibDevice(); - - // device start/stop (from cPlugin) - - public: - bool StartDevice(void); - void StopDevice(void); - - // function calls waiting to be executed in VDR main thread context - - private: - cList<cFunctor> m_MainThreadFunctors; - cMutex m_MainThreadLock; - - public: - void MainThreadHook(void); - - // Primary device switching - - private: - int m_OriginalPrimaryDevice; - int m_ForcePrimaryDeviceCnt; - - void ForcePrimaryDeviceImpl(bool On); - - public: - virtual void MakePrimaryDevice(bool On); - void ForcePrimaryDevice(bool On); - - // Device capabilities - - public: - virtual bool HasDecoder(void) const { return true; }; - virtual bool CanReplay(void) const { return true; }; - virtual bool HasIBPTrickSpeed(void) { return xc.ibp_trickspeed; } - - // Playback control - - private: - ePlayMode m_PlayMode; - int m_TrickSpeed; - int64_t m_TrickSpeedPts; - int m_TrickSpeedMode; - int m_TrickSpeedDelay; - - public: - virtual bool SetPlayMode(ePlayMode PlayMode); - ePlayMode GetPlayMode(void) const { return m_PlayMode; }; - - protected: - virtual void Clear(void); - virtual void Play(void); - virtual void TrickSpeed(int Speed); - virtual void Freeze(void); - virtual bool Flush(int TimeoutMs = 0); - virtual int64_t GetSTC(void); - - // Video format facilities - - public: - virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat); - virtual void SetVideoFormat(bool VideoFormat16_9); - virtual eVideoSystem GetVideoSystem(void); - - struct video_size_s *m_VideoSize; -#if VDRVERSNUM >= 10708 - virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect); -#endif - virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect); - - // Track facilities - - protected: - virtual void SetAudioTrackDevice(eTrackType Type); - public: - virtual void SetSubtitleTrackDevice(eTrackType Type); - - // Audio facilities - - private: - int m_AudioChannel; - - protected: - virtual int GetAudioChannelDevice(void) { return m_AudioChannel; } - virtual void SetAudioChannelDevice(int AudioChannel); - virtual void SetVolumeDevice(int Volume); - virtual void SetDigitalAudioDevice(bool On); - - // Image grabbing - - public: - virtual uchar *GrabImage(int &Size, bool Jpeg = true, - int Quality = -1, int SizeX = -1, int SizeY = -1); - - // SPU decoder - - private: - cSpuDecoder *m_spuDecoder; - - friend class cXineSpuDecoder; - - public: - virtual cSpuDecoder *GetSpuDecoder(void); - - // Messages from StatusMonitor: - - private: - cXinelibStatusMonitor *m_statusMonitor; - bool m_liveMode; - - public: - void SetTvMode(cChannel *Channel); - void SetReplayMode(void); - void StopOutput(void); - - // Osd Commands (from cXinelibOsd) - - public: - void OsdCmd(void *cmd); - - // Configuration - - private: - cList<cXinelibThread> m_clients; - cXinelibThread *m_server; - cXinelibThread *m_local; - - public: - void ConfigurePostprocessing(const char *deinterlace_method, - int audio_delay, - int audio_compression, - const int *audio_equalizer, - int audio_surround, - int speaker_type); - void ConfigurePostprocessing(const char *name, bool on = true, - const char *args = NULL); - void ConfigureVideo(int hue, int saturation, int brightness, int sharpness, - int noise_reduction, int contrast, int overscan, int vo_aspect_ratio); - // local mode: - void ConfigureWindow(int fullscreen, int width, int height, - int modeswitch, const char *modeline, - int aspect, int scale_video, int field_order); - void ConfigureDecoder(int pes_buffers); - // remote mode: - void Listen(bool activate, int port); - - // File playback - - private: - ePlayMode m_PlayingFile; - - public: - bool PlayFile(const char *Filename, int Position = 0, - bool LoopPlay = false, ePlayMode PlayMode = pmAudioVideo, - int TimeoutMs = -1); - int PlayFileCtrl(const char *Cmd, int TimeoutMs = -1); - bool EndOfStreamReached(void); - - // Metainfo cache - - private: - char m_MetaInfo[mi_Count][MAX_METAINFO_LEN+1]; - - public: - const char *GetMetaInfo(eMetainfoType Type); - void SetMetaInfo(eMetainfoType Type, const char *Value); - - // Stream data - - private: - bool m_ac3Present; - bool m_spuPresent; - bool m_RadioStream; - int m_AudioCount; - bool m_SkipAudio; - bool m_StreamStart; - int m_FreeBufs; - bool m_Cleared; - bool m_h264; - - int PlayAny(const uchar *Data, int Length); - int PlayTrickSpeed(const uchar *buf, int length); - - protected: - - virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); - - virtual void StillPicture(const uchar *Data, int Length); - - virtual int PlayVideo(const uchar *Data, int Length); - virtual int PlayAudio(const uchar *Data, int Length, uchar Id); - virtual int PlaySubtitle(const uchar *Data, int Length); - -#if VDRVERSNUM >= 10701 - cPatPmtParser m_PatPmtParser; - - /* join multiple TS packets to xineliboutput transport packet */ - uint8_t m_TsBuf[4096]; - uint m_TsBufSize; - int TsBufferFlush(void); - void TsBufferClear(void) { m_TsBufSize = 0; }; - - int PlayTsAny(const uchar *Data, int Length); - - virtual int PlayTsVideo(const uchar *Data, int Length); - virtual int PlayTsAudio(const uchar *Data, int Length); - virtual int PlayTsSubtitle(const uchar *Data, int Length); - virtual int PlayTs(const uchar *Data, int Length, bool VideoOnly = false); -#else - void TsBufferClear(void) {} - void TsBufferFlush(void) {} -#endif -}; - -#endif // __XINELIB_DEVICE_H diff --git a/dummy_player.c b/dummy_player.c deleted file mode 100644 index 8980e656..00000000 --- a/dummy_player.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * dummy_player.c: Player that does nothing (saves CPU time) - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: dummy_player.c,v 1.3 2007-10-15 00:15:07 phintuka Exp $ - * - */ - -#include <vdr/status.h> - -#include "dummy_player.h" -#include "tools/timer.h" - -#define STILLPICTURE_INTERVAL (5*1000) // 5 sec - -// -// cDummyPlayerControl -// - -extern const unsigned char v_mpg_vdrlogo[]; // vdrlogo_720x576.mpg.c -extern const int v_mpg_vdrlogo_length; // vdrlogo_720x576.mpg.c -//extern const unsigned char v_mpg_nosignal[];// nosignal_720x576.mpg.c -//extern const int v_mpg_nosignal_length; // nosignal_720x576.mpg.c -//extern const unsigned char v_mpg_black[]; // black_720x576.mpg.c -//extern const int v_mpg_black_length; // black_720x576.mpg.c - -class cDummyPlayer : public cPlayer { - protected: - virtual void Activate(bool On) - { - if(On) { - TimerHandler(); - CreateTimerEvent(this, &cDummyPlayer::TimerHandler, STILLPICTURE_INTERVAL); - } else { - CancelTimerEvents(this); - } - } - bool TimerHandler(void) - { - DeviceStillPicture(v_mpg_vdrlogo, v_mpg_vdrlogo_length); - //DeviceStillPicture(v_mpg_nosignal, v_mpg_nosignal_length); - //DeviceStillPicture(v_mpg_black, v_mpg_black_length); - return true; - } - - public: - cDummyPlayer(void) {}; - virtual ~cDummyPlayer() - { - Activate(false); - Detach(); - } -}; - -// -// cDummyPlayerControl -// - -cDummyPlayer *cDummyPlayerControl::m_Player = NULL; -cMutex cDummyPlayerControl::m_Lock; - -cDummyPlayerControl::cDummyPlayerControl(void) : - cControl(OpenPlayer()) -{ - cStatus::MsgReplaying(this, "none", NULL, true); -} - -cDummyPlayerControl::~cDummyPlayerControl() -{ - cStatus::MsgReplaying(this, NULL, NULL, false); - Close(); -} - -cDummyPlayer *cDummyPlayerControl::OpenPlayer(void) -{ - m_Lock.Lock(); - if(!m_Player) - m_Player = new cDummyPlayer; - m_Lock.Unlock(); - return m_Player; -} - -void cDummyPlayerControl::Close(void) -{ - m_Lock.Lock(); - if(m_Player) - delete m_Player; - m_Player = NULL; - m_Lock.Unlock(); -} - -eOSState cDummyPlayerControl::ProcessKey(eKeys Key) -{ - if(!ISMODELESSKEY(Key) || Key == kBack || Key == kStop) { - Close(); - return osEnd; - } - return osContinue; -} - diff --git a/dummy_player.h b/dummy_player.h deleted file mode 100644 index 9af28ba7..00000000 --- a/dummy_player.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * dummy_player.h: Player that does nothing (saves CPU time) - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: dummy_player.h,v 1.1 2006-06-03 09:50:54 phintuka Exp $ - * - */ - -#ifndef __DUMMY_PLAYER_H -#define __DUMMY_PLAYER_H - -#include <vdr/player.h> - -class cDummyPlayer; - -class cDummyPlayerControl : public cControl -{ - private: - static cDummyPlayer *m_Player; - static cMutex m_Lock; - - static cDummyPlayer *OpenPlayer(void); - - public: - cDummyPlayerControl(void); - virtual ~cDummyPlayerControl(); - - virtual void Show(void) {}; - virtual void Hide(void) {}; - virtual eOSState ProcessKey(eKeys Key); - - static void Close(void); - static bool IsOpen(void) {return m_Player != NULL;}; -}; - -#endif //__DUMMY_PLAYER_H - diff --git a/equalizer.c b/equalizer.c deleted file mode 100644 index 8762c88c..00000000 --- a/equalizer.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * equalizer.c: audio equalizer OSD control - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: equalizer.c,v 1.5 2008-11-20 11:46:30 rofafor Exp $ - * - */ - -#include <vdr/config.h> - -#include "config.h" -#include "device.h" -#include "equalizer.h" - -cEqualizer::cEqualizer() : cOsdObject() -{ - m_Values = new int[AUDIO_EQ_count]; - memcpy(m_Values, xc.audio_equalizer, sizeof(xc.audio_equalizer)); - m_Osd = NULL; - m_Current = 0; -} - -cEqualizer::~cEqualizer() -{ - delete m_Osd; - delete m_Values; -} - -#define OSD_W (220) -#define OSD_H (220) -#define OSD_X (720-50-OSD_W) -#define OSD_Y (576-50-OSD_H) -/* dvbdevice requires bpp*width to be n*8 */ - -#define ADJUST_MIN (-100) -#define ADJUST_MAX (100) -#define ADJUST_STEP (5) - -void cEqualizer::Show() -{ - tArea areas [] = { {0, 0, OSD_W - 1, OSD_H - 1, 4} }; - - m_Osd = cOsdProvider::NewOsd(OSD_X, OSD_Y, 0); - - if(m_Osd) { - if (m_Osd->CanHandleAreas(areas, sizeof(areas) / sizeof(tArea) ) == oeOk) { - m_Osd->SetAreas(areas, sizeof(areas) / sizeof(tArea)); - m_Osd->Flush(); - DrawBackground(); - DrawBar(0,true); - for(int i=1; i<AUDIO_EQ_count; i++) - DrawBar(i); - } - } -} - -eOSState cEqualizer::ProcessKey(eKeys key) -{ - eOSState state = cOsdObject::ProcessKey(key); - if (state == osUnknown) { - switch (key & ~k_Repeat) { - case kDown: - m_Values[m_Current] -= ADJUST_STEP; - if(m_Values[m_Current] < ADJUST_MIN) - m_Values[m_Current] = ADJUST_MIN; - DrawBar(m_Current,true); - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, xc.audio_compression, m_Values, xc.audio_surround, xc.speaker_type); - break; - case kUp: - m_Values[m_Current] += ADJUST_STEP; - if(m_Values[m_Current] > ADJUST_MAX) - m_Values[m_Current] = ADJUST_MAX; - DrawBar(m_Current,true); - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, xc.audio_compression, m_Values, xc.audio_surround, xc.speaker_type); - break; - case kLeft: - if(m_Current>0) { - DrawBar(m_Current); - m_Current--; - DrawBar(m_Current, true); - } - break; - case kRight: - if(m_Current+1 < AUDIO_EQ_count) { - DrawBar(m_Current); - m_Current++; - DrawBar(m_Current, true); - } - break; - case kBack: - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, xc.audio_compression, xc.audio_equalizer, xc.audio_surround, xc.speaker_type); - return osEnd; - case kOk: - memcpy(xc.audio_equalizer, m_Values, sizeof(xc.audio_equalizer)); - return osEnd; - } - } - - return state; -} - -#define COL_BORDER 0xffb0b0b0 -#define COL_BG 0x7f7f7f7f -#define COL_BAR 0xff000000 -#define COL_BAR_SEL 0xffff0000 -#define COL_BAR_ON 0xff00FF00 -#define COL_BAR_OFF 0xff000000 -#define COL_BAR_BORDER 0xff7f7f7f - -void cEqualizer::DrawBackground() -{ - // border - m_Osd->DrawRectangle(0, 0, OSD_W - 1, OSD_H - 1, COL_BORDER); - m_Osd->DrawRectangle(1, 1, OSD_W - 2, OSD_H - 2, COL_BORDER); - // background - m_Osd->DrawRectangle(2, 2, OSD_W - 3, OSD_H - 3, COL_BG); - // line - m_Osd->DrawRectangle(5, 10+100-1, OSD_W-6, 10+100, COL_BAR); - // commit - m_Osd->Flush(); -} - -void cEqualizer::DrawBar(int Index, bool Selected) -{ - // bar - if(Selected) - m_Osd->DrawRectangle(10+20*Index, 10, 10+20*Index+7, OSD_H - 10, COL_BAR_SEL); - else - m_Osd->DrawRectangle(10+20*Index, 10, 10+20*Index+7, OSD_H - 10, COL_BAR); - // off - m_Osd->DrawRectangle(12+20*Index, 10, 10+20*Index+5, OSD_H - 10, COL_BAR_OFF); - // on - if(m_Values[Index]>0) - m_Osd->DrawRectangle(12+20*Index, 10+100-m_Values[Index], 10+20*Index+5, 10+100, COL_BAR_ON); - else - m_Osd->DrawRectangle(12+20*Index, 10+100, 10+20*Index+5, 10+100-m_Values[Index], COL_BAR_ON); - // line - m_Osd->DrawRectangle(12+20*Index, 10+100-1, 10+20*Index+5, 10+100, COL_BAR_ON); - - m_Osd->Flush(); -} - - diff --git a/equalizer.h b/equalizer.h deleted file mode 100644 index e2c7a9fa..00000000 --- a/equalizer.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * equalizer.h: audio equalizer OSD control - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: equalizer.h,v 1.1 2006-06-03 09:50:54 phintuka Exp $ - * - */ - -#ifndef __EQUALIZER_H -#define __EQUALIZER_H - -#include <vdr/config.h> -#include <vdr/osdbase.h> - -class cEqualizer : public cOsdObject -{ - private: - int *m_Values; - int m_Current; - - cOsd *m_Osd; - - public: - cEqualizer(); - virtual ~cEqualizer(); - - virtual void Show(); - virtual eOSState ProcessKey(eKeys Key); - - void DrawBackground(void); - void DrawBar(int Index, bool Selected = false); -}; - -#endif // __EQUALIZER_H_ diff --git a/examples/Live Radio/BBC Radio 4 Live.m3u b/examples/Live Radio/BBC Radio 4 Live.m3u deleted file mode 100755 index daebab2f..00000000 --- a/examples/Live Radio/BBC Radio 4 Live.m3u +++ /dev/null @@ -1,4 +0,0 @@ -#EXTM3U
-#EXTINF:111,BBC Radio 4 Live
-rtsp://rmlivev8bb.bbc.net.uk/farm/*/ev7/live24/radio4/live/r4_dsat_g2.ra
-
diff --git a/examples/Live Radio/BBC World Service.ram b/examples/Live Radio/BBC World Service.ram deleted file mode 100644 index 0a706198..00000000 --- a/examples/Live Radio/BBC World Service.ram +++ /dev/null @@ -1 +0,0 @@ -rtsp://rmlivev8.bbc.net.uk/farm/*/ev7/live24/worldservice/liveinfent.ra diff --git a/examples/remote.conf.example b/examples/remote.conf.example deleted file mode 100644 index df13bc33..00000000 --- a/examples/remote.conf.example +++ /dev/null @@ -1,63 +0,0 @@ -LIRC.Up up -LIRC.Down down -LIRC.Left left -LIRC.Right right -LIRC.Menu menu -LIRC.Ok ok -LIRC.Back exit -KBD.Up 00000000001B5B41 -KBD.Down 00000000001B5B42 -KBD.Menu 000000000000006D -KBD.Ok 000000000000000D -KBD.Back 0000000000000062 -KBD.Left 00000000001B5B44 -KBD.Right 00000000001B5B43 -XKeySym.Up Up -XKeySym.Down Down -XKeySym.Left Left -XKeySym.Right Right -XKeySym.Menu F1 -XKeySym.Ok Return -XKeySym.Back BackSpace -XKeySym.Red F2 -XKeySym.Green F3 -XKeySym.Yellow F4 -XKeySym.Blue F5 -XKeySym.0 0 -XKeySym.1 1 -XKeySym.2 2 -XKeySym.3 3 -XKeySym.4 4 -XKeySym.5 5 -XKeySym.6 6 -XKeySym.7 7 -XKeySym.8 8 -XKeySym.9 9 -XKeySym.Play p -XKeySym.Pause space -XKeySym.Stop s -XKeySym.FastFwd f -XKeySym.FastRew b -XKeySym.Channel+ Prior -XKeySym.Channel- Next -XKeySym.Volume+ KP_Add -XKeySym.Volume- KP_Subtract -XKeySym.Mute m -XKeySym.Info I -XKeySym.Audio A -XKeySym.Subtitles S -XKeySym.Schedule F6 -XKeySym.Channels F7 -XKeySym.Timers F8 -XKeySym.Recordings F9 -XKeySym.Setup F10 -XKeySym.Commands F11 -XKeySym.User1 q -XKeySym.User2 w -XKeySym.User3 e -XKeySym.User4 r -XKeySym.User5 t -XKeySym.User6 y -XKeySym.User7 u -XKeySym.User8 i -XKeySym.User9 o diff --git a/frontend.c b/frontend.c deleted file mode 100644 index 9a45d2c7..00000000 --- a/frontend.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * frontend.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: frontend.c,v 1.69 2009-05-29 14:31:46 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS -#include <inttypes.h> - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <sys/types.h> -#include <unistd.h> -#include <time.h> -#include <pthread.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <netdb.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/plugin.h> - -#include "logdefs.h" -#include "config.h" -#include "frontend.h" -#include "device.h" - -#include "tools/pes.h" -#include "tools/mpeg.h" -#include "tools/h264.h" -#include "tools/general_remote.h" -#include "tools/iso639.h" - -//#define LOG_CONTROL_MESSAGES -//#define XINELIBOUTPUT_LOG_KEYS - -#ifndef STARTUP_IMAGE_FILE -# define STARTUP_IMAGE_FILE "/usr/share/vdr/xineliboutput/logo.mpv" -#endif -#ifndef STARTUP_MAX_SIZE -# define STARTUP_MAX_SIZE (256*1024) -#endif - -//----------------------------- cXinelibThread -------------------------------- - -// -// keyboard control handler -// - -/*static*/ -void cXinelibThread::KeypressHandler(const char *keymap, const char *key, - bool repeat, bool release) -{ -#ifdef XINELIBOUTPUT_LOG_KEYS - static FILE *flog = fopen("/video/keys.log","w"); - if (flog) { - fprintf(flog,"KEY %s %s %d %d\n",keymap,key,repeat,release); fflush(flog); - } -#endif - - TRACE("keypress_handler: " << (keymap?keymap:"") << " " << key); - - if(!key) - return; - - if(keymap) { - cRemote *item = Remotes.First(); - while(item) { - if(!strcmp(item->Name(), keymap)) { - // dirty... but only way to support learning ... - ((cGeneralRemote*)item)->Put(key, repeat, release); - return; - } - item = Remotes.Next(item); - } - cGeneralRemote *r = new cGeneralRemote(keymap); - if(*key) - r->Put(key, repeat, release); - } else { - cRemote::Put(cKey::FromString(key)); - } -} - -#include <vdr/status.h> -class cFrontendStatusMonitor : public cStatus { - private: - bool& m_SpuLangAuto; - public: - cFrontendStatusMonitor(bool& SpuLangAuto) : m_SpuLangAuto(SpuLangAuto) {}; - virtual void SetSubtitleTrack(int /*Index*/, const char * const */*Tracks*/) { m_SpuLangAuto = false; } -}; - -void cXinelibThread::InfoHandler(const char *info) -{ - char *pmap = strdup(info), *map = pmap, *pt; - - if(NULL != (pt=strchr(map, '\r'))) - *pt = 0; - - if(!strncmp(info, "TRACKMAP SPU", 12)) { - int CurrentTrack = ttXSubtitleAuto; - map += 12; - while(*map) { - bool Current = false; - while(*map == ' ') map++; - if(*map == '*') { - Current = true; - map++; - if (*map == '-') { - CurrentTrack = atoi(map); - while (*map && *map != ' ') map++; - continue; - } - } - if(*map >= '0' && *map <= '9') { - int id = atoi(map); - while(*map && *map != ':') map++; - if(*map == ':') map++; - char *lang = map; - while(*map && *map != ' ') map++; - if(*map == ' ') { *map = 0; map++; }; - cXinelibDevice::Instance().SetAvailableTrack(ttSubtitle, id, id+1, iso639_2_to_iso639_1(lang)); - if (Current) - CurrentTrack = id; - } - } - if (CurrentTrack == ttXSubtitleAuto) - cXinelibDevice::Instance().EnsureSubtitleTrack(); - else if (CurrentTrack == ttXSubtitleNone) - cXinelibDevice::Instance().SetCurrentSubtitleTrack(ttNone, true); - else - cXinelibDevice::Instance().SetCurrentSubtitleTrack(eTrackType(CurrentTrack+ttSubtitleFirst), true); - } - - else if(!strncmp(info, "TRACKMAP AUDIO", 14)) { - map += 14; - cXinelibDevice::Instance().ClrAvailableTracks(); - while(*map) { - bool Current = false; - while(*map == ' ') map++; - if(*map == '*') { - Current = true; - map++; - } - int id = atoi(map); - while(*map && *map != ':') map++; - if(*map == ':') map++; - char *lang = map; - while(*map && *map != ' ') map++; - if(*map == ' ') { *map = 0; map++; }; - cXinelibDevice::Instance().SetAvailableTrack(ttDolby, id, ttDolby+id, iso639_2_to_iso639_1(lang)); - if(Current) - cXinelibDevice::Instance().SetCurrentAudioTrack((eTrackType)(ttDolby+id)); - } - } - - else if(!strncmp(info, "METAINFO", 8)) { - map += 8; - while(*map) { - while(*map == ' ') map++; - char *next = strstr(map, "=@"); - if(!next) - break; - *next = 0; - next += 2; - char *end = strstr(next, "@"); - if(!end) - break; - *end = 0; - - if(!strcmp(map, "title")) - cXinelibDevice::Instance().SetMetaInfo(miTitle, next); - if(!strcmp(map, "tracknumber")) - cXinelibDevice::Instance().SetMetaInfo(miTracknumber, next); - if(!strcmp(map, "album")) - cXinelibDevice::Instance().SetMetaInfo(miAlbum, next); - if(!strcmp(map, "artist")) - cXinelibDevice::Instance().SetMetaInfo(miArtist, next); - map = end+1; - } - } - - else if(!strncmp(info, "DVDBUTTONS ", 11)) { - map += 11; - while(*map == ' ') map++; - cXinelibDevice::Instance().SetMetaInfo(miDvdButtons, map); - } - - else if(!strncmp(info, "TITLE ", 6)) { - map += 6; - while(*map == ' ') map++; - cXinelibDevice::Instance().SetMetaInfo(miTitle, map); - } - - else if(!strncmp(info, "DVDTITLE ", 9)) { - map += 9; - while(*map == ' ') map++; - cXinelibDevice::Instance().SetMetaInfo(miDvdTitleNo, map); - if (*map == '0') // DVD Menu, set spu track to 0 - cXinelibDevice::Instance().SetCurrentSubtitleTrack(ttSubtitleFirst); - } - - free(pmap); -} - -cXinelibThread::cXinelibThread(const char *Description) : cThread(Description) -{ - TRACEF("cXinelibThread::cXinelibThread"); - - m_Volume = 255; - m_bStopThread = false; - m_bReady = false; - m_bIsFinished = false; - m_bNoVideo = true; - m_bLiveMode = true; /* can't be replaying when there is no output device */ - m_StreamPos = 0; - m_Frames = 0; - m_bEndOfStreamReached = false; - m_bPlayingFile = false; - m_StatusMonitor = NULL; -} - -cXinelibThread::~cXinelibThread() -{ - TRACEF("cXinelibThread::~cXinelibThread"); - - m_bStopThread = true; - if(Active()) - Cancel(); - if(m_StatusMonitor) - delete m_StatusMonitor; -} - -// -// Thread control -// - -void cXinelibThread::Start(void) -{ - TRACEF("cXinelibThread::Start"); - - cThread::Start(); -} - -void cXinelibThread::Stop(void) -{ - TRACEF("cXinelibThread::Stop"); - - SetStopSignal(); - - //if(Active()) - Cancel(5); -} - -void cXinelibThread::SetStopSignal(void) -{ - TRACEF("cXinelibThread::SetStopSignal"); - - LOCK_THREAD; - m_bStopThread = true; -} - -bool cXinelibThread::GetStopSignal(void) -{ - TRACEF("cXinelibThread::GetStopSignal"); - - LOCK_THREAD; - return m_bStopThread; -} - -bool cXinelibThread::IsReady(void) -{ - LOCK_THREAD; - return m_bReady; -} - -bool cXinelibThread::IsFinished(void) -{ - LOCK_THREAD; - return m_bIsFinished; -} - -// -// Playback control -// - -void cXinelibThread::SetVolume(int NewVolume) -{ - m_Volume = NewVolume; - cString str = cString::sprintf("VOLUME %d%s", NewVolume * 100 / 255, - xc.sw_volume_control ? " SW" : ""); - Xine_Control(str); -} - -void cXinelibThread::TrickSpeed(int Speed) -{ - TRACEF("cXinelibThread::TrickSpeed"); - - Xine_Control("TRICKSPEED", Speed); -} - -void cXinelibThread::SetLiveMode(bool LiveModeOn) -{ - TRACEF("cXinelibThread::SetLiveMode"); - - Lock(); - if(m_bLiveMode == LiveModeOn) { - Unlock(); - return; - } - m_bLiveMode = LiveModeOn; - Unlock(); - - Xine_Control("LIVE", m_bLiveMode ? 1 : 0); -} - -void cXinelibThread::SetStillMode(bool StillModeOn) -{ - TRACEF("cXinelibThread::SetStillMode"); - Xine_Control("STILL", StillModeOn ? 1 : 0); -} - -void cXinelibThread::SetNoVideo(bool bVal) -{ - TRACEF("cXinelibThread::SetNoVideo"); - - Lock(); - if(m_bNoVideo == bVal) { - Unlock(); - return; - } - m_bNoVideo = bVal; - Unlock(); - - Xine_Control("NOVIDEO", m_bNoVideo ? 1 : 0); - - char *opts = NULL; - if(xc.audio_vis_goom_opts[0] && !strcmp(xc.audio_visualization, "goom")) - opts = xc.audio_vis_goom_opts; - - if(m_bNoVideo && strcmp(xc.audio_visualization, "none")) { - ConfigurePostprocessing(xc.audio_visualization, true, opts); - } else { - ConfigurePostprocessing("AudioVisualization", false, NULL); - } -} - -void cXinelibThread::AudioStreamChanged(bool ac3, int StreamId) -{ - TRACEF("cXinelibThread::AudioStreamChanged"); - if(ac3) - Xine_Control("AUDIOSTREAM AC3", StreamId); - else - Xine_Control("AUDIOSTREAM", StreamId); -} - -void cXinelibThread::SetSubtitleTrack(eTrackType Track) -{ - TRACEF("cXinelibThread::SetSubtitleTrack"); - cString buf = cString::sprintf("SPUSTREAM %d%s", - Track==ttNone ? ttXSubtitleNone : (Track - ttSubtitleFirst), - m_SpuLangAuto ? " auto" : ""); - Xine_Control(buf); -} - -void cXinelibThread::Clear(void) -{ - TRACEF("cXinelibThread::Clear"); - - Lock(); - int64_t tmp1 = m_StreamPos; - uint32_t tmp2 = m_Frames; - Unlock(); - - char buf[128]; - snprintf(buf, sizeof(buf), "DISCARD %" PRId64 " %d", tmp1, tmp2); - /* Send to control stream and data stream. If message is sent only to - * control stream, and it is delayed, engine flush will be skipped. - */ - Xine_Control(buf); - Xine_Control_Sync(buf); -} - -bool cXinelibThread::Flush(int TimeoutMs) -{ - TRACEF("cXinelibThread::Flush"); - - return Xine_Control("FLUSH", TimeoutMs) <= 0; -} - -int cXinelibThread::Poll(cPoller& Poller, int TimeoutMs) -{ - TRACEF("cXinelibThread::Poll"); - - if(!m_bReady) { - if(TimeoutMs>0) - cCondWait::SleepMs(TimeoutMs); - if(!m_bReady) - return 0; - } - - int n = Xine_Control("POLL", TimeoutMs); - - return max(n, 0); -} - -// -// Data transfer -// - -int cXinelibThread::Play_PES(const uchar *data, int len) -{ - Lock(); - m_StreamPos += len; - m_Frames++; - /*m_bEndOfStreamReached = false;*/ - Unlock(); - return len; -} - -// -// Stream conversions -// - -// Convert MPEG1 PES headers to MPEG2 PES headers - -int cXinelibThread::Play_Mpeg1_PES(const uchar *data1, int len) -{ - if(!data1[0] && !data1[1] && data1[2] == 0x01 && len>7 && /* header sync bytes */ - ( IS_VIDEO_PACKET(data1) || IS_AUDIO_PACKET(data1)) && /* video / audio / ps1 stream */ - ((data1[6] & 0xC0) != 0x80) && /* really mpeg1 pes */ - (len == ((data1[4]<<8) | data1[5]) + 6)) { /* whole PES packet and nothing else */ - uchar *data2 = new uchar[len+64]; - int i1=0, i2=0, r=0; - - data2[i2++]=data1[i1++]; // 00 (sync) - data2[i2++]=data1[i1++]; // 00 (sync) - data2[i2++]=data1[i1++]; // 01 (sync) - data2[i2++]=data1[i1++]; // stream ID - data2[i2++]=data1[i1++]; // len hi - data2[i2++]=data1[i1++]; // len lo - - // skip stuffing - while ((data1[i1] & 0x80) == 0x80) - i1++; - - if ((data1[i1] & 0xc0) == 0x40) { - // skip STD_buffer_scale, STD_buffer_size - i1 += 2; - } - - if(len<i1+5) return len; - - data2[i2++] = 0x80; - - if ((data1[i1] & 0xf0) == 0x20) { - /* PTS */ - data2[i2++] = 0x80; - data2[i2++] = 5; - data2[i2++] = data1[i1++] & 0x0E; - data2[i2++] = data1[i1++] & 0xFF; - data2[i2++] = data1[i1++] & 0xFE; - data2[i2++] = data1[i1++] & 0xFF; - data2[i2++] = data1[i1++] & 0xFE; - } - else if ((data1[i1] & 0xf0) == 0x30) { - /* PTS & DTS */ - data2[i2++] = 0x80|0x40; - data2[i2++] = 10; - data2[i2++] = data1[i1++] & 0x0E; - data2[i2++] = data1[i1++] & 0xFF; - data2[i2++] = data1[i1++] & 0xFE; - data2[i2++] = data1[i1++] & 0xFF; - data2[i2++] = data1[i1++] & 0xFE; - - data2[i2++] = data1[i1++] & 0x0E; - data2[i2++] = data1[i1++] & 0xFF; - data2[i2++] = data1[i1++] & 0xFE; - data2[i2++] = data1[i1++] & 0xFF; - data2[i2++] = data1[i1++] & 0xFE; - } else { - i1++; - data2[i2++] = 0; /* no pts, no dts */ - data2[i2++] = 0; /* header len */ - } - - int newlen = ((data1[4]<<8) | data1[5]) + (i2-i1), loops=0; - data2[4] = ((newlen)&0xff00)>>8; - data2[5] = ((newlen)&0xff); - if(len-i1 > 0) { - memcpy(data2+i2, data1+i1, len-i1); - cPoller p; - while(!Poll(p,100) && loops++ < 10) { - LOGDBG("Play_Mpeg1_PES: poll failed"); - } - r = Play_PES(data2,newlen+6); - } - - delete data2; - return r==newlen+6 ? ((data1[4]<<8)|data1[5])+6 : 0; - } - return len; // nothing useful found ... -} - -// Pack elementary MPEG stream to PES - -bool cXinelibThread::Play_Mpeg2_ES(const uchar *data, int len, int streamID) -{ - static uchar hdr_vid[] = {0x00,0x00,0x01,0xe0, 0x00,0x00,0x80,0x00,0x00}; /* mpeg2 */ - static uchar hdr_pts[] = {0x00,0x00,0x01,0xe0, 0x00,0x08,0x80,0x80, - 0x05,0x00,0x00,0x00, 0x00,0x00}; /* mpeg2 */ - static uchar seq_end[] = {0x00,0x00,0x01,0xe0, 0x00,0x07,0x80,0x00, - 0x00, - 0x00,0x00,0x01,0xB7}; /* mpeg2 */ - int todo = len, done = 0, hdrlen = 9/*sizeof(hdr)*/; - uchar *frame = new uchar[PES_CHUNK_SIZE+32]; - cPoller p; - bool h264 = IS_NAL_AUD(data); - - hdr_pts[3] = (uchar)streamID; - Poll(p, 100); - Play_PES(hdr_pts, sizeof(hdr_pts)); - - hdr_vid[3] = (uchar)streamID; - while(todo) { - int blocklen = todo; - if(blocklen > ((PES_CHUNK_SIZE - hdrlen) & 0xfffc)) - blocklen = (PES_CHUNK_SIZE - hdrlen) & 0xfffc; - hdr_vid[4] = ((blocklen+3)&0xff00)>>8; - hdr_vid[5] = ((blocklen+3)&0xff); - - memcpy(frame, hdr_vid, hdrlen); - memcpy(frame+hdrlen, data+done, blocklen); - - done += blocklen; - todo -= blocklen; - - Poll(p, 100); - - if(blocklen+hdrlen != Play_PES(frame,blocklen+hdrlen)) { - delete frame; - return false; - } - } - - // append sequence end code to video - if((streamID & 0xF0) == 0xE0) { - seq_end[3] = (uchar)streamID; - seq_end[12] = h264 ? NAL_END_SEQ : 0xB7; - Poll(p, 100); - Play_PES(seq_end, sizeof(seq_end)); - } - - delete[] frame; - return true; -} - -// -// Built-in still images -// - -bool cXinelibThread::QueueBlankDisplay(void) -{ - TRACEF("cXinelibThread::BlankDisplay"); -#if 0 - extern const unsigned char v_mpg_black[]; // black_720x576.c - extern const int v_mpg_black_length; - - Play_Mpeg2_ES(v_mpg_black, v_mpg_black_length, VIDEO_STREAM); -#endif - Xine_Control_Sync("BLANK"); - return true; -} - -bool cXinelibThread::BlankDisplay(void) -{ - TRACEF("cXinelibThread::BlankDisplay"); - - bool r = QueueBlankDisplay(); - for(int i=0; i<5 && !Flush(100); i++) - ; - return r; -} - -bool cXinelibThread::LogoDisplay(void) -{ - TRACEF("cXinelibThread::LogoDisplay"); - - cString Path; - int fd = -1; - - if(Setup.FileName()) { - cString SetupPath = Setup.FileName(); - const char *end = strrchr(SetupPath, '/'); - if(end) { - SetupPath.Truncate(end - (const char *)SetupPath); - fd = open(Path=cString::sprintf("%s/plugins/xineliboutput/logo.mpv", *SetupPath), O_RDONLY); - } - } - - if(fd<0) - fd = open(Path=STARTUP_IMAGE_FILE, O_RDONLY); - - if(fd >= 0) { - uint8_t *data = (uint8_t*)malloc(STARTUP_MAX_SIZE); - int datalen = read(fd, data, STARTUP_MAX_SIZE); - if(datalen == STARTUP_MAX_SIZE) { - LOGMSG("WARNING: custom startup image %s too large", *Path); - } else if(datalen<=0) { - LOGERR("error reading custom startup image %s", *Path); - } else { - LOGMSG("using custom startup image %s", *Path); - bool r = Play_Mpeg2_ES(data, datalen, VIDEO_STREAM); - free(data); - for(int i=0; i<5 && !Flush(100); i++) - ; - return r; - } - free(data); - close(fd); - } - - /* use default image */ - extern const unsigned char v_mpg_vdrlogo[]; // vdrlogo_720x576.c - extern const int v_mpg_vdrlogo_length; - - bool r = Play_Mpeg2_ES(v_mpg_vdrlogo, v_mpg_vdrlogo_length, VIDEO_STREAM); - for(int i=0; i<5 && !Flush(100); i++) - ; - return r; -} - -bool cXinelibThread::NoSignalDisplay(void) -{ - TRACEF("cXinelibThread::NoSignalDisplay"); - - extern const unsigned char v_mpg_nosignal[]; // nosignal_720x576.c - extern const int v_mpg_nosignal_length; - - bool r = Play_Mpeg2_ES(v_mpg_nosignal, v_mpg_nosignal_length, VIDEO_STREAM); - for(int i=0; i<5 && !Flush(100); i++) - ; - return r; -} - -// -// Xine Control -// - -int cXinelibThread::Xine_Control(const char *cmd, int p1) -{ - char buf[128]; - if(snprintf(buf, sizeof(buf), "%s %d", cmd, p1) >= (int)sizeof(buf)) { - LOGMSG("Xine_Control %s: message too long !", cmd); - return 0; - } - //buf[sizeof(buf)-1] = 0; - return Xine_Control(buf); -} - -int cXinelibThread::Xine_Control(const char *cmd, int64_t p1) -{ - char buf[128]; - if(snprintf(buf, sizeof(buf), "%s %" PRId64, cmd, p1) >= (int)sizeof(buf)) { - LOGMSG("Xine_Control %s: message too long !", cmd); - return 0; - } - //buf[sizeof(buf)-1] = 0; - return Xine_Control(buf); -} - -int cXinelibThread::Xine_Control(const char *cmd, const char *p1) -{ - char buf[1024]; - if(snprintf(buf, sizeof(buf), "%s %s", cmd, p1) >= (int)sizeof(buf)) { - LOGMSG("Xine_Control %s: message too long !", cmd); - return 0; - } - //buf[sizeof(buf)-1] = 0; - return Xine_Control(buf); -} - -bool cXinelibThread::PlayFile(const char *FileName, int Position, - bool LoopPlay, ePlayMode PlayMode, - int TimeoutMs) -{ - TRACEF("cXinelibThread::PlayFile"); - - char vis[256]; - - switch(PlayMode) { - case pmVideoOnly: - LOGDBG("cXinelibThread::PlayFile: Video from file, audio from VDR"); - strcpy(vis, "Video"); - break; - case pmAudioOnly: - LOGDBG("cXinelibThread::PlayFile: Audio from file, video from VDR"); - strcpy(vis, "Audio"); - break; - case pmAudioOnlyBlack: - //LOGDBG("cXinelibThread::PlayFile: Audio from file, no video"); - strcpy(vis, "none"); - break; - case pmAudioVideo: - default: - if(xc.audio_vis_goom_opts[0] && !strcmp(xc.audio_visualization, "goom")) - snprintf(vis, sizeof(vis), "%s:%s", xc.audio_visualization, xc.audio_vis_goom_opts); - else - strn0cpy(vis, xc.audio_visualization, sizeof(vis)); - vis[sizeof(vis)-1] = 0; - break; - } - - char buf[4096]; - m_bEndOfStreamReached = false; - if(snprintf(buf, sizeof(buf), "PLAYFILE %s %d %s %s", - LoopPlay ? "Loop" : "", Position, vis, FileName ? FileName : "") - >= 4096) { - LOGMSG("PlayFile: message too long !"); - return 0; - } - - if(FileName) { - Lock(); - m_FileName = FileName; - m_bPlayingFile = true; - m_SpuLangAuto = true; - if (m_StatusMonitor) - DELETENULL(m_StatusMonitor); - m_StatusMonitor = new cFrontendStatusMonitor(m_SpuLangAuto); - Unlock(); - } - - int result = PlayFileCtrl(buf, TimeoutMs); - - if(!FileName || result != 0) { - Lock(); - m_bPlayingFile = false; - m_FileName = NULL; - if (m_StatusMonitor) - DELETENULL(m_StatusMonitor); - Unlock(); - } else { - if(xc.extsub_size >= 0) - Xine_Control("EXTSUBSIZE", xc.extsub_size); - - // set preferred subtitle language - if (Setup.DisplaySubtitles) { - const char *langs = I18nLanguageCode(Setup.SubtitleLanguages[0]); - if (langs) { - char lang1[5]; - strn0cpy(lang1, langs, 4); /* truncate */ - const char *spu_lang = iso639_1_to_iso639_2(lang1); - LOGMSG("Preferred SPU language: %s (%s)", lang1, spu_lang); - if (spu_lang && spu_lang[0] && spu_lang[1] && !spu_lang[2]) - Xine_Control(cString::sprintf("SPUSTREAM %s", spu_lang)); - } - } else { - LOGMSG("Preferred SPU language: (none)"); - Xine_Control(cString::sprintf("SPUSTREAM %d", ttXSubtitleNone)); - } - } - - return (!GetStopSignal()) && (result==0); -} - - -// -// Configuration -// - -void cXinelibThread::Configure(void) -{ - ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, - xc.audio_compression, xc.audio_equalizer, - xc.audio_surround, xc.speaker_type); - ConfigureVideo(xc.hue, xc.saturation, xc.brightness, xc.sharpness, xc.noise_reduction, xc.contrast, xc.overscan, xc.vo_aspect_ratio); - ConfigurePostprocessing("upmix", xc.audio_upmix ? true : false, NULL); - ConfigurePostprocessing("autocrop", xc.autocrop ? true : false, - xc.AutocropOptions()); - ConfigurePostprocessing("swscale", xc.swscale ? true : false, - xc.SwScaleOptions()); - ConfigurePostprocessing("pp", xc.ffmpeg_pp ? true : false, - xc.FfmpegPpOptions()); - ConfigurePostprocessing("unsharp",xc.unsharp ? true : false, - xc.UnsharpOptions()); - ConfigurePostprocessing("denoise3d",xc.denoise3d ? true : false, - xc.Denoise3dOptions()); - -#ifdef ENABLE_TEST_POSTPLUGINS - ConfigurePostprocessing("headphone", xc.headphone ? true : false, NULL); -#endif - - Xine_Control(cString::sprintf("SCR %s %d", - xc.live_mode_sync ? "Sync" : "NoSync", - xc.scr_tuning ? xc.scr_hz : 90000)); -} - -int cXinelibThread::ConfigurePostprocessing(const char *deinterlace_method, - int audio_delay, - int audio_compression, - const int *audio_equalizer, - int audio_surround, - int speaker_type) -{ - char buf[1024]; - int r = true; - - if(strcmp(deinterlace_method, "tvtime")) - r = ConfigurePostprocessing("tvtime", false, NULL) && r; - - r = Xine_Control("DEINTERLACE", deinterlace_method) && r; - r = Xine_Control("AUDIODELAY", audio_delay) && r; - r = Xine_Control("AUDIOCOMPRESSION", audio_compression) && r; - r = Xine_Control("AUDIOSURROUND", audio_surround) && r; - r = Xine_Control("SPEAKERS", speaker_type) && r; - sprintf(buf,"EQUALIZER %d %d %d %d %d %d %d %d %d %d", - audio_equalizer[0],audio_equalizer[1], - audio_equalizer[2],audio_equalizer[3], - audio_equalizer[4],audio_equalizer[5], - audio_equalizer[6],audio_equalizer[7], - audio_equalizer[8],audio_equalizer[9]); - r = Xine_Control(buf) && r; - - if(m_bNoVideo && strcmp(xc.audio_visualization, "none")) { - char *opts = NULL; - if(xc.audio_vis_goom_opts[0] && !strcmp(xc.audio_visualization, "goom")) - opts = xc.audio_vis_goom_opts; - //fe->post_open(fe, xc.audio_visualization, NULL); - r = ConfigurePostprocessing(xc.audio_visualization, true, opts) && r; - } else { - //fe->post_close(fe, NULL, 0); - r = ConfigurePostprocessing("AudioVisualization", false, NULL) && r; - } - - if(!strcmp(deinterlace_method, "tvtime")) - r = ConfigurePostprocessing("tvtime", true, xc.deinterlace_opts) && r; - - return r; -} - -int cXinelibThread::ConfigurePostprocessing(const char *name, bool on, const char *args) -{ - char buf[1024]; - int l; - - if(on) - l = snprintf(buf, sizeof(buf), "POST %s On %s", (name&&*name)?name:"0", args?args:""); - else - // 0 - audio vis. - // 1 - audio post - // 2 - video post - //return fe->post_close(fe, name, -1); - l = snprintf(buf, sizeof(buf), "POST %s Off", (name&&*name)?name:"0"); - - if(l >= (int)sizeof(buf)) { - LOGMSG("ConfigurePostprocessing %s: message too long !", name); - return 0; - } - //buf[sizeof(buf)-1] = 0; - - return Xine_Control(buf); -} - -int cXinelibThread::ConfigureVideo(int hue, int saturation, - int brightness, int sharpness, - int noise_reduction, int contrast, - int overscan, int vo_aspect_ratio) -{ - char cmd[128]; - Xine_Control("OVERSCAN", overscan); - snprintf(cmd, sizeof(cmd), - "VIDEO_PROPERTIES %d %d %d %d %d %d %d", - hue, saturation, brightness, sharpness, noise_reduction, contrast, vo_aspect_ratio); - return Xine_Control(cmd); -} - -// -// Playback files -// - -bool cXinelibThread::EndOfStreamReached(void) -{ - LOCK_THREAD; - bool r = m_bEndOfStreamReached; - return r; -} - - diff --git a/frontend.h b/frontend.h deleted file mode 100644 index a80c5b9b..00000000 --- a/frontend.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * frontend.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: frontend.h,v 1.28 2009-03-20 18:26:23 phintuka Exp $ - * - */ - -#ifndef __XINELIB_FRONTEND_H -#define __XINELIB_FRONTEND_H - -#include <vdr/tools.h> -#include <vdr/thread.h> -#include <vdr/device.h> // ePlayMode - -class cStatus; - -//----------------------------- cXinelibThread -------------------------------- - -class cXinelibThread : public cThread, public cListObject -{ - private: - cXinelibThread(cXinelibThread&); // no copy contructor - - public: - cXinelibThread(const char *Description = NULL); - virtual ~cXinelibThread(); - - // - // Thread control - // - - public: - virtual void Start(void); - virtual void Stop(void); - bool IsReady(void); - bool IsFinished(void); - - protected: - void SetStopSignal(void); - bool GetStopSignal(void); - - virtual void Action(void) = 0; - - // - // Playback control - // - - public: - void PauseOutput(void) { TrickSpeed(0); } - void ResumeOutput(void) { TrickSpeed(1); } - virtual void TrickSpeed(int Speed); - void SetVolume(int NewVolume); - void SetLiveMode(bool); - void SetStillMode(bool); - void SetNoVideo(bool bVal); - void AudioStreamChanged(bool ac3, int StreamId); - void SetSubtitleTrack(eTrackType Track); - - protected: - int Xine_Control(const char *cmd, const char *p1); - int Xine_Control(const char *cmd, int p1); - int Xine_Control(const char *cmd, int64_t p1); - virtual int Xine_Control(const char *cmd) = 0; - virtual int Xine_Control_Sync(const char *cmd) { return Xine_Control(cmd); } - - void Configure(void); - - // - // Data transfer - // - - public: - virtual int Poll(cPoller &Poller, int TimeoutMs); - virtual bool Flush(int TimeoutMs); - virtual void Clear(void); - virtual int Play_PES(const uchar *buf, int len); - virtual void OsdCmd(void *cmd) = 0; - virtual int64_t GetSTC(void) { return -1; } - virtual void SetHDMode(bool On) { (void)Xine_Control("HDMODE",On?1:0); }; - virtual void SetHeader(const uchar *data, int length, bool reset = false) {}; - - // Stream type conversions - int Play_Mpeg1_PES(const uchar *data, int len); - bool Play_Mpeg2_ES(const uchar *data, int len, int streamID); - - // Built-in still images - bool BlankDisplay(void); - bool QueueBlankDisplay(void); - bool LogoDisplay(void); - bool NoSignalDisplay(void); - - // Playback files - virtual bool PlayFile(const char *FileName, int Position, - bool LoopPlay = false, ePlayMode PlayMode = pmAudioVideo, - int TimeoutMs = -1); - virtual int PlayFileCtrl(const char *Cmd, int TimeoutMs=-1) { return Xine_Control(Cmd); } - virtual bool EndOfStreamReached(void); - - // Image grabbing - virtual uchar *GrabImage(int &Size, bool Jpeg, int Quality, - int SizeX, int SizeY) { return NULL; } - - // Control from frontend - static void KeypressHandler(const char *keymap, const char *key, - bool repeat, bool release); - static void InfoHandler(const char *info); - - // - // Configuration - // - - public: - virtual int ConfigurePostprocessing(const char *deinterlace_method, - int audio_delay, - int audio_compression, - const int *audio_equalizer, - int audio_surround, - int speaker_type); - virtual int ConfigurePostprocessing(const char *name, bool on, const char *args); - virtual int ConfigureVideo(int hue, int saturation, - int brightness, int sharpness, int noise_reduction, int contrast, - int overscan, int vo_aspect_ratio); - // Local frontend: - virtual void ConfigureWindow(int fullscreen, int width, int height, - int modeswitch, const char *modeline, - int aspect, int scale_video, - int field_order) {}; - virtual void ConfigureDecoder(int pes_buffers) {}; - // Remote frontend server: - virtual bool Listen(int port) { return false; } - - // - // Data - // - - protected: - bool m_bStopThread; - bool m_bReady; - bool m_bIsFinished; - bool m_bNoVideo; - bool m_bLiveMode; - bool m_bEndOfStreamReached; - bool m_bPlayingFile; - int m_Volume; - cString m_FileName; - uint64_t m_StreamPos; - uint32_t m_Frames; - - cStatus *m_StatusMonitor; - bool m_SpuLangAuto; -}; - - -#endif // __XINELIB_FRONTEND_H diff --git a/frontend_local.c b/frontend_local.c deleted file mode 100644 index 6a4006c4..00000000 --- a/frontend_local.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - * frontend_local.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: frontend_local.c,v 1.41 2009-06-01 14:01:28 phintuka Exp $ - * - */ - -#define __STDC_CONSTANT_MACROS - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <sys/types.h> -#include <unistd.h> -#include <dlfcn.h> - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/shutdown.h> -#include <vdr/plugin.h> - -#include "logdefs.h" -#include "config.h" - -#include "xine_frontend.h" - -#include "frontend_local.h" - -//------------------------------ cRwLockBlock --------------------------------- - -class cRwLockBlock -{ - private: - cRwLock& m_Lock; - - public: - cRwLockBlock(cRwLock& lock, bool write) : m_Lock(lock) - { m_Lock.Lock(write);} - - ~cRwLockBlock() - { m_Lock.Unlock(); } -}; - -#define LOCK_FE cRwLockBlock(m_feLock, false) -#define LOCK_FE_WR cRwLockBlock(m_feLock, true) - -//----------------- keyboard control handler (C callback) -------------------- - -extern "C" { - static void keypress_handler(const char *keymap, const char *key) - { - if(!strncmp("INFO ", keymap, 5)) { - - cXinelibThread::InfoHandler(keymap+5); - - } else if(!xc.use_x_keyboard || !key) { - - /* Only X11 key events came this way in local mode. - Keyboard is handled by vdr. */ - LOGMSG("keypress_handler(%s): X11 Keyboard disabled in config", key); - - } else { - - cXinelibThread::KeypressHandler(keymap, key, false, false); - - } - } -}; - -//----------------------------- cXinelibLocal -------------------------------- - -cXinelibLocal::cXinelibLocal(const char *frontend_name) : - cXinelibThread("Local decoder/display (cXinelibThread)"), m_feLock(true) -{ - fe = NULL; - h_fe_lib = NULL; - m_bReconfigRequest = true; - - if (!xc.config_file && - 0 < asprintf(&xc.config_file, - "%s/xineliboutput/config", - cPlugin::ConfigDirectory())) - LOGMSG("cXinelibLocal: Using xine-lib configuration file %s", xc.config_file); -} - -cXinelibLocal::~cXinelibLocal() -{ - TRACEF("cXinelibLocal::~cXinelibLocal"); - - m_bReady = false; - - Stop(); - if(fe) { - fe->fe_free(fe); - fe = NULL; - } - if(h_fe_lib) { - dlclose(h_fe_lib); - } -} - -void cXinelibLocal::Stop(void) -{ - TRACEF("cXinelibLocal::Stop"); - - SetStopSignal(); - - { - LOCK_FE; - m_bReady = false; - if(fe) - fe->fe_interrupt(fe); - } - - cXinelibThread::Stop(); -} - -// -// Data transfer -// - -int cXinelibLocal::Play_PES(const uchar *data, int len) -{ - TRACEF("cXinelibLocal::Play_PES"); - - { - LOCK_FE; - if(fe && !m_bStopThread) { - int done = fe->xine_queue_pes_packet(fe, (char*)data, len); - if (done >= 0) { - Lock(); - m_StreamPos += done; - Unlock(); - return done; - } - } - } - - //cCondWait::SleepMs(5); - return len; -} - -void cXinelibLocal::OsdCmd(void *cmd) -{ - TRACEF("cXinelibLocal::OsdCmd"); - LOCK_FE; - if(cmd && fe && m_bReady) - fe->xine_osd_command(fe, (struct osd_command_s*)cmd); -} - -uchar *cXinelibLocal::GrabImage(int &Size, bool Jpeg, - int Quality, int SizeX, - int SizeY) -{ - uchar *data; - LOCK_FE; - if(fe && fe->grab && m_bReady) - if((data = (uchar*)fe->grab(fe, &Size, Jpeg, Quality, SizeX, SizeY))) - return data; - return NULL; -} - -int64_t cXinelibLocal::GetSTC() -{ - TRACEF("cXinelibLocal::GetSTC"); - - union { - char buf[32]; - int64_t pts; - } u = {"GETSTC\r\n"}; - - LOCK_FE; - - if (fe && m_bReady) - if (0 == fe->xine_control(fe, u.buf)) - return u.pts; - - return INT64_C(-1); -} - -// -// Playback files -// - -bool cXinelibLocal::EndOfStreamReached(void) -{ - LOCK_THREAD; - if(fe && fe->xine_is_finished(fe, 1)) - return true; - return cXinelibThread::EndOfStreamReached(); -} - -// -// Configuration -// - -void cXinelibLocal::ConfigureWindow(int fullscreen, int width, int height, - int modeswitch, const char *modeline, - int aspect, int scale_video, - int field_order) -{ - LOCK_FE; - if(fe) - fe->fe_display_config(fe, -1, -1, width, height, - fullscreen, modeswitch, modeline, - aspect, scale_video, field_order); -} - -void cXinelibLocal::ConfigureDecoder(int pes_buffers) -{ - // needs xine restart - { - LOCK_FE; - xc.pes_buffers = pes_buffers; - if(!fe) - return; - m_bReady = false; - m_bReconfigRequest = true; - fe->fe_interrupt(fe); - } - - while(!m_bReady && !GetStopSignal()) - cCondWait::SleepMs(100); - - cCondWait::SleepMs(100); -} - -// -// Xine control -// - -int cXinelibLocal::Xine_Control(const char *cmd) -{ - TRACEF("cXinelibLocal::Xine_Control"); - if(cmd && *cmd && !GetStopSignal()) { - char buf[4096]; - if(snprintf(buf, sizeof(buf), "%s\r\n", cmd) >= (int)sizeof(buf)) { - buf[sizeof(buf)-1] = 0; - LOGMSG("Xine_Control: message too long ! (%s)", buf); - return 0; - } - LOCK_FE; - if(fe) - return fe->xine_control(fe, (char*)buf); - } - return 0; -} - -// -// Frontend loader -// - -frontend_t *cXinelibLocal::load_frontend(const char *fe_name) -{ - Dl_info info; - struct stat statbuffer; - char libname[4096]=""; - void *lib = NULL; - fe_creator_f *fe_creator = NULL; - static int my_marker = 0; - - if(!dladdr((void *)&my_marker, &info)) { - LOGERR("Error searching plugin: dladdr() returned false (%s)",dlerror()); - return NULL; - } - LOGDBG("xineliboutput: plugin file is %s", info.dli_fname); - - int fe_ind = strstra(fe_name, xc.s_frontends, FRONTEND_NONE); - bool fe_try = false; - if(fe_ind == FRONTEND_NONE) { - LOGMSG("Front-end %s unknown!", fe_name); - fe_ind = 0; - fe_try = true; - } - - strn0cpy(libname, info.dli_fname, sizeof(libname) - 128); - if(strrchr(libname, '/')) - *(strrchr(libname, '/')+1) = 0; - - LOGDBG("Searching frontend %s from %s", xc.s_frontends[fe_ind], libname); - - do { - strncat(libname, xc.s_frontend_files[fe_ind], 64); - LOGDBG("Probing %s", libname); - - if (stat(libname, &statbuffer)) { - LOGERR("load_frontend: can't stat %s",libname); - } else if((statbuffer.st_mode & S_IFMT) != S_IFREG) { - LOGMSG("load_frontend: %s not regular file ! trying to load anyway ...", - libname); - } - - if( !(lib = dlopen (libname, RTLD_LAZY | RTLD_GLOBAL))) { - char *dl_error_msg = dlerror(); - LOGERR("load_frontend: cannot dlopen file %s: %s", - libname, dl_error_msg); - } else if ( (fe_creator = (fe_creator_f*)dlsym(lib, "fe_creator"))) { - LOGDBG("load_frontend: entry at %p", fe_creator); - frontend_t *fe = (**fe_creator)(); - - if(fe) { - if(h_fe_lib) - dlclose(h_fe_lib); - h_fe_lib = lib; - - LOGDBG("Using frontend %s (%s) from %s", - xc.s_frontends[fe_ind], xc.s_frontendNames[fe_ind], - xc.s_frontend_files[fe_ind]); - - return fe; - } else { - LOGMSG("Frontend %s (%s) creation failed", - xc.s_frontends[fe_ind], xc.s_frontendNames[fe_ind]); - } - } else { - LOGERR("Frontend entry point not found"); - dlclose(lib); - } - - fe_ind++; // try next frontend ... - - } while(fe_try && fe_ind < FRONTEND_count); - - LOGMSG("No usable frontends found, giving up !"); - return NULL; -} - -// -// Thread main loop -// - -void cXinelibLocal::Action(void) -{ - frontend_t *curr_fe = NULL; - - TRACEF("cXinelibLocal::Action"); - - SetPriority(2); /* lower priority */ - - // init frontend - if(!curr_fe) { - curr_fe = load_frontend(xc.local_frontend); - if(!curr_fe) { - LOGMSG("cXinelibLocal: Error initializing frontend"); - SetStopSignal(); - } else { - LOGDBG("cXinelibLocal::Action - fe created"); - if(!curr_fe->fe_display_open(curr_fe, 0, 0, xc.width, xc.height, xc.fullscreen, xc.hud_osd, - xc.modeswitch, xc.modeline, xc.display_aspect, - keypress_handler, 0/*no_x_kbd*/, 0/*gui_hotkeys*/, - xc.video_port, - xc.scale_video, - xc.field_order, - NULL, -1)) { - LOGMSG("cXinelibLocal: Error initializing display"); - SetStopSignal(); - } else { - LOGDBG("cXinelibLocal::Action - fe->fe_display_open ok"); - } - } - } - - // main loop - while (!GetStopSignal()) { - - { - // init and start xine engine - LOCK_FE_WR; - LOGDBG("cXinelibLocal::Action - xine_init"); - - fe = curr_fe; - if(m_bReconfigRequest) { - if(!fe->xine_init(fe, xc.audio_driver, xc.audio_port, - xc.video_driver, - xc.pes_buffers, - xc.post_plugins, xc.config_file)) { - LOGMSG("cXinelibLocal: Error initializing frontend"); - break; - } - LOGDBG("cXinelibLocal::Action - fe->xine_init ok"); - m_bReconfigRequest = false; - } - - // open (xine) stream - LOGDBG("cXinelibLocal::Action - xine_open"); - if(!fe->xine_open(fe, NULL)) { - LOGMSG("cXinelibLocal: Error opening xvdr://"); - break; - } - LOGDBG("cXinelibLocal::Action - fe->xine_open ok"); - - // start playing (xine) stream - if(!fe->xine_play(fe)) { - LOGMSG("cXinelibLocal: Error playing xvdr://"); - break; - } - LOGDBG("cXinelibLocal::Action - fe->xine_play ok"); - - m_StreamPos = 0; - Xine_Control("STREAMPOS 0"); - Xine_Control("VERSION " XINELIBOUTPUT_VERSION " " "\r\n"); - } - - // configure frontend and xine - m_bNoVideo = false; - Configure(); - LOGDBG("cXinelibLocal::Action - fe config OK"); - - LogoDisplay(); - LOGDBG("cXinelibLocal::Action - logo sent"); - - { - LOCK_THREAD; - Xine_Control("NOVIDEO 0"); - Xine_Control("LIVE 1"); - Xine_Control("CLEAR"); - m_bNoVideo = false; - m_bLiveMode = true; - m_bReady = true; - } - - // main event loop - LOGDBG("cXinelibLocal:Action - Starting event loop"); - { - LOCK_FE; - while(!GetStopSignal() && m_bReady && - (/*m_bLoopPlay ||*/ !fe->xine_is_finished(fe, 0)) && - fe->fe_run(fe)) - /*cCondWait::SleepMs(50)*/ ; - } - - LOGDBG("cXinelibLocal::Action - event loop terminated, " - "xine_is_finished=%d", fe->xine_is_finished(fe, 0)); - - { - LOCK_THREAD; - m_bReady = false; - m_bEndOfStreamReached = true; - } - - { - LOCK_FE_WR; - if(fe) - fe->xine_close(fe); - fe = NULL; - } - - LOGMSG("cXinelibLocal::Action: Xine closed"); - - if(!m_bReconfigRequest && xc.exit_on_close) { - LOGMSG("Shutting down VDR"); - ShutdownHandler.RequestEmergencyExit(); - break; - } - } - - if(curr_fe) { - curr_fe->xine_exit(fe); - curr_fe->fe_display_close(curr_fe); - curr_fe->fe_free(curr_fe); - } - - m_bIsFinished = true; - LOGMSG("cXinelibLocal::Action: thread finished"); -} - diff --git a/frontend_local.h b/frontend_local.h deleted file mode 100644 index 1a44f3bd..00000000 --- a/frontend_local.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * frontend_local.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: frontend_local.h,v 1.6 2008-11-18 15:06:12 phintuka Exp $ - * - */ - -#ifndef __XINELIB_FRONTEND_LOCAL_H -#define __XINELIB_FRONTEND_LOCAL_H - -#include "frontend.h" - -//----------------------------- cXinelibLocal -------------------------------- - -extern "C" { - typedef struct frontend_s frontend_t; -} - -class cXinelibLocal : public cXinelibThread -{ - - public: - cXinelibLocal(const char *frontend_name); - virtual ~cXinelibLocal(); - - // Thread control - virtual void Stop(void); - - protected: - virtual void Action(void); - - - public: - - // Data transfer - virtual int Play_PES(const uchar *buf, int len); - virtual void OsdCmd(void *cmd); - virtual int64_t GetSTC(); - - // Playback files - virtual bool EndOfStreamReached(void); - - // Image grabbing - virtual uchar *GrabImage(int &Size, bool Jpeg, int Quality, - int SizeX, int SizeY); - - // Configuration - virtual void ConfigureWindow(int fullscreen, int width, int height, - int modeswitch, const char *modeline, - int aspect, int scale_video, int field_order); - virtual void ConfigureDecoder(int pes_buffers); - - protected: - - // Playback control - virtual int Xine_Control(const char *cmd); - - protected: - - // Frontend access - frontend_t *load_frontend(const char *fe_name); - - // Data - void *h_fe_lib; - frontend_t *fe; - cRwLock m_feLock; - bool m_bReconfigRequest; -}; - - -#endif // __XINELIB_FRONTEND_LOCAL_H diff --git a/frontend_svr.c b/frontend_svr.c deleted file mode 100644 index c993fec2..00000000 --- a/frontend_svr.c +++ /dev/null @@ -1,1977 +0,0 @@ -/* - * frontend_svr.c: server for remote frontends - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: frontend_svr.c,v 1.74 2009-07-02 18:27:19 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#include <inttypes.h> - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <sys/types.h> -#include <unistd.h> -#include <time.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <netdb.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <netinet/tcp.h> - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/plugin.h> - -#include "logdefs.h" -#include "config.h" - -#include "xine_input_vdr_net.h" // stream header(s) -#include "xine_osd_command.h" // osd commands - -#include "tools/cxsocket.h" -#include "tools/future.h" -#include "tools/backgroundwriter.h" -#include "tools/udp_pes_scheduler.h" -#include "tools/http.h" -#include "tools/vdrdiscovery.h" -#include "tools/sdp.h" - -#include "frontend_svr.h" -#include "device.h" -#include "osd.h" - -//#define HTTP_OSD - -#define MAX_OSD_TIMEOUTS (25*5) /* max. rate 25 updates/s -> at least 5 seconds */ -#define LOG_OSD_BANDWIDTH (128*1024) /* log messages if OSD bandwidth > 1 Mbit/s */ - -#define PLAYFILE_CTRL_TIMEOUT 300 /* ms */ -#define PLAYFILE_TIMEOUT 20000 /* ms */ - -typedef struct { - int Size; - uchar *Data; -} grab_result_t; - -class cStcFuture : public cFuture<int64_t> {}; -class cReplyFuture : public cFuture<int>, public cListObject {}; -class cGrabReplyFuture : public cFuture<grab_result_t>, public cListObject {}; -class cCmdFutures : public cHash<cReplyFuture> {}; - - -//----------------------------- cXinelibServer -------------------------------- - -// (control stream) connection types -enum { - ctDetecting = 0x00, - ctControl = 0x01, - ctHttp = 0x02, - ctRtsp = 0x04, // TCP/RTSP + UDP/RTP - ctRtspMux = 0x08 // TCP: multiplexed RTSP control + RTP/RTCP data/control -}; - -// (data) connection types -enum { - dtPipe = 0x01, - dtTcp = 0x02, - dtUdp = 0x04, - dtRtp = 0x08, - dtHttp = 0x10, - dtRtspMux = 0x20, -}; - -// (data) connection properties -#define DATA_STREAM(dt) ((dt) & (dtPipe | dtTcp | dtHttp | dtRtspMux)) -#define DATA_DATAGRAM(dt) ((dt) & (dtUdp | dtRtp)) -#define DATA_NOPOLL(dt) ((dt) & (dtHttp | dtRtspMux)) -#define DATA_NOCONTROL(dt) ((dt) & (dtHttp | dtRtspMux)) - -cXinelibServer::cXinelibServer(int listen_port) : - cXinelibThread("Remote decoder/display server (cXinelibServer)") -{ - int i; - for(i=0; i<MAXCLIENTS; i++) { - fd_data[i] = -1; - m_OsdTimeouts[i] = 0; - m_Writer[i] = NULL; - m_State[i] = NULL; - m_bMulticast[i] = 0; - m_bConfigOk[i] = false; - m_bUdp[i] = 0; - m_ConnType[i] = ctDetecting; - } - - m_Port = listen_port; - m_ServerId = time(NULL) ^ getpid(); - - fd_listen = -1; - fd_discovery = -1; - - m_iMulticastMask = 0; - m_MasterCli = -1; - - m_Master = false; - - m_Scheduler = new cUdpScheduler; - m_StcFuture = new cStcFuture; - m_Futures = new cCmdFutures; - - cString Base(cPlugin::ConfigDirectory()); - if(*Base) - m_PipesDir = cString::sprintf("%s/xineliboutput/pipes.%d", *Base, getpid()); - else - m_PipesDir = cString::sprintf("/tmp/xineliboutput/pipes.%d", getpid()); - - m_Token = 1; - - m_Header = NULL; - m_HeaderLength = 0; - m_HeaderSize = 0; -} - -cXinelibServer::~cXinelibServer() -{ - int i; - - CLOSESOCKET(fd_listen); - CLOSESOCKET(fd_discovery); - - cHttpStreamer::CloseAll(); - - for(i=0; i<MAXCLIENTS; i++) - CloseConnection(i); - - delete m_StcFuture; - delete m_Futures; - delete m_Scheduler; - - free(m_Header); -} - -void cXinelibServer::Stop(void) -{ - int i; - - TRACEF("cXinelibServer::Stop"); - - SetStopSignal(); - - CLOSESOCKET(fd_listen); - CLOSESOCKET(fd_discovery); - - for(i=0; i<MAXCLIENTS; i++) - CloseConnection(i); - - cXinelibThread::Stop(); -} - -void cXinelibServer::Clear(void) -{ - TRACEF("cXinelibServer::Clear"); - - LOCK_THREAD; - - for(int i = 0; i < MAXCLIENTS; i++) - if(fd_control[i].open() && m_Writer[i]) - m_Writer[i]->Clear(); - - if(m_Scheduler) - m_Scheduler->Clear(); - - cXinelibThread::Clear(); -} - -void cXinelibServer::CloseDataConnection(int cli) -{ - if(m_bUdp[cli] && fd_data[cli]>=0) - m_Scheduler->RemoveHandle(fd_data[cli]); - - CLOSESOCKET(fd_data[cli]); - - if(m_Writer[cli]) { - delete m_Writer[cli]; - m_Writer[cli] = NULL; - } - - m_bUdp[cli] = false; - m_bMulticast[cli] = false; - m_bConfigOk[cli] = false; - - m_iMulticastMask &= ~(1<<cli); - - if(!m_iMulticastMask && !xc.remote_rtp_always_on) - m_Scheduler->RemoveRtp(); -} - -void cXinelibServer::CloseConnection(int cli) -{ - CloseDataConnection(cli); - if(fd_control[cli].open()) { - LOGMSG("Closing connection %d", cli); - fd_control[cli].close(); - if(m_State[cli]) { - delete m_State[cli]; - m_State[cli] = NULL; - } - cXinelibDevice::Instance().ForcePrimaryDevice(false); - } -} - -static int recompress_osd_net(uint8_t *raw, xine_rle_elem_t *data, int elems) -{ - uint8_t *raw0 = raw; - for(int i=0; i<elems; i++) { - uint16_t len = data[i].len; - uint16_t color = data[i].color; - if(len >= 0x80) { - *(raw++) = (len>>8) | 0x80; - *(raw++) = (len & 0xff); - } else { - *(raw++) = (len & 0x7f); - } - *(raw++) = color; - } - return (raw-raw0); -} - -static int write_osd_command(cxSocket& s, osd_command_t *cmd) -{ - cxPoller p(s, true); - if(!p.Poll(100)) { - LOGMSG("write_osd_command: poll failed, OSD send skipped"); - return 0; - } - - ssize_t max = s.tx_buffer_free(); - ssize_t size = (ssize_t)8 + - (ssize_t)(sizeof(osd_command_t)) + - (ssize_t)(sizeof(xine_clut_t) * ntohl(cmd->colors)) + - (ssize_t)(ntohl(cmd->datalen)); - - if(max > 0 && max < size) { -/* #warning TODO: buffer latest failed OSD and retry - -> skipped OSDs can be left out but - latest will be always delivered */ - LOGMSG("write_osd_command: socket buffer full, OSD send skipped (got %d ; need %d", - (int)max, (int)size); - return 0; - } - - cmd->size = sizeof(osd_command_t); - - if(8 != s.write("OSDCMD\r\n", 8, 100)) { - LOGDBG("write_osd_command: write (command) failed"); - return -1; - } - if((ssize_t)sizeof(osd_command_t) != - s.write(cmd, sizeof(osd_command_t), 100)) { - LOGDBG("write_osd_command: write (data) failed"); - return -1; - } - if(cmd->palette && cmd->colors && - (ssize_t)(sizeof(xine_clut_t)*ntohl(cmd->colors)) != - s.write(cmd->palette, sizeof(xine_clut_t)*ntohl(cmd->colors), 100)) { - LOGDBG("write_osd_command: write (palette) failed"); - return -1; - } - if(cmd->data && cmd->datalen && - (ssize_t)ntohl(cmd->datalen) != s.write(cmd->data, ntohl(cmd->datalen), 300)) { - LOGDBG("write_osd_command: write (bitmap) failed"); - return -1; - } - return 1; -} - -#ifdef HTTP_OSD -#include "dvdauthor/rgb.h" -#include "dvdauthor/subgen-encode.c" -#include "dvdauthor/subgen.c" -#include "dvdauthor/subgen-image.c" -//subgen-image: palette generation, image divided to buttons --> 16-col palette -static uint8_t *dvdspu_encode(osd_command_t *cmd, int *spulen) -{ -#if 0 - stinfo st; - st.x0 = cmd->x; - st.y0 = cmd->y; - st.xd = cmd->w; - st.yd = cmd->h; - - st.spts = 0; /* start pts */ - st.sd = 0; /* duration */ - st.forced = 0; - st.numbuttons = 0; - st.numpal = 0; - - st.autooutline = 0; /* -> 1 -> imgfix calls detectbuttons(s); */ - st.outlinewidth = 0; - st.autoorder = 0; - - st.img =; /* img */ - st.hlt =; /* img */ - st.sel =; /* img */ - st.fimg = NULL; - - st.pal[4] = ; /* palt */ - st.masterpal[16] = ; /* palt */ - st.transparentc = ; /* palt */ - - st.numgroups = ; - st.groupmap[3][4] = ; - st.buttons = ; /* button * */ - - if(imgfix(&st)) - dvd_encode(&st); -#endif - return NULL; - -} -#endif - -void cXinelibServer::OsdCmd(void *cmd_gen) -{ - TRACEF("cXinelibServer::OsdCmd"); - int i; - - LOCK_THREAD; - - // check if there are any clients - if(!HasClients()) - return; - - if(cmd_gen) { - osd_command_t *cmd = (osd_command_t*)cmd_gen; - osd_command_t cmdnet; - memcpy(&cmdnet, cmd, sizeof(osd_command_t)); - if (cmd->data) { - cmdnet.raw_data = (uint8_t *)malloc(cmd->datalen); - cmdnet.datalen = recompress_osd_net(cmdnet.raw_data, cmd->data, cmd->num_rle); - } - // -> network byte order - hton_osdcmd(cmdnet); - -#ifdef HTTP_OSD - uint8_t *spudata = NULL; - int spulen = 0; -#endif - - for(i = 0; i < MAXCLIENTS; i++) { - if(fd_control[i].open() && m_bConfigOk[i]) { - int r = write_osd_command(fd_control[i], &cmdnet); - if(r < 0) { - LOGMSG("Send OSD command failed, closing connection"); - CloseConnection(i); - } else if(r == 0) { - if(m_OsdTimeouts[i]++ > MAX_OSD_TIMEOUTS) { - LOGMSG("Too many OSD timeouts, dropping client"); - CloseConnection(i); - } - } else { - m_OsdTimeouts[i] = 0; - } - } -#ifdef HTTP_OSD - if(m_ConnType[i] == ctHttp) { - if(m_Writer[i]) { - if(!spudata) - spudata = dvdspu_encode(cmd, &spulen); - if(spudata) - m_Writer[i]->Put(-1, spudata, spulen); - } - } -#endif - } - -#ifdef HTTP_OSD - free(spudata); -#endif - - free(cmdnet.data); - -#ifdef LOG_OSD_BANDWIDTH - { - static int64_t timer = 0LL; - static int bytes = 0; - int64_t now = cTimeMs::Now(); - - if(timer + 5000LL < now) { - timer = now; - bytes = 0; - } else if(timer + 1000LL < now) { - bytes = bytes / (((int)(now - timer)) / 1000); - if(bytes > LOG_OSD_BANDWIDTH) - LOGMSG("OSD bandwidth: %d bytes/s (%d kbit/s)", bytes, bytes*8/1024); - timer = now; - bytes = 0; - } - bytes += sizeof(osd_command_t) + ntohl(cmdnet.datalen); - } -#endif - } -} - -int64_t cXinelibServer::GetSTC(void) -{ - Lock(); - - // check if there are any clients - if(!HasClients()) { - Unlock(); - return -1ULL; - } - - // Query client(s) - m_StcFuture->Reset(); - Xine_Control("GETSTC"); - - Unlock(); - - if(! m_StcFuture->Wait(200)) { - LOGMSG("cXinelibServer::GetSTC timeout (200ms)"); - return -1ULL; - } - - //if(delay.Elapsed() > 0 && !is_Paused) - // LOGMSG("GetSTC: compensating network delay by %s ticks (ms)\n", - // delay.Elapsed()*90000/2, delay.Elapsed()/2); - - return m_StcFuture->Value() /*+ (delay.Elapsed()*90000/2*/; -} - -void cXinelibServer::SetHeader(const uchar *Data, int Length, bool Reset) -{ - LOCK_THREAD; // Lock control thread out - - if (Reset) - m_HeaderLength = 0; - - if (m_HeaderSize < m_HeaderLength + Length) { - if (!m_Header) { - m_HeaderSize = Length; - m_Header = (uchar*)malloc(m_HeaderSize); - } else { - m_HeaderSize = m_HeaderLength + Length; - m_Header = (uchar*)realloc(m_Header, m_HeaderSize); - } - } - - if (m_Header) { - memcpy(m_Header + m_HeaderLength, Data, Length); - m_HeaderLength += Length; - } -} - -int cXinelibServer::Play_PES(const uchar *data, int len) -{ - int TcpClients = 0, UdpClients = 0, RtpClients = 0; - - LOCK_THREAD; // Lock control thread out - - for(int i=0; i<MAXCLIENTS; i++) { - if(fd_control[i].open()) { - if((m_bConfigOk[i] && fd_data[i] >= 0) || - m_ConnType[i] & (ctHttp|ctRtsp)) { - - if(m_bUdp[i]) { - - UdpClients++; - - } else if(m_Writer[i]) { - - int result = m_Writer[i]->Put(m_StreamPos, data, len); - if(!result) { - LOGMSG("cXinelibServer::Play_PES Write/Queue error (TCP/PIPE)"); - CloseConnection(i); - } else if(result<0) { - LOGMSG("cXinelibServer::Play_PES Buffer overflow (TCP/PIPE)"); - if(m_ConnType[i] == ctHttp) - m_Writer[i]->Clear(); - } - - TcpClients++; - } - } - } - } - - RtpClients = (m_iMulticastMask || xc.remote_rtp_always_on); - - if(UdpClients || RtpClients) - if(! m_Scheduler->Queue(m_StreamPos, data, len)) - LOGMSG("cXinelibServer::Play_PES Buffer overflow (UDP/RTP)"); - - if(TcpClients || UdpClients || RtpClients) - cXinelibThread::Play_PES(data, len); - - return len; -} - -void cXinelibServer::SetHDMode(bool On) -{ - cXinelibThread::SetHDMode(On); -#if 0 - /*#warning TODO*/ - LOCK_THREAD; - - int i; - for(i=0; i<MAXCLIENTS; i++) - if(m_Writer[i]) - m_Writer[i]->SetBuffer(On ? 2048 : 512); - m_Scheduler->SetWindow(On ? 512 : 128); -#endif -} - -int cXinelibServer::Poll(cPoller &Poller, int TimeoutMs) -{ - // in live mode transponder clock is the master ... - // in replay mode local frontend (if present) is master - if(m_bLiveMode || (*xc.local_frontend && strncmp(xc.local_frontend, "none", 4))) { - if(m_Scheduler->Clients()) - return m_Scheduler->Poll(TimeoutMs, m_Master = false); - return DEFAULT_POLL_SIZE; - } - - // replay mode: - do { - Lock(); - m_Master = true; - int Free = 0xfffff, FreeHttp = 0xfffff, FreeUdp = 0; - int Clients = 0, Http = 0, Udp = 0; - for(int i=0; i<MAXCLIENTS; i++) { - if(fd_control[i].open()) { - if(m_bConfigOk[i]) { - if(m_Writer[i]) - Free = min(Free, m_Writer[i]->Free()); - else if(m_bUdp[i]) - Udp++; - Clients++; - } else if(m_ConnType[i] & (ctHttp|ctRtspMux)) { - if(m_Writer[i]) { - FreeHttp = min(FreeHttp, m_Writer[i]->Free()); - Http++; - } - } - } - } - if(m_iMulticastMask) { - Clients++; - Udp++; - } - - /* select master timing source for replay mode */ - int master = -1; - if(Clients && !Udp) { - for(int i=0; i<MAXCLIENTS; i++) - if(fd_control[i].open() && m_bConfigOk[i] && m_Writer[i]) { - master = i; - break; - } - } - if(master != m_MasterCli) { - if(m_MasterCli >= 0) - Xine_Control("MASTER 0"); - if(master >= 0) - fd_control[master].write_cmd("MASTER 1\r\n"); - m_MasterCli = master; - } - - Unlock(); - - if(!Clients && !Http) { - // live mode runs even if there are no clients - if(m_bLiveMode) - return DEFAULT_POLL_SIZE; - // replay is paused when no clients - if(TimeoutMs>0) - cCondWait::SleepMs(TimeoutMs); - return 0; - } - - // in replay mode cUdpScheduler is master timing source - if( Free < 8128 || - ((FreeUdp = m_Scheduler->Poll(TimeoutMs, true)) < 1) || - (!Clients && FreeHttp < 8128)) { - - if(TimeoutMs > 0) - cCondWait::SleepMs(min(TimeoutMs, 5)); - TimeoutMs -= 5; - - } else { - Free = min(Free, FreeHttp) / 2070; - Free = min(Free, FreeUdp); - return max(0, Free); - } - - } while(TimeoutMs > 0); - - return 0; -} - -bool cXinelibServer::Flush(int TimeoutMs) -{ - int result = true; - - if(m_Scheduler) - result = m_Scheduler->Flush(TimeoutMs) && result; - - for(int i=0; i<MAXCLIENTS; i++) - if(fd_control[i].open() && fd_data[i]>=0 && m_Writer[i]) - result = m_Writer[i]->Flush(TimeoutMs) && result; - - if(TimeoutMs > 50) - TimeoutMs = 50; - - if(result) { - cString tmp = cString::sprintf("FLUSH %d %" PRIu64 " %d", - TimeoutMs, m_StreamPos, m_Frames); - result = (PlayFileCtrl(tmp)) <= 0 && result; - } - - return result; -} - -int cXinelibServer::Xine_Control(const char *cmd) -{ - TRACEF("cXinelibServer::Xine_Control"); - - if(cmd && *cmd) { - char buf[4096]; - int len = snprintf(buf, sizeof(buf), "%s\r\n", cmd); - if(len >= (int)sizeof(buf)) { - LOGMSG("Xine_Control: command truncated !"); - //len = sizeof(buf); - return 0; - } - - LOCK_THREAD; - - for(int i=0; i<MAXCLIENTS; i++) - if(fd_control[i].open() && (fd_data[i]>=0 || m_bMulticast[i]) && m_bConfigOk[i]) - if(len != fd_control[i].write(buf, len, 100)) { - LOGMSG("Control send failed (%s), dropping client", cmd); - CloseConnection(i); - } - } - - return 1; -} - -int cXinelibServer::Xine_Control_Sync(const char *cmd) -{ - TRACEF("cXinelibServer::Xine_Control_Sync"); - - if(cmd && *cmd) { - int i, len, UdpClients = 0, RtpClients = 0; - char buf[256]; - - len = snprintf(buf, sizeof(buf), "%s\r\n", cmd) + 1; - if(len >= (int)sizeof(buf)) { - LOGMSG("Xine_Control_Sync: command truncated ! (%s)", cmd); - len = sizeof(buf); - } - - LOCK_THREAD; - - for(i=0; i<MAXCLIENTS; i++) - if(fd_control[i].open() && m_bConfigOk[i]) { - if(fd_data[i] >= 0) { - if(m_bUdp[i]) - UdpClients++; - else if(m_Writer[i]) - m_Writer[i]->Put((uint64_t)(-1ULL), (const uchar*)buf, len); - } - } - - RtpClients = (m_iMulticastMask || xc.remote_rtp_always_on); - - if(UdpClients || RtpClients) - if(! m_Scheduler->Queue((uint64_t)(-1ULL), (const uchar*)buf, len)) - LOGMSG("cXinelibServer::Xine_Control_Sync overflow (UDP/RTP)"); - } - - return 1; -} - -void cXinelibServer::TrickSpeed(int Speed) -{ - if(Speed == 0) { - m_Scheduler->Pause(true); - } else { - m_Scheduler->Pause(false); - m_Scheduler->TrickSpeed(Speed == -1 ? 1 : Speed); - } - - cXinelibThread::TrickSpeed(Speed); -} - -bool cXinelibServer::EndOfStreamReached(void) -{ - LOCK_THREAD; - - /* Check if there are any clients */ - if(!HasClients()) - return true; - - return cXinelibThread::EndOfStreamReached(); -} - -int cXinelibServer::AllocToken(void) -{ - LOCK_THREAD; - - m_Token = (m_Token+1) & 0xffff; - - cXinelibThread::Xine_Control((const char *)"TOKEN", m_Token); - - return m_Token; -} - -bool cXinelibServer::HasClients(void) -{ - LOCK_THREAD; - - int i; - for(i=0; i<MAXCLIENTS; i++) - if(fd_control[i].open() && m_bConfigOk[i]) - return true; - - return false; -} - -int cXinelibServer::PlayFileCtrl(const char *Cmd, int TimeoutMs) -{ - /* Check if there are any clients */ - if(!HasClients()) { - cHttpStreamer::CloseAll(); - return -1; - } - - bool bPlayfile = false /*, bGet = false, bFlush = false*/; - if((!strncmp(Cmd, "FLUSH", 5) /*&& (bFlush=true)*/) || - (!strncmp(Cmd, "PLAYFILE", 8) && (bPlayfile=true)) || - (!strncmp(Cmd, "GET", 3) /*&& (bGet=true)*/)) { // GETPOS, GETLENGTH, ... - - Lock(); - - /* Get token, send it to client and set future for it */ - int token = AllocToken(); - cReplyFuture future; - m_Futures->Add(&future, token); - - /* Send actual command */ - cXinelibThread::PlayFileCtrl(Cmd); - - Unlock(); - - /* When server thread get REPLY %d %d (first %d == token, second returned value) - * it sets corresponding future (by token; if found) in list - * and removes it from list. - */ - -#ifdef XINELIBOUTPUT_DEBUG - int64_t t = cTimeMs::Now(); -#endif - - if(TimeoutMs < 0) - TimeoutMs = bPlayfile ? PLAYFILE_TIMEOUT : PLAYFILE_CTRL_TIMEOUT; - - future.Wait(TimeoutMs); - - Lock(); - m_Futures->Del(&future, token); - Unlock(); - - if(!future.IsReady()) { - LOGMSG("cXinelibServer::PlayFileCtrl: Timeout (%s , %d ms) %d", Cmd, TimeoutMs, token); - return -1; - } - - TRACE("cXinelibServer::PlayFileCtrl("<<Cmd<<"): result=" << future.Value() - << " delay: " << (int)(cTimeMs::Now()-t) << "ms"); - - if(bPlayfile) - m_bEndOfStreamReached = false; - - return future.Value(); - } - - bool result = cXinelibThread::PlayFileCtrl(Cmd); - if(!*m_FileName) - cHttpStreamer::CloseAll(); - return result; -} - - -bool cXinelibServer::Listen(int listen_port) -{ - LOCK_THREAD; - - bool result = false; - TRACEF("cXinelibServer::Listen"); - - if(listen_port <= 0 || listen_port > 0xffff) { - CLOSESOCKET(fd_listen); - CLOSESOCKET(fd_discovery); - if(m_Scheduler) - m_Scheduler->RemoveRtp(); - cHttpStreamer::CloseAll(); - LOGMSG("Not listening for remote connections"); - return false; - } - - if(fd_listen<0 || listen_port != m_Port) { - m_Port = listen_port; - CLOSESOCKET(fd_listen); - - int iReuse = 1; - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_addr.s_addr = htonl(INADDR_ANY); - name.sin_port = htons(m_Port); - - if(xc.remote_local_ip[0]) { - uint32_t ip = inet_addr(xc.remote_local_ip); - if(ip != INADDR_NONE) { - char txt[128]; - name.sin_addr.s_addr = ip; - LOGDBG("Binding server to %s", cxSocket::ip2txt(name.sin_addr.s_addr, htons(m_Port), txt)); - } else { - LOGERR("Local interface address %s is invalid !", xc.remote_local_ip); - } - } - fd_listen = socket(PF_INET,SOCK_STREAM,0); - setsockopt(fd_listen, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)); - - if (bind(fd_listen, (struct sockaddr *)&name, sizeof(name)) < 0) { - LOGERR("cXinelibServer: bind error %s port %d: %s", - xc.remote_local_ip[0] ? xc.remote_local_ip : "", - m_Port, strerror(errno)); - CLOSESOCKET(fd_listen); - } else if(listen(fd_listen, MAXCLIENTS)) { - LOGERR("cXinelibServer: listen error (port %d): %s", - m_Port, strerror(errno)); - CLOSESOCKET(fd_listen); - } else { - LOGMSG("Listening on port %d", m_Port); - result = true; - } - } else { - result = true; - } - - // set listen for discovery messages - CLOSESOCKET(fd_discovery); - if(xc.remote_usebcast) { - fd_discovery = udp_discovery_init(); - if(udp_discovery_broadcast(fd_discovery, m_Port, xc.remote_local_ip) < 0) - CLOSESOCKET(fd_discovery); - else - LOGMSG("Listening for UDP broadcasts on port %d", m_Port); - } - - // set up multicast sockets - - if(m_Scheduler) - m_Scheduler->RemoveRtp(); - - if(xc.remote_usertp) { - if(xc.remote_rtp_always_on) - LOGMSG("WARNING: RTP Configuration: transmission is always on !"); - if(xc.remote_rtp_always_on || m_iMulticastMask) - m_Scheduler->AddRtp(); - } - - return result; -} - -uchar *cXinelibServer::GrabImage(int &Size, bool Jpeg, - int Quality, int SizeX, int SizeY) -{ - cGrabReplyFuture future; - uchar *result = NULL; - cString cmd; - - cmd = cString::sprintf("GRAB %s %d %d %d\r\n", - Jpeg ? "JPEG" : "PNM", - Quality, SizeX, SizeY); - - Lock(); - - /* Check if there are any clients */ - if(!HasClients()) { - Unlock(); - return NULL; - } - - int token = AllocToken(); - m_Futures->Add(&future, token); - - // might be better to request iamge from one client only (?) - Xine_Control(cmd); - - Unlock(); - - if(future.Wait(5000)) { - grab_result_t r = future.Value(); - if((Size = r.Size) > 0) { - LOGDBG("cXinelibServer::GrabImage: image size is %d bytes", Size); - result = r.Data; - } else { - LOGMSG("cXinelibServer::Grab: Grab failed (%d)", Size); - } - } else { - LOGMSG("cXinelibServer::Grab: Timeout (5000 ms)"); - } - - Lock(); - m_Futures->Del(&future, token); - Unlock(); - - return result; -} - -// -// (Client) Control message handling -// - -void cXinelibServer::Handle_Control_PIPE(int cli, const char *arg) -{ - LOGDBG("Trying PIPE connection ..."); - - CloseDataConnection(cli); - - // - // TODO: client should create pipe; waiting here is not good thing ... - // - - if(!xc.remote_usepipe) { - LOGMSG("PIPE transport disabled in configuration"); - fd_control[cli].write_cmd("PIPE: Pipe transport disabled in config.\r\n"); - return; - } - - MakeDirs(m_PipesDir, true); - - int i; - cString pipeName; - for(i=0; i<10; i++) { - pipeName = cString::sprintf("%s/pipe.%d", *m_PipesDir, i); - if(mknod(pipeName, 0644|S_IFIFO, 0) < 0) { - unlink(pipeName); - continue; - } - else - break; - } - if(i>=10) { - LOGERR("Pipe creation failed (%s)", *pipeName); - RemoveFileOrDir(m_PipesDir, false); - fd_control[cli].write_cmd("PIPE: Pipe creation failed.\r\n"); - return; - } - - fd_control[cli].printf("PIPE %s\r\n", *pipeName); - - cxPoller poller(fd_control[cli]); - poller.Poll(500); /* quite short time ... */ - - int fd; - if((fd = open(pipeName, O_WRONLY|O_NONBLOCK)) < 0) { - LOGDBG("Pipe not opened by client"); - /*write_cmd(fd_control[cli], "PIPE NONE\r\n");*/ - unlink(pipeName); - RemoveFileOrDir(m_PipesDir, false); - return; - } - - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK); - - //LOGDBG("cXinelibServer::Handle_Control: pipe %s open", pipeName); - - unlink(pipeName); /* safe to remove now, both ends are open or closed. */ - RemoveFileOrDir(m_PipesDir, false); - fd_control[cli].write_cmd("PIPE OK\r\n"); - - if (m_Writer[cli]) - delete m_Writer[cli]; - m_Writer[cli] = new cTcpWriter(fd); - - if (m_Header) - m_Writer[cli]->Put(0, m_Header, m_HeaderLength); - - fd_data[cli] = fd; -} - - -void cXinelibServer::Handle_Control_DATA(int cli, const char *arg) -{ - int clientId = -1; - unsigned int ipc, portc; - - LOGDBG("Data connection (TCP) requested"); - - CloseDataConnection(cli); - - if(!xc.remote_usetcp) { - LOGMSG("TCP transports disabled in configuration"); - fd_control[cli].write_cmd("TCP: TCP transport disabled in config.\r\n"); - CloseConnection(cli); /* actually closes the new data connection */ - return; - } - - /* validate client ID */ - if(3 != sscanf(arg, "%d 0x%x:%d", &clientId, &ipc, &portc) || - clientId < 0 || - clientId >= MAXCLIENTS || - !fd_control[clientId].open()) { - fd_control[cli].write_cmd("TCP: Error in request (ClientId).\r\n"); - LOGDBG("Invalid data connection (TCP) request"); - /* close only new data connection, no control connection */ - CloseConnection(cli); - return; - } - - /* check client IP's */ - struct sockaddr_in sinc, sind; - socklen_t len = sizeof(sinc); - sinc.sin_addr.s_addr = 0; - sind.sin_addr.s_addr = ~0; - fd_control[cli].getpeername((struct sockaddr *)&sind, &len); - fd_control[clientId].getpeername((struct sockaddr *)&sinc, &len); - if(sinc.sin_addr.s_addr != sind.sin_addr.s_addr) { - fd_control[cli].write_cmd("TCP: Error in request (IP does not match).\r\n"); - LOGMSG("Invalid data connection (TCP) request: IP does not match: ctrl %x, data %x", - (unsigned int)sinc.sin_addr.s_addr, (unsigned int)sind.sin_addr.s_addr); - CloseConnection(cli); - return; - } - if(htonl(ipc) != sinc.sin_addr.s_addr || htons(portc) != sinc.sin_port) { - fd_control[cli].write_cmd("TCP: Error in request (invalid IP:port).\r\n"); - LOGMSG("Invalid data connection (TCP) request: control IP:port does not match" - "control: %x:%d client: %x:%d", - (unsigned int)sinc.sin_addr.s_addr, (unsigned int)sinc.sin_port, - (unsigned int)htonl(ipc), (unsigned int)htons(portc)); - CloseConnection(cli); - return; - } - - /* close old data connection */ - CloseDataConnection(clientId); - - /* change connection type */ - - fd_control[cli].write_cmd("DATA\r\n"); - fd_data[clientId] = fd_control[cli].handle(true); - - cli = clientId; - - if (m_Writer[cli]) - delete m_Writer[cli]; - m_Writer[cli] = new cTcpWriter(fd_data[cli]); - - if (m_Header) - m_Writer[cli]->Put(0, m_Header, m_HeaderLength); - - /* not anymore control connection, so dec primary device reference counter */ - cXinelibDevice::Instance().ForcePrimaryDevice(false); -} - -void cXinelibServer::Handle_Control_RTP(int cli, const char *arg) -{ - LOGDBG("Trying RTP connection ..."); - - CloseDataConnection(cli); - -#if VDRVERSNUM > 10700 - // UDP/RTP not MPEG-TS compatible yet - fd_control[cli].write_cmd("RTP: RTP transport not implemented for vdr-1.7.x.\r\n"); - LOGMSG("RTP transport not implemented for vdr-1.7.x"); - return; -#endif - - if(!xc.remote_usertp) { - fd_control[cli].write_cmd("RTP: RTP transport disabled in configuration.\r\n"); - LOGMSG("RTP transports disabled"); - return; - } - - fd_control[cli].printf("RTP %s:%d\r\n", xc.remote_rtp_addr, xc.remote_rtp_port); - - if(!m_iMulticastMask && !xc.remote_rtp_always_on) - m_Scheduler->AddRtp(); - - m_bMulticast[cli] = true; - m_iMulticastMask |= (1<<cli); - - // Send padding packet before header (PAT/PMT). - // Client uses first received UDP/RTP packet to test connection. - m_Scheduler->QueuePadding(); - if (m_Header) - m_Scheduler->Queue(0, m_Header, m_HeaderLength); -} - -void cXinelibServer::Handle_Control_UDP(int cli, const char *arg) -{ - LOGDBG("Trying UDP connection ..."); - - CloseDataConnection(cli); - -#if VDRVERSNUM > 10700 - // UDP/RTP not MPEG-TS compatible yet - fd_control[cli].write_cmd("UDP: UDP transport not implemented vor vdr-1.7.x.\r\n"); - LOGMSG("UDP transport not implemented for vdr-1.7.x"); - return; -#endif - - if(!xc.remote_useudp) { - fd_control[cli].write_cmd("UDP: UDP transport disabled in configuration.\r\n"); - LOGMSG("UDP transport disabled in configuration"); - return; - } - - int fd = sock_connect(fd_control[cli].handle(), atoi(arg), SOCK_DGRAM); - if(fd < 0) { - LOGERR("socket() for UDP failed"); - fd_control[cli].write_cmd("UDP: Socked failed.\r\n"); - return; - } - - fd_control[cli].write_cmd("UDP OK\r\n"); - m_bUdp[cli] = true; - fd_data[cli] = fd; - m_Scheduler->AddHandle(fd); - - // Send padding packet before header (PAT/PMT). - // Client uses first received UDP/RTP packet to test connection. - m_Scheduler->QueuePadding(); - if (m_Header) - m_Scheduler->Queue(0, m_Header, m_HeaderLength); -} - -void cXinelibServer::Handle_Control_KEY(int cli, const char *arg) -{ - TRACE("cXinelibServer received KEY " << buf); - - if(!xc.remote_keyboard) { - LOGMSG("Handle_Control_KEY(%s): Remote keyboard disabled in config", arg); - return; - } - - char buf[256], *pt, *key; - bool repeat = false, release = false; - strn0cpy(buf, arg, sizeof(buf)); - - size_t n = *buf ? strlen(buf)-1 : 0; - while(n && buf[n]==' ') buf[n--]=0; /* trailing spaces */ - if(NULL != (key=strchr(buf, ' '))) { - while(*key == ' ') - *(key++) = 0; - if(NULL != (pt = strchr(key, ' '))) { - *(pt++) = 0; - if(strstr(pt, "Repeat")) - repeat = true; - if(strstr(pt, "Release")) - release = true; - } - cXinelibThread::KeypressHandler(buf, key, repeat, release); - } else { - cXinelibThread::KeypressHandler(NULL, buf, repeat, release); - } -} - -void cXinelibServer::Handle_Control_CONFIG(int cli) -{ - m_bConfigOk[cli] = true; - - fd_control[cli].set_nodelay(true); - - fd_control[cli].printf("NOVIDEO %d\r\nLIVE %d\r\n", - m_bNoVideo?1:0, m_bLiveMode?1:0); - - SetVolume(m_Volume); - - Configure(); - - fd_control[cli].write_cmd("CLEAR\r\n"); - - if(m_bPlayingFile && *m_FileName) { - Unlock(); - int pos = cXinelibDevice::Instance().PlayFileCtrl("GETPOS"); - Lock(); - if(m_bPlayingFile && *m_FileName) { - fd_control[cli].printf("PLAYFILE %d %s %s\r\n", - (pos>0?pos/1000:0), xc.audio_visualization, *m_FileName); - } - } - - cXinelibOsdProvider::RefreshOsd(); -} - -void cXinelibServer::Handle_Control_UDP_RESEND(int cli, const char *arg) -{ - unsigned int seq1, seq2; - uint64_t pos; - - if( (!fd_data[cli] || !m_bUdp[cli]) && - (!m_bMulticast[cli])) { - LOGMSG("Got invalid re-send request: no udp/rtp in use"); - return; - } - - if(3 == sscanf(arg, "%d-%d %" PRIu64, &seq1, &seq2, &pos)) { - - if(seq1 <= UDP_SEQ_MASK && seq2 <= UDP_SEQ_MASK && pos <= m_StreamPos) { - - if(fd_data[cli] >= 0) - m_Scheduler->ReSend(fd_data[cli], pos, seq1, seq2); - else - m_Scheduler->ReSend(-1, pos, seq1, seq2); - } else { - LOGMSG("Invalid re-send request: %s (send pos=%" PRIu64 ")", - arg, m_StreamPos); - } - } else { - LOGMSG("Invalid re-send request: %s (send pos=%" PRIu64 ")", - arg, m_StreamPos); - } -} - -void cXinelibServer::Handle_Control_GRAB(int cli, const char *arg) -{ - cGrabReplyFuture *f; - int token = -1, size = 0; - if(2 == sscanf(arg, "%d %d", &token, &size)) { - if(size > 0 && size < 20480000) { - uchar *result = (uchar*)malloc(size); - Unlock(); /* may take a while ... */ - ssize_t n = fd_control[cli].read(result, size, 2000); - Lock(); - if(n == size) { - if(NULL != (f = (cGrabReplyFuture*)m_Futures->Get(token))) { - grab_result_t r; - r.Size = size; - r.Data = result; - m_Futures->Del(f, token); - f->Set(r); - result = NULL; - } else { - LOGMSG("cXinelibServer: Grab image discarded"); - } - } else { - LOGMSG("cXinelibServer: Grab result read() failed"); - CloseConnection(cli); - } - free(result); - } else if(NULL != (f = (cGrabReplyFuture*)m_Futures->Get(token))) { - grab_result_t r; - r.Size = 0; - r.Data = NULL; - m_Futures->Del(f, token); - f->Set(r); - } - } -} - -void cXinelibServer::Handle_Control_CONTROL(int cli, const char *arg) -{ - fd_control[cli].printf("VDR-" VDRVERSION " " - "xineliboutput-" XINELIBOUTPUT_VERSION " " - "READY\r\nCLIENT-ID %d\r\n", cli); - m_ConnType[cli] = ctControl; -} - -static int strcmp_escaped(const char *s1, const char *s2) -{ - if(!strncmp(s1, "file:", 5)) - s1 += 5; - - while(*s1 && *s2) { - int c1 = *s1; - int c2 = *s2; - if(c1 == '%' && s1[1] && s1[2] && 1 == sscanf(s1+1, "%02x", &c1)) s1 += 2; - if(c2 == '%' && s2[1] && s2[2] && 1 == sscanf(s2+1, "%02x", &c2)) s2 += 2; - if(c1 < c2) return -1; - if(c1 > c2) return 1; - s1++; s2++; - } - return *s1 ? -1 : *s2 ? 1 : 0; -} - -void cXinelibServer::Handle_Control_HTTP(int cli, const char *arg) -{ - // Parse request - if(m_ConnType[cli] == ctDetecting || !m_State[cli]) { - LOGDBG("HTTP request: %s", arg); - - DELETENULL(m_Writer[cli]); - DELETENULL(m_State[cli]); - - m_State[cli] = new cConnState; - if( !m_State[cli]->SetCommand(arg) || - strncmp(m_State[cli]->Version(), "HTTP/1.", 7) || - strcmp(m_State[cli]->Name(), "GET")) { - LOGMSG("invalid HTTP request: %s", arg); - CloseConnection(cli); - return; - } - m_ConnType[cli] = ctHttp; - return; - } - - // Handle request - else if(m_ConnType[cli] == ctHttp) { - LOGDBG("HTTP(%d): %s", cli, arg); - - // Collect headers - if(*arg) { - m_State[cli]->AddHeader(arg); - return; - } - - LOGMSG("HTTP Request complete"); - - // - // primary device output (PES) - // - if(!strcmp(m_State[cli]->Uri(), "/")) { - - if(!xc.remote_use_http) { - LOGMSG("HTTP transport disabled in configuration"); - fd_control[cli].write_cmd(HTTP_REPLY_404); - LOGDBG("HTTP Reply: HTTP/1.1 404 Not Found"); - CloseConnection(cli); - return; - } - - LOGMSG("HTTP streaming primary device feed"); - fd_control[cli].write_cmd(HTTP_REPLY_200_PRIMARY); -#if 0 - // pack header (scr 0, mux rate 0x6270) - fd_control[cli].write( - "\x00\x00\x01\xba" - "\x44\x00\x04\x00" "\x04\x01\x01\x89" "\xc3\xf8", 14); - // system header (streams C0, E0, BD, BF) - fd_control[cli].write( - "\x00\x00\x01\xbb" "\x00\x12" - "\x80\xc4\xe1" "\x00\xe1" "\x7f" - "\xb9\xe0\xe8" "\xb8\xc0\x20" "\xbd\xe0\x3a" "\xbf\xe0\x02", 24); -#endif - m_Writer[cli] = new cRawWriter(fd_control[cli].handle(), KILOBYTE(1024)); - - if (m_Header) - m_Writer[cli]->Put(0, m_Header, m_HeaderLength); - - DELETENULL(m_State[cli]); - return; - } - -#if 0 - // - // primary device output (TS) - // - if(!strcmp(m_State[cli]->Uri(), "/TS")) { - LOGMSG("HTTP streaming primary device feed (TS)"); - fd_control[cli].write_cmd(HTTP_REPLY_200_PRIMARY_TS); - m_Writer[cli] = new cTsWriter(fd_control[cli].handle(), KILOBYTE(1024)); - DELETENULL(m_State[cli]); - return; - } -#endif - -#if 0 /* for testing */ - else if(!strcmp(m_State[cli]->Uri(), "/test.avi")) { - LOGMSG("HTTP streaming test file"); - - // detach socket - new cHttpStreamer(fd_control[cli].handle(true), "/tmp/test.avi", m_State[cli]); - m_State[cli] = NULL; - CloseConnection(cli); - return; - } -#endif - - // - // currently playing media file - // - else if(!strncmp(m_State[cli]->Uri(), "/PLAYFILE", 9)) { - - if(!xc.remote_http_files) { - LOGMSG("HTTP transport for media files disabled in configuration"); - fd_control[cli].write_cmd(HTTP_REPLY_404); - LOGDBG("HTTP Reply: HTTP/1.1 404 Not Found"); - CloseConnection(cli); - return; - } - - if( *m_FileName && m_bPlayingFile) { - cString file = m_FileName; - const char *pos = strstr(m_FileName, "#subtitle:"); - if(pos) - file.Truncate(pos - m_FileName); - bool Allow = ( !strcmp_escaped(file, m_State[cli]->Uri() + 9) - || (pos && !strcmp_escaped(pos + 10, m_State[cli]->Uri() + 9))); - if(Allow) { - LOGMSG("HTTP streaming media file"); - - // detach socket - new cHttpStreamer(fd_control[cli].handle(true), m_State[cli]->Uri() + 9, m_State[cli]); - m_State[cli] = NULL; - CloseConnection(cli); - return; - } - LOGDBG("HTTP Unauthorized request: %s", *m_State[cli]->Uri()); - } - else - LOGDBG("No currently playing file"); - } - - // - // nothing else will be served ... - // - LOGMSG("Rejected HTTP request for \'%s\'", *m_State[cli]->Uri()); - fd_control[cli].write_cmd(HTTP_REPLY_404); - LOGDBG("HTTP Reply: HTTP/1.1 404 Not Found"); - CloseConnection(cli); - } -} - -#define RTSP_200_OK "RTSP/1.0 200 OK\r\n" \ - "CSeq: %d\r\n" -#define RTSP_401 "RTSP/1.0 401 Unauthorized\r\n" \ - "CSeq: %d\r\n" RTSP_FIN -#define RTSP_415 "RTSP/1.0 415 Unsupported media type\r\n" \ - "CSeq: %d\r\n" RTSP_FIN -#define RTSP_461 "RTSP/1.0 461 Unsupported transport\r\n" \ - "CSeq: %d\r\n" RTSP_FIN -#define RTSP_501 "RTSP/1.0 501 Not implemented\r\n" \ - "CSeq: %d\r\n" RTSP_FIN -#define RTSP_FIN "\r\n", CSeq - -#define RTSPOUT(x...) do { fd_control[cli].printf(x); LOGMSG("RTSP TX:" x); } while(0) -//#define RTSPOUT(x...) fd_control[cli].printf_cmd(x) - -void cXinelibServer::Handle_Control_RTSP(int cli, const char *arg) -{ - // - // Minimal RTSP (RFC 2326) server implementation - // - - - // - // collect request and headers - // - if(m_ConnType[cli] == ctDetecting || !m_State[cli]) { - LOGDBG("RTSP request: %s", arg); - - DELETENULL(m_State[cli]); - m_State[cli] = new cConnState; - - if( !m_State[cli]->SetCommand(arg) || - strcmp(m_State[cli]->Version(), "RTSP/1.0")) { - LOGMSG("invalid RTSP request: %s", arg); - CloseConnection(cli); - return; - } - m_ConnType[cli] = ctRtsp; - return; - } - - // - // Process complete request - // - else if(m_ConnType[cli] == ctRtsp) { - LOGDBG("RTSP(%d): %s", cli, arg); - - if(*arg) { - m_State[cli]->AddHeader(arg); - return; - } - - cHeader *cseq = m_State[cli]->Header("CSeq"); - int CSeq = cseq ? cseq->IntValue() : -1; - LOGMSG("RTSP Request complete (cseq %d)", CSeq); - - if(!xc.remote_use_rtsp) { - LOGMSG("RTSP transport disabled in configuration"); - fd_control[cli].write_cmd(RTSP_401); - LOGDBG("HTTP Reply: HTTP/1.1 404 Not Found"); - CloseConnection(cli); - return; - } - - // - // OPTIONS rtsp://127.0.0.1:37890 RTSP/1.0 - // CSeq: 1 - // - if(!strcmp(m_State[cli]->Name(), "OPTIONS")) { - RTSPOUT(RTSP_200_OK - "Public: DESCRIBE, SETUP, TEARDOWN, PLAY\r\n" - RTSP_FIN); - } // OPTIONS - - // - // DESCRIBE rtsp://127.0.0.1:37890 RTSP/1.0 - // CSeq: 2 - // Accept: application/sdp - // - else if(!strcmp(m_State[cli]->Name(), "DESCRIBE")) { - cHeader *accept = m_State[cli]->Header("Accept"); - if(accept && strstr(accept->Value(), "application/sdp")) { - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - char buf[64]; - uint32_t payload_type = VDRVERSNUM > 10702 ? SDP_PAYLOAD_MPEG_TS : SDP_PAYLOAD_MPEG_PES; - fd_control[cli].getsockname((struct sockaddr *)&sin, &len); - const char *sdp_descr = vdr_sdp_description(cxSocket::ip2txt(sin.sin_addr.s_addr, - sin.sin_port, buf), - 2001, - xc.listen_port, - xc.remote_rtp_addr, - payload_type, - /*m_ssrc*/0x4df73452, - xc.remote_rtp_port, - xc.remote_rtp_ttl); - size_t sdplen = sdp_descr ? strlen(sdp_descr) : 0; - RTSPOUT(RTSP_200_OK - "Content-Type: application/sdp\r\n" - "Content-Length: %lu\r\n" - "\r\n", - CSeq, (unsigned long)sdplen); - fd_control[cli].write_cmd(sdp_descr, sdplen); - } else { - RTSPOUT(RTSP_415 /*UNSUPPORTED_MEDIATYPE*/); - } - } // DESCRIBE - - // - // SETUP rtsp://127.0.0.1:37890/ RTSP/1.0 - // CSeq: 15 - // Transport: RTP/AVP;unicast;client_port=37890-37891 - // User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) - // - else if(!strcmp(m_State[cli]->Name(), "SETUP")) { - cHeader *transport = m_State[cli]->Header("Transport"); - int urtp=0, mrtp=0, tcp=0; - if(transport && - ( (strstr(transport->Value(), "RTP/AVP;multicast") && (mrtp=1)) || - (strstr(transport->Value(), "RTP/AVP;unicast") && (urtp=1)) || - (strstr(transport->Value(), "RTP/AVP;interleaved") && (tcp=1)))) { - //if(!mrtp) - // sprintf(buf, "RTSP/1.0 461 Unsupported transport\r\n" RTSP_H_CSEQ RTSP_OK_FIN); - //else - RTSPOUT(RTSP_200_OK - "Session: %u\r\n" - "Transport: RTP/AVP;multicast;destination=224.8.4.9;server_port=37890-37891\r\n" - RTSP_FIN, - cli); - } else { - RTSPOUT(RTSP_461 /*UNSUPPORTED_TRANSPORT*/ ); - } - } // SETUP - - // - // PLAY rtsp://127.0.0.1:37890 RTSP/1.0 - // CSeq: 13 - // Session: 0 - // Range: npt=0.000- - // User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) - // - else if(!strcmp(m_State[cli]->Name(), "PLAY")) { - RTSPOUT(RTSP_200_OK - RTSP_FIN); - - if(!m_iMulticastMask && !xc.remote_rtp_always_on) - m_Scheduler->AddRtp(); - - m_bMulticast[cli] = true; - m_iMulticastMask |= (1<<cli); -#if 0 - //udp - int fd = sock_connect(fd_control[cli], atoi(arg), SOCK_DGRAM); - if(fd < 0) { - LOGERR("socket() for UDP failed"); - write_cmd(fd_control[cli], "UDP: Socked failed.\r\n"); - return; - } - m_bUdp[cli] = true; - fd_data[cli] = fd; - m_Scheduler->AddHandle(fd); -#endif - } // PLAY - - // - // TEARDOWN rtsp://127.0.0.1:37890 RTSP/1.0 - // CSeq: 39 - // Session: 1 - // User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) - // - else if(!strcmp(m_State[cli]->Name(), "TEARDOWN")) { - RTSPOUT(RTSP_200_OK - RTSP_FIN); - CloseConnection(cli); - } // TEARDOWN - - // - // unknown/unsupported request - // - else { - LOGMSG("Unsupported RTSP request: %s", *m_State[cli]->Name()); - RTSPOUT(RTSP_501 /*NOT_IMPLEMENTED*/); - } // unsupported request - - - // dispose buffer - DELETENULL(m_State[cli]); - - } // ConnectionType == ctRtsp -} - -void cXinelibServer::Handle_Control(int cli, const char *cmd) -{ - TRACEF("cXinelibServer::Handle_Control"); - -#ifdef LOG_CONTROL_MESSAGES - static FILE *flog = fopen("/video/control.log","w"); - if (flog) { - fprintf(flog,"CTRL (%d): %s\n",cli,cmd); fflush(flog); - } -#endif - - //LOGDBG("Server received %s", cmd); - TRACE("Server received " << cmd); - - /* Order of tests is significant !!! - (example: UDP 2\r\n or UDP FULL 1\r\n) */ - - if(!strncasecmp(cmd, "OPTIONS ", 8) || - !strncasecmp(cmd, "SETUP ", 6) || - !strncasecmp(cmd, "DESCRIBE ", 9) || - m_ConnType[cli] == ctRtsp) { - - Handle_Control_RTSP(cli, cmd); - - } else if(!strncasecmp(cmd, "GET ", 4) || - m_ConnType[cli] == ctHttp) { - - Handle_Control_HTTP(cli, cmd); - - } else if(!strncasecmp(cmd, "PIPE OPEN", 9)) { - LOGDBG("Pipe open"); - - } else if(!strncasecmp(cmd, "PIPE", 4)) { - Handle_Control_PIPE(cli, cmd+4); - - } else if(!strncasecmp(cmd, "RTP", 3)) { - Handle_Control_RTP(cli, cmd+4); - - } else if(!strncasecmp(cmd, "UDP FULL", 8)) { - - } else if(!strncasecmp(cmd, "UDP RESEND ", 11)) { - Handle_Control_UDP_RESEND(cli, cmd+11); - - } else if(!strncasecmp(cmd, "UDP ", 4)) { - Handle_Control_UDP(cli, cmd+4); - - } else if(!strncasecmp(cmd, "DATA ", 5)) { - Handle_Control_DATA(cli, cmd+5); - - } else if(!strncasecmp(cmd, "KEY ", 4)) { - Handle_Control_KEY(cli, cmd+4); - - } else if(!strncasecmp(cmd, "CONFIG", 6)) { - Handle_Control_CONFIG(cli); - - } else if(!strncasecmp(cmd, "STC ", 4)) { - int64_t pts = -1; - if(1 == sscanf(cmd+4, "%" PRId64, &pts)) - m_StcFuture->Set(pts); - - } else if(!strncasecmp(cmd, "ENDOFSTREAM", 11)) { - m_bEndOfStreamReached = true; - - } else if(!strncasecmp(cmd, "RESULT ", 7)) { - int token = -1, result = -1; - if(2 == sscanf(cmd+7, "%d %d", &token, &result)) { - cReplyFuture *f = m_Futures->Get(token); - if(f) { - m_Futures->Del(f, token); - f->Set(result); - } - } - - } else if(!strncmp(cmd, "INFO ", 5)) { - if(!*xc.local_frontend || !strncmp(xc.local_frontend, "none", 4)) - cXinelibThread::InfoHandler(cmd+5); - - } else if(!strncasecmp(cmd, "GRAB ", 5)) { - Handle_Control_GRAB(cli, cmd+5); - - } else if(!strncasecmp(cmd, "CLOSE", 5)) { - CloseConnection(cli); - - } else if(!strncasecmp(cmd, "CONTROL", 7)) { - Handle_Control_CONTROL(cli, cmd); - - } -} - -void cXinelibServer::Read_Control(int cli) -{ - int n; - while((n = fd_control[cli].recv(&m_CtrlBuf[ cli ][ m_CtrlBufPos[cli] ], 1)) == 1) { - - ++m_CtrlBufPos[cli]; - - if( m_CtrlBufPos[cli] > CTRL_BUF_SIZE-2) { - LOGMSG("Received too long control message from client %d (%d bytes)", - cli, m_CtrlBufPos[cli]); - LOGMSG("%81s",m_CtrlBuf[cli]); - CloseConnection(cli); - return; - } - - if( m_CtrlBufPos[cli] > 1 && - m_CtrlBuf[ cli ][ m_CtrlBufPos[cli] - 2 ] == '\r' && - m_CtrlBuf[ cli ][ m_CtrlBufPos[cli] - 1 ] == '\n') { - - m_CtrlBufPos[cli] -= 2; - m_CtrlBuf[ cli ][ m_CtrlBufPos[cli] ] = 0; - - Handle_Control(cli, m_CtrlBuf[cli]); - - m_CtrlBufPos[cli] = 0; - } - } - if (n == 0) { - LOGMSG("Client connection %d closed", cli); - CloseConnection(cli); - } -} - -void cXinelibServer::Handle_ClientConnected(int fd) -{ - char buf[64]; - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - int cli; - - for(cli=0; cli<MAXCLIENTS; cli++) - if(!fd_control[cli].open()) - break; - - if(getpeername(fd, (struct sockaddr *)&sin, &len)) { - LOGERR("getpeername() failed, dropping new incoming connection %d", cli); - CLOSESOCKET(fd); - return; - } - - LOGMSG("Client %d connected: %s", cli, - cxSocket::ip2txt(sin.sin_addr.s_addr, sin.sin_port, buf)); - - bool accepted = SVDRPhosts.Acceptable(sin.sin_addr.s_addr); - if(!accepted) { - const char *msg = "Access denied.\r\n"; - ssize_t len = strlen(msg); - LOGMSG("Address not allowed to connect (svdrphosts.conf)."); - if(write(fd, msg, len) != len) - LOGERR("Write failed."); - CLOSESOCKET(fd); - return; - } - - if(cli>=xc.remote_max_clients || cli>=MAXCLIENTS) { - const char *msg = "Server busy.\r\n"; - ssize_t len = strlen(msg); - // too many clients - LOGMSG("Too many clients, connection refused"); - if(write(fd, msg, len) != len) - LOGERR("Write failed."); - CLOSESOCKET(fd); - return; - } - - if (fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK) == -1) { - LOGERR("Error setting control socket to nonblocking mode"); - CLOSESOCKET(fd); - } - - CloseDataConnection(cli); - - m_OsdTimeouts[cli] = 0; - m_CtrlBufPos[cli] = 0; - m_CtrlBuf[cli][0] = 0; - m_ConnType[cli] = ctDetecting; - fd_control[cli].set_handle(fd); - fd_control[cli].set_buffers(KILOBYTE(128), KILOBYTE(128)); - cXinelibDevice::Instance().ForcePrimaryDevice(true); -} - -void cXinelibServer::Handle_Discovery_Broadcast(void) -{ - if(!xc.remote_usebcast) { - LOGDBG("BROADCASTS disabled in configuration"); - CLOSESOCKET(fd_discovery); - return; - } - - char buf[DISCOVERY_MSG_MAXSIZE] = {0}; - struct sockaddr_in from; - - if(udp_discovery_recv(fd_discovery, buf, 0, &from) > 0) - if(udp_discovery_is_valid_search(buf)) { - - // Reply only if we can accept one more client - int clients = 0; - for(int c=0; c<MAXCLIENTS; c++) - if(fd_control[c].open()) - clients++; - if(clients >= xc.remote_max_clients) { - LOGMSG("Not replying to discovery broadcast (too many clients)"); - return; - } - - udp_discovery_broadcast(fd_discovery, m_Port, xc.remote_local_ip); - } -} - -void cXinelibServer::Action(void) -{ - TRACEF("cXinelibServer::Action"); - - int i, fds=0; - pollfd pfd[MAXCLIENTS]; - - /* higher priority */ - SetPriority(-1); - - sched_param temp; - temp.sched_priority = 2; - - /* request real-time scheduling */ - if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) { - LOGDBG("cXinelibServer priority set successful SCHED_RR %d [%d,%d]", - temp.sched_priority, - sched_get_priority_min(SCHED_RR), - sched_get_priority_max(SCHED_RR)); - } else { - LOGDBG("cXinelibServer: Can't set priority to SCHED_RR %d [%d,%d]", - temp.sched_priority, - sched_get_priority_min(SCHED_RR), - sched_get_priority_max(SCHED_RR)); - } - errno = 0; - - Lock(); - Listen(m_Port); - m_bReady=true; - - if(fd_listen>=0) - while (!GetStopSignal() && fds>=0) { - - fds = 0; - if(fd_listen>=0) { - pfd[fds].fd = fd_listen; - pfd[fds++].events = POLLIN; - } - if(fd_discovery >= 0) { - pfd[fds].fd = fd_discovery; - pfd[fds++].events = POLLIN; - } - - for(i=0; i<MAXCLIENTS; i++) { - if(fd_control[i].open()) { - pfd[fds].fd = fd_control[i].handle(); - pfd[fds++].events = POLLIN; - } - if(fd_data[i]>=0) { - pfd[fds].fd = fd_data[i]; - pfd[fds++].events = 0; /* check for errors only */ - } - } - Unlock(); - - int err = poll(pfd,fds,1000); - - if(err < 0) { - LOGERR("cXinelibServer: poll failed"); - if(!GetStopSignal()) - cCondWait::SleepMs(100); - - } else if(err == 0) { - // poll timeout - - } else { - Lock(); - for(int f=0; f<fds; f++) { - - // Check errors (closed connections etc.) - if(pfd[f].revents & (POLLERR|POLLHUP|POLLNVAL)) { - - if(pfd[f].fd == fd_listen) { - LOGERR("cXinelibServer: listen socket error"); - CLOSESOCKET(fd_listen); - cCondWait::SleepMs(100); - Listen(m_Port); - } /* fd_listen */ - - else if(pfd[f].fd == fd_discovery) { - LOGERR("cXinelibServer: discovery socket error"); - CLOSESOCKET(fd_discovery); - } /* fd_discovery */ - - else /* fd_data[] / fd_control[] */ { - for(i=0; i<MAXCLIENTS; i++) { - if(pfd[f].fd == fd_data[i] || pfd[f].fd == fd_control[i].handle()) { - LOGMSG("Client %d disconnected", i); - CloseConnection(i); - } - } - } /* fd_data / fd_control */ - - } /* Check ERRORS */ - - // Check ready for reading - else if(pfd[f].revents & POLLIN) { - - // New connection - if(pfd[f].fd == fd_listen) { - int fd = accept(fd_listen, 0, 0); - if(fd>=0) - Handle_ClientConnected(fd); - } /* fd_listen */ - - // VDR Discovery - else if(pfd[f].fd == fd_discovery) { - Handle_Discovery_Broadcast(); - } /* fd_discovery */ - - // Control data - else { - for(i=0; i<MAXCLIENTS; i++) { - if(pfd[f].fd == fd_control[i].handle()) { - Read_Control(i); - break; - } - } - } /* fd_control */ - - } /* Check ready for reading */ - - } /* for(fds) */ - - Unlock(); - } /* Check poll result */ - - Lock(); - } /* while running */ - - m_bReady = false; - m_bIsFinished = true; - Unlock(); -} diff --git a/frontend_svr.h b/frontend_svr.h deleted file mode 100644 index 73117944..00000000 --- a/frontend_svr.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * frontend_svr.h: server for remote frontends - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: frontend_svr.h,v 1.23 2009-03-20 07:20:53 phintuka Exp $ - * - */ - -#ifndef __XINELIB_FRONTEND_SVR_H -#define __XINELIB_FRONTEND_SVR_H - - -#include "config.h" -#include "frontend.h" - -//----------------------------- cXinelibServer -------------------------------- - -#define CTRL_BUF_SIZE 1024 - -class cBackgroundWriterI; -class cUdpScheduler; -class cStcFuture; -class cCmdFutures; -class cConnState; - -#include "tools/cxsocket.h" - -class cXinelibServer : public cXinelibThread -{ - - public: - cXinelibServer(int listen_port); - virtual ~cXinelibServer(); - - // Thread control - virtual void Stop(void); - - protected: - virtual void Action(void); - - public: - // Playback control - virtual void TrickSpeed(int Speed); - - // Data transfer - virtual int Poll(cPoller &Poller, int TimeoutMs); - virtual bool Flush(int TimeoutMs); - virtual void Clear(void); - virtual int Play_PES(const uchar *buf, int len); - virtual void OsdCmd(void *cmd); - virtual int64_t GetSTC(); - virtual void SetHDMode(bool On); - - // Image grabbing - virtual uchar *GrabImage(int &Size, bool Jpeg, int Quality, - int SizeX, int SizeY); - // Playback files - virtual int PlayFileCtrl(const char *Cmd, int TimeoutMs=-1); - virtual bool EndOfStreamReached(void); - - // Configuration - virtual bool Listen(int port); - -protected: - // Playback control - virtual int Xine_Control(const char *cmd); - virtual int Xine_Control_Sync(const char *cmd); - -protected: - - // Handling of messages from client(s) - - void Handle_Discovery_Broadcast(void); - void Handle_ClientConnected(int fd); - - void Read_Control(int cli); - void Handle_Control(int cli, const char *cmd); - - void Handle_Control_PIPE (int cli, const char *arg); - void Handle_Control_RTP (int cli, const char *arg); - void Handle_Control_UDP (int cli, const char *arg); - void Handle_Control_DATA (int cli, const char *arg); - void Handle_Control_KEY (int cli, const char *arg); - void Handle_Control_UDP_RESEND(int cli, const char *arg); - void Handle_Control_CONFIG (int cli); - void Handle_Control_GRAB (int cli, const char *arg); - void Handle_Control_CONTROL (int cli, const char *arg); - void Handle_Control_HTTP (int cli, const char *arg); - void Handle_Control_RTSP (int cli, const char *arg); - - void CloseDataConnection(int cli); - void CloseConnection (int cli); - -protected: - - // Data - - int m_Port; - int m_ServerId; - - int fd_listen; - int fd_discovery; - - cxSocket fd_control[MAXCLIENTS]; - int fd_data [MAXCLIENTS]; - - int m_OsdTimeouts[MAXCLIENTS]; - char m_CtrlBuf [MAXCLIENTS][CTRL_BUF_SIZE + 1]; - int m_CtrlBufPos [MAXCLIENTS]; - - int m_ConnType [MAXCLIENTS]; // Control connection type. See frontend_svr.c. - bool m_bUdp [MAXCLIENTS]; // Client uses UDP transport - bool m_bMulticast [MAXCLIENTS]; // Client uses multicast RTP - bool m_bConfigOk [MAXCLIENTS]; // Client has been configured - int m_iMulticastMask; // bit [cli] is 1 or 0. 1 == multicast in use. - int m_MasterCli; // Master client (controls playback speed) - - cString m_PipesDir; - - cBackgroundWriterI *m_Writer[MAXCLIENTS]; // buffered output (pipe/tcp/http) - cConnState *m_State[MAXCLIENTS]; // connection state (http/rtsp) - cUdpScheduler *m_Scheduler; - bool m_Master; - - // Storage for return values of pending RPCs - cStcFuture *m_StcFuture; - cCmdFutures *m_Futures; - - int m_Token; - int AllocToken(void); - bool HasClients(void); - - // Cache current PAT/PMT for new clients - uchar *m_Header; - size_t m_HeaderLength; // bytes used - size_t m_HeaderSize; // bytes allocated - public: - void SetHeader(const uchar *Data, int Length, bool Reset = false); -}; - -#endif // __XINELIB_FRONTEND_SVR_H diff --git a/logdefs.c b/logdefs.c deleted file mode 100644 index 063e1924..00000000 --- a/logdefs.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * logdefs.c: Logging and debug output - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: logdefs.c,v 1.2 2008-11-04 12:29:36 phintuka Exp $ - * - */ - -#include "logdefs.h" - -#include <stdio.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <stdarg.h> - -#ifndef __APPLE__ -# include <linux/unistd.h> /* syscall(__NR_gettid) */ -#endif - -/* next symbol is dynamically linked from input plugin */ -int LogToSysLog __attribute__((visibility("default"))) = 1; /* log to syslog instead of console */ - -void x_syslog(int level, const char *module, const char *fmt, ...) -{ - va_list argp; - char buf[512]; - - va_start(argp, fmt); - vsnprintf(buf, 512, fmt, argp); - buf[sizeof(buf)-1] = 0; - -#ifndef __APPLE__ - if(!LogToSysLog) { - fprintf(stderr,"[%ld] %s%s\n", (long int)syscall(__NR_gettid), module, buf); - } else { - syslog(level, "[%ld] %s%s", (long int)syscall(__NR_gettid), module, buf); - } -#else - if(!LogToSysLog) { - fprintf(stderr, "%s%s\n", module, buf); - } else { - syslog(level, "%s%s", module, buf); - } -#endif - - va_end(argp); -} - diff --git a/logdefs.h b/logdefs.h deleted file mode 100644 index f9076439..00000000 --- a/logdefs.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * logdefs.h: Logging and debug output - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: logdefs.h,v 1.13 2008-11-20 11:46:31 rofafor Exp $ - * - */ - -#ifndef _LOGDEFS_H_ -#define _LOGDEFS_H_ - -/* - * Default module name (goes to every log line) - */ - -#ifndef LOG_MODULENAME -# define LOG_MODULENAME "[xine..put] " -#endif - -/* - * Logging functions, should not be used directly - */ - -#include <syslog.h> /* logging levels: LOG_ERR, LOG_INFO, LOG_DEBUG */ - -#define SYSLOGLEVEL_NONE 0 -#define SYSLOGLEVEL_ERRORS 1 -#define SYSLOGLEVEL_INFO 2 -#define SYSLOGLEVEL_DEBUG 3 -#define SYSLOGLEVEL_VERBOSE 4 - -#if defined(esyslog) -# define x_syslog(l,m,x...) syslog_with_tid(l, m x) -#else - -# ifdef __cplusplus - extern "C" { -# endif - - /* from xine_frontend.c or vdr/tools.c: */ - extern int SysLogLevel; /* errors, info, debug */ - - /* from logdefs.c: */ - extern int LogToSysLog; - - void x_syslog(int level, const char *module, const char *fmt, ...) - __attribute__((format (printf, 3, 4))) - __attribute__((visibility("default"))); - -# ifdef __cplusplus - } /* extern "C" { */ -# endif - -#endif /* VDR */ - -#ifdef NEED_x_syslog -# error NEED_x_syslog is deprecated -#endif - - -/* - * Macros used for logging - */ - -#include <errno.h> - -#define LOG_ERRNO x_syslog(LOG_ERR, LOG_MODULENAME, " (ERROR (%s,%d): %s)", \ - __FILE__, __LINE__, strerror(errno)) - -#define LOGERR(x...) do { \ - if(SysLogLevel > 0) { \ - x_syslog(LOG_ERR, LOG_MODULENAME, x); \ - if(errno) \ - LOG_ERRNO; \ - } \ - } while(0) -#define LOGMSG(x...) do{ if(SysLogLevel > 1) x_syslog(LOG_INFO, LOG_MODULENAME, x); } while(0) -#define LOGDBG(x...) do{ if(SysLogLevel > 2) x_syslog(LOG_DEBUG, LOG_MODULENAME, x); } while(0) - -#define TRACELINE LOGDBG("at %s:%d %s", __FILE__, __LINE__, __FUNCTION__) - - - -/* - * ASSERT - */ - -#ifdef NDEBUG -# define ASSERT(expr) -#else -# define ASSERT(expr,fatal) \ - do { \ - if(!(expr)) { \ - LOGERR("Asseretion failed: %s at %s:%d (%s)", \ - #expr, __FILE__, __LINE__, __FUNCTION__); \ - if(fatal) \ - abort(); \ - } \ - } while(0) -#endif - - -/* - * Plugin (call)trace - */ - -#ifdef XINELIBOUTPUT_DEBUG -# ifdef __cplusplus -# -# include <fstream> -# include <iostream> -# include <stdio.h> -# -# ifndef TRACE_IDENT -# define TRACE_IDENT "" -# endif -# if defined(XINELIBOUTPUT_DEBUG_STDOUT) -# define TRACE(x) do {std::cout << TRACE_IDENT << x << "\n"; fflush(stdout);}while(0) -# elif defined(XINELIBOUTPUT_DEBUG_STDERR) -# define TRACE(x) do {std::cerr << TRACE_IDENT << x << "\n"; fflush(stderr);}while(0) -# else -# error No trace target ! -# endif -# define TRACEF(x) cTraceFunctionCall _x_cTraceFunctionCall(x); - class cTraceFunctionCall { - public: - const char *m_name; - cTraceFunctionCall(const char *name) : m_name(name) - { TRACE(m_name << " - Enter"); } - ~cTraceFunctionCall() - { TRACE(m_name << " - Leave "); } - }; -# endif -#else -# define TRACE(x) -# define TRACEF(x) -#endif - - -/* - * Execution time tracker: - * log a message when function execution takes longer than expected - */ - -#ifdef __cplusplus -# ifdef TRACK_EXEC_TIME - class cTimeTracker - { - private: - const char *m_Message; - const char *m_Where; - uint64_t m_Start; - uint64_t m_Trigger; - public: - cTimeTracker(const char *Message, int TriggerMs, const char *Where) { - m_Message = Message; - m_Where = Where; - m_Trigger = TriggerMs; - m_Start = cTimeMs::Now(); - } - ~cTimeTracker() { - if(cTimeMs::Now() - m_Start > m_Trigger) - LOGMSG("********** TimeTracker hit in %s: %d ms %s", - m_Where, (int)(cTimeMs::Now() - m_Start), - m_Message?m_Message:""); - } - }; -# define TRACK_TIME(limit) cTimeTracker _timetracker(NULL,limit,__PRETTY_FUNCTION__) -# define TRACK_TIME_EXT(limit,msg) cTrimeTracker __timetracker(msg,limit,__PRETTY_FUNCTION__) -# else -# define TRACK_TIME(limit) -# define TRACK_TIME_EXT(limit,msg) -# endif -# endif - - -#endif /* _LOGDEFS_H_ */ diff --git a/media_player.c b/media_player.c deleted file mode 100644 index f3901fca..00000000 --- a/media_player.c +++ /dev/null @@ -1,1346 +0,0 @@ -/* - * media_player.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: media_player.c,v 1.68 2009-06-02 08:59:45 phintuka Exp $ - * - */ - -#include <unistd.h> - -#include <vdr/config.h> -#include <vdr/status.h> -#include <vdr/interface.h> -#include <vdr/tools.h> - -#include "config.h" -#include "media_player.h" -#include "device.h" -#include "tools/playlist.h" -#include "tools/metainfo_menu.h" -#include "menu.h" - -#include "logdefs.h" - -static void BackToMenu(void) -{ - cRemote::CallPlugin("xineliboutput"); -} - - -// -// cXinelibPlayer -// - -class cXinelibPlayer : public cPlayer -{ - private: - cString m_File; - cString m_ResumeFile; - cString m_SubFile; - - cPlaylist m_Playlist; - - bool m_Error; - bool m_UseResumeFile; - int m_Speed; - - void UpdateNumTracks(void); - - protected: - virtual void Activate(bool On); - - public: - cXinelibPlayer(const char *File, bool Queue = false, const char *SubFile = NULL); - virtual ~cXinelibPlayer(); - - // cPlayer - virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId); - virtual void SetSubtitleTrack(eTrackType Type, const tTrackId *TrackId); - virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); - virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); - - // cXinelibPlayer - void Control(const char *s) { (void)cXinelibDevice::Instance().PlayFileCtrl(s); } - void Control(const char *s, int i) { - cString cmd = cString::sprintf(s, i); - Control(cmd); - } - void SetSpeed(int Speed); - int Speed(void) { return m_Speed; }; - - bool NextFile(int step); - bool Playing(void) { return !(m_Error || cXinelibDevice::Instance().EndOfStreamReached()); } - bool Error(void) { return m_Error; } - void UseResumeFile(bool Val) { m_UseResumeFile = Val; } - - /* Playlist access */ - cPlaylist& Playlist(void) { return m_Playlist; } - const cString& File(void) { return m_File; } - int CurrentFile(void) { return m_Playlist.Current()->Index(); } - int Files(void) { return m_Playlist.Count(); } -}; - -cXinelibPlayer::cXinelibPlayer(const char *File, bool Queue, const char *SubFile) -{ - m_ResumeFile = NULL; - m_UseResumeFile = true; - m_Error = false; - m_Speed = 1; - - if(File) { - size_t len = strlen(File); - if(len && File[len-1] == '/') { - // whole directory, create temporary playlist - m_Playlist.Read(File, true); - m_Playlist.Sort(); - } else if(xc.IsPlaylistFile(File)) { - m_Playlist.Read(File); - } else { - // a single file but not a playlist file, create playlist with only one item - m_Playlist.Read(File); - } - - if(m_Playlist.Count() < 1) - LOGMSG("cXinelibPlayer: nothing to play !"); - - if(m_Playlist.Count() > 0) - m_Playlist.StartScanner(); - - m_File = m_Playlist.Current()->Filename; - m_SubFile = SubFile; - } -} - -cXinelibPlayer::~cXinelibPlayer() -{ - Activate(false); - Detach(); -} - -void cXinelibPlayer::SetAudioTrack(eTrackType Type, const tTrackId *TrackId) -{ - if(IS_DOLBY_TRACK(Type)) - Control("AUDIOSTREAM AC3 %d", (int)(Type - ttDolbyFirst)); - if(IS_AUDIO_TRACK(Type)) - Control("AUDIOSTREAM AC3 %d", (int)(Type - ttAudioFirst)); -} - -void cXinelibPlayer::SetSubtitleTrack(eTrackType Type, const tTrackId *TrackId) -{ - cXinelibDevice::Instance().SetSubtitleTrackDevice(Type); -} - -bool cXinelibPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame) -{ - // Returns the current and total frame index, optionally snapped to the - // nearest I-frame. - int msCurrent = cXinelibDevice::Instance().PlayFileCtrl("GETPOS"); - int msTotal = cXinelibDevice::Instance().PlayFileCtrl("GETLENGTH"); - if(msCurrent>=0 && msTotal>=0) { - Current = msCurrent * 25 / 1000; - Total = msTotal * 25 / 1000; - return true; - } - return false; -} - -bool cXinelibPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) -{ - // Returns the current replay mode (if applicable). - // 'Play' tells whether we are playing or pausing, 'Forward' tells whether - // we are going forward or backward and 'Speed' is -1 if this is normal - // play/pause mode, 0 if it is single speed fast/slow forward/back mode - // and >0 if this is multi speed mode. - Play = (m_Speed>0); - Forward = true; - Speed = abs(m_Speed) - 2; - if(Speed<-1) Speed=-1; - - return true; -} - -void cXinelibPlayer::SetSpeed(int Speed) -{ - m_Speed = Speed; - switch(Speed) { - case -4: Control("TRICKSPEED 8"); break; - case -3: Control("TRICKSPEED 4"); break; - case -2: Control("TRICKSPEED 2"); break; - case 0: Control("TRICKSPEED 0"); break; - default: m_Speed = 1; - case 1: Control("TRICKSPEED 1"); break; - case 2: Control("TRICKSPEED -2"); break; - case 3: Control("TRICKSPEED -4"); break; - case 4: Control("TRICKSPEED -12"); break; - } -} - -bool cXinelibPlayer::NextFile(int step) -{ - if(m_Playlist.Count()>0) { - for(;step < 0; step++) - m_Playlist.Prev(); - for(;step > 0; step--) - m_Playlist.Next(); - - if(!m_Playlist.Current()) - LOGERR("!m_Playlist.Get(m_CurrInd)"); - m_File = *m_Playlist.Current()->Filename; - m_ResumeFile = NULL; - m_SubFile = NULL; - - Activate(true); - return !m_Error; - } - - return false; -} - -void cXinelibPlayer::UpdateNumTracks(void) -{ - // cdda tracks - if(m_Playlist.Count() == 1 && !strcmp("cdda:/", m_Playlist.First()->Filename)) { - int count = cXinelibDevice::Instance().PlayFileCtrl("GETAUTOPLAYSIZE CD", 10000); - if(count>0) { - for(int i=0; i<count; i++) - m_Playlist.Read(cString::sprintf("cdda:/%d", i+1)); - m_Playlist.Del(m_Playlist.First()); - } - } -} - -void cXinelibPlayer::Activate(bool On) -{ - int pos = 0, len = 0, fd = -1; - if(On) { - if(m_UseResumeFile && !*m_ResumeFile) - m_ResumeFile = cString::sprintf("%s.resume", *m_File); - if(m_UseResumeFile && 0 <= (fd = open(m_ResumeFile, O_RDONLY))) { - if(read(fd, &pos, sizeof(int)) != sizeof(int)) - pos = 0; - close(fd); - } - // escape file name and join subtitle file - // Maybe mrls from playlist files should not be escaped ? - // (those may contain #subtitle, #volnorm etc. directives) - cString mrl; - if(*m_SubFile) - mrl = cString::sprintf("%s%s#subtitle:%s%s", - m_File[0] == '/' ? "file:" : "", - *cPlaylist::EscapeMrl(m_File), - m_SubFile[0] == '/' ? "file:" : "", - *cPlaylist::EscapeMrl(m_SubFile)); - else if((*m_File)[0] == '/') - mrl = cString::sprintf("%s%s", - m_File[0] == '/' ? "file:" : "", - *cPlaylist::EscapeMrl(m_File)); - else - mrl = cPlaylist::EscapeMrl(m_File); - - // Start replay - UpdateNumTracks(); - m_Error = !cXinelibDevice::Instance().PlayFile(mrl, pos); - LOGDBG("cXinelibPlayer playing %s (%s)", *m_File, m_Error ? "FAIL" : "OK"); - - if(!m_Error) { - // update playlist metainfo - const char *ti = cXinelibDevice::Instance().GetMetaInfo(miTitle); - const char *tr = cXinelibDevice::Instance().GetMetaInfo(miTracknumber); - const char *al = cXinelibDevice::Instance().GetMetaInfo(miAlbum); - const char *ar = cXinelibDevice::Instance().GetMetaInfo(miArtist); - if(ti && ti[0] && (!*m_Playlist.Current()->Title || !strstr(m_Playlist.Current()->Title, ti))) - m_Playlist.Current()->Title = ti; - if(tr && tr[0]) - m_Playlist.Current()->Tracknumber = tr; - if(al && al[0]) - m_Playlist.Current()->Album = al; - if(ar && ar[0]) - m_Playlist.Current()->Artist = ar; - - UpdateNumTracks(); - } - } else { - if(m_UseResumeFile && *m_ResumeFile) { - pos = cXinelibDevice::Instance().PlayFileCtrl("GETPOS"); - len = cXinelibDevice::Instance().PlayFileCtrl("GETLENGTH"); - if(pos>10000 && pos < (len-10000)) { - pos = (pos/1000) - 10; // skip back 10 seconds ("VDR style") - if(0 <= (fd = open(m_ResumeFile, O_WRONLY | O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { - if(write(fd, &pos, sizeof(int)) != sizeof(int)) { - Skins.QueueMessage(mtInfo, "Error writing resume position !", 5, 30); - } - close(fd); - } else { - Skins.QueueMessage(mtInfo, "Error creating resume file !", 5, 30); - } - } else { - unlink(m_ResumeFile); - } - m_ResumeFile = NULL; - } - cXinelibDevice::Instance().PlayFile(NULL); - m_Error = false; - } -} - -// -// cPlaylistMenu -// - - -class cPlaylistMenu : public cOsdMenu, cPlaylistChangeNotify -{ - protected: - - cPlaylist& m_Playlist; - bool m_NeedsUpdate; - bool& m_RandomPlay; - cCharSetConv m_IC; - - public: - - cPlaylistMenu(cPlaylist &Playlist, bool& RandomPlay); - virtual ~cPlaylistMenu(); - - void Set(bool setCurrentPlaying = false); - void SetCurrentExt(int i); - void SetHelpButtons(void); - - // cOsdMenu - virtual eOSState ProcessKey(eKeys Key); - - // cPlaylistChangeNotify - virtual void PlaylistChanged(const cPlaylistItem *item); -}; - -cPlaylistMenu::cPlaylistMenu(cPlaylist &Playlist, bool& RandomPlay) : - cOsdMenu(tr("Playlist")), - m_Playlist(Playlist), - m_RandomPlay(RandomPlay), - m_IC("UTF-8", cCharSetConv::SystemCharacterTable()) -{ - SetTitle(cString::sprintf("%s: %s", tr("Playlist"), m_IC.Convert(*Playlist.Name()))); - Playlist.Listen(this); - Set(true); -} - -cPlaylistMenu::~cPlaylistMenu() -{ - m_Playlist.Listen(NULL); -} - -void cPlaylistMenu::PlaylistChanged(const cPlaylistItem *item) -{ - m_NeedsUpdate = true; -} - -eOSState cPlaylistMenu::ProcessKey(eKeys Key) -{ - bool hadSubMenu = HasSubMenu(); - - if(m_NeedsUpdate) - Set(); - - eOSState state = cOsdMenu::ProcessKey(Key); - - if(state == osUnknown) { - switch(Key) { - case kBack: - return osEnd; - case kRed: - m_RandomPlay = !m_RandomPlay; - SetHelpButtons(); - return osContinue; - case kGreen: - return AddSubMenu(cMenuXinelib::CreateMenuBrowseFiles(ShowMusic)); - case kYellow: if(m_Playlist.Count() > 1) { - eOSState result = osContinue; - cPlaylistItem *i = m_Playlist.Current(); - if(i->Index() == Current()) { - if(i->Next()) - result = (eOSState)(os_User + i->Index()); /* forces jump to next item */ - else - result = (eOSState)(os_User + i->Index() - 1);/* forces jump to last item */ - } - for(i = m_Playlist.First(); i && i->Index() != Current(); i = m_Playlist.Next(i)); - if(i) - m_Playlist.Del(i); - if(Current() == Count()-1) - SetCurrent(Get(Current()-1)); - Set(); - return result; - } - case kBlue: - m_Playlist.Sort(); - Set(); - return osContinue; - default: break; - } - } - - if(hadSubMenu && !HasSubMenu()) - Set(); - - return state; -} - -void cPlaylistMenu::SetCurrentExt(int i) -{ - SetCurrent(Get(i)); - Set(); -} - -void cPlaylistMenu::SetHelpButtons(void) -{ - SetHelp(!m_RandomPlay ? tr("Button$Random") : tr("Button$Normal"), - tr("Button$Add files"), - m_Playlist.Count()>1 ? tr("Button$Remove") : NULL, - tr("Button$Sort")); - Display(); -} - -void cPlaylistMenu::Set(bool setCurrentPlaying) -{ - m_NeedsUpdate = false; - - int currentItem = Current(); - Clear(); - SetHasHotkeys(); - SetCols(2, 30); - SetHelpButtons(); - - int currentPlaying = m_Playlist.Current()->Index(); - int j = 0; - - for(cPlaylistItem *i = m_Playlist.First(); i; i = m_Playlist.Next(i), j++) { - cString Title = cPlaylist::GetEntry(i, true, j==currentPlaying); - Add(new cOsdItem(m_IC.Convert(*Title), (eOSState)(os_User + j))); - } - - if(setCurrentPlaying) - SetCurrent(Get(currentPlaying)); - else - SetCurrent(Get(currentItem)); - - Display(); -} - - -// -// cXinelibPlayerControl -// - -#include <vdr/skins.h> - -cXinelibPlayer *cXinelibPlayerControl::m_Player = NULL; -cMutex cXinelibPlayerControl::m_Lock; - -cXinelibPlayerControl::cXinelibPlayerControl(eMainMenuMode Mode, const char *File, const char *SubFile) : - cControl(OpenPlayer(File, false, SubFile)) -{ - m_DisplayReplay = NULL; - m_PlaylistMenu = NULL; - m_ShowModeOnly = true; - m_Mode = Mode; - m_RandomPlay = false; - m_AutoShowStart = time(NULL); - m_BlinkState = true; - - number = 0; - lastTime.Set(); - - m_Player->UseResumeFile( (Mode==ShowFiles) ); - - MsgReplaying(*m_Player->Playlist().Current()->Title, *m_Player->File()); -} - -cXinelibPlayerControl::~cXinelibPlayerControl() -{ - if(m_PlaylistMenu) { - delete m_PlaylistMenu; - m_PlaylistMenu = NULL; - } - if(m_DisplayReplay) { - delete m_DisplayReplay; - m_DisplayReplay = NULL; - } - - MsgReplaying(NULL, NULL); - Close(); -} - -void cXinelibPlayerControl::MsgReplaying(const char *Title, const char *File) -{ - cStatus::MsgReplaying(this, NULL, NULL, false); - if(Title || File) - cStatus::MsgReplaying(this, Title, File, true); -} - -void cXinelibPlayerControl::Queue(const char *File) -{ - if(!File) - return; - - m_Lock.Lock(); - - LOGMSG("cXinelibPlayerControl::Queue(%s)", File); - - if(!m_Player) { - OpenPlayer(File, true); - cControl::Launch(new cXinelibPlayerControl(ShowMusic, NULL)); - } else { - size_t len = strlen(File); - if(len && File[len-1] == '/') - m_Player->Playlist().Read(File, true); - else - m_Player->Playlist().Read(File); - } - - Skins.Message(mtInfo, tr("Queued to playlist")); - - m_Lock.Unlock(); - - if(m_Player->Playlist().Count() > 0) - m_Player->Playlist().StartScanner(); - -} - -cXinelibPlayer *cXinelibPlayerControl::OpenPlayer(const char *File, bool Queue, const char *SubFile) -{ - m_Lock.Lock(); - if(!m_Player) - m_Player = new cXinelibPlayer(File, Queue, SubFile); - m_Lock.Unlock(); - return m_Player; -} - -void cXinelibPlayerControl::Close(void) -{ - m_Lock.Lock(); - if(m_Player) - delete m_Player; - m_Player = NULL; - m_Lock.Unlock(); -} - -void cXinelibPlayerControl::Show() -{ - bool Play = (m_Player->Speed() > 0); - bool Forward = true; - int Speed = abs(m_Player->Speed()) - 2; - if(Speed<-1) Speed=-1; - - if(!m_DisplayReplay) { - if(cOsd::IsOpen()) - return; - m_DisplayReplay = Skins.Current()->DisplayReplay(m_ShowModeOnly); - } - - if(!m_ShowModeOnly) { - char t[128] = ""; - int Current = cXinelibDevice::Instance().PlayFileCtrl("GETPOS"); - int Total = cXinelibDevice::Instance().PlayFileCtrl("GETLENGTH"); - if(Current>=0) m_CurrentPos = Current; - if(Total>=0) m_CurrentLen = Total; - - if(m_CurrentLen >= 0 /*&& Total >= 0*/) { - Total = (m_CurrentLen + 500) / 1000; // ms --> s - Current = (m_CurrentPos + 500) / 1000; - - cString Title = cPlaylist::GetEntry(m_Player->Playlist().Current()); - cCharSetConv ic("UTF-8", cCharSetConv::SystemCharacterTable()); - m_DisplayReplay->SetTitle(ic.Convert(*Title)); - - m_DisplayReplay->SetProgress(Current, Total); - sprintf(t, "%d:%02d:%02d", Total/3600, (Total%3600)/60, Total%60); - m_DisplayReplay->SetTotal( t ); - sprintf(t, "%d:%02d:%02d", Current/3600, (Current%3600)/60, Current%60); - m_BlinkState = (m_Player->Speed() != 0) || (!m_BlinkState); - m_DisplayReplay->SetCurrent( m_BlinkState ? t : ""); - } - } - - m_DisplayReplay->SetMode(Play, Forward, Speed); - - m_DisplayReplay->Flush(); -} - -void cXinelibPlayerControl::Hide() -{ - if(m_PlaylistMenu) { - delete m_PlaylistMenu; - m_PlaylistMenu = NULL; - } - if(m_DisplayReplay) { - delete m_DisplayReplay; - m_DisplayReplay = NULL; - } -} - -cOsdObject *cXinelibPlayerControl::GetInfo(void) -{ - return new cMetainfoMenu(m_Player->Playlist().Current()->Filename); -} - -eOSState cXinelibPlayerControl::ProcessKey(eKeys Key) -{ - if ( !m_Player->Playing() ) { - LOGDBG("cXinelibPlayerControl: EndOfStreamReached"); - if (m_Mode == ShowMusic && m_Player->Files() == 1 && !m_Player->Error()) { - m_Player->NextFile(0); - return osContinue; - } - int Jump = 1; - if(m_RandomPlay) { - srand((unsigned int)time(NULL)); - Jump = (random() % m_Player->Files()) - m_Player->CurrentFile(); - } - if(m_Player->Files() < 2 || !m_Player->NextFile(Jump)) { - Hide(); - return osEnd; - } - if(m_PlaylistMenu) { - m_PlaylistMenu->PlaylistChanged(m_Player->Playlist().Current()); - m_PlaylistMenu->SetCurrentExt(m_Player->CurrentFile()); - } - - if(!m_DisplayReplay) - m_AutoShowStart = time(NULL); - - MsgReplaying(*m_Player->Playlist().Current()->Title, *m_Player->File()); - } - - else { - // metainfo may change during playback (DVD titles, CDDA tracks) - const char *ti = cXinelibDevice::Instance().GetMetaInfo(miTitle); - if(ti && ti[0] && (!*m_Player->Playlist().Current()->Title || - !strstr(m_Player->Playlist().Current()->Title, ti))) { - const char *tr = cXinelibDevice::Instance().GetMetaInfo(miTracknumber); - const char *al = cXinelibDevice::Instance().GetMetaInfo(miAlbum); - const char *ar = cXinelibDevice::Instance().GetMetaInfo(miArtist); - LOGDBG("metainfo changed: %s->%s %s->%s %s->%s %s->%s", - *m_Player->Playlist().Current()->Artist?:"-", ar?:"-", - *m_Player->Playlist().Current()->Album ?:"-", al?:"-", - *m_Player->Playlist().Current()->Tracknumber ?:"-", tr?:"-", - *m_Player->Playlist().Current()->Title ?:"-", ti?:"-"); - m_Player->Playlist().Current()->Title = ti; - if(tr && tr[0]) - m_Player->Playlist().Current()->Tracknumber = tr; - if(al && al[0]) - m_Player->Playlist().Current()->Album = al; - if(ar && ar[0]) - m_Player->Playlist().Current()->Artist = ar; - MsgReplaying(*m_Player->Playlist().Current()->Title, *m_Player->File()); - } - } - - if(m_PlaylistMenu) { - m_AutoShowStart = 0; - - eOSState state = osUnknown; - - switch(state=m_PlaylistMenu->ProcessKey(Key)) { - case osBack: - case osEnd: Hide(); break; - default: if(state >= os_User) { - m_Player->NextFile( (int)state - (int)os_User - m_Player->CurrentFile()); - m_PlaylistMenu->SetCurrentExt(m_Player->CurrentFile()); - MsgReplaying(*m_Player->Playlist().Current()->Title, *m_Player->File()); - } - break; - } - - if(state != osUnknown) - return osContinue; - } - - if (m_DisplayReplay) - Show(); - - if ( m_Mode == ShowFiles ) { - switch(Key) { - case kRed: if(m_Player->Playlist().Count() > 1) { - Hide(); - m_PlaylistMenu = new cPlaylistMenu(m_Player->Playlist(), m_RandomPlay); - m_AutoShowStart = 0; - } else { - m_Player->Control("SEEK 0"); break; - } - break; - case kUser8: - case k1: m_Player->Control("SEEK -20"); break; - case kUser9: - case k3: m_Player->Control("SEEK +20"); break; - case k2: xc.subtitle_vpos -= 10; - case k5: xc.subtitle_vpos += 5; - m_Player->Control("SUBTITLES %d", xc.subtitle_vpos); - break; - case kRight: - { - static const int speeds[] = { -3, -2, 1, 2, -4, 2, 3, 4, 4 }; - m_Player->SetSpeed(speeds[m_Player->Speed() + 4]); - if(m_Player->Speed() != 1) - Show(); - else - Hide(); - break; - } - case kLeft: - { - static const int speeds[] = { 0, -4, -3, -2, 0, -2, 1, 2, 3 }; - m_Player->SetSpeed(speeds[m_Player->Speed() + 4]); - if(m_Player->Speed() != 1 || !m_ShowModeOnly) - Show(); - else - Hide(); - break; - } - default: break; - } - } - if ( m_Mode == ShowMusic ) { - switch(Key) { - case kRed: Hide(); - m_PlaylistMenu = new cPlaylistMenu(m_Player->Playlist(), m_RandomPlay); - m_AutoShowStart = 0; - break; - case kNext: - case kRight: if(m_RandomPlay) { - srand((unsigned int)time(NULL)); - m_Player->NextFile((random() % m_Player->Files()) - m_Player->CurrentFile()); - } - else { - m_Player->NextFile(1); - } - if(!m_DisplayReplay) - m_AutoShowStart = time(NULL); - MsgReplaying(*m_Player->Playlist().Current()->Title, *m_Player->File()); - break; - case kPrev: - case kLeft: if(cXinelibDevice::Instance().PlayFileCtrl("GETPOS") < 3000) { - m_Player->NextFile(-1); - if(!m_DisplayReplay) - m_AutoShowStart = time(NULL); - MsgReplaying(*m_Player->Playlist().Current()->Title, *m_Player->File()); - } - else { - m_Player->NextFile(0); - if(!m_DisplayReplay) - m_AutoShowStart = time(NULL); - } - break; - case k0 ... k9: - if (number >= 0) { - if (number * 10 + Key - k0 > m_Player->Files()) - number = m_Player->Files(); - else - number = number * 10 + Key - k0; - } - break; - case kNone: - if (number > 0 && int(lastTime.Elapsed()) > 3000) { - m_Player->NextFile( number - (m_Player->CurrentFile() + 1) ); - if (!m_DisplayReplay) - m_AutoShowStart = time(NULL); - MsgReplaying(*m_Player->Playlist().Current()->Title, *m_Player->File()); - number = 0; - lastTime.Set(); - } - break; - default: break; - } - } - switch(Key) { // key bindings common for both players - case kBack: xc.main_menu_mode = m_Mode; - Hide(); - BackToMenu(); - break; - case kStop: - case kBlue: Hide(); - Close(); - return osEnd; - case kUser7: if(m_Player->Playlist().Count()>1) { - m_RandomPlay = !m_RandomPlay; - if(m_RandomPlay) - Skins.Message(mtInfo, tr("Random play")); - else - Skins.Message(mtInfo, tr("Normal play")); - } - break; - case kGreen: m_Player->Control("SEEK -60"); break; - case kYellow: m_Player->Control("SEEK +60"); break; - case kUser8: m_Player->Control("SEEK -20"); break; - case kUser9: m_Player->Control("SEEK +20"); break; - case kDown: - case kPause: if(m_Player->Speed()) { - m_Player->SetSpeed(0); - if(!m_DisplayReplay) - m_ShowModeOnly = true; - Show(); - break; - } - // fall thru - case kUp: - case kPlay: m_Player->SetSpeed(1); - if(m_ShowModeOnly && m_DisplayReplay) - Hide(); - else if(m_DisplayReplay) - Show(); - m_ShowModeOnly = false; - break; - case kFastFwd: - { - static const int speeds[] = { -3, -2, 1, 2, -4, 2, 3, 4, 4 }; - m_Player->SetSpeed(speeds[m_Player->Speed() + 4]); - if(m_Player->Speed() != 1) - Show(); - else - Hide(); - break; - } - case kFastRew: - { - static const int speeds[] = { 0, -4, -3, -2, 0, -2, 1, 2, 3 }; - m_Player->SetSpeed(speeds[m_Player->Speed() + 4]); - if(m_Player->Speed() != 1 || !m_ShowModeOnly) - Show(); - else - Hide(); - break; - } - case kOk: - m_AutoShowStart = 0; - if(m_Player->Speed() != 1) { - Hide(); - m_ShowModeOnly = !m_ShowModeOnly; - Show(); - } else { - if(m_DisplayReplay) { - m_ShowModeOnly = true; - Hide(); - } else { - Hide(); - m_ShowModeOnly = false; - Show(); - } - } - break; - default: break; - } - - if(m_DisplayReplay && - m_AutoShowStart && - time(NULL) - m_AutoShowStart > 5) { - m_AutoShowStart = 0; - Hide(); - } - - if(!m_DisplayReplay && - m_AutoShowStart) { - m_ShowModeOnly = false; - Show(); - } - - return osContinue; -} - -// -// cDvdMenu -// - -class cDvdMenu : public cOsdMenu { - public: - cDvdMenu(void) : cOsdMenu("DVD Menu") - { - Add(new cOsdItem("Exit DVD menu", osUser1)); - Add(new cOsdItem("DVD Root menu", osUser2)); - Add(new cOsdItem("DVD Title menu", osUser3)); - Add(new cOsdItem("DVD SPU menu", osUser4)); - Add(new cOsdItem("DVD Audio menu", osUser5)); - Add(new cOsdItem("Close menu", osEnd)); - Display(); - } -}; - - -// -// cXinelibDvdPlayerControl -// - -cXinelibDvdPlayerControl::~cXinelibDvdPlayerControl() -{ - if(Menu) { - delete Menu; - Menu = NULL; - } -} - -void cXinelibDvdPlayerControl::Hide(void) -{ - if(Menu) { - delete Menu; - Menu = NULL; - } - cXinelibPlayerControl::Hide(); -} - -void cXinelibDvdPlayerControl::Show(void) -{ - if(!Menu) - cXinelibPlayerControl::Show(); - else - cXinelibPlayerControl::Hide(); -} - -eOSState cXinelibDvdPlayerControl::ProcessKey(eKeys Key) -{ - // Check for end of stream and failed open - if ( !m_Player->Playing() ) { - LOGDBG("cXinelibDvdPlayerControl: EndOfStreamReached"); - Hide(); - return osEnd; - } - - // Update DVD title information - const char *ti = cXinelibDevice::Instance().GetMetaInfo(miTitle); - if (ti && ti[0] && (!m_CurrentDVDTitle || !strstr(m_CurrentDVDTitle, ti))) { - memset(m_CurrentDVDTitle, 0, 63); - strn0cpy(m_CurrentDVDTitle, ti, 63); - m_Player->Playlist().Current()->Title = m_CurrentDVDTitle; - MsgReplaying(m_CurrentDVDTitle, NULL); - } - - // Handle menu selection - if(Menu) { - if(Key == kRed) - Hide(); - else switch(Menu->ProcessKey(Key)) { - case osUser1: Hide(); m_Player->Control("EVENT XINE_EVENT_INPUT_MENU1"); break; - case osUser2: Hide(); m_Player->Control("EVENT XINE_EVENT_INPUT_MENU2"); break; - case osUser3: Hide(); m_Player->Control("EVENT XINE_EVENT_INPUT_MENU3"); break; - case osUser4: Hide(); m_Player->Control("EVENT XINE_EVENT_INPUT_MENU4"); break; - case osUser5: Hide(); m_Player->Control("EVENT XINE_EVENT_INPUT_MENU5"); break; - case osBack: - case osEnd: Hide(); break; - default: break; - } - return osContinue; - } - - // Update progress bar display - if (m_DisplayReplay) - Show(); - - // Handle menu navigation - - bool MenuDomain = !xc.dvd_arrow_keys_control_playback; - if(Key != kNone || m_DisplayReplay) { - const char *dt = cXinelibDevice::Instance().GetMetaInfo(miDvdTitleNo); - if(dt && !strcmp("0", dt)) - MenuDomain = true; - else { - dt = cXinelibDevice::Instance().GetMetaInfo(miDvdButtons); - if(dt && *dt && *dt != '0') - MenuDomain = true; - } - } - - if(MenuDomain) { - if(m_DisplayReplay) - Hide(); - - switch(Key) { - // DVD navigation - case kUp: m_Player->Control("EVENT XINE_EVENT_INPUT_UP"); return osContinue; - case kDown: m_Player->Control("EVENT XINE_EVENT_INPUT_DOWN"); return osContinue; - case kLeft: m_Player->Control("EVENT XINE_EVENT_INPUT_LEFT"); return osContinue; - case kRight: m_Player->Control("EVENT XINE_EVENT_INPUT_RIGHT"); return osContinue; - case kOk: m_Player->Control("EVENT XINE_EVENT_INPUT_SELECT"); return osContinue; - case kBack: m_Player->Control("EVENT XINE_EVENT_INPUT_MENU1"); return osContinue; - default: break; - } - } - - // Handle normal keys - - if(!MenuDomain) { - switch(Key) { - // Replay control - case kUp: Key = kPlay; break; - case kDown: Key = kPause; break; - case kLeft: Key = kFastRew; break; - case kRight: Key = kFastFwd; break; - case kOk: - if(m_Player->Speed() != 1) { - Hide(); - m_ShowModeOnly = !m_ShowModeOnly; - Show(); - break; - } - if(m_DisplayReplay) { - Hide(); - m_ShowModeOnly = true; - } else { - Hide(); - m_ShowModeOnly = false; - Show(); - } - break; - case kInfo: Hide(); - if(m_DisplayReplay && !m_ShowModeOnly) { - m_ShowModeOnly = true; - } else { - m_ShowModeOnly = false; - Show(); - } - break; - case kBack: xc.main_menu_mode = m_Mode; - Hide(); - Close(); - return osEnd; - default: break; - } - } - - switch(Key) { - // DVD menus - case kRed: Hide(); - Menu = new cDvdMenu(); - break; - // Playback control - case kGreen: m_Player->Control("SEEK -60"); break; - case kYellow: m_Player->Control("SEEK +60"); break; - case kUser8: - case k1: m_Player->Control("SEEK -20"); break; - case kUser9: - case k3: m_Player->Control("SEEK +20"); break; - - case kStop: - case kBlue: Hide(); - Close(); - return osEnd; - - case k9: m_Player->Control("EVENT XINE_EVENT_INPUT_NEXT TITLE"); break; - case k7: m_Player->Control("EVENT XINE_EVENT_INPUT_PREVIOUS TITLE"); break; - case k6: - case kNext: m_Player->Control("EVENT XINE_EVENT_INPUT_NEXT CHAPTER"); break; - case k4: - case kPrev: m_Player->Control("EVENT XINE_EVENT_INPUT_PREVIOUS CHAPTER"); break; - - case kFastFwd: - { - static const int speeds[] = { -3, -2, 1, 2, -4, 2, 3, 4, 4 }; - m_Player->SetSpeed(speeds[m_Player->Speed() + 4]); - if(m_Player->Speed() != 1) - Show(); - else - Hide(); - break; - } - case kFastRew: - { - static const int speeds[] = { 0, -4, -3, -2, 0, -2, 1, 2, 3 }; - m_Player->SetSpeed(speeds[m_Player->Speed() + 4]); - if(m_Player->Speed() != 1 || !m_ShowModeOnly) - Show(); - else - Hide(); - break; - } - case kInfo: if(m_DisplayReplay) { - Hide(); - } else { - m_ShowModeOnly = false; - Show(); - } - break; - case kPause: if(m_Player->Speed()) { - m_Player->SetSpeed(0); - m_ShowModeOnly = false; - Show(); - break; - } - // fall thru - case kPlay: m_Player->SetSpeed(1); - m_ShowModeOnly = true; - Hide(); - break; - default: break; - } - - return osContinue; -} - -// -// cXinelibImagePlayer -// - -class cXinelibImagePlayer : public cPlayer { - private: - cString m_Mrl; - bool m_Active; - bool m_Error; - cXinelibDevice *m_Dev; - - bool Play(void); - - protected: - virtual void Activate(bool On); - - public: - cXinelibImagePlayer(const char *File); - virtual ~cXinelibImagePlayer(); - - bool ShowImage(const char *File); - bool Error(void) { return m_Error; } -}; - -cXinelibImagePlayer::cXinelibImagePlayer(const char *File) -{ - m_Mrl = File; - m_Active = false; - m_Error = false; - m_Dev = &(cXinelibDevice::Instance()); -} - -cXinelibImagePlayer::~cXinelibImagePlayer() -{ - Activate(false); - Detach(); -} - -bool cXinelibImagePlayer::Play(void) -{ - if ((*m_Mrl)[0] == '/') - m_Mrl = cString::sprintf("file:%s", *cPlaylist::EscapeMrl(m_Mrl)); - - return m_Dev->PlayFile(m_Mrl, 0, true); -} - -void cXinelibImagePlayer::Activate(bool On) -{ - m_Active = On; - m_Error = false; - if (On) - Play(); - else - m_Dev->PlayFile(NULL); -} - -bool cXinelibImagePlayer::ShowImage(const char *File) -{ - m_Mrl = File; - if (m_Active) - return Play(); - return true; -} - - -// -// cXinelibImagesControl -// - -cXinelibImagePlayer *cXinelibImagesControl::m_Player = NULL; -cMutex cXinelibImagesControl::m_Lock; - -cXinelibImagesControl::cXinelibImagesControl(char **Files, int Index, int Count) : - cControl(OpenPlayer(Files[Index])) -{ - m_DisplayReplay = NULL; - m_Files = Files; - m_File = NULL; - m_Index = Index; - m_Count = Count; - m_Speed = 0; - m_ShowModeOnly = false; - - Seek(0); -} - -cXinelibImagesControl::~cXinelibImagesControl() -{ - if(m_DisplayReplay) - delete m_DisplayReplay; - m_DisplayReplay = NULL; - - cStatus::MsgReplaying(this, NULL, NULL, false); - Close(); - - if(m_Files) { - int i=0; - while(m_Files[i]) { - free(m_Files[i]); - m_Files[i] = NULL; - i++; - } - delete [] m_Files; - m_Files = NULL; - } -} - -cXinelibImagePlayer *cXinelibImagesControl::OpenPlayer(const char *File) -{ - m_Lock.Lock(); - if(!m_Player) - m_Player = new cXinelibImagePlayer(File); - m_Lock.Unlock(); - return m_Player; -} - -void cXinelibImagesControl::Close(void) -{ - m_Lock.Lock(); - if(m_Player) - delete m_Player; - m_Player = NULL; - m_Lock.Unlock(); -} - -void cXinelibImagesControl::Delete(void) -{ - if(Interface->Confirm(tr("Delete image ?"))) { - if(!unlink(m_Files[m_Index])) { - free(m_Files[m_Index]); - for(int i=m_Index; i<m_Count; i++) - m_Files[i] = m_Files[i+1]; - m_Count--; - m_Files[m_Count] = NULL; - Seek(0); - } - } -} - -cOsdObject *cXinelibImagesControl::GetInfo(void) -{ - return new cMetainfoMenu(m_Files[m_Index]); -} - -void cXinelibImagesControl::Seek(int Rel) -{ - if(m_Index == m_Count-1 && Rel>0) - m_Index = 0; - else if(m_Index == 0 && Rel<0) - m_Index = m_Count-1; - else - m_Index += Rel; - - if(m_Index < 0) - m_Index = 0; - else if(m_Index >= m_Count) - m_Index = m_Count; - - char *pt; - free(m_File); - m_File = strdup(m_Files[m_Index]); - if(NULL != (pt=strrchr(m_File, '/'))) - strcpy(m_File, pt+1); - if(NULL != (pt=strrchr(m_File, '.'))) - *pt = 0; - - cStatus::MsgReplaying(this, m_File, m_Files[m_Index], true); - - m_Player->ShowImage(m_Files[m_Index]); - m_LastShowTime = time(NULL); - strn0cpy(xc.browse_images_dir, m_Files[m_Index], sizeof(xc.browse_images_dir)); -} - -void cXinelibImagesControl::Show(void) -{ - bool Play = (m_Speed!=0), Forward = m_Speed>=0; - int Speed = abs(m_Speed); - - if(!m_DisplayReplay) { - m_DisplayReplay = Skins.Current()->DisplayReplay(m_ShowModeOnly); - } - - if(!m_ShowModeOnly) { - char t[128] = ""; - m_DisplayReplay->SetTitle(m_File); - m_DisplayReplay->SetProgress(m_Index, m_Count); - sprintf(t, "%d", m_Count); - m_DisplayReplay->SetTotal( t ); - sprintf(t, "%d", m_Index+1); - m_DisplayReplay->SetCurrent( t ); - } - - m_DisplayReplay->SetMode(Play, Forward, Speed); - m_DisplayReplay->Flush(); -} - -void cXinelibImagesControl::Hide(void) -{ - if(m_DisplayReplay) { - delete m_DisplayReplay; - m_DisplayReplay = NULL; - } -} - -eOSState cXinelibImagesControl::ProcessKey(eKeys Key) -{ - switch(Key) { - case kBack: xc.main_menu_mode = ShowImages; - Hide(); - Close(); - BackToMenu(); - //return osPlugin; - return osEnd; - case kYellow: Delete(); - break; - case kStop: - case kBlue: Hide(); - Close(); - return osEnd; - case kPrev: - case kLeft: Seek(-1); - break; - case kNext: - case kRight: Seek(1); - break; - case kUp: Seek(5); - break; - case kDown: Seek(-5); - break; - case kPause: m_Speed = 0; - break; - case kPlay: m_Speed = 2; - break; - case kFastFwd: m_Speed++; - break; - case kFastRew: m_Speed--; - break; - case kOk: if(m_DisplayReplay) { - if(m_ShowModeOnly) { - Hide(); - m_ShowModeOnly = false; - Show(); - } else { - Hide(); - } - } else { - m_ShowModeOnly = true; - Show(); - } - break; - default: break; - } - - static const int Speed2Time[] = { 0, 5, 3, 1 }; - if(m_Speed > 3) - m_Speed = 3; - if(m_Speed < -3) - m_Speed = -3; - - if(Key == kNone && m_Speed != 0) { - if(m_LastShowTime + Speed2Time[m_Speed<0 ? -m_Speed : m_Speed] <= time(NULL)) - Seek(sgn(m_Speed)); - } - - if (m_DisplayReplay) - Show(); - - return osContinue; -} diff --git a/media_player.h b/media_player.h deleted file mode 100644 index 8b55fceb..00000000 --- a/media_player.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * media_player.h: Media and image players - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: media_player.h,v 1.16 2008-05-07 13:27:15 phintuka Exp $ - * - */ - -#ifndef __XINELIB_PLAYER_H -#define __XINELIB_PLAYER_H - -#include <vdr/player.h> - -#include "config.h" - -// --- Media player --------------------------------------------------------- - -class cXinelibPlayer; -class cSkinDisplayReplay; -class cPlaylistMenu; - -class cXinelibPlayerControl : public cControl -{ - private: - static cMutex m_Lock; - - static cXinelibPlayer *OpenPlayer(const char *File, bool Queue = false, const char *SubFile = NULL); - - protected: - static cXinelibPlayer *m_Player; - - cSkinDisplayReplay *m_DisplayReplay; - cPlaylistMenu *m_PlaylistMenu; - - eMainMenuMode m_Mode; - bool m_ShowModeOnly; - bool m_RandomPlay; - time_t m_AutoShowStart; - int m_CurrentPos; - int m_CurrentLen; - bool m_BlinkState; - - cTimeMs lastTime; - int number; - - void MsgReplaying(const char *Title, const char *File); - - public: - cXinelibPlayerControl(eMainMenuMode Mode, const char *File, const char *SubFile = NULL); - virtual ~cXinelibPlayerControl(); - - virtual void Show(void); - virtual void Hide(void); - virtual eOSState ProcessKey(eKeys Key); - - virtual cOsdObject *GetInfo(void); - - static void Close(void); - static bool IsOpen(void) { return m_Player != NULL; }; - static void Queue(const char *File); -}; - - -// --- DVD player ----------------------------------------------------------- - -class cDvdMenu; -class cXinelibDvdPlayerControl : public cXinelibPlayerControl -{ - private: - cDvdMenu *Menu; - char m_CurrentDVDTitle[63]; - - public: - cXinelibDvdPlayerControl(const char *File) : - cXinelibPlayerControl(ShowFiles, File), Menu(NULL) - {} - virtual ~cXinelibDvdPlayerControl(); - - virtual void Show(void); - virtual void Hide(void); - virtual eOSState ProcessKey(eKeys Key); -}; - -// --- Image player --------------------------------------------------------- - -class cXinelibImagePlayer; - -class cXinelibImagesControl : public cControl -{ - private: - static cXinelibImagePlayer *m_Player; - static cMutex m_Lock; - - cSkinDisplayReplay *m_DisplayReplay; - - char **m_Files; - char *m_File; - int m_Index; - int m_Count; - int m_Speed; - int m_LastShowTime; - bool m_ShowModeOnly; - - static cXinelibImagePlayer *OpenPlayer(const char *File); - - protected: - void Seek(int Rel); - void Delete(void); - - public: - cXinelibImagesControl(char **Files, int Index, int Count); - virtual ~cXinelibImagesControl(); - - virtual void Show(void); - virtual void Hide(void); - virtual eOSState ProcessKey(eKeys Key); - - virtual cOsdObject *GetInfo(void); - - static void Close(void); - static bool IsOpen(void) { return m_Player != NULL; } -}; - -#endif // __XINELIB_PLAYER_H - diff --git a/menu.c b/menu.c deleted file mode 100644 index 73b983cd..00000000 --- a/menu.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - * menu.c: Main Menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: menu.c,v 1.64 2009-06-01 14:04:42 phintuka Exp $ - * - */ - -#include "features.h" - -#include <dirent.h> - -#include <vdr/config.h> -#include <vdr/interface.h> -#include <vdr/menu.h> -#include <vdr/plugin.h> -#include <vdr/videodir.h> -#include <vdr/i18n.h> - -#include "logdefs.h" -#include "config.h" -#include "menu.h" -#include "menuitems.h" -#include "tools/metainfo_menu.h" -#include "device.h" -#include "media_player.h" -#include "equalizer.h" - -#ifndef HOTKEY_START -# define HOTKEY_START kRed - -# define HOTKEY_DVD k0 /* */ -# define HOTKEY_DVD_TRACK1 k1 /* */ -# define HOTKEY_RESERVED k2 /* */ - -# define HOTKEY_NEXT_ASPECT k3 /* auto, 4:3, 16:9 */ -# define HOTKEY_TOGGLE_CROP k4 /* off, force, auto */ -# define HOTKEY_UPMIX k5 /* off, on */ -# define HOTKEY_DOWNMIX k6 /* off, on */ -# define HOTKEY_DEINTERLACE k7 /* off, on */ -# define HOTKEY_LOCAL_FE k8 /* off, on */ - -# define HOTKEY_PLAYLIST k9 /* Start replaying playlist or file pointed by - symlink $(CONFDIR)/plugins/xineliboutput/default_playlist */ -# define HOTKEY_ADELAY_UP kUp /* audio delay up */ -# define HOTKEY_ADELAY_DOWN kDown /* audio delay down */ -# define HOTKEY_TOGGLE_VO_ASPECT kRight -#endif - -//#define OLD_TOGGLE_FE - -#define ISNUMBERKEY(k) (RAWKEY(k) >= k0 && RAWKEY(k) <= k9) - -//--------------------------- cMenuBrowseFiles ------------------------------- - -class cMenuBrowseFiles : public cOsdMenu -{ - protected: - const eMainMenuMode m_Mode; - bool m_OnlyQueue; - char *m_CurrentDir; - char *m_ConfigLastDir; - - virtual bool ScanDir(const char *DirName); - virtual eOSState Open(bool ForceOpen = false, bool Parent = false, bool Queue = false); - virtual eOSState Delete(void); - virtual eOSState Info(void); - virtual void Set(void); - virtual void SetHelpButtons(void); - cFileListItem *GetCurrent() { return (cFileListItem *)Get(Current()); } - void StoreConfig(void); - char *GetLastDir(void); - - public: - cMenuBrowseFiles(eMainMenuMode mode = ShowFiles, bool OnlyQueue=false); - ~cMenuBrowseFiles(); - - virtual eOSState ProcessKey(eKeys Key); -}; - -static char *ParentDir(const char *dir) -{ - char *result = strdup(dir); - char *pt = strrchr(result, '/'); - if(pt) { - *(pt+1)=0; - if(pt != result) - *pt = 0; - } - return result; -} - -static char *LastDir(const char *dir) -{ - const char *pt = strrchr(dir, '/'); - if(pt && pt[0] && pt[1]) - return strdup(pt+1); - return NULL; -} - -cMenuBrowseFiles::cMenuBrowseFiles(eMainMenuMode mode, bool OnlyQueue) : - cOsdMenu( ( mode==ShowImages ? tr("Images") : - mode==ShowMusic ? (!OnlyQueue ? tr("Play music") : tr("Add to playlist")) : - /*mode==ShowFiles ?*/ tr("Play file")), - 2, 4), - m_Mode(mode) -{ - m_CurrentDir = NULL; - m_OnlyQueue = OnlyQueue; - - m_ConfigLastDir = GetLastDir(); - Set(); -} - -cMenuBrowseFiles::~cMenuBrowseFiles() -{ - Setup.Save(); - free(m_CurrentDir); -} - -char *cMenuBrowseFiles::GetLastDir(void) -{ - switch(m_Mode) { - case ShowMusic: return xc.browse_music_dir; - case ShowImages: return xc.browse_images_dir; - default: - case ShowFiles: return xc.browse_files_dir; - } - return xc.browse_files_dir; -} - -void cMenuBrowseFiles::Set(void) -{ - Clear(); - - if(!m_CurrentDir) - m_CurrentDir = strdup(m_ConfigLastDir); - - if(m_CurrentDir[0] != '/') { - free(m_CurrentDir); - m_CurrentDir = strdup(VideoDirectory); - } - - // find deepest accessible directory from path - while(!ScanDir(m_CurrentDir) && strlen(m_CurrentDir) > 1) { - char *n = ParentDir(m_CurrentDir); - free(m_CurrentDir); - m_CurrentDir = n; - } - - // add link to parent folder - if(strlen(m_CurrentDir) > 1) - Add(new cFileListItem("..",true)); - - Sort(); - - SetCurrent(Get(Count()>1 && strlen(m_CurrentDir)>1 ? 1 : 0)); - - // select last selected item - - char *lastParent = ParentDir(m_ConfigLastDir); - if(!strncmp(m_CurrentDir,lastParent,strlen(m_CurrentDir))) { - char *item = LastDir(m_ConfigLastDir); - if(item) { - for(cFileListItem *it = (cFileListItem*)First(); it; it = (cFileListItem*)Next(it)) - if(!strcmp(it->Name(),item)) - SetCurrent(it); - free(item); - } - } - free(lastParent); - - strn0cpy(m_ConfigLastDir, m_CurrentDir, sizeof(xc.browse_files_dir)); - StoreConfig(); - - SetHelpButtons(); -} - -void cMenuBrowseFiles::StoreConfig(void) -{ - cPluginManager::GetPlugin(PLUGIN_NAME_I18N)->SetupStore("Media.BrowseMusicDir", - xc.browse_music_dir); - cPluginManager::GetPlugin(PLUGIN_NAME_I18N)->SetupStore("Media.BrowseFilesDir", - xc.browse_files_dir); - cPluginManager::GetPlugin(PLUGIN_NAME_I18N)->SetupStore("Media.BrowseImagesDir", - xc.browse_images_dir); -#if 1 - // delete old keys (<1.0.0) - cPluginManager::GetPlugin(PLUGIN_NAME_I18N)->SetupStore("BrowseMusicDir"); - cPluginManager::GetPlugin(PLUGIN_NAME_I18N)->SetupStore("BrowseFilesDir"); - cPluginManager::GetPlugin(PLUGIN_NAME_I18N)->SetupStore("BrowseImagesDir"); -#endif -} - -void cMenuBrowseFiles::SetHelpButtons(void) -{ - bool isDir = !GetCurrent() || GetCurrent()->IsDir(); - bool isDvd = GetCurrent() && GetCurrent()->IsDvd(); - SetHelp((isDir && isDvd) ? trVDR("Button$Open") : !m_OnlyQueue ? trVDR("Button$Play"): NULL, - (m_Mode == ShowMusic) ? tr("Button$Queue") : - strlen(m_CurrentDir)>1 ? "[..]" : NULL, - (isDir && !isDvd) ? NULL : trVDR("Button$Delete"), - isDir ? NULL : trVDR("Button$Info")); - Display(); -} - -eOSState cMenuBrowseFiles::Delete(void) -{ - cFileListItem *it = GetCurrent(); - if(!it->IsDir()) { - if (Interface->Confirm(trVDR("Delete recording?"))) { - cString name = cString::sprintf("%s/%s", m_CurrentDir, it->Name()); - if(!unlink(name)) { - isyslog("file %s deleted", *name); - if(m_Mode != ShowImages) { - name = cString::sprintf("%s.resume", *name); - unlink(name); - } - cOsdMenu::Del(Current()); - SetHelpButtons(); - Display(); - } else { - Skins.Message(mtError, trVDR("Error while deleting recording!")); - isyslog("Error deleting file %s", *name); - } - } - } - return osContinue; -} - -eOSState cMenuBrowseFiles::Open(bool ForceOpen, bool Parent, bool Queue) -{ - if(!GetCurrent()) { - return osContinue; - } - - /* parent directory */ - if(Parent || !strcmp("..", GetCurrent()->Name())) { - char *n = ParentDir(m_CurrentDir); - free(m_CurrentDir); - m_CurrentDir = n; - Set(); - return osContinue; - - /* directory */ - } else if (GetCurrent()->IsDir()) { - - if(!ForceOpen && GetCurrent()->IsDvd()) { - /* play dvd */ - cString f = cString::sprintf("dvd:%s/%s", m_CurrentDir, GetCurrent()->Name()); - cControl::Shutdown(); - cControl::Launch(new cXinelibDvdPlayerControl(f)); - return osEnd; - } - if(ForceOpen && GetCurrent()->IsDir() && !GetCurrent()->IsDvd()) { - /* play all files */ - if(m_Mode != ShowImages) { - - if(m_OnlyQueue && !Queue) - return osContinue; - - cString f = cString::sprintf("%s/%s/", m_CurrentDir, GetCurrent()->Name()); - - if(!Queue || !cXinelibPlayerControl::IsOpen()) - cControl::Shutdown(); - if(Queue) - cXinelibPlayerControl::Queue(f); - else - cControl::Launch(new cXinelibPlayerControl(m_Mode, f)); - return Queue ? osContinue : osEnd; - - } else { - // TODO: show all images - } - } - const char *d = GetCurrent()->Name(); - char *buffer = NULL; - if(asprintf(&buffer, "%s/%s", m_CurrentDir, d) >= 0) { - while(buffer[0] == '/' && buffer[1] == '/') - strcpy(buffer, buffer+1); - free(m_CurrentDir); - m_CurrentDir = buffer; - } - Set(); - return osContinue; - - /* regular file */ - } else { - cString f = cString::sprintf("%s%s/%s", - GetCurrent()->IsDvd() ? "dvd:" : "", - m_CurrentDir, GetCurrent()->Name()); - if (GetCurrent()->IsDvd()) - strn0cpy(m_ConfigLastDir, m_CurrentDir, sizeof(xc.browse_files_dir)); - else - strn0cpy(m_ConfigLastDir, f, sizeof(xc.browse_files_dir)); - StoreConfig(); - - if(m_Mode != ShowImages) { - /* video/audio */ - if(m_OnlyQueue && !Queue) - return osContinue; - if(!Queue || !cXinelibPlayerControl::IsOpen()) - cControl::Shutdown(); - if(Queue) - cXinelibPlayerControl::Queue(f); - if(!cXinelibPlayerControl::IsOpen()) - cControl::Launch(GetCurrent()->IsDvd() - ? new cXinelibDvdPlayerControl(f) - : new cXinelibPlayerControl(m_Mode, f, GetCurrent()->SubFile())); - if(Queue) - return osContinue; - } else { - /* image */ - char **files = new char*[Count()+1]; - int i = 0, index = 0; - memset(files, 0, sizeof(char*)*(Count()+1)); - for(cFileListItem *it = (cFileListItem*)First(); it; it=(cFileListItem*)Next(it)) { - if(it==Get(Current())) - index = i; - if(!it->IsDir()) - if(asprintf(&files[i++], "%s/%s", m_CurrentDir, it->Name()) < 0) - i--; - } - cControl::Shutdown(); - cControl::Launch(new cXinelibImagesControl(files, index, i)); - } - return osEnd; - } - return osContinue; -} - -eOSState cMenuBrowseFiles::Info(void) -{ - if(GetCurrent() && !GetCurrent()->IsDir()) { - cString filename = cString::sprintf("%s/%s", m_CurrentDir, GetCurrent()->Name()); - return AddSubMenu(new cMetainfoMenu(filename)); - } - return osContinue; -} - -bool cMenuBrowseFiles::ScanDir(const char *DirName) -{ - DIR *d = opendir(DirName); - if (d) { - struct dirent *e; - while ((e = readdir(d)) != NULL) { - if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) { - cString buffer = cString::sprintf("%s/%s", DirName, e->d_name); - struct stat st; - if (stat(buffer, &st) == 0) { - - // check symlink destination - if (S_ISLNK(st.st_mode)) { - buffer = ReadLink(buffer); - if (!*buffer || stat(buffer, &st)) - continue; - } - - // folders - if (S_ISDIR(st.st_mode)) { - - if(m_Mode == ShowImages || m_Mode == ShowMusic) - Add(new cFileListItem(e->d_name, true)); - else - Add(new cFileListItem(e->d_name, true, false, false, xc.IsDvdFolder(buffer))); - - // regular files - } else if(e->d_name[0] != '.') { - - // audio - if (m_Mode == ShowMusic && xc.IsAudioFile(buffer)) { - Add(new cFileListItem(e->d_name, false)); - - // images - } else if(m_Mode == ShowImages && xc.IsImageFile(buffer)) { - Add(new cFileListItem(e->d_name, false)); - - // DVD image (.iso) - } else if (m_Mode == ShowFiles && xc.IsDvdImage(buffer)) { - Add(new cFileListItem(e->d_name, false, false, false, true)); - - // video - } else if (m_Mode == ShowFiles && xc.IsVideoFile(buffer)) { - cString subfile; - cString resumefile; - - // separate subtitles ? - cString basename = cString::sprintf("%s/%s", DirName, e->d_name); - const char *p = strrchr(basename, '.'); - if (p) - basename.Truncate(p - basename); - int i; - for(i=0; xc.s_subExts[i] && !*subfile; i++) { - cString tmp = cString::sprintf("%s%s", *basename, xc.s_subExts[i]); - if (stat(tmp, &st) == 0) - subfile = tmp; - } - - // resume file ? - resumefile = cString::sprintf("%s/%s.resume", DirName, e->d_name); - if (stat(resumefile, &st) != 0) - resumefile = NULL; - - Add(new cFileListItem(e->d_name, false, *resumefile, subfile)); - } - } - } - } - } - closedir(d); - return true; - } - return false; -} - -eOSState cMenuBrowseFiles::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if (state == osUnknown) { - switch (Key) { - case kPlay: - case kOk: return Open(false, false, m_OnlyQueue); - case kRed: return Open(true); - case kGreen: return Open(true, m_Mode != ShowMusic, - m_Mode==ShowMusic ? m_OnlyQueue=true : false); - case kYellow: return Delete(); - case kBlue: return Info(); - default: break; - } - } - - if (state == osUnknown) - state = osContinue; - - if(!HasSubMenu()) - SetHelpButtons(); - - return state; -} - - -//----------------------------- cMenuXinelib --------------------------------- - -#include "tools/display_message.h" - -static cOsdItem *NewTitle(const char *s) -{ - cString str = cString::sprintf("----- %s -----", s); - cOsdItem *tmp = new cOsdItem(str); - tmp->SetSelectable(false); - return tmp; -} - - -extern cOsdObject *g_PendingMenuAction; - -time_t cMenuXinelib::g_LastHotkeyTime = 0; -eKeys cMenuXinelib::g_LastHotkey = kNone; - -cMenuXinelib::cMenuXinelib() -{ - field_order = xc.field_order; - compression = xc.audio_compression; - headphone = xc.headphone; - autocrop = xc.autocrop; - overscan = xc.overscan; - - hotkey_state = hkInit; - - novideo = cXinelibDevice::Instance().GetPlayMode() == pmAudioOnlyBlack ? 1 : 0; - - Add(NewTitle(tr("Media"))); - Add(new cOsdItem(tr("Play file >>"), osUser1)); - Add(new cOsdItem(tr("Play music >>"), osUser2)); - Add(new cOsdItem(tr("View images >>"), osUser3)); - if(xc.remote_mode) - Add(new cOsdItem(tr("Play remote DVD >>"), osUser4)); - else - Add(new cOsdItem(tr("Play DVD disc >>"), osUser4)); - if(xc.remote_mode) - Add(new cOsdItem(tr("Play remote CD >>"), osUser6)); - else - Add(new cOsdItem(tr("Play audio CD >>"), osUser6)); - Add(NewTitle(tr("Video settings"))); - Add(ctrl_novideo = new cMenuEditBoolItem(tr("Play only audio"), - &novideo)); - Add(ctrl_autocrop = new cMenuEditBoolItem(tr("Crop letterbox 4:3 to 16:9"), - &autocrop)); - Add(ctrl_overscan = new cMenuEditTypedIntItem(tr("Overscan (crop image borders)"), "%", - &overscan, 0, 10, - tr("Off"))); -#ifdef HAVE_XV_FIELD_ORDER - Add(video_ctrl_interlace_order = new cMenuEditStraI18nItem(tr("Interlaced Field Order"), - &field_order, 2, xc.s_fieldOrder)); -#endif - - Add(NewTitle(tr("Audio settings"))); -#ifdef ENABLE_TEST_POSTPLUGINS - Add(ctrl_headphone = new cMenuEditBoolItem(tr("Headphone audio mode"), - &headphone)); -#else - ctrl_headphone = NULL; -#endif - - Add(audio_ctrl_compress = new cMenuEditTypedIntItem(tr("Audio Compression"),"%", - &compression, 100, 500, NULL, tr("Off"))); - - Add(new cOsdItem(tr("Audio equalizer >>"), osUser7)); - - switch(xc.main_menu_mode) { - case ShowFiles: AddSubMenu(new cMenuBrowseFiles(ShowFiles)); break; - case ShowMusic: AddSubMenu(new cMenuBrowseFiles(ShowMusic)); break; - case ShowImages: AddSubMenu(new cMenuBrowseFiles(ShowImages)); break; - default: break; - } - - xc.main_menu_mode = ShowMenu; -} - -cMenuXinelib::~cMenuXinelib() -{ -#ifdef HAVE_XV_FIELD_ORDER - if(xc.field_order != field_order ) - cXinelibDevice::Instance().ConfigureWindow(xc.fullscreen, xc.width, xc.height, - xc.modeswitch, xc.modeline, xc.display_aspect, - xc.scale_video, xc.field_order); -#endif - - if(xc.audio_compression != compression) - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, - xc.audio_compression, xc.audio_equalizer, - xc.audio_surround, xc.speaker_type); - - if(xc.overscan != overscan) - cXinelibDevice::Instance().ConfigureVideo(xc.hue, xc.saturation, xc.brightness, xc.sharpness, - xc.noise_reduction, xc.contrast, xc.overscan, - xc.vo_aspect_ratio); - - if(xc.headphone != headphone) - cXinelibDevice::Instance().ConfigurePostprocessing("headphone", - xc.headphone ? true : false); - - if(xc.autocrop != autocrop) - cXinelibDevice::Instance().ConfigurePostprocessing("autocrop", - xc.autocrop ? true : false, - xc.AutocropOptions()); - - int dev_novideo = cXinelibDevice::Instance().GetPlayMode() == pmAudioOnlyBlack ? 1 : 0; - if(dev_novideo != novideo) - cXinelibDevice::Instance().SetPlayMode(novideo ? pmAudioOnlyBlack : pmNone); -} - -cOsdMenu *cMenuXinelib::CreateMenuBrowseFiles(eMainMenuMode mode, bool Queue) -{ - return new cMenuBrowseFiles(mode, true); -} - -eOSState cMenuXinelib::ProcessKey(eKeys Key) -{ - /* Hot key support */ - if(hotkey_state == hkInit && Key == kNone) - return osContinue; - if(hotkey_state == hkInit && Key == HOTKEY_START) { - hotkey_state = hkSeen; - return osContinue; - } else if(hotkey_state == hkSeen && Key != kNone) { - hotkey_state = hkNone; - return ProcessHotkey(Key); - } - hotkey_state = hkNone; - - cOsdItem *item = Get(Current()); - - eOSState state = cMenuSetupPage::ProcessKey(Key); - - if(HasSubMenu()) - return state; - - switch(state) { - case osUser1: - AddSubMenu(new cMenuBrowseFiles(ShowFiles)); - return osUnknown; - case osUser2: - AddSubMenu(new cMenuBrowseFiles(ShowMusic)); - return osUnknown; - case osUser3: - AddSubMenu(new cMenuBrowseFiles(ShowImages)); - return osContinue; - case osUser4: - cControl::Shutdown(); - cControl::Launch(new cXinelibDvdPlayerControl("dvd:/")); - return osEnd; - case osUser6: - cControl::Shutdown(); - cControl::Launch(new cXinelibPlayerControl(ShowMusic, "cdda:/")); - return osEnd; - case osUser7: - if(!g_PendingMenuAction) { - g_PendingMenuAction = new cEqualizer(); - return osPlugin; - } - return osContinue; - default: ; - } - - Key = NORMALKEY(Key); - - if(Key==kLeft || Key==kRight || ISNUMBERKEY(Key)) { - if(item == audio_ctrl_compress) - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, - compression, xc.audio_equalizer, - xc.audio_surround, xc.speaker_type); - else if(item == ctrl_overscan) - cXinelibDevice::Instance().ConfigureVideo(xc.hue, xc.saturation, xc.brightness, xc.sharpness, - xc.noise_reduction, xc.contrast, overscan, - xc.vo_aspect_ratio); - } - if(Key==kLeft || Key==kRight) { - if(item == ctrl_headphone) - cXinelibDevice::Instance().ConfigurePostprocessing("headphone", headphone?true:false); - else if(item == ctrl_autocrop) - cXinelibDevice::Instance().ConfigurePostprocessing("autocrop", autocrop?true:false, - xc.AutocropOptions()); - else if(item == ctrl_novideo) - cXinelibDevice::Instance().SetPlayMode(novideo ? pmAudioOnlyBlack : pmNone); -#ifdef HAVE_XV_FIELD_ORDER - else if(video_ctrl_interlace_order && item == video_ctrl_interlace_order) - cXinelibDevice::Instance().ConfigureWindow(xc.fullscreen, xc.width, xc.height, - xc.modeswitch, xc.modeline, - xc.display_aspect, xc.scale_video, - field_order); -#endif - } - - return state; -} - -void cMenuXinelib::Store(void) -{ -#ifdef HAVE_XV_FIELD_ORDER - xc.field_order = field_order; -#endif - xc.audio_compression = compression; - xc.autocrop = autocrop; - xc.overscan = overscan; - xc.headphone = headphone; -} - -eOSState cMenuXinelib::ProcessHotkey(eKeys Key) -{ - eOSState NewState = osEnd; - cString Message; - time_t now = time(NULL); - bool OnlyInfo = ((g_LastHotkeyTime < now-3) || g_LastHotkey != Key); - - switch(Key) { - case HOTKEY_DVD: - cControl::Shutdown(); - cControl::Launch(new cXinelibDvdPlayerControl("dvd:/")); - break; - - case HOTKEY_DVD_TRACK1: - cControl::Shutdown(); - cControl::Launch(new cXinelibDvdPlayerControl("dvd:/1")); - break; - - case HOTKEY_LOCAL_FE: - /* off, on */ - { - int local_frontend = strstra(xc.local_frontend, xc.s_frontends, 0); - -#ifndef OLD_TOGGLE_FE - if(local_frontend==FRONTEND_NONE) - // no need to show current frontend if there is no output device ... - OnlyInfo = false; -#endif - if(!OnlyInfo) { -#ifndef OLD_TOGGLE_FE - static int orig_frontend = -1; - if(orig_frontend < 0) - orig_frontend = local_frontend; - - if(orig_frontend == FRONTEND_NONE) { - // no frontends were loaded at startup -> loop thru all frontends - local_frontend++; - } else { - // frontend was loaded at startup -> toggle it on/off - if(local_frontend == FRONTEND_NONE) - local_frontend = orig_frontend; - else - local_frontend = FRONTEND_NONE; - } -#else - local_frontend++; -#endif - if(local_frontend >= FRONTEND_count) - local_frontend = 0; - strn0cpy(xc.local_frontend, xc.s_frontends[local_frontend], sizeof(xc.local_frontend)); - cXinelibDevice::Instance().ConfigureWindow( - xc.fullscreen, xc.width, xc.height, xc.modeswitch, xc.modeline, - xc.display_aspect, xc.scale_video, xc.field_order); - } - Message = cString::sprintf("%s %s %s", tr("Local Frontend"), - OnlyInfo ? ":" : "->", - xc.s_frontendNames[local_frontend]); - } - break; - - case HOTKEY_NEXT_ASPECT: - /* auto, 4:3, 16:9, ... */ - if(!OnlyInfo) { - xc.display_aspect = (xc.display_aspect < ASPECT_count-1) ? xc.display_aspect+1 : 0; - cXinelibDevice::Instance().ConfigureWindow(xc.fullscreen, xc.width, xc.height, - xc.modeswitch, xc.modeline, xc.display_aspect, - xc.scale_video, xc.field_order); - } - Message = cString::sprintf("%s %s %s", tr("Aspect ratio"), - OnlyInfo ? ":" : "->", - tr(xc.s_aspects[xc.display_aspect])); - break; - - case HOTKEY_TOGGLE_VO_ASPECT: - /* auto, square, 4:3, anamorphic or DVB */ - if(!OnlyInfo) { - xc.vo_aspect_ratio = (xc.vo_aspect_ratio < VO_ASPECT_count-1) ? xc.vo_aspect_ratio + 1 : 0; - cXinelibDevice::Instance().ConfigureVideo(xc.hue, xc.saturation, xc.brightness, xc.sharpness, - xc.noise_reduction, xc.contrast, xc.overscan, - xc.vo_aspect_ratio); - } - Message = cString::sprintf("%s %s %s", tr("Video aspect ratio"), - OnlyInfo ? ":" : "->", - tr(xc.s_vo_aspects[xc.vo_aspect_ratio])); - break; - - case HOTKEY_TOGGLE_CROP: - /* off, force, auto */ - if(!OnlyInfo) { - if(!xc.autocrop) { - xc.autocrop = 1; - xc.autocrop_autodetect = 1; - } else if(xc.autocrop_autodetect) { - xc.autocrop_autodetect = 0; - } else { - xc.autocrop = 0; - } - cXinelibDevice::Instance().ConfigurePostprocessing("autocrop", - xc.autocrop ? true : false, - xc.AutocropOptions()); - } - - Message = cString::sprintf("%s %s %s", tr("Crop letterbox 4:3 to 16:9"), - OnlyInfo ? ":" : "->", - !xc.autocrop ? tr("Off") : xc.autocrop_autodetect ? tr("automatic") : tr("On")); - break; - - case HOTKEY_DEINTERLACE: - { - /* off, on */ - int off = !strcmp(xc.deinterlace_method, "none"); - if(!OnlyInfo) { - off = !off; - if(off) - strcpy(xc.deinterlace_method, "none"); - else - strcpy(xc.deinterlace_method, "tvtime"); - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, - compression, xc.audio_equalizer, - xc.audio_surround, xc.speaker_type); - } - Message = cString::sprintf("%s %s %s", tr("Deinterlacing"), - OnlyInfo ? ":" : "->", - tr(off ? "Off":"On")); - } - break; - - case HOTKEY_UPMIX: - /* off, on */ - if(!OnlyInfo) { - xc.audio_upmix = xc.audio_upmix ? 0 : 1; - cXinelibDevice::Instance().ConfigurePostprocessing( - "upmix", xc.audio_upmix ? true : false, NULL); - } - Message = cString::sprintf("%s %s %s", - tr("Upmix stereo to 5.1"), - OnlyInfo ? ":" : "->", - tr(xc.audio_upmix ? "On" : "Off")); - break; - - case HOTKEY_DOWNMIX: - /* off, on */ - if(!OnlyInfo) { - xc.audio_surround = xc.audio_surround ? 0 : 1; - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, xc.audio_delay, xc.audio_compression, - xc.audio_equalizer, xc.audio_surround, xc.speaker_type); - } - Message = cString::sprintf("%s %s %s", - tr("Downmix AC3 to surround"), - OnlyInfo ? ":" : "->", - tr(xc.audio_surround ? "On":"Off")); - break; - - case HOTKEY_PLAYLIST: - /* Start replaying playlist or file pointed by - symlink $(CONFDIR)/plugins/xineliboutput/default_playlist */ - { - struct stat st; - cString file = cString::sprintf("%s%s", cPlugin::ConfigDirectory("xineliboutput"), "/default_playlist"); - if (lstat(file, &st) == 0) { - if (S_ISLNK(st.st_mode)) { - cString buffer(ReadLink(file), true); - if (!*buffer || stat(buffer, &st)) { - Message = tr("Default playlist not found"); - } else { - LOGDBG("Replaying default playlist: %s", *file); - cControl::Shutdown(); - cControl::Launch(new cXinelibPlayerControl(CloseOsd, buffer)); - } - } else { - Message = tr("Default playlist is not symlink"); - } - } else { - Message = tr("Default playlist not defined"); - } - } - break; - - case HOTKEY_ADELAY_UP: - /* audio delay up */ - if(!OnlyInfo) { - xc.audio_delay++; - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, - xc.audio_compression, xc.audio_equalizer, - xc.audio_surround, xc.speaker_type); - } - Message = cString::sprintf("%s %s %d %s", tr("Delay"), - OnlyInfo ? ":" : "->", - xc.audio_delay, tr("ms")); - break; - - case HOTKEY_ADELAY_DOWN: - /* audio delay up */ - if(!OnlyInfo) { - xc.audio_delay--; - cXinelibDevice::Instance().ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, - xc.audio_compression, xc.audio_equalizer, - xc.audio_surround, xc.speaker_type); - } - Message = cString::sprintf("%s %s %d %s", tr("Delay"), - OnlyInfo ? ":" : "->", - xc.audio_delay, tr("ms")); - break; - - default: - Message = cString::sprintf(tr("xineliboutput: hotkey %s not binded"), cKey::ToString(Key)); - break; - } - - if(*Message) { - if(!g_PendingMenuAction && - !cRemote::HasKeys() && - cRemote::CallPlugin("xineliboutput")) - g_PendingMenuAction = new cDisplayMessage(Message); - } - - g_LastHotkeyTime = now; - g_LastHotkey = Key; - - return NewState; -} diff --git a/menu.h b/menu.h deleted file mode 100644 index f6817996..00000000 --- a/menu.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * menu.h: Main Menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: menu.h,v 1.7 2008-11-01 07:23:00 phintuka Exp $ - * - */ - -#ifndef __XINELIB_MENU_H -#define __XINELIB_MENU_H - -#include "features.h" - -#include <vdr/menuitems.h> - -class cMenuXinelib : public cMenuSetupPage -{ - private: - int field_order; - int compression; - int headphone; - int autocrop; - int overscan; - int novideo; - - // Hotkeys - enum {hkInit, hkSeen, hkNone} hotkey_state; - static time_t g_LastHotkeyTime; - static eKeys g_LastHotkey; - virtual eOSState ProcessHotkey(eKeys Key); - -#ifdef HAVE_XV_FIELD_ORDER - cOsdItem *video_ctrl_interlace_order; -#endif - cOsdItem *audio_ctrl_compress; - - cOsdItem *ctrl_autocrop; - cOsdItem *ctrl_overscan; - cOsdItem *ctrl_headphone; - cOsdItem *ctrl_novideo; - - protected: - virtual void Store(void); - - public: - cMenuXinelib(void); - virtual ~cMenuXinelib(); - virtual eOSState ProcessKey(eKeys Key); - - static cOsdMenu *CreateMenuBrowseFiles(eMainMenuMode mode, bool Queue=true); -}; - -#endif //__XINELIB_SETUP_MENU_H diff --git a/menuitems.c b/menuitems.c deleted file mode 100644 index 609c6a6b..00000000 --- a/menuitems.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * menuitems.c: New menu item types - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: menuitems.c,v 1.14 2009-05-29 15:05:19 phintuka Exp $ - * - */ - -#include <vdr/i18n.h> - -#include "menuitems.h" - -// --- cMenuEditTypedIntItem ------------------------------------------------- - -cMenuEditTypedIntItem::cMenuEditTypedIntItem(const char *Name, const char *Type, int *Value, - int Min, int Max, const char *ZeroString, - const char *MinString, const char *MaxString) -:cMenuEditIntItem(Name,Value,Min,Max,MinString,MaxString) -{ - type = Type ? Type : ""; - zeroString = ZeroString ? ZeroString : NULL; - Set(); -} - -void cMenuEditTypedIntItem::Set(void) -{ - if(*value == 0 && *zeroString) - SetValue(zeroString); - else if (minString && *value == min) - SetValue(minString); - else if (maxString && *value == max) - SetValue(maxString); - else - SetValue(cString::sprintf("%d %s", *value, *type)); -} - -// --- cMenuEditOddIntItem ------------------------------------------------------ - -cMenuEditOddIntItem::cMenuEditOddIntItem(const char *Name, int *Value, int Min, int Max, const char *MinString, const char *MaxString) -:cMenuEditIntItem(Name,Value,Min,Max,MinString,MaxString) -{ - value = Value; - min = Min; - max = Max; - minString = MinString; - maxString = MaxString; - if (*value < min) - *value = min; - else if (*value > max) - *value = max; - Set(); -} - -eOSState cMenuEditOddIntItem::ProcessKey(eKeys Key) -{ - eOSState state = cMenuEditItem::ProcessKey(Key); - - if (state == osUnknown) { - int newValue = *value; - bool IsRepeat = Key & k_Repeat; - Key = NORMALKEY(Key); - switch (Key) { - case kNone: break; - case kLeft: - newValue = *value - 2; - fresh = true; - if (!IsRepeat && newValue < min && max != INT_MAX) - newValue = max; - break; - case kRight: - newValue = *value + 2; - fresh = true; - if (!IsRepeat && newValue > max && min != INT_MIN) - newValue = min; - break; - default: - if (*value < min) { *value = min; Set(); } - if (*value > max) { *value = max; Set(); } - return state; - } - if (newValue != *value && (!fresh || min <= newValue) && newValue <= max) { - *value = newValue; - Set(); - } - state = osContinue; - } - return state; -} - -// --- cMenuEditFpIntItem ---------------------------------------------------- - -cMenuEditFpIntItem::cMenuEditFpIntItem(const char *Name, int *Value, int Min, int Max, - int Decimals, const char *ZeroString, - const char *MinString, const char *MaxString) -:cMenuEditIntItem(Name,Value,Min,Max,MinString,MaxString) -{ - decimals = Decimals; - zeroString = ZeroString ? ZeroString : NULL; - Set(); -} - -static int my_exp10(int x) -{ - int r = 1; - for (; x > 0; x--, r *= 10) ; - return r; -} - -void cMenuEditFpIntItem::Set(void) -{ - if(*value == 0 && *zeroString) - SetValue(zeroString); - else if (minString && *value == min) - SetValue(minString); - else if (maxString && *value == max) - SetValue(maxString); - else - SetValue(cString::sprintf("%1.1f", ((float)(*value)) / (float)my_exp10(decimals))); -} - -// --- cMenuEditStraI18nItem ------------------------------------------------- - -cMenuEditStraI18nItem::cMenuEditStraI18nItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) -:cMenuEditIntItem(Name, Value, 0, NumStrings - 1) -{ - strings = Strings; - Set(); -} - -void cMenuEditStraI18nItem::Set(void) -{ - SetValue(tr(strings[*value])); -} - -// --- cFileListItem ------------------------------------------------- - -cFileListItem::cFileListItem(const char *name, bool isDir) -{ - m_Name = name; - m_IsDir = isDir; - m_IsDvd = false; - m_HasResume = false; - m_SubFile = NULL; - m_ShowFlags = false; - m_Up = m_IsDir && !strcmp(m_Name, ".."); - Set(); -} - -cFileListItem::cFileListItem(const char *name, bool IsDir, - bool HasResume, const char *subfile, - bool IsDvd) -{ - m_Name = name; - m_IsDir = IsDir; - m_IsDvd = IsDvd; - m_HasResume = HasResume; - m_SubFile = subfile; - m_ShowFlags = true; - m_Up = m_IsDir && !strcmp(m_Name, ".."); - Set(); -} - -void cFileListItem::Set(void) -{ - cString txt; - const char *pt; - if(m_ShowFlags) { - if(m_IsDir) { - if(m_IsDvd) - txt = cString::sprintf("\tD\t[%s] ", *m_Name); // text2skin requires space at end of string to display item correctly ... - else - txt = cString::sprintf("\t\t[%s] ", *m_Name); // text2skin requires space at end of string to display item correctly ... - } else { - txt = cString::sprintf("%c\t%c\t%s", m_HasResume ? ' ' : '*', *m_SubFile ? 'S' : m_IsDvd ? 'D' : ' ', *m_Name); - if(NULL != (pt = strrchr(txt,'.'))) - txt.Truncate(pt - txt); - } - } else { - if(m_IsDir) { - txt = cString::sprintf("[%s] ", *m_Name); // text2skin requires space at end of string to display item correctly ... - } else { - txt = m_Name; - if(NULL != (pt = strrchr(txt,'.'))) - txt.Truncate(pt - txt); - } - } - SetText(txt); -} - -int cFileListItem::Compare(const cListObject &ListObject) const -{ - cFileListItem *other = (cFileListItem *)&ListObject; - - if(m_IsDir && !other->m_IsDir) - return -1; - if(!m_IsDir && other->m_IsDir) - return 1; - if(m_Up && !other->m_Up) - return -1; - if(!m_Up && other->m_Up) - return 1; - return strcmp(m_Name, other->m_Name); -} - -bool cFileListItem::operator< (const cListObject &ListObject) -{ - cFileListItem *other = (cFileListItem *)&ListObject; - - if(m_IsDir && !other->m_IsDir) - return true; - if(!m_IsDir && other->m_IsDir) - return false; - if(m_Up && !other->m_Up) - return true; - if(!m_Up && other->m_Up) - return false; - return strcmp(m_Name, other->m_Name) < 0; -} diff --git a/menuitems.h b/menuitems.h deleted file mode 100644 index cb158881..00000000 --- a/menuitems.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * menuitems.h: New menu item types - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: menuitems.h,v 1.7 2007-06-21 10:00:29 phintuka Exp $ - * - */ - -#ifndef __XINELIB_MENUITEMS_H_ -#define __XINELIB_MENUITEMS_H_ - -#include <vdr/menuitems.h> - -// --- cMenuEditTypedIntItem ------------------------------------------------- - -class cMenuEditTypedIntItem : public cMenuEditIntItem -{ - protected: - cString type; - cString zeroString; - - virtual void Set(void); - - public: - cMenuEditTypedIntItem(const char *Name, const char *Type, int *Value, - int Min = 0, int Max = INT_MAX, const char *ZeroString = NULL, - const char *MinString = NULL, const char *MaxString = NULL); -}; - -// --- cMenuEditOddIntItem ------------------------------------------------- - -class cMenuEditOddIntItem : public cMenuEditIntItem -{ - public: - cMenuEditOddIntItem(const char *Name, int *Value, int Min = 1, int Max = INT_MAX, const char *MinString = NULL, const char *MaxString = NULL); - eOSState ProcessKey(eKeys Key); -}; - - -// --- cMenuEditFpIntItem ------------------------------------------------- - -// Fixed-point decimal number - -class cMenuEditFpIntItem : public cMenuEditIntItem -{ - protected: - int decimals; - cString zeroString; - - virtual void Set(void); - - public: - cMenuEditFpIntItem(const char *Name, int *Value, int Min = 1, int Max = INT_MAX, - int Decimals = 1, const char *ZeroString = NULL, - const char *MinString = NULL, const char *MaxString = NULL); -}; - - -// --- cMenuEditStraI18nItem ------------------------------------------------- - -class cMenuEditStraI18nItem : public cMenuEditIntItem -{ - private: - const char * const *strings; - - protected: - virtual void Set(void); - - public: - cMenuEditStraI18nItem(const char *Name, int *Value, - int NumStrings, const char * const *Strings); -}; - -// --- cFileListItem --------------------------------------------------------- - -class cFileListItem : public cOsdItem -{ - private: - cString m_Name; - cString m_SubFile; - bool m_IsDir, m_HasResume, m_ShowFlags, m_Up; - bool m_IsDvd; - - protected: - virtual void Set(void); - - public: - cFileListItem(const char *name, bool isDir, - bool HasResume, const char *subfile, - bool IsDvd = false); - cFileListItem(const char *name, bool isDir); - - const char *Name(void) { return m_Name; } - const char *SubFile(void) { return m_SubFile; } - bool IsDir(void) { return m_IsDir; } - bool IsDvd(void) { return m_IsDvd; } - - virtual bool operator< (const cListObject &ListObject); - virtual int Compare(const cListObject &ListObject) const; -}; - -#endif //__XINELIB_MENUITEMS_H_ diff --git a/mpg2c.c b/mpg2c.c deleted file mode 100644 index 50c1e25a..00000000 --- a/mpg2c.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2003-2006 Petri Hintukainen <phintuka@cc.hut.fi> - * - * This code is distributed under the terms and conditions of the - * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. - * - * mpg2.c: - * - * $Id: mpg2c.c,v 1.3 2006-06-04 11:00:04 phintuka Exp $ - * - */ - -#include <stdio.h> - -#define LINELEN 20 - -int main(int argc, char *argv[]) -{ - int ch; - int pos=1; - - if(argc != 4) { - printf("%s - convert binary file to C code\n\n" - "usage: %s variable inputfile outputfile\n", - argv[0],argv[0]); - return -1; - } - - FILE *fi = fopen(argv[2],"rb"); - FILE *fo = fopen(argv[3],"wt"); - if(!fi ||!fo) { - printf("Error opening files\n"); - return -1; - } - fprintf(fo, "extern const unsigned char v_mpg_%s[] = \n \"", argv[1]); - while(EOF != (ch = fgetc(fi))) { - fprintf(fo, "\\x%02x", ch); - if(pos++ > LINELEN) { - fprintf(fo, "\"\n \""); - pos=1; - } - } - fprintf(fo, "\";\n\nextern const int v_mpg_%s_length = sizeof(v_mpg_%s);\n\n", - argv[1], argv[1]); - - fclose(fi); - fclose(fo); - - return 0; -} diff --git a/nosignal_720x576.mpg b/nosignal_720x576.mpg Binary files differdeleted file mode 100644 index cff01b4c..00000000 --- a/nosignal_720x576.mpg +++ /dev/null @@ -1,620 +0,0 @@ -/* - * osd.c: Xinelib On Screen Display control - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: osd.c,v 1.37 2009-05-03 20:35:36 phintuka Exp $ - * - */ - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/thread.h> - -#include "logdefs.h" -#include "config.h" -#include "device.h" -#include "xine_osd_command.h" -#include "tools/rle.h" - -#include "osd.h" - -//#define LIMIT_OSD_REFRESH_RATE - -#define LOGOSD(x...) - -// -// tools -// - -static inline int saturate(int x, int min, int max) -{ - return x < min ? min : (x > max ? max : x); -} - -static inline void prepare_palette(xine_clut_t *clut, const unsigned int *palette, int colors, bool top, bool rgb) -{ - if (colors) { - int c; - - // Apply alpha layer correction and convert ARGB -> AYCrCb - - for(c=0; c<colors; c++) { - int A = (palette[c] & 0xff000000) >> 24; - int R = (palette[c] & 0x00ff0000) >> 16; - int G = (palette[c] & 0x0000ff00) >> 8; - int B = (palette[c] & 0x000000ff); - A = A + xc.alpha_correction*A/100 + xc.alpha_correction_abs; - if(rgb) { - clut[c].r = R; - clut[c].g = G; - clut[c].b = B; - clut[c].alpha = saturate( A, 0, 255); - } else { - int Y = (( + 66*R + 129*G + 25*B + 0x80) >> 8) + 16; - int CR = (( + 112*R - 94*G - 18*B + 0x80) >> 8) + 128; - int CB = (( - 38*R - 74*G + 112*B + 0x80) >> 8) + 128; - clut[c].y = saturate( Y, 16, 235); - clut[c].cb = saturate(CB, 16, 240); - clut[c].cr = saturate(CR, 16, 240); - clut[c].alpha = saturate( A, 0, 255); - } - } - - // Apply OSD mixer settings - - if(!top) { - if(xc.osd_mixer & OSD_MIXER_ALPHA) - for(c=0; c<colors; c++) - clut[c].alpha >>= 1; /* fade */ - if(xc.osd_mixer & OSD_MIXER_GRAY) - for(c=0; c<colors; c++) { - if(rgb) - clut[c].r = clut[c].g = clut[c].b = (clut[c].r + clut[c].g + clut[c].b)/3; - else - clut[c].cb = clut[c].cr = 0x80; - } - } - } -} - -// -// cXinelibOsd -// - -class cXinelibOsd : public cOsd, public cListObject -{ - private: - cXinelibOsd(); - cXinelibOsd(cXinelibOsd&); // no copy - - cXinelibDevice *m_Device; - - void CloseWindows(void); - void CmdSize(int Width, int Height); - void CmdRle(int Wnd, int X0, int Y0, - int W, int H, unsigned char *Data, - int Colors, unsigned int *Palette, - osd_rect_t *DirtyArea); - void CmdPalette(int Wnd, int Colors, unsigned int *Palette); - void CmdMove(int Wnd, int Width, int Height); - void CmdClose(int Wnd); - void CmdFlush(void); - - /* map single OSD window indexes to unique xine-side window handles */ - static uint64_t m_HandlesBitmap; - int *m_WindowHandles; - int AllocWindowHandles(int NumWindows); - void FreeWindowHandles(void); - - protected: - static cMutex m_Lock; - static cList<cXinelibOsd> m_OsdStack; - - bool m_IsVisible; - bool m_Refresh; - uint m_Layer; - uint16_t m_ExtentWidth; - uint16_t m_ExtentHeight; - - virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); - virtual eOsdError SetAreas(const tArea *Areas, int NumAreas); - virtual void Flush(void); - - // Messages from cXinelibOsdProvider - void Show(void); - void Hide(void); - void Refresh(void); - void Detach(void); - - friend class cXinelibOsdProvider; - - public: - cXinelibOsd(cXinelibDevice *Device, int x, int y, uint Level = 0); - virtual ~cXinelibOsd(); -}; - -cList<cXinelibOsd> cXinelibOsd::m_OsdStack; -cMutex cXinelibOsd::m_Lock; -uint64_t cXinelibOsd::m_HandlesBitmap; - -int cXinelibOsd::AllocWindowHandles(int NumWindows) -{ - uint64_t bit = 1; - int index = 0, wnd = 0; - - FreeWindowHandles(); - m_WindowHandles = new int[NumWindows+1]; - - for (index = 0; index < MAX_OSD_OBJECT; index++) { - if (! (m_HandlesBitmap & bit)) { - m_WindowHandles[wnd++] = index; - m_HandlesBitmap |= bit; - } - if (wnd >= NumWindows) - break; - bit <<= 1; - } - m_WindowHandles[NumWindows] = -1; - - if (wnd < NumWindows) { - LOGMSG("cXinelibOsd::AllocOsdHandles(): Too many open OSD windows !"); - while(wnd < NumWindows) m_WindowHandles[wnd++] = -1; - return 0; - } - - return NumWindows; -} - -void cXinelibOsd::FreeWindowHandles(void) -{ - if (m_WindowHandles) { - int wnd = 0; - while (m_WindowHandles[wnd] >= 0) { - m_HandlesBitmap &= ~( ((uint64_t)1) << m_WindowHandles[wnd]); - wnd++; - } - delete [] m_WindowHandles; - m_WindowHandles = NULL; - } -} - -void cXinelibOsd::CmdSize(int Width, int Height) -{ - TRACEF("cXinelibOsd::CmdSize"); - - if (m_Device) { - osd_command_t osdcmd = {0}; - - for (int Wnd = 0; GetBitmap(Wnd); Wnd++) { - osdcmd.cmd = OSD_Size; - osdcmd.wnd = m_WindowHandles[Wnd]; - osdcmd.w = Width; - osdcmd.h = Height; - - m_Device->OsdCmd((void*)&osdcmd); - } - } -} - -void cXinelibOsd::CmdMove(int Wnd, int NewX, int NewY) -{ - TRACEF("cXinelibOsd::CmdMove"); - - if (m_Device) { - osd_command_t osdcmd = {0}; - - osdcmd.cmd = OSD_Move; - osdcmd.wnd = m_WindowHandles[Wnd]; - osdcmd.x = NewX; - osdcmd.y = NewY; - - m_Device->OsdCmd((void*)&osdcmd); - } -} - -void cXinelibOsd::CmdPalette(int Wnd, int Colors, unsigned int *Palette) -{ - TRACEF("cXinelibOsd::CmdPalette"); - - if (m_Device) { - xine_clut_t clut[Colors]; - osd_command_t osdcmd = {0}; - - osdcmd.cmd = OSD_SetPalette; - osdcmd.wnd = m_WindowHandles[Wnd]; - osdcmd.palette = clut; - osdcmd.colors = Colors; - - prepare_palette(&clut[0], Palette, Colors, /*Top*/(Prev() == NULL), true); - - m_Device->OsdCmd((void*)&osdcmd); - } -} - -void cXinelibOsd::CmdClose(int Wnd) -{ - TRACEF("cXinelibOsd::CmdClose"); - - if (m_Device) { - osd_command_t osdcmd = {0}; - - osdcmd.cmd = OSD_Close; - osdcmd.wnd = m_WindowHandles[Wnd]; - - if (m_Refresh) - osdcmd.flags |= OSDFLAG_REFRESH; - if (Prev() == NULL) - osdcmd.flags |= OSDFLAG_TOP_LAYER; - - m_Device->OsdCmd((void*)&osdcmd); - } -} - -void cXinelibOsd::CmdFlush(void) -{ - TRACEF("cXinelibOsd::CmdFlush"); - - if (m_Device) { - osd_command_t osdcmd = {0}; - - osdcmd.cmd = OSD_Flush; - - m_Device->OsdCmd((void*)&osdcmd); - } -} - -void cXinelibOsd::CmdRle(int Wnd, int X0, int Y0, - int W, int H, unsigned char *Data, - int Colors, unsigned int *Palette, - osd_rect_t *DirtyArea) -{ - TRACEF("cXinelibOsd::CmdRle"); - - if (m_Device) { - - xine_clut_t clut[Colors]; - osd_command_t osdcmd = {0}; - - osdcmd.cmd = OSD_Set_RLE; - osdcmd.wnd = m_WindowHandles[Wnd]; - osdcmd.layer = saturate(m_Layer, 0, 0xffff); - osdcmd.x = X0; - osdcmd.y = Y0; - osdcmd.w = W; - osdcmd.h = H; - osdcmd.colors = Colors; - osdcmd.palette = clut; - osdcmd.scaling = xc.osd_scaling; - - if (DirtyArea) - memcpy(&osdcmd.dirty_area, DirtyArea, sizeof(osd_rect_t)); - if (m_Refresh) - osdcmd.flags |= OSDFLAG_REFRESH; - if (xc.osd_blending == OSD_BLENDING_HARDWARE) - osdcmd.flags |= OSDFLAG_UNSCALED; - if (xc.osd_blending_lowresvideo == OSD_BLENDING_HARDWARE) - osdcmd.flags |= OSDFLAG_UNSCALED_LOWRES; - if (Prev() == NULL) - osdcmd.flags |= OSDFLAG_TOP_LAYER; - - prepare_palette(&clut[0], Palette, Colors, /*Top*/(Prev() == NULL), true); - - if (xc.osd_blending_lowresvideo == OSD_BLENDING_HARDWARE) - osdcmd.flags |= OSDFLAG_UNSCALED_LOWRES; - osdcmd.num_rle = rle_compress(&osdcmd.data, Data, W, H); - osdcmd.datalen = 4 * osdcmd.num_rle; - - m_Device->OsdCmd((void*)&osdcmd); - - free(osdcmd.data); - } -} - -cXinelibOsd::cXinelibOsd(cXinelibDevice *Device, int x, int y, uint Level) - : cOsd(x, y, Level) -{ - TRACEF("cXinelibOsd::cXinelibOsd"); - - m_Device = Device; - m_Refresh = false; - m_IsVisible = true; - m_Layer = Level; - m_ExtentWidth = 720; - m_ExtentHeight = 576; - - m_WindowHandles = NULL; -} - -cXinelibOsd::~cXinelibOsd() -{ - TRACEF("cXinelibOsd::~cXinelibOsd"); - - cMutexLock ml(&m_Lock); - - CloseWindows(); - FreeWindowHandles(); - - m_OsdStack.Del(this, false); - - if(m_OsdStack.First()) - m_OsdStack.First()->Show(); -} - -eOsdError cXinelibOsd::SetAreas(const tArea *Areas, int NumAreas) -{ - TRACEF("cXinelibOsd::SetAreas"); - cMutexLock ml(&m_Lock); - - LOGOSD("cXinelibOsd::SetAreas"); - - // Close all existing windows - CloseWindows(); - FreeWindowHandles(); - - eOsdError Result = cOsd::SetAreas(Areas, NumAreas); - - if (Result != oeOk) - return Result; - - // Allocate xine OSD window handles - if (!AllocWindowHandles(NumAreas)) { - FreeWindowHandles(); - return oeTooManyAreas; - } - - // Detect full OSD area size - if(Left() + Width() > 720 || Top() + Height() > 576) { - m_ExtentWidth = Setup.OSDWidth + 2 * Setup.OSDLeft; - m_ExtentHeight = Setup.OSDHeight + 2 * Setup.OSDTop; - LOGDBG("Detected HD OSD, size > %dx%d, using setup values %dx%d", - 2*Left() + Width(), 2*Top() + Height(), - m_ExtentWidth, m_ExtentHeight); - } else { - m_ExtentWidth = 720; - m_ExtentHeight = 576; - } - CmdSize(m_ExtentWidth, m_ExtentHeight); - - return Result; -} - -eOsdError cXinelibOsd::CanHandleAreas(const tArea *Areas, int NumAreas) -{ - TRACEF("cXinelibOsd::CanHandleAreas"); - - eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas); - - if (Result != oeOk) - return Result; - - if (NumAreas > MAX_OSD_OBJECT) - return oeTooManyAreas; - - for (int i = 0; i < NumAreas; i++) { - if (Areas[i].bpp < 1 || Areas[i].bpp > 8) { - LOGMSG("cXinelibOsd::CanHandleAreas(): invalid bpp (%d)", Areas[i].bpp); - return oeBppNotSupported; - } - } - - // enough free xine OSD windows ? - uint64_t bit = 1; - int windows = NumAreas; - for (int index = 0; index < MAX_OSD_OBJECT && windows > 0; index++) { - if (! (m_HandlesBitmap & bit)) - windows--; - bit <<= 1; - } - if (windows > 0) { - LOGMSG("cXinelibOsd::CanHandleAreas(): not enough free window handles !"); - return oeTooManyAreas; - } - - return oeOk; -} - -void cXinelibOsd::Flush(void) -{ - TRACEF("cXinelibOsd::Flush"); - - cMutexLock ml(&m_Lock); - - cBitmap *Bitmap; - - if(!m_IsVisible) - return; - - int SendDone = 0; - for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { - int x1 = 0, y1 = 0, x2 = Bitmap->Width()-1, y2 = Bitmap->Height()-1; - if (m_Refresh || Bitmap->Dirty(x1, y1, x2, y2)) { - - /* XXX what if only palette has been changed ? */ - int NumColors; - const tColor *Colors = Bitmap->Colors(NumColors); - if (Colors) { - osd_rect_t DirtyArea = {x1:x1, y1:y1, x2:x2, y2:y2}; - CmdRle(i, - Left() + Bitmap->X0(), Top() + Bitmap->Y0(), - Bitmap->Width(), Bitmap->Height(), - (unsigned char *)Bitmap->Data(0,0), - NumColors, (unsigned int *)Colors, - &DirtyArea); - SendDone++; - } - } - Bitmap->Clean(); - } - -#ifdef LIMIT_OSD_REFRESH_RATE - if(SendDone) { - static int64_t last_refresh = 0LL; - int64_t now = cTimeMs::Now(); - if(now - last_refresh < 100) { - /* too fast refresh rate, delay ... */ - cCondWait::SleepMs(40); /* Can't update faster anyway ... */ -# if 0 - LOGDBG("cXinelibOsd::Flush: OSD refreshing too fast ! (>10Hz) -> Sleeping 50ms"); -# endif - } - last_refresh = now; - } -#endif -} - -void cXinelibOsd::Refresh(void) -{ - TRACEF("cXinelibOsd::Refresh"); - - cMutexLock ml(&m_Lock); - - m_Refresh = true; - CloseWindows(); - CmdSize(m_ExtentWidth, m_ExtentHeight); - Flush(); - m_Refresh = false; -} - -void cXinelibOsd::Show(void) -{ - TRACEF("cXinelibOsd::Show"); - - cMutexLock ml(&m_Lock); - - m_IsVisible = true; - Refresh(); -} - -void cXinelibOsd::CloseWindows(void) -{ - TRACEF("cXinelibOsd::CloseWindows"); - - if(m_IsVisible) { - cBitmap *Bitmap; - for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { - LOGOSD("Close OSD %d.%d", Index(), i); - if (m_WindowHandles[i] < 0) - LOGMSG("Close unallocated OSD %d.%d @%d", Index(), i, m_WindowHandles[i]); - CmdClose(i); - } - } - - if (!m_Refresh) - CmdFlush(); -} - -void cXinelibOsd::Hide(void) -{ - TRACEF("cXinelibOsd::Hide"); - - cMutexLock ml(&m_Lock); - - CloseWindows(); - m_IsVisible = false; -} - -void cXinelibOsd::Detach(void) -{ - TRACEF("cXinelibOsd::Detach"); - - cMutexLock ml(&m_Lock); - - Hide(); - m_Device = NULL; -} - -// -// cXinelibOsdProvider -// - -cXinelibOsdProvider::cXinelibOsdProvider(cXinelibDevice *Device) -{ - m_Device = Device; -} - -cXinelibOsdProvider::~cXinelibOsdProvider() -{ - LOGMSG("cXinelibOsdProvider: shutting down !"); - - cMutexLock ml(&cXinelibOsd::m_Lock); - - m_Device = NULL; - - if(cXinelibOsd::m_OsdStack.First()) { - LOGMSG("cXinelibOsdProvider: OSD open while OSD provider shutting down !"); - - // Detach all OSD instances from device - cXinelibOsd *osd; - while(NULL != (osd = cXinelibOsd::m_OsdStack.First())) { - osd->Detach(); - cXinelibOsd::m_OsdStack.Del(osd, false); - } - } -} - -cOsd *cXinelibOsdProvider::CreateOsd(int Left, int Top, uint Level) -{ - TRACEF("cXinelibOsdProvider::CreateOsd"); - - cMutexLock ml(&cXinelibOsd::m_Lock); - - cXinelibOsd *m_OsdInstance = new cXinelibOsd(m_Device, Left, Top, Level); - - // sorted insert - cXinelibOsd *it = cXinelibOsd::m_OsdStack.First(); - while(it) { - if(it->m_Layer >= Level) { - cXinelibOsd::m_OsdStack.Ins(m_OsdInstance, it); - break; - } - it = cXinelibOsd::m_OsdStack.Next(it); - } - if(!it) - cXinelibOsd::m_OsdStack.Add(m_OsdInstance); - - LOGOSD("New OSD: index %d, layer %d [now %d OSDs]", - m_OsdInstance->Index(), Level, cXinelibOsd::m_OsdStack.Count()); - - if(xc.osd_mixer == OSD_MIXER_NONE) { - // hide all but top-most OSD - LOGOSD(" OSD mixer off"); - it = cXinelibOsd::m_OsdStack.Last(); - while(cXinelibOsd::m_OsdStack.Prev(it)) { - LOGOSD(" -> hide OSD %d", it->Index()); - it->Hide(); - it = cXinelibOsd::m_OsdStack.Prev(it); - } - - } else /*if(xc.osd_mixer > OSD_MIXER_NONE)*/ { - LOGOSD("OSD mixer on (%d)", xc.osd_mixer); - it = cXinelibOsd::m_OsdStack.Last(); - while (cXinelibOsd::m_OsdStack.Prev(it)) { - LOGOSD(" -> show OSD %d", it->Index()); - it->Show(); - it = cXinelibOsd::m_OsdStack.Prev(it); - } - } - - it->Show(); - - return m_OsdInstance; -} - -void cXinelibOsdProvider::RefreshOsd(void) -{ - TRACEF("cXinelibOsdProvider::RefreshOsd"); - - cMutexLock ml(&cXinelibOsd::m_Lock); - - // bottom --> top (draw lower layer OSDs first) - cXinelibOsd *it = cXinelibOsd::m_OsdStack.Last(); - while(it) { - it->Refresh(); - it = cXinelibOsd::m_OsdStack.Prev(it); - } -} - - - @@ -1,36 +0,0 @@ -/* - * osd.h: Xinelib On Screen Display control - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: osd.h,v 1.5 2007-10-15 00:31:39 phintuka Exp $ - * - */ - -#ifndef __XINELIB_OSD_H -#define __XINELIB_OSD_H - -#include <vdr/osd.h> - -class cXinelibDevice; - -class cXinelibOsdProvider : public cOsdProvider -{ - protected: - cXinelibDevice *m_Device; - - public: - cXinelibOsdProvider(cXinelibDevice *Device); - virtual ~cXinelibOsdProvider(); - - virtual cOsd *CreateOsd(int Left, int Top, uint Level); - - static void RefreshOsd(void); - - // VDR < 1.5.9 compability - virtual cOsd *CreateOsd(int Left, int Top) { return CreateOsd(Left, Top, 0); } -}; - -#endif //__XINELIB_OSD_H - diff --git a/po/cs_CZ.po b/po/cs_CZ.po deleted file mode 100644 index 4cd41613..00000000 --- a/po/cs_CZ.po +++ /dev/null @@ -1,651 +0,0 @@ -# VDR plugin language source file. -# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> -# This file is distributed under the same license as the VDR package. -# -msgid "" -msgstr "" -"Project-Id-Version: Xineliboutput 1.1.0\n" -"Report-Msgid-Bugs-To: <phintuka@users.sourceforge.net>\n" -"POT-Creation-Date: 2009-01-07 15:46+0200\n" -"PO-Revision-Date: 2008-03-20 23:57+0100\n" -"Last-Translator: Maya <maja373@gmail.com>\n" -"Language-Team: <vdr@linuxtv.org>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=iso-8859-2\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Czech\n" -"X-Poedit-Country: CZECH REPUBLIC\n" - -msgid "custom" -msgstr "u¾ivatelský" - -msgid "tiny" -msgstr "nejmen¹í" - -msgid "small" -msgstr "malý" - -msgid "medium" -msgstr "støední" - -msgid "large" -msgstr "velký" - -msgid "huge" -msgstr "nejvìt¹í" - -msgid "automatic" -msgstr "automaticky" - -msgid "default" -msgstr "výchozí" - -msgid "Pan&Scan" -msgstr "Pan&Scan" - -msgid "CenterCutOut" -msgstr "" - -msgid "square" -msgstr "ètvercový" - -msgid "anamorphic" -msgstr "anamorfní" - -msgid "DVB" -msgstr "DVB" - -msgid "off" -msgstr "vypnuto" - -msgid "normal" -msgstr "normální" - -msgid "inverted" -msgstr "inverzní" - -msgid "no audio" -msgstr "bez zvuku" - -msgid "no video" -msgstr "bez obrazu" - -msgid "Off" -msgstr "vypnuto" - -msgid "Goom" -msgstr "Soutìska" - -msgid "Oscilloscope" -msgstr "Osciloskop" - -msgid "FFT Scope" -msgstr "FFT spektrum" - -msgid "FFT Graph" -msgstr "FFT graf" - -msgid "Mono 1.0" -msgstr "Mono 1.0" - -msgid "Stereo 2.0" -msgstr "Stereo 2.0" - -msgid "Headphones 2.0" -msgstr "Sluchátka 2.0" - -msgid "Stereo 2.1" -msgstr "Stereo 2.1" - -msgid "Surround 3.0" -msgstr "Surround 3.0" - -msgid "Surround 4.0" -msgstr "Surround 4.0" - -msgid "Surround 4.1" -msgstr "Surround 4.1" - -msgid "Surround 5.0" -msgstr "Surround 5.0" - -msgid "Surround 5.1" -msgstr "Surround 5.1" - -msgid "Surround 6.0" -msgstr "Surround 6.0" - -msgid "Surround 6.1" -msgstr "Surround 6.1" - -msgid "Surround 7.1" -msgstr "Surround 7.1" - -msgid "Pass Through" -msgstr "Prùchozí" - -msgid "very large" -msgstr "velmi velký" - -msgid "Software" -msgstr "softwarové" - -msgid "Hardware" -msgstr "hardwarové" - -msgid "no" -msgstr "ne" - -msgid "grayscale" -msgstr "odstíny ¹edi" - -msgid "transparent" -msgstr "prùhledný" - -msgid "transparent grayscale" -msgstr "" - -msgid "yes" -msgstr "ano" - -msgid "nearest" -msgstr "" - -msgid "bilinear" -msgstr "" - -msgid "none" -msgstr "" - -msgid "nonref" -msgstr "" - -msgid "bidir" -msgstr "" - -msgid "nonkey" -msgstr "" - -msgid "all" -msgstr "" - -msgid "Frontend initialization failed" -msgstr "Inicializace rozhraní selhala" - -msgid "Server initialization failed" -msgstr "Inicializace serveru selhala" - -msgid "Playlist" -msgstr "Seznam stop" - -msgid "Button$Random" -msgstr "Náhodné" - -msgid "Button$Normal" -msgstr "Normální" - -msgid "Button$Add files" -msgstr "Pøidat soubory" - -msgid "Button$Remove" -msgstr "Odstranit" - -msgid "Button$Sort" -msgstr "Tøídìní" - -msgid "Queued to playlist" -msgstr "Pøidáno do seznamu stop" - -msgid "Random play" -msgstr "Náhodné pøehrávání" - -msgid "Normal play" -msgstr "Normální pøehrávání" - -msgid "Delete image ?" -msgstr "Smazat obrázek ?" - -msgid "Images" -msgstr "Obrázky" - -msgid "Play music" -msgstr "Pøehrát hudbu" - -msgid "Add to playlist" -msgstr "Pøidat do seznamu stop" - -msgid "Play file" -msgstr "Pøehrát soubor" - -msgid "Button$Queue" -msgstr "Fronta" - -msgid "Media" -msgstr "Média" - -msgid "Play file >>" -msgstr "Pøehrát soubor >>" - -msgid "Play music >>" -msgstr "Pøehrát hudbu >>" - -msgid "View images >>" -msgstr "Prohlí¾et obrázky >>" - -msgid "Play remote DVD >>" -msgstr "Pøehrát vzdálené DVD >>" - -msgid "Play DVD disc >>" -msgstr "Pøehrát DVD >>" - -msgid "Play remote CD >>" -msgstr "Pøehrát vzdálené CD >>" - -msgid "Play audio CD >>" -msgstr "Pøehrát zvukové CD >>" - -msgid "Video settings" -msgstr "Nastavení obrazu" - -msgid "Play only audio" -msgstr "Pøehrávat pouze zvuk" - -msgid "Crop letterbox 4:3 to 16:9" -msgstr "Oøíznout letterbox 4:3 na 16:9" - -msgid "Overscan (crop image borders)" -msgstr "Overscan (oøez okrajù obrazu)" - -msgid "Interlaced Field Order" -msgstr "Poøadí pùlsnímkù" - -msgid "Audio settings" -msgstr "Nastavení zvuku" - -msgid "Headphone audio mode" -msgstr "" - -msgid "Audio Compression" -msgstr "" - -msgid "Audio equalizer >>" -msgstr "Korekce zvuku (ekvalizér) >>" - -msgid "Local Frontend" -msgstr "Lokální rozhraní" - -msgid "Aspect ratio" -msgstr "Pomìr stran" - -msgid "Video aspect ratio" -msgstr "Pomìr stran obrazu" - -msgid "On" -msgstr "zapnuto" - -msgid "Deinterlacing" -msgstr "Odstranìní prokládání" - -msgid "Upmix stereo to 5.1" -msgstr "Pøevzorkovat stereo na 5.1" - -msgid "Downmix AC3 to surround" -msgstr "Pøevzorkovat AC3 na surround" - -msgid "Default playlist not found" -msgstr "Výchozí seznam stop nenalezen" - -msgid "Default playlist is not symlink" -msgstr "Výchozí seznam stop není symbolický odkaz" - -msgid "Default playlist not defined" -msgstr "Výchozí seznam stop není definován" - -msgid "Delay" -msgstr "Zpo¾dìní" - -msgid "ms" -msgstr "ms" - -#, c-format -msgid "xineliboutput: hotkey %s not binded" -msgstr "xineliboutput: horká klávesa %s není pøiøazena" - -msgid "Audio" -msgstr "Zvuk" - -msgid "Speakers" -msgstr "Reproduktory" - -msgid "Volume control" -msgstr "Ovládání hlasitosti" - -msgid "Mix to headphones" -msgstr "" - -msgid "Visualization" -msgstr "Vizualizace" - -msgid " Width" -msgstr " ©íøka" - -msgid "px" -msgstr "bodù" - -msgid " Height" -msgstr " Vý¹ka" - -msgid " Speed" -msgstr " Rychlost" - -msgid "fps" -msgstr "snímkù/sek." - -msgid "Audio Equalizer" -msgstr "Korekce zvuku" - -msgid "Use Video-Out Driver" -msgstr "" - -msgid "vector" -msgstr "" - -msgid "full" -msgstr "" - -msgid "half (top)" -msgstr "" - -msgid "half (bottom)" -msgstr "" - -msgid "Video" -msgstr "Obraz" - -msgid " Autodetect letterbox" -msgstr " Automaticky detekovat letterbox" - -msgid " Soft start" -msgstr " Postupné zvìt¹ení" - -msgid " Crop to" -msgstr " Oøíznout na" - -msgid " Detect subtitles" -msgstr " Detekovat titulky" - -msgid "Software scaling" -msgstr "Softwarové ¹kálování" - -msgid " Change aspect ratio" -msgstr " Zmìna pomìru stran obrazu" - -msgid " Change video size" -msgstr " Zmìnit velikost obrazu" - -msgid " Allow downscaling" -msgstr " Povolit zmen¹ení" - -msgid "Post processing (ffmpeg)" -msgstr "Post processing (ffmpeg)" - -msgid " Quality" -msgstr " Kvalita" - -msgid " Mode" -msgstr " Mód" - -msgid " Method" -msgstr " Metoda" - -msgid " Cheap mode" -msgstr " Zjednodu¹ený mód" - -msgid " Pulldown" -msgstr "" - -msgid " Frame rate" -msgstr " Snímková rychlost" - -msgid " Judder Correction" -msgstr " Korekce chvìní" - -msgid " Use progressive frame flag" -msgstr "" - -msgid " Chroma Filter" -msgstr "" - -msgid "Sharpen / Blur" -msgstr "Zaostøení / rozmazání" - -msgid " Width of the luma matrix" -msgstr "" - -msgid " Height of the luma matrix" -msgstr "" - -msgid " Amount of luma sharpness/blur" -msgstr "" - -msgid " Width of the chroma matrix" -msgstr "" - -msgid " Height of the chroma matrix" -msgstr "" - -msgid " Amount of chroma sharpness/blur" -msgstr "" - -msgid "3D Denoiser" -msgstr "3D odstranìní ¹umu" - -msgid " Spatial luma strength" -msgstr "" - -msgid " Spatial chroma strength" -msgstr "" - -msgid " Temporal strength" -msgstr "" - -msgid "HUE" -msgstr "" - -msgid "Saturation" -msgstr "" - -msgid "Contrast" -msgstr "Kontrast" - -msgid "Brightness" -msgstr "Jas" - -msgid "Sharpness" -msgstr "" - -msgid "Noise Reduction" -msgstr "" - -msgid "Smooth fast forward" -msgstr "Plynulé pøetáèení" - -msgid "Fastest trick speed" -msgstr "" - -msgid "On-Screen Display" -msgstr "Obrazovkové menu" - -msgid "Hide main menu" -msgstr "Nezobrazovat v hlavním menu" - -msgid "Blending method" -msgstr "" - -msgid " Use hardware for low-res video" -msgstr "" - -msgid "Scaling method" -msgstr "" - -msgid "Show all layers" -msgstr "Zobrazit v¹echny vrstvy" - -msgid "Dynamic transparency correction" -msgstr "Úprava dynamické prùhlednosti" - -msgid "Static transparency correction" -msgstr "Úprava statické prùhlednosti" - -msgid "External subtitle size" -msgstr "Velikost externích titulkù" - -msgid "DVB subtitle decoder" -msgstr "" - -msgid "Decoder" -msgstr "Dekodér" - -msgid "Buffer size" -msgstr "Velikost vyrovnávací pamìti" - -msgid " Number of PES packets" -msgstr " Poèet PES paketù" - -msgid "Local Display Frontend" -msgstr "Lokální zobrazovací rozhraní" - -msgid "Use keyboard" -msgstr "Pou¾ívat klávesnici" - -msgid "Driver" -msgstr "Ovladaè" - -msgid "Display address" -msgstr "" - -msgid "Framebuffer device" -msgstr "" - -msgid "Fullscreen mode" -msgstr "Celoobrazovkový re¾im" - -msgid " Window width" -msgstr " ©íøka okna" - -msgid " Window height" -msgstr " Vý¹ka okna" - -msgid "Window aspect" -msgstr "Pomìr stran okna" - -msgid "Scale to window size" -msgstr "©kálovat do velikosti okna" - -msgid "Port" -msgstr "Port" - -msgid "Remote Clients" -msgstr "Vzdálení klienti" - -msgid "Allow remote clients" -msgstr "Povolit vzdálené klienty" - -msgid " Listen port (TCP and broadcast)" -msgstr "" - -msgid " Listen address" -msgstr "" - -msgid " Remote keyboard" -msgstr "" - -msgid " Max number of clients" -msgstr "" - -msgid " PIPE transport" -msgstr " PIPE transport" - -msgid " TCP transport" -msgstr " TCP transport" - -msgid " UDP transport" -msgstr " UDP transport" - -msgid " RTP (multicast) transport" -msgstr " RTP (multicast) transport" - -msgid " Address" -msgstr " Adresa" - -msgid " Port" -msgstr " Port" - -msgid " TTL" -msgstr "" - -msgid " Transmit always on" -msgstr " Pøenos stále zapnut" - -msgid " SAP announcements" -msgstr "" - -msgid " Server announce broadcasts" -msgstr "" - -msgid " HTTP transport for media files" -msgstr " HTTP transport pro média" - -msgid "Additional network services" -msgstr "Dal¹í sí»ové slu¾by" - -msgid "HTTP server" -msgstr "HTTP server" - -msgid "HTTP clients can control VDR" -msgstr "HTTP klienti mohou ovládat VDR" - -msgid "RTSP server" -msgstr "RTSP server" - -msgid "RTSP clients can control VDR" -msgstr "RTSP klienti mohou ovládat VDR" - -msgid "Playlist settings" -msgstr "Nastavení seznamu stop" - -msgid "Show the track number" -msgstr "Zobrazovat èíslo stopy" - -msgid "Show the name of the artist" -msgstr "Zobrazovat jméno autora" - -msgid "Show the name of the album" -msgstr "Zobrazovat název alba" - -msgid "Scan for metainfo" -msgstr "Vyhledávat metainfo" - -msgid "Cache metainfo" -msgstr "Uchovávat metainfo" - -msgid "Arrow keys control DVD playback" -msgstr "" - -msgid "Grayscale" -msgstr "Odstíny ¹edi" - -msgid "Bitmap" -msgstr "Rastr" - -msgid "OSD" -msgstr "OSD" - -msgid "Media Player" -msgstr "Pøehrávaè médií" - -msgid "Test Images" -msgstr "Zku¹ební obrazce" - -msgid "X11/xine-lib output plugin" -msgstr "X11/xine-lib výstupní plugin" diff --git a/po/de_DE.po b/po/de_DE.po deleted file mode 100644 index f1840bbf..00000000 --- a/po/de_DE.po +++ /dev/null @@ -1,650 +0,0 @@ -# VDR plugin language source file. -# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> -# This file is distributed under the same license as the VDR package. -# Udo Richter -# -msgid "" -msgstr "" -"Project-Id-Version: Xineliboutput 1.1.0\n" -"Report-Msgid-Bugs-To: <phintuka@users.sourceforge.net>\n" -"POT-Creation-Date: 2009-01-07 15:46+0200\n" -"PO-Revision-Date: 2007-11-23 10:17+0200\n" -"Last-Translator: Udo Richter\n" -"Language-Team: <vdr@linuxtv.org>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ISO-8859-15\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "custom" -msgstr "Benutzerdefiniert" - -msgid "tiny" -msgstr "Winzig" - -msgid "small" -msgstr "Klein" - -msgid "medium" -msgstr "Mittel" - -msgid "large" -msgstr "Groß" - -msgid "huge" -msgstr "Riesig" - -msgid "automatic" -msgstr "Automatik" - -msgid "default" -msgstr "Standard" - -msgid "Pan&Scan" -msgstr "Pan&Scan" - -msgid "CenterCutOut" -msgstr "CenterCutOut" - -msgid "square" -msgstr "" - -msgid "anamorphic" -msgstr "" - -msgid "DVB" -msgstr "" - -msgid "off" -msgstr "Aus" - -msgid "normal" -msgstr "Normal" - -msgid "inverted" -msgstr "Invertiert" - -msgid "no audio" -msgstr "Kein Audio" - -msgid "no video" -msgstr "Kein Video" - -msgid "Off" -msgstr "Aus" - -msgid "Goom" -msgstr "Goom" - -msgid "Oscilloscope" -msgstr "Oszilloskop" - -msgid "FFT Scope" -msgstr "FFT Spektrum" - -msgid "FFT Graph" -msgstr "FFT Graph" - -msgid "Mono 1.0" -msgstr "" - -msgid "Stereo 2.0" -msgstr "" - -msgid "Headphones 2.0" -msgstr "" - -msgid "Stereo 2.1" -msgstr "" - -msgid "Surround 3.0" -msgstr "" - -msgid "Surround 4.0" -msgstr "" - -msgid "Surround 4.1" -msgstr "" - -msgid "Surround 5.0" -msgstr "" - -msgid "Surround 5.1" -msgstr "" - -msgid "Surround 6.0" -msgstr "" - -msgid "Surround 6.1" -msgstr "" - -msgid "Surround 7.1" -msgstr "" - -msgid "Pass Through" -msgstr "" - -msgid "very large" -msgstr "" - -msgid "Software" -msgstr "" - -msgid "Hardware" -msgstr "" - -msgid "no" -msgstr "" - -msgid "grayscale" -msgstr "" - -msgid "transparent" -msgstr "" - -msgid "transparent grayscale" -msgstr "" - -msgid "yes" -msgstr "" - -msgid "nearest" -msgstr "" - -msgid "bilinear" -msgstr "" - -msgid "none" -msgstr "" - -msgid "nonref" -msgstr "" - -msgid "bidir" -msgstr "" - -msgid "nonkey" -msgstr "" - -msgid "all" -msgstr "" - -msgid "Frontend initialization failed" -msgstr "Initialisierung des Frontends fehlgeschlagen" - -msgid "Server initialization failed" -msgstr "Initialisierung des Servers fehlgeschlagen" - -msgid "Playlist" -msgstr "Wiedergabeliste" - -msgid "Button$Random" -msgstr "Zufall" - -msgid "Button$Normal" -msgstr "Normal" - -msgid "Button$Add files" -msgstr "Füge Dateien hinzu" - -msgid "Button$Remove" -msgstr "Entferne" - -msgid "Button$Sort" -msgstr "Sortiere" - -msgid "Queued to playlist" -msgstr "Hänge an Wiedergabeliste an" - -msgid "Random play" -msgstr "Zufallswiedergabe" - -msgid "Normal play" -msgstr "Normale Wiedergabe" - -msgid "Delete image ?" -msgstr "Bild löschen?" - -msgid "Images" -msgstr "Bilder" - -msgid "Play music" -msgstr "Musik abspielen" - -msgid "Add to playlist" -msgstr "Füge zur Wiedergabeliste hinzu" - -msgid "Play file" -msgstr "Datei abspielen" - -msgid "Button$Queue" -msgstr "Warteschlange" - -msgid "Media" -msgstr "Medien" - -msgid "Play file >>" -msgstr "Datei abspielen >>" - -msgid "Play music >>" -msgstr "Musik abspielen >>" - -msgid "View images >>" -msgstr "Bilder ansehen >>" - -msgid "Play remote DVD >>" -msgstr "Entfernte DVD abspielen >>" - -msgid "Play DVD disc >>" -msgstr "DVD abspielen >>" - -msgid "Play remote CD >>" -msgstr "Entfernte CD abspielen >>" - -msgid "Play audio CD >>" -msgstr "Musik-CD abspielen >>" - -msgid "Video settings" -msgstr "Video-Einstellungen" - -msgid "Play only audio" -msgstr "Nur Audio spielen" - -msgid "Crop letterbox 4:3 to 16:9" -msgstr "Schneide letterbox 4:3 zu 16:9" - -msgid "Overscan (crop image borders)" -msgstr "Overscan (Bildränder abschneiden)" - -msgid "Interlaced Field Order" -msgstr "Interlaced Halbbild-Reihenfolge" - -msgid "Audio settings" -msgstr "Audio-Einstellungen" - -msgid "Headphone audio mode" -msgstr "" - -msgid "Audio Compression" -msgstr "Audio-Komprimierung" - -msgid "Audio equalizer >>" -msgstr "Audio-Equalizer >>" - -msgid "Local Frontend" -msgstr "Lokale Anzeige" - -msgid "Aspect ratio" -msgstr "Seitenverhältnis" - -msgid "Video aspect ratio" -msgstr "" - -msgid "On" -msgstr "" - -msgid "Deinterlacing" -msgstr "Deinterlacing" - -msgid "Upmix stereo to 5.1" -msgstr "Stereo zu 5.1 hoch mischen" - -msgid "Downmix AC3 to surround" -msgstr "AC3 zu Surround herunter mischen" - -msgid "Default playlist not found" -msgstr "" - -msgid "Default playlist is not symlink" -msgstr "" - -msgid "Default playlist not defined" -msgstr "" - -msgid "Delay" -msgstr "Verzögerung" - -msgid "ms" -msgstr "ms" - -#, c-format -msgid "xineliboutput: hotkey %s not binded" -msgstr "" - -msgid "Audio" -msgstr "Audio" - -msgid "Speakers" -msgstr "Lautsprecher" - -msgid "Volume control" -msgstr "" - -msgid "Mix to headphones" -msgstr "" - -msgid "Visualization" -msgstr "Visualisierung" - -msgid " Width" -msgstr " Breite" - -msgid "px" -msgstr "px" - -msgid " Height" -msgstr " Höhe" - -msgid " Speed" -msgstr " Bildrate" - -msgid "fps" -msgstr "" - -msgid "Audio Equalizer" -msgstr "Audio Equalizer" - -msgid "Use Video-Out Driver" -msgstr "" - -msgid "vector" -msgstr "" - -msgid "full" -msgstr "" - -msgid "half (top)" -msgstr "" - -msgid "half (bottom)" -msgstr "" - -msgid "Video" -msgstr "Video" - -msgid " Autodetect letterbox" -msgstr " Letterbox automatisch erkennen" - -msgid " Soft start" -msgstr " Weich starten" - -msgid " Crop to" -msgstr " Schneide auf" - -msgid " Detect subtitles" -msgstr " Erkenne Untertitel" - -msgid "Software scaling" -msgstr "" - -msgid " Change aspect ratio" -msgstr "" - -msgid " Change video size" -msgstr "" - -msgid " Allow downscaling" -msgstr " Verkleinern zulassen" - -msgid "Post processing (ffmpeg)" -msgstr "Nachbearbeitung (ffmpeg)" - -msgid " Quality" -msgstr " Qualität" - -msgid " Mode" -msgstr " Modus" - -msgid " Method" -msgstr " Methode" - -msgid " Cheap mode" -msgstr " einfacher Modus" - -msgid " Pulldown" -msgstr " Pulldown" - -msgid " Frame rate" -msgstr " Bildrate" - -msgid " Judder Correction" -msgstr " Ruckel-Korrektur" - -msgid " Use progressive frame flag" -msgstr " Nutze progressive frame flag" - -msgid " Chroma Filter" -msgstr " Chrominanz-Filter" - -msgid "Sharpen / Blur" -msgstr "" - -msgid " Width of the luma matrix" -msgstr "" - -msgid " Height of the luma matrix" -msgstr "" - -msgid " Amount of luma sharpness/blur" -msgstr "" - -msgid " Width of the chroma matrix" -msgstr "" - -msgid " Height of the chroma matrix" -msgstr "" - -msgid " Amount of chroma sharpness/blur" -msgstr "" - -msgid "3D Denoiser" -msgstr "" - -msgid " Spatial luma strength" -msgstr "" - -msgid " Spatial chroma strength" -msgstr "" - -msgid " Temporal strength" -msgstr "" - -msgid "HUE" -msgstr "Farbton" - -msgid "Saturation" -msgstr "Sättigung" - -msgid "Contrast" -msgstr "Kontrast" - -msgid "Brightness" -msgstr "Helligkeit" - -msgid "Sharpness" -msgstr "" - -msgid "Noise Reduction" -msgstr "" - -msgid "Smooth fast forward" -msgstr "" - -msgid "Fastest trick speed" -msgstr "" - -msgid "On-Screen Display" -msgstr "On-Screen Display" - -msgid "Hide main menu" -msgstr "Verstecke Hauptmenü" - -msgid "Blending method" -msgstr "" - -msgid " Use hardware for low-res video" -msgstr "" - -msgid "Scaling method" -msgstr "" - -msgid "Show all layers" -msgstr "" - -msgid "Dynamic transparency correction" -msgstr "Dynamische Transparenz-Korrektur" - -msgid "Static transparency correction" -msgstr "Statische Transparenz-Korrektur" - -msgid "External subtitle size" -msgstr "Untertitel größe" - -msgid "DVB subtitle decoder" -msgstr "" - -msgid "Decoder" -msgstr "Dekoder" - -msgid "Buffer size" -msgstr "Puffergröße" - -msgid " Number of PES packets" -msgstr " Anzahl PES-Pakete" - -msgid "Local Display Frontend" -msgstr "Lokale Bildschirmanzeige" - -msgid "Use keyboard" -msgstr "Tastatur benutzen" - -msgid "Driver" -msgstr "Treiber" - -msgid "Display address" -msgstr "Bildschirm-Adresse" - -msgid "Framebuffer device" -msgstr "Framebuffer-Device" - -msgid "Fullscreen mode" -msgstr "Vollbild-Modus" - -msgid " Window width" -msgstr " Fensterbreite" - -msgid " Window height" -msgstr " Fensterhöhe" - -msgid "Window aspect" -msgstr "Fenster-Seitenverhältnis" - -msgid "Scale to window size" -msgstr "Skaliere auf Fenster-Größe" - -msgid "Port" -msgstr "Port" - -msgid "Remote Clients" -msgstr "Entfernte Clients" - -msgid "Allow remote clients" -msgstr "Erlaube entfernte Clients" - -msgid " Listen port (TCP and broadcast)" -msgstr " Empfangender Port (TCP und Broadcast)" - -msgid " Listen address" -msgstr "" - -msgid " Remote keyboard" -msgstr " Tastaturfernsteuerung" - -msgid " Max number of clients" -msgstr "" - -msgid " PIPE transport" -msgstr " Pipe-Übertragung" - -msgid " TCP transport" -msgstr " TCP-Übertragung" - -msgid " UDP transport" -msgstr " UDP-Übertragung" - -msgid " RTP (multicast) transport" -msgstr " RTP (multicast) Übertragung" - -msgid " Address" -msgstr " Multicast-Adresse" - -msgid " Port" -msgstr " Multicast-Port" - -msgid " TTL" -msgstr " Multicast-TTL" - -msgid " Transmit always on" -msgstr " Immer senden" - -msgid " SAP announcements" -msgstr " SAP-Ankündigungen" - -msgid " Server announce broadcasts" -msgstr " Server-Bekanntmachung Broadcast" - -msgid " HTTP transport for media files" -msgstr " HTTP-Verbindung für Medien-Dateien" - -msgid "Additional network services" -msgstr "Zusätzliche Netzwerk-Services" - -msgid "HTTP server" -msgstr "HTTP-Server" - -msgid "HTTP clients can control VDR" -msgstr "HTTP-Clients können VDR kontrollieren" - -msgid "RTSP server" -msgstr "RTSP-Server" - -msgid "RTSP clients can control VDR" -msgstr "RTSP-Clients können VDR kontrollieren" - -msgid "Playlist settings" -msgstr "" - -msgid "Show the track number" -msgstr "" - -msgid "Show the name of the artist" -msgstr "" - -msgid "Show the name of the album" -msgstr "" - -msgid "Scan for metainfo" -msgstr "" - -msgid "Cache metainfo" -msgstr "" - -msgid "Arrow keys control DVD playback" -msgstr "" - -msgid "Grayscale" -msgstr "Graustufen" - -msgid "Bitmap" -msgstr "Bitmap" - -msgid "OSD" -msgstr "" - -msgid "Media Player" -msgstr "Medien..." - -msgid "Test Images" -msgstr "Testbilder" - -msgid "X11/xine-lib output plugin" -msgstr "X11/xine-lib Ausgabe-Plugin" diff --git a/po/fi_FI.po b/po/fi_FI.po deleted file mode 100644 index e3c8a9b9..00000000 --- a/po/fi_FI.po +++ /dev/null @@ -1,651 +0,0 @@ -# VDR plugin language source file. -# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> -# This file is distributed under the same license as the VDR package. -# Petri Hintukainen -# Rolf Ahrenberg -# -msgid "" -msgstr "" -"Project-Id-Version: Xineliboutput 1.1.0\n" -"Report-Msgid-Bugs-To: <phintuka@users.sourceforge.net>\n" -"POT-Creation-Date: 2009-01-07 15:46+0200\n" -"PO-Revision-Date: 2008-10-06 11:19+0200\n" -"Last-Translator: Rolf Ahrenberg\n" -"Language-Team: <vdr@linuxtv.org>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "custom" -msgstr "oma" - -msgid "tiny" -msgstr "olematon" - -msgid "small" -msgstr "pieni" - -msgid "medium" -msgstr "keskikokoinen" - -msgid "large" -msgstr "suuri" - -msgid "huge" -msgstr "valtava" - -msgid "automatic" -msgstr "automaattinen" - -msgid "default" -msgstr "oletus" - -msgid "Pan&Scan" -msgstr "Pan&Scan" - -msgid "CenterCutOut" -msgstr "CenterCutOut" - -msgid "square" -msgstr "neliö" - -msgid "anamorphic" -msgstr "anamorfinen" - -msgid "DVB" -msgstr "DVB" - -msgid "off" -msgstr "ei käytössä" - -msgid "normal" -msgstr "normaali" - -msgid "inverted" -msgstr "käänteinen" - -msgid "no audio" -msgstr "ei ääntä" - -msgid "no video" -msgstr "ei kuvaa" - -msgid "Off" -msgstr "ei käytössä" - -msgid "Goom" -msgstr "Goom" - -msgid "Oscilloscope" -msgstr "oskilloskooppi" - -msgid "FFT Scope" -msgstr "spektri" - -msgid "FFT Graph" -msgstr "spektrogrammi" - -msgid "Mono 1.0" -msgstr "Mono 1.0" - -msgid "Stereo 2.0" -msgstr "Stereo 2.0" - -msgid "Headphones 2.0" -msgstr "Kuulokkeet 2.0" - -msgid "Stereo 2.1" -msgstr "Stereo 2.1" - -msgid "Surround 3.0" -msgstr "Surround 3.0" - -msgid "Surround 4.0" -msgstr "Surround 4.0" - -msgid "Surround 4.1" -msgstr "Surround 4.1" - -msgid "Surround 5.0" -msgstr "Surround 5.0" - -msgid "Surround 5.1" -msgstr "Surround 5.1" - -msgid "Surround 6.0" -msgstr "Surround 6.0" - -msgid "Surround 6.1" -msgstr "Surround 6.1" - -msgid "Surround 7.1" -msgstr "Surround 7.1" - -msgid "Pass Through" -msgstr "läpivienti" - -msgid "very large" -msgstr "erittäin suuri" - -msgid "Software" -msgstr "ohjelmallisesti" - -msgid "Hardware" -msgstr "laitteistolla" - -msgid "no" -msgstr "ei" - -msgid "grayscale" -msgstr "harmaasävy" - -msgid "transparent" -msgstr "läpinäkyvä" - -msgid "transparent grayscale" -msgstr "läpinäkyvä harmaasävy" - -msgid "yes" -msgstr "kyllä" - -msgid "nearest" -msgstr "lähin" - -msgid "bilinear" -msgstr "bilineaarinen" - -msgid "none" -msgstr "ei" - -msgid "nonref" -msgstr "ei referoituja" - -msgid "bidir" -msgstr "vain B-ruudut" - -msgid "nonkey" -msgstr "ei avainruutuja" - -msgid "all" -msgstr "kaikki" - -msgid "Frontend initialization failed" -msgstr "Näyttölaitteen alustus epäonnistui" - -msgid "Server initialization failed" -msgstr "Palvelimen käynnistys epäonnistui" - -msgid "Playlist" -msgstr "Soittolista" - -msgid "Button$Random" -msgstr "Satunnaistoisto" - -msgid "Button$Normal" -msgstr "Normaali toisto" - -msgid "Button$Add files" -msgstr "Lisää" - -msgid "Button$Remove" -msgstr "Poista" - -msgid "Button$Sort" -msgstr "Järjestä" - -msgid "Queued to playlist" -msgstr "Lisätty soittolistalle" - -msgid "Random play" -msgstr "Satunnaistoisto" - -msgid "Normal play" -msgstr "Normaali toisto" - -msgid "Delete image ?" -msgstr "Poistetaanko kuva ?" - -msgid "Images" -msgstr "Kuvat" - -msgid "Play music" -msgstr "Toista musiikkia" - -msgid "Add to playlist" -msgstr "Lisää soittolistalle" - -msgid "Play file" -msgstr "Toista tiedosto" - -msgid "Button$Queue" -msgstr "Soittolistalle" - -msgid "Media" -msgstr "Media" - -msgid "Play file >>" -msgstr "Toista tiedosto >>" - -msgid "Play music >>" -msgstr "Toista musiikkia >>" - -msgid "View images >>" -msgstr "Katsele kuvia >>" - -msgid "Play remote DVD >>" -msgstr "Toista DVD-levy etäkoneesta >>" - -msgid "Play DVD disc >>" -msgstr "Toista DVD-levy >>" - -msgid "Play remote CD >>" -msgstr "Toista CD-levy etäkoneesta >>" - -msgid "Play audio CD >>" -msgstr "Toista CD-levy >>" - -msgid "Video settings" -msgstr "Videoasetukset" - -msgid "Play only audio" -msgstr "Toista pelkkä ääni" - -msgid "Crop letterbox 4:3 to 16:9" -msgstr "Leikkaa 4:3-letterbox 16:9:ksi" - -msgid "Overscan (crop image borders)" -msgstr "Leikkaa kuvan reunoja (overscan)" - -msgid "Interlaced Field Order" -msgstr "Lomitettujen kenttien järjestys" - -msgid "Audio settings" -msgstr "Ääniasetukset" - -msgid "Headphone audio mode" -msgstr "Kuulokkeiden äänimoodi" - -msgid "Audio Compression" -msgstr "Voimista hiljaisia ääniä" - -msgid "Audio equalizer >>" -msgstr "Taajuuskorjain >>" - -msgid "Local Frontend" -msgstr "Paikallinen näyttö" - -msgid "Aspect ratio" -msgstr "Kuvasuhde" - -msgid "Video aspect ratio" -msgstr "Videon kuvasuhde" - -msgid "On" -msgstr "Käytössä" - -msgid "Deinterlacing" -msgstr "Lomituksen poisto" - -msgid "Upmix stereo to 5.1" -msgstr "Miksaa stereoääni 5.1-kanavaiseksi" - -msgid "Downmix AC3 to surround" -msgstr "Miksaa AC3-ääni surroundiksi" - -msgid "Default playlist not found" -msgstr "Oletussoittolistaa ei löydetä" - -msgid "Default playlist is not symlink" -msgstr "Oletussoittolista ei ole symbolinen linkki" - -msgid "Default playlist not defined" -msgstr "Oletussoittolistaa ei ole määritelty" - -msgid "Delay" -msgstr "Viive" - -msgid "ms" -msgstr "ms" - -#, c-format -msgid "xineliboutput: hotkey %s not binded" -msgstr "xineliboutput: pikanäppäintä %s ei ole kytketty" - -msgid "Audio" -msgstr "Ääni" - -msgid "Speakers" -msgstr "Kaiuttimet" - -msgid "Volume control" -msgstr "Äänenvoimakkuuden säätö" - -msgid "Mix to headphones" -msgstr "Miksaa kuulokkeille" - -msgid "Visualization" -msgstr "Visualisointi" - -msgid " Width" -msgstr " Leveys" - -msgid "px" -msgstr "px" - -msgid " Height" -msgstr " Korkeus" - -msgid " Speed" -msgstr " Nopeus" - -msgid "fps" -msgstr "fps" - -msgid "Audio Equalizer" -msgstr "Taajuuskorjain" - -msgid "Use Video-Out Driver" -msgstr "videoajuri" - -msgid "vector" -msgstr "vektoroitu" - -msgid "full" -msgstr "täysi" - -msgid "half (top)" -msgstr "alempi puolisko" - -msgid "half (bottom)" -msgstr "ylempi puolisko" - -msgid "Video" -msgstr "Kuva" - -msgid " Autodetect letterbox" -msgstr " Tunnista letterbox automaattisesti" - -msgid " Soft start" -msgstr " Portaittainen aloitus" - -msgid " Crop to" -msgstr " Leikkaa kokoon" - -msgid " Detect subtitles" -msgstr " Huomioi tekstitys" - -msgid "Software scaling" -msgstr "Skaalaa ohjelmistolla" - -msgid " Change aspect ratio" -msgstr " Muuta kuvasuhdetta" - -msgid " Change video size" -msgstr " Muuta videokuvan kokoa" - -msgid " Allow downscaling" -msgstr " Salli skaalaus pienemmäksi" - -msgid "Post processing (ffmpeg)" -msgstr "Käytä jälkikäsittelyä (ffmpeg)" - -msgid " Quality" -msgstr " Laatu" - -msgid " Mode" -msgstr " Moodi" - -msgid " Method" -msgstr " Menetelmä" - -msgid " Cheap mode" -msgstr " Käytä Cheap-moodia" - -msgid " Pulldown" -msgstr " Pulldown-moodi" - -msgid " Frame rate" -msgstr " Ruudunpäivitys" - -msgid " Judder Correction" -msgstr " Käytä tärinänkorjausta" - -msgid " Use progressive frame flag" -msgstr " Tunnista progressiivinen kuva" - -msgid " Chroma Filter" -msgstr " Käytä Chroma-suodinta" - -msgid "Sharpen / Blur" -msgstr "Terävöinti / sumennus" - -msgid " Width of the luma matrix" -msgstr " Luma-matriisin leveys" - -msgid " Height of the luma matrix" -msgstr " Luma-matriisin korkeus" - -msgid " Amount of luma sharpness/blur" -msgstr " Luma-terävöinti/-sumennus" - -msgid " Width of the chroma matrix" -msgstr " Chroma-matriisin leveys" - -msgid " Height of the chroma matrix" -msgstr " Chroma-matriisin korkeus" - -msgid " Amount of chroma sharpness/blur" -msgstr " Chroma-terävöinti/-sumennus" - -msgid "3D Denoiser" -msgstr "3D-kohinanpoisto" - -msgid " Spatial luma strength" -msgstr " Luman tilavoimakkuus" - -msgid " Spatial chroma strength" -msgstr " Chroman tilavoimakkuus" - -msgid " Temporal strength" -msgstr " Ajallinen voimakkuus" - -msgid "HUE" -msgstr "Värisävy" - -msgid "Saturation" -msgstr "Saturaatio" - -msgid "Contrast" -msgstr "Kontrasti" - -msgid "Brightness" -msgstr "Kirkkaus" - -msgid "Sharpness" -msgstr "Terävöinti" - -msgid "Noise Reduction" -msgstr "Kohinanpoisto" - -msgid "Smooth fast forward" -msgstr "Tasainen kuvakelaus" - -msgid "Fastest trick speed" -msgstr "Suurin kelausnopeus" - -msgid "On-Screen Display" -msgstr "Kuvaruutunäyttö" - -msgid "Hide main menu" -msgstr "Piilota valinta päävalikossa" - -msgid "Blending method" -msgstr "Piirtotapa" - -msgid " Use hardware for low-res video" -msgstr " Laitteisto matalaresoluutioisella videolla" - -msgid "Scaling method" -msgstr "Skaalaustapa" - -msgid "Show all layers" -msgstr "Näytä kaikki kerrokset" - -msgid "Dynamic transparency correction" -msgstr "Dynaaminen läpinäkyvyyden korjaus" - -msgid "Static transparency correction" -msgstr "Läpinäkyvyyden korjaus" - -msgid "External subtitle size" -msgstr "Erillisen tekstityksen koko" - -msgid "DVB subtitle decoder" -msgstr "DVB-tekstityksen dekooderi" - -msgid "Decoder" -msgstr "Dekooderi" - -msgid "Buffer size" -msgstr "Puskurin koko" - -msgid " Number of PES packets" -msgstr " PES-pakettien lukumäärä" - -msgid "Local Display Frontend" -msgstr "Paikallinen näyttö" - -msgid "Use keyboard" -msgstr "Käytä näppäimistöä" - -msgid "Driver" -msgstr "Ohjain" - -msgid "Display address" -msgstr "Näytön osoite" - -msgid "Framebuffer device" -msgstr "Framebuffer-laite" - -msgid "Fullscreen mode" -msgstr "Kokoruututila" - -msgid " Window width" -msgstr " Ikkunan leveys" - -msgid " Window height" -msgstr " Ikkunan korkeus" - -msgid "Window aspect" -msgstr "Ikkunan kuvasuhde" - -msgid "Scale to window size" -msgstr "Skaalaa ikkunan kokoiseksi" - -msgid "Port" -msgstr "Portti" - -msgid "Remote Clients" -msgstr "Etäkäyttö" - -msgid "Allow remote clients" -msgstr "Salli etäkäyttö" - -msgid " Listen port (TCP and broadcast)" -msgstr " Kuuntele TCP-porttia" - -msgid " Listen address" -msgstr " Kuuntele osoitteessa" - -msgid " Remote keyboard" -msgstr " Käytä etänäppäimistöä" - -msgid " Max number of clients" -msgstr " Asiakkaiden maksimimäärä" - -msgid " PIPE transport" -msgstr " PIPE-siirto" - -msgid " TCP transport" -msgstr " TCP-siirto" - -msgid " UDP transport" -msgstr " UDP-siirto" - -msgid " RTP (multicast) transport" -msgstr " RTP (multicast) -siirto" - -msgid " Address" -msgstr " Osoite" - -msgid " Port" -msgstr " Portti" - -msgid " TTL" -msgstr " TTL-aika" - -msgid " Transmit always on" -msgstr " Pidä lähetys aina päällä" - -msgid " SAP announcements" -msgstr " SAP-ilmoitukset" - -msgid " Server announce broadcasts" -msgstr " Palvelimen broadcast-ilmoitukset" - -msgid " HTTP transport for media files" -msgstr " HTTP -siirto mediatiedostoille" - -msgid "Additional network services" -msgstr "Muut verkkopalvelut" - -msgid "HTTP server" -msgstr "HTTP-palvelin" - -msgid "HTTP clients can control VDR" -msgstr "Anna HTTP-asiakkaiden ohjata VDR:ää" - -msgid "RTSP server" -msgstr "RTSP-palvelin" - -msgid "RTSP clients can control VDR" -msgstr "Anna RTSP-asiakkaiden ohjata VDR:ää" - -msgid "Playlist settings" -msgstr "Soittolistan asetukset" - -msgid "Show the track number" -msgstr "Näytä raidan numero" - -msgid "Show the name of the artist" -msgstr "Näytä esittäjän nimi" - -msgid "Show the name of the album" -msgstr "Näytä levyn nimi" - -msgid "Scan for metainfo" -msgstr "Tutki kappaleiden metatiedot" - -msgid "Cache metainfo" -msgstr "Tallenna metatieto" - -msgid "Arrow keys control DVD playback" -msgstr "Ohjaa nuolinäppäimillä DVD-toistoa" - -msgid "Grayscale" -msgstr "Harmaasävy" - -msgid "Bitmap" -msgstr "Bittikartta" - -msgid "OSD" -msgstr "Kuvaruutunäyttö" - -msgid "Media Player" -msgstr "Mediasoitin" - -msgid "Test Images" -msgstr "Testikuvat" - -msgid "X11/xine-lib output plugin" -msgstr "X11/xine-lib näyttölaite" diff --git a/po/it_IT.po b/po/it_IT.po deleted file mode 100644 index 9276bd93..00000000 --- a/po/it_IT.po +++ /dev/null @@ -1,653 +0,0 @@ -# VDR plugin language source file. -# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> -# This file is distributed under the same license as the VDR package. -# -msgid "" -msgstr "" -"Project-Id-Version: Xineliboutput 1.1.0\n" -"Report-Msgid-Bugs-To: <phintuka@users.sourceforge.net>\n" -"POT-Creation-Date: 2009-01-07 15:46+0200\n" -"PO-Revision-Date: 2009-02-08 20:09+0100\n" -"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" -"Language-Team: <vdr@linuxtv.org>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Italian\n" -"X-Poedit-Country: ITALY\n" -"X-Poedit-SourceCharset: utf-8\n" - -msgid "custom" -msgstr "personalizza" - -msgid "tiny" -msgstr "molto piccolo" - -msgid "small" -msgstr "piccolo" - -msgid "medium" -msgstr "medio" - -msgid "large" -msgstr "grande" - -msgid "huge" -msgstr "enorme" - -msgid "automatic" -msgstr "automatica" - -msgid "default" -msgstr "predefinita" - -msgid "Pan&Scan" -msgstr "Pan&Scan" - -msgid "CenterCutOut" -msgstr "CenterCutOut" - -msgid "square" -msgstr "quadrato" - -msgid "anamorphic" -msgstr "anamorfico" - -msgid "DVB" -msgstr "DVB" - -msgid "off" -msgstr "spento" - -msgid "normal" -msgstr "normale" - -msgid "inverted" -msgstr "invertito" - -msgid "no audio" -msgstr "niente audio" - -msgid "no video" -msgstr "niente video" - -msgid "Off" -msgstr "Spento" - -msgid "Goom" -msgstr "Goom" - -msgid "Oscilloscope" -msgstr "Oscilloscopio" - -msgid "FFT Scope" -msgstr "Spettro FFT" - -msgid "FFT Graph" -msgstr "Grafico FFT" - -msgid "Mono 1.0" -msgstr "Mono 1.0" - -msgid "Stereo 2.0" -msgstr "Stereo 2.0" - -msgid "Headphones 2.0" -msgstr "Cuffie 2.0" - -msgid "Stereo 2.1" -msgstr "Stereo 2.1" - -msgid "Surround 3.0" -msgstr "Surround 3.0" - -msgid "Surround 4.0" -msgstr "Surround 4.0" - -msgid "Surround 4.1" -msgstr "Surround 4.1" - -msgid "Surround 5.0" -msgstr "Surround 5.0" - -msgid "Surround 5.1" -msgstr "Surround 5.1" - -msgid "Surround 6.0" -msgstr "Surround 6.0" - -msgid "Surround 6.1" -msgstr "Surround 6.1" - -msgid "Surround 7.1" -msgstr "Surround 7.1" - -msgid "Pass Through" -msgstr "Passa attraverso" - -msgid "very large" -msgstr "molto grande" - -msgid "Software" -msgstr "Software" - -msgid "Hardware" -msgstr "Hardware" - -msgid "no" -msgstr "no" - -msgid "grayscale" -msgstr "scala di grigi" - -msgid "transparent" -msgstr "trasparente" - -msgid "transparent grayscale" -msgstr "scala di grigi trasparente" - -msgid "yes" -msgstr "sì" - -msgid "nearest" -msgstr "più vicino" - -msgid "bilinear" -msgstr "bilineare" - -msgid "none" -msgstr "nessuno" - -msgid "nonref" -msgstr "nonref" - -msgid "bidir" -msgstr "nonref" - -msgid "nonkey" -msgstr "nonref" - -msgid "all" -msgstr "tutti" - -msgid "Frontend initialization failed" -msgstr "Inizializzazione frontend fallita" - -msgid "Server initialization failed" -msgstr "Inizializzazione server fallita" - -msgid "Playlist" -msgstr "Lista esecuzione" - -msgid "Button$Random" -msgstr "Casuale" - -msgid "Button$Normal" -msgstr "Normale" - -msgid "Button$Add files" -msgstr "Aggiungi files" - -msgid "Button$Remove" -msgstr "Rimuovi" - -msgid "Button$Sort" -msgstr "Ordina" - -msgid "Queued to playlist" -msgstr "Accoda alla lista esecuzione" - -msgid "Random play" -msgstr "Riproduzione casuale" - -msgid "Normal play" -msgstr "Riproduzione normale" - -msgid "Delete image ?" -msgstr "Eliminare immagine ?" - -msgid "Images" -msgstr "Immagini" - -msgid "Play music" -msgstr "Riproduci musica" - -msgid "Add to playlist" -msgstr "Aggiungi alla lista esec." - -msgid "Play file" -msgstr "Riproduci file" - -msgid "Button$Queue" -msgstr "Coda" - -msgid "Media" -msgstr "Media" - -msgid "Play file >>" -msgstr "Riproduci file >>" - -msgid "Play music >>" -msgstr "Riproduci musica >>" - -msgid "View images >>" -msgstr "Visualizza immagini >>" - -msgid "Play remote DVD >>" -msgstr "Riproduci DVD remoto >>" - -msgid "Play DVD disc >>" -msgstr "Riproduci disco DVD >>" - -msgid "Play remote CD >>" -msgstr "Riproduci CD remoto >>" - -msgid "Play audio CD >>" -msgstr "Riproduci CD audio >>" - -msgid "Video settings" -msgstr "Impostazioni video" - -msgid "Play only audio" -msgstr "Riproduci solo audio" - -msgid "Crop letterbox 4:3 to 16:9" -msgstr "Ritaglia letterbox 4:3 a 16:9" - -msgid "Overscan (crop image borders)" -msgstr "Overscan (ritaglia bordi immagine)" - -msgid "Interlaced Field Order" -msgstr "Ordine campo interlacciato" - -msgid "Audio settings" -msgstr "Impostazioni audio" - -msgid "Headphone audio mode" -msgstr "Modalità cuffie audio" - -msgid "Audio Compression" -msgstr "Compressione audio" - -msgid "Audio equalizer >>" -msgstr "Equalizzatore audio >>" - -msgid "Local Frontend" -msgstr "Frontend locale" - -msgid "Aspect ratio" -msgstr "Formato" - -msgid "Video aspect ratio" -msgstr "Formato video" - -msgid "On" -msgstr "Attivo" - -msgid "Deinterlacing" -msgstr "Deinterlacciamento" - -msgid "Upmix stereo to 5.1" -msgstr "Suono da Stereo a 5.1" - -msgid "Downmix AC3 to surround" -msgstr "Suono da AC3 a Surround" - -msgid "Default playlist not found" -msgstr "Lista esec. predefinita non trovata" - -msgid "Default playlist is not symlink" -msgstr "La lista esec. predefinita non è un link simbolico" - -msgid "Default playlist not defined" -msgstr "Lista esec. predefinita non definita" - -msgid "Delay" -msgstr "Ritardo" - -msgid "ms" -msgstr "ms" - -#, c-format -msgid "xineliboutput: hotkey %s not binded" -msgstr "xineliboutput: tasto %s non associato" - -msgid "Audio" -msgstr "Audio" - -msgid "Speakers" -msgstr "Altoparlanti" - -msgid "Volume control" -msgstr "Controllo volume" - -msgid "Mix to headphones" -msgstr "Suono a cuffie" - -msgid "Visualization" -msgstr "Visualizzazione" - -msgid " Width" -msgstr " Larghezza" - -msgid "px" -msgstr "px" - -msgid " Height" -msgstr " Altezza" - -msgid " Speed" -msgstr " Velocità " - -msgid "fps" -msgstr "fps" - -msgid "Audio Equalizer" -msgstr "Equalizzatore audio" - -msgid "Use Video-Out Driver" -msgstr "Utilizza driver uscita video" - -msgid "vector" -msgstr "vettoriale" - -msgid "full" -msgstr "intero" - -msgid "half (top)" -msgstr "metà (superiore)" - -msgid "half (bottom)" -msgstr "metà (inferiore)" - -msgid "Video" -msgstr "Video" - -msgid " Autodetect letterbox" -msgstr " Rileva letterbox in automatico" - -msgid " Soft start" -msgstr " Avvio leggero" - -msgid " Crop to" -msgstr " Ritaglia a" - -msgid " Detect subtitles" -msgstr " Rileva sottotitoli" - -msgid "Software scaling" -msgstr "Ridimensionamento software" - -msgid " Change aspect ratio" -msgstr " Cambia formato video" - -msgid " Change video size" -msgstr " Cambia dimensione video" - -msgid " Allow downscaling" -msgstr " Permetti ridimensionamento" - -msgid "Post processing (ffmpeg)" -msgstr "Codifica (ffmpeg)" - -msgid " Quality" -msgstr " Qualità " - -msgid " Mode" -msgstr " Modalità " - -msgid " Method" -msgstr " Metodo" - -msgid " Cheap mode" -msgstr " Modalità economica" - -msgid " Pulldown" -msgstr " Pulldown" - -msgid " Frame rate" -msgstr " Frame rate" - -msgid " Judder Correction" -msgstr " Correzione gamma" - -msgid " Use progressive frame flag" -msgstr " Utilizza flag frame progressivo" - -msgid " Chroma Filter" -msgstr " Filtro Chroma" - -msgid "Sharpen / Blur" -msgstr "Nitido / Blur" - -msgid " Width of the luma matrix" -msgstr " Larghezza della matrice luma" - -msgid " Height of the luma matrix" -msgstr " Altezza della matrice luma" - -msgid " Amount of luma sharpness/blur" -msgstr " Valore di nitidezza/blur luma" - -msgid " Width of the chroma matrix" -msgstr " Larghezza della matrice chroma" - -msgid " Height of the chroma matrix" -msgstr " Altezza della matrice chroma" - -msgid " Amount of chroma sharpness/blur" -msgstr " Valore di nitidezza/blur chroma" - -msgid "3D Denoiser" -msgstr "Denoiser 3D" - -msgid " Spatial luma strength" -msgstr " Resistenza luma spaziale" - -msgid " Spatial chroma strength" -msgstr " Resistenza chroma spaziale" - -msgid " Temporal strength" -msgstr " Resistenza temporale" - -msgid "HUE" -msgstr "Tonalità " - -msgid "Saturation" -msgstr "Saturazione" - -msgid "Contrast" -msgstr "Contrasto" - -msgid "Brightness" -msgstr "Luminosità " - -msgid "Sharpness" -msgstr "Nitidezza" - -msgid "Noise Reduction" -msgstr "Riduzione rumore" - -msgid "Smooth fast forward" -msgstr "Avanzamento veloce leggero" - -msgid "Fastest trick speed" -msgstr "Trucco velocità più rapida" - -msgid "On-Screen Display" -msgstr "Messaggi in sovrimpressione (OSD)" - -msgid "Hide main menu" -msgstr "Nascondi voce menu princ." - -msgid "Blending method" -msgstr "Metodo di sfocatura" - -msgid " Use hardware for low-res video" -msgstr "Utilizza hardware per video bassa risoluzione" - -msgid "Scaling method" -msgstr "Metodo ridimensione" - -msgid "Show all layers" -msgstr "Mostra tutti i livelli" - -msgid "Dynamic transparency correction" -msgstr "Correzione trasparenza dinamica" - -msgid "Static transparency correction" -msgstr "Correzione trasparenza statica" - -msgid "External subtitle size" -msgstr "Dimensione sottotitoli esterni" - -msgid "DVB subtitle decoder" -msgstr "Decoder sottotitoli DVB" - -msgid "Decoder" -msgstr "Decoder" - -msgid "Buffer size" -msgstr "Dimensione buffer" - -msgid " Number of PES packets" -msgstr " Numero di pacchetti PES" - -msgid "Local Display Frontend" -msgstr "Frontend visualizzazione locale" - -msgid "Use keyboard" -msgstr "Utilizza tastiera" - -msgid "Driver" -msgstr "Driver" - -msgid "Display address" -msgstr "Mostra indirizzo" - -msgid "Framebuffer device" -msgstr "Periferica framebuffer" - -msgid "Fullscreen mode" -msgstr "Mod. schermo intero" - -msgid " Window width" -msgstr " Larghezza finestra" - -msgid " Window height" -msgstr " Altezza finestra" - -msgid "Window aspect" -msgstr "Aspetto finestra" - -msgid "Scale to window size" -msgstr "Scala a dimensione finestra" - -msgid "Port" -msgstr "Porta" - -msgid "Remote Clients" -msgstr "Client remoti" - -msgid "Allow remote clients" -msgstr "Permetti client remoti" - -msgid " Listen port (TCP and broadcast)" -msgstr " Porta in ascolto (TCP e broadcast)" - -msgid " Listen address" -msgstr " Indirizzo in ascolto" - -msgid " Remote keyboard" -msgstr " Tastiera remota" - -msgid " Max number of clients" -msgstr " Numero massimo di client" - -msgid " PIPE transport" -msgstr " Protocollo PIPE" - -msgid " TCP transport" -msgstr " Protocollo TCP" - -msgid " UDP transport" -msgstr " Protocollo UDP" - -msgid " RTP (multicast) transport" -msgstr " Protocollo RTP (multicast)" - -msgid " Address" -msgstr " Indirizzo" - -msgid " Port" -msgstr " Porta" - -msgid " TTL" -msgstr " TTL" - -msgid " Transmit always on" -msgstr " Trasmetti sempre" - -msgid " SAP announcements" -msgstr " Annunci SAP" - -msgid " Server announce broadcasts" -msgstr " Annuncio trasmissioni dal server" - -msgid " HTTP transport for media files" -msgstr " Protocollo HTTP per file multimediali" - -msgid "Additional network services" -msgstr "Ulteriori servizi di rete" - -msgid "HTTP server" -msgstr "Server HTTP" - -msgid "HTTP clients can control VDR" -msgstr "I client HTTP possono controllare VDR" - -msgid "RTSP server" -msgstr "Server RTSP" - -msgid "RTSP clients can control VDR" -msgstr "I client RTSP possono controllare VDR" - -msgid "Playlist settings" -msgstr "Impostazioni lista esec." - -msgid "Show the track number" -msgstr "Mostra il numero della traccia" - -msgid "Show the name of the artist" -msgstr "Mostra il nome dell'artista" - -msgid "Show the name of the album" -msgstr "Mostra il nome dell'album" - -msgid "Scan for metainfo" -msgstr "Scansione metainfo" - -msgid "Cache metainfo" -msgstr "Cache metainfo" - -msgid "Arrow keys control DVD playback" -msgstr "Controllo riprod. DVD con tasti freccia" - -msgid "Grayscale" -msgstr "Scala di grigi" - -msgid "Bitmap" -msgstr "Bitmap" - -msgid "OSD" -msgstr "OSD" - -msgid "Media Player" -msgstr "Lettore multimediale" - -msgid "Test Images" -msgstr "Prova immagini" - -msgid "X11/xine-lib output plugin" -msgstr "Plugin uscita X11/xine-lib" - diff --git a/po/ru_RU.po b/po/ru_RU.po deleted file mode 100644 index 27a45d25..00000000 --- a/po/ru_RU.po +++ /dev/null @@ -1,650 +0,0 @@ -# VDR plugin language source file. -# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> -# This file is distributed under the same license as the VDR package. -# Vladimir Monchenko -# -msgid "" -msgstr "" -"Project-Id-Version: Xineliboutput 1.1.0\n" -"Report-Msgid-Bugs-To: <phintuka@users.sourceforge.net>\n" -"POT-Creation-Date: 2009-01-07 15:46+0200\n" -"PO-Revision-Date: 2007-11-23 10:17+0200\n" -"Last-Translator: Vladimir Monchenko\n" -"Language-Team: <vdr@linuxtv.org>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ISO-8859-5\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "custom" -msgstr "¿ÞÛì×ÞÒÐâÕÛì" - -msgid "tiny" -msgstr "¾çÕÝì ÜÐÛÕÝìÚØÙ" - -msgid "small" -msgstr "¼ÐÛÕÝìÚØÙ" - -msgid "medium" -msgstr "ÁàÕÔÝØÙ" - -msgid "large" -msgstr "±ÞÛìèÞÙ" - -msgid "huge" -msgstr "¾çÕÝì ÑÞÛìÝÞÙ" - -msgid "automatic" -msgstr "°ÒâÞÜÐâØçÕáÚØ" - -msgid "default" -msgstr "¿Þ ãÜÞÛçÐÝØî" - -msgid "Pan&Scan" -msgstr "Pan&Scan" - -msgid "CenterCutOut" -msgstr "" - -msgid "square" -msgstr "" - -msgid "anamorphic" -msgstr "" - -msgid "DVB" -msgstr "" - -msgid "off" -msgstr "²ëÚÛ." - -msgid "normal" -msgstr "½ÞàÜÐÛìÝëÙ" - -msgid "inverted" -msgstr "¸ÝÒÕàâØàÞÒÐÝÞ" - -msgid "no audio" -msgstr "½Õâ ÐãÔØÞ" - -msgid "no video" -msgstr "½Õâ ÒØÔÕÞ" - -msgid "Off" -msgstr "" - -msgid "Goom" -msgstr "" - -msgid "Oscilloscope" -msgstr "" - -msgid "FFT Scope" -msgstr "" - -msgid "FFT Graph" -msgstr "" - -msgid "Mono 1.0" -msgstr "" - -msgid "Stereo 2.0" -msgstr "" - -msgid "Headphones 2.0" -msgstr "" - -msgid "Stereo 2.1" -msgstr "" - -msgid "Surround 3.0" -msgstr "" - -msgid "Surround 4.0" -msgstr "" - -msgid "Surround 4.1" -msgstr "" - -msgid "Surround 5.0" -msgstr "" - -msgid "Surround 5.1" -msgstr "" - -msgid "Surround 6.0" -msgstr "" - -msgid "Surround 6.1" -msgstr "" - -msgid "Surround 7.1" -msgstr "" - -msgid "Pass Through" -msgstr "" - -msgid "very large" -msgstr "" - -msgid "Software" -msgstr "" - -msgid "Hardware" -msgstr "" - -msgid "no" -msgstr "" - -msgid "grayscale" -msgstr "" - -msgid "transparent" -msgstr "" - -msgid "transparent grayscale" -msgstr "" - -msgid "yes" -msgstr "" - -msgid "nearest" -msgstr "" - -msgid "bilinear" -msgstr "" - -msgid "none" -msgstr "" - -msgid "nonref" -msgstr "" - -msgid "bidir" -msgstr "" - -msgid "nonkey" -msgstr "" - -msgid "all" -msgstr "" - -msgid "Frontend initialization failed" -msgstr "" - -msgid "Server initialization failed" -msgstr "" - -msgid "Playlist" -msgstr "" - -msgid "Button$Random" -msgstr "" - -msgid "Button$Normal" -msgstr "" - -msgid "Button$Add files" -msgstr "" - -msgid "Button$Remove" -msgstr "" - -msgid "Button$Sort" -msgstr "" - -msgid "Queued to playlist" -msgstr "" - -msgid "Random play" -msgstr "" - -msgid "Normal play" -msgstr "" - -msgid "Delete image ?" -msgstr "ÃÔÐÛØâì ÚÐàâØÝÚã ?" - -msgid "Images" -msgstr "¸×ÞÑàÐÖÕÝØï" - -msgid "Play music" -msgstr "" - -msgid "Add to playlist" -msgstr "" - -msgid "Play file" -msgstr "¿àÞØÓàÐâì äÐÙÛ" - -msgid "Button$Queue" -msgstr "" - -msgid "Media" -msgstr "" - -msgid "Play file >>" -msgstr "¿àÞØÓàÐâì äÐÙÛ >>" - -msgid "Play music >>" -msgstr "¿àÞØÓàÐâì äÐÙÛ >>" - -msgid "View images >>" -msgstr "¿àÞáÜÞâàÕâì Ø×ÞÑàÐÖÕÝØï >>" - -msgid "Play remote DVD >>" -msgstr "" - -msgid "Play DVD disc >>" -msgstr "" - -msgid "Play remote CD >>" -msgstr "" - -msgid "Play audio CD >>" -msgstr "" - -msgid "Video settings" -msgstr "" - -msgid "Play only audio" -msgstr "" - -msgid "Crop letterbox 4:3 to 16:9" -msgstr "" - -msgid "Overscan (crop image borders)" -msgstr "" - -msgid "Interlaced Field Order" -msgstr "ÇÕàÕ×áâàÞçÝëÙ ßÞàïÔÞÚ ßÞÛÕÙ" - -msgid "Audio settings" -msgstr "" - -msgid "Headphone audio mode" -msgstr "" - -msgid "Audio Compression" -msgstr "°ãÔØÞ ÚÞÜßàÕááØï" - -msgid "Audio equalizer >>" -msgstr "°ãÔØÞ íÚÒÐÛÐÙ×Õà >>" - -msgid "Local Frontend" -msgstr "»ÞÚÐÛìÝëÙ äàÞÝâÕÝÔ" - -msgid "Aspect ratio" -msgstr "" - -msgid "Video aspect ratio" -msgstr "" - -msgid "On" -msgstr "" - -msgid "Deinterlacing" -msgstr "´ÕØÝâÕàÛÕÙáØÝÓ" - -msgid "Upmix stereo to 5.1" -msgstr "¿àÕÞÑàÐ×ÞÒÐâì áâÕàÕÞ Ò 5.1" - -msgid "Downmix AC3 to surround" -msgstr "" - -msgid "Default playlist not found" -msgstr "" - -msgid "Default playlist is not symlink" -msgstr "" - -msgid "Default playlist not defined" -msgstr "" - -msgid "Delay" -msgstr "·ÐÔÕàÖÚÐ" - -msgid "ms" -msgstr "ms" - -#, c-format -msgid "xineliboutput: hotkey %s not binded" -msgstr "" - -msgid "Audio" -msgstr "°ãÔØÞ" - -msgid "Speakers" -msgstr "" - -msgid "Volume control" -msgstr "" - -msgid "Mix to headphones" -msgstr "" - -msgid "Visualization" -msgstr "²Ø×ãÐÛØ×ÐæØï" - -msgid " Width" -msgstr "" - -msgid "px" -msgstr "ߨÚáÕÛÕÙ" - -msgid " Height" -msgstr "" - -msgid " Speed" -msgstr "" - -msgid "fps" -msgstr "" - -msgid "Audio Equalizer" -msgstr "°ãÔØÞ íÚÒÐÛÐÙ×Õà" - -msgid "Use Video-Out Driver" -msgstr "" - -msgid "vector" -msgstr "" - -msgid "full" -msgstr "" - -msgid "half (top)" -msgstr "" - -msgid "half (bottom)" -msgstr "" - -msgid "Video" -msgstr "²ØÔÕÞ" - -msgid " Autodetect letterbox" -msgstr "" - -msgid " Soft start" -msgstr "" - -msgid " Crop to" -msgstr "" - -msgid " Detect subtitles" -msgstr "" - -msgid "Software scaling" -msgstr "" - -msgid " Change aspect ratio" -msgstr "" - -msgid " Change video size" -msgstr "" - -msgid " Allow downscaling" -msgstr " ¼ÐáèâÐÑØàÞÒÐâì á ßÐÔÕÝØÕÜ ÚÐçÕáâÒÐ" - -msgid "Post processing (ffmpeg)" -msgstr "" - -msgid " Quality" -msgstr "" - -msgid " Mode" -msgstr "" - -msgid " Method" -msgstr "" - -msgid " Cheap mode" -msgstr "" - -msgid " Pulldown" -msgstr "" - -msgid " Frame rate" -msgstr "" - -msgid " Judder Correction" -msgstr "" - -msgid " Use progressive frame flag" -msgstr "" - -msgid " Chroma Filter" -msgstr "" - -msgid "Sharpen / Blur" -msgstr "" - -msgid " Width of the luma matrix" -msgstr "" - -msgid " Height of the luma matrix" -msgstr "" - -msgid " Amount of luma sharpness/blur" -msgstr "" - -msgid " Width of the chroma matrix" -msgstr "" - -msgid " Height of the chroma matrix" -msgstr "" - -msgid " Amount of chroma sharpness/blur" -msgstr "" - -msgid "3D Denoiser" -msgstr "" - -msgid " Spatial luma strength" -msgstr "" - -msgid " Spatial chroma strength" -msgstr "" - -msgid " Temporal strength" -msgstr "" - -msgid "HUE" -msgstr "HUE" - -msgid "Saturation" -msgstr "½ÐáëéÕÝÝÞáâì" - -msgid "Contrast" -msgstr "ºÞÝâàÐáâÝÞáâì" - -msgid "Brightness" -msgstr "ÏàÚÞáâì" - -msgid "Sharpness" -msgstr "" - -msgid "Noise Reduction" -msgstr "" - -msgid "Smooth fast forward" -msgstr "" - -msgid "Fastest trick speed" -msgstr "" - -msgid "On-Screen Display" -msgstr "ÍÚàÐÝÝÞÕ ÜÕÝî" - -msgid "Hide main menu" -msgstr "ÁÚàëâì ÞáÝÞÒÝÞÕ ÜÕÝî" - -msgid "Blending method" -msgstr "" - -msgid " Use hardware for low-res video" -msgstr "" - -msgid "Scaling method" -msgstr "" - -msgid "Show all layers" -msgstr "" - -msgid "Dynamic transparency correction" -msgstr "´ØÝÐÜØçÕáÚÐï ÚÞààÕÚæØï ßàÞ×àÐçÝÞáâØ" - -msgid "Static transparency correction" -msgstr "ÁâÐâØçÕáÚÐï ÚÞààÕÚæØï ßàÞ×àÐçÝÞáâØ" - -msgid "External subtitle size" -msgstr "" - -msgid "DVB subtitle decoder" -msgstr "" - -msgid "Decoder" -msgstr "´ÕÚÞÔÕà" - -msgid "Buffer size" -msgstr "ÀÐ×ÜÕà ÑãäÕàÐ" - -msgid " Number of PES packets" -msgstr " PES ßÐÚÕâÞÒ" - -msgid "Local Display Frontend" -msgstr "ÄàÞÝâÕÝÔ ÛÞÚÐÛìÝÞÓÞ íÚàÐÝÐ" - -msgid "Use keyboard" -msgstr "¸áßÞÛì×ÞÒÐâì ÚÛÐÒØÐâãàã" - -msgid "Driver" -msgstr "´àÐÙÒÕà" - -msgid "Display address" -msgstr "°ÔàÕá ÔØáßÛÕï" - -msgid "Framebuffer device" -msgstr "Framebuffer ãáâàÞÙáâÒÞ" - -msgid "Fullscreen mode" -msgstr "¿ÞÛÝÞíÚàÐÝÝëÙ àÕÖØÜ" - -msgid " Window width" -msgstr " ÈØàØÝÐ ÞÚÝÐ" - -msgid " Window height" -msgstr " ²ëáÞâÐ ÞÚÝÐ" - -msgid "Window aspect" -msgstr "ÁÞÞâÝÞèÕÝØÕ áâÞàÞÝ" - -msgid "Scale to window size" -msgstr "¼ÐáèâÐÑØàÞÒÐâì Ò àÐ×ÜÕà ÞÚÝÐ" - -msgid "Port" -msgstr "¿Þàâ" - -msgid "Remote Clients" -msgstr "ÃÔÐÛÕÝÝëÕ ÚÛØÕÝâë" - -msgid "Allow remote clients" -msgstr "ÀÐ×àÕèØâì ãÔÐÛÕÝÝëå ÚÛØÕÝâÞÒ" - -msgid " Listen port (TCP and broadcast)" -msgstr " ¿Þàâ (TCP Ø èØàÞÚÞÒÕèÐâÕÛìÝëÙ)" - -msgid " Listen address" -msgstr "" - -msgid " Remote keyboard" -msgstr " ÃÔÐÛÕÝÝÐï ÚÛÐÒØÐâãàÐ" - -msgid " Max number of clients" -msgstr "" - -msgid " PIPE transport" -msgstr " PIPE âàÐÝáßÞàâ" - -msgid " TCP transport" -msgstr "TCP âàÐÝáßÞàâ" - -msgid " UDP transport" -msgstr "UDP âàÐÝáßÞàâ" - -msgid " RTP (multicast) transport" -msgstr " RTP (èØàÞÚÞÒÕéÐâÕÛìÝëÙ) âàÐÝáßÞàâ" - -msgid " Address" -msgstr "" - -msgid " Port" -msgstr "" - -msgid " TTL" -msgstr "" - -msgid " Transmit always on" -msgstr "" - -msgid " SAP announcements" -msgstr "" - -msgid " Server announce broadcasts" -msgstr " ÁÕàÒÕà ØáßÞÛì×ãÕâ èØàÞÚÞÒÕéÐÝØÕ" - -msgid " HTTP transport for media files" -msgstr "" - -msgid "Additional network services" -msgstr "" - -msgid "HTTP server" -msgstr "" - -msgid "HTTP clients can control VDR" -msgstr "" - -msgid "RTSP server" -msgstr "" - -msgid "RTSP clients can control VDR" -msgstr "" - -msgid "Playlist settings" -msgstr "" - -msgid "Show the track number" -msgstr "" - -msgid "Show the name of the artist" -msgstr "" - -msgid "Show the name of the album" -msgstr "" - -msgid "Scan for metainfo" -msgstr "" - -msgid "Cache metainfo" -msgstr "" - -msgid "Arrow keys control DVD playback" -msgstr "" - -msgid "Grayscale" -msgstr "¾ââÕÝÚØ áÕàÞÓÞ" - -msgid "Bitmap" -msgstr "±ØâÞÒÐï ÚÐàâÐ" - -msgid "OSD" -msgstr "" - -msgid "Media Player" -msgstr "Xine-lib" - -msgid "Test Images" -msgstr "ÂÕáâÞÒëÕ Ø×ÞÑàÐÖÕÝØï" - -msgid "X11/xine-lib output plugin" -msgstr "X11/xine-lib ÒØÔÕÞ ÜÞÔãÛì" diff --git a/setup_menu.c b/setup_menu.c deleted file mode 100644 index 0cd91bf8..00000000 --- a/setup_menu.c +++ /dev/null @@ -1,1983 +0,0 @@ -/* - * setup_menu.c: Setup Menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: setup_menu.c,v 1.70 2009-05-29 15:09:10 phintuka Exp $ - * - */ - -#include "features.h" - -#include <vdr/config.h> -#include <vdr/plugin.h> -#include <vdr/remote.h> -#include <vdr/i18n.h> - -#include "config.h" -#include "device.h" -#include "menuitems.h" -#include "osd.h" // cXinelibOsdProvider::RefreshOsd() -#include "setup_menu.h" - - -namespace XinelibOutputSetupMenu { - -//#define INTEGER_CONFIG_VIDEO_CONTROLS -//#define LINEAR_VIDEO_CONTROLS -//#define LOGARITHM_SCALING - -#define ISNUMBERKEY(k) (RAWKEY(k) >= k0 && RAWKEY(k) <= k9) - -//--- Setup Menu ------------------------------------------------------------- - -const char *ModeLineChars = - " 0123456789+-hvsync."; -const char *DriverNameChars = - " abcdefghijklmnopqrstuvwxyz0123456789-.,#~:;"; -const char *OptionsChars = - "=.,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; -const char *LangNameChars = - "abcdefghijklmnopqrstuvwxyz"; - -const char *controls[] = - { "Off", - "[|---------------]","[|---------------]", - "[-|--------------]","[-|--------------]", - "[--|-------------]","[--|-------------]", - "[---|------------]","[---|------------]", - "[----|-----------]","[----|-----------]", - "[-----|----------]","[-----|----------]", - "[------|---------]","[------|---------]", - "[-------|--------]","[-------|--------]", - "[--------|-------]","[--------|-------]", - "[---------|------]","[---------|------]", - "[----------|-----]","[----------|-----]", - "[-----------|----]","[-----------|----]", - "[------------|---]","[------------|---]", - "[-------------|--]","[-------------|--]", - "[--------------|-]","[--------------|-]", - "[---------------|]","[---------------|]", - NULL - }; - -#ifdef LINEAR_VIDEO_CONTROLS -# define CONTROL_TO_INDEX(val) ((val)>=0 ? ((val)>>11)+1 : 0) -# define INDEX_TO_CONTROL(ind) ((ind)==0 ? -1 : ((ind)-1)<<11) -#else -#ifdef LOGARITHM_SCALING -const int ind2ctrl_tbl[33] = { - -1, 0, 0x0001, 0x0002, 0x0003, 0x0004, 0x0007, 0x000a, - 0x000f, 0x0014, 0x001f, 42, 0x003f, 80, 0x007f, 170, - 0x00ff, 336, 0x01ff, 682, 0x03ff, 1630, 0x07ff, 2730, - 0x0fff, 5726, 0x1fff, 10858, 0x3fff, 22110, 0x7fff, 43224, - 0xffff }; -#else -const int ind2ctrl_tbl[33] = { - -1, - 0x0000, 0x0843, 0x1085, 0x18c7, 0x2109, 0x294b, 0x318d, 0x39cf, - 0x4211, 0x4a53, 0x5295, 0x5ad7, 0x6319, 0x6b5b, 0x739d, 0x7bdf, - 0x8421, 0x8c63, 0x94a5, 0x9ce7, 0xa529, 0xad6b, 0xb5ad, 0xbdef, - 0xc631, 0xce73, 0xd6b5, 0xdef7, 0xe739, 0xef7b, 0xf7bd, 0xffff -}; -#endif -static int CONTROL_TO_INDEX(int val) -{ - for(int i=0; i<33;i++) - if(val<=ind2ctrl_tbl[i]) - return i; - return 32; -} -static int INDEX_TO_CONTROL(int ind) -{ - if(ind<0) ind=0; - if(ind>32) ind=32; - return ind2ctrl_tbl[ind]; -} -#endif - -static cOsdItem *NewTitle(const char *s) -{ - char str[128]; - cOsdItem *tmp; - snprintf(str, sizeof(str), "----- %s -----", s); - str[sizeof(str)-1] = 0; - tmp = new cOsdItem(str); - tmp->SetSelectable(false); - return tmp; -} - -//--- cMenuSetupAudio -------------------------------------------------------- - -class cMenuSetupAudio : public cMenuSetupPage -{ - private: - config_t newconfig; - int visualization; - int goom_width, goom_height, goom_fps; - - cOsdItem *audio_ctrl_speakers; - cOsdItem *audio_ctrl_volume; - cOsdItem *audio_ctrl_delay; - cOsdItem *audio_ctrl_compression; - cOsdItem *audio_ctrl_upmix; - cOsdItem *audio_ctrl_surround; - cOsdItem *audio_ctrl_headphone; - cOsdItem *audio_ctrl_vis; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupAudio(void); - ~cMenuSetupAudio(void); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupAudio::cMenuSetupAudio(void) -{ - memcpy(&newconfig, &xc, sizeof(config_t)); - - visualization = strstra(xc.audio_visualization, - xc.s_audioVisualizations, - 0); - goom_width = 720; - goom_height = 576; - goom_fps = 25; - - char *pt; - if(NULL != (pt=strstr(xc.audio_vis_goom_opts, "width="))) - goom_width = max(320, min(1920, atoi(pt+6))); - if(NULL != (pt=strstr(xc.audio_vis_goom_opts, "height="))) - goom_height = max(240, min(1280, atoi(pt+7))); - if(NULL != (pt=strstr(xc.audio_vis_goom_opts, "fps="))) - goom_fps = max(1, min(100, atoi(pt+4))); - - Set(); -} - -cMenuSetupAudio::~cMenuSetupAudio(void) -{ - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, xc.audio_delay, xc.audio_compression, - xc.audio_equalizer, xc.audio_surround, xc.speaker_type); - cXinelibDevice::Instance().ConfigurePostprocessing( - "upmix", xc.audio_upmix ? true : false, NULL); -#ifdef ENABLE_TEST_POSTPLUGINS - cXinelibDevice::Instance().ConfigurePostprocessing( - "headphone", xc.headphone ? true : false, NULL); -#endif -} - -void cMenuSetupAudio::Set(void) -{ - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - int current = Current(); - Clear(); - - Add(NewTitle(tr("Audio"))); - - Add(audio_ctrl_speakers = - new cMenuEditStraI18nItem(tr("Speakers"), &newconfig.speaker_type, - SPEAKERS_count, xc.s_speakerArrangements)); - - Add(audio_ctrl_volume = - new cMenuEditBoolItem(tr("Volume control"), - &newconfig.sw_volume_control, - tr("Hardware"), tr("Software"))); - - Add(audio_ctrl_delay = - new cMenuEditTypedIntItem(tr("Delay"), tr("ms"), &newconfig.audio_delay, - -3000, 3000, tr("Off"))); - Add(audio_ctrl_compression = - new cMenuEditTypedIntItem(tr("Audio Compression"), "%", - &newconfig.audio_compression, - 100, 500, NULL, tr("Off"))); - Add(audio_ctrl_upmix = - new cMenuEditBoolItem(tr("Upmix stereo to 5.1"), - &newconfig.audio_upmix)); - Add(audio_ctrl_surround = - new cMenuEditBoolItem(tr("Downmix AC3 to surround"), - &newconfig.audio_surround)); -#ifdef ENABLE_TEST_POSTPLUGINS - Add(audio_ctrl_headphone = - new cMenuEditBoolItem(tr("Mix to headphones"), - &newconfig.headphone)); -#else - audio_ctrl_headphone = NULL; -#endif - Add(audio_ctrl_vis = - new cMenuEditStraI18nItem(tr("Visualization"), &visualization, - AUDIO_VIS_count, - xc.s_audioVisualizationNames)); - if(visualization == AUDIO_VIS_GOOM) { - Add(new cMenuEditTypedIntItem(tr(" Width"), tr("px"), &goom_width, - 320, 1920)); - Add(new cMenuEditTypedIntItem(tr(" Height"),tr("px"), &goom_height, - 240, 1280)); - Add(new cMenuEditTypedIntItem(tr(" Speed"), tr("fps"), &goom_fps, - 1, 100)); - } - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - Display(); -} - -eOSState cMenuSetupAudio::ProcessKey(eKeys Key) -{ - cOsdItem *item = Get(Current()); - - eOSState state = cMenuSetupPage::ProcessKey(Key); - - Key = NORMALKEY(Key); - - if(Key!=kLeft && Key!=kRight) - return state; - - if(item == audio_ctrl_delay || item == audio_ctrl_compression) { - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, newconfig.audio_delay, - newconfig.audio_compression, newconfig.audio_equalizer, - newconfig.audio_surround, newconfig.speaker_type); - } - else if(item == audio_ctrl_vis) { - Set(); - } - else if(item == audio_ctrl_speakers) { - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, newconfig.audio_delay, - newconfig.audio_compression, newconfig.audio_equalizer, - newconfig.audio_surround, newconfig.speaker_type); - if(newconfig.speaker_type <= SPEAKERS_STEREO && - newconfig.audio_upmix) { - newconfig.audio_upmix = false; - Set(); - } - } - else if(item == audio_ctrl_surround) { - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, newconfig.audio_delay, - newconfig.audio_compression, newconfig.audio_equalizer, - newconfig.audio_surround, newconfig.speaker_type); - if(newconfig.audio_surround && newconfig.audio_upmix) { - newconfig.audio_upmix = 0; - Set(); - } - } - else if(item == audio_ctrl_volume) { - // trigger volume control message by toggling mute - cRemote::Put(kMute); - cRemote::Put(kMute); - } - else if(item == audio_ctrl_upmix) { - cXinelibDevice::Instance().ConfigurePostprocessing( - "upmix", newconfig.audio_upmix ? true : false, NULL); - if(newconfig.audio_upmix && newconfig.audio_surround) { - newconfig.audio_surround = 0; - Set(); - } - } -#ifdef ENABLE_TEST_POSTPLUGINS - else if(item == audio_ctrl_headphone) { - cXinelibDevice::Instance().ConfigurePostprocessing( - "headphone", newconfig.headphone ? true : false, NULL); - } -#endif - - return state; -} - - -void cMenuSetupAudio::Store(void) -{ - memcpy(&xc, &newconfig, sizeof(config_t)); - - strn0cpy(xc.audio_visualization, xc.s_audioVisualizations[visualization], - sizeof(xc.audio_visualization)); - snprintf(xc.audio_vis_goom_opts, sizeof(xc.audio_vis_goom_opts), - "width=%d,height=%d,fps=%d", - goom_width, goom_height, goom_fps); - xc.audio_vis_goom_opts[sizeof(xc.audio_vis_goom_opts)-1] = 0; - - SetupStore("Audio.Speakers", xc.s_speakerArrangements[xc.speaker_type]); - SetupStore("Audio.Delay", xc.audio_delay); - SetupStore("Audio.Compression", xc.audio_compression); - SetupStore("Audio.Surround", xc.audio_surround); - SetupStore("Audio.Upmix", xc.audio_upmix); - SetupStore("Audio.Headphone", xc.headphone); - SetupStore("Audio.Visualization",xc.audio_visualization); - SetupStore("Audio.Visualization.GoomOpts",xc.audio_vis_goom_opts); - SetupStore("Audio.SoftwareVolumeControl", xc.sw_volume_control); - Setup.Save(); -} - -//--- cMenuSetupAudioEq ------------------------------------------------------ - -class cMenuSetupAudioEq : public cMenuSetupPage -{ - private: - config_t newconfig; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupAudioEq(void); - ~cMenuSetupAudioEq(void); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupAudioEq::cMenuSetupAudioEq(void) -{ - memcpy(&newconfig, &xc, sizeof(config_t)); - Set(); -} - -cMenuSetupAudioEq::~cMenuSetupAudioEq(void) -{ - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, xc.audio_delay, xc.audio_compression, - xc.audio_equalizer, xc.audio_surround, xc.speaker_type); -} - -void cMenuSetupAudioEq::Set(void) -{ - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - int current = Current(); - Clear(); - - Add(NewTitle(tr("Audio Equalizer"))); - for(int i=0; i<AUDIO_EQ_count; i++) - Add(new cMenuEditTypedIntItem(config_t::s_audioEqNames[i], "%", - &newconfig.audio_equalizer[i], - -100, 100, tr("Off"))); - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - Display(); -} - -eOSState cMenuSetupAudioEq::ProcessKey(eKeys Key) -{ - eOSState state = cMenuSetupPage::ProcessKey(Key); - - Key = NORMALKEY(Key); - - if(Key == kLeft || Key == kRight) { - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, xc.audio_delay, xc.audio_compression, - newconfig.audio_equalizer, xc.audio_surround, xc.speaker_type); - } - - return state; -} - -void cMenuSetupAudioEq::Store(void) -{ - memcpy(&xc, &newconfig, sizeof(config_t)); - - char tmp[256]; - sprintf(tmp,"%d %d %d %d %d %d %d %d %d %d", - xc.audio_equalizer[0], xc.audio_equalizer[1], - xc.audio_equalizer[2], xc.audio_equalizer[3], - xc.audio_equalizer[4], xc.audio_equalizer[5], - xc.audio_equalizer[6], xc.audio_equalizer[7], - xc.audio_equalizer[8], xc.audio_equalizer[9]); - SetupStore("Audio.Equalizer", tmp); - Setup.Save(); -} - -//--- cMenuSetupVideo -------------------------------------------------------- - -static const char * const tvtime_method[] = - { "use_vo_driver", - "Linear", - "LinearBlend", - "Greedy", - "Greedy2Frame", - "Weave", - "LineDoubler", - "Vertical", - "ScalerBob", - "GreedyH", - "TomsMoComp", - NULL}; - -static const int tvtime_methods_count = (sizeof(tvtime_method)/sizeof(tvtime_method[0]) - 1); - -static const char * const tvtime_method_name[] = - {trNOOP("Use Video-Out Driver"), // "use_vo_driver" - "Linear Interpolation", // "Linear", - "Linear Blend (mplayer)", // "LinearBlend", - "Greedy - Low motion (DScaler)", // "Greedy", - "Greedy 2-frame (DScaler)", // "Greedy2Frame", - "Weave Last Field", // "Weave", - "Line Doubler", // "LineDoubler", - "Vertical Blend (ffmpeg)", // "Vertical", - "Scaler Bob", // "ScalerBob", - "Greedy - High Motion (DScaler)", // "GreedyH", - "Tom's Motion Compensated (DScaler)", // "TomsMoComp", - NULL}; - -static const char * const tvtime_pulldown[] = - { "none", - "vector", - NULL}; - -static const char * const tvtime_pulldown_name[] = - { trNOOP("none"), - trNOOP("vector"), - NULL}; - -static const char * const tvtime_framerate[] = - { "full", - "half_top", - "half_bottom", - NULL}; - -static const char * const tvtime_framerate_name[] = - { trNOOP("full"), - trNOOP("half (top)"), - trNOOP("half (bottom)"), - NULL}; - -struct tvtime_s { - int method; - int cheap_mode; // on/off - int pulldown; // none, vector - int framerate; // full, half_top, half_bottom - int judder_correction; // on/off - int use_progressive_frame_flag; // on/off - int chroma_filter; // on/off - - void Parse(const char *str) - { - cheap_mode = strstr(str, "cheap_mode=1") ? 1 : 0; - pulldown = strstr(str, "pulldown=none") ? 0 : - strstr(str, "pulldown=0") ? 0 : 1; - framerate = strstr(str, "framerate_mode=half_top") ? 1 : - strstr(str, "framerate_mode=1") ? 1 : - strstr(str, "framerate_mode=half_bottom") ? 2 : - strstr(str, "framerate_mode=2") ? 2 : 0; - chroma_filter = strstr(str, "chroma_filter=1") ? 1 : 0; - judder_correction = strstr(str, "judder_correction=0") ? 0 : 1; - use_progressive_frame_flag = strstr(str, "use_progressive_frame_flag=0") ? 0 : 1; - method=1; - const char *m = strstr(str, "method="); - if(m) { - char *tmp = strdup(m + 7); - if(strchr(tmp, ',')) - *strchr(tmp, ',') = 0; - method = strstra(tmp, tvtime_method, 1); - free(tmp); - } - } - - const char *ToString(void) - { - static char buf[256]; - snprintf(buf, sizeof(buf), - "method=%s,cheap_mode=%d,pulldown=%s,framerate_mode=%s," - "judder_correction=%d,use_progressive_frame_flag=%d," - "chroma_filter=%d,enabled=1", - tvtime_method[method], cheap_mode, tvtime_pulldown[pulldown], - tvtime_framerate[framerate], judder_correction, - use_progressive_frame_flag, chroma_filter); - buf[sizeof(buf)-1] = 0; - return buf; - } -}; - -class cMenuSetupVideo : public cMenuSetupPage -{ - private: - config_t newconfig; - - cOsdItem *ctrl_autocrop; - cOsdItem *ctrl_swscale; - cOsdItem *ctrl_swscale_resize; - cOsdItem *ctrl_swscale_aspect; - cOsdItem *ctrl_swscale_width; - cOsdItem *ctrl_swscale_height; - cOsdItem *ctrl_hue; - cOsdItem *ctrl_saturation; - cOsdItem *ctrl_contrast; - cOsdItem *ctrl_brightness; - cOsdItem *ctrl_sharpness; - cOsdItem *ctrl_noise_reduction; - cOsdItem *ctrl_overscan; - cOsdItem *ctrl_pp; - cOsdItem *ctrl_deinterlace; - cOsdItem *ctrl_tvtime_method; - cOsdItem *ctrl_unsharp; - cOsdItem *ctrl_denoise3d; - cOsdItem *ctrl_vo_aspect_ratio; - - int deinterlace; - struct tvtime_s tvtime; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupVideo(void); - ~cMenuSetupVideo(void); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupVideo::cMenuSetupVideo(void) -{ - memcpy(&newconfig, &xc, sizeof(config_t)); - - newconfig.hue = CONTROL_TO_INDEX(newconfig.hue); - newconfig.saturation = CONTROL_TO_INDEX(newconfig.saturation); - newconfig.contrast = CONTROL_TO_INDEX(newconfig.contrast); - newconfig.brightness = CONTROL_TO_INDEX(newconfig.brightness); - newconfig.sharpness = CONTROL_TO_INDEX(newconfig.sharpness); - newconfig.noise_reduction = CONTROL_TO_INDEX(newconfig.noise_reduction); - - deinterlace = strstra(xc.deinterlace_method, xc.s_deinterlaceMethods, 0); - - tvtime.Parse(newconfig.deinterlace_opts); - - Set(); -} - -cMenuSetupVideo::~cMenuSetupVideo(void) -{ - cXinelibDevice::Instance().ConfigureVideo(xc.hue, xc.saturation, - xc.brightness, xc.sharpness, - xc.noise_reduction, xc.contrast, - xc.overscan, xc.vo_aspect_ratio); - cXinelibDevice::Instance().ConfigurePostprocessing( - "autocrop", xc.autocrop ? true : false, xc.AutocropOptions()); - cXinelibDevice::Instance().ConfigurePostprocessing( - "swscale", xc.swscale ? true : false, xc.SwScaleOptions()); - cXinelibDevice::Instance().ConfigurePostprocessing( - "pp", xc.ffmpeg_pp ? true : false, xc.FfmpegPpOptions()); - cXinelibDevice::Instance().ConfigurePostprocessing( - "unsharp", xc.unsharp ? true : false, xc.UnsharpOptions()); - cXinelibDevice::Instance().ConfigurePostprocessing( - "denoise3d", xc.denoise3d ? true : false, xc.Denoise3dOptions()); - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, xc.audio_delay, xc.audio_compression, - xc.audio_equalizer, xc.audio_surround, xc.speaker_type); -} - -void cMenuSetupVideo::Set(void) -{ - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - int current = Current(); - Clear(); - - Add(NewTitle(tr("Video"))); - - Add(ctrl_vo_aspect_ratio = - new cMenuEditStraI18nItem(tr("Aspect ratio"), &newconfig.vo_aspect_ratio, - VO_ASPECT_count, xc.s_vo_aspects)); - - Add(ctrl_autocrop = - new cMenuEditBoolItem(tr("Crop letterbox 4:3 to 16:9"), - &newconfig.autocrop)); - if(newconfig.autocrop) { - Add(new cMenuEditBoolItem(tr(" Autodetect letterbox"), - &newconfig.autocrop_autodetect)); - Add(new cMenuEditBoolItem(tr(" Soft start"), - &newconfig.autocrop_soft)); - Add(new cMenuEditBoolItem(tr(" Crop to"), - &newconfig.autocrop_fixedsize, - "4:3...20:9", "14:9/16:9")); - Add(new cMenuEditBoolItem(tr(" Detect subtitles"), - &newconfig.autocrop_subs)); - } - - ctrl_swscale_resize = ctrl_swscale_aspect = ctrl_swscale_width = ctrl_swscale_height = NULL; - Add(ctrl_swscale = - new cMenuEditBoolItem(tr("Software scaling"), - &newconfig.swscale)); - if(newconfig.swscale) { - Add(ctrl_swscale_aspect = - new cMenuEditBoolItem(tr(" Change aspect ratio"), - &newconfig.swscale_change_aspect)); - Add(ctrl_swscale_resize = - new cMenuEditBoolItem(tr(" Change video size"), - &newconfig.swscale_resize)); - if(newconfig.swscale_resize) { - Add(ctrl_swscale_width = - new cMenuEditIntItem( tr(" Width"), - &newconfig.swscale_width, 360, 2000)); - Add(ctrl_swscale_height = - new cMenuEditIntItem( tr(" Height"), - &newconfig.swscale_height, 288, 1200)); - Add(new cMenuEditBoolItem(tr(" Allow downscaling"), - &newconfig.swscale_downscale)); - } - } - - Add(ctrl_overscan = - new cMenuEditTypedIntItem(tr("Overscan (crop image borders)"), "%", - &newconfig.overscan, 0, 10, - tr("Off"))); - - Add(ctrl_pp = new cMenuEditBoolItem(tr("Post processing (ffmpeg)"), - &newconfig.ffmpeg_pp)); - if(newconfig.ffmpeg_pp) { - Add(new cMenuEditIntItem( tr(" Quality"), - &newconfig.ffmpeg_pp_quality, 0, 6)); - Add(new cMenuEditStrItem( tr(" Mode"), newconfig.ffmpeg_pp_mode, - 255, OptionsChars)); - } - - Add(ctrl_deinterlace = - new cMenuEditStraI18nItem(tr("Deinterlacing"), &deinterlace, - DEINTERLACE_count, - xc.s_deinterlaceMethodNames)); - - ctrl_tvtime_method = NULL; - if(deinterlace == DEINTERLACE_TVTIME) { - Add(ctrl_tvtime_method = - new cMenuEditStraI18nItem(tr(" Method"), &tvtime.method, - tvtime_methods_count, tvtime_method_name)); - Add(new cMenuEditBoolItem(tr(" Cheap mode"), &tvtime.cheap_mode)); - Add(new cMenuEditStraI18nItem(tr(" Pulldown"), &tvtime.pulldown, - 2, tvtime_pulldown_name)); - Add(new cMenuEditStraI18nItem(tr(" Frame rate"), &tvtime.framerate, - 3, tvtime_framerate_name)); - Add(new cMenuEditBoolItem(tr(" Judder Correction"), &tvtime.judder_correction)); - Add(new cMenuEditBoolItem(tr(" Use progressive frame flag"), - &tvtime.use_progressive_frame_flag)); - Add(new cMenuEditBoolItem(tr(" Chroma Filter"), - &tvtime.chroma_filter)); - } - - Add(ctrl_unsharp = new cMenuEditBoolItem(tr("Sharpen / Blur"), - &newconfig.unsharp)); - if(newconfig.unsharp) { - Add(new cMenuEditOddIntItem( tr(" Width of the luma matrix"), - &newconfig.unsharp_luma_matrix_width, 3, 11)); - Add(new cMenuEditOddIntItem( tr(" Height of the luma matrix"), - &newconfig.unsharp_luma_matrix_height, 3, 11)); - Add(new cMenuEditFpIntItem( tr(" Amount of luma sharpness/blur"), - &newconfig.unsharp_luma_amount, -20, 20, 1, - tr("Off"))); - Add(new cMenuEditOddIntItem( tr(" Width of the chroma matrix"), - &newconfig.unsharp_chroma_matrix_width, 3, 11)); - Add(new cMenuEditOddIntItem( tr(" Height of the chroma matrix"), - &newconfig.unsharp_chroma_matrix_height, 3, 11)); - Add(new cMenuEditFpIntItem( tr(" Amount of chroma sharpness/blur"), - &newconfig.unsharp_chroma_amount, -20, 20, 1, - tr("Off"))); - } - - Add(ctrl_denoise3d = new cMenuEditBoolItem(tr("3D Denoiser"), - &newconfig.denoise3d)); - if(newconfig.denoise3d) { - Add(new cMenuEditFpIntItem( tr(" Spatial luma strength"), - &newconfig.denoise3d_luma, 0, 100, 1)); - Add(new cMenuEditFpIntItem( tr(" Spatial chroma strength"), - &newconfig.denoise3d_chroma, 0, 100, 1)); - Add(new cMenuEditFpIntItem( tr(" Temporal strength"), - &newconfig.denoise3d_time, 0, 100, 1)); - } - - -#ifdef INTEGER_CONFIG_VIDEO_CONTROLS - Add(new cMenuEditIntItem(tr("HUE"), &newconfig.hue, -1, 0xffff)); - Add(new cMenuEditIntItem(tr("Saturation"), &newconfig.saturation,-1,0xffff)); - Add(new cMenuEditIntItem(tr("Contrast"), &newconfig.contrast, -1, 0xffff)); - Add(new cMenuEditIntItem(tr("Brightness"), &newconfig.brightness,-1,0xffff)); -#ifdef HAVE_VDPAU - Add(new cMenuEditIntItem(tr("Sharpness"), &newconfig.sharpness, -1,0xffff)); - Add(new cMenuEditIntItem(tr("Noise Reduction"), &newconfig.noise_reduction, -1,0xffff)); -#endif -#else - Add(ctrl_hue = new cMenuEditStraItem(tr("HUE"), &newconfig.hue, 33, - controls)); - Add(ctrl_saturation = - new cMenuEditStraItem(tr("Saturation"), &newconfig.saturation, 33, - controls)); - Add(ctrl_contrast = - new cMenuEditStraItem(tr("Contrast"), &newconfig.contrast, 33, - controls)); - Add(ctrl_brightness = - new cMenuEditStraItem(tr("Brightness"), &newconfig.brightness, 33, - controls)); -#ifdef HAVE_VDPAU - Add(ctrl_sharpness = - new cMenuEditStraItem(tr("Sharpness"), &newconfig.sharpness, 33, - controls)); - Add(ctrl_noise_reduction = - new cMenuEditStraItem(tr("Noise Reduction"), &newconfig.noise_reduction, 33, - controls)); -#endif -#endif - -#ifdef DEVICE_SUPPORTS_IBP_TRICKSPEED - Add(new cMenuEditBoolItem(tr("Smooth fast forward"), - &newconfig.ibp_trickspeed)); -#endif - Add(new cMenuEditIntItem(tr("Fastest trick speed"), - &newconfig.max_trickspeed, 1, 12)); - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - //SetCurrent(Get(1)); - Display(); -} - -eOSState cMenuSetupVideo::ProcessKey(eKeys Key) -{ - cOsdItem *item = Get(Current()); - - eOSState state = cMenuSetupPage::ProcessKey(Key); - - Key = NORMALKEY(Key); - - if(Key!=kLeft && Key!=kRight) - return state; - - if(item == ctrl_hue || item == ctrl_saturation || - item == ctrl_sharpness || item == ctrl_noise_reduction || - item == ctrl_contrast || item == ctrl_brightness || - item == ctrl_overscan || item == ctrl_vo_aspect_ratio) -#ifdef INTEGER_CONFIG_VIDEO_CONTROLS - cXinelibDevice::Instance().ConfigureVideo(newconfig.hue, - newconfig.saturation, - newconfig.brightness, - newconfig.sharpness, - newconfig.noise_reduction, - newconfig.contrast, - newconfig.overscan, - newconfig.vo_aspect_ratio); -#else - cXinelibDevice::Instance().ConfigureVideo( - INDEX_TO_CONTROL(newconfig.hue), - INDEX_TO_CONTROL(newconfig.saturation), - INDEX_TO_CONTROL(newconfig.brightness), - INDEX_TO_CONTROL(newconfig.sharpness), - INDEX_TO_CONTROL(newconfig.noise_reduction), - INDEX_TO_CONTROL(newconfig.contrast), - newconfig.overscan, newconfig.vo_aspect_ratio); -#endif - else if(item == ctrl_autocrop) { - cXinelibDevice::Instance().ConfigurePostprocessing( - "autocrop", newconfig.autocrop ? true : false, - newconfig.AutocropOptions()); - Set(); - } - else if(item == ctrl_swscale || - item == ctrl_swscale_resize || - item == ctrl_swscale_aspect || - item == ctrl_swscale_width || - item == ctrl_swscale_height) { - cXinelibDevice::Instance().ConfigurePostprocessing( - "swscale", newconfig.swscale ? true : false, - newconfig.SwScaleOptions()); - Set(); - } - else if(item == ctrl_pp) { - cXinelibDevice::Instance().ConfigurePostprocessing( - "pp", newconfig.ffmpeg_pp ? true : false, - newconfig.FfmpegPpOptions()); - Set(); - } - else if(item == ctrl_unsharp) { - cXinelibDevice::Instance().ConfigurePostprocessing( - "unsharp", newconfig.unsharp ? true : false, - newconfig.UnsharpOptions()); - Set(); - } - else if(item == ctrl_denoise3d) { - cXinelibDevice::Instance().ConfigurePostprocessing( - "denoise3d", newconfig.denoise3d ? true : false, - newconfig.Denoise3dOptions()); - Set(); - } - else if(item == ctrl_deinterlace) { - if(deinterlace == DEINTERLACE_TVTIME && !ctrl_tvtime_method) { - Set(); - } else if(deinterlace != DEINTERLACE_TVTIME && ctrl_tvtime_method) { - Set(); - } - } - - return state; -} - -void cMenuSetupVideo::Store(void) -{ - memcpy(&xc, &newconfig, sizeof(config_t)); - -#ifdef INTEGER_CONFIG_VIDEO_CONTROLS -#else - xc.hue = INDEX_TO_CONTROL(xc.hue); - xc.saturation = INDEX_TO_CONTROL(xc.saturation); - xc.contrast = INDEX_TO_CONTROL(xc.contrast); - xc.brightness = INDEX_TO_CONTROL(xc.brightness); - xc.sharpness = INDEX_TO_CONTROL(xc.sharpness); - xc.noise_reduction = INDEX_TO_CONTROL(xc.noise_reduction); -#endif - - strn0cpy(xc.deinterlace_method, xc.s_deinterlaceMethods[deinterlace], sizeof(xc.deinterlace_method)); - strn0cpy(xc.deinterlace_opts, tvtime.ToString(), sizeof(xc.deinterlace_opts)); - SetupStore("Video.Deinterlace", xc.deinterlace_method); - SetupStore("Video.DeinterlaceOptions", xc.deinterlace_opts); - - SetupStore("Video.AutoCrop", xc.autocrop); - SetupStore("Video.AutoCrop.AutoDetect", xc.autocrop_autodetect); - SetupStore("Video.AutoCrop.SoftStart", xc.autocrop_soft); - SetupStore("Video.AutoCrop.FixedSize", xc.autocrop_fixedsize); - SetupStore("Video.AutoCrop.DetectSubs", xc.autocrop_subs); - SetupStore("Video.SwScale", xc.swscale); - SetupStore("Video.SwScale.Aspect", xc.swscale_change_aspect); - SetupStore("Video.SwScale.Resize", xc.swscale_resize); - SetupStore("Video.SwScale.Width", xc.swscale_width); - SetupStore("Video.SwScale.Height", xc.swscale_height); - SetupStore("Video.SwScale.Downscale", xc.swscale_downscale); - SetupStore("Video.HUE", xc.hue); - SetupStore("Video.Saturation", xc.saturation); - SetupStore("Video.Contrast", xc.contrast); - SetupStore("Video.Brightness", xc.brightness); - SetupStore("Video.Sharpness", xc.sharpness); - SetupStore("Video.NoiseReduction", xc.noise_reduction); - SetupStore("Video.Overscan", xc.overscan); - SetupStore("Video.IBPTrickSpeed", xc.ibp_trickspeed); - SetupStore("Video.MaxTrickSpeed", xc.max_trickspeed); - SetupStore("Video.AspectRatio", xc.vo_aspect_ratio); - SetupStore("Post.pp.Enable", xc.ffmpeg_pp); - SetupStore("Post.pp.Quality", xc.ffmpeg_pp_quality); - SetupStore("Post.pp.Mode", xc.ffmpeg_pp_mode); - SetupStore("Post.unsharp.Enable", xc.unsharp); - SetupStore("Post.unsharp.luma_matrix_width", xc.unsharp_luma_matrix_width); - SetupStore("Post.unsharp.luma_matrix_height", xc.unsharp_luma_matrix_height); - SetupStore("Post.unsharp.luma_amount", xc.unsharp_luma_amount); - SetupStore("Post.unsharp.chroma_matrix_width", xc.unsharp_chroma_matrix_width); - SetupStore("Post.unsharp.chroma_matrix_height", xc.unsharp_chroma_matrix_height); - SetupStore("Post.unsharp.chroma_amount", xc.unsharp_chroma_amount); - SetupStore("Post.denoise3d.Enable", xc.denoise3d); - SetupStore("Post.denoise3d.luma", xc.denoise3d_luma); - SetupStore("Post.denoise3d.chroma", xc.denoise3d_chroma); - SetupStore("Post.denoise3d.time", xc.denoise3d_time); - SetupStore("Video.Decoder.MPEG2", xc.s_decoders_MPEG2[xc.decoder_mpeg2]); - SetupStore("Video.Decoder.H264", xc.s_decoders_H264[xc.decoder_h264]); -#if 1 - // delete old keys (<1.0.0) - SetupStore("Video.AutoScale"); -#endif - Setup.Save(); -} - - -//--- cMenuSetupOSD ---------------------------------------------------------- - -class cMenuSetupOSD : public cMenuSetupPage -{ - private: - config_t newconfig; - - int orig_alpha_correction; - int orig_alpha_correction_abs; - - cOsdItem *ctrl_scaling; - cOsdItem *ctrl_alpha; - cOsdItem *ctrl_alpha_abs; - cOsdItem *ctrl_blending; - cOsdItem *ctrl_lowres; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupOSD(void); - ~cMenuSetupOSD(); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupOSD::cMenuSetupOSD(void) -{ - memcpy(&newconfig, &xc, sizeof(config_t)); - orig_alpha_correction = xc.alpha_correction; - orig_alpha_correction_abs = xc.alpha_correction_abs; - newconfig.extsub_size++; - - Set(); -} - -cMenuSetupOSD::~cMenuSetupOSD() -{ - xc.alpha_correction = orig_alpha_correction; - xc.alpha_correction_abs = orig_alpha_correction_abs; -} - -void cMenuSetupOSD::Set(void) -{ - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - int current = Current(); - Clear(); - - ctrl_scaling = NULL; - ctrl_blending = NULL; - ctrl_lowres = NULL; - ctrl_alpha = NULL; - ctrl_alpha_abs = NULL; - - Add(NewTitle(tr("On-Screen Display"))); - Add(new cMenuEditBoolItem(tr("Hide main menu"), - &newconfig.hide_main_menu)); - - Add(ctrl_blending = - new cMenuEditBoolItem(tr("Blending method"), - &newconfig.osd_blending, - tr(xc.s_osdBlendingMethods[OSD_BLENDING_SOFTWARE]), - tr(xc.s_osdBlendingMethods[OSD_BLENDING_HARDWARE]))); - if(newconfig.osd_blending == OSD_BLENDING_SOFTWARE) { - Add(ctrl_lowres = - new cMenuEditBoolItem(tr(" Use hardware for low-res video"), - &newconfig.osd_blending_lowresvideo)); - } - - Add(ctrl_scaling = - new cMenuEditStraI18nItem(tr("Scaling method"), &newconfig.osd_scaling, - OSD_SCALING_count, xc.s_osdScalings)); - - Add(new cMenuEditStraI18nItem(tr("Show all layers"), &newconfig.osd_mixer, - OSD_MIXER_count, xc.s_osdMixers)); - - Add(ctrl_alpha = - new cMenuEditTypedIntItem(tr("Dynamic transparency correction"), "%", - &newconfig.alpha_correction, -200, 200, - tr("Off"))); - Add(ctrl_alpha_abs = - new cMenuEditTypedIntItem(tr("Static transparency correction"), "", - &newconfig.alpha_correction_abs, -0xff, 0xff, - tr("Off"))); - - Add(new cMenuEditStraI18nItem(tr("External subtitle size"), - &newconfig.extsub_size, SUBTITLESIZE_count, xc.s_subtitleSizes)); - - Add(new cMenuEditBoolItem(tr("DVB subtitle decoder"), - &newconfig.dvb_subtitles, - "VDR", - "frontend")); - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - //SetCurrent(Get(1)); - Display(); -} - -eOSState cMenuSetupOSD::ProcessKey(eKeys Key) -{ - cOsdItem *item = Get(Current()); - - eOSState state = cMenuSetupPage::ProcessKey(Key); - - Key = NORMALKEY(Key); - - if(Key!=kLeft && Key!=kRight) - return state; - - if(item == ctrl_scaling) - cXinelibOsdProvider::RefreshOsd(); - else if(item == ctrl_alpha) - xc.alpha_correction = newconfig.alpha_correction; - else if(item == ctrl_alpha_abs) - xc.alpha_correction_abs = newconfig.alpha_correction_abs; - - if(newconfig.osd_blending==OSD_BLENDING_SOFTWARE && !ctrl_lowres) - Set(); - if(newconfig.osd_blending!=OSD_BLENDING_SOFTWARE && ctrl_lowres) - Set(); - return state; -} - -void cMenuSetupOSD::Store(void) -{ - newconfig.extsub_size --; - if(newconfig.extsub_size != xc.extsub_size) { - cString tmp = cString::sprintf("EXTSUBSIZE %d", newconfig.extsub_size); - cXinelibDevice::Instance().PlayFileCtrl(tmp); - } - - memcpy(&xc, &newconfig, sizeof(config_t)); - orig_alpha_correction = xc.alpha_correction; - orig_alpha_correction_abs = xc.alpha_correction_abs; - - SetupStore("OSD.Scaling", xc.osd_scaling); - SetupStore("OSD.HideMainMenu", xc.hide_main_menu); - SetupStore("OSD.LayersVisible", xc.osd_mixer); - SetupStore("OSD.Blending", xc.osd_blending); - SetupStore("OSD.BlendingLowRes", xc.osd_blending_lowresvideo); -#if 1 - // Delete old keys (<=1.0.0) - SetupStore("OSD.UnscaledAlways"); - SetupStore("OSD.UnscaledLowRes"); - SetupStore("OSD.UnscaledOpaque"); - SetupStore("OSD.Prescale"); - SetupStore("OSD.Downscale"); -#endif - SetupStore("OSD.AlphaCorrection", xc.alpha_correction); - SetupStore("OSD.AlphaCorrectionAbs", xc.alpha_correction_abs); - - SetupStore("OSD.ExtSubSize", xc.extsub_size); - SetupStore("OSD.DvbSubtitles", xc.dvb_subtitles); - - Setup.Save(); -} - - -//--- cMenuSetupDecoder ------------------------------------------------------ - -class cMenuSetupDecoder : public cMenuSetupPage -{ - private: - config_t newconfig; - - int pes_buffers_ind; - - cOsdItem *ctrl_pes_buffers_ind; - cOsdItem *ctrl_pes_buffers; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupDecoder(void); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupDecoder::cMenuSetupDecoder(void) -{ - int i; - memcpy(&newconfig, &xc, sizeof(config_t)); - - pes_buffers_ind = PES_BUFFERS_CUSTOM; - for(i=0;xc.s_bufferSize[i];i++) - if(xc.pes_buffers == xc.i_pesBufferSize[i]) - pes_buffers_ind = i; - - Set(); -} - -void cMenuSetupDecoder::Set(void) -{ - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - int current = Current(); - Clear(); - - Add(NewTitle(tr("Decoder"))); - Add(ctrl_pes_buffers_ind = - new cMenuEditStraI18nItem(tr("Buffer size"), &pes_buffers_ind, - PES_BUFFERS_count, xc.s_bufferSize)); - if(pes_buffers_ind == PES_BUFFERS_CUSTOM) - Add(ctrl_pes_buffers = - new cMenuEditIntItem(tr(" Number of PES packets"), &newconfig.pes_buffers, - 10, 10000)); - else - ctrl_pes_buffers = NULL; - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - Display(); -} - -eOSState cMenuSetupDecoder::ProcessKey(eKeys Key) -{ - cOsdItem *item = Get(Current()); - - eOSState state = cMenuSetupPage::ProcessKey(Key); - - Key = NORMALKEY(Key); - - if(Key!=kLeft && Key!=kRight) - return state; - - if(item == ctrl_pes_buffers_ind) { - if(pes_buffers_ind == PES_BUFFERS_CUSTOM && !ctrl_pes_buffers) { - Set(); - } else if(pes_buffers_ind != PES_BUFFERS_CUSTOM && ctrl_pes_buffers) { - Set(); - } - } - - return state; -} - -void cMenuSetupDecoder::Store(void) -{ - int old_buffers = xc.pes_buffers; - - //memcpy(&xc, &newconfig, sizeof(config_t)); - xc.pes_buffers = newconfig.pes_buffers; - - if(pes_buffers_ind != PES_BUFFERS_CUSTOM) - xc.pes_buffers = xc.i_pesBufferSize[pes_buffers_ind]; - - SetupStore("Decoder.PesBuffers", xc.pes_buffers); -#if 1 - // delete old keys (<1.0.0) - SetupStore("Decoder.Priority"); - SetupStore("Decoder.InactivityTimer"); -#endif - - if(xc.pes_buffers != old_buffers) - cXinelibDevice::Instance().ConfigureDecoder(xc.pes_buffers); - Setup.Save(); -} - - -//--- cMenuSetupLocal -------------------------------------------------------- - -class cMenuSetupLocal : public cMenuSetupPage -{ - private: - config_t newconfig; - - int local_frontend; - int local_frontend_orig; - int audio_driver; - int audio_driver_orig; - int video_driver; - int video_driver_orig; - - cOsdItem *ctrl_scale; - cOsdItem *ctrl_local_fe; - cOsdItem *ctrl_driver; - cOsdItem *ctrl_fullscreen; - cOsdItem *ctrl_window_width; - cOsdItem *ctrl_window_height; - cOsdItem *ctrl_interlace_order; - cOsdItem *ctrl_aspect; - cOsdItem *ctrl_audio_driver; - cOsdItem *ctrl_audio_port; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupLocal(void); - ~cMenuSetupLocal(void); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupLocal::cMenuSetupLocal(void) -{ - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - - memcpy(&newconfig, &xc, sizeof(config_t)); - - local_frontend_orig = local_frontend = strstra(xc.local_frontend, xc.s_frontends, 0); - audio_driver_orig = audio_driver = strstra(xc.audio_driver, xc.s_audioDrivers, 0); - - video_driver = 0; - if(local_frontend == FRONTEND_X11) - video_driver = strstra(xc.video_driver, xc.s_videoDriversX11, 0); - if(local_frontend == FRONTEND_FB) - video_driver = strstra(xc.video_driver, xc.s_videoDriversFB, 0); - video_driver_orig = video_driver; - - Set(); -} - -cMenuSetupLocal::~cMenuSetupLocal(void) -{ - cXinelibDevice::Instance().ConfigureWindow( - xc.fullscreen, xc.width, xc.height, xc.modeswitch, xc.modeline, - xc.display_aspect, xc.scale_video, xc.field_order); - cXinelibDevice::Instance().ConfigurePostprocessing( - xc.deinterlace_method, xc.audio_delay, xc.audio_compression, - xc.audio_equalizer, xc.audio_surround, xc.speaker_type); -} - -void cMenuSetupLocal::Set(void) -{ - int current = Current(); - Clear(); - - ctrl_interlace_order = NULL; - ctrl_fullscreen = NULL; - ctrl_window_width = NULL; - ctrl_window_height = NULL; - ctrl_driver = NULL; - ctrl_aspect = NULL; - ctrl_scale = NULL; - ctrl_audio_driver = NULL; - ctrl_audio_port = NULL; - - Add(NewTitle(tr("Local Frontend"))); - - Add(ctrl_local_fe = - new cMenuEditStraI18nItem(tr("Local Display Frontend"), &local_frontend, - FRONTEND_count, xc.s_frontendNames)); - - if(local_frontend == FRONTEND_X11) { - Add(new cMenuEditBoolItem(tr("Use keyboard"), - &newconfig.use_x_keyboard)); - } - - if(local_frontend != FRONTEND_NONE) { - cString tmp = cString::sprintf("%s >>", tr("Decoder")); - Add(new cOsdItem(tmp, osUser1)); - Add(NewTitle(tr("Video"))); - } - - if(local_frontend == FRONTEND_X11) { - Add(ctrl_driver = - new cMenuEditStraI18nItem(tr("Driver"), &video_driver, - X11_DRIVER_count, - xc.s_videoDriverNamesX11)); - Add(new cMenuEditStrItem(tr("Display address"), newconfig.video_port, - 31, DriverNameChars)); - - } else if(local_frontend == FRONTEND_FB) { - Add(ctrl_driver = - new cMenuEditStraI18nItem(tr("Driver"), &video_driver, - FB_DRIVER_count, - xc.s_videoDriverNamesFB)); - Add(new cMenuEditStrItem(tr("Framebuffer device"), newconfig.video_port, 31, - DriverNameChars)); - } -#if 0 - if(local_frontend == FRONTEND_FB || !newconfig.fullscreen) { - Add(new cMenuEditStrItem( "Modeline", newconfig.modeline, 31, - ModeLineChars)); - Add(new cMenuEditBoolItem("Videomode switching", &xc.modeswitch)); - } -#endif - - if(local_frontend == FRONTEND_X11) { - Add(ctrl_fullscreen = new cMenuEditBoolItem(tr("Fullscreen mode"), - &newconfig.fullscreen)); - if(!newconfig.fullscreen) { - Add(ctrl_window_width = - new cMenuEditTypedIntItem( tr(" Window width"), tr("px"), - &newconfig.width, 1, 2048)); - Add(ctrl_window_height = - new cMenuEditTypedIntItem( tr(" Window height"), tr("px"), - &newconfig.height, 1, 2048)); - } - } - - if(local_frontend != FRONTEND_NONE) { - Add(ctrl_aspect = - new cMenuEditStraI18nItem(tr("Window aspect"), &newconfig.display_aspect, - ASPECT_count, xc.s_aspects)); - Add(ctrl_scale = - new cMenuEditBoolItem(tr("Scale to window size"), &newconfig.scale_video)); - -#ifdef HAVE_XV_FIELD_ORDER - Add(ctrl_interlace_order = - new cMenuEditStraI18nItem(tr("Interlaced Field Order"), - &newconfig.field_order, FIELD_ORDER_count, - xc.s_fieldOrder)); -#endif - - Add(NewTitle(tr("Audio"))); - - Add(ctrl_audio_driver = - new cMenuEditStraI18nItem(tr("Driver"), &audio_driver, - AUDIO_DRIVER_count, xc.s_audioDriverNames)); - if(audio_driver != AUDIO_DRIVER_AUTO && audio_driver != AUDIO_DRIVER_NONE) - Add(ctrl_audio_port = - new cMenuEditStrItem(tr("Port"), newconfig.audio_port, 31, - DriverNameChars)); - } - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - Display(); -} - -eOSState cMenuSetupLocal::ProcessKey(eKeys Key) -{ - int prev_frontend = local_frontend; - int prev_audio_driver = audio_driver; - - cOsdItem *item = Get(Current()); - - eOSState state = cMenuSetupPage::ProcessKey(Key); - - if(state == osUser1) - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupDecoder); - - Key = NORMALKEY(Key); - - if((Key!=kLeft && Key!=kRight) || !item) - return state; - - if(item == ctrl_audio_driver) { - if(prev_audio_driver != audio_driver) { - - if(audio_driver == audio_driver_orig) - strcpy(newconfig.audio_port, xc.audio_port); - else if(audio_driver == AUDIO_DRIVER_ALSA) - strcpy(newconfig.audio_port, "default"); - else if(audio_driver == AUDIO_DRIVER_OSS) - strcpy(newconfig.audio_port, "/dev/dsp"); - else - strcpy(newconfig.audio_port, ""); - Set(); - } - else if((audio_driver != AUDIO_DRIVER_AUTO && - audio_driver != AUDIO_DRIVER_NONE) && - !ctrl_audio_port) - Set(); - else if((audio_driver == AUDIO_DRIVER_AUTO || - audio_driver == AUDIO_DRIVER_NONE) && - ctrl_audio_port) - Set(); - } - else if(item == ctrl_aspect || item == ctrl_scale || item == ctrl_interlace_order) - cXinelibDevice::Instance().ConfigureWindow( - xc.fullscreen, xc.width, xc.height, xc.modeswitch, xc.modeline, - newconfig.display_aspect, newconfig.scale_video, - newconfig.field_order); - else if(item == ctrl_local_fe && local_frontend != prev_frontend) { - - if(local_frontend == local_frontend_orig) { - video_driver = video_driver_orig; - strcpy(newconfig.video_port, xc.video_port); - } - else if(local_frontend == FRONTEND_FB) - strcpy(newconfig.video_port, "/dev/fb/0"); - else if(local_frontend == FRONTEND_X11) - strcpy(newconfig.video_port, "0.0"); - - Set(); - } - else if(item == ctrl_fullscreen) { - if(!newconfig.fullscreen && !ctrl_window_width) { - Set(); - } else if(newconfig.fullscreen && ctrl_window_width) { - Set(); - } - } - - return state; -} - -void cMenuSetupLocal::Store(void) -{ - int old_buffers = xc.pes_buffers; - - memcpy(&xc, &newconfig, sizeof(config_t)); - - xc.pes_buffers = old_buffers; - - strn0cpy(xc.audio_driver, xc.s_audioDrivers[audio_driver], sizeof(xc.audio_driver)); - strn0cpy(xc.local_frontend, xc.s_frontends[local_frontend], sizeof(xc.local_frontend)); - if(local_frontend == FRONTEND_X11) - strn0cpy(xc.video_driver, xc.s_videoDriversX11[video_driver], sizeof(xc.video_driver)); - if(local_frontend == FRONTEND_FB) - strn0cpy(xc.video_driver, xc.s_videoDriversFB[video_driver], sizeof(xc.video_driver)); - - SetupStore("Frontend", xc.local_frontend); - SetupStore("Audio.Driver", xc.audio_driver); - SetupStore("Audio.Port", xc.audio_port); - SetupStore("Video.Driver", xc.video_driver); - SetupStore("Video.Port", xc.video_port); -#if 0 - SetupStore("Video.Port", NULL); /* should delete entry ? */ - SetupStore("Video.Port.X11",xc.video_port_x11); - SetupStore("Video.Port.FB", xc.video_port_fb); -#endif - SetupStore("Video.Scale", xc.scale_video); - SetupStore("Video.FieldOrder", xc.field_order); - SetupStore("Modeline", xc.modeline); - SetupStore("VideoModeSwitching", xc.modeswitch); - SetupStore("Fullscreen", xc.fullscreen); - SetupStore("DisplayAspect", xc.s_aspects[xc.display_aspect]); - SetupStore("X11.WindowWidth", xc.width); - SetupStore("X11.WindowHeight", xc.height); - SetupStore("X11.UseKeyboard", xc.use_x_keyboard); - Setup.Save(); -} - -//--- cMenuSetupRemote ------------------------------------------------------- - -class cMenuSetupRemote : public cMenuSetupPage -{ - private: - config_t newconfig; - - cOsdItem *ctrl_remote_mode; - cOsdItem *ctrl_usertp; - cOsdItem *ctrl_rtp_addr; - cOsdItem *ctrl_use_http; - cOsdItem *ctrl_http_ctrl; - cOsdItem *ctrl_use_rtsp; - cOsdItem *ctrl_rtsp_ctrl; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupRemote(void); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupRemote::cMenuSetupRemote(void) -{ - memcpy(&newconfig, &xc, sizeof(config_t)); - Set(); -} - -void cMenuSetupRemote::Set(void) -{ - int current = Current(); - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - Clear(); - - Add(NewTitle(tr("Remote Clients"))); - Add(ctrl_remote_mode = new cMenuEditBoolItem(tr("Allow remote clients"), - &newconfig.remote_mode)); - ctrl_usertp = NULL; - ctrl_rtp_addr = NULL; - ctrl_use_http = NULL; - ctrl_use_rtsp = NULL; - ctrl_http_ctrl = NULL; - ctrl_rtsp_ctrl = NULL; - if(newconfig.remote_mode) { - Add(new cMenuEditIntItem( tr(" Listen port (TCP and broadcast)"), - &newconfig.listen_port, - 0, 0xffff)); - Add(new cMenuEditStrItem( tr(" Listen address"), - &newconfig.remote_local_ip[0], 16, "0123456789.")); - Add(new cMenuEditBoolItem(tr(" Remote keyboard"), - &newconfig.remote_keyboard)); - Add(new cMenuEditIntItem( tr(" Max number of clients"), - &newconfig.remote_max_clients, - 1, MAXCLIENTS)); - - Add(new cMenuEditBoolItem(tr(" PIPE transport"), - &newconfig.remote_usepipe)); - Add(new cMenuEditBoolItem(tr(" TCP transport"), - &newconfig.remote_usetcp)); - Add(new cMenuEditBoolItem(tr(" UDP transport"), - &newconfig.remote_useudp)); - Add(ctrl_usertp = - new cMenuEditBoolItem(tr(" RTP (multicast) transport"), - &newconfig.remote_usertp)); - if(newconfig.remote_usertp) { - Add(ctrl_rtp_addr = - new cMenuEditStrItem( tr(" Address"), - &newconfig.remote_rtp_addr[0], 16, "0123456789.")); - Add(new cMenuEditOddIntItem( tr(" Port"), - &newconfig.remote_rtp_port, 1000, 0xfffe)); - Add(new cMenuEditIntItem( tr(" TTL"), - &newconfig.remote_rtp_ttl, 1, 10)); - Add(new cMenuEditBoolItem(tr(" Transmit always on"), - &newconfig.remote_rtp_always_on)); - Add(new cMenuEditBoolItem(tr(" SAP announcements"), - &newconfig.remote_rtp_sap)); - } - Add(new cMenuEditBoolItem(tr(" Server announce broadcasts"), - &newconfig.remote_usebcast)); - - Add(new cMenuEditBoolItem(tr(" HTTP transport for media files"), - &newconfig.remote_http_files)); - - Add(NewTitle(tr("Additional network services"))); - Add(ctrl_use_http = - new cMenuEditBoolItem(tr("HTTP server"), - &newconfig.remote_use_http)); - if(newconfig.remote_use_http) - Add(ctrl_http_ctrl = - new cMenuEditBoolItem(tr("HTTP clients can control VDR"), - &newconfig.remote_use_http_ctrl)); - Add(ctrl_use_rtsp = - new cMenuEditBoolItem(tr("RTSP server"), - &newconfig.remote_use_rtsp)); - if(newconfig.remote_use_rtsp) - Add(ctrl_rtsp_ctrl = - new cMenuEditBoolItem(tr("RTSP clients can control VDR"), - &newconfig.remote_use_rtsp_ctrl)); - } - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - Display(); -} - -eOSState cMenuSetupRemote::ProcessKey(eKeys Key) -{ - cOsdItem *item = Get(Current()); - - eOSState state = cMenuSetupPage::ProcessKey(Key); - - Key = NORMALKEY(Key); - - if(Key!=kLeft && Key!=kRight) - return state; - - if(item == ctrl_remote_mode) { - if(newconfig.remote_mode && !ctrl_usertp) { - Set(); - } else if(!newconfig.remote_mode && ctrl_usertp) { - Set(); - } - } - if(item == ctrl_usertp) { - if(newconfig.remote_usertp && !ctrl_rtp_addr) { - Set(); - } else if(!newconfig.remote_usertp && ctrl_rtp_addr) { - Set(); - } - } - if(item == ctrl_use_http) { - if(newconfig.remote_use_http && !ctrl_http_ctrl) { - Set(); - } else if(!newconfig.remote_use_http && ctrl_http_ctrl) { - Set(); - } - } - if(item == ctrl_use_rtsp) { - if(newconfig.remote_use_rtsp && !ctrl_rtsp_ctrl) { - Set(); - } else if(!newconfig.remote_use_rtsp && ctrl_rtsp_ctrl) { - Set(); - } - } - - return state; -} - -void cMenuSetupRemote::Store(void) -{ - memcpy(&xc, &newconfig, sizeof(config_t)); - - SetupStore("RemoteMode", xc.remote_mode); - SetupStore("Remote.ListenPort", xc.listen_port); - SetupStore("Remote.Iface", xc.remote_local_if); - SetupStore("Remote.LocalIP", xc.remote_local_ip); - SetupStore("Remote.Keyboard", xc.remote_keyboard); - - SetupStore("Remote.MaxClients", xc.remote_max_clients); - SetupStore("Remote.UsePipe",xc.remote_usepipe); - SetupStore("Remote.UseTcp", xc.remote_usetcp); - SetupStore("Remote.UseUdp", xc.remote_useudp); - SetupStore("Remote.UseRtp", xc.remote_usertp); - SetupStore("Remote.UseBroadcast", xc.remote_usebcast); - - SetupStore("Remote.UseHttp", xc.remote_http_files); - - SetupStore("Remote.Rtp.Address", xc.remote_rtp_addr); - SetupStore("Remote.Rtp.Port", xc.remote_rtp_port); - SetupStore("Remote.Rtp.TTL", xc.remote_rtp_ttl); - SetupStore("Remote.Rtp.AlwaysOn", xc.remote_rtp_always_on); - SetupStore("Remote.Rtp.SapAnnouncements", xc.remote_rtp_sap); - - SetupStore("Remote.AllowRtsp", xc.remote_use_rtsp); - SetupStore("Remote.AllowRtspCtrl", xc.remote_use_rtsp_ctrl); - SetupStore("Remote.AllowHttp", xc.remote_use_http); - SetupStore("Remote.AllowHttpCtrl", xc.remote_use_http_ctrl); - - cXinelibDevice::Instance().Listen(xc.remote_mode, xc.listen_port); - Setup.Save(); -} - -//--- cMenuSetupMediaPlayer -------------------------------------------------------- - -class cMenuSetupMediaPlayer : public cMenuSetupPage -{ - private: - config_t newconfig; - - cOsdItem *media_ctrl_playlist_tracknumber; - cOsdItem *media_ctrl_playlist_artist; - cOsdItem *media_ctrl_playlist_album; - cOsdItem *media_ctrl_playlist_cache; - cOsdItem *media_ctrl_playlist_id3scanner; - - protected: - virtual void Store(void); - void Set(void); - - public: - cMenuSetupMediaPlayer(void); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuSetupMediaPlayer::cMenuSetupMediaPlayer(void) -{ - memcpy(&newconfig, &xc, sizeof(config_t)); - Set(); -} - -void cMenuSetupMediaPlayer::Set(void) -{ - SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N)); - int current = Current(); - Clear(); - - Add(NewTitle(tr("Playlist settings"))); - - Add(media_ctrl_playlist_tracknumber = - new cMenuEditBoolItem(tr("Show the track number"), - &newconfig.playlist_tracknumber)); - - Add(media_ctrl_playlist_artist = - new cMenuEditBoolItem(tr("Show the name of the artist"), - &newconfig.playlist_artist)); - - Add(media_ctrl_playlist_album = - new cMenuEditBoolItem(tr("Show the name of the album"), - &newconfig.playlist_album)); - - Add(media_ctrl_playlist_id3scanner = - new cMenuEditBoolItem(tr("Scan for metainfo"), - &newconfig.enable_id3_scanner)); - - Add(media_ctrl_playlist_cache = - new cMenuEditBoolItem(tr("Cache metainfo"), - &newconfig.cache_implicit_playlists)); - - Add(new cMenuEditBoolItem(tr("Arrow keys control DVD playback"), - &newconfig.dvd_arrow_keys_control_playback)); - - if(current<1) current=1; /* first item is not selectable */ - SetCurrent(Get(current)); - Display(); -} - -eOSState cMenuSetupMediaPlayer::ProcessKey(eKeys Key) -{ - eOSState state = cMenuSetupPage::ProcessKey(Key); - return state; -} - -void cMenuSetupMediaPlayer::Store(void) -{ - memcpy(&xc, &newconfig, sizeof(config_t)); - - SetupStore("Playlist.Tracknumber", xc.playlist_tracknumber); - SetupStore("Playlist.Album", xc.playlist_album); - SetupStore("Playlist.Artist", xc.playlist_artist); - SetupStore("Media.CacheImplicitPlaylists", xc.cache_implicit_playlists); - SetupStore("Media.EnableID3Scanner", xc.enable_id3_scanner); - SetupStore("Media.DVD.ArrowKeysControlPlayback", xc.dvd_arrow_keys_control_playback); - - Setup.Save(); -} - -} // namespace - - -//--- cMenuTestImages ------------------------------------------------------ - -#include <vdr/osdbase.h> - -#define OSD_W (720-2) -#define OSD_H (576-2) -#define OSD_X (1) -#define OSD_Y (1) - -// -// cTestGrayscale -// - -class cTestGrayscale : public cOsdObject -{ - private: - cOsd *m_Osd; - - public: - cTestGrayscale() { m_Osd = NULL; } - virtual ~cTestGrayscale() { delete m_Osd; } - - virtual void Show(); - virtual eOSState ProcessKey(eKeys Key); -}; - -void cTestGrayscale::Show() -{ - tArea areas [] = { { 0, 0, OSD_W/2 - 1, OSD_H - 1, 8}, - {OSD_W/2, 0, OSD_W - 1, OSD_H - 1, 8}}; - int i; - - if(!m_Osd) - m_Osd = cOsdProvider::NewOsd(OSD_X, OSD_Y, 0); - - if(m_Osd) { - if (m_Osd->CanHandleAreas(areas, sizeof(areas) / sizeof(tArea) ) == oeOk) { - m_Osd->SetAreas(areas, sizeof(areas) / sizeof(tArea)); - m_Osd->Flush(); - - // border - m_Osd->DrawRectangle(0, 0, OSD_W - 1, OSD_H - 1, 0xff000000); - m_Osd->DrawRectangle(1, 1, OSD_W - 2, OSD_H - 2, 0xff000000); - - // background - m_Osd->DrawRectangle(2, 2, 2+103, OSD_H - 3, 0xffffffff); - m_Osd->DrawRectangle(OSD_W-2-103, 2, OSD_W-2, OSD_H - 3, 0xff000000); - - for(i=0; i<0xff; i++) - m_Osd->DrawRectangle(2+103+2*i, 2, 2+103+2*(i+1), OSD_H - 3, - 0xff000000|(i*0x00010101)/*=(i<<16)|(i<<8)|(i)*/); - // line - m_Osd->DrawRectangle(1, OSD_H/2-20, OSD_W - 2, OSD_H/2, 0xffffffff); - m_Osd->DrawRectangle(1, OSD_H/2+1, OSD_W - 2, OSD_H/2+21, 0xff000000); - - // Cross - for(int x=0; x<OSD_W;x++) { - m_Osd->DrawPixel(x, x*OSD_H/OSD_W, 0x00000000); - m_Osd->DrawPixel(x, OSD_H - 1 - x*OSD_H/OSD_W, 0x00000000); - } - - // commit - m_Osd->Flush(); - } - - } -} - -eOSState cTestGrayscale::ProcessKey(eKeys key) -{ - char s[32]; - static int br = xc.brightness; - static int co = xc.contrast; - eOSState state = cOsdObject::ProcessKey(key); - if (state == osUnknown) { - switch (key & ~k_Repeat) { - case kOk: - case kBack: - return osEnd; - case kRight: - br += 0xffff/1024*2; - case kLeft: - br -= 0xffff/1024; - sprintf(s, "b %d", br); - m_Osd->DrawText(400, 100, s, 0xff000000, 0xffffffff, cFont::GetFont(fontSml)); - cXinelibDevice::Instance().ConfigureVideo(xc.hue, xc.saturation, br, xc.sharpness, xc.noise_reduction, co, xc.overscan, xc.vo_aspect_ratio); - m_Osd->Flush(); - return osContinue; - case kUp: - co += 0xffff/1024*2; - case kDown: - co -= 0xffff/1024; - sprintf(s, "c %d", co); - m_Osd->DrawText(400, 130, s, 0xff000000, 0xffffffff, cFont::GetFont(fontSml)); - cXinelibDevice::Instance().ConfigureVideo(xc.hue, xc.saturation, br, xc.sharpness, xc.noise_reduction, co, xc.overscan, xc.vo_aspect_ratio); - m_Osd->Flush(); - return osContinue; - } - } - return state; -} - - -// -// cTestBitmap -// - -class cTestBitmap : public cOsdObject -{ - private: - cOsd *m_Osd; - int bpp; - - public: - cTestBitmap(int _bpp = 1) { - m_Osd = NULL; - if(_bpp<1) _bpp = 1; - if(_bpp>6) _bpp = 6; - bpp = 1<<_bpp; - } - virtual ~cTestBitmap() { delete m_Osd; } - - virtual void Show(); - virtual eOSState ProcessKey(eKeys Key); -}; - -void cTestBitmap::Show() -{ - tArea areas [] = {{ 0, 0, OSD_W - 1, OSD_H - 1, 8}}; - int x, y, bit = 0; - - if(!m_Osd) { - m_Osd = cOsdProvider::NewOsd(OSD_X, OSD_Y, 0); - - if(m_Osd) { - if (m_Osd->CanHandleAreas(areas, sizeof(areas) / sizeof(tArea) ) == oeOk) { - m_Osd->SetAreas(areas, sizeof(areas) / sizeof(tArea)); - m_Osd->Flush(); - } - } - } - - if(m_Osd) { - for(x=0; x<OSD_W; x+=bpp) { - bit = (x/bpp) & 1; - for(y=0; y<OSD_H; y+=bpp) { - m_Osd->DrawRectangle(x, y, x+bpp, y+bpp, bit?0xffffffff:0xff000000); - bit = !bit; - } - } - // commit - m_Osd->Flush(); - } -} - -eOSState cTestBitmap::ProcessKey(eKeys key) -{ - eOSState state = cOsdObject::ProcessKey(key); - - if (state == osUnknown) { - switch (key & ~k_Repeat) { - case kOk: - case kBack: - return osEnd; - case kRight: - bpp = (bpp<64) ? (bpp<<1) : 1; - Show(); - return osContinue; - case kLeft: - bpp = (bpp>1) ? (bpp>>1) : 64; - Show(); - return osContinue; - default: - break; - } - } - return state; -} - -// -// cMenuTestImages -// - -#include <vdr/remote.h> // CallPlugin - -extern cOsdObject *g_PendingMenuAction; - -class cMenuTestImages : public cMenuSetupPage { - - protected: - void Set(void); - virtual void Store(void) {}; - - public: - cMenuTestImages(); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cMenuTestImages::cMenuTestImages() -{ - Set(); -} - -void cMenuTestImages::Set(void) -{ - char buf[128]; - Clear(); - - SetHasHotkeys(); - Add(new cOsdItem(tr("Grayscale"), osUser1)); - - snprintf(buf, sizeof(buf), "%s 1bit", tr("Bitmap")); - buf[sizeof(buf)-1] = 0; - Add(new cOsdItem(buf, osUser2)); - - snprintf(buf, sizeof(buf), "%s 4bit", tr("Bitmap")); - buf[sizeof(buf)-1] = 0; - Add(new cOsdItem(buf, osUser3)); - - Display(); -} - -eOSState cMenuTestImages::ProcessKey(eKeys Key) -{ - eOSState state = cMenuSetupPage::ProcessKey(Key); - - switch (state) { - case osUser1: - if(cRemote::CallPlugin("xineliboutput")) - g_PendingMenuAction = new cTestGrayscale(); - return osEnd; - case osUser2: - if(cRemote::CallPlugin("xineliboutput")) - g_PendingMenuAction = new cTestBitmap(1); - return osEnd; - case osUser3: - if(cRemote::CallPlugin("xineliboutput")) - g_PendingMenuAction = new cTestBitmap(4); - return osEnd; - default: ; - } - - return state; -} - -//--- cMenuSetupXinelib ------------------------------------------------------ - -cMenuSetupXinelib::cMenuSetupXinelib(void) -{ - XinelibOutputSetupMenu::controls[0] = tr("Off"); - Set(); -} - -void cMenuSetupXinelib::Set(void) -{ - Clear(); - - SetHasHotkeys(); - Add(new cOsdItem(hk(tr("Audio")), osUser1)); - Add(new cOsdItem(hk(tr("Audio Equalizer")),osUser2)); - Add(new cOsdItem(hk(tr("Video")), osUser3)); - Add(new cOsdItem(hk(tr("OSD")), osUser4)); - //Add(new cOsdItem(hk(tr("Decoder")), osUser5)); - Add(new cOsdItem(hk(tr("Media Player")), osUser5)); - Add(new cOsdItem(hk(tr("Local Frontend")), osUser6)); - Add(new cOsdItem(hk(tr("Remote Clients")), osUser7)); - Add(new cOsdItem(hk(tr("Test Images")), osUser8)); - - Display(); -} - -eOSState cMenuSetupXinelib::ProcessKey(eKeys Key) -{ - eOSState state = cMenuSetupPage::ProcessKey(Key); - - switch (state) { - case osUser1: - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupAudio); - case osUser2: - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupAudioEq); - case osUser3: - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupVideo); - case osUser4: - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupOSD); - case osUser5: - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupMediaPlayer); - case osUser6: - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupLocal); - case osUser7: - return AddSubMenu(new XinelibOutputSetupMenu::cMenuSetupRemote); - case osUser8: - return AddSubMenu(new cMenuTestImages); - - default: ; - } - - return state; -} - - diff --git a/setup_menu.h b/setup_menu.h deleted file mode 100644 index d77cc797..00000000 --- a/setup_menu.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * setup_menu.h: Setup Menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: setup_menu.h,v 1.1 2006-06-03 09:50:54 phintuka Exp $ - * - */ - -#ifndef __XINELIB_SETUP_MENU_H -#define __XINELIB_SETUP_MENU_H - -#include <vdr/menuitems.h> - -class cMenuSetupXinelib : public cMenuSetupPage { - - protected: - void Set(void); - virtual void Store(void) {}; - - public: - cMenuSetupXinelib(void); - virtual eOSState ProcessKey(eKeys Key); -}; - -#endif //__XINELIB_SETUP_MENU_H diff --git a/tools.c b/tools.c deleted file mode 100644 index 480325f0..00000000 --- a/tools.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * tools.c: VDR/C++ wrapper for common tools - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: tools.c,v 1.2 2009-01-27 09:25:22 phintuka Exp $ - * - */ - -#define __STDC_CONSTANT_MACROS -#include <stdint.h> -#define __STDC_FORMAT_MACROS -#include <inttypes.h> - -#include <vdr/tools.h> -#include "logdefs.h" - -//#include "tools/vdrdiscovery.c" - -#include "tools/pes.c" -#include "tools/mpeg.c" -#include "tools/h264.c" -#include "tools/ts.c" diff --git a/tools/backgroundwriter.h b/tools/backgroundwriter.h deleted file mode 100644 index d7a0dacc..00000000 --- a/tools/backgroundwriter.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * backgroundwriter.h: Buffered socket/file writing thread - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: backgroundwriter.h,v 1.5 2009-07-21 10:45:13 phintuka Exp $ - * - */ - -#ifndef __BACKGROUNDWRITER_H -#define __BACKGROUNDWRITER_H - -#include <stdint.h> - -#include <vdr/thread.h> -#include <vdr/ringbuffer.h> - -// -// cBackgroundWriterI -// - generic interface for buffered output -// -class cBackgroundWriterI : public cThread -{ - protected: - cRingBufferLinear m_RingBuffer; - - volatile bool m_Active; - int m_fd; - bool m_IsSocket; - - uint64_t m_PutPos; - uint64_t m_DiscardStart; - uint64_t m_DiscardEnd; - - int m_BufferOverflows; - - protected: - virtual void Action(void) = 0; - void Cork(void); - - public: - cBackgroundWriterI(int fd, int Size = KILOBYTE(512), int Margin = 0); - virtual ~cBackgroundWriterI(); - - // Add PES frame to buffer - // - // Return value: - // Success: Count (all bytes pushed to queue) - // Error: 0 (write error ; socket disconnected) - // Buffer full: -Count (no bytes will be pushed to queue) - // - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount) = 0; - - int Free(void); // Return largest possible Put size - void Clear(void); // Drop all data (only complete frames) from buffer - bool Flush(int TimeoutMs); // Flush buffer (wait for data to be sent) -}; - - -// -// cTcpWriter -// - xineliboutput TCP data steam -// - stream_tcp_header_t encapsulated PES frames -// -class cTcpWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - int Put(const uchar *Header, int HeaderCount, - const uchar *Data, int DataCount); - - public: - cTcpWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cTcpWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cRawWriter -// - Raw PES stream -// - Used with HTTP -// -class cRawWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cRawWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cRawWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cTsWriter -// - Demux PES stream to PS -// -class cTsWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cTsWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cTsWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cRtspMuxWriter -// - RTSP multiplexed control+data -// - Each encapsulated PES frame is written atomically to socket buffer -// - Atomic control data can be written directly to socket -// from another thread to bypass buffer -// - -class cRtspMuxWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cRtspMuxWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cRtspMuxWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cRtspRemuxWriter -// - RTSP multiplexed control+data -// - Demux PES stream to independent ES streams -// - encapsulate ES to RTP/AVP compatible frames -// - Mux RTP/AVP ES streams to pipelined RTCP control connection -// - Each encapsulated frame is written atomically to socket buffer -// - Atomic control data can be written directly to socket -// from another thread to bypass buffer -// - -class cRtspRemuxWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cRtspRemuxWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cRtspRemuxWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -#endif diff --git a/tools/bitstream.h b/tools/bitstream.h deleted file mode 100644 index 569c491b..00000000 --- a/tools/bitstream.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * bitstream.h: generic bitstream parsing - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: bitstream.h,v 1.3 2009-02-14 20:44:15 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_BITSTREAM_H_ -#define _XINELIBOUTPUT_BITSTREAM_H_ - - -# ifdef NOCACHE - -typedef struct { - const uint8_t *data; - int count; /* in bits */ - int index; /* in bits */ -} br_state; - -#define BR_INIT(data,bytes) { (data), 8*(bytes), 0 } - -#define BR_EOF(br) ((br)->index >= (br)->count) - -static inline void br_init(br_state *br, const uint8_t *data, int bytes) -{ - br->data = data; - br->count = 8*bytes; - br->index = 0; -} - -static inline int br_get_bit(br_state *br) -{ - if(br->index >= br->count) - return 1; /* -> no infinite colomb's ... */ - - int r = (br->data[br->index>>3] >> (7 - (br->index&7))) & 1; - br->index++; - return r; -} - -static inline uint32_t br_get_bits(br_state *br, uint32_t n) -{ - uint32_t r = 0; - while(n--) - r = r | (br_get_bit(br) << n); - return r; -} - -#define br_skip_bit(br) br_skip_bits(br,1) - -static inline void br_skip_bits(br_state *br, int n) -{ - br->index += n; -} - - -# else /* NOCACHE */ - - -typedef struct { - uint8_t *data; - uint8_t *data_end; - uint32_t cache; - uint32_t cache_bits; -} br_state; - -#define BR_INIT(data,bytes) { (data), (data)+(bytes), 0, 0 } - -static inline void br_init(br_state *br, const uint8_t *data, int bytes) -{ - br->data = data; - br->data_end = data + bytes; - br->cache = 0; - br->cache_bits = 0; -} - -#define BR_GET_BYTE(br) \ - (br->data < br->data_end ? *br->data++ : 0xff) - -#define BR_EOF(br) ((br)->data >= (br)->data_end) - -static inline uint32_t br_get_bits(br_state *br, uint32_t n) -{ - if(n > 24) - return (br_get_bits(br, 16) << 16) | br_get_bits(br, n-16); - - while (br->cache_bits < 24) { - br->cache = (br->cache<<8) | BR_GET_BYTE(br); - br->cache_bits += 8; - } - - br->cache_bits -= n; - return (br->cache >> br->cache_bits) & ((1<<n) - 1); -} - -static inline int br_get_bit(br_state *br) -{ - if(!br->cache_bits) { - br->cache = BR_GET_BYTE(br); - br->cache_bits = 7; - } else { - br->cache_bits--; - } - return (br->cache >> br->cache_bits) & 1; -} - -static inline void br_skip_bit(br_state *br) -{ - if(!br->cache_bits) { - br->cache = BR_GET_BYTE(br); - br->cache_bits = 7; - } else { - br->cache_bits--; - } -} - -static inline void br_skip_bits(br_state *br, int n) -{ - if(br->cache_bits >= n) { - br->cache_bits -= n; - } else { - /* drop cached bits */ - n -= br->cache_bits; - - /* drop full bytes */ - br->data += (n >> 3); - n &= 7; - - /* update cache */ - if(n) { - br->cache = BR_GET_BYTE(br); - br->cache_bits = 8 - n; - } else { - br->cache_bits = 0; - } - } -} - - -# endif /* NOCACHE */ - - -#define br_get_u8(br) br_get_bits(br, 8) -#define br_get_u16(br) ((br_get_bits(br, 8)<<8) | br_get_bits(br, 8)) - -static inline uint32_t br_get_ue_golomb(br_state *br) -{ - int n = 0; - while (!br_get_bit(br) && n < 32) - n++; - return n ? ((1<<n) - 1) + br_get_bits(br, n) : 0; -} - -static inline int32_t br_get_se_golomb(br_state *br) -{ - uint32_t r = br_get_ue_golomb(br) + 1; - return (r&1) ? -(r>>1) : (r>>1); -} - -static inline void br_skip_golomb(br_state *br) -{ - int n = 0; - while (!br_get_bit(br) && n < 32) - n++; - br_skip_bits(br, n); -} - -#define br_skip_ue_golomb(br) br_skip_golomb(br) -#define br_skip_se_golomb(br) br_skip_golomb(br) - - -#endif /* _XINELIBOUTPUT_BITSTREAM_H_ */ diff --git a/tools/cxsocket.c b/tools/cxsocket.c deleted file mode 100644 index e6a95a72..00000000 --- a/tools/cxsocket.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * cxsocket.c: Socket wrapper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: cxsocket.c,v 1.11 2007-03-27 02:45:48 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#include <inttypes.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#ifndef __APPLE__ -# include <sys/sendfile.h> -#endif -#include <netinet/tcp.h> - -#include <vdr/config.h> -#include <vdr/tools.h> - -#include "../logdefs.h" - -#include "cxsocket.h" - -bool cxSocket::connect(struct sockaddr *addr, socklen_t len) -{ - return ::connect(m_fd, addr, len) == 0; -} - -bool cxSocket::connect(const char *ip, int port) -{ - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = inet_addr(ip); - return connect((struct sockaddr *)&sin, sizeof(sin)); -} - -bool cxSocket::set_blocking(bool state) -{ - int flags = fcntl (m_fd, F_GETFL); - - if(flags == -1) { - LOGERR("cxSocket::SetBlocking: fcntl(F_GETFL) failed"); - return false; - } - - flags = state ? (flags&(~O_NONBLOCK)) : (flags|O_NONBLOCK); - - if(fcntl (m_fd, F_SETFL, flags) == -1) { - LOGERR("cxSocket::SetBlocking: fcntl(F_SETFL) failed"); - return false; - } - - return true; -} - -bool cxSocket::set_buffers(int Tx, int Rx) -{ - int max_buf = Tx; - /*while(max_buf) {*/ - errno = 0; - if(setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(int))) { - LOGERR("cxSocket: setsockopt(SO_SNDBUF,%d) failed", max_buf); - /*max_buf >>= 1;*/ - } - /*else {*/ - int tmp = 0; - int len = sizeof(int); - errno = 0; - if(getsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &tmp, (socklen_t*)&len)) { - LOGERR("cxSocket: getsockopt(SO_SNDBUF,%d) failed", max_buf); - /*break;*/ - } else if(tmp != max_buf) { - LOGDBG("cxSocket: setsockopt(SO_SNDBUF): got %d bytes", tmp); - /*max_buf >>= 1;*/ - /*continue;*/ - } - /*}*/ - /*}*/ - - max_buf = Rx; - setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &max_buf, sizeof(int)); - - return true; -} - -bool cxSocket::set_multicast(int ttl) -{ - int iReuse = 1, iLoop = 1, iTtl = ttl; - - errno = 0; - - if(setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)) < 0) { - LOGERR("cxSocket: setsockopt(SO_REUSEADDR) failed"); - return false; - } - - if(setsockopt(m_fd, IPPROTO_IP, IP_MULTICAST_TTL, &iTtl, sizeof(int))) { - LOGERR("cxSocket: setsockopt(IP_MULTICAST_TTL, %d) failed", iTtl); - return false; - } - - if(setsockopt(m_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &iLoop, sizeof(int))) { - LOGERR("cxSocket: setsockopt(IP_MULTICAST_LOOP) failed"); - return false; - } - - return true; -} - -ssize_t cxSocket::sendfile(int fd_file, off_t *offset, size_t count) -{ - int r; -#ifndef __APPLE__ - r = ::sendfile(m_fd, fd_file, offset, count); - if(r<0 && (errno == ENOSYS || errno == EINVAL)) { - // fall back to read/write - LOGERR("sendfile failed - using simple read/write"); -#endif - cxPoller p(*this, true); - char buf[0x10000]; - int todor = count, todow, done = 0; - if(offset) - if((r=::lseek(fd_file, *offset, SEEK_SET)) < 0) - return r; - todow = ::read(fd_file, buf, count>sizeof(buf) ? sizeof(buf) : count); - if(todow <= 0) - return todow; - todor -= todow; - while(todow > 0) { - if(p.Poll(100)) { - r = write(buf+done, todow); - if(r <= 0) - return r; - todow -= r; - done += r; - } - } - return done; -#ifndef __APPLE__ - } - return r; -#endif -} - -bool cxSocket::set_cork(bool state) -{ -#ifdef __APPLE__ - return false; -#else - int iCork = state ? 1 : 0; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_CORK, &iCork, sizeof(int))) { - LOGERR("cxSocket: setsockopt(TCP_CORK) failed"); - return false; - } - return true; -#endif -} - -bool cxSocket::set_nodelay(bool state) -{ - int i = state ? 1 : 0; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(int))) { - LOGERR("cxSocket: setsockopt(TCP_NODELAY) failed"); - return false; - } - return true; -} - -ssize_t cxSocket::tx_buffer_size(void) -{ - socklen_t l = sizeof(int); - int wmem = -1; - if(getsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &wmem, &l)) { - LOGERR("getsockopt(SO_SNDBUF) failed"); - return (ssize_t)-1; - } - return (ssize_t)wmem; -} - -ssize_t cxSocket::tx_buffer_free(void) -{ - int wmem = tx_buffer_size(); - int size = -1; - if(ioctl(m_fd, TIOCOUTQ, &size)) { - LOGERR("ioctl(TIOCOUTQ) failed"); - return (ssize_t)-1; - } - - return (ssize_t)(wmem - size); -} - -int cxSocket::getsockname(struct sockaddr *name, socklen_t *namelen) -{ - return ::getsockname(m_fd, name, namelen); -} - -int cxSocket::getpeername(struct sockaddr *name, socklen_t *namelen) -{ - return ::getpeername(m_fd, name, namelen); -} - -ssize_t cxSocket::send(const void *buf, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen) -{ - return ::sendto(m_fd, buf, size, flags, to, tolen); -} - -ssize_t cxSocket::recv(void *buf, size_t size, int flags, - struct sockaddr *from, socklen_t *fromlen) -{ - return ::recvfrom(m_fd, buf, size, flags, from, fromlen); -} - -ssize_t cxSocket::write(const void *buffer, size_t size, - int timeout_ms) -{ - ssize_t written = (ssize_t)size; - const unsigned char *ptr = (const unsigned char *)buffer; - cPoller poller(m_fd, true); - - while (size > 0) { - errno = 0; - if(!poller.Poll(timeout_ms)) { - LOGERR("cxSocket::write: poll() failed"); - return written-size; - } - - errno = 0; - ssize_t p = ::write(m_fd, ptr, size); - - if (p <= 0) { - if (errno == EINTR || errno == EAGAIN) { - LOGDBG("cxSocket::write: EINTR during write(), retrying"); - continue; - } - LOGERR("cxSocket::write: write() error"); - return p; - } - - ptr += p; - size -= p; - } - - return written; -} - -ssize_t cxSocket::read(void *buffer, size_t size, int timeout_ms) -{ - ssize_t missing = (ssize_t)size; - unsigned char *ptr = (unsigned char *)buffer; - cPoller poller(m_fd); - - while (missing > 0) { - - if(!poller.Poll(timeout_ms)) { - LOGERR("cxSocket::read: poll() failed at %d/%d", (int)(size-missing), (int)size); - return size-missing; - } - - errno = 0; - ssize_t p = ::read(m_fd, ptr, missing); - - if (p <= 0) { - if (errno == EINTR || errno == EAGAIN) { - LOGDBG("cxSocket::read: EINTR/EAGAIN during read(), retrying"); - continue; - } - LOGERR("cxSocket::read: read() error at %d/%d", (int)(size-missing), (int)size); - return size-missing; - } - - ptr += p; - missing -= p; - } - - return size; -} - -ssize_t cxSocket::printf(const char *fmt, ...) -{ - va_list argp; - char buf[1024]; - int r; - - va_start(argp, fmt); - r = vsnprintf(buf, sizeof(buf), fmt, argp); - if(r<0) - LOGERR("cxSocket::printf: vsnprintf failed"); - else if(r >= (int)sizeof(buf)) - LOGMSG("cxSocket::printf: vsnprintf overflow (%20s)", buf); - else - return write(buf, r); - - return (ssize_t)-1; -} - -/* readline return value: - * <0 : failed - * >=maxsize : buffer overflow - * >=0 : if errno = EAGAIN -> line is not complete (there was timeout) - * if errno = 0 -> succeed - * (return value 0 indicates empty line "\r\n") - */ -ssize_t cxSocket::readline(char *buf, int bufsize, int timeout, int bufpos) -{ - int n = -1, cnt = bufpos; - cPoller p(m_fd); - - do { - if(timeout>0 && !p.Poll(timeout)) { - errno = EAGAIN; - return cnt; - } - - while((n = ::read(m_fd, buf+cnt, 1)) == 1) { - buf[++cnt] = 0; - - if( cnt > 1 && buf[cnt - 2] == '\r' && buf[cnt - 1] == '\n') { - cnt -= 2; - buf[cnt] = 0; - errno = 0; - return cnt; - } - - if( cnt >= bufsize) { - LOGMSG("cxSocket::readline: too long control message (%d bytes): %20s", cnt, buf); - errno = 0; - return bufsize; - } - } - - /* connection closed ? */ - if (n == 0) { - LOGMSG("cxSocket::readline: disconnected"); - if(errno == EAGAIN) - errno = ENOTCONN; - return -1; - } - - } while (timeout>0 && n<0 && errno == EAGAIN); - - if(errno == EAGAIN) - return cnt; - - LOGERR("cxSocket::readline: read failed"); - return n; -} - -#include <sys/ioctl.h> -#include <net/if.h> - -uint32_t cxSocket::get_local_address(char *ip_address) -{ - uint32_t local_addr = 0; - struct ifconf conf; - struct ifreq buf[3]; - unsigned int n; - - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - - if(!getsockname((struct sockaddr *)&sin, &len)) { - local_addr = sin.sin_addr.s_addr; - - } else { - //LOGERR("getsockname failed"); - - // scan network interfaces - - conf.ifc_len = sizeof(buf); - conf.ifc_req = buf; - memset(buf, 0, sizeof(buf)); - - errno = 0; - if(ioctl(m_fd, SIOCGIFCONF, &conf) < 0) - LOGERR("cxSocket: can't obtain socket local address"); - else { - for(n=0; n<conf.ifc_len/sizeof(struct ifreq); n++) { - struct sockaddr_in *in = (struct sockaddr_in *) &buf[n].ifr_addr; -# if 0 - uint32_t tmp = ntohl(in->sin_addr.s_addr); - LOGMSG("Local address %6s %d.%d.%d.%d", - conf.ifc_req[n].ifr_name, - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff)); -# endif - if(n==0 || local_addr == htonl(INADDR_LOOPBACK)) - local_addr = in->sin_addr.s_addr; - else - break; - } - } - } - - if(!local_addr) - LOGERR("No local address found"); - - if(ip_address) - cxSocket::ip2txt(local_addr, 0, ip_address); - - return local_addr; -} - -char *cxSocket::ip2txt(uint32_t ip, unsigned int port, char *str) -{ - // inet_ntoa is not thread-safe (?) - if(str) { - unsigned int iph =(unsigned int)ntohl(ip); - unsigned int porth =(unsigned int)ntohs(port); - if(!porth) - sprintf(str, "%d.%d.%d.%d", - ((iph>>24)&0xff), ((iph>>16)&0xff), - ((iph>>8)&0xff), ((iph)&0xff)); - else - sprintf(str, "%u.%u.%u.%u:%u", - ((iph>>24)&0xff), ((iph>>16)&0xff), - ((iph>>8)&0xff), ((iph)&0xff), - porth); - } - return str; -} diff --git a/tools/cxsocket.h b/tools/cxsocket.h deleted file mode 100644 index 92954f3c..00000000 --- a/tools/cxsocket.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * cxsocket.h: Socket wrapper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: cxsocket.h,v 1.20 2007-01-20 17:24:40 phintuka Exp $ - * - */ - -#ifndef __CXSOCKET_H -#define __CXSOCKET_H - -#include <inttypes.h> -#include <sys/types.h> -#include <sys/socket.h> - -#define CLOSESOCKET(fd) do { if(fd>=0) { ::close(fd); fd=-1; } } while(0) - -class cxSocket { - private: - int m_fd; - - cxSocket(const cxSocket& s) ;//{ m_fd = s.m_fd>=0 ? dup(s.m_fd) : -1; } - cxSocket &operator=(const cxSocket &S) - ;// { close(); m_fd = S.m_fd >= 0 ? dup(S.m_fd) : -1; return *this; }; - - public: - - typedef enum { - estSTREAM = SOCK_STREAM, - estDGRAM = SOCK_DGRAM - } eSockType; - - cxSocket() : m_fd(-1) {} - cxSocket(eSockType type) : m_fd(::socket(PF_INET, (int)type, 0)) {} - - ~cxSocket() { CLOSESOCKET(m_fd); } - - //operator int () const { return Handle(); } - //operator bool () const { return open(); } - //bool operator==(const cxSocket &s) { return m_fd == s.m_fd; } - - int handle(bool take_ownership=false) - { int r=m_fd; if(take_ownership) m_fd=-1; return r; } - void set_handle(int h) { if(h != m_fd) {close(); m_fd = h;} } - bool create(eSockType type) { close(); return (m_fd=::socket(PF_INET, (int)type, 0)) >= 0; } - bool open(void) const { return m_fd>0; } - void close(void) { CLOSESOCKET(m_fd); } - - ssize_t send(const void *buf, size_t size, int flags=0, - const struct sockaddr *to = NULL, socklen_t tolen = 0); - ssize_t recv(void *buf, size_t size, int flags = 0, - struct sockaddr *from = NULL, socklen_t *fromlen = NULL); - ssize_t sendfile(int fd_file, off_t *offset, size_t count); - - ssize_t read(void *buffer, size_t size, int timeout_ms = -1); - ssize_t write(const void *buffer, size_t size, int timeout_ms = -1); - - ssize_t printf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); - ssize_t write_str(const char *str, int timeout_ms=-1, int len=0) - { return write(str, len ?: strlen(str), timeout_ms); } - ssize_t write_cmd(const char *str, int len=0) - { return write(str, len ?: strlen(str), 10); } - -/* readline return value: - * <0 : failed - * >=maxsize : buffer overflow - * >=0 : if errno = EAGAIN -> line is not complete (there was timeout) - * if errno = 0 -> succeed - * (return value 0 indicates empty line "\r\n") - */ - ssize_t readline(char *buf, int bufsize, int timeout=0, int bufpos=0); - - bool set_buffers(int Tx, int Rx); - bool set_multicast(int ttl); - bool set_blocking(bool state); - bool set_cork(bool state); - bool flush_cork(void) { return set_nodelay(true); }; - bool set_nodelay(bool state); - ssize_t tx_buffer_size(void); - ssize_t tx_buffer_free(void); - int getsockname(struct sockaddr *name, socklen_t *namelen); - int getpeername(struct sockaddr *name, socklen_t *namelen); - - - bool connect(struct sockaddr *addr, socklen_t len); - bool connect(const char *ip, int port); - - uint32_t get_local_address(char *ip_address); - - static char *ip2txt(uint32_t ip, unsigned int port, char *str); -}; - - -#include <vdr/tools.h> - -class cxPoller : public cPoller { - public: - cxPoller(cxSocket& Sock, bool Out=false) : cPoller(Sock.handle(), Out) {}; - - cxPoller(cxSocket* Socks, int count, bool Out=false) - { - for(int i=0; i<count; i++) - Add(Socks[i].handle(), Out); - } -}; - -// -// Set socket buffers -// -static inline void set_socket_buffers(int s, int txbuf, int rxbuf) -{ - int max_buf = txbuf; - /*while(max_buf) {*/ - errno = 0; - if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(int))) { - LOGERR("setsockopt(SO_SNDBUF,%d) failed", max_buf); - /*max_buf >>= 1;*/ - } - /*else {*/ - int tmp = 0; - int len = sizeof(int); - errno = 0; - if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &tmp, (socklen_t*)&len)) { - LOGERR("getsockopt(SO_SNDBUF,%d) failed", max_buf); - /*break;*/ - } else if(tmp != max_buf) { - LOGDBG("setsockopt(SO_SNDBUF): got %d bytes", tmp); - /*max_buf >>= 1;*/ - /*continue;*/ - } - /*}*/ - /*}*/ - - max_buf = rxbuf; - setsockopt(s, SOL_SOCKET, SO_RCVBUF, &max_buf, sizeof(int)); -} - -// -// Connect data socket to client (take address from fd_control) -// -static inline int sock_connect(int fd_control, int port, int type) -{ - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - int s, one = 1; - - if(getpeername(fd_control, (struct sockaddr *)&sin, &len)) { - LOGERR("sock_connect: getpeername failed"); - return -1; - } - - uint32_t tmp = ntohl(sin.sin_addr.s_addr); - LOGMSG("Client address: %d.%d.%d.%d", - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff)); - -#if 0 - if ((h = gethostbyname(tmp)) == NULL) { - LOGDBG("sock_connect: unable to resolve host name", tmp); - } -#endif - - if ((s = socket(PF_INET, type, - type==SOCK_DGRAM?IPPROTO_UDP:IPPROTO_TCP)) < 0) { - LOGERR("sock_connect: failed to create socket"); - return -1; - } - - // Set socket buffers: large send buffer, small receive buffer - set_socket_buffers(s, KILOBYTE(256), 2048); - - if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0) - LOGERR("sock_connect: setsockopt(SO_REUSEADDR) failed"); - - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1 && - errno != EINPROGRESS) { - LOGERR("connect() failed"); - CLOSESOCKET(s); - } - - if (fcntl (s, F_SETFL, fcntl (s, F_GETFL) | O_NONBLOCK) == -1) { - LOGERR("can't put socket in non-blocking mode"); - CLOSESOCKET(s); - return -1; - } - - return s; -} - -#endif // __CXSOCKET_H diff --git a/tools/debug_mutex.h b/tools/debug_mutex.h deleted file mode 100644 index 0802c7cc..00000000 --- a/tools/debug_mutex.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * debug_mutex.h: debugging wrappers for pthread_mutex_ functions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: debug_mutex.h,v 1.3 2007-03-14 11:50:08 phintuka Exp $ - * - */ - -#ifndef DEBUG_MUTEX_H -#define DEBUG_MUTEX_H - -#ifndef _PTHREAD_H -# error pthread.h must be included before debug_mutex.h -#endif - -/* - * Override pthread_mutex_ calls: - * - * Change type of each mutex to PTHREAD_MUTEX_ERRORCHECK_NP - * - * Store line number of last succeed pthread_mutex_lock call - * for each initialized mutex - * - * Check every pthread_mutex_ call for errors and log all errors - * - * To help detecting deadlocks and minimize logging: - * - Try locking first in pthread_mutex_lock - * - If pthread_mutex_trylock fails, log a message and retry. - * - When trylock failed, log another message when lock is acquired. - * - * - * NOTE: debugging itself is not thread-safe and may indicate wrong line numbers ! - * - */ - -#define MAX_DBG_MUTEX 64 -static struct { - pthread_mutex_t *lock; - int line; - int tid; -} dbgdata[MAX_DBG_MUTEX+1] = {{NULL,0}}; - -static void dbg_setdata(pthread_mutex_t *mutex, int line) -{ - int i; - for(i=0; i<MAX_DBG_MUTEX; i++) - if(dbgdata[i].lock == mutex) { - dbgdata[i].line = line; - dbgdata[i].tid = syscall(__NR_gettid); - return; - } - - LOGMSG("********** dbg_setdata: new entry (0x%lx at %d)", (unsigned long int)mutex, line); - for(i=0; i<MAX_DBG_MUTEX; i++) - if(!dbgdata[i].lock) { - dbgdata[i].lock = mutex; - dbgdata[i].line = line; - dbgdata[i].tid = syscall(__NR_gettid); - return; - } - - LOGMSG("********** dbg_setdata: table full !"); -} - -static int dbg_getdata(pthread_mutex_t *mutex, int line) -{ - int i; - for(i=0; i<MAX_DBG_MUTEX; i++) - if(dbgdata[i].lock == mutex) - return dbgdata[i].line; - - LOGMSG("********** dbg_getdata: NO ENTRY ! (%d)", line); - return -1; -} - -static void dbg_deldata(pthread_mutex_t *mutex, int line) -{ - int i; - for(i=0; i<MAX_DBG_MUTEX; i++) - if(dbgdata[i].lock == mutex) { - dbgdata[i].lock = NULL; - return; - } - - LOGMSG("********** dbg_deldata: NO ENTRY ! (%d)", line); - return; -} - -static int dbg_init(pthread_mutex_t *mutex, pthread_mutexattr_t *pattr, int line) -{ - int r; - - errno = 0; - if(!pattr) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); - r = pthread_mutex_init(mutex, &attr); - } else { - LOGMSG("********** dbg_init: mutex attribute already given !"); - r = pthread_mutex_init(mutex, pattr); - } - - if(r) - LOGERR("********** dbg_init: pthread_mutex_init FAILED at %d", line); - - dbg_setdata(mutex, line); - - return r; -} - -static int dbg_free(pthread_mutex_t *mutex, int line) -{ - int r; - - errno = 0; - r = pthread_mutex_destroy(mutex); - - if(r) - LOGERR("********** dbg_free: pthread_mutex_destroy FAILED at %d ; last lock at %d", - line, dbg_getdata(mutex, line)); - dbg_deldata(mutex, line); - - return r; -} - -static int dbg_lock(pthread_mutex_t *mutex, int line) -{ - int r; - /*struct timespec abs_timeout;*/ - - /* try lock first to reduce logging */ - errno = 0; - r = pthread_mutex_trylock(mutex); - if(!r) { - dbg_setdata(mutex,line); - return r; - } - - /* try failed - we're going to wait, so log at wait start and end to detect deadlocks */ - LOGERR("********** dbg_lock: pthread_mutex_trylock failed at %d (locked at %d)", - line, dbg_getdata(mutex, line)); - - /* int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, - const struct timespec *restrict abs_timeout); */ - - errno = 0; - r = pthread_mutex_lock(mutex); - - if(r) - LOGERR("********** dbg_lock: pthread_mutex_lock FAILED at %d", line); - - dbg_setdata(mutex, line); - LOGMSG("********** dbg_lock: pthread_mutex_lock done at %d", line); - - return r; -} - -static int dbg_trylock(pthread_mutex_t *mutex, int line) -{ - int r; - /*struct timespec abs_timeout;*/ - - /* try lock first to reduce logging */ - errno = 0; - r = pthread_mutex_trylock(mutex); - if(!r) { - dbg_setdata(mutex,line); - return r; - } - - LOGERR("********** dbg_trylock: pthread_mutex_trylock failed at %d (locked at %d)", - line, dbg_getdata(mutex, line)); - - return r; -} - -static int dbg_unlock(pthread_mutex_t *mutex, int line) -{ - int r; - - errno = 0; - r = pthread_mutex_unlock(mutex); - - if(r) - LOGERR("********** dbg_unlock: pthread_mutex_unlock FAILED at %d (last locket at %d)", - line, dbg_getdata(mutex, line)); - - //else - // dbg_setdata(mutex, 0); - - return r; -} - -/* override pthread_ functions with own ones */ -#define pthread_mutex_init(l,a) dbg_init(l, a, __LINE__) -#define pthread_mutex_lock(l) dbg_lock(l, __LINE__) -#define pthread_mutex_trylock(l) dbg_trylock(l, __LINE__) -#define pthread_mutex_unlock(l) dbg_unlock(l, __LINE__) -#define pthread_mutex_destroy(l) dbg_free(l, __LINE__) - -#else -# error debug_mutex.h included twice -#endif /* DEBUG_MUTEX_H */ diff --git a/tools/display_message.h b/tools/display_message.h deleted file mode 100644 index 407f07c8..00000000 --- a/tools/display_message.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * display_message.h: Display simple message - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: display_message.h,v 1.2 2007-01-06 04:28:08 phintuka Exp $ - * - */ - -#ifndef __DISPLAY_MESSAGE_H -#define __DISPLAY_MESSAGE_H - -#include <vdr/osdbase.h> -#include <vdr/skins.h> - -class cDisplayMessage : public cOsdObject -{ - cSkinDisplayMessage *displayMessage; - char *Message; - int Timer; - int Timeout; - - public: - - cDisplayMessage(const char *message, int timeout = 3) - { - displayMessage = NULL; - Message = strdup(message); - Timer = 0; - Timeout = timeout; - } - - virtual ~cDisplayMessage() - { - delete displayMessage; - free(Message); - } - - void Update(const char *message) - { - Timer = 0; - free(Message); - Message = strdup(message); - Show(); - } - - virtual eOSState ProcessKey(eKeys Key) - { - if(Key == kNone && Timer++ > Timeout) - return osEnd; - - if(Key != kNone) { - // put back and close - cRemote::Put(Key, true); - return osEnd; - } - - return osContinue; - } - - virtual void Show(void) - { - if(!displayMessage) - displayMessage = Skins.Current()->DisplayMessage(); - - displayMessage->SetMessage(mtInfo, Message); - displayMessage->Flush(); - } - -}; - -#endif diff --git a/tools/functor.h b/tools/functor.h deleted file mode 100644 index 0dadf1fc..00000000 --- a/tools/functor.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * functor.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: functor.h,v 1.1 2006-08-24 23:25:07 phintuka Exp $ - * - */ - -#ifndef __XINELIB_FUNCTOR_H -#define __XINELIB_FUNCTOR_H - -#include <vdr/tools.h> - - -class cFunctor : public cListObject -{ - public: - cFunctor() : cListObject() {} - virtual ~cFunctor() {} - virtual void Execute(void) = 0; -}; - -#if 1 /* gcc 3.3.x (?) does not accept class TRESULT=void */ -template<class TCLASS> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(void)); - -template<class TCLASS, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(TARG1), - TARG1 arg1); -#endif - -template<class TCLASS, class TRESULT> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(void)); - -template<class TCLASS, class TRESULT, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1); - -#include "functorimpl.h" - -#endif diff --git a/tools/functorimpl.h b/tools/functorimpl.h deleted file mode 100644 index 2d3504e6..00000000 --- a/tools/functorimpl.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * functorimpl.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: functorimpl.h,v 1.1 2006-08-24 23:25:07 phintuka Exp $ - * - */ - -#ifndef __XINELIB_FUNCTORIMPL_H - -#ifndef __XINELIB_FUNCTOR_H -# error functorimpl.h should not be included, use functor.h instead -#endif - -#if 1 /* gcc 3.3.x (?) does not accept class TRESULT=void */ -template <class TCLASS> -class cFunctor0 : public cFunctor { - - public: - protected: - - typedef void (TCLASS::*TFUNC)(void); - - cFunctor0(TCLASS *obj, TFUNC f) : m_obj(obj), m_f(f) {} - virtual ~cFunctor0() {}; - - virtual void Execute(void) - { - (*m_obj.*m_f)(); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - - friend cFunctor *CreateFunctor<TCLASS>(TCLASS*,TFUNC); -}; - -template <class TCLASS, class TARG1> -class cFunctor1 : public cFunctor { - - public: - - protected: - typedef void (TCLASS::*TFUNC)(TARG1); - - cFunctor1(TCLASS *obj, TFUNC f, TARG1 arg1) : - m_obj(obj), m_f(f), m_arg1(arg1) {} - virtual ~cFunctor1() {}; - - virtual void Execute(void) - { - (*m_obj.*m_f)(m_arg1); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - - friend cFunctor *CreateFunctor<TCLASS,TARG1>(TCLASS*,TFUNC,TARG1); -}; -#endif - -template <class TCLASS, class TRESULT> -class cFunctorR0 : public cFunctor { - - public: - protected: - - typedef TRESULT (TCLASS::*TFUNC)(void); - - cFunctorR0(TCLASS *obj, TFUNC f) : m_obj(obj), m_f(f) {} - virtual ~cFunctorR0() {}; - - virtual void Execute(void) - { - // TODO: use future to pass back value - (void) (*m_obj.*m_f)(); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - - friend cFunctor *CreateFunctor<TCLASS,TRESULT>(TCLASS*,TFUNC); -}; - -template <class TCLASS, class TRESULT, class TARG1> -class cFunctorR1 : public cFunctor { - - public: - protected: - - typedef TRESULT (TCLASS::*TFUNC)(TARG1); - - cFunctorR1(TCLASS *obj, TFUNC f, TARG1 arg1) : - m_obj(obj), m_f(f), m_arg1(arg1) {} - virtual ~cFunctorR1() {}; - - virtual void Execute(void) - { - // TODO: use future to pass back value - (void) (*m_obj.*m_f)(m_arg1); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - - friend cFunctor *CreateFunctor<TCLASS,TRESULT>(TCLASS*,TFUNC,TARG1); -}; - -#if 1 /* gcc 3.3.x (?) does not accept class TRESULT=void */ -template<class TCLASS> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(void)) -{ - return new cFunctor0<TCLASS>(c, fp); -} - -template<class TCLASS, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(TARG1), - TARG1 arg1) -{ - return new cFunctor1<TCLASS,TARG1>(c, fp, arg1); -} -#endif - -template<class TCLASS, class TRESULT> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(void)) -{ - return new cFunctorR0<TCLASS,TRESULT>(c, fp); -} - -template<class TCLASS, class TRESULT, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1) -{ - return new cFunctorR1<TCLASS,TRESULT,TARG1>(c, fp, arg1); -} - - -#endif diff --git a/tools/future.h b/tools/future.h deleted file mode 100644 index bdd0498c..00000000 --- a/tools/future.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * future.h: A variable that gets its value in future. - * Used to convert asynchronous IPCs to synchronous. - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: future.h,v 1.2 2006-08-19 23:44:07 phintuka Exp $ - * - */ - -#ifndef __FUTURE_H -#define __FUTURE_H - -#include <vdr/thread.h> - -template <class T> -class cFuture { - - private: - cMutex mutex; - cCondVar cond; - bool m_Ready; - T m_Value; - - public: - - cFuture() - { - m_Ready = false; - } - - void Reset(void) - { - cMutexLock l(&mutex); - m_Ready = false; - } - - // - // Producer interface - // - - void Set(T& Value) - { - cMutexLock l(&mutex); - m_Value = Value; - m_Ready = true; - cond.Broadcast(); - } - - // - // Consumer interface - // - - bool Wait(int Timeout = -1) - { - cMutexLock l(&mutex); - - if(Timeout==0 || m_Ready) - return m_Ready; - - if(Timeout >= 0) - return cond.TimedWait(mutex, Timeout) && m_Ready; - - while(!m_Ready) - cond.Wait(mutex); - - return m_Ready; - } - - bool IsReady(void) - { - cMutexLock l(&mutex); - return m_Ready; - } - - T Value(void) - { - cMutexLock l(&mutex); - while(!m_Ready) - cond.Wait(mutex); - return m_Value; - } -}; - - -#endif // __FUTURE_H diff --git a/tools/general_remote.h b/tools/general_remote.h deleted file mode 100644 index aed60463..00000000 --- a/tools/general_remote.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * general_remote.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: general_remote.h,v 1.1 2006-06-03 10:04:27 phintuka Exp $ - * - */ - -#ifndef __GENERAL_REMOTE_H -#define __GENERAL_REMOTE_H - - -//----------------------------- cGeneralRemote -------------------------------- - -#include <vdr/remote.h> - -class cGeneralRemote : public cRemote { - public: - cGeneralRemote(const char *Name) : cRemote(Name) {}; - bool Put(const char *Code, bool Repeat=false, bool Release=false) - { return cRemote::Put(Code, Repeat, Release); }; -}; - - -#endif diff --git a/tools/gnome_screensaver.c b/tools/gnome_screensaver.c deleted file mode 100644 index 245f1f63..00000000 --- a/tools/gnome_screensaver.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * gnome_screensaver.c v0.0.7 - * - * Enable/Disable the GNOME screensaver - * Supports GNOME screensaver API 2.14 and 2.15 - * - * Call gnome_screensaver_control(1) to enable and - * gnome_screensaver_control(0) to disable - * - */ -/* - * Orginally written for mplayer by Piotr Kaczuba - * (http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/2006-April/042661.html) - * - * Modified for xineliboutput by Alex Stansfield - * (http://www.linuxtv.org/pipermail/vdr/2007-July/013458.html) - */ - -#include <stdlib.h> -#include <unistd.h> -#include <dbus/dbus-glib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> - -#define LOG_MODULENAME "[vdr-fe] " -#include "../logdefs.h" - -#include "gnome_screensaver.h" - -#define GS_SERVICE "org.gnome.ScreenSaver" -#define GS_PATH "/org/gnome/ScreenSaver" -#define GS_INTERFACE "org.gnome.ScreenSaver" - -#define GS_APPLICATION_NAME "vdr-sxfe" -#define GS_REASON_FOR_INHIBIT "Watching TV" - -/* Log Messages */ -#define MSG_OpenBusConnectionError "Failed to open connection to bus: %s" -#define MSG_RemoteMethodException "Caught remote method exception %s: %s" -#define MSG_GnomeAPI215Failed "GNOME screensaver 2.15 API failed, trying 2.14 API" -#define MSG_GError "Error: %s" -#define MSG_GNOMEScreensaverEnabled "GNOME screensaver enabled" -#define MSG_GNOMEScreensaverDisabled "GNOME screensaver disabled" - -static guint32 cookie; - -void gnome_screensaver_control(int enable) -{ - DBusGConnection *connection; - GError *error; - DBusGProxy *proxy; - gboolean ret; - - g_type_init(); - - /* Get a connection to the session bus */ - error = NULL; - connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); - if (connection == NULL) { - LOGERR(MSG_OpenBusConnectionError, error->message); - g_error_free(error); - return; - } - - /* Create a proxy object */ - proxy = dbus_g_proxy_new_for_name(connection, - GS_SERVICE, GS_PATH, GS_INTERFACE); - - /* Enable the screensaver */ - if (enable) { - /* First call the GNOME screensaver 2.15 API method */ - error = NULL; - ret = - dbus_g_proxy_call(proxy, "UnInhibit", &error, G_TYPE_UINT, - cookie, G_TYPE_INVALID, G_TYPE_INVALID); - - /* If this fails, try the GNOME screensaver 2.14 API */ - if (!ret && error->domain == DBUS_GERROR - && error->code == DBUS_GERROR_UNKNOWN_METHOD) { - LOGERR(MSG_GnomeAPI215Failed); - g_error_free(error); - error = NULL; - ret = - dbus_g_proxy_call(proxy, "AllowActivation", &error, - G_TYPE_INVALID, G_TYPE_INVALID); - } - } - /* Disable the screensaver */ - else { - /* First call the GNOME screensaver 2.15 API method */ - error = NULL; - ret = - dbus_g_proxy_call(proxy, "Inhibit", &error, G_TYPE_STRING, - GS_APPLICATION_NAME, G_TYPE_STRING, - GS_REASON_FOR_INHIBIT, G_TYPE_INVALID, - G_TYPE_UINT, cookie, G_TYPE_INVALID); - - /* If this fails, try the GNOME screensaver 2.14 API */ - if (!ret && error->domain == DBUS_GERROR - && error->code == DBUS_GERROR_UNKNOWN_METHOD) { - LOGERR(MSG_GnomeAPI215Failed); - g_error_free(error); - error = NULL; - ret = - dbus_g_proxy_call(proxy, "InhibitActivation", &error, - G_TYPE_STRING, GS_REASON_FOR_INHIBIT, - G_TYPE_INVALID, G_TYPE_INVALID); - } - } - - if (!ret) { - /* Check if it's a remote exception or a regular GError */ - if (error->domain == DBUS_GERROR - && error->code == DBUS_GERROR_REMOTE_EXCEPTION) { - LOGERR(MSG_RemoteMethodException, dbus_g_error_get_name(error), error->message); - } - else { - LOGERR(MSG_GError, error->message); - } - g_error_free(error); - } - else { - LOGMSG(enable ? MSG_GNOMEScreensaverEnabled : MSG_GNOMEScreensaverDisabled); - } - - g_object_unref(proxy); -} diff --git a/tools/gnome_screensaver.h b/tools/gnome_screensaver.h deleted file mode 100644 index 84dee38e..00000000 --- a/tools/gnome_screensaver.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _GNOME_SCREENSAVER_H -#define _GNOME_SCREENSAVER_H - -extern void gnome_screensaver_control(int enable); - -#endif /* !_GNOME_SCREENSAVER_H */ diff --git a/tools/h264.c b/tools/h264.c deleted file mode 100644 index a729a289..00000000 --- a/tools/h264.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * h264.c: H.264 bitstream decoding - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: h264.c,v 1.7 2009-03-31 11:33:05 phintuka Exp $ - * - */ - -#include <stdint.h> -#include <string.h> - -#ifndef LOG_MODULENAME -# define LOG_MODULENAME "[h264 ] " -# define SysLogLevel iSysLogLevel -# include "../logdefs.h" -#endif - -#define NOCACHE 1 -#include "bitstream.h" - -#include "mpeg.h" -#include "h264.h" - - -int h264_parse_sps(const uint8_t *buf, int len, h264_sps_data_t *sps) -{ - br_state br = BR_INIT(buf, len); - int profile_idc, pic_order_cnt_type; - int frame_mbs_only; - int i, j; - - profile_idc = br_get_u8(&br); - LOGDBG("H.264 SPS: profile_idc %d", profile_idc); - /* constraint_set0_flag = br_get_bit(br); */ - /* constraint_set1_flag = br_get_bit(br); */ - /* constraint_set2_flag = br_get_bit(br); */ - /* constraint_set3_flag = br_get_bit(br); */ - /* reserved = br_get_bits(br,4); */ - /* level_idc = br_get_u8(br); */ - br_skip_bits(&br, 16); - br_skip_ue_golomb(&br); /* seq_parameter_set_id */ - if (profile_idc >= 100) { - if (br_get_ue_golomb(&br) == 3) /* chroma_format_idc */ - br_skip_bit(&br); /* residual_colour_transform_flag */ - br_skip_ue_golomb(&br); /* bit_depth_luma - 8 */ - br_skip_ue_golomb(&br); /* bit_depth_chroma - 8 */ - br_skip_bit(&br); /* transform_bypass */ - if (br_get_bit(&br)) /* seq_scaling_matrix_present */ - for (i = 0; i < 8; i++) - if (br_get_bit(&br)) { /* seq_scaling_list_present */ - int last = 8, next = 8, size = (i<6) ? 16 : 64; - for (j = 0; j < size; j++) { - if (next) - next = (last + br_get_se_golomb(&br)) & 0xff; - last = next ?: last; - } - } - } - - br_skip_ue_golomb(&br); /* log2_max_frame_num - 4 */ - pic_order_cnt_type = br_get_ue_golomb(&br); - if (pic_order_cnt_type == 0) - br_skip_ue_golomb(&br); /* log2_max_poc_lsb - 4 */ - else if (pic_order_cnt_type == 1) { - br_skip_bit(&br); /* delta_pic_order_always_zero */ - br_skip_se_golomb(&br); /* offset_for_non_ref_pic */ - br_skip_se_golomb(&br); /* offset_for_top_to_bottom_field */ - j = br_get_ue_golomb(&br); /* num_ref_frames_in_pic_order_cnt_cycle */ - for (i = 0; i < j; i++) - br_skip_se_golomb(&br); /* offset_for_ref_frame[i] */ - } - br_skip_ue_golomb(&br); /* ref_frames */ - br_skip_bit(&br); /* gaps_in_frame_num_allowed */ - sps->width /* mbs */ = br_get_ue_golomb(&br) + 1; - sps->height /* mbs */ = br_get_ue_golomb(&br) + 1; - frame_mbs_only = br_get_bit(&br); - LOGDBG("H.264 SPS: pic_width: %u mbs", (unsigned) sps->width); - LOGDBG("H.264 SPS: pic_height: %u mbs", (unsigned) sps->height); - LOGDBG("H.264 SPS: frame only flag: %d", frame_mbs_only); - - sps->width *= 16; - sps->height *= 16 * (2-frame_mbs_only); - - if (!frame_mbs_only) - if (br_get_bit(&br)) /* mb_adaptive_frame_field_flag */ - LOGDBG("H.264 SPS: MBAFF"); - br_skip_bit(&br); /* direct_8x8_inference_flag */ - if (br_get_bit(&br)) { /* frame_cropping_flag */ - uint32_t crop_left = br_get_ue_golomb(&br); - uint32_t crop_right = br_get_ue_golomb(&br); - uint32_t crop_top = br_get_ue_golomb(&br); - uint32_t crop_bottom = br_get_ue_golomb(&br); - LOGDBG("H.264 SPS: cropping %d %d %d %d", - crop_left, crop_top, crop_right, crop_bottom); - - sps->width -= 2*(crop_left + crop_right); - if (frame_mbs_only) - sps->height -= 2*(crop_top + crop_bottom); - else - sps->height -= 4*(crop_top + crop_bottom); - } - - /* VUI parameters */ - sps->pixel_aspect.num = 0; - if (br_get_bit(&br)) { /* vui_parameters_present flag */ - if (br_get_bit(&br)) { /* aspect_ratio_info_present */ - uint32_t aspect_ratio_idc = br_get_u8(&br); - LOGDBG("H.264 SPS: aspect_ratio_idc %d", aspect_ratio_idc); - - if (aspect_ratio_idc == 255 /* Extended_SAR */) { - sps->pixel_aspect.num = br_get_u16(&br); /* sar_width */ - sps->pixel_aspect.den = br_get_u16(&br); /* sar_height */ - LOGDBG("H.264 SPS: -> sar %dx%d", sps->pixel_aspect.num, sps->pixel_aspect.den); - } else { - static const mpeg_rational_t aspect_ratios[] = - { /* page 213: */ - /* 0: unknown */ - {0, 1}, - /* 1...16: */ - { 1, 1}, {12, 11}, {10, 11}, {16, 11}, { 40, 33}, {24, 11}, {20, 11}, {32, 11}, - {80, 33}, {18, 11}, {15, 11}, {64, 33}, {160, 99}, { 4, 3}, { 3, 2}, { 2, 1} - }; - - if (aspect_ratio_idc < sizeof(aspect_ratios)/sizeof(aspect_ratios[0])) { - memcpy(&sps->pixel_aspect, &aspect_ratios[aspect_ratio_idc], sizeof(mpeg_rational_t)); - LOGDBG("H.264 SPS: -> aspect ratio %d / %d", sps->pixel_aspect.num, sps->pixel_aspect.den); - } else { - LOGMSG("H.264 SPS: aspect_ratio_idc out of range !"); - } - } - } - } - - LOGDBG("H.264 SPS: -> video size %dx%d, aspect %d:%d", - sps->width, sps->height, sps->pixel_aspect.num, sps->pixel_aspect.den); - - if(BR_EOF(&br)) { - LOGDBG("H.264 SPS: not enough data ?"); - return 0; - } - return 1; -} - -static int h264_nal_unescape(uint8_t *dst, const uint8_t *src, int len) -{ - int s = 0, d = 0; - while (s < len) { - if (!src[s] && !src[s+1]) { - /* hit 00 00 xx */ - dst[d] = dst[d+1] = 0; - s += 2; - d += 2; - if (src[s] == 3) { - s++; /* 00 00 03 xx --> 00 00 xx */ - /*LOGDBG("h264_nal_unescape: hit 00 00 03 %02x", src[s]);*/ - if (s >= len) - return d; - } /* else if (src[s] == 0 || src[s] == 1) { - LOGDBG("h264_nal_unescape: invalid NAL sequence 00 00 %02x %02x", src[s], src[s+1]); - return -1; - }*/ - } - dst[d++] = src[s++]; - } - return d; -} - -int h264_get_picture_type(const uint8_t *buf, int len) -{ - int i; - for (i = 0; i < len-5; i++) { - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1 && buf[i + 3] == NAL_AUD) { - uint8_t type = (buf[i + 4] >> 5); - switch (type) { - case 0: case 3: case 5: return I_FRAME; - case 1: case 4: case 6: return P_FRAME; - case 2: case 7: return B_FRAME; - default:; - } - } - } - return NO_PICTURE; -} - -int h264_get_video_size(const uint8_t *buf, int len, video_size_t *size) -{ - int i; - - /* H.264 detection, search for NAL AUD */ - if (!IS_NAL_AUD(buf)) - return 0; - - /* if I-frame, search for NAL SPS */ - if (h264_get_picture_type(buf, len) != I_FRAME) - return 0; - - /* scan video packet for sequence parameter set */ - for (i = 5; i < len-4; i++) - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1 && (buf[i + 3] & 0x1f) == NAL_SPS) { - - uint8_t nal_data[len]; - int nal_len; - - LOGDBG("H.264: Found NAL SPS at offset %d/%d", i, len); - - if (0 < (nal_len = h264_nal_unescape(nal_data, buf+i+4, len-i-4))) { - - h264_sps_data_t sps = {0}; - - if (h264_parse_sps(nal_data, nal_len, &sps)) { - size->width = sps.width; - size->height = sps.height; - memcpy(&size->pixel_aspect, &sps.pixel_aspect, sizeof(mpeg_rational_t)); - return 1; - } - LOGMSG("h264_get_video_size: not enough data ?"); - } - } - - return 0; -} - diff --git a/tools/h264.h b/tools/h264.h deleted file mode 100644 index df869e96..00000000 --- a/tools/h264.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * h264.h: H.264 bitstream decoding - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: h264.h,v 1.9 2009-06-29 15:49:43 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_H264_H_ -#define _XINELIBOUTPUT_H264_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "mpeg.h" - - -#define NAL_SPS 0x07 /* Sequence Parameter Set */ -#define NAL_AUD 0x09 /* Access Unit Delimiter */ -#define NAL_END_SEQ 0x0a /* End of Sequence */ - - -#if defined(__i386__) || defined(__x86_64__) -# define IS_NAL_SPS(buf) (*(uint32_t*)(buf) == 0x07010000U) -# define IS_NAL_AUD(buf) (*(uint32_t*)(buf) == 0x09010000U) -# define IS_NAL_END_SEQ(buf) (*(uint32_t*)(buf) == 0x0a010000U) -#else -# define IS_NAL_SPS(buf) ((buf)[0] == 0 && (buf)[1] == 0 && (buf)[2] == 1 && (buf)[3] == NAL_SPS) -# define IS_NAL_AUD(buf) ((buf)[0] == 0 && (buf)[1] == 0 && (buf)[2] == 1 && (buf)[3] == NAL_AUD) -# define IS_NAL_END_SEQ(buf) ((buf)[0] == 0 && (buf)[1] == 0 && (buf)[2] == 1 && (buf)[3] == NAL_END_SEQ) -#endif - - -typedef struct { - uint16_t width; - uint16_t height; - mpeg_rational_t pixel_aspect; - /* ... */ -} h264_sps_data_t; - -struct video_size_s; - - -/* - * input: start of NAL SPS (without 00 00 01 07) - */ -int h264_parse_sps(const uint8_t *buf, int len, h264_sps_data_t *sps); - -/* - * input: start of H.264 video data (not PES) - */ -int h264_get_picture_type(const uint8_t *buf, int len); - -/* - * input: start of H.264 video data (not PES) - */ -int h264_get_video_size(const uint8_t *buf, int len, struct video_size_s *size); - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - - -#endif /* _XINELIBOUTPUT_H264_H_ */ diff --git a/tools/http.c b/tools/http.c deleted file mode 100644 index 0e7de26a..00000000 --- a/tools/http.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * http.c: HTTP (/RTSP) helper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: http.c,v 1.7 2009-06-02 08:37:58 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#include <inttypes.h> - -#include <string.h> - -#include <vdr/config.h> -#include <vdr/tools.h> - -#include "../logdefs.h" - -#include "http.h" - -// -// cHttpReq -// - -bool cHttpReq::SetCommand(const char *Command) -{ - char *tmp = strdup(Command); - char *pt = strchr(tmp, ' '), *uri; - - m_Valid = false; - if(pt) { - *pt++ = 0; - m_Name = tmp; - - while(*pt && *pt == ' ') pt++; - - uri = pt; - pt = strrchr(uri, ' '); - if(pt) { - m_Version = pt+1; - while(*pt && *pt == ' ') *pt-- = 0; - m_Uri = uri; - m_Valid = true; - } - } - - free(tmp); - return m_Valid; -} - -cHeader *cHttpReq::Header(const char *Name) -{ - for(cHeader *i = m_Headers.First(); i; i = m_Headers.Next(i)) - if(!strcmp(Name, i->Name())) - return i; - return NULL; -} - -void cHttpReq::AddHeader(const char *Header, bool Duplicate) -{ - if(strlen(Header) < 4096) { - char *name = strdup(Header); - char *val = strchr(name, ':'); - if(val) { - *val++ = 0; - while(*val == ' ') val++; - AddHeader(name, val, Duplicate); - } - free(name); - } else { - LOGMSG("cConnState::AddHeader: header length exceeds 4096 !"); - } -} - -void cHttpReq::AddHeader(const char *Name, const char *Value, bool Duplicate) -{ - if(strlen(Name) > 64 || strlen(Value) > 4096) { - LOGMSG("cConnState::AddHeader: header length exceeds limit !"); - } else { - cHeader *h = Header(Name); - if(!Duplicate && h) - h->SetValue(Value); - else { - if(m_Headers.Count() < 50) - m_Headers.Add(new cHeader(Name, Value)); - else - LOGMSG("cConnState::AddHeader: header count exceeds 50 !"); - } - } -} - -void cHttpReq::Reset(void) -{ - m_Name = NULL; - m_Uri = NULL; - m_Version = NULL; - m_Valid = false; - m_Headers.Clear(); -} - -// -// Map file extensions to mime types -// - -static const char *mimetype(const char *ext) -{ - static const struct { - const char *ext; - const char *mime; - } ext2mime[] = { - {"avi", "video/avi"}, - {"vob", "video/mpeg"}, - {"mpg", "video/mpeg"}, - {"mpeg", "video/mpeg"}, - {"vdr", "video/mp2p"}, - - {"mp3", "audio/mp3"}, - {"flac", "audio/flac"}, - - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - {"gif", "image/gif"}, - - {NULL, NULL} - }; - - int i = -1; - while(ext2mime[++i].ext) - if(!strcmp(ext, ext2mime[i].ext)) - return ext2mime[i].mime; - return NULL; -} - -static char *unescape_uri(const char *uri) -{ - char *d = strdup(uri), *s = d, *result = d; - while(*s) { - if(s[0] == '%' && s[1] && s[2]) { - unsigned int c; - if (sscanf(s+1, "%02x", &c) == 1) { - *d++ = (char)c; - s += 3; - continue; - } - } - *d++ = *s++; - } - *d = 0; - return result; -} - -// -// cHttpStreamer -// - -cList<cHttpStreamer> cHttpStreamer::m_Streamers; - -void cHttpStreamer::CloseAll(bool OnlyFinished) -{ - if(!OnlyFinished) { - while(m_Streamers.First()) - m_Streamers.Del(m_Streamers.First()); - - } else { - /* purge finished streamers from list */ - cHttpStreamer *it = m_Streamers.First(); - while(it) { - if(it->Active()) { - it = (cHttpStreamer*)it->Next(); - } else { - m_Streamers.Del(it); - it = m_Streamers.First(); - } - } - } -} - -cHttpStreamer::cHttpStreamer(int fd_http, const char *filename, - cConnState *Request) : - m_Filename(unescape_uri(filename), true) -{ - m_fds.set_handle(fd_http); - m_fds.set_cork(true); - m_fdf = -1; - - //m_Filename = filename; - m_FileSize = -1; - m_Start = 0; - m_End = -1; - m_KeepOpen = true; - - m_ConnState = Request; - - m_Finished = false; - - CloseAll(true); - - m_Streamers.Add(this); - - if(m_Streamers.Count() > 5) { - LOGMSG("WARNING: There are %d running HTTP streamers !", m_Streamers.Count()); - if(m_Streamers.Count() > 20) { - errno = 0; - LOGERR("ERROR: There are %d running HTTP streamers, cancelling first", - m_Streamers.Count()); - m_Streamers.Del(m_Streamers.First()); - } - } - - Start(); -} - -cHttpStreamer::~cHttpStreamer() -{ - Cancel(3); - if(m_ConnState) - delete m_ConnState; - if(m_fdf >= 0) - close(m_fdf); - m_fdf = -1; -} - -void cHttpStreamer::ParseRange(const char *Range) -{ - m_Start = 0; - m_End = -1; - if(Range) { - LOGDBG("cHttpStreamer: Request range is \'%s\'", Range); - switch(sscanf(Range, "bytes=%" PRId64 "-%" PRId64, &m_Start, &m_End)) { - case 2: LOGMSG(" Range: %s (%" PRId64 " - %" PRId64 ")", Range, m_Start, m_End); - break; - case 1: m_End = -1; - LOGMSG(" Range start: %s (%" PRId64 " - )", Range, m_Start); - break; - default: - case 0: m_Start = 0; - m_End = -1; - break; - } - } -} - -bool cHttpStreamer::ParseRequest(void) -{ - cHeader *h; - - if((h = m_ConnState->Header("Range")) != NULL) - ParseRange(h->Value()); - - m_KeepOpen = false; - if((h = m_ConnState->Header("Connection")) != NULL) { - m_KeepOpen = !strcasecmp(h->Value(), "keep-alive"); - if(m_KeepOpen) - LOGDBG("cHttpStreamer: client wants to keep connection open"); - } - - return true; -} - -bool cHttpStreamer::Seek(void) -{ - if(m_fdf < 0) { - m_fdf = open(m_Filename, O_RDONLY); - if(m_fdf < 0) { - LOGERR("cHttpStreamer: error opening %s", *m_Filename); - m_fds.write_cmd(HTTP_REPLY_401); // 401 Not Found - return false; - } - - m_FileSize = lseek(m_fdf, 0, SEEK_END); - if(m_FileSize <= 0) { - LOGERR("cHttpStreamer: error seeking %s to end", *m_Filename); - m_fds.write_cmd(HTTP_REPLY_401); // 401 Not Found - return false; - } - } - - if(m_Start >= m_FileSize) { - LOGERR("cHttpStreamer: Requested range not available " - "(%s:%" PRId64 "-%" PRId64 " ; len=%" PRIu64 ")", - *m_Filename, m_Start, m_End, (uint64_t)m_FileSize); - m_fds.write_cmd(HTTP_REPLY_416); // 416 Requested Range Not Satisfiable - return false; - } - - if(m_Start > 0) { - if(m_End >= m_FileSize || m_End < 0) - m_End = m_FileSize-1; - - m_fds.write_cmd("HTTP/1.1 206 Partial Content\r\n"); - m_fds.printf("Content-Range: bytes %" PRId64 "-%" PRId64 "/%" PRIu64 "\r\n", - m_Start, m_End, (uint64_t)m_FileSize); - } else { - m_fds.write_cmd("HTTP/1.1 200 OK\r\n"); - } - - /* content type */ - const char *ext = strrchr(m_Filename, '.'); - if(ext) { - const char *mime = mimetype(ext+1); - if(mime) - m_fds.printf("Content-Type: %s\r\n", mime); - } - - /* Content-Length */ - if(m_FileSize >= 0) { - int64_t len = m_FileSize; - if(m_End >= 0) - len = m_End + 1; - if(m_Start >= 0) - len -= m_Start; - m_fds.printf("Content-Length: %" PRId64 "\r\n", len); - } - - /* Connection and end of reply */ - if(m_KeepOpen) - m_fds.write_cmd("Connection: Keep-Alive\r\n" - "\r\n"); - else - m_fds.write_cmd("Connection: Close\r\n" - "\r\n"); - - if(m_Start) - lseek(m_fdf, (off_t)m_Start, SEEK_SET); - else - lseek(m_fdf, 0, SEEK_SET); - - return true; -} - -bool cHttpStreamer::ReadPipelined(void) -{ - char buf[2048]; - int r; - - if(m_ConnState) - delete m_ConnState; - m_ConnState = new cConnState; - - do { - r = m_fds.readline(buf, sizeof(buf), 1000); - if(r < 0 || errno == EAGAIN || r >= (int)sizeof(buf)) { - LOGMSG("cHttpStreamer: disconnected"); - return false; - } - - LOGMSG("cHttpStreamer: pipelined request: %s", buf); - - if(!*m_ConnState->Name()) { - if(!m_ConnState->SetCommand(buf) || - strcmp(m_ConnState->Name(), "GET") || - strncmp(m_ConnState->Uri(), "/PLAYFILE", 9) || - strncmp(m_ConnState->Version(), "HTTP/1.", 7)) { - LOGMSG("Incorrect HTTP request: %s", buf); - return false; - } - } - else if(r > 0) - m_ConnState->AddHeader(buf); - } while(r>0); - - return true; -} - -void cHttpStreamer::Action(void) -{ - int n = 0; - cxPoller p(m_fds); - bool Disc = !(ParseRequest() && Seek()); - uint64_t pos = m_Start; - off_t start = (off_t)m_Start; - - while(Running() && !Disc) { - - n = m_End>0 ? (m_End-start+1) : m_FileSize - start; - if(n > 0) { - errno = 0; - pthread_testcancel(); - n = m_fds.sendfile(m_fdf, &start, n); - pthread_testcancel(); - if(n <= 0) { - if(errno == EAGAIN || errno == EINTR) { - p.Poll(100); - pthread_testcancel(); - } else { - LOGERR("cHttpStreamer: sendfile() failed"); - Disc=true; - } - } else if(n == 0) { - LOGMSG("cHttpStreamer: disconnected at %" PRId64, (int64_t)start); - Disc = true; - } - continue; - } - - LOGDBG("cHttpStreamer: Hit to EOF or end of requested range"); - - m_fds.flush_cork(); - - if(!m_KeepOpen) { - LOGMSG("cHttpStreamer: disconnecting (request complete)"); - Disc = true; - continue; - } - - // keep connection open for new range for max. 30 sec - n = 30; - do { - pthread_testcancel(); - //cxPoller p(m_fds); - LOGDBG("cHttpStreamer: Request complete, waiting..."); - if(p.Poll(1000)) { - LOGDBG("cHttpStreamer: Reading pipelined request"); - pthread_testcancel(); - Disc = !(ReadPipelined() && ParseRequest() && Seek()); - pos = m_Start; - } - } while(--n && Running() && !Disc); - - if(n <= 0) { - LOGMSG("cHttpStreamer: Disconnecting (timeout)"); - Disc = true; - } - } - - close(m_fdf); - m_fdf = -1; - - m_fds.close(); - - m_Finished = true; -} diff --git a/tools/http.h b/tools/http.h deleted file mode 100644 index 2adcf8e3..00000000 --- a/tools/http.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * http.h: HTTP (/RTSP) helper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: http.h,v 1.5 2007-01-07 09:45:48 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_HTTP_H_ -#define XINELIBOUTPUT_HTTP_H_ - -#include <vdr/tools.h> - - -#define HTTP_REPLY_401 \ - "HTTP/1.1 401 Unauthorized\r\n" \ - "Connection: Close\r\n" \ - "\r\n" - -#define HTTP_REPLY_404 \ - "HTTP/1.1 404 Not Found\r\n" \ - "Connection: Close\r\n" \ - "\r\n" - -#define HTTP_REPLY_416 \ - "HTTP/1.1 416 Requested Range Not Satisfiable\r\n" \ - "Connection: Close\r\n" \ - "\r\n" - -#define HTTP_REPLY_200_PRIMARY \ - "HTTP/1.1 200 OK\r\n" \ - "Content-Type: video/mpeg\r\n" \ - "Connection: Close\r\n" \ - "\r\n" -//"Content-Type: video/mp2p\r\n" - - -// -// cHeader -// - -class cHeader : public cListObject -{ - protected: - cString m_Name; - cString m_Value; - - private: - cHeader(); - - public: - cHeader(const char *Name, const char *Value) : - m_Name(Name), m_Value(Value) {}; - - const cString& Name(void) { return m_Name; } - const cString& Value(void) { return m_Value; } - int IntValue(void) { return *m_Value?atoi(m_Value):-1; } - void SetValue(const char *Value) { m_Value = Value; } -}; - - -// -// cHttpReq -// - -class cHttpReq -{ - private: - cString m_Name; - cString m_Uri; - cString m_Version; - cList<cHeader> m_Headers; - - bool m_Valid; - - public: - cHttpReq() : m_Valid(false) {} - - bool SetCommand(const char *Command); - const cString& Name(void) { return m_Name; } - const cString& Uri(void) { return m_Uri; } - const cString& Version(void) { return m_Version; } - bool Valid(void) { return m_Valid; } - - void AddHeader(const char *Header, bool Duplicate=false); - void AddHeader(const char *Name, const char *Value, bool Duplicate=false); - cHeader *Header(const char *Name); - - void Reset(void); -}; - - -// -// cConnState -// - -class cConnState : public cHttpReq -{ - public: -}; - - -// -// cHttpStreamer -// - -#include <vdr/tools.h> -#include <vdr/thread.h> - -#include "cxsocket.h" - -class cHttpStreamer : protected cListObject, cThread -{ - public: - cHttpStreamer(int fd_http, const char *filename, cConnState *Request); - virtual ~cHttpStreamer(); - - static void CloseAll(bool OnlyFinished = false); - - private: - static cList<cHttpStreamer> m_Streamers; - - cxSocket m_fds; - int m_fdf; - - cString m_Filename; - int64_t m_FileSize; - int64_t m_Start; - int64_t m_End; - bool m_KeepOpen; - - cConnState *m_ConnState; - - bool m_Finished; - - virtual void Action(void); - - bool ParseRequest(void); - void ParseRange(const char *Range); - bool ReadPipelined(void); - bool Seek(void); -}; - -#endif // XINELIBOUTPUT_HTTP_H_ - diff --git a/tools/iso639.h b/tools/iso639.h deleted file mode 100644 index ae30fa0e..00000000 --- a/tools/iso639.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * iso639.h: iso-639-1 <-> iso-639-2 language code translations - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: iso639.h,v 1.4 2009-05-29 14:25:06 phintuka Exp $ - * - */ - -#ifndef __ISO_639_H -#define __ISO_639_H - -static const struct { - const char iso639_2[4]; - const char iso639_1[4]; -} ISO639_map[] = -{ - {"???", "??"}, - {"abk", "ab"}, - {"aar", "aa"}, - {"afr", "af"}, - {"alb", "sq"}, - {"amh", "am"}, - {"ara", "ar"}, - {"arm", "hy"}, - {"ast", "as"}, - {"aym", "ay"}, - {"aze", "az"}, - {"bak", "ba"}, - {"baq", "eu"}, - {"bel", "be"}, - {"ben", "bn"}, - {"bih", "bh"}, - {"bis", "bi"}, - {"bre", "br"}, - {"bul", "bg"}, - {"bur", "my"}, - {"cat", "ca"}, - {"chi", "zh"}, - {"cos", "co"}, - {"scr", "hr"}, - {"cze", "cs"}, - {"dan", "da"}, - {"dut", "nl"}, - {"dzo", "dz"}, - {"eng", "en"}, - {"epo", "eo"}, - {"est", "et"}, - {"fao", "fo"}, - {"fij", "fj"}, - {"fin", "fi"}, - {"fre", "fr"}, - {"fry", "fy"}, - {"glg", "gl"}, - {"geo", "ka"}, - {"ger", "de"}, - {"gre", "el"}, - {"grn", "gn"}, - {"guj", "gu"}, - {"hau", "ha"}, - {"heb", "he"}, - {"heb", "iw"}, - {"hin", "hi"}, - {"hun", "hu"}, - {"ice", "is"}, - {"ind", "id"}, - {"ina", "ia"}, - {"iku", "iu"}, - {"ipk", "ik"}, - {"gle", "ga"}, - {"ita", "it"}, - {"jpn", "ja"}, - {"jav", "jv"}, - {"kal", "kl"}, - {"kan", "kn"}, - {"kas", "ks"}, - {"kaz", "kk"}, - {"khm", "km"}, - {"kin", "rw"}, - {"kir", "ky"}, - {"kor", "ko"}, - {"kur", "ku"}, - {"lao", "lo"}, - {"lat", "la"}, - {"lav", "lv"}, - {"lin", "ln"}, - {"lit", "lt"}, - {"mac", "mk"}, - {"mlg", "mg"}, - {"may", "ms"}, - {"mlt", "ml"}, - {"mao", "mi"}, - {"mar", "mr"}, - {"mol", "mo"}, - {"mon", "mn"}, - {"nau", "na"}, - {"nep", "ne"}, - {"nor", "no"}, - {"oci", "oc"}, - {"ori", "or"}, - {"orm", "om"}, - {"per", "fa"}, - {"pol", "pl"}, - {"por", "pt"}, - {"pus", "ps"}, - {"que", "qu"}, - {"roh", "rm"}, - {"rum", "ro"}, - {"run", "rn"}, - {"rus", "ru"}, - {"smo", "sm"}, - {"sag", "sg"}, - {"san", "sa"}, - {"srp", "sr"}, - {"scr", "sh"}, - {"sna", "sn"}, - {"snd", "sd"}, - {"sin", "si"}, - {"slo", "sk"}, - {"slv", "sl"}, - {"som", "so"}, - {"sot", "st"}, - {"spa", "es"}, - {"sun", "su"}, - {"swa", "sw"}, - {"ssw", "ss"}, - {"swe", "sv"}, - {"tgl", "tl"}, - {"tgk", "tg"}, - {"tam", "ta"}, - {"tat", "tt"}, - {"tel", "te"}, - {"tha", "th"}, - {"tib", "bo"}, - {"tir", "ti"}, - {"tog", "to"}, - {"tso", "ts"}, - {"tsn", "tn"}, - {"tur", "tr"}, - {"tuk", "tk"}, - {"twi", "tw"}, - {"uig", "ug"}, - {"ukr", "uk"}, - {"urd", "ur"}, - {"uzb", "uz"}, - {"vie", "vi"}, - {"vol", "vo"}, - {"wel", "cy"}, - {"wol", "wo"}, - {"xho", "xh"}, - {"yid", "yi"}, - {"yor", "yo"}, - {"zha", "za"}, - {"zul", "zu"}, -}; - -static const char *iso639_2_to_iso639_1(const char *lang) -{ - if (lang && lang[0]) { - if (lang[1] && !lang[2]) { - for (unsigned int i = 0 ; i < sizeof(ISO639_map) / sizeof(ISO639_map[0]); i++) - if (!memcmp(ISO639_map[i].iso639_1, lang, 2)) - return ISO639_map[i].iso639_2; - LOGMSG("Unknown iso639-2 code: %s", lang); - } - return lang; - } - return NULL; -} - -static const char *iso639_1_to_iso639_2(const char *lang) -{ - if (lang && lang[0]) { - if (lang[1] && lang[2] && !lang[3]) { - for (unsigned int i = 0 ; i < sizeof(ISO639_map) / sizeof(ISO639_map[0]); i++) - if (!memcmp(ISO639_map[i].iso639_2, lang, 3)) - return ISO639_map[i].iso639_1; - LOGMSG("Unknown iso639-1 code: %s", lang); - } - return lang; - } - return NULL; -} - -#endif diff --git a/tools/listiter.h b/tools/listiter.h deleted file mode 100644 index 9c88940e..00000000 --- a/tools/listiter.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * listiter.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: listiter.h,v 1.1 2006-06-03 10:04:27 phintuka Exp $ - * - */ - - -#ifndef _LISTITER_H_ -#define _LISTITER_H_ - -//------------------------------ list ---------------------------------------- - -template <class LIST,class ITEM, class RESULT> -void ForEach(LIST& List, RESULT (ITEM::*f)()) -{ - for(ITEM *it = List.First(); it; it = List.Next(it)) - (*it.*f)(); -} - -template <class LIST,class ITEM, class ARG1, class RESULT> -void ForEach(LIST& List, RESULT (ITEM::*f)(ARG1), ARG1 arg1) -{ - for(ITEM *it = List.First(); it; it = List.Next(it)) - (*it.*f)(arg1); -} - -template <class LIST,class ITEM, class ARG1, class ARG2> -void ForEach(LIST& List, void (ITEM::*f)(ARG1,ARG2), ARG1 arg1, ARG2 arg2) -{ - for(ITEM *it = List.First(); it; it = List.Next(it)) - (*it.*f)(arg1,arg2); -} - -template <class LIST,class ITEM, class ARG1, class RESULT> -RESULT ForEach(LIST& List, RESULT (ITEM::*f)(ARG1), ARG1 arg1, - RESULT (*combiner)(RESULT,RESULT), RESULT def) -{ - RESULT result = def; - for(ITEM *it = List.First(); it; it = List.Next(it)) - result = (*combiner)((*it.*f)(arg1),result); - return result; -} - -template <class LIST,class ITEM, class ARG1, class ARG2, class RESULT> -RESULT ForEach(LIST& List, RESULT (ITEM::*f)(ARG1,ARG2), - ARG1 arg1, ARG2 arg2, - RESULT (*combiner)(RESULT,RESULT), RESULT def) -{ - RESULT result = def; - for(ITEM *it = List.First(); it; it = List.Next(it)) - result = (*combiner)((*it.*f)(arg1,arg2),result); - return result; -} - -template <class LIST,class ITEM, class ARG1, class ARG2, class ARG3, - class RESULT> -RESULT ForEach(LIST& List, RESULT (ITEM::*f)(ARG1,ARG2,ARG3), - ARG1 arg1, ARG2 arg2, ARG3 arg3, - RESULT (*combiner)(RESULT,RESULT), RESULT def) -{ - RESULT result = def; - for(ITEM *it = List.First(); it; it = List.Next(it)) - result = (*combiner)((*it.*f)(arg1,arg2,arg3),result); - return result; -} - -template<class T> -T mmin(T a, T b) {return a<b ? a : b;} - -template<class T> -T mmax(T a, T b) {return a>b ? a : b;} - -template<class T> -T mand(T a, T b) {return a&&b;} - -template<class T> -T mor(T a, T b) {return a||b;} - -#endif diff --git a/tools/metainfo_menu.c b/tools/metainfo_menu.c deleted file mode 100644 index 01d97f30..00000000 --- a/tools/metainfo_menu.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * metainfo_menu.c: Media file info menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: metainfo_menu.c,v 1.7 2008-11-20 15:44:37 phintuka Exp $ - * - */ - -#include "../features.h" - -#ifdef HAVE_LIBEXTRACTOR -# include <extractor.h> -#endif - -#include <vdr/status.h> -#include <vdr/i18n.h> - -#include "../config.h" - -#include "metainfo_menu.h" - -// -// cMetainfoMenu -// - -cMetainfoMenu::cMetainfoMenu(cString Filename) : - cOsdMenu(Filename), - m_Filename(Filename) -{ - const char *Title = strrchr(Filename, '/'); - if(Title && *(Title+1)) - SetTitle(Title+1); -} - -cMetainfoMenu::~cMetainfoMenu() -{ -} - -void cMetainfoMenu::Display(void) -{ - cOsdMenu::Display(); - char metadata[4096]; - metadata[0] = 0; - -#ifdef HAVE_LIBEXTRACTOR - EXTRACTOR_ExtractorList * plugins; - EXTRACTOR_KeywordList * md_list; - plugins = EXTRACTOR_loadDefaultLibraries(); - md_list = EXTRACTOR_getKeywords(plugins, m_Filename); - md_list = EXTRACTOR_removeEmptyKeywords (md_list); - md_list = EXTRACTOR_removeDuplicateKeywords(md_list, 0); - md_list = EXTRACTOR_removeKeywordsOfType(md_list, EXTRACTOR_THUMBNAILS); - - const char *key; - char * buf; - while(md_list) { - if((key=EXTRACTOR_getKeywordTypeAsString(md_list->keywordType))) { - buf = strdup(md_list->keyword); - sprintf(metadata, "%s%s: %s\n", metadata, key, buf); - free(buf); - } - md_list=md_list->next; - } - EXTRACTOR_freeKeywords(md_list); - EXTRACTOR_removeAll(plugins); /* unload plugins */ -#else - cString cmd; - if(xc.IsPlaylistFile(m_Filename)) - cmd = cString::sprintf("file -b '%s'; cat '%s'", *m_Filename, *m_Filename); - else if(xc.IsAudioFile(m_Filename)) - cmd = cString::sprintf("mp3info -x '%s' ; file -b '%s'", *m_Filename, *m_Filename); - else if(xc.IsVideoFile(m_Filename)) - cmd = cString::sprintf("file -b '%s'; midentify '%s'", *m_Filename, *m_Filename); - else if(xc.IsImageFile(m_Filename)) - cmd = cString::sprintf("file -b '%s'; identify '%s'", *m_Filename, *m_Filename); - else - cmd = cString::sprintf("file -b '%s'", *m_Filename); - - cPipe p; - if(p.Open(*cmd, "r")) { - int n = fread(metadata, 1, sizeof(metadata)-1, p); - if(n>0) { - metadata[n] = 0; - strreplace(metadata, ',', '\n'); - } - } -#endif - DisplayMenu()->SetText(metadata, false); - cStatus::MsgOsdTextItem(cString::sprintf("%s\n%s", tr("Metainfo"), *m_Filename)); -} - -eOSState cMetainfoMenu::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - return state; -} diff --git a/tools/metainfo_menu.h b/tools/metainfo_menu.h deleted file mode 100644 index 45d60f22..00000000 --- a/tools/metainfo_menu.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * metainfo_menu.h: Media file info menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: metainfo_menu.h,v 1.1 2008-05-07 13:27:15 phintuka Exp $ - * - */ - -#ifndef __XINELIB_INFO_MENU_H_ -#define __XINELIB_INFO_MENU_H_ - -// -// cMetainfoMenu -// - -#include <vdr/osdbase.h> - -class cMetainfoMenu : public cOsdMenu -{ - protected: - - cString m_Filename; - - public: - - cMetainfoMenu(cString Filename); - virtual ~cMetainfoMenu(); - - virtual void Display(void); - - // cOsdMenu - virtual eOSState ProcessKey(eKeys Key); - -}; - -#endif // __XINELIB_INFO_MENU_H_ diff --git a/tools/mpeg.c b/tools/mpeg.c deleted file mode 100644 index b827e096..00000000 --- a/tools/mpeg.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * mpeg.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: mpeg.c,v 1.3 2009-02-16 16:03:18 phintuka Exp $ - * - */ - -#include <inttypes.h> -#include <string.h> - -#include "mpeg.h" - - -const char * const picture_type_str[] = { - "(none)", - "I-Frame", - "B-Frame", - "P-Frame" -}; - -int mpeg2_get_picture_type(const uint8_t *buf, int len) -{ - int i; - for (i = 0; i < len-5; i++) { - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) { - switch (buf[i + 3]) { - case SC_PICTURE: - return (buf[i + 5] >> 3) & 0x07; - } - } - } - return NO_PICTURE; -} - -int mpeg2_get_video_size(const uint8_t *buf, int len, video_size_t *size) -{ - int i; - for (i = 0; i < len-6; i++) { - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) { - if (buf[i + 3] == SC_SEQUENCE) { - static const mpeg_rational_t mpeg2_aspect[16] = { - {0,1}, {1,1}, {4,3}, {16,9}, {221,100}, - {0,1}, {0,1}, {0,1}, { 0,1}, { 0,1}, - {0,1}, {0,1}, {0,1}, { 0,1}, { 0,1}, - {0,1}, - }; - - int d = (buf[i+4] << 16) | (buf[i+5] << 8) | buf[i+6]; - int a = buf[i+7] >> 4; - - size->width = (d >> 12); - size->height = (d & 0xfff); - - memcpy(&size->pixel_aspect, &mpeg2_aspect[a], sizeof(mpeg_rational_t)); - size->pixel_aspect.num *= size->height; - size->pixel_aspect.den *= size->width; - - return 1; - } - } - } - return 0; -} - diff --git a/tools/mpeg.h b/tools/mpeg.h deleted file mode 100644 index 8a9b6493..00000000 --- a/tools/mpeg.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * mpeg.h: MPEG definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: mpeg.h,v 1.6 2009-02-16 16:03:18 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_MPEG_H_ -#define XINELIBOUTPUT_MPEG_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - - -#define SC_PICTURE 0x00 /* picture atart code */ -#define SC_SEQUENCE 0xb3 /* sequence header */ - -/* Picture types */ -#define NO_PICTURE 0 -#define I_FRAME 1 -#define P_FRAME 2 -#define B_FRAME 3 - -typedef struct mpeg_rational_s { - int num; - int den; -} mpeg_rational_t; - -typedef struct video_size_s { - uint16_t width; - uint16_t height; - mpeg_rational_t pixel_aspect; -} video_size_t; - -extern const char * const picture_type_str[]; - -/* - * input: start of MPEG video data (not PES) - */ -int mpeg2_get_picture_type(const uint8_t *buf, int len); - -/* - * input: start of MPEG video data (not PES) - */ -int mpeg2_get_video_size(const uint8_t *buf, int len, video_size_t *size); - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - - -#endif diff --git a/tools/pes.c b/tools/pes.c deleted file mode 100644 index 14773f2e..00000000 --- a/tools/pes.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * pes.h: PES header definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: pes.c,v 1.10 2009-07-01 09:31:17 phintuka Exp $ - * - */ - -#include <inttypes.h> -#include <string.h> - -#include "../logdefs.h" - -#include "mpeg.h" -#include "h264.h" - -#include "pes.h" - - -int64_t pes_get_pts(const uint8_t *buf, int len) -{ - /* assume mpeg2 pes header ... */ - if (IS_VIDEO_PACKET(buf) || IS_AUDIO_PACKET(buf)) { - - if ((buf[6] & 0xC0) != 0x80) - return NO_PTS; - if ((buf[6] & 0x30) != 0) - return NO_PTS; - - if ((len > 13) && (buf[7] & 0x80)) { /* pts avail */ - int64_t pts; - pts = ((int64_t)(buf[ 9] & 0x0E)) << 29 ; - pts |= ((int64_t) buf[10]) << 22 ; - pts |= ((int64_t)(buf[11] & 0xFE)) << 14 ; - pts |= ((int64_t) buf[12]) << 7 ; - pts |= ((int64_t)(buf[13] & 0xFE)) >> 1 ; - return pts; - } - } - return NO_PTS; -} - -int64_t pes_get_dts(const uint8_t *buf, int len) -{ - if (IS_VIDEO_PACKET(buf) || IS_AUDIO_PACKET(buf)) { - - if ((buf[6] & 0xC0) != 0x80) - return NO_PTS; - if ((buf[6] & 0x30) != 0) - return NO_PTS; - - if (len > 18 && (buf[7] & 0x40)) { /* dts avail */ - int64_t dts; - dts = ((int64_t)( buf[14] & 0x0E)) << 29 ; - dts |= (int64_t)( buf[15] << 22 ); - dts |= (int64_t)((buf[16] & 0xFE) << 14 ); - dts |= (int64_t)( buf[17] << 7 ); - dts |= (int64_t)((buf[18] & 0xFE) >> 1 ); - return dts; - } - } - return NO_PTS; -} - -void pes_change_pts(uint8_t *buf, int len, int64_t new_pts) -{ - /* assume mpeg2 pes header ... Assume header already HAS pts */ - if (IS_VIDEO_PACKET(buf) || IS_AUDIO_PACKET(buf)) { - - if ((buf[6] & 0xC0) != 0x80) - return; - if ((buf[6] & 0x30) != 0) - return; - - if ((len > 13) && (buf[7] & 0x80)) { /* pts avail */ - buf[ 9] = ((new_pts >> 29) & 0x0E) | (buf[ 9] & 0xf1); - buf[10] = ((new_pts >> 22) & 0xFF); - buf[11] = ((new_pts >> 14) & 0xFE) | (buf[11] & 0x01); - buf[12] = ((new_pts >> 7 ) & 0xFF); - buf[13] = ((new_pts << 1 ) & 0xFE) | (buf[13] & 0x01); - } - } -} - -int pes_strip_pts_dts(uint8_t *buf, int size) -{ - if(size > 13 && buf[7] & 0x80) { /* pts avail */ - int n = 5; - int pes_len = (buf[4] << 8) | buf[5]; - if ((buf[6] & 0xC0) != 0x80) - return size; - if ((buf[6] & 0x30) != 0) /* scrambling control */ - return size; - /* dts too ? */ - if(size > 18 && buf[7] & 0x40) - n += 5; - pes_len -= n; /* update packet len */ - buf[4] = pes_len >> 8; /* packet len (hi) */ - buf[5] = pes_len & 0xff; /* packet len (lo) */ - buf[7] &= 0x3f; /* clear pts and dts flags */ - buf[8] -= n; /* update header len */ - memmove(buf+4+n, buf+9+n, size-9-n); - return size - n; - } - return size; -} - -int pes_is_frame_h264(const uint8_t *buf, int len) -{ - if (len < 9 || len < 9 + buf[8]) - return 0; - if ( (buf[6] & 0xC0) != 0x80) /* MPEG 2 PES */ - return 0; - - buf += 9 + buf[8]; - - if (IS_NAL_AUD(buf)) - return 1; - return 0; -} - -uint8_t pes_get_picture_type(const uint8_t *buf, int len) -{ - int i = PES_HEADER_LEN(buf); - - buf += i; - len -= i; - - if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) { - if (buf[3] == NAL_AUD) - return h264_get_picture_type(buf, len); - return mpeg2_get_picture_type(buf, len); - } - - return NO_PICTURE; -} - -int pes_get_video_size(const uint8_t *buf, int len, video_size_t *size, int h264) -{ - int i = PES_HEADER_LEN(buf); - - buf += i; - len -= i; - - if (h264 || IS_NAL_AUD(buf)) - return h264_get_video_size(buf, len, size); - - return mpeg2_get_video_size(buf, len, size); -} - diff --git a/tools/pes.h b/tools/pes.h deleted file mode 100644 index d25374a7..00000000 --- a/tools/pes.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * pes.h: PES header definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: pes.h,v 1.13 2009-07-01 09:56:26 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_PES_H_ -#define _XINELIBOUTPUT_PES_H_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * Constants - */ - -#define PES_CHUNK_SIZE 2048 - -#define MAX_SCR ((int64_t)0x1ffffffffLL) - -#define NO_PTS (INT64_C(-1)) - -/* PES PIDs */ -#define PRIVATE_STREAM1 0xBD -#define PADDING_STREAM 0xBE -#define PRIVATE_STREAM2 0xBF -#define AUDIO_STREAM_S 0xC0 /* 1100 0000 */ -#define AUDIO_STREAM_E 0xDF /* 1101 1111 */ -#define VIDEO_STREAM_S 0xE0 /* 1110 0000 */ -#define VIDEO_STREAM_E 0xEF /* 1110 1111 */ - -#define AUDIO_STREAM_MASK 0x1F /* 0001 1111 */ -#define VIDEO_STREAM_MASK 0x0F /* 0000 1111 */ -#define AUDIO_STREAM 0xC0 /* 1100 0000 */ -#define VIDEO_STREAM 0xE0 /* 1110 0000 */ - -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -#define IS_VIDEO_PACKET(data) (VIDEO_STREAM == ((data)[3] & ~VIDEO_STREAM_MASK)) -#define IS_MPEG_AUDIO_PACKET(data) (AUDIO_STREAM == ((data)[3] & ~AUDIO_STREAM_MASK)) -#define IS_PS1_PACKET(data) (PRIVATE_STREAM1 == (data)[3]) -#define IS_PADDING_PACKET(data) (PADDING_STREAM == (data)[3]) -#define IS_AUDIO_PACKET(data) (IS_MPEG_AUDIO_PACKET(data) || IS_PS1_PACKET(data)) - -#define PES_HAS_PTS(data) ((data)[7] & 0x80) -#define PES_HAS_DTS(data) ((data)[7] & 0x40) - -#define DATA_IS_PES(data) (!(data)[0] && !(data)[1] && (data)[2] == 1) - -#define PES_HEADER_LEN(data) (8 + (data)[8] + 1) - - -/* - * timestamps - */ - -static inline int pts_to_ms(int64_t pts) { return (int)(pts/INT64_C(90)); } -static inline int64_t ms_to_pts(int ms) { return ((int64_t)(ms)) * INT64_C(90); } - -int64_t pes_get_pts(const uint8_t *buf, int len); -int64_t pes_get_dts(const uint8_t *buf, int len); -void pes_change_pts(uint8_t *buf, int len, int64_t new_pts); -int pes_strip_pts_dts(uint8_t *buf, int len); - -/* - * payload - */ - -struct video_size_s; - -int pes_is_frame_h264(const uint8_t *buf, int len); -uint8_t pes_get_picture_type(const uint8_t *buf, int len); -int pes_get_video_size(const uint8_t *buf, int len, struct video_size_s *size, int h264); - -static inline int pes_is_mpeg1(const uint8_t *header) -{ - if (IS_VIDEO_PACKET(header) || IS_AUDIO_PACKET(header)) - return ((header[6] & 0xC0) != 0x80); - if (header[3] == 0xBA) - return ((header[4] & 0x40) == 0); /* mpeg1 */ - return 0; -} - -/* - * Extract PES packet length - */ - -static inline int pes_packet_len(const uint8_t *data, const int len) -{ - if (IS_VIDEO_PACKET(data) || IS_AUDIO_PACKET(data)) { - return 6 + (data[4] << 8 | data[5]); - } else if (data[3] == PADDING_STREAM) { - return 6 + (data[4] << 8 | data[5]); - } else if (data[3] == 0xBA) { - if ((data[4] & 0x40) == 0) /* mpeg1 */ - return 12; - else /* mpeg 2 */ - return 14 + (data[0xD] & 0x07); - } else if (data[3] <= 0xB9) { - return -3; - } - return -(6 + (data[4] << 8 | data[5])); -} - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - -#endif /* _XINELIBOUTPUT_PES_H_ */ diff --git a/tools/playlist.c b/tools/playlist.c deleted file mode 100644 index e227b9c9..00000000 --- a/tools/playlist.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * playlist.c: Media player playlist - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: playlist.c,v 1.23 2009-06-02 08:36:16 phintuka Exp $ - * - */ - -#include "../features.h" - -#include <stdlib.h> - -#ifdef HAVE_LIBEXTRACTOR -# include <extractor.h> - // libextractor 0.5.20 (2008-03-20) adds support for track numbers -# if EXTRACTOR_VERSION < 0x00052000 -# warning libextractor version too old (0.5.20 required for track numbers) -# undef HAVE_LIBEXTRACTOR -# endif -#endif - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/thread.h> - -#include "../config.h" - -#include "playlist.h" - -#include "../logdefs.h" - - -#ifndef PLAYLIST_CACHE -# define PLAYLIST_CACHE ".xineliboutput-playlist.pls" -#endif - -#define MAX_PLAYLIST_FILES 1024 - -static void strip_extension(cString& fname) -{ - const char *ext = strrchr(fname, '.'); - if (ext) - fname.Truncate(ext - fname); -} - -// -// cPlaylistItem -// - -cPlaylistItem::cPlaylistItem(const char *filename) -{ - const char *pt; - - Filename = filename; - Position = -1; - - if(NULL != (pt = strrchr(filename, '/'))) - Title = pt + 1; - else - Title = filename; - - strip_extension(Title); -} - -cPlaylistItem::cPlaylistItem(const char *filename, - const char *path, - const char *title, - int position) -{ - if(path[strlen(path)-1] != '/') - Filename = cString::sprintf("%s/%s", path, filename); - else - Filename = cString::sprintf("%s%s", path, filename); - Position = position; - Title = title ?: filename; - - if (!title) - strip_extension(Title); -} - -int cPlaylistItem::Compare(const cListObject &ListObject) const -{ - ///< Must return 0 if this object is equal to ListObject, a positive value - ///< if it is "greater", and a negative value if it is "smaller". - - const cPlaylistItem *o = (cPlaylistItem *)&ListObject; - - // Use Position (if defined in playlist file) - // compare as unsigned --> -1 goes to last position - if(Position != o->Position) - return ((unsigned int)Position) > ((unsigned int)o->Position) ? 1 : -1; - - // same position (or no positions definend) -> alphabetical order -#if 0 - return strcmp(Title, o->Title); -#else - // use filename, because: - // - implicit playlist has no track names available when sorting - // (track names are read during playback), so track name is - // just file name without path. - // using full path allows sorting of each album and tracks inside albums... - // - "normal" playlist is ordered using Position, - // so track names are never compared anyway ... - return strcmp(Filename, o->Filename); -#endif -} - - -// -// cID3Scanner -// - -#ifndef HAVE_LIBEXTRACTOR -static const char *shell_escape(char *buf, int buflen, const cString& src, char ch) -{ - const char *pt = *src; - int n = 0; - - if(pt) { - while(*pt && n < buflen-2) { - if(*pt == ch || *pt == '\\' /*|| *pt == '\"' || *pt == '\''*/) { - buf[n++] = '\\'; - } - buf[n++] = *pt++; - } - buf[n] = 0; - return buf; - } - return ""; -} -#endif - -class cID3Scanner : public cThread -{ - public: - cPlaylist& m_List; - cID3Scanner(cPlaylist& List) : cThread("Metadata scanner"), m_List(List), m_Done(false) {}; - - void CancelScanner(void) { Cancel(3); } - - private: - bool m_Done; - - virtual void Action(void) - { - cPlaylistItem *Item = NULL; - unsigned int Version = 0; - const int priority = 10; - errno = 0; - if((nice(priority) == -1) && errno) - LOGDBG("ID3Scanner: Can't nice to value: %d", priority); - - LOGDBG("ID3Scanner Started"); - while(Running()) { - - cMutexLock ml(&m_List.m_Lock); - - if(Version < m_List.m_Version) { - // restart after sort, add, del - Item = NULL; - Version = m_List.m_Version; - } - - if(!(Item = m_List.Next(Item))) - break; - - if(xc.IsAudioFile(Item->Filename)) { - LOGDBG("Scanning metainfo for file %s", *Item->Filename); -#ifdef HAVE_LIBEXTRACTOR - EXTRACTOR_ExtractorList * plugins; - EXTRACTOR_KeywordList * md_list; - plugins = EXTRACTOR_loadDefaultLibraries(); - md_list = EXTRACTOR_getKeywords(plugins, *Item->Filename); - const char *key; - while(md_list) { - if ((key=EXTRACTOR_getKeywordTypeAsString(md_list->keywordType))) { - if (!strcasecmp(key,"title")) - Item->Title = md_list->keyword; - else if (!strcasecmp(key,"artist")) - Item->Artist = md_list->keyword; - else if (!strcasecmp(key,"album")) - Item->Album = md_list->keyword; - else if (!strcasecmp(key,"track number")) - Item->Tracknumber = cString::sprintf("%s%s", strlen(md_list->keyword) == 1 ? "0" : "", md_list->keyword); - md_list=md_list->next; - } - } - EXTRACTOR_freeKeywords(md_list); - EXTRACTOR_removeAll(plugins); /* unload plugins */ -#else - char buf[4096]; - cString Cmd = ""; - if(!strcasecmp((Item->Filename) + strlen(Item->Filename) - 5, ".flac")) - Cmd = cString::sprintf("metaflac " - " --show-tag=TITLE " - " --show-tag=ALBUM " - " --show-tag=ARTIST " - " --show-tag=TRACKNUMBER " - " \"%s\"", - shell_escape(buf, sizeof(buf)-1, Item->Filename, '\"')); - else - Cmd = cString::sprintf("mp3info -p \"" - "ARTIST=%%a\\r\\n" - "ALBUM=%%l\\r\\n" - "TITLE=%%t\\r\\n" - "TRACKNUMBER=%%n\\r\\n\"" - " \"%s\"", - shell_escape(buf, sizeof(buf)-1, Item->Filename, '\"')); - - cPipe p; - if(p.Open(*Cmd, "r")) { - cReadLine r; - char *pt; - while(NULL != (pt = r.Read(p))) { - if(!strncasecmp(pt, "ARTIST=", 7) && strlen(pt) > 8) - Item->Artist = (pt+7); - else if(!strncasecmp(pt, "ALBUM=", 6) && strlen(pt) > 7) - Item->Album = (pt+6); - else if(!strncasecmp(pt, "TITLE=", 6) && strlen(pt) > 7) - Item->Title = (pt+6); - else if(!strncasecmp(pt, "TRACKNUMBER=", 12) && strlen(pt) > 12) - Item->Tracknumber = cString::sprintf("%s%s", strlen(pt) == 13 ? "0" : "", (pt+12)); - } - } -#endif - } - } - LOGDBG("ID3Scanner Done."); - - m_List.PlaylistChanged(Item); - m_Done = true; - } -}; - -// -// cPlaylistReader -// - -class cPlaylistReader -{ - private: - cPlaylist& m_Playlist; - - protected: - cString m_Title; - int m_Position; - - cPlaylistItem *Prev(void) { return m_Playlist.Last(); } - - public: - cPlaylistReader(cPlaylist& Playlist) : m_Playlist(Playlist) {} - virtual ~cPlaylistReader() {} - - virtual char *Parse(char *line) = 0; - - void ResetCache(void) { m_Title = NULL; m_Position = -1; } - const char *Title(void) { return m_Title; } - int Position(void) { return m_Position; } -}; - -class cM3uReader : public cPlaylistReader -{ - public: - cM3uReader(cPlaylist& Playlist) : cPlaylistReader(Playlist), m_Next(1) {} - - protected: - int m_Next; - virtual char *Parse(char *line) { - if(!*line) - return NULL; - if(*line == '#') { - if(!strncmp(line, "#EXTINF:", 8)) { - int len = -1; - sscanf(line+8,"%d", &len); - while(*line && *line != ',') - line++; - m_Title = *line ? (line+1) : NULL; - m_Position = m_Next++; - } - return NULL; - } - return *line ? line : NULL; - } -}; - -class cPlsReader : public cPlaylistReader -{ - public: - cPlsReader(cPlaylist& Playlist) : cPlaylistReader(Playlist), m_Current(0) {} - - protected: - int m_Current; - virtual char *Parse(char *line) { - char *t = strchr(line, '='); - if(t) { - int n; - if(!strncasecmp(line, "file", 4) && - 1 == sscanf(line + 4, "%d=", &n)) { - m_Current = n; - m_Position = n; - if(*(t+1)) - return t+1; - } - else if(!strncasecmp(line, "title", 5) && - 1 == sscanf(line + 5, "%d=", &n)) { - if(*(t+1)) { - if(n == m_Current) - Prev()->Title = t; - else - m_Title = t; - } - } - //else if(!strncasecmp(line, "length", 6) && - // 1 == sscanf(line + 4, "%d=", &n)) { - //} - } - return NULL; - } -}; - -class cAsxReader : public cPlaylistReader -{ - public: - cAsxReader(cPlaylist& Playlist) : cPlaylistReader(Playlist) {} - - protected: - virtual char *Parse(char *line) { - char *pt = strstr(line, "<REF HREF"); - if(!pt) - pt = strstr(line, "<ref href"); - if(!pt) - pt = strstr(line, "<ENTRY HREF"); - if(!pt) - pt = strstr(line, "<entry href"); - if(pt) { - pt = strchr(pt, '='); - if(pt) { - pt = strchr(pt, '\"'); - if(pt) { - pt++; - if(strchr(pt, '\"')) - *strchr(pt, '\"') = 0; - return pt; - } - } - } - - pt = strstr(line, "<TITLE>"); - if(!pt) - pt = strstr(line, "<title>"); - if(pt) { - pt += 7; - if(strstr(line, "</")) - *strstr(line, "</") = 0; - m_Title = pt; - } - - if(*m_Title) { - pt = strstr(line, "<ENTRY>"); - if(!pt) - pt = strstr(line, "<entry>"); - if(pt) { - if(*m_Title && Prev()) { - Prev()->Title = m_Title; - m_Title = NULL; - } - } - } - return NULL; - } -}; - - -// -// cPlaylist -// - -cPlaylist::cPlaylist() -{ - m_Origin = eImplicit; - m_Menu = NULL; - m_Scanner = NULL; - m_Current = NULL; - m_Version = 1; -} - -cPlaylist::~cPlaylist() -{ - if(m_Scanner) { - m_Scanner->CancelScanner(); - delete m_Scanner; - } - - if(m_Origin == eImplicit) - StoreCache(); -} - -void cPlaylist::Listen(cPlaylistChangeNotify *Menu) -{ - cMutexLock ml(&m_Lock); - m_Menu = Menu; -} - -void cPlaylist::PlaylistChanged(const cPlaylistItem *Item) -{ - cMutexLock ml(&m_Lock); - /*if(m_Origin == eImplicit)*/ - Sort(); - if(m_Menu) - m_Menu->PlaylistChanged(Item); -} - -void cPlaylist::Sort(void) -{ - cMutexLock ml(&m_Lock); - cListBase::Sort(); - m_Version++; -} - -int cPlaylist::Count(void) const -{ - return cListBase::Count(); -} - -cPlaylistItem *cPlaylist::Next(const cPlaylistItem *i) -{ - cMutexLock ml(&m_Lock); - return i ? cList<cPlaylistItem>::Next(i) : cList<cPlaylistItem>::First(); -} - -cPlaylistItem *cPlaylist::Current(void) -{ - cMutexLock ml(&m_Lock); - return m_Current ?: First(); -} - -void cPlaylist::Del(cPlaylistItem *it) -{ - cMutexLock ml(&m_Lock); - - if(!it || Count() < 2) - return; - - if(m_Current == it) - m_Current = cList<cPlaylistItem>::Next(Current()) ?: - cList<cPlaylistItem>::Prev(Current()); - - cListBase::Del(it); - m_Version++; -} - -void cPlaylist::SetCurrent(cPlaylistItem *current) -{ - cMutexLock ml(&m_Lock); - m_Current = current; -} - -cPlaylistItem *cPlaylist::Next(void) -{ - cMutexLock ml(&m_Lock); - if(Current()) - return m_Current = (cList<cPlaylistItem>::Next(Current()) ?: First()); - return NULL; -} - -cPlaylistItem *cPlaylist::Prev(void) -{ - cMutexLock ml(&m_Lock); - if(Current()) - return m_Current = (cList<cPlaylistItem>::Prev(Current()) ?: Last()); - return NULL; -} - -bool cPlaylist::StoreCache(void) -{ - if(!xc.cache_implicit_playlists || - m_Origin != eImplicit || - !*m_Folder) - return false; - - cString Name = cString::sprintf("%s%s", *m_Folder, PLAYLIST_CACHE); - int len = strlen(m_Folder), entries = 0; - FILE *f = NULL; - - for(cPlaylistItem *i = First(); i; i=Next(i)) { - // store only items in "current" root folder - if(!strncmp(i->Filename, m_Folder, len)) { - if(/**i->Title ||*/ *i->Artist || *i->Album) { - cString Filename = ((*i->Filename) + len); // relative - if(entries < 1) { - f = fopen(Name, "w"); - if(!f) { - LOGERR("creation of metadata cache %s%s failed", - *m_Folder, PLAYLIST_CACHE); - return false; - } - fprintf(f, "[playlist]\r\n"); - } - entries++; - fprintf(f, "File%d=%s\r\n", entries, *Filename); - if(*i->Title && (*i->Title)[0]) - fprintf(f, "Title%d=%s\r\n", entries, *i->Title); - if(*i->Tracknumber && (*i->Tracknumber)[0]) - fprintf(f, "Tracknumber%d=%s\r\n", entries, *i->Tracknumber); - if(*i->Artist && (*i->Artist)[0]) - fprintf(f, "Artist%d=%s\r\n", entries, *i->Artist); - if(*i->Album && (*i->Album)[0]) - fprintf(f, "Album%d=%s\r\n", entries, *i->Album); - } - } - } - - if(entries > 0) { - fprintf(f, "NumberOfEntries=%d\r\nVersion=2\r\n", entries); - fclose(f); - return true; - } - - return false; -} - -static const char *strchrnext(const char *s, char c) -{ - return (s = strchr(s, c)) ? ((*(s+1))?(s+1):NULL) : NULL; -} - -bool cPlaylist::ReadCache(void) -{ - if(xc.cache_implicit_playlists && m_Origin == eImplicit && *m_Folder) { - - cString Name = cString::sprintf("%s%s", *m_Folder, PLAYLIST_CACHE); - FILE *f = fopen(Name, "r"); - if(f) { - int len = strlen(m_Folder); - cPlaylistItem *it = NULL; - cReadLine r; - const char *pt; - while(NULL != (pt = r.Read(f))) { - if(!strncmp(pt, "File", 4)) { - it = NULL; - const char *Filename = strchrnext(pt+4, '='); - if(Filename && *Filename) { - for(cPlaylistItem *i = First(); i; i=Next(i)) { - if(!strncmp(i->Filename, m_Folder, len)) { - if(!strcmp(*i->Filename + len, Filename)) { - it = i; - break; - } - } - } - } - } else if(it && !strncmp(pt, "Title", 5)) { - it->Title = strchrnext(pt, '='); - } else if(it && !strncmp(pt, "Tracknumber", 11)) { - it->Tracknumber = strchrnext(pt, '='); - } else if(it && !strncmp(pt, "Artist", 6)) { - it->Artist = strchrnext(pt, '='); - } else if(it && !strncmp(pt, "Album", 5)) { - it->Album = strchrnext(pt, '='); - } else { - /*it = NULL;*/ - } - } - fclose(f); - return true; - } - } - - return false; -} - -#if 0 -static FILE *open_http(const char *PlaylistFile) -{ - char file[1024] = "", host[128] = "", pt; - int fd, port = 80; - - strn0cpy(host, PlaylistFile+strlen("http://"), sizeof(host)-1); - pt = strchr(host, '/'); - if(pt) { - strn0cpy(file, pt, sizeof(file)-1); - *pt = 0; - } - pt = strchr(host, ':'); - if(pt) { - *pt++ = 0; - port = atoi(pt); - } - - fd = tcp_connect(host, port); - if(fd < 0) { - LOGERR("TCP connect failed"); - return NULL; - } - - int len = asprintf(&pt, - "GET %s HTTP/1.1" "\r\n" - "Host: %s" "\r\n" - "\r\n", - file, host); - if(len != write(fd, pt, len)) { - LOGERR("HTTP request write failed"); - free(pt); - close(fd); - return NULL; - } - free(pt); - - int state = 0; - FILE *f = fdopen(fd, "r"); - cReadLine r; - while(state >= 0 && NULL != (pt = r.Read(f))) { - switch(state) { - case 0: if(!strncmp(pt, "HTTP/1", 6) || !strstr(pt, " 200 ")) { - LOGERR("HTTP error: %s", pt); - fclose(f); - return NULL; - } - state = 1; - break; - case 1: if(strcmp(pt, "\r\n")) - break; - return f; - default: break; - } - } - - fclose(f); - return NULL; -} -#endif - -int cPlaylist::ScanFolder(const char *FolderName, - bool Recursive, - bool (config_t::*Filter)(const char *)) -{ - cMutexLock ml(&m_Lock); - static int depth = 0; - - DIR *d = opendir(FolderName); - - if (d) { - LOGDBG("ScanFolder(%s)", FolderName); - struct dirent *e; - int n = 0, warn = -1; - while ((e = readdir(d)) != NULL) { - cString Buffer = cString::sprintf("%s%s", FolderName, e->d_name); - struct stat st; - if (stat(Buffer, &st) == 0) { - if(S_ISDIR(st.st_mode)) { - if (Recursive && !S_ISLNK(st.st_mode)) { /* don't want to loop ... */ - if(depth > 4) { - LOGMSG("ScanFolder: Too deep directory tree"); - } else if(e->d_name[0]=='.') { - } else { - if(n<MAX_PLAYLIST_FILES) { - depth++; /* limit depth */ - Buffer = cString::sprintf("%s/", *Buffer); - n += ScanFolder(Buffer, Recursive, Filter); - depth--; - } else { - if(!++warn) - LOGMSG("ScanFolder: Found over %d matching files, list truncated!", n); - break; - } - } - } - } else /* == if(!S_ISDIR(st.st_mode))*/ { - // check symlink destination - if (S_ISLNK(st.st_mode)) { - Buffer = ReadLink(Buffer); - if (!*Buffer) - continue; - if (stat(Buffer, &st) != 0) - continue; - } - if((xc.*Filter)(Buffer)) { - /* TODO: Should ScanDir add contents of playlist files ... ? */ - if(Filter == &config_t::IsPlaylistFile || !xc.IsPlaylistFile(Buffer)) { - n++; - if(n<MAX_PLAYLIST_FILES) { - Add(new cPlaylistItem(e->d_name, FolderName)); - //LOGDBG("ScanFolder: %s", e->d_name); - } else { - if(!++warn) - LOGMSG("ScanFolder: Found over %d matching files, list truncated!", n); - break; - } - } - } - } - } - } - LOGDBG("ScanFolder: Found %d matching files from %s", n, FolderName); - closedir(d); - - return n; - } - - LOGERR("ScanFolder: Error opening %s", FolderName); - return 0; -} - -void cPlaylist::StartScanner(void) -{ - cMutexLock ml(&m_Lock); - - if(m_Scanner) { - if(m_Scanner->Active()) - return; - delete m_Scanner; - m_Scanner = NULL; - } - - /* check if cache is already up-to-date */ - cString CacheName = cString::sprintf("%s%s", *m_Folder, PLAYLIST_CACHE); - struct stat stf, stc; - if(!stat(m_Folder, &stf)) { - if(!stat(CacheName, &stc)) { - //LOGDBG("ID3 Cache modified %d, folder modified %d, diff %d", - // (unsigned int)stc.st_mtime, (unsigned int)stf.st_mtime, - // (unsigned int)(stc.st_mtime - stf.st_mtime)); - if(stc.st_mtime >= stf.st_mtime) { - if(ReadCache()) { - LOGDBG("cPlaylist: using up-to-date ID3 cache"); - //LOGMSG(" Cache read OK."); - return; - } - LOGMSG("cPlaylist: ID3 cache read FAILED"); - } else { - LOGDBG("cPlaylist: ID3 cache not up-to-date, using old cache and scanning for changes"); - ReadCache(); - } - } - //else LOGERR("cPlaylist: stat(%s) failed"); - } - //else LOGERR("cPlaylist: stat(%s) failed"); - - if(xc.enable_id3_scanner) { - m_Scanner = new cID3Scanner(*this); - m_Scanner->Start(); - } -} - -int cPlaylist::ReadPlaylist(const char *file) -{ - static int depth = 0; /* limit recursion */ - cPipe p; - cPlaylistReader *parser = NULL; - FILE *f; - - if(strncmp(file, "http:", 5) && strncmp(file, "https:", 6)) { - f = fopen(file, "r"); - } else { - // fetch playlist from server using curl - LOGDBG("cPlaylist: fetching remote playlist from %s", file); - cString Cmd = cString::sprintf("curl %s", file); - if(!p.Open(Cmd, "r")) { - LOGERR("cPlaylist: CURL command (%s) failed", *Cmd); - return false; - } - // process as normal file - f = p; - } - - if(f) { - LOGDBG("cPlaylist: parsing %s", file); - const char *ext = strrchr(file, '.'); - if(!strcasecmp(ext, ".pls")) - parser = new cPlsReader(*this); - else if(!strcasecmp(ext, ".asx")) - parser = new cAsxReader(*this); - else /*if(!strcasecmp(ext, ".m3u"))*/ - parser = new cM3uReader(*this); /* parses plain lists (.ram, ...) too ...*/ - - /* get folder */ - cString Folder = file; - const char *folder = strrchr(Folder, '/'); - if (folder) - Folder.Truncate(folder - Folder + 1); - - int n = 0; - cReadLine r; - char *pt; - while(NULL != (pt = r.Read(f)) && n < MAX_PLAYLIST_FILES) { - if(NULL != (pt = parser->Parse(pt))) { - - if(xc.IsPlaylistFile(pt)) { - parser->ResetCache(); - LOGDBG("cPlaylist: found playlist inside playlist"); - if(depth > 4) - LOGMSG("cPlaylist: recursion too deep, skipped %s", pt); - else { - depth++; - if(*pt == '/' || - (strstr(pt,"://")+1 == strchr(pt,'/') && - strchr(pt,'/') - pt < 8)) - n += ReadPlaylist(pt); - else - n += ReadPlaylist(cString::sprintf("%s%s", *Folder, pt)); - depth--; - } - - } else { - if(*pt == '/' || - (strstr(pt,"://")+1 == strchr(pt,'/') && - strchr(pt,'/') - pt < 8)) { - // absolute path - Add(new cPlaylistItem(pt)); - if(parser->Title()) - Last()->Title = parser->Title(); - } else { - // relative path - Add(new cPlaylistItem(pt, Folder, parser->Title())); - } - Last()->Position = parser->Position(); - parser->ResetCache(); - //LOGDBG("read_playlist: %s", pt); - n++; - } - } - } - - if(! (FILE*) p) - fclose(f); - - if(n >= MAX_PLAYLIST_FILES) - LOGMSG("cPlaylist: Found over %d matching files, list truncated!", n); - LOGDBG("cPlaylist: Found %d matching files", n); - return n; - } - - LOGERR("cPlaylist: Error opening %s", file); - return 0; -} - -static cString LastDir(cString& path) -{ - cString tmp = path; - const char *pt = strrchr(tmp, '/'); - if(pt && pt > *tmp) { - tmp.Truncate(pt - tmp); - pt = strrchr(tmp, '/'); - if(pt) - return cString(pt+1); - } - return cString(NULL); -} - -bool cPlaylist::Read(const char *PlaylistFile, bool Recursive) -{ - cMutexLock ml(&m_Lock); - bool Result = true; - - // extract playlist root folder - if(!*m_Folder) { - const char *pt; - m_Folder = PlaylistFile; - if (NULL != (pt=strrchr(m_Folder, '/'))) - m_Folder.Truncate(pt - m_Folder + 1); - } - - if(xc.IsPlaylistFile(PlaylistFile)) { - // Read playlist file - Result = ReadPlaylist(PlaylistFile); - m_Origin = ePlaylist; - - cString dir = LastDir(m_Folder); - const char *name = strrchr(PlaylistFile, '/'); - name = name ? name+1 : NULL; - if(*dir && name) - m_Name = cString::sprintf("%s - %s", *dir, name); - else - m_Name = name ?: ""; - - strip_extension(m_Name); - - } else if(PlaylistFile[ 0] == '/' && - PlaylistFile[strlen(PlaylistFile)-1] == '/') { - // Scan folder - Result = ScanFolder(PlaylistFile, Recursive) > 0; - m_Origin = eImplicit; - Sort(); - - if(!*m_Name) { - m_Name = PlaylistFile; - m_Name.Truncate( strrchr(m_Name, '/') - m_Name); - if(strrchr(m_Name, '/')) { - cString dir = LastDir(m_Name); - if(*dir) - m_Name = cString::sprintf("%s - %s", *dir, strrchr(m_Name, '/')+1); - else - m_Name = strrchr(m_Name, '/')+1; - } - } - - } else { - // Single file - Add(new cPlaylistItem(PlaylistFile)); - m_Origin = eImplicit; - - if(!*m_Name) { - m_Name = LastDir(m_Folder); - if(!*m_Name) - m_Name = ""; - } - } - - if(Count() < 1) { - LOGMSG("Empty playlist %s !", PlaylistFile); - Add(new cPlaylistItem(PlaylistFile)); - } - - m_Version++; - return Result; -} - -cString cPlaylist::EscapeMrl(const char *mrl) -{ - static const uint8_t hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; - const uint8_t *fn = (const uint8_t*)mrl; - int size = strlen(mrl) + 16; - char *buf = (char *)malloc(size); - int i = 0, found = 0; - LOGDBG("cPlaylist::EscapeMrl('%s')", fn); - - // Wait for first '/' (do not escape mrl start dvd:/, http://a@b/, ...) - if (*fn == '/') - found = 3; - - while (*fn) { - if(size-7 < i) - buf = (char *)realloc(buf, (size=size+16)); - switch (*fn) { - case 1 ... ' ': - case 127 ... 255: - case '#': - case '%': - case ':': - case ';': - case '\'': - case '\"': - case '(': - case ')': - if (found > 2) { - buf[i++] = '%'; - buf[i++] = hex[(*fn & 0xf0)>>4]; - buf[i++] = hex[(*fn & 0x0f)]; - break; - } - default: - // file:/... -> only one '/' before escaping - // http://.../ --> three '/' before escaping - if(!found && (fn[0] == ':' && fn[1] == '/')) { - if(fn[2] == '/') { - // ex. http://user:pass@host/... --> wait for third '/' - buf[i++] = *fn++; - buf[i++] = *fn++; - found += 2; - } else { - // ex. file:/local_file - buf[i++] = *fn++; - found += 3; - } - } else if(*fn == '/') { - found++; - } - buf[i++] = *fn; - break; - } - fn++; - } - - buf[i] = 0; - LOGDBG(" --> '%s'", buf); - return cString(buf, true); -} - -cString cPlaylist::GetEntry(cPlaylistItem *i, bool isPlaylist, bool isCurrent) -{ - - cString Entry = ""; - if ((*i->Artist && xc.playlist_artist) || (*i->Album && xc.playlist_album)) { - Entry = cString::sprintf("%s%s%s%s%s%s(%s%s%s)", - isPlaylist ? (isCurrent ? "*" : " ") : "", - isPlaylist ? "\t" : " ", - xc.playlist_tracknumber ? (*i->Tracknumber ?: "") : "", - xc.playlist_tracknumber ? (*i->Tracknumber ? " - " : "") : "", - *i->Title, - isPlaylist ? "\t" : " ", - xc.playlist_artist ? (*i->Artist ?: "") : "", - xc.playlist_artist && xc.playlist_album ? (*i->Artist && *i->Album ? ":" : "") : "", - xc.playlist_album ? (*i->Album ?: "") : ""); - } else { - Entry = cString::sprintf("%s%s%s%s%s", - isPlaylist ? (isCurrent ? "*" : " ") : "", - isPlaylist ? "\t" : " ", - xc.playlist_tracknumber ? (*i->Tracknumber ?: "") : "", - xc.playlist_tracknumber ? (*i->Tracknumber ? " - " : "") : "", - *i->Title); - } - return Entry; -} diff --git a/tools/playlist.h b/tools/playlist.h deleted file mode 100644 index 50c3d97a..00000000 --- a/tools/playlist.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * playlist.h: Media player playlist - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: playlist.h,v 1.8 2008-02-19 04:24:34 phintuka Exp $ - * - */ - -#ifndef __XINELIBOUTPUT_PLAYLIST_H -#define __XINELIBOUTPUT_PLAYLIST_H - -#include <vdr/tools.h> // cString, cListObject, cList<> -#include <vdr/thread.h> // cMutex - - -// -// cPlaylistItem -// - -class cPlaylistItem : public cListObject -{ - private: - cPlaylistItem(); - - virtual int Compare(const cListObject &ListObject) const; - - public: - cPlaylistItem(const char *filename); /* file name with full path */ - cPlaylistItem(const char *filename, /* file name without path */ - const char *path, - const char *title = NULL, - int position = -1); - - cString Filename; /* file name and full path */ - - // Metainfo (ID3 etc.) - cString Title; - cString Tracknumber; - cString Artist; - cString Album; - - // position in playlist (if given in playlist file) - int Position; -}; - - -// -// cPlaylistChangeNotify interface -// - -class cPlaylistChangeNotify -{ - public: - virtual void PlaylistChanged(const cPlaylistItem *Item) = 0; - - virtual ~cPlaylistChangeNotify() {} -}; - - -// -// cPlaylist -// - - -class cID3Scanner; - -class cPlaylist : protected cList<cPlaylistItem> -{ - private: - - cMutex m_Lock; - cString m_Name; // playlist (or folder) name - cString m_Folder; // path to "root" of playlist - cPlaylistItem *m_Current; // now playing - unsigned int m_Version; - - enum { ePlaylist, eImplicit } m_Origin; - - cPlaylistChangeNotify *m_Menu; - cID3Scanner *m_Scanner; - - protected: - - bool StoreCache(void); - bool ReadCache(void); - - int ReadPlaylist(const char *PlaylistFile); - int ScanFolder(const char *FolderName, - bool Recursive = false, - bool (config_t::*Filter)(const char *) = &config_t::IsAudioFile); - - friend class cID3Scanner; - friend class cPlaylistReader; - void PlaylistChanged(const cPlaylistItem *Item); - cPlaylistItem *Last(void) { return cList<cPlaylistItem>::Last(); } - - public: - - cPlaylist(); - virtual ~cPlaylist(); - - const cString& Name(void) const { return m_Name; } - - // listen for changes in playlist - void Listen(cPlaylistChangeNotify *Menu = NULL); - - // read playlist from file or create playlist from directory tree - bool Read(const char *PlaylistFile, bool Recursive = false); - void StartScanner(void); - void Del(cPlaylistItem *it); - - void Sort(void); - int Count(void) const; - - // access/iterate playlist items - cPlaylistItem *First(void) { return Next(NULL); } - cPlaylistItem *Next(const cPlaylistItem *i); - - // get/set current (now playing) item - cPlaylistItem *Current(void); - void SetCurrent(cPlaylistItem *current); - cPlaylistItem *Next(void); - cPlaylistItem *Prev(void); - - static cString EscapeMrl(const char *name); - static cString GetEntry(cPlaylistItem *i, bool isPlaylist = false, bool isCurrent = false); -}; - - -#endif // __XINELIBOUTPUT_PLAYLIST_H diff --git a/tools/rle.c b/tools/rle.c deleted file mode 100644 index 2425630b..00000000 --- a/tools/rle.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * rle.c: RLE utils - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rle.c,v 1.3 2009-02-16 16:14:58 phintuka Exp $ - * - */ - -#include <stdint.h> -#include <stdlib.h> - -#include "../xine_osd_command.h" - -#include "rle.h" - - -#undef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -/* - * rle_compress() - * - */ -int rle_compress(xine_rle_elem_t **rle_data, const uint8_t *data, uint w, uint h) -{ - xine_rle_elem_t rle, *rle_p = 0, *rle_base; - int x, y, num_rle = 0, rle_size = 8128; - const uint8_t *c; - - rle_p = (xine_rle_elem_t*)malloc(4*rle_size); - rle_base = rle_p; - - for (y = 0; y < h; y++) { - rle.len = 0; - rle.color = 0; - c = data + y * w; - for (x = 0; x < w; x++, c++) { - if (rle.color != *c) { - if (rle.len) { - if ( (num_rle + h-y+1) > rle_size ) { - rle_size *= 2; - rle_base = (xine_rle_elem_t*)realloc( rle_base, 4*rle_size ); - rle_p = rle_base + num_rle; - } - *rle_p++ = rle; - num_rle++; - } - rle.color = *c; - rle.len = 1; - } else { - rle.len++; - } - } - *rle_p++ = rle; - num_rle++; - } - - *rle_data = rle_base; - return num_rle; -} - -/* - * rle_scale_nearest() - * - * - Simple nearest-neighbour scaling for RLE-compressed image - * - fast scaling in compressed form without decompression - */ -xine_rle_elem_t *rle_scale_nearest(const xine_rle_elem_t *old_rle, int *rle_elems, - uint w, uint h, uint new_w, uint new_h) -{ - #define FACTORBASE 0x100 - #define FACTOR2PIXEL(f) ((f)>>8) - #define SCALEX(x) FACTOR2PIXEL(factor_x*(x)) - #define SCALEY(y) FACTOR2PIXEL(factor_y*(y)) - - uint old_w = w, old_h = h; - uint old_y = 0, new_y = 0; - uint factor_x = FACTORBASE*new_w/old_w; - uint factor_y = FACTORBASE*new_h/old_h; - uint rle_size = MAX(8128, *rle_elems * new_h/h ); /* guess ... */ - uint num_rle = 0; - xine_rle_elem_t *new_rle = (xine_rle_elem_t*)malloc(sizeof(xine_rle_elem_t)*rle_size); - xine_rle_elem_t *new_rle_start = new_rle; - - /* we assume rle elements are breaked at end of line */ - while (old_y < old_h) { - uint elems_current_line = 0; - uint old_x = 0, new_x = 0; - - while (old_x < old_w) { - uint new_x_end = SCALEX(old_x + old_rle->len); - - if (new_x_end > new_w) { - new_x_end = new_w; - } - - new_rle->len = new_x_end - new_x; - new_rle->color = old_rle->color; - - old_x += old_rle->len; - old_rle++; /* may be incremented to last element + 1 (element is not accessed anymore) */ - - if (new_rle->len > 0) { - new_x += new_rle->len; - new_rle++; - - num_rle++; - elems_current_line++; - - if ( (num_rle + 1) >= rle_size ) { - rle_size *= 2; - new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size); - new_rle = new_rle_start + num_rle; - } - } - } - if (new_x < new_w) - (new_rle-1)->len += new_w - new_x; - old_y++; - new_y++; - - if (factor_y > FACTORBASE) { - /* scale up -- duplicate current line ? */ - int dup = SCALEY(old_y) - new_y; - - /* if no lines left in (old) rle, copy all lines still missing from new */ - if (old_y == old_h) - dup = new_h - new_y - 1; - - while (dup-- && (new_y+1<new_h)) { - xine_rle_elem_t *prevline; - uint n; - if ( (num_rle + elems_current_line + 1) >= rle_size ) { - rle_size *= 2; - new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size); - new_rle = new_rle_start + num_rle; - } - - /* duplicate previous line */ - prevline = new_rle - elems_current_line; - for (n = 0; n < elems_current_line; n++) { - *new_rle++ = *prevline++; - num_rle++; - } - new_y++; - } - - } else if (factor_y < FACTORBASE) { - /* scale down -- drop next line ? */ - uint skip = new_y - SCALEY(old_y); - if (old_y == old_h-1) { - /* one (old) line left ; don't skip it if new rle is not complete */ - if (new_y < new_h) - skip = 0; - } - while (skip-- && - old_y<old_h /* rounding error may add one line, filter it out */) { - for (old_x = 0; old_x < old_w;) { - old_x += old_rle->len; - old_rle++; - } - old_y++; - } - } - } - - *rle_elems = num_rle; - return new_rle_start; -} diff --git a/tools/rle.h b/tools/rle.h deleted file mode 100644 index d6900e8f..00000000 --- a/tools/rle.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * rle.h: RLE utils - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rle.h,v 1.2 2009-02-16 16:14:58 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_RLE_H_ -#define XINELIBOUTPUT_RLE_H_ - -#if defined __cplusplus -extern "C" { -#endif - -typedef enum { - scale_fast = 0, /* simple pixel doubling/dropping */ - scale_good_BW = 1, /* linear interpolation, palette re-generation */ -} scale_mode_t; - - -struct xine_rle_elem_s; -struct xine_clut_s; - - -int rle_compress(struct xine_rle_elem_s **rle_data, const uint8_t *data, uint w, uint h); - -void rle_uncompress_lut8(const struct xine_rle_elem_s *rle_data, - uint8_t *data, uint w, uint h); -void rle_uncompress_argb(uint32_t *dst, - const struct xine_rle_elem_s *rle_data, uint num_rle, - uint w, uint h, uint stride, - struct xine_clut_s *palette); - -/* - * rle_scale_nearest() - * - * - Simple nearest-neighbour scaling for RLE-compressed image - * - fast scaling in compressed form without decompression - */ -struct xine_rle_elem_s *rle_scale_nearest(const struct xine_rle_elem_s *old_rle, - int *rle_elems, - uint w, uint h, uint new_w, uint new_h); - - -#if defined __cplusplus -} -#endif - -#endif /* XINELIBOUTPUT_RLE_H_ */ diff --git a/tools/rtcp.h b/tools/rtcp.h deleted file mode 100644 index 608f2daf..00000000 --- a/tools/rtcp.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * rtcp.h: RFC1889: RTCP - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rtcp.h,v 1.3 2007-03-29 14:22:31 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_RTCP_H_ -#define XINELIBOUTPUT_RTCP_H_ - -#ifdef __APPLE__ -# include <machine/endian.h> -#else -# include <endian.h> -#endif - - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - -#if __BYTE_ORDER == __BIG_ENDIAN -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#else -# error __BYTE_ORDER not defined -#endif - -#if defined __cplusplus -extern "C" { -#endif - - -/* RTCP packet types */ -typedef enum { - RTCP_SR = 200, - RTCP_RR = 201, - RTCP_SDES = 202, - RTCP_BYE = 203, - RTCP_APP = 204 -} rtcp_type_t; - -/* RTCP SDES types */ -typedef enum { - RTCP_SDES_END = 0, - RTCP_SDES_CNAME = 1, - - RTCP_SDES_NAME = 2, - RTCP_SDES_EMAIL = 3, - RTCP_SDES_PHONE = 4, - RTCP_SDES_LOC = 5, - RTCP_SDES_TOOL = 6, - RTCP_SDES_NOTE = 7, - RTCP_SDES_PRIV = 8 -} rtcp_sdes_type_t; - -/* RTCP common header word */ -typedef struct { - union { - uint8_t raw[4]; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned int version:2; /* protocol version */ - unsigned int padding:1; /* padding flag */ - unsigned int count:5; /* varies by packet type */ -#else - unsigned int count:5; /* varies by packet type */ - unsigned int padding:1; /* padding flag */ - unsigned int version:2; /* protocol version */ -#endif - unsigned int ptype:8; /* RTCP packet type */ - - uint16_t length; /* pkt len in words, w/o this word */ - } PACKED; - } PACKED; -} PACKED rtcp_common_t; - -/* RTCP RR (Reception report) */ -typedef struct { - uint32_t ssrc; /* data source being reported */ - unsigned int fraction:8; /* fraction lost since last SR/RR */ - int lost:24; /* cumul. no. pkts lost (signed!) */ - uint32_t last_seq; /* extended last seq. no. received */ - uint32_t jitter; /* interarrival jitter */ - uint32_t lsr; /* last SR packet from this source */ - uint32_t dlsr; /* delay since last SR packet */ -} PACKED rtcp_rr_t; - -/* RTCP SR (Sender report) */ -typedef struct { - uint32_t ssrc; - uint32_t ntp_sec; /* NTP timestamp, most significant word / seconds */ - uint32_t ntp_frac; - uint32_t rtp_ts; - uint32_t psent; /* packets sent */ - uint32_t osent; /* octets sent */ - rtcp_rr_t rr[0]; /* variable-length list */ -} PACKED rtcp_sr_t; - -/* RTCP SDES item */ -typedef struct { - uint8_t type; /* type of item (rtcp_sdes_type_t) */ - uint8_t length; /* length of item (in octets) */ - char data[0]; /* text, not null-terminated */ -} PACKED rtcp_sdes_item_t; - -/* RTCP packet */ -typedef struct { - rtcp_common_t hdr; - union { - rtcp_sr_t sr; - struct { - uint32_t ssrc; - rtcp_rr_t rr[0]; - } PACKED rr; - struct { - uint32_t ssrc; /* first SSRC/CSRC */ - rtcp_sdes_item_t item[0]; /* list of SDES items */ - } PACKED sdes; - struct { - uint32_t src[0]; /* list of sources */ - /* can't express trailing text for reason */ - } PACKED bye; - } PACKED; -} PACKED rtcp_packet_t; - - -#if defined __cplusplus -}; -#endif - -#endif /* XINELIBOUTPUT_RTCP_H_ */ diff --git a/tools/rtp.h b/tools/rtp.h deleted file mode 100644 index fa2ccf63..00000000 --- a/tools/rtp.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * rtp.h: RFC1889: RTP - A Transport Protocol for Real-Time Applications - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rtp.h,v 1.3 2007-03-29 14:22:31 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_RTP_H_ -#define XINELIBOUTPUT_RTP_H_ - -#ifdef __APPLE__ -# include <machine/endian.h> -#else -# include <endian.h> -#endif - - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - -#if __BYTE_ORDER == __BIG_ENDIAN -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#else -# error __BYTE_ORDER not defined -#endif - -#if defined __cplusplus -extern "C" { -#endif - - -/* Generic RTP header extension */ -typedef struct stream_rtp_header_ext { - - union { - uint8_t raw[4]; - uint32_t rawd; - - struct { - uint16_t type; - uint16_t size; /* Size of ext_data field in DWORDS */ - } PACKED; - } PACKED; - - uint8_t ext_data[0]; - -} PACKED stream_rtp_header_ext_t; - - -/* Common RTP data header */ -typedef struct stream_rtp_header { - - union { - uint8_t raw[12]; - - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned int version:2; /* protocol version */ - unsigned int padding:1; /* padding flag */ - unsigned int ext:1; /* header extension flag */ - unsigned int cc:4; /* CSRC count */ - - unsigned int marker:1; /* marker bit */ - unsigned int paytype:7; /* payload type */ -#else - unsigned int cc:4; /* CSRC count */ - unsigned int ext:1; /* header extension flag */ - unsigned int padding:1; /* padding flag */ - unsigned int version:2; /* protocol version */ - - unsigned int paytype:7; /* payload type */ - unsigned int marker:1; /* marker bit */ -#endif - uint16_t seq; /* sequence number */ - uint32_t ts; /* timestamp */ - uint32_t ssrc; /* synchronization source */ - - /*uint32_t csrc[0];*/ /* optional CSRC list */ - } PACKED; - } PACKED; - - - union { - stream_rtp_header_ext_t hdr_ext[0]; - uint8_t payload[0]; - } PACKED; - - -} PACKED stream_rtp_header_t; - -#if defined __cplusplus -}; -#endif - -#endif /* XINELIBOUTPUT_RTP_H_ */ - diff --git a/tools/sap.h b/tools/sap.h deleted file mode 100644 index 6b341efc..00000000 --- a/tools/sap.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * sap.h: RFC2974 Session Announcement Protocol (SAP) version 2 - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: sap.h,v 1.8 2007-03-29 14:22:30 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_SAP_H_ -#define XINELIBOUTPUT_SAP_H_ - -#include <arpa/inet.h> -#ifdef __APPLE__ -# include <machine/endian.h> -#else -# include <endian.h> -#endif - - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - -/*#define LOG_SAP*/ - -/* SAP IPv4 multicast addresses */ -#define SAP_IP_ADDRESS_GLOBAL "224.2.127.254" /* SAPv1 IP4 global scope multicast address */ -#define SAP_IP_ADDRESS_ORG "239.195.255.255" /* organization-local */ -#define SAP_IP_ADDRESS_LOCAL "239.255.255.255" /* local */ -#define SAP_IP_ADDRESS_LINK "224.0.0.255" /* link-local */ - -#define SAP_IP_TTL 255 -#define SAP_UDP_PORT 9875 - - -typedef struct { - - /* RFC2974: SAP (Session Announcement Protocol) version 2 PDU */ - - union { - uint8_t raw0; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - uint8_t version : 3; - uint8_t addr_type : 1; - uint8_t reserved : 1; - uint8_t msg_type : 1; - uint8_t encrypted : 1; - uint8_t compressed : 1; -#else - uint8_t compressed : 1; - uint8_t encrypted : 1; - uint8_t msg_type : 1; - uint8_t reserved : 1; - uint8_t addr_type : 1; - uint8_t version : 3; -#endif - } PACKED; - } PACKED; - - uint8_t auth_len; - uint16_t msgid_hash; - - union { - uint8_t u8[4]; - uint32_t u32; - } PACKED ip4_source; - - char payload[0]; - -} PACKED sap_pdu_t; - - -static inline sap_pdu_t *sap_create_pdu(uint32_t src_ip, - uint16_t msgid, - int announce, - const char *payload_type, - const char *payload) -{ - sap_pdu_t *pdu; - int length = sizeof(sap_pdu_t) + strlen(payload) + 3; - - if(payload_type) - length += strlen(payload_type); - - if(! (pdu = (sap_pdu_t*)malloc(length))) - return NULL; - - memset(pdu, 0, sizeof(sap_pdu_t)); - pdu->version = 1; /* SAP v1 / v2 */ - pdu->msg_type = announce ? 0 : 1; - pdu->msgid_hash = msgid; - pdu->ip4_source.u32 = src_ip; - - if(payload_type) { - char *tmp = &pdu->payload[0]; - strcpy(tmp, payload_type); - tmp += strlen(tmp) + 1; - strcpy(tmp, payload); - } else { - /* payload type defaults to application/sdp */ - sprintf(&pdu->payload[0], "%s%c%c", payload, 0, 0); - } - - return pdu; -} - -static inline int sap_compress_pdu(sap_pdu_t *pdu) -{ -#ifdef HAVE_ZLIB_H - - /* zlib compression */ - - Compress(); - - /*pdu->compressed = 1;*/ - -#endif - - /* not implemented */ - - pdu->compressed = 0; - return -1; -} - -static inline int sap_send_pdu(int *pfd, sap_pdu_t *pdu, uint32_t dst_ip) -{ - int len = 0, r; - int iReuse = 1, iLoop = 1, iTtl = SAP_IP_TTL; - int fd; - - if(!pfd || *pfd < 0) { - fd = socket(AF_INET, SOCK_DGRAM, 0); - - if(fd < 0) { - LOGERR("socket() failed (UDP/SAP multicast)"); - return -1; - } - - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)); - setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &iTtl, sizeof(int)); - setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &iLoop, sizeof(int)); - - // Connect to multicast address - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = htons(SAP_UDP_PORT); - sin.sin_addr.s_addr = dst_ip ? dst_ip : inet_addr(SAP_IP_ADDRESS_GLOBAL); - - if(connect(fd, (struct sockaddr *)&sin, sizeof(sin))==-1) - LOGERR("UDP/SAP multicast connect() failed."); - - // Set to non-blocking mode - fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK); - - if(pfd) - *pfd = fd; - - } else { - fd = *pfd; - } - - // size of PDU - len += strlen(&pdu->payload[0]); - if(!strstr(&pdu->payload[0], "\r\n")) { - /* assume mime content type is present */ - len += 1; - len += strlen(&pdu->payload[len]); - len += sizeof(sap_pdu_t); - } - - // network order - pdu->msgid_hash = htons(pdu->msgid_hash); - - // send - r = send(fd, pdu, len, 0); - if(r < 0) - LOGERR("UDP/SAP multicast send() failed."); - - if(!pfd) - close(fd); - -#ifdef LOG_SAP - /* log PDU */ - for(int i=0; i<len;) { - char x[4096]="", a[4096]=""; - for(int j=0; j<16 && i<len; i++, j++) { - char t[8], ch = ((char*)pdu)[i]; - sprintf(t, "%02X ", ((unsigned int)ch)&0xff); - strcat(x, t); - sprintf(t, "%c", (ch>=32 && ch<127) ? ch : '.'); - strcat(a, t); - } - LOGMSG("SAP: 0x%02x: %-50s%-18s", i/16-1, x, a); - } -#endif - - // back to host order - pdu->msgid_hash = ntohs(pdu->msgid_hash); - - return r == len ? len : -1; -} - - -#endif /* XINELIBOUTPUT_SAP_H_ */ diff --git a/tools/sdp.h b/tools/sdp.h deleted file mode 100644 index 514c29c1..00000000 --- a/tools/sdp.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * sdp.h: RFC2974 Session Description Protocol (SDP) - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: sdp.h,v 1.5 2009-02-10 12:42:38 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_SDP_H_ -#define XINELIBOUTPUT_SDP_H_ - - -#define SDP_MIME_TYPE "application/sdp" - -#define SDP_PAYLOAD_MPEG_PES 96 -#define SDP_PAYLOAD_MPEG_TS 33 - -static const char *vdr_sdp_description(const char *vdr_ip, - int vdr_svdrp_port, - int vdr_xineliboutput_port, - const char *rtp_ip, - uint32_t rtp_ssrc, - uint32_t payload_type, - int rtp_port, - int rtp_ttl) -{ - static uint8_t s_serial = 0; - static cString s_data; - static char s_hostname[257] = {0}; - - uint64_t serial = (time(NULL) << 2) + ((s_serial++) & 0x03); - cString payload; - - if (!s_hostname[0]) - gethostname(s_hostname, 256); - - if (payload_type == SDP_PAYLOAD_MPEG_PES) { - payload = cString::sprintf( - /* video/mp2p udp/rtp */ - /* media */ "m=video %d RTP/AVP 96" - /* */ "\r\n" "a=rtpmap:96 MP2P/90000" - , rtp_port - ); - } else { - payload = cString::sprintf( - /* video/mp2t udp/rtp */ - /* media */ "m=video %d RTP/AVP 33" - , rtp_port - ); - } - - s_data = cString::sprintf( - /*** session ***/ - /* version */ "v=0" - /* origin */ "\r\n" "o=%s %u %"PRIu64" IN IP4 %s" - /* name */ "\r\n" "s=%s@%s (multicast %s:%d)" - /* opt:info */ /*"\r\n" "i=vdr-xineliboutput primary device output"*/ - /* time */ "\r\n" "t=0 0" - - /*** data stream(s) ***/ - /* connection */ "\r\n" "c=IN IP4 %s/%d" - /* */ "\r\n" "a=recvonly" - /* */ "\r\n" "a=type:broadcast" - /* */ "\r\n" "a=x-plgroup:vdr" - /* *media */ "\r\n" "%s" - - /* media */ /*"\r\n" "m=video %d udp MP2P"*/ - /* */ /*"\r\n" "a=mux:ps"*/ - /* */ /*"\r\n" "a=packetformat:RAW"*/ -#if 0 - /*** rtsp control port ***/ - /* connection */ "\r\n" "c=IN IP4 %s" - /* media */ "\r\n" "m=control %d tcp/http rtsp" -#endif - /*** xineliboutput control port ***/ - /* connection */ "\r\n" "c=IN IP4 %s" - /* media */ "\r\n" "m=control %d tcp x-vdr-xineliboutput" - - /*** SVDRP control port ***/ - /* connection */ "\r\n" "c=IN IP4 %s" - /* media */ "\r\n" "m=control %d tcp x-svdrp" - - /* origin */ - , "vdr", rtp_ssrc, serial, vdr_ip - - /* name */ - , "vdr", s_hostname, rtp_ip, rtp_port - - /* media */ - , rtp_ip, rtp_ttl - , *payload - -#if 0 - /* tcp/http control/rtsp */ - , vdr_ip - , vdr_xineliboutput_port -#endif - /* tcp control/x-vdr-xineliboutput */ - , vdr_ip - , vdr_xineliboutput_port - - /* tcp control/x-svdrp */ - , vdr_ip - , vdr_svdrp_port - ); - return s_data; -} - - -#endif /* XINELIBOUTPUT_SDP_H_ */ diff --git a/tools/time_pts.c b/tools/time_pts.c deleted file mode 100644 index 81ee7c73..00000000 --- a/tools/time_pts.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * time_pts.c: Adjustable clock in PTS units - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: time_pts.c,v 1.4 2008-04-28 20:48:05 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS -#include <inttypes.h> -#include <time.h> - -#include <vdr/config.h> - -#include "../logdefs.h" // logging - -#include "time_pts.h" - - -#define MAX_SCR ((int64_t)0x1ffffffffLL) - -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) -#else -# warning Posix monotonic clock not available -#endif - -int cTimePts::m_Monotonic = -1; - -void cTimePts::Init(void) -{ -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) - if(m_Monotonic >= 0) - return; - - m_Monotonic = 0; - - struct timespec resolution; - if(clock_getres(CLOCK_MONOTONIC, &resolution)) { - LOGERR("cTimePts: clock_getres(CLOCK_MONOTONIC) failed"); - return; - } - - LOGDBG("cTimePts: clock_gettime(CLOCK_MONOTONIC): clock resolution %d us", - ((int)resolution.tv_nsec) / 1000); - - if( resolution.tv_sec == 0 && resolution.tv_nsec <= 1000000 ) { - struct timespec tp; - if(clock_gettime(CLOCK_MONOTONIC, &tp)) { - LOGERR("cTimePts: clock_gettime(CLOCK_MONOTONIC) failed"); - } else { - LOGDBG("cTimePts: using monotonic clock"); - m_Monotonic = 1; - } - } -#endif -} - -cTimePts::cTimePts(void) -{ - m_Paused = false; - m_ScrSpeed = 90000; - m_Multiplier = 90000; - - Init(); - - Set(); -} - -int64_t cTimePts::Now(void) const -{ - if(m_Paused) - return begin; - - struct timeval t; - -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) - if(m_Monotonic) { - struct timespec tp; - - if(clock_gettime(CLOCK_MONOTONIC, &tp)) { - LOGERR("cTimePts: clock_gettime(CLOCK_MONOTONIC) failed"); - return -1; - } - - t.tv_sec = tp.tv_sec; - t.tv_usec = tp.tv_nsec/1000; - - } else if (gettimeofday(&t, NULL)) { - LOGERR("cTimePts: gettimeofday() failed"); - return -1; - } -#else - if (gettimeofday(&t, NULL)) { - LOGERR("cTimePts: gettimeofday() failed"); - return -1; - } -#endif - - t.tv_sec -= tbegin.tv_sec; - if(t.tv_usec < tbegin.tv_usec) { - t.tv_sec--; - t.tv_usec += 1000000; - } - t.tv_usec -= tbegin.tv_usec; - - int64_t pts = 0; - pts += (int64_t)t.tv_sec * (int64_t)m_ScrSpeed; - pts += (int64_t)t.tv_usec * (int64_t)m_ScrSpeed / INT64_C(1000000); - - if(m_Multiplier != 90000) - pts = pts * m_Multiplier / INT64_C(90000); - - return ( pts + begin ) & MAX_SCR; -} - -void cTimePts::Set(int64_t Pts) -{ - begin = Pts; - -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) - if(m_Monotonic) { - struct timespec tp; - - if(!clock_gettime(CLOCK_MONOTONIC, &tp)) { - tbegin.tv_sec = tp.tv_sec; - tbegin.tv_usec = tp.tv_nsec/1000; - return; - } - - LOGERR("cTimePts: clock_gettime(CLOCL_MONOTONIC) failed"); - m_Monotonic = 0; - } -#endif - - gettimeofday(&tbegin, NULL); -} - -void cTimePts::Pause(void) -{ - Set(Now()); - m_Paused = true; -} - -void cTimePts::Resume(void) -{ - if(m_Paused) { - Set(begin); - m_Paused = false; - } -} - -void cTimePts::TrickSpeed(const int Multiplier) -{ - Set(Now()); - - if(Multiplier < 0) - m_Multiplier = 90000 * (-Multiplier); - else if(Multiplier > 0) - m_Multiplier = 90000 / Multiplier; - else - LOGERR("cTimePts::SetSpeed: Multiplier=%d", Multiplier); -} - -void cTimePts::SetScrSpeed(const int ScrSpeed) -{ - Set(Now()); - - m_ScrSpeed = ScrSpeed; -} diff --git a/tools/time_pts.h b/tools/time_pts.h deleted file mode 100644 index fafc7199..00000000 --- a/tools/time_pts.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * time_pts.h: Adjustable clock in PTS units - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: time_pts.h,v 1.4 2008-04-28 20:48:05 phintuka Exp $ - * - */ - -#ifndef __TIME_PTS_H -#define __TIME_PTS_H - -#include <stdint.h> // int64_t -#include <sys/time.h> // struct timeval - - -class cTimePts -{ - private: - int64_t begin; /* Start time (PTS) */ - struct timeval tbegin; /* Start time (real time) */ - bool m_Paused; - int m_Multiplier; - int m_ScrSpeed; - - static int m_Monotonic; - static void Init(void); - - public: - cTimePts(void); - - int64_t Now(void) const; - void Set(int64_t Pts = 0LL); - - void Pause(void); - void Resume(void); - void TrickSpeed(const int Multiplier); - - void SetScrSpeed(const int ScrSpeed = 90000); -}; - -#endif // __TIME_PTS_H diff --git a/tools/timer.c b/tools/timer.c deleted file mode 100644 index f24e925a..00000000 --- a/tools/timer.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * timer.c: Threaded timer class - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: timer.c,v 1.2 2007-10-15 00:15:07 phintuka Exp $ - * - */ - -#include <sys/time.h> - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/thread.h> - -#include "timer.h" - -//#define XINELIBOUTPUT_DEBUG -//#define XINELIBOUTPUT_DEBUG_STDOUT -#ifdef XINELIBOUTPUT_DEBUG -# include "logdefs.h" -#else -# define TRACE(x) -# define TRACEF(x) -#endif - -// ---------------------------- cTimerThreadEvent ---------------------------- - -class cTimerThreadEvent : public cListObject { - public: - cTimerThreadEvent(cTimerCallback *Handler, unsigned int TimeoutMs, - bool DeleteOnCancel = false) : - m_Handler(Handler), - m_DeleteOnCancel(DeleteOnCancel), - m_TimeoutMs(TimeoutMs) - { - m_NextEventTime = cTimeMs::Now(); - UpdateEventTime(); - } - - ~cTimerThreadEvent() - { - if(m_DeleteOnCancel && m_Handler) - delete m_Handler; - } - - void UpdateEventTime() - { - m_NextEventTime += m_TimeoutMs; - } - - int TimeToNextEvent(void) - { - return m_NextEventTime - cTimeMs::Now(); - } - - virtual bool operator< (const cListObject &ListObject) - { - const cTimerThreadEvent *o = (cTimerThreadEvent *)&ListObject; - return m_NextEventTime<o->m_NextEventTime; - } - - virtual int Compare(const cListObject &ListObject) const - { - const cTimerThreadEvent *o = (cTimerThreadEvent *)&ListObject; - if(m_NextEventTime<o->m_NextEventTime) - return -1; - else if(m_NextEventTime>o->m_NextEventTime) - return 1; - return 0; - } - - cTimerCallback *m_Handler; - - protected: - bool m_DeleteOnCancel; - unsigned int m_TimeoutMs; - int64_t m_NextEventTime; -}; - -// ------------------------------- cTimerThread ------------------------------ - -class cTimerThread : public cThread { - private: - cTimerThread(cTimerThread&); // copy not allowed - - static cMutex m_InstanceLock; - static cTimerThread *m_Instance; // singleton - - cMutex m_Lock; - cCondVar m_Signal; - cList<cTimerThreadEvent> m_Events; - cTimerThreadEvent *m_RunningEvent; - bool m_Finished; - bool m_HandlerRunning; - - cTimerThread() : - m_RunningEvent(NULL), - m_Finished(false), - m_HandlerRunning(false) - { - } - - virtual ~cTimerThread() - { - m_Lock.Lock(); - cTimerThreadEvent *ev; - while(NULL != (ev = m_Events.First())) { - m_Events.Del(ev,true); - } - m_Lock.Unlock(); - m_Signal.Broadcast(); - Cancel(1); - } - - protected: - - virtual void Action() - { - TRACEF("cTimerThread::Action"); - m_Lock.Lock(); - while(m_Events.First()) { - m_Signal.TimedWait(m_Lock, - max(1, m_Events.First()->TimeToNextEvent())); - TRACE("cTimerThread::Action waked up"); - while(NULL != (m_RunningEvent = m_Events.First()) && - m_RunningEvent->TimeToNextEvent() <= 0) { - TRACE("cTimerThread::Action calling handler"); - m_HandlerRunning=true; -// m_Lock.Unlock(); -// - can't unlock or running timer handler may be deleted while -// executing (or thread may be killed by Delete) - bool result = m_RunningEvent->m_Handler->TimerEvent(); -// m_Lock.Lock(); - m_HandlerRunning=false; - if(!result) { - if(m_RunningEvent) { // check if event was cancelled in handler... - TRACE("cTimerThread::Action handler cancelled timer"); - m_Events.Del(m_RunningEvent, true); - } - } else { - if(m_RunningEvent) { - TRACE("cTimerThread::Action timer re-scheduled"); - m_RunningEvent->UpdateEventTime(); - m_Events.Sort(); - } - } - m_RunningEvent = NULL; - } - } - m_Finished = true; - m_Lock.Unlock(); - } - - void Add(cTimerThreadEvent *Event) - { - TRACEF("cTimerThread::Add"); - //m_Events.Del(Event, false); - Event->Unlink(); - Del(Event->m_Handler); - m_Events.Add(Event); - m_Events.Sort(); - } - - bool Del(cTimerCallback *Handler, void *TargetId=NULL, - bool inDestructor=false) - { - TRACEF("cTimerThread::Del"); - cTimerThreadEvent *ev = m_Events.First(); - while(ev) { - if(ev->m_Handler == Handler || - (TargetId && ev->m_Handler->TargetId() == TargetId) || - (Handler && ev->m_Handler->is(Handler,Handler->size()))) { - cTimerThreadEvent *nev = m_Events.Next(ev); - if(inDestructor) ev->m_Handler=NULL; - m_Events.Del(ev, true); - ev = nev; - } else - ev = m_Events.Next(ev); - } - if(m_RunningEvent && - (m_RunningEvent->m_Handler == Handler || - m_RunningEvent->m_Handler->TargetId() == TargetId)) - m_RunningEvent = NULL; - return !m_HandlerRunning && !m_RunningEvent && !m_Events.First(); - } - - public: - - static void AddEvent(cTimerCallback *Handler, unsigned int TimeoutMs, - bool DeleteOnCancel=false) - { - TRACEF("cTimerThread::AddEvent"); - m_InstanceLock.Lock(); - if(m_Instance && m_Instance->m_Finished) { - delete m_Instance; - m_Instance = NULL; - } - if(!m_Instance) { - m_Instance = new cTimerThread; - m_Instance->m_Lock.Lock(); - m_Instance->Start(); - } else { - m_Instance->m_Lock.Lock(); - m_Instance->m_Signal.Broadcast(); - } - m_Instance->Add(new cTimerThreadEvent(Handler, max(1U,TimeoutMs), - DeleteOnCancel)); - m_Instance->m_Lock.Unlock(); - m_InstanceLock.Unlock(); - } - - static void CancelEvent(cTimerCallback *Handler, void *TargetId = NULL, - bool inDestructor=false) - { - TRACEF("cTimerThread::CancelEvent"); - m_InstanceLock.Lock(); - if(m_Instance && !m_Instance->m_Finished) { - m_Instance->m_Lock.Lock(); - if(m_Instance->Del(Handler, TargetId, inDestructor) && !inDestructor) { - m_Instance->m_Lock.Unlock(); - delete m_Instance; - m_Instance = NULL; - } else - m_Instance->m_Lock.Unlock(); - } - m_InstanceLock.Unlock(); - } - -}; - -cMutex cTimerThread::m_InstanceLock; -cTimerThread *cTimerThread::m_Instance = NULL; - -// ------------------------------ cTimerCallback ----------------------------- - -cTimerCallback::~cTimerCallback() -{ - TRACEF("cTimerCallback::~cTimerCallback"); - cTimerThread::CancelEvent(this, NULL, true); -} - -void cTimerCallback::Set(cTimerCallback *handler, unsigned int TimeoutMs) -{ - TRACEF("cTimerCallback::Set"); - cTimerThread::AddEvent(handler, TimeoutMs); -} - -void cTimerCallback::Cancel(cTimerCallback *handler) -{ - TRACEF("cTimerCallback::Cancel"); - cTimerThread::CancelEvent(handler); -} - -// ------------------------------- cTimerEvent ------------------------------- - -//cTimerEvent::cTimerEvent(unsigned int TimeoutMs) -//{ -// TRACEF("cTimerEvent::cTimerEvent"); -//// cTimerThread::AddEvent(this, TimeoutMs, true); -//} - -void cTimerEvent::AddEvent(unsigned int TimeoutMs) -{ - TRACEF("cTimerEvent::AddEvent"); - cTimerThread::AddEvent(this, TimeoutMs, true); -} - -void cTimerEvent::Cancel(cTimerEvent *&event) -{ - TRACEF("cTimerEvent::Cancel"); - cTimerThread::CancelEvent(event); - event = NULL; -} - -void cTimerEvent::CancelAll(void *Target) -{ - TRACEF("cTimerEvent::CancelAll"); - cTimerThread::CancelEvent(NULL, Target); -} - - - - - - - diff --git a/tools/timer.h b/tools/timer.h deleted file mode 100644 index 2ee8724b..00000000 --- a/tools/timer.h +++ /dev/null @@ -1,296 +0,0 @@ -/* - * timer.h: Threaded timer class - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: timer.h,v 1.1 2006-06-03 10:04:28 phintuka Exp $ - * - */ - -#ifndef __XINELIBOUTPUT_TIMER_H -#define __XINELIBOUTPUT_TIMER_H - -// -// cTimerCallback : timer callback handler interface -// -class cTimerCallback { - protected: - virtual bool TimerEvent() = 0; // return false to cancel timer - - virtual void *TargetId() { return (void*)this; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return len==sizeof(*this) && TargetId()==data; - } - - friend class cTimerThread; - - public: - static void Set(cTimerCallback *, unsigned int TimeoutMs); - static void Cancel(cTimerCallback *); - - virtual ~cTimerCallback(); -}; - -// -// cTimerEvent : base class for timer events -// -class cTimerEvent : protected cTimerCallback { - private: - cTimerEvent(cTimerEvent&); - - protected: - cTimerEvent() {}; - - virtual void AddEvent(unsigned int TimeoutMs); - - static void CancelAll(void *Target); - - template<class TCLASS> friend void CancelTimerEvents(TCLASS*); - friend class cTimerThread; - - public: - static void Cancel(cTimerEvent *&); -}; - -// -// make gcc 3.4.5 happy -// -template<class TCLASS, class TRESULT> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(void), - unsigned int TimeoutMs); -template<class TCLASS, class TRESULT, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs); -template<class TCLASS> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(void), - unsigned int TimeoutMs, bool runOnce = true); -template<class TCLASS, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs, bool runOnce = true); - -// -// Timer event templates -// - -template <class TCLASS, class TRESULT> -class cTimerFunctorR0 : public cTimerEvent { - - public: - - protected: - typedef TRESULT (TCLASS::*TFUNC)(void); - - cTimerFunctorR0(TCLASS *obj, TFUNC f, unsigned int TimeoutMs) : - m_obj(obj), m_f(f) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctorR0() {}; - - virtual bool TimerEvent(void) - { - return (*m_obj.*m_f)(); - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - - friend cTimerEvent *CreateTimerEvent<TCLASS,TRESULT>(TCLASS*,TFUNC,unsigned int); -}; - -template <class TCLASS, class TRESULT, class TARG1> -class cTimerFunctorR1 : public cTimerEvent { - - public: - - protected: - typedef TRESULT (TCLASS::*TFUNC)(TARG1); - - cTimerFunctorR1(TCLASS *obj, TFUNC f, TARG1 arg1, unsigned int TimeoutMs) : - m_obj(obj), m_f(f), m_arg1(arg1) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctorR1() {}; - - virtual bool TimerEvent(void) - { - return (*m_obj.*m_f)(m_arg1); - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - - friend cTimerEvent *CreateTimerEvent<TCLASS,TRESULT,TARG1>(TCLASS*,TFUNC,TARG1,unsigned int); -}; - -template <class TCLASS> -class cTimerFunctor0 : public cTimerEvent { - - public: - - protected: - typedef void (TCLASS::*TFUNC)(void); - - cTimerFunctor0(TCLASS *obj, TFUNC f, - unsigned int TimeoutMs, bool runOnce) : - m_obj(obj), m_f(f), m_runAgain(!runOnce) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctor0() {}; - - virtual bool TimerEvent(void) - { - (*m_obj.*m_f)(); - return m_runAgain; - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - bool m_runAgain; - - friend cTimerEvent *CreateTimerEvent<TCLASS>(TCLASS*,TFUNC,unsigned int,bool); -}; - -template <class TCLASS, class TARG1> -class cTimerFunctor1 : public cTimerEvent { - - public: - - protected: - typedef void (TCLASS::*TFUNC)(TARG1); - - cTimerFunctor1(TCLASS *obj, TFUNC f, TARG1 arg1, - unsigned int TimeoutMs, bool runOnce) : - m_obj(obj), m_f(f), m_arg1(arg1), m_runAgain(!runOnce) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctor1() {}; - - virtual bool TimerEvent(void) - { - (*m_obj.*m_f)(m_arg1); - return m_runAgain; - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - bool m_runAgain; - - friend cTimerEvent *CreateTimerEvent<TCLASS,TARG1>(TCLASS*,TFUNC,TARG1,unsigned int,bool); -}; - -// -// Function templates for timer event creation and cancellation -// - -template<class TCLASS, class TRESULT> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(void), - unsigned int TimeoutMs) -{ - return new cTimerFunctorR0<TCLASS,TRESULT>(c,fp,TimeoutMs); -} - -template<class TCLASS, class TRESULT, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs) -{ - return new cTimerFunctorR1<TCLASS,TRESULT,TARG1>(c,fp,arg1,TimeoutMs); -} - -template<class TCLASS> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(void), - unsigned int TimeoutMs, bool runOnce = true) -{ - return new cTimerFunctor0<TCLASS>(c,fp,TimeoutMs,runOnce); -} - -template<class TCLASS, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs, bool runOnce = true) -{ - return new cTimerFunctor1<TCLASS,TARG1>(c,fp,arg1,TimeoutMs,runOnce); -} - -template<class TCLASS> -void CancelTimerEvents(TCLASS *c) -{ - cTimerEvent::CancelAll((void*)c); -} - - -// usage: -// -// 'this' derived from cTimerHandler: -// Set timer: -// cTimerCallback::Set(this, TimeoutMs); -// Cancel timer: -// - return false from handler or -// - call cTimerCallback::Cancel(this); or -// - delete 'this' object -// -// any function of any class: -// Set timer: -// - cTimerEvent *event = CreateTimerEvent(...); -// example: -// CreateTimerEvent(this, &cXinelibDevice::TimerEvent, 1, 1000); -// -> calls this->cXinelibDevice::TimerEvent(1) every second until stopped. -// Cancel timer: -// - if handler returns bool: return false from handler -// - handler is type of void: timer runs only once -// - call cTimerEvent::Cancel(event) -// Cancel all timers for object: -// - Call CancelTimerEvents(object) -// - Call CancelTimerEvents(this) - - -#endif // __XINELIBOUTPUT_TIMER_H - - diff --git a/tools/ts.c b/tools/ts.c deleted file mode 100644 index 3177bf5f..00000000 --- a/tools/ts.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * ts.c: MPEG-TS - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts.c,v 1.11 2009-07-03 05:37:05 phintuka Exp $ - * - */ - -/*#define LOG_PCR*/ -/*#define LOG_PMT*/ - -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> - -#ifndef LOG_MODULENAME -# define LOG_MODULENAME "[mpeg-ts ] " -# define SysLogLevel iSysLogLevel -# include "../logdefs.h" -#endif - -#include "mpeg.h" -#include "ts.h" -#include "pes.h" - -#ifdef LOG_PMT -# define LOGPMT LOGMSG -#else -# define LOGPMT(x...) -#endif - -#ifdef LOG_PCR -# define LOGPCR LOGMSG -#else -# define LOGPCR(x...) -#endif - - -/* - * ts_compute_crc32() - * - * taken from xine-lib demux_ts.c - */ -static uint32_t ts_compute_crc32(const uint8_t *data, uint32_t length, uint32_t crc32) -{ - static uint32_t crc32_table[256]; - static uint init_done = 0; - - if (!init_done) { - uint32_t i, j, k; - init_done = 1; - for (i = 0 ; i < 256 ; i++) { - k = 0; - for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) - k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); - crc32_table[i] = k; - } - } - - uint32_t i; - for(i = 0; i < length; i++) - crc32 = (crc32 << 8) ^ crc32_table[(crc32 >> 24) ^ data[i]]; - - return crc32; -} - -/* - * parse_pat() - * - * - parse PAT for PMT pid and program number - * - * modified from xine-lib demux_ts.c - */ -int ts_parse_pat(pat_data_t *pat, const uint8_t *pkt) -{ - const uint8_t *original_pkt = pkt; - - if (! ts_PAYLOAD_START(pkt)) { - LOGMSG ("parse_pat: PAT without payload unit start indicator"); - return 0; - } - - /* jump to payload */ - pkt += pkt[4]; /* pointer */ - if (pkt - original_pkt > TS_SIZE) { - LOGMSG("parse_pat: PAT with invalid pointer"); - return 0; - } - - uint section_syntax_indicator = ((pkt[6] >> 7) & 0x01) ; - uint section_length = ((pkt[6] & 0x03) << 8) | pkt[7]; -/*uint transport_stream_id = (pkt[8] << 8) | pkt[9];*/ -/*uint version_number = (pkt[10] >> 1) & 0x1f;*/ - uint current_next_indicator = pkt[10] & 0x01; - uint section_number = pkt[11]; - uint last_section_number = pkt[12]; - uint32_t crc32, calc_crc32; - - crc32 = pkt[section_length + 4] << 24; - crc32 |= pkt[section_length + 5] << 16; - crc32 |= pkt[section_length + 6] << 8; - crc32 |= pkt[section_length + 7] ; - - if ((section_syntax_indicator != 1) || !(current_next_indicator)) { - LOGMSG("parse_pat: ssi error"); - return 0; - } - - if (pkt - original_pkt > TS_SIZE - 4 - 1 - 3 - (int)section_length) { - LOGMSG("parse_pat: unsupported PAT does not fit to single TS packet"); - return 0; - } - - if ((section_number != 0) || (last_section_number != 0)) { - LOGMSG("parse_pat: unsoupported PAT consists of multiple (%d) sections", last_section_number); - return 0; - } - - /* Check CRC */ - calc_crc32 = ts_compute_crc32 (pkt + 5, section_length + 3 - 4, 0xffffffff); - if (crc32 != calc_crc32) { - LOGMSG("parse_pat: invalid CRC"); - return 0; - } - - /* - * Process all programs in the program loop - */ - - const uint8_t *program; - uint program_count; - - program_count = 0; - for (program = pkt + 13; - program < pkt + 13 + section_length - 9; - program += 4) { - uint program_number = (program[0] << 8) | program[1]; - uint pmt_pid = ((program[2] & 0x1f) << 8) | program[3]; - - /* skip NIT pids */ - if (program_number == 0x0000) - continue; - - pat->program_number[program_count] = program_number; - pat->pmt_pid[program_count] = pmt_pid; - - LOGDBG("PAT acquired count=%d programNumber=0x%04x pmtPid=0x%04x", - program_count, - pat->program_number[program_count], - pat->pmt_pid[program_count]); - - program_count++; - } - - pat->program_number[program_count] = 0; - - return program_count; -} - -/* - * ts_get_reg_desc() - * - * Find the registration code (tag=5) and return it as a uint32_t - * This should return "AC-3" or 0x41432d33 for AC3/A52 audio tracks. - * - * taken from xine-lib demux_ts.c - */ -static void ts_get_reg_desc(uint32_t *dest, const uint8_t *data, int length) -{ - const unsigned char *d = data; - - while (d < (data + length)) { - if (d[0] == 5 && d[1] >= 4) { - *dest = (d[2] << 24) | (d[3] << 16) | (d[4] << 8) | d[5]; - LOGPMT("parse_pmt: found registration format identifier 0x%.4x", *dest); - return; - } - d += 2 + d[1]; - } - LOGPMT("pare_pmt: found no format id"); - *dest = 0; -} - -/* - * ts_parse_pmt() - * - * modified from xine-lib demux_ts.c - */ -int ts_parse_pmt (pmt_data_t *pmt, uint program_no, const uint8_t *pkt) -{ - const uint8_t *originalPkt = pkt; - const uint8_t *ptr = NULL; - uint pusi = ts_PAYLOAD_START(pkt); - - uint32_t section_syntax_indicator; - uint32_t section_length = 0; /* to calm down gcc */ - uint32_t program_number; - uint32_t version_number; - uint32_t current_next_indicator; - uint32_t section_number; - uint32_t last_section_number; - uint32_t program_info_length; - uint32_t crc32; - uint32_t calc_crc32; - uint32_t coded_length; - uint pid; - uint8_t *stream; - uint i; - int count; - uint8_t len; - uint offset = 0; - - /* - * A new section should start with the payload unit start - * indicator set. We allocate some mem (max. allowed for a PM section) - * to copy the complete section into one chunk. - */ - if (pusi) { - pkt += pkt[4]; /* pointer */ - offset = 1; - - if (pmt->pmt != NULL) - free(pmt->pmt); - pmt->pmt = (uint8_t *) calloc(4096, sizeof(uint8_t)); - pmt->pmt_write_ptr = pmt->pmt; - - section_syntax_indicator = (pkt[6] >> 7) & 0x01; - section_length = ((pkt[6] << 8) | pkt[7]) & 0x03ff; - program_number = (pkt[8] << 8) | pkt[9]; - version_number = (pkt[10] >> 1) & 0x1f; - current_next_indicator = pkt[10] & 0x01; - section_number = pkt[11]; - last_section_number = pkt[12]; - - LOGPMT("PMT: section_syntax: %d", section_syntax_indicator); - LOGPMT(" section_length: %d", section_length); - LOGPMT(" program_number: %#.4x", program_number); - LOGPMT(" version_number: %d", version_number); - LOGPMT(" c/n indicator: %d", current_next_indicator); - LOGPMT(" section_number: %d", section_number); - LOGPMT(" last_section_number: %d", last_section_number); - - if ((section_syntax_indicator != 1) || !current_next_indicator) { - LOGMSG("parse_pmt: ssi error"); - return 0; - } - - if (program_number != program_no) { - /* several programs can share the same PMT pid */ - LOGMSG("parse_pmt: program number %i, looking for %i", program_number, program_no); - return 0; - } - - if ((section_number != 0) || (last_section_number != 0)) { - LOGMSG("parse_pmt: unsupported PMT (%d sections)", last_section_number); - return 0; - } - } - - if (!pusi) { - section_length = (pmt->pmt[1] << 8 | pmt->pmt[2]) & 0x03ff; - version_number = (pkt[10] >> 1) & 0x1f; - } - - count = ts_PAYLOAD_SIZE(originalPkt); - - ptr = originalPkt + offset + (TS_SIZE - count); - len = count - offset; - memcpy(pmt->pmt_write_ptr, ptr, len); - pmt->pmt_write_ptr += len; - - if (pmt->pmt_write_ptr < pmt->pmt + section_length) { - LOGPMT("parse_pmt: didn't get all PMT TS packets yet..."); - return 0; - } - - if (!section_length) { - free(pmt->pmt); - pmt->pmt = NULL; - LOGMSG("parse_pmt: zero-length section"); - return 0; - } - - LOGPMT("parse_pmt: have all TS packets for the PMT section"); - - crc32 = (uint32_t) pmt->pmt[section_length+3-4] << 24; - crc32 |= (uint32_t) pmt->pmt[section_length+3-3] << 16; - crc32 |= (uint32_t) pmt->pmt[section_length+3-2] << 8; - crc32 |= (uint32_t) pmt->pmt[section_length+3-1] ; - - /* Check CRC. */ - calc_crc32 = ts_compute_crc32 (pmt->pmt, section_length + 3 - 4, 0xffffffff); - if (crc32 != calc_crc32) { - LOGMSG("parse_pmt: invalid CRC32"); - return 0; - } - - if (crc32 == pmt->crc32 && version_number == pmt->version_number) { - LOGPMT("parse_pmt: PMT with CRC32=%d already parsed. Skipping.", crc32); - return 0; - } - - LOGPMT("parse_pmt: new PMT, parsing..."); - pmt->crc32 = crc32; - pmt->version_number = version_number; - - /* reset PIDs */ - pmt->audio_tracks_count = 0; - pmt->spu_tracks_count = 0; - pmt->video_pid = INVALID_PID; - - /* ES definitions start here */ - program_info_length = ((pmt->pmt[10] << 8) | pmt->pmt[11]) & 0x0fff; - - stream = &pmt->pmt[12] + program_info_length; - coded_length = 13 + program_info_length; - if (coded_length > section_length) { - LOGMSG("parse_pmt: PMT with inconsistent progInfo length"); - return 0; - } - section_length -= coded_length; - - - /* - * Extract the elementary streams. - */ - while (section_length > 0) { - unsigned int stream_info_length; - - pid = ((stream[1] << 8) | stream[2]) & 0x1fff; - stream_info_length = ((stream[3] << 8) | stream[4]) & 0x0fff; - coded_length = 5 + stream_info_length; - if (coded_length > section_length) { - LOGMSG("parse_pmt: PMT with inconsistent streamInfo length"); - return 0; - } - - switch (stream[0]) { - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - case ISO_14496_PART2_VIDEO: - case ISO_14496_PART10_VIDEO: - LOGPMT("parse_pmt: video pid 0x%.4x type %2.2x", pid, stream[0]); - if (pmt->video_pid == INVALID_PID) { - pmt->video_pid = pid; - pmt->video_type = (ts_stream_type)stream[0]; - } - break; - - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: - if (pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS) { - int i, found = 0; - for (i = 0; i < pmt->audio_tracks_count; i++) { - if (pmt->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if (!found) { - LOGPMT("parse_pmt: audio pid 0x%.4x type %2.2x", pid, stream[0]); - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = (ts_stream_type)stream[0]; - /* ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - } - } - break; - - case ISO_13818_PRIVATE: - case ISO_13818_TYPE_C: - break; - - case ISO_13818_PES_PRIVATE: - for (i = 5; i < coded_length; i += stream[i+1] + 2) { - if ((stream[i] == 0x6a) && (pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS)) { - int i, found = 0; - for (i = 0; i < pmt->audio_tracks_count; i++) { - if (pmt->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if (!found) { - LOGPMT("parse_pmt: AC3 audio pid 0x%.4x type %2.2x", pid, stream[0]); - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = (ts_stream_type)stream[0]; - /* demux_ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - break; - } - } - /* DVBSUB */ - else if (stream[i] == 0x59) { - uint pos; - for (pos = i + 2; - pos + 8 <= i + 2 + stream[i + 1] - && pmt->spu_tracks_count < TS_MAX_SPU_TRACKS; - pos += 8) { - int no = pmt->spu_tracks_count; - - pmt->spu_tracks_count++; - - memcpy(pmt->spu_tracks[no].lang, &stream[pos], 3); - pmt->spu_tracks[no].lang[3] = 0; - pmt->spu_tracks[no].comp_page_id = (stream[pos + 4] << 8) | stream[pos + 5]; - pmt->spu_tracks[no].aux_page_id = (stream[pos + 6] << 8) | stream[pos + 7]; - pmt->spu_tracks[no].pid = pid; - - LOGPMT("parse_pmt: DVBSUB pid 0x%.4x: %s page %d %d type %2.2x", pid, - pmt->spu_tracks[no].lang, pmt->spu_tracks[no].comp_page_id, - pmt->spu_tracks[no].aux_page_id, stream[0]); - } - } - } - break; - - default: - - /* This following section handles all the cases where the audio track info is stored - * in PMT user info with stream id >= 0x80 - * We first check that the stream id >= 0x80, because all values below that are - * invalid if not handled above, then we check the registration format identifier - * to see if it holds "AC-3" (0x41432d33) and if is does, we tag this as an audio stream. - */ - if ((pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) { - int i, found = 0; - for (i = 0; i < pmt->audio_tracks_count; i++) { - if (pmt->audio_tracks[i].pid == pid) { - found = 1; - break; - } - } - if (!found) { - uint32_t format_identifier = 0; - ts_get_reg_desc(&format_identifier, stream + 5, stream_info_length); - /* If no format identifier, assume A52 */ - if ((format_identifier == 0x41432d33) || (format_identifier == 0)) { - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = (ts_stream_type)stream[0]; - /* ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - break; - } - } - } else { - LOGPMT("parse_pmt: unknown stream_type: 0x%.2x pid: 0x%.4x", stream[0], pid); - } - break; - } - stream += coded_length; - section_length -= coded_length; - } - - - /* - * Get the current PCR PID. - */ - pid = ((pmt->pmt[8] << 8) | pmt->pmt[9]) & 0x1fff; - if (pmt->pcr_pid != pid) { - - if (pmt->pcr_pid == INVALID_PID) - LOGPMT("parse_pmt: pcr pid 0x%.4x", pid); - else - LOGPMT("parse_pmt: pcr pid changed 0x%.4x", pid); - - pmt->pcr_pid = pid; - } - - return 1; -} - -/* - * ts_get_pcr() - */ -static int ts_get_pcr_1(const uint8_t *pkt, int64_t *ppcr) -{ - if (!ts_ADAPT_FIELD_EXISTS(pkt)) { - return 0; - } - - if (ts_HAS_ERROR(pkt)) { - LOGMSG("ts_get_pcr: transport error"); - return 0; - } - - /* pcr flag ? */ - if (! (pkt[5] & 0x10)) - return 0; - - int64_t pcr; - uint epcr; - - pcr = ((int64_t) pkt[6]) << 25; - pcr += (int64_t) (pkt[7] << 17); - pcr += (int64_t) (pkt[8] << 9); - pcr += (int64_t) (pkt[9] << 1); - pcr += (int64_t) ((pkt[10] & 0x80) >> 7); - - epcr = ((pkt[10] & 0x1) << 8) | pkt[11]; - - LOGPCR("ts_get_pcr: PCR: %"PRId64", EPCR: %u", pcr, epcr); - *ppcr = pcr; - return 1; -} - -int64_t ts_get_pcr(const uint8_t *pkt) -{ - int64_t pcr = NO_PTS; - ts_get_pcr_1(pkt, &pcr); - return pcr; -} - -int ts_get_pcr_n(const uint8_t *pkt, int npkt, int64_t *pcr) -{ - pkt += TS_SIZE * npkt; - while (npkt > 0) { - npkt--; - pkt -= TS_SIZE; - if (ts_get_pcr_1(pkt, pcr)) - return 1; - } - return 0; -} - - -/* - * ts_state_t - */ - -struct ts_state_s { - - uint8_t pusi_seen; - - uint8_t inside_pes; /* Scanning ES (PES start code seen and skipped) */ - - uint32_t buf_len; /* bytes queued */ - uint32_t buf_size; /* buffer size */ - uint8_t buf[0]; /* payload: partial PES / video stream header etc. */ -}; - -ts_state_t *ts_state_init(int buffer_size) -{ - if (buffer_size < 8 * TS_SIZE) - buffer_size = 8 * TS_SIZE; - - ts_state_t *ts = (ts_state_t*)calloc(1, sizeof(ts_state_t) + buffer_size); - ts->buf_size = buffer_size; - return ts; -} - -void ts_state_reset(ts_state_t *ts) -{ - int buf_size = ts->buf_size; - memset(ts, 0, sizeof(ts_state_t)); - ts->buf_size = buf_size; -} - -void ts_state_dispose(ts_state_t *ts) -{ - free(ts); -} - -/* - * ts_add_payload() - * - * Add TS packet payload to buffer. - * - PUSI resets the buffer - * - all data before first PUSI is discarded - */ -static int ts_add_payload(ts_state_t *ts, const uint8_t *data) -{ - /* start from PUSI */ - if (!ts->pusi_seen) { - if (!ts_PAYLOAD_START(data)) - return 0; - ts->pusi_seen = 1; - ts->buf_len = 0; - } - - if (ts->buf_len >= ts->buf_size - TS_SIZE) { - LOGMSG("ts_add_payload: buffer full"); - ts->buf_len -= TS_SIZE; - memcpy(ts->buf, ts->buf+TS_SIZE, ts->buf_len); - } - - int len = ts_PAYLOAD_SIZE(data); - if (len > 0) { - memcpy(ts->buf + ts->buf_len, ts_GET_PAYLOAD(data), len); - ts->buf_len += len; - } - - return ts->buf_len; -} - -/* - * ts_skip_payload() - */ -static void ts_skip_payload(ts_state_t *ts, unsigned int n) -{ - if (n < ts->buf_len) { - ts->buf_len -= n; - memcpy(ts->buf, ts->buf + n, ts->buf_len); - } else { - ts->buf_len = 0; - } -} - -/* - * ts_scan_startcode() - * - * - discard all data until startcode (00 00 01) is found - * - returns number of bytes left - */ -static int ts_scan_startcode(ts_state_t *ts) -{ - if (ts->buf_len > 2) { - /* scan for PES or MPEG 00 00 01 */ - unsigned int i = 0, n = ts->buf_len - 2; - while (i < n) { - if (ts->buf[i+2] != 1) - i += 3; - else if(ts->buf[i+1]) - i += 2; - else if(ts->buf[i]) - i++; - else - break; - } - - /* skip data until start code */ - ts_skip_payload(ts, i); - } - - return ts->buf_len; -} - -/* - * ts_get_pes() - * - * - scan for PES start - * - return (PES) bytes queued - */ -static int ts_get_pes(ts_state_t *ts, const uint8_t *data) -{ - if (ts_add_payload(ts, data) > 0) - return ts_scan_startcode(ts); - return 0; -} - -/* - * ts_get_pts() - */ - -int64_t ts_get_pts(ts_state_t *ts, const uint8_t *data) -{ - int64_t pts = NO_PTS; - int cnt = ts_get_pes(ts, data); - - if (cnt > 14) { - pts = pes_get_pts(ts->buf, ts->buf_len); - - if (pts < 0 && cnt > 2*TS_SIZE) - ts_state_reset(ts); - } - - return pts; -} - -/* - * ts_get_picture_type() - */ - -int ts_get_picture_type(ts_state_t *ts, const uint8_t *data, int h264) -{ - int pic = NO_PICTURE; - return pic; -} - -/* - * ts_get_video_size() - */ - -int ts_get_video_size(ts_state_t *ts, const uint8_t *data, video_size_t *size, int h264) -{ - return 0; -} diff --git a/tools/ts.h b/tools/ts.h deleted file mode 100644 index ca5ec516..00000000 --- a/tools/ts.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * ts.h: MPEG-TS header definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts.h,v 1.11 2009-07-03 05:37:05 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_TS_H_ -#define _XINELIBOUTPUT_TS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Avoid warnings when included to VDR plugin */ -#undef TS_SYNC_BYTE -#undef TS_SIZE -#undef TS_PAYLOAD_EXISTS -#undef TS_ADAPT_FIELD_EXISTS -#undef TS_PAYLOAD_START -#undef TS_ERROR -#undef TS_PID_MASK_HI - -/* - * Constants - */ - -#define TS_SYNC_BYTE 0x47 -#define TS_SIZE 188 -#define TS_ADAPT_FIELD_EXISTS 0x20 -#define TS_PAYLOAD_EXISTS 0x10 -#define TS_PAYLOAD_START 0x40 -#define TS_ERROR 0x80 -#define TS_PID_MASK_HI 0x1F - -#define ts_HAS_PAYLOAD(ts) ((ts)[3] & TS_PAYLOAD_EXISTS) -#define ts_PAYLOAD_START(ts) ((ts)[1] & TS_PAYLOAD_START) -#define ts_HAS_ERROR(ts) ((ts)[1] & TS_ERROR) -#define ts_PID(ts) ((((ts)[1] & TS_PID_MASK_HI) << 8) + (ts)[2]) -#define ts_PAYLOAD_OFFSET(ts) (((ts)[3] & TS_ADAPT_FIELD_EXISTS) ? (ts)[4] + 5 : 4) - -#define ts_GET_PAYLOAD(ts) ((ts) + ts_PAYLOAD_OFFSET(ts)) -#define ts_PAYLOAD_SIZE(ts) (TS_SIZE - ts_PAYLOAD_OFFSET(ts)) - -#define ts_ADAPT_FIELD_EXISTS(ts) ((ts)[3] & TS_ADAPT_FIELD_EXISTS) -#define ts_ADAPT_FIELD_LENGTH(ts) (ts_ADAPT_FIELD_EXISTS(ts) ? (ts)[4] : 0) - - -#define DATA_IS_TS(data) ((data)[0] == TS_SYNC_BYTE) - - -typedef enum { - ISO_11172_VIDEO = 0x01, /* ISO/IEC 11172 Video */ - ISO_13818_VIDEO = 0x02, /* ISO/IEC 13818-2 Video */ - ISO_11172_AUDIO = 0x03, /* ISO/IEC 11172 Audio */ - ISO_13818_AUDIO = 0x04, /* ISO/IEC 13818-3 Audi */ - ISO_13818_PRIVATE = 0x05, /* ISO/IEC 13818-1 private sections */ - ISO_13818_PES_PRIVATE = 0x06, /* ISO/IEC 13818-1 PES packets containing private data */ - ISO_13522_MHEG = 0x07, /* ISO/IEC 13512 MHEG */ - ISO_13818_DSMCC = 0x08, /* ISO/IEC 13818-1 Annex A DSM CC */ - ISO_13818_TYPE_A = 0x0a, /* ISO/IEC 13818-6 Multiprotocol encapsulation */ - ISO_13818_TYPE_B = 0x0b, /* ISO/IEC 13818-6 DSM-CC U-N Messages */ - ISO_13818_TYPE_C = 0x0c, /* ISO/IEC 13818-6 Stream Descriptors */ - ISO_13818_TYPE_D = 0x0d, /* ISO/IEC 13818-6 Sections (any type, including private data) */ - ISO_13818_AUX = 0x0e, /* ISO/IEC 13818-1 auxiliary */ - ISO_13818_PART7_AUDIO = 0x0f, /* ISO/IEC 13818-7 Audio with ADTS transport sytax */ - ISO_14496_PART2_VIDEO = 0x10, /* ISO/IEC 14496-2 Visual (MPEG-4) */ - ISO_14496_PART3_AUDIO = 0x11, /* ISO/IEC 14496-3 Audio with LATM transport syntax */ - ISO_14496_PART10_VIDEO = 0x1b, /* ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) */ - STREAM_VIDEO_MPEG = 0x80, - STREAM_AUDIO_AC3 = 0x81, - STREAM_DVBSUB = 0x100 -} ts_stream_type; - - -/* - * PAT - */ - -#define TS_MAX_PROGRAMS 64 -#define TS_MAX_PMTS 32 -#define TS_MAX_AUDIO_TRACKS 32 -#define TS_MAX_SPU_TRACKS 32 - -typedef struct { - int program_number[TS_MAX_PROGRAMS]; - uint16_t pmt_pid[TS_MAX_PROGRAMS]; -} pat_data_t; - -int ts_parse_pat(pat_data_t *pat_data, const uint8_t *ts_data); - - -/* - * PMT - */ - -#define INVALID_PID 0xffff - -typedef struct { - uint8_t *pmt; /* raw data */ - uint8_t *pmt_write_ptr; - - uint32_t crc32; - uint version_number; - - uint16_t pcr_pid; - uint16_t video_pid; - ts_stream_type video_type; - - uint8_t audio_tracks_count; - uint8_t spu_tracks_count; - - struct { - uint16_t pid; - ts_stream_type type; - /*uint8_t lang[8];*/ - } audio_tracks[TS_MAX_AUDIO_TRACKS]; - - struct { - uint16_t pid; - uint8_t lang[8]; - uint16_t comp_page_id; - uint16_t aux_page_id; - } spu_tracks[TS_MAX_SPU_TRACKS]; - -} pmt_data_t; - -/* - * parse_pmt() - * - * returns 1 : PMT parsed and changed - * 0 : error or unchanged pmt - */ -int ts_parse_pmt(pmt_data_t *pmt, uint program_no, const uint8_t *ts_data); - -/* - * PCR - */ - -int64_t ts_get_pcr(const uint8_t *data); -int ts_get_pcr_n(const uint8_t *pkt, int npkt, int64_t *pcr); - -/* - * TS->ES, simple ES parsers - */ - -typedef struct ts_state_s ts_state_t; -struct video_size_s; - -ts_state_t *ts_state_init(int buffer_size); -void ts_state_reset(ts_state_t *ts); -void ts_state_dispose(ts_state_t *ts); - -int64_t ts_get_pts(ts_state_t *ts, const uint8_t *data); -int ts_get_picture_type(ts_state_t *ts, const uint8_t *data, int h264); -int ts_get_video_size(ts_state_t *ts, const uint8_t *data, struct video_size_s *size, int h264); - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - -#endif // _XINELIBOUTPUT_TS_H_ diff --git a/tools/udp_buffer.h b/tools/udp_buffer.h deleted file mode 100644 index 6044b794..00000000 --- a/tools/udp_buffer.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * udp_buffer.h: Ring buffer for UDP/RTP streams - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: udp_buffer.h,v 1.6 2009-03-24 19:35:23 phintuka Exp $ - * - */ - -#ifndef __UDP_BUFFER_H -#define __UDP_BUFFER_H - -#include <stdint.h> - -#include <vdr/config.h> // VDRVERSNUM - -#include "../xine_input_vdr_net.h" // frame headers -#include "ts.h" - -#define UDP_BUFFER_SIZE 0x100 // 2^n -#define UDP_BUFFER_MASK 0xff // 2^n - 1 - -#if UDP_BUFFER_MASK != UDP_SEQ_MASK -# error Buffer handling error !!! -#endif - - -class cUdpBackLog -{ - friend class cUdpScheduler; - - private: - - cUdpBackLog(cUdpBackLog&); - - stream_rtp_header_impl_t *m_UdpBuffer[UDP_BUFFER_SIZE]; - int m_UdpBufLen[UDP_BUFFER_SIZE]; /* size of allocated memory, not frame */ - int m_PayloadSize[UDP_BUFFER_SIZE]; /* size of frame */ - unsigned int m_SeqNo; /* next (outgoing) sequence number */ - unsigned int m_RtpSeqNo; /* next (outgoing) RTP sequence number */ - - protected: - - cUdpBackLog() - { - memset(m_UdpBuffer, 0, sizeof(stream_rtp_header_impl_t *)*UDP_BUFFER_SIZE); - memset(m_UdpBufLen, 0, sizeof(int) * UDP_BUFFER_SIZE); - memset(m_PayloadSize, 0, sizeof(int) * UDP_BUFFER_SIZE); - m_SeqNo = 0; - m_RtpSeqNo = random(); - } - - void Clear(int HowManyFrames) - { - // Clear n last frames from buffer. - // (called to adjust sequence numbering when some - // already allocated frames won't be sent) - // - // Note: Nothing is freed. - // To completely reset buffer it must be deleted and re-created. - // - m_SeqNo = (m_SeqNo + UDP_BUFFER_SIZE - HowManyFrames) & UDP_BUFFER_MASK; - } - - virtual ~cUdpBackLog() - { - for(int i=0; i<UDP_BUFFER_SIZE; i++) - if(m_UdpBuffer[i]) { - //m_UdpBufLen[i] = 0; - delete[] m_UdpBuffer[i]; - m_UdpBuffer[i] = NULL; - } - } - - stream_rtp_header_impl_t *Get(int UdpSeqNo) - { - int BufIndex = UdpSeqNo & UDP_BUFFER_MASK; - return m_UdpBuffer[BufIndex]; - } - - int PayloadSize(int UdpSeqNo) - { - int BufIndex = UdpSeqNo & UDP_BUFFER_MASK; - return m_UdpBuffer[BufIndex] ? m_PayloadSize[BufIndex] : 0; - } - - stream_rtp_header_impl_t *MakeFrame(uint64_t StreamPos, - const uchar *Data, int DataLen) - { - int UdpPacketLen = DataLen + sizeof(stream_rtp_header_impl_t); - int BufIndex = m_SeqNo & UDP_BUFFER_MASK; - - // old buffer too small ? free it - if(m_UdpBuffer[BufIndex] && m_UdpBufLen[BufIndex] < UdpPacketLen) { - delete[] m_UdpBuffer[BufIndex]; - m_UdpBuffer[BufIndex] = NULL; - } - - // no buffer ? alloc it - if(!m_UdpBuffer[BufIndex]) { - m_UdpBuffer[BufIndex] = (stream_rtp_header_impl_t*)new uchar[UdpPacketLen]; - m_UdpBufLen[BufIndex] = UdpPacketLen; - } - m_PayloadSize[BufIndex] = DataLen; - - // Fill frame to buffer - stream_rtp_header_impl_t *header = m_UdpBuffer[BufIndex]; - - memcpy(header->payload, Data, DataLen); - - // RTP header - header->rtp_hdr.raw[0] = RTP_VERSION_BYTE | RTP_HDREXT_BIT; -#if VDRVERSNUM >= 10701 - if (DATA_IS_TS(Data)) - header->rtp_hdr.raw[1] = RTP_PAYLOAD_TYPE_TS; - else - header->rtp_hdr.raw[1] = RTP_PAYLOAD_TYPE_PES; -#else - header->rtp_hdr.raw[1] = RTP_PAYLOAD_TYPE_PES; -#endif - header->rtp_hdr.seq = htons(m_RtpSeqNo & 0xFFFF); - /*header->rtp_hdr.ts = htonl((uint32_t)(RtpScr.Now() & 0xffffffff));*/ - /*header->rtp_hdr.ssrc = htonl(m_ssrc);*/ - - // RTP header extension - header->hdr_ext.hdr.size = htons(RTP_HEADER_EXT_X_SIZE); - header->hdr_ext.hdr.type = htons(RTP_HEADER_EXT_X_TYPE); - - // UDP header - header->hdr_ext.pos = htonull(StreamPos); - header->hdr_ext.seq = htons(m_SeqNo); - - header->hdr_ext.padding1 = 0; - - m_RtpSeqNo = (m_RtpSeqNo + 1) & 0xFFFF; - m_SeqNo = (m_SeqNo + 1) & UDP_SEQ_MASK; - - return header; - } -}; - - -#endif diff --git a/tools/udp_pes_scheduler.c b/tools/udp_pes_scheduler.c deleted file mode 100644 index 0de6997e..00000000 --- a/tools/udp_pes_scheduler.c +++ /dev/null @@ -1,945 +0,0 @@ -/* - * udp_pes_scheduler.h: PES scheduler for UDP/RTP streams - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: udp_pes_scheduler.c,v 1.46 2009-07-02 10:38:29 phintuka Exp $ - * - */ - -//#define LOG_UDP_RATE -//#define LOG_RESEND -//#define LOG_SCR - -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS -#include <inttypes.h> - -#include <stdint.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/videodir.h> - -#include "../logdefs.h" // logging -#include "../config.h" // configuration data -#include "../xine_input_vdr_net.h" // frame headers and constants - -#include "pes.h" -#include "udp_buffer.h" -#include "udp_pes_scheduler.h" -#include "time_pts.h" -#include "cxsocket.h" -#include "sap.h" // SAP - Session Announcement Protocol -#include "sdp.h" // SDP - Session Description Protocol -#include "rtcp.h" // RTCP - - -#ifdef LOG_RESEND -# define LOGRESEND LOGDBG -#else -# define LOGRESEND(x...) -#endif - -#ifdef LOG_SCR -# define LOGSCR LOGDBG -#else -# define LOGSCR(x...) -#endif - -/* - * constants - */ - -const uint MAX_QUEUE_SIZE = 64; // ~ 65 ms with typical DVB stream -const uint MAX_LIVE_QUEUE_SIZE = (64+60); // ~ 100 ms with typical DVB stream -const uint HARD_LIMIT = (4*1024); // ~ 40 Mbit/s === 4 Mb/s - -const uint MAX_BURST_BYTES = 32768; // 32 kb -const uint MAX_BURST_FRAMES = 15; // 15 UDP packets - -const uint RTCP_MIN_INTERVAL = 45000; // 500 ms (pts units) - -// initial burst length after seek (500ms = ~13 video frames) -const int64_t INITIAL_BURST_TIME = INT64_C(45000); // pts units (90kHz) - -// assume seek when when pts difference between two frames exceeds this (2,5 seconds) -const int64_t JUMP_LIMIT_TIME = INT64_C(225000); // pts units (90kHz) - -const uint SCHEDULER_MIN_DELAY_MS = 3; -const uint SCHEDULER_MAX_DELAY_MS = 20; - - -typedef enum { - eScrDetect, - eScrFromAudio, - eScrFromPS1, - eScrFromVideo -} ScrSource_t; - - -cUdpScheduler::cUdpScheduler() -{ - - // Scheduler data - - m_CurrentAudioVtime = 0; - m_CurrentVideoVtime = 0; - m_MasterClock.Set(INT64_C(0)); - - m_BurstBytes = 0; - m_BurstFrames = 0; - - m_Master = false; - m_TrickSpeed = false; - - // RTP - - srandom(time(NULL) ^ getpid()); - - m_ssrc = random(); - LOGDBG("RTP SSRC: 0x%08x", m_ssrc); - m_LastRtcpTime = 0; - m_Frames = 0; - m_Octets = 0; - m_RtpScr.Set((int64_t)random()); - - m_fd_sap = -1; - - // Queuing - - int i; - for(i=0; i<MAX_UDP_HANDLES; i++) - m_Handles[i] = -1; - - m_BackLog = new cUdpBackLog; - - m_QueueNextSeq = 0; - m_QueuePending = 0; - - // Thread - - Start(); -} - -cUdpScheduler::~cUdpScheduler() -{ - m_Lock.Lock(); - - Cancel(-1); - m_Cond.Broadcast(); - m_CondWait.Signal(); - m_Lock.Unlock(); - - Cancel(3); - - if(m_fd_rtcp.open() || m_fd_rtp.open()) - Send_SAP(false); - - CLOSESOCKET(m_fd_sap); - - delete m_BackLog; -} - -void cUdpScheduler::Scheduler_Sleep(int ms) -{ - m_CondWait.Wait(ms); - m_BurstBytes = 0; - m_BurstFrames = 0; -} - -bool cUdpScheduler::AddRtp(void) -{ - cMutexLock ml(&m_Lock); - - if(m_fd_rtcp.open()) { - LOGERR("cUdpScheduler::AddHandle: RTCP socket already open !"); - Send_SAP(false); - m_fd_rtcp.close(); - } - - /* need new ssrc */ - m_ssrc = random(); - LOGDBG("RTP SSRC: 0x%08x", m_ssrc); - - // - // RTP - // - if(! m_fd_rtp.create(cxSocket::estDGRAM)) { - LOGERR("socket() failed (UDP/RTP multicast)"); - return false; - } - - // Set buffer sizes - m_fd_rtp.set_buffers(KILOBYTE(256), 2048); - - // Set multicast socket options - if(!m_fd_rtp.set_multicast(xc.remote_rtp_ttl)) { - m_fd_rtp.close(); - return false; - } - - if(xc.remote_local_ip[0]) { - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_addr.s_addr = inet_addr(xc.remote_local_ip); - if(name.sin_addr.s_addr == INADDR_NONE) - LOGERR("Local address %s is invalid", xc.remote_local_ip); - name.sin_port = htons(xc.remote_rtp_port); - if (bind(m_fd_rtp.handle(), (struct sockaddr *)&name, sizeof(name)) < 0) - LOGERR("bind(%s:%d) failed for udp/rtp multicast", xc.remote_local_ip, xc.remote_rtp_port); -#if 0 - struct ip_mreqn mreqn; - mreqn.imr_multiaddr.s_addr = inet_addr(xc.remote_rtp_addr); - mreqn.imr_address.s_addr = inet_addr(xc.remote_local_ip); /* IP address of local interface */ - //mreqn.imr_ifindex = ; /* interface index */ - if(setsockopt(m_fd_rtp.handle(), IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn))) - LOGERR("setting multicast source address/interface failed"); -#endif - } - - // Connect to multicast address - if(!m_fd_rtp.connect(xc.remote_rtp_addr, xc.remote_rtp_port) && - errno != EINPROGRESS) { - LOGERR("connect(fd_rtp) failed. Address=%s, port=%d", - xc.remote_rtp_addr, xc.remote_rtp_port); - m_fd_rtp.close(); - return false; - } - - // Set to non-blocking mode - m_fd_rtp.set_blocking(false); - - // - // RTCP - // - if(! m_fd_rtcp.create(cxSocket::estDGRAM)) - LOGERR("socket() failed (RTCP multicast)"); - - m_fd_rtcp.set_buffers(16384, 16384); - if(!m_fd_rtcp.set_multicast(xc.remote_rtp_ttl)) - m_fd_rtcp.close(); - - if(xc.remote_local_ip[0]) { - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_addr.s_addr = inet_addr(xc.remote_local_ip); - name.sin_port = htons(xc.remote_rtp_port+1); - if (bind(m_fd_rtcp.handle(), (struct sockaddr *)&name, sizeof(name)) < 0) - LOGERR("bind(%s:%d) failed for udp/rtp multicast", xc.remote_local_ip, xc.remote_rtp_port); -#if 0 - struct ip_mreqn mreqn; - mreqn.imr_multiaddr.s_addr = inet_addr(xc.remote_rtp_addr); - mreqn.imr_address.s_addr = inet_addr(xc.remote_local_ip); /* IP address of local interface */ - //mreqn.imr_ifindex = ; /* interface index */ - if(setsockopt(m_fd_rtp.handle(), IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn))) - LOGERR("setting multicast source address/interface failed"); -#endif - } - - /* RTCP port (RFC 1889) */ - if(!m_fd_rtcp.connect(xc.remote_rtp_addr, xc.remote_rtp_port + 1) && - errno != EINPROGRESS) { - LOGERR("connect(fd_rtcp) failed. Address=%s, port=%d", - xc.remote_rtp_addr, xc.remote_rtp_port + - (xc.remote_rtp_port&1)?-1:1); - m_fd_rtcp.close(); - } - - // Set to non-blocking mode - m_fd_rtcp.set_blocking(false); - - // Finished - - if(!AddHandle(m_fd_rtp)) - LOGERR("cUdpScheduler::AddHandle(fd_rtp) failed"); - - Send_SAP(true); - - return true; -} - -bool cUdpScheduler::AddHandle(int fd) -{ - cMutexLock ml(&m_Lock); - - int i; - - for(i=0; i<MAX_UDP_HANDLES; i++) - if(m_Handles[i] < 0 || m_Handles[i] == fd) { - m_Handles[i] = fd; - - /* query socket send buffer size */ - m_wmem[i] = 0x10000; /* default to 64k */ - socklen_t l = sizeof(int); - if(getsockopt(m_Handles[i], SOL_SOCKET, SO_SNDBUF, &m_wmem[i], &l)) - LOGERR("getsockopt(SO_SNDBUF) failed"); - m_wmem[i] /= 2; /* man 7 socket */ - - m_Cond.Broadcast(); - - return true; - } - - return false; -} - -void cUdpScheduler::RemoveRtp(void) -{ - cMutexLock ml(&m_Lock); - - if(m_fd_rtp.open() || m_fd_rtcp.open()) { - Send_SAP(false); - - RemoveHandle(m_fd_rtp); - - m_fd_rtp.close(); - m_fd_rtcp.close(); - CLOSESOCKET(m_fd_sap); - } -} - -void cUdpScheduler::RemoveHandle(int fd) -{ - cMutexLock ml(&m_Lock); - - int i; - for(i=0; i<MAX_UDP_HANDLES; i++) - if(m_Handles[i] == fd) - break; - - for(; i<MAX_UDP_HANDLES-1; i++) - m_Handles[i] = m_Handles[i+1]; - - m_Handles[MAX_UDP_HANDLES-1] = -1; - - if(m_Handles[0] < 0) { - // No clients left ... - - // Flush all buffers - m_QueueNextSeq = 0; - m_QueuePending = 0; - - m_BackLogDeleteMutex.Lock(); - delete m_BackLog; - m_BackLog = new cUdpBackLog; - m_BackLogDeleteMutex.Unlock(); - - m_Frames = 0; - m_Octets = 0; - } -} - -int cUdpScheduler::Poll(int TimeoutMs, bool Master) -{ - cMutexLock ml(&m_Lock); - - m_Master = Master; - - if(m_Handles[0] < 0) { - // no clients, so we can eat all data we are given ... - return DEFAULT_POLL_SIZE; - } - - uint limit = m_Master ? MAX_QUEUE_SIZE : MAX_LIVE_QUEUE_SIZE; - if(m_QueuePending >= limit) { - uint64_t WaitEnd = cTimeMs::Now(); - if(TimeoutMs >= 0) - WaitEnd += (uint64_t)TimeoutMs; - - while (cTimeMs::Now() < WaitEnd && - Running() && - m_QueuePending >= limit) - m_Cond.TimedWait(m_Lock, 5); - } - - return limit > m_QueuePending ? limit - m_QueuePending : 0; -} - -bool cUdpScheduler::Flush(int TimeoutMs) -{ - cMutexLock ml(&m_Lock); - - if(m_Handles[0] < 0) - return true; - - if(m_QueuePending > 0) { - uint64_t WaitEnd = cTimeMs::Now(); - if(TimeoutMs >= 0) - WaitEnd += (uint64_t)TimeoutMs; - - while (cTimeMs::Now() < WaitEnd && - Running() && - m_QueuePending > 0) - m_Cond.TimedWait(m_Lock, 5); - } - return m_QueuePending == 0; -} - -void cUdpScheduler::Clear(void) -{ - cMutexLock ml(&m_Lock); - - m_BackLog->Clear(m_QueuePending); - - m_QueuePending = 0; - m_Cond.Broadcast(); -} - -void cUdpScheduler::Pause(bool On) -{ - cMutexLock ml(&m_Lock); - - if(On) - m_MasterClock.Pause(); - else - m_MasterClock.Resume(); - - m_TrickSpeed = false; -} - -void cUdpScheduler::TrickSpeed(const int Multiplier) -{ - cMutexLock ml(&m_Lock); - -#ifdef LOG_SCR - if(Multiplier == 1 || Multiplier == -1) { - LOGMSG("UDP clock --> normal"); - } else if(Multiplier < 0) - LOGMSG("UDP clock --> %dx", -Multiplier); - else - LOGMSG("UDP clock --> 1/%d", Multiplier); -#endif - - m_MasterClock.TrickSpeed(Multiplier); - - m_TrickSpeed = (Multiplier==-1 || Multiplier==1) ? false : true; -} - -void cUdpScheduler::SetScrSpeed(const int Speed) -{ - cMutexLock ml(&m_Lock); - - m_MasterClock.SetScrSpeed(Speed); - m_RtpScr.SetScrSpeed(Speed); -} - -bool cUdpScheduler::Queue(uint64_t StreamPos, const uchar *Data, int Length) -{ - cMutexLock ml(&m_Lock); - - if(m_Handles[0] < 0) - return true; - - uint limit = m_Master ? MAX_QUEUE_SIZE : MAX_LIVE_QUEUE_SIZE; - if(m_QueuePending >= limit) - return false; - - m_BackLog->MakeFrame(StreamPos, Data, Length); - m_QueuePending++; - - m_Cond.Broadcast(); - - return true; -} - -void cUdpScheduler::QueuePadding(void) -{ - cMutexLock ml(&m_Lock); - - if (m_Handles[0] < 0) - return; - - if (m_QueuePending > 2) - return; - - QueuePaddingInternal(); - - m_Cond.Broadcast(); -} - -void cUdpScheduler::QueuePaddingInternal(void) -{ - static unsigned const char Padding[] = {0x00,0x00,0x01,0xBE,0x00,0x02,0xff,0xff}; - - int PrevSeq = (m_QueueNextSeq + UDP_BUFFER_SIZE - 1) & UDP_BUFFER_MASK; - stream_rtp_header_impl_t *Frame = m_BackLog->Get(PrevSeq); - if (Frame) { - int PrevLen = m_BackLog->PayloadSize(PrevSeq); - uint64_t Pos = ntohll(Frame->hdr_ext.pos) + PrevLen - 8; - m_BackLog->MakeFrame(Pos, Padding, 8); - } else - m_BackLog->MakeFrame(0, Padding, 8); - - m_QueuePending++; -} - -int cUdpScheduler::CalcElapsedVtime(int64_t pts, bool Audio) -{ - int64_t diff = 0; - - if(!Audio) { - diff = pts - m_CurrentVideoVtime; - if(diff > JUMP_LIMIT_TIME || (-diff) > JUMP_LIMIT_TIME) { // 1 s (must be > GOP) - // RESET -#ifdef LOG_SCR - LOGDBG("cUdpScheduler RESET (Video jump %lld->%lld)", - m_CurrentVideoVtime, pts); -#endif - m_CurrentVideoVtime = pts; - - // Use video pts for sync only in audioless trickspeeds - // (audio has smaller, constant and increasing intervals) - if(m_TrickSpeed) - m_MasterClock.Set(m_CurrentVideoVtime + INITIAL_BURST_TIME); - - return -1; - } - if(diff < 0) /* ignore small negative differences (B/P frames are sent out-of-order) */ - diff = 0; - else - m_CurrentVideoVtime = pts; - - } else if(Audio) { - diff = pts - m_CurrentAudioVtime; - if(diff < 0) diff = -diff; - if(diff > JUMP_LIMIT_TIME) { // 1 sec - // RESET -#ifdef LOG_SCR - LOGDBG("cUdpScheduler RESET (Audio jump %lld->%lld)", - m_CurrentAudioVtime, pts); -#endif - m_CurrentAudioVtime = pts; - - // Use audio pts for sync (audio has constant and increasing intervals) - m_MasterClock.Set(m_CurrentAudioVtime + INITIAL_BURST_TIME); - - return -1; - } - m_CurrentAudioVtime = pts; - } - - return (int) diff; -} - -void cUdpScheduler::Send_RTCP(void) -{ - if(!m_fd_rtcp.open()) - return; - - uint64_t scr = m_RtpScr.Now(); - - if(scr > (m_LastRtcpTime + RTCP_MIN_INTERVAL)) { - uint8_t frame[2048], *content = frame; - char hostname[64] = ""; - rtcp_packet_t *msg = (rtcp_packet_t *)content; - struct timeval tv; - - gettimeofday(&tv, NULL); - gethostname(hostname, sizeof(hostname)-1); - hostname[sizeof(hostname)-1] = 0; - - // SR (Sender report) - msg->hdr.raw[0] = 0x81; // RTP version = 2, Report count = 1 */ - msg->hdr.ptype = RTCP_SR; - msg->hdr.length = htons(6); // length 6 dwords - - msg->sr.ssrc = htonl(m_ssrc); - msg->sr.ntp_sec = htonl(tv.tv_sec + 0x83AA7E80); - msg->sr.ntp_frac = htonl((uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6)); - msg->sr.rtp_ts = htonl((uint32_t)(scr & 0xffffffff)); - msg->sr.psent = htonl((uint32_t)(m_Frames & 0xffffffff)); - msg->sr.osent = htonl((uint32_t)(m_Octets & 0xffffffff)); - - content += sizeof(rtcp_common_t) + sizeof(rtcp_sr_t); - msg = (rtcp_packet_t *)content; - - // SDES - msg->hdr.raw[0] = 0x81; // RTP version = 2, Report count = 1 */ - msg->hdr.ptype = RTCP_SDES; - msg->hdr.count = 1; - - msg->sdes.ssrc = m_ssrc; - msg->sdes.item[0].type = RTCP_SDES_CNAME; - sprintf(msg->sdes.item[0].data, "VDR@%s:%d%c%c%c", - hostname[0] ? hostname : xc.remote_rtp_addr, - xc.remote_rtp_port, 0, 0, 0); - msg->sdes.item[0].length = strlen(msg->sdes.item[0].data); - msg->hdr.length = htons(1 + 1 + ((msg->sdes.item[0].length - 2) + 3) / 4); - - content += sizeof(rtcp_common_t) + 4*ntohs(msg->hdr.length); - msg = (rtcp_packet_t *)content; - - // Send -#ifndef LOG_RTCP - (void) m_fd_rtcp.send(frame, content - frame); -#else - LOGMSG("RTCP send (%d)", m_fd_rtcp.send(frame, content - frame)); - for(int i=0; i<content-frame; i+=16) - LOGMSG("%02X %02X %02X %02X %02X %02X %02X %02X " - "%02X %02X %02X %02X %02X %02X %02X %02X " - " %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c", - frame[i+0],frame[i+1],frame[i+2],frame[i+3], - frame[i+4],frame[i+5],frame[i+6],frame[i+7], - frame[i+8],frame[i+9],frame[i+10],frame[i+11], - frame[i+12],frame[i+13],frame[i+14],frame[i+15], - frame[i+0],frame[i+1],frame[i+2],frame[i+3], - frame[i+4],frame[i+5],frame[i+6],frame[i+7], - frame[i+8],frame[i+9],frame[i+10],frame[i+11], - frame[i+12],frame[i+13],frame[i+14],frame[i+15]); -#endif - - m_LastRtcpTime = scr; - } -} - - -void cUdpScheduler::Send_SAP(bool Announce) -{ - if(!xc.remote_rtp_sap || !m_fd_rtp.open()) - return; - - char ip[64] = ""; - uint32_t local_addr = m_fd_rtp.get_local_address(ip); - - if(!local_addr) - return; - - uint32_t payload_type = VDRVERSNUM > 10702 ? SDP_PAYLOAD_MPEG_TS : SDP_PAYLOAD_MPEG_PES; - const char *sdp_descr = vdr_sdp_description(ip, - 2001, - xc.listen_port, - xc.remote_rtp_addr, - payload_type, - m_ssrc, - xc.remote_rtp_port, - xc.remote_rtp_ttl); - if(!sdp_descr) - return; - -#if 1 - /* store copy of SDP data */ - if(m_fd_sap < 0) { - cString fname = AddDirectory(VideoDirectory, - cString::sprintf("xineliboutput@%s.sdp", - ip)); - FILE *fp = fopen(fname, "w"); - if(fp) { - fprintf(fp, "%s", sdp_descr); - fclose(fp); - } - } -#endif - - sap_pdu_t *pdu = sap_create_pdu(local_addr, - Announce, - (m_ssrc >> 16 | m_ssrc) & 0xffff, - "application/sdp", - sdp_descr); - - if(!sap_send_pdu(&m_fd_sap, pdu, 0)) - LOGERR("SAP/SDP announce failed"); - free(pdu); - - if(!Announce) - CLOSESOCKET(m_fd_sap); -} - -void cUdpScheduler::Schedule(const uchar *Data, int Length) -{ - bool Audio = IS_AUDIO_PACKET(Data), Video = IS_VIDEO_PACKET(Data); - int64_t pts = PES_HAS_PTS(Data) ? pes_get_pts(Data, Length) : INT64_C(-1); - int elapsed = pts>0 ? CalcElapsedVtime(pts, Audio) : 0; - - if(elapsed > 0) { - int64_t now = m_MasterClock.Now(); - LOGSCR("PTS: %lld (%s) elapsed %d ms (PID %02x)", - pts, Video?"Video":Audio?"Audio":"?", pts_to_ms(elapsed), Data[3]); - - // - // Detect discontinuity - // - if(Audio) { - if(now > m_CurrentAudioVtime && (now - m_CurrentAudioVtime)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in past)"); - m_MasterClock.Set(m_CurrentAudioVtime + INITIAL_BURST_TIME); - } else if(now < m_CurrentAudioVtime && (m_CurrentAudioVtime-now)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in future)"); - m_MasterClock.Set(m_CurrentAudioVtime + INITIAL_BURST_TIME); - } - } - - else if(Video && m_TrickSpeed) { - if(now > m_CurrentVideoVtime && (now - m_CurrentVideoVtime)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in past) - VIDEO"); - m_MasterClock.Set(m_CurrentVideoVtime + INITIAL_BURST_TIME); - } else if(now < m_CurrentVideoVtime && (m_CurrentVideoVtime-now)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in future) - VIDEO"); - m_MasterClock.Set(m_CurrentVideoVtime + INITIAL_BURST_TIME); - } - } - - // - // Delay - // - uint delay_ms = 0; - if(m_TrickSpeed ) { - if(m_CurrentVideoVtime > now) { - delay_ms = pts_to_ms(m_CurrentVideoVtime - now); - LOGSCR("cUdpScheduler sleeping %d ms " - "(time reference: %s, beat interval %d ms)", - delay_ms, (Audio?"Audio PTS":"Video PTS"), pts_to_ms(elapsed)); - } - } else { - if(m_CurrentAudioVtime > now) { - delay_ms = pts_to_ms(m_CurrentAudioVtime - now); - LOGSCR("cUdpScheduler sleeping %d ms " - "(time reference: %s, beat interval %d ms)", - delay_ms, (Audio?"Audio PTS":"Video PTS"), pts_to_ms(elapsed)); - } - } - - while (delay_ms > SCHEDULER_MIN_DELAY_MS) { - if (delay_ms > SCHEDULER_MAX_DELAY_MS) - delay_ms = SCHEDULER_MAX_DELAY_MS; - LOGSCR(" -> cUdpScheduler sleeping %d ms ", delay_ms); - Scheduler_Sleep(delay_ms); - now = m_MasterClock.Now(); - delay_ms = pts_to_ms(m_CurrentVideoVtime - now); - } - } -} - -void cUdpScheduler::Action(void) -{ -#if 0 - { - // Request real-time scheduling - sched_param temp; - temp.sched_priority = 2; - - if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) { - LOGMSG("cUdpScheduler priority set successful SCHED_RR %d [%d,%d]", - temp.sched_priority, - sched_get_priority_min(SCHED_RR), - sched_get_priority_max(SCHED_RR)); - } else { - LOGMSG("cUdpScheduer: Can't set priority to SCHED_RR %d [%d,%d]", - temp.sched_priority, - sched_get_priority_min(SCHED_RR), - sched_get_priority_max(SCHED_RR)); - } - } -#endif - - /* UDP Scheduler needs high priority */ - const int priority = -5; - SetPriority(priority); - errno = 0; - if ((nice(priority) == -1) && errno) - LOGDBG("cUdpScheduler: Can't nice to value: %d", priority); - - m_Lock.Lock(); - - while (Running()) { - - if(m_Handles[0] < 0) { - m_Cond.TimedWait(m_Lock, 5000); - continue; - } - - // Wait until we have outgoing data in queue - if(m_QueuePending <= 0) { - m_BurstFrames = m_BurstBytes = 0; - m_Cond.TimedWait(m_Lock, 100); - if(m_QueuePending <= 0) { - // Still nothing... - // Send padding frame once in 100ms so clients can detect - // possible missing frames and server shutdown - QueuePaddingInternal(); - } - continue; // to check Running() - } - - // Take next frame from queue - stream_rtp_header_impl_t *frame = m_BackLog->Get(m_QueueNextSeq); - int PayloadSize = m_BackLog->PayloadSize(m_QueueNextSeq); - int UdpPacketLen = PayloadSize + sizeof(stream_udp_header_t); - int RtpPacketLen = PayloadSize + sizeof(stream_rtp_header_impl_t); - - m_QueueNextSeq = (m_QueueNextSeq + 1) & UDP_BUFFER_MASK; - m_QueuePending--; - - m_Cond.Broadcast(); - m_BackLogDeleteMutex.Lock(); /* ensure frame will not be deleted from queue */ - m_Lock.Unlock(); - - // Schedule frame - if(m_Master) - Schedule(frame->payload, PayloadSize); - - // Need some bandwidth limit for ex. sequence of still frames when - // moving cutting marks very fast (no audio or PTS available). - // Hard limit for used bandwidth: - // - ~1 frames/ms & 8kb/ms -> 8mb/s -> ~ 80 Mbit/s ( / client) - // - max burst 15 frames or 32 kb - m_BurstFrames ++; - m_BurstBytes += PayloadSize; - if (m_BurstFrames >= MAX_BURST_FRAMES && m_BurstBytes >= MAX_BURST_BYTES) { - Scheduler_Sleep(4); -#ifdef LOG_UDP_RATE - static uint64_t dbg_timer = cTimeMs::Now(); - static int dbg_bytes = 0; - dbg_bytes += bytes; - if (dbg_timer + 60000 <= cTimeMs::Now()) { - LOGDBG("UDP rate: %4d Kbps (queue %d)", dbg_bytes/(60*1024/8), m_QueuePending); - dbg_bytes = 0; - dbg_timer = cTimeMs::Now(); - } -#endif - } - - /* tag frame with ssrc and timestamp */ - frame->rtp_hdr.ts = htonl((uint32_t)(m_RtpScr.Now() & 0xffffffff)); - frame->rtp_hdr.ssrc = htonl(m_ssrc); - - /* deliver to all active sockets */ - for(int i=0; i<MAX_UDP_HANDLES && m_Handles[i]>=0; i++) { - - // - // use TIOCOUTQ ioctl instead of poll/select. - // - poll/select for UDP/RTP may return true even when queue - // is (almost) full - // - kernel silently drops frames it cant send - // -> poll() + send() just causes frames to be dropped - // - uint size = 0; - if(!ioctl(m_Handles[i], TIOCOUTQ, &size)) { - if(size >= (m_wmem[i] - 2*RtpPacketLen)) { - LOGMSG("cUdpScheduler: kernel transmit queue > ~%dkb (max %dkb) ! (master=%d)", - (m_wmem[i] - 2*RtpPacketLen)/1024, m_wmem[i]/1024, m_Master); - Scheduler_Sleep(2); - } - } else { - if(m_QueuePending > (MAX_QUEUE_SIZE-5)) - LOGDBG("cUdpScheduler: kernel transmit queue > ~30kb ! (master=%d ; Queue=%d)", - m_Master, m_QueuePending); - Scheduler_Sleep(2); - } - - if(m_Handles[i] == m_fd_rtp.handle()) { - if(send(m_Handles[i], frame, RtpPacketLen, 0) <= 0) - LOGERR("cUdpScheduler: UDP/RTP send() failed !"); - } else { - /* UDP: send without rtp header */ - if(send(m_Handles[i], - ((uint8_t*)frame) + sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t), - UdpPacketLen, 0) <= 0) - LOGERR("cUdpScheduler: UDP send() failed !"); - } - } - - m_BackLogDeleteMutex.Unlock(); /* release queue */ - m_Lock.Lock(); - - m_Frames ++; - m_Octets += PayloadSize; - if(m_fd_rtcp.open() && (m_Frames & 0xff) == 1) { // every 256th frame - Send_RTCP(); -#if 0 - if((m_Frames & 0xff00) == 0) // every 65536th frame (~ 2 min) - Send_SAP(); -#else - if((m_Frames & 0x0300) == 0) // every 1024th frame (~ 2...4 sec) - Send_SAP(); -#endif - } - } - - m_Lock.Unlock(); -} - -void cUdpScheduler::ReSend(int fd, uint64_t Pos, int Seq1, int Seq2) -{ - if(fd < 0) /* no re-send for RTP */ - return; - - struct { - stream_udp_header_t hdr; - char mem[64-sizeof(stream_udp_header_t)]; - } udp_ctrl = {{(uint64_t)INT64_C(-1), (uint16_t)-1}, {0}}; - - // Handle buffer wrap - if(Seq1 > Seq2) - Seq2 += UDP_BUFFER_SIZE; - - cMutexLock ml(&m_Lock); // keeps also scheduler thread suspended ... - - if(Seq2-Seq1 > 64) { - LOGDBG("cUdpScheduler::ReSend: requested range too large (%d-%d)", - Seq1, Seq2); - - sprintf((char*)udp_ctrl.hdr.payload, - "UDP MISSING %d-%d %" PRIu64, - Seq1, (Seq2 & UDP_BUFFER_MASK), Pos); - send(fd, &udp_ctrl, sizeof(udp_ctrl), 0); - return; - } - - // re-send whole range - for(; Seq1 <= Seq2; Seq1++) { - - // Wait if kernel queue is full - int size = 0; - if(!ioctl(fd, TIOCOUTQ, &size)) - if(size > ((0x10000)/2 - 2048)) { // assume 64k kernel buffer - LOGDBG("cUdpScheduler::ReSend: kernel transmit queue > ~30kb !"); - Scheduler_Sleep(2); - } - - stream_rtp_header_impl_t *frame = m_BackLog->Get(Seq1); - - if(frame) { - if(ntohull(frame->hdr_ext.pos) - Pos < 100000) { - send(fd, - ((uint8_t*)frame) + sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t), - m_BackLog->PayloadSize(Seq1) + sizeof(stream_udp_header_t), - 0); - LOGRESEND("cUdpScheduler::ReSend: %d (%d bytes) @%lld sent", - Seq1, m_BackLog->PayloadSize(Seq1), Pos); - Pos = ntohull(frame->hdr_ext.pos) + m_BackLog->PayloadSize(Seq1); - continue; - } else { - // buffer has been lost long time ago... - LOGRESEND("cUdpScheduler::ReSend: Requested position does not match " - "(%lld ; has %lld)", Pos, ntohll(frame->hdr_ext.pos)); - } - } else { - LOGRESEND("cUdpScheduler::ReSend: %d @%lld missing", Seq1, Pos); - } - - // buffer has been lost - send packet missing info - - LOGRESEND("cUdpScheduler::ReSend: missing %d-%d @%d (hdr 0x%llx 0x%x)", - Seq1, Seq1, Pos, udp_ctrl.hdr.pos, udp_ctrl.hdr.seq); - - int Seq0 = Seq1; - for(; Seq1 < Seq2; Seq1++) { - stream_rtp_header_impl_t *frame = m_BackLog->Get(Seq1+1); - if(frame && (ntohull(frame->hdr_ext.pos) - Pos < 100000)) - break; - } - - sprintf((char*)udp_ctrl.hdr.payload, - "UDP MISSING %d-%d %" PRIu64, - Seq0, (Seq1 & UDP_BUFFER_MASK), Pos); - - send(fd, &udp_ctrl, sizeof(udp_ctrl), 0); - } -} diff --git a/tools/udp_pes_scheduler.h b/tools/udp_pes_scheduler.h deleted file mode 100644 index a889f728..00000000 --- a/tools/udp_pes_scheduler.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * udp_pes_scheduler.h: PES scheduler for UDP/RTP streams - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: udp_pes_scheduler.h,v 1.20 2009-07-02 10:38:29 phintuka Exp $ - * - */ - -#ifndef __UDP_PES_SCHEDULER_H -#define __UDP_PES_SCHEDULER_H - -#include <stdint.h> - -#include <vdr/tools.h> // uchar -#include <vdr/thread.h> - -#include "cxsocket.h" -#include "time_pts.h" - -#define MAX_UDP_HANDLES 16 - -class cUdpBackLog; - -class cUdpScheduler : public cThread -{ - public: - - cUdpScheduler(); - virtual ~cUdpScheduler(); - - // fd should be binded & connected to IP:PORT (local+remote) pair ! - bool AddHandle(int fd); /* UDP unicast */ - void RemoveHandle(int fd); /* UDP unicast */ - bool AddRtp(void); /* UDP/RTP multicast */ - void RemoveRtp(void); /* UDP/RTP multicast */ - bool AddHandle(cxSocket& s) { return AddHandle(s.handle()); } - void RemoveHandle(cxSocket& s) { RemoveHandle(s.handle()); } - - bool Clients(void) { return m_Handles[0] >= 0; } - int Poll(int TimeoutMs, bool Master); - bool Queue(uint64_t StreamPos, const uchar *Data, int Length); - void QueuePadding(void); - void ReSend(int fd, uint64_t Pos, int Seq1, int Seq2); - - void Clear(void); - bool Flush(int TimeoutMs); - - void Pause(bool On); - void TrickSpeed(const int Multiplier); - void SetScrSpeed(const int Speed = 90000); - - protected: - - // Signalling - - cCondVar m_Cond; - cMutex m_Lock; - - // Clients - - int m_Handles[MAX_UDP_HANDLES]; - uint m_wmem[MAX_UDP_HANDLES]; /* kernel buffer size */ - - cxSocket m_fd_rtp; - cxSocket m_fd_rtcp; - - // Queue - - uint m_QueueNextSeq; /* next outgoing */ - uint m_QueuePending; /* outgoing queue size */ - cUdpBackLog *m_BackLog; /* queue for incoming data (not yet send) and retransmissions */ - cMutex m_BackLogDeleteMutex; - - // Scheduling - - cTimePts m_MasterClock; /* Current MPEG PTS (synchronized to current stream) */ - bool m_TrickSpeed; /* current (replay) speed */ - bool m_Master; /* if true, we are master metronom for playback */ - - int64_t m_CurrentAudioVtime; - int64_t m_CurrentVideoVtime; - - uint m_BurstBytes; /* number of bytes sent without sleeps */ - uint m_BurstFrames; /* number of frames sent without sleeps */ - - cCondWait m_CondWait; - - int CalcElapsedVtime(int64_t pts, bool Audio); - void Schedule(const uchar *Data, int Length); - void Scheduler_Sleep(int ms); - void QueuePaddingInternal(void); - - // RTP - - uint32_t m_ssrc; /* RTP synchronization source id */ - cTimePts m_RtpScr; /* 90 kHz monotonic time source for RTP timestamps */ - - // RTCP - - uint64_t m_LastRtcpTime; - uint32_t m_Frames; - uint32_t m_Octets; - - void Send_RTCP(void); - - // SAP - - int m_fd_sap; - - void Send_SAP(bool Announce = true); - - // Thread - - virtual void Action(void); -}; - -#endif diff --git a/tools/vdrdiscovery.c b/tools/vdrdiscovery.c deleted file mode 100644 index e301056d..00000000 --- a/tools/vdrdiscovery.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * vdrdiscovery.c - * - * Simple broadcast protocol to search VDR with xineliboutput server - * from (local) network. - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vdrdiscovery.c,v 1.9 2009-06-29 21:23:33 phintuka Exp $ - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <poll.h> -#include <unistd.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <arpa/inet.h> - -#define LOG_MODULENAME "[discovery] " -#include "../logdefs.h" - -#include "vdrdiscovery.h" - -/* - * constants - */ - -#ifndef DISCOVERY_PORT -# define DISCOVERY_PORT 37890 -#endif - -/* discovery protocol strings (v1.0) */ -#define DISCOVERY_1_0_HDR "VDR xineliboutput DISCOVERY 1.0" "\r\n" -#define DISCOVERY_1_0_CLI "Client: %s:%d" "\r\n" -#define DISCOVERY_1_0_SVR "Server port: %d" "\r\n" -#define DISCOVERY_1_0_ADDR "Server address: %s" "\r\n" -#define DISCOVERY_1_0_VERSION "Server version: " /*vdr-" VDRVERSION "\r\n\t"*/ \ - "xineliboutput-" XINELIBOUTPUT_VERSION "\r\n" - -/* - * - */ - -static inline int discovery_init(int port) -{ - int fd_discovery = -1; - int iBroadcast = 1, iReuse = 1; - struct sockaddr_in sin; - - if ((fd_discovery = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_TCP*/)) < 0) { - LOGERR("discovery_init: socket() failed"); - return -1; - } - - if (setsockopt(fd_discovery, SOL_SOCKET, SO_BROADCAST, &iBroadcast, sizeof(int)) < 0) - LOGERR("discovery_init: setsockopt(SO_BROADCAST) failed"); - - if (setsockopt(fd_discovery, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)) < 0) - LOGERR("discovery_init: setsockopt(SO_REUSEADDR) failed"); - - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); - - if (bind(fd_discovery, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - LOGERR("discovery_init: bind() failed"); - close(fd_discovery); - return -1; - } - - return fd_discovery; -} - -int udp_discovery_init(void) -{ - return discovery_init(DISCOVERY_PORT); -} - -static inline int udp_discovery_send(int fd_discovery, int port, char *msg) -{ - struct sockaddr_in sin; - int len = strlen(msg); - - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = INADDR_BROADCAST; - - if(len != sendto(fd_discovery, msg, len, 0, - (struct sockaddr *)&sin, sizeof(sin))) { - LOGERR("UDP broadcast send failed (discovery)"); - return -1; - } - - //LOGDBG("UDP broadcast send succeed (discovery)"); - return 0; -} - -int udp_discovery_broadcast(int fd_discovery, int server_port, const char *server_address) -{ - char *msg = NULL; - int result; - - if(server_address && *server_address) { - result = asprintf(&msg, - DISCOVERY_1_0_HDR //"VDR xineliboutput DISCOVERY 1.0" "\r\n" - DISCOVERY_1_0_SVR //"Server port: %d" "\r\n" - DISCOVERY_1_0_ADDR //"Server Address: %d.%d.%d.%d \r\n" - DISCOVERY_1_0_VERSION //"Server version: xineliboutput-" XINELIBOUTPUT_VERSION "\r\n" - "\r\n", - server_port, server_address); - } else { - result = asprintf(&msg, - DISCOVERY_1_0_HDR //"VDR xineliboutput DISCOVERY 1.0" "\r\n" - DISCOVERY_1_0_SVR //"Server port: %d" "\r\n" - DISCOVERY_1_0_VERSION //"Server version: xineliboutput-" XINELIBOUTPUT_VERSION "\r\n" - "\r\n", - server_port); - } - - if (result >= 0) { - result = udp_discovery_send(fd_discovery, DISCOVERY_PORT, msg); - free(msg); - } - - return result; -} - -static inline int udp_discovery_search(int fd_discovery, int port) -{ - char *msg = NULL; - int result; - - result = asprintf(&msg, - DISCOVERY_1_0_HDR /* "VDR xineliboutput DISCOVERY 1.0" "\r\n" */ - DISCOVERY_1_0_CLI /* "Client: %s:%d" "\r\n" */ - "\r\n", - "255.255.255.255", - port); - - if (result >= 0) { - result = udp_discovery_send(fd_discovery, port, msg); - free(msg); - } - - return result; -} - -int udp_discovery_recv(int fd_discovery, char *buf, int timeout, - struct sockaddr_in *source) -{ - socklen_t sourcelen = sizeof(struct sockaddr_in); - struct pollfd pfd; - int err; - - pfd.fd = fd_discovery; - pfd.events = POLLIN; - - errno = 0; - err = poll(&pfd, 1, timeout); - if(err < 1) { - if(err < 0) - LOGERR("broadcast poll error"); - return err; - } - - memset(source, 0, sourcelen); - memset(buf, 0, DISCOVERY_MSG_MAXSIZE); - - err = recvfrom(fd_discovery, buf, DISCOVERY_MSG_MAXSIZE-1, 0, - (struct sockaddr *)source, &sourcelen); - - if(err <= 0) - LOGDBG("fd_discovery recvfrom() error"); - - return err; -} - -int udp_discovery_is_valid_search(const char *buf) -{ - static const char id_string[] = { DISCOVERY_1_0_HDR "Client:" }; - - if(!strncmp(id_string, buf, strlen(id_string))) { - LOGMSG("Received valid discovery message %s", buf); - return 1; - } - - LOGDBG("BROADCAST: %s", buf); - return 0; -} - -int udp_discovery_find_server(int *port, char *address) -{ - static const char mystring[] = DISCOVERY_1_0_HDR "Server port: "; - struct sockaddr_in from; - char buf[DISCOVERY_MSG_MAXSIZE]; - int fd_discovery = -1; - int trycount = 0; - int err = 0; - - *port = DISCOVERY_PORT; - strcpy(address, "vdr"); - - if((fd_discovery = discovery_init(DISCOVERY_PORT)) < 0) - return 0; - - while(err >= 0 && ++trycount < 4) { - - if((err = udp_discovery_search(fd_discovery, DISCOVERY_PORT) >= 0)) { - - errno = 0; - while( (err = udp_discovery_recv(fd_discovery, buf, 500, &from)) > 0) { - - uint32_t tmp = ntohl(from.sin_addr.s_addr); - - buf[err] = 0; - LOGDBG("Reveived broadcast: %d bytes from %d.%d.%d.%d \n%s", - err, - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff), - buf); - if(!strncmp(mystring, buf, strlen(mystring))) { - char *iploc; - LOGDBG("Valid discovery message"); - close(fd_discovery); - - // default: use broadcast source address - sprintf(address, "%d.%d.%d.%d", - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff)); - - // Check if announce message includes alternative server address - iploc = strstr(buf + strlen(mystring), "Server address: "); - if(iploc) { - uint32_t svraddr; - iploc += strlen("Server address: "); - svraddr = inet_addr(iploc); - if(svraddr == INADDR_NONE) { - LOGMSG("Server provided invalid address !"); - } else { - svraddr = ntohl(svraddr); - sprintf(address, "%d.%d.%d.%d", - ((svraddr>>24)&0xff), ((svraddr>>16)&0xff), - ((svraddr>>8)&0xff), ((svraddr)&0xff)); - LOGMSG("Replacing broadcast source address %d.%d.%d.%d " - "with server-given address %s", - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff), - address); - } - } - - *port = -1; - if(1 == sscanf(buf + strlen(mystring), "%d", port) && - *port >= 1000 && *port <= 0xffff) - return 1; - LOGMSG("Server-given port is invalid !"); - } else { - LOGDBG("NOT valid discovery message"); - } - } - } - } - - /* failed */ - close(fd_discovery); - return 0; -} - - diff --git a/tools/vdrdiscovery.h b/tools/vdrdiscovery.h deleted file mode 100644 index de612733..00000000 --- a/tools/vdrdiscovery.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * vdrdiscovery.h - * - * Simple broadcast protocol to search VDR with xineliboutput server - * from (local) network. - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vdrdiscovery.h,v 1.5 2009-02-10 15:26:11 phintuka Exp $ - * - */ - -#ifndef _VDRDISCOVERY_H_ -#define _VDRDISCOVERY_H_ - -#define DISCOVERY_MSG_MAXSIZE 1024 - -#ifdef __cplusplus -extern "C" { -#endif - -struct sockaddr_in; - -/* - * Client interface - */ - -/* - * udp_discovery_find_server() - * - * Search for server. Return address and port. - * Returns 0 on success. - */ -int udp_discovery_find_server(int *port, char *address); - -/* - * Server interface - */ - -/* - * udp_discovery_init() - * - * Initialize server socket. Return value is the socket file descriptor, - * and can be used for polling. - * Returns < 0 on error. - */ -int udp_discovery_init(void); - -/* - * udp_discovery_broadcast() - * - * Send server announcement. - * Returns 0 on success. - */ -int udp_discovery_broadcast(int fd_discovery, int server_port, const char *server_address); - -/* - * udp_discovery_recv() - * - * Receive query or announcement. - * Returns number of bytes received, <= 0 on error. - * Result is null-terminated string, not more than DISCOVERY_MSG_MAXSIZE bytes. - */ -int udp_discovery_recv(int fd_discovery, char *buf, int timeout, - struct sockaddr_in *source); - -/* - * udp_discovery_is_valid_search() - * - * Check if string is valid search message. - * Returns 1 for valid messages, 0 for invalid messages. - */ -int udp_discovery_is_valid_search(const char *buf); - -#ifdef __cplusplus -}; -#endif - - -#endif // _VDRDISCOVERY_H_ diff --git a/vdrlogo_32x32.c b/vdrlogo_32x32.c deleted file mode 100644 index 00045db6..00000000 --- a/vdrlogo_32x32.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * vdrlogo_32x32.c: 32x32 logo icon - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vdrlogo_32x32.c,v 1.4 2009-05-27 09:39:08 phintuka Exp $ - * - */ - -/* GIMP RGBA C-Source image dump (vdrlogo_32x32.c) */ - -typedef struct { - const uint32_t width; - const uint32_t height; - const uint8_t pixel_data[32 * 32 * sizeof(uint32_t) + 1]; -} __attribute__((packed)) sxfe_32x32_icon_t; - -static const sxfe_32x32_icon_t vdrlogo_32x32 = { - 32, 32, /*4,*/ - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\214v\246\32<\31xcT5\210F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0sZ\226\37F$|^;\30yc;\30yc;\30ycC!~cY7\205U\231\210\265FL" - ".\202c<\30yc;\30yc;\30yc;\30yc;\30yc;\30ycE\"\177cU4\200Jv^\227\14\0\0\0" - "\0\0\0\0\0\0\0\0\0\243\224\304\10B\33z\354I!~\366\315\276\331\22\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0R3\202a>\24z\367:\17y\377:\17x\377" - ":\17x\377:\17x\377:\17y\377:\17|\377>\25{\377_C\204\377M*\200\377:\20x\377" - ":\20x\377:\20w\377:\20w\377:\20w\377:\17x\377:\17y\377@\31|\357eH\215G\0" - "\0\0\0\0\0\0\0\0\0\0\0R.\204\225;\17z\377tY\231e\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0mT\223\40=\24z\373=\33n\377>!f\377lax\254f^n\211f]q\211e" - "]r\220_Ov\254J*x\363;\17y\377cH\215\345gbjvgbjskfmsnipsqkrsoiv|^G|\274<\23" - "y\377E\36~\352\272\252\320\21\0\0\0\0\0\0\0\0u\\\2261;\22z\377Y7\207\304" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0O+\204\202;\21u\377M4t\370;\20y\377" - "rf\207Y\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\240\227\256\"J(\177\341:\21{\377" - "sZ\233J\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\342\340\343\1P*\203\266;" - "\17x\377zi\220a\0\0\0\0\0\0\0\0\0\0\0\0K&\204\316A\32{\375\243\230\264\37" - "\0\0\0\0\0\0\0\0\0\0\0\0\335\313\362\3C\34}\340M1t\370J&\177\251:\20x\377" - "rf\207Y\0\0\0\0ddd\6\24\24\24\301\35\35\35\301ZZZ\22hL\217X;\17{\377[=\212" - "\265\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0G!~\251:\17y\377se\205" - "{\0\0\0\0\0\0\0\0\0\0\0\0W7\203g9\20z\377iM\221}\0\0\0\0\0\0\0\0\0\0\0\0" - "\\;\215F:\20y\377eU{\250?\26y\230:\20x\377rf\207Y\0\0\0\0fgg$GB3\377NKF\377" - "JJJ\177\231\205\264\21=\23x\377T2\201\360\335\337\320\1\0\0\0\0\0\0\0\0\0" - "\0\0\0\236\213\273\17Y7\210i<\23y\372?\32o\377\222\216\227H\0\0\0\0\0\0\0" - "\0\0\0\0\0\212t\252\15@\30}\364T2\207\330\351\343\345\1\0\0\0\0\0\0\0\0H" - "#~\252=\31r\377\225\216\230E?\26y\230:\20x\377rf\207Y\0\0\0\0\222\217\220" - "\"\260\2215\377\237\213K\377788\236\352\332\366\6F\36\201\377L'|\377H$\202" - "\366@\30}\365@\30}\365A\27{\365=\23y\375;\17x\377;\31n\377j_w\254\327\322" - "\326\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0I&\201\236>\24z\377\226\203\2617\0" - "\0\0\0|b\242\24=\24{\367V@x\340\344\342\343\2?\26y\230:\20x\377rf\207Y\0" - "\0\0\0TUU\236\353\352\353\377\355\354\354\377('(\366MJP2B\31}\377I'z\377" - "bN\201\357T?v\365P8v\367<\27u\377:\21x\377UDq\330\177}\203]\333\335\332\2" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0eM\222;;\20z\377aC\214\223\0\0\0" - "\0L*\205n:\21w\377od}\202\0\0\0\0?\26y\230:\20x\377rf\207YY\\\\\40\230\230" - "\232\372\364\365\365\377\366\366\366\377||}\3772-8\327:\17x\377U9}\372\337" - "\342\332\3\0\0\0\0\340\340\330\2\203w\230TE\40z\365<\23{\367W7\210D\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\327\305\357\1G\"}\330O,\203\353" - "\336\322\347\6F\37~\321F&r\375\255\254\256$\0\0\0\0?\26y\230:\17x\377\200" - "t\216c\262\222D\221\272\260\216\377\363\364\365\377\366\366\366\377\212\201" - "^\3773#%\377:\17x\377[Hx\302\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0xb\232]<\24z" - "\377>\27z\353\204l\242\36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "R2\205t;\20z\377y`\231w;\21v\377`Nz\303\0\0\0\0\0\0\0\0@\27z\230:\17y\377" - "\242\217r\245\355\272\21\377\310\240\20\377\331\326\323\377\324\324\324\377" - "\311\231\37\377\337\257\25\377S-^\377|u\203e\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0_?\214\2539\20z\377M*\202\262\367\361\363\2\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\205o\246\27?\26{\371J$\177\370:\24s\377\202{\206`" - "\0\0\0\0\0\0\0\0?\26z\230;\17x\377gG\200\325}QB\377\214\\C\377<\40L\377$" - "\15H\377\207^\25\377V9,\377TM_\307\312\317\307\5\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\242\215\271\26I$\200\355;\20z\377_C\213Y\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0M+\202\2619\20z\377P5u\361\313\314\307\15" - "\0\0\0\0\0\0\0\0>\25x\231;\17y\377:\20y\377:\17y\377;\17y\3779\17z\377<\24" - "p\377@)`\376bXo\262\266\264\253\26\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0u\\\233`<\21y\377A\34|\351\205s\246\25\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\221\211\2319kct\217|y\206a\0\0\0\0\0\0\0\0\0\0\0" - "\0\204y\215Mjcx\217kav\215lbx\217kar\215icr\205\202\202\204i\260\261\251" - "&\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\360\355\347\3wo\202zj`u\215\217\220\223?\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", -}; - diff --git a/vdrlogo_720x576.mpg b/vdrlogo_720x576.mpg Binary files differdeleted file mode 100644 index 2ef0f3f4..00000000 --- a/vdrlogo_720x576.mpg +++ /dev/null diff --git a/xine/adjustable_scr.c b/xine/adjustable_scr.c deleted file mode 100644 index 4301e348..00000000 --- a/xine/adjustable_scr.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * adjustable_scr.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: adjustable_scr.c,v 1.2 2008-12-14 01:21:20 phintuka Exp $ - * - */ - - -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/metronom.h> - -#include "adjustable_scr.h" - -/* - * SCR code is mostly copied from xine-lib (src/input/input_pvr.c) - * - * - * Copyright (C) 2000-2005 the xine project - * March 2003 - Miguel Freitas - * This plugin was sponsored by 1Control - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - */ - -typedef struct scr_impl_s scr_impl_t; - -struct scr_impl_s { - union { - scr_plugin_t scr; - adjustable_scr_t ascr; - }; - - xine_t *xine; - - struct timeval cur_time; - int64_t cur_pts; - int xine_speed; - int scr_speed_base; - double speed_factor; - double speed_tuning; - - pthread_mutex_t lock; - - struct timeval last_time; -}; - -/* Only call set_pivot when already mutex locked ! */ -static void set_pivot (scr_impl_t *this) -{ - struct timeval tv; - int64_t pts; - double pts_calc; - - xine_monotonic_clock(&tv,NULL); - - pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor; - pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6; - pts = this->cur_pts + pts_calc; - - /* This next part introduces a one off inaccuracy - * to the scr due to rounding tv to pts. - */ - this->cur_time.tv_sec=tv.tv_sec; - this->cur_time.tv_usec=tv.tv_usec; - this->cur_pts=pts; - - this->last_time.tv_sec = tv.tv_sec; - this->last_time.tv_usec = tv.tv_usec; - - return ; -} - -/* - * xine interface (scr_plugin_t) - */ - -static int scr_get_priority (scr_plugin_t *scr) -{ - return 50; /* high priority */ -} - -static int scr_set_fine_speed (scr_plugin_t *scr, int speed) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->xine_speed = speed; - this->speed_factor = (double) speed * (double)this->scr_speed_base /*90000.0*/ / - (1.0*XINE_FINE_SPEED_NORMAL) * - this->speed_tuning; - - pthread_mutex_unlock (&this->lock); - - return speed; -} - -static void scr_adjust (scr_plugin_t *scr, int64_t vpts) -{ - scr_impl_t *this = (scr_impl_t*) scr; - struct timeval tv; - - pthread_mutex_lock (&this->lock); - - xine_monotonic_clock(&tv,NULL); - this->cur_time.tv_sec=tv.tv_sec; - this->cur_time.tv_usec=tv.tv_usec; - this->cur_pts = vpts; - - this->last_time.tv_sec = tv.tv_sec; - this->last_time.tv_usec = tv.tv_usec; - - pthread_mutex_unlock (&this->lock); -} - -static void scr_start (scr_plugin_t *scr, int64_t start_vpts) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - xine_monotonic_clock(&this->cur_time, NULL); - this->cur_pts = start_vpts; - - this->last_time.tv_sec = this->cur_time.tv_sec; - this->last_time.tv_usec = this->cur_time.tv_usec; - - pthread_mutex_unlock (&this->lock); - - scr_set_fine_speed (&this->scr, XINE_FINE_SPEED_NORMAL); -} - -static int64_t scr_get_current (scr_plugin_t *scr) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - struct timeval tv; - int64_t pts; - double pts_calc; - pthread_mutex_lock (&this->lock); - - xine_monotonic_clock(&tv,NULL); - - pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor; - pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6; - - pts = this->cur_pts + pts_calc; - - this->last_time.tv_sec = tv.tv_sec; - this->last_time.tv_usec = tv.tv_usec; - - pthread_mutex_unlock (&this->lock); - - return pts; -} - -static void scr_exit (scr_plugin_t *scr) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_destroy (&this->lock); - free(this); -} - -/* - * adjusteble_scr_t - */ - -/* - * speed_tuning() - * - * - fine-tune SCR speed. Actual speed is base_speed * factor. - */ -static void adjustable_scr_speed_tuning (adjustable_scr_t *scr, double factor) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->speed_tuning = factor; - this->speed_factor = (double) this->xine_speed * (double)this->scr_speed_base /*90000.0*/ / - (1.0*XINE_FINE_SPEED_NORMAL) * - this->speed_tuning; - - pthread_mutex_unlock (&this->lock); -} - -/* - * speed_base() - * - * - set base speed of SCR (default is 90kHz) - */ -static void adjustable_scr_speed_base (adjustable_scr_t *scr, int hz) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->scr_speed_base = hz; - this->speed_factor = (double) this->xine_speed * (double)this->scr_speed_base /*90000.0*/ / - (1.0*XINE_FINE_SPEED_NORMAL) * - this->speed_tuning; - - pthread_mutex_unlock (&this->lock); -} - -/* - * jump() - * - * - Move SCR 'pts' ticks forward - */ -static void adjustable_scr_jump (adjustable_scr_t *scr, int pts) -{ - scr_impl_t *this = (scr_impl_t*) scr; - - pthread_mutex_lock (&this->lock); - - set_pivot( this ); - this->cur_pts += pts; - - pthread_mutex_unlock (&this->lock); -} - -/* - * dispose() - * - * - unregister, stop and free resources - */ -static void adjustable_scr_dispose(adjustable_scr_t *scr) -{ - scr_impl_t *this = (scr_impl_t*)scr; - - /* unregister */ - if (this->xine) - this->xine->clock->unregister_scr(this->xine->clock, &this->scr); - - /* exit and dispose */ - this->scr.exit(&this->scr); -} - -/* - * adjusteble_scr_start() - * - */ -adjustable_scr_t* adjustable_scr_start (xine_t *xine) -{ - scr_impl_t *this; - - this = calloc(1, sizeof(scr_impl_t)); - - /* xine scr plugin interface */ - this->scr.interface_version = 3; - this->scr.set_fine_speed = scr_set_fine_speed; - this->scr.get_priority = scr_get_priority; - this->scr.adjust = scr_adjust; - this->scr.start = scr_start; - this->scr.get_current = scr_get_current; - this->scr.exit = scr_exit; - - /* tuning / management interface */ - this->ascr.set_speed_tuning = adjustable_scr_speed_tuning; - this->ascr.set_speed_base = adjustable_scr_speed_base; - this->ascr.jump = adjustable_scr_jump; - this->ascr.dispose = adjustable_scr_dispose; - - /* initialize */ - - pthread_mutex_init (&this->lock, NULL); - - this->xine = xine; - this->scr_speed_base = 90000; - - adjustable_scr_speed_tuning(&this->ascr, 1.0 ); - scr_set_fine_speed (&this->scr, XINE_SPEED_PAUSE); - - /* start and register */ - - uint64_t time = xine->clock->get_current_time(xine->clock); - this->scr.start(&this->scr, time); - - if (xine->clock->register_scr(xine->clock, &this->scr)) { - scr_exit(&this->scr); - return NULL; - } - - return &this->ascr; -} diff --git a/xine/adjustable_scr.h b/xine/adjustable_scr.h deleted file mode 100644 index 61707684..00000000 --- a/xine/adjustable_scr.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * adjustable_scr.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: adjustable_scr.h,v 1.1 2008-12-03 22:50:04 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_ADJUSTABLE_SCR_H_ -#define XINELIBOUTPUT_ADJUSTABLE_SCR_H_ - -/******************************* SCR ************************************* - * - * unix System Clock Reference + fine tuning - * - * fine tuning is used to change playback speed in live mode - * to keep in sync with mpeg source - *************************************************************************/ - -typedef struct adjustable_scr_s adjustable_scr_t; - -struct adjustable_scr_s { - scr_plugin_t scr; - - void (*set_speed_tuning)(adjustable_scr_t *this, double factor); - void (*set_speed_base) (adjustable_scr_t *this, int hz); - void (*jump) (adjustable_scr_t *this, int pts); - - void (*dispose) (adjustable_scr_t *this); -}; - -adjustable_scr_t *adjustable_scr_start (xine_t *xine); - - -#endif /* XINELIBOUTPUT_ADJUSTABLE_SCR_H_ */ diff --git a/xine/demux_xvdr.c b/xine/demux_xvdr.c deleted file mode 100644 index b1387fd3..00000000 --- a/xine/demux_xvdr.c +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * Copyright (C) 2000-2006 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * demultiplexer for xineliboutput (xvdr) - */ - -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> - -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/demux.h> - -#include "../xine_input_vdr_mrl.h" -#include "../tools/mpeg.h" -#include "../tools/h264.h" -#include "../tools/pes.h" -#include "../tools/ts.h" - -#include "ts2es.h" -#include "demux_xvdr_tsdata.h" - -/* - * features - */ - -#define VDR_SUBTITLES -#define TEST_DVB_SPU - -/* - * logging - */ - -static const char log_module_demux_xvdr[] = "[demux_vdr] "; -#define LOG_MODULENAME log_module_demux_xvdr -#define SysLogLevel iSysLogLevel - -#include "../logdefs.h" - -#define LOGSPU(x...) - -/* - * constants - */ - -#define DISC_TRESHOLD 90000 -#define WRAP_THRESHOLD 120000 -#define PTS_AUDIO 0 -#define PTS_VIDEO 1 - - -/* redefine abs as macro to handle 64-bit diffs. - i guess llabs may not be available everywhere */ -#define abs(x) ( ((x)<0) ? -(x) : (x) ) - -typedef struct demux_xvdr_s { - demux_plugin_t demux_plugin; - - xine_stream_t *stream; - fifo_buffer_t *audio_fifo; - fifo_buffer_t *video_fifo; - - input_plugin_t *input; - - ts_data_t *ts_data; /* MPEG-TS stuff */ - - int64_t last_pts[2]; - int64_t last_vpts; - int status; - uint32_t video_type; - uint32_t audio_type; - uint32_t subtitle_type; - - /* current buf_element */ - int64_t pts; - int64_t dts; - uint32_t packet_len; - uint8_t stream_id; - - uint8_t send_newpts : 1; - uint8_t buf_flag_seek : 1; - uint8_t ffmpeg_mpeg2_decoder : 1; - uint8_t coreavc_h264_decoder : 1; - uint8_t bih_posted : 1; -} demux_xvdr_t ; - -typedef struct { - - demux_class_t demux_class; - - /* class-wide, global variables here */ - - xine_t *xine; - config_values_t *config; -} demux_xvdr_class_t; - - -static const char * get_decoder_name(xine_t *xine, int video_type) -{ - int streamtype = (video_type >> 16) & 0xFF; - plugin_node_t *node = xine->plugin_catalog->video_decoder_map[streamtype][0]; - if (node) { - plugin_info_t *info = node->info; - if (info) - return info->id; - } - return ""; -} - -static void detect_video_decoders(demux_xvdr_t *this) -{ - if (!strcmp(get_decoder_name(this->stream->xine, BUF_VIDEO_MPEG), "ffmpegvideo")) - this->ffmpeg_mpeg2_decoder = 1; - LOGMSG("Using decoder \"%s\" for mpeg2 video", - this->ffmpeg_mpeg2_decoder ? "FFmpeg" : "libmpeg2"); - - if (!strcmp(get_decoder_name(this->stream->xine, BUF_VIDEO_H264), "dshowserver")) - this->coreavc_h264_decoder = 1; - LOGMSG("Using decoder \"%s\" for H.264 video", - this->coreavc_h264_decoder ? "dshowserver (CoreAVC)" : "FFmpeg"); -} - -static void demux_xvdr_parse_ts(demux_xvdr_t *this, buf_element_t *buf); -static void demux_xvdr_parse_pes(demux_xvdr_t *this, buf_element_t *buf); - -static int32_t parse_video_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); -static int32_t parse_audio_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); -static int32_t parse_private_stream_1(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); -static int32_t parse_padding_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf); - -static void pts_wrap_workaround(demux_xvdr_t *this, buf_element_t *buf, int video) -{ - /* PTS wrap workaround */ - if (buf->pts >= 0) { - if (video) - this->last_vpts = buf->pts; - else if (buf->pts > INT64_C( 0x40400000 ) && - this->last_vpts < INT64_C( 0x40000000 ) && - this->last_vpts > INT64_C( 0 )) { - LOGMSG("VIDEO pts wrap before AUDIO, ignoring audio pts %" PRId64, buf->pts); - buf->pts = INT64_C(0); - } - } -} - -static void check_newpts(demux_xvdr_t *this, buf_element_t *buf, int video ) -{ - pts_wrap_workaround(this, buf, video); - - if (buf->pts) { - int64_t diff = buf->pts - this->last_pts[video]; - - if (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD)) { - - if (this->buf_flag_seek) { - _x_demux_control_newpts(this->stream, buf->pts, BUF_FLAG_SEEK); - this->buf_flag_seek = 0; - } else { - _x_demux_control_newpts(this->stream, buf->pts, 0); - } - this->send_newpts = 0; - - this->last_pts[1-video] = 0; - } - - this->last_pts[video] = buf->pts; - } -} - -static void put_control_buf(fifo_buffer_t *buffer, fifo_buffer_t *pool, int cmd) -{ - buf_element_t *buf = pool->buffer_pool_try_alloc(pool); - if(buf) { - buf->type = cmd; - buffer->put(buffer, buf); - } -} - -/* - * post_sequence_end() - * - * Add MPEG2 or H.264 sequence end code to fifo buffer - */ -static void post_sequence_end(fifo_buffer_t *fifo, uint32_t video_type) -{ - buf_element_t *buf = fifo->buffer_pool_try_alloc(fifo); - if (buf) { - buf->type = video_type; - buf->size = 4; - buf->decoder_flags = BUF_FLAG_FRAME_END; - buf->content[0] = 0x00; - buf->content[1] = 0x00; - buf->content[2] = 0x01; - buf->content[3] = (video_type == BUF_VIDEO_H264) ? NAL_END_SEQ : 0xB7; - fifo->put(fifo, buf); - } -} - -/* - * post_frame_end() - * - * Signal end of video frame to decoder. - * - * This function is used with: - * - FFmpeg mpeg2 decoder - * - FFmpeg and CoreAVC H.264 decoders - * - NOT with libmpeg2 mpeg decoder - */ -static void post_frame_end(demux_xvdr_t *this, buf_element_t *vid_buf) -{ - buf_element_t *cbuf = this->video_fifo->buffer_pool_try_alloc (this->video_fifo) ?: - this->audio_fifo->buffer_pool_try_alloc (this->audio_fifo); - - if (!cbuf) { - LOGMSG("post_frame_end(): buffer_pool_try_alloc() failed, retrying"); - xine_usec_sleep (10*1000); - cbuf = this->video_fifo->buffer_pool_try_alloc (this->video_fifo); - if (!cbuf) { - LOGERR("post_frame_end(): get_buf_element() failed !"); - return; - } - } - - cbuf->type = this->video_type; - cbuf->decoder_flags = BUF_FLAG_FRAME_END; - - if (!this->bih_posted) { - video_size_t size = {0}; - if (pes_get_video_size(vid_buf->content, vid_buf->size, &size, this->video_type == BUF_VIDEO_H264)) { - - /* reset decoder buffer */ - cbuf->decoder_flags |= BUF_FLAG_FRAME_START; - - /* Fill xine_bmiheader for CoreAVC / H.264 */ - - if (this->video_type == BUF_VIDEO_H264 && this->coreavc_h264_decoder) { - xine_bmiheader *bmi = (xine_bmiheader*) cbuf->content; - - cbuf->decoder_flags |= BUF_FLAG_HEADER; - cbuf->decoder_flags |= BUF_FLAG_STDHEADER; /* CoreAVC: buffer contains bmiheader */ - cbuf->size = sizeof(xine_bmiheader); - - memset (bmi, 0, sizeof(xine_bmiheader)); - - bmi->biSize = sizeof(xine_bmiheader); - bmi->biWidth = size.width; - bmi->biHeight = size.height; - - bmi->biPlanes = 1; - bmi->biBitCount = 24; - bmi->biCompression = 0x34363248; - bmi->biSizeImage = 0; - bmi->biXPelsPerMeter = size.pixel_aspect.num; - bmi->biYPelsPerMeter = size.pixel_aspect.den; - bmi->biClrUsed = 0; - bmi->biClrImportant = 0; - } - - /* Set aspect ratio for ffmpeg mpeg2 / CoreAVC H.264 decoder - * (not for FFmpeg H.264 or libmpeg2 mpeg2 decoders) - */ - - if (size.pixel_aspect.num && - (this->video_type != BUF_VIDEO_H264 || this->coreavc_h264_decoder)) { - cbuf->decoder_flags |= BUF_FLAG_HEADER; - cbuf->decoder_flags |= BUF_FLAG_ASPECT; - /* pixel ratio -> frame ratio */ - if (size.pixel_aspect.num > size.height) { - cbuf->decoder_info[1] = size.pixel_aspect.num / size.height; - cbuf->decoder_info[2] = size.pixel_aspect.den / size.width; - } else { - cbuf->decoder_info[1] = size.pixel_aspect.num * size.width; - cbuf->decoder_info[2] = size.pixel_aspect.den * size.height; - } - } - - LOGDBG("post_frame_end: video width %d, height %d, pixel aspect %d:%d", - size.width, size.height, size.pixel_aspect.num, size.pixel_aspect.den); - - this->bih_posted = 1; - } - } - - this->video_fifo->put (this->video_fifo, cbuf); -} - -static void track_audio_stream_change(demux_xvdr_t *this, buf_element_t *buf) -{ -#if !defined(BUF_CONTROL_RESET_TRACK_MAP) -# warning xine-lib is older than 1.1.2. Multiple audio streams are not supported. -#else - if (this->audio_type != buf->type) { - LOGDBG("audio stream changed: %08x -> %08x", this->audio_type, buf->type); - this->audio_type = buf->type; - put_control_buf(this->audio_fifo, - this->audio_fifo, - BUF_CONTROL_RESET_TRACK_MAP); - } -#endif -} - -static void demux_xvdr_fwd_buf(demux_xvdr_t *this, buf_element_t *buf) -{ - /* demuxed video --> video_fifo */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_VIDEO_BASE) { - this->video_type = buf->type; - check_newpts (this, buf, PTS_VIDEO); - this->video_fifo->put (this->video_fifo, buf); - return; - } - - /* demuxed audio --> audio_fifo */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_AUDIO_BASE) { - if (this->audio_fifo) { - check_newpts (this, buf, PTS_AUDIO); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - } else { - buf->free_buffer (buf); - } - return; - } - - /* decoder flush --> video_fifo */ - if (buf->type == BUF_CONTROL_FLUSH_DECODER) { - /* append sequence end code */ - post_sequence_end (this->video_fifo, this->video_type); - this->video_fifo->put (this->video_fifo, buf); - return; - } - - /* control buffer --> both fifos */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE) { - if (this->audio_fifo) { - /* duplicate goes to audio fifo */ - buf_element_t *cbuf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - cbuf->type = buf->type; - cbuf->decoder_flags = buf->decoder_flags; - memcpy (cbuf->decoder_info, buf->decoder_info, sizeof(cbuf->decoder_info)); - memcpy (cbuf->decoder_info_ptr, buf->decoder_info_ptr, sizeof(cbuf->decoder_info_ptr)); - - this->audio_fifo->put (this->audio_fifo, cbuf); - } - this->video_fifo->put (this->video_fifo, buf); - return; - } - - LOGMSG("Unhandled buffer type %08x", buf->type); - buf->free_buffer (buf); -} - -static void demux_xvdr_parse_pack (demux_xvdr_t *this) -{ - buf_element_t *buf = NULL; - uint8_t *p; - - buf = this->input->read_block (this->input, this->video_fifo, 8128); - - if (!buf) { - if (errno == EINTR) - LOGMSG("input->read_block() was interrupted"); - else if (errno != EAGAIN) - this->status = DEMUX_FINISHED; - return; - } - - /* If this is not a block for the demuxer, pass it - * straight through. */ - if (buf->type != BUF_DEMUX_BLOCK) { - ts_data_flush (this->ts_data); - demux_xvdr_fwd_buf (this, buf); - return; - } - - p = buf->content; /* len = this->blocksize; */ - buf->decoder_flags = 0; - - if (DATA_IS_TS(p)) { - demux_xvdr_parse_ts (this, buf); - return; - } - if (DATA_IS_PES(p)) { - demux_xvdr_parse_pes (this, buf); - return; - } - - LOGMSG("Header %02x %02x %02x (should be 0x000001 or 0x47)", p[0], p[1], p[2]); - buf->free_buffer (buf); - return; -} - -static void demux_xvdr_parse_pes (demux_xvdr_t *this, buf_element_t *buf) -{ - uint8_t *p = buf->content; - int32_t result; - - this->stream_id = p[3]; - - if (IS_VIDEO_PACKET(p)) { - result = parse_video_stream(this, p, buf); - } else if (IS_MPEG_AUDIO_PACKET(p)) { - result = parse_audio_stream(this, p, buf); - } else if (IS_PADDING_PACKET(p)) { - result = parse_padding_stream(this, p, buf); - } else if (IS_PS1_PACKET(p)) { - result = parse_private_stream_1(this, p, buf); - } else { - LOGMSG("Unrecognised PES stream 0x%02x", this->stream_id); - buf->free_buffer (buf); - return; - } - - if (result < 0) { - return; - } - - LOGMSG("error! freeing buffer."); - buf->free_buffer (buf); -} - -/* - * demux_xvdr_parse_ts() - * - * MPEG-TS demuxing - */ -static void demux_xvdr_parse_ts (demux_xvdr_t *this, buf_element_t *buf) -{ - if (!this->ts_data) - this->ts_data = calloc(1, sizeof(ts_data_t)); - - ts_data_t *ts_data = this->ts_data; - - while (buf->size >= TS_SIZE) { - - unsigned int ts_pid = ts_PID(buf->content); - - /* parse PAT */ - if (ts_pid == 0) { - pat_data_t pat; - - ts_data_flush(ts_data); - - if (ts_parse_pat(&pat, buf->content)) { - ts_data->pmt_pid = pat.pmt_pid[0]; - ts_data->program_number = pat.program_number[0]; - LOGMSG("Got PAT, PMT pid = %d, program = %d", ts_data->pmt_pid, ts_data->program_number); - } - } - - /* parse PMT */ - else if (ts_pid == ts_data->pmt_pid) { - - ts_data_flush(ts_data); - - if (ts_parse_pmt(&ts_data->pmt, ts_data->program_number, buf->content)) { - - /* PMT changed, reset ts->es converters */ - LOGMSG("PMT changed"); - ts_data_ts2es_init(&ts_data, this->stream->video_fifo, this->stream->audio_fifo); - - this->video_type = (ts_data->pmt.video_type == ISO_14496_PART10_VIDEO) ? - BUF_VIDEO_H264 : BUF_VIDEO_MPEG; - - /* Inform UI of channels changes */ - xine_event_t event; - event.type = XINE_EVENT_UI_CHANNELS_CHANGED; - event.data_length = 0; - xine_event_send(this->stream, &event); - } - } - - /* demux video */ - else if (ts_pid == ts_data->pmt.video_pid) { - - if (ts_data->video) { - buf_element_t *vbuf = ts2es_put(ts_data->video, buf->content); - if (vbuf) { - this->pts = vbuf->pts; - check_newpts( this, vbuf, PTS_VIDEO ); - - this->stream->video_fifo->put(this->stream->video_fifo, vbuf); - } - } - } - - /* demux audio */ - else { - int i, done = 0; - for (i=0; i < ts_data->pmt.audio_tracks_count; i++) - if (ts_pid == ts_data->pmt.audio_tracks[i].pid) { - if (ts_data->audio[i]) { - buf_element_t *abuf = ts2es_put(ts_data->audio[i], buf->content); - if (abuf) { - this->pts = abuf->pts; - check_newpts( this, abuf, PTS_AUDIO ); - track_audio_stream_change (this, abuf); - - this->stream->audio_fifo->put(this->stream->audio_fifo, abuf); - } - } - done = 1; - break; - } -#if 0 - /* demux subtitles */ - if (!done) - for (i=0; i < ts_data->pmt.spu_tracks_count; i++) - if (ts_pid == ts_data->pmt.spu_tracks[i].pid) { - if (ts_data->spu[i]) { - buf_element_t *sbuf = ts2es_put(ts_data->spu[i], buf->content); - if (sbuf) - this->stream->video_fifo->put(this->stream->video_fifo, sbuf); - } - done = 1; - break; - } - - if (!done) - LOGMSG("Got unknown TS packet, pid = %d", ts_pid); -#endif - } - - buf->content += TS_SIZE; - buf->size -= TS_SIZE; - } - - buf->free_buffer(buf); -} - -static int32_t parse_padding_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - buf->free_buffer (buf); - return -1; -} - -/* FIXME: Extension data is not parsed, and is also not skipped. */ - -static int32_t parse_pes_for_pts(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int32_t header_len; - - this->packet_len = p[4] << 8 | p[5]; - - if ((p[6] & 0xC0) != 0x80 /* mpeg1 */) { - header_len = 6; - p += 6; /* packet_len -= 6; */ - - while ((p[0] & 0x80) == 0x80) { - p++; - header_len++; - this->packet_len--; - } - - if ((p[0] & 0xc0) == 0x40) { - /* STD_buffer_scale, STD_buffer_size */ - p += 2; - header_len += 2; - this->packet_len -= 2; - } - - this->pts = 0; - this->dts = 0; - - if ((p[0] & 0xf0) == 0x20) { - this->pts = (int64_t)(p[ 0] & 0x0E) << 29 ; - this->pts |= p[ 1] << 22 ; - this->pts |= (p[ 2] & 0xFE) << 14 ; - this->pts |= p[ 3] << 7 ; - this->pts |= (p[ 4] & 0xFE) >> 1 ; - p += 5; - header_len+= 5; - this->packet_len -=5; - return header_len; - } else if ((p[0] & 0xf0) == 0x30) { - this->pts = (int64_t)(p[ 0] & 0x0E) << 29 ; - this->pts |= p[ 1] << 22 ; - this->pts |= (p[ 2] & 0xFE) << 14 ; - this->pts |= p[ 3] << 7 ; - this->pts |= (p[ 4] & 0xFE) >> 1 ; - - this->dts = (int64_t)(p[ 5] & 0x0E) << 29 ; - this->dts |= p[ 6] << 22 ; - this->dts |= (p[ 7] & 0xFE) << 14 ; - this->dts |= p[ 8] << 7 ; - this->dts |= (p[ 9] & 0xFE) >> 1 ; - - p += 10; - header_len += 10; - this->packet_len -= 10; - return header_len; - } else { - p++; - header_len++; - this->packet_len--; - return header_len; - } - - } else { /* mpeg 2 */ - - - if ((p[6] & 0xC0) != 0x80) { - LOGMSG("warning: PES header reserved 10 bits not found"); - buf->free_buffer(buf); - return -1; - } - - - /* check PES scrambling_control */ - if ((p[6] & 0x30) != 0) { - LOGMSG("encrypted PES ?"); - buf->free_buffer(buf); - return -1; - } - - if (p[7] & 0x80) { /* pts avail */ - - this->pts = (int64_t)(p[ 9] & 0x0E) << 29 ; - this->pts |= p[10] << 22 ; - this->pts |= (p[11] & 0xFE) << 14 ; - this->pts |= p[12] << 7 ; - this->pts |= (p[13] & 0xFE) >> 1 ; - - } else - this->pts = 0; - - if (p[7] & 0x40) { /* dts avail */ - - this->dts = (int64_t)(p[14] & 0x0E) << 29 ; - this->dts |= p[15] << 22 ; - this->dts |= (p[16] & 0xFE) << 14 ; - this->dts |= p[17] << 7 ; - this->dts |= (p[18] & 0xFE) >> 1 ; - - } else - this->dts = 0; - - - header_len = p[8]; - - this->packet_len -= header_len + 3; - return header_len + 9; - } - return 0; -} - -#if defined(TEST_DVB_SPU) -/* - * parse_dvb_spu() - * - * DVB subtitle stream demuxing - */ -static int32_t parse_dvb_spu(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf, int substream_header_len) -{ - uint spu_id = p[0] & 0x1f; - _x_select_spu_channel(this->stream, spu_id); - -# ifdef VDR_SUBTITLES - if (substream_header_len == 1) { - p--; - this->packet_len++; - } -# endif /* VDR_SUBTITLES */ - - /* Skip substream header */ - p += substream_header_len; - buf->content = p; - buf->size = this->packet_len - substream_header_len; - - /* Special buffer when payload packet changes */ - if (this->pts > 0) { - buf_element_t *cbuf = this->video_fifo->buffer_pool_alloc(this->video_fifo); - int page_id = (*(p+4) << 8) | *(p+5); - - spu_dvb_descriptor_t *spu_descriptor = (spu_dvb_descriptor_t *) cbuf->content; - memset(spu_descriptor, 0, sizeof(spu_dvb_descriptor_t)); - spu_descriptor->comp_page_id = page_id; - - cbuf->type = BUF_SPU_DVB + spu_id; - cbuf->size = 0; - cbuf->decoder_flags = BUF_FLAG_SPECIAL; - cbuf->decoder_info[1] = BUF_SPECIAL_SPU_DVB_DESCRIPTOR; - cbuf->decoder_info[2] = sizeof(spu_dvb_descriptor_t); - cbuf->decoder_info_ptr[2] = spu_descriptor; - - this->video_fifo->put (this->video_fifo, cbuf); - } - - buf->type = BUF_SPU_DVB + spu_id; - buf->pts = this->pts; - buf->decoder_info[2] = this->pts > 0 ? 0xffff : 0; /* hack - size unknown here (?) */ - - this->video_fifo->put (this->video_fifo, buf); - - return -1; -} - -int detect_dvb_spu(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - LOGSPU("%s%02x %02x %02x %02x %02x %02x %02x %02x", - this->pts>0?"* ":" ",p[0], p[1], p[2], p[3], - p[4], p[5], p[6], p[7]); - - /* If PES packet has PTS, it starts new subtitle (ES) packet. */ - if (this->pts > 0) { - /* Reset SPU type */ - this->subtitle_type = 0; - } - -# ifdef VDR_SUBTITLES - /* Compatibility mode for old subtitles plugin */ - if (this->subtitle_type != BUF_SPU_DVD) { - if ((buf->content[7] & 0x01) && (p[-3] & 0x81) == 0x01 && p[-2] == 0x81) { - LOGDBG("DVB SPU: Old vdr-subtitles compability mode"); - return parse_dvb_spu(this, p, buf, 1); - } - } -# endif /* VDR_SUBTITLES */ - - /* Start of subtitle packet. Guess substream type */ - if (this->pts > 0) { - if (p[4] == 0x20 && p[5] == 0x00 && (p[6] == 0x0f || p[4] == 0x0f)) { - this->subtitle_type = BUF_SPU_DVB; - LOGSPU(" -> DVB SPU"); - } else if (p[2] || (p[3] & 0xfe)) { - this->subtitle_type = BUF_SPU_DVD; - LOGSPU(" -> DVD SPU"); - } else { - this->subtitle_type = BUF_SPU_DVD; - LOGMSG(" -> DV? SPU -> DVD"); - } - } - - /* DVD SPU ? */ - if (this->subtitle_type == BUF_SPU_DVD) - return this->packet_len; - - /* DVB SPU */ - return parse_dvb_spu(this, p, buf, 4); -} - -#endif /* TEST_DVB_SPU */ - -static int32_t parse_private_stream_1(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int track, spu_id; - int32_t result; - - result = parse_pes_for_pts(this, p, buf); - if (result < 0) return -1; - - p += result; - - /* SPU */ - if ((p[0] & 0xE0) == 0x20) { - spu_id = (p[0] & 0x1f); - - if (this->pts <= 0 && !this->subtitle_type) { - /* need whole ES packet (after seek etc.) */ - buf->free_buffer(buf); - return -1; - } - -#ifdef TEST_DVB_SPU - if (detect_dvb_spu(this, p, buf) < 0) - return -1; -#endif /* TEST_DVB_SPU */ - this->subtitle_type = BUF_SPU_DVD; - - /* DVD SPU */ - buf->content = p+1; - buf->size = this->packet_len-1; - - buf->type = BUF_SPU_DVD + spu_id; - buf->decoder_flags |= BUF_FLAG_SPECIAL; - buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE; - buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE; - buf->pts = this->pts; - - this->video_fifo->put (this->video_fifo, buf); - - return -1; - } - - if ((p[0]&0xF0) == 0x80) { - - track = p[0] & 0x0F; /* hack : ac3 track */ - - buf->decoder_info[1] = p[1]; /* Number of frame headers */ - buf->decoder_info[2] = p[2] << 8 | p[3]; /* First access unit pointer */ - - buf->content = p+4; - buf->size = this->packet_len-4; - if (track & 0x8) { - buf->type = BUF_AUDIO_DTS + (track & 0x07); /* DVDs only have 8 tracks */ - } else { - buf->type = BUF_AUDIO_A52 + track; - } - buf->pts = this->pts; - - if (this->audio_fifo) { - check_newpts( this, buf, PTS_AUDIO ); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - return -1; - } else { - buf->free_buffer(buf); - return -1; - } - - } else if ((p[0]&0xf0) == 0xa0) { - - int pcm_offset; - int number_of_frame_headers; - int first_access_unit_pointer; - int audio_frame_number; - int bits_per_sample; - int sample_rate; - int num_channels; - int dynamic_range; - - /* - * found in http://members.freemail.absa.co.za/ginggs/dvd/mpeg2_lpcm.txt - * appears to be correct. - */ - - track = p[0] & 0x0F; - number_of_frame_headers = p[1]; - /* unknown = p[2]; */ - first_access_unit_pointer = p[3]; - audio_frame_number = p[4]; - - /* - * 000 => mono - * 001 => stereo - * 010 => 3 channel - * ... - * 111 => 8 channel - */ - num_channels = (p[5] & 0x7) + 1; - sample_rate = p[5] & 0x10 ? 96000 : 48000; - switch ((p[5]>>6) & 3) { - case 3: /* illegal, use 16-bits? */ - default: - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "illegal lpcm sample format (%d), assume 16-bit samples\n", (p[5]>>6) & 3 ); - case 0: bits_per_sample = 16; break; - case 1: bits_per_sample = 20; break; - case 2: bits_per_sample = 24; break; - } - dynamic_range = p[6]; - - /* send lpcm config byte */ - buf->decoder_flags |= BUF_FLAG_SPECIAL; - buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG; - buf->decoder_info[2] = p[5]; - - pcm_offset = 7; - - buf->content = p+pcm_offset; - buf->size = this->packet_len-pcm_offset; - buf->type = BUF_AUDIO_LPCM_BE + track; - buf->pts = this->pts; - - if (this->audio_fifo) { - check_newpts( this, buf, PTS_AUDIO ); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - return -1; - } else { - buf->free_buffer(buf); - return -1; - } - } - - buf->free_buffer(buf); - return -1; -} - -/* - * detect_h264() - * - * Detect video codec (MPEG2 or H.264) - */ -static int detect_h264(uint8_t *data) -{ - /* H.264 detection */ - if (data[0] == 0 && data[1] == 0 && data[2] == 1) { - if (data[3] == NAL_AUD) { - LOGMSG("H.264 scanner: Possible H.264 NAL AUD"); - return BUF_VIDEO_H264; - } - if (data[3] == 0) { - LOGDBG("H.264 scanner: Possible MPEG2 start code PICTURE (0x00)"); - return BUF_VIDEO_MPEG; - } - if (data[3] >= 0x80) { - LOGDBG("H.264 scanner: Possible MPEG2 start code (0x%02x)", data[3]); - return BUF_VIDEO_MPEG; - } - LOGMSG("H.264 scanner: Unregonized header 00 00 01 %02x", data[3]); - } - - return 0; -} - -static int32_t parse_video_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int32_t result; - - result = parse_pes_for_pts(this, p, buf); - if (result < 0) return -1; - - p += result; - - if (this->video_type == 0) { - this->video_type = detect_h264(p); - } - - buf->type = this->video_type ?: BUF_VIDEO_MPEG; - buf->pts = this->pts; - buf->decoder_info[0] = this->pts - this->dts; - - /* MPEG2 */ - if (this->video_type == BUF_VIDEO_MPEG) { - /* Special handling for FFMPEG MPEG2 decoder */ - if (this->ffmpeg_mpeg2_decoder) { - uint8_t type = pes_get_picture_type(buf->content, buf->size); - if (type) { - /* signal FRAME_END to decoder */ - post_frame_end(this, buf); - /* for some reason ffmpeg mpeg2 decoder does not understand pts'es in B frames ? - * (B-frame pts's are smaller than in previous P-frame) - * Anyway, without this block of code B frames with pts are dropped. */ - if (type == B_FRAME) - buf->pts = 0; - } - } - } - - /* H.264 */ - else if (this->video_type == BUF_VIDEO_H264) { - /* Access Unit Delimiter */ - if (IS_NAL_AUD(p)) - post_frame_end (this, buf); - - /* Check for end of still image. - VDR ensures that H.264 still images end with an end of sequence NAL unit */ - if (buf->size > 4) { - uint8_t *end = buf->content + buf->size; - if (IS_NAL_END_SEQ(end-4)) { - LOGMSG("post_frame_h264: Still frame ? (frame ends with end of sequence NAL unit)"); - buf->decoder_flags |= BUF_FLAG_FRAME_END; - } - } - } - - buf->content = p; - buf->size = this->packet_len; - - check_newpts( this, buf, PTS_VIDEO ); - - this->video_fifo->put (this->video_fifo, buf); - - return -1; -} - -static int32_t parse_audio_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf) -{ - int track; - int32_t result; - - result = parse_pes_for_pts(this, p, buf); - if (result < 0) return -1; - - p += result; - - track = this->stream_id & 0x1f; - - buf->content = p; - buf->size = this->packet_len; - buf->type = BUF_AUDIO_MPEG + track; - buf->pts = this->pts; - - if (this->audio_fifo) { - check_newpts( this, buf, PTS_AUDIO ); - track_audio_stream_change (this, buf); - this->audio_fifo->put (this->audio_fifo, buf); - } else { - buf->free_buffer(buf); - } - - return -1; -} - -/* - * interface - */ - -static int demux_xvdr_send_chunk (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - demux_xvdr_parse_pack(this); - - return this->status; -} - -static void demux_xvdr_dispose (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - free (this); -} - -static int demux_xvdr_get_status (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - return this->status; -} - -static void demux_xvdr_send_headers (demux_plugin_t *this_gen) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - this->video_fifo = this->stream->video_fifo; - this->audio_fifo = this->stream->audio_fifo; - - /* - * send start buffer - */ - - _x_demux_control_start(this->stream); - - this->status = DEMUX_OK; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, 5000000); -} - - -static int demux_xvdr_seek (demux_plugin_t *this_gen, - off_t start_pos, int start_time, int playing) -{ - demux_xvdr_t *this = (demux_xvdr_t *) this_gen; - - /* - * now start demuxing - */ - this->send_newpts = 1; - this->video_type = 0; - this->audio_type = 0; - this->subtitle_type = 0; - this->bih_posted = 0; - ts_data_dispose(&this->ts_data); - - if (!playing) { - - this->buf_flag_seek = 0; - this->status = DEMUX_OK; - this->last_pts[0] = 0; - this->last_pts[1] = 0; - } else { - this->buf_flag_seek = 1; - this->last_vpts = INT64_C(-1); - _x_demux_flush_engine(this->stream); - } - - return this->status; -} - -/* - * demux class - */ - -static int demux_xvdr_get_stream_length (demux_plugin_t *this_gen) -{ - return 0; -} - -static uint32_t demux_xvdr_get_capabilities(demux_plugin_t *this_gen) -{ - return DEMUX_CAP_NOCAP; -} - -static int demux_xvdr_get_optional_data(demux_plugin_t *this_gen, - void *data, int data_type) -{ - return DEMUX_OPTIONAL_UNSUPPORTED; -} - -static demux_plugin_t *demux_xvdr_open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, - input_plugin_t *input_gen) -{ - input_plugin_t *input = (input_plugin_t *) input_gen; - demux_xvdr_t *this; - const char *mrl = input->get_mrl(input); - - if (strncmp(mrl, MRL_ID ":/", MRL_ID_LEN + 2 ) && - strncmp(mrl, MRL_ID "+pipe://", MRL_ID_LEN + 8) && - strncmp(mrl, MRL_ID "+tcp://", MRL_ID_LEN + 7) && - strncmp(mrl, MRL_ID "+udp://", MRL_ID_LEN + 7) && - strncmp(mrl, MRL_ID "+rtp://", MRL_ID_LEN + 7)) - return NULL; - - this = calloc(1, sizeof(demux_xvdr_t)); - this->stream = stream; - this->input = input; - - this->demux_plugin.send_headers = demux_xvdr_send_headers; - this->demux_plugin.send_chunk = demux_xvdr_send_chunk; - this->demux_plugin.seek = demux_xvdr_seek; - this->demux_plugin.dispose = demux_xvdr_dispose; - this->demux_plugin.get_status = demux_xvdr_get_status; - this->demux_plugin.get_stream_length = demux_xvdr_get_stream_length; - this->demux_plugin.get_capabilities = demux_xvdr_get_capabilities; - this->demux_plugin.get_optional_data = demux_xvdr_get_optional_data; - this->demux_plugin.demux_class = class_gen; - - this->status = DEMUX_FINISHED; - - detect_video_decoders(this); - - return &this->demux_plugin; -} - -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 -static const char *demux_xvdr_get_description (demux_class_t *this_gen) -{ - return MRL_ID " demux plugin"; -} - -static const char *demux_xvdr_get_identifier (demux_class_t *this_gen) -{ - return MRL_ID; -} - -static const char *demux_xvdr_get_extensions (demux_class_t *this_gen) -{ - return NULL; -} - -static const char *demux_xvdr_get_mimetypes (demux_class_t *this_gen) -{ - return NULL; -} - -static void demux_xvdr_class_dispose (demux_class_t *this_gen) -{ - demux_xvdr_class_t *this = (demux_xvdr_class_t *) this_gen; - - free (this); -} -#endif - -void *demux_xvdr_init_class (xine_t *xine, void *data) -{ - demux_xvdr_class_t *this; - - this = calloc(1, sizeof(demux_xvdr_class_t)); - this->config = xine->config; - this->xine = xine; - - this->demux_class.open_plugin = demux_xvdr_open_plugin; -#if DEMUXER_PLUGIN_IFACE_VERSION < 27 - this->demux_class.get_description = demux_xvdr_get_description; - this->demux_class.get_identifier = demux_xvdr_get_identifier; - this->demux_class.get_mimetypes = demux_xvdr_get_mimetypes; - this->demux_class.get_extensions = demux_xvdr_get_extensions; - this->demux_class.dispose = demux_xvdr_class_dispose; -#else - this->demux_class.description = N_("XVDR demux plugin"); - this->demux_class.identifier = MRL_ID; - this->demux_class.mimetypes = NULL; - this->demux_class.extensions = - MRL_ID":/ " - MRL_ID"+pipe:/ " - MRL_ID"+tcp:/ " - MRL_ID"+udp:/ " - MRL_ID"+rtp:/ " - MRL_ID"+slave:/"; - this->demux_class.dispose = default_demux_class_dispose; -#endif - - return this; -} - - diff --git a/xine/demux_xvdr_tsdata.c b/xine/demux_xvdr_tsdata.c deleted file mode 100644 index 38904a97..00000000 --- a/xine/demux_xvdr_tsdata.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * demux_xvdr_tsdata.h: data for MPEG-TS demuxer - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: demux_xvdr_tsdata.c,v 1.1 2009-02-24 19:50:42 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/buffer.h> - -#define LOG_MODULENAME "[demux_vdr] " -#define SysLogLevel iSysLogLevel -#include "../logdefs.h" - -#include "../tools/ts.h" -#include "ts2es.h" - -#include "demux_xvdr_tsdata.h" - -static void ts_data_ts2es_reset(ts_data_t *ts_data) -{ - int i; - - ts2es_dispose(ts_data->video); - ts_data->video = NULL; - - for (i = 0; ts_data->audio[i]; i++) { - ts2es_dispose(ts_data->audio[i]); - ts_data->audio[i] = NULL; - } - - for (i = 0; ts_data->spu[i]; i++) { - ts2es_dispose(ts_data->spu[i]); - ts_data->spu[i] = NULL; - } -} - -void ts_data_ts2es_init(ts_data_t **ts_data, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo) -{ - if (*ts_data) - ts_data_ts2es_reset(*ts_data); - else - *ts_data = calloc (1, sizeof(ts_data_t)); - - ts_data_t *this = *ts_data; - int i; - - if (video_fifo) { - if (this->pmt.video_pid != INVALID_PID) - this->video = ts2es_init(video_fifo, this->pmt.video_type, 0); - - for (i=0; i < this->pmt.spu_tracks_count; i++) - this->spu[i] = ts2es_init(video_fifo, STREAM_DVBSUB, i); - } - - if (audio_fifo) { - for (i=0; i < this->pmt.audio_tracks_count; i++) - this->audio[i] = ts2es_init(audio_fifo, this->pmt.audio_tracks[i].type, i); - } -} - -void ts_data_flush(ts_data_t *ts_data) -{ - if (ts_data) { - int i; - - if (ts_data->video) - ts2es_flush(ts_data->video); - - for (i = 0; ts_data->audio[i]; i++) - ts2es_flush(ts_data->audio[i]); - - for (i = 0; ts_data->spu[i]; i++) - ts2es_flush(ts_data->spu[i]); - } -} - -void ts_data_dispose(ts_data_t **ts_data) -{ - if (*ts_data) { - - ts_data_ts2es_reset(*ts_data); - - free(*ts_data); - *ts_data = NULL; - } -} diff --git a/xine/demux_xvdr_tsdata.h b/xine/demux_xvdr_tsdata.h deleted file mode 100644 index 96a1b893..00000000 --- a/xine/demux_xvdr_tsdata.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * demux_xvdr_tsdata.h: data for MPEG-TS demuxer - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: demux_xvdr_tsdata.h,v 1.1 2009-02-24 19:50:42 phintuka Exp $ - * - */ - -#ifndef _DEMUX_XVDR_TSDATA_H_ -#define _DEMUX_XVDR_TSDATA_H_ - -struct ts2es_s; - -struct ts_data_s { - uint16_t pmt_pid; - uint16_t program_number; - - pmt_data_t pmt; - - struct ts2es_s *video; - struct ts2es_s *audio[TS_MAX_AUDIO_TRACKS]; - struct ts2es_s *spu[TS_MAX_SPU_TRACKS]; -}; - -typedef struct ts_data_s ts_data_t; - -void ts_data_ts2es_init (ts_data_t **ts_data, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo); -void ts_data_flush (ts_data_t *ts_data); -void ts_data_dispose (ts_data_t **ts_data); - - -#endif /* _DEMUX_XVDR_TSDATA_H_ */ diff --git a/xine/osd_manager.c b/xine/osd_manager.c deleted file mode 100644 index a7d0d6b4..00000000 --- a/xine/osd_manager.c +++ /dev/null @@ -1,729 +0,0 @@ -/* - * osd_manager.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: osd_manager.c,v 1.13 2009-06-02 14:17:05 phintuka Exp $ - * - */ - -#include <stdlib.h> -#include <pthread.h> - -#define XINE_ENGINE_INTERNAL -#include <xine/xine_internal.h> -#include <xine/video_out.h> - -#include "../xine_osd_command.h" -#include "../xine_input_vdr.h" - -#include "../tools/rle.h" - -#include "vo_props.h" -#include "osd_manager.h" - -/*#define LOGOSD(x...) LOGMSG(x)*/ -#define LOGOSD(x...) - -static const char log_module_input_osd[] = "[input_osd] "; -#define LOG_MODULENAME log_module_input_osd -#define SysLogLevel iSysLogLevel - -#include "../logdefs.h" - - -typedef struct { - int handle; /* xine-lib overlay handle */ - osd_command_t cmd; /* Full OSD data: last OSD_Set_RLE event */ - - uint16_t extent_width; /* output size this OSD was designed for */ - uint16_t extent_height; - - int64_t last_changed_vpts; -} osd_data_t; - -typedef struct osd_manager_impl_s { - osd_manager_t mgr; - - pthread_mutex_t lock; - uint8_t ticket_acquired; - xine_stream_t *stream; - - uint16_t video_width; - uint16_t video_height; - uint8_t vo_scaling; - - osd_data_t osd[MAX_OSD_OBJECT]; - -} osd_manager_impl_t; - -/************************************* Tools ************************************/ - -/* - * acquire_ticket() - */ -static void acquire_ticket(osd_manager_impl_t *this) -{ - if (!this->ticket_acquired) { - this->stream->xine->port_ticket->acquire(this->stream->xine->port_ticket, 1); - this->ticket_acquired = 1; - } -} - -static void release_ticket(osd_manager_impl_t *this) -{ - if (this->ticket_acquired) { - this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 1); - this->ticket_acquired = 0; - } -} - -/* - * get_overlay_manager() - */ -video_overlay_manager_t *get_ovl_manager(osd_manager_impl_t *this) -{ - /* Get overlay manager. We need ticket ... */ - acquire_ticket(this); - video_overlay_manager_t *ovl_manager = this->stream->video_out->get_overlay_manager(this->stream->video_out); - if (!ovl_manager) { - LOGMSG("Stream has no overlay manager !"); - return NULL; - } - return ovl_manager; -} - -/* - * palette_argb_to_ayuv() - */ - -#define saturate(x,min,max) ( (x)<(min) ? (min) : (x)>(max) ? (max) : (x)) - -static void palette_argb_to_ayuv(xine_clut_t *clut, int colors) -{ - if (clut && colors>0) { - int c; - for (c=0; c<colors; c++) { - int R = clut[c].r; - int G = clut[c].g; - int B = clut[c].b; - int Y = (( + 66*R + 129*G + 25*B + 0x80) >> 8) + 16; - int CR = (( + 112*R - 94*G - 18*B + 0x80) >> 8) + 128; - int CB = (( - 38*R - 74*G + 112*B + 0x80) >> 8) + 128; - clut[c].y = saturate( Y, 16, 235); - clut[c].cb = saturate(CB, 16, 240); - clut[c].cr = saturate(CR, 16, 240); - } - } -} - -/* - * clear_osdcmd() - * - * - free allocated memory from osd_command_t - */ -static void clear_osdcmd(osd_command_t *cmd) -{ - free(cmd->data); - cmd->data = NULL; - free(cmd->palette); - cmd->palette = NULL; -} - -/* - * osdcmd_to_overlay() - * - * - fill xine-lib vo_overlay_t from osd_command_t - */ -static void osdcmd_to_overlay(vo_overlay_t *ovl, osd_command_t *cmd) -{ - int i; - - ovl->rle = (rle_elem_t*)cmd->data; - ovl->data_size = cmd->datalen; - ovl->num_rle = cmd->datalen / 4; - - ovl->x = cmd->x; - ovl->y = cmd->y; - ovl->width = cmd->w; - ovl->height = cmd->h; - - /* palette */ - for (i=0; i<cmd->colors; i++) { - ovl->color[i] = (*(uint32_t*)(cmd->palette + i)) & 0x00ffffff; - ovl->trans[i] = (cmd->palette[i].alpha + 0x7)/0xf; - } - ovl->rgb_clut = cmd->flags & OSDFLAG_YUV_CLUT ? 0 : 1; - - ovl->unscaled = cmd->flags & OSDFLAG_UNSCALED ? 1 : 0; - - ovl->hili_top = ovl->hili_bottom = ovl->hili_left = ovl->hili_right = -1; -} - -/* - * osdcmd_scale() - * - * Scale OSD_Set_RLE data - * - modified fields: x, y, w, h, (RLE) data and datalen - * - old RLE data is stored to osd_data_t *osd - */ -static void osdcmd_scale(osd_manager_impl_t *this, osd_command_t *cmd, - osd_data_t *osd, int output_width, int output_height) -{ - LOGOSD("Size out of margins, rescaling rle image"); - - /* new position and size */ - int new_x = cmd->x * this->video_width / osd->extent_width; - int new_y = cmd->y * this->video_height / osd->extent_height; - int x2 = cmd->x + cmd->w + 1; - int y2 = cmd->y + cmd->h + 1; - x2 = ((x2+1) * this->video_width - 1) / osd->extent_width; - y2 = ((y2+1) * this->video_height - 1) / osd->extent_height; - int new_w = x2 - new_x - 1; - int new_h = y2 - new_y - 1; - - /* store original RLE data */ - osd->cmd.data = cmd->data; - osd->cmd.datalen = cmd->datalen; - - /* scale */ - int rle_elems = cmd->datalen / sizeof(xine_rle_elem_t); - cmd->data = rle_scale_nearest(cmd->data, &rle_elems, cmd->w, cmd->h, - new_w, new_h); - cmd->datalen = rle_elems * sizeof(xine_rle_elem_t); - - cmd->x = new_x; - cmd->y = new_y; - cmd->w = new_w; - cmd->h = new_h; -} - -/* - * osd_exec_vpts() - * - * - calculate execution time (vpts) for OSD update - */ -static int64_t osd_exec_vpts(osd_manager_impl_t *this, osd_command_t *cmd) -{ - int64_t vpts = 0; /* now */ - - /* calculate exec time */ - if (cmd->pts || cmd->delay_ms) { - int64_t now = xine_get_current_vpts(this->stream); - - if (cmd->pts) - vpts = cmd->pts + this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET); - else - vpts = this->osd[cmd->wnd].last_changed_vpts + cmd->delay_ms*90; - - /* execution time must be in future */ - if (vpts < now) - vpts = 0; - - /* limit delay to 5 seconds */ - if (vpts > now + 5*90000) - vpts = vpts + 5*90000; - - LOGOSD("OSD Command %d scheduled to +%dms", cmd->cmd, (int)(vpts>now ? vpts-now : 0)/90); - } - - return vpts; -} - -/***************************** OSD command handlers *****************************/ - -/* - * exec_osd_size() - * - * - set the assumed full OSD size - */ -static int exec_osd_size(osd_manager_impl_t *this, osd_command_t *cmd) -{ - osd_data_t *osd = &this->osd[cmd->wnd]; - osd->extent_width = cmd->w; - osd->extent_height = cmd->h; - - acquire_ticket(this); - - xine_video_port_t *video_out = this->stream->video_out; - this->vo_scaling = 0; - if (video_out->get_capabilities(video_out) & VO_CAP_OSDSCALING) { - this->vo_scaling = 1; - } - - return CONTROL_OK; -} - -/* - * exec_osd_nop() - * - * - update last changed time of an OSD window - */ -static int exec_osd_nop(osd_manager_impl_t *this, osd_command_t *cmd) -{ - this->osd[cmd->wnd].last_changed_vpts = xine_get_current_vpts(this->stream); - return CONTROL_OK; -} - -/* - * exec_osd_flush() - * - * - commit all pending OSD events immediately - */ -static int exec_osd_flush(osd_manager_impl_t *this, osd_command_t *cmd) -{ - video_overlay_manager_t *ovl_manager = get_ovl_manager(this); - if (!ovl_manager) - return CONTROL_PARAM_ERROR; - - ovl_manager->flush_events(ovl_manager); - - return CONTROL_OK; -} - -/* - * exec_osd_close() - * - */ -static int exec_osd_close(osd_manager_impl_t *this, osd_command_t *cmd) -{ - video_overlay_manager_t *ovl_manager = get_ovl_manager(this); - osd_data_t *osd = &this->osd[cmd->wnd]; - int handle = osd->handle; - - if (cmd->flags & OSDFLAG_REFRESH) { - LOGDBG("Ignoring OSD_Close(OSDFLAG_REFRESH)"); - return CONTROL_OK; - } - - if (handle < 0) { - LOGMSG("OSD_Close(%d): non-existing OSD !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - if (!ovl_manager) - return CONTROL_PARAM_ERROR; - - video_overlay_event_t ov_event = {0}; - ov_event.event_type = OVERLAY_EVENT_FREE_HANDLE; - ov_event.vpts = osd_exec_vpts(this, cmd); - ov_event.object.handle = handle; - - while (ovl_manager->add_event(ovl_manager, (void *)&ov_event) < 0) { - LOGMSG("OSD_Close(%d): overlay manager queue full !", cmd->wnd); - ovl_manager->flush_events(ovl_manager); - } - - clear_osdcmd(&osd->cmd); - osd->handle = -1; - osd->extent_width = 720; - osd->extent_height = 576; - osd->last_changed_vpts = 0; - - return CONTROL_OK; -} - -/* - * exec_osd_set_rle() - * - */ -static int exec_osd_set_rle(osd_manager_impl_t *this, osd_command_t *cmd) -{ - video_overlay_manager_t *ovl_manager = get_ovl_manager(this); - video_overlay_event_t ov_event = {0}; - vo_overlay_t ov_overlay = {0}; - osd_data_t *osd = &this->osd[cmd->wnd]; - int use_unscaled = 0; - int rle_scaled = 0; - int unscaled_supported = 1; - int handle = osd->handle; - - if (!ovl_manager) - return CONTROL_PARAM_ERROR; - - this->stream->video_out->enable_ovl(this->stream->video_out, 1); - - /* get / allocate OSD handle */ - if (handle < 0) { - handle = ovl_manager->get_handle(ovl_manager,0); - osd->handle = handle; - osd->extent_width = osd->extent_width ?: 720; - osd->extent_height = osd->extent_height ?: 576; - osd->last_changed_vpts = 0; - } - - /* fill SHOW event */ - ov_event.event_type = OVERLAY_EVENT_SHOW; - ov_event.vpts = osd_exec_vpts(this, cmd); - ov_event.object.handle = handle; - ov_event.object.overlay = &ov_overlay; - ov_event.object.object_type = 1; /* menu */ - - /* check for unscaled OSD capability and request */ - xine_video_port_t *video_out = this->stream->video_out; - if (! (video_out->get_capabilities(video_out) & VO_CAP_UNSCALED_OVERLAY)) - unscaled_supported = 0; - else if (cmd->flags & OSDFLAG_UNSCALED) - use_unscaled = 1; - - /* store osd for later rescaling (done if video size changes) */ - - clear_osdcmd(&osd->cmd); - - memcpy(&osd->cmd, cmd, sizeof(osd_command_t)); - osd->cmd.data = NULL; - if (cmd->palette) { - /* RGB -> YUV */ - if(!(cmd->flags & OSDFLAG_YUV_CLUT)) - palette_argb_to_ayuv(cmd->palette, cmd->colors); - cmd->flags |= OSDFLAG_YUV_CLUT; - - osd->cmd.palette = malloc(sizeof(xine_clut_t)*cmd->colors); - memcpy(osd->cmd.palette, cmd->palette, 4*cmd->colors); - osd->cmd.flags |= OSDFLAG_YUV_CLUT; - } - - /* request OSD scaling from video_out layer */ - this->vo_scaling = 0; - if (video_out->get_capabilities(video_out) & VO_CAP_OSDSCALING) { - video_out->set_property(video_out, VO_PROP_OSD_SCALING, cmd->scaling ? 1 : 0); - this->vo_scaling = 1; - } - - /* if video size differs from expected (VDR osd is designed for 720x576), - scale osd to video size or use unscaled (display resolution) - blending */ - - /* scale OSD ? */ - if (!this->vo_scaling && !use_unscaled) { - int w_diff = (this->video_width < ((osd->extent_width *242) >> 8) /* 95% */) ? -1 : - (this->video_width > ((osd->extent_width *280) >> 8) /* 110% */) ? 1 : 0; - int h_diff = (this->video_height < ((osd->extent_height*242) >> 8) /* 95% */) ? -1 : - (this->video_height > ((osd->extent_height*280) >> 8) /* 110% */) ? 1 : 0; - - if (w_diff || h_diff) { - - /* unscaled OSD instead of downscaling ? */ - if (w_diff < 0 || h_diff < 0) - if (cmd->flags & OSDFLAG_UNSCALED_LOWRES) - if (0 < (use_unscaled = unscaled_supported)) - LOGOSD("Size out of margins, using unscaled overlay"); - - if (!use_unscaled && cmd->scaling > 0) { - osdcmd_scale(this, cmd, osd, this->video_width, this->video_height); - rle_scaled = 1; - } - } - } - - /* Scale unscaled OSD ? */ - if (!this->vo_scaling && use_unscaled && cmd->scaling > 0) { - int win_width = video_out->get_property(video_out, VO_PROP_WINDOW_WIDTH); - int win_height = video_out->get_property(video_out, VO_PROP_WINDOW_HEIGHT); - - if (win_width >= 360 && win_height >= 288) { - if (win_width != osd->extent_width || win_height != osd->extent_height) { - osdcmd_scale(this, cmd, osd, win_width, win_height); - rle_scaled = 1; - } - } - } - - /* fill ov_overlay */ - osdcmd_to_overlay(&ov_overlay, cmd); - ov_overlay.unscaled = use_unscaled; - - /* tag this overlay */ - ov_overlay.hili_rgb_clut = VDR_OSD_MAGIC; - - /* fill extra data */ - const vdr_osd_extradata_t extra_data = { - extent_width: osd->extent_width, - extent_height: osd->extent_height, - layer: cmd->layer, - scaling: cmd->scaling - }; - memcpy(ov_overlay.hili_color, &extra_data, sizeof(extra_data)); - -#ifdef VO_CAP_CUSTOM_EXTENT_OVERLAY - if (cmd->scaling && !rle_scaled) { - ov_overlay.extent_width = osd->extent_width; - ov_overlay.extent_height = osd->extent_height; - } -#endif - - /* if no scaling was required, we may still need to re-center OSD */ - if (!this->vo_scaling && !rle_scaled) { - if (this->video_width != osd->extent_width) - ov_overlay.x += (this->video_width - osd->extent_width)/2; - if (this->video_height != osd->extent_height) - ov_overlay.y += (this->video_height - osd->extent_height)/2; - } - - /* store rle for later scaling (done if video size changes) */ - if (!rle_scaled /* if scaled, we already have a copy (original data) */ ) { - osd->cmd.data = malloc(cmd->datalen); - memcpy(osd->cmd.data, cmd->data, cmd->datalen); - } - cmd->data = NULL; /* we 'consume' data (ownership goes for xine-lib osd manager) */ - - /* send event to overlay manager */ - while (ovl_manager->add_event(ovl_manager, (void *)&ov_event) < 0) { - LOGMSG("OSD_Set_RLE(%d): overlay manager queue full !", cmd->wnd); - ovl_manager->flush_events(ovl_manager); - } - - osd->last_changed_vpts = ov_event.vpts ?: xine_get_current_vpts(this->stream); - - return CONTROL_OK; -} - -/* - * exec_osd_set_palette() - * - * - replace palette of an already existing OSD - */ -static int exec_osd_set_palette(osd_manager_impl_t *this, osd_command_t *cmd) -{ - osd_data_t *osd = &this->osd[cmd->wnd]; - - if (!osd->cmd.data) { - LOGMSG("OSD_SetPalette(%d): old RLE data missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - if (!cmd->palette) { - LOGMSG("OSD_SetPalette(%d): new palette missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - /* use cached event to re-create Set_RLE command with modified palette */ - osd_command_t tmp; - /* steal the original command */ - memcpy(&tmp, &osd->cmd, sizeof(osd_command_t)); - memset(&osd->cmd, 0, sizeof(osd_command_t)); - - /* replace palette */ - tmp.cmd = OSD_Set_RLE; - free(tmp.palette); - tmp.palette = malloc(cmd->colors*sizeof(xine_rle_elem_t)); - memcpy(tmp.palette, cmd->palette, cmd->colors*sizeof(xine_rle_elem_t)); - tmp.colors = cmd->colors; - tmp.pts = cmd->pts; - tmp.delay_ms = cmd->delay_ms; - tmp.flags |= cmd->flags & OSDFLAG_YUV_CLUT; - - /* redraw */ - int r = exec_osd_set_rle(this, &tmp); - clear_osdcmd(&tmp); - return r; -} - -/* - * exec_osd_move() - * - * - move existing OSD to new position - */ -static int exec_osd_move(osd_manager_impl_t *this, osd_command_t *cmd) -{ - osd_data_t *osd = &this->osd[cmd->wnd]; - - if (!osd->cmd.data) { - LOGMSG("OSD_Move(%d): old RLE data missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - if (!osd->cmd.palette) { - LOGMSG("OSD_Move(%d): old palette missing !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - /* use cached event to re-create Set_RLE command with modified palette */ - osd_command_t tmp; - /* steal the original command */ - memcpy(&tmp, &osd->cmd, sizeof(osd_command_t)); - memset(&osd->cmd, 0, sizeof(osd_command_t)); - - /* replace position */ - tmp.cmd = OSD_Set_RLE; - tmp.x = cmd->x; - tmp.y = cmd->y; - tmp.pts = cmd->pts; - tmp.delay_ms = cmd->delay_ms; - - /* redraw */ - int r = exec_osd_set_rle(this, &tmp); - clear_osdcmd(&tmp); - return r; -} - -/* - * exec_osd_command_internal() - */ -static int exec_osd_command_internal(osd_manager_impl_t *this, struct osd_command_s *cmd) -{ - LOGOSD("exec_osd_command %d", cmd->cmd); - - switch (cmd->cmd) { - case OSD_Nop: return exec_osd_nop(this, cmd); - case OSD_Size: return exec_osd_size(this, cmd); - case OSD_SetPalette: return exec_osd_set_palette(this, cmd); - case OSD_Move: return exec_osd_move(this, cmd); - case OSD_Flush: return exec_osd_flush(this, cmd); - case OSD_Set_RLE: return exec_osd_set_rle(this, cmd); - case OSD_Close: return exec_osd_close(this, cmd); - case OSD_Set_YUV: - /* TODO */ - LOGMSG("OSD_Set_YUV not implemented !"); - return CONTROL_PARAM_ERROR; - } - - LOGMSG("Unknown OSD command %d", cmd->cmd); - return CONTROL_PARAM_ERROR; -} - -/****************************** Interface handlers ******************************/ - -/* - * exec_osd_command() - * - * - handler for VDR-based osd_command_t events - */ -static int exec_osd_command(osd_manager_t *this_gen, - struct osd_command_s *cmd, xine_stream_t *stream) -{ - osd_manager_impl_t *this = (osd_manager_impl_t*)this_gen; - int result; - - if (!cmd || !stream) { - LOGMSG("exec_osd_command: Stream not initialized !"); - return CONTROL_DISCONNECTED; - } - if (cmd->wnd >= MAX_OSD_OBJECT) { - LOGMSG("exec_osd_command: OSD window handle %d out of range !", cmd->wnd); - return CONTROL_PARAM_ERROR; - } - - if (pthread_mutex_lock(&this->lock)) { - LOGERR("exec_osd_command: mutex lock failed"); - return CONTROL_DISCONNECTED; - } - - this->stream = stream; - result = exec_osd_command_internal(this, cmd); - - release_ticket(this); - - pthread_mutex_unlock(&this->lock); - - return result; -} - -/* - * video_size_changed() - */ -static void video_size_changed(osd_manager_t *this_gen, xine_stream_t *stream, int width, int height) -{ - osd_manager_impl_t *this = (osd_manager_impl_t*)this_gen; - int i; - - if (!stream) { - LOGMSG("video_size_changed: Stream not initialized !"); - return; - } - - if (width < 1 || height < 1) { - LOGMSG("video_size_changed: Invalid video size %dx%d", width, height); - return; - } - - if (pthread_mutex_lock(&this->lock)) { - LOGERR("video_size_changed: mutex lock failed"); - return; - } - - if (this->video_width == width && this->video_height == height) { - pthread_mutex_unlock(&this->lock); - return; - } - - LOGOSD("New video size (%dx%d->%dx%d)", this->video_width, this->video_height, width, height); - - this->stream = stream; - this->video_width = width; - this->video_height = height; - - /* just call exec_osd_command for all stored osd's. - scaling is done automatically if required. */ - if (!this->vo_scaling) - for (i = 0; i < MAX_OSD_OBJECT; i++) - if (this->osd[i].handle >= 0 && - this->osd[i].cmd.data && - this->osd[i].cmd.scaling > 0) { - osd_command_t tmp; - memcpy(&tmp, &this->osd[i].cmd, sizeof(osd_command_t)); - memset(&this->osd[i].cmd, 0, sizeof(osd_command_t)); - - exec_osd_command_internal(this, &tmp); - - clear_osdcmd(&tmp); - } - - release_ticket(this); - pthread_mutex_unlock(&this->lock); -} - -/* - * osd_manager_dispose() - */ -static void osd_manager_dispose(osd_manager_t *this_gen, xine_stream_t *stream) -{ - osd_manager_impl_t *this = (osd_manager_impl_t*)this_gen; - int i; - - while (pthread_mutex_destroy(&this->lock) == EBUSY) { - LOGMSG("osd_manager_dispose: lock busy ..."); - pthread_mutex_lock(&this->lock); - pthread_mutex_unlock(&this->lock); - } - - /* close all */ - for (i=0; i<MAX_OSD_OBJECT; i++) { - if (this->osd[i].handle >= 0) { - osd_command_t cmd = { - .cmd = OSD_Close, - .wnd = i, - }; - LOGOSD("Closing osd %d", i); - exec_osd_close(this, &cmd); - } - } - - release_ticket(this); - - free(this); -} - -/* - * init_osd_manager() - * - * - exported - */ -osd_manager_t *init_osd_manager(void) -{ - osd_manager_impl_t *this = calloc(1, sizeof(osd_manager_impl_t)); - int i; - - this->mgr.command = exec_osd_command; - this->mgr.dispose = osd_manager_dispose; - this->mgr.video_size_changed = video_size_changed; - - pthread_mutex_init(&this->lock, NULL); - - this->video_width = 720; - this->video_height = 576; - - for (i = 0; i < MAX_OSD_OBJECT; i++) - this->osd[i].handle = -1; - - return &this->mgr; -} diff --git a/xine/osd_manager.h b/xine/osd_manager.h deleted file mode 100644 index d71336ed..00000000 --- a/xine/osd_manager.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * osd_manager.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: osd_manager.h,v 1.1 2008-12-06 16:17:18 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_OSD_MANAGER_H_ -#define XINELIBOUTPUT_OSD_MANAGER_H_ - -/* - * OSD manager executes OSD control messages from VDR. - * - cache OSD data - * - scale OSD when required - * - re-scale OSD when video size changes - * - generate xine overlay events - */ - -struct osd_command_s; - -typedef struct osd_manager_s osd_manager_t; - -struct osd_manager_s { - int (*command)(osd_manager_t *, struct osd_command_s *, xine_stream_t *); - void (*dispose)(osd_manager_t *, xine_stream_t *); - - void (*video_size_changed)(osd_manager_t *, xine_stream_t *, int width, int height); -}; - -osd_manager_t *init_osd_manager(void); - - -#endif /* XINELIBOUTPUT_OSD_MANAGER_H_ */ diff --git a/xine/post.c b/xine/post.c deleted file mode 100644 index 6c637634..00000000 --- a/xine/post.c +++ /dev/null @@ -1,901 +0,0 @@ -/* - * Copyright (C) 2003 by Dirk Meyer - * - * This file is part of xine, a unix video player. - * - * xine 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. - * - * xine 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 - * - * The code is taken from xine-ui/src/xitk/post.c at changed to work with fbxine - * - * Modified for VDR xineliboutput plugin by Petri Hintukainen, 2006 - * - runtime re-configuration (load/unload, enable/disable) - * - support for multiple streams - * - support for mosaico post plugin (picture-in-picture) - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "post.h" - -#include <sys/types.h> -#include <sys/syscall.h> -#include <unistd.h> -#include <errno.h> -#include <syslog.h> - -#define LOG_MODULENAME "[xine-post] " -#include "../logdefs.h" - -#define fe_t post_plugins_t - -typedef struct { - xine_post_t *post; - xine_post_api_t *api; - xine_post_api_descr_t *descr; - xine_post_api_parameter_t *param; - char *param_data; - - int x; - int y; - - int readonly; - - char **properties_names; -} post_object_t; - - -static int __pplugin_retrieve_parameters(post_object_t *pobj) -{ - xine_post_in_t *input_api; - - if((input_api = (xine_post_in_t *) xine_post_input(pobj->post, - "parameters"))) { - xine_post_api_t *post_api; - xine_post_api_descr_t *api_descr; - xine_post_api_parameter_t *parm; - int pnum = 0; - - post_api = (xine_post_api_t *) input_api->data; - - api_descr = post_api->get_param_descr(); - - parm = api_descr->parameter; - pobj->param_data = malloc(api_descr->struct_size); - - while(parm->type != POST_PARAM_TYPE_LAST) { - - post_api->get_parameters(pobj->post, pobj->param_data); - - if(!pnum) - pobj->properties_names = (char **) calloc(2, sizeof(char *)); - else - pobj->properties_names = (char **) - realloc(pobj->properties_names, sizeof(char *) * (pnum + 2)); - - pobj->properties_names[pnum] = strdup(parm->name); - pobj->properties_names[pnum + 1] = NULL; - pnum++; - parm++; - } - - pobj->api = post_api; - pobj->descr = api_descr; - pobj->param = api_descr->parameter; - - return 1; - } - - return 0; -} - -static void _pplugin_update_parameter(post_object_t *pobj) -{ - pobj->api->set_parameters(pobj->post, pobj->param_data); - pobj->api->get_parameters(pobj->post, pobj->param_data); -} - -static void __pplugin_update_parameters(xine_post_t *post, char *args) -{ - char *p; - post_object_t pobj = { - .post = post, - }; - - if(__pplugin_retrieve_parameters(&pobj)) { - int i; - - if(pobj.properties_names && args && *args) { - char *param; - - while((param = xine_strsep(&args, ",")) != NULL) { - - p = param; - - while((*p != '\0') && (*p != '=')) - p++; - - if(p && strlen(p)) { - int param_num = 0; - - *p++ = '\0'; - - while(pobj.properties_names[param_num] - && strcasecmp(pobj.properties_names[param_num], param)) - param_num++; - - if(pobj.properties_names[param_num]) { - - pobj.param = pobj.descr->parameter; - pobj.param += param_num; - pobj.readonly = pobj.param->readonly; - - switch(pobj.param->type) { - case POST_PARAM_TYPE_INT: - if(!pobj.readonly) { - if(pobj.param->enum_values) { - char **values = pobj.param->enum_values; - int i = 0; - - while(values[i]) { - if(!strcasecmp(values[i], p)) { - *(int *)(pobj.param_data + pobj.param->offset) = i; - break; - } - i++; - } - - if( !values[i] ) - *(int *)(pobj.param_data + pobj.param->offset) = (int) strtol(p, &p, 10); - } else { - *(int *)(pobj.param_data + pobj.param->offset) = (int) strtol(p, &p, 10); - } - _pplugin_update_parameter(&pobj); - } - break; - - case POST_PARAM_TYPE_DOUBLE: - if(!pobj.readonly) { - *(double *)(pobj.param_data + pobj.param->offset) = strtod(p, &p); - _pplugin_update_parameter(&pobj); - } - break; - - case POST_PARAM_TYPE_CHAR: - case POST_PARAM_TYPE_STRING: - if(!pobj.readonly) { - if(pobj.param->type == POST_PARAM_TYPE_CHAR) { - int maxlen = pobj.param->size / sizeof(char); - - snprintf((char *)(pobj.param_data + pobj.param->offset), maxlen, "%s", p); - _pplugin_update_parameter(&pobj); - } - else - fprintf(stderr, "parameter type POST_PARAM_TYPE_STRING not supported yet.\n"); - } - break; - - case POST_PARAM_TYPE_STRINGLIST: /* unsupported */ - if(!pobj.readonly) - fprintf(stderr, "parameter type POST_PARAM_TYPE_STRINGLIST not supported yet.\n"); - break; - - case POST_PARAM_TYPE_BOOL: - if(!pobj.readonly) { - *(int *)(pobj.param_data + pobj.param->offset) = ((int) strtol(p, &p, 10)) ? 1 : 0; - _pplugin_update_parameter(&pobj); - } - break; - } - } else { - LOGMSG("Unknown post plugin parameter %s !", param); - } - } - } - - i = 0; - - while(pobj.properties_names[i]) { - free(pobj.properties_names[i]); - i++; - } - - free(pobj.properties_names); - } - - free(pobj.param_data); - } -} - -/* -post <name>:option1=value1,option2=value2... */ -static post_element_t **pplugin_parse_and_load(fe_t *fe, - int plugin_type, - const char *pchain, - int *post_elements_num) -{ - post_element_t **post_elements = NULL; - - *post_elements_num = 0; - - if(pchain && strlen(pchain)) { - char *post_chain, *freeme, *p; - - freeme = post_chain = strdup(pchain); - - while((p = xine_strsep(&post_chain, ";"))) { - - if(p && strlen(p)) { - char *plugin, *args = NULL; - xine_post_t *post; - - while(*p == ' ') - p++; - - plugin = strdup(p); - - if((p = strchr(plugin, ':'))) - *p++ = '\0'; - - if(p && (strlen(p) > 1)) - args = p; -#if 0 - post = xine_post_init(fe->xine, plugin, 0, - &fe->audio_port, &fe->video_port); -#else - if(plugin_type == XINE_POST_TYPE_VIDEO_COMPOSE) { - post = xine_post_init(fe->xine, plugin, 2, - &fe->audio_port, &fe->video_port); - } else - post = xine_post_init(fe->xine, plugin, 0, - &fe->audio_port, &fe->video_port); -#endif - - if (post && plugin_type) { - if (post->type != plugin_type) { - xine_post_dispose(fe->xine, post); - post = NULL; - } - } - - if(post) { - - if(!(*post_elements_num)) - post_elements = (post_element_t **) calloc(2, sizeof(post_element_t *)); - else - post_elements = (post_element_t **) - realloc(post_elements, sizeof(post_element_t *) * ((*post_elements_num) + 2)); - - post_elements[(*post_elements_num)] = calloc(1, sizeof(post_element_t)); - post_elements[(*post_elements_num)]->post = post; - post_elements[(*post_elements_num)]->name = strdup(plugin); -#if 1 - post_elements[(*post_elements_num)]->args = args ? strdup(args) : NULL; - post_elements[(*post_elements_num)]->enable = 0; -#endif - (*post_elements_num)++; - post_elements[(*post_elements_num)] = NULL; - - __pplugin_update_parameters(post, args); - } - - free(plugin); - } - } - free(freeme); - } - - return post_elements; -} - -void pplugin_parse_and_store_post(fe_t *fe, int plugin_type, - const char *post_chain) -{ - post_element_t ***_post_elements; - int *_post_elements_num; - post_element_t **posts = NULL; - int num; - - switch(plugin_type) { - case XINE_POST_TYPE_VIDEO_FILTER: - _post_elements = &fe->post_video_elements; - _post_elements_num = &fe->post_video_elements_num; - break; - case XINE_POST_TYPE_VIDEO_COMPOSE: - _post_elements = &fe->post_pip_elements; - _post_elements_num = &fe->post_pip_elements_num; - break; - case XINE_POST_TYPE_AUDIO_VISUALIZATION: - _post_elements = &fe->post_vis_elements; - _post_elements_num = &fe->post_vis_elements_num; - break; - default: - _post_elements = &fe->post_audio_elements; - _post_elements_num = &fe->post_audio_elements_num; - break; - } - - if((posts = pplugin_parse_and_load(fe, plugin_type, post_chain, &num))) { - if(*_post_elements_num) { - int i; - int ptot = *_post_elements_num + num; - - *_post_elements = (post_element_t **) realloc(*_post_elements, - sizeof(post_element_t *) * (ptot + 1)); - for(i = *_post_elements_num; i < ptot; i++) - (*_post_elements)[i] = posts[i - *_post_elements_num]; - - (*_post_elements)[i] = NULL; - (*_post_elements_num) += num; - } - else { - *_post_elements = posts; - *_post_elements_num = num; - } -#if 1 - if(SysLogLevel > 2) { - /* dump list of all loaded plugins */ - int ptot = *_post_elements_num; - int i; - char s[4096]=""; - for(i=0; i<ptot; i++) - if((*_post_elements)[i]) - if(((*_post_elements)[i])->post) { - if(((*_post_elements)[i])->enable) - strcat(s, "*"); - if(((*_post_elements)[i])->name) - strcat(s, ((*_post_elements)[i])->name); - else - strcat(s, "<no name!>"); - strcat(s, " "); - } - LOGDBG(" loaded plugins (type %d.%d): %s", - (plugin_type>>16), (plugin_type&0xffff), s); - } -#endif - } -} - - -void vpplugin_parse_and_store_post(fe_t *fe, const char *post_chain) -{ - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_VIDEO_FILTER, post_chain); - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_VIDEO_COMPOSE, post_chain); -} - - -void applugin_parse_and_store_post(fe_t *fe, const char *post_chain) -{ - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_AUDIO_FILTER, post_chain); - pplugin_parse_and_store_post(fe, XINE_POST_TYPE_AUDIO_VISUALIZATION, post_chain); -} - - -static void _vpplugin_unwire(fe_t *fe) -{ - xine_post_out_t *vo_source; - vo_source = xine_get_video_source(fe->video_source); - (void) xine_post_wire_video_port(vo_source, fe->video_port); -} - - -static void _applugin_unwire(fe_t *fe) -{ - xine_post_out_t *ao_source; - ao_source = xine_get_audio_source(fe->audio_source); - (void) xine_post_wire_audio_port(ao_source, fe->audio_port); -} - - -static void _vpplugin_rewire_from_post_elements(fe_t *fe, post_element_t **post_elements, int post_elements_num) -{ - if(post_elements_num) { - xine_post_out_t *vo_source; - int i = 0; - - for(i = (post_elements_num - 1); i >= 0; i--) { - const char *const *outs = xine_post_list_outputs(post_elements[i]->post); - const xine_post_out_t *vo_out = xine_post_output(post_elements[i]->post, (char *) *outs); - if(i == (post_elements_num - 1)) { - LOGDBG(" wiring %10s[out] -> [in]video_out", post_elements[i]->name); - xine_post_wire_video_port((xine_post_out_t *) vo_out, fe->video_port); - } - else { - const xine_post_in_t *vo_in; - int err; - - /* look for standard input names */ - vo_in = xine_post_input(post_elements[i + 1]->post, "video"); - if( !vo_in ) - vo_in = xine_post_input(post_elements[i + 1]->post, "video in"); - - LOGDBG(" wiring %10s[out] -> [in]%-10s ", - post_elements[i]->name, post_elements[i+1]->name); - err = xine_post_wire((xine_post_out_t *) vo_out, - (xine_post_in_t *) vo_in); - } - } - - if(fe->post_pip_enable && - !strcmp(post_elements[0]->name, "mosaico") && - fe->pip_stream) { - vo_source = xine_get_video_source(fe->pip_stream); - LOGDBG(" wiring %10s[out] -> [in1]%-10s ", "pip stream", post_elements[0]->name); - xine_post_wire_video_port(vo_source, - post_elements[0]->post->video_input[1]); - } - - vo_source = xine_get_video_source(fe->video_source); - LOGDBG(" wiring %10s[out] -> [in]%-10s", "stream", post_elements[0]->name); - xine_post_wire_video_port(vo_source, - post_elements[0]->post->video_input[0]); - } -} - - -static void _applugin_rewire_from_post_elements(fe_t *fe, post_element_t **post_elements, int post_elements_num) -{ - if(post_elements_num) { - xine_post_out_t *ao_source; - int i = 0; - - for(i = (post_elements_num - 1); i >= 0; i--) { - const char *const *outs = xine_post_list_outputs(post_elements[i]->post); - const xine_post_out_t *ao_out = xine_post_output(post_elements[i]->post, (char *) *outs); - - if(i == (post_elements_num - 1)) { - LOGDBG(" wiring %10s[out] -> [in]audio_out", post_elements[i]->name); - xine_post_wire_audio_port((xine_post_out_t *) ao_out, fe->audio_port); - } - else { - const xine_post_in_t *ao_in; - int err; - - /* look for standard input names */ - ao_in = xine_post_input(post_elements[i + 1]->post, "audio"); - if( !ao_in ) - ao_in = xine_post_input(post_elements[i + 1]->post, "audio in"); - - LOGDBG(" wiring %10s[out] -> [in]%-10s ", - post_elements[i]->name, post_elements[i+1]->name); - err = xine_post_wire((xine_post_out_t *) ao_out, (xine_post_in_t *) ao_in); - } - } - - ao_source = xine_get_audio_source(fe->audio_source); - LOGDBG(" wiring %10s[out] -> [in]%-10s", "stream", post_elements[0]->name); - xine_post_wire_audio_port(ao_source, post_elements[0]->post->audio_input[0]); - } -} - -static post_element_t **_pplugin_join_deinterlace_and_post_elements(fe_t *fe, int *post_elements_num) -{ - post_element_t **post_elements; - int i = 0, j = 0, n = 0, p = 0; - static const char *order[] = {"autocrop", "thread", "tvtime", "swscale", NULL}; - - *post_elements_num = 0; - if( fe->post_video_enable ) - *post_elements_num += fe->post_video_elements_num; - - if( fe->post_pip_enable ) - *post_elements_num += fe->post_pip_elements_num; - - if( *post_elements_num == 0 ) - return NULL; - - post_elements = calloc( (*post_elements_num), sizeof(post_element_t *)); - - if(fe->post_pip_enable) - for( i = 0; i < fe->post_pip_elements_num; i++ ) { - if(fe->post_pip_elements[i]->enable) - post_elements[i+j-n] = fe->post_pip_elements[i]; - else - n++; - } - - if(fe->post_video_enable) - for( j = 0; j < fe->post_video_elements_num; j++ ) { - if(fe->post_video_elements[j]->enable) { - post_elements[i+j-n] = fe->post_video_elements[j]; - } else - n++; - } - - *post_elements_num -= n; - if( *post_elements_num == 0 ) { - free(post_elements); - return NULL; - } - - /* in some special cases order is important. By default plugin order - * in post plugin chain is post plugin loading order. - * But, we want: - * - * 1. autocrop - less data to process for other plugins - * - accepts only YV12 - * 2. deinterlace - blur etc. makes deinterlacing difficult. - * - upscales chroma (YV12->YUY2) in some modes. - * 3. anything else - * - * So let's move those two to beginning ... - */ - n = 0; - while(order[p]) { - for(i = 0; i<*post_elements_num; i++) - if(!strcmp(post_elements[i]->name, order[p])) { - if(i != n) { - post_element_t *tmp = post_elements[i]; - for(j=i; j>n; j--) - post_elements[j] = post_elements[j-1]; - post_elements[n] = tmp; - LOGDBG(" moved %s to post slot %d", order[p], n); - } - n++; - break; - } - p++; - } - - return post_elements; -} - -static post_element_t **_pplugin_join_visualization_and_post_elements(fe_t *fe, int *post_elements_num) -{ - post_element_t **post_elements; - int i = 0, j = 0, n = 0; - - *post_elements_num = 0; - if( fe->post_audio_enable ) - *post_elements_num += fe->post_audio_elements_num; - - if( fe->post_vis_enable ) - *post_elements_num += fe->post_vis_elements_num; - - if( *post_elements_num == 0 ) - return NULL; - - post_elements = calloc( (*post_elements_num), sizeof(post_element_t *)); - - if(fe->post_audio_enable) - for( j = 0; j < fe->post_audio_elements_num; j++ ) { - if(fe->post_audio_elements[j]->enable) - post_elements[i+j-n] = fe->post_audio_elements[j]; - else - n++; - } - - if(fe->post_vis_enable) - for( i = 0; i < fe->post_vis_elements_num; i++ ) { - if(fe->post_vis_elements[i]->enable) - post_elements[i+j-n] = fe->post_vis_elements[i]; - else - n++; - } - - *post_elements_num -= n; - if( *post_elements_num == 0 ) { - free(post_elements); - return NULL; - } - - return post_elements; -} - -static void _vpplugin_rewire(fe_t *fe) -{ - static post_element_t **post_elements; - int post_elements_num; - - post_elements = _pplugin_join_deinterlace_and_post_elements(fe, &post_elements_num); - - if( post_elements ) { - _vpplugin_rewire_from_post_elements(fe, post_elements, post_elements_num); - - free(post_elements); - } -} - -static void _applugin_rewire(fe_t *fe) -{ - static post_element_t **post_elements; - int post_elements_num; - - post_elements = _pplugin_join_visualization_and_post_elements(fe, &post_elements_num); - - if( post_elements ) { - _applugin_rewire_from_post_elements(fe, post_elements, post_elements_num); - - free(post_elements); - } -} - -void vpplugin_rewire_posts(fe_t *fe) -{ - /*TRACELINE;*/ - _vpplugin_unwire(fe); - _vpplugin_rewire(fe); -} - -void applugin_rewire_posts(fe_t *fe) -{ - /*TRACELINE;*/ - _applugin_unwire(fe); - _applugin_rewire(fe); -} - -static int _pplugin_enable_post(post_plugins_t *fe, const char *name, - const char *args, - post_element_t **post_elements, - int post_elements_num, - int *found) -{ - int i, result = 0; - - for(i=0; i<post_elements_num; i++) - if(post_elements[i]) - if(!strcmp(post_elements[i]->name, name)) { - if(post_elements[i]->enable == 0) { - post_elements[i]->enable = 1; - result = 1; - } - - *found = 1; - - if(args && *args) { - if(post_elements[i]->enable != 2) { - char *tmp = strdup(args); - __pplugin_update_parameters(post_elements[i]->post, tmp); - free(tmp); - if(post_elements[i]->args) - free(post_elements[i]->args); - post_elements[i]->args = strdup(args); - } else { - LOGDBG(" * enable post %s, parameters fixed in command line.", name); - LOGDBG(" requested: %s", args ? : "none"); - LOGDBG(" using : %s", post_elements[i]->args ? : "none"); - } - } - } - - return result; -} - -static int _vpplugin_enable_post(post_plugins_t *fe, const char *name, - const char *args, int *found) -{ - int result = 0; - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_video_elements, - fe->post_video_elements_num, found); - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_pip_elements, - fe->post_pip_elements_num, found); - return result; -} - -static int _applugin_enable_post(post_plugins_t *fe, const char *name, - const char *args, int *found) -{ - int result = 0; - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_audio_elements, - fe->post_audio_elements_num, found); - if(!*found) - result = _pplugin_enable_post(fe, name, args, fe->post_vis_elements, - fe->post_vis_elements_num, found); - return result; -} - -static char * _pp_name_strdup(const char *initstr) -{ - char *name = strdup(initstr), *pt; - - if(NULL != (pt = strchr(name, ':'))) - *pt = 0; - - return name; -} - -static const char * _pp_args(const char *initstr) -{ - char *pt = strchr(initstr, ':'); - if(pt && *(pt+1)) - return pt+1; - return NULL; -} - -int vpplugin_enable_post(post_plugins_t *fe, const char *initstr, - int *found) -{ - char *name = _pp_name_strdup(initstr); - const char *args = _pp_args(initstr); - - int result = _vpplugin_enable_post(fe, name, args, found); - - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - - if(!*found) { - LOGDBG(" * loading post %s", initstr); - vpplugin_parse_and_store_post(fe, initstr); - result = _vpplugin_enable_post(fe, name, NULL, found); - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - } - - if(result) - _vpplugin_unwire(fe); - - free(name); - return result; -} - -int applugin_enable_post(post_plugins_t *fe, const char *initstr, - int *found) -{ - const char * args = _pp_args(initstr); - char *name = _pp_name_strdup(initstr); - - int result = _applugin_enable_post(fe, name, args, found); - - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - - if(!*found) { - LOGDBG(" * loading post %s", initstr); - applugin_parse_and_store_post(fe, initstr); - result = _applugin_enable_post(fe, name, NULL, found); - LOGDBG(" * enable post %s --> %s, %s", name, - *found ? "found" : "not found", - result ? "enabled" : "no action"); - } - - if(result) - _applugin_unwire(fe); - - free(name); - return result; -} - -static int _pplugin_disable_post(post_plugins_t *fe, const char *name, - post_element_t **post_elements, - int post_elements_num) -{ - int i, result = 0; - /*TRACELINE;*/ - if(post_elements) - for(i = 0; i < post_elements_num; i++) - if(post_elements[i]) - if(!name || !strcmp(post_elements[i]->name, name)) - if(post_elements[i]->enable == 1) { - post_elements[i]->enable = 0; - result = 1; - } - return result; -} - -int vpplugin_disable_post(post_plugins_t *fe, const char *name) -{ - /*TRACELINE;*/ - if(_pplugin_disable_post(fe, name, fe->post_video_elements, - fe->post_video_elements_num) || - _pplugin_disable_post(fe, name, fe->post_pip_elements, - fe->post_pip_elements_num)) { - _vpplugin_unwire(fe); - return 1; - } - return 0; -} - -int applugin_disable_post(post_plugins_t *fe, const char *name) -{ - /*TRACELINE;*/ - if(_pplugin_disable_post(fe, name, fe->post_audio_elements, - fe->post_audio_elements_num) || - _pplugin_disable_post(fe, name, fe->post_vis_elements, - fe->post_vis_elements_num)) { - _applugin_unwire(fe); - return 1; - } - return 0; -} - -static int _pplugin_unload_post(post_plugins_t *fe, const char *name, - post_element_t ***post_elements, - int *post_elements_num) -{ - /* does not unwrire plugins ! */ - int i, j, result = 0; - /*TRACELINE;*/ - - if(!*post_elements || !*post_elements_num) - return 0; - - for(i=0; i < *post_elements_num; i++) { - if((*post_elements)[i]) { - if(!name || !strcmp((*post_elements)[i]->name, name)) { - - if((*post_elements)[i]->enable == 0 || !name) { - xine_post_dispose(fe->xine, (*post_elements)[i]->post); - - free((*post_elements)[i]->name); - - if((*post_elements)[i]->args) - free((*post_elements)[i]->args); - - free((*post_elements)[i]); - - for(j=i; j < *post_elements_num - 1; j++) - (*post_elements)[j] = (*post_elements)[j+1]; - - (*post_elements_num) --; - (*post_elements)[(*post_elements_num)] = 0; - - result = 1; - i--; - - } else { - LOGDBG("Unload %s failed: plugin enabled and in use", - (*post_elements)[i]->name); - } - } - } - } - - if(*post_elements_num <= 0) { - if(*post_elements) - free(*post_elements); - *post_elements = NULL; - } - - return result; -} - -int vpplugin_unload_post(post_plugins_t *fe, const char *name) -{ - int result = vpplugin_disable_post(fe, name); - - /* unload already disabled plugins too (result=0) */ - _pplugin_unload_post(fe, name, &fe->post_video_elements, - &fe->post_video_elements_num); - _pplugin_unload_post(fe, name, &fe->post_pip_elements, - &fe->post_pip_elements_num); - - /* result indicates only unwiring condition, not unload result */ - return result; -} - -int applugin_unload_post(post_plugins_t *fe, const char *name) -{ - int result = applugin_disable_post(fe, name); - - /* unload already disabled plugins too (result=0) */ - _pplugin_unload_post(fe, name, &fe->post_audio_elements, - &fe->post_audio_elements_num); - _pplugin_unload_post(fe, name, &fe->post_vis_elements, - &fe->post_vis_elements_num); - - /* result indicates only unwiring condition, not unload result */ - return result; -} - - -/* end of post.c */ - diff --git a/xine/post.h b/xine/post.h deleted file mode 100644 index 355e8e2c..00000000 --- a/xine/post.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2003 by Dirk Meyer - * - * This file is part of xine, a unix video player. - * - * xine 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. - * - * xine 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 - * - * Modified for xineliboutput by Petri Hintukainen, 2006 - * - */ - -#ifndef POST_HH -#define POST_HH - -#include <xine.h> -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/plugin_catalog.h> - -typedef struct { - xine_post_t *post; - char *name; - char *args; - int enable; /* 0 - disabled, 1 - enabled, 2 - can't disable */ -} post_element_t; - - -typedef struct post_plugins_s post_plugins_t; - -struct post_plugins_s { - - /* frontend data */ - char *static_post_plugins; /* post plugins from command line; always on */ - xine_stream_t *video_source; /* stream to take video from */ - xine_stream_t *audio_source; /* stream to take audio from */ - xine_stream_t *pip_stream; /* pip stream */ - - /* xine */ - xine_t *xine; - xine_video_port_t *video_port; - xine_audio_port_t *audio_port; - - /* post.c internal use */ - int post_audio_elements_num; - int post_video_elements_num; - int post_vis_elements_num; - int post_pip_elements_num; - - post_element_t **post_audio_elements; - post_element_t **post_video_elements; - post_element_t **post_vis_elements; /* supports only one */ - post_element_t **post_pip_elements; /* supports only one and two input */ - - int post_audio_enable; - int post_video_enable; - int post_vis_enable; - int post_pip_enable; -}; - - -void vpplugin_rewire_posts(post_plugins_t *fe); -void applugin_rewire_posts(post_plugins_t *fe); - -/* load and config post plugin(s) */ -/* post == "plugin:arg1=val1,arg2=val2;plugin2..." */ -void vpplugin_parse_and_store_post(post_plugins_t *fe, const char *post); -void applugin_parse_and_store_post(post_plugins_t *fe, const char *post); - -/* enable (and load if not loaded), but don't rewire */ -/* result indicates only unwiring condition, not enable result */ -/* -> if result <> 0, something was enabled and post chain is unwired */ -int vpplugin_enable_post(post_plugins_t *fe, const char *name, int *found); -int applugin_enable_post(post_plugins_t *fe, const char *name, int *found); - -/* disable (and unwire if found), but don't unload */ -/* result indicates only unwiring condition, not disable result */ -int vpplugin_disable_post(post_plugins_t *fe, const char *name); -int applugin_disable_post(post_plugins_t *fe, const char *name); - -/* unload (and unwire) plugin(s) */ -/* result indicates only unwiring condition, not unload result */ -int vpplugin_unload_post(post_plugins_t *fe, const char *name); -int applugin_unload_post(post_plugins_t *fe, const char *name); - -#endif - -/* end of post.h */ diff --git a/xine/post_util.h b/xine/post_util.h deleted file mode 100644 index a539d31d..00000000 --- a/xine/post_util.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * post_util.h: post plugin utility functions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: post_util.h,v 1.5 2008-12-14 00:52:35 phintuka Exp $ - * - */ - -#if POST_PLUGIN_IFACE_VERSION < 9 -# warning POST_PLUGIN_IFACE_VERSION < 9 not supported ! -#endif -#if POST_PLUGIN_IFACE_VERSION > 10 -# warning POST_PLUGIN_IFACE_VERSION > 10 not supported ! -#endif - -/* - * class util prototypes - */ - -static void *init_plugin(xine_t *xine, void *data); -#if POST_PLUGIN_IFACE_VERSION < 10 -static char *get_identifier(post_class_t *class_gen); -static char *get_description(post_class_t *class_gen); -static void class_dispose(post_class_t *class_gen); -#endif - -/* required from plugin: */ -static post_plugin_t *open_plugin(post_class_t *class_gen, int inputs, - xine_audio_port_t **audio_target, - xine_video_port_t **video_target); - -/* - * plugin util prototypes - */ - -static int dispatch_draw(vo_frame_t *frame, xine_stream_t *stream); -static int intercept_frame_yuy(post_video_port_t *port, vo_frame_t *frame); -static int post_draw(vo_frame_t *frame, xine_stream_t *stream); -#ifdef ENABLE_SLICED -static void dispatch_slice(vo_frame_t *vo_img, uint8_t **src); -#endif - -/* required from plugin: */ -static vo_frame_t *got_frame(vo_frame_t *frame); -static void draw_internal(vo_frame_t *frame, vo_frame_t *new_frame); - - -/* - * class utils - */ - -static void *init_plugin(xine_t *xine, void *data) -{ - post_class_t *class = calloc(1, sizeof(post_class_t)); - - if (!class) - return NULL; - - class->open_plugin = open_plugin; -#if POST_PLUGIN_IFACE_VERSION < 10 - class->get_identifier = get_identifier; - class->get_description = get_description; - class->dispose = class_dispose; -#else - class->identifier = PLUGIN_ID; - class->description = PLUGIN_DESCR; - class->dispose = default_post_class_dispose; -#endif - - return class; -} - -#if POST_PLUGIN_IFACE_VERSION < 10 -static char *get_identifier(post_class_t *class_gen) -{ - return PLUGIN_ID; -} - -static char *get_description(post_class_t *class_gen) -{ - return PLUGIN_DESCR; -} - -static void class_dispose(post_class_t *class_gen) -{ - free(class_gen); -} -#endif - -/* - * plugin utils - */ - -#ifdef ENABLE_SLICED -static void dispatch_slice(vo_frame_t *vo_img, uint8_t **src) -{ - if (vo_img->next->proc_slice) { - _x_post_frame_copy_down(vo_img, vo_img->next); - vo_img->next->proc_slice(vo_img->next, src); - _x_post_frame_copy_up(vo_img, vo_img->next); - } -} -#endif - -static int dispatch_draw(vo_frame_t *frame, xine_stream_t *stream) -{ - int skip; - _x_post_frame_copy_down(frame, frame->next); - skip = frame->next->draw(frame->next, stream); - _x_post_frame_copy_up(frame, frame->next); - return skip; -} - -static int intercept_frame_yuy(post_video_port_t *port, vo_frame_t *frame) -{ - return (frame->format == XINE_IMGFMT_YV12 || frame->format == XINE_IMGFMT_YUY2); -} - -static int post_draw(vo_frame_t *frame, xine_stream_t *stream) -{ - vo_frame_t *new_frame; - int skip; - - if (frame->bad_frame) - return dispatch_draw(frame, stream); - - new_frame = got_frame(frame); - - if (!new_frame) - return dispatch_draw(frame, stream); - - _x_post_frame_copy_down(frame, new_frame); - - draw_internal(frame, new_frame); - - skip = new_frame->draw(new_frame, stream); - _x_post_frame_copy_up(frame, new_frame); - new_frame->free(new_frame); - - return skip; -} - diff --git a/xine/ts2es.c b/xine/ts2es.c deleted file mode 100644 index bf0ec7fb..00000000 --- a/xine/ts2es.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * ts2es.c: demux MPEG-TS -> ES - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts2es.c,v 1.1 2009-02-23 22:16:08 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/buffer.h> - -#include "../tools/ts.h" -#include "../tools/pes.h" - -#include "ts2es.h" - -#define LOG_MODULENAME "[demux_vdr] " -#define SysLogLevel iSysLogLevel -#include "../logdefs.h" - - -struct ts2es_s { - fifo_buffer_t *fifo; - uint32_t stream_type; - uint32_t xine_buf_type; - - buf_element_t *buf; - int pes_start; - int64_t pts; -}; - - -static void ts2es_parse_pes(ts2es_t *this) -{ - if (!DATA_IS_PES(this->buf->content)) { - LOGMSG("ts2es: payload not PES ?"); - return; - } - - /* parse PES header */ - uint hdr_len = PES_HEADER_LEN(this->buf->content); - uint8_t pes_pid = this->buf->content[3]; - uint pes_len = (this->buf->content[4] << 8) | this->buf->content[5]; - - /* parse PTS */ - this->buf->pts = pes_get_pts(this->buf->content, this->buf->size); - if(this->buf->pts >= 0) - this->pts = this->buf->pts; - else - this->pts = 0; - - /* strip PES header */ - this->buf->content += hdr_len; - this->buf->size -= hdr_len; - - /* parse substream header */ - - if (pes_pid != PRIVATE_STREAM1) - return; - - /* RAW AC3 audio ? -> do nothing */ - if (this->stream_type == STREAM_AUDIO_AC3) { - this->xine_buf_type |= BUF_AUDIO_A52; - this->buf->type = this->xine_buf_type; - return; - } - - /* AC3 syncword in beginning of PS1 payload ? */ - if (this->buf->content[0] == 0x0B && - this->buf->content[1] == 0x77) { - /* --> RAW AC3 audio - do nothing */ - this->xine_buf_type |= BUF_AUDIO_A52; - this->buf->type = this->xine_buf_type; - return; - } - - /* audio in PS1 */ - if (this->stream_type == ISO_13818_PES_PRIVATE) { - - if ((this->buf->content[0] & 0xf0) == 0x80) { - /* AC3, strip substream header */ - this->buf->content += 4; - this->buf->size -= 4; - this->xine_buf_type |= BUF_AUDIO_A52; - this->buf->type = this->xine_buf_type; - return; - } - - if ((this->buf->content[0] & 0xf0) == 0xa0) { - /* PCM, strip substream header */ - int pcm_offset; - for (pcm_offset=0; ++pcm_offset < this->buf->size-1 ; ) { - if (this->buf->content[pcm_offset] == 0x01 && - this->buf->content[pcm_offset+1] == 0x80 ) { /* START */ - pcm_offset += 2; - break; - } - } - this->buf->content += pcm_offset; - this->buf->size -= pcm_offset; - - this->xine_buf_type |= BUF_AUDIO_LPCM_BE; - this->buf->type = this->xine_buf_type; - return; - } - - LOGMSG("ts2es: unhandled PS1 substream 0x%x", this->buf->content[0]); - return; - } - - /* DVB SPU */ - if (this->stream_type == STREAM_DVBSUB) { - if (this->buf->content[0] != 0x20 || - this->buf->content[1] != 0x00) - LOGMSG("ts2es: DVB SPU, invalid PES substream header"); - this->buf->decoder_info[2] = pes_len - hdr_len - 3 + 9; - return; - } -} - -buf_element_t *ts2es_put(ts2es_t *this, uint8_t *data) -{ - int bytes = ts_PAYLOAD_SIZE(data); - int pusi = ts_PAYLOAD_START(data); - buf_element_t *result = NULL; - - if (ts_HAS_ERROR(data)) { - LOGDBG("ts2es: transport error"); - return NULL; - } - if (!ts_HAS_PAYLOAD(data)) { - LOGDBG("ts2es: no payload, size %d", bytes); - return NULL; - } - - /* handle new payload unit */ - if (pusi) { - this->pes_start = 1; - if (this->buf) { - - this->buf->decoder_flags |= BUF_FLAG_FRAME_END; - this->buf->pts = this->pts; - - result = this->buf; - this->buf = NULL; - } - } - - /* need new buffer ? */ - if (!this->buf) { - this->buf = this->fifo->buffer_pool_alloc(this->fifo); - this->buf->type = this->xine_buf_type; - this->buf->decoder_info[0] = 1; - } - - /* strip ts header */ - data += TS_SIZE - bytes; - - /* copy payload */ - memcpy(this->buf->content + this->buf->size, data, bytes); - this->buf->size += bytes; - - /* parse PES header */ - if (this->pes_start) { - this->pes_start = 0; - - ts2es_parse_pes(this); - } - - /* split large packets */ - if (this->buf->size > 2048) { - this->buf->pts = this->pts; - - result = this->buf; - this->buf = NULL; - } - - return result; -} - -void ts2es_flush(ts2es_t *this) -{ - if (this->buf) { - - this->buf->decoder_flags |= BUF_FLAG_FRAME_END; - this->buf->pts = this->pts; - - this->fifo->put (this->fifo, this->buf); - this->buf = NULL; - } -} - -void ts2es_dispose(ts2es_t *data) -{ - if (data) { - if (data->buf) - data->buf->free_buffer(data->buf); - free(data); - } -} - -ts2es_t *ts2es_init(fifo_buffer_t *dst_fifo, ts_stream_type stream_type, uint stream_index) -{ - ts2es_t *data = calloc(1, sizeof(ts2es_t)); - data->fifo = dst_fifo; - - data->stream_type = stream_type; - - switch(stream_type) { - /* VIDEO (PES streams 0xe0...0xef) */ - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - case STREAM_VIDEO_MPEG: - data->xine_buf_type = BUF_VIDEO_MPEG; - break; - case ISO_14496_PART2_VIDEO: - data->xine_buf_type = BUF_VIDEO_MPEG4; - break; - case ISO_14496_PART10_VIDEO: - data->xine_buf_type = BUF_VIDEO_H264; - break; - - /* AUDIO (PES streams 0xc0...0xdf) */ - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - data->xine_buf_type = BUF_AUDIO_MPEG; - break; - case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: - data->xine_buf_type = BUF_AUDIO_AAC; - break; - - /* AUDIO (PES stream 0xbd) */ - case ISO_13818_PES_PRIVATE: - data->xine_buf_type = 0; - /* detect from PES substream header */ - break; - - /* DVB SPU (PES stream 0xbd) */ - case STREAM_DVBSUB: - data->xine_buf_type = BUF_SPU_DVB; - break; - - /* RAW AC3 */ - case STREAM_AUDIO_AC3: - data->xine_buf_type = BUF_AUDIO_A52; - break; - - default: - LOGMSG("ts2es: unknown stream type 0x%x", stream_type); - break; - } - - /* substream ID (audio/SPU) */ - data->xine_buf_type |= stream_index; - - return data; -} - diff --git a/xine/ts2es.h b/xine/ts2es.h deleted file mode 100644 index 8a5ab724..00000000 --- a/xine/ts2es.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ts2es.h: demux MPEG-TS -> ES - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts2es.h,v 1.1 2009-02-23 22:16:08 phintuka Exp $ - * - */ - -#ifndef _DEMUX_XVDR_TS2ES_H_ -#define _DEMUX_XVDR_TS2ES_H_ - -typedef struct ts2es_s ts2es_t; - -ts2es_t *ts2es_init (fifo_buffer_t *dst_fifo, ts_stream_type stream_type, uint stream_index); -buf_element_t *ts2es_put (ts2es_t *ts2es, uint8_t *ts_packet); -void ts2es_flush (ts2es_t *ts2es); -void ts2es_dispose (ts2es_t *ts2es); - -#endif /* _DEMUX_XVDR_TS2ES_H_ */ diff --git a/xine/vo_hook.c b/xine/vo_hook.c deleted file mode 100644 index 89190b9c..00000000 --- a/xine/vo_hook.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * vo_hook.c: Intercept video driver - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_hook.c,v 1.5 2009-05-09 16:05:06 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/video_out.h> - -#define LOG_MODULENAME "[xine-vo ] " -#include "../logdefs.h" - -#include "vo_hook.h" -#include "vo_post.h" - -/* This module supports only video driver interface version 21 */ -#if (VIDEO_OUT_DRIVER_IFACE_VERSION < 21) -# error xine-lib VIDEO_OUT_DRIVER_IFACE_VERSION < 21 -#endif - - -/* - * default handlers - * - * - Forward function call to original driver - */ - -#define DEF_HANDLER3(RET, NAME, ARG1, ARG2, ARG3) \ -RET vo_def_##NAME (vo_driver_t *self, ARG1 a1, ARG2 a2, ARG3 a3) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver, a1, a2, a3); \ -} - -#define DEF_HANDLER2(RET, NAME, ARG1, ARG2) \ -RET vo_def_##NAME (vo_driver_t *self, ARG1 a1, ARG2 a2) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver, a1, a2); \ -} - -#define DEF_HANDLER1(RET, NAME, ARG1) \ -RET vo_def_##NAME (vo_driver_t *self, ARG1 a1) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver, a1); \ -} - -#define DEF_HANDLER0(RET, NAME) \ -RET vo_def_##NAME (vo_driver_t *self) { \ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; \ - return this->orig_driver-> NAME (this->orig_driver); \ -} - -/* - * - */ - -DEF_HANDLER0(uint32_t, get_capabilities); -DEF_HANDLER0(vo_frame_t*, alloc_frame); - -void vo_def_update_frame_format (vo_driver_t *self, vo_frame_t *img, - uint32_t width, uint32_t height, - double ratio, int format, int flags) -{ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; - return this->orig_driver-> update_frame_format (this->orig_driver, img, width, height, ratio, format, flags); -} - -DEF_HANDLER1(void, display_frame, vo_frame_t * ); -DEF_HANDLER2(void, overlay_begin, vo_frame_t *, int ); -DEF_HANDLER2(void, overlay_blend, vo_frame_t *, vo_overlay_t * ); -DEF_HANDLER1(void, overlay_end, vo_frame_t *); -DEF_HANDLER1(int, get_property, int); -DEF_HANDLER2(int, set_property, int, int); -DEF_HANDLER3(void, get_property_min_max, int, int*, int*); -DEF_HANDLER2(int, gui_data_exchange, int, void * ); -DEF_HANDLER0(int, redraw_needed ); - -void vo_def_dispose(vo_driver_t *self) -{ - vo_driver_hook_t *this = (vo_driver_hook_t *) self; - if (this->orig_driver) - this->orig_driver->dispose(this->orig_driver); - free(self); -} - -/* - * vo_def_hooks_init() - * - * initialize driver_hook_t with default handlers - * - */ -static void vo_proxy_hooks_init(vo_driver_t *drv, vo_driver_t *next_driver) -{ - drv->get_capabilities = drv->get_capabilities ?: vo_def_get_capabilities; - drv->alloc_frame = drv->alloc_frame ?: vo_def_alloc_frame; - drv->update_frame_format = drv->update_frame_format ?: vo_def_update_frame_format; - drv->display_frame = drv->display_frame ?: vo_def_display_frame; - - drv->get_property = drv->get_property ?: vo_def_get_property; - drv->set_property = drv->set_property ?: vo_def_set_property; - drv->get_property_min_max = drv->get_property_min_max ?: vo_def_get_property_min_max; - drv->gui_data_exchange = drv->gui_data_exchange ?: vo_def_gui_data_exchange; - drv->redraw_needed = drv->redraw_needed ?: vo_def_redraw_needed; - drv->dispose = drv->dispose ?: vo_def_dispose; - - /* drop old default handlers for OSD (OSD handlers are optional) */ - if (drv->overlay_begin == vo_def_overlay_begin) - drv->overlay_begin = NULL; - if (drv->overlay_blend == vo_def_overlay_blend) - drv->overlay_blend = NULL; - if (drv->overlay_end == vo_def_overlay_end) - drv->overlay_end = NULL; - - /* Set proxy handlers for OSD only if next driver has OSD handlers */ - if (!drv->overlay_begin && next_driver->overlay_begin) - drv->overlay_begin = vo_def_overlay_begin; - if (!drv->overlay_blend && next_driver->overlay_blend) - drv->overlay_blend = vo_def_overlay_blend; - if (!drv->overlay_end && next_driver->overlay_end) - drv->overlay_end = vo_def_overlay_end; - - drv->node = next_driver->node; /* ??? used only by plugin_loader ? */ -} - -/* - * - */ - -/* from xine-lib video_out.c */ -typedef struct { - xine_video_port_t vo; /* public part */ - vo_driver_t *driver; - /* ... */ -} vos_t; - -/* - * wire_video_driver() - * - */ -int wire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook) -{ - vo_driver_t *vos_driver = ((vos_t*)video_port)->driver; - - if (video_port->driver != vos_driver) { - LOGMSG("wire_video_driver() FAILED (vo_driver != vos_driver)"); - return 0; - } - - /*LOGMSG("wire_video_driver: vo_driver == vos_driver");*/ - - /* wire */ - - /* set proxy handlers for undefined methods */ - vo_proxy_hooks_init(hook, video_port->driver); - - /* append original driver chain to new driver */ - ((vo_driver_hook_t *)hook)->orig_driver = video_port->driver; - - /* push new driver to start of driver chain */ - video_port->driver = hook; - ((vos_t*)video_port)->driver = hook; - - return 1; -} - -/* - * unwire_video_driver() - * - */ -int unwire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook_gen, vo_driver_t *video_out) -{ - vo_driver_hook_t *hook = (vo_driver_hook_t*)hook_gen; - vo_driver_hook_t *next = (vo_driver_hook_t*)video_port->driver; - - if (next == hook) { - /* special handling for first entry */ - video_port->driver = next->orig_driver; - /* need to patch video_port private driver pointer too ... */ - ((vos_t*)video_port)->driver = next->orig_driver; - next->orig_driver = NULL; - return 1; - } - - vo_driver_hook_t *prev = next; - while (next && next != hook && (vo_driver_t*)next != video_out) { - prev = next; - next = (vo_driver_hook_t*)next->orig_driver; - } - - if (prev && next == hook) { - prev->orig_driver = next->orig_driver; - next->orig_driver = NULL; - return 1; - } - - return 0; -} diff --git a/xine/vo_hook.h b/xine/vo_hook.h deleted file mode 100644 index 0de93fd0..00000000 --- a/xine/vo_hook.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * vo_hook.h: Intercept video driver - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_hook.h,v 1.3 2008-12-14 01:14:54 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_HOOK_H -#define _XINELIBOUTPUT_VO_HOOK_H - -#include <xine/video_out.h> - -/* - * synchronous video post plugins - * internal API - */ - - -/* - * vo_driver_hook_t - * - * Used as base for video driver hooks - */ - -typedef struct driver_hook_s { - vo_driver_t vo; /* public part */ - vo_driver_t *orig_driver; -} vo_driver_hook_t; - -/* proxy handlers: forward call to original driver */ - -uint32_t vo_def_get_capabilities(vo_driver_t *self); -int vo_def_get_property(vo_driver_t *self, int prop); -int vo_def_set_property(vo_driver_t *self, int prop, int val); - -void vo_def_dispose(vo_driver_t *self); - - -#endif /* _XINELIBOUTPUT_VO_HOOK_H */ diff --git a/xine/vo_osdreorder.c b/xine/vo_osdreorder.c deleted file mode 100644 index 6fed9e3c..00000000 --- a/xine/vo_osdreorder.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * vo_osdreorder.c: OSD re-ordering video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdreorder.c,v 1.1 2009-03-17 12:14:41 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/video_out.h> - -#include "vo_props.h" -#include "vo_hook.h" - -/* - * osdreorder_hook_t - */ -typedef struct { - vo_driver_hook_t h; - - /* currently showing OSDs in new drawing order */ - vo_overlay_t *overlay[50]; - -} osdreorder_hook_t; - -/* - * - */ - -static int osd_level(vo_overlay_t *overlay) -{ - if (overlay->hili_rgb_clut != VDR_OSD_MAGIC /* not from vdr */) { - return 9999; - } - - /* VDR input plugin stores some control data in hili clut area */ - vdr_osd_extradata_t *data = (vdr_osd_extradata_t *)overlay->hili_color; - return data->layer; -} - -/* - * interface - */ - -/* - * override overlay_blend() - */ -static void osdreorder_overlay_blend (vo_driver_t *self, vo_frame_t *frame, vo_overlay_t *overlay) -{ - osdreorder_hook_t *this = (osdreorder_hook_t*)self; - int my_level = osd_level(overlay); - int i; - - /* search position */ - for (i = 0; this->overlay[i] && osd_level(this->overlay[i]) >= my_level; i++) - ; - - /* make room */ - if (this->overlay[i]) - memmove(&this->overlay[i+1], &this->overlay[i], (49-i)*sizeof(vo_overlay_t*)); - - this->overlay[i] = overlay; - return; -} - -/* - * override overlay_end() - */ -static void osdreorder_overlay_end (vo_driver_t *self, vo_frame_t *vo_img) -{ - osdreorder_hook_t *this = (osdreorder_hook_t*)self; - int i; - - for (i = 0; this->overlay[i]; i++) { - this->h.orig_driver->overlay_blend(this->h.orig_driver, vo_img, this->overlay[i]); - this->overlay[i] = NULL; - } - - /* redirect */ - if (this->h.orig_driver->overlay_end) - this->h.orig_driver->overlay_end(this->h.orig_driver, vo_img); -} - -/* - * init() - */ -vo_driver_t *osd_reorder_init(void) -{ - osdreorder_hook_t *this = calloc(1, sizeof(osdreorder_hook_t)); - - /* OSD interface */ - this->h.vo.overlay_blend = osdreorder_overlay_blend; - this->h.vo.overlay_end = osdreorder_overlay_end; - - return &this->h.vo; -} - diff --git a/xine/vo_osdreorder.h b/xine/vo_osdreorder.h deleted file mode 100644 index 15ec7a6b..00000000 --- a/xine/vo_osdreorder.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * vo_osdreorder.h: OSD re-ordering video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdreorder.h,v 1.1 2009-03-17 12:14:41 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_OSDREORDER_H -#define _XINELIBOUTPUT_VO_OSDREORDER_H - -vo_driver_t *osd_reorder_init(void); - -#endif /* _XINELIBOUTPUT_VO_OSDREORDER_H */ diff --git a/xine/vo_osdscaler.c b/xine/vo_osdscaler.c deleted file mode 100644 index d9562d9e..00000000 --- a/xine/vo_osdscaler.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * vo_osdscaler.c: OSD scaling video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdscaler.c,v 1.4 2009-05-27 08:37:06 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/video_out.h> -#ifdef SWBLEND -# include <xine/alphablend.h> -#endif - -#define LOG_MODULENAME "[osdscaler] " -#include "../logdefs.h" - -#include "vo_props.h" -#include "vo_hook.h" - -/*#define LOGOSD(x...) LOGMSG(x)*/ -#define LOGOSD(x...) - -typedef rle_elem_t xine_rle_elem_t; - -#include "../tools/rle.h" - - -/* Make sure our properties won't overlap with xine's properties */ -#if VO_NUM_PROPERTIES > VO_PROP_OSD_SCALING -# error VO_NUM_PROPERTIES > VO_PROP_OSD_SCALING -#endif - -#undef ABS -#define ABS(x) ((x)<0?-(x):(x)) - - -/* - * osd_data_t - * - * - cache scaled OSD data - */ - -typedef struct osd_data_s osd_data_t; - -struct osd_data_s { - /* original source */ - vo_overlay_t *source; - - /* scaled overlay */ - uint8_t scaled : 1; - vo_overlay_t ovl; - - /* for what output resolution overlay was scaled */ - uint16_t output_width; - uint16_t output_height; - - /* linked list */ - osd_data_t *next; -}; - -/* - * osd_data_dispose() - * - * - free() osd_data_t and all allocated memory - */ -static void osd_data_dispose(osd_data_t *data) -{ - if (data->scaled) - free(data->ovl.rle); - free(data); -} - -/* - * osd_data_clear() - * - * - free() whole linked list - */ -static void osd_data_clear(osd_data_t *data) -{ - if (data) { - if (data->next) - osd_data_clear(data->next); - osd_data_dispose(data); - } -} - -/* - * osd_data_remove() - * - * - remove (and free) specific osd_data_t item from linked list - */ -static void osd_data_remove(osd_data_t **list, osd_data_t *data) -{ - if (!list || !*list) - return; - - /* special handling for list head */ - if (data == *list) { - *list = data->next; - free(data); - return; - } - - osd_data_t *it = *list; - while (it) { - if (data == it->next) { - it->next = data->next; - free(data); - return; - } - it = it->next; - } -} - -/* - * osd_data_init() - * - * - allocate and fill new osd_data_t - * - */ -static osd_data_t *osd_data_init(vo_overlay_t *ovl, osd_data_t *next, - uint32_t factor_x, uint32_t factor_y) -{ - osd_data_t *data = calloc(1, sizeof(osd_data_t)); - - data->source = ovl; - data->next = next; - - memcpy(&data->ovl, ovl, sizeof(vo_overlay_t)); - - int num_rle = data->ovl.num_rle; - - /* new position and size */ - int x2 = ovl->x + ovl->width + 1; - int y2 = ovl->y + ovl->height + 1; - x2 = ((x2+1) * factor_x) >> 16; - y2 = ((y2+1) * factor_y) >> 16; - data->ovl.x = (ovl->x * factor_x) >> 16; - data->ovl.y = (ovl->y * factor_y) >> 16; - data->ovl.width = x2 - data->ovl.x - 1; - data->ovl.height = y2 - data->ovl.y - 1; - - data->ovl.rle = (rle_elem_t*) - rle_scale_nearest((struct xine_rle_elem_s*)ovl->rle, &num_rle, - ovl->width, ovl->height, - data->ovl.width, data->ovl.height); - data->ovl.num_rle = num_rle; - data->scaled = 1; - - LOGOSD("I: %d,%d %dx%d", ovl->x, ovl->y, ovl->width, ovl->height); - LOGOSD("O: %d,%d %dx%d", data->ovl.x, data->ovl.y, data->ovl.width, data->ovl.height); - - return data; -} - -/* - * osdscaler_hook_t - */ -typedef struct { - vo_driver_hook_t h; - - /* configuration */ - uint8_t enable; - uint8_t unscaled_supported; - uint8_t custom_extent_supported; - uint8_t argb_supported; - - /* current output */ - uint16_t output_width; - uint16_t output_height; - uint32_t factor_x; /* scaling factor << 16 */ - uint32_t factor_y; - uint16_t x_move; /* OSD displacement */ - uint16_t y_move; - - /* currently showing OSDs - pre-scaled data */ - osd_data_t *active_osds; - -} osdscaler_hook_t; - -/* - * - */ - -/* - * override overlay_begin() - */ -static void osdscaler_overlay_begin (vo_driver_t *self, vo_frame_t *frame, int changed) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - /* assume we're wired when called */ - if (!this->h.orig_driver) { - LOGMSG("osdscaler_overlay_begin: assertion this->h.orig_driver failed !"); - abort(); - } - - /* re-scale all if OSD changed */ - if (changed) { - LOGOSD("osdscaler_overlay_begin: changed = 1"); - osd_data_clear(this->active_osds); - this->active_osds = NULL; - this->unscaled_supported = (vo_def_get_capabilities(self) & VO_CAP_UNSCALED_OVERLAY); - /* VO_CAP_OSDSCALING == VO_CAP_CUSTOM_EXTENT_OVERLAY */ - this->custom_extent_supported = (vo_def_get_capabilities(self) & VO_CAP_OSDSCALING); - /* VO_CAP_ARGB == VO_CAP_ARGB_LAYER_OVERLAY */ - this->argb_supported = (vo_def_get_capabilities(self) & VO_CAP_ARGB); - } - - /* redirect */ - if (this->h.orig_driver->overlay_begin) - this->h.orig_driver->overlay_begin(this->h.orig_driver, frame, changed); -} - -static int check_for_scaling(osdscaler_hook_t *this, vo_frame_t *frame, vo_overlay_t *overlay) -{ - this->x_move = this->y_move = 0; - - if (!this->enable) - return 0; - - /* check for VDR OSD */ - if (overlay->hili_rgb_clut != VDR_OSD_MAGIC /* not from vdr */) { - LOGOSD("overlay: source not VDR"); - return 0; - } - - /* VDR input plugin stores some control data in hili clut area */ - vdr_osd_extradata_t *data = (vdr_osd_extradata_t *)overlay->hili_color; - int extent_width = data->extent_width; - int extent_height = data->extent_height; - - if (!data->scaling) - return 0; - -#if 0 - if (this->custom_extent_supported) { - /* let the "real" video driver do scaling */ - return 0; - } -#else -# ifdef VO_CAP_CUSTOM_EXTENT_OVERLAY - /* disable VDPAU HW scaler */ - overlay->extent_width = 0; - overlay->extent_height = 0; -# endif -#endif - - /* detect output size */ - if (overlay->unscaled && this->unscaled_supported) { - this->output_width = vo_def_get_property((vo_driver_t*)this, VO_PROP_WINDOW_WIDTH); - this->output_height = vo_def_get_property((vo_driver_t*)this, VO_PROP_WINDOW_HEIGHT); - } else { - this->output_width = frame->width; - this->output_height = frame->height; - /* check cropping */ - if (frame->crop_top > 0) this->output_height -= frame->crop_top; - if (frame->crop_bottom > 0) this->output_height -= frame->crop_bottom; - if (frame->crop_left > 0) this->output_width -= frame->crop_left; - if (frame->crop_right > 0) this->output_width -= frame->crop_right; - } - - /* check if scaling should be done */ - if (ABS(this->output_width - extent_width) > extent_width /20 || - ABS(this->output_height - extent_height) > extent_height/20 ) { - LOGOSD("scaling required"); - this->factor_x = 0x10000 * this->output_width / extent_width; - this->factor_y = 0x10000 * this->output_height / extent_height; - return 1; - } - - /* if no scaling was required, we may still need to re-center OSD */ - if(this->output_width != extent_width) - this->x_move = (this->output_width - extent_width)/2; - if(this->output_height != extent_height) - this->y_move = (this->output_height - extent_height)/2; - - return 0; -} - -static vo_overlay_t *scale_overlay(osdscaler_hook_t *this, vo_frame_t *frame, vo_overlay_t *overlay) -{ - if (check_for_scaling(this, frame, overlay)) { - - /* find old scaled OSD */ - osd_data_t *scaled = this->active_osds; - while (scaled && scaled->source != overlay) - scaled = scaled->next; - - /* output size changed since last scaling (need to re-scale) ? */ - if (scaled && - (scaled->output_width != this->output_width || - scaled->output_height != this->output_height)) { - - LOGOSD("re-scaling required: output size changed %dx%d -> %dx%d", - scaled->output_width, scaled->output_height, this->output_width, this->output_height); - - osd_data_remove(&this->active_osds, scaled); - scaled = NULL; - } - - /* not scaled found ? */ - if (!scaled) { - LOGOSD("scaling OSD"); - scaled = this->active_osds = osd_data_init(overlay, this->active_osds, - this->factor_x, this->factor_y); - scaled->output_width = this->output_width; - scaled->output_height = this->output_height; - } - - /* override */ - overlay = &scaled->ovl; - } - - return overlay; -} - - -/* - * interface - */ - -/* - * override overlay_blend() - */ -static void osdscaler_overlay_blend (vo_driver_t *self, vo_frame_t *frame, vo_overlay_t *overlay) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - overlay = scale_overlay(this, frame, overlay); - - /* redirect */ - if (this->h.orig_driver->overlay_blend) - this->h.orig_driver->overlay_blend(this->h.orig_driver, frame, overlay); -} - -/* - * override overlay_end() - */ -static void osdscaler_overlay_end (vo_driver_t *self, vo_frame_t *vo_img) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - /* redirect */ - if (this->h.orig_driver->overlay_end) - this->h.orig_driver->overlay_end(this->h.orig_driver, vo_img); -} - - -/* - * Management interface - */ - -/* - * override get_capabilities() - */ -static uint32_t osdscaler_get_capabilities(vo_driver_t *self) -{ - return vo_def_get_capabilities(self) | - VO_CAP_OSDSCALING; -} - -/* - * override get_property() - */ -static int osdscaler_get_property(vo_driver_t *self, int prop) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - switch (prop) { - case VO_PROP_OSD_SCALING: return this->enable; - default:; - } - - return vo_def_get_property(self, prop); -} - -/* - * override set_property() - */ -static int osdscaler_set_property(vo_driver_t *self, int prop, int val) -{ - osdscaler_hook_t *this = (osdscaler_hook_t*)self; - - switch (prop) { - case VO_PROP_OSD_SCALING: - if (this->enable != val) { - LOGOSD("osdscaler_set_property: enable %d->%d", this->enable, val); - this->enable = val?1:0; - } - return this->enable; - } - - return vo_def_set_property(self, prop, val); -} - - -/* - * dispose() - */ -static void osdscaler_dispose(vo_driver_t *self) -{ - osdscaler_hook_t *this = (osdscaler_hook_t *) self; - - osd_data_clear(this->active_osds); - - vo_def_dispose(self); -} - - -/* - * init() - */ -vo_driver_t *osdscaler_init(void) -{ - osdscaler_hook_t *this = calloc(1, sizeof(osdscaler_hook_t)); - - /* OSD interface */ - this->h.vo.overlay_begin = osdscaler_overlay_begin; - this->h.vo.overlay_blend = osdscaler_overlay_blend; - this->h.vo.overlay_end = osdscaler_overlay_end; - - /* management interface */ - this->h.vo.get_capabilities = osdscaler_get_capabilities; - this->h.vo.get_property = osdscaler_get_property; - this->h.vo.set_property = osdscaler_set_property; - - this->h.vo.dispose = osdscaler_dispose; - - /* initialize data */ - this->enable = 0; - - return &this->h.vo; -} - diff --git a/xine/vo_osdscaler.h b/xine/vo_osdscaler.h deleted file mode 100644 index fe7d21d0..00000000 --- a/xine/vo_osdscaler.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * vo_osdscaler.h: OSD scaling video-out post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_osdscaler.h,v 1.1 2008-11-20 09:24:27 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_OSDSCALER_H -#define _XINELIBOUTPUT_VO_OSDSCALER_H - -vo_driver_t *osdscaler_init(void); - -#endif /* _XINELIBOUTPUT_VO_OSDSCALER_H */ diff --git a/xine/vo_post.h b/xine/vo_post.h deleted file mode 100644 index 8ed7b076..00000000 --- a/xine/vo_post.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * vo_post.h: Intercept video driver - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_post.h,v 1.3 2008-12-14 01:19:21 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_VO_POST_H -#define _XINELIBOUTPUT_VO_POST_H - -#include <xine/video_out.h> - -/* - * synchronous video post plugins - * public API - */ - -/* Wire / unwire hook chain to video port */ -int wire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook); -int unwire_video_driver(xine_video_port_t *video_port, vo_driver_t *hook, vo_driver_t *video_out); - -#endif /* _XINELIBOUTPUT_VO_POST_H */ diff --git a/xine/vo_props.h b/xine/vo_props.h deleted file mode 100644 index dc377dfc..00000000 --- a/xine/vo_props.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * vo_props.h: Extended video-out capabilities and properties - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vo_props.h,v 1.4 2009-03-17 12:20:33 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_VO_PROPS_H_ -#define XINELIBOUTPUT_VO_PROPS_H_ - -/* - * Extended vo capabilities - */ - -/* output can scale OSD */ -#ifdef VO_CAP_CUSTOM_EXTENT_OVERLAY - /* xine-lib 1.2 */ -# define VO_CAP_OSDSCALING VO_CAP_CUSTOM_EXTENT_OVERLAY -#else -# define VO_CAP_OSDSCALING 0x01000000 -#endif - -/* Output can blend ARGB surfaces */ -#ifdef VO_CAP_ARGB_LAYER_OVERLAY -# define VO_CAP_ARGB VO_CAP_ARGB_LAYER_OVERLAY -#else -# define VO_CAP_ARGB 0x02000000 -#endif - - -/* - * Extended vo properties - */ - -/* enable/disable OSD scaling */ -#define VO_PROP_OSD_SCALING 0x1001 - - -/* - * VDR OSD tagging and extra data - */ - -/* VDR OSD , stored in overlay hili_rgb_clut member */ -#define VDR_OSD_MAGIC -9999 - -/* VDR OSD extra data, stored in overlay hili clut data */ -typedef struct { - /* extent of reference coordinate system */ - uint16_t extent_width; - uint16_t extent_height; - /* overlay layer */ - uint32_t layer; - /* scaling: 0 - disable , 1...N - quality */ - uint8_t scaling; -} vdr_osd_extradata_t; - -#endif /* XINELIBOUTPUT_VO_PROPS_H_ */ diff --git a/xine/xvdr_metronom.c b/xine/xvdr_metronom.c deleted file mode 100644 index 1a2316ab..00000000 --- a/xine/xvdr_metronom.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * xvdr_metronom.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xvdr_metronom.c,v 1.1 2009-05-22 21:02:30 phintuka Exp $ - * - */ - -#include <stdlib.h> - -#include <xine/xine_internal.h> -#include <xine/metronom.h> - -#define LOG_MODULENAME "[metronom ] " -#define SysLogLevel iSysLogLevel -#include "../logdefs.h" - -#define XVDR_METRONOM_COMPILE -#include "xvdr_metronom.h" - - -static void got_video_frame(metronom_t *metronom, vo_frame_t *frame) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - - this->video_frames++; - - if (this->frame_decoded) - this->frame_decoded(this->handle, this->video_frames, this->audio_frames); - - return this->orig_metronom->got_video_frame (this->orig_metronom, frame); -} - -static int64_t got_audio_samples(metronom_t *metronom, int64_t pts, int nsamples) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - - this->audio_frames++; - - if (this->frame_decoded) - this->frame_decoded(this->handle, this->video_frames, this->audio_frames); - - return this->orig_metronom->got_audio_samples (this->orig_metronom, pts, nsamples); -} - -/* - * dummy hooks - */ - -static int64_t got_spu_packet(metronom_t *metronom, int64_t pts) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - return this->orig_metronom->got_spu_packet(this->orig_metronom, pts); -} - -static void handle_audio_discontinuity(metronom_t *metronom, int type, int64_t disc_off) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->handle_audio_discontinuity(this->orig_metronom, type, disc_off); -} - -static void handle_video_discontinuity(metronom_t *metronom, int type, int64_t disc_off) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->handle_video_discontinuity(this->orig_metronom, type, disc_off); -} - -static void set_audio_rate(metronom_t *metronom, int64_t pts_per_smpls) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->set_audio_rate(this->orig_metronom, pts_per_smpls); -} - -static void set_option(metronom_t *metronom, int option, int64_t value) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->set_option(this->orig_metronom, option, value); -} - -static int64_t get_option(metronom_t *metronom, int option) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - return this->orig_metronom->get_option(this->orig_metronom, option); -} - -static void set_master(metronom_t *metronom, metronom_t *master) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - this->orig_metronom->set_master(this->orig_metronom, master); -} - -static void metronom_exit(metronom_t *metronom) -{ - xvdr_metronom_t *this = (xvdr_metronom_t *)metronom; - - LOGERR("xvdr_metronom: metronom_exit() called !"); - - /* un-hook */ - this->stream->metronom = this->orig_metronom; - this->orig_metronom = NULL; - this->stream = NULL; - - this->orig_metronom->exit(this->orig_metronom); -} - -/* - * xvdr_metronom_t - */ - -static void xvdr_metronom_set_cb(xvdr_metronom_t *this, - void (*cb)(void*, uint, uint), - void *handle) -{ - this->handle = handle; - this->frame_decoded = cb; -} - -static void xvdr_metronom_dispose(xvdr_metronom_t *this) -{ - if (this->stream && this->orig_metronom) - this->stream->metronom = this->orig_metronom; - - free(this); -} - -static void xvdr_metronom_reset_frames(xvdr_metronom_t *this) -{ - this->video_frames = this->audio_frames = 0; -} - -/* - * init - */ - -xvdr_metronom_t *xvdr_metronom_init(xine_stream_t *stream) -{ - xvdr_metronom_t *this = calloc(1, sizeof(xvdr_metronom_t)); - - this->stream = stream; - this->orig_metronom = stream->metronom; - - this->set_cb = xvdr_metronom_set_cb; - this->reset_frames = xvdr_metronom_reset_frames; - this->dispose = xvdr_metronom_dispose; - - this->metronom.set_audio_rate = set_audio_rate; - this->metronom.got_video_frame = got_video_frame; - this->metronom.got_audio_samples = got_audio_samples; - this->metronom.got_spu_packet = got_spu_packet; - this->metronom.handle_audio_discontinuity = handle_audio_discontinuity; - this->metronom.handle_video_discontinuity = handle_video_discontinuity; - this->metronom.set_option = set_option; - this->metronom.get_option = get_option; - this->metronom.set_master = set_master; - - this->metronom.exit = metronom_exit; - - /* hook up to stream */ - this->stream->metronom = &this->metronom; - - return this; -} diff --git a/xine/xvdr_metronom.h b/xine/xvdr_metronom.h deleted file mode 100644 index 21188f28..00000000 --- a/xine/xvdr_metronom.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * xvdr_metronom.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xvdr_metronom.h,v 1.1 2009-05-22 21:02:30 phintuka Exp $ - * - */ - -#ifndef XVDR_METRONOM_H -#define XVDR_METRONOM_H - -typedef struct xvdr_metronom_s xvdr_metronom_t; - -struct xvdr_metronom_s { - /* xine-lib metronom interface */ - metronom_t metronom; - - /* management interface */ - void (*set_cb) (xvdr_metronom_t *, - void (*cb) (void *, uint, uint), - void *); - void (*reset_frames)(xvdr_metronom_t *); - void (*dispose) (xvdr_metronom_t *); - - /* accumulated frame data */ - volatile uint video_frames; - volatile uint audio_frames; - - /* private data */ - -#ifdef XVDR_METRONOM_COMPILE - - /* original metronom */ - metronom_t *orig_metronom; - xine_stream_t *stream; - - /* callback */ - void *handle; - void (*frame_decoded)(void *handle, uint video_count, uint audio_count); - -#endif -}; - -xvdr_metronom_t *xvdr_metronom_init(xine_stream_t *); - - -#endif /* XVDR_METRONOM_H */ diff --git a/xine_fbfe_frontend.c b/xine_fbfe_frontend.c deleted file mode 100644 index b1394dec..00000000 --- a/xine_fbfe_frontend.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * xine_fbfe_frontend.c: Simple front-end, framebuffer functions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_fbfe_frontend.c,v 1.45 2009-05-31 16:51:26 phintuka Exp $ - * - */ - -#include <inttypes.h> -#include <sys/ioctl.h> -#include <fcntl.h> -#include <unistd.h> - -#if defined(__linux__) -# include <linux/kd.h> -#endif - -#define LOG_MODULENAME "[vdr-fbfe] " -#include "logdefs.h" - -#include "xine_frontend_internal.h" - - -/* - * data - */ - -typedef struct fbfe_s { - - /* function pointers / base class */ - union { - frontend_t fe; /* generic frontend */ - fe_t x; /* xine frontend */ - }; - - /* stored original handlers */ - int (*fe_xine_init)(frontend_t *this_gen, const char *audio_driver, - const char *audio_port, - const char *video_driver, - int pes_buffers, - const char *static_post_plugins, - const char *config_file); - - /* display */ -/*char *modeline;*/ - int fd_tty; - - /* frontend */ - uint8_t fullscreen : 1; -/*uint8_t vmode_switch : 1;*/ - -} fbfe_t; - -static void fbfe_update_display_size(fe_t *this_gen) -{ - fbfe_t *this = (fbfe_t*)this_gen; - if(this->fullscreen && this->x.video_port) { - this->x.width = this->x.video_port->get_property(this->x.video_port, - VO_PROP_WINDOW_WIDTH); - this->x.height = this->x.video_port->get_property(this->x.video_port, - VO_PROP_WINDOW_HEIGHT); - LOGDBG("Framebuffer size after initialization: %dx%d", - this->x.width, this->x.height); - } -} - -/* - * update_DFBARGS - * - * (optionally) add fbdev option to DFBARGS environment variable - */ -static void update_DFBARGS(const char *fb_dev) -{ - const char *env_old = getenv("DFBARGS"); - char *env_new = NULL; - - if (env_old) { - char *env_tmp = strdup(env_old); - char *head = strstr(env_tmp, "fbdev="); - - if (head) { - char *tail = strchr(head, ','); - if(head == env_tmp) - head = NULL; - else - *head = 0; - if(asprintf(&env_new, "%sfbdev=%s%s", - head ? env_tmp : "", fb_dev, tail ? tail : "") < 0) { - free(env_tmp); - return; - } - } else { - if(asprintf(&env_new, "fbdev=%s%s%s", fb_dev, env_tmp ? "," : "", env_tmp ?: "") < 0) { - free(env_tmp); - return; - } - } - free(env_tmp); - - LOGMSG("replacing environment variable DFBARGS with %s (original was %s)", - env_new, env_old); - - } else { - if(asprintf(&env_new, "fbdev=%s", fb_dev) < 0) - return; - - LOGMSG("setting environment variable DFBARGS to %s", env_new); - } - - setenv("DFBARGS", env_new, 1); - free(env_new); -} - -/* - * fbfe_display_open - */ -static int fbfe_display_open(frontend_t *this_gen, - int xpos, int ypos, - int width, int height, int fullscreen, int hud, - int modeswitch, const char *modeline, int aspect, - fe_keypress_f keyfunc, int no_x_kbd, int gui_hotkeys, - const char *video_port, int scale_video, int field_order, - const char *aspect_controller, int window_id) -{ - fbfe_t *this = (fbfe_t*)this_gen; - - if(!this) - return 0; - - if(this->fd_tty >= 0) - this->fe.fe_display_close(this_gen); - - if(keyfunc) { - this->x.keypress = keyfunc; - this->x.keypress("KBD", ""); - } - - LOGDBG("fbfe_display_open(width=%d, height=%d, fullscreen=%d, display=%s)", - width, height, fullscreen, video_port); - - this->x.xpos = xpos; - this->x.ypos = ypos; - this->x.width = width; - this->x.height = height; - this->x.aspect = aspect; -/*this->x.cropping = 0;*/ - this->x.field_order = field_order; - this->x.scale_video = scale_video; - this->x.overscan = 0; - this->x.display_ratio = 1.0; - this->x.aspect_controller = aspect_controller ? strdup(aspect_controller) : NULL; - - this->fullscreen = fullscreen; -/*this->vmode_switch = modeswitch;*/ -/*this->modeline = strdup(modeline ?: "");*/ - - /* setup xine FB visual */ - this->x.xine_visual_type = XINE_VISUAL_TYPE_FB; - this->x.vis_fb.frame_output_cb = this->x.frame_output_handler; - this->x.vis_fb.user_data = this; - - /* select framebuffer device ? */ - if(video_port && !strncmp(video_port, "/dev/", 5)) - this->x.video_port_name = strdup(video_port); - else - this->x.video_port_name = NULL; - - /* set console to graphics mode */ -#if defined(KDSETMODE) && defined(KD_GRAPHICS) - if (isatty(STDIN_FILENO)) - this->fd_tty = dup(STDIN_FILENO); - else - this->fd_tty = open("/dev/tty", O_RDWR); - - if(this->fd_tty < 0) - LOGERR("fbfe_display_open: error opening /dev/tty"); - else if (ioctl(this->fd_tty, KDSETMODE, KD_GRAPHICS) == -1) - LOGERR("fbfe_display_open: failed to set /dev/tty to graphics mode"); -#else -# warning No support for console graphics mode - this->fd_tty = -1; -#endif - - return 1; -} - -/* - * fbfe_display_config - * - * configure windows - */ -static int fbfe_display_config(frontend_t *this_gen, - int xpos, int ypos, - int width, int height, int fullscreen, - int modeswitch, const char *modeline, - int aspect, int scale_video, int field_order) -{ - fbfe_t *this = (fbfe_t*)this_gen; - - if(!this) - return 0; - - this->x.xpos = xpos >= 0 ? xpos : this->x.xpos; - this->x.ypos = ypos >= 0 ? ypos : this->x.ypos; - this->x.width = width >= 0 ? width : this->x.width; - this->x.height = height >= 0 ? height : this->x.height; - this->x.aspect = aspect; - this->x.scale_video = scale_video; - this->x.field_order = field_order; - this->fullscreen = fullscreen; -/*this->vmode_switch = modeswitch;*/ -#if 0 - if(!modeswitch && strcmp(modeline, this->modeline)) { - free(this->modeline); - this->modeline = strdup(modeline ?: ""); - /* #warning XXX TODO - switch vmode */ - } -#endif - - return 1; -} - -static void fbfe_interrupt(frontend_t *this_gen) -{ - /* stop fbfe_run() */ -} - -static int fbfe_run(frontend_t *this_gen) -{ - fbfe_t *this = (fbfe_t*)this_gen; - - if (!this || this->fe.xine_is_finished(this_gen, 0) != FE_XINE_RUNNING) - return 0; - - /* just sleep 500ms */ - select(0, NULL, NULL, NULL, &(struct timeval){ .tv_sec = 0, .tv_usec = 500*1000 }); - - return 1; -} - -static void fbfe_display_close(frontend_t *this_gen) -{ - fbfe_t *this = (fbfe_t*)this_gen; - - if (!this) - return; - - if (this->x.xine) - this->fe.xine_exit(this_gen); - - if (this->fd_tty >= 0) { -#if defined(KDSETMODE) && defined(KD_TEXT) - if(ioctl(this->fd_tty, KDSETMODE, KD_TEXT) == -1) - LOGERR("fbfe_display_close: failed to set /dev/tty to text mode"); -#endif - close(this->fd_tty); - this->fd_tty = -1; - } - - free(this->x.video_port_name); - this->x.video_port_name = NULL; - - free(this->x.aspect_controller); - this->x.aspect_controller = NULL; -#if 0 - free(this->modeline); - this->modeline = NULL; -#endif -} - -static int fbfe_xine_init(frontend_t *this_gen, const char *audio_driver, - const char *audio_port, - const char *video_driver, - int pes_buffers, - const char *static_post_plugins, - const char *config_file) -{ - fbfe_t *this = (fbfe_t*)this_gen; - - if (video_driver && !strcmp(video_driver, "DirectFB")) - update_DFBARGS(this->x.video_port_name); - - return this->fe_xine_init(this_gen, audio_driver, audio_port, - video_driver, pes_buffers, static_post_plugins, config_file); -} - -static frontend_t *fbfe_get_frontend(void) -{ - fbfe_t *this = calloc(1, sizeof(fbfe_t)); - - this->fd_tty = -1; - - init_fe((fe_t*)this); - - this->fe.fe_display_open = fbfe_display_open; - this->fe.fe_display_config = fbfe_display_config; - this->fe.fe_display_close = fbfe_display_close; - - this->fe.fe_run = fbfe_run; - this->fe.fe_interrupt = fbfe_interrupt; - - this->x.update_display_size_cb = fbfe_update_display_size; - - /* override */ - this->fe_xine_init = this->fe.xine_init; - this->fe.xine_init = fbfe_xine_init; - - return (frontend_t*)this; -} - -/* ENTRY POINT */ -const fe_creator_f fe_creator __attribute__((visibility("default"))) = fbfe_get_frontend; - - diff --git a/xine_frontend.c b/xine_frontend.c deleted file mode 100644 index ff98270f..00000000 --- a/xine_frontend.c +++ /dev/null @@ -1,1854 +0,0 @@ -/* - * xine_frontend.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_frontend.c,v 1.97 2009-03-17 12:16:23 phintuka Exp $ - * - */ - -#include "features.h" - -#include <inttypes.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#ifdef HAVE_LIBJPEG -# ifdef boolean -# define HAVE_BOOLEAN -# endif -# include <jpeglib.h> -# undef boolean -#endif - -#define XINE_ENGINE_INTERNAL -#include <xine.h> -#include <xine/xine_internal.h> - -#define LOG_MODULENAME "[vdr-fe] " -#include "logdefs.h" - -#include "xine_frontend_internal.h" -#include "xine/post.h" - -#include "xine/vo_post.h" -#include "xine/vo_osdscaler.h" -#include "xine/vo_osdreorder.h" - -#undef MIN -#define MIN(a,b) ( (a) < (b) ? (a) : (b)) -#undef MAX -#define MAX(a,b) ( (a) > (b) ? (a) : (b)) - - -static void intercept_video_driver(xine_video_port_t *video_port) -{ - vo_driver_t *osdscaler = osdscaler_init(); - if (! wire_video_driver(video_port, osdscaler)) { - LOGMSG("wire_video_driver() for osdscaler failed"); - osdscaler->dispose(osdscaler); - } - - vo_driver_t *osdreorder = osd_reorder_init(); - if (! wire_video_driver(video_port, osdreorder)) { - LOGMSG("wire_video_driver() for osdreorder failed"); - osdreorder->dispose(osdreorder); - } -} - - -char *strn0cpy(char *dest, const char *src, int n) -{ - char *s = dest; - for ( ; --n && (*dest = *src) != 0; dest++, src++) ; - *dest = 0; - return s; -} - -static int guess_cpu_count(void) -{ - static int cores = -1; - FILE *f; - - if(cores >= 0) - return cores; - - cores = 0; - if(NULL != (f = fopen("/proc/cpuinfo", "r"))) { - char buf[256]; - while (NULL != fgets(buf, 255, f)) - sscanf(buf, "processor : %d", &cores); - fclose(f); - } - cores++; - - if(cores > 1) - LOGMSG("Detected %d CPUs", cores); - else - LOGDBG("Detected single CPU. Multithreaded decoding and post processing disabled."); - - return cores; -} - -/* - * list available plugins - */ - -static void list_plugins_type(xine_t *xine, const char *msg, typeof (xine_list_audio_output_plugins) list_func) -{ - static xine_t *tmp_xine = NULL; - if(!xine) { - if(!tmp_xine) - xine_init(tmp_xine = xine_new()); - xine = tmp_xine; - } - const char *const *list = list_func(xine); - - printf("%s", msg); - while(list && *list) - printf(" %s", *list++); - printf("\n"); -} - -void list_xine_plugins(frontend_t *fe, int verbose) -{ - fe_t *this = (fe_t *)fe; - - xine_t *tmp_xine = NULL; - xine_t *xine = this ? this->xine : NULL; - - if (!xine) - xine_init(xine = tmp_xine = xine_new()); - - list_plugins_type (xine, "Available video drivers:", xine_list_video_output_plugins); - list_plugins_type (xine, "Available audio drivers:", xine_list_audio_output_plugins); - if (verbose) { - list_plugins_type (xine, "Available post plugins: ", xine_list_post_plugins); - list_plugins_type (xine, "Available input plugins:", xine_list_input_plugins); - list_plugins_type (xine, "Available demux plugins:", xine_list_demuxer_plugins); - list_plugins_type (xine, "Available audio decoder plugins:", xine_list_audio_decoder_plugins); - list_plugins_type (xine, "Available video decoder plugins:", xine_list_video_decoder_plugins); - list_plugins_type (xine, "Available SPU decoder plugins: ", xine_list_spu_plugins); - } - - if (tmp_xine) - xine_exit(tmp_xine); -} - -/* - * detect input plugin - */ - -static int find_input_plugin(fe_t *this) -{ - if(!this->input_plugin) { - if(!this->stream || !this->stream->input_plugin || - !this->stream->input_plugin->input_class || this->playback_finished) { - LOGMSG("find_input_plugin: stream not initialized or playback finished !"); - usleep(100*1000); - return 0; - } -#if XINE_VERSION_CODE < 10190 - if(strcmp(this->stream->input_plugin->input_class->get_identifier( - this->stream->input_plugin->input_class), - MRL_ID)) { -#else - if(strcmp(this->stream->input_plugin->input_class->identifier, - MRL_ID)) { -#endif - LOGMSG("find_input_plugin: current xine input plugin is not " MRL_ID " !"); - return 0; - } - this->input_plugin = (vdr_input_plugin_if_t*)this->stream->input_plugin; - } - return 1; -} - -static void *fe_control(frontend_t *this_gen, const char *cmd); - -/* - * xine callbacks - */ - -static double fe_dest_pixel_aspect(const fe_t *this, double video_pixel_aspect, - int video_width, int video_height) -{ - /*int new_cropping = 0;*/ - double result = 1.0; - - if(!this->scale_video) { - - /*#warning what to do if scaling disabled ???*/ - - /*return video_pixel_aspect;*/ - } - - switch(this->aspect) { - /* Auto */ - default: { - double correction = - ((double)video_width/(double)video_height) / - ((double)this->width/(double)this->height); - - result = video_pixel_aspect * correction; - if(result > (16.9/9.0 * (double)this->height/ - (double)this->width)) - result = (16.0/9.0 * (double)this->height/ - (double)this->width); - break; - } - /* Default */ - case 1: result = this->display_ratio; break; - - /* 4:3 */ - case 2: result = (4.0/3.0 * (double)this->height/(double)this->width); break; - /* 16:9 */ - case 3: result = (16.0/9.0 * (double)this->height/(double)this->width); break; - /* 16:10 */ - case 4: result = (16.0/10.0 * (double)this->height/(double)this->width); break; - /* Pan&Scan */ - case 5: { - double aspect_diff /*= video_pixel_aspect - 1.0*/; - /* TODO */ - /* does not work (?) */ -aspect_diff=(video_pixel_aspect*(double)video_width/(double)video_height) - 4.0 / 3.0; - if ((aspect_diff < 0.05) && (aspect_diff > -0.05)) { - result = (4.0/3.0 * (double)this->height/(double)this->width); - /*LOGDBG("diff: %f", aspect_diff);*/ - /*new_cropping = 1;*/ - } else { - result = (16.0/9.0 * (double)this->height/(double)this->width); - } - /*result = (4.0/3.0 * (double)this->height/(double)this->width);*/ - break; - } - /* center cut-out */ - case 6: { -/*#warning center cut-out mode not implemented*/ - break; - } - - } -#if 0 - if(this->cropping && !new_cropping) { - LOGDBG("pan&scan CROP OFF"); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_LEFT, 0); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_TOP, 72); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_RIGHT, 0); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_BOTTOM, 72); - this->cropping = 0; - } - if(!this->cropping && new_cropping) { - LOGDBG("pan&scan CROP ON"); - /*** Should set unscaled osd (or top & bottom will be cropped off) */ - xine_set_param(this->stream, XINE_PARAM_VO_CROP_LEFT, 0); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_TOP, 0); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_RIGHT, 0); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_BOTTOM, 0); - this->cropping = 1; - } -#endif - - return result; -} - -static void fe_frame_output_cb (void *data, - int video_width, int video_height, - double video_pixel_aspect, - int *dest_x, int *dest_y, - int *dest_width, int *dest_height, - double *dest_pixel_aspect, - int *win_x, int *win_y) -{ - fe_t *this = (fe_t *)data; - - if (!this) - return; - - *dest_width = this->width; - *dest_height = this->height; - *dest_x = 0; -#ifndef HAVE_XV_FIELD_ORDER - *dest_y = 0 + this->field_order; -#else - *dest_y = 0; -#endif - -#if 1 - if(!this->scale_video) { - if(video_height < this->height) { - *dest_height = video_height; - *dest_y = (this->height - video_height) / 2; - } - if(video_width < this->width) { - *dest_width = video_width; - *dest_x = (this->width - video_width) / 2; - } - } -#endif - - *win_x = this->xpos; - *win_y = this->ypos; - - *dest_pixel_aspect = this->dest_pixel_aspect(this, video_pixel_aspect, - video_width, video_height); - -#if 0 - if(this->cropping) { - *dest_pixel_aspect = *dest_pixel_aspect * (16.0/9.0)/(4.0/3.0); - *dest_y = *dest_y - 72; - *dest_height = *dest_height + 144; - } -#endif - -#if 0 - /* video_out cropping works better */ - if(this->overscan) { - int crop_x = this->overscan * this->width / 100 / 2; - int crop_y = this->overscan * this->height / 100 / 2; - *dest_x -= crop_x; - *dest_y -= crop_y; - *dest_width += crop_x; - *dest_height += crop_y; - } -#endif - - if(!this->stream) - return; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, - (int)(10000.0*video_pixel_aspect * - ((double)video_width)/((double)video_height))); - if(this->video_width != video_width || - this->video_height != video_height) { - xine_format_change_data_t framedata = { - .width = video_width, - .height = video_height, - .aspect = 0, /* TODO */ - .pan_scan = 0, - }; - const xine_event_t event = { - .type = XINE_EVENT_FRAME_FORMAT_CHANGE, - .stream = this->stream, - .data = &framedata, - .data_length = sizeof(framedata), - }; - xine_event_send(this->stream, &event); - this->video_width = video_width; - this->video_height = video_height; -#if 0 - /* trigger forced redraw to make cropping changes effective */ - if(this->cropping) - xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, 100); -#endif - } - - if(this->aspect_controller) { - double video_aspect = (video_pixel_aspect * (double)video_width / (double)video_height); - double aspect_diff = video_aspect - this->video_aspect; - if ((aspect_diff > 0.05) || (aspect_diff < -0.05)) { - char cmd[4096]; - if(snprintf(cmd, sizeof(cmd), "%s %d", - this->aspect_controller, (int)(video_aspect * 10000.0)) - < sizeof(cmd)) { - LOGDBG("Aspect ratio changed, executing %s", cmd); - if(system(cmd) == -1) - LOGERR("Executing /bin/sh -c %s failed", cmd); - this->video_aspect = video_aspect; - } - } - } -} - -static void xine_event_cb (void *user_data, const xine_event_t *event) -{ - fe_t *this = (fe_t *)user_data; - - switch (event->type) { - /* in local mode: vdr stream / slave stream ; in remote mode: vdr stream only */ - case XINE_EVENT_UI_PLAYBACK_FINISHED: - LOGMSG("xine_event_cb: XINE_EVENT_UI_PLAYBACK_FINISHED"); - if(this) { - if(event->stream == this->stream) - this->playback_finished = 1; - } else { - LOGMSG("xine_event_cb: NO USER DATA !"); - } - break; - default: break; - } -} - -/* - * fe_xine_init - * - * initialize xine engine, initialize audio and video ports, setup stream - */ - -#define MONO 0 -#define STEREO 1 -#define HEADPHONES 2 -#define SURROUND21 3 -#define SURROUND3 4 -#define SURROUND4 5 -#define SURROUND41 6 -#define SURROUND5 7 -#define SURROUND51 8 -#define SURROUND6 9 -#define SURROUND61 10 -#define SURROUND71 11 -#define A52_PASSTHRU 12 - -#define x_reg_num(x...) xine_config_register_num(this->xine, x) -#define x_reg_str(x...) xine_config_register_string(this->xine, x) -#define x_reg_enum(x...) xine_config_register_enum(this->xine, x) -#define x_reg_bool(x...) xine_config_register_bool(this->xine, x) - -#define x_upd_num(x...) this->xine->config->update_num(this->xine->config, x) -#define x_upd_str(x...) this->xine->config->update_string(this->xine->config, x) - -static void configure_audio_out(const fe_t *this, const char *audio_driver, const char *audio_port) -{ - /* - * alsa - */ - if(audio_driver && audio_port && !strcmp("alsa", audio_driver) && strlen(audio_port) > 0) { - - /* define possible speaker arrangements */ - /* From xine audio_alsa_out.c ; must be synchronized ! */ - static char *speaker_arrangement[] = - {"Mono 1.0", "Stereo 2.0", "Headphones 2.0", "Stereo 2.1", - "Surround 3.0", "Surround 4.0", "Surround 4.1", - "Surround 5.0", "Surround 5.1", "Surround 6.0", - "Surround 6.1", "Surround 7.1", "Pass Through", NULL}; - - x_reg_enum("audio.output.speaker_arrangement", - STEREO, - speaker_arrangement, - _("speaker arrangement"), - _("Select how your speakers are arranged, " - "this determines which speakers xine uses for sound output. " - "The individual values are:\n\n" - "Mono 1.0: You have only one speaker.\n" - "Stereo 2.0: You have two speakers for left and right channel.\n" - "Headphones 2.0: You use headphones.\n" - "Stereo 2.1: You have two speakers for left and right channel, and one " - "subwoofer for the low frequencies.\n" - "Surround 3.0: You have three speakers for left, right and rear channel.\n" - "Surround 4.0: You have four speakers for front left and right and rear " - "left and right channels.\n" - "Surround 4.1: You have four speakers for front left and right and rear " - "left and right channels, and one subwoofer for the low frequencies.\n" - "Surround 5.0: You have five speakers for front left, center and right and " - "rear left and right channels.\n" - "Surround 5.1: You have five speakers for front left, center and right and " - "rear left and right channels, and one subwoofer for the low frequencies.\n" - "Surround 6.0: You have six speakers for front left, center and right and " - "rear left, center and right channels.\n" - "Surround 6.1: You have six speakers for front left, center and right and " - "rear left, center and right channels, and one subwoofer for the low frequencies.\n" - "Surround 7.1: You have seven speakers for front left, center and right, " - "left and right and rear left and right channels, and one subwoofer for the " - "low frequencies.\n" - "Pass Through: Your sound system will receive undecoded digital sound from xine. " - "You need to connect a digital surround decoder capable of decoding the " - "formats you want to play to your sound card's digital output."), - 10, NULL, NULL); - - x_reg_str("audio.device.alsa_default_device", - "default", - _("device used for mono output"), - _("xine will use this alsa device " - "to output mono sound.\n" - "See the alsa documentation " - "for information on alsa devices."), - 10, NULL, NULL); - x_reg_str("audio.device.alsa_front_device", - "plug:front:default", - _("device used for stereo output"), - _("xine will use this alsa device " - "to output stereo sound.\n" - "See the alsa documentation " - "for information on alsa devices."), - 10, NULL, NULL); - x_reg_str("audio.device.alsa_surround51_device", - "plug:surround51:0", - _("device used for 5.1-channel output"), - _("xine will use this alsa device to output " - "5 channel plus LFE (5.1) surround sound.\n" - "See the alsa documentation for information " - "on alsa devices."), - 10, NULL, NULL); - x_reg_str("audio.device.alsa_passthrough_device", - "iec958:AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2", - _("device used for 5.1-channel output"), - _("xine will use this alsa device to output " - "undecoded digital surround sound. This can " - "be used be external surround decoders.\nSee the " - "alsa documentation for information on alsa " - "devices."), - 10, NULL, NULL); - - x_upd_str("audio.device.alsa_front_device", audio_port); - x_upd_str("audio.device.alsa_default_device", audio_port); - x_upd_str("audio.device.alsa_surround51_device", audio_port); - if(strstr(audio_port, "iec") || - strstr(audio_port, "spdif")) { - x_upd_str("audio.device.alsa_passthrough_device", audio_port); - x_upd_num("audio.output.speaker_arrangement", A52_PASSTHRU); - } else { - x_upd_num("audio.output.speaker_arrangement", - strstr(audio_port, "surround") ? SURROUND51 : STEREO); - } - } - - - /* - * OSS - */ - if(audio_driver && !strcmp("oss", audio_driver) && audio_port) { - int devnum = -2; - if(!strcmp("default", audio_port)) - devnum = -1; - if(!strncmp("/dev/dsp", audio_port, 8) && - sscanf(audio_port+8, "%d", &devnum) < 1) - devnum = -1; - if(!strncmp("/dev/sound/dsp", audio_port, 14) && - sscanf(audio_port+14, "%d", &devnum) < 1) - devnum = -1; - if(devnum > -2) { - x_reg_num("audio.device.oss_device_number", -1, - _("OSS audio device number, -1 for none"), - _("The full audio device name is created by concatenating the " - "OSS device name and the audio device number.\n" - "If you do not need a number because you are happy with " - "your system's default audio device, set this to -1.\n" - "The range of this value is -1 or 0-15. This setting is " - "ignored, when the OSS audio device name is set to \"auto\"."), - 10, NULL, NULL); - x_upd_num("audio.device.oss_device_num", devnum); - } - } -} - -static int fe_xine_init(frontend_t *this_gen, const char *audio_driver, - const char *audio_port, - const char *video_driver, - int pes_buffers, - const char *static_post_plugins, - const char *config_file) -{ - fe_t *this = (fe_t*)this_gen; - post_plugins_t *posts = NULL; - - if(!this) - return 0; - - /* check xine-lib version */ - if(!xine_check_version(1, 1, 0)) { - LOGERR("xine-lib is too old, require at least xine library version 1.1.0\n"); - return FE_ERROR; - } - - - /* - * init xine engine - */ - - if(this->xine) - this->fe.xine_exit(this_gen); - - this->stream = NULL; - this->video_port = NULL; - this->audio_port = NULL; - this->input_plugin = NULL; - - /* create a new xine and load config file */ - this->xine = xine_new(); - if(!this->xine) - return 0; - - /* Set xine engine logging verbosity */ - this->xine->verbosity = (SysLogLevel>2); - - /*xine_register_log_cb(this->xine, xine_log_cb, this);*/ - - free(this->configfile); - this->configfile = NULL; - if (config_file) - this->configfile = strdup(config_file); - else if(asprintf(&this->configfile, "%s%s", xine_get_homedir(), - "/.xine/config_xineliboutput") < 0) - return 0; - - xine_config_load (this->xine, this->configfile); - - x_reg_num ("engine.buffers.video_num_buffers", - 500, - _("number of video buffers"), - _("The number of video buffers " - "(each is 8k in size) " - "xine uses in its internal queue. " - "Higher values " - "mean smoother playback for unreliable " - "inputs, but " - "also increased latency and memory " - "consumption."), - 20, NULL, NULL); - x_reg_bool("gui.osd_use_unscaled", - 0, - _("Use unscaled OSD"), - _("Use unscaled (full screen resolution) OSD if possible"), - 10, NULL, NULL); - - xine_init (this->xine); - - x_upd_num("video.device.xv_double_buffer", 1); - x_upd_num("engine.buffers.video_num_buffers", pes_buffers); - - if(this->video_port_name) { - if(video_driver && !strcmp(video_driver, "fb")) - x_upd_str("video.device.fb_device", this->video_port_name); - } - - this->playback_finished = 0; - - /* create video port */ - if(video_driver && !strcmp(video_driver, "none")) - this->video_port = xine_open_video_driver(this->xine, - video_driver, - XINE_VISUAL_TYPE_NONE, - NULL); - else if(video_driver && !strcmp(video_driver, "dxr3")) - this->video_port = xine_open_video_driver(this->xine, - video_driver, - XINE_VISUAL_TYPE_X11, - NULL); - else if(video_driver && !strcmp(video_driver, "aadxr3")) - this->video_port = xine_open_video_driver(this->xine, - video_driver, - XINE_VISUAL_TYPE_AA, - NULL); - else - this->video_port = xine_open_video_driver(this->xine, - video_driver, - this->xine_visual_type, - (void *) &(this->vis)); - if(!this->video_port) { - LOGMSG("fe_xine_init: xine_open_video_driver(\"%s\") failed", - video_driver?video_driver:"(NULL)"); - xine_exit(this->xine); - return 0; - } - - intercept_video_driver(this->video_port); - - this->video_port_none = NULL; - - /* re-configure display size (DirectFB driver changes display mode in init) */ - if(this->update_display_size_cb) - this->update_display_size_cb(this); - - /* create audio port */ - - if(audio_driver && audio_port) - configure_audio_out(this, audio_driver, audio_port); - - if(audio_driver && !strcmp(audio_driver, "auto")) { - this->audio_port = xine_open_audio_driver (this->xine, NULL, NULL); -#if XINE_VERSION_CODE < 10190 - } else if(audio_driver && !strcmp(audio_driver, "none")) { - this->audio_port = _x_ao_new_port (this->xine, NULL, 1); - this->audio_port->set_property(this->audio_port, AO_PROP_DISCARD_BUFFERS, 1); -#endif - } else { - this->audio_port = xine_open_audio_driver (this->xine, audio_driver, NULL); - } - - if(!this->audio_port && (audio_driver && !!strcmp(audio_driver, "none"))) { - LOGMSG("fe_xine_init: xine_open_audio_driver(\"%s%s%s\") failed", - audio_driver?audio_driver:"(NULL)", - audio_port?":":"", audio_port?audio_port:""); - } - - this->audio_port_none = NULL; - - /* create stream */ - - this->stream = xine_stream_new(this->xine, this->audio_port, this->video_port); - this->slave_stream = NULL; - - if(!this->stream) { - LOGMSG("fe_xine_init: xine_stream_new failed"); - xine_exit(this->xine); - return 0; - } - - /* event handling */ - - this->event_queue = xine_event_new_queue (this->stream); - xine_event_create_listener_thread (this->event_queue, xine_event_cb, this); - - if(!this->event_queue) - LOGMSG("fe_xine_init: xine_event_new_queue failed"); - - /* misc. config */ - - this->pes_buffers = pes_buffers; - - posts = this->postplugins = calloc(1, sizeof(post_plugins_t)); - posts->xine = this->xine; - posts->audio_port = this->audio_port; - posts->video_port = this->video_port; - posts->video_source = posts->audio_source = this->stream; - - /* multithreaded decoding / post processing */ - - if(guess_cpu_count() > 1) { - if(!xine_check_version(1,1,9)) - LOGMSG("FFmpeg multithreaded video decoding is not supported in xine-lib < 1.1.9"); - else - LOGMSG("Enabling FFmpeg multithreaded video decoding"); - - /* try to enable anyway, maybe someone is using patched 1.1.8 ... */ - x_upd_num("video.processing.ffmpeg_thread_count", guess_cpu_count()); -#if 0 - LOGMSG("Enabling multithreaded post processing"); - vpplugin_parse_and_store_post(posts, "thread"); -#endif - } - - /* static post plugins from command-line */ - - if(static_post_plugins && *static_post_plugins) { - int i; - LOGDBG("static post plugins (from command line): %s", static_post_plugins); - posts->static_post_plugins = strdup(static_post_plugins); - vpplugin_parse_and_store_post(posts, posts->static_post_plugins); - applugin_parse_and_store_post(posts, posts->static_post_plugins); - - for(i=0; i<posts->post_audio_elements_num; i++) - if(posts->post_audio_elements[i]) - posts->post_audio_elements[i]->enable = 2; - for(i=0; i<posts->post_video_elements_num; i++) - if(posts->post_video_elements[i]) - posts->post_video_elements[i]->enable = 2; - posts->post_video_enable = 1; - posts->post_audio_enable = 1; - } - - this->video_width = this->video_height = 0; - - return 1; -} - -/* - * fe_xine_open - * - * open xine stream - */ - -static int fe_xine_open(frontend_t *this_gen, const char *mrl) -{ - fe_t *this = (fe_t*)this_gen; - int result = 0; - char *url = NULL; - - if(!this) - return 0; - - this->input_plugin = NULL; - this->playback_finished = 1; - this->terminate_key_pressed = 0; - - if (asprintf(&url, "%s#nocache", mrl ? : MRL_ID "://") < 0) - return 0; - - result = xine_open(this->stream, url); - - if(!result) { - LOGMSG("fe_xine_open: xine_open(\"%s\") failed", url); - free(url); - return 0; - } - free(url); - -#if 0 - this->xine->config->update_num(this->xine->config, - "video.output.xv_double_buffer", - 1); -#endif - x_upd_num("engine.buffers.video_num_buffers", this->pes_buffers); - - return result; -} - -/* - * post plugin handling - * - */ - -#define POST_AUDIO_VIS 0 -#define POST_AUDIO 1 -#define POST_VIDEO 2 -#define POST_VIDEO_PIP 3 - - -static void init_dummy_ports(fe_t *this, int on) -{ - if(!on) { - if(this->slave_stream) - LOGMSG("ERROR: init_dummy_ports(false) called while port is still in use !"); - - if(this->audio_port_none) - xine_close_audio_driver(this->xine, this->audio_port_none); - this->audio_port_none = NULL; - if(this->video_port_none) - xine_close_video_driver(this->xine, this->video_port_none); - this->video_port_none = NULL; - } else { - if(! this->audio_port_none) -#if XINE_VERSION_CODE < 10190 - this->audio_port_none = _x_ao_new_port (this->xine, NULL, 1); -#else - this->audio_port_none = NULL;/*xine_new_framegrab_audio_port(this->xine);*/ -#endif - if(this->audio_port_none) - this->audio_port_none->set_property(this->audio_port_none, AO_PROP_DISCARD_BUFFERS, 1); - /*LOGMSG("initialized dummy audio port %x", this->audio_port_none);*/ -#if 0 - if(! this->video_port_none) - this->video_port_none = - _x_vo_new_port(this->xine, - _x_load_video_output_plugin(this->xine, "none", - XINE_VISUAL_TYPE_NONE, NULL), - 1); - this->video_port_none->set_property(this->video_port_none, VO_PROP_DISCARD_FRAMES, 1); -#endif - } -} - -static void fe_post_unwire(fe_t *this) -{ - xine_post_out_t *vo_source = xine_get_video_source(this->stream); - xine_post_out_t *ao_source = xine_get_audio_source(this->stream); - - if(this->slave_stream && - this->slave_stream == this->postplugins->audio_source) { - LOGDBG("unwiring slave stream audio post plugins"); - init_dummy_ports(this, 1); - - if(ao_source && this->audio_port_none) - (void) xine_post_wire_audio_port(ao_source, this->audio_port_none); - - ao_source = xine_get_audio_source(this->slave_stream); - if(ao_source && this->audio_port) - (void) xine_post_wire_audio_port(ao_source, this->audio_port); - - } else { - LOGDBG("unwiring audio post plugins"); - init_dummy_ports(this, 0); - if(ao_source && this->audio_port) - (void) xine_post_wire_audio_port(ao_source, this->audio_port); - } - - if(this->slave_stream && - this->slave_stream == this->postplugins->video_source) { - LOGDBG("unwiring slave stream video post plugins"); - /*init_dummy_ports(this, 1);*/ - /*(void) xine_post_wire_video_port(vo_source, this->video_port_none);*/ - - vo_source = xine_get_video_source(this->slave_stream); - if(vo_source && this->video_port) - (void) xine_post_wire_video_port(vo_source, this->video_port); - - } else { - LOGDBG("unwiring video post plugins"); - /*init_dummy_ports(this, 0);*/ - if(vo_source && this->video_port) - (void) xine_post_wire_video_port(vo_source, this->video_port); - } -} - -static void fe_post_rewire(const fe_t *this) -{ - LOGDBG("re-wiring post plugins"); - vpplugin_rewire_posts(this->postplugins); - applugin_rewire_posts(this->postplugins); -} - -static void fe_post_unload(const fe_t *this) -{ - LOGDBG("unloading post plugins"); - vpplugin_unload_post(this->postplugins, NULL); - applugin_unload_post(this->postplugins, NULL); -} - -static void fe_post_close(const fe_t *this, const char *name, int which) -{ - post_plugins_t *posts = this->postplugins; - - if(!this) - return; - - if(name && !strcmp(name, "AudioVisualization")) { - name = NULL; - which = POST_AUDIO_VIS; - } - if(name && !strcmp(name, "Pip")) { - name = NULL; - which = POST_VIDEO_PIP; - } - - /* by name */ - if(name) { - LOGDBG("closing post plugin: %s", name); - if(applugin_unload_post(posts, name)) { - /*LOGDBG(" * rewiring audio");*/ - applugin_rewire_posts(posts); - return; - } - if(vpplugin_unload_post(posts, name)) { - /*LOGDBG(" * rewiring video");*/ - vpplugin_rewire_posts(posts); - return; - } - return; - } - - /* by type */ - if(which == POST_AUDIO_VIS || which < 0) { /* audio visualization */ - if(posts->post_vis_elements_num && - posts->post_vis_elements && - posts->post_vis_elements[0]) { - LOGDBG("Closing audio visualization post plugins"); - if(applugin_unload_post(posts, posts->post_vis_elements[0]->name)) { - /*LOGDBG(" * rewiring audio");*/ - applugin_rewire_posts(posts); - } - } - } - - if(which == POST_AUDIO || which < 0) { /* audio effect(s) */ - LOGDBG("Closing audio post plugins"); - if(applugin_disable_post(posts, NULL)) { - /*LOGDBG(" * rewiring audio");*/ - applugin_rewire_posts(posts); - } - } - if(which == POST_VIDEO || which < 0) { /* video effect(s) */ - LOGDBG("Closing video post plugins"); - if(vpplugin_unload_post(posts, NULL)) { - /*LOGDBG(" * rewiring video");*/ - vpplugin_rewire_posts(posts); - } - } - - if(which == POST_VIDEO_PIP || which < 0) { /* Picture-In-Picture */ - if(posts->post_pip_elements_num && - posts->post_pip_elements && - posts->post_pip_elements[0]) { - LOGDBG("Closing PIP (mosaico) post plugins"); - if(vpplugin_unload_post(posts, "mosaico")) { - /*LOGDBG(" * rewiring video");*/ - vpplugin_rewire_posts(posts); - } - } - } -} - -static int get_opt_val(const char *s, const char *opt) -{ - int val = -1; - const char *pt = strstr(s, opt); - if(pt) - if(1 == sscanf(pt+strlen(opt)+1, "%d", &val)) - return val; - return -1; -} - -static void fe_post_open(const fe_t *this, const char *name, const char *args) -{ - post_plugins_t *posts = this->postplugins; - char initstr[1024]; - int found = 0; - - if(!this || !this->xine || !this->stream || !name) - return; - - /* pip */ - if(!strcmp(name, "Pip")) { - posts->post_pip_enable = 1; - name = "mosaico"; - if(!posts->post_pip_elements || - !posts->post_vis_elements[0] || - !posts->post_vis_elements[0]->enable) - LOGMSG("enabling picture-in-picture (\"%s:%s\") post plugin", name, args); - } - - if(args) { - snprintf(initstr, sizeof(initstr), "%s:%s", name, args); - initstr[sizeof(initstr)-1] = 0; - } else - strn0cpy(initstr, name, sizeof(initstr)); - - /* swscale aspect ratio */ - if (!strcmp(name, "swscale")) { - char *pt = strstr(initstr, "output_aspect=auto"); - if (pt) { - char tmp[16]; - double r = 0.0; - pt += 14; - switch(this->aspect) { - case 0: - case 1: /* */ r = this->display_ratio * (double)this->width / (double)this->height; break; - case 2: /* 4:3 */ r = 4.0/3.0; break; - case 3: /* 16:9 */ r = 16.0/9.0; break; - case 4: /* 16:10 */ r = 16.0/10.0; break; - } - /* in finnish locale decimal separator is "," - same as post plugin parameter separator :( */ - sprintf(tmp, "%04d", (int)(r*1000.0)); - strncpy(pt, tmp, 4); - } - } - - LOGDBG("opening post plugin: %s", initstr); - - /* close old audio visualization plugin */ - if(!strcmp(name,"goom") || - !strcmp(name,"oscope") || - !strcmp(name,"fftscope") || - !strcmp(name,"fftgraph") || - !strcmp(name,"fooviz")) { - - /* close if changed */ - if(posts->post_vis_elements_num && - posts->post_vis_elements && - posts->post_vis_elements[0] && - strcmp(name, posts->post_vis_elements[0]->name)) { - - fe_post_close(this, NULL, POST_AUDIO_VIS); - } - - if(!found && applugin_enable_post(posts, initstr, &found)) { - posts->post_vis_enable = 1; - applugin_rewire_posts(posts); - - // goom wants options thru config ... - if(args && !strcmp(name,"goom")) { - int val; - if((val = get_opt_val(initstr, "fps")) > 0) - x_upd_num ("effects.goom.fps", val ); - if((val = get_opt_val(initstr, "width")) > 0) - x_upd_num ("effects.goom.width", val); - if((val = get_opt_val(initstr, "height")) > 0) - x_upd_num ("effects.goom.height", val); - //if((val = get_opt_val(initstr, "csc_method"))>0) - // this->xine->config->update_enum (this->xine->config, "effects.goom.csc_method", val); - } - } - - } else { - - /* video filters */ - if(strcmp(name, "audiochannel") && - strcmp(name, "volnorm") && - strcmp(name, "stretch") && - strcmp(name, "upmix_mono") && - strcmp(name, "upmix") && - vpplugin_enable_post(posts, initstr, &found)) { - - posts->post_video_enable = 1; - vpplugin_rewire_posts(posts); - } - - /* audio filters */ - if(!found && applugin_enable_post(posts, initstr, &found)) { - posts->post_audio_enable = 1; - applugin_rewire_posts(posts); - } - } - - if(!found) - LOGMSG("Can't load post plugin %s", name); - else - LOGDBG("Post plugin %s loaded and wired", name); -} - -static int fe_xine_play(frontend_t *this_gen) -{ - fe_t *this = (fe_t*)this_gen; - - if(!this) - return 0; - - fe_post_rewire(this); - - this->input_plugin = NULL; - this->playback_finished = xine_play(this->stream, 0, 0) ? 0 : 1; - - if(!find_input_plugin(this)) - return -1; - - this->input_plugin->f.xine_input_event = this->keypress; - this->input_plugin->f.fe_control = fe_control; - this->input_plugin->f.fe_handle = this_gen; - - if(this->playback_finished) - LOGMSG("Error playing " MRL_ID ":// !"); - - return !this->playback_finished; -} - -static int fe_xine_stop(frontend_t *this_gen) -{ - fe_t *this = (fe_t*)this_gen; - - if(!this) - return 0; - - this->input_plugin = NULL; - this->playback_finished = 1; - - xine_stop(this->stream); - - fe_post_unwire(this); - - return 1; -} - -static void fe_xine_close(frontend_t *this_gen) -{ - fe_t *this = (fe_t*)this_gen; - - if(!this) - return; - - if (this && this->xine) { - if(this->input_plugin) { - this->input_plugin->f.xine_input_event = NULL; - this->input_plugin->f.fe_control = NULL; - } - - fe_xine_stop(this_gen); - - fe_post_unload(this); - - xine_close(this->stream); - if(this->postplugins->pip_stream) - xine_close(this->postplugins->pip_stream); - } -} - -static void fe_xine_exit(frontend_t *this_gen) -{ - fe_t *this = (fe_t*)this_gen; - - if (this && this->xine) { - - if(this->input_plugin || !this->playback_finished) - fe_xine_close(this_gen); - fe_post_unload(this); - - if(this->configfile) { - xine_config_save (this->xine, this->configfile); - free(this->configfile); - this->configfile = NULL; - } - if(this->event_queue) - xine_event_dispose_queue(this->event_queue); - this->event_queue = NULL; - - if(this->stream) - xine_dispose(this->stream); - this->stream = NULL; - - if(this->postplugins->pip_stream) - xine_dispose(this->postplugins->pip_stream); - this->postplugins->pip_stream = NULL; - - if(this->slave_stream) - xine_dispose(this->slave_stream); - this->slave_stream = NULL; - - if(this->audio_port) - xine_close_audio_driver(this->xine, this->audio_port); - this->audio_port = NULL; - - init_dummy_ports(this, 0); - - if(this->video_port) - xine_close_video_driver(this->xine, this->video_port); - this->video_port = NULL; - - if(this->postplugins->static_post_plugins) - free(this->postplugins->static_post_plugins); - free(this->postplugins); - this->postplugins = NULL; - - xine_exit(this->xine); - this->xine = NULL; - } -} - -static void fe_free(frontend_t *this_gen) -{ - if (this_gen) { - fe_t *this = (fe_t*)this_gen; - this->fe.fe_display_close(this_gen); - free(this->configfile); - free(this); - } -} - -static int fe_is_finished(frontend_t *this_gen, int slave_stream) -{ - fe_t *this = (fe_t*)this_gen; - - if(!this || this->playback_finished) - return FE_XINE_ERROR; - if(this->terminate_key_pressed) - return FE_XINE_EXIT; - - if(slave_stream) { - if(!this->slave_stream || this->slave_playback_finished) - return FE_XINE_EXIT; - } - - return FE_XINE_RUNNING; -} - -/************************** hooks to input plugin ****************************/ - -/* - * data/control from VDR - */ - -static int xine_control(frontend_t *this_gen, const char *cmd) -{ - fe_t *this = (fe_t*)this_gen; - - if(!find_input_plugin(this)) - return -1; - - return this->input_plugin->f.push_input_control(this->input_plugin, cmd); -} - -static int xine_osd_command(frontend_t *this_gen, struct osd_command_s *cmd) { - fe_t *this = (fe_t*)this_gen; - - if(!find_input_plugin(this)) - return -1; - - return this->input_plugin->f.push_input_osd(this->input_plugin, cmd); -} - -static int xine_queue_pes_packet(frontend_t *this_gen, const char *data, int len) -{ - fe_t *this = (fe_t*)this_gen; - - if(!find_input_plugin(this)) - return 0/*-1*/; - - return this->input_plugin->f.push_input_write(this->input_plugin, data, len); -} - -/* - * control from frontend to xine/vdr - */ - - -static int fe_send_input_event(frontend_t *this_gen, const char *map, - const char *key, int repeat, int release) -{ - fe_t *this = (fe_t*)this_gen; - - LOGDBG("Keypress: %s %s %s %s", - map, key, repeat?"Repeat":"", release?"Release":""); - - /* local mode: --> vdr callback */ - if(this->keypress) { - this->keypress(map, key); - return FE_OK; - } - - /* remote mode: --> input plugin --> vdr */ - if (find_input_plugin(this)) { - if (this->input_plugin->f.post_vdr_event) { - char *msg = NULL; - if (map) { - if (asprintf(&msg, "KEY %s %s %s %s\r\n", map, key, - repeat?"Repeat":"", release?"Release":"") < 0) - msg = NULL; - } else { - if (asprintf(&msg, "KEY %s\r\n", key) < 0) - msg = NULL; - } - - if (msg) { - int r = this->input_plugin->f.post_vdr_event(this->input_plugin, msg); - free(msg); - if (r > 0) - return FE_OK; - } - LOGMSG("fe_send_input_event: message KEY %s lost", key); - return FE_ERROR; - } - } - - LOGMSG("fe_send_input_event: handler not set, event lost !"); - return FE_ERROR; -} - - -static int fe_send_event(frontend_t *this_gen, const char *data) -{ - fe_t *this = (fe_t*)this_gen; - - if (!data) - return FE_ERROR; - - if (!strcmp(data, "TOGGLE_FULLSCREEN")) { - if(this->toggle_fullscreen_cb) - this->toggle_fullscreen_cb(this); - - } else if (!strcmp(data, "QUIT")) { - this->terminate_key_pressed = 1; - - } else if(!strcmp(data, "TOGGLE_DEINTERLACE")) { - xine_set_param(this->stream, XINE_PARAM_VO_DEINTERLACE, - xine_get_param(this->stream, XINE_PARAM_VO_DEINTERLACE) ? 0 : 1); - - } else if(!strncasecmp(data, "DEINTERLACE ", 12)) { - xine_set_param(this->stream, XINE_PARAM_VO_DEINTERLACE, atoi(data+12) ? 1 : 0); - - } else { - return fe_send_input_event(this_gen, NULL, data, 0, 0); - } - - return FE_OK; -} - -/* - * Control messages from input plugin - */ -static void *fe_control(frontend_t *this_gen, const char *cmd) -{ - fe_t *this = (fe_t*)this_gen; - post_plugins_t *posts; - - /*LOGDBG("fe_control(\"%s\")", cmd);*/ - - if(!cmd || !this) { - LOGMSG("fe_control(0x%lx,0x%lx) : invalid argument", - (unsigned long int)this_gen, (unsigned long int)cmd); - return NULL; - } - - posts = this->postplugins; - - if(!posts) { - LOGMSG("fe_control : this->posts == NULL"); - return NULL; - } - - if(!strncmp(cmd, "SLAVE CLOSED", 16)) { - /*LOGMSG("fe_control : slave closed");*/ - if(this->slave_stream) - fe_control(this_gen, "SLAVE 0x0\r\n"); - init_dummy_ports(this, 0); - - } else if(!strncmp(cmd, "SLAVE 0x", 8)) { - unsigned long pt; - if(1 == sscanf(cmd+8, "%lx", &pt)) { - xine_stream_t *slave_stream = (xine_stream_t*)pt; - if(this->slave_stream != slave_stream) { - - fe_post_unwire(this); - - if(this->slave_stream) { - /*xine_post_out_t *vo_source = xine_get_video_source(posts->slave_stream);*/ - if(this->slave_stream == this->postplugins->audio_source) { - xine_post_out_t *ao_source = xine_get_audio_source(this->slave_stream); - LOGMSG("unwiring slave stream from output"); - /*(void) xine_post_wire_video_port(vo_source, this->video_port_none);*/ - (void) xine_post_wire_audio_port(ao_source, this->audio_port_none); - } - } - - this->slave_stream = slave_stream; - - this->postplugins->video_source = this->postplugins->audio_source = - this->slave_stream ?: this->stream; - if(strstr(cmd, "Video")) /* video only, audio from VDR */ - this->postplugins->audio_source = this->stream; - if(strstr(cmd, "Audio")) /* audio only, video from VDR */ - this->postplugins->video_source = this->stream; - - if(this->slave_stream) - fe_post_unwire(this); - - fe_post_rewire(this); - } - this->slave_playback_finished = !slave_stream; - } - - } else if(!strncmp(cmd, "ENDOFSTREAM", 11)) { - if(this->slave_stream) - this->slave_playback_finished = 1; - - } else if(!strncmp(cmd, "SUBSTREAM ", 10)) { - unsigned int pid; - int x, y, w, h; - if(5 == sscanf(cmd+10, "0x%x %d %d %d %d", &pid, &x, &y, &w, &h)) { - char mrl[256]; - if(!posts->pip_stream) - posts->pip_stream = xine_stream_new(this->xine, - this->audio_port, - this->video_port); - LOGMSG(" PIP %d: %dx%d @ (%d,%d)", pid & 0x0f, w, h, x, y); - LOGMSG("create pip stream done"); - sprintf(mrl, MRL_ID "+slave://0x%lx#nocache", - (unsigned long int)this); - if(!xine_open(posts->pip_stream, mrl) || - !xine_play(posts->pip_stream, 0, 0)) { - LOGERR(" pip stream open/play failed"); - } else { - char params[64]; - sprintf(params, "pip_num=1,x=%d,y=%d,w=%d,h=%d", x,y,w,h); - fe_post_open(this, "Pip", params); - return posts->pip_stream; - } - } - fe_post_close(this, NULL, POST_VIDEO_PIP); - if(posts->pip_stream) { - xine_close(posts->pip_stream); - xine_dispose(posts->pip_stream); - posts->pip_stream = NULL; - } - return NULL; - - } else if(!strncmp(cmd, "POST ", 5)) { - char *name = strdup(cmd+5), *args = name, *pt; - - if(NULL != (pt=strchr(name, '\r'))) - *pt = 0; - if(NULL != (pt=strchr(name, '\n'))) - *pt = 0; - - while(*args && *args != ' ') /* skip name */ - args++; - if(*args /*== ' '*/) - *args++ = 0; - - while(*args && *args == ' ') /* skip whitespace between name and args */ - args++; - - /*this->stream->xine->port_ticket->acquire(this->stream->xine->port_ticket, 0);*/ - /* - locks local frontend at startup */ - if(!strncmp(args, "On", 2)) { - args += 2; - while(*args == ' ') - args++; - /*LOGDBG(" POST: %s On \"%s\"", name, args);*/ - fe_post_open(this, name, args); - } else if(!strncmp(args, "Off", 3)) { - /*LOGDBG(" POST: %s Off (name len=%d), name => int = %d", name, strlen(name), atoi(name));*/ - if(strlen(name) == 1) - fe_post_close(this, NULL, atoi(name)); - else - fe_post_close(this, name, -1); - } else { - LOGMSG("fe_control: POST: unknown command %s", cmd); - } - /*this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 0);*/ - /* - locks local frontend at startup */ - free(name); - return NULL; - - } else if(!strncmp(cmd, "GRAB ", 5)) { - int quality, width, height, jpeg, size=0; - jpeg = !strncmp(cmd+5,"JPEG",4); - if(3 == sscanf(cmd+5+4, "%d %d %d", &quality, &width, &height)) { - grab_data_t *result = (grab_data_t*)malloc(sizeof(grab_data_t)); - result->data = this->fe.grab((frontend_t*)this, &size, - jpeg, quality, width, height); - if(result->data && (result->size=size)>0) - return result; - free(result->data); - free(result); - } - - } else if(!strncmp(cmd, "OVERSCAN ", 9)) { - int overscan; - if(1 == sscanf(cmd+9, "%d", &overscan)) { - int crop_x = overscan * this->width / 100 / 2; - int crop_y = overscan * this->height / 100 / 2; - this->overscan = overscan; - xine_set_param(this->stream, XINE_PARAM_VO_CROP_LEFT, crop_x); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_TOP, crop_y); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_RIGHT, crop_x); - xine_set_param(this->stream, XINE_PARAM_VO_CROP_BOTTOM, crop_y); - /* trigger forced redraw to make changes effective */ - xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, 100); - } - } - - - return NULL; -} - -/* - * --- RgbToJpeg ------------------------------------------------------------- - * - * source: vdr-1.3.42, tools.c - * modified to accept YUV data - * - * - move to xine_input_vdr ? - */ - -#ifdef HAVE_LIBJPEG - -#define JPEGCOMPRESSMEM 500000 - -typedef struct tJpegCompressData_s { - int size; - unsigned char *mem; -} tJpegCompressData; - -static void JpegCompressInitDestination(const j_compress_ptr cinfo) -{ - tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; - if (jcd) { - cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM; - cinfo->dest->next_output_byte = jcd->mem = - (unsigned char *)malloc(jcd->size); - } -} - -static boolean JpegCompressEmptyOutputBuffer(const j_compress_ptr cinfo) -{ - tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; - if (jcd) { - int Used = jcd->size; - jcd->size += JPEGCOMPRESSMEM; - jcd->mem = (unsigned char *)realloc(jcd->mem, jcd->size); - if (jcd->mem) { - cinfo->dest->next_output_byte = jcd->mem + Used; - cinfo->dest->free_in_buffer = jcd->size - Used; - return TRUE; - } - } - return FALSE; -} - -static void JpegCompressTermDestination(const j_compress_ptr cinfo) -{ - tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; - if (jcd) { - int Used = cinfo->dest->next_output_byte - jcd->mem; - if (Used < jcd->size) { - jcd->size = Used; - jcd->mem = (unsigned char *)realloc(jcd->mem, jcd->size); - } - } -} - -static vo_frame_t *yuy2_to_yv12_frame(xine_stream_t *stream, vo_frame_t *frame) -{ - /* convert yuy12 frames to yv12 */ - if (frame->format == XINE_IMGFMT_YUY2) { - stream->xine->port_ticket->acquire(stream->xine->port_ticket, 0); - vo_frame_t *img = stream->video_out->get_frame (stream->video_out, - frame->width, frame->height, - frame->ratio, XINE_IMGFMT_YV12, - VO_BOTH_FIELDS); - stream->xine->port_ticket->release(stream->xine->port_ticket, 0); - - if (!img) { - LOGMSG("yuy2_to_yv12_frame: get_frame failed"); - frame->free(frame); - return NULL; - } - - init_yuv_conversion(); - yuy2_to_yv12(frame->base[0], frame->pitches[0], - img->base[0], img->pitches[0], - img->base[1], img->pitches[1], - img->base[2], img->pitches[2], - frame->width, frame->height); - - frame->free(frame); - return img; - } - - return frame; -} - -static char *frame_compress_jpeg(fe_t *this, int *size, int quality, vo_frame_t *frame) -{ - struct jpeg_destination_mgr jdm; - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - tJpegCompressData jcd; - - /* convert yuy2 frames to yv12 */ - frame = yuy2_to_yv12_frame(this->stream, frame); - - /* Compress JPEG */ - - jdm.init_destination = JpegCompressInitDestination; - jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer; - jdm.term_destination = JpegCompressTermDestination; - - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - cinfo.dest = &jdm; - - cinfo.client_data = &jcd; - cinfo.image_width = frame->width; - cinfo.image_height = frame->height; - - cinfo.input_components = 3; - cinfo.in_color_space = JCS_YCbCr; - - switch (frame->format) { - case XINE_IMGFMT_YV12: { - JSAMPARRAY pp[3]; - JSAMPROW *rpY = (JSAMPROW*)malloc(sizeof(JSAMPROW) * frame->height); - JSAMPROW *rpU = (JSAMPROW*)malloc(sizeof(JSAMPROW) * frame->height); - JSAMPROW *rpV = (JSAMPROW*)malloc(sizeof(JSAMPROW) * frame->height); - int k; - - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, quality, TRUE); - cinfo.raw_data_in = TRUE; - - jpeg_set_colorspace(&cinfo, JCS_YCbCr); - cinfo.comp_info[0].h_samp_factor = - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = - cinfo.comp_info[1].v_samp_factor = - cinfo.comp_info[2].h_samp_factor = - cinfo.comp_info[2].v_samp_factor = 1; - jpeg_start_compress(&cinfo, TRUE); - - for (k = 0; k < frame->height; k+=2) { - rpY[k] = frame->base[0] + k*frame->pitches[0]; - rpY[k+1] = frame->base[0] + (k+1)*frame->pitches[0]; - rpU[k/2] = frame->base[1] + (k/2)*frame->pitches[1]; - rpV[k/2] = frame->base[2] + (k/2)*frame->pitches[2]; - } - for (k = 0; k < frame->height; k+=2*DCTSIZE) { - pp[0] = &rpY[k]; - pp[1] = &rpU[k/2]; - pp[2] = &rpV[k/2]; - jpeg_write_raw_data(&cinfo, pp, 2*DCTSIZE); - } - free(rpY); - free(rpU); - free(rpV); - break; - } -#if 0 - case XINE_IMGFMT_RGB: { - JSAMPROW rp[height]; - int rs, k; - - cinfo.in_color_space = JCS_RGB; - - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, quality, TRUE); - jpeg_start_compress(&cinfo, TRUE); - - rs = frame->pitches[0]; - for (k = 0; k < height; k++) - rp[k] = frame->base[0] + k*rs; - jpeg_write_scanlines(&cinfo, rp, height); - break; - } -#endif - default: - LOGMSG("fe_grab: grabbing failed (unsupported image format %d)", - frame->format); - break; - } - - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - frame->free(frame); - - *size = jcd.size; - return (char*) jcd.mem; -} - -#endif /* HAVE_LIBJPEG */ - -static vo_frame_t *yv12_to_yuy2_frame(xine_stream_t *stream, vo_frame_t *frame) -{ - /* convert yv12 frames to yuy2 */ - if (frame->format == XINE_IMGFMT_YV12) { - stream->xine->port_ticket->acquire(stream->xine->port_ticket, 0); - vo_frame_t *img = stream->video_out->get_frame (stream->video_out, - frame->width, frame->height, - frame->ratio, XINE_IMGFMT_YUY2, - VO_BOTH_FIELDS); - stream->xine->port_ticket->release(stream->xine->port_ticket, 0); - - if (!img) { - LOGMSG("yv12_to_yuy2_frame: get_frame failed"); - frame->free(frame); - return NULL; - } - - init_yuv_conversion(); - yv12_to_yuy2(frame->base[0], frame->pitches[0], - frame->base[1], frame->pitches[1], - frame->base[2], frame->pitches[2], - img->base[0], img->pitches[0], - frame->width, frame->height, - frame->progressive_frame); - - frame->free(frame); - return img; - } - - return frame; -} - -#define YCBCR_TO_RGB( y, cb, cr, r, g, b ) \ - do { \ - int _y, _cb, _cr, _r, _g, _b; \ - _y = ((y) - 16) * 76309; \ - _cb = (cb) - 128; \ - _cr = (cr) - 128; \ - _r = (_y + _cr * 104597 + 0x8000) >> 16; \ - _g = (_y - _cb * 25675 - _cr * 53279 + 0x8000) >> 16; \ - _b = (_y + _cb * 132201 + 0x8000) >> 16; \ - (r) = (_r < 0) ? 0 : ((_r > 255) ? 255 : _r); \ - (g) = (_g < 0) ? 0 : ((_g > 255) ? 255 : _g); \ - (b) = (_b < 0) ? 0 : ((_b > 255) ? 255 : _b); \ -} while (0) - -static char *frame_compress_pnm(fe_t *this, int *size, vo_frame_t *frame) -{ - /* ensure yuy2 */ - if (!(frame = yv12_to_yuy2_frame(this->stream, frame))) - return NULL; - - /* convert to PNM */ - - /* allocate memory for result */ - size_t bytes = frame->width * frame->height * 3; - uint8_t *pnm = malloc(bytes + 64); - if (!pnm) { - LOGMSG("fe_grab: malloc failed"); - return NULL; - } - - /* PNM header */ - sprintf((char*)pnm, "P6\n%d\n%d\n255\n", frame->width, frame->height); - int hdrlen = strlen((char*)pnm); - uint8_t *p = pnm + hdrlen; - uint8_t *s = frame->base[0]; - int x, y; - - *size = bytes + hdrlen; - - /* convert to RGB */ - for (y=0; y < frame->height; y++) { - for (x=0; x < frame->width; x+=2, s+=4, p+=6) { - YCBCR_TO_RGB(s[0], s[1], s[3], p[0], p[1], p[2]); - YCBCR_TO_RGB(s[2], s[1], s[3], p[3], p[4], p[5]); - } - s = frame->base[0] + y*frame->pitches[0]; - } - - return (char*)pnm; -} - -static char *fe_grab(frontend_t *this_gen, int *size, int jpeg, - int quality, int width, int height) -{ - fe_t *this = (fe_t*)this_gen; - vo_frame_t *frame; - -#ifndef HAVE_LIBJPEG - if(jpeg) { - LOGMSG("fe_grab: JPEG grab support was not compiled in"); - return 0; - } -#endif /* HAVE_LIBJPEG */ - - if(!find_input_plugin(this)) - return 0; - - LOGDBG("fe_grab: grabbing %s %d %dx%d", - jpeg ? "JPEG" : "PNM", quality, width, height); - - /* validate parameters */ - if ((quality < 0) || (quality > 100)) - quality = 100; - width = (MIN(16, MAX(width, 1920)) + 1) & ~1; /* 16...1920, even */ - height = (MIN(16, MAX(width, 1200)) + 1) & ~1; /* 16...1200, even */ - - /* get last frame */ - this->stream->xine->port_ticket->acquire(this->stream->xine->port_ticket, 0); - frame = this->stream->video_out->get_last_frame (this->stream->video_out); - if(frame) - frame->lock(frame); - this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 0); - - if(!frame) { - LOGMSG("fe_grab: get_last_frame() failed"); - return NULL; - } - - /* Scale image */ - if (frame->width != width || frame->height != height) { - /* #warning TODO - scaling here */ - } - - if (!jpeg) - return frame_compress_pnm(this, size, frame); - -#ifdef HAVE_LIBJPEG - return frame_compress_jpeg(this, size, quality, frame); -#else /* HAVE_LIBJPEG */ - return NULL; -#endif -} - -/* - * init_fe() - * - * initialize function pointers - */ -void init_fe(fe_t *fe) -{ - fe->fe.xine_init = fe_xine_init; - fe->fe.xine_open = fe_xine_open; - fe->fe.xine_play = fe_xine_play; - fe->fe.xine_stop = fe_xine_stop; - fe->fe.xine_close = fe_xine_close; - fe->fe.xine_exit = fe_xine_exit; - - fe->fe.fe_free = fe_free; - - fe->fe.xine_is_finished = fe_is_finished; - - fe->fe.xine_osd_command = xine_osd_command; - fe->fe.xine_control = xine_control; - fe->fe.xine_queue_pes_packet = xine_queue_pes_packet; - - fe->fe.grab = fe_grab; - - fe->fe.send_event = fe_send_event; - fe->fe.send_input_event = fe_send_input_event; - - fe->dest_pixel_aspect = fe_dest_pixel_aspect; - fe->frame_output_handler = fe_frame_output_cb; -} - diff --git a/xine_frontend.h b/xine_frontend.h deleted file mode 100644 index f588dc04..00000000 --- a/xine_frontend.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * xine_frontend.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_frontend.h,v 1.19 2009-05-31 16:51:25 phintuka Exp $ - * - */ - -#ifndef _XINE_FRONTEND_H -#define _XINE_FRONTEND_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define FE_VERSION_STR XINELIBOUTPUT_VERSION /*"1.0.0pre1"*/ - -typedef void (*fe_keypress_f)(const char *keymap, const char *name); - -typedef struct frontend_config_s frontend_config_t; -typedef struct frontend_s frontend_t; - -struct osd_command_s; - -#if 0 -struct frontend_config_s { - /* Display */ - int width; - int height; - int fullscreen; - int modeswitch; - char *modeline; - int aspect; - - char *video_port; - - int scale_video; - int field_order; - - fe_keypress_f keypresshandler; - - /* Xine engine */ - char *audio_driver; - char *audio_port; - char *video_driver; - int pes_buffers; - int priority; -}; -#endif - -/* xine_is_finished return values */ -#define FE_XINE_RUNNING 0 -#define FE_XINE_ERROR -1 -#define FE_XINE_EXIT 1 - -/* return values */ -#define FE_OK 1 -#define FE_ERROR 0 - -struct frontend_s { - /* Display */ - int (*fe_display_open)(frontend_t*, - int xpos, int ypos, - int winwidth, int winheight, - int fullscreen, int hud, int modeswitch, const char *modeline, - int aspect, fe_keypress_f keypresshandler, - int no_x_kbd, int gui_hotkeys, - const char *video_port, - int scale_video, int field_order, - const char *aspect_controller, int window_id); - int (*fe_display_config)(frontend_t *, - int xpos, int ypos, - int width, int height, - int fullscreen, - int modeswitch, const char *modeline, - int aspect, int scale_video, int field_order); - void (*fe_display_close)(frontend_t*); - - /* Xine engine */ - int (*xine_init)(frontend_t*, - const char *audio_driver, - const char *audio_port, - const char *video_driver, - int pes_buffers, - const char *static_post, - const char *config_file); - int (*xine_open)(frontend_t*, const char *mrl); - int (*xine_play)(frontend_t*); - int (*xine_stop)(frontend_t*); - void (*xine_close)(frontend_t*); - void (*xine_exit)(frontend_t*); - - /* Execution control */ - int (*fe_run)(frontend_t*); - void (*fe_interrupt)(frontend_t*); - void (*fe_free)(frontend_t*); - - int (*xine_is_finished)(frontend_t*, int slave_stream); - - /* Data transfer VDR -> frontend/xine */ - int (*xine_osd_command)(frontend_t*, struct osd_command_s *cmd); - int (*xine_control)(frontend_t*, const char *cmd); - int (*xine_queue_pes_packet)(frontend_t*, const char *data, int len); - - char *(*grab)(frontend_t*, int *size, int jpeg, int quality, - int width, int height); - - /* events from frontend -> xine/vdr */ - int (*send_event)(frontend_t *fe, const char *data); - int (*send_input_event)(frontend_t *fe, - const char *map, const char *key, - int repeat, int release); -#if 0 - frontend_config_t config; -#endif -}; - -typedef frontend_t *(*fe_creator_f)(void); - -void list_xine_plugins(frontend_t *fe, int verbose); - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - -#endif /* _XINE_FRONTEND_H */ - diff --git a/xine_frontend_internal.h b/xine_frontend_internal.h deleted file mode 100644 index 7409c867..00000000 --- a/xine_frontend_internal.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * xine_frontend_internal.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_frontend_internal.h,v 1.5 2008-11-14 23:31:37 phintuka Exp $ - * - */ - -#ifndef XINE_FRONTEND_INTERNAL_H -#define XINE_FRONTEND_INTERNAL_H - -#include <xine.h> -#include <xine/input_plugin.h> - -#include "xine_frontend.h" -#include "xine_input_vdr.h" -#include "xine/post.h" - -typedef struct fe_s { - /* base class */ - frontend_t fe; - - /* from xine_frontend.c */ - double (*dest_pixel_aspect) (const struct fe_s *, - double video_pixel_aspect, - int video_width, int video_height); - void (*frame_output_handler)(void *data, - int video_width, int video_height, - double video_pixel_aspect, - int *dest_x, int *dest_y, - int *dest_width, int *dest_height, - double *dest_pixel_aspect, - int *win_x, int *win_y); - - /* called from xine_frontend.c */ - void (*update_display_size_cb) (struct fe_s *); - void (*toggle_fullscreen_cb) (struct fe_s *); - - /* vdr callbacks */ - fe_keypress_f keypress; - - /* xine stuff */ - xine_t *xine; - xine_stream_t *stream; - xine_stream_t *slave_stream; - vdr_input_plugin_if_t *input_plugin; - xine_video_port_t *video_port; - xine_video_port_t *video_port_none; - xine_audio_port_t *audio_port; - xine_audio_port_t *audio_port_none; - xine_event_queue_t *event_queue; - - post_plugins_t *postplugins; - char *video_port_name; /* frame buffer device */ - char *aspect_controller; /* path to external HW aspect ratio controller */ - char *configfile; /* path of our config file */ - - int xine_visual_type; - union { - void *vis; - fb_visual_t vis_fb; - x11_visual_t vis_x11; - }; - - /* frontend */ - double video_aspect; /* aspect ratio of video frame */ - double display_ratio; /* aspect ratio of video window */ - uint terminate_key_pressed; - uint16_t xpos, ypos; /* position of video window */ - uint16_t width; /* size of video window */ - uint16_t height; /* */ - uint16_t video_width; /* size of video frame */ - uint16_t video_height; /* */ - uint16_t pes_buffers; /* max. number of PES packets in video fifo */ - uint8_t aspect; /* aspect ratio of video window (user setting) */ - uint8_t overscan; /* overscan in % (crop video borders) */ -/*uint8_t cropping : 1;*/ - uint8_t scale_video : 1; /* enable/disable all video scaling */ - uint8_t field_order : 1; /* invert top/bottom field order */ - uint8_t playback_finished : 1; - uint8_t slave_playback_finished : 1; - -} fe_t; - -/* setup function pointers */ -void init_fe(fe_t *fe); - -char *strn0cpy(char *dest, const char *src, int n); - -#endif /* XINE_FRONTEND_INTERNAL_H */ diff --git a/xine_frontend_lirc.c b/xine_frontend_lirc.c deleted file mode 100644 index 9b08da83..00000000 --- a/xine_frontend_lirc.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * xine_frontend_lirc.c: Forward (local) lirc keys to VDR (server) - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_frontend_lirc.c,v 1.21 2008-11-19 18:55:20 rofafor Exp $ - * - */ -/* - * - * Almost directly copied from vdr-1.4.3-2 (lirc.c : cLircRemote) - * - */ -/* - * lirc.c: LIRC remote control - * - * See the main source file 'vdr.c' for copyright information and - * how to reach the author. - * - * LIRC support added by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16. - * - */ - - -#include <stdint.h> -#include <stdio.h> -#include <unistd.h> -#include <pthread.h> -#include <netinet/in.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/un.h> - -#define LOG_MODULENAME "[lirc] " -#include "logdefs.h" - -#include "xine_frontend.h" -#include "xine_frontend_lirc.h" - - -#define REPEATDELAY 350 /* ms */ -#define REPEATFREQ 100 /* ms */ -#define REPEATTIMEOUT 500 /* ms */ -#define RECONNECTDELAY 3000 /* ms */ - -#define LIRC_KEY_BUF 30 -#define LIRC_BUFFER_SIZE 128 -#define MIN_LIRCD_CMD_LEN 5 - -/* static data */ -static pthread_t lirc_thread; -static volatile char *lirc_device_name = NULL; -static volatile int fd_lirc = -1; -static int lirc_repeat_emu = 0; - -/* xine_frontend_main.c: */ -extern int gui_hotkeys; - -static uint64_t time_ms() -{ - struct timeval t; - if (gettimeofday(&t, NULL) == 0) - return ((uint64_t)t.tv_sec) * 1000ULL + t.tv_usec / 1000ULL; - return 0; -} - -static uint64_t elapsed(uint64_t t) -{ - return time_ms() - t; -} - -static void lircd_connect(void) -{ - struct sockaddr_un addr; - - if(fd_lirc >= 0) { - close(fd_lirc); - fd_lirc = -1; - } - - if(!lirc_device_name) { - LOGDBG("no lirc device given"); - return; - } - - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, (char*)lirc_device_name, sizeof(addr.sun_path)); - addr.sun_path[sizeof(addr.sun_path)-1] = 0; - - if ((fd_lirc = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - LOGERR("lirc error: socket() < 0"); - return; - } - - if (connect(fd_lirc, (struct sockaddr *)&addr, sizeof(addr))) { - LOGERR("lirc error: connect(%s) < 0", lirc_device_name); - close(fd_lirc); - fd_lirc = -1; - return; - } -} - -static void *lirc_receiver_thread(void *fe_gen) -{ - frontend_t *fe = (frontend_t*)fe_gen; - int timeout = -1; - uint64_t FirstTime = time_ms(); - uint64_t LastTime = time_ms(); - char buf[LIRC_BUFFER_SIZE]; - char LastKeyName[LIRC_KEY_BUF] = ""; - int repeat = 0; - - LOGMSG("lirc forwarding started"); - - const int priority = -1; - errno = 0; - if((nice(priority) == -1) && errno) - LOGDBG("LIRC: Can't nice to value: %d", priority); - - lircd_connect(); - - while(lirc_device_name && fd_lirc >= 0) { - fd_set set; - int ready, ret = -1; - FD_ZERO(&set); - FD_SET(fd_lirc, &set); - - pthread_testcancel(); - if (timeout >= 0) { - struct timeval tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - ready = select(FD_SETSIZE, &set, NULL, NULL, &tv) > 0 && FD_ISSET(fd_lirc, &set); - } else { - ready = select(FD_SETSIZE, &set, NULL, NULL, NULL) > 0 && FD_ISSET(fd_lirc, &set); - } - - pthread_testcancel(); - if(ready < 0) { - LOGMSG("LIRC connection lost ?"); - break; - } - - if(ready) { - - do { - errno = 0; - ret = read(fd_lirc, buf, sizeof(buf)); - pthread_testcancel(); - } while(ret < 0 && errno == EINTR); - - if (ret <= 0 ) { - /* try reconnecting */ - LOGERR("LIRC connection lost"); - lircd_connect(); - while(lirc_device_name && fd_lirc < 0) { - pthread_testcancel(); - sleep(RECONNECTDELAY/1000); - lircd_connect(); - } - if(fd_lirc >= 0) - LOGMSG("LIRC reconnected"); - continue; - } - - if (ret >= MIN_LIRCD_CMD_LEN) { - unsigned int count; - char KeyName[LIRC_KEY_BUF]; - LOGDBG("LIRC: %s", buf); - - if (sscanf(buf, "%*x %x %29s", &count, KeyName) != 2) { - /* '29' in '%29s' is LIRC_KEY_BUF-1! */ - LOGMSG("unparseable lirc command: %s", buf); - continue; - } - - if(lirc_repeat_emu) - if (strcmp(KeyName, LastKeyName) == 0 && elapsed(LastTime) < REPEATDELAY) - count = repeat + 1; - - if (count == 0) { - if (strcmp(KeyName, LastKeyName) == 0 && elapsed(FirstTime) < REPEATDELAY) - continue; /* skip keys coming in too fast */ - if (repeat) { - alarm(3); - fe->send_input_event(fe, "LIRC", LastKeyName, 0, 1); - alarm(0); - } - - strcpy(LastKeyName, KeyName); - repeat = 0; - FirstTime = time_ms(); - timeout = -1; - } - else { - if (elapsed(LastTime) < REPEATFREQ) - continue; /* repeat function kicks in after a short delay */ - - if (elapsed(FirstTime) < REPEATDELAY) { - if(lirc_repeat_emu) - LastTime = time_ms(); - continue; /* skip keys coming in too fast */ - } - repeat = 1; - timeout = REPEATDELAY; - } - LastTime = time_ms(); - - if (gui_hotkeys) { - if(!strcmp(KeyName, "Quit")) { - fe->send_event(fe, "QUIT"); - break; - } - if(!strcmp(KeyName, "Fullscreen")) { - if(!repeat) - fe->send_event(fe, "TOGGLE_FULLSCREEN"); - continue; - } - if(!strcmp(KeyName, "Deinterlace")) { - if(!repeat) - fe->send_event(fe, "TOGGLE_DEINTERLACE"); - continue; - } - } - - alarm(3); - fe->send_input_event(fe, "LIRC", KeyName, repeat, 0); - alarm(0); - - } - else if (repeat) { /* the last one was a repeat, so let's generate a release */ - if (elapsed(LastTime) >= REPEATTIMEOUT) { - alarm(3); - fe->send_input_event(fe, "LIRC", LastKeyName, 0, 1); - alarm(0); - repeat = 0; - *LastKeyName = 0; - timeout = -1; - } - } - - } - } - - - if(fd_lirc >= 0) - close(fd_lirc); - fd_lirc = -1; - pthread_exit(NULL); - return NULL; /* never reached */ -} - -void lirc_start(struct frontend_s *fe, char *lirc_dev, int repeat_emu) -{ - if(lirc_dev) { - int err; - lirc_device_name = lirc_dev; - lirc_repeat_emu = repeat_emu; - if ((err = pthread_create (&lirc_thread, - NULL, lirc_receiver_thread, - (void*)fe)) != 0) { - fprintf(stderr, "can't create new thread for lirc (%s)\n", - strerror(err)); - } - } -} - -void lirc_stop(void) -{ - if(lirc_device_name) { - void *p; - /*free(lirc_device_name);*/ - lirc_device_name = NULL; - if(fd_lirc >= 0) - close(fd_lirc); - fd_lirc = -1; - pthread_cancel (lirc_thread); - pthread_join (lirc_thread, &p); - } -} diff --git a/xine_frontend_lirc.h b/xine_frontend_lirc.h deleted file mode 100644 index df3972a6..00000000 --- a/xine_frontend_lirc.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * xine_frontend_lirc.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_frontend_lirc.h,v 1.3 2008-11-13 22:58:40 phintuka Exp $ - * - */ - -#ifndef XINE_FRONTEND_LIRC_H -#define XINE_FRONTEND_LIRC_H - -struct frontend_s; - -void lirc_start(struct frontend_s *fe, char *lirc_dev, int repeat_emu); -void lirc_stop(void); - -#endif /* XINE_FRONTEND_LIRC_H */ diff --git a/xine_frontend_main.c b/xine_frontend_main.c deleted file mode 100644 index 8c8fa81a..00000000 --- a/xine_frontend_main.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Simple main() routine for stand-alone frontends. - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_frontend_main.c,v 1.76 2009-05-31 18:53:32 phintuka Exp $ - * - */ - -#include "features.h" - -#include <stdio.h> -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> -#include <poll.h> -#include <errno.h> -#include <termios.h> -#include <pthread.h> -#include <unistd.h> -#include <syslog.h> -#include <getopt.h> -#include <signal.h> - -#include <xine.h> /* xine_get_version */ - -#define LOG_MODULENAME "[vdr-fe] " -#include "logdefs.h" - -#include "xine_input_vdr_mrl.h" -#include "xine_frontend.h" -#include "tools/vdrdiscovery.h" -#include "xine_frontend_lirc.h" - -/* static data */ - -/* next symbol is dynamically linked from input plugin */ -int SysLogLevel __attribute__((visibility("default"))) = SYSLOGLEVEL_INFO; /* errors and info, no debug */ - -volatile int last_signal = 0; -int gui_hotkeys = 0; - -/* - * stdin (keyboard/slave mode) reading - */ - -/* static data */ -pthread_t kbd_thread; -struct termios tm, saved_tm; - -/* - * read_key() - * - * Try to read single char from stdin. - * - * Returns: >=0 char readed - * -1 nothing to read - * -2 fatal error - */ -#define READ_KEY_ERROR -2 -#define READ_KEY_EAGAIN -1 -static int read_key(void) -{ - unsigned char ch; - int err; - struct pollfd pfd; - pfd.fd = STDIN_FILENO; - pfd.events = POLLIN; - - errno = 0; - pthread_testcancel(); - - if (1 == (err = poll(&pfd, 1, 50))) { - pthread_testcancel(); - - if (1 == (err = read(STDIN_FILENO, &ch, 1))) - return (int)ch; - - if (err < 0) - LOGERR("read_key: read(stdin) failed"); - else - LOGERR("read_key: read(stdin) failed: no stdin"); - return READ_KEY_ERROR; - - } else if (err < 0 && errno != EINTR) { - LOGERR("read_key: poll(stdin) failed"); - return READ_KEY_ERROR; - } - - pthread_testcancel(); - return READ_KEY_EAGAIN; -} - -/* - * read_key_seq() - * - * Read a key sequence from stdin. - * Key sequence is either normal key or escape sequence. - * - * Returns the key or escape sequence as uint64_t. - */ -#define READ_KEY_SEQ_ERROR 0xffffffff -static uint64_t read_key_seq(void) -{ - /* from vdr, remote.c */ - uint64_t k = 0; - int key1; - - if ((key1 = read_key()) >= 0) { - k = key1; - if (key1 == 0x1B) { - /* Start of escape sequence */ - if ((key1 = read_key()) >= 0) { - k <<= 8; - k |= key1 & 0xFF; - switch (key1) { - case 0x4F: /* 3-byte sequence */ - if ((key1 = read_key()) >= 0) { - k <<= 8; - k |= key1 & 0xFF; - } - break; - case 0x5B: /* 3- or more-byte sequence */ - if ((key1 = read_key()) >= 0) { - k <<= 8; - k |= key1 & 0xFF; - switch (key1) { - case 0x31 ... 0x3F: /* more-byte sequence */ - case 0x5B: /* strange, may apparently occur */ - do { - if ((key1 = read_key()) < 0) - break; /* Sequence ends here */ - k <<= 8; - k |= key1 & 0xFF; - } while (key1 != 0x7E); - break; - } - } - break; - } - } - } - } - - if (key1 == READ_KEY_ERROR) - return READ_KEY_SEQ_ERROR; - - return k; -} - -/* - * kbd_receiver_thread() - * - * Read key(sequence)s from stdin and pass those to frontend. - */ - -static void kbd_receiver_thread_cleanup(void *arg) -{ - int status; - tcsetattr(STDIN_FILENO, TCSANOW, &saved_tm); - status = system("setterm -cursor on"); - LOGMSG("Keyboard thread terminated"); -} - -static void *kbd_receiver_thread(void *fe_gen) -{ - frontend_t *fe = (frontend_t*)fe_gen; - uint64_t code = 0; - char str[64]; - int status; - - status = system("setterm -cursor off"); - status = system("setterm -blank off"); - - /* Set stdin to deliver keypresses without buffering whole lines */ - tcgetattr(STDIN_FILENO, &saved_tm); - if (tcgetattr(STDIN_FILENO, &tm) == 0) { - tm.c_iflag = 0; - tm.c_lflag &= ~(ICANON | ECHO); - tm.c_cc[VMIN] = 0; - tm.c_cc[VTIME] = 0; - tcsetattr(STDIN_FILENO, TCSANOW, &tm); - } - - pthread_cleanup_push(kbd_receiver_thread_cleanup, NULL); - - do { - alarm(0); - errno = 0; - code = read_key_seq(); - alarm(3); /* watchdog */ - if (code == 0) - continue; - if (code == READ_KEY_SEQ_ERROR) - break; - if (code == 27) { - fe->send_event(fe, "QUIT"); - break; - } - - if (gui_hotkeys) { - if (code == 'f' || code == 'F') { - fe->send_event(fe, "TOGGLE_FULLSCREEN"); - continue; - } else if (code == 'd' || code == 'D') { - fe->send_event(fe, "TOGGLE_DEINTERLACE"); - continue; - } - } - - snprintf(str, sizeof(str), "%016" PRIX64, code); - fe->send_input_event(fe, "KBD", str, 0, 0); - - } while (fe->xine_is_finished(fe, 0) != FE_XINE_EXIT); - - alarm(0); - - LOGDBG("Keyboard thread terminating"); - - pthread_cleanup_pop(1); - - pthread_exit(NULL); - return NULL; /* never reached */ -} - -/* - * slave_receiver_thread() - * - * Read slave mode commands from stdin - * Interpret and execute valid commands - */ - -static void slave_receiver_thread_cleanup(void *arg) -{ - /* restore terminal settings */ - tcsetattr(STDIN_FILENO, TCSANOW, &saved_tm); - LOGDBG("Slave mode receiver terminated"); -} - -static void *slave_receiver_thread(void *fe_gen) -{ - frontend_t *fe = (frontend_t*)fe_gen; - char str[128], *pt; - - tcgetattr(STDIN_FILENO, &saved_tm); - - pthread_cleanup_push(slave_receiver_thread_cleanup, NULL); - - do { - errno = 0; - str[0] = 0; - - pthread_testcancel(); - if (!fgets(str, sizeof(str), stdin)) - break; - pthread_testcancel(); - - if (NULL != (pt = strchr(str, '\r'))) - *pt = 0; - if (NULL != (pt = strchr(str, '\n'))) - *pt = 0; - - if (!strncasecmp(str, "QUIT", 4)) { - fe->send_event(fe, "QUIT"); - break; - } - if (!strncasecmp(str, "FULLSCREEN", 10)) { - fe->send_event(fe, "TOGGLE_FULLSCREEN"); - continue; - } - if (!strncasecmp(str, "DEINTERLACE ", 12)) { - fe->send_event(fe, str); - continue; - } - if (!strncasecmp(str, "HITK ", 5)) { - fe->send_input_event(fe, NULL, str+5, 0, 0); - continue; - } - - LOGMSG("Unknown slave mode command: %s", str); - - } while (fe->xine_is_finished(fe, 0) != FE_XINE_EXIT); - - LOGDBG("Slave mode receiver terminating"); - - pthread_cleanup_pop(1); - - pthread_exit(NULL); - return NULL; /* never reached */ -} - -/* - * kbd_start() - * - * Start keyboard/slave mode reader thread - */ -static void kbd_start(frontend_t *fe, int slave_mode) -{ - int err; - if ((err = pthread_create (&kbd_thread, - NULL, - slave_mode ? slave_receiver_thread : kbd_receiver_thread, - (void*)fe)) != 0) { - fprintf(stderr, "Can't create new thread for keyboard (%s)\n", - strerror(err)); - } -} - -/* - * kbd_stop() - * - * Stop keyboard/slave mode reader thread - */ -static void kbd_stop(void) -{ - void *p; - - pthread_cancel(kbd_thread); - pthread_join(kbd_thread, &p); -} - -/* - * SignalHandler() - */ -static void SignalHandler(int signum) -{ - LOGMSG("caught signal %d", signum); - - switch (signum) { - case SIGHUP: - last_signal = signum; - case SIGPIPE: - break; - default: - if (last_signal) { - LOGMSG("SignalHandler: exit(-1)"); - exit(-1); - } - last_signal = signum; - break; - } - - signal(signum, SignalHandler); -} - -/* - * strcatrealloc() - */ -static char *strcatrealloc(char *dest, const char *src) -{ - size_t l; - - if (!src || !*src) - return dest; - - l = (dest ? strlen(dest) : 0) + strlen(src) + 1; - if(dest) { - dest = (char *)realloc(dest, l); - strcat(dest, src); - } else { - dest = (char*)malloc(l); - strcpy(dest, src); - } - return dest; -} - -/* - * static data - */ - -static const char help_str[] = -"When server address is not given, server is searched from local network.\n" -"If server is not found, localhost (127.0.0.1) is used as default.\n\n" - " --help Show (this) help message\n" - " --audio=audiodriver[:device] Select audio driver and optional port\n" - " --video=videodriver[:device] Select video driver and optional port\n" -#ifndef IS_FBFE - " --display=displayaddress X11 display address\n" - " --wid=id Use existing X11 window\n" -#endif - " --aspect=[auto|4:3|16:9|16:10|default]\n" - " Display aspect ratio\n" - " Use script to control HW aspect ratio:\n" - " --aspect=auto:path_to_script\n" - " --fullscreen Fullscreen mode\n" -#ifdef HAVE_XRENDER - " --hud Head Up Display OSD mode\n" -#endif - " --width=x Video window width\n" - " --height=x Video window height\n" - " --geometry=WxH[+X+Y] Set output window geometry (X style)\n" - " --noscaling Disable all video scaling\n" - " --post=name[:arg=val[,arg=val]] Load and use xine post plugin(s)\n" - " examples:\n" - " --post=upmix\n" - " --post=upmix;tvtime:enabled=1,cheap_mode=1\n" - " --lirc[=devicename] Use lirc input device\n" - " Optional lirc socket name can be given\n" - " --config=file Use config file (default: ~/.xine/config_xineliboutput).\n" - " --verbose Verbose debug output\n" - " --silent Silent mode (report only errors)\n" - " --syslog Write all output to system log\n" - " --nokbd Disable console keyboard input\n" -#ifndef IS_FBFE - " --noxkbd Disable X11 keyboard input\n" -#endif - " --hotkeys Enable frontend GUI hotkeys\n" - " --daemon Run as daemon (disable keyboard,\n" - " log to syslog and fork to background)\n" - " --slave Enable slave mode (read commands from stdin)\n" - " --reconnect Automatically reconnect when connection has been lost\n" - " --tcp Use TCP transport\n" - " --udp Use UDP transport\n" - " --rtp Use RTP transport\n\n" - " If no transport options are given, transports\n" - " are tried in following order:\n" - " local pipe, rtp, udp, tcp\n\n"; - -static const char short_options[] = "HA:V:d:W:a:fg:Dw:h:nP:L:C:vsxlkobSRtur"; - -static const struct option long_options[] = { - { "help", no_argument, NULL, 'H' }, - { "audio", required_argument, NULL, 'A' }, - { "video", required_argument, NULL, 'V' }, - { "display", required_argument, NULL, 'd' }, - { "wid", required_argument, NULL, 'W' }, - { "aspect", required_argument, NULL, 'a' }, - { "fullscreen", no_argument, NULL, 'f' }, - { "geometry", required_argument, NULL, 'g' }, - { "hud", no_argument, NULL, 'D' }, - { "width", required_argument, NULL, 'w' }, - { "height", required_argument, NULL, 'h' }, - { "noscaling", no_argument, NULL, 'n' }, - { "post", required_argument, NULL, 'P' }, - { "lirc", optional_argument, NULL, 'L' }, - { "config", required_argument, NULL, 'C' }, - - { "verbose", no_argument, NULL, 'v' }, - { "silent", no_argument, NULL, 's' }, - { "syslog", no_argument, NULL, 'l' }, - { "nokbd", no_argument, NULL, 'k' }, - { "noxkbd", no_argument, NULL, 'x' }, - { "hotkeys", no_argument, NULL, 'o' }, - { "daemon", no_argument, NULL, 'b' }, - { "slave", no_argument, NULL, 'S' }, - - { "reconnect", no_argument, NULL, 'R' }, - { "tcp", no_argument, NULL, 't' }, - { "udp", no_argument, NULL, 'u' }, - { "rtp", no_argument, NULL, 'r' }, - { NULL } -}; - -#define PRINTF(x...) do { if(SysLogLevel>1) printf(x); } while(0) - -int main(int argc, char *argv[]) -{ - char *mrl = NULL, *gdrv = NULL, *adrv = NULL, *adev = NULL; - int ftcp = 0, fudp = 0, frtp = 0, reconnect = 0, firsttry = 1; - int fullscreen = 0, hud = 0, xpos = 0, ypos = 0, width = 720, height = 576; - int scale_video = 1, aspect = 1; - int daemon_mode = 0, nokbd = 0, noxkbd = 0, slave_mode = 0; - char *video_port = NULL; - int window_id = -1; - int xmajor, xminor, xsub; - int c; - int xine_finished = FE_XINE_ERROR; - frontend_t *fe = NULL; - extern const fe_creator_f fe_creator; - char *static_post_plugins = NULL; - char *lirc_dev = NULL; - char *aspect_controller = NULL; - int repeat_emu = 0; - char *exec_name = argv[0]; - char *config_file = NULL; - - LogToSysLog = 0; - - if (strrchr(argv[0],'/')) - exec_name = strrchr(argv[0],'/')+1; - - xine_get_version(&xmajor, &xminor, &xsub); - printf("%s %s (build with xine-lib %d.%d.%d, using xine-lib %d.%d.%d)\n\n", - exec_name, - FE_VERSION_STR, - XINE_MAJOR_VERSION, XINE_MINOR_VERSION, XINE_SUB_VERSION, - xmajor, xminor, xsub); - - /* Parse arguments */ - while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { - switch (c) { - default: - case 'H': printf("\nUsage: %s [options] [" MRL_ID "[+udp|+tcp|+rtp]:[//host[:port]]] \n" - "\nAvailable options:\n", exec_name); - printf("%s", help_str); - list_xine_plugins(NULL, SysLogLevel>2); - exit(0); - case 'A': adrv = strdup(optarg); - adev = strchr(adrv, ':'); - if (adev) - *(adev++) = 0; - PRINTF("Audio driver: %s\n",adrv); - if (adev) - PRINTF("Audio device: %s\n",adev); - break; - case 'V': gdrv = strdup(optarg); - if (strchr(gdrv, ':')) { - video_port = strchr(gdrv, ':'); - *video_port = 0; - video_port++; - PRINTF("Video port: %s\n",video_port); - } - PRINTF("Video driver: %s\n",gdrv); - break; -#ifndef IS_FBFE - case 'W': window_id = atoi(optarg); - break; - case 'd': video_port = strdup(optarg); - break; - case 'x': noxkbd = 1; - break; -#endif - case 'a': if (!strncmp(optarg, "auto", 4)) - aspect = 0; - if (!strncmp(optarg, "4:3", 3)) - aspect = 2; - if (!strncmp(optarg, "16:9", 4)) - aspect = 3; - if (!strncmp(optarg, "16:10", 5)) - aspect = 4; - if (aspect == 0 && optarg[4] == ':') - aspect_controller = strdup(optarg+5); - PRINTF("Aspect ratio: %s\n", - aspect==0?"Auto":aspect==2?"4:3":aspect==3?"16:9": - aspect==4?"16:10":"Default"); - if (aspect_controller) - PRINTF("Using %s to switch aspect ratio\n", - aspect_controller); - break; - case 'f': fullscreen=1; - PRINTF("Fullscreen mode\n"); - break; - case 'D': hud=1; -#ifdef HAVE_XRENDER - PRINTF("HUD OSD mode\n"); -#else - PRINTF("HUD OSD not supported\n"); -#endif - break; - case 'w': width = atoi(optarg); - PRINTF("Width: %d\n", width); - break; - case 'g': sscanf (optarg, "%dx%d+%d+%d", &width, &height, &xpos, &ypos); - PRINTF("Geometry: %dx%d+%d+%d\n", width, height, xpos, ypos); - break; - case 'h': height = atoi(optarg); - PRINTF("Height: %d\n", height); - break; - case 'n': scale_video = 0; - PRINTF("Video scaling disabled\n"); - break; - case 'P': if (static_post_plugins) - strcatrealloc(static_post_plugins, ";"); - static_post_plugins = strcatrealloc(static_post_plugins, optarg); - PRINTF("Post plugins: %s\n", static_post_plugins); - break; - case 'C': config_file = strdup(optarg); - PRINTF("Config file: %s\n", config_file); - break; - case 'L': lirc_dev = strdup(optarg ? : "/dev/lircd"); - if (strstr((char*)lirc_dev, ",repeatemu")) { - *strstr((char*)lirc_dev, ",repeatemu") = 0; - repeat_emu = 1; - } - PRINTF("LIRC device: %s%s\n", lirc_dev, - repeat_emu?", emulating key repeat":""); - break; - case 'v': SysLogLevel = (SysLogLevel<SYSLOGLEVEL_DEBUG) ? SYSLOGLEVEL_DEBUG : SysLogLevel+1; - PRINTF("Verbose mode\n"); - break; - case 's': SysLogLevel = 1; - PRINTF("Silent mode\n"); - break; - case 'S': slave_mode = 1; - PRINTF("Slave mode\n"); - break; - case 'l': LogToSysLog = 1; - openlog(exec_name, LOG_PID|LOG_CONS, LOG_USER); - break; - case 'k': nokbd = 1; - PRINTF("Keyboard input disabled\n"); - break; - case 'o': gui_hotkeys = 1; - PRINTF("GUI hotkeys enabled\n" - " mapping keyboard f,F -> fullscreen toggle\n" - " keyboard d,D -> deinterlace toggle\n" - " LIRC Deinterlace -> deinterlace toggle\n" - " LIRC Fullscreen -> fullscreen toggle\n" - " LIRC Quit -> exit\n"); - break; - case 'b': nokbd = daemon_mode = 1; - PRINTF("Keyboard input disabled\n"); - break; - case 'R': reconnect = 1; - PRINTF("Automatic reconnection enabled\n"); - break; - case 't': ftcp = 1; - PRINTF("Protocol: TCP\n"); - break; - case 'u': fudp = 1; - PRINTF("Protocol: UDP\n"); - break; - case 'r': frtp = 1; - PRINTF("Protocol: RTP\n"); - break; - case 1: printf("arg 1 (%s)\n", long_options[optind].name); exit(0); - } - } - - if (optind < argc) { - mrl = strdup(argv[optind]); - PRINTF("VDR Server: %s\n", mrl); - while (++optind < argc) - printf("Unknown argument: %s\n", argv[optind]); - } - - PRINTF("\n"); - -#if 1 - /* backward compability */ - if (mrl && ( !strncmp(mrl, MRL_ID ":tcp:", MRL_ID_LEN+5) || - !strncmp(mrl, MRL_ID ":udp:", MRL_ID_LEN+5) || - !strncmp(mrl, MRL_ID ":rtp:", MRL_ID_LEN+5) || - !strncmp(mrl, MRL_ID ":pipe:", MRL_ID_LEN+6))) - mrl[4] = '+'; -#endif - - /* If server address not given, try to find server automatically */ - if (!mrl || - !strcmp(mrl, MRL_ID ":") || - !strcmp(mrl, MRL_ID "+tcp:") || - !strcmp(mrl, MRL_ID "+udp:") || - !strcmp(mrl, MRL_ID "+rtp:") || - !strcmp(mrl, MRL_ID "+pipe:")) { - char address[1024] = ""; - int port = -1; - PRINTF("VDR server not given, searching ...\n"); - if (udp_discovery_find_server(&port, &address[0])) { - PRINTF("Found VDR server: host %s, port %d\n", address, port); - if (mrl) { - char *tmp = mrl; - mrl = NULL; - if (asprintf(&mrl, "%s//%s:%d", tmp, address, port) < 0) - return -1; - free(tmp); - } else - if (asprintf(&mrl, MRL_ID "://%s:%d", address, port) < 0) - return -1; - } else { - PRINTF("---------------------------------------------------------------\n" - "WARNING: MRL not given and server not found from local network.\n" - " Trying to connect to default port on local host.\n" - "---------------------------------------------------------------\n"); - mrl = strdup(MRL_ID "://127.0.0.1"); - } - } - - if (mrl && - strncmp(mrl, MRL_ID ":", MRL_ID_LEN+1) && - strncmp(mrl, MRL_ID "+", MRL_ID_LEN+1)) { - char *mrl2 = mrl; - PRINTF("WARNING: MRL does not start with \'" MRL_ID ":\' (%s)", mrl); - if (asprintf(&mrl, MRL_ID "://%s", mrl) < 0) - return -1; - free(mrl2); - } - - { - char *tmp = NULL, *mrl2 = mrl; - if (frtp && !strstr(mrl, "rtp:")) - tmp = strdup(MRL_ID "+rtp:"); - else if (fudp && !strstr(mrl, "udp:")) - tmp = strdup(MRL_ID "+udp:"); - else if (ftcp && !strstr(mrl, "tcp:")) - tmp = strdup(MRL_ID "+tcp:"); - if (tmp) { - mrl = strcatrealloc(tmp, strchr(mrl, '/')); - free(mrl2); - } - } - - if (daemon_mode) { - PRINTF("Entering daemon mode\n\n"); - if (daemon(1, 0) == -1) { - fprintf(stderr, "%s: %m\n", exec_name); - LOGERR("daemon() failed"); - return -2; - } - } - - /* Create front-end */ - fe = (*fe_creator)(); - if (!fe) { - fprintf(stderr, "Error initializing frontend\n"); - return -3; - } - - /* Initialize display */ - if (!fe->fe_display_open(fe, xpos, ypos, width, height, fullscreen, hud, 0, - "", aspect, NULL, noxkbd, gui_hotkeys, - video_port, scale_video, 0, - aspect_controller, window_id)) { - fprintf(stderr, "Error opening display\n"); - fe->fe_free(fe); - return -4; - } - - /* Initialize xine */ - if (!fe->xine_init(fe, adrv, adev, gdrv, 250, static_post_plugins, config_file)) { - fprintf(stderr, "Error initializing xine\n"); - list_xine_plugins(fe, SysLogLevel>2); - fe->fe_free(fe); - return -5; - } - - if (SysLogLevel > 2) - list_xine_plugins(fe, SysLogLevel>2); - - /* signal handlers */ - - if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN); - if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN); - if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN); - if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN); - - do { - - if (!firsttry) { - PRINTF("Connection to server lost. Reconnecting after two seconds...\n"); - sleep(2); - PRINTF("Reconnecting...\n"); - } - - /* Connect to VDR xineliboutput server */ - if (!fe->xine_open(fe, mrl)) { - /*print_xine_log(((fe_t *)fe)->xine);*/ - if (!firsttry) { - PRINTF("Error opening %s\n", mrl); - continue; - } - fprintf(stderr, "Error opening %s\n", mrl); - fe->fe_free(fe); - return -6; - } - - if (!fe->xine_play(fe)) { - if (!firsttry) { - PRINTF("Error playing %s\n", argv[1]); - continue; - } - fprintf(stderr, "Error playing %s\n", argv[1]); - fe->fe_free(fe); - return -7; - } - - if (firsttry) { - - /* Start LIRC forwarding */ - lirc_start(fe, lirc_dev, repeat_emu); - - /* Start keyboard listener thread */ - if (!nokbd) { - PRINTF("\n\nPress Esc to exit\n\n"); - kbd_start(fe, slave_mode); - } - } - - /* Main loop */ - - fflush(stdout); - fflush(stderr); - - while (!last_signal && fe->fe_run(fe)) - ; - xine_finished = fe->xine_is_finished(fe,0); - - fe->xine_close(fe); - firsttry = 0; - - /* HUP reconnects */ - if (last_signal == SIGHUP) - last_signal = 0; - - } while (!last_signal && xine_finished != FE_XINE_EXIT && reconnect); - - /* Clean up */ - - PRINTF("Terminating...\n"); - - fe->send_event(fe, "QUIT"); - - /* stop input threads */ - lirc_stop(); - if (!nokbd) - kbd_stop(); - - fe->fe_free(fe); - - free(config_file); - free(static_post_plugins); - free(mrl); - free(adrv); - free(gdrv); - free(video_port); - free(aspect_controller); - free(lirc_dev); - - return xine_finished==FE_XINE_EXIT ? 0 : 1; -} diff --git a/xine_input_vdr.c b/xine_input_vdr.c deleted file mode 100644 index 2f7e35b0..00000000 --- a/xine_input_vdr.c +++ /dev/null @@ -1,5641 +0,0 @@ -/* - * xine_input_vdr.c: xine VDR input plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_input_vdr.c,v 1.273 2009-07-17 22:48:29 phintuka Exp $ - * - */ - - -#define XINE_ENGINE_INTERNAL - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <poll.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <errno.h> -#include <sys/time.h> -#include <dlfcn.h> -#include <sys/resource.h> /* setpriority() */ -#include <sys/stat.h> -#include <syslog.h> - -#ifndef __APPLE__ -# define DVD_STREAMING_SPEED -#endif - -#ifdef DVD_STREAMING_SPEED -# include <linux/cdrom.h> -# include <scsi/sg.h> -#endif - -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/input_plugin.h> -#include <xine/plugin_catalog.h> -#include <xine/io_helper.h> -#include <xine/buffer.h> -#include <xine/post.h> - -#ifndef XINE_VERSION_CODE -# error XINE_VERSION_CODE undefined ! -#endif - -#if XINE_VERSION_CODE >= 10190 -# include "features.h" -# ifdef HAVE_LIBAVUTIL -# include <libavutil/mem.h> -# else -# error "plugin was configured without libavutil. It can't be compiled against xine-lib 1.2 !" -# endif -#endif - -#include "xine/adjustable_scr.h" -#include "xine/osd_manager.h" - -#include "xine_input_vdr.h" -#include "xine_input_vdr_net.h" -#include "xine_osd_command.h" - -#include "tools/mpeg.h" -#include "tools/pes.h" -#include "tools/ts.h" - -/***************************** DEFINES *********************************/ - -/*#define LOG_UDP*/ -/*#define LOG_OSD*/ -/*#define LOG_CMD*/ -/*#define LOG_SCR*/ -/*#define LOG_TRACE*/ - -#define METRONOM_PREBUFFER_VAL (4 * 90000 / 25 ) -#define HD_BUF_NUM_BUFS (2048) /* 2k payload * 2048 = 4Mb , ~ 1 second */ -#define HD_BUF_ELEM_SIZE (2048+64) - -#define RADIO_MAX_BUFFERS 10 - -#ifndef NOSIGNAL_IMAGE_FILE -# define NOSIGNAL_IMAGE_FILE "/usr/share/vdr/xineliboutput/nosignal.mpv" -#endif -#ifndef NOSIGNAL_MAX_SIZE -# define NOSIGNAL_MAX_SIZE 0x10000 /* 64k */ -#endif - -/* - Note: - I tried to set speed to something very small instead of full pause - when pausing SCR but it didn't work in all systems. - TEST_SCR_PAUSE replaces this by adding delay before stream - is paused (pause is triggered by first received PES containing PTS). - This should allow immediate processing of still frames and let video_out - run in paused_loop when there is gap in feed (ex. channel can't be decrypted). - Not running video_out in paused_loop caused very long delays in - OSD updating in some setups. -*/ -#define TEST_SCR_PAUSE - -/* picture-in-picture support */ -/*#define TEST_PIP 1*/ - - -#define CONTROL_BUF_BASE ( 0x0f000000) /* 0x0f000000 */ -#define CONTROL_BUF_BLANK (CONTROL_BUF_BASE|0x00010000) /* 0x0f010000 */ -#define CONTROL_BUF_CLEAR (CONTROL_BUF_BASE|0x00020000) /* 0x0f020000 */ -#define BUF_NETWORK_BLOCK (BUF_DEMUX_BLOCK |0x00010000) /* 0x05010000 */ - -#define SPU_CHANNEL_NONE (-2) -#define SPU_CHANNEL_AUTO (-1) - -/******************************* LOG ***********************************/ - -#ifndef __APPLE__ -# include <linux/unistd.h> /* syscall(__NR_gettid) */ -#endif - -static const char log_module_input_vdr[] = "[input_vdr] "; -#define LOG_MODULENAME log_module_input_vdr -#define SysLogLevel iSysLogLevel - -#include "logdefs.h" - -int iSysLogLevel = 1; /* 0:none, 1:errors, 2:info, 3:debug */ -int bLogToSysLog = 0; -int bSymbolsFound = 0; - -void x_syslog(int level, const char *module, const char *fmt, ...) -{ - va_list argp; - char buf[512]; - va_start(argp, fmt); - vsnprintf(buf, sizeof(buf), fmt, argp); - buf[sizeof(buf)-1] = 0; -#ifdef __APPLE__ - if(!bLogToSysLog) { - fprintf(stderr, "%s%s\n", module, buf); - } else { - syslog(level, "%s%s", module, buf); - } -#else - if(!bLogToSysLog) { - fprintf(stderr,"[%ld] %s%s\n", syscall(__NR_gettid), module, buf); - } else { - syslog(level, "[%ld] %s%s", syscall(__NR_gettid), module, buf); - } -#endif - va_end(argp); -} - -static void SetupLogLevel(void) -{ - void *lib = NULL; - if( !(lib = dlopen (NULL, RTLD_LAZY | RTLD_GLOBAL))) { - LOGERR("Can't dlopen self: %s", dlerror()); - } else { - int *pLogToSyslog = (int*)dlsym(lib, "LogToSysLog"); - int *pSysLogLevel = (int*)dlsym(lib, "SysLogLevel"); - bLogToSysLog = pLogToSyslog && *pLogToSyslog; - iSysLogLevel = pSysLogLevel ? (*pSysLogLevel) : iSysLogLevel; - LOGDBG("Symbol SysLogLevel %s : value %d", - pSysLogLevel ? "found" : "not found", iSysLogLevel); - LOGDBG("Symbol LogToSysLog %s : value %s", - pLogToSyslog ? "found" : "not found", bLogToSysLog ? "yes" : "no"); - bSymbolsFound = pSysLogLevel && pLogToSyslog; - dlclose(lib); - } -} - -#define LOG_UDP - -#ifdef LOG_SCR -# define LOGSCR(x...) LOGMSG("SCR: " x) -#else -# define LOGSCR(x...) -#endif -# -#ifdef LOG_OSD -# define LOGOSD(x...) LOGMSG("OSD: " x) -#else -# define LOGOSD(x...) -#endif -# -#ifdef LOG_UDP -# define LOGUDP(x...) LOGMSG("UDP:" x) -#else -# define LOGUDP(x...) -#endif -#ifdef LOG_CMD -# define LOGCMD(x...) LOGMSG("CMD:" x) -#else -# define LOGCMD(x...) -#endif -#ifdef LOG_TRACE -# undef TRACE -# define TRACE(x...) printf(x) -#else -# undef TRACE -# define TRACE(x...) -#endif - - -/*#define DEBUG_LOCKING*/ -#ifdef DEBUG_LOCKING -# include "tools/debug_mutex.h" -#endif - -/******************************* DATA ***********************************/ - -#define KILOBYTE(x) (1024 * (x)) - -typedef struct udp_data_s udp_data_t; - -/* plugin class */ -typedef struct vdr_input_class_s { - input_class_t input_class; - xine_t *xine; - char *mrls[ 2 ]; - int fast_osd_scaling; - double scr_tuning_step; -} vdr_input_class_t; - -/* input plugin */ -typedef struct vdr_input_plugin_s { - union { - vdr_input_plugin_if_t iface; - struct { - input_plugin_t input_plugin; - vdr_input_plugin_funcs_t funcs; - }; - }; - - /* plugin */ - vdr_input_class_t *class; - xine_stream_t *stream; - xine_event_queue_t *event_queue; - osd_manager_t *osd_manager; - - char *mrl; - - xine_stream_t *pip_stream; - xine_stream_t *slave_stream; - xine_event_queue_t *slave_event_queue; - int autoplay_size; - - /* Sync */ - pthread_mutex_t lock; - pthread_mutex_t vdr_entry_lock; - pthread_cond_t engine_flushed; - - /* Playback */ - uint8_t read_timeouts; /* number of timeouts in read_block */ - uint8_t no_video : 1; - uint8_t live_mode : 1; - uint8_t still_mode : 1; - uint8_t stream_start : 1; - uint8_t loop_play : 1; - uint8_t dvd_menu : 1; - uint8_t hd_stream : 1; /* true if current stream is HD */ - uint8_t sw_volume_control : 1; - - /* SCR */ - adjustable_scr_t *scr; - int speed_before_pause; - int8_t scr_tuning; - uint8_t fixed_scr : 1; - uint8_t scr_live_sync : 1; - uint8_t is_paused : 1; - uint8_t is_trickspeed : 1; - - uint I_frames; /* amount of I-frames passed to demux */ - uint B_frames; - uint P_frames; - - /* Network */ - pthread_t control_thread; - pthread_t data_thread; - pthread_mutex_t fd_control_lock; - buf_element_t *read_buffer; - int threads_initialized; - volatile int control_running; - volatile int fd_data; - volatile int fd_control; - uint8_t tcp, udp, rtp; - udp_data_t *udp_data; - int client_id; - int token; - - /* buffer */ - fifo_buffer_t *block_buffer; /* blocks to be demuxed */ - fifo_buffer_t *buffer_pool; /* stream's video fifo */ - fifo_buffer_t *hd_buffer; /* more buffer for HD streams */ - fifo_buffer_t *iframe_buffer; /* buffer for cached I-frame */ - int saving_iframe; - uint64_t discard_index; /* index of next byte to feed to demux; - all data before this offset will - be discarded */ - uint64_t discard_index_ds; - int discard_frame; - uint64_t guard_index; /* data before this offset will not be discarded */ - int guard_frame; - uint64_t curpos; /* current position (demux side) */ - int curframe; - int max_buffers; /* max no. of non-demuxed buffers */ - - /* saved video properties */ - int video_properties_saved; - int orig_hue; - int orig_brightness; - int orig_saturation; - int orig_sharpness; - int orig_noise_reduction; - int orig_contrast; - int orig_vo_aspect_ratio; - -} vdr_input_plugin_t; - - -/***************************** UDP DATA *********************************/ - -struct udp_data_s { - - /* Server address (used to validate incoming packets) */ - struct sockaddr_in server_address; - uint32_t ssrc; - - /* receiving queue for re-ordering and re-transmissions */ - buf_element_t *queue[UDP_SEQ_MASK+1]; - uint64_t queue_input_pos; /* stream position of next incoming byte */ - uint16_t queued; /* count of frames in queue */ - uint16_t next_seq; /* expected sequence number of next incoming packet */ - - uint16_t current_seq; /* sequence number of last received packet */ - uint8_t is_padding; /* true, if last received packet was padding packet */ - - /* missing frames ratio statistics */ - int16_t missed_frames; - int16_t received_frames; - - /* SCR adjust */ - uint8_t scr_jump_done; - - int resend_requested; -}; - -/* UDP sequence number handling */ -#define NEXTSEQ(x) ((x + 1) & UDP_SEQ_MASK) -#define PREVSEQ(x) ((x + UDP_SEQ_MASK) & UDP_SEQ_MASK) -#define INCSEQ(x) (x = NEXTSEQ(x)) -#define ADDSEQ(x,n) ((x + UDP_SEQ_MASK + 1 + n) & UDP_SEQ_MASK) - -#define UDP_SIGNAL_FULL_TRESHOLD 50 /* ~100ms with DVB mpeg2 - (2k-blocks @ 8 Mbps) */ -#define UDP_SIGNAL_NOT_FULL_TRESHOLD 100 /* ~200ms with DVB mpeg2 - (2k-blocks @ 8 Mbps) */ - -static udp_data_t *init_udp_data(void) -{ - udp_data_t *data = calloc(1, sizeof(udp_data_t)); - - data->received_frames = -1; - - return data; -} - -static void free_udp_data(udp_data_t *data) -{ - int i; - - for(i=0; i<=UDP_SEQ_MASK; i++) - if(data->queue[i]) { - data->queue[i]->free_buffer(data->queue[i]); - data->queue[i] = NULL; - } - free(data); -} - -#if 0 -static void flush_udp_data(udp_data_t *data) -{ - /* flush all data immediately even if there are gaps */ -} -#endif - -/********************* cancellable mutex locking *************************/ - -/* - * mutex cleanup() - * - * Unlock mutex. Used as thread cleanup handler. - */ -static void mutex_cleanup(void *arg) -{ - pthread_mutex_unlock((pthread_mutex_t *)arg); -} - -/* - * mutex_lock_cancellable() / mutex_unlock_cancellable() - * - * mutex lock/unlock for cancellable sections - * - * - do not enter protected section if locking fails - * - unlock mutex if thread is cancelled while holding the lock - * - * - lock/unlock must be used pairwise within the same lexical scope ! - * - */ -#define mutex_lock_cancellable(mutex) \ - if (pthread_mutex_lock(mutex)) { \ - LOGERR("pthread_mutex_lock (%s) failed, skipping locked block !", #mutex); \ - } else { \ - pthread_cleanup_push(mutex_cleanup, (void*) mutex); - -#define mutex_unlock_cancellable(mutex) \ - if (pthread_mutex_unlock(mutex)) \ - LOGERR("pthread_mutex_unlock (%s) failed !", #mutex); \ - pthread_cleanup_pop(0); \ - } - -/******************************* SCR ***********************************/ -/* - * SCR fine tuning - * - * fine tuning is used to change playback speed in live mode - * to keep in sync with mpeg source - * - * SCR code is mostly copied from xine-lib (src/input/input_pvr.c) - */ - -#define SCR_TUNING_PAUSED -3 -#define SCR_TUNING_OFF 0 - -#ifdef LOG_SCR -static inline const char *scr_tuning_str(int value) -{ - switch(value) { - case 2: return "SCR +2"; - case 1: return "SCR +1"; - case SCR_TUNING_OFF: return "SCR +0"; - case -1: return "SCR -1"; - case -2: return "SCR -2"; - case SCR_TUNING_PAUSED: return "SCR PAUSED"; - default: break; - } - return "ERROR"; -} -#endif - -static void scr_tuning_set_paused(vdr_input_plugin_t *this) -{ - if(this->scr_tuning != SCR_TUNING_PAUSED && - !this->slave_stream && - !this->is_trickspeed) { - - this->scr_tuning = SCR_TUNING_PAUSED; /* marked as paused */ - if(this->scr) - this->scr->set_speed_tuning(this->scr, 1.0); - - this->speed_before_pause = _x_get_fine_speed(this->stream); - -#ifdef TEST_SCR_PAUSE - if(_x_get_fine_speed(this->stream) != XINE_SPEED_PAUSE) - _x_set_fine_speed(this->stream, XINE_SPEED_PAUSE); -#else - _x_set_fine_speed(this->stream, 1000000 / 1000); /* -> speed to 0.1% */ -#endif - this->I_frames = this->P_frames = this->B_frames = 0; - } -} - -static void reset_scr_tuning(vdr_input_plugin_t *this, int new_speed) -{ - if(this->scr_tuning != SCR_TUNING_OFF) { - this->scr_tuning = SCR_TUNING_OFF; /* marked as normal */ - if(this->scr) - this->scr->set_speed_tuning(this->scr, 1.0); - - if(new_speed >= 0) { - if(_x_get_fine_speed(this->stream) != new_speed) { - _x_set_fine_speed(this->stream, XINE_FINE_SPEED_NORMAL); - } - this->scr->scr.set_fine_speed(&this->scr->scr, XINE_FINE_SPEED_NORMAL); - } - } -} - -static void vdr_adjust_realtime_speed(vdr_input_plugin_t *this) -{ - /* - * Grab current buffer usage - */ - int num_used = this->buffer_pool->size(this->buffer_pool) + - this->block_buffer->size(this->block_buffer); - int num_free = this->buffer_pool->num_free(this->buffer_pool); - int scr_tuning = this->scr_tuning; - /*int num_vbufs = 0;*/ - - if(this->hd_stream && this->hd_buffer) { - num_free += this->hd_buffer->num_free(this->hd_buffer); - } - - if(this->stream->audio_fifo) - num_used += this->stream->audio_fifo->size(this->stream->audio_fifo); - num_free -= (this->buffer_pool->buffer_pool_capacity - this->max_buffers); - -#ifdef LOG_SCR - /* - * Trace current buffer and tuning status - */ - { - static int fcnt=0; - if(!((fcnt++)%2500) || - (this->scr_tuning==SCR_TUNING_PAUSED && !(fcnt%10)) || - (this->no_video && !(fcnt%50))) { - LOGSCR("Buffer %2d%% (%3d/%3d) %s", - 100*num_used/(num_used+num_free), - num_used, num_used+num_free, - scr_tuning_str(this->scr_tuning)); - } - } - - if(this->scr_tuning==SCR_TUNING_PAUSED) { - if(_x_get_fine_speed(this->stream) != XINE_SPEED_PAUSE) { - LOGMSG("ERROR: SCR PAUSED ; speed=%d bool=%d", - _x_get_fine_speed(this->stream), - (int)_x_get_fine_speed(this->stream) == XINE_SPEED_PAUSE); - _x_set_fine_speed(this->stream, XINE_SPEED_PAUSE); - } - } -#endif - - /* - * SCR -> PAUSE - * - If buffer is empty, pause SCR (playback) for a while - */ - if( num_used < 1 && - scr_tuning != SCR_TUNING_PAUSED && - !this->no_video && !this->still_mode && !this->is_trickspeed) { -#if 0 - this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 0); - num_vbufs = this->stream->video_out->get_property(this->stream->video_out, - VO_PROP_BUFS_IN_FIFO); - this->class->xine->port_ticket->release(this->class->xine->port_ticket, 0); - if(num_vbufs < 3) { - LOGSCR("SCR paused by adjust_speed (vbufs=%d)", num_vbufs); -#endif - scr_tuning_set_paused(this); -#if 0 - } else { - LOGSCR("adjust_speed: no pause, enough vbufs queued (%d)", num_vbufs); - } -#endif - - - /* SCR -> RESUME - * - If SCR (playback) is currently paused due to previous buffer underflow, - * revert to normal if buffer fill is > 66% - */ - } else if( scr_tuning == SCR_TUNING_PAUSED) { -/* - #warning TODO: - - Using amount of buffers is not good trigger as it depends on channel bitrate - - Wait time is not not good trigger as it depends on tuner lock time - -> maybe keep track of PTSes or wait until decoder has complete IBBBP frame sequence ? - - First I-frame can be delivered as soon as it is decoded - -> illusion of faster channel switches -*/ -#if 0 - /* causes random freezes with some post plugins */ - this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 0); - num_vbufs = this->stream->video_out->get_property(this->stream->video_out, - VO_PROP_BUFS_IN_FIFO); - this->class->xine->port_ticket->release(this->class->xine->port_ticket, 0); -#endif - - if( num_used/2 > num_free - || (this->no_video && num_used > 5) - || this->still_mode - || this->is_trickspeed - || ( this->I_frames > 0 - && (this->I_frames > 2 || this->P_frames > 6 )) - ) { - LOGSCR("SCR tuning resetted by adjust_speed, " - "I %d B %d P %d", this->I_frames, this->B_frames, this->P_frames); - - this->I_frames = 0; - reset_scr_tuning(this, this->speed_before_pause); - } - - /* - * Adjust SCR rate - * - Live data is coming in at rate defined by sending transponder, - * there is no way to change it -> we must adapt to it - * - when playing realtime (live) stream, adjust our SCR to keep - * xine buffers half full. This efficiently synchronizes our SCR - * to transponder SCR and prevents buffer under/overruns caused by - * minor differences in clock speeds. - * - if buffer is getting empty, slow don SCR by 0.5...1% - * - if buffer is getting full, speed up SCR by 0.5...1% - * - * TODO: collect simple statistics and try to calculate more exact - * clock rate difference to minimize SCR speed changes - */ - } else if( _x_get_fine_speed(this->stream) == XINE_FINE_SPEED_NORMAL) { - - if(!this->scr_live_sync) { - scr_tuning = SCR_TUNING_OFF; - - } else if(this->no_video) { /* radio stream ? */ - if( num_used >= (RADIO_MAX_BUFFERS-1)) - scr_tuning = +1; /* play faster */ - else if( num_used <= (RADIO_MAX_BUFFERS/3)) - scr_tuning = -1; /* play slower */ - else - scr_tuning = SCR_TUNING_OFF; - } else { - if( num_used > 4*num_free && this->class->scr_tuning_step >= 0.001) - scr_tuning = +2; /* play 1% faster */ - else if( num_used > 2*num_free ) - scr_tuning = +1; /* play .5% faster */ - else if( num_free > 4*num_used && this->class->scr_tuning_step >= 0.001) /* <20% */ - scr_tuning = -2; /* play 1% slower */ - else if( num_free > 2*num_used ) /* <33% */ - scr_tuning = -1; /* play .5% slower */ - else if( (scr_tuning > 0 && num_free > num_used) || - (scr_tuning < 0 && num_used > num_free) ) - scr_tuning = SCR_TUNING_OFF; - } - - if( scr_tuning != this->scr_tuning ) { - LOGSCR("scr_tuning: %s -> %s (buffer %d/%d) (tuning now %f%%)", - scr_tuning_str(this->scr_tuning), - scr_tuning_str(scr_tuning), num_used, num_free, this->class->scr_tuning_step * scr_tuning * 100.0); - this->scr_tuning = scr_tuning; - - /* make it play .5% / 1% faster or slower */ - if(this->scr) - this->scr->set_speed_tuning(this->scr, 1.0 + (this->class->scr_tuning_step * scr_tuning) ); - } - - /* - * SCR -> NORMAL - * - If we are in replay (or trick speed) mode, switch SCR tuning off - * as we can always have complete control on incoming data rate - */ - } else if( this->scr_tuning ) { - reset_scr_tuning(this, -1); - } -} - -/******************************* TOOLS ***********************************/ - -#ifndef MIN -# define MIN(a,b) ((a)<(b)?(a):(b)) -#endif -#ifndef MAX -# define MAX(a,b) ((a)>(b)?(a):(b)) -#endif - -static char *strn0cpy(char *dest, const char *src, int n) -{ - char *s = dest; - for ( ; --n && (*dest = *src) != 0; dest++, src++) ; - *dest = 0; - return s; -} - -static char *unescape_filename(const char *fn) -{ - char *d = strdup(fn), *s = d, *result = d; - while(*s && *s != '#') { - if(s[0] == '%' && s[1] && s[2]) { - unsigned int c; - if (sscanf(s+1, "%02x", &c) == 1) { - *d++ = (char)c; - s += 3; - continue; - } - } - *d++ = *s++; - } - *d = 0; - return result; -} - -static void create_timeout_time(struct timespec *abstime, int timeout_ms) -{ - struct timeval now; - gettimeofday(&now, NULL); - now.tv_usec += timeout_ms * 1000; - while (now.tv_usec >= 1000000) { /* take care of an overflow */ - now.tv_sec++; - now.tv_usec -= 1000000; - } - abstime->tv_sec = now.tv_sec; - abstime->tv_nsec = now.tv_usec * 1000; -} - -/**************************** socket I/O *********************************/ - -/* - * io_select_rd() - * - * - poll socket for read - * - timeouts in 500 ms - * - returns XIO_* - */ -static int io_select_rd (int fd) -{ - fd_set fdset, eset; - int ret; - struct timeval select_timeout; - - if(fd < 0) - return XIO_ERROR; - - FD_ZERO (&fdset); - FD_ZERO (&eset); - FD_SET (fd, &fdset); - FD_SET (fd, &eset); - - select_timeout.tv_sec = 0; - select_timeout.tv_usec = 500*1000; /* 500 ms */ - errno = 0; - ret = select (fd + 1, &fdset, NULL, &eset, &select_timeout); - - if (ret == 0) - return XIO_TIMEOUT; - if (ret < 0) { - if (errno == EINTR || errno == EAGAIN) - return XIO_TIMEOUT; - return XIO_ERROR; - } - - if (FD_ISSET(fd, &eset)) - return XIO_ERROR; - if (FD_ISSET(fd, &fdset)) - return XIO_READY; - - return XIO_TIMEOUT; -} - -/* - * write_control_data() - * - * - write len bytes to control socket. - * - returns number of bytes written, < 0 on error. - * - * NOTE: caller must hold fd_control lock ! - */ -static ssize_t write_control_data(vdr_input_plugin_t *this, const void *str, size_t len) -{ - size_t ret, result = len; - - while (len > 0) { - - if (!this->control_running) { - LOGERR("write_control aborted"); - return -1; - } - - /* poll the socket */ - fd_set fdset, eset; - struct timeval select_timeout; - FD_ZERO (&fdset); - FD_ZERO (&eset); - FD_SET (this->fd_control, &fdset); - FD_SET (this->fd_control, &eset); - select_timeout.tv_sec = 0; - select_timeout.tv_usec = 500*1000; /* 500 ms */ - errno = 0; - if (1 != select (this->fd_control + 1, NULL, &fdset, &eset, &select_timeout) || - !FD_ISSET(this->fd_control, &fdset) || - FD_ISSET(this->fd_control, &eset)) { - LOGERR("write_control failed (poll timeout or error)"); - this->control_running = 0; - return -1; - } - - if (!this->control_running) { - LOGERR("write_control aborted"); - return -1; - } - - errno = 0; - ret = write (this->fd_control, str, len); - - if (ret <= 0) { - if (ret == 0) { - LOGMSG("write_control: disconnected"); - } else if (errno == EAGAIN) { - LOGERR("write_control failed: EAGAIN"); - continue; - } else if (errno == EINTR) { - LOGERR("write_control failed: EINTR"); - pthread_testcancel(); - continue; - } else { - LOGERR("write_control failed"); - } - this->control_running = 0; - return -1; - } - len -= ret; - str += ret; - } - - return result; -} - -/* - * write_control() - * - * - write null-terminated string to control socket. - * - returns number of bytes written, < 0 on error - * - * NOTE: caller should NOT hold fd_control lock ! - */ -static ssize_t write_control(vdr_input_plugin_t *this, const char *str) -{ - ssize_t ret = -1; - mutex_lock_cancellable (&this->fd_control_lock); - ret = write_control_data(this, str, strlen(str)); - mutex_unlock_cancellable (&this->fd_control_lock); - return ret; -} - -/* - * printf_control() - * - * - returns number of bytes written, < 0 on error - * - * NOTE: caller should NOT hold fd_control lock ! - */ -static ssize_t printf_control(vdr_input_plugin_t *this, const char *fmt, ...) -{ - va_list argp; - char buf[512]; - ssize_t result; - - va_start(argp, fmt); - vsnprintf(buf, sizeof(buf), fmt, argp); - buf[sizeof(buf)-1] = 0; - - result = write_control(this, buf); - - va_end(argp); - - return result; -} - -/* - * readline_control() - * - * - read CR/LF terminated string from control socket - * - remove trailing CR/LF - * - returns > 0 : length of string - * = 0 : timeout - * < 0 : error - */ -static ssize_t readline_control(vdr_input_plugin_t *this, char *buf, size_t maxlen, int timeout) -{ - int poll_result; - ssize_t read_result; - size_t total_bytes = 0; - - *buf = 0; - while (total_bytes < maxlen - 1) { - - if (!this->control_running && timeout < 0) - return -1; - - pthread_testcancel(); - poll_result = io_select_rd(this->fd_control); - pthread_testcancel(); - - if (!this->control_running && timeout < 0) - return -1; - - if (poll_result == XIO_TIMEOUT) { - if (timeout == 0) - return 0; - if (timeout > 0) - timeout--; - continue; - } - if (poll_result == XIO_ABORTED) { - LOGERR("readline_control: XIO_ABORTED at [%u]", (uint)total_bytes); - continue; - } - if (poll_result != XIO_READY /* == XIO_ERROR */) { - LOGERR("readline_control: poll error at [%u]", (uint)total_bytes); - return -1; - } - - errno = 0; - read_result = read (this->fd_control, buf + total_bytes, 1); - pthread_testcancel(); - - if (!this->control_running && timeout < 0) - return -1; - - if (read_result <= 0) { - if (read_result == 0) - LOGERR("Control stream disconnected"); - else - LOGERR("readline_control: read error at [%u]", (uint)total_bytes); - if (read_result < 0 && (errno == EINTR || errno == EAGAIN)) - continue; - return -1; - } - - if (buf[total_bytes]) { - if (buf[total_bytes] == '\r') { - buf[total_bytes] = 0; - } else if (buf[total_bytes] == '\n') { - buf[total_bytes] = 0; - break; - } else { - total_bytes ++; - buf[total_bytes] = 0; - } - } - TRACE("readline_control: %d bytes ... %s\n", len, buf); - } - - TRACE("readline_control: %d bytes (max %d)\n", len, maxlen); - - return total_bytes; -} - -/* - * read_control() - * - * - read len bytes from control socket - * - returns < 0 on error - */ -static ssize_t read_control(vdr_input_plugin_t *this, uint8_t *buf, size_t len) -{ - int poll_result; - ssize_t num_bytes; - size_t total_bytes = 0; - - while (total_bytes < len) { - - if (!this->control_running) - return -1; - - pthread_testcancel(); - poll_result = io_select_rd(this->fd_control); - pthread_testcancel(); - - if (!this->control_running) - return -1; - - if (poll_result == XIO_TIMEOUT) { - continue; - } - if (poll_result == XIO_ABORTED) { - LOGERR("read_control: XIO_ABORTED"); - continue; - } - if (poll_result == XIO_ERROR) { - LOGERR("read_control: poll error"); - return -1; - } - - errno = 0; - num_bytes = read (this->fd_control, buf + total_bytes, len - total_bytes); - pthread_testcancel(); - - if (num_bytes <= 0) { - if (this->control_running && num_bytes < 0) - LOGERR("read_control read() error"); - return -1; - } - total_bytes += num_bytes; - } - - return total_bytes; -} - -/************************** BUFFER HANDLING ******************************/ - -static void buffer_pool_free (buf_element_t *element) -{ - fifo_buffer_t *this = (fifo_buffer_t *) element->source; - - pthread_mutex_lock (&this->buffer_pool_mutex); - - element->next = this->buffer_pool_top; - this->buffer_pool_top = element; - - this->buffer_pool_num_free++; - if (this->buffer_pool_num_free > this->buffer_pool_capacity) { - LOGERR("xine-lib:buffer: There has been a fatal error: TOO MANY FREE's"); - _x_abort(); - } - - if(this->buffer_pool_num_free > 20) - pthread_cond_signal (&this->buffer_pool_cond_not_empty); - - pthread_mutex_unlock (&this->buffer_pool_mutex); -} - -static buf_element_t *fifo_buffer_try_get(fifo_buffer_t *fifo) -{ - int i; - buf_element_t *buf; - - pthread_mutex_lock (&fifo->mutex); - - if (fifo->first==NULL) { - pthread_mutex_unlock (&fifo->mutex); - return NULL; - } - - buf = fifo->first; - - fifo->first = fifo->first->next; - if (fifo->first==NULL) - fifo->last = NULL; - - fifo->fifo_size--; - fifo->fifo_data_size -= buf->size; - - for(i = 0; fifo->get_cb[i]; i++) - fifo->get_cb[i](fifo, buf, fifo->get_cb_data[i]); - - pthread_mutex_unlock (&fifo->mutex); - - return buf; -} - -static buf_element_t *fifo_buffer_timed_get(fifo_buffer_t *fifo, int timeout) -{ - buf_element_t *buf = fifo_buffer_try_get (fifo); - - if (!buf) { - struct timespec abstime; - int result = 0; - create_timeout_time (&abstime, timeout); - - mutex_lock_cancellable (&fifo->mutex); - while (fifo->first == NULL && !result) - result = pthread_cond_timedwait (&fifo->not_empty, &fifo->mutex, &abstime); - mutex_unlock_cancellable (&fifo->mutex); - buf = fifo_buffer_try_get (fifo); - } - - return buf; -} - -static void signal_buffer_pool_not_empty(vdr_input_plugin_t *this) -{ - if (this->buffer_pool) { - pthread_mutex_lock(&this->buffer_pool->buffer_pool_mutex); - pthread_cond_broadcast(&this->buffer_pool->buffer_pool_cond_not_empty); - pthread_mutex_unlock(&this->buffer_pool->buffer_pool_mutex); - } - if (this->hd_buffer) { - pthread_mutex_lock(&this->hd_buffer->buffer_pool_mutex); - pthread_cond_broadcast(&this->hd_buffer->buffer_pool_cond_not_empty); - pthread_mutex_unlock(&this->hd_buffer->buffer_pool_mutex); - } -} - -static void signal_buffer_not_empty(vdr_input_plugin_t *this) -{ - if(this->block_buffer) { - pthread_mutex_lock(&this->block_buffer->mutex); - pthread_cond_broadcast(&this->block_buffer->not_empty); - pthread_mutex_unlock(&this->block_buffer->mutex); - } -} - -#if XINE_VERSION_CODE < 10190 -# define fifo_buffer_new(stream, n, s) _x_fifo_buffer_new(n, s) -#else -static fifo_buffer_t *fifo_buffer_new (xine_stream_t *stream, int num_buffers, uint32_t buf_size) -{ - fifo_buffer_t *ref = stream->video_fifo; - fifo_buffer_t *this; - int i; - unsigned char *multi_buffer; - - LOGDBG("fifo_buffer_new..."); - this = calloc(1, sizeof (fifo_buffer_t)); - - this->first = NULL; - this->last = NULL; - this->fifo_size = 0; - this->put = ref->put; - this->insert = ref->insert; - this->get = ref->get; - this->clear = ref->clear; - this->size = ref->size; - this->num_free = ref->num_free; - this->data_size = ref->data_size; - this->dispose = ref->dispose; - this->register_alloc_cb = ref->register_alloc_cb; - this->register_get_cb = ref->register_get_cb; - this->register_put_cb = ref->register_put_cb; - this->unregister_alloc_cb = ref->unregister_alloc_cb; - this->unregister_get_cb = ref->unregister_get_cb; - this->unregister_put_cb = ref->unregister_put_cb; - pthread_mutex_init (&this->mutex, NULL); - pthread_cond_init (&this->not_empty, NULL); - - /* - * init buffer pool, allocate nNumBuffers of buf_size bytes each - */ - - multi_buffer = this->buffer_pool_base = av_mallocz (num_buffers * buf_size); - - pthread_mutex_init (&this->buffer_pool_mutex, NULL); - pthread_cond_init (&this->buffer_pool_cond_not_empty, NULL); - - this->buffer_pool_capacity = num_buffers; - this->buffer_pool_buf_size = buf_size; - this->buffer_pool_alloc = ref->buffer_pool_alloc; - this->buffer_pool_try_alloc = ref->buffer_pool_try_alloc; - - for (i = 0; i<num_buffers; i++) { - buf_element_t *buf; - - buf = calloc(1, sizeof (buf_element_t)); - - buf->mem = multi_buffer; - multi_buffer += buf_size; - - buf->max_size = buf_size; - buf->free_buffer = buffer_pool_free; - buf->source = this; - buf->extra_info = malloc(sizeof(extra_info_t)); - - buffer_pool_free (buf); - } - - LOGDBG("fifo_buffer_new done."); - return this; -} -#endif - -static void flush_all_fifos (vdr_input_plugin_t *this, int full) -{ - if (this->read_buffer) { - this->read_buffer->free_buffer(this->read_buffer); - this->read_buffer = NULL; - } - - if (this->udp_data) { - int i; - for (i = 0; i <= UDP_SEQ_MASK; i++) - if (this->udp_data->queue[i]) { - this->udp_data->queue[i]->free_buffer(this->udp_data->queue[i]); - this->udp_data->queue[i] = NULL; - } - } - - if (full) { - if (this->stream && this->stream->audio_fifo) - this->stream->audio_fifo->clear(this->stream->audio_fifo); - if (this->stream && this->stream->video_fifo) - this->stream->video_fifo->clear(this->stream->video_fifo); - } - - if (this->iframe_buffer) - this->iframe_buffer->clear(this->iframe_buffer); - if (this->block_buffer) - this->block_buffer->clear(this->block_buffer); - if (this->hd_buffer) - this->hd_buffer->clear(this->hd_buffer); -} - -static buf_element_t *get_buf_element(vdr_input_plugin_t *this, int size, int force) -{ - buf_element_t *buf = NULL; - - /* HD buffer */ - if (this->hd_stream && size <= HD_BUF_ELEM_SIZE) { - buf = this->hd_buffer->buffer_pool_try_alloc(this->hd_buffer); - if (!force && !buf) - return NULL; - } - - /* limit max. buffered data */ - if(!force && !buf) { - int buffer_limit = this->buffer_pool->buffer_pool_capacity - this->max_buffers; - if (this->buffer_pool->buffer_pool_num_free < buffer_limit) - return NULL; - } - - /* get smallest possible buffer */ - if(!buf) { - if(size < 8000) - buf = this->buffer_pool->buffer_pool_try_alloc(this->buffer_pool); - else if(size < 0xffff) { - buf = this->block_buffer->buffer_pool_try_alloc(this->block_buffer); - LOGDBG("get_buf_element: big PES (%d bytes) !", size); - } - else { /* len>64k */ - LOGDBG("get_buf_element: jumbo PES (%d bytes) !", size); - } - } - - /* final try from audio fifo */ - if(!buf) - buf = this->stream->audio_fifo->buffer_pool_try_alloc(this->stream->audio_fifo); - - if(buf) { - buf->content = buf->mem; - buf->size = 0; - buf->type = BUF_DEMUX_BLOCK; - buf->pts = 0; - - buf->free_buffer = buffer_pool_free; - } - - return buf; -} - -static buf_element_t *get_buf_element_timed(vdr_input_plugin_t *this, int size, int timeout) -{ - buf_element_t *buf = get_buf_element (this, size, 0); - if (!buf) { - int result = 0; - fifo_buffer_t *fifo = this->hd_stream ? this->hd_buffer : this->buffer_pool; - struct timespec abstime; - create_timeout_time (&abstime, timeout); - - do { - mutex_lock_cancellable (&fifo->buffer_pool_mutex); - result = pthread_cond_timedwait (&fifo->buffer_pool_cond_not_empty, &fifo->buffer_pool_mutex, &abstime); - mutex_unlock_cancellable (&fifo->buffer_pool_mutex); - buf = get_buf_element (this, size, 0); - } while (!buf && !result); - } - return buf; -} - -static void strip_network_headers(vdr_input_plugin_t *this, buf_element_t *buf) -{ - if (buf->type == BUF_NETWORK_BLOCK) { - if (this->udp || this->rtp) { - stream_udp_header_t *header = (stream_udp_header_t *)buf->content; - this->curpos = header->pos; - buf->content += sizeof(stream_udp_header_t); - buf->size -= sizeof(stream_udp_header_t); - } else { - stream_tcp_header_t *header = (stream_tcp_header_t *)buf->content; - this->curpos = header->pos; - buf->content += sizeof(stream_tcp_header_t); - buf->size -= sizeof(stream_tcp_header_t); - } - buf->type = BUF_DEMUX_BLOCK; - } -} - -static void put_control_buf(fifo_buffer_t *buffer, fifo_buffer_t *pool, int cmd) -{ - buf_element_t *buf = pool->buffer_pool_try_alloc(pool); - if(buf) { - buf->type = cmd; - buffer->put(buffer, buf); - } -} - -static void queue_blank_yv12(vdr_input_plugin_t *this) -{ - int ratio = _x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_RATIO); - double dratio; - - if(!this || !this->stream) - return; - - if(ratio > 13300 && ratio < 13400) dratio = 4.0/3.0; - else if(ratio > 17700 && ratio < 17800) dratio = 16.0/9.0; - else if(ratio > 21000 && ratio < 22000) dratio = 2.11/1.0; - else dratio = ((double)ratio)/10000.0; - - if(this->stream && this->stream->video_out) { - - vo_frame_t *img = NULL; - int width = _x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH); - int height = _x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT); - - if (width >= 360 && height >= 288 && width <= 1920 && height <= 1200) { - this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1); - img = this->stream->video_out->get_frame (this->stream->video_out, - width, height, - dratio, XINE_IMGFMT_YV12, - VO_BOTH_FIELDS); - this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1); - } else { - LOGMSG("queue_blank_yv12: invalid dimensions %dx%d in stream_info !", width, height); - } - - if(img) { - if(img->format == XINE_IMGFMT_YV12 && img->base[0] && img->base[1] && img->base[2]) { - if(img->pitches[0] < width) - width = img->pitches[0]; - if(img->width < width) - width = img->width; - if(img->height < height) - height = img->height; - memset( img->base[0], 0x00, width * height); - memset( img->base[1], 0x80, width * height / 4 ); - memset( img->base[2], 0x80, width * height / 4 ); - img->duration = 3600; - img->pts = 3600; - img->bad_frame = 0; - img->draw(img, this->stream); - } - img->free(img); - } - } - - this->still_mode = 0; - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode); -} - -static void queue_nosignal(vdr_input_plugin_t *this) -{ -#define extern static -#include "nosignal_720x576.c" -#undef extern - char *data = NULL, *tmp = NULL; - int datalen = 0, pos = 0; - buf_element_t *buf = NULL; - char *path, *home; - - if(this->stream->video_fifo->num_free(this->stream->video_fifo) < 10) { - LOGMSG("queue_nosignal: not enough free buffers (%d) !", - this->stream->video_fifo->num_free(this->stream->video_fifo)); - return; - } - - if(asprintf(&home,"%s/.xine/nosignal.mpg", xine_get_homedir()) < 0) - return; - int fd = open(path=home, O_RDONLY); - if(fd<0) fd = open(path="/etc/vdr/plugins/xineliboutput/nosignal.mpg", O_RDONLY); - if(fd<0) fd = open(path="/etc/vdr/plugins/xine/noSignal.mpg", O_RDONLY); - if(fd<0) fd = open(path="/video/plugins/xineliboutput/nosignal.mpg", O_RDONLY); - if(fd<0) fd = open(path="/video/plugins/xine/noSignal.mpg", O_RDONLY); - if(fd<0) fd = open(path=NOSIGNAL_IMAGE_FILE, O_RDONLY); - if(fd>=0) { - tmp = data = malloc(NOSIGNAL_MAX_SIZE); - datalen = read(fd, data, NOSIGNAL_MAX_SIZE); - if(datalen==NOSIGNAL_MAX_SIZE) { - LOGMSG("WARNING: custom \"no signal\" image %s too large", path); - } else if(datalen<=0) { - LOGERR("error reading %s", path); - } else { - LOGMSG("using custom \"no signal\" image %s", path); - } - close(fd); - } - free(home); - - if(datalen<=0) { - data = (char*)&v_mpg_nosignal[0]; - datalen = v_mpg_nosignal_length; - } - - /* need to reset decoder if video format is not the same */ - _x_demux_control_start(this->stream); - - while(pos < datalen) { - buf = this->stream->video_fifo->buffer_pool_try_alloc(this->stream->video_fifo); - if(buf) { - buf->content = buf->mem; - buf->size = MIN(datalen - pos, buf->max_size); - buf->type = BUF_VIDEO_MPEG; - xine_fast_memcpy(buf->content, &data[pos], buf->size); - pos += buf->size; - if(pos >= datalen) - buf->decoder_flags |= BUF_FLAG_FRAME_END; - this->stream->video_fifo->put(this->stream->video_fifo, buf); - } else { - LOGMSG("Error: queue_nosignal: no buffers !"); - break; - } - } - - put_control_buf(this->stream->video_fifo, this->stream->video_fifo, BUF_CONTROL_FLUSH_DECODER); - put_control_buf(this->stream->video_fifo, this->stream->video_fifo, BUF_CONTROL_NOP); - - free(tmp); -} - - -/*************************** slave input (PIP stream) ********************/ - -typedef struct fifo_input_plugin_s { - input_plugin_t i; - vdr_input_plugin_t *master; - xine_stream_t *stream; - fifo_buffer_t *buffer; - fifo_buffer_t *buffer_pool; - off_t pos; -} fifo_input_plugin_t; - -static int fifo_open(input_plugin_t *this_gen) -{ return 1; } -static uint32_t fifo_get_capabilities (input_plugin_t *this_gen) -{ return INPUT_CAP_BLOCK; } -static uint32_t fifo_get_blocksize (input_plugin_t *this_gen) -{ return 2 * 2048; } -static off_t fifo_get_current_pos (input_plugin_t *this_gen) -{ return -1; } -static off_t fifo_get_length (input_plugin_t *this_gen) -{ return -1; } -static off_t fifo_seek (input_plugin_t *this_gen, off_t offset, int origin) -{ return offset; } -static int fifo_get_optional_data (input_plugin_t *this_gen, void *data, int data_type) -{ return INPUT_OPTIONAL_UNSUPPORTED; } -#if XINE_VERSION_CODE > 10103 -static const char* fifo_get_mrl (input_plugin_t *this_gen) -#else -static char* fifo_get_mrl (input_plugin_t *this_gen) -#endif -{ return MRL_ID "+slave:"; } - -#if XINE_VERSION_CODE < 10190 -static off_t fifo_read (input_plugin_t *this_gen, char *buf, off_t len) -#else -static off_t fifo_read (input_plugin_t *this_gen, void *buf, off_t len) -#endif -{ - int got = 0; - LOGERR("fifo_input_plugin::fifo_read() not implemented !"); - exit(-1); /* assert(false); */ - return got; -} - -static buf_element_t *fifo_read_block (input_plugin_t *this_gen, - fifo_buffer_t *fifo, off_t todo) -{ - fifo_input_plugin_t *this = (fifo_input_plugin_t *) this_gen; - /*LOGDBG("fifo_read_block");*/ - - while(!this->stream->demux_action_pending) { - buf_element_t *buf = fifo_buffer_try_get(this->buffer); - if(buf) { - /* LOGDBG("fifo_read_block: got, return"); */ - return buf; - } - /* LOGDBG("fifo_read_block: no buf, poll..."); */ - /* poll(NULL, 0, 10); */ - xine_usec_sleep(5*1000); - /* LOGDBG("fifo_read_block: poll timeout"); */ - } - - LOGDBG("fifo_read_block: return NULL !"); - errno = EAGAIN; - return NULL; -} - -static void fifo_dispose (input_plugin_t *this_gen) -{ - fifo_input_plugin_t *this = (fifo_input_plugin_t *) this_gen; - LOGDBG("fifo_dispose"); - - if(this) { - if(this->buffer) - this->buffer->dispose(this->buffer); - free(this); - } -} - -static input_plugin_t *fifo_class_get_instance (input_class_t *class_gen, - xine_stream_t *stream, - const char *data) -{ - fifo_input_plugin_t *slave = calloc(1, sizeof(fifo_input_plugin_t)); - unsigned long int imaster; - vdr_input_plugin_t *master; - LOGDBG("fifo_class_get_instance"); - - sscanf(data+15, "%lx", &imaster); - master = (vdr_input_plugin_t*)imaster; - - slave->master = (vdr_input_plugin_t*)master; - slave->stream = stream; - slave->buffer_pool = stream->video_fifo; - slave->buffer = fifo_buffer_new(stream, 4, 4096); - slave->i.open = fifo_open; - slave->i.get_mrl = fifo_get_mrl; - slave->i.dispose = fifo_dispose; - slave->i.input_class = class_gen; - slave->i.get_capabilities = fifo_get_capabilities; - slave->i.read = fifo_read; - slave->i.read_block = fifo_read_block; - slave->i.seek = fifo_seek; - slave->i.get_current_pos = fifo_get_current_pos; - slave->i.get_length = fifo_get_length; - slave->i.get_blocksize = fifo_get_blocksize; - slave->i.get_optional_data = fifo_get_optional_data; - - return (input_plugin_t*)slave; -} - - -/******************************** OSD ************************************/ - -static xine_rle_elem_t *uncompress_osd_net(uint8_t *raw, int elems, int datalen) -{ - xine_rle_elem_t *data = (xine_rle_elem_t*)malloc(elems*sizeof(xine_rle_elem_t)); - int i; - - /* - * xine-lib rle format: - * - palette index and length are uint16_t - * - * network format: - * - palette entry is uint8_t - * - length is uint8_t for lengths <=0x7f and uint16_t for lengths >0x7f - * - high-order bit of first byte is used to signal size of length field: - * bit=0 -> 7-bit, bit=1 -> 15-bit - */ - - for(i=0; i<elems; i++) { - if((*raw) & 0x80) { - data[i].len = ((*(raw++)) & 0x7f) << 8; - data[i].len |= *(raw++); - } else - data[i].len = *(raw++); - data[i].color = *(raw++); - } - - return data; -} - -/* - * vdr_plugin_exec_osd_command() - * - * - entry point for VDR-based osd_command_t events - */ -static int vdr_plugin_exec_osd_command(vdr_input_plugin_if_t *this_if, - osd_command_t *cmd) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if; - - if (this->fd_control >= 0 && /* remote mode */ - this->funcs.intercept_osd /* frontend handles OSD */ ) { - return this->funcs.intercept_osd(this->funcs.fe_handle, cmd) ? CONTROL_OK : CONTROL_DISCONNECTED; - } - - return this->osd_manager->command(this->osd_manager, cmd, this->slave_stream ?: this->stream); -} - - -/******************************* Control *********************************/ - -#if XINE_VERSION_CODE < 10111 -# define DEMUX_MUTEX_LOCK -# define DEMUX_MUTEX_UNLOCK -# define DEMUX_RESUME_SIGNAL -#else -# define DEMUX_MUTEX_LOCK pthread_mutex_lock(&stream->demux_mutex) -# define DEMUX_MUTEX_UNLOCK pthread_mutex_unlock(&stream->demux_mutex) -# define DEMUX_RESUME_SIGNAL pthread_cond_signal(&this->stream->demux_resume) -#endif - -static void suspend_demuxer(vdr_input_plugin_t *this) -{ - this->stream->demux_action_pending = 1; - signal_buffer_not_empty(this); - if(this->is_paused) - LOGMSG("WARNING: called suspend_demuxer in paused mode !"); - pthread_mutex_lock( &this->stream->demux_lock ); - this->stream->demux_action_pending = 0; - /* must be paired with resume_demuxer !!! */ -} - -static void resume_demuxer(vdr_input_plugin_t *this) -{ - /* must be paired with suspend_demuxer !!! */ - DEMUX_RESUME_SIGNAL; - pthread_mutex_unlock( &this->stream->demux_lock ); -} - -static void vdr_x_demux_control_newpts( xine_stream_t *stream, int64_t pts, - uint32_t flags ) -{ - buf_element_t *buf; - - DEMUX_MUTEX_LOCK; - - buf = stream->video_fifo ? stream->video_fifo->buffer_pool_try_alloc (stream->video_fifo) : NULL; - if(buf) { - buf->type = BUF_CONTROL_NEWPTS; - buf->decoder_flags = flags; - buf->disc_off = pts; - stream->video_fifo->put (stream->video_fifo, buf); - } else { - LOGMSG("vdr_x_demux_control_newpts: video fifo full !"); - } - - buf = stream->audio_fifo ? stream->audio_fifo->buffer_pool_try_alloc (stream->audio_fifo) : NULL; - if (buf) { - buf->type = BUF_CONTROL_NEWPTS; - buf->decoder_flags = flags; - buf->disc_off = pts; - stream->audio_fifo->put (stream->audio_fifo, buf); - } else { - LOGMSG("vdr_x_demux_control_newpts: audio fifo full !"); - } - - DEMUX_MUTEX_UNLOCK; -} - -static void vdr_flush_engine(vdr_input_plugin_t *this, uint64_t discard_index) -{ - if(this->stream_start) { - LOGMSG("vdr_flush_engine: stream_start, flush skipped"); - return; - } - - if(this->curpos > discard_index) { - if(this->curpos < this->guard_index) { - LOGMSG("vdr_flush_engine: guard > curpos, flush skipped"); - return; - } - LOGMSG("vdr_flush_engine: %"PRIu64" < current position %"PRIu64", flush skipped", - discard_index, this->curpos); - return; - } - - /* reset speed */ - if(xine_get_param(this->stream, XINE_PARAM_FINE_SPEED) <= 0) { - LOGMSG("vdr_flush_engine: playback is paused <0>"); - xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL); - } - - /* suspend demuxer */ - this->stream->demux_action_pending = 1; - pthread_cond_broadcast(&this->engine_flushed); - if(pthread_mutex_unlock( &this->lock )) /* to let demuxer return from vdr_plugin_read_* */ - LOGERR("pthread_mutex_unlock failed !"); - suspend_demuxer(this); - pthread_mutex_lock( &this->lock ); - - reset_scr_tuning(this, this->speed_before_pause); - - /* reset speed again (adjust_realtime_speed might have set pause) */ - if(xine_get_param(this->stream, XINE_PARAM_FINE_SPEED) <= 0) { - LOGMSG("vdr_flush_engine: playback is paused <1>"); - xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL); - } - -#if 0 - _x_demux_flush_engine (this->stream); - /* warning: after clearing decoders fifos an absolute discontinuity - * indication must be sent. relative discontinuities are likely - * to cause "jumps" on metronom. - */ -#else - this->stream->demux_plugin->seek (this->stream->demux_plugin, - 0, 0, this->stream->demux_thread_running); -#endif - -#if XINE_VERSION_CODE < 10104 - /* disabled _x_demux_control_start as it causes alsa output driver to exit now and then ... */ -#else - _x_demux_control_start(this->stream); -#endif - this->stream_start = 1; - this->I_frames = this->B_frames = this->P_frames = 0; - this->discard_index = discard_index; - - resume_demuxer(this); -} - -static int set_deinterlace_method(vdr_input_plugin_t *this, const char *method_name) -{ - int method = 0; - if(!strncasecmp(method_name,"bob",3)) { method = 1; - } else if(!strncasecmp(method_name,"weave",5)) { method = 2; - } else if(!strncasecmp(method_name,"greedy",6)) { method = 3; - } else if(!strncasecmp(method_name,"onefield",8)) { method = 4; - } else if(!strncasecmp(method_name,"onefield_xv",11)) { method = 5; - } else if(!strncasecmp(method_name,"linearblend",11)) { method = 6; - } else if(!strncasecmp(method_name,"none",4)) { method = 0; - } else if(!*method_name) { method = 0; - } else if(!strncasecmp(method_name,"tvtime",6)) { method = -1; - /* old deinterlacing system must be switched off. - tvtime will be configured as all other post plugins with - "POST tvtime ..." control message */ - } else return -2; - - this->class->xine->config->update_num(this->class->xine->config, - "video.output.xv_deinterlace_method", - method >= 0 ? method : 0); - xine_set_param(this->stream, XINE_PARAM_VO_DEINTERLACE, method ? 1 : 0); - - return 0; -} - -static int set_video_properties(vdr_input_plugin_t *this, - int hue, int saturation, - int brightness, int sharpness, - int noise_reduction, int contrast, - int vo_aspect_ratio) -{ - pthread_mutex_lock(&this->lock); - - /* when changed first time, save original/default values */ - if(!this->video_properties_saved && - (hue>=0 || saturation>=0 || contrast>=0 || brightness>=0 || - sharpness>=0 || noise_reduction>=0 || vo_aspect_ratio>=0)) { - this->video_properties_saved = 1; - this->orig_hue = xine_get_param(this->stream, - XINE_PARAM_VO_HUE ); - this->orig_saturation = xine_get_param(this->stream, - XINE_PARAM_VO_SATURATION ); - this->orig_brightness = xine_get_param(this->stream, - XINE_PARAM_VO_BRIGHTNESS ); -#ifdef XINE_PARAM_VO_SHARPNESS - this->orig_sharpness = xine_get_param(this->stream, - XINE_PARAM_VO_SHARPNESS ); -#endif -#ifdef XINE_PARAM_VO_NOISE_REDUCTION - this->orig_noise_reduction = xine_get_param(this->stream, - XINE_PARAM_VO_NOISE_REDUCTION ); -#endif - this->orig_contrast = xine_get_param(this->stream, - XINE_PARAM_VO_CONTRAST ); - this->orig_vo_aspect_ratio = xine_get_param(this->stream, - XINE_PARAM_VO_ASPECT_RATIO ); - } - - /* set new values, or restore default/original values */ - if(hue>=0 || this->video_properties_saved) - xine_set_param(this->stream, XINE_PARAM_VO_HUE, - hue>=0 ? hue : this->orig_hue ); - if(saturation>=0 || this->video_properties_saved) - xine_set_param(this->stream, XINE_PARAM_VO_SATURATION, - saturation>0 ? saturation : this->orig_saturation ); - if(brightness>=0 || this->video_properties_saved) - xine_set_param(this->stream, XINE_PARAM_VO_BRIGHTNESS, - brightness>=0 ? brightness : this->orig_brightness ); -#ifdef XINE_PARAM_VO_SHARPNESS - if(sharpness>=0 || this->video_properties_saved) - xine_set_param(this->stream, XINE_PARAM_VO_SHARPNESS, - sharpness>=0 ? sharpness : this->orig_sharpness ); -#endif -#ifdef XINE_PARAM_VO_NOISE_REDUCTION - if(noise_reduction>=0 || this->video_properties_saved) - xine_set_param(this->stream, XINE_PARAM_VO_NOISE_REDUCTION, - noise_reduction>=0 ? noise_reduction : this->orig_noise_reduction ); -#endif - if(contrast>=0 || this->video_properties_saved) - xine_set_param(this->stream, XINE_PARAM_VO_CONTRAST, - contrast>=0 ? contrast : this->orig_contrast ); - if(vo_aspect_ratio>=0 || this->video_properties_saved) - xine_set_param(this->stream, XINE_PARAM_VO_ASPECT_RATIO, - vo_aspect_ratio>=0 ? vo_aspect_ratio : this->orig_vo_aspect_ratio ); - - if(hue<0 && saturation<0 && contrast<0 && brightness<0 && sharpness<0 && noise_reduction<0 && vo_aspect_ratio<0) - this->video_properties_saved = 0; - - pthread_mutex_unlock(&this->lock); - return 0; -} - -static int set_live_mode(vdr_input_plugin_t *this, int onoff) -{ - pthread_mutex_lock(&this->lock); - - if(this->live_mode != onoff) { - config_values_t *config = this->class->xine->config; - this->live_mode = onoff; - - this->stream->metronom->set_option(this->stream->metronom, - METRONOM_PREBUFFER, METRONOM_PREBUFFER_VAL); - - if(this->live_mode || (this->fd_control >= 0 && !this->slave_stream)) - config->update_num(config, "audio.synchronization.av_sync_method", 1); -#if 0 - /* does not work after playing music files (?) */ - else - config->update_num(config, "audio.synchronization.av_sync_method", 0); -#endif - - } - - /* set buffer usage limits */ - this->max_buffers = this->buffer_pool->buffer_pool_capacity; - if(this->live_mode && this->fd_control < 0) - this->max_buffers >>= 1; - this->max_buffers -= 10; - - if(this->no_video) - this->max_buffers = RADIO_MAX_BUFFERS; - - /* SCR tuning */ - if(this->live_mode) { -#ifndef TEST_SCR_PAUSE - LOGSCR("pause scr tuning by set_live_mode"); - scr_tuning_set_paused(this); -#endif - } else { - LOGSCR("reset scr tuning by set_live_mode"); - reset_scr_tuning(this, this->speed_before_pause=XINE_FINE_SPEED_NORMAL); - } - - this->still_mode = 0; - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode); - - pthread_mutex_unlock(&this->lock); - - signal_buffer_pool_not_empty(this); - return 0; -} - -static int set_playback_speed(vdr_input_plugin_t *this, int speed) -{ -/* speed: - <0 - show each abs(n)'th frame (drop other frames) - * no audio - 0 - paused - * audio back if mute != 0 - >0 - show each frame n times - * no audio - 1 - normal -*/ - pthread_mutex_lock(&this->lock); - this->is_paused = 0; - if(speed == 0) { - this->is_paused = 1; - } else if(speed>64 || speed<-64) { - pthread_mutex_unlock(&this->lock); - return -2; - } - - if(speed > 1 || speed < -1) { - reset_scr_tuning(this, -1); - this->is_trickspeed = 1; - } else { - this->is_trickspeed = 0; - } - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode || speed==0); - - if(speed>0) - speed = this->speed_before_pause = XINE_FINE_SPEED_NORMAL/speed; - else - speed = this->speed_before_pause = XINE_FINE_SPEED_NORMAL*(-speed); - - if(this->scr_tuning != SCR_TUNING_PAUSED && - _x_get_fine_speed(this->stream) != speed) { - _x_set_fine_speed (this->stream, speed); - } - - if(this->slave_stream) - _x_set_fine_speed (this->slave_stream, speed); - - pthread_mutex_unlock(&this->lock); - return 0; -} - -static void send_meta_info(vdr_input_plugin_t *this) -{ - if(this->slave_stream) { - - /* send stream meta info */ - char *meta = NULL; - char *title = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_TITLE); - char *artist = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_ARTIST); - char *album = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_ALBUM); - char *tracknumber = (char *)xine_get_meta_info(this->slave_stream, XINE_META_INFO_TRACK_NUMBER); - - if(asprintf(&meta, - "INFO METAINFO title=@%s@ artist=@%s@ album=@%s@ tracknumber=@%s@\r\n", - title?:"", artist?:"", album?:"", tracknumber?:"") < 0) - return; - - if(this->fd_control < 0) - this->funcs.xine_input_event(meta, NULL); - else - write_control(this, meta); - - free(meta); - } -} - -#ifdef DVD_STREAMING_SPEED -static void dvd_set_speed(const char *device, int speed) -{ - /* - * Original idea & code from mplayer-dev-eng mailing list: - * Date: Sun, 17 Dec 2006 09:15:30 +0100 - * From: Tobias Diedrich <ranma@xxxxxxxxxxxx> - * Subject: [MPlayer-dev-eng] Re: [PATCH] Add "-dvd-speed", use SET_STREAMING command to quieten DVD drives - * (http://lists-archives.org/mplayer-dev-eng/14383-add-dvd-speed-use-set_streaming-command-to-quieten-dvd-drives.html) - */ -#if defined(__linux__) && defined(SG_IO) && defined(GPCMD_SET_STREAMING) - unsigned char buffer[28], cmd[16], sense[16]; - struct sg_io_hdr sghdr; - struct stat st; - int fd; - - /* remember previous device so we can restore default speed */ - static int dvd_speed = 0; - static const char *dvd_dev = NULL; - if (speed < 0 && dvd_speed == 0) return; /* we haven't touched the speed setting */ - if (!device) device = dvd_dev; /* use previous device */ - if (!device) return; - if (!speed) return; - - if (stat(device, &st) == -1) return; - - if (!S_ISBLK(st.st_mode)) return; /* not a block device */ - - if ((fd = open(device, O_RDWR | O_NONBLOCK)) == -1) { - LOGMSG("set_dvd_speed: error opening DVD device %s for read/write", device); - return; - } - - memset(&sghdr, 0, sizeof(sghdr)); - memset(buffer, 0, sizeof(buffer)); - memset(sense, 0, sizeof(sense)); - memset(cmd, 0, sizeof(cmd)); - - if(speed < 0) { - /* restore default value */ - speed = 0; - buffer[0] = 4; /* restore default */ - LOGMSG("Setting DVD streaming speed to <default>"); - } else { - /* limit to <speed> KB/s */ - LOGMSG("Setting DVD streaming speed to %d", speed); - } - - sghdr.interface_id = 'S'; - sghdr.timeout = 5000; - sghdr.dxfer_direction = SG_DXFER_TO_DEV; - sghdr.mx_sb_len = sizeof(sense); - sghdr.dxfer_len = sizeof(buffer); - sghdr.cmd_len = sizeof(cmd); - sghdr.sbp = sense; - sghdr.dxferp = buffer; - sghdr.cmdp = cmd; - - cmd[0] = GPCMD_SET_STREAMING; - cmd[10] = 28; - - buffer[8] = 0xff; - buffer[9] = 0xff; - buffer[10] = 0xff; - buffer[11] = 0xff; - - buffer[12] = buffer[20] = (speed >> 24) & 0xff; /* <speed> kilobyte */ - buffer[13] = buffer[21] = (speed >> 16) & 0xff; - buffer[14] = buffer[22] = (speed >> 8) & 0xff; - buffer[15] = buffer[23] = speed & 0xff; - - buffer[18] = buffer[26] = 0x03; /* 1 second */ - buffer[19] = buffer[27] = 0xe8; - - if (ioctl(fd, SG_IO, &sghdr) < 0) - LOGERR("Failed setting DVD streaming speed to %d", speed); - else if(speed > 0) - LOGMSG("DVD streaming speed set to %d", speed); - else - LOGMSG("DVD streaming speed set to <default>"); - - dvd_speed = speed; - dvd_dev = device; - close(fd); -#else -# warning Changing DVD streaming speed not supported -#endif -} -#endif - -static void vdr_event_cb (void *user_data, const xine_event_t *event); - -static void select_spu_channel(xine_stream_t *stream, int channel) -{ - _x_select_spu_channel(stream, channel); - if (channel == SPU_CHANNEL_NONE) { - /* re-enable overlay for VDR OSD ... */ - if (stream->video_out) { - pthread_mutex_lock (&stream->frontend_lock); - stream->xine->port_ticket->acquire (stream->xine->port_ticket, 0); - - stream->video_out->enable_ovl (stream->video_out, 1); - - stream->xine->port_ticket->release (stream->xine->port_ticket, 0); - pthread_mutex_unlock (&stream->frontend_lock); - } - } -} - -static void dvd_menu_domain(vdr_input_plugin_t *this, int value) -{ - if (value) { - LOGDBG("dvd_menu_domain(1)"); - this->dvd_menu = 1; - this->slave_stream->spu_channel_user = SPU_CHANNEL_AUTO; - this->slave_stream->spu_channel = this->slave_stream->spu_channel_auto; - } else { - LOGDBG("dvd_menu_domain(0)"); - this->dvd_menu = 0; - } -} - -static int handle_control_playfile(vdr_input_plugin_t *this, const char *cmd) -{ - const char *pt = cmd + 9; - char filename[4096], av[256], *pav = av; - int loop = 0, pos = 0, err = 0, avsize = sizeof(av)-2, mix_streams = 0; - - while(*pt==' ') pt++; - - if(!strncmp(pt, "Loop ", 5)) { - loop = 1; - pt += 5; - while(*pt==' ') pt++; - } - - pos = atoi(pt); - - while(*pt && *pt != ' ') pt++; - while(*pt == ' ') pt++; - - /* audio visualization / audio/video mixing */ - while(*pt && *pt != ' ' && --avsize) - *pav++ = *pt++; - *pav = 0; - while(*pt == ' ') pt++; - mix_streams = (!strcmp(av, "Audio")) || (!strcmp(av, "Video")); - - strn0cpy(filename, pt, sizeof(filename)); - - this->autoplay_size = -1; - - if(*filename) { - int is_file_mrl = !strncmp(filename, "file:/", 6) ? 5 : 0; - this->loop_play = 0; - - if(this->slave_stream) - handle_control_playfile(this, "PLAYFILE 0"); - - LOGMSG("PLAYFILE (Loop: %d, Offset: %ds, File: %s %s)", - loop, pos, av, filename); - - /* check if it is really a file (not mrl) and try to access it */ - if(is_file_mrl || filename[0] == '/') { - struct stat st; - char *f = unescape_filename(filename); - errno = 0; - if(stat(f+is_file_mrl, &st)) { - if(errno == EACCES || errno == ELOOP) - LOGERR("Can't access file !"); - if(errno == ENOENT || errno == ENOTDIR) - LOGERR("File not found !"); - if(this->fd_control >= 0) { - char mrl[sizeof(filename)+256], mrlbase[256]; - char *host = strdup(strstr(this->mrl, "//")+2); - char *port = strchr(host, ':'); - char *sub = strstr(filename, "#subtitle:"); - int iport = port ? atoi(port+1) : DEFAULT_VDR_PORT; - if(port) *port = 0; - if(sub) *sub = 0; - snprintf(mrlbase, sizeof(mrlbase), "http://%s:%d/PLAYFILE", - host?:"127.0.0.1", iport); - sprintf(mrl, "%s%s", mrlbase, filename + is_file_mrl); - if(sub) { - sub += 10; /*strlen("#subtitle:");*/ - strcat(mrl, "#subtitle:"); - strcat(mrl, mrlbase); - strcat(mrl, sub); - } - free(host); - LOGMSG(" -> trying to stream from server (%s) ...", mrl); - strn0cpy(filename, mrl, sizeof(filename)); - } - } - free(f); - } - - if(!strcmp(filename,"dvd:/")) { -#if 0 - /* input/media_helper.c */ - eject_media(0); /* DVD tray in */ -#endif -#ifdef DVD_STREAMING_SPEED - xine_cfg_entry_t device; - if (xine_config_lookup_entry(this->class->xine, - "media.dvd.device", &device)) - dvd_set_speed(device.str_value, 2700); -#endif - } -#if XINE_VERSION_CODE < 10109 - else if(!strncmp(filename,"dvd:/", 5)) { - /* DVD plugin 'bug': unescaping is not implemented ... */ - char *mrl = unescape_filename(filename); - strn0cpy(filename, mrl, sizeof(filename)); - free(mrl); - } -#endif - - if(!this->slave_stream) { - this->slave_stream = xine_stream_new(this->class->xine, - this->stream->audio_out, - this->stream->video_out); - } - - if(!this->slave_event_queue) { - this->slave_event_queue = xine_event_new_queue (this->slave_stream); - xine_event_create_listener_thread (this->slave_event_queue, - vdr_event_cb, this); - } - select_spu_channel(this->slave_stream, SPU_CHANNEL_AUTO); - this->dvd_menu = 0; - - errno = 0; - err = !xine_open(this->slave_stream, filename); - if(err) { - LOGERR("Error opening file ! (File not found ? Unknown format ?)"); - *filename = 0; /* this triggers stop */ - } else { -#if 1 - if(this->stream->video_fifo->size(this->stream->video_fifo)) - LOGMSG("playfile: main stream video_fifo not empty ! (%d)", - this->stream->video_fifo->size(this->stream->video_fifo)); - - /* flush decoders and output fifos, close decoders and free frames. */ - _x_demux_control_start(this->stream); - xine_usec_sleep(50*1000); - - /* keep our own demux happy while playing another stream */ - set_playback_speed(this, 1); - this->live_mode = 1; - set_live_mode(this, 0); - set_playback_speed(this, 1); - reset_scr_tuning(this, this->speed_before_pause = XINE_FINE_SPEED_NORMAL); - this->slave_stream->metronom->set_option(this->slave_stream->metronom, - METRONOM_PREBUFFER, 90000); -#endif - - this->loop_play = loop; - err = !xine_play(this->slave_stream, 0, 1000 * pos); - if(err) { - LOGMSG("Error playing file"); - *filename = 0; /* this triggers stop */ - } else { - send_meta_info(this); - - if(this->funcs.fe_control) { - char tmp[128]; - int has_video; - sprintf(tmp, "SLAVE 0x%lx %s\r\n", - (unsigned long int)this->slave_stream, - mix_streams ? av : ""); - this->funcs.fe_control(this->funcs.fe_handle, tmp); - has_video = _x_stream_info_get(this->slave_stream, XINE_STREAM_INFO_HAS_VIDEO); - this->funcs.fe_control(this->funcs.fe_handle, - has_video ? "NOVIDEO 1\r\n" : "NOVIDEO 0\r\n"); - if(!has_video && !mix_streams && *av && strcmp(av, "none")) { - char str[128], *avopts; - if(NULL != (avopts = strchr(av, ':'))) - *avopts++ = 0; - else - avopts = ""; - snprintf(str, sizeof(str), "POST %s On %s\r\n", av, avopts); - str[sizeof(str)-1] = 0; - this->funcs.fe_control(this->funcs.fe_handle, str); - } else { - this->funcs.fe_control(this->funcs.fe_handle, "POST 0 Off\r\n"); - } - } - } - } - } - - /* next code is also executed after failed open, so no "} else { " */ - if(!*filename) { - LOGMSG("PLAYFILE <STOP>: Closing slave stream"); - this->loop_play = 0; - if(this->slave_stream) { - xine_stop(this->slave_stream); - - if (this->slave_event_queue) { - xine_event_dispose_queue (this->slave_event_queue); - this->slave_event_queue = NULL; - } - - if(this->funcs.fe_control) { - this->funcs.fe_control(this->funcs.fe_handle, "POST 0 Off\r\n"); - this->funcs.fe_control(this->funcs.fe_handle, "SLAVE 0x0\r\n"); - } - xine_close(this->slave_stream); - xine_dispose(this->slave_stream); - this->slave_stream = NULL; - - if(this->funcs.fe_control) - this->funcs.fe_control(this->funcs.fe_handle, "SLAVE CLOSED\r\n"); - - _x_demux_control_start(this->stream); - -#ifdef DVD_STREAMING_SPEED - dvd_set_speed(NULL, -1); -#endif - } - } - - return err ? CONTROL_PARAM_ERROR : CONTROL_OK; -} - -static int handle_control_grab(vdr_input_plugin_t *this, const char *cmd) -{ - int quality, width, height, jpeg; - jpeg = !strcmp(cmd+5,"JPEG"); - - if(3 == sscanf(cmd+5+4, "%d %d %d", &quality, &width, &height)) { - - if(this->fd_control >= 0) { - - grab_data_t *data = NULL; - LOGDBG("GRAB: jpeg=%d quality=%d w=%d h=%d", jpeg, quality, width, height); - - /* grab takes long time and we don't want to lose data connection - or interrupt video ... */ - if(pthread_mutex_unlock(&this->vdr_entry_lock)) - LOGERR("pthread_mutex_unlock failed"); - - if(this->funcs.fe_control) - data = (grab_data_t*)(this->funcs.fe_control(this->funcs.fe_handle, cmd)); - - if(data && data->size>0 && data->data) { - char s[128]; - sprintf(s, "GRAB %d %lu\r\n", this->token, (unsigned long)data->size); - mutex_lock_cancellable (&this->fd_control_lock); - write_control_data(this, s, strlen(s)); - write_control_data(this, data->data, data->size); - mutex_unlock_cancellable (&this->fd_control_lock); - } else { - /* failed */ - printf_control(this, "GRAB %d 0\r\n", this->token); - } - - pthread_mutex_lock(&this->vdr_entry_lock); - - if(data) { - free(data->data); - free(data); - } - - return CONTROL_OK; - } - } - - return CONTROL_PARAM_ERROR; -} - -static int handle_control_substream(vdr_input_plugin_t *this, const char *cmd) -{ - unsigned int pid; - if(1 == sscanf(cmd, "SUBSTREAM 0x%x", &pid)) { - pthread_mutex_lock(&this->lock); - - if(!this->funcs.fe_control) - LOGERR("ERROR - no fe_control set !"); - - if((pid & 0xf0) == 0xe0 && this->funcs.fe_control) { /* video 0...15 */ - if(!this->pip_stream) { -LOGMSG("create pip stream %s", cmd); - this->pip_stream = - this->funcs.fe_control(this->funcs.fe_handle, cmd); -LOGMSG(" pip stream created"); - } - } else { - /*} else if(audio) {*/ - if(this->pip_stream && this->funcs.fe_control) { - LOGMSG("close pip stream"); - - this->pip_stream = NULL; - this->funcs.fe_control(this->funcs.fe_handle, cmd); - /* xine_stop(this->pip_stream); */ - /* xine_close(this->pip_stream); */ - /* xine_dispose(this->pip_stream); */ - } - } - pthread_mutex_unlock(&this->lock); - return CONTROL_OK; - } - return CONTROL_PARAM_ERROR; -} - -static int handle_control_osdcmd(vdr_input_plugin_t *this) -{ - osd_command_t osdcmd = {0}; - int err = CONTROL_OK; - - if (!this->control_running) - return CONTROL_DISCONNECTED; - - /* read struct size first */ - size_t todo, expect = sizeof(osd_command_t); - uint8_t *pt = (uint8_t*)&osdcmd; - if (read_control(this, pt, sizeof(osdcmd.size)) != sizeof(osdcmd.size)) { - LOGMSG("control: error reading OSDCMD data length"); - return CONTROL_DISCONNECTED; - } - pt += sizeof(osdcmd.size); - expect -= sizeof(osdcmd.size); - todo = osdcmd.size - sizeof(osdcmd.size); - - /* read data */ - size_t bytes = MIN(todo, expect); - if (read_control(this, pt, bytes) != bytes) { - LOGMSG("control: error reading OSDCMD data"); - return CONTROL_DISCONNECTED; - } - - if (expect < todo) { - /* server uses larger struct, discard rest of data */ - uint8_t dummy[todo-expect]; - LOGMSG("osd_command_t size %d, expected %d", (int)osdcmd.size, (int)expect); - if (read_control(this, dummy, todo-expect) != todo-expect) { - LOGMSG("control: error reading OSDCMD data (unknown part)"); - return CONTROL_DISCONNECTED; - } - } - - ntoh_osdcmd(osdcmd); - - /* read palette */ - if (osdcmd.palette && osdcmd.colors>0) { - int bytes = sizeof(xine_clut_t)*(osdcmd.colors); - osdcmd.palette = malloc(bytes); - if (read_control(this, (unsigned char *)osdcmd.palette, bytes) != bytes) { - LOGMSG("control: error reading OSDCMD palette"); - err = CONTROL_DISCONNECTED; - } - } else { - osdcmd.palette = NULL; - } - - /* read (RLE) data */ - if (err == CONTROL_OK && osdcmd.data && osdcmd.datalen>0) { - osdcmd.data = (xine_rle_elem_t*)malloc(osdcmd.datalen); - if(read_control(this, (unsigned char *)osdcmd.data, osdcmd.datalen) - != osdcmd.datalen) { - LOGMSG("control: error reading OSDCMD bitmap"); - err = CONTROL_DISCONNECTED; - } else { - uint8_t *raw = osdcmd.raw_data; - osdcmd.data = uncompress_osd_net(raw, osdcmd.num_rle, osdcmd.datalen); - osdcmd.datalen = osdcmd.num_rle*4; - free(raw); - } - } else { - osdcmd.data = NULL; - } - - if (err == CONTROL_OK) - err = vdr_plugin_exec_osd_command(&this->iface, &osdcmd); - - free(osdcmd.data); - free(osdcmd.palette); - - return err; -} - -/************************** Control from VDR ******************************/ - -#define VDR_ENTRY_LOCK(ret...) \ - do { \ - if(pthread_mutex_lock(&this->vdr_entry_lock)) { \ - LOGERR("%s:%d: pthread_mutex_lock failed", __PRETTY_FUNCTION__, __LINE__); \ - return ret ; \ - } \ - } while(0) - -#define VDR_ENTRY_UNLOCK() \ - do { \ - if(pthread_mutex_unlock(&this->vdr_entry_lock)) { \ - LOGERR("%s:%d: pthread_mutex_unlock failed", __PRETTY_FUNCTION__, __LINE__); \ - } \ - } while(0) - -static const struct { - const uint32_t type; - const char name[28]; -} eventmap[] = { - {XINE_EVENT_INPUT_UP, "XINE_EVENT_INPUT_UP"}, - {XINE_EVENT_INPUT_DOWN, "XINE_EVENT_INPUT_DOWN"}, - {XINE_EVENT_INPUT_LEFT, "XINE_EVENT_INPUT_LEFT"}, - {XINE_EVENT_INPUT_RIGHT, "XINE_EVENT_INPUT_RIGHT"}, - {XINE_EVENT_INPUT_SELECT, "XINE_EVENT_INPUT_SELECT"}, - {XINE_EVENT_INPUT_MENU1, "XINE_EVENT_INPUT_MENU1"}, - {XINE_EVENT_INPUT_MENU2, "XINE_EVENT_INPUT_MENU2"}, - {XINE_EVENT_INPUT_MENU3, "XINE_EVENT_INPUT_MENU3"}, - {XINE_EVENT_INPUT_MENU4, "XINE_EVENT_INPUT_MENU4"}, - {XINE_EVENT_INPUT_MENU5, "XINE_EVENT_INPUT_MENU5"}, - {XINE_EVENT_INPUT_NEXT, "XINE_EVENT_INPUT_NEXT"}, - {XINE_EVENT_INPUT_PREVIOUS,"XINE_EVENT_INPUT_PREVIOUS"}, -}; - -/* - * vdr_plugin_poll() - * - * Query buffer state - * Returns amount of free PES buffer blocks in queue. - */ -static int vdr_plugin_poll(vdr_input_plugin_t *this, int timeout_ms) -{ - struct timespec abstime; - int result = 0; - - /* Caller must have locked this->vdr_entry_lock ! */ - - if(this->slave_stream) { - LOGMSG("vdr_plugin_poll: called while playing slave stream !"); - return 1; - } - - TRACE("vdr_plugin_poll (%d ms), buffer_pool: blocks=%d, bytes=%d", - timeout_ms, this->buffer_pool->size(this->buffer_pool), - this->buffer_pool->data_size(this->buffer_pool)); - - pthread_mutex_lock (&this->buffer_pool->buffer_pool_mutex); - result = this->buffer_pool->buffer_pool_num_free - - (this->buffer_pool->buffer_pool_capacity - this->max_buffers); - pthread_mutex_unlock (&this->buffer_pool->buffer_pool_mutex); - - if(timeout_ms > 0 && result <= 0) { - if(timeout_ms > 250) { - LOGMSG("vdr_plugin_poll: timeout too large (%d ms), forced to 250ms", timeout_ms); - timeout_ms = 250; - } - create_timeout_time(&abstime, timeout_ms); - pthread_mutex_lock(&this->lock); - if(this->scr_tuning == SCR_TUNING_PAUSED) { - LOGSCR("scr tuning reset by POLL"); - reset_scr_tuning(this,this->speed_before_pause); - } - pthread_mutex_unlock(&this->lock); - - signal_buffer_not_empty(this); - - VDR_ENTRY_UNLOCK(); - - pthread_mutex_lock (&this->buffer_pool->buffer_pool_mutex); - while(result <= 5) { - if(pthread_cond_timedwait (&this->buffer_pool->buffer_pool_cond_not_empty, - &this->buffer_pool->buffer_pool_mutex, - &abstime) == ETIMEDOUT) - break; - result = this->buffer_pool->buffer_pool_num_free - - (this->buffer_pool->buffer_pool_capacity - this->max_buffers); - } - pthread_mutex_unlock (&this->buffer_pool->buffer_pool_mutex); - VDR_ENTRY_LOCK(0); - } - - TRACE("vdr_plugin_poll returns, %d free (%d used, %d bytes)\n", result, - this->buffer_pool->size(this->buffer_pool), - this->buffer_pool->data_size(this->buffer_pool)); - - /* handle priority problem in paused mode when - data source has higher priority than control source */ - if(result <= 0) { - result = 0; - xine_usec_sleep(3*1000); - } - - return result; -} - -/* - * vdr_plugin_flush() - * - * Flush all data from buffers to output devices. - * Returns 0 when there is no data or frames in stream buffers. - */ -static int vdr_plugin_flush(vdr_input_plugin_t *this, int timeout_ms) -{ - struct timespec abstime; - fifo_buffer_t *pool = this->buffer_pool; - fifo_buffer_t *buffer = this->block_buffer; - int result = 0, waitresult=0; - - /* Caller must have locked this->vdr_entry_lock ! */ - - if(this->slave_stream) { - LOGDBG("vdr_plugin_flush: called while playing slave stream !"); - return 0; - } - - TRACE("vdr_plugin_flush (%d ms) blocks=%d+%d, frames=%d", timeout_ms, - buffer->size(buffer), pool->size(pool), - this->stream->video_out->get_property(this->stream->video_out, - VO_PROP_BUFS_IN_FIFO)); - - if(this->live_mode /*&& this->fd_control < 0*/) { - /* No flush in live mode */ - return 1; - } - - this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1); - result = MAX(0, pool->size(pool)) + - MAX(0, buffer->size(buffer)) + - this->stream->video_out->get_property(this->stream->video_out, - VO_PROP_BUFS_IN_FIFO); - this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1); - - put_control_buf(buffer, pool, BUF_CONTROL_FLUSH_DECODER); - put_control_buf(buffer, pool, BUF_CONTROL_NOP); - - if (result <= 0) - return 0; - - create_timeout_time(&abstime, timeout_ms); - - while(result > 0 && waitresult != ETIMEDOUT) { - TRACE("vdr_plugin_flush waiting (max %d ms), %d+%d buffers used, " - "%d frames (rd pos=%" PRIu64 ")\n", timeout_ms, - pool->size(pool), buffer->size(buffer), - (int)this->stream->video_out->get_property(this->stream->video_out, - VO_PROP_BUFS_IN_FIFO), - this->curpos); - - pthread_mutex_lock(&pool->buffer_pool_mutex); - waitresult = pthread_cond_timedwait (&pool->buffer_pool_cond_not_empty, - &pool->buffer_pool_mutex, &abstime); - pthread_mutex_unlock(&pool->buffer_pool_mutex); - - this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1); - result = MAX(0, pool->size(pool)) + - MAX(0, buffer->size(buffer)) + - this->stream->video_out->get_property(this->stream->video_out, - VO_PROP_BUFS_IN_FIFO); - this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1); - } - - TRACE("vdr_plugin_flush returns %d (%d+%d used, %d frames)\n", result, - pool->size(pool), buffer->size(buffer), - (int)this->stream->video_out->get_property(this->stream->video_out, - VO_PROP_BUFS_IN_FIFO)); - - return result; -} - -/* - * vdr_plugin_flush_remote() - * - * vdr_plugin_flush() Wrapper for remote mode - * - wait for data in network buffers - */ -static int vdr_plugin_flush_remote(vdr_input_plugin_t *this, int timeout_ms, - uint64_t offset, int frame) -{ - int r, live_mode; - - pthread_mutex_lock(&this->lock); - - live_mode = this->live_mode; - this->live_mode = 0; /* --> 1 again when data arrives ... */ - - LOGSCR("reset scr tuning by flush_remote"); - reset_scr_tuning(this, this->speed_before_pause); - - /* wait until all data has been received */ - while(this->curpos < offset && timeout_ms > 0) { - TRACE("FLUSH: wait position (%" PRIu64 " ; need %" PRIu64 ")", - this->curpos, offset); - pthread_mutex_unlock(&this->lock); - xine_usec_sleep(3*1000); - pthread_mutex_lock(&this->lock); - timeout_ms -= 3; - } - - LOGSCR("reset scr tuning by flush_remote"); - reset_scr_tuning(this, this->speed_before_pause); - - pthread_mutex_unlock(&this->lock); - - r = vdr_plugin_flush(this, MAX(5, timeout_ms)); - printf_control(this, "RESULT %d %d\r\n", this->token, r); - - pthread_mutex_lock(&this->lock); - - this->live_mode = live_mode; - this->stream->metronom->set_option(this->stream->metronom, - METRONOM_PREBUFFER, - METRONOM_PREBUFFER_VAL); - this->guard_index = offset; - - pthread_mutex_unlock(&this->lock); - - return CONTROL_OK; -} - -static int vdr_plugin_parse_control(vdr_input_plugin_if_t *this_if, const char *cmd) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if; - int err = CONTROL_OK, i, j; - int /*int32_t*/ tmp32 = 0; - uint64_t tmp64 = 0ULL; - xine_stream_t *stream = this->stream; - static const char str_poll[] = "POLL"; - char *pt; - - VDR_ENTRY_LOCK(CONTROL_DISCONNECTED); - - LOGCMD("vdr_plugin_parse_control: %s", cmd); - - if( !memcmp(cmd, str_poll, 4) || - !strncasecmp(cmd, "POLL ", 5)) { - tmp32 = atoi(cmd+5); - if(tmp32 >= 0 && tmp32 < 1000) { - if(this->fd_control >= 0) { - printf_control(this, "POLL %d\r\n", vdr_plugin_poll(this, tmp32)); - } else { - err = vdr_plugin_poll(this, tmp32); - } - } else { - err = CONTROL_PARAM_ERROR; - } - VDR_ENTRY_UNLOCK(); - return err; - } - - if(this->slave_stream) - stream = this->slave_stream; - - if(NULL != (pt = strstr(cmd, "\r\n"))) - *((char*)pt) = 0; /* auts */ - - /* very verbose logging ? */ - if (iSysLogLevel>3) - LOGDBG("<control> %s",cmd); - - if(!strncasecmp(cmd, "OSDCMD", 6)) { - err = handle_control_osdcmd(this); - - } else if(!strncasecmp(cmd, "VIDEO_PROPERTIES ", 17)) { - int hue, saturation, brightness, sharpness, noise_reduction, contrast, vo_aspect_ratio; - if(7 == sscanf(cmd+17, "%d %d %d %d %d %d %d", - &hue, &saturation, &brightness, &sharpness, &noise_reduction, &contrast, &vo_aspect_ratio)) - err = set_video_properties(this, hue, saturation, brightness, sharpness, noise_reduction, contrast, vo_aspect_ratio); - else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "OVERSCAN ", 9)) { - if(!this->funcs.fe_control) - LOGMSG("No fe_control function! %s failed.", cmd); - else - this->funcs.fe_control(this->funcs.fe_handle, cmd); - - } else if(!strncasecmp(cmd, "VO_ASPECT ", 10)) { - if(1 == sscanf(cmd+10, "%d", &tmp32)) { - xine_set_param(stream, XINE_PARAM_VO_ASPECT_RATIO, tmp32); - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "DEINTERLACE ", 12)) { - if(this->fd_control < 0) - err = set_deinterlace_method(this, cmd+12); - - } else if(!strncasecmp(cmd, "EVENT ", 6)) { - int i; - char *pt = strchr(cmd, '\n'); - if(pt) *pt=0; - pt = strstr(cmd+6, " CHAPTER"); - if(pt) { - *pt = 0; - this->class->xine->config->update_num(this->class->xine->config, - "media.dvd.skip_behaviour", 1); - } - pt = strstr(cmd+6, " TITLE"); - if(pt) { - *pt = 0; - this->class->xine->config->update_num(this->class->xine->config, - "media.dvd.skip_behaviour", 2); - } - for(i=0; i<sizeof(eventmap)/sizeof(eventmap[0]); i++) - if(!strcmp(cmd+6, eventmap[i].name)) { - xine_event_t ev = { - .type = eventmap[i].type, - .stream = this->slave_stream ?: this->stream, - /* tag event to prevent circular input events - (vdr -> here -> event_listener -> vdr -> ...) */ - .data = "VDR", - .data_length = 4, - }; - xine_event_send(ev.stream, &ev); - break; - } - - } else if(!strncasecmp(cmd, "VERSION ", 7)) { - if(strncmp(XINELIBOUTPUT_VERSION " ", cmd+8, - strlen(XINELIBOUTPUT_VERSION)+1)) { - if(this->fd_control < 0) { - /* Check should use protocol version. - * In remote mode check is done in connect */ - LOGMSG("WARNING! xineplug_inp_xvdr.so and libvdr-xineliboutput.so " - "are from different version (%s and %s)", XINELIBOUTPUT_VERSION, cmd+8); - LOGMSG("Re-install plugin !"); - /*abort();*/ - } - } - - } else if(!strncasecmp(cmd, "HDMODE ", 7)) { - if(1 == sscanf(cmd+7, "%d", &tmp32)) { - pthread_mutex_lock(&this->lock); - if(tmp32) { - if(!this->hd_buffer) - this->hd_buffer = fifo_buffer_new(this->stream, HD_BUF_NUM_BUFS, HD_BUF_ELEM_SIZE); - this->hd_stream = 1; - } else { - this->hd_stream = 0; - } - pthread_mutex_unlock(&this->lock); - } - - } else if(!strncasecmp(cmd, "NOVIDEO ", 8)) { - if(1 == sscanf(cmd+8, "%d", &tmp32)) { - pthread_mutex_lock(&this->lock); - this->no_video = tmp32; - if(this->no_video) { - this->max_buffers = RADIO_MAX_BUFFERS; - } else { - this->max_buffers = this->buffer_pool->buffer_pool_capacity; - if(!this->live_mode && this->fd_control < 0) - this->max_buffers >>= 1; - this->max_buffers -= 10; - } - pthread_mutex_unlock(&this->lock); - } else - err = CONTROL_PARAM_ERROR; - - signal_buffer_pool_not_empty(this); - - } else if(!strncasecmp(cmd, "DISCARD ", 8)) { - if(2 == sscanf(cmd+8, "%" PRIu64 " %d", &tmp64, &tmp32)) { - pthread_mutex_lock(&this->lock); - if(this->discard_index < tmp64) { - this->discard_frame = tmp32; - vdr_flush_engine(this, tmp64); - this->discard_index = tmp64; - } else if(this->discard_index != tmp64) { - LOGMSG("Ignoring delayed control message %s", cmd); - } - pthread_cond_broadcast(&this->engine_flushed); - pthread_mutex_unlock(&this->lock); - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "STREAMPOS ", 10)) { - if(1 == sscanf(cmd+10, "%" PRIu64, &tmp64)) { - pthread_mutex_lock(&this->lock); - vdr_flush_engine(this, tmp64); - this->curpos = tmp64; - this->discard_index = this->curpos; - this->guard_index = 0; - pthread_mutex_unlock(&this->lock); - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "TRICKSPEED ", 11)) { - err = (1 == sscanf(cmd+11, "%d", &tmp32)) ? - set_playback_speed(this, tmp32) : - CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "STILL ", 6)) { - pthread_mutex_lock(&this->lock); - /*if(this->fd_control >= 0) {*/ - if(1 == sscanf(cmd+6, "%d", &tmp32)) { - this->still_mode = tmp32; - if(this->still_mode) - reset_scr_tuning(this, this->speed_before_pause); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode); - this->stream_start = 1; - } else - err = CONTROL_PARAM_ERROR; - /*}*/ - pthread_mutex_unlock(&this->lock); - - } else if(!strncasecmp(cmd, "SCR ", 4)) { - pthread_mutex_lock(&this->lock); - if(1 == sscanf(cmd, "SCR Sync %d", &tmp32)) { - this->scr_live_sync = 1; - this->scr->set_speed_base(this->scr, tmp32); - } - else if(1 == sscanf(cmd, "SCR NoSync %d", &tmp32)) { - this->scr_live_sync = 0; - this->scr->set_speed_base(this->scr, tmp32); - reset_scr_tuning(this, -1); - } - pthread_mutex_unlock(&this->lock); - - } else if(!strncasecmp(cmd, "LIVE ", 5)) { - this->still_mode = 0; - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL, this->still_mode); - err = (1 == sscanf(cmd+5, "%d", &tmp32)) ? - set_live_mode(this, tmp32) : -2 ; - - } else if(!strncasecmp(cmd, "MASTER ", 7)) { - if(1 == sscanf(cmd+7, "%d", &tmp32)) - this->fixed_scr = tmp32 ? 1 : 0; - else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "VOLUME ", 7)) { - if(1 == sscanf(cmd+7, "%d", &tmp32)) { - int sw = strstr(cmd, "SW") ? 1 : 0; - if(!sw) { - xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, tmp32); - xine_set_param(stream, XINE_PARAM_AUDIO_MUTE, tmp32<=0 ? 1 : 0); - } else { - xine_set_param(stream, XINE_PARAM_AUDIO_AMP_LEVEL, tmp32); - xine_set_param(stream, XINE_PARAM_AUDIO_AMP_MUTE, tmp32<=0 ? 1 : 0); - } - if(sw != this->sw_volume_control) { - this->sw_volume_control = sw; - if(sw) { - xine_set_param(stream, XINE_PARAM_AUDIO_MUTE, 0); - } else { - xine_set_param(stream, XINE_PARAM_AUDIO_AMP_LEVEL, 100); - xine_set_param(stream, XINE_PARAM_AUDIO_AMP_MUTE, 0); - } - } - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "AUDIOCOMPRESSION ",17)) { - if(1 == sscanf(cmd+17, "%d", &tmp32)) { - xine_set_param(stream, XINE_PARAM_AUDIO_COMPR_LEVEL, tmp32); - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "AUDIOSURROUND ",14)) { - if(1 == sscanf(cmd+14, "%d", &tmp32)) { - this->class->xine->config->update_num(this->class->xine->config, - "audio.a52.surround_downmix", tmp32?1:0); - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "SPEAKERS ",9)) { - if(1 == sscanf(cmd+9, "%d", &tmp32)) { - this->class->xine->config->update_num(this->class->xine->config, - "audio.output.speaker_arrangement", tmp32); - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "EQUALIZER ", 10)) { - int eqs[XINE_PARAM_EQ_16000HZ - XINE_PARAM_EQ_30HZ + 2] = {0}; - sscanf(cmd+10,"%d %d %d %d %d %d %d %d %d %d", - eqs,eqs+1,eqs+2,eqs+3,eqs+4,eqs+5,eqs+6,eqs+7,eqs+8,eqs+9); - for(i=XINE_PARAM_EQ_30HZ,j=0; i<=XINE_PARAM_EQ_16000HZ; i++,j++) - xine_set_param(stream, i, eqs[j]); - - } else if(!strncasecmp(cmd, "AUDIOSTREAM ", 12)) { - if(!this->slave_stream) { -#if 0 - int ac3 = strncmp(cmd+12, "AC3", 3) ? 0 : 1; - if(1 == sscanf(cmd+12 + 4*ac3, "%d", &tmp32)) { - pthread_mutex_lock(&this->lock); - this->audio_stream_id = tmp32; - pthread_mutex_unlock(&this->lock); - } else { - err = CONTROL_PARAM_ERROR; - } -#endif - } else { - if(1 == sscanf(cmd+12, "AC3 %d", &tmp32)) { - tmp32 &= 0xff; - LOGDBG("Audio channel -> [%d]", tmp32); - xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, tmp32); - } - LOGDBG("Audio channel selected: [%d]", _x_get_audio_channel (stream)); - } - - } else if(!strncasecmp(cmd, "SPUSTREAM ", 10)) { - int old_ch = _x_get_spu_channel(stream); - int max_ch = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL); - int ch = old_ch; - int ch_auto = strstr(cmd+10, "auto") ? 1 : 0; - int is_dvd = 0; - - if (this->slave_stream && this->slave_stream->input_plugin) { - const char *mrl = this->slave_stream->input_plugin->get_mrl(this->slave_stream->input_plugin); - is_dvd = !strncmp(mrl, "dvd:/", 5); - } - - if(strstr(cmd+10, "NEXT")) - ch = ch < max_ch ? ch+1 : -2; - else if(strstr(cmd+10, "PREV")) - ch = ch > -2 ? ch-1 : max_ch-1; - else if(1 == sscanf(cmd+10, "%d", &tmp32)) { - ch = tmp32; - } else if(cmd[10] && cmd[11] && (cmd[12] < 'a' || cmd[12] > 'z')) { - /* ISO 639-1 language code */ - const char spu_lang[3] = {cmd[10], cmd[11], 0}; - LOGMSG("Preferred SPU language: %s", spu_lang); - this->class->xine->config->update_string(this->class->xine->config, - "media.dvd.language", spu_lang); - ch = old_ch = 0; - } else - err = CONTROL_PARAM_ERROR; - - if (old_ch == SPU_CHANNEL_AUTO) - old_ch = stream->spu_channel_auto; - - if (ch != old_ch) { - if (is_dvd && ch_auto && stream->spu_channel_user == SPU_CHANNEL_AUTO) { - LOGDBG("Automatic SPU channel %d->%d ignored", old_ch, ch); - } else { - LOGDBG("Forced SPU channel %d->%d", old_ch, ch); - select_spu_channel(stream, ch); - } - LOGDBG("SPU channel selected: [%d]", _x_get_spu_channel (stream)); - } - - } else if(!strncasecmp(cmd, "AUDIODELAY ", 11)) { - if(1 == sscanf(cmd+11, "%d", &tmp32)) - xine_set_param(stream, XINE_PARAM_AV_OFFSET, tmp32*90000/1000); - else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "SYNC ", 5)) { - if(this->fd_control >= 0) - write_control(this, cmd); - - } else if(!strncasecmp(cmd, "GETSTC", 6)) { - int64_t pts = xine_get_current_vpts(stream) - - stream->metronom->get_option(stream->metronom, - METRONOM_VPTS_OFFSET); - if(this->fd_control >= 0) { - printf_control(this, "STC %" PRId64 "\r\n", pts); - } else { - *((int64_t *)cmd) = pts; - } - - } else if(!strncasecmp(cmd, "FLUSH ", 6)) { - if(1 == sscanf(cmd+6, "%d", &tmp32)) { - if(this->fd_control >= 0) { - uint32_t frame = 0; - tmp64 = 0ULL; - tmp32 = 0; - sscanf(cmd+6, "%d %" PRIu64 " %d", &tmp32, &tmp64, &frame); - err = vdr_plugin_flush_remote(this, tmp32, tmp64, frame); - } else { - err = vdr_plugin_flush(this, tmp32); - } - } else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "TOKEN ", 6)) { - if(1 == sscanf(cmd+6, "%d", &tmp32)) - this->token = tmp32; - else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "SUBSTREAM ", 9)) { - err = handle_control_substream(this, cmd); - - } else if(!strncasecmp(cmd, "POST ", 5)) { - /* lock demuxer thread out of adjust_realtime_speed */ - pthread_mutex_lock(&this->lock); - if(!this->funcs.fe_control) - LOGMSG("No fe_control function! %s failed.", cmd); - else - this->funcs.fe_control(this->funcs.fe_handle, cmd); - pthread_mutex_unlock(&this->lock); - - } else if(!strncasecmp(cmd, "PLAYFILE ", 9)) { - err = handle_control_playfile(this, cmd); - if(this->fd_control >= 0) { - printf_control(this, "RESULT %d %d\r\n", this->token, err); - err = CONTROL_OK; - } - - } else if(!strncasecmp(cmd, "SEEK ", 5)) { - if(this->slave_stream) { - int pos_stream=0, pos_time=0, length_time=0; - xine_get_pos_length(this->slave_stream, - &pos_stream, &pos_time, &length_time); - if(cmd[5]=='+') - pos_time += atoi(cmd+6) * 1000; - else if(cmd[5]=='-') - pos_time -= atoi(cmd+6) * 1000; - else - pos_time = atoi(cmd+5) * 1000; - err = xine_play (this->slave_stream, 0, pos_time); - if(this->fd_control >= 0) - err = CONTROL_OK; - } - - } else if(!strncasecmp(cmd, "GETLENGTH", 9)) { - int pos_stream=0, pos_time=0, length_time=0; - xine_get_pos_length(stream, &pos_stream, &pos_time, &length_time); - err = length_time/*/1000*/; - if(this->fd_control >= 0) { - printf_control(this, "RESULT %d %d\r\n", this->token, err); - err = CONTROL_OK; - } - - } else if(!strncasecmp(cmd, "GETAUTOPLAYSIZE", 15)) { - - if (cmd[15]==' ' && cmd[16]) { - /* query from specific input plugin */ - const char *cls_name = cmd + 16; - this->autoplay_size = 0; - if (! xine_get_browse_mrls (stream->xine, - cls_name, - NULL, &this->autoplay_size)) - /* try older method */ - xine_get_autoplay_mrls(stream->xine, cls_name, &this->autoplay_size); - } - - if(this->autoplay_size < 0) { - char **list; - if(this->slave_stream && - this->slave_stream->input_plugin && - this->slave_stream->input_plugin->input_class) - list = this->slave_stream->input_plugin->input_class-> - get_autoplay_list(this->slave_stream->input_plugin->input_class, &this->autoplay_size); - } - err = this->autoplay_size; - if(this->fd_control >= 0) { - printf_control(this, "RESULT %d %d\r\n", this->token, err); - err = CONTROL_OK; - } - - } else if(!strncasecmp(cmd, "GETPOS", 6)) { - int pos_stream=0, pos_time=0, length_time=0; - xine_get_pos_length(stream, &pos_stream, &pos_time, &length_time); - err = pos_time/*/1000*/; - if(this->fd_control >= 0) { - printf_control(this, "RESULT %d %d\r\n", this->token, err); - err = CONTROL_OK; - } - - } else if(!strncasecmp(cmd, "SUBTITLES ", 10)) { - if(this->slave_stream) { - int vpos = 0; - if(1 == sscanf(cmd+10, "%d", &vpos)) - this->class->xine->config->update_num(this->class->xine->config, - "subtitles.separate.vertical_offset", vpos); - else - err = CONTROL_PARAM_ERROR; - } - - } else if(!strncasecmp(cmd, "EXTSUBSIZE ", 11)) { - int size = 0; - if(1 == sscanf(cmd+11, "%d", &size)) - /* size of separate subtitles : - -1 = xine default - 0...6 = { tiny small normal large very large huge } */ - this->class->xine->config->update_num(this->class->xine->config, - "subtitles.separate.subtitle_size", size); - else - err = CONTROL_PARAM_ERROR; - - } else if(!strncasecmp(cmd, "GRAB ", 5)) { - handle_control_grab(this, cmd); - - /* next ones need to be synchronized to data stream */ - } else if(!strncasecmp(cmd, "BLANK", 5)) { - put_control_buf(this->block_buffer, this->buffer_pool, CONTROL_BUF_BLANK); - - } else if(!strncasecmp(cmd, "CLEAR", 5)) { - /* #warning should be delayed and executed in read_block */ - - } else { - LOGMSG("unknown control %s", cmd); - err = CONTROL_UNKNOWN; - } - - LOGCMD("vdr_plugin_parse_control: DONE (%d): %s", err, cmd); - - VDR_ENTRY_UNLOCK(); - - return err; -} - -static void *vdr_control_thread(void *this_gen) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - char line[8128]; - int err; - int counter = 100; - - LOGDBG("Control thread started"); - - /*(void)nice(-1);*/ - - /* wait until state changes from open to play */ - while(bSymbolsFound && counter>0 && ! this->funcs.fe_control) { - xine_usec_sleep(50*1000); - counter--; - } - - write_control(this, "CONFIG\r\n"); - - while(this->control_running) { - - /* read next command */ - line[0] = 0; - pthread_testcancel(); - if((err=readline_control(this, line, sizeof(line)-1, -1)) <= 0) { - if(err < 0) - break; - continue; - } - LOGCMD("Received command %s",line); - pthread_testcancel(); - - if(!this->control_running) - break; - - /* parse */ - switch(err = vdr_plugin_parse_control(&this->iface, line)) { - case CONTROL_OK: - break; - case CONTROL_UNKNOWN: - LOGMSG("unknown control message %s", line); - break; - case CONTROL_PARAM_ERROR: - LOGMSG("invalid parameter in control message %s", line); - break; - case CONTROL_DISCONNECTED: - LOGMSG("control stream read error - disconnected ?"); - this->control_running = 0; - break; - default: - LOGMSG("parse_control failed with result: %d", err); - break; - } - } - - if(this->control_running) - write_control(this, "CLOSE\r\n"); - this->control_running = 0; - - if(this->slave_stream) - xine_stop(this->slave_stream); - - LOGDBG("Control thread terminated"); - pthread_exit(NULL); -} - -/**************************** Control to VDR ********************************/ - -static void slave_track_maps_changed(vdr_input_plugin_t *this) -{ - char tracks[1024], lang[128]; - int i, current, n = 0; - size_t cnt; - - /* DVD title and menu domain detection */ -#ifdef XINE_STREAM_INFO_DVD_TITLE_NUMBER - i = _x_stream_info_get(this->slave_stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER); - if(i >= 0) { - if (i == 0) - dvd_menu_domain(this, 1); - sprintf(tracks, "INFO DVDTITLE %d\r\n", i); - if(this->funcs.xine_input_event) - this->funcs.xine_input_event(tracks, NULL); - else - write_control(this, tracks); - LOGDBG("%s", tracks); - } -#endif - - /* Audio tracks */ - - strcpy(tracks, "INFO TRACKMAP AUDIO "); - cnt = strlen(tracks); - current = xine_get_param(this->slave_stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL); - for(i=0; i<32 && cnt<sizeof(tracks)-32; i++) - if(xine_get_audio_lang(this->slave_stream, i, lang)) { - while(lang[0]==' ') strcpy(lang, lang+1); - cnt += snprintf(tracks+cnt, sizeof(tracks)-cnt-32, - "%s%d:%s ", i==current?"*":"", i, lang); - n++; - } - tracks[sizeof(tracks)-1] = 0; - if(n>1) - LOGDBG("%s", tracks); - - if(this->funcs.xine_input_event) { - /* local mode: -> VDR */ - this->funcs.xine_input_event(tracks, NULL); - } else { - /* remote mode: -> connection -> VDR */ - strcpy(tracks+cnt, "\r\n"); - write_control(this, tracks); - } - - /* DVD SPU tracks */ - - n = 0; - strcpy(tracks, "INFO TRACKMAP SPU "); - cnt = strlen(tracks); - current = _x_get_spu_channel (this->slave_stream); - if(current < 0) { - /* -2 == none, -1 == auto */ - cnt += snprintf(tracks+cnt, sizeof(tracks)-cnt-32, - "*%d:%s ", current, - current==SPU_CHANNEL_NONE ? "none" : "auto"); - n++; - if(current == SPU_CHANNEL_AUTO) - current = this->slave_stream->spu_channel_auto; - } - for(i=0; i<32 && cnt<sizeof(tracks)-32; i++) - if(xine_get_spu_lang(this->slave_stream, i, lang)) { - while(lang[0]==' ') strcpy(lang, lang+1); - cnt += snprintf(tracks+cnt, sizeof(tracks)-cnt-32, - "%s%d:%s ", i==current?"*":"", i, lang); - n++; - } - tracks[sizeof(tracks)-1] = 0; - if(n>1) - LOGDBG("%s", tracks); - - if(this->funcs.xine_input_event) { - this->funcs.xine_input_event(tracks, NULL); - } else { - strcpy(tracks+cnt, "\r\n"); - write_control(this, tracks); - } -} - -/* Map some xine input events to vdr input (remote key names) */ -static const struct { - const uint32_t event; - const char name[12]; -} vdr_keymap[] = { - {XINE_EVENT_INPUT_NEXT, "Next"}, - {XINE_EVENT_INPUT_PREVIOUS, "Previous"}, - - {XINE_EVENT_INPUT_DOWN, "Down"}, - {XINE_EVENT_INPUT_UP, "Up"}, - {XINE_EVENT_INPUT_LEFT, "Left"}, - {XINE_EVENT_INPUT_RIGHT, "Right"}, - {XINE_EVENT_INPUT_SELECT, "Ok"}, - - {XINE_EVENT_INPUT_MENU1, "Menu"}, - {XINE_EVENT_INPUT_MENU2, "Red"}, - {XINE_EVENT_INPUT_MENU3, "Green"}, - {XINE_EVENT_INPUT_MENU4, "Yellow"}, - {XINE_EVENT_INPUT_MENU5, "Blue"}, - {XINE_EVENT_INPUT_NUMBER_0, "0"}, - {XINE_EVENT_INPUT_NUMBER_1, "1"}, - {XINE_EVENT_INPUT_NUMBER_2, "2"}, - {XINE_EVENT_INPUT_NUMBER_3, "3"}, - {XINE_EVENT_INPUT_NUMBER_4, "4"}, - {XINE_EVENT_INPUT_NUMBER_5, "5"}, - {XINE_EVENT_INPUT_NUMBER_6, "6"}, - {XINE_EVENT_INPUT_NUMBER_7, "7"}, - {XINE_EVENT_INPUT_NUMBER_8, "8"}, - {XINE_EVENT_INPUT_NUMBER_9, "9"}, - -#if defined(XINE_EVENT_VDR_RED) - {XINE_EVENT_VDR_BACK, "Back"}, - {XINE_EVENT_VDR_CHANNELPLUS, "Channel+"}, - {XINE_EVENT_VDR_CHANNELMINUS, "Channel-"}, - {XINE_EVENT_VDR_RED, "Red"}, - {XINE_EVENT_VDR_GREEN, "Green"}, - {XINE_EVENT_VDR_YELLOW, "Yellow"}, - {XINE_EVENT_VDR_BLUE, "Blue"}, - {XINE_EVENT_VDR_PLAY, "Play"}, - {XINE_EVENT_VDR_PAUSE, "Pause"}, - {XINE_EVENT_VDR_STOP, "Stop"}, - {XINE_EVENT_VDR_RECORD, "Record"}, - {XINE_EVENT_VDR_FASTFWD, "FastFwd"}, - {XINE_EVENT_VDR_FASTREW, "FastRew"}, - {XINE_EVENT_VDR_POWER, "Power"}, - {XINE_EVENT_VDR_SCHEDULE, "Schedule"}, - {XINE_EVENT_VDR_CHANNELS, "Channels"}, - {XINE_EVENT_VDR_TIMERS, "Timers"}, - {XINE_EVENT_VDR_RECORDINGS, "Recordings"}, - {XINE_EVENT_VDR_SETUP, "Setup"}, - {XINE_EVENT_VDR_COMMANDS, "Commands"}, - {XINE_EVENT_VDR_USER1, "User1"}, - {XINE_EVENT_VDR_USER2, "User2"}, - {XINE_EVENT_VDR_USER3, "User3"}, - {XINE_EVENT_VDR_USER4, "User4"}, - {XINE_EVENT_VDR_USER5, "User5"}, - {XINE_EVENT_VDR_USER6, "User6"}, - {XINE_EVENT_VDR_USER7, "User7"}, - {XINE_EVENT_VDR_USER8, "User8"}, - {XINE_EVENT_VDR_USER9, "User9"}, - {XINE_EVENT_VDR_VOLPLUS, "Volume+"}, - {XINE_EVENT_VDR_VOLMINUS, "Volume-"}, - {XINE_EVENT_VDR_MUTE, "Mute"}, - {XINE_EVENT_VDR_AUDIO, "Audio"}, -#endif -#if defined(XINE_EVENT_VDR_INFO) - {XINE_EVENT_VDR_INFO, "Info"}, -#endif -#if defined(XINE_EVENT_VDR_SUBTITLES) - {XINE_EVENT_VDR_SUBTITLES, "Subtitles"}, -#endif -}; - -static void vdr_event_cb (void *user_data, const xine_event_t *event) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *)user_data; - int i; - - for (i = 0; i < sizeof(vdr_keymap) / sizeof(vdr_keymap[0]); i++) { - if (event->type == vdr_keymap[i].event) { - if (event->data && event->data_length == 4 && - !strncmp(event->data, "VDR", 4)) { - /*LOGMSG("Input event created by self, ignoring");*/ - return; - } - LOGDBG("XINE_EVENT (input) %d --> %s", - event->type, vdr_keymap[i].name); - - if (this->fd_control >= 0) { - /* remote mode: -> input_plugin -> connection -> VDR */ - printf_control(this, "KEY %s\r\n", vdr_keymap[i].name); - } - if (this->funcs.xine_input_event) { - /* local mode: -> VDR */ - this->funcs.xine_input_event(NULL, vdr_keymap[i].name); - } - return; - } - } - - switch (event->type) { - case XINE_EVENT_UI_SET_TITLE: - if(event->stream==this->slave_stream) { - char msg[256], titlen[64] = ""; - xine_ui_data_t *data = (xine_ui_data_t *)event->data; - LOGMSG("XINE_EVENT_UI_SET_TITLE: %s", data->str); - -#ifdef XINE_STREAM_INFO_DVD_TITLE_NUMBER - int tt = _x_stream_info_get(this->slave_stream,XINE_STREAM_INFO_DVD_TITLE_NUMBER); - snprintf(titlen, sizeof(titlen), "INFO DVDTITLE %d\r\n", tt); - if (tt == 0) - dvd_menu_domain(this, 1); -#endif - snprintf(msg, sizeof(msg), "INFO TITLE %s\r\n%s", data->str, titlen); - msg[sizeof(msg)-1] = 0; - if(this->funcs.xine_input_event) - this->funcs.xine_input_event(msg, NULL); - else - write_control(this, msg); - break; - } - - case XINE_EVENT_UI_NUM_BUTTONS: - if (event->stream == this->slave_stream) { - xine_ui_data_t *data = (xine_ui_data_t*)event->data; - char msg[64]; - dvd_menu_domain(this, data->num_buttons > 0); - snprintf(msg, sizeof(msg), "INFO DVDBUTTONS %d\r\n", data->num_buttons); - msg[sizeof(msg)-1] = 0; - if (this->funcs.xine_input_event) - this->funcs.xine_input_event(msg, NULL); - else - write_control(this, msg); - break; - } - - case XINE_EVENT_UI_CHANNELS_CHANGED: - if(event->stream==this->slave_stream) - slave_track_maps_changed(this); - break; - - case XINE_EVENT_FRAME_FORMAT_CHANGE: - { - xine_format_change_data_t *frame_change = - (xine_format_change_data_t *)event->data; - LOGOSD("XINE_EVENT_FRAME_FORMAT_CHANGE (%dx%d, aspect=%d)", - frame_change->width, frame_change->height, - frame_change->aspect); - if (!frame_change->aspect) /* from frontend */ - this->osd_manager->video_size_changed(this->osd_manager, event->stream, - frame_change->width, frame_change->height); -#if 0 - if(frame_change->aspect) - queue_blank_yv12(this); -#endif - } - break; - - case XINE_EVENT_UI_PLAYBACK_FINISHED: - if(event->stream == this->stream) { - LOGMSG("XINE_EVENT_UI_PLAYBACK_FINISHED"); - this->control_running = 0; -#if 1 - if(iSysLogLevel > 2) { - /* dump whole xine log as we should not be here ... */ - xine_t *xine = this->class->xine; - int i, j; - int logs = xine_get_log_section_count(xine); - const char * const * names = xine_get_log_names(xine); - for(i=0; i<logs; i++) { -#if XINE_VERSION_CODE < 10105 - const char * const * lines = xine_get_log(xine, i); -#else - char * const * lines = xine_get_log(xine, i); -#endif - if(lines[0]) { - printf("\nLOG: %s\n",names[i]); - for(j=0; lines[j] && *lines[j]; j++) - printf(" %2d: %s", j, lines[j]); - } - } - } -#endif - } else if(event->stream == this->slave_stream) { - LOGMSG("XINE_EVENT_UI_PLAYBACK_FINISHED (slave stream)"); - if(this->fd_control >= 0) { - write_control(this, "ENDOFSTREAM\r\n"); - } else { - if(this->funcs.fe_control) - this->funcs.fe_control(this->funcs.fe_handle, "ENDOFSTREAM\r\n"); -#if 0 - if(!this->loop_play) { - /* forward to vdr-fe (listening only VDR stream events) */ - xine_event_t event = { - .type = XINE_EVENT_UI_PLAYBACK_FINISHED, - .data_length = 0, - }; - xine_event_send (this->stream, &event); - } else { -# if 0 - xine_usec_sleep(500*1000); - xine_play(this->slave_stream, 0, 0); -# endif - } -#endif - } - } - break; - - default: - LOGCMD("Got an xine event, type 0x%08x", event->type); - break; - } -} - -/**************************** Data Stream *********************************/ - -/* - * wait_stream_sync() - * - * Wait until data and control streams have reached the same sync point. - * - wait_stream_sync() is called only from data thread. - * - data stream handling is suspended until control stream has - * reached the same sync point (and xine engine has been flushed). - * - * Function is interrupred when - * - control thread has been terminated - * - demux_action_pending signal is set - * - * return value: - * 1: Both streams have reached the same sync point - * 0: timeout (errno = EAGAIN) or - * interrupted (errno = EINTR) or - * disconnected (errno = ENOTCONN) - */ -static int wait_stream_sync(vdr_input_plugin_t *this) -{ - int counter = 100; - - mutex_lock_cancellable(&this->lock); - - if (this->discard_index < this->discard_index_ds) - LOGDBG("wait_stream_sync: waiting for engine_flushed condition %"PRIu64"<%"PRIu64, - this->discard_index, this->discard_index_ds); - - while(this->control_running && - this->discard_index < this->discard_index_ds && - /*!this->stream->demux_action_pending &&*/ - --counter > 0) { - struct timespec abstime; - create_timeout_time(&abstime, 10); - pthread_cond_timedwait(&this->engine_flushed, &this->lock, &abstime); - } - - mutex_unlock_cancellable(&this->lock); - - if (this->discard_index == this->discard_index_ds) { - LOGDBG("wait_stream_sync: streams synced at %"PRIu64"/%"PRIu64, - this->discard_index_ds, this->discard_index); - return 0; - } - - if (!this->control_running) { - errno = ENOTCONN; - } - else if (this->stream->demux_action_pending) { - LOGMSG("wait_stream_sync: demux_action_pending set"); - errno = EINTR; - } - else if (counter <= 0) { - LOGMSG("wait_stream_sync: Timed out ! diff %"PRIu64, this->discard_index - this->discard_index_ds); - errno = EAGAIN; - } - - return 1; -} - -static void data_stream_parse_control(vdr_input_plugin_t *this, char *cmd) -{ - char *tmp; - - cmd[64] = 0; - if(NULL != (tmp=strchr(cmd, '\r'))) - *tmp = '\0'; - if(NULL != (tmp=strchr(cmd, '\n'))) - *tmp = '\0'; - - if(!strncasecmp(cmd, "DISCARD ", 8)) { - uint64_t index; - if(1 == sscanf(cmd+8, "%" PRIu64, &index)) { - - this->discard_index_ds = index; - - this->block_buffer->clear(this->block_buffer); - - wait_stream_sync(this); - } - return; - - } else if(!strncasecmp(cmd, "BLANK", 5)) { - put_control_buf(this->block_buffer, this->buffer_pool, CONTROL_BUF_BLANK); - return; - } - - LOGMSG("Unexpected data_stream_parse_control(%s)", cmd); - vdr_plugin_parse_control(&this->iface, cmd); -} - -/* - * vdr_plugin_read_block_tcp() - * - * - Read single transport block from socket / pipe. - * - * Returns NULL if read failed or data is not available. - * (sets errno to EAGAIN, EINTR or ENOTCONN) - * - */ -static buf_element_t *vdr_plugin_read_block_tcp(vdr_input_plugin_t *this) -{ - buf_element_t *read_buffer = this->read_buffer; - int todo = sizeof(stream_tcp_header_t); - int warnings = 0; - int result, n; - - if (read_buffer && read_buffer->size >= sizeof(stream_tcp_header_t)) - todo += ((stream_tcp_header_t *)read_buffer->content)->len; - - while (XIO_READY == (result = _x_io_select(this->stream, this->fd_data, XIO_READ_READY, 100))) { - - pthread_testcancel(); - if (!this->control_running || this->fd_data < 0) { - errno = ENOTCONN; - return NULL; - } - - /* Allocate buffer */ - if (!read_buffer) { - this->read_buffer = read_buffer = get_buf_element_timed(this, 2048+sizeof(stream_tcp_header_t), 100); - if (!read_buffer) { - /* do not drop any data here ; dropping is done only at server side. */ - if (!this->is_paused && !warnings) - LOGDBG("TCP: fifo buffer full"); - warnings++; - continue; /* must call select to check fd for errors / closing */ - } - - /* read the header first */ - todo = sizeof(stream_tcp_header_t); - read_buffer->size = 0; - warnings = 0; - } - - /* Read data */ - errno = 0; - n = read(this->fd_data, read_buffer->content + read_buffer->size, todo - read_buffer->size); - if (n <= 0) { - if (!n || (errno != EINTR && errno != EAGAIN)) { - if (n < 0 && this->fd_data >= 0) - LOGERR("TCP read error (data stream %d : %d)", this->fd_data, n); - if (n == 0) - LOGMSG("Data stream disconnected"); - errno = ENOTCONN; - } - /* errno == EINTR || errno == EAGAIN || errno == ENOTCONN */ - return NULL; - } - - read_buffer->size += n; - - /* Header complete ? */ - if (read_buffer->size == sizeof(stream_tcp_header_t)) { - stream_tcp_header_t *hdr = ((stream_tcp_header_t *)read_buffer->content); - hdr->len = ntohl(hdr->len); - hdr->pos = ntohull(hdr->pos); - - todo += hdr->len; - - if (todo + read_buffer->size >= read_buffer->max_size) { - LOGMSG("TCP: Buffer too small (%d ; incoming frame %d bytes)", - read_buffer->max_size, todo + read_buffer->size); - errno = ENOTCONN; - return NULL; - } - } - - /* Buffer complete ? */ - if (read_buffer->size >= todo) { - stream_tcp_header_t *hdr = ((stream_tcp_header_t *)read_buffer->content); - if (hdr->pos == (uint64_t)(-1ULL) /*0xffffffff ffffffff*/) { - /* control data */ - uint8_t *pkt_data = read_buffer->content + sizeof(stream_tcp_header_t); - if (!DATA_IS_TS(pkt_data) && pkt_data[0]) { /* -> can't be pes or ts frame */ - data_stream_parse_control(this, (char*)pkt_data); - - read_buffer->free_buffer(read_buffer); - this->read_buffer = NULL; - errno = EAGAIN; - return NULL; - } - } - - /* frame ready */ - read_buffer->type = BUF_NETWORK_BLOCK; - this->read_buffer = NULL; - return read_buffer; - } - } - - errno = (result == XIO_TIMEOUT) ? EAGAIN : - (result == XIO_ABORTED) ? EINTR : - ENOTCONN; - return NULL; -} - -static int vdr_plugin_read_net_tcp(vdr_input_plugin_t *this) -{ - buf_element_t *buf = vdr_plugin_read_block_tcp(this); - if (buf) { - this->block_buffer->put(this->block_buffer, buf); - return XIO_READY; - } - if (errno == EAGAIN || errno == EINTR) - return XIO_TIMEOUT; - return XIO_ERROR; -} - -/* - * read_socket_udp() - * - * - Read single transport block from datagram socket - * - * Returns NULL if read failed or data is not available. - * (sets errno to EAGAIN, EINTR or ENOTCONN) - * - */ -static buf_element_t *read_socket_udp(vdr_input_plugin_t *this) -{ - /* - * poll for incoming data - */ - - int result = _x_io_select(this->stream, this->fd_data, XIO_READ_READY, 100); - - if (!this->control_running) { - errno = ENOTCONN; - return NULL; - } - if (result != XIO_READY) { - if (result == XIO_ERROR) - LOGERR("read_socket_udp(): select() failed"); - - errno = (result == XIO_TIMEOUT) ? EAGAIN : - (result == XIO_ABORTED) ? EINTR : - ENOTCONN; - return NULL; - } - - pthread_testcancel(); - - /* - * allocate buffer - */ - - udp_data_t *udp = this->udp_data; - buf_element_t *read_buffer = get_buf_element_timed(this, 2048+sizeof(stream_rtp_header_impl_t), 100); - - if (!read_buffer) { - /* if queue is full, skip (video) frame. - Waiting longer for free buffers just makes things worse ... */ - if (!this->is_paused) { - LOGDBG("UDP Fifo buffer full !"); - if (this->scr && !udp->scr_jump_done) { - this->scr->jump (this->scr, 40*90); - LOGMSG("SCR jump: +40 ms (live=%d, tuning=%d)", this->live_mode, this->scr_tuning); - udp->scr_jump_done = 50; - } - } - errno = EAGAIN; - return NULL; - } - - if (udp->scr_jump_done) - udp->scr_jump_done --; - - /* - * Receive frame from socket and check for errors - */ - - struct sockaddr_in server_address; - socklen_t address_len = sizeof(server_address); - - int n = recvfrom(this->fd_data, read_buffer->mem, - read_buffer->max_size, MSG_TRUNC, - &server_address, &address_len); - if (n <= 0) { - if (!n || (errno != EINTR && errno != EAGAIN)) { - LOGERR("read_socket_udp(): recvfrom() failed"); - errno = ENOTCONN; - } - read_buffer->free_buffer(read_buffer); - /* errno == EAGAIN || errno == EINTR || errno == ENOTCONN */ - return NULL; - } - - /* - * check source address - */ - - if ((server_address.sin_addr.s_addr != - udp->server_address.sin_addr.s_addr) || - server_address.sin_port != udp->server_address.sin_port) { -#ifdef LOG_UDP - uint32_t tmp_ip = ntohl(server_address.sin_addr.s_addr); - LOGUDP("Received data from unknown sender: %d.%d.%d.%d:%d", - ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff), - ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff), - server_address.sin_port); -#endif - read_buffer->free_buffer(read_buffer); - errno = EAGAIN; - return NULL; - } - - /* - * Check if frame size is valid - */ - - if (this->rtp) { - if (n < sizeof(stream_rtp_header_impl_t)) { - LOGMSG("received invalid RTP packet (too short)"); - read_buffer->free_buffer(read_buffer); - errno = EAGAIN; - return NULL; - } - } - else if (n < sizeof(stream_udp_header_t)) { - LOGMSG("received invalid UDP packet (too short)"); - read_buffer->free_buffer(read_buffer); - errno = EAGAIN; - return NULL; - } - - if (n > read_buffer->max_size) { - LOGMSG("received too large UDP packet (%d bytes, buffer is %d bytes)", n, read_buffer->max_size); - read_buffer->free_buffer(read_buffer); - errno = EAGAIN; - return NULL; - } - - /* - * - */ - - read_buffer->size = n; - read_buffer->type = BUF_NETWORK_BLOCK; - - return read_buffer; -} - -static buf_element_t *udp_parse_header(buf_element_t *read_buffer, int rtp) -{ - if (rtp) { - - /* check if RTP header is valid. If not, assume UDP without RTP. */ - stream_rtp_header_impl_t *rtp_pkt = (stream_rtp_header_impl_t*)read_buffer->content; - if (rtp_pkt->rtp_hdr.raw[0] == (RTP_VERSION_BYTE | RTP_HDREXT_BIT) && - ( rtp_pkt->rtp_hdr.raw[1] == RTP_PAYLOAD_TYPE_PES || - rtp_pkt->rtp_hdr.raw[1] == RTP_PAYLOAD_TYPE_TS ) && - rtp_pkt->hdr_ext.hdr.size == htons(RTP_HEADER_EXT_X_SIZE) && - rtp_pkt->hdr_ext.hdr.type == htons(RTP_HEADER_EXT_X_TYPE)) { - - /* strip RTP header but leave UDP header (carried inside RTP header extension) */ - read_buffer->content += sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t); - read_buffer->size -= sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t); - } - } - - stream_udp_header_t *pkt = (stream_udp_header_t*)read_buffer->content; - - pkt->seq = ntohs(pkt->seq); - pkt->pos = ntohull(pkt->pos); - - return read_buffer; -} - -static buf_element_t *udp_check_packet(buf_element_t *read_buffer) -{ - stream_udp_header_t *pkt = (stream_udp_header_t*)read_buffer->content; - uint8_t *pkt_data = read_buffer->content + sizeof(stream_udp_header_t); - - /* Check for MPEG-TS sync byte or PES header */ - if (read_buffer->size > sizeof(stream_udp_header_t) && - !DATA_IS_TS(pkt_data) && - (pkt_data[0] || pkt_data[1] || pkt_data[2] != 1)) { - LOGMSG("received invalid UDP packet (TS sync byte or PES header missing)"); - read_buffer->free_buffer(read_buffer); - return NULL; - } - - /* Check if header is valid */ - if (pkt->seq > UDP_SEQ_MASK) { - LOGMSG("received invalid UDP packet (sequence number too big)"); - read_buffer->free_buffer(read_buffer); - return NULL; - } - - return read_buffer; -} - -static buf_element_t *udp_parse_control(vdr_input_plugin_t *this, buf_element_t *read_buffer) -{ - stream_udp_header_t *pkt = (stream_udp_header_t*)read_buffer->content; - uint8_t *pkt_data = read_buffer->content + sizeof(stream_udp_header_t); - - /* Check for control messages */ - if (/*pkt->seq == (uint16_t)(-1) &&*/ /*0xffff*/ - pkt->pos == (uint64_t)(-1ULL) && /*0xffffffff ffffffff*/ - pkt_data[0]) { /* -> can't be PES frame */ - pkt_data[64] = 0; - - if (!strncmp((char*)pkt_data, "UDP MISSING", 11)) { - /* Re-send failed */ - int seq1 = 0; - int seq2 = 0; - uint64_t rpos = UINT64_C(0); - udp_data_t *udp = this->udp_data; - - sscanf(((char*)pkt_data)+12, "%d-%d %" PRIu64, - &seq1, &seq2, &rpos); - read_buffer->size = sizeof(stream_udp_header_t); - read_buffer->type = BUF_NETWORK_BLOCK; - pkt->pos = rpos; - LOGUDP("Got UDP MISSING %d-%d (currseq=%d)", seq1, seq2, udp->next_seq); - - if (seq1 == udp->next_seq) { - /* this is the one we are expecting ... */ - int n = ADDSEQ(seq2 + 1, -seq1); - udp->missed_frames += n; - seq2 &= UDP_SEQ_MASK; - pkt->seq = seq2; - udp->next_seq = seq2; - LOGUDP(" accepted: now currseq %d", udp->next_seq); - /* -> drop frame thru as empty ; it will trigger queue to continue */ - - } else { - LOGUDP(" UDP packet rejected: not expected seq ???"); - - read_buffer->free_buffer(read_buffer); - return NULL; - } - - } else { - data_stream_parse_control(this, (char*)pkt_data); - - read_buffer->free_buffer(read_buffer); - return NULL; - } - } - - return read_buffer; -} - -static buf_element_t *udp_process_queue(vdr_input_plugin_t *this) -{ - udp_data_t *udp = this->udp_data; - - if (udp->queued <= 0) - return NULL; - - /* - * Stay inside receiving window: - * if window exceeded, skip missing frames - */ - - if (udp->queued > ((UDP_SEQ_MASK+1)>>2)) { -#ifdef LOG_UDP - int start = udp->next_seq; -#endif - while (!udp->queue[udp->next_seq]) { - INCSEQ(udp->next_seq); - udp->missed_frames++; - } - udp->resend_requested = 0; - LOGUDP("Re-ordering window exceeded, skipped missed frames %d-%d", - start, udp->next_seq-1); - } - - /* - * flush all packets when idle padding found - */ - - if (udp->is_padding && udp->queued > 0) - while (!udp->queue[udp->next_seq]) { - INCSEQ(udp->next_seq); - udp->missed_frames++; - } - - /* - * return next packet if available - */ - - while (udp->queued > 0 && udp->queue[udp->next_seq]) { - buf_element_t *buf = NULL; - stream_udp_header_t *pkt = (stream_udp_header_t*)udp->queue[udp->next_seq]->content; - udp->queue_input_pos = pkt->pos + udp->queue[udp->next_seq]->size - sizeof(stream_udp_header_t); - if (udp->queue[udp->next_seq]->size > sizeof(stream_udp_header_t)) - buf = udp->queue[udp->next_seq]; - else - udp->queue[udp->next_seq]->free_buffer(udp->queue[udp->next_seq]); - - udp->queue[udp->next_seq] = NULL; - udp->queued --; - INCSEQ(udp->next_seq); - - if (udp->resend_requested) - udp->resend_requested --; - - /* flush all packets when idle padding found */ - if (udp->is_padding && udp->queued > 0) - while (!udp->queue[udp->next_seq]) { - INCSEQ(udp->next_seq); - udp->missed_frames++; - } - - if (buf) - return buf; - } - - errno = EAGAIN; - return NULL; -} - -static void udp_process_resend(vdr_input_plugin_t *this) -{ - udp_data_t *udp = this->udp_data; - - /* no new resend requests until previous has been completed or failed */ - if (udp->resend_requested) - return; - - /* If frames are missing, request re-send */ - if (NEXTSEQ(udp->current_seq) != udp->next_seq && udp->queued) { - - int max_req = 20; - - while (!udp->queue[udp->current_seq] && --max_req > 0) - INCSEQ(udp->current_seq); - - printf_control(this, "UDP RESEND %d-%d %" PRIu64 "\r\n", - udp->next_seq, PREVSEQ(udp->current_seq), - udp->queue_input_pos); - - udp->resend_requested = - (udp->current_seq + (UDP_SEQ_MASK+1) - udp->next_seq) & UDP_SEQ_MASK; - - LOGUDP("%d-%d missing, requested re-send for %d frames", - udp->next_seq, PREVSEQ(udp->current_seq), udp->resend_requested); - } -} - -/* - * vdr_plugin_read_block_udp() - * - * - Get next UDP transport block from (socket)/queue. - * - * Returns NULL if read failed or data is not available. - * (sets errno to EAGAIN, EINTR or ENOTCONN) - * - */ -static buf_element_t *vdr_plugin_read_block_udp(vdr_input_plugin_t *this) -{ - udp_data_t *udp = this->udp_data; - - while (this->control_running && this->fd_data >= 0) { - - buf_element_t *read_buffer; - - /* return next packet from reordering queue (if any) */ - if (NULL != (read_buffer = udp_process_queue(this))) - return read_buffer; - - /* poll + read socket */ - if ( ! (read_buffer = read_socket_udp(this))) - return NULL; - - if (! (read_buffer = udp_parse_header(read_buffer, this->rtp)) || - ! (read_buffer = udp_parse_control(this, read_buffer)) || - ! (read_buffer = udp_check_packet(read_buffer))) { - errno = EAGAIN; - return NULL; - } - - /* - * handle re-ordering and retransmissios - */ - - stream_udp_header_t *pkt = (stream_udp_header_t*)read_buffer->content; - uint8_t *pkt_data = read_buffer->content + sizeof(stream_udp_header_t); - - udp->current_seq = pkt->seq & UDP_SEQ_MASK; - udp->is_padding = DATA_IS_PES(pkt_data) && IS_PADDING_PACKET(pkt_data); - - /* first received frame initializes sequence counter */ - if (udp->received_frames == -1) { - udp->next_seq = udp->current_seq; - udp->received_frames = 0; - } - - /* check if received sequence number is inside allowed window - (half of whole range) */ - - if (ADDSEQ(udp->current_seq, -udp->next_seq) > ((UDP_SEQ_MASK+1) >> 1)/*0x80*/) { - struct sockaddr_in sin; - LOGUDP("Received SeqNo out of window (%d ; [%d..%d])", - udp->current_seq, udp->next_seq, - (udp->next_seq+((UDP_SEQ_MASK+1) >> 1)/*0x80*/) & UDP_SEQ_MASK); - /* reset link */ - LOGDBG("UDP: resetting link"); - memcpy(&sin, &udp->server_address, sizeof(sin)); - free_udp_data(udp); - udp = this->udp_data = init_udp_data(); - memcpy(&udp->server_address, &sin, sizeof(sin)); - read_buffer->free_buffer(read_buffer); - errno = EAGAIN; - return NULL; - } - - /* Add received frame to incoming queue */ - if (udp->queue[udp->current_seq]) { - /* Duplicate packet or lot of dropped packets */ - LOGUDP("Got duplicate or window exceeded ? (queue slot %d in use) !", - udp->current_seq); - udp->queue[udp->current_seq]->free_buffer(udp->queue[udp->current_seq]); - udp->queue[udp->current_seq] = NULL; - if (!udp->queued) - LOGERR("UDP queue corrupt !!!"); - else - udp->queued--; - } - - udp->queue[udp->current_seq] = read_buffer; - read_buffer = NULL; - udp->queued ++; - - /* return next packet from queue (if any) */ - if (NULL != (read_buffer = udp_process_queue(this))) - return read_buffer; - - udp_process_resend(this); - -#ifdef LOG_UDP - /* Link quality statistics */ - udp->received_frames++; - if (udp->received_frames >= 1000) { - if (udp->missed_frames) - LOGUDP("packet loss %d.%d%% (%4d/%4d)", - udp->missed_frames*100/udp->received_frames, - (udp->missed_frames*1000/udp->received_frames)%10, - udp->missed_frames, udp->received_frames); - udp->missed_frames = udp->received_frames = 0; - } -#endif - } - - errno = ENOTCONN; - return NULL; -} - -static int vdr_plugin_read_net_udp(vdr_input_plugin_t *this) -{ - buf_element_t *buf = vdr_plugin_read_block_udp(this); - if (buf) { - this->block_buffer->put(this->block_buffer, buf); - return XIO_READY; - } - if (errno == EAGAIN || errno == EINTR) - return XIO_TIMEOUT; - return XIO_ERROR; -} - -static void *vdr_data_thread(void *this_gen) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - - LOGDBG("Data thread started"); - - const int priority = -1; - errno = 0; - if((nice(priority) == -1) && errno) - LOGDBG("Data thread: Can't nice to value: %d", priority); - - if(this->udp || this->rtp) { - while(this->control_running) { - if(vdr_plugin_read_net_udp(this) == XIO_ERROR) - break; - pthread_testcancel(); - } - } else { - while(this->control_running) { - if(vdr_plugin_read_net_tcp(this) == XIO_ERROR) - break; - pthread_testcancel(); - } - } - - this->control_running = 0; - LOGDBG("Data thread terminated"); - pthread_exit(NULL); -} - -#ifdef TEST_PIP -static int write_slave_stream(vdr_input_plugin_t *this, const char *data, int len) -{ - fifo_input_plugin_t *slave; - buf_element_t *buf; - - TRACE("write_slave_stream (%d bytes)", len); - - if(!this->pip_stream) { - LOGMSG("Detected new video stream 0x%X", (unsigned int)data[3]); - LOGMSG(" no xine stream yet, trying to create ..."); - vdr_plugin_parse_control((input_plugin_t*)this, "SUBSTREAM 0xE1 50 50 288 196"); - } - if(!this->pip_stream) { - LOGMSG(" pip substream: no stream !"); - return -1; - } - /*LOGMSG(" pip substream open, queuing data");*/ - - slave = (fifo_input_plugin_t*)this->pip_stream->input_plugin; - if(!slave) { - LOGMSG(" pip substream: no input plugin !"); - return len; - } - - if(slave->buffer_pool->num_free(slave->buffer_pool) < 20) { - /*LOGMSG(" pip substream: fifo almost full !");*/ - xine_usec_sleep(3000); - return 0; - } - buf = slave->buffer_pool->buffer_pool_try_alloc(slave->buffer_pool); - if(!buf) { - LOGMSG(" pip substream: fifo full !"); - return 0; - } - if(len > buf->max_size) { - LOGMSG(" pip substream: buf too small"); - buf->free_buffer(buf); - return len; - } - - buf->content = buf->mem; - buf->size = len; - buf->type = BUF_DEMUX_BLOCK; - xine_fast_memcpy(buf->content, data, len); - slave->buffer->put(slave->buffer, buf); - return len; -} -#endif - -static int vdr_plugin_write(vdr_input_plugin_if_t *this_if, const char *data, int len) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if; - buf_element_t *buf = NULL; - static int overflows = 0; - - if(this->slave_stream) - return len; - -#ifdef TEST_PIP - /* some (older?) VDR recordings have video PID != 0xE0 ... */ - - /* slave (PES) */ - if(!buf[0] && ((uint8_t*)data)[3] > 0xe0 && ((uint8_t*)data)[3] <= 0xef) - return write_slave_stream(this, data, len); -#endif - - TRACE("vdr_plugin_write (%d bytes)", len); - - VDR_ENTRY_LOCK(0); - - buf = get_buf_element(this, len, 0); - if(!buf) { - /* need counter to filter non-fatal overflows - (VDR is not polling for every PES packet) */ - if(overflows++ > 1) - LOGMSG("vdr_plugin_write: buffer overflow ! (%d bytes)", len); - VDR_ENTRY_UNLOCK(); - xine_usec_sleep(5*1000); - errno = EAGAIN; - return 0; /* EAGAIN */ - } - overflows = 0; - - if(len > buf->max_size) { - LOGMSG("vdr_plugin_write: PES too long (%d bytes, max size " - "%d bytes), data ignored !", len, buf->max_size); - buf->free_buffer(buf); -/* curr_pos will be invalid when this point is reached ! */ - VDR_ENTRY_UNLOCK(); - return len; - } - - buf->size = len; - xine_fast_memcpy(buf->content, data, len); - this->block_buffer->put(this->block_buffer, buf); - - VDR_ENTRY_UNLOCK(); - - TRACE("vdr_plugin_write returns %d", len); - - return len; -} - -/* - * vdr_plugin_keypress() - * - * - Called by frontend - * - forward (input) events to VDR - * - * It is safe to cancel thread while this function is being executed. - */ -static int post_vdr_event(vdr_input_plugin_if_t *this_if, const char *msg) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_if; - - if (msg && this->fd_control >= 0) - return write_control (this, msg); - - LOGMSG("post_vdr_event: error ! \"%s\" not delivered.", msg ?: "<null>"); - return -1; -} - - -/******************************* Plugin **********************************/ - -#if XINE_VERSION_CODE < 10190 -static off_t vdr_plugin_read (input_plugin_t *this_gen, char *buf_gen, off_t len) -#else -static off_t vdr_plugin_read (input_plugin_t *this_gen, void *buf_gen, off_t len) -#endif -{ - memset(buf_gen, 0, len); - return 0; -} - -/*#define CACHE_FIRST_IFRAME*/ -#ifdef CACHE_FIRST_IFRAME -# include "cache_iframe.c" -#endif - -/* - * update_frames() - * - * Update frame type counters. - * Collected information is used to start replay when enough data has been buffered - */ -static uint8_t update_frames(vdr_input_plugin_t *this, const uint8_t *data, int len) -{ - uint8_t type = pes_get_picture_type(data, len); - - if (!this->I_frames) - this->P_frames = this->B_frames = 0; - - switch (type) { - case I_FRAME: this->I_frames++; LOGSCR("I"); break; - case P_FRAME: this->P_frames++; LOGSCR("P"); break; - case B_FRAME: this->B_frames++; LOGSCR("B"); break; - default: break; - } - return type; -} - -/* - * Preprocess buffer before passing it to demux - * - handle discard - * - handle display blanking - * - handle stream start - * - strip network headers - */ -static buf_element_t *preprocess_buf(vdr_input_plugin_t *this, buf_element_t *buf) -{ - /* internal control bufs */ - if(buf->type == CONTROL_BUF_BLANK) { - - pthread_mutex_lock(&this->lock); - if(!this->stream_start) { - LOGMSG("BLANK in middle of stream! bufs queue %d , video_fifo %d", - this->block_buffer->fifo_size, - this->stream->video_fifo->fifo_size); - } else { - vdr_x_demux_control_newpts(this->stream, 0, BUF_FLAG_SEEK); - queue_blank_yv12(this); - } - pthread_mutex_unlock(&this->lock); - - buf->free_buffer(buf); - return NULL; - } - - /* control buffers go always to demuxer */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE) - return buf; - - pthread_mutex_lock(&this->lock); - - /* Update stream position and remove network headers */ - strip_network_headers(this, buf); - - /* Update stream position */ - if ((buf->type & BUF_MAJOR_MASK) == BUF_DEMUX_BLOCK) { - this->curpos += buf->size; - this->curframe ++; - } else { - if ((buf->type & BUF_MAJOR_MASK) == BUF_VIDEO_BASE) { - /* demuxed video */ - pthread_mutex_unlock(&this->lock); - this->stream->video_fifo->put(this->stream->video_fifo, buf); - return NULL; - } - LOGMSG("!!! curpos not updated for unregonized buffer type 0x%x !!!", buf->type); - } - - /* Handle discard */ - if (this->discard_index > this->curpos && this->guard_index < this->curpos) { - pthread_mutex_unlock(&this->lock); - buf->free_buffer(buf); - return NULL; - } - - /* ignore UDP/RTP "idle" padding */ - if (!DATA_IS_TS(buf->content) && IS_PADDING_PACKET(buf->content)) { - pthread_mutex_unlock(&this->lock); - return buf; - } - - /* Send current PTS ? */ - if (this->stream_start) { - this->stream_start = 0; - pthread_mutex_lock (&this->stream->first_frame_lock); - this->stream->first_frame_flag = 2; - pthread_mutex_unlock (&this->stream->first_frame_lock); - } - - pthread_mutex_unlock(&this->lock); - return buf; -} - -/* - * Postprocess buffer before passing it to demuxer - * - Signal new pts upstream after stream changes - * - Special handling for still images - * - Count video frames for SCR tuning - * - Special handling for ffmpeg mpeg2 video decoder - */ -static void postprocess_buf(vdr_input_plugin_t *this, buf_element_t *buf, int need_pause) -{ -#ifdef CACHE_FIRST_IFRAME - cache_iframe(this, buf); -#endif - - if (buf->type != BUF_DEMUX_BLOCK || DATA_IS_TS(buf->content)) - return; - -#ifdef TEST_SCR_PAUSE - if(need_pause) - scr_tuning_set_paused(this); -#endif - - /* generated still images start with empty video PES, PTS = 0. - Reset metronom pts so images will be displayed */ - if(this->still_mode && buf->size == 14) { - int64_t pts = pes_get_pts(buf->content, buf->size); - if(pts==0) { - vdr_x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK); - /* delay frame 10ms (9000 ticks) */ - /*buf->content[12] = (uint8_t)((10*90) >> 7);*/ - } - } - - /* Count video frames for SCR tuning algorithm */ - if(this->live_mode && this->I_frames < 4) - if(IS_VIDEO_PACKET(buf->content) && buf->size > 32) - update_frames(this, buf->content, buf->size); -} - -static void handle_disconnect(vdr_input_plugin_t *this) -{ - LOGMSG("read_block: no data source, returning NULL"); - - flush_all_fifos (this, 0); - - set_playback_speed(this, 1); - this->live_mode = 0; - reset_scr_tuning(this, XINE_FINE_SPEED_NORMAL); - this->stream->emergency_brake = 1; - - this->control_running = 0; - errno = ENOTCONN; -} - -static int adjust_scr_speed(vdr_input_plugin_t *this) -{ - int need_pause = 0; - - if(pthread_mutex_lock(&this->lock)) { - LOGERR("adjust_scr_speed: pthread_mutex_lock failed"); - return 0; - } - - if( (!this->live_mode && (this->fd_control < 0 || - this->fixed_scr)) || - this->slave_stream) { - if(this->scr_tuning) - reset_scr_tuning(this, this->speed_before_pause); - } else { -#ifdef TEST_SCR_PAUSE - if(this->stream_start) { - reset_scr_tuning(this, this->speed_before_pause); - need_pause = 1; - } else { - vdr_adjust_realtime_speed(this); - } -#else - vdr_adjust_realtime_speed(this); -#endif - } - pthread_mutex_unlock(&this->lock); - - return need_pause; -} - -static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen, - fifo_buffer_t *fifo, off_t todo) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - buf_element_t *buf = NULL; - int need_pause = 0; - - TRACE("vdr_plugin_read_block"); - - if (this->slave_stream) { - xine_usec_sleep(50*1000); - if (this->slave_stream) { - errno = EAGAIN; - return NULL; - } - } - - do { - - /* check for disconnection/termination */ - if (!this->funcs.push_input_write /* reading from socket */ && - !this->control_running) { - /* disconnected ? */ - handle_disconnect(this); - return NULL; - } - - /* Return immediately if demux_action_pending flag is set */ - if (this->stream->demux_action_pending) { - errno = EINTR; - return NULL; - } - -#ifdef CACHE_FIRST_IFRAME - if (NULL != (buf = get_cached_iframe(this))) - return buf; -#endif - - /* adjust SCR speed */ - need_pause = adjust_scr_speed(this); - - /* get next buffer */ - buf = fifo_buffer_timed_get(this->block_buffer, 100); - - if (!buf) { - if (!this->is_paused && - !this->still_mode && - !this->is_trickspeed && - !this->slave_stream && - this->stream->video_fifo->fifo_size <= 0) { - - this->read_timeouts++; - if (this->read_timeouts > 80) { - LOGMSG("No data in 8 seconds, queuing no signal image"); - queue_nosignal(this); - this->read_timeouts = 0; - } - } else { - this->read_timeouts = 0; - } - errno = this->stream->demux_action_pending ? EINTR : EAGAIN; - return NULL; - } - this->read_timeouts = 0; - - if (! (buf = preprocess_buf(this, buf))) - continue; - - } while (!buf); - - postprocess_buf(this, buf, need_pause); - - TRACE("vdr_plugin_read_block: return data, pos end = %" PRIu64, this->curpos); - return buf; -} - -static off_t vdr_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) -{ - return -1; -} - -static off_t vdr_plugin_get_length (input_plugin_t *this_gen) -{ - return -1; -} - -static uint32_t vdr_plugin_get_capabilities (input_plugin_t *this_gen) -{ - return -#ifdef INPUT_CAP_NOCACHE - INPUT_CAP_NOCACHE | -#endif - INPUT_CAP_BLOCK; -} - -static uint32_t vdr_plugin_get_blocksize (input_plugin_t *this_gen) -{ - return 2048; -} - -static off_t vdr_plugin_get_current_pos (input_plugin_t *this_gen) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - return this->discard_index > this->curpos ? this->discard_index : this->curpos; -} - -static void vdr_plugin_dispose (input_plugin_t *this_gen) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - int local; - int fd = -1, fc = -1; - - if(!this_gen) - return; - - LOGDBG("vdr_plugin_dispose"); - - /* stop slave stream */ - if (this->slave_stream) { - LOGMSG("dispose: Closing slave stream"); - if (this->slave_event_queue) - xine_event_dispose_queue (this->slave_event_queue); - this->slave_event_queue = NULL; - if(this->funcs.fe_control) { - this->funcs.fe_control(this->funcs.fe_handle, "POST 0 Off\r\n"); - this->funcs.fe_control(this->funcs.fe_handle, "SLAVE 0x0\r\n"); - } - xine_stop(this->slave_stream); - xine_close(this->slave_stream); - xine_dispose(this->slave_stream); - this->slave_stream = NULL; - } - - if(this->fd_control>=0) - write_control(this, "CLOSE\r\n"); - - this->control_running = 0; - - local = this->funcs.push_input_write ? 1 : 0; - memset(&this->funcs, 0, sizeof(this->funcs)); - - /* shutdown sockets */ - if(!local) { - struct linger { - int l_onoff; /* linger active */ - int l_linger; /* how many seconds to linger for */ - } l = {0,0}; - - fd = this->fd_data; - fc = this->fd_control; - - if(fc >= 0) { - LOGDBG("Shutdown control"); - setsockopt(fc, SOL_SOCKET, SO_LINGER, &l, sizeof(struct linger)); - shutdown(fc, SHUT_RDWR); - } - - if(fd >= 0 && this->tcp) { - LOGDBG("Shutdown data"); - setsockopt(fc, SOL_SOCKET, SO_LINGER, &l, sizeof(struct linger)); - shutdown(fd, SHUT_RDWR); - } - } - - /* threads */ - if(!local && this->threads_initialized) { - void *p; - LOGDBG("Cancel control thread ..."); - /*pthread_cancel(this->control_thread);*/ - pthread_join (this->control_thread, &p); - LOGDBG("Cancel data thread ..."); - /*pthread_cancel(this->data_thread);*/ - pthread_join (this->data_thread, &p); - LOGDBG("Threads joined"); - } - - /* event queue(s) and listener threads */ - LOGDBG("Disposing event queues"); - if (this->event_queue) { - xine_event_dispose_queue (this->event_queue); - this->event_queue = NULL; - } - - pthread_cond_broadcast(&this->engine_flushed); - while(pthread_cond_destroy(&this->engine_flushed) == EBUSY) { - LOGMSG("discard_signal busy !"); - pthread_cond_broadcast(&this->engine_flushed); - xine_usec_sleep(10); - } - - /* destroy mutexes (keep VDR out) */ - LOGDBG("Destroying mutexes"); - while(pthread_mutex_destroy(&this->vdr_entry_lock) == EBUSY) { - LOGMSG("vdr_entry_lock busy ..."); - pthread_mutex_lock(&this->vdr_entry_lock); - pthread_mutex_unlock(&this->vdr_entry_lock); - } - while(pthread_mutex_destroy(&this->lock) == EBUSY) { - LOGMSG("lock busy ..."); - pthread_mutex_lock(&this->lock); - pthread_mutex_unlock(&this->lock); - } - while(pthread_mutex_destroy(&this->fd_control_lock) == EBUSY) { - LOGMSG("fd_control_lock busy ..."); - pthread_mutex_lock(&this->fd_control_lock); - pthread_mutex_unlock(&this->fd_control_lock); - } - - signal_buffer_pool_not_empty(this); - signal_buffer_not_empty(this); - - /* close sockets */ - if(!local) { - LOGDBG("Closing data connection"); - if(fd >= 0) - if(close(fd)) - LOGERR("close(fd_data) failed"); - LOGDBG("Closing control connection"); - if(fc >= 0) - if(close(fc)) - LOGERR("close(fd_control) failed"); - this->fd_data = this->fd_control = -1; - LOGMSG("Connections closed."); - } - - /* OSD */ - if (this->osd_manager) { - this->osd_manager->dispose(this->osd_manager, this->stream); - this->osd_manager = NULL; - } - - /* restore video properties */ - if(this->video_properties_saved) - set_video_properties(this, -1,-1,-1,-1,-1, -1, -1); /* restore defaults */ - - signal_buffer_pool_not_empty(this); - signal_buffer_not_empty(this); - - /* SCR */ - if (this->scr) - this->scr->dispose(this->scr); - - free (this->mrl); - - if(this->udp_data) - free_udp_data(this->udp_data); - - /* fifos */ - LOGDBG("Disposing fifos"); - - /* need to get all buffer elements back before disposing own buffers ... */ - flush_all_fifos (this, 1); - - if (this->iframe_buffer) - this->iframe_buffer->dispose(this->iframe_buffer); - if (this->block_buffer) - this->block_buffer->dispose(this->block_buffer); - if (this->hd_buffer) - this->hd_buffer->dispose(this->hd_buffer); - - free (this); - LOGDBG("dispose done."); -} - -#if XINE_VERSION_CODE > 10103 -static const char* vdr_plugin_get_mrl (input_plugin_t *this_gen) -#else -static char* vdr_plugin_get_mrl (input_plugin_t *this_gen) -#endif -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - return this->mrl; -} - -static int vdr_plugin_get_optional_data (input_plugin_t *this_gen, - void *data, int data_type) -{ -#ifdef INPUT_OPTIONAL_DATA_DEMUXER - if (data_type == INPUT_OPTIONAL_DATA_DEMUXER) { - static const char demux_name[] = "xvdr"; - *((const char **)data) = demux_name; - return INPUT_OPTIONAL_SUCCESS; - } -#endif - return INPUT_OPTIONAL_UNSUPPORTED; -} - -static int vdr_plugin_open(input_plugin_t *this_gen) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - xine_t *xine = this->class->xine; - - this->event_queue = xine_event_new_queue (this->stream); - xine_event_create_listener_thread (this->event_queue, vdr_event_cb, this); - - this->buffer_pool = this->stream->video_fifo; - - /* enable resample method */ - xine->config->update_num(xine->config, "audio.synchronization.av_sync_method", 1); - - /* register our own scr provider */ - this->scr = adjustable_scr_start(this->class->xine); - if (!this->scr) - LOGMSG("adjustable_scr_start() FAILED !"); - this->scr_live_sync = 1; - - this->scr_tuning = SCR_TUNING_OFF; - this->curpos = 0; - - /* buffer */ - this->block_buffer = fifo_buffer_new(this->stream, 4, 0x10000+64); /* dummy buf to be used before first read and for big PES frames */ - - /* OSD */ - this->osd_manager = init_osd_manager(); - - /* sync */ - pthread_mutex_init (&this->lock, NULL); - pthread_mutex_init (&this->vdr_entry_lock, NULL); - pthread_mutex_init (&this->fd_control_lock, NULL); - pthread_cond_init (&this->engine_flushed, NULL); - - return 1; -} - -static int vdr_plugin_open_local (input_plugin_t *this_gen) -{ - LOGDBG("vdr_plugin_open_local"); - return vdr_plugin_open(this_gen); -} - -static void set_recv_buffer_size(int fd, int max_buf) -{ - /* try to have larger receiving buffer */ - - /*while(max_buf) {*/ - if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &max_buf, sizeof(int)) < 0) { - LOGERR("setsockopt(SO_RCVBUF,%d) failed", max_buf); - /*max_buf >>= 1;*/ - } else { - unsigned int tmp = 0, len = sizeof(int);; - if(getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) { - LOGERR("getsockopt(SO_RCVBUF,%d) failed", max_buf); - /*max_buf >>= 1;*/ - } else if(tmp != 2*max_buf) { - LOGDBG("setsockopt(SO_RCVBUF): got %d bytes", tmp); - /*max_buf >>= 1;*/ - } - } - /*}*/ - max_buf = 256; - /* not going to send anything, so shrink send buffer ... */ - setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(int)); -} - -static int alloc_udp_data_socket(int firstport, int trycount, int *port) -{ - int fd, one = 1; - struct sockaddr_in name; - - name.sin_family = AF_INET; - name.sin_port = htons(firstport); - name.sin_addr.s_addr = htonl(INADDR_ANY); - - fd = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/); - - set_recv_buffer_size(fd, KILOBYTE(512)); - - if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0) - LOGERR("UDP data stream: setsockopt(SO_REUSEADDR) failed"); - - while(bind(fd, (struct sockaddr *)&name, sizeof(name)) < 0) { - if(!--trycount) { - LOGMSG("UDP Data stream: bind error, no free port found"); - close(fd); - return -1; - } - LOGERR("UDP Data stream: bind error, port %d: %s", - name.sin_port, strerror(errno)); - name.sin_port = htons(++firstport); - } - - *port = ntohs(name.sin_port); - return fd; -} - -static int connect_control_stream(vdr_input_plugin_t *this, const char *host, - int port, int *client_id) -{ - char tmpbuf[256]; - int fd_control; - int saved_fd = this->fd_control, one = 1; - - /* Connect to server */ - this->fd_control = fd_control = _x_io_tcp_connect(this->stream, host, port); - - if(fd_control < 0 || - XIO_READY != _x_io_tcp_connect_finish(this->stream, this->fd_control, - 3000)) { - LOGERR("Can't connect to tcp://%s:%d", host, port); - close(fd_control); - this->fd_control = saved_fd; - return -1; - } - - set_recv_buffer_size(fd_control, KILOBYTE(128)); - - /* request control connection */ - if(_x_io_tcp_write(this->stream, fd_control, "CONTROL\r\n", 9) < 0) { - LOGERR("Control stream write error"); - return -1; - } - - /* Check server greeting */ - if(readline_control(this, tmpbuf, sizeof(tmpbuf)-1, 4) <= 0) { - LOGMSG("Server not replying"); - close(fd_control); - this->fd_control = saved_fd; - return -1; - } - LOGMSG("Server greeting: %s", tmpbuf); - if(!strncmp(tmpbuf, "Access denied", 13)) { - LOGMSG("Maybe host address is missing from server-side svdrphosts.conf ?"); - close(fd_control); - this->fd_control = saved_fd; - return -1; - } - if(!strstr(tmpbuf, "VDR-") || !strstr(tmpbuf, "xineliboutput-") || !strstr(tmpbuf, "READY")) { - LOGMSG("Unregonized greeting !"); - close(fd_control); - this->fd_control = saved_fd; - return -1; - } - /* Check server xineliboutput version */ - if(!strstr(tmpbuf, "xineliboutput-" XINELIBOUTPUT_VERSION " ")) { - LOGMSG("-----------------------------------------------------------------"); - LOGMSG("WARNING: Client and server versions of xinelibout are different !"); - LOGMSG(" Client version (xine_input_vdr.so) is " XINELIBOUTPUT_VERSION); - LOGMSG("-----------------------------------------------------------------"); - } - - /* Store our client-id */ - if(readline_control(this, tmpbuf, sizeof(tmpbuf)-1, 4) > 0 && - !strncmp(tmpbuf, "CLIENT-ID ", 10)) { - LOGDBG("Got Client-ID: %s", tmpbuf+10); - if(client_id) - if(1 != sscanf(tmpbuf+10, "%d", client_id)) - *client_id = -1; - } else { - LOGMSG("Warning: No Client-ID !"); - if(*client_id) - *client_id = -1; - } - - /* set socket to non-blocking mode */ - fcntl (fd_control, F_SETFL, fcntl (fd_control, F_GETFL) | O_NONBLOCK); - - /* set control socket to deliver data immediately - instead of waiting for full TCP segments */ - setsockopt(fd_control, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(int)); - - this->fd_control = saved_fd; - return fd_control; -} - - -static int connect_rtp_data_stream(vdr_input_plugin_t *this) -{ - char cmd[256]; - unsigned int ip0, ip1, ip2, ip3, port; - int fd=-1, one = 1, retries = 0, n; - struct sockaddr_in multicastAddress; - struct ip_mreq mreq; - struct sockaddr_in server_address, sin; - socklen_t len = sizeof(sin); - stream_rtp_header_impl_t tmp_rtp; - - /* get server IP address */ - if(getpeername(this->fd_control, (struct sockaddr *)&server_address, &len)) { - LOGERR("getpeername(fd_control) failed"); - /* close(fd); */ - return -1; - } - - /* request RTP data transport from server */ - - LOGDBG("Requesting RTP transport"); - if(_x_io_tcp_write(this->stream, this->fd_control, "RTP\r\n", 5) < 0) { - LOGERR("Control stream write error"); - return -1; - } - - cmd[0] = 0; - if(readline_control(this, cmd, sizeof(cmd)-1, 4) < 8 || - strncmp(cmd, "RTP ", 4)) { - LOGMSG("Server does not support RTP ? (%s)", cmd); - return -1; - } - - LOGDBG("Got: %s", cmd); - if(5 != sscanf(cmd, "RTP %u.%u.%u.%u:%u", &ip0, &ip1, &ip2, &ip3, &port) || - ip0>0xff || ip1>0xff || ip2>0xff || ip3>0xff || port>0xffff) { - LOGMSG("Server does not support RTP ? (%s)", cmd); - return -1; - } - - LOGMSG("Connecting (data) to rtp://@%u.%u.%u.%u:%u ...", - ip0, ip1, ip2, ip3, port); - multicastAddress.sin_family = AF_INET; - multicastAddress.sin_port = htons(port); - multicastAddress.sin_addr.s_addr = htonl((ip0<<24)|(ip1<<16)|(ip2<<8)|ip3); - - if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - LOGERR("socket() failed"); - return -1; - } - set_recv_buffer_size(fd, KILOBYTE(512)); - - if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0) { - LOGERR("setsockopt(SO_REUSEADDR) failed"); - close(fd); - return -1; - } - - if(bind(fd, (struct sockaddr *)&multicastAddress, - sizeof(multicastAddress)) < 0) { - LOGERR("bind() to multicast address failed"); - close(fd); - return -1; - } - - /* Join to multicast group */ - - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr.s_addr = multicastAddress.sin_addr.s_addr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - /*mreq.imr_ifindex = 0;*/ - if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) { - LOGERR("setsockopt(IP_ADD_MEMBERSHIP) failed. No multicast in kernel?"); - close(fd); - return -1; - } - -retry_select: - - /* wait until server sends first RTP packet */ - - if( XIO_READY != io_select_rd(fd)) { - LOGDBG("Requesting RTP transport: RTP poll timeout"); - if(++retries < 10) { - LOGDBG("Requesting RTP transport"); - if(_x_io_tcp_write(this->stream, this->fd_control, "RTP\r\n", 5) < 0) { - LOGERR("Control stream write error"); - close(fd); - return -1; - } - goto retry_select; - } - LOGMSG("Data stream connection timed out (RTP)"); - close(fd); - return -1; - } - -retry_recvfrom: - - /* check sender address */ - - n = recvfrom(fd, &tmp_rtp, sizeof(tmp_rtp), 0, &sin, &len); - if(sin.sin_addr.s_addr != server_address.sin_addr.s_addr) { - uint32_t tmp_ip = ntohl(sin.sin_addr.s_addr); - LOGMSG("Received UDP/RTP multicast from unknown sender: %d.%d.%d.%d:%d", - ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff), - ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff), - sin.sin_port); - - if(XIO_READY == _x_io_select(this->stream, fd, XIO_READ_READY, 0)) - goto retry_recvfrom; - if(++retries < 4) - goto retry_select; - close(fd); - return -1; - } - - /* Succeed */ - - this->udp_data = init_udp_data(); - - /* store server address */ - memcpy(&this->udp_data->server_address, &sin, sizeof(sin)); - this->udp_data->ssrc = tmp_rtp.rtp_hdr.ssrc; - - return fd; -} - - -static int connect_udp_data_stream(vdr_input_plugin_t *this) -{ - char cmd[256]; - struct sockaddr_in server_address, sin; - socklen_t len = sizeof(sin); - uint32_t tmp_ip; - stream_udp_header_t tmp_udp; - int n, retries = 0, port = -1, fd = -1; - - /* get server IP address */ - if(getpeername(this->fd_control, (struct sockaddr *)&server_address, &len)) { - LOGERR("getpeername(fd_control) failed"); - /* close(fd); */ - return -1; - } - tmp_ip = ntohl(server_address.sin_addr.s_addr); - - LOGDBG("VDR server address: %d.%d.%d.%d", - ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff), - ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff)); - - /* allocate UDP socket */ - if((fd = alloc_udp_data_socket(DEFAULT_VDR_PORT, 20, &port)) < 0) - return -1; - /*LOGDBG("my UDP port is: %d", port);*/ - -retry_request: - - /* request UDP data transport from server */ - - LOGDBG("Requesting UDP transport"); - sprintf(cmd, "UDP %d\r\n", port); - if(_x_io_tcp_write(this->stream, this->fd_control, cmd, strlen(cmd)) < 0) { - LOGERR("Control stream write error"); - close(fd); - return -1; - } - - cmd[0] = 0; - if(readline_control(this, cmd, sizeof(cmd)-1, 4) < 6 || - strncmp(cmd, "UDP OK", 6)) { - LOGMSG("Server does not support UDP ? (%s)", cmd); - return -1; - } - -retry_select: - - /* wait until server sends first UDP packet */ - - if( XIO_READY != io_select_rd(fd)) { - LOGDBG("Requesting UDP transport: UDP poll timeout"); - if(++retries < 4) - goto retry_request; - LOGMSG("Data stream connection timed out (UDP)"); - close(fd); - return -1; - } - -retry_recvfrom: - - /* check sender address */ - - n = recvfrom(fd, &tmp_udp, sizeof(tmp_udp), 0, &sin, &len); - if(sin.sin_addr.s_addr != server_address.sin_addr.s_addr) { - tmp_ip = ntohl(sin.sin_addr.s_addr); - LOGMSG("Received UDP packet from unknown sender: %d.%d.%d.%d:%d", - ((tmp_ip>>24)&0xff), ((tmp_ip>>16)&0xff), - ((tmp_ip>>8)&0xff), ((tmp_ip)&0xff), - sin.sin_port); - - if(XIO_READY == _x_io_select(this->stream, fd, XIO_READ_READY, 0)) - goto retry_recvfrom; - if(++retries < 4) - goto retry_select; - close(fd); - return -1; - } - - /* Succeed */ - - this->udp_data = init_udp_data(); - - /* store server address */ - memcpy(&this->udp_data->server_address, &sin, sizeof(sin)); - - return fd; -} - -static int connect_tcp_data_stream(vdr_input_plugin_t *this, const char *host, - int port) -{ - struct sockaddr_in sinc; - socklen_t len = sizeof(sinc); - uint32_t ipc; - char tmpbuf[256]; - int fd_data, n; - - /* Connect to server */ - fd_data = _x_io_tcp_connect(this->stream, host, port); - - if(fd_data < 0 || - XIO_READY != _x_io_tcp_connect_finish(this->stream, fd_data, 3000)) { - LOGERR("Can't connect to tcp://%s:%d", host, port); - close(fd_data); - return -1; - } - - set_recv_buffer_size(fd_data, KILOBYTE(128)); - - /* request data connection */ - - getsockname(this->fd_control, (struct sockaddr *)&sinc, &len); - ipc = ntohl(sinc.sin_addr.s_addr); - sprintf(tmpbuf, - "DATA %d 0x%x:%u %d.%d.%d.%d\r\n", - this->client_id, - (unsigned int)ipc, - (unsigned int)ntohs(sinc.sin_port), - ((ipc>>24)&0xff), ((ipc>>16)&0xff), ((ipc>>8)&0xff), ((ipc)&0xff) - ); - if(_x_io_tcp_write(this->stream, fd_data, tmpbuf, strlen(tmpbuf)) < 0) { - LOGERR("Data stream write error (TCP)"); - } else if( XIO_READY != io_select_rd(fd_data)) { - LOGERR("Data stream poll failed (TCP)"); - } else if((n=read(fd_data, tmpbuf, sizeof(tmpbuf))) <= 0) { - LOGERR("Data stream read failed (TCP)"); - } else if(n<6 || strncmp(tmpbuf, "DATA\r\n", 6)) { - tmpbuf[n] = 0; - LOGMSG("Server does not support TCP ? (%s)", tmpbuf); - } else { - /* succeed */ - /* set socket to non-blocking mode */ - fcntl (fd_data, F_SETFL, fcntl (fd_data, F_GETFL) | O_NONBLOCK); - return fd_data; - } - - close(fd_data); - return -1; -} - -static int connect_pipe_data_stream(vdr_input_plugin_t *this) -{ - char tmpbuf[256]; - int fd_data = -1; - - /* check if IP address matches */ - if(!strstr(this->mrl, "127.0.0.1")) { - struct sockaddr_in sinc; - struct sockaddr_in sins; - socklen_t len = sizeof(sinc); - getsockname(this->fd_control, &sinc, &len); - getpeername(this->fd_control, &sins, &len); - if(sinc.sin_addr.s_addr != sins.sin_addr.s_addr) { - LOGMSG("connect_pipe_data_stream: client ip=0x%x != server ip=0x%x !", - (unsigned int)sinc.sin_addr.s_addr, (unsigned int)sins.sin_addr.s_addr); -#if 0 - return -1; -#endif - } - } - - _x_io_tcp_write(this->stream, this->fd_control, "PIPE\r\n", 6); - - if(readline_control(this, tmpbuf, sizeof(tmpbuf), 4) <= 0) { - LOGMSG("Pipe request failed"); - } else if(strncmp(tmpbuf, "PIPE /", 6)) { - LOGMSG("Server does not support pipes ? (%s)", tmpbuf); - } else { - - LOGMSG("Connecting (data) to pipe://%s", tmpbuf+5); - if((fd_data = open(tmpbuf+5, O_RDONLY|O_NONBLOCK)) < 0) { - if(errno == ENOENT) - LOGMSG("Pipe not found"); - else - LOGERR("Pipe opening failed"); - } else { - _x_io_tcp_write(this->stream, this->fd_control, "PIPE OPEN\r\n", 11); - if(readline_control(this, tmpbuf, sizeof(tmpbuf)-1, 4) >6 && - !strncmp(tmpbuf, "PIPE OK", 7)) { - fcntl (fd_data, F_SETFL, fcntl (fd_data, F_GETFL) | O_NONBLOCK); - return fd_data; - } - LOGMSG("Data stream connection failed (PIPE)"); - } - } - - close(fd_data); - return -1; -} - -static int vdr_plugin_open_net (input_plugin_t *this_gen) -{ - vdr_input_plugin_t *this = (vdr_input_plugin_t *) this_gen; - char tmpbuf[256]; - int err; - - LOGDBG("vdr_plugin_open_net %s", this->mrl); - - if(strchr(this->mrl, '#')) - *strchr(this->mrl, '#') = 0; - if((!strncasecmp(this->mrl, MRL_ID "+tcp://", MRL_ID_LEN+7) && (this->tcp=1)) || - (!strncasecmp(this->mrl, MRL_ID "+udp://", MRL_ID_LEN+7) && (this->udp=1)) || - (!strncasecmp(this->mrl, MRL_ID "+rtp://", MRL_ID_LEN+7) && (this->rtp=1)) || - (!strncasecmp(this->mrl, MRL_ID "+pipe://", MRL_ID_LEN+8)) || - (!strncasecmp(this->mrl, MRL_ID ":tcp://", MRL_ID_LEN+7) && (this->tcp=1)) || - (!strncasecmp(this->mrl, MRL_ID ":udp://", MRL_ID_LEN+7) && (this->udp=1)) || - (!strncasecmp(this->mrl, MRL_ID ":rtp://", MRL_ID_LEN+7) && (this->rtp=1)) || - (!strncasecmp(this->mrl, MRL_ID ":pipe://", MRL_ID_LEN+8)) || - (!strncasecmp(this->mrl, MRL_ID "://", MRL_ID_LEN+3))) { - - char *phost = strdup(strstr(this->mrl, "//") + 2); - char host[256]; - char *port = strchr(phost, ':'); - int iport; - int one = 1; - if(port) *port++ = 0; - iport = port ? atoi(port) : DEFAULT_VDR_PORT; - strn0cpy(host, phost, 254); - /*host[sizeof(host)-1] = 0;*/ - free(phost); - /* TODO: use multiple input plugins - tcp/udp/file */ - - /* connect control stream */ - - LOGMSG("Connecting (control) to tcp://%s:%d ...", host, iport); - this->fd_control = connect_control_stream(this, host, iport, - &this->client_id); - if (this->fd_control < 0) { - LOGERR("Can't connect to tcp://%s:%d", host, iport); - return 0; - } - setsockopt(this->fd_control, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(int)); - - LOGMSG("Connected (control) to tcp://%s:%d", host, iport); - - /* connect data stream */ - - /* try pipe ? */ - - if(!this->tcp && !this->udp && !this->rtp) { - if((this->fd_data = connect_pipe_data_stream(this)) < 0) { - LOGMSG("Data stream connection failed (PIPE)"); - } else { - this->tcp = this->udp = this->tcp = 0; - LOGMSG("Data stream connected (PIPE)"); - } - } - - /* try RTP ? */ - - if(this->fd_data < 0 && !this->udp && !this->tcp) { - /* flush control buffer (if PIPE was tried first) */ - while(0 < read(this->fd_control, tmpbuf, 255)) ; - if((this->fd_data = connect_rtp_data_stream(this)) < 0) { - LOGMSG("Data stream connection failed (RTP)"); - this->rtp = 0; - } else { - this->rtp = 1; - this->tcp = this->udp = 0; - LOGMSG("Data stream connected (RTP)"); - } - } - - /* try UDP ? */ - - if(this->fd_data < 0 && !this->tcp) { - LOGMSG("Connecting (data) to udp://%s ...", host); - /* flush control buffer (if RTP was tried first) */ - while(0 < read(this->fd_control, tmpbuf, 255)) ; - if((this->fd_data = connect_udp_data_stream(this)) < 0) { - LOGMSG("Data stream connection failed (UDP)"); - this->udp = 0; - } else { - this->udp = 1; - this->tcp = this->rtp = 0; - LOGMSG("Data stream connected (UDP)"); - } - } - - /* fall back to TCP ? */ - - if(this->fd_data < 0) { - LOGMSG("Connecting (data) to tcp://%s:%d ...", host, iport); - this->tcp = 0; - if((this->fd_data = connect_tcp_data_stream(this, host, iport)) < 0) { - LOGMSG("Data stream connection failed (TCP)"); - this->tcp = 0; - } else { - this->tcp = 1; - } - if(this->tcp) { - /* succeed */ - this->rtp = this->udp = 0; - LOGMSG("Data stream connected (TCP)"); - } else { - /* failed */ - close(this->fd_data); - close(this->fd_control); - this->fd_control = this->fd_data = -1; - return 0; - } - } - - } else { - LOGMSG("Unknown mrl (%s)", this->mrl); - return 0; - } - - if(!vdr_plugin_open(this_gen)) - return 0; - - queue_nosignal(this); - - this->control_running = 1; - if ((err = pthread_create (&this->control_thread, - NULL, vdr_control_thread, (void*)this)) != 0) { - LOGERR("Can't create new thread"); - return 0; - } - if ((err = pthread_create (&this->data_thread, - NULL, vdr_data_thread, (void*)this)) != 0) { - LOGERR("Can't create new thread"); - return 0; - } - - this->class->xine->port_ticket->acquire(this->class->xine->port_ticket, 1); - if(!(this->stream->video_out->get_capabilities(this->stream->video_out) & - VO_CAP_UNSCALED_OVERLAY)) - LOGMSG("WARNING: Video output driver reports it does not support unscaled overlays !"); - this->class->xine->port_ticket->release(this->class->xine->port_ticket, 1); - - this->threads_initialized = 1; - return 1; -} - -/**************************** Plugin class *******************************/ -/* Callback on default mrl change */ -static void vdr_class_default_mrl_change_cb(void *data, xine_cfg_entry_t *cfg) -{ - vdr_input_class_t *class = (vdr_input_class_t *) data; - - class->mrls[0] = cfg->str_value; -} - -/* callback on scr tuning step change */ -static void vdr_class_scr_tuning_step_cb(void *data, xine_cfg_entry_t *cfg) -{ - vdr_input_class_t *class = (vdr_input_class_t *) data; - - class->scr_tuning_step = cfg->num_value / 1000000.0; -} - -/* callback on OSD scaling mode change */ -static void vdr_class_fast_osd_scaling_cb(void *data, xine_cfg_entry_t *cfg) -{ - vdr_input_class_t *class = (vdr_input_class_t *) data; - - class->fast_osd_scaling = cfg->num_value; -} - -static input_plugin_t *vdr_class_get_instance (input_class_t *class_gen, - xine_stream_t *stream, - const char *data) -{ - vdr_input_class_t *class = (vdr_input_class_t *) class_gen; - vdr_input_plugin_t *this; - char *mrl = (char *) data; - int local_mode; - - LOGDBG("vdr_class_get_instance"); - - if (strncasecmp (mrl, MRL_ID ":", MRL_ID_LEN+1) && - strncasecmp (mrl, MRL_ID "+", MRL_ID_LEN+1)) - return NULL; - - if(!strncasecmp(mrl, MRL_ID "+slave://0x", MRL_ID_LEN+11)) { - LOGMSG("vdr_class_get_instance: slave stream requested"); - return fifo_class_get_instance(class_gen, stream, data); - } - - this = calloc(1, sizeof(vdr_input_plugin_t)); - - this->stream = stream; - this->mrl = strdup(mrl); - this->class = class; - - this->fd_data = -1; - this->fd_control = -1; - - this->stream_start = 1; - this->max_buffers = 10; - this->autoplay_size = -1; - - local_mode = ( (!strncasecmp(mrl, MRL_ID "://", MRL_ID_LEN+3)) && - (strlen(mrl)==7)) - || (!strncasecmp(mrl, MRL_ID ":///", MRL_ID_LEN+4)); - - if(!bSymbolsFound) { - /* not running under VDR or vdr-sxfe/vdr-fbfe */ - if(local_mode) { - LOGDBG("vdr or vdr-??fe not detected, forcing remote mode"); - local_mode = 0; - } - if(!strcasecmp(mrl, MRL_ID ":") || - !strcasecmp(mrl, MRL_ID ":/") || - !strcasecmp(mrl, MRL_ID "://") || - !strcasecmp(mrl, MRL_ID ":///")) { - /* default to local host */ - free(this->mrl); - this->mrl = strdup(MRL_ID "://127.0.0.1"); - LOGMSG("Changed mrl from %s to %s", mrl, this->mrl); - } - } - - this->input_plugin.open = local_mode ? vdr_plugin_open_local - : vdr_plugin_open_net; - this->input_plugin.get_mrl = vdr_plugin_get_mrl; - this->input_plugin.dispose = vdr_plugin_dispose; - this->input_plugin.input_class = class_gen; - - this->input_plugin.get_capabilities = vdr_plugin_get_capabilities; - this->input_plugin.read = vdr_plugin_read; - this->input_plugin.read_block = vdr_plugin_read_block; - this->input_plugin.seek = vdr_plugin_seek; - this->input_plugin.get_current_pos = vdr_plugin_get_current_pos; - this->input_plugin.get_length = vdr_plugin_get_length; - this->input_plugin.get_blocksize = vdr_plugin_get_blocksize; - this->input_plugin.get_optional_data = vdr_plugin_get_optional_data; - - if(local_mode) { - this->funcs.push_input_write = vdr_plugin_write; - this->funcs.push_input_control= vdr_plugin_parse_control; - this->funcs.push_input_osd = vdr_plugin_exec_osd_command; - /*this->funcs.xine_input_event= NULL; -- frontend sets this */ - } else { - this->funcs.post_vdr_event = post_vdr_event; - } - - LOGDBG("vdr_class_get_instance done."); - return &this->input_plugin; -} - -/* - * vdr input plugin class stuff - */ - -#if INPUT_PLUGIN_IFACE_VERSION < 18 -#if XINE_VERSION_CODE > 10103 -static const char *vdr_class_get_description (input_class_t *this_gen) -#else -static char *vdr_class_get_description (input_class_t *this_gen) -#endif -{ - return _("VDR (Video Disk Recorder) input plugin"); -} - -static const char *vdr_class_get_identifier (input_class_t *this_gen) -{ - return MRL_ID; -} -#endif - -static char **vdr_plugin_get_autoplay_list(input_class_t *this_gen, int *num_files) -{ - vdr_input_class_t *this = (vdr_input_class_t *)this_gen; - *num_files = 1; - - return this->mrls; -} - -static void vdr_class_dispose (input_class_t *this_gen) -{ - vdr_input_class_t *this = (vdr_input_class_t *) this_gen; - config_values_t *config = this->xine->config; - - config->unregister_callback(config, "media." MRL_ID ".default_mrl"); - config->unregister_callback(config, "media." MRL_ID ".osd.fast_scaling"); - config->unregister_callback(config, "media." MRL_ID ".scr_tuning_step"); - free (this); -} - -static void *input_xvdr_init_class (xine_t *xine, void *data) -{ - vdr_input_class_t *this; - config_values_t *config = xine->config; - - SetupLogLevel(); - - if(!bSymbolsFound) { - if(xine->verbosity > 0) { - iSysLogLevel = xine->verbosity + 1; - LOGMSG("detected verbose logging xine->verbosity=%d, setting log level to %d:%s", - xine->verbosity, iSysLogLevel, - (iSysLogLevel < 1) ? "NONE" : - (iSysLogLevel < 2) ? "ERRORS" : - (iSysLogLevel < 3) ? "INFO" : - (iSysLogLevel < 4) ? "DEBUG" : - "VERBOSE DEBUG"); - } - } - - this = calloc(1, sizeof (vdr_input_class_t)); - - this->xine = xine; - - this->mrls[ 0 ] = config->register_string(config, - "media." MRL_ID ".default_mrl", - MRL_ID "://127.0.0.1#nocache;demux:mpeg_block", - _("default VDR host"), - _("The default VDR host"), - 10, vdr_class_default_mrl_change_cb, (void *)this); - this->mrls[ 1 ] = 0; - - this->fast_osd_scaling = config->register_bool(config, - "media." MRL_ID ".fast_osd_scaling", 0, - _("Fast (low-quality) OSD scaling"), - _("Enable fast (lower quality) OSD scaling.\n" - "Default is to use (slow) linear interpolation " - "to calculate pixels and full palette re-allocation " - "to optimize color palette.\n" - "Fast method only duplicates/removes rows and columns " - "and does not modify palette."), - 10, vdr_class_fast_osd_scaling_cb, - (void *)this); - - this->scr_tuning_step = config->register_num(config, - "media." MRL_ID ".scr_tuning_step", 5000, - _("SRC tuning step"), - _("SCR tuning step width unit %1000000."), - 10, vdr_class_scr_tuning_step_cb, - (void *)this) / 1000000.0; - - this->input_class.get_instance = vdr_class_get_instance; -#if INPUT_PLUGIN_IFACE_VERSION < 18 - this->input_class.get_identifier = vdr_class_get_identifier; - this->input_class.get_description = vdr_class_get_description; -#else - this->input_class.identifier = MRL_ID; - this->input_class.description = N_("VDR (Video Disk Recorder) input plugin"); -#endif - this->input_class.get_autoplay_list = vdr_plugin_get_autoplay_list; - this->input_class.dispose = vdr_class_dispose; - - LOGDBG("init class succeeded"); - - return this; -} - -/* - * demuxer (xine/demux_xvdr.c) - */ - -void *demux_xvdr_init_class (xine_t *xine, void *data); - -static const demuxer_info_t demux_info_xvdr = { - 100 /* priority */ -}; - -/* - * exported plugin catalog entry - */ - -const plugin_info_t xine_plugin_info[] __attribute__((visibility("default"))) = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_INPUT, INPUT_PLUGIN_IFACE_VERSION, MRL_ID, XINE_VERSION_CODE, NULL, input_xvdr_init_class }, - - { PLUGIN_DEMUX, DEMUXER_PLUGIN_IFACE_VERSION, MRL_ID, XINE_VERSION_CODE, &demux_info_xvdr, demux_xvdr_init_class }, - - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; - -const plugin_info_t *xine_plugin_info_xvdr = xine_plugin_info; - - diff --git a/xine_input_vdr.h b/xine_input_vdr.h deleted file mode 100644 index 1039ca8c..00000000 --- a/xine_input_vdr.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * xine_input_vdr.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_input_vdr.h,v 1.10 2009-02-25 14:34:24 phintuka Exp $ - * - */ - -#ifndef __XINE_INPUT_VDR_H_ -#define __XINE_INPUT_VDR_H_ - -#if defined __cplusplus -extern "C" { -#endif - -#include <xine/input_plugin.h> - -#include "xine_input_vdr_mrl.h" - -struct input_plugin_s; -struct vdr_input_plugin_if_s; -struct osd_command_s; -struct frontend_s; - -typedef struct vdr_input_plugin_funcs_s { - /* VDR --> input plugin (only local mode) */ - int (*push_input_write) (struct vdr_input_plugin_if_s *, const char *, int); - int (*push_input_control)(struct vdr_input_plugin_if_s *, const char *); - int (*push_input_osd) (struct vdr_input_plugin_if_s *, struct osd_command_s *); - - /* input plugin --> frontend (only local mode) */ - void (*xine_input_event) (const char *, const char *); - - /* input plugin --> frontend (remote mode) */ - int (*intercept_osd) (struct frontend_s *, struct osd_command_s *); - - /* input plugin --> frontend */ - void *(*fe_control) (struct frontend_s *, const char *); - struct frontend_s *fe_handle; - - /* frontend --> input plugin (remote mode) */ - int (*post_vdr_event) (struct vdr_input_plugin_if_s *, const char *); -} vdr_input_plugin_funcs_t; - -typedef struct vdr_input_plugin_if_s { - input_plugin_t input_plugin; - vdr_input_plugin_funcs_t f; -} vdr_input_plugin_if_t; - -#define CONTROL_OK 0 -#define CONTROL_UNKNOWN -1 -#define CONTROL_PARAM_ERROR -2 -#define CONTROL_DISCONNECTED -3 - -typedef struct grab_data_s { - size_t size; - char *data; -} grab_data_t; - -#if defined __cplusplus -} -#endif - - -#endif /*__XINE_INPUT_VDR_H_*/ - diff --git a/xine_input_vdr_mrl.h b/xine_input_vdr_mrl.h deleted file mode 100644 index 9924d5cc..00000000 --- a/xine_input_vdr_mrl.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * xine_input_vdr_mrl.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_input_vdr_mrl.h,v 1.1 2008-11-11 23:46:41 phintuka Exp $ - * - */ - -#ifndef XINE_INPUT_VDR_MRL_H -#define XINE_INPUT_VDR_MRL_H - -# ifndef MRL_ID - -# define MRL_ID "xvdr" - -# undef MRL_ID_LEN -# define MRL_ID_LEN 4 - -# endif - -#endif diff --git a/xine_input_vdr_net.h b/xine_input_vdr_net.h deleted file mode 100644 index adb389aa..00000000 --- a/xine_input_vdr_net.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * xine_input_vdr_net.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_input_vdr_net.h,v 1.11 2009-03-24 19:35:22 phintuka Exp $ - * - */ - -#ifndef __XINE_INPUT_VDR_NET_H_ -#define __XINE_INPUT_VDR_NET_H_ - -#include <arpa/inet.h> -#ifdef __APPLE__ -# include <machine/endian.h> -#else -# include <endian.h> -#endif - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - -#include "tools/rtp.h" /* generic RTP headers */ - - -/* - * Default port(s) - */ - -#ifndef DEFAULT_VDR_PORT -# define DEFAULT_VDR_PORT 37890 -#endif - -/* - * Byte-order conversions - */ - -#if __BYTE_ORDER == __BIG_ENDIAN -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#else -# error __BYTE_ORDER not defined ! -#endif - -#if __BYTE_ORDER == __BIG_ENDIAN -# define ntohll(val) (val) -# define htonll(val) (val) -# define ntohull(val) (val) -# define htonull(val) (val) -#else -# define ntohll(val) ((int64_t)ntohull((uint64_t)val)) -# define htonll(val) ((int64_t)htonull((uint64_t)val)) -# define ntohull(val) \ - ((uint64_t) ntohl((uint32_t)((val) >> 32)) | \ - (uint64_t) ntohl((uint32_t)(val)) << 32) -# define htonull(val) \ - ((uint64_t) htonl((uint32_t)((val) >> 32)) | \ - (uint64_t) htonl((uint32_t)(val)) << 32) -#endif - - -/* - * Network packet headers - */ - -#if defined __cplusplus -extern "C" { -#endif - - -/* - * TCP / PIPE - */ - -typedef struct stream_tcp_header { - uint64_t pos; /* stream position of first byte */ - uint32_t len; /* length of following PES packet */ - - uint8_t payload[0]; - -} PACKED stream_tcp_header_t; - - -/* - * UDP - */ - -typedef struct stream_udp_header { - uint64_t pos; /* stream position of first byte */ - /* -1ULL and first bytes of frame != 00 00 01 */ - /* --> embedded control stream data */ - uint16_t seq; /* packet sequence number - (for re-ordering and detecting missing packets) */ - - uint8_t payload[0]; - -} PACKED stream_udp_header_t; - -#define UDP_SEQ_MASK 0xff - - -/* - * RTP - */ - -/* xineliboutput RTP header extension */ -typedef struct stream_rtp_header_ext_x { - - stream_rtp_header_ext_t hdr; - - union { - uint8_t raw[12]; /* 3 DWORDs */ - uint32_t rawd[3]; - - union { - - struct { - uint16_t padding0; /* must be padded to full DWORDs */ - stream_udp_header_t udphdr; - } PACKED; - - struct { - uint16_t padding1; /* must be padded to full DWORDs */ - - uint64_t pos; - uint16_t seq; - } PACKED; - - } PACKED; - } PACKED; - - uint8_t payload[0]; - -} PACKED stream_rtp_header_ext_x_t; - - -/* xineliboutput RTP header */ -typedef struct stream_rtp_header_impl { - - stream_rtp_header_t rtp_hdr; - stream_rtp_header_ext_x_t hdr_ext; - - uint8_t payload[0]; - -} PACKED stream_rtp_header_impl_t; - - -#define RTP_VERSION 2 -#define RTP_MARKER_BIT 0x80 -#define RTP_HDREXT_BIT 0x10 -#define RTP_PAYLOAD_TYPE_PES 96 /* application */ -#define RTP_PAYLOAD_TYPE_TS 33 /* MPEG-TS */ - -#define RTP_VERSION_BYTE (RTP_VERSION<<6) -#define RTP_PAYLOAD_TYPE_PES_M (RTP_PAYLOAD_TYPE_PES|RTP_MARKER_BIT) -#define RTP_PAYLOAD_TYPE_TS_M (RTP_PAYLOAD_TYPE_TS |RTP_MARKER_BIT) - -#define RTP_HEADER_EXT_X_SIZE 3 /* dwords, not counting stream_rtp_header_ext_t */ -#define RTP_HEADER_EXT_X_TYPE 0x54d3 - - -#if defined __cplusplus -} -#endif - - -#endif /*__XINE_INPUT_VDR_NET_H_*/ - diff --git a/xine_osd_command.h b/xine_osd_command.h deleted file mode 100644 index 7988b0fb..00000000 --- a/xine_osd_command.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * xine_osd_command.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_osd_command.h,v 1.14 2008-12-19 15:08:19 phintuka Exp $ - * - */ - -#ifndef __XINE_OSD_COMMAND_H_ -#define __XINE_OSD_COMMAND_H_ - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - - -#define MAX_OSD_OBJECT 50 - -#if defined __cplusplus -extern "C" { -#endif - -typedef enum { - OSD_Nop = 0, /* Do nothing ; used to initialize delay_ms counter */ - OSD_Size = 1, /* Set size of VDR OSD area (usually 720x576) */ - OSD_Set_RLE = 2, /* Create/update OSD window. Data is rle-compressed. */ - OSD_SetPalette = 3, /* Modify palette of already created OSD window */ - OSD_Move = 4, /* Change x/y position of already created OSD window */ - OSD_Close = 5, /* Close OSD window */ - OSD_Set_YUV = 6, /* Create/update OSD window. Data is in YUV420 format. */ - OSD_Commit = 7, /* All OSD areas have been updated, commit changes to display */ - OSD_Flush = 8 /* Flush all pending OSD operations immediately */ -} osd_command_id_t; - -#define OSDFLAG_YUV_CLUT 0x01 /* palette is in YUV format */ -#define OSDFLAG_REFRESH 0x02 /* OSD data refresh for new config, clients, etc. - no changes in bitmap */ -#define OSDFLAG_UNSCALED 0x04 /* xine-lib unscaled (hardware) blending */ -#define OSDFLAG_UNSCALED_LOWRES 0x08 /* unscaled blending when video resolution < .95 * 720x576 */ - -#define OSDFLAG_TOP_LAYER 0x10 /* window is part of top layer OSD */ - -typedef struct xine_clut_s { - union { - uint8_t cb /*: 8*/; - uint8_t g; - }; - union { - uint8_t cr /*: 8*/; - uint8_t b; - }; - union { - uint8_t y /*: 8*/; - uint8_t r; - }; - uint8_t alpha /*: 8*/; -} PACKED xine_clut_t; /* from xine, alphablend.h */ - -typedef struct xine_rle_elem_s { - uint16_t len; - uint16_t color; -} PACKED xine_rle_elem_t; /* from xine */ - -typedef struct osd_rect_s { - uint16_t x1; - uint16_t y1; - uint16_t x2; - uint16_t y2; -} osd_rect_t; - -typedef struct osd_command_s { - uint8_t size; /* size of osd_command_t struct */ - - uint8_t cmd; /* osd_command_id_t */ - - uint8_t wnd; /* OSD window handle */ - uint8_t layer; /* OSD layer */ - - int64_t pts; /* execute at given pts */ - uint32_t delay_ms; /* execute 'delay_ms' ms after previous command (for same window). */ - - uint16_t x; /* window position, x */ - uint16_t y; /* window position, y */ - uint16_t w; /* window width */ - uint16_t h; /* window height */ - - uint32_t datalen; /* size of image data, in bytes */ - uint32_t num_rle; - union { - xine_rle_elem_t *data; /* RLE compressed image */ - uint8_t *raw_data; - uint64_t dummy01; - }; - uint32_t colors; /* palette size */ - union { - xine_clut_t *palette; /* palette (YCrCb) */ - uint64_t dummy02; - }; - - osd_rect_t dirty_area; - uint8_t flags; - uint8_t scaling; - -} PACKED osd_command_t; - - -#if __BYTE_ORDER == __LITTLE_ENDIAN -# define hton_osdcmd(cmdP) \ - do { \ - cmdP.pts = htonll(cmdP.pts); \ - cmdP.delay_ms = htonl (cmdP.delay_ms); \ - cmdP.x = htons (cmdP.x); \ - cmdP.y = htons (cmdP.y); \ - cmdP.w = htons (cmdP.w); \ - cmdP.h = htons (cmdP.h); \ - cmdP.datalen = htonl (cmdP.datalen); \ - cmdP.num_rle = htonl (cmdP.num_rle); \ - cmdP.colors = htonl (cmdP.colors); \ - cmdP.dirty_area.x1 = htons(cmdP.dirty_area.x1); \ - cmdP.dirty_area.y1 = htons(cmdP.dirty_area.y1); \ - cmdP.dirty_area.x2 = htons(cmdP.dirty_area.x2); \ - cmdP.dirty_area.y2 = htons(cmdP.dirty_area.y2); \ - } while(0) - -# define ntoh_osdcmd(cmdP) \ - do { \ - cmdP.pts = ntohll(cmdP.pts); \ - cmdP.delay_ms = ntohl (cmdP.delay_ms); \ - cmdP.x = ntohs (cmdP.x); \ - cmdP.y = ntohs (cmdP.y); \ - cmdP.w = ntohs (cmdP.w); \ - cmdP.h = ntohs (cmdP.h); \ - cmdP.datalen = ntohl (cmdP.datalen); \ - cmdP.num_rle = ntohl (cmdP.num_rle); \ - cmdP.colors = ntohl (cmdP.colors); \ - cmdP.dirty_area.x1 = ntohs(cmdP.dirty_area.x1); \ - cmdP.dirty_area.y1 = ntohs(cmdP.dirty_area.y1); \ - cmdP.dirty_area.x2 = ntohs(cmdP.dirty_area.x2); \ - cmdP.dirty_area.y2 = ntohs(cmdP.dirty_area.y2); \ - } while(0) - -#elif __BYTE_ORDER == __BIG_ENDIAN - -# define hton_osdcmd(cmd) do {} while(0) -# define ntoh_osdcmd(cmd) do {} while(0) - -#else -# error __BYTE_ORDER undefined ! -#endif - - -#if defined __cplusplus -} -#endif - -#endif /*__XINE_OSD_COMMAND_H_*/ diff --git a/xine_post_audiochannel.c b/xine_post_audiochannel.c deleted file mode 100644 index 9326162b..00000000 --- a/xine_post_audiochannel.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * xine_post_audiochannel.c: xine post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_post_audiochannel.c,v 1.6 2008-05-22 09:56:02 phintuka Exp $ - * - */ - -/* - * Copyright (C) 2006 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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 - * - * $Id: - * - * audio channel selection post plugin by Petri Hintukainen 01/09/2006 - * based on upmix.c - * - * Removes left or right channel from stereo audio track - * and fills both channels with same data. - * This is useful with some bi-lingual DVB transmissions where - * two different languages are sent on same (stereo) audio track. - * - */ - -#include <xine/xine_internal.h> -#include <xine/post.h> - - -typedef struct audioch_parameters_s { - int channel; -} audioch_parameters_t; - -START_PARAM_DESCR(audioch_parameters_t) -PARAM_ITEM(POST_PARAM_TYPE_BOOL, channel, NULL, 0, 1, 0, - "select channel (0=left, 1=right)") -END_PARAM_DESCR(audioch_param_descr) - - -typedef struct audioch_post_plugin_s -{ - post_plugin_t post_plugin; - xine_post_in_t parameter_input; - - /* Config */ - int channel; /* 0 - left, 1 - right */ - - /* Data */ - int channels; - -} audioch_post_plugin_t; - - -/* - * Port functions - */ -#if XINE_VERSION_CODE < 10200 -static int audioch_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream, - uint32_t bits, uint32_t rate, int mode) -#else -static int audioch_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream, - ao_format_t format) -#endif -{ - post_audio_port_t *port = (post_audio_port_t *)port_gen; - audioch_post_plugin_t *this = (audioch_post_plugin_t *)port->post; - - _x_post_rewire(&this->post_plugin); - _x_post_inc_usage(port); - - port->stream = stream; -#if XINE_VERSION_CODE < 10200 - port->bits = bits; - port->rate = rate; - port->mode = mode; - - this->channels = _x_ao_mode2channels(mode); - - return port->original_port->open(port->original_port, stream, bits, rate, mode ); -#else - port->format = format; - - this->num_channels = _x_ao_mode2channels(format.mode); - - return port->original_port->open(port->original_port, stream, format); -#endif - - -} - -static void audioch_port_put_buffer (xine_audio_port_t *port_gen, - audio_buffer_t *buf, xine_stream_t *stream) -{ - post_audio_port_t *port = (post_audio_port_t *)port_gen; - audioch_post_plugin_t *this = (audioch_post_plugin_t *)port->post; - int i; - - if(this->channels == 2) { -#if XINE_VERSION_CODE < 10200 - int step = buf->format.bits / 8; -#else - int step = sample_bytes_table[buf->format.sample_format]; -#endif - audio_buffer_t *newbuf = port->original_port->get_buffer(port->original_port); - newbuf->num_frames = buf->num_frames; - newbuf->vpts = buf->vpts; - newbuf->frame_header_count = buf->frame_header_count; - newbuf->first_access_unit = buf->first_access_unit; -#if XINE_VERSION_CODE < 10200 - newbuf->format.bits = buf->format.bits; - newbuf->format.rate = buf->format.rate; - newbuf->format.mode = buf->format.mode; -#else - newbuf->format = buf->format; -#endif - _x_extra_info_merge( newbuf->extra_info, buf->extra_info); - - switch(step) { - case 1: - for(i=0; i<buf->num_frames; i++) - newbuf->mem[i*2+1] = newbuf->mem[i*2] = buf->mem[i*2+this->channel]; - break; - case 2: - for(i=0; i<buf->num_frames; i++) - ((uint16_t*)newbuf->mem)[i*2+1] = - ((uint16_t*)newbuf->mem)[i*2] = ((uint16_t*)buf->mem)[i*2+this->channel]; - break; - case 3: - for(i=0; i<buf->num_frames*3; i+=3) { - newbuf->mem[i*2+0] = newbuf->mem[i*2+3] = buf->mem[i*2+0+3*this->channel]; - newbuf->mem[i*2+1] = newbuf->mem[i*2+4] = buf->mem[i*2+1+3*this->channel]; - newbuf->mem[i*2+2] = newbuf->mem[i*2+5] = buf->mem[i*2+2+3*this->channel]; - } - break; - case 4: - for(i=0; i<buf->num_frames; i++) - ((uint32_t*)newbuf->mem)[i*2+1] = - ((uint32_t*)newbuf->mem)[i*2] = ((uint32_t*)buf->mem)[i*2+this->channel]; - break; - default: /* ??? */ - memcpy(newbuf->mem, buf->mem, buf->num_frames*2*buf->format.bits); - break; - } - - /* pass data to original port */ - port->original_port->put_buffer(port->original_port, newbuf, stream ); - - /* free data from origial buffer */ - buf->num_frames=0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */ - } - - port->original_port->put_buffer(port->original_port, buf, stream ); -} - -/* - * Parameter functions - */ - -static xine_post_api_descr_t *audioch_get_param_descr(void) -{ - return &audioch_param_descr; -} - -static int audioch_set_parameters(xine_post_t *this_gen, void *param_gen) -{ - audioch_post_plugin_t *this = (audioch_post_plugin_t *)this_gen; - audioch_parameters_t *param = (audioch_parameters_t *)param_gen; - - this->channel = param->channel; - return 1; -} - -static int audioch_get_parameters(xine_post_t *this_gen, void *param_gen) -{ - audioch_post_plugin_t *this = (audioch_post_plugin_t *)this_gen; - audioch_parameters_t *param = (audioch_parameters_t *)param_gen; - - param->channel = this->channel; - return 1; -} - -static char *audioch_get_help(void) { - return _("The audiochannel plugin is meant to take stereo audio and \n" - "remove left or right channel by replacing both channels \n" - "with the same data. \n" - "\n" - "Parameters \n" - " channel: Select channel (left=0, right=1) \n" - "\n" - ); -} - - -/* - * Open / Close - */ - -static void audioch_dispose(post_plugin_t *this_gen) -{ - if (_x_post_dispose(this_gen)) - free(this_gen); -} - -static post_plugin_t *audioch_open_plugin(post_class_t *class_gen, - int inputs, - xine_audio_port_t **audio_target, - xine_video_port_t **video_target) -{ - audioch_post_plugin_t *this = calloc(1, sizeof(audioch_post_plugin_t)); - post_in_t *input; - post_out_t *output; - post_audio_port_t *port; - xine_post_in_t *input_param; - - static xine_post_api_t post_api = - { audioch_set_parameters, audioch_get_parameters, - audioch_get_param_descr, audioch_get_help }; - - if (!this || !audio_target || !audio_target[0] ) { - free(this); - return NULL; - } - - _x_post_init(&this->post_plugin, 1, 0); - - port = _x_post_intercept_audio_port(&this->post_plugin, - audio_target[ 0 ], - &input, &output); - - port->new_port.open = audioch_port_open; - port->new_port.put_buffer = audioch_port_put_buffer; - - input->xine_in.name = "audio in"; - output->xine_out.name = "audio out"; - - this->post_plugin.xine_post.audio_input[ 0 ] = &port->new_port; - this->post_plugin.dispose = audioch_dispose; - - input_param = &this->parameter_input; - input_param->name = "parameters"; - input_param->type = XINE_POST_DATA_PARAMETERS; - input_param->data = &post_api; -#if XINE_VERSION_CODE >= 10102 - xine_list_push_back(this->post_plugin.input, input_param); -#else - xine_list_append_content(this->post_plugin.input, input_param); -#endif - - this->channel = 0; - - this->channels = 0; - - return &this->post_plugin; -} - -/* - * Plugin class - */ - -#if POST_PLUGIN_IFACE_VERSION < 10 -static char *audioch_get_identifier(post_class_t *class_gen) -{ - return "audiochannel"; -} - -static char *audioch_get_description(post_class_t *class_gen) -{ - return "Select audio channel"; -} - -static void audioch_class_dispose(post_class_t *class_gen) -{ - free(class_gen); -} -#endif - -static void *audioch_init_plugin(xine_t *xine, void *data) -{ - post_class_t *class = calloc(1, sizeof(post_class_t)); - - if(!class) - return NULL; - - class->open_plugin = audioch_open_plugin; -#if POST_PLUGIN_IFACE_VERSION < 10 - class->get_identifier = audioch_get_identifier; - class->get_description = audioch_get_description; - class->dispose = audioch_class_dispose; -#else - class->identifier = "audiochannel"; - class->description = N_("Select audio channel"); - class->dispose = default_post_class_dispose; -#endif - - return class; -} - -static post_info_t audioch_info = { XINE_POST_TYPE_AUDIO_FILTER }; - -#ifndef NO_INFO_EXPORT -plugin_info_t xine_plugin_info[] __attribute__((visibility("default"))) = -{ - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_POST, POST_PLUGIN_IFACE_VERSION, "audiochannel", XINE_VERSION_CODE, &audioch_info, &audioch_init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; -#endif diff --git a/xine_post_autocrop.c b/xine_post_autocrop.c deleted file mode 100644 index 014bb95e..00000000 --- a/xine_post_autocrop.c +++ /dev/null @@ -1,1617 +0,0 @@ -/* - * xine_post_autocrop.c: xine post plugin - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_post_autocrop.c,v 1.15 2008-11-01 07:07:12 phintuka Exp $ - * - */ - -/* - * Copyright (C) 2006 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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 - * - * - * autocrop video filter by Petri Hintukainen 25/03/2006 - * - * Automatically crop 4:3 letterbox frames to 16:9 - * - * based on expand.c - * - * - * TODO: - * - more reliable border detection, including channel logo detection - * - OSD re-positioning (?) - * - */ - -#include <stdint.h> - -#include <xine/xine_internal.h> -#include <xine/post.h> - -/* - * Configuration - */ - -/*#define USE_CROP / * Crop frame in video_out instead of copying */ -/*#define MARK_FRAME Draw markers on detected boundaries */ -/*#define ENABLE_64BIT 1 Force using of 64-bit routines */ -/*#undef __MMX__ Disable MMX */ -/*#undef __SSE__ Disable SSE */ -/*#define FILTER2 Tighter Y-filter */ - -# if defined(__SSE__) -# warning Compiling with SSE support -# include <xmmintrin.h> -# elif defined(__MMX__) -# warning Compiling with MMX support -# include <mmintrin.h> -# endif - -#if defined(__WORDSIZE) -# if __WORDSIZE == 64 -# warning Compiling with 64-bit integer support -# define ENABLE_64BIT (sizeof(int) > 32) -# endif -#endif - -/*#define TRACE printf*/ -#define TRACE(x...) do {} while(0) -#define INFO printf - - -/* - * Constants - */ - -#define YNOISEFILTER (0xE0U) -#define YSHIFTUP (0x05U) -#define UVBLACK (0x80U) -#define UVSHIFTUP (0x03U) -#define UVNOISEFILTER (0xF8U) - -/* YV12 */ -#define YNOISEFILTER32 (YNOISEFILTER * 0x01010101U) -#define YSHIFTUP32 (YSHIFTUP * 0x01010101U) -#define UVBLACK32 (UVBLACK * 0x01010101U) -#define UVSHIFTUP32 (UVSHIFTUP * 0x01010101U) -#define UVNOISEFILTER32 (UVNOISEFILTER * 0x01010101U) - -#define YNOISEFILTER64 (YNOISEFILTER * UINT64_C(0x0101010101010101)) -#define YSHIFTUP64 (YSHIFTUP * UINT64_C(0x0101010101010101)) -#define UVBLACK64 (UVBLACK * UINT64_C(0x0101010101010101)) -#define UVSHIFTUP64 (UVSHIFTUP * UINT64_C(0x0101010101010101)) -#define UVNOISEFILTER64 (UVNOISEFILTER * UINT64_C(0x0101010101010101)) - -/* YUY2 */ -/* TODO: should use normal/inverse order based on endianess */ -#if 0 -#define YUY2BLACK32 (UVBLACK * 0x00010001U) -#define YUY2SHIFTUP32 (UVSHIFTUP * 0x00010001U) -#define YUY2NOISEFILTER32 ((YNOISEFILTER * 0x01000100U)|(UVNOISEFILTER * 0x00010001U)) -#else -#define YUY2BLACK32 (UVBLACK * 0x01000100U) -#define YUY2SHIFTUP32 (UVSHIFTUP * 0x01000100U) -#define YUY2NOISEFILTER32 ((YNOISEFILTER * 0x00010001U)|(UVNOISEFILTER * 0x01000100U)) -#endif - -#define YUY2BLACK64 (YUY2BLACK32 * UINT64_C(0x0000000100000001)) -#define YUY2SHIFTUP64 (YUY2SHIFTUP32 * UINT64_C(0x0000000100000001)) -#define YUY2NOISEFILTER64 (YUY2NOISEFILTER32 * UINT64_C(0x0000000100000001)) - -#ifdef FILTER2 -/* tighter Y-filter: original black threshold is 0x1f ; here it is 0x1f - 0x0b = 0x14 */ -# define YUY2SHIFTUP32 ((UVSHIFTUP * 0x00010001U)|(YSHIFTUP * 0x01000100U)) -# undef __SSE__ -#endif - - -#define START_TIMER_INIT (25) /* 1 second, unit: frames */ -#define HEIGHT_LIMIT_LIFETIME (60*25) /* 1 minute, unit: frames */ - -#define LOGOSKIP (frame->width/4) /* skip logo (Y, top-left or top-right quarter) */ - -/* - * Plugin - */ - -typedef struct autocrop_parameters_s { - int enable_autodetect; - int enable_subs_detect; - int soft_start; - int stabilize; -} autocrop_parameters_t; - -START_PARAM_DESCR(autocrop_parameters_t) -PARAM_ITEM(POST_PARAM_TYPE_BOOL, enable_autodetect, NULL, 0, 1, 0, - "enable automatic border detecton") -PARAM_ITEM(POST_PARAM_TYPE_BOOL, enable_subs_detect, NULL, 0, 1, 0, - "enable automatic subtitle detecton") -PARAM_ITEM(POST_PARAM_TYPE_BOOL, soft_start, NULL, 0, 1, 0, - "enable soft start of cropping") -PARAM_ITEM(POST_PARAM_TYPE_BOOL, stabilize, NULL, 0, 1, 0, - "stabilize cropping to 14:9, 16:9, (16:9+subs), 20:9, (20:9+subs)") -END_PARAM_DESCR(autocrop_param_descr) - - -typedef struct autocrop_post_plugin_s -{ - post_plugin_t post_plugin; - - xine_post_in_t parameter_input; - - /* setup */ - int autodetect; - int subs_detect; - int soft_start; - int stabilize; - - /* Current cropping status */ - int cropping_active; - - /* Detected bars */ - int start_line; - int end_line; - int crop_total; - - /* Previously detected bars - - eliminate jumping if there is some noise at bar boundaries: - don't change cropped area unless it has been stable for - some time */ - int prev_start_line; - int prev_end_line; - - /* Delayed start for cropping */ - int start_timer; - int stabilize_timer; - - /* Last seen frame */ - int prev_height; - int prev_width; - int64_t prev_pts; - - /* eliminate jumping when when there are subtitles inside bottom bar: - - when cropping is active and one frame has larger end_line - than previous, we enlarge frame. - - after this, cropping is not resetted to previous value unless - bottom bar has been empty for certain time */ - int height_limit_active; /* true if detected possible subtitles in bottom area */ - int height_limit; /* do not crop bottom above this value (bottom of subtitles) */ - int height_limit_timer; /* counter how many following frames must have black - bottom bar until returning to full cropping - (used to reset height_limit when there are no subtitles) */ -} autocrop_post_plugin_t; - - -/* - * Black bar detection - * - * Detect black lines with simple noise filtering. - * Line is "black" if Y-valus are less than 0x20 and - * U/V values inside range 0x7d...0x84. - * ~ 32 first and last pixels are not checked. - * - */ - -static int blank_line_Y_C(uint8_t *data, int length); -static int blank_line_UV_C(uint8_t *data, int length); -static int blank_line_YUY2_C(uint8_t *data, int length); -#if defined(ENABLE_64BIT) -static int blank_line_Y_C64(uint8_t *data, int length); -static int blank_line_UV_C64(uint8_t *data, int length); -static int blank_line_YUY2_C64(uint8_t *data, int length); -#endif -#if defined(__MMX__) -static int blank_line_Y_mmx(uint8_t *data, int length); -static int blank_line_UV_mmx(uint8_t *data, int length); -static int blank_line_YUY2_mmx(uint8_t *data, int length); -#endif -#if defined(__SSE__) -static int blank_line_Y_sse(uint8_t *data, int length); -static int blank_line_UV_sse(uint8_t *data, int length); -static int blank_line_YUY2_sse(uint8_t *data, int length); -#endif - -static int blank_line_Y_INIT(uint8_t *data, int length); -static int blank_line_UV_INIT(uint8_t *data, int length); -static int blank_line_YUY2_INIT(uint8_t *data, int length); - -static void autocrop_init_mm_accel(void); - -int (*blank_line_Y)(uint8_t *data, int length) = blank_line_Y_INIT; -int (*blank_line_UV)(uint8_t *data, int length) = blank_line_UV_INIT; -int (*blank_line_YUY2)(uint8_t *data, int length) = blank_line_YUY2_INIT; - -static int blank_line_Y_C(uint8_t *data, int length) -{ - uint32_t *data32 = (uint32_t*)((((long int)data) + 32 + 3) & (~3)), r = 0; - - length -= 64; /* skip borders (2 x 32 pixels) */ - length /= 4; /* 4 bytes / loop */ - -#ifdef FILTER2 - while(length) { - /* shiftdown needs saturated unsigned element-wise substraction, available only in MMX ...*/ - /* -> use shiftup and looser noise filter for same result. */ - /* this needs special handling for large values */ - r = r | data32[--length]; /* this catches large values (0xf9 : 0xf9+0x7=0x100 === black) */ - r = r | (data32[length] + YSHIFTUP32); /* this catches small walues (0x1d...0x1f) */ - } -#else - while(length) - r = r | data32[--length]; -#endif - - return !(r & YNOISEFILTER32); -} - -static int blank_line_UV_C(uint8_t *data, int length) -{ - uint32_t *data32 = (uint32_t*)((((long int)data) + 16 + 3) & (~3)); - uint32_t r1 = 0, r2 = 0; - - length -= 32; /* skip borders (2 x 32 pixels, 2 pix/byte) */ - length /= 4; /* 2 x 4 bytes / loop */ - - while(length>0) { - r1 = r1 | ((data32[--length] + UVSHIFTUP32) ^ UVBLACK32); - r2 = r2 | ((data32[--length] + UVSHIFTUP32) ^ UVBLACK32); - } - return !((r1|r2) & (UVNOISEFILTER32)); -} - -#if defined(ENABLE_64BIT) -static int blank_line_Y_C64(uint8_t *data, int length) -{ - uint64_t *data64 = (uint64_t*)((((long int)data) + 32 + 7) & (~7)), r = 0; - - length -= 64; /* skip borders (2 x 32 pixels) */ - length /= 8; /* 8 bytes / loop */ - -#ifdef FILTER2 - while(length) { - r = r | data64[--length]; - r = r | (data64[length] + YSHIFTUP64); - } -#else - while(length) - r = r | data64[--length]; -#endif - - return !(r & YNOISEFILTER64); -} -#endif - -#if defined(ENABLE_64BIT) -static int blank_line_UV_C64(uint8_t *data, int length) -{ - uint64_t *data64 = (uint64_t*)((((long int)data) + 16 + 7) & (~7)); - uint64_t r1 = UINT64_C(0), r2 = UINT64_C(0); - - length -= 32; /* skip borders (2x32 pixels, 2 pix/byte) */ - length /= 8; /* 2 x 8 bytes / loop */ - - while(length>0) { - r1 = r1 | ((data64[--length] + UVSHIFTUP64) ^ UVBLACK64); - r2 = r2 | ((data64[--length] + UVSHIFTUP64) ^ UVBLACK64); - } - return !((r1|r2) & (UVNOISEFILTER64)); -} -#endif - - -#if defined(__MMX__) -typedef union { - uint32_t u32[2]; - __m64 m64; -} __attribute__((__aligned__ (8))) __m64_wrapper; -#endif - -#if defined(__MMX__) - int blank_line_Y_mmx(uint8_t *data, int length) -{ -#ifdef FILTER2 - static const __m64_wrapper mask = {{YNOISEFILTER32, YNOISEFILTER32}}; - static const __m64_wrapper gshift = {{YSHIFTUP32, YSHIFTUP32}}; - register __m64 sum, sum2, shift = gshift.m64, val; -#else - static const __m64_wrapper mask = {{YNOISEFILTER32, YNOISEFILTER32}}; - register __m64 sum; -#endif - __m64 *data64 = (__m64*)(((long int)(data + 32 + 7)) & (~7)); - - /*sum = _m_pxor(sum,sum);*/ - __asm__("pxor %0,%0" : "=y"(sum)); - - length -= 64; /* skip borders (2 x 32 pixels) */ - length /= 8; /* 8 bytes / loop */ - -#ifdef FILTER2 - __asm__("pxor %0,%0" : "=y"(sum2)); - while(length) { - val = data64[--length]; - sum = _m_por(sum, val); - sum2 = _m_por(sum2, _m_paddb(val, shift)); - } - sum = _m_por(sum, sum2); -#else - while(length) - sum = _m_por(sum, data64[--length]); -#endif - - sum = _m_pand(sum, mask.m64); - return 0 == _m_to_int(_m_packsswb(sum, sum)); -} -#endif - -#if defined(__MMX__) -static int blank_line_UV_mmx(uint8_t *data, int length) -{ - static const __m64_wrapper gm_03 = {{UVSHIFTUP32, UVSHIFTUP32}}; - static const __m64_wrapper gm_f8 = {{UVNOISEFILTER32, UVNOISEFILTER32}}; - static const __m64_wrapper gm_80 = {{UVBLACK32, UVBLACK32}}; - __m64 *data64 = (__m64*)(((long int)(data) + 16 + 7) & (~7)); - register __m64 sum1, sum2, m_03, /*m_f8,*/ m_80; - - /*sum1 = _m_pxor(sum1, sum1); sum1 = _mm_setzero_si64(); */ - /*sum2 = _m_pxor(sum2, sum2); sum2 = _mm_setzero_si64(); */ - __asm__("pxor %0,%0" : "=y"(sum1)); - __asm__("pxor %0,%0" : "=y"(sum2)); - - /* fetch static data to MMX registers */ - m_03 = gm_03.m64; - /*m_f8 = gm_f8.m64;*/ - m_80 = gm_80.m64; - - length -= 32; /* skip borders (2 x 32 pixels, 2pix/byte) */ - length /= 8; /* 8 bytes / vector */ - - do { - /* process two 8-byte vectors */ - sum1 = _m_por(sum1, - /* grab every byte that is not black (x ^ 0x80 != 0) */ - _m_pxor( - /* filter noise: U/V of each "black" pixel should be 0x7d..0x84 - -> each black pixel should be 0x80 after (x+3) & 0xf8 */ - /*_m_pand(*/ - /* each black pixel should be 0x80..0x87 after adding 3 */ - _m_paddb( - data64[length-1], - m_03)/*, - m_f8)*/, - m_80)); - sum2 = _m_por(sum2, - _m_pxor( - /*_m_pand( */ - _m_paddb( - data64[length-2], - m_03)/*, - m_f8)*/, - m_80)); - length -= 2; - } while(length>0); - - /* combine two result vectors (or), filter noise (and) */ - sum1 = _m_pand(_m_por(sum1, - sum2), - gm_f8.m64); - /* result vector of black line is 0 */ - return 0 == _m_to_int(_m_packsswb(sum1, sum1)); -} -#endif - -#if defined(__SSE__) -typedef union { - uint32_t u32[4]; - __m128 m128; -} __attribute((__aligned__ (16))) __m128_wrapper; -#endif - -#if defined(__SSE__) -static int blank_line_Y_sse(uint8_t *data, int length) -{ - static const __m128_wrapper gmask = {{YNOISEFILTER32, YNOISEFILTER32, - YNOISEFILTER32, YNOISEFILTER32}}; - __m128 *data128 = (__m128*)(((long int)(data) + 32 + 15) & (~15)); - register __m128 sum1, sum2, zero, mask; - - length -= 64; /* skip borders (2 x 32 pixels) */ - length /= 16; /* 16 bytes / loop */ - - /* Start prefetching data to CPU cache */ - _mm_prefetch(data128+length-1, _MM_HINT_NTA); - _mm_prefetch(data128+length-3, _MM_HINT_NTA); - - /* - * Process in two paraller loops, one 16 byte vector / each sub-loop - * - grabs bytes with value larger than treshold - */ - - zero = _mm_setzero_ps(); - mask = gmask.m128; - sum1 = zero; - sum2 = zero; - - do { - _mm_prefetch(data128+length-5, _MM_HINT_NTA); - sum1 = _mm_or_ps(sum1, data128[--length]); - sum2 = _mm_or_ps(sum2, data128[--length]); - } while(length>0); - - return 0x0f == _mm_movemask_ps(_mm_cmpeq_ps(_mm_and_ps(_mm_or_ps(sum1, - sum2), - gmask.m128), - _mm_setzero_ps())); -} -#endif - -#if defined(__SSE__) -static int blank_line_UV_sse(uint8_t *data, int length) -{ - uint8_t *top = data + length - 1; - do { - _mm_prefetch(top, _MM_HINT_NTA); - _mm_prefetch(top-32, _MM_HINT_NTA); - _mm_prefetch(top-64, _MM_HINT_NTA); - _mm_prefetch(top-72, _MM_HINT_NTA); - top -= 128; - } while(top >= data); - - return blank_line_UV_mmx(data, length); -} -#endif - -static int blank_line_YUY2_C(uint8_t *data, int length) -{ - uint32_t *data32 = (uint32_t*)((((long int)data) + 64 + 3) & (~3)); - uint32_t r1 = 0, r2 = 0; - - length -= 128; /* skip borders (2 x 32 pixels, 2 bytes/pixel) */ - length /= 4; /* 2 x 4 bytes / loop */ - - while(length) { - r1 = r1 | ((data32[--length] + YUY2SHIFTUP32) ^ YUY2BLACK32); - r2 = r2 | ((data32[--length] + YUY2SHIFTUP32) ^ YUY2BLACK32); - } - return !((r1|r2) & YUY2NOISEFILTER32); -} - -#if defined(ENABLE_64BIT) -static int blank_line_YUY2_C64(uint8_t *data, int length) -{ - uint64_t *data64 = (uint64_t*)((((long int)data) + 64 + 7) & (~7)); - uint64_t r1 = 0, r2 = 0; - - length -= 128; /* skip borders (2 x 32 pixels, 2 bytes/pixel) */ - length /= 8; /* 2 x 8 bytes / loop */ - - while(length) { - r1 = r1 | ((data64[--length] + YUY2SHIFTUP64) ^ YUY2BLACK64); - r2 = r2 | ((data64[--length] + YUY2SHIFTUP64) ^ YUY2BLACK64); - } - return !((r1|r2) & YUY2NOISEFILTER64); -} -#endif - -#if defined(__MMX__) -static int blank_line_YUY2_mmx(uint8_t *data, int length) -{ - /* not implemented */ - -# if !defined(ENABLE_64BIT) - return blank_line_YUY2_C(data, length); -# else - return blank_line_YUY2_C64(data, length); -# endif -} -#endif - -#if defined(__SSE__) -static int blank_line_YUY2_sse(uint8_t *data, int length) -{ - uint8_t *top = data + length - 1; - do { - _mm_prefetch(top, _MM_HINT_NTA); - _mm_prefetch(top-32, _MM_HINT_NTA); - _mm_prefetch(top-64, _MM_HINT_NTA); - _mm_prefetch(top-72, _MM_HINT_NTA); - top -= 128; - } while(top >= data); - - return blank_line_YUY2_mmx(data, length); -} -#endif - -static void autocrop_init_mm_accel(void) -{ - blank_line_Y = blank_line_Y_C; - blank_line_UV = blank_line_UV_C; - blank_line_YUY2 = blank_line_YUY2_C; - -#if defined(__SSE__) - if(xine_mm_accel() & MM_ACCEL_X86_SSE) { - INFO("autocrop_init_mm_accel: using SSE\n"); - blank_line_Y = blank_line_Y_sse; - blank_line_UV = blank_line_UV_sse; - blank_line_YUY2 = blank_line_YUY2_sse; - return; - } -#endif -#if defined(ENABLE_64BIT) - if(ENABLE_64BIT) { - INFO("autocrop_init_mm_accel: using 64-bit integer operations\n"); - blank_line_Y = blank_line_Y_C64; - blank_line_UV = blank_line_UV_C64; - blank_line_YUY2 = blank_line_YUY2_C64; - return; - } -#endif -#if defined(__MMX__) - if(xine_mm_accel() & MM_ACCEL_X86_MMX) { - /* mmx not faster than normal x64 (?) */ - INFO("autocrop_init_mm_accel: using MMX\n"); - blank_line_Y = blank_line_Y_mmx; - blank_line_UV = blank_line_UV_mmx; - blank_line_YUY2 = blank_line_YUY2_mmx; - return; - } -#endif - INFO("autocrop_init_mm_accel: no compatible acceleration methods found\n"); -} - -static int blank_line_Y_INIT(uint8_t *data, int length) -{ - autocrop_init_mm_accel(); - return (*blank_line_Y)(data, length); -} - -static int blank_line_UV_INIT(uint8_t *data, int length) -{ - autocrop_init_mm_accel(); - return (*blank_line_UV)(data, length); -} - -static int blank_line_YUY2_INIT(uint8_t *data, int length) -{ - autocrop_init_mm_accel(); - return (*blank_line_YUY2)(data, length); -} - -/* - * Analyze frame - * - if frame needs cropping set crop_top & crop_bottom - */ - -#ifdef MARK_FRAME -int dbg_top=0, dbg_bottom=0; -#endif - -static int analyze_frame_yv12(vo_frame_t *frame, int *crop_top, int *crop_bottom) -{ - int y; - int ypitch = frame->pitches[0]; - int upitch = frame->pitches[1]; - int vpitch = frame->pitches[2]; - uint8_t *ydata = frame->base[0]; - uint8_t *udata = frame->base[1]; - uint8_t *vdata = frame->base[2]; - int max_crop = (frame->height / 4) / 2; /* 4:3 --> 16:9 */ - - /* from top -> down */ - ydata += 8 * ypitch; /* skip 8 first lines */ - udata += 4 * upitch; - vdata += 4 * vpitch; - for(y = 8; y <= max_crop *2 /* *2 = 20:9+subs -> 16:9 */ ; y += 2) { - if( ! ( blank_line_UV(udata, (frame->width-LOGOSKIP)/2) || - blank_line_UV(udata+LOGOSKIP/2, (frame->width-LOGOSKIP)/2) ) || - ! ( blank_line_UV(vdata, (frame->width-LOGOSKIP)/2) || - blank_line_UV(vdata+LOGOSKIP/2, (frame->width-LOGOSKIP)/2) ) || - ! ( blank_line_Y( ydata, (frame->width-LOGOSKIP) ) || - blank_line_Y( ydata+LOGOSKIP, (frame->width-LOGOSKIP) ) ) || - ! ( blank_line_Y( ydata+ypitch, (frame->width-LOGOSKIP) ) || - blank_line_Y( ydata+ypitch+LOGOSKIP,(frame->width-LOGOSKIP) ) )) { - break; - } else { - ydata += 2 * ypitch; - udata += upitch; - vdata += vpitch; - } - } - *crop_top = y>8 ? y : 0; - - /* from bottom -> up */ - ydata = frame->base[0] + ((frame->height-4) -1 ) * ypitch; - udata = frame->base[1] + ((frame->height-4)/2 -1 ) * upitch; - vdata = frame->base[2] + ((frame->height-4)/2 -1 ) * vpitch; - for(y = frame->height - 5; y >= frame->height-max_crop; y -=2 ) { - if( ! blank_line_Y(ydata, frame->width) || - ! blank_line_Y(ydata-ypitch, frame->width) || - ! blank_line_UV(udata, frame->width/2) || - ! blank_line_UV(vdata, frame->width/2)) { - break; - } else { - ydata -= 2*ypitch; - udata -= upitch; - vdata -= vpitch; - } - } - *crop_bottom = y; - - /* test for black in center - don't crop if frame is empty */ - if(*crop_top >= max_crop*2 && *crop_bottom <= frame->height-max_crop) { - ydata = frame->base[0] + (frame->height/2)*ypitch; - udata = frame->base[1] + (frame->height/4)*upitch; - vdata = frame->base[2] + (frame->height/4)*vpitch; - if( blank_line_Y(ydata, frame->width) && - blank_line_Y(ydata-ypitch, frame->width) && - blank_line_UV(udata, frame->width/2) && - blank_line_UV(vdata, frame->width/2)) { - TRACE("not cropping black frame\n"); -#if 0 - *crop_top = 0; - *crop_bottom = frame->height - 1; -#else - return 0; -#endif - } - } - return 1; -} - -static int analyze_frame_yuy2(vo_frame_t *frame, int *crop_top, int *crop_bottom) -{ - int y; - int pitch = frame->pitches[0]; - uint8_t *data = frame->base[0]; - int max_crop = (frame->height / 4) / 2; /* 4:3 --> 16:9 */ - - /* from top -> down */ - data += 6 * pitch; /* skip 6 first lines */ - for(y = 6; y <= max_crop *2 /* *2 = 20:9+subs -> 16:9 */ ; y ++) - if( ! ( blank_line_YUY2(data, (frame->width-LOGOSKIP)*2) || - blank_line_YUY2(data+2*LOGOSKIP, (frame->width-LOGOSKIP)*2))) - break; - else - data += pitch; - - *crop_top = y; - - /* from bottom -> up */ - data = frame->base[0] + ((frame->height-4) -1 ) * pitch; - for(y = frame->height - 5; y >= frame->height-max_crop; y -- ) - if( ! blank_line_YUY2(data, frame->width * 2)) - break; - else - data -= pitch; - - *crop_bottom = y; - - /* test for black in center - don't crop if frame is empty */ - if(*crop_top >= max_crop*2 && *crop_bottom <= frame->height-max_crop) { - data = frame->base[0] + (frame->height/2)*pitch; - if( blank_line_YUY2(data, frame->width * 2)) { - TRACE("not cropping black frame\n"); -#if 0 - *crop_top = 0; - *crop_bottom = frame->height - 1; -#else - return 0; -#endif - } - } - - return 1; -} - -static void analyze_frame(vo_frame_t *frame, int *crop_top, int *crop_bottom) -{ - post_video_port_t *port = (post_video_port_t *)frame->port; - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - int result; - - if(frame->format == XINE_IMGFMT_YV12) - result = analyze_frame_yv12(frame, crop_top, crop_bottom); - else /*if(frame->format == XINE_IMGFMT_YUY2)*/ - result = analyze_frame_yuy2(frame, crop_top, crop_bottom); - -#if defined(__MMX__) - _mm_empty(); -#endif - - if(!result) - return; - -#ifdef MARK_FRAME - dbg_top = *crop_top; dbg_bottom = *crop_bottom; -#endif - - if(this->stabilize) { - int bottom = frame->height - *crop_bottom; - int wide = 0; - - /* bottom bar size */ - if(bottom < frame->height/32) { - TRACE("bottom: %d -> 4:3 ", *crop_bottom); - *crop_bottom = frame->height - 1; /* no cropping */ - } else if(bottom < frame->height*3/32) { - TRACE("bottom: %d -> 14:9 (%d) ", *crop_bottom, frame->height * 15 / 16 - 1); - *crop_bottom = frame->height * 15 / 16 - 1; /* 14:9 */ - } else if(bottom < frame->height*3/16) { - TRACE("bottom: %d -> 16:9 (%d) ", *crop_bottom, frame->height * 7 / 8 - 1); - *crop_bottom = frame->height * 7 / 8 - 1; /* 16:9 */ - wide = 1; - } else { - TRACE("bottom: %d -> 20:9 (%d) ", *crop_bottom, frame->height * 3 / 4 - 1); - *crop_bottom = frame->height * 3 / 4 - 1; /* 20:9 */ - wide = 2; - } - - /* top bar size */ - if(*crop_top < frame->height/32) { - TRACE("top: %3d -> 4:3 \n", *crop_top); - *crop_top = 0; /* no cropping */ - } else if(*crop_top < frame->height*3/32) { - TRACE("top: %3d -> 14:9 (%d)\n", *crop_top, frame->height / 16); - *crop_top = frame->height / 16; /* 14:9 */ - } else if(*crop_top < frame->height*3/16 || wide) { - TRACE("top: %3d -> 16:9 (%d)\n", *crop_top, frame->height / 8); - *crop_top = frame->height / 8; /* 16:9 */ - } else { - TRACE("top: %3d -> 20:9 (%d)\n", *crop_top, frame->height / 4); - *crop_top = frame->height / 4; /* 20:9 */ - wide++; - } - switch(wide) { - case 3: *crop_top -= frame->height / 8; - if(*crop_top < 0) - *crop_top = 0; - TRACE(" wide -> center top\n"); - case 2: *crop_bottom += frame->height / 8; - if(*crop_bottom >= frame->height) - *crop_bottom = frame->height-1; - TRACE(" wide -> center bottom\n"); - } - - } else { - - if(*crop_top > (frame->height/8 *2)) /* *2 --> 20:9 -> 16:9 + subtitles */ - *crop_top = frame->height/8 *2 ; - if(*crop_bottom < (frame->height*7/8)) - *crop_bottom = frame->height*7/8; - - if(*crop_top > (frame->height/8)) { - /* if wider than 16:9, prefer cropping top if subtitles are inside bottom bar */ - if(*crop_top + (frame->height - *crop_bottom) > frame->height/4) { - int diff = *crop_top + (frame->height - *crop_bottom) - frame->height/4; - diff &= ~1; - TRACE("balance: %d,%d -> %d,%d\n", - *crop_top, *crop_bottom, - *crop_top, *crop_bottom + diff); -#if 0 - /* this moves image to top (crop only top) */ - *crop_bottom += diff; -#endif -#if 0 - /* this moves image to center */ - /* may cause problems with subtitles ... */ - *crop_top -= diff; -#endif -#if 1 - /* this moves image to center when there are no - detected subtitles inside bottom bar */ - if(this->height_limit_active) { - int reserved = this->height_limit - *crop_bottom; - if(reserved>0) { - *crop_bottom += reserved; - diff -= reserved; - } - } - *crop_top -= diff; -#endif -#if 0 - /* do nothing - image will be centered in video out. - - problems with subtitles using unscaled OSD */ -#endif - } - } - - /* stay inside frame and forget very small bars */ - if(*crop_top <= 8) - *crop_top = 0; - if(*crop_bottom >= (frame->height-6)) - *crop_bottom = frame->height; - - if(*crop_top < frame->height/12 || *crop_bottom > frame->height*11/12) { - /* Small bars -> crop only detected borders */ - if(*crop_top || *crop_bottom < frame->height-1) { - TRACE("Small bars -> <16:9 : start_line = %d end_line = %d (%s%d t%d)\n", - *crop_top, *crop_bottom, - this->height_limit_active ? "height limit " : "", - this->height_limit, - this->height_limit_active ? this->height_limit_timer : 0); - } - } else { - /* Large bars -> crop to 16:9 */ - TRACE("Large bars -> 16:9 : start_line = %d end_line = %d (%s%d t%d)\n", - *crop_top, *crop_bottom, - this->height_limit_active ? "height limit " : "", - this->height_limit, - this->height_limit_active ? this->height_limit_timer : 0); - if(*crop_top < frame->height / 8) - *crop_top = frame->height / 8; - if(*crop_bottom < frame->height * 7 / 8) - *crop_bottom = frame->height * 7 / 8; - } - } - - /* adjust start and stop to even lines */ - (*crop_top) = (*crop_top) & (~1); - (*crop_bottom) = (*crop_bottom + 1) & (~1); -} - -#ifdef MARK_FRAME -static void mark_frame_yv12(autocrop_post_plugin_t *this, - vo_frame_t *frame, int *crop_top, int *crop_bottom) -{ - int ypitch = frame->pitches[0]; - int upitch = frame->pitches[1]; - int vpitch = frame->pitches[2]; - uint8_t *ydata = frame->base[0]; - uint8_t *udata = frame->base[1]; - uint8_t *vdata = frame->base[2]; - - /* draw markers to detected boundaries and expected boundaries */ - if(*crop_top > 4 && *crop_top < 200) { - ydata = frame->base[0] + ((*crop_top)-2)*ypitch; - udata = frame->base[1] + ((*crop_top)/2 -1)*upitch; - memset(ydata, 0xff, frame->width/10); - memset(ydata+ypitch, 0xff, frame->width/10); - memset(udata, 0xff, frame->width/2/10); - - if(dbg_top < *crop_top) dbg_top = *crop_top; - ydata = frame->base[0] + ((dbg_top - *crop_top))*ypitch; - udata = frame->base[1] + ((dbg_top - *crop_top)/2)*upitch; - memset(ydata, 0x80, frame->width/2); - memset(ydata+ypitch, 0x80, frame->width/2); - memset(udata, 0xff, frame->width/2/2); - } - if(*crop_bottom > 300) { - if(*crop_bottom < frame->height - 2) { - ydata = frame->base[0] + (*crop_bottom + 2)*ypitch; - udata = frame->base[1] + ((*crop_bottom)/2)*upitch; - memset(ydata, 0xff, frame->width); - memset(ydata+ypitch, 0xff, frame->width); - memset(udata, 0xff, frame->width/2); - } - if(dbg_bottom - *crop_top - 2 < frame->height) { - ydata = frame->base[0] + (dbg_bottom - *crop_top - 2)*ypitch; - udata = frame->base[1] + (dbg_bottom - *crop_top - 2)/2*upitch; - memset(ydata, 0x80, frame->width/2); - memset(ydata+ypitch, 0xff, frame->width/2); - memset(udata, 0xff, frame->width/2/2); - } - } - if(frame->height > 500) { - /* TODO: use frame height instead of assuming 576 ... -> 72 */ - vdata = frame->base[2] + ((72-*crop_top)/2)*vpitch; -vdata = frame->base[2] + (72/2)*vpitch; - memset(vdata, 0xff, frame->width/2); - vdata = frame->base[2] + ((frame->height-72+(576-*crop_bottom))/2)*vpitch; -vdata = frame->base[2] + ((frame->height-72)/2)*vpitch; - memset(vdata, 0xff, frame->width/2); - } -} -#endif - -/* - * crop frame by copying - */ -#ifndef USE_CROP -static int crop_copy_yv12(vo_frame_t *frame, xine_stream_t *stream) -{ - post_video_port_t *port = (post_video_port_t *)frame->port; - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - vo_frame_t *new_frame; - - int y, result; - int yp = frame->pitches[0], yp2; - int up = frame->pitches[1], up2; - int vp = frame->pitches[2], vp2; - uint8_t *ydata = frame->base[0], *ydata2; - uint8_t *udata = frame->base[1], *udata2; - uint8_t *vdata = frame->base[2], *vdata2; - - int new_height; - float new_ratio; - - /* top bar */ - ydata += this->start_line * yp; - udata += (this->start_line/2) * up; - vdata += (this->start_line/2) * vp; - - new_height = this->end_line - this->start_line; - new_ratio = 12.0/9.0 * ((float)frame->height / (float)new_height); - - new_frame = port->original_port->get_frame(port->original_port, - frame->width, new_height, - new_ratio, frame->format, - frame->flags | VO_BOTH_FIELDS); - - /* ??? */ - frame->ratio = new_frame->ratio; - - _x_post_frame_copy_down(frame, new_frame); - - yp2 = new_frame->pitches[0]; - up2 = new_frame->pitches[1]; - vp2 = new_frame->pitches[2]; - ydata2 = new_frame->base[0]; - udata2 = new_frame->base[1]; - vdata2 = new_frame->base[2]; - - /* - TODO: - save channel logo mask (from top) - - no changes in 3 sec -> next time crop it out ... - */ - - for(y=0; y < new_height/2; y++) { - xine_fast_memcpy(ydata2, ydata, frame->width); - ydata += yp; - ydata2 += yp2; - xine_fast_memcpy(ydata2, ydata, frame->width); - ydata += yp; - ydata2 += yp2; - xine_fast_memcpy(udata2, udata, frame->width/2); - udata += up; - udata2 += up2; - xine_fast_memcpy(vdata2, vdata, frame->width/2); - vdata += vp; - vdata2 += vp2; - } - -#ifdef MARK_FRAME - mark_frame_yv12(this, new_frame, &this->start_line, &this->end_line); -#endif - - result = new_frame->draw(new_frame, stream); - _x_post_frame_copy_up(frame, new_frame); - new_frame->free(new_frame); - - return result; -} - -static int crop_copy_yuy2(vo_frame_t *frame, xine_stream_t *stream) -{ - post_video_port_t *port = (post_video_port_t *)frame->port; - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - vo_frame_t *new_frame; - - int y, result; - int p = frame->pitches[0], p2; - uint8_t *data = frame->base[0], *data2; - - int new_height; - float new_ratio; - - /* top bar */ - data += this->start_line * p; - - new_height = this->end_line - this->start_line; - new_ratio = 12.0/9.0 * ((float)frame->height / (float)new_height); - new_frame = port->original_port->get_frame(port->original_port, - frame->width, new_height, - new_ratio, frame->format, - frame->flags | VO_BOTH_FIELDS); - /* ??? */ - frame->ratio = new_frame->ratio; - - _x_post_frame_copy_down(frame, new_frame); - - p2 = new_frame->pitches[0]; - data2 = new_frame->base[0]; - - for(y=0; y < new_height; y++) { - xine_fast_memcpy(data2, data, frame->width); - data += p; - data2 += p2; - } - - result = new_frame->draw(new_frame, stream); - _x_post_frame_copy_up(frame, new_frame); - new_frame->free(new_frame); - - return result; -} - -#endif - -/* - * crop frame without copying - */ -#ifdef USE_CROP -static int crop_nocopy(vo_frame_t *frame, xine_stream_t *stream) -{ - post_video_port_t *port = (post_video_port_t *)frame->port; - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - int skip; - double new_ratio = frame->ratio; - int new_height; - - if(this->cropping_active) { - frame->crop_top += this->start_line; - frame->crop_bottom += (frame->height + 1 - this->end_line); - - TRACE("crop_nocopy: top ->%d bottom ->%d\n", frame->crop_top, frame->crop_bottom); - - new_height = this->end_line - this->start_line; - new_ratio = 12.0/9.0 * ((float)frame->height / (float)new_height); - } - - _x_post_frame_copy_down(frame, frame->next); - - /* ??? */ - frame->ratio = new_ratio; - - skip = frame->next->draw(frame->next, stream); - TRACE("crop: top %d, bottom %d\n", frame->crop_top, frame->crop_bottom); - _x_post_frame_copy_up(frame, frame->next); - - return skip; -} -#endif - -/* - * Frame handling - */ - -static int autocrop_draw(vo_frame_t *frame, xine_stream_t *stream) -{ - post_video_port_t *port = (post_video_port_t *)frame->port; - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - int result; - int detected_start, detected_end; - - if(!this->autodetect) { - this->start_line = frame->height/8; - this->end_line = frame->height*7/8; - this->crop_total = frame->height/4; -#ifdef USE_CROP - return crop_nocopy(frame, stream); -#else - if(frame->format == XINE_IMGFMT_YV12) - return crop_copy_yv12(frame, stream); - else /*if(frame->format == XINE_IMGFMT_YUY2)*/ - return crop_copy_yuy2(frame, stream); -#endif - } - - /* use pts jumps to track stream changes (and seeks) */ - if(frame->pts > 0) { - if(this->prev_pts>0) { - int64_t dpts = frame->pts - this->prev_pts; - if(dpts < INT64_C(-30*90000) || dpts > INT64_C(30*90000)) { /* 30 sec */ - if(this->height_limit_active) { - this->height_limit_timer = START_TIMER_INIT; - TRACE("short pts jump resetted height limit"); - } - } - if(dpts < INT64_C(-30*60*90000) || dpts > INT64_C(30*60*90000)) { /* 30 min */ - this->cropping_active = 0; - TRACE("long pts jump resetted cropping"); - } - } - this->prev_pts = frame->pts; - } - - /* reset ? */ - if(! this->cropping_active) { - this->prev_start_line = 0; - this->prev_end_line = frame->height; - this->start_timer = START_TIMER_INIT; - this->prev_pts = -1; - if(this->height_limit_active) { - TRACE("height limit reset (no cropping)"); - } - this->height_limit_active = 0; - this->height_limit = frame->height; - } - - /* only 4:3 YV12 frames are cropped */ - if(frame->ratio != 4.0/3.0 || (frame->format != XINE_IMGFMT_YV12 && - frame->format != XINE_IMGFMT_YUY2)) { - this->cropping_active = 0; - - } else if(frame->bad_frame) { - - /* check for letterbox borders only from I-frames */ - } else if(frame->picture_coding_type == 1/*XINE_PICT_I_TYPE*/) { - - analyze_frame(frame, &this->start_line, &this->end_line); - - /* ignore very small bars */ - if(this->start_line > 10 || this->end_line < frame->height - 10) - this->cropping_active = 1; - else - this->cropping_active = 0; - - this->prev_height = frame->height; - this->prev_width = frame->width; - - /* no change unless same values for several frames */ - if(this->stabilize && - (this->start_line != this->prev_start_line || - this->end_line != this->prev_end_line)) { - if(this->stabilize_timer) - this->stabilize_timer--; - else - this->stabilize_timer = 4; - if(this->stabilize_timer) { - TRACE("stabilize start_line: %d -> %d, end_line %d -> %d\n", - this->start_line, this->prev_start_line, - this->end_line, this->prev_end_line); - this->start_line = this->prev_start_line; - this->end_line = this->prev_end_line; - } - } - - } else { - /* reset when format changes */ - if(frame->height != this->prev_height) - this->cropping_active = 0; - if(frame->width != this->prev_width) - this->cropping_active = 0; - } - - /* update timers */ - if(this->start_timer) - this->start_timer--; - - if(this->height_limit_timer) { - if (! --this->height_limit_timer) { - this->height_limit_active = 0; - this->height_limit = frame->height; - TRACE("height limit timer expired"); - } - } - - /* no cropping to be done ? */ - if (/*frame->bad_frame ||*/ !this->cropping_active || this->start_timer>0) { - _x_post_frame_copy_down(frame, frame->next); - result = frame->next->draw(frame->next, stream); - _x_post_frame_copy_up(frame, frame->next); - return result; - } - - /* "soft start" and border stabilization */ - detected_start = this->start_line; - detected_end = this->end_line; - if(this->soft_start) { - if(this->prev_start_line != this->start_line) { - int diff = this->prev_start_line - this->start_line; - if(diff < -4) diff = -4; - else if(diff > 4) diff = 4; - else diff = 0; - this->start_line = this->prev_start_line - diff; - } - if(this->prev_end_line != this->end_line) { - int diff = this->prev_end_line - this->end_line; - if(diff < -4) diff = -4; - else if(diff > 4) diff = 4; - else diff = 0; - this->end_line = this->prev_end_line - diff; - } - } - - /* handle fixed subtitles inside bottom bar */ - if(this->subs_detect) { - if(abs(this->prev_start_line - this->start_line) > 5 ) { - /* reset height limit if top bar changes */ - TRACE("height limit reset, top bar moved from %d -> %d\n", - this->prev_start_line, this->start_line); - this->height_limit_active = 0; - this->height_limit = frame->height; - this->height_limit_timer = 0; - } - if (this->end_line > this->prev_end_line) { - if(!this->height_limit_active || - this->height_limit < this->end_line) { - /* start or increase height limit */ - TRACE("height limit %d -> %d (%d secs)\n", - this->height_limit, this->end_line, - HEIGHT_LIMIT_LIFETIME/25); - this->height_limit = this->end_line; - this->height_limit_timer = HEIGHT_LIMIT_LIFETIME; - this->height_limit_active = 1; - } - if(this->height_limit_active && - this->height_limit_timer < HEIGHT_LIMIT_LIFETIME/4) { - /* keep heigh limit timer running */ - TRACE("height_limit_timer increment (still needed)\n"); - this->height_limit_timer = HEIGHT_LIMIT_LIFETIME/2; - } - } - } - - this->prev_start_line = this->start_line; - this->prev_end_line = this->end_line; - - if(this->subs_detect) { - if(this->height_limit_active) { - /* apply height limit */ - if(this->end_line < this->height_limit) - this->end_line = this->height_limit; - } else { - this->height_limit = frame->height; - } - } - - /* - * do cropping - * - using frame->crop_... does not seem to work with my xv and xine-lib-1.1.1. - * - maybe cropping could be done by adjusting y/u/v data pointers - * and height of frame ? - * -> no time-consuming copying - */ -#ifdef USE_CROP - result = crop_nocopy(frame, stream); -#else - if(frame->format == XINE_IMGFMT_YV12) - result = crop_copy_yv12(frame, stream); - else /*if(frame->format == XINE_IMGFMT_YUY2)*/ - result = crop_copy_yuy2(frame, stream); -#endif - this->crop_total = this->start_line + frame->height - this->end_line; - - /* forget stabilized values */ - this->start_line = detected_start; - this->end_line = detected_end; - - return result; -} - -#ifdef USE_CROP -static vo_frame_t *autocrop_get_frame(xine_video_port_t *port_gen, - uint32_t width, uint32_t height, - double ratio, int format, int flags) -{ - post_video_port_t *port = (post_video_port_t *)port_gen; - post_plugin_t *this_gen = port->post; - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)this_gen; - vo_frame_t *frame; - - _x_post_rewire(this_gen); - - if (ratio <= 0.0) - if(height > 1) - ratio = (double)width / (double)height; - - if (this->cropping_active && - ratio == 4.0/3.0 && (format == XINE_IMGFMT_YV12 || - format == XINE_IMGFMT_YUY2)) { - int new_height = this->end_line+2 - this->start_line; - float new_ratio = 12.0/9.0 * ((float)height / (float)new_height); - - frame = port->original_port->get_frame(port->original_port, - width, height, - new_ratio, format, flags); - _x_post_inc_usage(port); - frame = _x_post_intercept_video_frame(frame, port); - - frame->ratio = ratio; - return frame; - } - - return port->original_port->get_frame(port->original_port, - width, height, - ratio, format, flags); -} -#endif - -static int autocrop_intercept_frame(post_video_port_t *port, vo_frame_t *frame) -{ - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - - /* Crop only SDTV YV12 4:3 frames ... */ - int intercept = ((frame->format == XINE_IMGFMT_YV12 || - frame->format == XINE_IMGFMT_YUY2) && - frame->ratio == 4.0/3.0 && - frame->width >= 480 && frame->width <= 768 && - frame->height >= 288 && frame->height <= 576); - if(!intercept) { - this->height_limit_active = 0; - this->crop_total = 0; - this->cropping_active = 0; - } - - return intercept; -} - -static int autocrop_intercept_ovl(post_video_port_t *port) -{ - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - - if (!this->cropping_active) - return 0; - - return 1; -} - -static int32_t autocrop_overlay_add_event(video_overlay_manager_t *this_gen, void *event_gen) -{ - post_video_port_t *port = _x_post_ovl_manager_to_port(this_gen); - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)port->post; - video_overlay_event_t *event = (video_overlay_event_t *)event_gen; - int caps; - - if(this->cropping_active && this->crop_total>10) { - if (event->event_type == OVERLAY_EVENT_SHOW) { - switch (event->object.object_type) { - case 0: - /* regular subtitle */ - /* Subtitle overlays must be coming somewhere inside xine engine */ - - caps = port->stream->video_out->get_capabilities (port->stream->video_out); -#ifdef USE_CROP - if(caps & VO_CAP_CROP) { - if(! event->object.overlay->unscaled || !(caps & VO_CAP_UNSCALED_OVERLAY)) { - event->object.overlay->y -= this->crop_total; - } - } else { - /* object is moved crop_top amount in video_out */ - if(event->object.overlay->unscaled && (caps & VO_CAP_UNSCALED_OVERLAY)) { - /* cancel incorrect move that will be done in video_out */ - event->object.overlay->y += this->start_line; - } else { - /* move crop_bottom pixels up */ - event->object.overlay->y -= (this->crop_total - this->start_line); - } - } - - /* when using cropping overlays are moved in video_out */ - INFO("autocrop_overlay_add_event: subtitle event untouched\n"); -#else - /* when cropping here subtitles coming from inside of xine must be re-positioned */ - if(! event->object.overlay->unscaled || !(caps & VO_CAP_UNSCALED_OVERLAY)) { - event->object.overlay->y -= this->crop_total; - INFO("autocrop_overlay_add_event: subtitle event moved up\n"); - } -#endif - break; - case 1: - /* menu overlay */ - /* All overlays coming from VDR have this type */ - { -#ifdef DVDTEST - int dvd_menu = 0; - if (stream->input_plugin) { - if (stream->input_plugin->get_capabilities (stream->input_plugin) & - INPUT_CAP_SPULANG) { - *((int *)lang) = 0; /* channel */ - if (stream->input_plugin->get_optional_data (stream->input_plugin, lang, - INPUT_OPTIONAL_DATA_SPULANG) - == INPUT_OPTIONAL_SUCCESS) - if(!strcmp(lang, "menu")) - dvd_menu = 1; /* -> cropping off */ - /* should turn on when not in menu ... -> where ? */ - } - } -#endif -#ifdef USE_CROP - if(!event->object.overlay->unscaled) { - event->object.overlay->y += this->start_line;//crop_total; - } else { - caps = port->stream->video_out->get_capabilities (port->stream->video_out); - if(!(caps & VO_CAP_UNSCALED_OVERLAY)) - event->object.overlay->y += this->start_line;//crop_total; - } -#endif - } - break; - } - } - } - - return port->original_manager->add_event(port->original_manager, event_gen); -} - - -/* - * Parameter functions - */ - -static xine_post_api_descr_t *autocrop_get_param_descr(void) -{ - return &autocrop_param_descr; -} - -static int autocrop_set_parameters(xine_post_t *this_gen, void *param_gen) -{ - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)this_gen; - autocrop_parameters_t *param = (autocrop_parameters_t *)param_gen; - - this->autodetect = param->enable_autodetect; - this->subs_detect = param->enable_subs_detect; - this->soft_start = param->soft_start; - this->stabilize = param->stabilize; - TRACE("autocrop_set_parameters: " - "auto=%d subs=%d soft=%d stabilize=%d\n", - this->autodetect, this->subs_detect, - this->soft_start, this->stabilize); - return 1; -} - -static int autocrop_get_parameters(xine_post_t *this_gen, void *param_gen) -{ - autocrop_post_plugin_t *this = (autocrop_post_plugin_t *)this_gen; - autocrop_parameters_t *param = (autocrop_parameters_t *)param_gen; - - TRACE("autocrop_get_parameters: " - "auto=%d subs=%d soft=%d stabilize=%d\n", - this->autodetect, this->subs_detect, - this->soft_start, this->stabilize); - param->enable_autodetect = this->autodetect; - param->enable_subs_detect = this->subs_detect; - param->soft_start = this->soft_start; - param->stabilize = this->stabilize; - return 1; -} - -static char *autocrop_get_help(void) { - return _("The autocrop plugin is meant to take 4:3 letterboxed frames and " - "convert them to 16:9 by removing black bars on the top and bottom " - "of the frame.\n" - "\n" - "Parameters\n" - " enable_autodetect: Enable automatic letterbox detection\n" - " enable_subs_detect: Enable automatic subtitle detection inside bottom bar\n" - " soft_start: Enable soft start of cropping\n" - " stabilize: Stabilize cropping to\n" - " 14:9, 16:9, (16:9+subs), 20:9, (20:9+subs)\n" - "\n" - ); -} - - -/* - * Open/close - */ - -static void autocrop_dispose(post_plugin_t *this_gen) -{ - if (_x_post_dispose(this_gen)) - free(this_gen); -} - -static post_plugin_t *autocrop_open_plugin(post_class_t *class_gen, - int inputs, - xine_audio_port_t **audio_target, - xine_video_port_t **video_target) -{ - if (video_target && video_target[ 0 ]) { - autocrop_post_plugin_t *this = calloc(1, sizeof(autocrop_post_plugin_t)); - post_in_t *input; - post_out_t *output; - post_video_port_t *port; - xine_post_in_t *input_param; - - static xine_post_api_t post_api = - { autocrop_set_parameters, autocrop_get_parameters, - autocrop_get_param_descr, autocrop_get_help }; - - if (this) { - _x_post_init(&this->post_plugin, 0, 1); - - port = _x_post_intercept_video_port(&this->post_plugin, - video_target[ 0 ], - &input, &output); - - input->xine_in.name = "video in"; - output->xine_out.name = "video out"; - - port->intercept_ovl = autocrop_intercept_ovl; - port->new_manager->add_event = autocrop_overlay_add_event; - port->intercept_frame = autocrop_intercept_frame; -#ifdef USE_CROP - port->new_port.get_frame = autocrop_get_frame; -#endif - port->new_frame->draw = autocrop_draw; - - this->post_plugin.xine_post.video_input[ 0 ] = &port->new_port; - this->post_plugin.dispose = autocrop_dispose; - - input_param = &this->parameter_input; - input_param->name = "parameters"; - input_param->type = XINE_POST_DATA_PARAMETERS; - input_param->data = &post_api; -#if XINE_VERSION_CODE >= 10102 - xine_list_push_back(this->post_plugin.input, input_param); -#else - xine_list_append_content(this->post_plugin.input, input_param); -#endif - this->cropping_active = 0; - this->autodetect = 1; - this->subs_detect = 1; - this->soft_start = 1; - this->stabilize = 1; - this->start_line = 0; - this->end_line = 576; - - this->prev_start_line = 0; - this->prev_end_line = 576; - - return &this->post_plugin; - } - } - - return NULL; -} - - -/* - * Plugin class - */ - -#if POST_PLUGIN_IFACE_VERSION < 10 -static char *autocrop_get_identifier(post_class_t *class_gen) -{ - return "autocrop"; -} - -static char *autocrop_get_description(post_class_t *class_gen) -{ - return "Crop letterboxed 4:3 video to 16:9"; -} - -static void autocrop_class_dispose(post_class_t *class_gen) -{ - free(class_gen); -} -#endif - -static void *autocrop_init_plugin(xine_t *xine, void *data) -{ - post_class_t *class = calloc(1, sizeof(post_class_t)); - - if(class) { - class->open_plugin = autocrop_open_plugin; -#if POST_PLUGIN_IFACE_VERSION < 10 - class->get_identifier = autocrop_get_identifier; - class->get_description = autocrop_get_description; - class->dispose = autocrop_class_dispose; -#else - class->identifier = "autocrop"; - class->description = N_("Crop letterboxed 4:3 video to 16:9"); - class->dispose = default_post_class_dispose; -#endif - } - - return class; -} - - -static post_info_t info = { XINE_POST_TYPE_VIDEO_FILTER }; - -const plugin_info_t xine_plugin_info[] __attribute__((visibility("default"))) = -{ - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_POST, POST_PLUGIN_IFACE_VERSION, "autocrop", XINE_VERSION_CODE, &info, &autocrop_init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/xine_post_swscale.c b/xine_post_swscale.c deleted file mode 100644 index 9e5be7c2..00000000 --- a/xine_post_swscale.c +++ /dev/null @@ -1,1730 +0,0 @@ -/* - * Copyright (C) 2000-2007 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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 - * - * $Id: xine_post_swscale.c,v 1.9 2008-12-13 14:24:03 phintuka Exp $ - * - * Simple (faster) resize for avisynth - * Copyright (C) 2002 Tom Barry - * - * Very simple 2 tap linear interpolation. - * It is unfiltered which means it will not soften much. - * - * WarpedResize will do a non-linear stretch/squeeze in both the horizontal - * and vertical dimensions. This can be useful when you want to change the - * aspect ratio of a video clip and have it mostly distorted at the - * top, bottom, and side edges. - * - * - * Ported to linux/xine by Petri Hintukainen <phintuka@users.sourceforge.net> - * - Added x86_64 support - * - Added PIC support (do not clobber ebx in x86, access only local variables from asm) - * - Fixed yv12 stretched warp tables generation - */ - -#include <xine/xine_internal.h> -#include <xine/post.h> - -/*#define DBG(x...)*/ -#define DBG(x...) fprintf(stderr, "post_warp: " x) - -/*#define STREAMING_STORE_TMP*/ -/*#define STREAMING_STORE*/ -/*#define PREFETCH*/ -/* streaming store and prefetch seems to be slower ... - * Tested with P3 (128M L2) and C2D (4M L2). - * Maybe access pattern is enough simple for HW prefetchers. - */ - -/*#define VANILLA*/ - -/* - * This function accepts a position from 0 to 1 and warps it, to 0 through 1 based - * upon the wFact var. The warp equations are designed to: - * - * * Always be rising but yield results from 0 to 1 - * - * * Have a first derivative that doesn't go to 0 or infinity, at least close - * to the center of the screen - * - * * Have a curvature (absolute val of 2nd derivative) that is small in the - * center and smoothly rises towards the edges. We would like the curvature - * to be everywhere = 0 when the warp factor = 1 - */ -static double WarpFactor(double position, double wFact) -{ - double x; - double z; - double w; - x = 2 * (position - .5); - if (1) /*(wFact < 1.0)*/ - /* For warp factor < 1 the warp is calculated as (1-w) * x^3 + w *x, centered - * - * The warp is calculated as z = (1 - w) * x^3 + w * x, centered - * around .5 and ranging from 0 to 1. After some tinkering this seems - * to give decent values and derivatives at the right places. - */ - w = 2.0 - wFact; /* reverse parm for compat with initial release */ - - if (x < 0.0) { - z = -(1 - w) * x*x*x - w * x; /* -1 < x < 0, wFact < 1 */ - return .5 - .5 * z; - } else { - z = (1 - w) * x*x*x + w * x; /* -1 < x < 0, wFact < 1 */ - return .5 + .5 * z; /* amts to same formula as above for now */ - } -} - -/* - * YV12 - * - * For each horizontal output pair of pixels there is are 2 qword masks followed by 2 int - * offsets. The 2 masks are the weights to be used for the luma and chroma, respectively. - * Each mask contains LeftWeight1, RightWeight1, LeftWeight2, RightWeight2. So a pair of pixels - * will later be processed each pass through the horizontal resize loop. I think with my - * current math the Horizontal Luma and Chroma contains the same values but since I may have screwed it - * up I'll leave it this way for now. Vertical chroma is different. - * - * Note - try just using the luma calcs for both, seem to be the same. - * - * The weights are scaled 0-256 and the left and right weights will sum to 256 for each pixel. - */ -static void init_tables_yv12(int newwidth, int newheight, int oldwidth, int oldheight, - int Interlaced, double hWarp, double vWarp, - uint32_t *hControl, uint32_t *vOffsets, uint32_t *vWeights, - uint32_t *hControlUV, uint32_t *vOffsetsUV, uint32_t *vWeightsUV) -{ - int i; - int j; - int k; - int wY1; - int wY2; - DBG("init_yv12: %dx%d->%dx%d hWarp %1.3lf vWarp %1.3lf\n", - oldwidth, oldheight, newwidth, newheight, hWarp, vWarp); - - /* First set up horizontal table, use for both luma & chroma since - * it seems to have the same equation. - * We will geneerate these values in pairs, mostly because that's the way - * I wrote it for YUY2 above. - */ - - for(i=0; i < newwidth; i+=2) { - /* first make even pixel control */ - if (hWarp==1) /*if no warp factor */ - j = i * 256 * (oldwidth-1) / (newwidth-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor(i / (newwidth-1.0), hWarp) * (oldwidth-1)); - - k = j>>8; - wY2 = j - (k << 8); /* luma weight of right pixel */ - wY1 = 256 - wY2; /* luma weight of left pixel */ - - if (k > oldwidth - 2) { - hControl[i*3+4] = oldwidth - 1; /* point to last byte */ - hControl[i*3] = 0x00000100; /* use 100% of rightmost Y */ - } else { - hControl[i*3+4] = k; /* pixel offset */ - hControl[i*3] = wY2 << 16 | wY1; /* luma weights */ - } - - /* now make odd pixel control */ - if (hWarp==1) /* if no warp factor */ - j = (i+1) * 256 * (oldwidth-1) / (newwidth-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor((i+1) / (newwidth-1.0), hWarp) * (oldwidth-1)); - - k = j>>8; - wY2 = j - (k << 8); /* luma weight of right pixel */ - wY1 = 256 - wY2; /* luma weight of left pixel */ - - if (k > oldwidth - 2) { - hControl[i*3+5] = oldwidth - 1; /* point to last byte */ - hControl[i*3+1] = 0x00000100; /* use 100% of rightmost Y */ - } else { - hControl[i*3+5] = k; /* pixel offset */ - hControl[i*3+1] = wY2 << 16 | wY1; /* luma weights */ - } - } - - hControl[newwidth*3+4] = 2 * (oldwidth-1); /* give it something to prefetch at end */ - hControl[newwidth*3+5] = 2 * (oldwidth-1); /* " */ -#ifndef VANILLA - // UV - for(i=0; i < newwidth/2; i+=2) { - /* first make even pixel control */ - if (hWarp==1) /*if no warp factor */ - j = i * 256 * (oldwidth/2-1) / (newwidth/2-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor(i / (newwidth/2-1.0), hWarp) * (oldwidth/2-1)); - - k = j>>8; - wY2 = j - (k << 8); /* luma weight of right pixel */ - wY1 = 256 - wY2; /* luma weight of left pixel */ - - if (k > oldwidth/2 - 2) { - hControlUV[i*3+4] = oldwidth/2 - 1; /* point to last byte */ - hControlUV[i*3] = 0x00000100; /* use 100% of rightmost Y */ - } else { - hControlUV[i*3+4] = k; /* pixel offset */ - hControlUV[i*3] = wY2 << 16 | wY1; /* luma weights */ - } - - /* now make odd pixel control */ - if (hWarp==1) /* if no warp factor */ - j = (i+1) * 256 * (oldwidth/2-1) / (newwidth/2-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor((i+1) / (newwidth/2-1.0), hWarp) * (oldwidth/2-1)); - - k = j>>8; - wY2 = j - (k << 8); /* luma weight of right pixel */ - wY1 = 256 - wY2; /* luma weight of left pixel */ - - if (k > oldwidth/2 - 2) { - hControlUV[i*3+5] = oldwidth/2 - 1; /* point to last byte */ - hControlUV[i*3+1] = 0x00000100; /* use 100% of rightmost Y */ - } else { - hControlUV[i*3+5] = k; /* pixel offset */ - hControlUV[i*3+1] = wY2 << 16 | wY1; /* luma weights */ - } - } - - hControlUV[newwidth/2*3+4] = (oldwidth/2-1); /* give it something to prefetch at end */ - hControlUV[newwidth/2*3+5] = (oldwidth/2-1); /* " */ -#endif - - /* Next set up vertical tables. The offsets are measured in lines and will be mult */ - /* by the source pitch later . */ - - /* For YV12 we need separate Luma and chroma tables */ - - /* First Luma Table */ - for(i=0; i< newheight; ++i) { - if (vWarp==1) /* if no warp factor */ - j = i * 256 * (oldheight-1) / (newheight-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor(i / (newheight-1.0), vWarp) * (oldheight-1)); - - if (Interlaced) { /* do hard way? */ - if (i%2) { /* is odd output line? */ - if (j < 256) { /* before 1st odd input line */ - vOffsets[i] = 1; /* all from line 1 */ - vWeights[i] = 0; /* weight to give to 2nd line */ - } else { - k = (((j-256) >> 9) << 1) + 1; /* next lowest odd line */ - vOffsets[i] = k; - wY2 = j - (k << 8); - vWeights[i] = wY2 >> 1; /* weight to give to 2nd line */ - } - } else { /* is even output line */ - k = (j >> 9) << 1; /* next lower even line */ - vOffsets[i] = k; - wY2 = j - (k << 8); - vWeights[i] = wY2 >> 1; /* weight to give to 2nd line */ - } - } else { /* simple way, do as progressive */ - k = j >> 8; - vOffsets[i] = k; - wY2 = j - (k << 8); - vWeights[i] = wY2; /* weight to give to 2nd line */ - } - } - - /* Vertical table for chroma */ - for(i=0; i< newheight/2; ++i) { - if (vWarp==1) /* if no warp factor */ -#ifdef VANILLA - j = (int) ( (i+.25) * 256 * (oldheight-1) / (newheight-1.0) - 64 ); -#else - j = (int) ( (i+.25) * 256 * (oldheight/2-1) / (newheight/2-1.0) - 64 ); -#endif - else /* stretch and warp somehow */ -#ifdef VANILLA - j = (int) (256 * WarpFactor( (i+.25) / (newheight-1.0), vWarp) * (oldheight-1.0) ); -#else - j = (int) (256 * WarpFactor( (i+.25) / (newheight/2 - 1.0), vWarp) * (oldheight/2 - 1.0) ); -#endif -#ifndef VANILLA - if(j<0) j=0; -#endif - if (Interlaced) { /* do hard way? */ - if (i%2) { /* is odd output line? */ - if (j < 256) { /* before 1st odd input line */ - vOffsetsUV[i] = 1; /* all from line 1 */ - vWeightsUV[i] = 0; /* weight to give to 2nd line */ - } else { - k = (((j-256) >> 9) << 1) + 1; /* next lowest odd line */ - vOffsetsUV[i] = k; - wY2 = j - (k << 8); - vWeightsUV[i] = wY2 >> 1; /* weight to give to 2nd line */ - } - } else { /* is even output line */ -#ifdef VANILLA - k = (j >> 9) << 1; /* next lower even line */ - vOffsetsUV[i] = k; - wY2 = j - (k << 8); - vWeightsUV[i] = wY2 >> 1; /* weight to give to 2nd line */ -#else - k = (j / 512) << 1; /* next lower even line */ - vOffsetsUV[i] = k; - wY2 = j - (k << 8); - vWeightsUV[i] = wY2 >> 1; /* weight to give to 2nd line */ -#endif - } - } else { /* simple way, do as progressive */ -#ifdef VANILLA - k = j >> 8; -#else - k = j / 256; /* j >> 8; does not work right if -256 < j < 0 */ -#endif - vOffsetsUV[i] = k; - wY2 = j - (k << 8); - vWeightsUV[i] = wY2; /* weight to give to 2nd line */ - } - } -} - -/* - * YUY2 - * - * For each horizontal output pair of pixels there is are 2 qword masks followed by 2 int - * offsets. The 2 masks are the weights to be used for the luma and chroma, respectively. - * Each mask contains LeftWeight1, RightWeight1, LeftWeight2, RightWeight2. So a pair of pixels - * will later be processed each pass through the horizontal resize loop. - * - * The weights are scaled 0-256 and the left and right weights will sum to 256 for each pixel. - */ -static void init_tables_yuy2(int newwidth, int newheight, int oldwidth, int oldheight, - int Interlaced, double hWarp, double vWarp, - uint32_t *hControl, uint32_t *vOffsets, uint32_t *vWeights ) -{ - int i; - int j; - int k; - int wY1; - int wY2; - int wUV1; - int wUV2; - DBG("init_yuy2: %dx%d->%dx%d hWarp %1.3lf vWarp %1.3lf\n", - oldwidth, oldheight, newwidth, newheight, hWarp, vWarp); - - /* First set up horizontal table */ - for(i=0; i < newwidth; i+=2) { - /* first make even pixel control */ - if (hWarp==1) /* if no warp factor */ - j = i * 256 * (oldwidth-1) / (newwidth-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor(i / (newwidth-1.0), hWarp) * (oldwidth-1)); - - k = j>>8; - wY2 = j - (k << 8); /* luma weight of right pixel */ - wY1 = 256 - wY2; /* luma weight of left pixel */ - wUV2 = (k%2) ? 128 + (wY2 >> 1) : wY2 >> 1; - wUV1 = 256 - wUV2; - - if (k > oldwidth - 2) { - hControl[i*3+4] = oldwidth - 1; /* point to last byte */ - hControl[i*3] = 0x00000100; /* use 100% of rightmost Y */ - hControl[i*3+2] = 0x00000100; /* use 100% of rightmost U */ - } else { - hControl[i*3+4] = k; /* pixel offset */ - hControl[i*3] = wY2 << 16 | wY1; /* luma weights */ - hControl[i*3+2] = wUV2 << 16 | wUV1; /* chroma weights */ - } - - /* now make odd pixel control */ - if (hWarp==1) /* if no warp factor */ - j = (i+1) * 256 * (oldwidth-1) / (newwidth-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor((i+1) / (newwidth-1.0), hWarp) * (oldwidth-1)); - - k = j>>8; - wY2 = j - (k << 8); /* luma weight of right pixel */ - wY1 = 256 - wY2; /* luma weight of left pixel */ - wUV2 = (k%2) ? 128 + (wY2 >> 1) : wY2 >> 1; - wUV1 = 256 - wUV2; - - if (k > oldwidth - 2) { - hControl[i*3+5] = oldwidth - 1; /* point to last byte */ - hControl[i*3+1] = 0x00000100; /* use 100% of rightmost Y */ - hControl[i*3+3] = 0x00000100; /* use 100% of rightmost V */ - } else { - hControl[i*3+5] = k; /* pixel offset */ - hControl[i*3+1] = wY2 << 16 | wY1; /* luma weights */ - /* hControl[i*3+3] = wUV2 << 16 | wUV1; // chroma weights */ - /* horiz chroma weights should be same as for even pixel - trbarry 09/16/2002 */ - hControl[i*3+3] = hControl[i*3+2]; /* chroma weights */ - } - } - - hControl[newwidth*3+4] = 2 * (oldwidth-1); /* give it something to prefetch at end */ - hControl[newwidth*3+5] = 2 * (oldwidth-1); - - /* Next set up vertical table. The offsets are measured in lines and will be mult */ - /* by the source pitch later */ - for(i=0; i< newheight; ++i) { - if (vWarp==1) /* if no warp factor */ - j = i * 256 * (oldheight-1) / (newheight-1); - else /* stretch and warp somehow */ - j = (int) (256 * WarpFactor(i / (newheight-1.0), vWarp) * (oldheight-1)); - - if (Interlaced) { /* do hard way? */ - if (i%2) { /* is odd output line? */ - if (j < 256) { /* before 1st odd input line */ - vOffsets[i] = 1; /* all from line 1 */ - vWeights[i] = 0; /* weight to give to 2nd line */ - } else { - k = (((j-256) >> 9) << 1) + 1; /* next lowest odd line */ - vOffsets[i] = k; - wY2 = j - (k << 8); - vWeights[i] = wY2 >> 1; /* weight to give to 2nd line */ - } - } else { /* is even output line */ - k = (j >> 9) << 1; /* next lower even line */ - vOffsets[i] = k; - wY2 = j - (k << 8); - vWeights[i] = wY2 >> 1; /* weight to give to 2nd line */ - } - } else { /* simple way, do as progressive */ - k = j >> 8; - vOffsets[i] = k; - wY2 = j - (k << 8); - vWeights[i] = wY2; /* weight to give to 2nd line */ - } - } -} - -/* Register allocation */ -/* index/counter registers (REGA, REGC) are loaded from 32bit vars/arrays ! */ -#define REGEA "eax" -#define REGEB "ebx" -#if defined(__x86_64__) -# define REGA "rax" -# define REGB "rbx" -# define REGC "ecx" -# define REGD "rdx" -# define REGDI "rdi" -# define REGSI "rsi" -#elif defined(__i386__) -# define REGA "eax" -# define REGB "ebx" -# define REGC "ecx" -# define REGD "edx" -# define REGDI "edi" -# define REGSI "esi" -#endif - -/* variables accessed from assembler code */ -#define _FPround1 "%0" -#define _vWeight1 "%1" -#define _vWeight2 "%2" -#define _YMask "%3" -#define _src_row_size "%4" -#define _EndOffset "%5" -#define _pControl "%6" -#define _row_size "%7" -#define _vWorkYW "%8" -#define _dstp "%9" -#define _vWorkUVW "%10" -#define _FPround2 "%11" -#define _srcp1 "%12" -#define _srcp2 "%13" -#if !defined(__x86_64__) -#define _oldbx "%14" -#define _SSEMMXenabledW "%15" -#define _SSE2enabledW "%16" -#endif - -/* Labels */ -#define vMaybeSSEMMX "1" -#define LessThan8 "2" -#define LessThan4 "3" -#define AllDone "4" -#define LastOne "5" -#define vLoopSSE2_Fetch "6" -#define vLoopSSE2 "7" -#define vLoopSSEMMX_Fetch "8" -#define vLoopSSEMMX "9" -#define vLoopMMX "10" -#define MoreSpareChange "11" -#define DoHorizontal "12" -#define hLoopMMX "13" -#define hLoopMMXSSE "14" - - -/* structure for mmx constants */ -typedef union { - uint64_t uq[1]; /* Unsigned Quadword */ - uint32_t ud[2]; /* Unsigned Doubleword */ -} ATTR_ALIGN(16) mmx_t; - -/* structure for sse2 constants */ -typedef union { - uint64_t uq[2]; /* Unsigned Quadword */ - uint32_t ud[4]; /* Unsigned Doubleword */ -} ATTR_ALIGN(16) sse2_t; - - -static int do_warp_yuy2(uint8_t *dst, const uint8_t *src, - const int dst_pitch, const int src_pitch, - const int dst_width, const int dst_height, - const int src_width, const int src_height, - const int Interlaced, const uint32_t * const hControl, - const uint32_t * const vOffsets, const uint32_t * const vWeights, - uint32_t *vWorkY, uint32_t *vWorkUV, - int dst_start) -{ -#if defined(__i386__) || defined(__x86_64__) - sse2_t YMask = {uq:{UINT64_C(0x00ff00ff00ff00ff),UINT64_C(0x00ff00ff00ff00ff)}}; /* keeps only luma */ - sse2_t FPround1 = {uq:{UINT64_C(0x0080008000800080),UINT64_C(0x0080008000800080)}}; /* round words */ - sse2_t FPround2 = {uq:{UINT64_C(0x0000008000000080),UINT64_C(0x0000008000000080)}}; /* round dwords */ - sse2_t vWeight1; - sse2_t vWeight2; - - const uint32_t *pControl = &hControl[0]; - const uint32_t *vWorkYW = vWorkY; - const uint32_t *vWorkUVW = vWorkUV; - const uint8_t *srcp = src; - const uint8_t *srcp1; - const uint8_t *srcp2; - uint8_t *dstp = dst + dst_pitch*dst_start; - - const uint32_t src_row_size = src_width * 2; - const uint32_t row_size = dst_width * 2; - const uint32_t EndOffset = src_row_size / 2; - -#if !defined(__x86_64__) - const int accel = xine_mm_accel(); - const uint32_t SSE2enabledW = !!(accel & MM_ACCEL_X86_SSE2); /* in local storage for asm */ - const uint32_t SSEMMXenabledW = !!(accel & MM_ACCEL_X86_MMXEXT); /* in local storage for asm */ - long int oldbx; -#endif - int y; - - for (y = dst_start; y < dst_height; y++) { - - if(vOffsets[y] >= src_height) { - /* slice completed */ - /*DBG("do_warp_yuy2: max input height reached: need line %d, height %d\n -> Returning next output line: %d\n", - vOffsets[y], src_height, y);*/ - return y; - } - - vWeight1.ud[0] = vWeight1.ud[1] = vWeight1.ud[2] = vWeight1.ud[3] = - (256-vWeights[y]) << 16 | (256-vWeights[y]); - vWeight2.ud[0] = vWeight2.ud[1] = vWeight2.ud[2] = vWeight2.ud[3] = - vWeights[y] << 16 | vWeights[y]; - - srcp1 = srcp + vOffsets[y] * src_pitch; - if (Interlaced) - srcp2 = (y < dst_height-2) ? srcp1 + 2 * src_pitch : srcp1; - else - srcp2 = (y < dst_height-1) ? srcp1 + src_pitch : srcp1; - - __asm__ __volatile__ ( -#if !defined(__x86_64__) - /* store ebx (PIC) */ - "mov %%"REGB", "_oldbx" \n\t" -#endif - "movl "_src_row_size", %%"REGC" \n\t" - "shrl $3, %%"REGC" \n\t" /* 8 bytes a time */ - "mov "_srcp1", %%"REGSI" \n\t" /* top of 2 src lines to get */ - "mov "_srcp2", %%"REGD" \n\t" /* next " */ - "mov "_vWorkYW", %%"REGDI" \n\t" /* luma work destination line */ - "mov "_vWorkUVW", %%"REGB" \n\t" /* luma work destination line */ - "xor %%"REGA", %%"REGA" \n\t" -#if !defined(__x86_64__) - /* Let's check here to see if we are on a P4 or higher and can use SSE2 instructions. - * This first loop is not the performance bottleneck anyway but it is trivial to tune - * using SSE2 if we have proper alignment. - */ - "testl $1, "_SSE2enabledW" \n\t" /* is SSE2 supported?*/ - "jz "vMaybeSSEMMX"f \n\t" /* n, can't do anyway*/ -#endif - "cmpl $2, %%"REGC" \n\t" /* we have at least 16 bytes, 2 qwords? */ - "jl "vMaybeSSEMMX"f \n\t" /* n, don't bother*/ - - "shrl $1, %%"REGC" \n\t" /* do 16 bytes at a time instead*/ - "decl %%"REGC" \n" /* jigger loop ct */ - - ".align 16 \n\t" - - "movdqa "_FPround1", %%xmm0 \n\t" - "movdqa "_vWeight1", %%xmm5 \n\t" - "movdqa "_vWeight2", %%xmm6 \n\t" - "movdqa "_YMask", %%xmm7 \n" - - ""vLoopSSE2_Fetch": \n\t" -#ifdef PREFETCH - " prefetcht0 16(%%"REGSI", %%"REGA", 2) \n\t" - " prefetcht0 16(%%"REGD", %%"REGA", 2) \n" -#endif - ""vLoopSSE2": \n\t" - " movdqu (%%"REGSI", %%"REGA", 2), %%xmm1 \n\t" /* top of 2 lines to interpolate */ - " movdqu (%%"REGD", %%"REGA", 2), %%xmm2 \n\t" /* 2nd of 2 lines */ - - " movdqa %%xmm1, %%xmm3 \n\t" /* get chroma bytes */ - " pand %%xmm7, %%xmm1 \n\t" /* keep only luma */ - " psrlw $8, %%xmm3 \n\t" /* right just chroma */ - " pmullw %%xmm5, %%xmm1 \n\t" /* mult by weighting factor */ - " pmullw %%xmm5, %%xmm3 \n\t" /* mult by weighting factor */ - - " movdqa %%xmm2, %%xmm4 \n\t" /* get chroma bytes */ - " pand %%xmm7, %%xmm2 \n\t" /* keep only luma */ - " psrlw $8, %%xmm4 \n\t" /* right just chroma */ - " pmullw %%xmm6, %%xmm2 \n\t" /* mult by weighting factor */ - " pmullw %%xmm6, %%xmm4 \n\t" /* mult by weighting factor */ - - " paddw %%xmm2, %%xmm1 \n\t" /* combine lumas */ - " paddusw %%xmm0, %%xmm1 \n\t" /* round */ - " psrlw $8, %%xmm1 \n\t" /* right adjust luma */ -#ifdef STREAMING_STORE_TMP - " movntdq %%xmm1, (%%"REGDI", %%"REGA", 2) \n\t" /* save lumas in our work area */ -#else - " movdqu %%xmm1, (%%"REGDI", %%"REGA", 2) \n\t" /* save lumas in our work area */ -#endif - " paddw %%xmm4, %%xmm3 \n\t" /* combine chromas */ - " paddusw %%xmm0, %%xmm3 \n\t" /* round */ - " psrlw $8, %%xmm3 \n\t" /* right adjust chroma */ - " packuswb %%xmm3, %%xmm3 \n\t" /* pack UV's into low dword */ - " movdq2q %%xmm3, %%mm1 \n\t" /* save in our work area */ -#ifdef STREAMING_STORE_TMP - " movntq %%mm1, (%%"REGB", %%"REGA") \n\t" /* save in our work area */ -#else - " movq %%mm1, (%%"REGB", %%"REGA") \n\t" /* save in our work area */ -#endif - " lea 8(%%"REGA"), %%"REGA" \n\t" - " decl %%"REGC" \n\t" - - " jg "vLoopSSE2_Fetch"b \n\t" /* if not on last one loop, prefetch */ - " jz "vLoopSSE2"b \n\t" /* or just loop, or not */ - - /* done with our SSE2 fortified loop but we may need to pick up the spare change */ -#ifdef STREAMING_STORE_TMP - " sfence \n\t" -#endif - " movl "_src_row_size", %%"REGC" \n\t" /* get count again */ - " andl $15, %%"REGC" \n\t" /* just need mod 16 */ - - " movq "_YMask", %%mm7 \n\t" /* useful luma mask constant - lazy dupl init */ - " movq "_vWeight1", %%mm5 \n\t" - " movq "_vWeight2", %%mm6 \n\t" - " movq "_FPround1", %%mm0 \n\t" /* useful rounding constant */ - - " shrl $3, %%"REGC" \n\t" /* 8 bytes at a time, any? */ - " jz "MoreSpareChange"f \n" /* n, did them all */ - - /* Let's check here to see if we are on a P2 or Athlon and can use SSEMMX instructions. - * This first loop is not the performance bottleneck anyway but it is trivial to tune - * using SSE if we have proper alignment. - */ - ""vMaybeSSEMMX": \n\t" - - " movq "_YMask", %%mm7 \n\t" /* useful luma mask constant - lazy dupl init */ - " movq "_vWeight1", %%mm5 \n\t" - " movq "_vWeight2", %%mm6 \n\t" - " movq "_FPround1", %%mm0 \n\t" /* useful rounding constant */ -#if !defined(__x86_64__) - " testl $1, "_SSEMMXenabledW" \n\t" /* MMXEXTsupported? */ - " jz "vLoopMMX"f \n\t" /* n, can't do anyway */ -#endif - " decl %%"REGC" \n" /* jigger loop ctr */ - - ".align 16 \n" - ""vLoopSSEMMX_Fetch": \n\t" -#ifdef PREFETCH - " prefetcht0 8(%%"REGSI", %%"REGA", 2) \n\t" - " prefetcht0 8(%%"REGD", %%"REGA", 2) \n" -#endif - ""vLoopSSEMMX": \n\t" - " movq (%%"REGSI", %%"REGA", 2), %%mm1 \n\t" /* top of 2 lines to interpolate */ - " movq (%%"REGD", %%"REGA", 2), %%mm2 \n\t" /* 2nd of 2 lines */ - - " movq %%mm1, %%mm3 \n\t" /* copy top bytes */ - " pand %%mm7, %%mm1 \n\t" /* keep only luma */ - " pxor %%mm1, %%mm3 \n\t" /* keep only chroma */ - " psrlw $8, %%mm3 \n\t" /* right just chroma */ - " pmullw %%mm5, %%mm1 \n\t" /* mult by weighting factor */ - " pmullw %%mm5, %%mm3 \n\t" /* mult by weighting factor */ - - " movq %%mm2, %%mm4 \n\t" /* copy 2nd bytes */ - " pand %%mm7, %%mm2 \n\t" /* keep only luma */ - " pxor %%mm2, %%mm4 \n\t" /* keep only chroma */ - " psrlw $8, %%mm4 \n\t" /* right just chroma */ - " pmullw %%mm6, %%mm2 \n\t" /* mult by weighting factor */ - " pmullw %%mm6, %%mm4 \n\t" /* mult by weighting factor */ - - " paddw %%mm2, %%mm1 \n\t" /* combine lumas */ - " paddusw %%mm0, %%mm1 \n\t" /* round */ - " psrlw $8, %%mm1 \n\t" /* right adjust luma */ -#ifdef STREAMING_STORE_TMP - " movntq %%mm1, (%%"REGDI", %%"REGA", 2) \n\t" /* save lumas in our work area */ -#else - " movq %%mm1, (%%"REGDI", %%"REGA", 2) \n\t" /* save lumas in our work area */ -#endif - " paddw %%mm4, %%mm3 \n\t" /* combine chromas */ - " paddusw %%mm0, %%mm3 \n\t" /* round */ - " psrlw $8, %%mm3 \n\t" /* right adjust chroma */ - " packuswb %%mm3, %%mm3 \n\t" /* pack UV's into low dword */ - " movd %%mm3, (%%"REGB", %%"REGA") \n\t" /* save in our work area */ - - " lea 4(%%"REGA"), %%"REGA" \n\t" - " decl %%"REGC" \n\t" - " jg "vLoopSSEMMX_Fetch"b \n\t" /* if not on last one loop, prefetch */ - " jz "vLoopSSEMMX"b \n\t" /* or just loop, or not */ -#ifdef STREAMING_STORE_TMP - " sfence \n\t" -#endif - " jmp "MoreSpareChange"f \n" /* all done with vertical */ - - ".align 16 \n" - ""vLoopMMX": \n\t" - - " movq (%%"REGSI", %%"REGA", 2), %%mm1 \n\t" /* top of 2 lines to interpolate */ - " movq (%%"REGD", %%"REGA", 2), %%mm2 \n\t" /* 2nd of 2 lines */ - - " movq %%mm1, %%mm3 \n\t" /* copy top bytes */ - " pand %%mm7, %%mm1 \n\t" /* keep only luma */ - " pxor %%mm1, %%mm3 \n\t" /* keep only chroma */ - " psrlw $8, %%mm3 \n\t" /* right just chroma */ - " pmullw %%mm5, %%mm1 \n\t" /* mult by weighting factor */ - " pmullw %%mm5, %%mm3 \n\t" /* mult by weighting factor */ - - " movq %%mm2, %%mm4 \n\t" /* copy 2nd bytes */ - " pand %%mm7, %%mm2 \n\t" /* keep only luma */ - " pxor %%mm2, %%mm4 \n\t" /* keep only chroma */ - " psrlw $8, %%mm4 \n\t" /* right just chroma */ - " pmullw %%mm6, %%mm2 \n\t" /* mult by weighting factor */ - " pmullw %%mm6, %%mm4 \n\t" /* mult by weighting factor */ - - " paddw %%mm2, %%mm1 \n\t" /* combine lumas */ - " paddusw %%mm0, %%mm1 \n\t" /* round */ - " psrlw $8, %%mm1 \n\t" /* right adjust luma */ - " movq %%mm1, (%%"REGDI", %%"REGA", 2) \n\t" /* save lumas in our work area */ - - " paddw %%mm4, %%mm3 \n\t" /* combine chromas */ - " paddusw %%mm0, %%mm3 \n\t" /* round */ - " psrlw $8, %%mm3 \n\t" /* right adjust chroma */ - " packuswb %%mm3, %%mm3 \n\t" /* pack UV's into low dword */ - " movd %%mm3, (%%"REGB", %%"REGA") \n\t" /* save in our work area */ - - " lea 4(%%"REGA"), %%"REGA" \n\t" - " loop "vLoopMMX"b \n" - - /* Add a little code here to check if we have 2 more pixels to do and, if so, make one - * more pass thru vLoopMMX. We were processing in multiples of 4 pixels and alway have - * an even number so there will never be more than 2 left. trbarry 7/29/2002 - */ - ""MoreSpareChange": \n\t" - - " cmpl "_EndOffset", %%"REGEA" \n\t" /* did we get them all */ - " jnl "DoHorizontal"f \n\t" /* yes, else have 2 left */ - " movl $1, %%"REGC" \n\t" /* jigger loop ct */ - " sub $2, %%"REGA" \n\t" /* back up 2 pixels (4 bytes, but eax carried as 1/2) */ - " jmp "vLoopMMX"b \n" - - /* We've taken care of the vertical scaling, now do horizontal */ - ""DoHorizontal": \n\t" - - " movq "_YMask", %%mm7 \n\t" /* useful 0U0U.. mask constant */ - " movq "_FPround2", %%mm6 \n\t" /* useful rounding constant, dwords */ - " mov "_pControl", %%"REGSI" \n\t" /* @ horiz control bytes */ - " movl "_row_size", %%"REGC" \n\t" - " shrl $2, %%"REGC" \n\t" /* bytes a time, 2 pixels */ - " mov "_vWorkYW", %%"REGD" \n\t" /* our luma data, as 0Y0Y 0Y0Y.. */ - " mov "_dstp", %%"REGDI" \n\t" /* the destination line */ - " mov "_vWorkUVW", %%"REGB" \n" /* chroma data, as UVUV UVUV... */ - - ".align 16 \n" - ""hLoopMMX": \n\t" - - /* x86_64: must use movl (accessing table of uint32's) */ - " movl 16(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 1st pixel pair */ - " movd (%%"REGD", %%"REGA", 2), %%mm0 \n\t" /* copy luma pair */ - " shr $1, %%"REGA" \n\t" /* div offset by 2 */ - " movd (%%"REGB", %%"REGA", 2), %%mm1 \n\t" /* copy UV pair VUVU */ - " psllw $8, %%mm1 \n\t" /* shift out V, keep 0000U0U0 */ - - /* we need to use both even and odd croma from same location - trb 9/2002 */ - " punpckldq (%%"REGB", %%"REGA", 2), %%mm1 \r\n" /* copy UV pair VUVU */ - " psrlw $8, %%mm1 \r\n" /* shift out U0, keep 0V0V 0U0U */ - " movl 20(%%"REGSI"), %%"REGEA" \r\n" /* get data offset in pixels, 2nd pixel pair */ - " punpckldq (%%"REGD", %%"REGA", 2), %%mm0 \r\n" /* copy luma pair */ - - " pmaddwd (%%"REGSI"), %%mm0 \r\n" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm0 \r\n" /* round */ - " psrlw $8, %%mm0 \r\n" /* right just 2 luma pixel value 000Y,000Y */ - - " pmaddwd 8(%%"REGSI"), %%mm1 \r\n" /* mult and sum chromas by ctl weights */ - " paddusw %%mm6, %%mm1 \r\n" /* round */ - " pslld $8, %%mm1 \r\n" /* shift into low bytes of different words */ - " pand %%mm7, %%mm1 \r\n" /* keep only 2 chroma values 0V00,0U00 */ - " por %%mm1, %%mm0 \r\n" /* combine luma and chroma, 0V0Y,0U0Y */ - " packuswb %%mm0, %%mm0 \r\n" /* pack all into low dword, xxxxVYUY */ - " movd %%mm0, (%%"REGDI") \n\t" /* done with 2 pixels */ - - " lea 24(%%"REGSI"), %%"REGSI" \n\t" /* bump to next control bytest */ - " lea 4(%%"REGDI"), %%"REGDI" \n\t" /* bump to next output pixel addr */ - - " loop "hLoopMMX"b \n\t" /* loop for more */ - - "emms \n\t" - /* done with one line */ - -#if !defined(__x86_64__) - "mov "_oldbx", %%"REGB" \n\t" -#endif - :: - "m" /*0*/(FPround1), - "m" /*1*/(vWeight1), - "m" /*2*/(vWeight2), - "m" /*3*/(YMask), - "m" /*4*/(src_row_size), - "m" /*5*/(EndOffset), - "m" /*6*/(pControl), - "m" /*7*/(row_size), - "m" /*8*/(vWorkYW), - "m" /*9*/(dstp), - "m" /*10*/(vWorkUVW), - "m" /*11*/(FPround2), - "m" /*12*/(srcp1), - "m" /*13*/(srcp2) -#if !defined(__x86_64__) - , - "m" /*14*/(oldbx), - "m" /*15*/(SSEMMXenabledW), - "m" /*16*/(SSE2enabledW) - : REGA, /*REGB,*/ REGC, REGD, REGSI, REGDI -#else - : REGA, REGB, REGC, REGD, REGSI, REGDI -#endif - ); - - dstp += dst_pitch; - } -#endif - return 0; -} - -static int do_warp_yv12(uint8_t *dst, const uint8_t * const src, - const int dst_pitch, const int src_pitch, - const int dst_width, const int dst_height, - const int src_width, const int src_height, - const int Interlaced, const uint32_t * const hControl, - const uint32_t * vOffsets, const uint32_t * vWeights, - uint32_t *vWorkY, int dst_start) -{ -#if defined(__i386__) || defined(__x86_64__) - sse2_t FPround1 = {uq:{UINT64_C(0x0080008000800080),UINT64_C(0x0080008000800080)}}; /* round words */ - sse2_t FPround2 = {uq:{UINT64_C(0x0000008000000080),UINT64_C(0x0000008000000080)}}; /* round dwords */ - sse2_t vWeight1; - sse2_t vWeight2; - - const uint32_t *pControl = &hControl[0]; - const uint32_t *vWorkYW = vWorkY; - const uint8_t *srcp = src; - const uint8_t *srcp1; - const uint8_t *srcp2; - uint8_t *dstp = dst + dst_pitch*dst_start; - - const uint32_t src_row_size = src_width; - const uint32_t row_size = dst_width; - -#if !defined(__x86_64__) - const int accel = xine_mm_accel(); - const uint32_t SSE2enabledW = !!(accel & MM_ACCEL_X86_SSE2); /* in local storage for asm */ - const uint32_t SSEMMXenabledW = !!(accel & MM_ACCEL_X86_MMXEXT); /* in local storage for asm */ - long int oldbx; -#endif - int y; - - /* Operation in sliced mode: - * - continue until required next source line is out of slice - * - return next output line - * - at next call, continue from next souce line - */ - - for (y = dst_start; y < dst_height; y++) { - if(vOffsets[y] >= src_height) { - /* slice completed */ - /*DBG("do_warp_yv12: max input height reached: need line %d, height %d\n -> Returning next output line: %d , start was %d\n", - (int)vOffsets[y], (int)src_height, (int)y, (int)dst_start);*/ - return y; - } - - vWeight1.ud[0] = vWeight1.ud[1] = vWeight1.ud[2] = vWeight1.ud[3] = - (256-vWeights[y]) << 16 | (256-vWeights[y]); - vWeight2.ud[0] = vWeight2.ud[1] = vWeight2.ud[2] = vWeight2.ud[3] = - vWeights[y] << 16 | vWeights[y]; - - srcp1 = srcp + vOffsets[y] * src_pitch; - - if (Interlaced) - srcp2 = (y < dst_height-2) ? srcp1 + 2 * src_pitch : srcp1; - else - srcp2 = (y < dst_height-1) ? srcp1 + src_pitch : srcp1; - - __asm__ __volatile__( - "movl "_src_row_size", %%"REGC" \n\t" - "shr $3, %%"REGC" \n\t" /* 8 bytes a time */ - "mov "_srcp1", %%"REGSI" \n\t" /* top of 2 src lines to get */ - "mov "_srcp2", %%"REGD" \n\t" /* next " */ - "mov "_vWorkYW", %%"REGDI" \n\t" /* luma work destination line */ - "xor %%"REGA", %%"REGA" \n\t" -#if !defined(__x86_64__) - /* Let's check here to see if we are on a P4 or higher and can use SSE2 instructions. - * This first loop is not the performance bottleneck anyway but it is trivial to tune - * using SSE2 if we have proper alignment. - */ - "testl $1, "_SSE2enabledW" \n\t" /* is SSE2 supported? */ - "jz "vMaybeSSEMMX"f \n\t" /* n, can't do anyway */ -#endif - "cmpl $2, %%"REGC" \n\t" /* we have at least 16 byts, 2 qwords? */ - "jl "vMaybeSSEMMX"f \n\t" /* n, don't bother */ - - "mov %%"REGSI", %%"REGB" \n\t" - "or %%"REGD", %%"REGB" \n\t" - "test $15, %%"REGB" \n\t" /* both src rows 16 byte aligned? */ - "jnz "vMaybeSSEMMX"f \n\t" /* n, don't use sse2 */ - - "shr $1, %%"REGC" \n\t" /* do 16 bytes at a time instead */ - "dec %%"REGC" \n\t" /* jigger loop ct */ - - "movdqa "_FPround1", %%xmm0 \n\t" - "movdqa "_vWeight1", %%xmm5 \n\t" - "movdqa "_vWeight2", %%xmm6 \n\t" - "pxor %%xmm7, %%xmm7 \n" - - ".align 16 \n" - ""vLoopSSE2_Fetch": \n\t" -#ifdef PREFETCH - " prefetcht0 16(%%"REGSI", %%"REGA", 2) \n\t" - " prefetcht0 16(%%"REGD", %%"REGA", 2) \n" -#endif - ""vLoopSSE2": \n\t" - /* we're already checked pointers to be on dqword aligned */ - " movdqa (%%"REGSI", %%"REGA"), %%xmm1 \n\t" /* top of 2 lines to interpolate */ - " movdqa (%%"REGD", %%"REGA"), %%xmm3 \n\t" /* 2nd of 2 lines */ - " movdqa %%xmm1, %%xmm2 \n\t" - " movdqa %%xmm3, %%xmm4 \n\t" - - " punpcklbw %%xmm7, %%xmm1 \n\t" /* make words */ - " punpckhbw %%xmm7, %%xmm2 \n\t" /* " */ - " punpcklbw %%xmm7, %%xmm3 \n\t" /* " */ - " punpckhbw %%xmm7, %%xmm4 \n\t" /* " */ - - " pmullw %%xmm5, %%xmm1 \n\t" /* mult by top weighting factor */ - " pmullw %%xmm5, %%xmm2 \n\t" /* " */ - " pmullw %%xmm6, %%xmm3 \n\t" /* mult by bot weighting factor */ - " pmullw %%xmm6, %%xmm4 \n\t" /* " */ - - " paddw %%xmm3, %%xmm1 \n\t" /* combine lumas low */ - " paddw %%xmm4, %%xmm2 \n\t" /* combine lumas high */ - - " paddusw %%xmm0, %%xmm1 \n\t" /* round */ - " paddusw %%xmm0, %%xmm2 \n\t" /* round */ - - " psrlw $8, %%xmm1 \n\t" /* right adjust luma */ - " psrlw $8, %%xmm2 \n\t" /* right adjust luma */ - - " packuswb %%xmm2, %%xmm1 \n\t" /* pack words to our 16 byte answer */ -#ifdef STREAMING_STORE_TMP - " movntdq %%xmm1, (%%"REGDI", %%"REGA") \n\t" /* save lumas in our work area */ -#else - " movdqu %%xmm1, (%%"REGDI", %%"REGA") \n\t" /* save lumas in our work area */ -#endif - " lea 16(%%"REGA"), %%"REGA" \n\t" - " decl %%"REGC" \n\t" - - " jg "vLoopSSE2_Fetch"b \n\t" /* if not on last one loop, prefetch */ - " jz "vLoopSSE2"b \n\t" /* or just loop, or not */ - - /* done with our SSE2 fortified loop but we may need to pick up the spare change */ -#ifdef STREAMING_STORE_TMP - " sfence \n\t" -#endif - " movl "_src_row_size", %%"REGC" \n\t" /* get count again */ - " andl $15, %%"REGC" \n\t" /* just need mod 16 */ - " movq "_vWeight1", %%mm5 \n\t" - " movq "_vWeight2", %%mm6 \n\t" - " movq "_FPround1", %%mm0 \n\t" /* useful rounding constant */ - - " shrl $3, %%"REGC" \n\t" /* 8 bytes at a time, any? */ - " jz "MoreSpareChange"f \n" /* n, did them all */ - - /* Let's check here to see if we are on a P2 or Athlon and can use SSEMMX instructions. - * This first loop is not the performance bottleneck anyway but it is trivial to tune - * using SSE if we have proper alignment. - */ - ""vMaybeSSEMMX": \n\t" - - " movq "_vWeight1", %%mm5 \n\t" - " movq "_vWeight2", %%mm6 \n\t" - " movq "_FPround1", %%mm0 \n\t" /* useful rounding constant */ - " pxor %%mm7, %%mm7 \n\t" -#if !defined(__x86_64__) - " testl $1, "_SSEMMXenabledW" \n\t"/* MMXEXTsupported? */ - " jz "vLoopMMX"f \n\t" /* n, can't do anyway */ -#endif - " decl %%"REGC" \n" /* jigger loop ctr */ - - ".align 16 \n" - ""vLoopSSEMMX_Fetch": \n\t" -#ifdef PREFETCH - " prefetcht0 8(%%"REGSI", %%"REGA") \n\t" - " prefetcht0 8(%%"REGD", %%"REGA") \n" -#endif - ""vLoopSSEMMX": \n\t" - - " movq (%%"REGSI", %%"REGA"), %%mm1 \n\t" /* top of 2 lines to interpolate */ - " movq (%%"REGD", %%"REGA"), %%mm3 \n\t" /* 2nd of 2 lines */ - - " movq %%mm1, %%mm2 \n\t" - " movq %%mm3, %%mm4 \n\t" - - " punpcklbw %%mm7, %%mm1 \n\t" /* make words */ - " punpckhbw %%mm7, %%mm2 \n\t" /* " */ - " punpcklbw %%mm7, %%mm3 \n\t" /* " */ - " punpckhbw %%mm7, %%mm4 \n\t" /* " */ - - " pmullw %%mm5, %%mm1 \n\t" /* mult by top weighting factor */ - " pmullw %%mm5, %%mm2 \n\t" /* " */ - " pmullw %%mm6, %%mm3 \n\t" /* mult by bot weighting factor */ - " pmullw %%mm6, %%mm4 \n\t" /* " */ - - " paddw %%mm3, %%mm1 \n\t" /* combine lumas low */ - " paddw %%mm4, %%mm2 \n\t" /* combine lumas high */ - - " paddusw %%mm0, %%mm1 \n\t" /* round */ - " paddusw %%mm0, %%mm2 \n\t" /* round */ - - " psrlw $8, %%mm1 \n\t" /* right adjust luma */ - " psrlw $8, %%mm2 \n\t" /* right adjust luma */ - - " packuswb %%mm2, %%mm1 \n\t" /* pack words to our 8 byte answer */ -#ifdef STREAMING_STORE_TMP - " movntq %%mm1, (%%"REGDI", %%"REGA") \n\t" /* save lumas in our work area */ -#else - " movq %%mm1, (%%"REGDI", %%"REGA") \n\t" /* save lumas in our work area */ -#endif - " lea 8(%%"REGA"), %%"REGA" \n\t" - " decl %%"REGC" \n\t" - - " jg "vLoopSSEMMX_Fetch"b \n\t" /* if not on last one loop, prefetch */ - " jz "vLoopSSEMMX"b \n\t" /* or just loop, or not */ -#ifdef STREAMING_STORE_TMP - " sfence \n\t" -#endif - " jmp "MoreSpareChange"f \n" /* all done with vertical */ - - ".align 16 \n" - ""vLoopMMX": \n\t" - - " movq (%%"REGSI", %%"REGA"), %%mm1 \n\t" /* top of 2 lines to interpolate */ - " movq (%%"REGD", %%"REGA"), %%mm3 \n\t" /* 2nd of 2 lines */ - - " movq %%mm1, %%mm2 \n\t" - " movq %%mm3, %%mm4 \n\t" - - " punpcklbw %%mm7, %%mm1 \n\t" /* make words */ - " punpckhbw %%mm7, %%mm2 \n\t" /* " */ - " punpcklbw %%mm7, %%mm3 \n\t" /* " */ - " punpckhbw %%mm7, %%mm4 \n\t" /* " */ - - " pmullw %%mm5, %%mm1 \n\t" /* mult by top weighting factor */ - " pmullw %%mm5, %%mm2 \n\t" /* " */ - " pmullw %%mm6, %%mm3 \n\t" /* mult by bot weighting factor */ - " pmullw %%mm6, %%mm4 \n\t" /* " */ - - " paddw %%mm3, %%mm1 \n\t" /* combine lumas low */ - " paddw %%mm4, %%mm2 \n\t" /* combine lumas high */ - - " paddusw %%mm0, %%mm1 \n\t" /* round */ - " paddusw %%mm0, %%mm2 \n\t" /* round */ - - " psrlw $8, %%mm1 \n\t" /* right adjust luma */ - " psrlw $8, %%mm2 \n\t" /* right adjust luma */ - - " packuswb %%mm2, %%mm1 \n\t" /* pack words to our 8 byte answer */ - " movq %%mm1, (%%"REGDI", %%"REGA") \n\t" /* save lumas in our work area */ - - " lea 8(%%"REGA"), %%"REGA" \n\t" - " loop "vLoopMMX"b \n" - - /* Add a little code here to check if we have more pixels to do and, if so, make one - * more pass thru vLoopMMX. We were processing in multiples of 8 pixels and alway have - * an even number so there will never be more than 7 left. - */ - ""MoreSpareChange": \n\t" - - " cmpl "_src_row_size", %%"REGEA" \n\t" /* did we get them all */ - " jnl "DoHorizontal"f \n\t" /* yes, else have 2 left */ - " movl $1, %%"REGC" \n\t" /* jigger loop ct */ - " movl "_src_row_size", %%"REGEA" \n\t" - " sub $8, %%"REGA" \n\t" /* back up to last 8 pixels */ - " jmp "vLoopMMX"b \n" - - /* We've taken care of the vertical scaling, now do horizontal */ - ""DoHorizontal": \n\t" - " pxor %%mm7, %%mm7 \n\t" - " movq "_FPround2", %%mm6 \n\t" /* useful rounding constant, dwords */ - " mov "_pControl", %%"REGSI" \n\t" /* @ horiz control bytes */ - " movl "_row_size", %%"REGC" \n\t" - " shrl $2, %%"REGC" \n\t" /* 4 bytes a time, 4 pixels */ - " mov "_vWorkYW", %%"REGD" \n\t" /* our luma data, as 0Y0Y 0Y0Y.. */ - " mov "_dstp", %%"REGDI" \n\t" /* the destination line */ -#if !defined(__x86_64__) - " testl $1, "_SSEMMXenabledW" \n\t" /* MMXEXTsupported? */ - " jz "hLoopMMX"f \n\t" /* n, can't do anyway */ -#endif - /* With SSE support we will make 8 pixels (from 8 pairs) at a time */ - " shrl $1, %%"REGC" \n\t" /* 8 bytes a time instead of 4 */ - " jz "LessThan8"f \n" - - ".align 16 \n" - ""hLoopMMXSSE": \n\t" - - - /* handle first 2 pixels */ - /* phi: must use movl here (x86_64, reading from table of uint_32's) */ - " movl 16(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 1st pixel pair */ - " movl 20(%%"REGSI"), %%"REGEB" \r\n" /* get data offset in pixels, 2nd pixel pair */ - - " movd (%%"REGD", %%"REGA"), %%mm0 \n\t" /* copy luma pair 0000xxYY */ - " punpcklwd (%%"REGD", %%"REGB"), %%mm0 \r\n" /* 2nd luma pair, now xxxxYYYY */ - " punpcklbw %%mm7, %%mm0 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - " movl 16+24(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 3st pixel pair */ - " movl 20+24(%%"REGSI"), %%"REGEB" \r\n" /* get data offset in pixels, 4nd pixel pair */ - " pmaddwd (%%"REGSI"), %%mm0 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm0 \n\t" /* round */ - " psrlw $8, %%mm0 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - - /* handle 3rd and 4th pixel pairs */ - " movd (%%"REGD", %%"REGA"), %%mm1 \n\t" /* copy luma pair 0000xxYY */ - " punpcklwd (%%"REGD", %%"REGB"), %%mm1 \r\n" /* 2nd luma pair, now xxxxYYYY */ - " punpcklbw %%mm7, %%mm1 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - " movl 16+48(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 5st pixel pair */ - " movl 20+48(%%"REGSI"), %%"REGEB" \r\n" /* get data offset in pixels, 6nd pixel pair */ - " pmaddwd 24(%%"REGSI"), %%mm1 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm1 \n\t" /* round */ - " psrlw $8, %%mm1 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - - /* handle 5th and 6th pixel pairs */ - " movd (%%"REGD", %%"REGA"), %%mm2 \n\t" /* copy luma pair 0000xxYY */ - " punpcklwd (%%"REGD", %%"REGB"), %%mm2 \r\n" /* 2nd luma pair, now xxxxYYYY */ - " punpcklbw %%mm7, %%mm2 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - " movl 16+72(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 7st pixel pair */ - " movl 20+72(%%"REGSI"), %%"REGEB" \r\n" /* get data offset in pixels, 8nd pixel pair */ - " pmaddwd 48(%%"REGSI"), %%mm2 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm2 \n\t" /* round */ - " psrlw $8, %%mm2 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - - /* handle 7th and 8th pixel pairs */ - " movd (%%"REGD", %%"REGA"), %%mm3 \n\t" /* copy luma pair 0000xxYY */ - " punpcklwd (%%"REGD", %%"REGB"), %%mm3 \r\n" /* 2nd luma pair, now xxxxYYYY */ - " punpcklbw %%mm7, %%mm3 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - " pmaddwd 72(%%"REGSI"), %%mm3 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm3 \n\t" /* round */ - " psrlw $8, %%mm3 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - - /* combine, store, and loop */ - " packuswb %%mm1, %%mm0 \n\t" /* pack into qword, 0Y0Y0Y0Y */ - " packuswb %%mm3, %%mm2 \n\t" /* pack into qword, 0Y0Y0Y0Y */ - " packuswb %%mm2, %%mm0 \n\t" /* and again into YYYYYYYY */ -#ifdef STREAMING_STORE - " movntq %%mm0, (%%"REGDI") \n\t" /* done with 4 pixels */ -#else - " movq %%mm0, (%%"REGDI") \n\t" /* done with 4 pixels */ -#endif - - " lea 96(%%"REGSI"), %%"REGSI" \n\t" - " lea 8(%%"REGDI"), %%"REGDI" \n\t" - " decl %%"REGC" \n\t" - " jg "hLoopMMXSSE"b \n\t" /* loop for more */ -#ifdef STREAMING_STORE - " sfence \n" -#endif - ""LessThan8": \n\t" - " movl "_row_size", %%"REGC" \n\t" - " andl $7, %%"REGC" \n\t" /* we have done all but maybe this */ - " shrl $2, %%"REGC" \n\t" /* now do only 4 bytes at a time */ - " jz "LessThan4"f \n" - - ".align 16 \n" - ""hLoopMMX": \n\t" - - /* handle first 2 pixels */ - " movl 16(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 1st pixel pair */ - " movl 20(%%"REGSI"), %%"REGEB" \r\n" /* get data offset in pixels, 2nd pixel pair */ - " movd (%%"REGD", %%"REGA"), %%mm0 \n\t" /* copy luma pair 0000xxYY */ - " punpcklwd (%%"REGD", %%"REGB"), %%mm0 \r\n" /* 2nd luma pair, now xxxxYYYY */ - " punpcklbw %%mm7, %%mm0 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - " movl 16+24(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 3st pixel pair */ - " movl 20+24(%%"REGSI"), %%"REGEB" \r\n" /* get data offset in pixels, 4nd pixel pair */ - " pmaddwd (%%"REGSI"), %%mm0 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm0 \n\t" /* round */ - " psrlw $8, %%mm0 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - - /* handle 3rd and 4th pixel pairs */ - " movd (%%"REGD", %%"REGA"), %%mm1 \n\t" /* copy luma pair 0000xxYY */ - " punpckldq (%%"REGD", %%"REGB"), %%mm1 \r\n" /* 2nd luma pair, now xxxxYYYY */ - " punpcklbw %%mm7, %%mm1 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - " pmaddwd 24(%%"REGSI"), %%mm1 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm1 \n\t" /* round */ - " psrlw $8, %%mm1 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - - /* combine, store, and loop */ - " packuswb %%mm1, %%mm0 \n\t" /* pack into qword, 0Y0Y0Y0Y */ - " packuswb %%mm7, %%mm0 \n\t" /* and again into 0000YYYY */ - " movd %%mm0, (%%"REGDI") \n\t" /* done with 4 pixels */ - " lea 48(%%"REGSI"), %%"REGSI" \n\t" - " lea 4(%%"REGDI"), %%"REGDI" \n\t" - - " loop "hLoopMMX"b \n" /* loop for more */ - - /* test to see if we have a mod 4 size row, if not then more spare change */ - ""LessThan4": \n\t" - " movl "_row_size", %%"REGC" \n\t" - " andl $3, %%"REGC" \n\t" /* remainder side mod 4 */ - " cmpl $2, %%"REGC" \n\t" - " jl "LastOne"f \n\t" /* none, none */ - - /* handle 2 more pixels */ - " movl 16(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 1st pixel pair */ - " movl 20(%%"REGSI"), %%"REGEB" \r\n" /* get data offset in pixels, 2nd pixel pair */ - " movd (%%"REGD", %%"REGA"), %%mm0 \n\t" /* copy luma pair 0000xxYY */ - " punpcklwd (%%"REGD", %%"REGB"), %%mm0 \r\n" /* 2nd luma pair, now xxxxYYYY */ - " punpcklbw %%mm7, %%mm0 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - - " pmaddwd (%%"REGSI"), %%mm0 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm0 \n\t" /* round */ - " psrlw $8, %%mm0 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - " packuswb %%mm7, %%mm0 \n\t" /* pack into qword, 00000Y0Y */ - " packuswb %%mm7, %%mm0 \n\t" /* and again into 000000YY */ - " movd %%mm0, (%%"REGDI") \n\t" /* store, we are guarrenteed room in buffer (8 byte mult) */ - " subl $2, %%"REGC" \n\t" - - " lea 24(%%"REGSI"), %%"REGSI" \n\t" /* bump to next control bytes */ - " lea 2(%%"REGDI"), %%"REGDI" \n" /* bump to next output pixel addr */ - - /* maybe one last pixel */ - ""LastOne": \n\t" - " cmpl $0, %%"REGC" \r\n" /* still more ? */ - " jz "AllDone"f \r\n" /* n, done */ - " movl 16(%%"REGSI"), %%"REGEA" \n\t" /* get data offset in pixels, 1st pixel pair */ - " movd (%%"REGD", %%"REGA"), %%mm0 \n\t" /* copy luma pair 0000xxYY */ - " punpcklbw %%mm7, %%mm0 \n\t" /* make words out of bytes, 0Y0Y0Y0Y */ - - " pmaddwd (%%"REGSI"), %%mm0 \n\t" /* mult and sum lumas by ctl weights */ - " paddusw %%mm6, %%mm0 \n\t" /* round */ - " psrlw $8, %%mm0 \n\t" /* right just 4 luma pixel value 0Y0Y0Y0Y */ - " movd %%mm0, %%"REGEA" \n\t" - " movb %%al, (%%"REGDI") \n" /* store last one */ - - ""AllDone": \n\t" - " emms \n\t" -#if !defined(__x86_64__) - "mov "_oldbx", %%"REGB" \n\t" -#endif - :: - "m" /*0*/(FPround1), - "m" /*1*/(vWeight1), - "m" /*2*/(vWeight2), - "m" /*3*/(y/*YMask[0]*/), - "m" /*4*/(src_row_size), - "m" /*5*/(y/*EndOffset*/), - "m" /*6*/(pControl), - "m" /*7*/(row_size), - "m" /*8*/(vWorkYW), - "m" /*9*/(dstp), - "m" /*10*/(y/*vWorkUVW*/), - "m" /*11*/(FPround2), - "m" /*12*/(srcp1), - "m" /*13*/(srcp2) -#if !defined(__x86_64__) - , - "m" /*14*/(oldbx), - "m" /*15*/(SSEMMXenabledW), - "m" /*16*/(SSE2enabledW) - : REGA, /*REGB,*/ REGC, REGD, REGSI, REGDI -#else - : REGA, REGB, REGC, REGD, REGSI, REGDI -#endif - ); - - dstp += dst_pitch; - } -#endif - return 0; -} - -/* - * tools - */ - -#ifndef ALIGN -# define ALIGN(b,p) ((void*)((((unsigned long)(p)) + (b)-1) & (~((b)-1)))) -#endif -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef MAX -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif -#ifndef FABS -# define FABS(x) ((x) < 0.0 ? -(x) : (x)) -#endif - -/* - * xine plugin - */ - -#define PLUGIN_ID "warp" -#define PLUGIN_DESCR "(non-)linear software scaling post plugin"; -#define PLUGIN_T warp_plugin_t -/*#define POST_THREADS*/ -/*#define POST_SLICES*/ -#include "xine/post_util.h" - - -/* plugin class initialization function */ -void *warp_init_plugin(xine_t *xine, void *); - -/* plugin class functions */ -static post_plugin_t *open_plugin(post_class_t *class_gen, int inputs, - xine_audio_port_t **audio_target, - xine_video_port_t **video_target); - -/* plugin instance functions */ -static void warp_dispose(post_plugin_t *this_gen); - -/* vo_frame functions */ -static vo_frame_t *got_frame(vo_frame_t *frame); -static void draw_internal(vo_frame_t *frame, vo_frame_t *new_frame); - - -/* parameter functions */ -static xine_post_api_descr_t *warp_get_param_descr(void); -static int warp_set_parameters(xine_post_t *this_gen, void *param_gen); -static int warp_get_parameters(xine_post_t *this_gen, void *param_gen); -static char *warp_get_help(void); - - -typedef struct warp_parameters_s { - int output_width; - int output_height; - double output_aspect; - int no_downscaling; -} warp_parameters_t; - -START_PARAM_DESCR(warp_parameters_t) -PARAM_ITEM(POST_PARAM_TYPE_INT, output_width, NULL, 640, 1920, 0, - "output video width") -PARAM_ITEM(POST_PARAM_TYPE_INT, output_height, NULL, 480, 1080, 0, - "output video height") -PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, output_aspect, NULL, 1, 3, 0, - "output video aspect ratio") -PARAM_ITEM(POST_PARAM_TYPE_BOOL, no_downscaling,NULL, 0, 1, 0, - "disable downscaling") -END_PARAM_DESCR(warp_param_descr) - - -typedef struct { - post_plugin_t post; - - xine_post_in_t parameter_input; - - /* User config (changes to actual config are delayed) */ - warp_parameters_t config; - - /* Current config */ - int enable; - int output_width; - int output_height; - double output_aspect; - double factor_x; - double factor_y; - - /* Last seen input frame */ - int input_width; - int input_height; - int input_format; - int input_interlaced; - double input_aspect; - - /* working buffers */ - uint32_t *vWorkY; - uint32_t *vWorkUV; - - /* scaling tables */ - uint32_t *hControl; - uint32_t *hControlUV; - uint32_t *vOffsets; - uint32_t *vOffsetsUV; - uint32_t *vWeights; - uint32_t *vWeightsUV; - - /* memory for work areas and scaling tables */ - void *pMem; - -} warp_plugin_t; - -/* - * - */ - -static void init_tables(warp_plugin_t *this) -{ -#define BP(x) ((uint8_t*)(x)) - /* allocate memory for scaling tables and workspace */ - free(this->pMem); - this->pMem = malloc(this->input_width*3 + this->output_width*sizeof(uint32_t)*3*2 + - this->output_height*sizeof(uint32_t)*4 + 2*9*128); - - /* - aligned for P4 cache line */ - this->vWorkY = (uint32_t*)ALIGN(128, this->pMem); - this->vWorkUV = (uint32_t*)ALIGN(128, BP(this->vWorkY) + this->input_width*2 + 128); - this->hControl = (uint32_t*)ALIGN(128, BP(this->vWorkUV) + this->input_width + 128); - this->vOffsets = (uint32_t*)ALIGN(128, BP(this->hControl) + this->output_width * sizeof(uint32_t) * 3 + 128); - this->vWeights = (uint32_t*)ALIGN(128, BP(this->vOffsets) + this->output_height * sizeof(uint32_t) + 128); - - if (this->input_format == XINE_IMGFMT_YV12) { - this->vOffsetsUV = (uint32_t*)ALIGN(128, BP(this->vWeights) + this->output_height * sizeof(uint32_t) + 128); - this->vWeightsUV = (uint32_t*)ALIGN(128, BP(this->vOffsetsUV) + this->output_height * sizeof(uint32_t) + 128); - this->hControlUV = (uint32_t*)ALIGN(128, BP(this->vWeightsUV) + this->output_height * sizeof(uint32_t) + 128); - - init_tables_yv12(this->output_width, this->output_height, - this->input_width, this->input_height, - this->input_interlaced, this->factor_x, this->factor_y, - this->hControl, this->vOffsets, this->vWeights, - this->hControlUV, this->vOffsetsUV, this->vWeightsUV ); - - } else if (this->input_format == XINE_IMGFMT_YUY2) { - - init_tables_yuy2(this->output_width, this->output_height, - this->input_width, this->input_height, - this->input_interlaced, this->factor_x, this->factor_y, - this->hControl, this->vOffsets, this->vWeights ); - } -} - -static void calculate_factors(warp_plugin_t *this) -{ - /* try to guess amount to stretch/shrink */ - double adiff = this->input_aspect - this->output_aspect; - this->factor_x = 1.0; - this->factor_y = 1.0; - - if (adiff > 0.1) { - - if (adiff > 0.1 + ((16.0-12.0)/9.0)) { - /* >16:9 -> >4:3 */ - DBG("aspect ratio diff %1.3lf > 0 : too large !\n", adiff); - this->factor_x = 0.95; - this->factor_y = 1.15; - this->output_aspect += (adiff - 4.0/9.0); - DBG(" changing target ratio to %3.1lf\n", this->output_aspect); - } else { - /* 16:9 ... 12:9 -> 4:3 */ - DBG("aspect ratio diff %1.3lf > 0 : 16.9...12:9 -> 4:3\n", adiff); - this->factor_x = 1.0 - 0.05 * adiff * 9.0/4.0; - this->factor_y = 1.0 + 0.15 * adiff * 9.0/4.0; - } - - } else if (adiff < -0.1) { - - if(adiff < -0.1-((16.0-12.0)/9.0)) { - /* <4:3 -> <16:9 */ - DBG("aspect ratio diff %1.3lf > 0 : too large !\n", adiff); - this->factor_x = 1.05; - this->factor_y = 0.85; - this->output_aspect += (adiff + 4.0/9.0); - DBG(" changing target ratio to %3.1lf\n", this->output_aspect); - } else { - /* 4:3...16:9 -> 16:9 */ - DBG("aspect ratio diff %1.3lf < 0 : 4:3...16:9 -> 16:9\n", adiff); - this->factor_x = 1.0 + 0.05 * adiff * 9.0/4.0; - this->factor_y = 1.0 - 0.15 * adiff * 9.0/4.0; - } - - } else { - DBG("aspect ratio matches, no warp\n"); - this->factor_x = 1.0; - this->factor_y = 1.0; - } - - DBG("factor_x = %1.3lf factor_y = %1.3lf output ratio = %1.3lf\n", - this->factor_x, this->factor_y, this->output_aspect); -} - -/* - * - */ - -void *warp_init_plugin(xine_t *xine, void *data) -{ -#if !defined(__x86_64__) - /* Need at least MMX */ - if (!(xine_mm_accel() & MM_ACCEL_X86_MMX)) { - fprintf(stderr, "warp_init_plugin: ERROR: at least MMX required\n"); - return NULL; - } -#endif - - return init_plugin(xine, data); -} - -static post_plugin_t *open_plugin(post_class_t *class_gen, int inputs, - xine_audio_port_t **audio_target, - xine_video_port_t **video_target) -{ - warp_plugin_t *this = calloc(1, sizeof(warp_plugin_t)); - post_plugin_t *this_gen = (post_plugin_t *) this; - post_in_t *input; - post_out_t *output; - xine_post_in_t *input_param; - post_video_port_t *port; - - static xine_post_api_t post_api = - { warp_set_parameters, warp_get_parameters, warp_get_param_descr, warp_get_help }; - - if (!this || !video_target || !video_target[0]) { - free(this); - return NULL; - } - - _x_post_init(this_gen, 0, 1); - - port = _x_post_intercept_video_port(this_gen, video_target[0], &input, &output); - port->intercept_frame = intercept_frame_yuy; - port->new_frame->draw = post_draw; - input->xine_in.name = "video"; - output->xine_out.name = "video (scaled)"; - this_gen->xine_post.video_input[0] = &port->new_port; - - this_gen->dispose = warp_dispose; - - input_param = &this->parameter_input; - input_param->name = "parameters"; - input_param->type = XINE_POST_DATA_PARAMETERS; - input_param->data = &post_api; - xine_list_push_back(this_gen->input, input_param); - - this->config.output_aspect = 0.0; /* -> do not change aspect ratio */ - this->config.output_width = 0; /* -> do not change width */ - this->config.output_height = 0; /* -> do not change height */ - this->config.no_downscaling = 0; - - this->input_width = 0; /* not known yet, triggers initialization later */ - this->input_height = 0; - - return this_gen; -} - -static void warp_dispose(post_plugin_t *this_gen) -{ - if (_x_post_dispose(this_gen)) { - warp_plugin_t *this = (warp_plugin_t *) this_gen; - - DBG("dispose\n"); - - free(this->pMem); - free(this); - } -} - -static vo_frame_t *got_frame(vo_frame_t *frame) -{ - post_video_port_t *port = (post_video_port_t *)frame->port; - warp_plugin_t *this = (warp_plugin_t *)port->post; - double adiff = this->input_aspect - frame->ratio; - - if (this->input_width != frame->width || this->input_height != frame->height || - this->input_format != frame->format || FABS(adiff)>0.1 || - this->input_interlaced != !!(frame->flags & VO_INTERLACED_FLAG)) { - - DBG("detected frame format change: %dx%d -> %dx%d, interlaced %d->%d, aspect %1.3lf->%1.3lf, %s->%s\n", - this->input_width, this->input_height, frame->width, frame->height, - this->input_interlaced, !!(frame->flags & VO_INTERLACED_FLAG), - this->input_aspect, frame->ratio, - this->input_format==XINE_IMGFMT_YV12 ? "yv12":"yuy2", - frame->format==XINE_IMGFMT_YV12 ? "yv12":"yuy2" ); - - /* free tables and buffers */ - free(this->pMem); - this->pMem = NULL; - - /* remember frame properties to detect changes in video format */ - this->input_width = frame->width; - this->input_height = frame->height; - this->input_format = frame->format; - this->input_aspect = frame->ratio; - this->input_interlaced = !!(frame->flags & VO_INTERLACED_FLAG); - - /* re-configure target size and aspect ratio */ - this->output_aspect = this->config.output_aspect ?: frame->ratio; - if (!this->config.no_downscaling) { - this->output_width = this->config.output_width ?: frame->width; - this->output_height = this->config.output_height ?: frame->height; - } else { - this->output_width = MAX(this->config.output_width, frame->width); - this->output_height = MAX(this->config.output_height, frame->height); - } - - /* calculate warp function factors */ - calculate_factors(this); - - adiff = this->input_aspect - this->output_aspect; - if(this->output_width == frame->width && - this->output_height == frame->height && - adiff < 0.1 && - adiff > -0.1 ) { - this->enable = 0; - DBG("--> nothing to do, disabling processing for now\n"); - return NULL; - } - - this->enable = 1; - - init_tables(this); - } - - if (!this->enable) - return NULL; - - return port->original_port->get_frame(port->original_port, - this->output_width, this->output_height, - this->output_aspect, frame->format, - frame->flags | VO_BOTH_FIELDS); -} - -static void draw_internal(vo_frame_t *frame, vo_frame_t *new_frame) -{ - post_video_port_t *port = (post_video_port_t *)frame->port; - warp_plugin_t *this = (warp_plugin_t *)port->post; - int proc_height = frame->height; - - if (frame->format == XINE_IMGFMT_YV12) { - - do_warp_yv12(new_frame->base[0], frame->base[0], - new_frame->pitches[0], frame->pitches[0], - this->output_width, this->output_height, - frame->width, proc_height, - this->input_interlaced, - this->hControl, this->vOffsets, this->vWeights, - this->vWorkY, - 0); - proc_height /= 2; - do_warp_yv12(new_frame->base[1], frame->base[1], - new_frame->pitches[1], frame->pitches[1], - this->output_width/2, this->output_height/2, - frame->width/2, proc_height, - this->input_interlaced, - this->hControlUV, this->vOffsetsUV, this->vWeightsUV, - this->vWorkUV, - 0); - do_warp_yv12(new_frame->base[2], frame->base[2], - new_frame->pitches[2], frame->pitches[2], - this->output_width/2, this->output_height/2, - frame->width/2, proc_height, - this->input_interlaced, - this->hControlUV, this->vOffsetsUV, this->vWeightsUV, - this->vWorkUV, - 0); - - } else if (frame->format == XINE_IMGFMT_YUY2) { - do_warp_yuy2(new_frame->base[0], frame->base[0], - new_frame->pitches[0], frame->pitches[0], - this->output_width, this->output_height, - frame->width, proc_height, - this->input_interlaced, - this->hControl, this->vOffsets, this->vWeights, - this->vWorkY, this->vWorkUV, - 0); - } -} - -/* - * parameter functions - */ - -static xine_post_api_descr_t *warp_get_param_descr(void) -{ - return &warp_param_descr; -} - -static int warp_set_parameters(xine_post_t *this_gen, void *param_gen) -{ - warp_plugin_t *this = (warp_plugin_t *)this_gen; - warp_parameters_t *params = (warp_parameters_t *)param_gen; - - memcpy(&this->config, params, sizeof(warp_parameters_t)); - this->input_width = this->input_height = 0; - - if(this->config.output_aspect > 999) - this->config.output_aspect /= 1000.0; - - DBG("warp_set_parameters: " - "output_width=%d, output_height=%d, output_aspect=%4.3lf, no_downscaling=%d\n", - this->config.output_width, this->config.output_height, this->config.output_aspect, - this->config.no_downscaling); - - return 1; -} - -static int warp_get_parameters(xine_post_t *this_gen, void *param_gen) -{ - warp_plugin_t *this = (warp_plugin_t *)this_gen; - warp_parameters_t *params = (warp_parameters_t *)param_gen; - - DBG("warp_get_parameters\n"); - memcpy(params, &this->config, sizeof(warp_parameters_t)); - - return 1; -} - -static char *warp_get_help(void) { - return _( - "The warp plugin scales video to another resolution. " - "It supports non-linear stretching to change video aspect ratio. " - "\n" - "Parameters\n" - " output_width: Scale video to width\n" - " (0 -> do not change video width)\n" - " output_height: Scale video to height\n" - " (0 -> do not change video height)\n" - " output_aspect: Adjust aspect ratio using non-linear scaling\n" - " (0 -> do not change video aspect ratio)\n" - " no_downscaling: Do not downscale video\n" - "\n" - ); -} - - -/* - * plugin info - */ - -static post_info_t info = { XINE_POST_TYPE_VIDEO_FILTER }; - -const plugin_info_t xine_plugin_info[] __attribute__((visibility("default"))) = -{ - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_POST, POST_PLUGIN_IFACE_VERSION, "warp", XINE_VERSION_CODE, &info, &warp_init_plugin }, - { PLUGIN_POST, POST_PLUGIN_IFACE_VERSION, "swscale", XINE_VERSION_CODE, &info, &warp_init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/xine_sxfe_frontend.c b/xine_sxfe_frontend.c deleted file mode 100644 index a3221429..00000000 --- a/xine_sxfe_frontend.c +++ /dev/null @@ -1,1779 +0,0 @@ -/* - * xine_sxfe_frontend.c: Simple front-end, X11 functions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: xine_sxfe_frontend.c,v 1.112 2009-05-31 19:25:03 phintuka Exp $ - * - */ - -/*#define HAVE_XF86VIDMODE*/ -#include "features.h" - -#include <poll.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#include <math.h> - -/* X11 */ -#include <X11/Xlib.h> -#include <X11/Xatom.h> -#include <X11/keysym.h> -#include <X11/Xutil.h> -#ifdef HAVE_XSHM -# include <X11/extensions/XShm.h> -#endif -#ifdef HAVE_XRENDER -# include <X11/extensions/Xrender.h> -#endif -#ifdef HAVE_XF86VIDMODE -# include <X11/extensions/xf86vmode.h> -#endif -#ifdef HAVE_XDPMS -# include <X11/extensions/dpms.h> -#endif -#ifdef HAVE_XINERAMA -# include <X11/extensions/Xinerama.h> -#endif - -#include <xine.h> - -#define LOG_MODULENAME "[vdr-sxfe] " -#include "logdefs.h" - -#include "xine_osd_command.h" -#include "xine_frontend_internal.h" - -#ifdef HAVE_DBUS_GLIB_1 -# include "tools/gnome_screensaver.h" -#endif - -#ifndef WIN_LAYER_NORMAL - #define WIN_LAYER_NORMAL 4 -#endif -#ifndef WIN_LAYER_ONTOP - #define WIN_LAYER_ONTOP 6 -#endif - -#define MWM_HINTS_DECORATIONS (1L << 1) -#define PROP_MWM_HINTS_ELEMENTS 5 -typedef struct _mwmhints { - uint32_t flags; - uint32_t functions; - uint32_t decorations; - int32_t input_mode; - uint32_t status; -} MWMHints; - -#ifdef HAVE_XRENDER -/* HUD Scaling */ -typedef struct _xrender_surf -{ - Visual *vis; - Drawable draw; - Picture pic; - uint16_t w, h; - uint8_t depth; - uint8_t allocated : 1; -} Xrender_Surf; -#endif /* HAVE_XRENDER */ - -/* - * data - */ - -typedef struct sxfe_s { - - /* function pointers / base class */ - union { - frontend_t fe; /* generic frontend */ - fe_t x; /* xine frontend */ - }; - - /* stored original handlers */ - int (*fe_xine_open)(frontend_t *this_gen, const char *mrl); - int (*fe_xine_play)(frontend_t *this_gen); - - - /* X11 */ - Display *display; - Window window[2]; - int screen; - int window_id; /* output to another window */ - int completion_event; -#ifdef HAVE_XF86VIDMODE - int XF86_modelines_count; - XF86VidModeModeInfo** XF86_modelines; -#endif - Time prev_click_time; /* time of previous mouse button click (grab double clicks) */ -#ifdef HAVE_XDPMS - BOOL dpms_state; -#endif - - /* Atoms */ - Atom xa_SXFE_INTERRUPT; - Atom xa_WM_DELETE_WINDOW; - Atom xa_MOTIF_WM_HINTS; - Atom xa_WIN_LAYER; - Atom xa_WIN_STATE; - Atom xa_NET_ACTIVE_WINDOW; - Atom xa_NET_WM_STATE; - Atom xa_NET_WM_STATE_ADD; - Atom xa_NET_WM_STATE_DEL; - Atom xa_NET_WM_STATE_ABOVE; - Atom xa_NET_WM_STATE_STICKY; - Atom xa_NET_WM_STATE_FULLSCREEN; - Atom xa_NET_WM_STATE_STAYS_ON_TOP; - - int xinerama_screen; /* current xinerama screen, -1 = auto */ - uint16_t xinerama_x; /* left-top position of current xinerama screen */ - uint16_t xinerama_y; - uint16_t origwidth; /* saved window-mode window size */ - uint16_t origheight; - uint16_t origxpos; /* saved window-mode window position */ - uint16_t origypos; - uint16_t dragging_x; - uint16_t dragging_y; - - uint8_t fullscreen : 1; -/*uint8_t vmode_switch : 1;*/ - uint8_t fullscreen_state_forced : 1; - uint8_t stay_above : 1; - uint8_t no_border : 1; - uint8_t check_move : 1; - uint8_t dragging : 1; - uint8_t hud : 1; - uint8_t gui_hotkeys : 1; - uint8_t no_x_kbd : 1; - - /* HUD stuff */ -#ifdef HAVE_XRENDER - XImage *hud_img; - Visual *hud_vis; - Xrender_Surf *surf_win; - Xrender_Surf *surf_img; - uint32_t *hud_img_mem; - GC gc; - Window hud_window; -# ifdef HAVE_XSHM - XShmSegmentInfo hud_shminfo; -# endif - - uint16_t osd_width; - uint16_t osd_height; -#endif /* HAVE_XRENDER */ - -} sxfe_t; - - -#define DOUBLECLICK_TIME 500 // ms - -#define OSD_DEF_WIDTH 720 -#define OSD_DEF_HEIGHT 576 -#define HUD_MAX_WIDTH 1920 -#define HUD_MAX_HEIGHT 1080 - -static void sxfe_dest_size_cb (void *data, - int video_width, int video_height, double video_pixel_aspect, - int *dest_width, int *dest_height, double *dest_pixel_aspect) -{ - fe_t *this = (fe_t *)data; - - if (!this) - return; - - *dest_width = this->width; - *dest_height = this->height; - - *dest_pixel_aspect = this->dest_pixel_aspect(this, video_pixel_aspect, - video_width, video_height); -} - -static void init_atoms(sxfe_t *this) -{ - if (this->xa_SXFE_INTERRUPT == None) { - this->xa_SXFE_INTERRUPT = XInternAtom(this->display, "SXFE_INTERRUPT", False); - this->xa_WM_DELETE_WINDOW = XInternAtom(this->display, "WM_DELETE_WINDOW", False); - this->xa_MOTIF_WM_HINTS = XInternAtom(this->display, "_MOTIF_WM_HINTS", False); - this->xa_WIN_LAYER = XInternAtom(this->display, "_WIN_LAYER", False); - this->xa_WIN_STATE = XInternAtom(this->display, "_WIN_STATE", False); - this->xa_NET_ACTIVE_WINDOW = XInternAtom(this->display, "_NET_ACTIVE_WINDOW", False); - this->xa_NET_WM_STATE = XInternAtom(this->display, "_NET_WM_STATE", False); - this->xa_NET_WM_STATE_ADD = XInternAtom(this->display, "_NET_WM_STATE_ADD", False); - this->xa_NET_WM_STATE_DEL = XInternAtom(this->display, "_NET_WM_STATE_DEL", False); - this->xa_NET_WM_STATE_ABOVE = XInternAtom(this->display, "_NET_WM_STATE_ABOVE", False); - this->xa_NET_WM_STATE_STICKY= XInternAtom(this->display, "_NET_WM_STATE_STICKY", False); - this->xa_NET_WM_STATE_FULLSCREEN = XInternAtom(this->display, "_NET_WM_STATE_FULLSCREEN", False); - this->xa_NET_WM_STATE_STAYS_ON_TOP = XInternAtom(this->display, "_NET_WM_STATE_STAYS_ON_TOP", False); - } -} - -static void set_fs_size_hint(sxfe_t *this) -{ - XSizeHints hint; - hint.flags = USSize | USPosition | PPosition | PSize; - hint.x = this->xinerama_x; - hint.y = this->xinerama_y; - hint.width = this->x.width; - hint.height = this->x.height; - XLockDisplay(this->display); - XSetNormalHints(this->display, this->window[1], &hint); - XUnlockDisplay(this->display); -} - -/* set_border - * - * Set/remove window border - * - */ -static void set_border(sxfe_t *this, Window window, int border) -{ - MWMHints mwmhints = { - .flags = MWM_HINTS_DECORATIONS, - .decorations = border ? 1 : 0, - }; - - if(this->window_id > 0) - return; - - XLockDisplay(this->display); - XChangeProperty(this->display, window, - this->xa_MOTIF_WM_HINTS, this->xa_MOTIF_WM_HINTS, 32, - PropModeReplace, (unsigned char *) &mwmhints, - PROP_MWM_HINTS_ELEMENTS); - XUnlockDisplay(this->display); -} - -static void set_fullscreen_props(sxfe_t *this) -{ - XEvent ev; - - if(this->window_id > 0) - return; - - set_fs_size_hint(this); - - /* no border in fullscreen window */ - set_border(this, this->window[1], 0); - - memset(&ev, 0, sizeof(ev)); - ev.type = ClientMessage; - ev.xclient.type = ClientMessage; - ev.xclient.message_type = this->xa_NET_WM_STATE; - ev.xclient.display = this->display; - ev.xclient.window = this->window[1]; - ev.xclient.format = 32; - ev.xclient.data.l[0] = 1; - /*ev.xclient.data.l[0] = this->atom_state_add;*/ - - /* _NET_WM_STATE_FULLSCREEN */ - XLockDisplay(this->display); - ev.xclient.data.l[1] = this->xa_NET_WM_STATE_FULLSCREEN; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); - XUnlockDisplay(this->display); - - /* _NET_WM_STATE_ABOVE */ - XLockDisplay(this->display); - ev.xclient.data.l[1] = this->xa_NET_WM_STATE_ABOVE; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); - XUnlockDisplay(this->display); - - /* _NET_WM_STATE_ON_TOP */ - XLockDisplay(this->display); - ev.xclient.data.l[1] = this->xa_NET_WM_STATE_STAYS_ON_TOP; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); - XUnlockDisplay(this->display); - - /* _NET_ACTIVE_WINDOW */ - XLockDisplay(this->display); - ev.xclient.message_type = this->xa_NET_ACTIVE_WINDOW; - ev.xclient.data.l[0] = 0; - ev.xclient.data.l[1] = 0; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); - XUnlockDisplay(this->display); -} - -static void update_window_title(sxfe_t *this) -{ - XLockDisplay(this->display); - - if (!this->x.keypress) { /* handler is set only in local mode */ - char *name = NULL; - if (XFetchName(this->display, this->window[0], &name) && name) { - char *newname = NULL; - if (strstr(name, " (top)")) - *strstr(name, " (top)") = 0; - if (this->stay_above) - if (asprintf(&newname, "%s (top)", name) < 0) - newname = NULL; - XStoreName(this->display, this->window[0], newname ?: name); - XStoreName(this->display, this->window[1], newname ?: name); - XFree(name); - free(newname); - } else { - XStoreName(this->display, this->window[0], this->stay_above ? "VDR - (top)" : "VDR"); - XStoreName(this->display, this->window[1], this->stay_above ? "VDR - (top)" : "VDR"); - } - } else { - XStoreName(this->display, this->window[0], this->stay_above ? "Local VDR (top)" : "Local VDR"); - XStoreName(this->display, this->window[1], this->stay_above ? "Local VDR (top)" : "Local VDR"); - } - XUnlockDisplay(this->display); -} - -static void set_above(sxfe_t *this, int stay_above) -{ - XEvent ev; - long propvalue[1]; - - if(this->window_id > 0) - return; - - if(this->stay_above != stay_above) { - this->stay_above = stay_above; - /* Update window title */ - update_window_title(this); - } - - memset(&ev, 0, sizeof(ev)); - ev.type = ClientMessage; - ev.xclient.type = ClientMessage; - ev.xclient.message_type = this->xa_NET_WM_STATE; - ev.xclient.display = this->display; - ev.xclient.window = this->window[0]; - ev.xclient.format = 32; - ev.xclient.data.l[0] = stay_above ? 1:0; /*this->atom_state_add : this->atom_state_del;*/ - - /* _NET_WM_STATE_ABOVE */ - XLockDisplay(this->display); - ev.xclient.data.l[1] = this->xa_NET_WM_STATE_ABOVE; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); - XUnlockDisplay(this->display); - - /* _NET_WM_STATE_STAYS_ON_TOP */ - XLockDisplay(this->display); - ev.xclient.data.l[1] = this->xa_NET_WM_STATE_STAYS_ON_TOP; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); - XUnlockDisplay(this->display); - - /* _NET_WM_STATE_STICKY */ - XLockDisplay(this->display); - ev.xclient.data.l[1] = this->xa_NET_WM_STATE_STICKY; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); - XUnlockDisplay(this->display); - - /* _WIN_LAYER */ - propvalue[0] = stay_above ? WIN_LAYER_ONTOP : WIN_LAYER_NORMAL; - XLockDisplay(this->display); - XChangeProperty(this->display, this->window[0], this->xa_WIN_LAYER, - XA_CARDINAL, 32, PropModeReplace, (unsigned char *)propvalue, - 1); - XUnlockDisplay(this->display); - -#if 0 - /* sticky */ - memset(&ev, 0, sizeof(ev)); - ev.xclient.type = ClientMessage; - ev.xclient.message_type = this->xa_WIN_STATE; - ev.xclient.display = this->display; - ev.xclient.window = this->window[0]; - ev.xclient.format = 32; - ev.xclient.data.l[0] = (1<<0); - ev.xclient.data.l[1] = (stay_above?(1<<0):0); - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); -#endif -#if 0 - /* on top */ - memset(&ev, 0, sizeof(ev)); - ev.xclient.type = ClientMessage; - ev.xclient.message_type = this->xa_WIN_LAYER; - ev.xclient.display = this->display; - ev.xclient.window = this->window[0]; - ev.xclient.format = 32; - ev.xclient.data.l[0] = (stay_above?10:6); - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask|SubstructureRedirectMask, &ev); -#endif -#if 0 - /* layer */ - XClientMessageEvent xev; - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.display = this->display; - xev.window = this->window[0]; - xev.message_type = this->xa_WIN_LAYER; - xev.format = 32; - xev.data.l[0] = 10; - xev.data.l[1] = CurrentTime; - XSendEvent(this->display, DefaultRootWindow(this->display), False, - SubstructureNotifyMask, (XEvent *) & xev); - - XMapRaised(this->display, this->window[0]); -#endif -#if 0 - xine_port_send_gui_data(this->video_port, XINE_GUI_SEND_DRAWABLE_CHANGED, - (void*) this->window[this->fullscreen ? 1 : 0]); -#endif -} - -/* - * set_cursor - * - * Disable mouse cursor in video window (set transparent cursor) - */ -static void set_cursor(Display *dpy, Window win, const int enable) -{ - if(enable) - XDefineCursor(dpy, win, None); - else { - /* no cursor */ - const char bm_no_data[] = { 0,0,0,0, 0,0,0,0 }; - Cursor no_ptr; - XColor black, dummy; - Pixmap bm_no = XCreateBitmapFromData(dpy, win, bm_no_data, 8, 8); - XAllocNamedColor(dpy, DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)), - "black", &black, &dummy); - no_ptr = XCreatePixmapCursor(dpy, bm_no, bm_no, &black, &black, 0, 0); - XDefineCursor(dpy, win, None); - XDefineCursor(dpy, win, no_ptr); - } -} - -static void update_xinerama_info(sxfe_t *this) -{ -#ifdef HAVE_XINERAMA - int screen = this->xinerama_screen; - this->xinerama_x = this->xinerama_y = 0; - XLockDisplay(this->display); - if(screen >= -1 && XineramaIsActive(this->display)) { - XineramaScreenInfo *screens; - int num_screens; - screens = XineramaQueryScreens(this->display, &num_screens); - if(screen >= num_screens) - screen = num_screens - 1; - if(screen == -1) { - const int x = this->origxpos + this->origwidth / 2; - const int y = this->origypos + this->origheight / 2; - for(screen = num_screens - 1; screen > 0; screen--) { - const int x0 = screens[screen].x_org; - const int y0 = screens[screen].y_org; - const int x1 = x0 + screens[screen].width; - const int y1 = y0 + screens[screen].height; - if(x0 <= x && x <= x1 && y0 <= y && y <= y1) - break; - } - } - if (screen < 0) - screen = 0; - this->xinerama_x = screens[screen].x_org; - this->xinerama_y = screens[screen].y_org; - this->x.width = screens[screen].width; - this->x.height = screens[screen].height; - - XFree(screens); - } - XUnlockDisplay(this->display); -#endif -} - -/* - * update_screen_size - * - * Update screen size (= size of fullscreen window) - */ -static void update_screen_size(sxfe_t *this) -{ - this->x.width = DisplayWidth(this->display, this->screen); - this->x.height = DisplayHeight(this->display, this->screen); - update_xinerama_info(this); -} - -/* - * HUD OSD stuff - */ - -#ifdef HAVE_XRENDER -static Xrender_Surf * xrender_surf_new(Display *dpy, Drawable draw, Visual *vis, - int w, int h, int alpha) -{ - Xrender_Surf *rs; - XRenderPictFormat *fmt; - XRenderPictureAttributes att; - - rs = calloc(1, sizeof (Xrender_Surf)); - - fmt = XRenderFindStandardFormat(dpy, alpha ? PictStandardARGB32 : PictStandardRGB24); - rs->w = w; - rs->h = h; - rs->depth = fmt->depth; - rs->vis = vis; - rs->draw = XCreatePixmap(dpy, draw, w, h, fmt->depth); - att.dither = 1; - att.component_alpha = 1; - att.repeat = 0; - rs->pic = XRenderCreatePicture(dpy, rs->draw, fmt, CPRepeat | CPDither | CPComponentAlpha, &att); - rs->allocated = 1; - return rs; -} - -static void xrender_surf_blend(Display *dpy, Xrender_Surf *src, Xrender_Surf *dst, - int x, int y, int w, int h, - XDouble scale_x, XDouble scale_y, int smooth) -{ - XTransform xf; - - if(!scale_x) - scale_x = 1; - if(!scale_y) - scale_y = 1; - - xf.matrix[0][0] = XDoubleToFixed(1.0 / scale_x); xf.matrix[0][1] = 0; xf.matrix[0][2] = 0; - xf.matrix[1][0] = 0; xf.matrix[1][1] = XDoubleToFixed(1.0 / scale_y); xf.matrix[1][2] = 0; - xf.matrix[2][0] = 0; xf.matrix[2][1] = 0; xf.matrix[2][2] = XDoubleToFixed(1.0); - XRenderSetPictureFilter(dpy, src->pic, smooth ? "bilinear" : "nearest", NULL, 0); - XRenderSetPictureTransform(dpy, src->pic, &xf); - x = (int)ceil((double)(x>0?x-1:0) * scale_x); - y = (int)ceil((double)(y>0?y-1:0) * scale_y); - w = (int)floor((double)(w+2) * scale_x); - h = (int)floor((double)(h+2) * scale_y); - XRenderComposite(dpy, PictOpSrc, src->pic, None, dst->pic, x, y, 0, 0, x, y, w, h); -} - -static Xrender_Surf * xrender_surf_adopt(Display *dpy, Drawable draw, Visual *vis, int w, int h) -{ - Xrender_Surf *rs; - XRenderPictFormat *fmt; - XRenderPictureAttributes att; - - rs = calloc(1, sizeof(Xrender_Surf)); - - fmt = XRenderFindVisualFormat(dpy, vis); - rs->w = w; - rs->h = h; - rs->depth = fmt->depth; - rs->vis = vis; - rs->draw = draw; - att.dither = 1; - att.component_alpha = 1; - att.repeat = 0; - rs->pic = XRenderCreatePicture(dpy, rs->draw, fmt, CPRepeat | CPDither | CPComponentAlpha, &att); - rs->allocated = 0; - return rs; -} - -static void xrender_surf_free(Display *dpy, Xrender_Surf *rs) -{ - if(rs->allocated) - XFreePixmap(dpy, rs->draw); - XRenderFreePicture(dpy, rs->pic); - free(rs); -} - -static Visual *find_argb_visual(Display *dpy, int scr) -{ - XVisualInfo *xvi, template; - int nvi, i; - XRenderPictFormat *format; - Visual *visual; - - template.screen = scr; - template.depth = 32; - template.class = TrueColor; - xvi = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | - VisualClassMask, &template, &nvi); - - if(!xvi) { - LOGERR("find_argb_visual: XGetVisualInfo failed (no xvi)"); - return 0; - } - - visual = 0; - for(i = 0; i < nvi; i++) { - LOGDBG("find_argb_visual: iteration %d of %d", i, nvi); - format = XRenderFindVisualFormat(dpy, xvi[i].visual); - if((format->type == PictTypeDirect) && format->direct.alphaMask) { - visual = xvi[i].visual; - break; - } - } - - XFree(xvi); - - if(!visual) - LOGERR("find_argb_visual: No visual found"); - - return visual; -} - -static void hud_fill_img_memory(uint32_t* dst, const struct osd_command_s *cmd) -{ - int i, pixelcounter = 0; - int idx = cmd->y * HUD_MAX_WIDTH + cmd->x; - - for(i = 0; i < cmd->num_rle; ++i) { - const uint8_t alpha = (cmd->palette + (cmd->data + i)->color)->alpha; - const uint8_t r = (cmd->palette + (cmd->data + i)->color)->r; - const uint8_t g = (cmd->palette + (cmd->data + i)->color)->g; - const uint8_t b = (cmd->palette + (cmd->data + i)->color)->b; - int j, finalcolor = 0; - finalcolor |= ((alpha << 24) & 0xFF000000); - finalcolor |= ((r << 16) & 0x00FF0000); - finalcolor |= ((g << 8) & 0x0000FF00); - finalcolor |= (b & 0x000000FF); - - for(j = 0; j < (cmd->data + i)->len; ++j) { - if(pixelcounter >= cmd->w) { - idx += HUD_MAX_WIDTH - pixelcounter; - pixelcounter = 0; - } - dst[idx++] = finalcolor; - ++pixelcounter; - } - } -} - -static int hud_osd_command(frontend_t *this_gen, struct osd_command_s *cmd) -{ - sxfe_t *this = (sxfe_t*)this_gen; - if(this && this->hud && cmd) { - XLockDisplay(this->display); - switch(cmd->cmd) { - case OSD_Nop: /* Do nothing ; used to initialize delay_ms counter */ - LOGDBG("HUD osd NOP"); - break; - - case OSD_Size: /* Set size of VDR OSD area */ - LOGDBG("HUD Set Size"); - this->osd_width = (cmd->w > 0) ? cmd->w : OSD_DEF_WIDTH; - this->osd_height = (cmd->h > 0) ? cmd->h : OSD_DEF_HEIGHT; - - XSetForeground(this->display, this->gc, 0x00000000); - XFillRectangle(this->display, this->surf_img->draw, this->gc, - 0, 0, this->osd_width+2, this->osd_height+2); - XFlush(this->display); - break; - - case OSD_Set_RLE: /* Create/update OSD window. Data is rle-compressed. */ - LOGDBG("HUD Set RLE"); - if (!(cmd->flags & OSDFLAG_TOP_LAYER)) - break; -#ifdef HAVE_XSHM - if(this->completion_event != -1) { - hud_fill_img_memory((uint32_t*)(this->hud_img->data), cmd); - if(!cmd->scaling) { - /* Place image directly onto hud window */ - XShmPutImage(this->display, this->hud_window, this->gc, this->hud_img, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1, - cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1, - False); - } else { - /* Place image onto Xrender surface which will be blended onto hud window */ - XShmPutImage(this->display, this->surf_img->draw, this->gc, this->hud_img, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1, - cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1, - False); - xrender_surf_blend(this->display, this->surf_img, this->surf_win, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1, - cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1, - (XDouble)this->x.width / (XDouble)this->osd_width, - (XDouble)this->x.height / (XDouble)this->osd_height, - (cmd->scaling & 2)); // Note: HUD_SCALING_BILINEAR=2 - } - } - else -#endif - { - hud_fill_img_memory(this->hud_img_mem, cmd); - if(!cmd->scaling) { - /* Place image directly onto hud window (always unscaled) */ - XPutImage(this->display, this->hud_window, this->gc, this->hud_img, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1, - cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1); - } else { - /* Place image onto Xrender surface which will be blended onto hud window */ - XPutImage(this->display, this->surf_img->draw, this->gc, this->hud_img, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1, - cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1); - xrender_surf_blend(this->display, this->surf_img, this->surf_win, - cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1, - cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1, - cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1, - (XDouble)this->x.width / (XDouble)this->osd_width, - (XDouble)this->x.height / (XDouble)this->osd_height, - (cmd->scaling & 2)); // Note: HUD_SCALING_BILINEAR=2 - } - } - break; - - case OSD_SetPalette: /* Modify palette of already created OSD window */ - LOGDBG("HUD osd SetPalette"); - break; - - case OSD_Move: /* Change x/y position of already created OSD window */ - LOGDBG("HUD osd Move"); - break; - - case OSD_Set_YUV: /* Create/update OSD window. Data is in YUV420 format. */ - LOGDBG("HUD osd set YUV"); - break; - - case OSD_Close: /* Close OSD window */ - LOGDBG("HUD osd Close"); - if (!(cmd->flags & OSDFLAG_TOP_LAYER)) - break; - XSetForeground(this->display, this->gc, 0x00000000); - XFillRectangle(this->display, this->hud_window, this->gc, - 0, 0, this->x.width, this->x.height); - XFillRectangle(this->display, this->surf_img->draw, this->gc, - 0, 0, this->osd_width+2, this->osd_height+2); - XFlush(this->display); - break; - - default: - LOGDBG("hud_osd_command: unknown osd command"); - break; - } - XUnlockDisplay(this->display); - } - return 1; -} - -static int hud_osd_open(sxfe_t *this) -{ - if(this && this->hud) { - int dummy; - - XLockDisplay(this->display); - - LOGDBG("opening HUD OSD window..."); - - if(!XRenderQueryExtension(this->display, &dummy, &dummy)) { - LOGMSG("hud_osd_open: ERROR: XRender extension not available."); - LOGMSG("XRender extension must be enabled in X configuration (xorg.conf etc.)"); - this->hud = 0; - XUnlockDisplay(this->display); - return 1; - } - - this->hud_vis = find_argb_visual(this->display, DefaultScreen(this->display)); - if(!this->hud_vis) { - LOGMSG("find_argb_visual() failed. HUD OSD disabled."); - this->hud = 0; - XUnlockDisplay(this->display); - return 1; - } - - Colormap hud_colormap = XCreateColormap(this->display, - RootWindow(this->display, DefaultScreen(this->display)), - this->hud_vis, AllocNone); - - XSetWindowAttributes attributes; - attributes.override_redirect = True; - attributes.background_pixel = 0x00000000; - attributes.border_pixel = 0; - attributes.colormap = hud_colormap; - attributes.backing_store = Always; - - this->hud_window = XCreateWindow(this->display, DefaultRootWindow(this->display), - this->x.xpos, this->x.ypos, - this->x.width, this->x.height, - 0, 32, InputOutput, this->hud_vis, - CWBackPixel | CWBorderPixel | - CWOverrideRedirect | CWColormap, - &attributes); - - XSelectInput(this->display, this->hud_window, - StructureNotifyMask | - ExposureMask | - KeyPressMask | - ButtonPressMask | - FocusChangeMask); - - XStoreName(this->display, this->hud_window, "HUD"); - this->gc = XCreateGC(this->display, this->hud_window, 0, NULL); - -#ifdef HAVE_XSHM - if(this->completion_event != -1) { - this->hud_img = XShmCreateImage(this->display, this->hud_vis, 32, ZPixmap, NULL, &(this->hud_shminfo), - HUD_MAX_WIDTH, HUD_MAX_HEIGHT); - - this->hud_shminfo.shmid = shmget(IPC_PRIVATE, this->hud_img->bytes_per_line * this->hud_img->height, - IPC_CREAT | 0777); - - this->hud_shminfo.shmaddr = this->hud_img->data = shmat(this->hud_shminfo.shmid, 0, 0); - this->hud_shminfo.readOnly = True; - - XShmAttach(this->display, &(this->hud_shminfo)); - } - else -#endif - { - /* Fall-back to traditional memory */ - LOGMSG("hud_osd_open: XShm not available, falling back to normal (slow) memory"); - this->hud_img_mem = malloc(4 * HUD_MAX_WIDTH * HUD_MAX_HEIGHT); - this->hud_img = XCreateImage(this->display, this->hud_vis, 32, ZPixmap, 0, (char*)this->hud_img_mem, - HUD_MAX_WIDTH, HUD_MAX_HEIGHT, 32, 0); - } - - this->surf_win = xrender_surf_adopt(this->display, this->hud_window, this->hud_vis, HUD_MAX_WIDTH, HUD_MAX_HEIGHT); - this->surf_img = xrender_surf_new(this->display, this->hud_window, this->hud_vis, HUD_MAX_WIDTH, HUD_MAX_HEIGHT, 1); - - XUnlockDisplay(this->display); - - this->fe.xine_osd_command = hud_osd_command; - } - return 1; -} - -/* - * hud_osd_resize - * - * - Move and resize HUD along with main or fullscreen window - */ -static void hud_osd_resize(sxfe_t *this, Window video_window, int width, int height) -{ - if(this->hud) { - if(video_window == this->window[0]) { - int hud_x, hud_y; - Window tmp_win; - XLockDisplay(this->display); - XTranslateCoordinates(this->display, this->window[0], - DefaultRootWindow(this->display), - 0, 0, &hud_x, &hud_y, &tmp_win); - XResizeWindow(this->display, this->hud_window, width, height); - XMoveWindow(this->display, this->hud_window, hud_x, hud_y); - set_cursor(this->display, this->hud_window, 1); - XUnlockDisplay(this->display); - } else if(video_window == this->window[1]) { - XLockDisplay(this->display); - XResizeWindow(this->display, this->hud_window, width, height); - XMoveWindow(this->display, this->hud_window, 0, 0); - set_cursor(this->display, this->hud_window, 0); - XUnlockDisplay(this->display); - } - } -} - -/* - * hud_osd_focus - * - * - show / hide HUD OSD window - */ -static void hud_osd_focus(sxfe_t *this, XFocusChangeEvent *fev) -{ - if(this && this->hud) - if(fev->window == this->window[0] || fev->window == this->window[1]) { - - XLockDisplay(this->display); - - if(fev->type == FocusIn) - /* Show HUD again if sxfe window receives focus */ - XMapWindow(this->display, this->hud_window); - - else if(fev->type == FocusOut) - /* Dismiss HUD window if focusing away from frontend window */ - XUnmapWindow(this->display, this->hud_window); - - XUnlockDisplay(this->display); - } -} - -static void hud_osd_close(sxfe_t *this) -{ - if(this && this->hud) { - XLockDisplay(this->display); - LOGDBG("closing hud window..."); - -#ifdef HAVE_XSHM - if(this->completion_event != -1) { - XShmDetach(this->display, &(this->hud_shminfo)); - XDestroyImage(this->hud_img); - shmdt(this->hud_shminfo.shmaddr); - shmctl(this->hud_shminfo.shmid, IPC_RMID, 0); - } - else -#endif - XDestroyImage(this->hud_img); - - if(this->surf_img) - xrender_surf_free(this->display, this->surf_img); - if(this->surf_win) - xrender_surf_free(this->display, this->surf_win); - - XDestroyWindow(this->display, this->hud_window); - XUnlockDisplay(this->display); - } -} -#endif /* HAVE_XRENDER */ - -/* - * disable_DPMS - */ -static void disable_DPMS(sxfe_t *this) -{ -#ifdef HAVE_XDPMS - int dpms_dummy; - XLockDisplay(this->display); - if (DPMSQueryExtension(this->display, &dpms_dummy, &dpms_dummy) && DPMSCapable(this->display)) { - CARD16 dpms_level; - DPMSInfo(this->display, &dpms_level, &this->dpms_state); - DPMSDisable(this->display); - } else { - LOGMSG("disable_DPMS: DPMS unavailable"); - } - XUnlockDisplay(this->display); -#endif -} - -/* - * open_display - * - * Try to connect to X server, in order - * 1) user-given display - * 2) DISPLAY environment variable - * 3) default display - * 4) :0.0 - * 5) 127.0.0.1:0.0 - */ -static int open_display(sxfe_t *this, const char *video_port) -{ - if (video_port && strlen(video_port)>2) { - if (!(this->display = XOpenDisplay(video_port))) - LOGERR("sxfe_display_open: failed to connect to X server (%s)", - video_port); - } - - if (!this->display) { - if (NULL!=(video_port=getenv("DISPLAY")) && !(this->display = XOpenDisplay(video_port))) - LOGERR("sxfe_display_open: failed to connect to X server (%s)", - video_port); - } - - if (!this->display) { - this->display = XOpenDisplay(NULL); - } - - if (!this->display) { - if (!(this->display = XOpenDisplay(":0.0"))) - LOGERR("sxfe_display_open: failed to connect to X server (:0.0)"); - } - - if (!this->display) { - if (!(this->display = XOpenDisplay("127.0.0.1:0.0"))) - LOGERR("sxfe_display_open: failed to connect to X server (127.0.0.1:0.0"); - } - - if (!this->display) { - LOGERR("sxfe_display_open: failed to connect to X server."); - LOGMSG("If X server is running, try running \"xhost +\" in xterm window"); - return 0; - } - - return 1; -} - -/* - * set_icon - */ -static void set_icon(sxfe_t *this) -{ -# include "vdrlogo_32x32.c" - XLockDisplay(this->display); -#if defined(__WORDSIZE) && (__WORDSIZE == 32) - /* Icon */ - XChangeProperty(this->display, this->window[0], - XInternAtom(this->display, "_NET_WM_ICON", False), - XA_CARDINAL, 32, PropModeReplace, - (unsigned char *) &vdrlogo_32x32, - 2 + vdrlogo_32x32.width*vdrlogo_32x32.height); -#else - long q[2+32*32]; - uint32_t *p = (uint32_t*)&vdrlogo_32x32; - int i; - for (i = 0; i < 2 + vdrlogo_32x32.width*vdrlogo_32x32.height; i++) - q[i] = p[i]; - XChangeProperty(this->display, this->window[0], - XInternAtom(this->display, "_NET_WM_ICON", False), - XA_CARDINAL, 32, PropModeReplace, - (unsigned char *) q, - 2 + vdrlogo_32x32.width*vdrlogo_32x32.height); -#endif - XUnlockDisplay(this->display); -} - -/* - * detect_display_ratio - * - * Calculate display aspect ratio - */ -static double detect_display_ratio(Display *dpy, int screen) -{ - double res_h = DisplayWidth (dpy, screen) * 1000.0 / DisplayWidthMM (dpy, screen); - double res_v = DisplayHeight (dpy, screen) * 1000.0 / DisplayHeightMM (dpy, screen); - - double display_ratio = res_v / res_h; - double diff = display_ratio - 1.0; - - if ((diff < 0.01) && (diff > -0.01)) - display_ratio = 1.0; - - LOGDBG("Display size : %d x %d mm", - DisplayWidthMM (dpy, screen), - DisplayHeightMM (dpy, screen)); - LOGDBG(" %d x %d pixels", - DisplayWidth (dpy, screen), - DisplayHeight (dpy, screen)); - LOGDBG(" %ddpi / %ddpi", - (int)(res_v/1000*25.4), (int)(res_h/1000*25.4)); - LOGDBG("Display ratio: %f/%f = %f", res_v, res_h, display_ratio); - - return display_ratio; -} - -/* - * create_windows - * - * Create and initialize fullscreen and windowed mode X11 windows - * - Borderless fullscreen window - * - Set window title and icon - */ -static void create_windows(sxfe_t *this) -{ - XLockDisplay(this->display); - /* create and display our video window */ - this->window[0] = XCreateSimpleWindow (this->display, - DefaultRootWindow(this->display), - this->x.xpos, this->x.ypos, - this->x.width, this->x.height, - 1, 0, 0); - this->window[1] = XCreateSimpleWindow(this->display, XDefaultRootWindow(this->display), - this->xinerama_x, this->xinerama_y, - this->x.width, this->x.height, - 0, 0, 0); - - /* full-screen window */ - set_fullscreen_props(this); - - /* Window hint */ - XClassHint *classHint = XAllocClassHint(); - if(classHint) { - classHint->res_name = "VDR"; - classHint->res_class = "VDR"; - XSetClassHint(this->display, this->window[0], classHint); - XSetClassHint(this->display, this->window[1], classHint); - XFree(classHint); - } - - /* Window name */ - const char *initial_title = (!this->x.keypress) ? "Connecting to VDR ..." : "Local VDR"; - XStoreName(this->display, this->window[0], initial_title); - XStoreName(this->display, this->window[1], initial_title); - - /* Icon */ - set_icon(this); - XUnlockDisplay(this->display); -} - -/* - * sxfe_display_open - * - * connect to X server, create windows - */ -static int sxfe_display_open(frontend_t *this_gen, - int xpos, int ypos, - int width, int height, int fullscreen, int hud, - int modeswitch, const char *modeline, int aspect, - fe_keypress_f keyfunc, int no_x_kbd, int gui_hotkeys, - const char *video_port, int scale_video, int field_order, - const char *aspect_controller, int window_id) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - if(this->display) - this->fe.fe_display_close(this_gen); - - if(keyfunc) { - this->x.keypress = keyfunc; - this->x.keypress("XKeySym", ""); /* triggers learning mode */ - } - - LOGDBG("sxfe_display_open(width=%d, height=%d, fullscreen=%d, display=%s)", - width, height, fullscreen, video_port); - - if(hud) { -#ifdef HAVE_XRENDER - LOGDBG("sxfe_display_open: Enabling HUD OSD"); - this->hud = hud; - this->osd_width = OSD_DEF_WIDTH; - this->osd_height = OSD_DEF_HEIGHT; -#else - LOGMSG("sxfe_display_open: Application was compiled without XRender support. HUD OSD disabled."); -#endif - } - - this->x.xpos = xpos; - this->x.ypos = ypos; - this->x.width = width; - this->x.height = height; - this->x.aspect = aspect; -/*this->x.cropping = 0;*/ - this->x.overscan = 0; - this->x.scale_video = scale_video; - this->x.field_order = field_order ? 1 : 0; - this->x.aspect_controller = aspect_controller ? strdup(aspect_controller) : NULL; - - this->origxpos = 0; - this->origypos = 0; - this->origwidth = width>0 ? width : OSD_DEF_WIDTH; - this->origheight = height>0 ? height : OSD_DEF_HEIGHT; - - this->check_move = 0; - this->dragging = 0; - this->dragging_x = 0; - this->dragging_y = 0; - - this->fullscreen = fullscreen; -/*this->vmode_switch = modeswitch;*/ - this->fullscreen_state_forced = 0; -/*this->modeline = strdup(modeline ?: "");*/ - this->window_id = window_id; - - this->xinerama_screen = -1; - - this->gui_hotkeys = gui_hotkeys; - this->no_x_kbd = no_x_kbd ? 1 : 0; - - /* - * init x11 stuff - */ - - if (!XInitThreads ()) { - LOGERR("sxfe_display_open: XInitThreads failed"); - free(this); - return 0; - } - - if (!open_display(this, video_port)) - return 0; - - XLockDisplay (this->display); - - this->screen = DefaultScreen(this->display); - - /* #warning sxfe_display_open: TODO: switch vmode */ - - /* completion event */ - this->completion_event = -1; -#ifdef HAVE_XSHM - if (XShmQueryExtension (this->display) == True) { - this->completion_event = XShmGetEventBase (this->display) + ShmCompletion; - } -#endif - - init_atoms(this); - - if(fullscreen) - update_screen_size(this); - - /* Output to existing window ? (embedded to another app) */ - if(this->window_id > 0) { - LOGMSG("sxfe_display_open(): Using X11 window %d for output", this->window_id); - this->window[0] = this->window[1] = (Window)this->window_id; - XUnmapWindow(this->display, this->window[0]); - } else { - create_windows(this); - } - - /* Select input */ - XSelectInput (this->display, this->window[0], - StructureNotifyMask | - ExposureMask | - KeyPressMask | - ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | - FocusChangeMask); - XSelectInput (this->display, this->window[1], - StructureNotifyMask | - ExposureMask | - KeyPressMask | - ButtonPressMask | - FocusChangeMask); - - /* Map current window */ - XMapRaised (this->display, this->window[this->fullscreen ? 1 : 0]); - XMoveWindow(this->display, this->window[0], this->x.xpos, this->x.ypos); - - /* determine display aspect ratio */ - this->x.display_ratio = detect_display_ratio(this->display, this->screen); - - /* we want to get notified if user closes the window */ - XSetWMProtocols(this->display, this->window[this->fullscreen ? 1 : 0], &(this->xa_WM_DELETE_WINDOW), 1); - - /* Hide cursor */ - if(this->window_id <= 0) - set_cursor(this->display, this->window[1], 0); - - /* No screen saver */ - /* #warning TODO: suspend --> activate blank screen saver / DPMS display off ? */ - XSetScreenSaver(this->display, 0, 0, DefaultBlanking, DefaultExposures); - - /* Disable DPMS */ - disable_DPMS(this); - -#ifdef HAVE_DBUS_GLIB_1 - /* Disable GNOME screensaver */ - gnome_screensaver_control(0); -#endif - - /* setup xine visual type */ - this->x.xine_visual_type = XINE_VISUAL_TYPE_X11; - this->x.vis_x11.display = this->display; - this->x.vis_x11.screen = this->screen; - this->x.vis_x11.d = this->window[this->fullscreen ? 1 : 0]; - this->x.vis_x11.dest_size_cb = sxfe_dest_size_cb; - this->x.vis_x11.frame_output_cb = this->x.frame_output_handler; - this->x.vis_x11.user_data = this; - - set_fullscreen_props(this); - - XUnlockDisplay (this->display); -#ifdef HAVE_XRENDER - return hud_osd_open(this); -#else - return 1; -#endif -} - -/* - * sxfe_display_config - * - * configure windows - */ -static int sxfe_display_config(frontend_t *this_gen, - int xpos, int ypos, - int width, int height, int fullscreen, - int modeswitch, const char *modeline, - int aspect, int scale_video, - int field_order) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - if(this->fullscreen_state_forced) - fullscreen = this->fullscreen ? 1 : 0; - - if(!fullscreen && (this->x.width != width || this->x.height != height)) { - this->x.width = width; - this->x.height = height; - - XLockDisplay(this->display); - XResizeWindow(this->display, this->window[0], this->x.width, this->x.height); - XUnlockDisplay(this->display); - if(!fullscreen && !this->fullscreen) - xine_port_send_gui_data(this->x.video_port, XINE_GUI_SEND_DRAWABLE_CHANGED, - (void*) this->window[0]); - } - - if(fullscreen) - update_screen_size(this); - - if(fullscreen != this->fullscreen) { - Window tmp_win; - int tmp_x, tmp_y; - XLockDisplay(this->display); - XUnmapWindow(this->display, this->window[this->fullscreen ? 1 : 0]); - this->fullscreen = fullscreen ? 1 : 0; - if(fullscreen) - set_fullscreen_props(this); - else - set_above(this, this->stay_above); - XMapRaised(this->display, this->window[this->fullscreen ? 1 : 0]); - if(!fullscreen) { - XResizeWindow(this->display, this->window[0], this->x.width, this->x.height); - XMoveWindow(this->display, this->window[0], this->x.xpos, this->x.ypos); - LOGDBG("sxfe_display_config: XMoveWindow called with x=%d and y=%d", - this->x.xpos, this->x.ypos); - this->check_move = 1; - set_above(this, this->stay_above); - } else { - set_fullscreen_props(this); - XResizeWindow(this->display, this->window[1], this->x.width, this->x.height); - XMoveWindow(this->display, this->window[1], this->xinerama_x, this->xinerama_y); - } - XSync(this->display, False); - if(XTranslateCoordinates(this->display, this->window[this->fullscreen ? 1 : 0], - DefaultRootWindow(this->display), - 0, 0, &tmp_x, &tmp_y, &tmp_win)) { - this->x.xpos = tmp_x; - this->x.ypos = tmp_y; - } - XUnlockDisplay(this->display); - xine_port_send_gui_data(this->x.video_port, XINE_GUI_SEND_DRAWABLE_CHANGED, - (void*) this->window[this->fullscreen ? 1 : 0]); - } - -#if 0 - if(!modeswitch && strcmp(modeline, this->modeline)) { - free(this->modeline); - this->modeline = strdup(modeline ?: ""); - /* #warning TODO - switch vmode */ - } -#endif - -/*this->vmode_switch = modeswitch;*/ - this->x.aspect = aspect; - this->x.scale_video = scale_video; - this->x.field_order = field_order ? 1 : 0; - - return 1; -} - -static void sxfe_toggle_fullscreen(fe_t *this_gen) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - int force = this->fullscreen_state_forced; - this->fullscreen_state_forced = 0; - - if(!this->fullscreen) { - this->origwidth = this->x.width; - this->origheight = this->x.height; - this->origxpos = this->x.xpos; - this->origypos = this->x.ypos; - } else { - this->x.xpos = this->origxpos; - this->x.ypos = this->origypos; - } - - this->fe.fe_display_config((frontend_t*)this, -1, -1, this->origwidth, this->origheight, - this->fullscreen ? 0 : 1, - 0/*this->vmode_switch*/, NULL/*this->modeline*/, - this->x.aspect, this->x.scale_video, this->x.field_order); - - this->fullscreen_state_forced = !force; -} - -/* - * X event loop - */ - -/* - * sxfe_interrupt - * - * - Interrupt X event loop (sxfe_run) - * - */ -static void sxfe_interrupt(frontend_t *this_gen) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - XClientMessageEvent event = { - .type = ClientMessage, - .display = this->display, - .window = this->window[this->fullscreen ? 1 : 0], - .message_type = this->xa_SXFE_INTERRUPT, - .format = 32, - }; - XLockDisplay (this->display); - if(!XSendEvent(event.display, event.window, 1, /*KeyPressMask*/0, (XEvent *)&event)) - LOGERR("sxfe_interrupt: XSendEvent(ClientMessage) FAILED\n"); - - XFlush(this->display); - XUnlockDisplay (this->display); -} - -/* - * XKeyEvent handler - * - */ -static void XKeyEvent_handler(sxfe_t *this, XKeyEvent *kev) -{ - if(kev->keycode) { - KeySym ks; - char buffer[20]; - XComposeStatus status; - const char *fe_event = NULL; - - XLockDisplay (this->display); - XLookupString(kev, buffer, sizeof(buffer), &ks, &status); - XUnlockDisplay (this->display); - - switch(ks) { - case XK_f: - case XK_F: - if (this->gui_hotkeys) - fe_event = "TOGGLE_FULLSCREEN"; - break; - case XK_d: - case XK_D: - if (this->gui_hotkeys) - fe_event = "TOGGLE_DEINTERLACE"; - break; - case XK_Escape: - if (!this->x.keypress) /* ESC exits only in remote mode */ - fe_event = "QUIT"; - break; - default:; - } - if (fe_event) - this->x.fe.send_event((frontend_t*)this, fe_event); - else if (!this->no_x_kbd) - this->x.fe.send_input_event((frontend_t*)this, "XKeySym", XKeysymToString(ks), 0, 0); - } -} - -/* - * XConfigureEvent handler - * - */ -static void XConfigureEvent_handler(sxfe_t *this, XConfigureEvent *cev) -{ - /* Move and resize HUD along with main or fullscreen window */ -#ifdef HAVE_XRENDER - if(this->hud) - hud_osd_resize(this, cev->window, cev->width, cev->height); -#endif - - /* update video window size */ - this->x.width = cev->width; - this->x.height = cev->height; - - if(this->window[0] == cev->window && this->check_move) { - LOGDBG("ConfigureNotify reveived with x=%d, y=%d, check_move=%d", - cev->x, cev->y, this->check_move); - this->check_move = 0; - if(this->x.xpos != cev->x && this->x.ypos != cev->y) { - XLockDisplay (this->display); - XMoveWindow(this->display, this->window[0], cev->x, cev->y); - XUnlockDisplay (this->display); - } - } - - if ((cev->x == 0) && (cev->y == 0)) { - if(!this->fullscreen) { - int tmp_x, tmp_y; - Window tmp_win; - XLockDisplay(this->display); - if(XTranslateCoordinates(this->display, cev->window, - DefaultRootWindow(this->display), - 0, 0, &tmp_x, &tmp_y, &tmp_win)) { - this->x.xpos = tmp_x; - this->x.ypos = tmp_y; - } - XUnlockDisplay(this->display); - } - } else { - if(!this->fullscreen) { - /* update video window position */ - this->x.xpos = cev->x; - this->x.ypos = cev->y; - } - } -} - -/* - * XMotionEvent handler - * - * Track mouse movement when Button1 is pressed down - * - enable window dragging: user can simply drag window around screen - * - useful when window is borderless (no title bar) - */ -static void XMotionEvent_handler(sxfe_t *this, XMotionEvent *mev) -{ - if(this->dragging && !this->fullscreen) { - Window tmp_win; - int xpos, ypos; - - XLockDisplay(this->display); - - while(XCheckMaskEvent(this->display, ButtonMotionMask, (XEvent*)mev)); - - XTranslateCoordinates(this->display, this->window[0], - DefaultRootWindow(this->display), - 0, 0, &xpos, &ypos, &tmp_win); - - this->x.xpos = (xpos += mev->x_root - this->dragging_x); - this->x.ypos = (ypos += mev->y_root - this->dragging_y); - this->dragging_x = mev->x_root; - this->dragging_y = mev->y_root; - - XMoveWindow(this->display, this->window[0], xpos, ypos); - LOGDBG("MotionNotify: XMoveWindow called with x=%d and y=%d", xpos, ypos); - - XUnlockDisplay(this->display); - } -} - -/* - * XButtonEvent handler - * - * - Double click switches between windowed and fullscreen mode - * - Window can be moved by dragging it - * - Right mouse button switches window state: - * normal window -> borderless window -> always on top -> ... - */ -static void XButtonEvent_handler(sxfe_t *this, XButtonEvent *bev) -{ - switch(bev->button) { - case Button1: - /* Double-click toggles between fullscreen and windowed mode */ - if(bev->time - this->prev_click_time < DOUBLECLICK_TIME) { - /* Toggle fullscreen */ - sxfe_toggle_fullscreen((fe_t*)this); - this->prev_click_time = 0; /* don't react to third click ... */ - } else { - this->prev_click_time = bev->time; - if(!this->fullscreen && this->no_border && !this->dragging) { - /* start dragging window */ - this->dragging = 1; - this->dragging_x = bev->x_root; - this->dragging_y = bev->y_root; - } - } - break; - - case Button3: - /* Toggle border and stacking */ - if(!this->fullscreen) { - if(!this->stay_above) { - set_above(this, 1); - } else if(!this->no_border) { - set_border(this, this->window[0], 0); - this->no_border = 1; - } else { - set_border(this, this->window[0], 1); - this->no_border = 0; - set_above(this, 0); - } - } - break; - } -} - -/* - * sxfe_run - * - * - main X event loop - */ -static int sxfe_run(frontend_t *this_gen) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - /* poll X server (connection socket). - * (XNextEvent will block until events are queued). - * We want to use timeout, blocking for long time usually causes vdr - * watchdog to emergency exit ... - */ - if (! XPending(this->display)) { - struct pollfd pfd = { - .fd = ConnectionNumber(this->display), - .events = POLLIN, - }; - if (poll(&pfd, 1, 50) < 1 || !(pfd.revents & POLLIN)) { - return 1; - } - } - - while (XPending(this->display) > 0) { - - XEvent event; - - XLockDisplay (this->display); - XNextEvent (this->display, &event); - XUnlockDisplay (this->display); - - switch (event.type) { - case Expose: - if (event.xexpose.count == 0) - xine_port_send_gui_data (this->x.video_port, XINE_GUI_SEND_EXPOSE_EVENT, &event); - break; - - case ConfigureNotify: - XConfigureEvent_handler(this, (XConfigureEvent *) &event); - break; - -#ifdef HAVE_XRENDER - case FocusIn: - case FocusOut: - hud_osd_focus(this, (XFocusChangeEvent *) &event); - break; -#endif - - case ButtonRelease: - this->dragging = 0; - break; - - case MotionNotify: - XMotionEvent_handler(this, (XMotionEvent *) &event); - break; - - case ButtonPress: - XButtonEvent_handler(this, (XButtonEvent *) &event); - break; - - case KeyPress: - case KeyRelease: - XKeyEvent_handler(this, (XKeyEvent *) &event); - break; - - case ClientMessage: - { - XClientMessageEvent *cmessage = (XClientMessageEvent *) &event; - if ( cmessage->message_type == this->xa_SXFE_INTERRUPT ) - LOGDBG("ClientMessage: sxfe_interrupt"); - - if ( cmessage->data.l[0] == this->xa_WM_DELETE_WINDOW ) { - /* we got a window deletion message from out window manager.*/ - LOGDBG("ClientMessage: WM_DELETE_WINDOW"); - - this->x.fe.send_event((frontend_t*)this, "QUIT"); - } - break; - } - } - - if (event.type == this->completion_event) - xine_port_send_gui_data (this->x.video_port, XINE_GUI_SEND_COMPLETION_EVENT, &event); - } - - return !this->x.fe.xine_is_finished((frontend_t*)this, 0); -} - -static void sxfe_display_close(frontend_t *this_gen) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - if(!this) - return; - - if(this->x.xine) - this->fe.xine_exit(this_gen); - - if(this->display) { - -#ifdef HAVE_XRENDER - hud_osd_close(this); -#endif - -#ifdef HAVE_DBUS_GLIB_1 - /* Restore GNOE screensaver */ - gnome_screensaver_control(1); -#endif - -#ifdef HAVE_XDPMS - if(this->dpms_state) - DPMSEnable(this->display); -#endif - if(this->window_id <= 0) { - XLockDisplay(this->display); - XUnmapWindow(this->display, this->window[this->fullscreen ? 1 : 0]); - XDestroyWindow(this->display, this->window[0]); - XDestroyWindow(this->display, this->window[1]); - XUnlockDisplay(this->display); - } - XCloseDisplay (this->display); - this->display = NULL; - } - - free(this->x.aspect_controller); - this->x.aspect_controller = NULL; -#if 0 - free(this->modeline); - this->modeline = NULL; -#endif -} - -/* - * sxfe_xine_open - * - * Override fe_xine_open: - * - Set window name: append remote host address to title bar text - */ -static int sxfe_xine_open(frontend_t *this_gen, const char *mrl) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - int result = this->fe_xine_open(this_gen, mrl); - - if(result && mrl && !strncmp(mrl, MRL_ID, MRL_ID_LEN) && strstr(mrl, "//")) { - char *name = NULL, *end; - if (asprintf(&name, "VDR - %s", strstr(mrl, "//")+2) >= 0) { - if (NULL != (end = strstr(name, ":37890")) || /* hide only default port */ - NULL != (end = strchr(name, '#'))) /* hide attributes */ - *end = 0; - XStoreName(this->display, this->window[0], name); - XStoreName(this->display, this->window[1], name); - free(name); - } - } - - return result; -} - -static int sxfe_xine_play(frontend_t *this_gen) -{ - sxfe_t *this = (sxfe_t*)this_gen; - - int result = this->fe_xine_play(this_gen); - -#ifdef HAVE_XRENDER - if (result && this->x.input_plugin && this->hud) { - LOGDBG("sxfe_xine_play: Enabling HUD OSD"); - this->x.input_plugin->f.fe_handle = this_gen; - this->x.input_plugin->f.intercept_osd = hud_osd_command; - } -#endif /* HAVE_XRENDER */ - - return result; -} - -static frontend_t *sxfe_get_frontend(void) -{ - sxfe_t *this = calloc(1, sizeof(sxfe_t)); - - init_fe((fe_t*)this); - - this->window_id = -1; - - this->fe.fe_display_open = sxfe_display_open; - this->fe.fe_display_config = sxfe_display_config; - this->fe.fe_display_close = sxfe_display_close; - - this->fe.fe_run = sxfe_run; - this->fe.fe_interrupt = sxfe_interrupt; - - this->x.toggle_fullscreen_cb = sxfe_toggle_fullscreen; - - /* override */ - - this->fe_xine_open = this->fe.xine_open; - this->fe_xine_play = this->fe.xine_play; - - this->fe.xine_open = sxfe_xine_open; - this->fe.xine_play = sxfe_xine_play; - - return (frontend_t*)this; -} - -/* ENTRY POINT */ -const fe_creator_f fe_creator __attribute__((visibility("default"))) = sxfe_get_frontend; - - - diff --git a/xineliboutput.c b/xineliboutput.c deleted file mode 100644 index fbd5b1b4..00000000 --- a/xineliboutput.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * vdr-xineliboutput: xine-lib based output device plugin for VDR - * - * Copyright (C) 2003-2008 Petri Hintukainen <phintuka@users.sourceforge.net> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * xineliboutput.c: VDR Plugin interface - * - * $Id: xineliboutput.c,v 1.38 2009-03-12 17:29:13 rofafor Exp $ - * - */ - -#include "features.h" - -#include <vdr/plugin.h> -#include <vdr/i18n.h> - -#include "logdefs.h" -#include "config.h" -#include "device.h" -#include "setup_menu.h" -#include "menu.h" -#include "media_player.h" - -#if defined(APIVERSNUM) && (APIVERSNUM < 10600) -# error VDR API versions < 1.6.0 are not supported ! -#endif - -//---------------------------------plugin------------------------------------- - -static const char *VERSION = "1.0.90-cvs"; -static const char *DESCRIPTION = trNOOP("X11/xine-lib output plugin"); -static const char *MAINMENUENTRY = trNOOP("Media Player"); - -cOsdObject *g_PendingMenuAction = NULL; - -class cPluginXinelibOutput : public cPlugin -{ - private: - // Add any member variables or functions you may need here. - - public: - cPluginXinelibOutput(void); - virtual ~cPluginXinelibOutput(); - - virtual const char *Version(void) { return VERSION; } - 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 bool Start(void); - virtual void Stop(void); - //virtual void Housekeeping(void); - virtual void MainThreadHook(); - //virtual cString Active(void); - //virtual time_t WakeupTime(void); - - virtual const char *MainMenuEntry(void) { return xc.hide_main_menu ? NULL : tr(MAINMENUENTRY); } - 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 = NULL); - virtual const char **SVDRPHelpPages(void); - virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); -}; - -cPluginXinelibOutput::cPluginXinelibOutput(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! -} - -cPluginXinelibOutput::~cPluginXinelibOutput() -{ - // Clean up after yourself! - cXinelibDevice::Dispose(); -} - - -const char cmdLineHelp[] = -" -l NAME --local=NAME Use local frontend NAME\n" -" Supported frontends:\n" -" sxfe (X11)\n" -" fbfe (framebuffer)\n" -" none (only remote frontends)\n" -" -r PORT --remote=PORT Listen PORT for remote clients\n" -" (default "LISTEN_PORT_S")\n" -" none or 0 disables remote mode\n" -" Also local interface address can be specified:\n" -" --remote=<ip>:<port> (default is all interfaces)\n" -" -A NAME --audio=NAME Use audio driver NAME for local frontend\n" -" Supported values:\n" -" auto, alsa, oss, esound, none\n" -" -V NAME --video=NAME Use video driver NAME for local frontend\n" -" Supported values:\n" -" for sxfe: auto, x11, xshm, xv, xvmc, xxmc,\n" -" vidix, sdl, opengl, none\n" -" for fbfe: auto, fb, DirectFB, vidixfb,\n" -" sdl, dxr3, aadxr3, none\n" -#if 0 -" -m M --modeline=M Use modeline M for local frontend\n" -" (example: )\n" -#endif -" -f --fullscreen Fullscreen mode (X11)\n" -#ifdef HAVE_XRENDER -" -D --hud Head Up Display OSD (X11)\n" -#endif -" -w --width=x Window width\n" -" -h --height=x Window width\n" -" -d DISP --display=DISP Use X11 display DISP\n" -" (or framebuffer device name)\n" -" -P NAME --post=NAME Use xine post plugin NAME\n" -" format: pluginname[:arg=val[,arg=val]][,...]\n" -" example: \n" -" --post=upmix;tvtime:enabled=1,cheap_mode=1\n" -" -p --primary Force xineliboutput to be primary device when\n" -" there are active frontend(s)\n" -" -c --exit-on-close Exit vdr when local frontend window is closed\n" -; - -const char *cPluginXinelibOutput::CommandLineHelp(void) -{ - // Return a string that describes all known command line options. - return cmdLineHelp; -} - -bool cPluginXinelibOutput::ProcessArgs(int argc, char *argv[]) -{ - // Implement command line argument processing here if applicable. - return xc.ProcessArgs(argc, argv); -} - -bool cPluginXinelibOutput::Initialize(void) -{ - // Initialize any background activities the plugin shall perform. - TRACEF("cPluginXinelibOutput::Initialize"); - - cXinelibDevice::Instance(); - return true; -} - -bool cPluginXinelibOutput::Start(void) -{ - // Start any background activities the plugin shall perform. - TRACEF("cPluginXinelibOutput::Start"); - return cXinelibDevice::Instance().StartDevice(); -} - -void cPluginXinelibOutput::MainThreadHook(void) -{ - TRACEF("cPluginXinelibOutput::MainThreadHook"); - return cXinelibDevice::Instance().MainThreadHook(); -} - -void cPluginXinelibOutput::Stop(void) -{ - // Start any background activities the plugin shall perform. - TRACEF("cPluginXinelibOutput::Stop"); - return cXinelibDevice::Instance().StopDevice(); -} - -cOsdObject *cPluginXinelibOutput::MainMenuAction(void) -{ - // Perform the action when selected from the main VDR menu. - TRACEF("cPluginXinelibOutput::MainMenuAction"); - - if(xc.main_menu_mode == CloseOsd) { - xc.main_menu_mode = ShowMenu; - return NULL; - } - - if(g_PendingMenuAction) { - cOsdObject *tmp = g_PendingMenuAction; - g_PendingMenuAction = NULL; - return tmp; - } - - if(xc.hide_main_menu) - return NULL; - -#ifdef HAVE_XV_FIELD_ORDER - xc.field_order = xc.field_order ? 0 : 1; - cXinelibDevice::Instance().ConfigureWindow(xc.fullscreen, xc.width, xc.height, - xc.modeswitch, xc.modeline, xc.display_aspect, - xc.scale_video, xc.field_order); -#endif - return new cMenuXinelib(); -} - -cMenuSetupPage *cPluginXinelibOutput::SetupMenu(void) -{ - // Return a setup menu in case the plugin supports one. - TRACEF("cPluginXinelibOutput::SetupMenu"); - return new cMenuSetupXinelib(); -} - -bool cPluginXinelibOutput::SetupParse(const char *Name, const char *Value) -{ - // Parse your own setup parameters and store their values. - return xc.SetupParse(Name, Value); -} - -bool cPluginXinelibOutput::Service(const char *Id, void *Data) -{ - if(Id) { - char *CData = (char*)Data; - - if(!strcmp(Id, "MediaPlayer-1.0")) { - if(CData && *CData) { - LOGMSG("Service(%s, %s)", Id, CData); - cControl::Launch(new cXinelibPlayerControl(ShowFiles, CData)); - return true; - } - LOGMSG("Service(%s) -> true", Id); - return true; - } - - else if(!strcmp(Id, "MusicPlayer-1.0")) { - if(CData && *CData) { - LOGMSG("Service(%s, %s)", Id, CData); - cControl::Launch(new cXinelibPlayerControl(ShowMusic, CData)); - return true; - } - LOGMSG("Service(%s) -> true", Id); - return true; - } - - else if(!strcmp(Id, "DvdPlayer-1.0")) { - if(Data && *CData) { - LOGMSG("Service(%s, %s)", Id, CData); - cControl::Launch(new cXinelibDvdPlayerControl(CData)); - return true; - } - LOGMSG("Service(%s) -> true", Id); - return true; - } - - else if(!strcmp(Id, "ImagePlayer-1.0")) { - if(CData && *CData) { - LOGMSG("Service(%s, %s)", Id, CData); - char **list = new char*[2]; - list[0] = strdup(CData); - list[1] = NULL; - cControl::Launch(new cXinelibImagesControl(list, 0, 1)); - return true; - } - LOGMSG("Service(%s) -> true", Id); - return true; - } - - } - return false; -} - -const char **cPluginXinelibOutput::SVDRPHelpPages(void) -{ - static const char *HelpPages[] = { - "PMDA <file>\n" - " Play media file.", - "PDVD <file>\n" - " Play DVD disc.", - "PMSC <file>\n" - " Play music file.", - "PIMG <file>\n" - " Play/show image file.", - "QMSC <file>\n" - " Queue music file to playlist.", - NULL - }; - return HelpPages; -} - -cString cPluginXinelibOutput::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) -{ - if(strcasecmp(Command, "PMDA") == 0) { - if(*Option) { - LOGMSG("SVDRP(%s, %s)", Command, Option); - cControl::Launch(new cXinelibPlayerControl(ShowFiles, Option)); - return cString("Playing video file"); - } else { - ReplyCode = 550; // Requested action not taken - } - } - - else if(strcasecmp(Command, "PDVD") == 0) { - if(*Option) { - LOGMSG("SVDRP(%s, %s)", Command, Option); - cControl::Launch(new cXinelibDvdPlayerControl(Option)); - return cString("Playing DVD disc"); - } else { - ReplyCode = 550; // Requested action not taken - } - } - - else if(strcasecmp(Command, "PMSC") == 0) { - if(*Option) { - LOGMSG("SVDRP(%s, %s)", Command, Option); - cControl::Launch(new cXinelibPlayerControl(ShowMusic, Option)); - return cString("Playing music file"); - } else { - ReplyCode = 550; // Requested action not taken - } - } - - else if(strcasecmp(Command, "PIMG") == 0) { - if(*Option) { - char **list = new char*[2]; - list[0] = strdup(Option); - list[1] = NULL; - LOGMSG("SVDRP(%s, %s)", Command, Option); - cControl::Launch(new cXinelibImagesControl(list, 0, 1)); - return cString("Showing image file"); - } else { - ReplyCode = 550; // Requested action not taken - } - } - - else if(strcasecmp(Command, "QMSC") == 0) { - if(*Option) { - LOGMSG("SVDRP(%s, %s)", Command, Option); - cXinelibPlayerControl::Queue(Option); - return cString("Queueing music file"); - } else { - ReplyCode = 550; // Requested action not taken - } - } - - return NULL; -} - -extern "C" -void *VDRPluginCreator(void) __attribute__((visibility("default"))); - -VDRPLUGINCREATOR(cPluginXinelibOutput); // Don't touch this! |