From c47666d42f7972e1b51f9de61ce0fa27c72f3127 Mon Sep 17 00:00:00 2001 From: austriancoder Date: Thu, 5 Aug 2004 23:05:21 +0000 Subject: initial import --- COPYING | 340 ++++++++++++ HISTORY | 230 ++++++++ INSTALL | 18 + Makefile | 97 ++++ README | 14 + dxr3.c | 189 +++++++ dxr3.h | 107 ++++ dxr3audiodecoder.c | 296 ++++++++++ dxr3audiodecoder.h | 53 ++ dxr3blackframe.c | 1286 +++++++++++++++++++++++++++++++++++++++++++ dxr3colormanager.c | 378 +++++++++++++ dxr3colormanager.h | 122 ++++ dxr3configdata.c | 16 + dxr3configdata.h | 76 +++ dxr3cpu.c | 127 +++++ dxr3cpu.h | 107 ++++ dxr3demuxdevice.c | 662 ++++++++++++++++++++++ dxr3demuxdevice.h | 75 +++ dxr3device.c | 472 ++++++++++++++++ dxr3device.h | 65 +++ dxr3ffmpeg.c | 72 +++ dxr3ffmpeg.h | 42 ++ dxr3generaldefines.h | 37 ++ dxr3i18n.c | 804 +++++++++++++++++++++++++++ dxr3i18n.h | 12 + dxr3interface.c | 1072 ++++++++++++++++++++++++++++++++++++ dxr3interface.h | 136 +++++ dxr3interface_spu_encoder.c | 620 +++++++++++++++++++++ dxr3interface_spu_encoder.h | 153 +++++ dxr3log.c | 60 ++ dxr3log.h | 94 ++++ dxr3memcpy.c | 421 ++++++++++++++ dxr3memcpy.h | 74 +++ dxr3multichannelaudio.c | 645 ++++++++++++++++++++++ dxr3multichannelaudio.h | 33 ++ dxr3nextpts.c | 4 + dxr3nextpts.h | 42 ++ dxr3osd.c | 161 ++++++ dxr3osd.h | 42 ++ dxr3osd_subpicture.c | 174 ++++++ dxr3osd_subpicture.h | 29 + dxr3outputthread.c | 279 ++++++++++ dxr3outputthread.h | 71 +++ dxr3palettemanager.c | 114 ++++ dxr3palettemanager.h | 39 ++ dxr3pesframe.c | 226 ++++++++ dxr3pesframe.h | 158 ++++++ dxr3singleton.h | 43 ++ dxr3spudecoder.c | 628 +++++++++++++++++++++ dxr3spudecoder.h | 138 +++++ dxr3syncbuffer.c | 420 ++++++++++++++ dxr3syncbuffer.h | 123 +++++ dxr3sysclock.c | 49 ++ dxr3sysclock.h | 36 ++ dxr3tools.h | 82 +++ dxr3unixserversocket.c | 190 +++++++ dxr3unixserversocket.h | 71 +++ dxr3vdrincludes.h | 33 ++ 58 files changed, 12157 insertions(+) create mode 100644 COPYING create mode 100644 HISTORY create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 README create mode 100644 dxr3.c create mode 100644 dxr3.h create mode 100644 dxr3audiodecoder.c create mode 100644 dxr3audiodecoder.h create mode 100644 dxr3blackframe.c create mode 100644 dxr3colormanager.c create mode 100644 dxr3colormanager.h create mode 100644 dxr3configdata.c create mode 100644 dxr3configdata.h create mode 100644 dxr3cpu.c create mode 100644 dxr3cpu.h create mode 100644 dxr3demuxdevice.c create mode 100644 dxr3demuxdevice.h create mode 100644 dxr3device.c create mode 100644 dxr3device.h create mode 100644 dxr3ffmpeg.c create mode 100644 dxr3ffmpeg.h create mode 100644 dxr3generaldefines.h create mode 100644 dxr3i18n.c create mode 100644 dxr3i18n.h create mode 100644 dxr3interface.c create mode 100644 dxr3interface.h create mode 100644 dxr3interface_spu_encoder.c create mode 100644 dxr3interface_spu_encoder.h create mode 100644 dxr3log.c create mode 100644 dxr3log.h create mode 100644 dxr3memcpy.c create mode 100644 dxr3memcpy.h create mode 100644 dxr3multichannelaudio.c create mode 100644 dxr3multichannelaudio.h create mode 100644 dxr3nextpts.c create mode 100644 dxr3nextpts.h create mode 100644 dxr3osd.c create mode 100644 dxr3osd.h create mode 100644 dxr3osd_subpicture.c create mode 100644 dxr3osd_subpicture.h create mode 100644 dxr3outputthread.c create mode 100644 dxr3outputthread.h create mode 100644 dxr3palettemanager.c create mode 100644 dxr3palettemanager.h create mode 100644 dxr3pesframe.c create mode 100644 dxr3pesframe.h create mode 100644 dxr3singleton.h create mode 100644 dxr3spudecoder.c create mode 100644 dxr3spudecoder.h create mode 100644 dxr3syncbuffer.c create mode 100644 dxr3syncbuffer.h create mode 100644 dxr3sysclock.c create mode 100644 dxr3sysclock.h create mode 100644 dxr3tools.h create mode 100644 dxr3unixserversocket.c create mode 100644 dxr3unixserversocket.h create mode 100644 dxr3vdrincludes.h diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..6c25450 --- /dev/null +++ b/HISTORY @@ -0,0 +1,230 @@ +VDR Plugin 'dxr3' Revision History +---------------------------------- + +2002-08-04: Version 0.0.1 + +- Initial revision. + +2002-11-10: Version 0.1.0 + +- Rewritten Audio/Video-sync engine +- Changed OSD colors (but still limited to four colors) + +2002-11-12: Version 0.1.1 + +- Changed Makefile (needed for vdr 1.1.15) +- The plugin should now work smoother under heavy system load (e.g. network traffic) + +2002-12-23: Version 0.1.2 +- Compiles now with gcc3.2. +- Fixed unsigned / signed bug in output thread (dxr3outputthread.c) which led +to sporadic resync (still frame and jump of about 1s). +- OSD is now as colorful as vdr with DVB-s +- OSD rescaling for channels with a lower horizontal resolution + +2002-12-29: Version 0.1.3 +- SPU write is now protected with a mutex by using the Dxr3AbstractionDevice. +- Fixed horizontal size detection. +- Added usleep call during still picture to reduce cpu load. +- Removed calls to WaitForSysClock in dxr3outputthread.c which led to problems +during replay on some systems (Thanks to Atte Manninen for reporting this). +- Did some minor changes to dxr3outputthread.c which hopefully will increase +reliability. +- Changed osd scale rule. Scaling now only happens if the horizontal size is +smaller than 700. + +2003-01-05: Version 0.1.4 +- Small bugfix in dxr3demuxdevice.c + +2003-02-19: Version 0.1.5 +- Support for MP3 plugin. +- Support for radio channels. Requested by Richard P. (???) who send me a + sample code ... thanks. +- Some fixes to get along with corrupt pes data (which should actually be + solved in a lower layer). Thanks to Teemu Rantanen. +- Changed sync buffer size during replay to reduce "jumps" in cutted streams. + Thanks to Atte Manninen for the idea. +- Support for still frame handling. Now it is possible to move the editing + marks with visible corresponding i-frames. Unfortunately this doesn't seem to + work with finish dvb streams. +- Some tuning to reduce cpu load during replay. + +2003-02-25: Version 0.1.6 +- Added black frames between channel switches (which solves the frozen picture + 'problem' when using the mp3-plugin, too). +- Increased thread priority of output threads which improves live stream + quality on my system (K6II 350). + +2003-03-23: Version 0.1.7 +- Added unix domain server interface to close and reopen dxr3 devices without + stopping vdr (see dxr3_ux_client.pl script on how to use this). + Requested by Atte Manninen. + Thanks to Atte Manninen and Teemu Rantanen for testing and fixing some problems. +- Added support for external player mode. +- Some cosmetic changes. +- Some changes to reduce cpu load. +- Added workaround handling for osd crash (driver patch necessary; patch with + em8300_patch.diff). + Thanks to Teemu Rantanen and Malcolm Caldwell for testing this. +- Added buffered output for mp3-plugin audio data. This seems to improve audio + quality significantly. +- Reduced count of audio errors (wrong data rate). +- Changed channel switch behavior (to remove audio disturbances => channel switching + is a little bit slower now). +- Added exception handling for defect pes streams. +- Added more checks by introducing a new pes parsing class. +- Fixed buffer overrun problem. Because of the missing pll control a buffer overrun + happens after staying for a long time on the same channel. In older version + the output stopped after a buffer overrun. Now the buffer will be cleared and + the output will continue after about a second. +- New buffer handling in PlayVideo. + +2003-03-23: Version 0.1.7a +- Bugfix in A/V-engine for audio output with less dropouts + +2003-04-28: Version 0.1.8 +- Added support for dvd-plugin (subtitles doesn't work properly so far). +- Added setup parameter to define the dxr3-card which shall be used by vdr + (thanks to Tobias Haustein). +- Added setup parameter to force letter box mode (for wrong aspect ratio coded + in pes-stream). This parameter is not saved. +- Added support for video format setup parameter (no WSS support). +- Fixed external player support (thanks to Seppo Ingalsuo). +- Added volume support (thanks to Teemu Rantanen). +- Fixed I-Frame display problem (cutting and fast forward/backwards in some streams). + Those who have problems with fast forward/backward might want to patch + vdr (use vdr_iframe_patch.diff / for vdr-1.1.29). +- Reduced memory consumption. +- Fixed problem with digital output setup parameter. +- Fixed wrong bit error detection. +- Changed bit error handling. + +2003-04-28: Version 0.1.8a +- Second trial to fix external player support (thanks to Jarkko Santala) + +2003-05-07: Version 0.1.9 +- Added support for AC3 streams (based on classes of + the AC3overDVB Patch maintained by Stefan Huelswitt). +- Added DXR3 main menu entry. It's now possible to: + - Reset DXR3-hardware. + - Toggle Force LetterBox. + - Switch to Digital Output. + - Switch to AC3 Output (when already listening to digital output). +- Added short ac3 information text on channel switch. +- Reduced analog audio disturbances. +- Fixed audio initialization problem. + +2003-05-07: Version 0.2.0 +- Fixed compatibility problem with vdr version 1.1.31 and higher. +- Fixed analog audio problem (spurious disturbances). +- Added first cut mpeg1 support: It works quite good with vcd plugin. As far as I know + this doesn't work reliable together with analog plugin. Thanks to Gavin Hamill for + testing support and investigations with analog plugin. + No osd scaling for mpeg1 at the moment. +- Changed channel switch behavior with respect to mpeg1 support (it doesn't seem + to be possible to switch between mpeg1 and mpeg2 without closing and reopening the + video device). +- Improved lib sync. + +2003-08-10: Version 0.2.1 +- Added setup entry to switch between ntsc and pal. This setting becomes active + after restarting vdr and reseting the dxr3 card, respectively. +- Fixed uninitialized variable m_audioMode in dxr3abstractiondevice.c. Thanks + to Jon Burgess. +- Fixed incorrect ioctl-problem. Thanks to Jon Burgess. +- Fixed wrong scaled osd problem when starting vdr without live stream. +- Fixed external player problem when return to dxr3 output after using ac3 output. + Thanks to Jarkko Santala for reporting this one. +- Fixed wrong assert-call. Thanks to Andre Neumann. + +2004-01-04: Version 0.2.2 + +- Some initialization fixes. Thanks to Jon Burgess. +- Added patch from Teemu Rantanen to emergency exit if + the plugin is not able to recover from dxr3 driver crash. +- Fixed some osd problems (Elchi, Games, etc.). +- Changed Makefile to support vdr-1.3.0. + +2004-06-22: Version 0.2.3-alpha1 (only for vdr-portal.de) + +- we are using now instead of "em8300.h" +- updated multichannelaudio.h/c with newest AC3overDVB-Patch-Source (0.2.6) +- switched to new osd routines for vdr-1.3.7 +- added dxr3singleton.h +- new interface to work with ffmpeg (chagned include to ) +- added a lot of commments and cosmetic code cleanups +- using everywhere std::string - makes life nicer +- moved dxr3absdevice to dxr3interface +- rewritten some parts of dxr3interface +- added anti-glinsch-when-fast-forward-and-then-play-patch ;) +- killed DIAG and added a global logger, which is used only in + a few functions and not in every like DIAG +- removed cDxr3StatusMonitor - i dont know why we need this +- cleaned out unneeded includes +- fixed memory leak in cDxr3Interface::UploadMicroCode: + If uploading of the microcode failed, the allocated memory wasn't + freed. +- If we are changing the audiooutput now the plugin will call an overworked + AudioRepoen function, which does not shutdown the whole card. +- Things like VIDEOMODE and AUDIOMODE are now set only ONCE on plugin start! +- added check if memory in cDxr3SyncBuffer is allocated correct +- introced a 'ToDo-System'. + in every *.c file there can be something like this at the top of the file: + /* + ToDo: + - cDxr3SyncBuffer::Push: XXX This is only a workaround until a sufficient control algorithm is implemented + */ + + So it is easier to keep track of stuff, which needs more work. +- some small changes in dxr3colormanger.h/c +- some small changes in dxr3pesframe.h/c +- some small changes in spuenc.h/c +- killed spu_dump in spuenc.h/c +- renamed spuenc.h/c to dxr3interface_spu_encoder.h/c +- changed dxr3audiodecoder to support the new ffmpeg interface +- renamed dxr3absspu/dxr3absspulist to dxr3interace_spu/dxr3interace_spu_list +- volume control logarithmic instead of linear. + This is a more natural sounding way of controlling the + volume. Thanks to Jon Burgess +- added patch for DVD subtitles. Thanks to Stuart Daines +- fixed memory leak in dxr3osd.c - Thanks to Miika Pekkarinen +- added Tools namespace, which has a fixed Rgb2YCrCb function in it (dxr3tools.h) +- kicked out Cmd in dxr3osd.h/c +- added dxr3i18n.h/c +- added Portuguese language support - thanks to Paulo Lopes +- added Finnish language support - thanks to Hannu Savolainen +- added Swedish language support - thanks to Tomas Prybil +NOTE: I havent found time to include all of the languages, will be done in pre2 +- kicked out - i hope - some unneeded usleeps +- rewrote cSPUEncoder: Now we imitate the Cmd funtion form the dvb drivers. So + we can use now the normal osd functions form dvbosd.c :) +- added support for vdr-1.3.11 +- added videomode pal 60 + + +2004-07-29: Version 0.2.3-pre2 (now aviable on SourceForge) + +- fixed audio and video problems +- works now with vdr < 1.3.7 +- added YUV2Rgb int dxr3tools.h (for dxr3spudecoder) +- added some more debug infos in dxr3outputthread.c +- added const keyword in dxr3configdata.h +- added EM8300 include define in Makefile +- added debuglevels, so we can define how much we want to log +- assimilated spudecoder from vdr's dvbspu.c/h -> nice nav in dvds +- kicked out cDxr3InterfaceSpu from dxr3interface.c/h +- a little fix for cDxr3Interface::ResampleVolume +- kicked out dxr3interface_spu.c/h and dxr3interface_spu_list.c/h, because + the new spudecoder dont need it anymore. +- added dxr3cpu.c/h to get some infos about the cpu +- added dxr3memcpy.c/h to get a little speedup - i hope +- maybe a little audiofix: lastHeader in cDxr3AudioDecoder will now set to 0 + with the constr. and not via Init()-function. So there should be now some lesser + audio scratches. +- osd works now on every resolution (viva, viva plus,...) +- added main-menu-entry +- added in some parts some memory allocation tests +- added fix for Makefile from vdr-portal.de -> should compile on more machines :) +- added Tools::WriteInfoToOsd(...) - now some infos like "Releasing devices" are show + now on the osd again +- fixed dxr3osd_subpicutre.c - thanks to Paavo Hartikainen diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..f5ef4c4 --- /dev/null +++ b/INSTALL @@ -0,0 +1,18 @@ +Prerequisites: + +- Make sure your DXR3 card is running under linux. For more information look at the "http://dxr3.sourceforge.net" + You should modify the dxr3-driver by applying the delivered patch with "patch -p1 -R < em8300_patch.diff" in + the dxr3/modules directory. + +- Install the (latest) VDR developer version +- The plugin needs the libavcodec library from "http://ffmpeg.sourceforge.net" + +Installation: + +- Get the latest dxr3-plugin version from "http://www.schluenss.de/dxr3.html" +- Get the current CVS of the dxr3 drivers from dxr3.sf.net +- Unpack the package into "PLUGINS/SRC" directory +- Make a symbolic link to this dxr3-plugin (ln -s vdr_dxr3_x.x.x dxr3) +- Call "make plugins" in the VDR root directory +- Make sure your DXR3 driver modules are loaded and ready to run +- Start VDR with "vdr -Pdxr3" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7d9fa05 --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.1 2004/08/05 23:05:21 austriancoder 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 = dxr3 + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: + +CXX = g++ +CXXFLAGS = -O2 -Wall -Woverloaded-virtual + +### The directory environment: + +##DVBDIR = ../../../../DVB +##VDRDIR = ../../.. +##LIBDIR = ../../lib +##TMPDIR = /tmp +##FFMDIR = ../../../../ffmpeg +### LIBMP3DIR = /usr/lib + +DVBDIR = /usr/src/linux +VDRDIR = /usr/include/vdr +LIBDIR = /usr/lib +TMPDIR = /tmp +FFMDIR = /usr/include/ffmpeg +EM8300 = /usr/include + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR (taken from VDR's "config.h"): + +VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -I$(FFMDIR) -I$(EM8300) +LIBS = -L$(FFMDIR)/libavcodec -lavcodec -ljpeg +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -DSOCKET_CHMOD=0660 +DEFINES += -D_GNU_SOURCE + +### The object files (add further files here): + +OBJS = $(PLUGIN).o dxr3multichannelaudio.o dxr3sysclock.o dxr3colormanager.o dxr3syncbuffer.o dxr3audiodecoder.o \ +dxr3blackframe.o dxr3palettemanager.o dxr3nextpts.o dxr3pesframe.o dxr3demuxdevice.o dxr3configdata.o \ +dxr3log.o dxr3ffmpeg.o dxr3interface_spu_encoder.o dxr3i18n.o \ +dxr3interface.o dxr3device.o dxr3outputthread.o dxr3osd.o dxr3osd_subpicture.o dxr3spudecoder.o dxr3unixserversocket.o \ +dxr3cpu.o dxr3memcpy.o + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +all: libvdr-$(PLUGIN).so + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -lz -shared $(OBJS) $(LIBS) -o $@ + @cp $@ $(LIBDIR)/$@.$(VDRVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ diff --git a/README b/README new file mode 100644 index 0000000..fa2addc --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Kai Moeller , Stefan Schluenss + Christian Gmeiner + +Project's homepage: http://www.schluenss.de/DXR3.html + +Latest version available at: see homepage + +See the file COPYING for license information. + +Description: DXR3/Hollywod+ MPEG decoder card plugin which allows using such a + card as primary interface for VDR. + diff --git a/dxr3.c b/dxr3.c new file mode 100644 index 0000000..0024a48 --- /dev/null +++ b/dxr3.c @@ -0,0 +1,189 @@ +/* +* dxr3.c: A plugin for the Video Disk Recorder +* +* See the README file for copyright information and how to reach the author. +* +* $Id: dxr3.c,v 1.1 2004/08/05 23:05:21 austriancoder Exp $ +*/ + + +#include "dxr3vdrincludes.h" +#include "dxr3device.h" +#include "dxr3syncbuffer.h" +#include "dxr3configdata.h" +#include "dxr3interface.h" +#include "dxr3.h" + +static const char *VERSION = "0.2.3-pre3-cvs"; +static const char *DESCRIPTION = "DXR3-MPEG decoder plugin"; +static const char *MAINMENUENTRY = "DXR3"; + +#include "dxr3cpu.h" + +// ================================== +// 'message-handler' for the main screen +eOSState cDxr3OsdItem::ProcessKey(eKeys Key) +{ + if (Key == kOk) + { + switch (m_item) + { + case DXR3_RESET_HARDWARE: + cDxr3Interface::Instance().ResetHardware(); + cDxr3Device::Instance().Reset(); + break; + + case DXR3_FORCE_LETTER_BOX: + cDxr3ConfigData::Instance().SetForceLetterBox(!cDxr3ConfigData::Instance().GetForceLetterBox()); + break; + + case DXR3_ANALOG_OUT: + cLog::Instance() << "Changing audio to analog\n"; + cDxr3ConfigData::Instance().SetUseDigitalOut(0); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + cDxr3Device::Instance().Reset(); + break; + + case DXR3_DIGITAL_OUT: + cLog::Instance() << "Changing audio to digital\n"; + cDxr3ConfigData::Instance().SetUseDigitalOut(1); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + cDxr3Device::Instance().Reset(); + break; + + case DXR3_AC3_OUT: + cLog::Instance() << "Changing audio to ac3\n"; + cDxr3ConfigData::Instance().SetAc3OutPut(!cDxr3ConfigData::Instance().GetAc3OutPut()); + cDxr3Device::Instance().Reset(); + break; + } + } + + return Key == kOk ? osBack : cOsdItem::ProcessKey(Key); +} + +// ================================== +// setup menu +cMenuSetupDxr3::cMenuSetupDxr3(void) +{ + newUseDigitalOut = cDxr3ConfigData::Instance().GetUseDigitalOut(); + Add(new cMenuEditBoolItem(tr("Digital audio output"), &newUseDigitalOut)); + newDxr3Card = cDxr3ConfigData::Instance().GetDxr3Card(); + Add(new cMenuEditIntItem(tr("DXR3 card"), &newDxr3Card)); + newVideoMode = (int) cDxr3ConfigData::Instance().GetVideoMode(); + Add(new cMenuEditStraItem(tr("DXR3 video mode"), &newVideoMode, 3, menuVideoModes)); + newDebug = (int) cDxr3ConfigData::Instance().GetDebug(); + Add(new cMenuEditBoolItem(tr("Debug mode"), &newDebug)); + newDebugLevel = (int) cDxr3ConfigData::Instance().GetDebugLevel(); + Add(new cMenuEditStraItem(tr("Debug level"), &newDebugLevel, 2, menuDebugModes)); +} + +// ================================== +// save menu values +void cMenuSetupDxr3::Store(void) +{ + SetupStore("UseDigitalOut", cDxr3ConfigData::Instance().SetUseDigitalOut(newUseDigitalOut)); + SetupStore("Dxr3Card", cDxr3ConfigData::Instance().SetDxr3Card(newDxr3Card)); + SetupStore("Dxr3VideoMode", cDxr3ConfigData::Instance().SetVideoMode((eVideoMode) newVideoMode)); + SetupStore("Dxr3Debug", cDxr3ConfigData::Instance().SetDebug(newDebug)); + SetupStore("Dxr3DebugLevel", cDxr3ConfigData::Instance().SetDebugLevel(newDebugLevel)); +} + +// ================================== +class cPluginDxr3 : public cPlugin +{ +private: + // Add any member variables or functions you may need here. +public: + cPluginDxr3(); + ~cPluginDxr3(); + const char *Version() { return VERSION; } + const char *Description() { return DESCRIPTION; } + const char *CommandLineHelp(); + bool ProcessArgs(int argc, char *argv[]); + bool Initialize(); + bool Start(); + void Housekeeping(); + cMenuSetupPage *SetupMenu(); + bool SetupParse(const char *Name, const char *Value); + const char* MainMenuEntry(); + cOsdObject* MainMenuAction(); +}; + +// ================================== +cPluginDxr3::cPluginDxr3() +{ + // Initialize any member varaiables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! + cDxr3ConfigData::Instance(); +} + +// ================================== +cPluginDxr3::~cPluginDxr3() +{ +} + +// ================================== +const char *cPluginDxr3::CommandLineHelp() +{ + return NULL; +} + +// ================================== +bool cPluginDxr3::ProcessArgs(int argc, char *argv[]) +{ + return true; +} + +// ================================== +bool cPluginDxr3::Start() +{ + return true; +} + +// ================================== +bool cPluginDxr3::Initialize() +{ + new cDxr3CPU(); + cDxr3Device::Instance(); + return true; +} + +// ================================== +void cPluginDxr3::Housekeeping() +{ +} + +// ================================== +cMenuSetupPage* cPluginDxr3::SetupMenu() +{ + return new cMenuSetupDxr3(); +} + +// ================================== +bool cPluginDxr3::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + if (!strcasecmp(Name, "UseDigitalOut")) { cDxr3ConfigData::Instance().SetUseDigitalOut(atoi(Value)); return true; } + if (!strcasecmp(Name, "Dxr3Card")) { cDxr3ConfigData::Instance().SetDxr3Card(atoi(Value)); return true; } + if (!strcasecmp(Name, "Dxr3Debug")) { cDxr3ConfigData::Instance().SetDebug(atoi(Value)); return true; } + if (!strcasecmp(Name, "Dxr3VideoMode")) { cDxr3ConfigData::Instance().SetVideoMode((eVideoMode) atoi(Value)); return true;} + if (!strcasecmp(Name, "Dxr3DebugLevel")) { cDxr3ConfigData::Instance().SetDebugLevel(atoi(Value)); return true;} + + return false; +} + +// ================================== +const char* cPluginDxr3::MainMenuEntry() +{ + return tr(MAINMENUENTRY); +} + +// ================================== +cOsdObject* cPluginDxr3::MainMenuAction() +{ + return new cDxr3OsdMenu; +} + +VDRPLUGINCREATOR(cPluginDxr3); // Don't touch this! diff --git a/dxr3.h b/dxr3.h new file mode 100644 index 0000000..069f488 --- /dev/null +++ b/dxr3.h @@ -0,0 +1,107 @@ +#ifndef _DXR3_H_ +#define _DXR3_H_ + +// --- cMenuSetupDxr3 ------------------------------------------------------- +const char* menuVideoModes[] = +{ + "PAL", + "PAL60", + "NTSC" +}; + +// debug modes +const char* menuDebugModes[] = +{ + "Low", + "Everything" +}; + +// ================================== +// setup screen +class cMenuSetupDxr3 : public cMenuSetupPage +{ +public: + cMenuSetupDxr3(); + +protected: + virtual void Store(); + +private: + int newUseDigitalOut; + int newDxr3Card; + int newVideoMode; + int newDebug; + int newDebugLevel; +}; + + +// ================================== +enum eDxr3OsdItem +{ + DXR3_RESET_HARDWARE, + DXR3_FORCE_LETTER_BOX, + DXR3_DIGITAL_OUT, + DXR3_ANALOG_OUT, + DXR3_AC3_OUT +}; + +// ================================== +// osd item +class cDxr3OsdItem : public cOsdItem +{ +public: + cDxr3OsdItem(const char* text, eDxr3OsdItem item) : cOsdItem(text), m_item(item) {} + + // process fb input + eOSState ProcessKey(eKeys Key); + +protected: + eDxr3OsdItem m_item; +}; + +// ================================== +// main screen +class cDxr3OsdMenu : public cOsdMenu +{ +public: + cDxr3OsdMenu(): cOsdMenu("DXR3 Adjustment") + { + Clear(); + SetHasHotkeys(); + Add(new cDxr3OsdItem(hk("Reset DXR3 Hardware"), DXR3_RESET_HARDWARE)); + Add(new cDxr3OsdItem(hk("Toggle Force LetterBox"), DXR3_FORCE_LETTER_BOX)); + + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + Add(new cDxr3OsdItem(hk("Analog Output"), DXR3_ANALOG_OUT)); + } + else + { + Add(new cDxr3OsdItem(hk("Digital Output"), DXR3_DIGITAL_OUT)); + } +/* + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + Add(new cDxr3OsdItem(hk("Analog Output"), DXR3_ANALOG_OUT)); + + if (cDxr3ConfigData::Instance().GetAc3OutPut()) + { + Add(new cDxr3OsdItem(hk("AC3 Output Off"), DXR3_AC3_OUT)); + } + else + { + if (cDxr3Interface::Instance().IsAc3Present()) + { + Add(new cDxr3OsdItem(hk("AC3 Output On"), DXR3_AC3_OUT)); + } + } + } + else + { + Add(new cDxr3OsdItem(hk("Digital Output"), DXR3_DIGITAL_OUT)); + } + */ + } +}; + +#endif /*_DXR3_H_*/ diff --git a/dxr3audiodecoder.c b/dxr3audiodecoder.c new file mode 100644 index 0000000..c7fb3a7 --- /dev/null +++ b/dxr3audiodecoder.c @@ -0,0 +1,296 @@ +/* + * dxr3audiodecoder.c + * + * Copyright (C) 2002-2004 Kai Möller + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ + + +/* +ToDo: + - cDxr3AudioDecoder::Init: Why are we always reinit the codec? +*/ + + +#include +#include "dxr3audiodecoder.h" +#include "dxr3pesframe.h" + +// ================================== +const int LPCM_HEADER_LENGTH = 7; + +// ================================== +// constr. +cDxr3AudioDecoder::cDxr3AudioDecoder() : rbuf(50000), ac3dtsDecoder(&rbuf) +{ + decoderOpened = false; + audioSynched = false; + volume = 255; + Codec.id = CODEC_ID_MP2; + + Init(); + + lastHeader[0] = 0xFF; + lastHeader[1] = lastHeader[2] = lastHeader[3] = 0; +}; + +// ================================== +// deconst. +cDxr3AudioDecoder::~cDxr3AudioDecoder() +{ + // close codec, if it is open + cDxr3Ffmepg::Instance().CloseCodec(Codec); +}; + +// ================================== +// (re)init ffmpeg codec +void cDxr3AudioDecoder::Init() +{ + // (re)init codec + cDxr3Ffmepg::Instance().CloseCodec(Codec); + if (cDxr3Ffmepg::Instance().FindCodec(Codec)) + { + cDxr3Ffmepg::Instance().OpenCodec(Codec); + rate = channels = -1; + frameSize = Codec.codec_context.frame_size; + decoderOpened = true; + foundHeader = false; + decodeAudio = true; + + //lastHeader[0] = 0xFF; + //lastHeader[1] = lastHeader[2] = lastHeader[3] = 0; + } + else + { + decoderOpened = false; + } +} + +// ================================== +// decode given buffer +void cDxr3AudioDecoder::Decode(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf) +{ + if (!decoderOpened) + { + // No decoder is open, so it + // is better to stop here. + return; + } + + int len; + int out_size; + + enum audioException + { + WRONG_LENGTH, + UNEXPECTED_PARAMETER_CHANGE + }; + + int i = 0; + for (i = 0; i < length-4 && !foundHeader; i++) + { + unsigned int tempHead = *((unsigned int*)(buf+i)); + if (HeadCheck(tempHead)) + { + if ((buf[i+2] & 0xFC) != (lastHeader[2] & 0xFC)) + { + cLog::Instance() << "cDxr3AudioDecoder::Decode Found different audio header -> init\n"; + cLog::Instance() << "cDxr3AduioDecoder::Decode Old header 0x" << hex << *((uint32_t*) lastHeader) << " new header 0x" << *((uint32_t*) (buf+i))<< dec << "\n"; + + Init(); + lastHeader[0] = buf[i]; + lastHeader[1] = buf[i+1]; + lastHeader[2] = buf[i+2]; + lastHeader[3] = buf[i+3]; + } + foundHeader = true; + } + } + + if (audioSynched) + { + // no header found + decodeAudio = true; + } + else + { + if (foundHeader && pts) + { + decodeAudio = true; + audioSynched = true; + } + } + + try + { + while (length > 0 && decodeAudio) + { + len = avcodec_decode_audio(&Codec.codec_context, (short *)(&pcmbuf), &out_size, + const_cast(buf), length); + if (len < 0 || out_size < 0) throw WRONG_LENGTH; + + if (Codec.codec_context.sample_rate != rate) + { + cLog::Instance() << "cDxr3AudioDecoder::Decode Sample rate = " << Codec.codec_context.sample_rate << "\n"; + if (rate != -1) throw UNEXPECTED_PARAMETER_CHANGE; + rate = Codec.codec_context.sample_rate; + } + if (Codec.codec_context.channels != channels+1 ) + { + if (channels != -1) throw UNEXPECTED_PARAMETER_CHANGE; + channels = (Codec.codec_context.channels == 2) ? 1 : 0; + cLog::Instance() << "cDxr3AudioDecoder::Decode channels = " << Codec.codec_context.channels << "\n"; + } + if (out_size) + { + cFixedLengthFrame* pTempFrame = aBuf.Push(pcmbuf, out_size, pts); + pTempFrame->SetChannelCount(channels); + pTempFrame->SetDataRate(rate); + } + length -= len; + buf += len; + } + } + catch (audioException ex) + { + switch (ex) + { + case WRONG_LENGTH: + cLog::Instance() << "cDxr3AudioDecoder::Decode wrong length\n"; + break; + + case UNEXPECTED_PARAMETER_CHANGE: + cLog::Instance() << "cDxr3AudioDecoder::Decode unexpected parameter change\n"; + break; + + default: + cLog::Instance() << "cDxr3AudioDecoder::Decode unexpeced exception\n"; + break; + } + dsyslog("cDxr3AudioDecoder::Decode skipping %d broken data bytes", length); + + Init(); + } +} + +// ================================== +// decode lpcm +void cDxr3AudioDecoder::DecodeLpcm(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf) +{ + if (length > (LPCM_HEADER_LENGTH + 2)) + { + uint8_t* pFrame = new uint8_t[length - LPCM_HEADER_LENGTH]; + assert(!((length - LPCM_HEADER_LENGTH) % 2)); // only even number of bytes are allowed + + for (int i = LPCM_HEADER_LENGTH; i < length; i += 2) + { + pFrame[i - LPCM_HEADER_LENGTH] = buf[i + 1]; + pFrame[i - LPCM_HEADER_LENGTH + 1] = buf[i]; + } + + int codedSpeed = (buf[5] >> 4) & 0x03; + int speed = 0; + + switch (codedSpeed) + { + case 1: + speed = 96000; + break; + + case 2: + speed = 44100; + break; + + case 3: + speed = 32000; + break; + + default: + speed = 48000; + break; + } + + cFixedLengthFrame* pTempFrame = aBuf.Push(pFrame, length - LPCM_HEADER_LENGTH, pts); + pTempFrame->SetChannelCount(1); + pTempFrame->SetDataRate(speed); + + delete[] pFrame; + } +} + +// ================================== +// decode ac3 +void cDxr3AudioDecoder::DecodeAc3Dts(const uint8_t* pPes, const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf) +{ + int headerLength = (int) (buf - pPes); + + uint8_t* pBuf = (uint8_t*) pPes; + ac3dtsDecoder.Check(pBuf + headerLength, length, pBuf); + ac3dtsDecoder.Encapsulate(pBuf + headerLength, length); + + cFrame* pFrame = 0; + while ((pFrame = rbuf.Get())) + { + if (pFrame && pFrame->Count()) + { + cDxr3PesFrame tempPes; + tempPes.ExtractNextFrame(pFrame->Data(), pFrame->Count()); + int pesHeaderLength = (int) (tempPes.GetEsStart() - tempPes.GetPesStart()); + uint8_t* pData = pFrame->Data() + pesHeaderLength + LPCM_HEADER_LENGTH; + + for (int i = 0; i < pFrame->Count() - pesHeaderLength - LPCM_HEADER_LENGTH; i += 2) + { + swap(pData[i], pData[i + 1]); + } + + aBuf.Push(pFrame->Data() + pesHeaderLength + LPCM_HEADER_LENGTH, pFrame->Count() - pesHeaderLength - 7, tempPes.GetPts()); + if (pFrame) rbuf.Drop(pFrame); + } + } +} + +// ================================== +// checking routine +bool cDxr3AudioDecoder::HeadCheck(unsigned long head) +{ + bool retval = false; + + uint8_t* phead = (uint8_t*) (&head); + if (phead[0] != 0xFF) + { + retval = false; + } + else if (phead[1] != 0xFC && phead[1] != 0xFE) + { + retval = false; + } + else if ((phead[2] & 0xF0) == 0xF0) + { + retval = false; + } + else if ((phead[2] & 0xC) == 0xC) + { + retval = false; + } + else + { + retval = true; + } + + return retval; +} diff --git a/dxr3audiodecoder.h b/dxr3audiodecoder.h new file mode 100644 index 0000000..32467e4 --- /dev/null +++ b/dxr3audiodecoder.h @@ -0,0 +1,53 @@ +#ifndef _DXR3_AUDIODECODER_H_ +#define _DXR3_AUDIODECODER_H_ + +#include +#include + +#include "dxr3ffmpeg.h" +#include "dxr3syncbuffer.h" +#include "dxr3multichannelaudio.h" +#include "dxr3log.h" + +// ================================== +// decode audio to mp2 or use DD :) +class cDxr3AudioDecoder +{ +public: + cDxr3AudioDecoder(); + ~cDxr3AudioDecoder(); + + void Init(void); // init in const? + + void Decode(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf); + void DecodeLpcm(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf); + void DecodeAc3Dts(const uint8_t* pPes, const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf); + + int GetRate(void) const { return rate; } + int GetChannelCount(void) const { return channels; } + int GetFrameSize(void) const { return frameSize; } + void Reset(void) { ac3dtsDecoder.Clear(); rbuf.Clear(); } + +private: + bool HeadCheck(unsigned long head); + + struct Dxr3Codec Codec; + + cRingBufferFrame rbuf; + cMultichannelAudio ac3dtsDecoder; + + bool audioSynched; + bool decoderOpened; + uint8_t lastHeader[4]; + int rate; + int channels; + uint32_t frameSize; + uint8_t pcmbuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]; + int volume; + bool foundHeader; + bool decodeAudio; + + cDxr3AudioDecoder(cDxr3AudioDecoder&); // no copy constructor +}; + +#endif /*_DXR3_AUDIODECODER_H_*/ diff --git a/dxr3blackframe.c b/dxr3blackframe.c new file mode 100644 index 0000000..c21417b --- /dev/null +++ b/dxr3blackframe.c @@ -0,0 +1,1286 @@ +/* + * dxr3blackframe.c + * + * Copyright (C) 2002-2004 Kai Möller + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ + +// ================================== +// used when channel gets switched +char blackframe[] = + +{ 0x0, 0x0, 0x1, 0xb3, 0x2d, 0x2, 0x40, 0x23, 0x24, 0x9f, 0x23, 0x82, 0x10, 0x20, 0x20, 0x26, +0x20, 0x26, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x34, 0x30, 0x34, 0x36, 0x36, 0x36, 0x34, +0x34, 0x34, 0x34, 0x36, 0x36, 0x36, 0x3a, 0x3a, 0x3a, 0x44, 0x44, 0x44, 0x3a, 0x3a, 0x3a, +0x36, 0x36, 0x3a, 0x3a, 0x40, 0x40, 0x44, 0x44, 0x4a, 0x4c, 0x4a, 0x46, 0x46, 0x44, 0x46, +0x4c, 0x4c, 0x50, 0x50, 0x50, 0x60, 0x60, 0x5c, 0x5c, 0x70, 0x70, 0x74, 0x8a, 0x8a, 0xa7, +0x10, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, +0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19, 0x1a, +0x1a, 0x1a, 0x1a, 0x19, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1e, 0x1e, +0x1e, 0x1f, 0x1f, 0x21, 0x0, 0x0, 0x1, 0xb5, 0x14, 0x82, 0x0, 0x1, 0x0, 0x0, 0x0, +0x0, 0x1, 0xb8, 0x5a, 0x9, 0xc4, 0x80, 0x0, 0x0, 0x1, 0x0, 0x0, 0x4b, 0x9, 0xb0, +0x0, 0x0, 0x1, 0xb5, 0x8f, 0xff, 0xf7, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0xb, 0x7e, +0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xd4, 0x28, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x13, 0x7e, 0x1f, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x3, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xa8, 0x31, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1a, 0x83, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xc, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x35, 0x6, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xc, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0x41, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x62, 0xb5, 0x4e, 0x81, +0x2a, 0x5, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x1, 0x7, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x8, 0xb, +0x7e, 0x1f, 0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x21, 0xea, 0x31, 0x6, 0x97, 0x54, 0x85, 0x18, 0x61, 0x80, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x9, +0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xa, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xb, 0xb, 0x7e, +0x1f, 0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc, 0xb, +0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x1, 0xd, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe, 0xb, 0x7e, 0x1f, +0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xf, 0xb, 0x7e, 0x1f, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x10, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x11, 0xb, 0x7e, 0x1f, 0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xc0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x12, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x13, 0xb, +0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x1, 0x14, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x1, 0x15, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x1, 0x16, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x17, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x1, 0x18, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x19, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x1, 0x1a, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1b, 0xb, 0x7e, 0x1f, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1c, 0xb, +0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x1d, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x1, 0x1e, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x1f, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x20, 0xb, 0xfe, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x21, 0xb, 0x7e, 0x1f, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x22, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x1, 0x23, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x24, 0xb, 0x7e, 0x1f, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0 }; + +int blackframeLength = sizeof(blackframe); diff --git a/dxr3colormanager.c b/dxr3colormanager.c new file mode 100644 index 0000000..50e3877 --- /dev/null +++ b/dxr3colormanager.c @@ -0,0 +1,378 @@ +/*************************************************************************** + dxr3colormanager.c - description + ------------------- + begin : Tue Oct 22 2002 + copyright : (C) 2002 by Stefan Schluenss + email : vdr@schluenss.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +/** + * Background: + * Each encoded pixel in the SPU could have one of the values 0,1,2,3. * + * These values + + Pixelvalue Maps + to index + 0 --> 4 --> + + + * The SPU data definition allows highlighting of rectangular areas. They * + * are defined by a starting and ending row. Whithin these rows one could * + * define a starting column for using a new color palette mapping. This * + * mapping will be used til the end of the line or up to the next column * + * defintion. + * Look at the picture below: + * + Row Col=5 Col=16 + n-2 ............................... + n-1 ............................... + n .....-------------------------- <- Highligh region starts here + .....| 6,3,1,2 | 0,2,8,9 + .....| 6,3,1,2 | 0,2,8,9 + .....| 6,3,1,2 | 0,2,8,9 + n+4 .....-------------------------- <- Highligh region ends here + n+5 ............................... + n+6 ............................... + + In the above example one region (from n to n+4) is defined with two * + highlight sections - one from column 5 up to 15 and the second from 16 * + til the end of the line. +**/ + + +#include + +#include "dxr3colormanager.h" +#include "dxr3memcpy.h" +#include +#include + +// ================================== +cColorManager::cColorManager() +{ + NrOfRegions = 0; + isopen = false; + for(int i = 0; i < MAX_NO_OF_REGIONS; i++) + hlr[i] = NULL; +} + +// ================================== +cColorManager::~cColorManager() +{ + for (int i = 0; i < NrOfRegions; i++) + { + if (hlr[i]) + { + delete(hlr[i]); + } + } +} + +// ================================== +// Opens a new highlight region +void cColorManager::OpenRegion(int y, int NrOfSecToCopy) +{ + hlr[NrOfRegions] = new yRegion(); + hlr[NrOfRegions]->Y1 = y; + isopen = true; + + if (NrOfSecToCopy > 0) + { + for (int i = 0; i < NrOfSecToCopy; i++) + { + hlr[NrOfRegions]->Section[i] = hlr[NrOfRegions - 1]->Section[i]; + } + } +} + +// ================================== +// Closes the spu-highlight region +void cColorManager::CloseRegion(int y) +{ + + hlr[NrOfRegions]->Y2 = y; + isopen = false; + + if (hlr[NrOfRegions]->N != 0) // skip this region if there is no section defined + { + if (NrOfRegions < MAX_NO_OF_SECTIONS -1) + { + NrOfRegions++; + } + } + +} + +// ================================== +void cColorManager::EncodeColors(int width, int height, unsigned char* map, unsigned char* dmap) +{ + unsigned char color = 0xFF, ccol = 0xFF; + unsigned char ColorIndex = 0xFF; + unsigned char buffer[1024] = {0}; + + for (int y = 0; y < height; ++y) + { + color = 0xFF; + for(int x = 0; x < width; ++x) + { + ccol = map[y * width + x]; + if (ccol != 0) MaxY = y; + if (ccol != color) + { + color = ccol; // save this color + if (!AddColor(x,y,color, ColorIndex)) + { + // add this color to highlight regions + color = 0xFF; + x = -1; + } + else + { + // color successfully added + buffer[x] = ColorIndex; + } + } + else + { + buffer[x] = ColorIndex;//*(dmap+(y * width + x)) = ColorIndex; + } + } + dxr3_memcpy(dmap+y*width, buffer,width); + } +} + +// ================================== +unsigned char cColorManager::AddColor(int x, int y, unsigned char color, unsigned char &ColorIndex) { + static int yold = -1; + xSection* Section = 0; + int SectionIndex = 0; + + if (isopen) + { + // there is an opened highlight-region + Section = GetSection(x, SectionIndex); + + // checks whether we have a section defined on the formerly line on this x-position + if (Section != NULL) + { + // there was a section + if (!Section->HasColor(color, ColorIndex)) + { + // this color is new for this section + if (Section->AllColorsUsed()) + { + // no more free colors + if (yold != y) + { + CloseRegion(y-1); + // terminate region + return(0); + yold = y; + // open new region + OpenRegion(y,SectionIndex+1); + } + // create new section + Section = NewSection(x); + } + // and add new color + ColorIndex = Section->AddColor(color); + } + } + else + { + // no section found (but region already open) + + // terminate region + CloseRegion(y-1); + yold = y; + // open new region + OpenRegion(y); + // create new section + Section = NewSection(x); + // and add new color + ColorIndex = Section->AddColor(color); + } + } + else + { + // currently no region open + yold = y; + + // open new region + OpenRegion(y); + // create new section + Section = NewSection(x); + // and add new color + ColorIndex = Section->AddColor(color); + } + return(1); +} + +// ================================== +xSection *cColorManager::GetSection(int x, int &n) +{ + int i; + n = 0; + + // for every section in the current region + for (i = 0; i < hlr[NrOfRegions]->N; i++) + { + if ((x <= hlr[NrOfRegions]->Section[i]->X2) && (x >= hlr[NrOfRegions]->Section[i]->X1)) // x-pos is in section + { + n = i; + return (hlr[NrOfRegions]->Section[i]); + } + } + return(NULL); +} + +/** Adds a new highlight region beginning from FIRST to LAST column */ +/** +void cColorManager::AddRegion(int first, int last, unsigned int color, unsigned int opac) +{ + DIAG("AddRegion(%d %d %x %x)\n",first, last, color, opac); + hlr[NrOfRegions]->AddSection(first, last, color, opac); +} +**/ + +// ================================== +// convert into SPU - hope is correct description +unsigned char* cColorManager::GetSpuData(int& len) +{ + if (isopen) // there is an opened highlight-region + CloseRegion(MaxY); + + if (NrOfRegions != 0) + { + int ptr = 0; + spudata[ptr++] = 0x07; // CHG_COLCON command + spudata[ptr++] = 0x00; // total size of parameter area + spudata[ptr++] = 0x00; // will be filled later + + + for(int i = 0; i < NrOfRegions;i++) + { + spudata[ptr++] = (hlr[i]->Y1 >> 8) & 0x0f; + spudata[ptr++] = (hlr[i]->Y1 & 0xff); + spudata[ptr++] = ( ( (hlr[i]->N) & 0x0f) << 4) | ((hlr[i]->Y2 >> 8) & 0x0f); + spudata[ptr++] = (hlr[i]->Y2 & 0xff); + + for(int c = 0; c < hlr[i]->N; c++) + { + spudata[ptr++] = hlr[i]->Section[c]->X1 >> 8; + spudata[ptr++] = hlr[i]->Section[c]->X1 & 0xff; + spudata[ptr++] = (hlr[i]->Section[c]->Colors[3] << 4) | (hlr[i]->Section[c]->Colors[2] & 0x0F); + spudata[ptr++] = (hlr[i]->Section[c]->Colors[1] << 4) | (hlr[i]->Section[c]->Colors[0] & 0x0F); + + spudata[ptr++] = (hlr[i]->Section[c]->Opac[3] << 4) | hlr[i]->Section[c]->Opac[2]; + spudata[ptr++] = (hlr[i]->Section[c]->Opac[1] << 4) | hlr[i]->Section[c]->Opac[0]; + } + } + spudata[ptr++] = 0x0f; // termination of parameter block + spudata[ptr++] = 0xff; + spudata[ptr++] = 0xff; + spudata[ptr++] = 0xff; + int size = ptr - 1; + spudata[1] = size >> 8; + spudata[2] = size & 0xff; + + len = ptr; + } + else + len = 0; + +#if OSD_SPU_CM_DUMP + FILE *fp; + fp = fopen("CM.dump","a+"); + fprintf(fp,"len:%03d ",len); + for (int i = 0; i < len; i++) + fprintf(fp,"%02X",*(spudata+i)); + fprintf(fp,"\n"); + fclose(fp); +#endif + + return(spudata); +} + +// ================================== +xSection *cColorManager::NewSection(int x) +{ + xSection* sec = new xSection(x); + int N = hlr[NrOfRegions]->N; + + hlr[NrOfRegions]->Section[hlr[NrOfRegions]->N] = sec; + if (N > 0) + hlr[NrOfRegions]->Section[hlr[NrOfRegions]->N - 1]->X2 = x-1; + (hlr[NrOfRegions]->N)++; + + return(sec); +} + +/** +// No descriptions */ +/** +void HLRegion::AddSection(int first, int last, unsigned int color, unsigned int opac) +{ + DIAG(" AddSection %d,%d %X,%X\n",first, last, color, opac); + Region[N] = new ColRegion(first, last, color, opac); + assert(N> 4; + ColorIndex = NrOfColors; + NrOfColors++; + } + return(ColorIndex); +} + +// ================================== +bool xSection::HasColor(unsigned int color, unsigned char &ColorIndex) +{ + for(int i = 0; i < NrOfColors; i++) + { + if (Colors[i] == color) + { + ColorIndex = i; + return (true); + } + } + return(false); +} + +/** No descriptions */ +void cColorManager::SetBgColor(unsigned int bgColor) +{ +// cColorManager::BgColor = bgColor; +} diff --git a/dxr3colormanager.h b/dxr3colormanager.h new file mode 100644 index 0000000..063252d --- /dev/null +++ b/dxr3colormanager.h @@ -0,0 +1,122 @@ +/*************************************************************************** + dxr3colormanager.h - description + ------------------- + begin : Tue Oct 22 2002 + copyright : (C) 2002 by Stefan Schluenss + email : vdr@schluenss.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _DXR3COLORMANAGER_H_ +#define _DXR3COLORMANAGER_H_ +/* +// ================================== +struct rectangular_area +{ + rectangular_area() : m_startrow(0), m_endrow(0), m_startcol(0), m_endcol(0) {} + +private: + size_t m_startrow; + size_t m_endrow; + size_t m_startcol; + size_t m_endcol; + + unsigned int Colors[4]; + unsigned int Opac[4]; +} + + + +*/ + + + +/**SPU-ColorManager + *@author Stefan Schluenss +*/ + +#include + +#define OSD_SPU_CM_DUMP 0 + +#define MAX_NO_OF_SECTIONS 15 +#define MAX_NO_OF_REGIONS 30 + + +// ================================== +class xSection +{ +public: + xSection(int x); + bool HasColor(unsigned int color, unsigned char &ColorIndex); + unsigned char AddColor(unsigned int color); + bool AllColorsUsed() {/*DIAG("AllColorsUsed: %d\n",NrOfColors)*/;if(NrOfColors >= 4) return(true); else return (false); }; + int X1; + int X2; + int NrOfColors; + unsigned int Colors[4]; + unsigned int Opac[4]; +}; + +// ================================== +class yRegion +{ +public: + yRegion(): Y1(0), Y2(0), N(0) {} + + /** No descriptions */ + void AddSection(int first, int last, unsigned int color, unsigned int opac); + int Y1; + int Y2; + int N; + + xSection* Section[MAX_NO_OF_SECTIONS]; +}; + +// ================================== +class cColorManager +{ +public: + cColorManager(); + ~cColorManager(); + + void EncodeColors(int width, int height, unsigned char* smap, unsigned char* dmap); + + /** Sets a new color on the OSD */ + unsigned char AddColor(int x, int y, unsigned char color, unsigned char &ColorIndex); + + /** encodes the color information as highlight spu data*/ + unsigned char* GetSpuData(int &len); + + /** Adds a new highlight region beginning from FIRST to LAST column */ +// void AddRegion(int first, int last, unsigned int color, unsigned int opac=0xFFFF); + + /** No descriptions */ + void SetBgColor(unsigned int bgColor); + +private: // Private attributes + yRegion *hlr[MAX_NO_OF_REGIONS]; + int NrOfRegions; + bool isopen; + unsigned char spudata[2*4096]; + unsigned int BgCol; + int MaxY; + + /** Opens a new highlight region */ + void OpenRegion(int y, int NrOfSecToCopy = 0); + /** Closes the spu-highlight region */ + void CloseRegion(int y); + + xSection* NewSection(int x); + xSection *GetSection(int x, int &n); +}; + +#endif /*_DXR3COLORMANAGER_H_*/ diff --git a/dxr3configdata.c b/dxr3configdata.c new file mode 100644 index 0000000..ee46081 --- /dev/null +++ b/dxr3configdata.c @@ -0,0 +1,16 @@ +//#include +#include "dxr3configdata.h" + +// ================================== +// constr. +cDxr3ConfigData::cDxr3ConfigData() +{ + UseDigitalOut = 0; + Dxr3Card = 0; + ForceLetterBox = 0; + Ac3OutPut = 0; + m_videoMode = PAL; + m_menuMode = SUBPICTURE; + m_debug = 1; + m_debuglevel = 0; +} diff --git a/dxr3configdata.h b/dxr3configdata.h new file mode 100644 index 0000000..672c3f9 --- /dev/null +++ b/dxr3configdata.h @@ -0,0 +1,76 @@ +#ifndef _DXR3_CONFIGDATA_H_ +#define _DXR3_CONFIGDATA_H_ + +//#include + +#include "dxr3singleton.h" + +// ================================== +// possible video modes +enum eVideoMode +{ + PAL = 0, + PAL60, + NTSC +}; + +// ================================== +// possible menu modes +enum eMenuMode +{ + SUBPICTURE = 0, + MPEG +}; + +// ================================== +// possible debug levels +enum eDebugLevel +{ + LOW = 0, + EVERYTHING +}; + +// ================================== +// global interface to access all config +// datas of this plugin +class cDxr3ConfigData : public Singleton +{ +public: + cDxr3ConfigData(); + ~cDxr3ConfigData() {} + + int GetUseDigitalOut() const { return UseDigitalOut; } + int SetUseDigitalOut(int value) { return UseDigitalOut = value; } + int GetDxr3Card() const { return Dxr3Card; } + int SetDxr3Card(int value) { return Dxr3Card = value; } + int GetForceLetterBox() const { return ForceLetterBox; } + int SetForceLetterBox(int value) { return ForceLetterBox = value; } + int GetAc3OutPut() const { return Ac3OutPut; } + int SetAc3OutPut(int value) { return Ac3OutPut = value;} + + eVideoMode GetVideoMode() const { return m_videoMode;} + eVideoMode SetVideoMode(eVideoMode videoMode) { return m_videoMode = videoMode;} + eMenuMode GetMenuMode() const { return m_menuMode; } + eMenuMode SetMenuMode(eMenuMode menuMode) { return m_menuMode = menuMode; } + + int GetDebug() const { return m_debug; } + int SetDebug(int value) { return m_debug = value; } + int GetDebugLevel() const { return m_debuglevel; } + int SetDebugLevel(int value) { return m_debuglevel = value; } + + // some little helpers to save some writing + int GetDebugLow() const { return (m_debug && !m_debuglevel); } + int GetDebugEverything() const { if (m_debug == 1 && m_debuglevel == 0) { return 1; } else { return 0; } } + +protected: + int UseDigitalOut; + int Dxr3Card; + int ForceLetterBox; + int Ac3OutPut; + eVideoMode m_videoMode; + eMenuMode m_menuMode; + int m_debug; + int m_debuglevel; +}; + +#endif /*_DXR3_CONFIGDATA_H_*/ diff --git a/dxr3cpu.c b/dxr3cpu.c new file mode 100644 index 0000000..4666e89 --- /dev/null +++ b/dxr3cpu.c @@ -0,0 +1,127 @@ +/* +* dxr3cpu.c +* +* Copyright (C) 2004 Christian Gmeiner +* +* Taken from Nesseia-Renderengine Copyright (C) 2003-2004 Christian Gmeiner +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License +* as published by the Free Software Foundation; either version 2.1 +* 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 Lesser General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ + +#include "dxr3cpu.h" +#include "dxr3log.h" +#include "dxr3memcpy.h" + +// ================================== +// const. +cDxr3CPU::cDxr3CPU() +{ + unsigned long eax,ebx,edx,unused; + + // readout the vendor + cpuid(0,eax,ebx,unused,edx); + + // set Vendor to "" + memset(m_Info.Vendor, 0, 16); + + // connect the single register values to the vendor string + // maybe there is an better solution - i will google :) + *(unsigned long *)(m_Info.Vendor) = ebx; + *(unsigned long *)(m_Info.Vendor + 4) = edx; + *(unsigned long *)(m_Info.Vendor + 8) = unused; + + // check the features + // could we get the needed infos? + if (cpuid(1,eax,ebx,unused,edx)) + { + m_Info.MMX = ((edx & 1<<23) != 0); + m_Info.SSE = ((edx & 1<<25) != 0); + m_Info.SSE2= ((edx & 1<<26) != 0); + m_Info.RDTSC=((edx & 1<<4) != 0); /*0x10*/ + m_Info.HT = ((edx & 1<<28) !=0); // should we do here addinonal checks? + + // 3DNow is a litle bit harder to read out + // We read the ext. CPUID level 0x80000000 + if (cpuid(0x80000000,eax,ebx,unused,edx)) + { + // now in eax there is the max. supported extended CPUID level + // we check if theres an extended CPUID level support + if (eax >= 0x80000001) + { + // If we can access the extended CPUID level 0x80000001 we get the + // edx register + if (cpuid(0x80000001,eax,ebx,unused,edx)) + { + // Now we can mask some AMD specific cpu extensions + // 22 ... Extended MMX_MultimediaExtensions + m_Info.MMXEXT = ((edx & 1<<22) != 0); + m_Info.AMD64Bit = ((edx & 1<<29) != 0); + // 30 ... Extended 3DNOW_InstructionExtensions + m_Info.Now = ((edx & (1<<31)) != 0); + } + } + } + } + + // fill cabs + if (m_Info.MMX) + { + m_Info.caps = CC_MMX; + } + + if (m_Info.MMXEXT) + { + m_Info.caps |= CC_MMXEXT; + } + + if (m_Info.SSE) + { + m_Info.caps |= CC_SSE; + } + + if (m_Info.Now) + { + m_Info.caps |= CC_3DNOW; + } + + // print some infos about cpu + cLog::Instance() << "cpu vandor: " << m_Info.Vendor << "\n"; + cLog::Instance() << "cpu extensions:\n"; + cLog::Instance() << "mmx: " << m_Info.MMX << "\n"; + cLog::Instance() << "mmx-ext: " << m_Info.MMXEXT << "\n"; + cLog::Instance() << "sse: " << m_Info.SSE << "\n"; + cLog::Instance() << "sse2: " << m_Info.SSE2 << "\n"; + cLog::Instance() << "3dnow: " << m_Info.Now << "\n"; + + // now we select the best memcpy mehtode + cDxr3MemcpyBench Benchmark(m_Info.caps); +} + +// ================================== +// does the cpu support cpuid instructions +bool cDxr3CPU::CheckCPUIDPresence() +{ + // todo + return true; +} + +// ================================== +// cpuid function +bool cDxr3CPU::cpuid(unsigned long function, unsigned long& out_eax, unsigned long& out_ebx, unsigned long& out_ecx, unsigned long& out_edx) +{ + asm("cpuid": "=a" (out_eax), "=b" (out_ebx), "=c" (out_ecx), "=d" (out_edx) : "a" (function)); + return true; +} diff --git a/dxr3cpu.h b/dxr3cpu.h new file mode 100644 index 0000000..b18f510 --- /dev/null +++ b/dxr3cpu.h @@ -0,0 +1,107 @@ +/* + * dxr3cpu.h + * + * Copyright (C) 2004 Christian Gmeiner + * + * Taken (modifized) from Nesseia-Renderengine Copyright (C) 2003-2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ + +#ifndef _DXR3_CPU_H_ +#define _DXR3_CPU_H_ + +#include +#include "dxr3singleton.h" + +// ================================== +// all possible cabs +enum Cpu_cabs +{ + CC_MMX = 0x80000000, + CC_3DNOW = 0x40000000, + CC_MMXEXT = 0x20000000, + CC_SSE = 0x10000000, + CC_SSE2 = 0x08000000 +}; + +// ================================== +// Easy and fast access to all infos +struct CPUInformation +{ + CPUInformation() + { + AMD = false; + INTEL = false; + MMX = false; + MMXEXT = false; + SSE = false; + SSE2 = false; + Now = false; + RDTSC = false; + HT = false; + AMD64Bit = false; + } + + char Vendor[16]; + + bool AMD; // is it an AMD CPU? + bool INTEL; // is it an Intel CPU? + bool MMX; // is MMX-Technology supported? + bool MMXEXT; // are Extended MMX_MultimediaExtensions supported? + bool SSE; // is SSE-Technology supported? + bool SSE2; // is SSE2-Technology supported? + bool Now; // is 3DNow-Technology supported? + bool RDTSC; // is RDTSC-Technology supported? + bool HT; // is HyperThreading supported? + bool AMD64Bit; // is it a 64 bit machine? + + uint32_t caps; // all features represanted as caps +}; + +// ================================== +//! Grab some infos about the cpu(s) +/*! +If you want to know what the cpu of the +target machine can do, this class is for you :) +It is used intern for the math and memcpy part. +*/ +class cDxr3CPU : public Singleton +{ +public: + cDxr3CPU(); + ~cDxr3CPU() {} + + bool HasMMXSupport() const { return m_Info.MMX; } + bool HasSSESupport() const { return m_Info.SSE; } + bool HasSSE2Support() const { return m_Info.SSE2; } + bool Has3DNowSupport() const { return m_Info.Now; } + bool HasRDTSCSupport() const { return m_Info.RDTSC; } + bool HasHTSupport() const { return m_Info.HT; } + + inline CPUInformation GetInfos() const { return m_Info ;} + +private: + bool CheckCPUIDPresence(); + + // main function to get cpu(s) features + bool cpuid(unsigned long function, unsigned long& out_eax, unsigned long& out_ebx, unsigned long& out_ecx, unsigned long& out_edx); + + CPUInformation m_Info; +}; + + +#endif /*_DXR3_CPU_H_*/ diff --git a/dxr3demuxdevice.c b/dxr3demuxdevice.c new file mode 100644 index 0000000..d39b07b --- /dev/null +++ b/dxr3demuxdevice.c @@ -0,0 +1,662 @@ +/* + * dxr3demuxdevice.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#include +#include +#include +#include +#include "dxr3demuxdevice.h" +#include +#include "dxr3log.h" +#include "dxr3pesframe.h" +#include "dxr3configdata.h" +#include "dxr3log.h" + +// ================================== +// constr. +cDxr3DemuxDevice::cDxr3DemuxDevice(cDxr3Interface& dxr3Device) : +m_dxr3Device(dxr3Device), +m_aBuf(AUDIO_MAX_BUFFER_SIZE, AUIDO_MAX_FRAME_SIZE, m_dxr3Device), +m_vBuf(VIDEO_MAX_BUFFER_SIZE, VIDEO_MAX_FRAME_SIZE, m_dxr3Device) +{ + m_ReUseFrame = 1; + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; + m_pAudioThread = new cDxr3AudioOutThread(dxr3Device, m_aBuf); + if (!m_pAudioThread) + { + cLog::Instance() << "cDxr3DemuxDevice::cDxr3DemuxDevice: failed to allocate memory\n"; + exit(1); + } + m_pAudioThread->Start(); + + m_pVideoThread = new cDxr3VideoOutThread(dxr3Device, m_vBuf); + if (!m_pVideoThread) + { + cLog::Instance() << "cDxr3DemuxDevice::cDxr3DemuxDevice: failed to allocate memory\n"; + exit(1); + } + m_pVideoThread->Start(); + m_aDecoder.Init(); +} + +// ================================== +cDxr3DemuxDevice::cDxr3DemuxDevice() : // dummy constructor +m_dxr3Device(cDxr3Interface::Instance()), +m_aBuf(AUDIO_MAX_BUFFER_SIZE, AUIDO_MAX_FRAME_SIZE, m_dxr3Device), +m_vBuf(VIDEO_MAX_BUFFER_SIZE, VIDEO_MAX_FRAME_SIZE, m_dxr3Device) +{ + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; +} + +// ================================== +// deconstr. +cDxr3DemuxDevice::~cDxr3DemuxDevice() +{ + if (!m_pVideoThread) + { + delete m_pVideoThread; + } + + if (!m_pVideoThread) + { + delete m_pVideoThread; + } +} + +// ================================== +// stop demuxing process +void cDxr3DemuxDevice::Stop() +{ + m_dxr3Device.DisableVideo(); + m_dxr3Device.DisableAudio(); + m_vBuf.Clear(); + m_aBuf.Clear(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + m_aDecoder.Init(); + m_vBuf.WaitForReceiverStopped(); + m_aBuf.WaitForReceiverStopped(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; + + m_dxr3Device.PlayBlackFrame(); + m_dxr3Device.ReOpenAudio(); +} + +// ================================== +void cDxr3DemuxDevice::Resync() +{ + m_dxr3Device.DisableVideo(); + m_dxr3Device.DisableAudio(); + m_vBuf.Clear(); + m_aBuf.Clear(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + m_aDecoder.Init(); + m_vBuf.WaitForReceiverStopped(); + m_aBuf.WaitForReceiverStopped(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; +} + +// ================================== +void cDxr3DemuxDevice::Clear() +{ + m_dxr3Device.DisableVideo(); + m_dxr3Device.DisableAudio(); + m_vBuf.Clear(); + m_aBuf.Clear(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + m_aDecoder.Init(); + m_vBuf.WaitForReceiverStopped(); + m_aBuf.WaitForReceiverStopped(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; +} + +// ================================== +void cDxr3DemuxDevice::Init() +{ + m_vBuf.Clear(); + m_aBuf.Clear(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; + m_aDecoder.Init(); +} + +// ================================== +void cDxr3DemuxDevice::SetTvMode() +{ + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_TV_MODE; + m_aBuf.SetDemuxMode(DXR3_DEMUX_TV_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_TV_MODE); + m_aBuf.Start(); + m_vBuf.Start(); +} + +// ================================== +void cDxr3DemuxDevice::SetAudioOnlyMode() +{ + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_AUDIO_ONLY_MODE; + m_aBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_aBuf.Start(); + m_vBuf.Start(); +} + +// ================================== +void cDxr3DemuxDevice::SetReplayMode() +{ + if (m_demuxMode != DXR3_DEMUX_REPLAY_MODE) + { + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE && m_trickState == DXR3_FREEZE) + { + m_dxr3Device.SetPlayMode(); + m_dxr3Device.SetSysClock(m_stopScr); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + } + else + { + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_aBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + } + } + m_demuxMode = DXR3_DEMUX_REPLAY_MODE; +} + +// ================================== +void cDxr3DemuxDevice::SetTrickMode(eDxr3TrickState trickState, int Speed) +{ + m_demuxMode = DXR3_DEMUX_TRICK_MODE; + m_trickState = trickState; + m_dxr3Device.DisableAudio(); + + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE && m_trickState == DXR3_FREEZE) + { + m_stopScr = m_dxr3Device.GetSysClock(); + // m_dxr3Device.Pause(); + m_vBuf.Stop(); + m_aBuf.Stop(); + } + else + { + m_vBuf.Clear(); + m_aBuf.Clear(); + } + + m_ReUseFrame = 1;//Speed; +} + +// ================================== +void cDxr3DemuxDevice::SetVideoOnlyMode() +{ + m_demuxMode = DXR3_DEMUX_VIDEO_ONLY_MODE; + m_dxr3Device.DisableAudio(); + + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE && m_trickState == DXR3_FREEZE) + { + m_stopScr = m_dxr3Device.GetSysClock(); + // m_dxr3Device.Pause(); + m_vBuf.Stop(); + m_aBuf.Stop(); + } + else + { + m_vBuf.Clear(); + m_aBuf.Clear(); + } + m_dxr3Device.SetPlayMode(); + +} + +#if VDRVERSNUM < 10307 +// ================================== +cOsdBase* cDxr3DemuxDevice::NewOsd(int x, int y) +{ + return m_dxr3Device.NewOsd(x, y); +} +#endif + +// ================================== +void cDxr3DemuxDevice::StillPicture(const uint8_t* buf, int length) +{ + m_vBuf.Clear(); + m_aBuf.Clear(); + m_demuxMode = DXR3_DEMUX_TRICK_MODE; + m_trickState = DXR3_FREEZE; + m_dxr3Device.SingleStep(); + + cLog::Instance() << "StillPicture: len = " << length << "\n"; + + DemuxPes(buf, length); + DemuxPes(buf, length); + DemuxPes(buf, length); +} + +// ================================== +int cDxr3DemuxDevice::DemuxPes(const uint8_t* buf, int length, bool bAc3Dts) +{ + uint32_t pts = 0; + static uint32_t aPts = 0; + static uint32_t vPts = 0; + static uint32_t lastPts = 0; + static bool bPlaySuc = false; + static bool bPlayedFrame = false; + int origLength = length; + + int scr = 0; + int pcr = 0; + + scr = m_dxr3Device.GetSysClock(); + + // printf("vBuf size = %d\n", m_vBuf.Available()); + // printf("aBuf size = %d\n", m_aBuf.Available()); + /* + if (cDxr3ConfigData::Instance().GetAc3OutPut()) { + cDxr3AbsDevice::Instance().SetAudioDigitalAC3(); // !!! FIXME + } + */ + + if (m_pAudioThread->NeedResync() || m_pVideoThread->NeedResync()) + { + Resync(); + if (m_demuxMode == DXR3_DEMUX_REPLAY_MODE) + { + SetReplayMode(); + } + m_aBuf.Clear(); + m_vBuf.Clear(); + m_pAudioThread->ClearResyncRequest(); + m_pVideoThread->ClearResyncRequest(); + m_aDecoder.Reset(); + lastPts = 0; + aPts = 0; + vPts = 0; + bPlaySuc = false; + } + + if (m_demuxMode == DXR3_DEMUX_OFF_MODE) + { + m_demuxMode = DXR3_DEMUX_TV_MODE; + m_synchState = DXR3_DEMUX_UNSYNCHED; + + lastPts = 0; + aPts = 0; + vPts = 0; + bPlaySuc = false; + /* + if (cDxr3ConfigData::Instance().GetAc3OutPut()) { + cDxr3AbsDevice::Instance().SetAudioDigitalAC3(); // !!! FIXME + } + */ + } + + // find start code + try + { + cDxr3PesFrame pesFrame; + + pesFrame.ExtractNextFrame(buf, length); + + while (pesFrame.IsValid()) + { + if (pesFrame.GetEsLength() > (uint32_t) VIDEO_MAX_FRAME_SIZE) { throw (cDxr3PesFrame::PES_GENERAL_ERROR);}; + if (pesFrame.GetPts() != lastPts) + { + pts = lastPts = pesFrame.GetPts(); + } + else + { + pts = 0; + } + + if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_VIDEO_DATA) + { + // m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength())); + + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE) + { + switch (pesFrame.GetFrameType()) + { + case I_FRAME: + cLog::Instance() << "i - frame\n"; + m_dxr3Device.SingleStep(); + bPlaySuc = true; + // if (bPlayedFrame) return length; + bPlayedFrame = true; + // usleep(30000); // otherwise there is problem with audio (driver bug?) + m_dxr3Device.SetHorizontalSize(pesFrame.GetHorizontalSize()); + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), m_ReUseFrame); + break; + + case UNKNOWN_FRAME: + cLog::Instance() << "frame unknown\n"; + if (bPlaySuc) + { + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), m_ReUseFrame); + } + break; + + default: + cLog::Instance() << "default frame\n"; + if (bPlaySuc) + { + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetOffset()), m_ReUseFrame); + } + + bPlaySuc = false; + break; + } + + } + else if (m_demuxMode == DXR3_DEMUX_VIDEO_ONLY_MODE) + { + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength())); + } + else if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + m_dxr3Device.SetHorizontalSize(pesFrame.GetHorizontalSize()); + while(!Poll(100)); + cFixedLengthFrame* pTempFrame = m_vBuf.Push(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, ftVideo); + pTempFrame->SetAspectRatio(pesFrame.GetAspectRatio()); + + m_aBuf.WakeUp(); + + if (m_vBuf.GetFillLevel() > 5 && m_synchState != DXR3_DEMUX_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + pcr = vPts - PRE_BUFFER_LENGTH; + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + else + { + if (pesFrame.GetFrameType() == I_FRAME) + { + vPts = pts; + + m_dxr3Device.SetHorizontalSize(pesFrame.GetHorizontalSize()); + cFixedLengthFrame* pTempFrame = m_vBuf.Push(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, ftVideo); + pTempFrame->SetAspectRatio(pesFrame.GetAspectRatio()); + + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_VIDEO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + + } + else if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_AUDIO_DATA + && m_demuxMode != DXR3_DEMUX_VIDEO_ONLY_MODE + && !cDxr3ConfigData::Instance().GetAc3OutPut()) + { + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + if (pts && m_synchState != DXR3_DEMUX_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + pcr = aPts - PRE_BUFFER_LENGTH; + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + while(!Poll(100)); + m_aDecoder.Decode(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, m_aBuf); + + } + else + { + if (pts) + { + aPts = pts; + + m_aDecoder.Decode(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, m_aBuf); + + if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + } + else if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_PRIVATE_DATA + && m_demuxMode != DXR3_DEMUX_VIDEO_ONLY_MODE + && !cDxr3ConfigData::Instance().GetAc3OutPut() + && !bAc3Dts) + { + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + m_aDecoder.DecodeLpcm(pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + } + else + { + if (pts) + { + aPts = pts; + m_aDecoder.DecodeLpcm(pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + + if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + } + else if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_PRIVATE_DATA + && m_demuxMode != DXR3_DEMUX_VIDEO_ONLY_MODE + && cDxr3ConfigData::Instance().GetAc3OutPut() + && bAc3Dts) + { + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + m_aDecoder.DecodeAc3Dts(pesFrame.GetPesStart(), pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + } + else + { + if (pts) + { + aPts = pts; + m_aDecoder.DecodeAc3Dts(pesFrame.GetPesStart(), pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + + if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + + } + + if (pesFrame.IsValid()) + { + pesFrame.ExtractNextFrame(pesFrame.GetNextStart(), pesFrame.GetRemainingLength()); + } + + } + + length -= pesFrame.GetRemainingLength(); + + // if (m_demuxMode == DXR3_DEMUX_TRICK_MODE) return origLength; + return length; + } + catch (cDxr3PesFrame::ePesFrameError err) + { + dsyslog("cDxr3DemuxDevice::DemuxPes() ePesFrameError skipping data and resync"); + Resync(); + return origLength; + } + catch (cDxr3SyncBuffer::eSyncBufferException err) + { + Stop(); + return origLength; + } +} + +// ================================== +int cDxr3DemuxDevice::DemuxAudioPes(const uint8_t* buf, int length) +{ + static int syncCounter = 0; + int origLength = length; + + m_demuxMode = DXR3_DEMUX_AUDIO_ONLY_MODE; + m_aBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + + try + { + cDxr3PesFrame pesFrame; + + pesFrame.ExtractNextFrame(buf, length); + + while (pesFrame.IsValid()) + { + if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_PRIVATE_DATA) + { + if (m_synchState != DXR3_DEMUX_AUDIO_SYNCHED && syncCounter > 2) + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + if (m_synchState != DXR3_DEMUX_AUDIO_SYNCHED && syncCounter <= 2) + { + syncCounter++; + } + while (!m_aBuf.Poll(100)); + m_aDecoder.DecodeLpcm(pesFrame.GetEsStart(), pesFrame.GetEsLength(), 0, m_aBuf); + + } + + if (pesFrame.IsValid()) + { + pesFrame.ExtractNextFrame(pesFrame.GetNextStart(), pesFrame.GetRemainingLength()); + } + } + + length -= pesFrame.GetRemainingLength(); + + return length; + } + catch (cDxr3PesFrame::ePesFrameError err) + { + dsyslog("cDxr3DemuxDevice::DemuxAudioPes() ePesFrameError skipping data and resync"); + Stop(); + return origLength; + } +} diff --git a/dxr3demuxdevice.h b/dxr3demuxdevice.h new file mode 100644 index 0000000..0bd6add --- /dev/null +++ b/dxr3demuxdevice.h @@ -0,0 +1,75 @@ +/* + * dxr3demuxdevice.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef __DXR3_DEMUX_DEVICE_H +#define __DXR3_DEMUX_DEVICE_H + +#include "dxr3vdrincludes.h" +#include "dxr3generaldefines.h" +#include "dxr3syncbuffer.h" +#include "dxr3audiodecoder.h" +#include "dxr3outputthread.h" + +const int AUDIO_MAX_BUFFER_SIZE = 200; +const int VIDEO_MAX_BUFFER_SIZE = 500; + +const int AUIDO_MAX_FRAME_SIZE = 5000; +const int VIDEO_MAX_FRAME_SIZE = 3000; +const uint32_t PRE_BUFFER_LENGTH = 0; + +// ================================== +// extract video and audio +class cDxr3DemuxDevice +{ +public: + cDxr3DemuxDevice(); + cDxr3DemuxDevice(cDxr3Interface& dxr3Device); + ~cDxr3DemuxDevice(); + +public: + void Stop(void); + void Resync(void); + void Clear(void); + void Init(void); + void SetTvMode(void); + void SetAudioOnlyMode(void); + void SetVideoOnlyMode(void); + void SetReplayMode(void); + void SetTrickMode(eDxr3TrickState trickState, int Speed = 1); + + #if VDRVERSNUM < 10307 + cOsdBase* NewOsd(int x, int y); + #endif + + int DemuxPes(const uint8_t* buf, int length, bool bAc3Dts = false); + int DemuxAudioPes(const uint8_t* buf, int length); + void StillPicture(const uint8_t* buf, int length); + + eDxr3DemuxMode GetDemuxMode(void) { return m_demuxMode;}; + eDxr3TrickState GetTrickState(void) { return m_trickState;}; + bool Poll(int TimeoutMs){ return m_aBuf.Poll(TimeoutMs) && m_vBuf.Poll(TimeoutMs); }; + // { return m_demuxMode == DXR3_DEMUX_AUDIO_ONLY_MODE ? m_aBuf.Poll(TimeoutMs) : m_aBuf.Poll(TimeoutMs); }; + +protected: + cDxr3Interface& m_dxr3Device; + cDxr3SyncBuffer m_aBuf; + cDxr3SyncBuffer m_vBuf; + eDxr3DemuxSynchState m_synchState; + eDxr3DemuxMode m_demuxMode; + eDxr3TrickState m_trickState; + cDxr3AudioDecoder m_aDecoder; + cDxr3AudioOutThread* m_pAudioThread; + cDxr3VideoOutThread* m_pVideoThread; + uint32_t m_stopScr; + int m_ReUseFrame; // how often a frame should be used + +private: + cDxr3DemuxDevice(cDxr3DemuxDevice&); // no copy constructor +}; + +#endif // __DXR3_DEMUX_DEVICE_H diff --git a/dxr3device.c b/dxr3device.c new file mode 100644 index 0000000..b7e2553 --- /dev/null +++ b/dxr3device.c @@ -0,0 +1,472 @@ +#include "dxr3device.h" +#include "dxr3configdata.h" +#include "dxr3interface.h" +#include "dxr3tools.h" +#include "dxr3log.h" + +extern "C" +{ + #include +} + +// ================================== +cDxr3Device::cDxr3Device() : m_DemuxDevice(cDxr3Interface::Instance()) +{ + m_Offset = 0; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); + m_spuDecoder = NULL; + m_AC3Present = false; + m_CalledBySet = false; +} + +// ================================== +cDxr3Device::~cDxr3Device() +{ + if (m_spuDecoder) + { + delete m_spuDecoder; + } +} + +// ================================== +void cDxr3Device::MakePrimaryDevice(bool On) +{ +#if VDRVERSNUM >= 10307 + new cDxr3OsdProvider(); +#endif +} + +// replaying +// ================================== +bool cDxr3Device::HasDecoder() const +{ + // sure we have one ;) + return true; +} + +// ================================== +bool cDxr3Device::CanReplay() const +{ + // also sure... + return true; +} + +// ================================== +bool cDxr3Device::SetPlayMode(ePlayMode PlayMode) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + switch (PlayMode) + { + case pmNone: + cLog::Instance() << "cDxr3Device::SetPlayMode audio/video from decoder\n"; + break; + + case pmAudioVideo: + cLog::Instance() << "cDxr3Device::SetPlayMode audio/video from player\n"; + break; + + case pmAudioOnly: + cLog::Instance() << "cDxr3Device::SetPlayMode audio only from player, video from decoder\n"; + break; + + case pmAudioOnlyBlack: + cLog::Instance() << "cDxr3Device::SetPlayMode audio only from player, no video (black screen)\n"; + break; + + case pmExtern_THIS_SHOULD_BE_AVOIDED: + cLog::Instance() << "cDxr3Device::SetPlayMode this should be avoided\n"; + break; + + #if VDRVERSNUM >= 10307 + case pmVideoOnly: + cLog::Instance() << "cDxr3Device::SetPlayMode video only from player, audio from decoder\n"; + break; + #endif + } + } + + if (PlayMode == pmExtern_THIS_SHOULD_BE_AVOIDED) + { + Tools::WriteInfoToOsd("Dxr3: Releasing devices\n"); + cDxr3Interface::Instance().ExternalReleaseDevices(); + } + else + { + cDxr3Interface::Instance().ExternalReopenDevices(); + } + + // should this relay be here? + m_Offset = 0; + m_AC3Present = false; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); + + if (PlayMode == pmAudioOnlyBlack) + { + m_PlayMode = pmAudioOnly; + } + else + { + m_PlayMode = PlayMode; + } + + if (m_PlayMode == pmAudioVideo) + { + m_DemuxDevice.SetReplayMode(); + } + + if (m_PlayMode == pmNone) + { + m_DemuxDevice.Stop(); + } + + cLog::Instance() << "Setting audio mode..."; + + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + if (cDxr3ConfigData::Instance().GetAc3OutPut() && m_CalledBySet) + { + cDxr3Interface::Instance().SetAudioDigitalAC3(); // !!! FIXME + cLog::Instance() << "ac3\n"; + } + else + { + cDxr3Interface::Instance().SetAudioDigitalPCM(); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + cLog::Instance() << "digital pcm\n"; + } + } + else + { + cDxr3Interface::Instance().SetAudioAnalog(); + cLog::Instance() << "analog\n"; + } + + return true; +} + +// ================================== +int64_t cDxr3Device::GetSTC() +{ + return cDxr3Interface::Instance().GetSysClock(); +} + +// ================================== +void cDxr3Device::TrickSpeed(int Speed) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::TrickSpeed(int Speed): " << Speed << "\n"; + } + + + m_DemuxDevice.SetTrickMode(DXR3_FAST, Speed); + + +/* + switch (Speed) + { + case 6: + cLog::Instance() << "Trickspeed: 1x vorwärts\n"; + break; + + case 3: + cLog::Instance() << "Trickspeed: 2x vorwärts\n"; + break; + + case 1: + cLog::Instance() << "Trickspeed: 3x vorwärts\n"; + break; + }; +*/ +/* + 6 ... 1x vowärts + 3 ... 2x vowärts + 1 ... 2x vowärts + + 6 ... 1x rückwärts + 3 ... 2x rückwärts + 1 ... 3x rückwärts + + 8 ... 1x vorwörts, wenn Pause gedrückt +*/ + + /* +#define EM8300_PLAYMODE_PAUSED 1 +#define EM8300_PLAYMODE_SLOWFORWARDS 2 +#define EM8300_PLAYMODE_SLOWBACKWARDS 3 +#define EM8300_PLAYMODE_SINGLESTEP 4 + */ + /* + if (Speed == 8) + { + cDxr3Interface::Instance().SingleStep(); + } + else + { + m_DemuxDevice.SetTrickMode(DXR3_FAST); + }*/ +} + +// ================================== +// clear our demux buffer +void cDxr3Device::Clear() +{ + m_DemuxDevice.Clear(); + m_Offset = 0; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); +} + +// ================================== +// play a recording +void cDxr3Device::Play() +{ + m_DemuxDevice.SetReplayMode(); + m_Offset = 0; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); +} + +// ================================== +// puts the device into "freeze frame" mode +void cDxr3Device::Freeze() +{ + m_DemuxDevice.SetTrickMode(DXR3_FREEZE); +} + +// ================================== +void cDxr3Device::Mute() +{ + m_DemuxDevice.SetTrickMode(DXR3_FAST); +} + +// ================================== +// displays the given I-frame as a still picture. +void cDxr3Device::StillPicture(const uchar *Data, int Length) +{ + m_DemuxDevice.StillPicture(Data, Length); +} + +// ================================== +bool cDxr3Device::Poll(cPoller &Poller, int TimeoutMs) +{ + return m_DemuxDevice.Poll(TimeoutMs); // Poller.Poll(TimeoutMs); +} + +// ================================== +// actually plays the given data block as video +int cDxr3Device::PlayVideo(const uchar *Data, int Length) +{ + int retLength = 0; + int origLength = Length; + + if ((m_DemuxDevice.GetDemuxMode() == DXR3_DEMUX_TRICK_MODE && + m_DemuxDevice.GetTrickState() == DXR3_FREEZE) || cDxr3Interface::Instance().IsExternalReleased()) + { + // Why is here so a huge time waster? + //usleep(1000000); + return 0; + } + + if (m_strBuf.length()) + { + m_strBuf.append((const char*)Data, Length); + + if (m_PlayMode == pmAudioOnly) + { + retLength = m_DemuxDevice.DemuxAudioPes((const uint8_t*)m_strBuf.data(), m_strBuf.length()); + } + else + { + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)m_strBuf.data(), m_strBuf.length()); + } + } + else + { + if (m_PlayMode == pmAudioOnly) + { + retLength = m_DemuxDevice.DemuxAudioPes((const uint8_t*)Data, Length); + } + else + { + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)Data, Length); + } + } + + Length -= retLength; + + if (m_strBuf.length()) + { + m_strBuf.erase(m_strBuf.length() - retLength, retLength); + } + else + { + if (Length) + { + m_strBuf.append((const char*)(Data + retLength), Length); + } + } + + return origLength; +} + +// ================================== +// plays additional audio streams, like Dolby Digital +void cDxr3Device::PlayAudio(const uchar *Data, int Length) +{ + int retLength = 0; + + #if VDRVERSNUM < 10307 + if (!m_AC3Present) + { + Interface->Write(Interface->Width() / 2, 0, "AC3", clrRed); + } + #endif + + m_AC3Present = true; + + if ((m_DemuxDevice.GetDemuxMode() == DXR3_DEMUX_TRICK_MODE && + m_DemuxDevice.GetTrickState() == DXR3_FREEZE) || cDxr3Interface::Instance().IsExternalReleased()) + { + //usleep(1000000); + return; + } + + if (m_strBuf.length()) + { + m_strBuf.append((const char*)Data, Length); + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)m_strBuf.data(), m_strBuf.length(), true); + } + else + { + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)Data, Length, true); + } + + Length -= retLength; + + if (m_strBuf.length()) + { + m_strBuf.erase(m_strBuf.length() - retLength, retLength); + } + else + { + if (Length) + { + m_strBuf.append((const char*)(Data + retLength), Length); + } + } +} + +// addition functions +// ================================== +// capture a single frame as an image +bool cDxr3Device::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) +{ + int w = SizeX; + int h = SizeY; + unsigned char *Data = new unsigned char[w*h*3]; + memset(Data, 0, w*h*3); + + // we could get a I-Frame and save it + //m_DemuxDevice.StillPicture(Data, 100*1024); + + isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, w, h); + FILE *f = fopen(FileName, "wb"); + if (f) + { + if (Jpeg) + { + // write JPEG file: + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = w; + cinfo.image_height = h; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, Quality, true); + jpeg_start_compress(&cinfo, true); + + int rs = w * 3; + JSAMPROW rp[h]; + for (int k = 0; k < h; k++) + { + rp[k] = &Data[rs * k]; + } + jpeg_write_scanlines(&cinfo, rp, h); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + } + else + { + // write PNM file: + if (fprintf(f, "P6\n%d\n%d\n255\n", w, h) < 0 || fwrite(Data, w * h * 3, 1, f) < 0) + { + LOG_ERROR_STR(FileName); + } + } + fclose(f); + } + else + { + return false; + } + + delete Data; + return true; +} + +// ================================== +void cDxr3Device::SetVideoFormat(bool VideoFormat16_9) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::SetPlayMode(ePlayMode PlayMode)() done\n"; + } + // Do we need this function? +} + +// ================================== +// sets volume for audio output +void cDxr3Device::SetVolumeDevice(int Volume) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "change volume to " << Volume << " \n"; + } + cDxr3Interface::Instance().SetVolume(Volume); +} + +// ================================== +// get spudecoder +cSpuDecoder *cDxr3Device::GetSpuDecoder(void) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::GetSpuDecoder"; + } + + if (!m_spuDecoder && IsPrimaryDevice()) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::GetSpuDecoder: ok"; + } + m_spuDecoder = new cDxr3SpuDecoder(); + } + return m_spuDecoder; +} + +#if VDRVERSNUM < 10307 +// ================================== +// return osd +cOsdBase *cDxr3Device::NewOsd(int x, int y) +{ + return m_DemuxDevice.NewOsd(x, y); +} +#endif + diff --git a/dxr3device.h b/dxr3device.h new file mode 100644 index 0000000..69ad28d --- /dev/null +++ b/dxr3device.h @@ -0,0 +1,65 @@ +#ifndef _DXR3_DEVICE_H_ +#define _DXR3_DEVICE_H_ + +#include "dxr3interface.h" +#include "dxr3log.h" +#include "dxr3demuxdevice.h" +#include "dxr3spudecoder.h" +#include +using namespace std; + +// ================================== +// our device :) +class cDxr3Device : public cDevice, public Singleton +{ +public: + cDxr3Device(); + cDxr3Device(cDxr3Interface& demuxDevice); + ~cDxr3Device(); + + virtual void MakePrimaryDevice(bool On); + + // replaying + virtual bool HasDecoder() const; + virtual bool CanReplay() const; + virtual bool SetPlayMode(ePlayMode PlayMode); + virtual int64_t GetSTC(); + virtual void TrickSpeed(int Speed); + virtual void Clear(); + virtual void Play(); + virtual void Freeze(); + virtual void Mute(); + virtual void StillPicture(const uchar *Data, int Length); + virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); + virtual int PlayVideo(const uchar *Data, int Length); + virtual void PlayAudio(const uchar *Data, int Length); + + // addition functions + virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + virtual void SetVideoFormat(bool VideoFormat16_9); + virtual void SetVolumeDevice(int Volume); + + // osd + virtual cSpuDecoder *GetSpuDecoder(); + #if VDRVERSNUM < 10307 + virtual cOsdBase* NewOsd(int x, int y); + #endif + + // helper function + void Reset() { m_CalledBySet = true; SetPlayMode(m_PlayMode); m_CalledBySet = false; } + +protected: + ePlayMode m_PlayMode; + cDxr3DemuxDevice m_DemuxDevice; + bool m_AC3Present; + bool m_CalledBySet; + string m_strBuf; + int m_Offset; + + //virtual bool SetPlayMode(ePlayMode PlayMode); + //uint8_t m_pBuffer[MAX_VIDEO_BUFFER_SIZE]; + //cDxr3StartStopThread* m_pStartStopThread; + cDxr3SpuDecoder* m_spuDecoder; +}; + +#endif /*_DXR3_DEVICE_H_*/ diff --git a/dxr3ffmpeg.c b/dxr3ffmpeg.c new file mode 100644 index 0000000..e35319a --- /dev/null +++ b/dxr3ffmpeg.c @@ -0,0 +1,72 @@ +/* + * dxr3audiodecoder.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#include "dxr3ffmpeg.h" + +#include "dxr3configdata.h" +#include "dxr3log.h" + +// ================================== +cDxr3Ffmepg::cDxr3Ffmepg() +{ + avcodec_init(); + avcodec_register_all(); +} + +// ================================== +bool cDxr3Ffmepg::FindCodec(struct Dxr3Codec& Codec) +{ + // find codec + Codec.codec = avcodec_find_decoder(Codec.id); + + if (!Codec.codec) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Ffmepg::OpenCodec(struct Dxr3Codec& Codec) codec not found (" << Codec.id << ")\n"; + } + return false; + } + + // init codec_context + memset(&Codec.codec_context, 0, sizeof(Codec.codec_context)); + + return true; +} + +// ================================== +bool cDxr3Ffmepg::OpenCodec(struct Dxr3Codec& Codec) +{ + // try to open codec + int result = avcodec_open(&Codec.codec_context, Codec.codec); + + if (result < 0) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Ffmepg::OpenCodec(struct Dxr3Codec& Codec) coudnt open codec (" << Codec.id << ")\n"; + } + return false; + } + else + { + Codec.Open = true; + } + + return true; +} + +// ================================== +void cDxr3Ffmepg::CloseCodec(struct Dxr3Codec& Codec) +{ + if (Codec.Open) + { + avcodec_close(&Codec.codec_context); + Codec.Open = false; + } +} diff --git a/dxr3ffmpeg.h b/dxr3ffmpeg.h new file mode 100644 index 0000000..7795f74 --- /dev/null +++ b/dxr3ffmpeg.h @@ -0,0 +1,42 @@ +#ifndef _DXR3_FFMPEG_H_ +#define _DXR3_FFMPEG_H_ + +extern "C" +{ + #include +}; + +//#include +//#include +#include +#include "dxr3singleton.h" + +// ================================== +// a codec used by this plugin +struct Dxr3Codec +{ + Dxr3Codec() : Open(false) {} + + AVCodec* codec; + AVCodecContext codec_context; + enum CodecID id; + bool Open; +}; + +// ================================== +// class to work with ffmpeg +class cDxr3Ffmepg : public Singleton +{ +public: + cDxr3Ffmepg(); + ~cDxr3Ffmepg() {} + + bool FindCodec(struct Dxr3Codec& Codec); + bool OpenCodec(struct Dxr3Codec& Codec); + void CloseCodec(struct Dxr3Codec& Codec); + +private: + cDxr3Ffmepg(cDxr3Ffmepg&); // no copy constructor +}; + +#endif /*_DXR3_FFMPEG_H_*/ diff --git a/dxr3generaldefines.h b/dxr3generaldefines.h new file mode 100644 index 0000000..29a0ae6 --- /dev/null +++ b/dxr3generaldefines.h @@ -0,0 +1,37 @@ +/* + * dxr3generaldefines.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef __DXR3_GENERAL_DEFINES_H +#define __DXR3_GENERAL_DEFINES_H + +enum eDxr3DemuxSynchState { + DXR3_DEMUX_AUDIO_SYNCHED, + DXR3_DEMUX_VIDEO_SYNCHED, + DXR3_DEMUX_SYNCHED, + DXR3_DEMUX_UNSYNCHED +}; + +enum eDxr3DemuxMode { + DXR3_DEMUX_TV_MODE, + DXR3_DEMUX_REPLAY_MODE, + DXR3_DEMUX_AUDIO_ONLY_MODE, + DXR3_DEMUX_VIDEO_ONLY_MODE, + DXR3_DEMUX_TRICK_MODE, + DXR3_DEMUX_OFF_MODE +}; + +enum eDxr3TrickState { + DXR3_FAST, + DXR3_SLOW, + DXR3_FREEZE, +}; + + + + +#endif // __DXR3_GENERAL_DEFINES_H diff --git a/dxr3i18n.c b/dxr3i18n.c new file mode 100644 index 0000000..2c91e33 --- /dev/null +++ b/dxr3i18n.c @@ -0,0 +1,804 @@ +#include "dxr3i18n.h" + +const char *i18n_name = 0; + +// vdr 1.1.32 -> 16 +// vdr 1.3.2 -> 17 +// vdr 1.3.7 -> 18 + +// Digital audio output +// DXR3 card +// DXR3 video mode +// DXR3 menu mode +// Reset DXR3 Hardware +// Toggle Force LetterBox +// Analog Output +// AC3 Output On +// AC3 Output Off +// Digital Output +// Sub-Picutre +// MPEG +// Dxr3: Releasing devices + +// add +// Dxr3: Releasing devices +/* + * Translations provided by: + * + * Slovenian Miha Setina and Matjaz Thaler + * Italian Alberto Carraro and Antonio Ospite + * Dutch Arnold Niessen and Hans Dingemans + * Portuguese Paulo Lopes + * French Jean-Claude Repetto , Olivier Jacques and Gregoire Favre + * Norwegian Jørgen Tvedt and Truls Slevigen + * Finnish Hannu Savolainen , Jaakko Hyvätti , Niko Tarnanen and Rolf Ahrenberg + * Polish Michael Rakowski + * Spanish Ruben Nunez Francisco + * Greek Dimitrios Dimitrakos + * Swedish Tomas Prybil and Jan Ekholm + * Romanian Paul Lacatus + * Hungarian Istvan Koenigsberger and Guido Josten + * Catalanian Marc Rovira Vall , Ramon Roca and Jordi Vilà + * Russian Vyacheslav Dikonov + * Croatian Drazen Dupor + * + */ + + +#if VDRVERSNUM >= 10307 +// vdr 1.3.7 -> 18 languages + +/* +const tI18nPhrase Phrases[] = { + // The name of the language (this MUST be the first phrase!): + { "English", + "Deutsch", + "Slovenski", + "Italiano", + "Nederlands", + "Português", + "Français", + "Norsk", + "suomi", // this is not a typo - it's really lowercase! + "Polski", + "Español", + "ÅëëçíéêÜ", // Greek + "Svenska", + "Romaneste", + "Magyar", + "Català", + "ÀãááÚØÙ", // Russian + "Hrvatski", + }, +*/ + +const tI18nPhrase Phrases[] = { + { + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + }, + { + "Digital audio output", + "Digitaler Audioausgang", + "", // TODO + "", // TODO + "", // TODO + "Saída áudio digital", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 card", + "DXR3 Karte", + "", // TODO + "", // TODO + "", // TODO + "Placa DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 video mode", + "DXR3 Video-Modus", + "", // TODO + "", // TODO + "", // TODO + "Modo vídeo DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 menu mode", + "DXR3 Menü-Modus", + "", // TODO + "", // TODO + "", // TODO + "Modo menu DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Reset DXR3 Hardware", + "Resete DXR3 Hardware", + "", // TODO + "", // TODO + "", // TODO + "Reiniciar DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Toggle Force LetterBox", + "LetterBox erzwingen", + "", // TODO + "", // TODO + "", // TODO + "Activar Forçar LetterBox", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Analog Output", + "Analoge Ausgabe", + "", // TODO + "", // TODO + "", // TODO + "Saída Analógica", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output On", + "AC3 Ausgabe Ein", + "", // TODO + "", // TODO + "", // TODO + "Saída AC3 Activa", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output Off", + "AC3 Ausgabe Aus", + "", // TODO + "", // TODO + "", // TODO + "Saída AC3 Inactiva", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Digital Output", + "Digitaler Ausgang", + "", // TODO + "", // TODO + "", // TODO + "Saída Digital", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Imagem", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + }, + { "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + }, + { "DXR3: Releasing devices", + "DXR3: Releasing devices", + "", // TODO + "", // TODO + "", // TODO + "DXR3: A libertar dispositivos", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { NULL } +}; + + +#elif VDRVERSNUM <= 10302 +// vdr 1.1.32 -> 16 languages + +const tI18nPhrase Phrases[] = { + { + "Digital audio output", + "Digitaler Audioausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 card", + "DXR3 Karte", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 video mode", + "DXR3 Video-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 menu mode", + "DXR3 Menü-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Reset DXR3 Hardware", + "Resete DXR3 Hardware", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Toggle Force LetterBox", + "LetterBox erzwingen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Analog Output", + "Analoge Ausgabe", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output On", + "AC3 Ausgabe Ein", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output Off", + "AC3 Ausgabe Aus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Digital Output", + "Digitaler Ausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + }, + { "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + }, + { NULL } +}; + +#else +// vdr 1.3.2 -> 17 languages + +const tI18nPhrase Phrases[] = { + { + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + }, + { + "Digital audio output", + "Digitaler Audioausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 card", + "DXR3 Karte", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 video mode", + "DXR3 Video-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 menu mode", + "DXR3 Menü-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Reset DXR3 Hardware", + "Resete DXR3 Hardware", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Toggle Force LetterBox", + "LetterBox erzwingen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Analog Output", + "Analoge Ausgabe", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output On", + "AC3 Ausgabe Ein", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output Off", + "AC3 Ausgabe Aus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Digital Output", + "Digitaler Ausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + }, + { "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + }, + { NULL } +}; + +#endif diff --git a/dxr3i18n.h b/dxr3i18n.h new file mode 100644 index 0000000..990d2ee --- /dev/null +++ b/dxr3i18n.h @@ -0,0 +1,12 @@ +#ifndef _DXR3_I18N_H_ +#define _DXR3_I18N_H_ + +#include + +extern const char *i18n_name; +extern const tI18nPhrase Phrases[]; + +#undef tr +#define tr(s) I18nTranslate(s, i18n_name) + +#endif /*_DXR3_I18N_H_*/ diff --git a/dxr3interface.c b/dxr3interface.c new file mode 100644 index 0000000..50302d6 --- /dev/null +++ b/dxr3interface.c @@ -0,0 +1,1072 @@ +#include +#include +#include +#include "dxr3interface.h" +#include "dxr3syncbuffer.h" + +#include "dxr3log.h" +#include "dxr3configdata.h" + +// ================================== +const int LPCM_HEADER_LENGTH = 7; +const int ZEROBUFFER_SIZE = 4096; +uint8_t zerobuffer[ZEROBUFFER_SIZE] = {0}; + +// ================================== +// helper function to generate name +static const char *Dxr3Name(const char *Name, int n) +{ + static char buffer[PATH_MAX]; + snprintf(buffer, sizeof(buffer), "/dev/em8300%s-%d", Name, n); + return buffer; +} + +// ================================== +// helper function to open the card #n +static int Dxr3Open(const char *Name, int n, int Mode) +{ + const char *FileName = Dxr3Name(Name, n); + int fd = open(FileName, Mode); + + if (fd < 0) + { + cLog::Instance() << "Unable to open " << FileName << "\n"; + } + return fd; +} + +// ================================== +cDxr3Interface::cDxr3Interface() +{ + // open control stream + m_fdControl = Dxr3Open("", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + if (!m_fdControl) + { + cLog::Instance() << "Unable to open the control stream!\n"; + cLog::Instance() << "Please check if the dxr3 modules are loaded!\n"; + } + + // upload microcode to dxr3 + UploadMicroCode(); + + // open 'multimedia' streams + m_fdVideo = Dxr3Open("_mv", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdAudio = Dxr3Open("_ma", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdSpu = Dxr3Open("_sp", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + + // everything ok? + if (!m_fdVideo || !m_fdAudio || !m_fdSpu) + { + cLog::Instance() << "Unable to open one of the 'mulitmedia' streams!\n"; + exit(1); + } + + m_pClock = new cDxr3SysClock(m_fdControl, m_fdVideo, m_fdSpu); + + if (!m_pClock) + { + cLog::Instance() << "Unable to allocate memory for m_pClock in cDxr3Interface\n"; + exit(1); + } + + // set default values + m_AudioActive = false; + m_VideoActive = false; + m_OverlayActive = false; + m_ExternalReleased = false; + m_volume = 255; + m_horizontal = 720; + m_audioChannelCount = UNKNOWN_CHANNEL_COUNT; + m_audioDataRate = 0; + m_audioSampleSize = 0; + + // default value 9 = unused value + m_audioMode = 9; + m_aspectRatio = UNKNOWN_ASPECT_RATIO; + m_spuMode = EM8300_SPUMODE_OFF; + + // configure device based on settings + ConfigureDevice(); + + PlayBlackFrame(); + SetChannelCount(1); +} + +// ================================== +cDxr3Interface::~cDxr3Interface() +{ + // close filehandles + if (m_fdControl) + { + close(m_fdControl); + } + if (m_fdVideo) + { + close(m_fdVideo); + } + if (m_fdSpu) + { + close(m_fdSpu); + } + if (m_fdAudio) + { + close(m_fdAudio); + } + + // free some memory + if (m_pClock) + { + delete m_pClock; + } +} + +// main +// ================================== +void cDxr3Interface::Start() +{ +} + +// ================================== +void cDxr3Interface::Stop() +{ +} + +// audio +// ================================== +// set audio-output to analog +void cDxr3Interface::SetAudioAnalog() +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_audioMode != EM8300_AUDIOMODE_ANALOG) + { + int prevMode = m_audioMode; + m_audioMode = ioval = EM8300_AUDIOMODE_ANALOG; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_AUDIOMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioAnalog Unable to set audiomode!\n"; + } + if (prevMode == EM8300_AUDIOMODE_DIGITALAC3) + { + ReOpenAudio(); + } + } + + Unlock(); +} + +// ================================== +// set audio-output to digital pcm +void cDxr3Interface::SetAudioDigitalPCM() +{ + int ioval = 0; + Lock(); + + if (m_ExternalReleased && m_audioMode != EM8300_AUDIOMODE_DIGITALPCM) + { + int prevMode = m_audioMode; + m_audioMode = ioval = EM8300_AUDIOMODE_DIGITALPCM; + + if (ioctl(m_fdControl, EM8300_IOCTL_SET_AUDIOMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioAnalog Unable to set audiomode!\n"; + } + if (prevMode == EM8300_AUDIOMODE_DIGITALAC3) + { + ReOpenAudio(); + } + } + + Unlock(); +} + +// ================================== +// set audio-output to digital ac3 +void cDxr3Interface::SetAudioDigitalAC3() +{ + if (m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + m_audioMode = ioval = EM8300_AUDIOMODE_DIGITALAC3; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_AUDIOMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioAnalog Unable to set audiomode!\n"; + } + ReOpenAudio(); + } + + Unlock(); + } +} + +// ================================== +void cDxr3Interface::SetAudioSpeed(uint32_t speed) +{ + if (m_audioDataRate != speed && speed != UNKNOWN_DATA_RATE) + { + if (!m_ExternalReleased) + { + if (m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + if(ioctl(m_fdAudio, SNDCTL_DSP_SPEED, &speed) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioSpeed Unable to set dsp speed\n"; + } + } + } + m_audioDataRate = speed; + } +} + +// ================================== +void cDxr3Interface::SetChannelCount(uint32_t count) +{ + if (m_audioChannelCount != count && count != UNKNOWN_CHANNEL_COUNT) + { + if (!m_ExternalReleased) + { + if (m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + if (ioctl(m_fdAudio, SNDCTL_DSP_STEREO, &count) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetChannelCount Unable to set channel count\n"; + } + } + } + m_audioChannelCount = count; + } +} + +// ================================== +void cDxr3Interface::SetAudioSampleSize(uint32_t sampleSize) +{ + if (!m_ExternalReleased) + { + if (ioctl(m_fdAudio, SNDCTL_DSP_SAMPLESIZE, sampleSize)) + { + cLog::Instance() <<"cDxr3AbsDevice::SetAudioSampleSize Unable to set audio sample size\n"; + } + } + m_audioSampleSize = sampleSize; +} + +// clock +// ================================== +void cDxr3Interface::SetSysClock(uint32_t scr) +{ + if (!m_ExternalReleased) + { + m_pClock->SetSysClock(scr); + } +} + +// ================================== +uint32_t cDxr3Interface::GetSysClock() const +{ + uint32_t ret = 0; + if (!m_ExternalReleased) + { + ret = m_pClock->GetSysClock(); + } + return ret; +} + +// ================================== +void cDxr3Interface::SetPts(uint32_t pts) +{ + if (!m_ExternalReleased) + { + m_pClock->SetPts(pts); + } +} + +// ================================== +void cDxr3Interface::SetSpuPts(uint32_t pts) +{ + pts = pts >> 1; + if (!m_ExternalReleased) + { + if (pts > m_pClock->GetSysClock() && pts - m_pClock->GetSysClock() < 100000) + { + m_pClock->SetSpuPts(pts); + } + } +} + +// state changes +// ================================== +// enable subpicture proeccesing of the dxr3 +void cDxr3Interface::EnableSPU() +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_spuMode != EM8300_SPUMODE_ON) + { + m_spuMode = ioval = EM8300_SPUMODE_ON; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_SPUMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::EnableSpu Unable to set subpicture mode!\n"; + } + } + + Unlock(); +} + +// ================================== +// disable subpicture proeccesing of the dxr3 +void cDxr3Interface::DisableSPU() +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_spuMode != EM8300_SPUMODE_OFF) + { + m_spuMode = ioval = EM8300_SPUMODE_OFF; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_SPUMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::EnableSpu Unable to set subpicture mode!\n"; + } + } + + Unlock(); +} + +// ================================== +// disable audio output of dxr3 +void cDxr3Interface::DisableAudio() +{ + m_AudioActive = false; + + // we wirte zero buffers to dxr3 + if (!m_ExternalReleased) + { + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + } +} + +// ================================== +// enable overlay mode of the dxr3 +void cDxr3Interface::EnableOverlay() +{ + // first we check, if it is enable yet + if (m_OverlayActive) + { + return; + } + + /* + #define EM8300_OVERLAY_SIGNAL_ONLY 1 + #define EM8300_OVERLAY_SIGNAL_WITH_VGA 2 + #define EM8300_OVERLAY_VGA_ONLY 3 + */ + + int ioval = EM8300_OVERLAY_SIGNAL_WITH_VGA; + // set overlay signal mode + if (ioctl(m_fdControl, EM8300_IOCTL_OVERLAY_SIGNALMODE, &ioval) < 0) + { + //###### + cLog::Instance() << "Singnalmode failed\n"; + return; + } + + // setup overlay screen + em8300_overlay_screen_t scr; + scr.xsize = 1024; + scr.ysize = 768; + + if (ioctl(m_fdControl, EM8300_IOCTL_OVERLAY_SETSCREEN, &scr) < 0) + { + //###### + cLog::Instance() << "seting up screen failed\n"; + return; + } + + // setup overlay window + em8300_overlay_window_t win; + win.xpos = 0; + win.ypos = 0; + win.width = 1024; + win.height = 768; + + if (ioctl(m_fdControl, EM8300_IOCTL_OVERLAY_SETWINDOW, &win) < 0) + { + //###### + cLog::Instance() << "seting up window failed\n"; + return; + } + + m_OverlayActive = true; +} + +// ================================== +// disable overlay mode of the dxr3 +void cDxr3Interface::DisanleOverlay() +{ + // is it allready disabled + if (!m_OverlayActive) + { + return; + } +} + +// set/get functions +// ================================== +// get aspect ratio +uint32_t cDxr3Interface::GetAspectRatio() const +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_GET_ASPECTRATIO, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::GetAspectRatio Unable to get aspect ratio\n"; + } + } + + Unlock(); + return ioval; +} + +// ================================== +void cDxr3Interface::SetAspectRatio(uint32_t ratio) +{ + static int requestCounter = 0; + + Lock(); + + if (cDxr3ConfigData::Instance().GetForceLetterBox()) ratio = EM8300_ASPECTRATIO_16_9; + + if (!m_ExternalReleased && ratio != UNKNOWN_ASPECT_RATIO) + { + if (ratio != m_aspectRatio && requestCounter > 50) + { + requestCounter = 0; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_ASPECTRATIO, &ratio) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAspectRatio Unable to set aspect ratio\n"; + } + else + { + m_aspectRatio = ratio; + } + } + else + { + if (ratio != m_aspectRatio) + { + ++requestCounter; + } + else + { + requestCounter = 0; + } + } + } + + Unlock(); +} + +// play functions +// ================================== +// set playing mode and start sync engine +void cDxr3Interface::SetPlayMode() +{ + em8300_register_t reg; + int ioval; + + Lock(); + + if (!m_ExternalReleased) + { + ioval = EM8300_SUBDEVICE_AUDIO; + ioctl(m_fdControl, EM8300_IOCTL_FLUSH, &ioval); + fsync(m_fdVideo); + + + ioval = EM8300_PLAYMODE_PLAY; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3Device::SetPlayMode Unable to set playmode!\n"; + } + reg.microcode_register = 1; + reg.reg = 0; + reg.val = MVCOMMAND_SYNC; + + if (ioctl(m_fdControl, EM8300_IOCTL_WRITEREG, ®) < 0) + { + cLog::Instance() << "cDxr3Device::SetPlayMode Unable to start em8300 sync engine\n"; + } + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::Pause() +{ + int ioval = EM8300_PLAYMODE_PAUSED; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3Device::Pause Unable to set playmode!\n"; + } + } + + Unlock(); +} +// ================================== +void cDxr3Interface::SingleStep() +{ + int ioval = EM8300_PLAYMODE_SINGLESTEP; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) { + cLog::Instance() << "cDxr3Device::Pause Unable to set playmode!\n"; + } + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::PlayVideoFrame(cFixedLengthFrame* pFrame, int times) +{ + int written = 0; + int count = 0; + + if (m_VideoActive) + { + Lock(); + + if (!m_ExternalReleased) + { + for (int i = 0; i < times; i++) + { + if (times > 1) + { + cLog::Instance() << "times: " << times << "\n"; + } + + while (written < pFrame->GetCount() && count >= 0) + { + if ((count = write(m_fdVideo, pFrame->GetData() + written, pFrame->GetCount() - written)) < 0) + { + // an error occured + Resuscitation(); + } + written += count; + } + + // reset + written = 0; + } + } + + Unlock(); + + SetAspectRatio(pFrame->GetAspectRatio()); + } +} + +// ================================== +void cDxr3Interface::PlayVideoFrame(const uint8_t* pBuf, int length, int times) +{ + Lock(); + + if (!m_ExternalReleased) + { + for (int i = 0; i < times; i++) + { + if (write(m_fdVideo, pBuf, length) < 0) Resuscitation(); + } + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::PlayAudioFrame(cFixedLengthFrame* pFrame) +{ + + // XXX: Call this only with we are not in external mode? + + if (m_AudioActive) + { + Lock(); + + SetAudioSpeed(pFrame->GetDataRate()); + SetChannelCount(pFrame->GetChannelCount()); + + if (!m_ExternalReleased) + { + if (!cDxr3ConfigData::Instance().GetAc3OutPut()) ResampleVolume((short*)pFrame->GetData(), pFrame->GetCount()); + write(m_fdAudio, pFrame->GetData(), pFrame->GetCount()); + } + + Unlock(); + } +} + +// ================================== +void cDxr3Interface::PlayAudioFrame(uint8_t* pBuf, int length) +{ + int written = 0; + Lock(); + + if (!m_ExternalReleased) + { + if (!cDxr3ConfigData::Instance().GetAc3OutPut()) ResampleVolume((short*)pBuf, length); + + if ((written = write(m_fdAudio, pBuf, length) < 0)) Resuscitation(); + if (written != length) + { + cLog::Instance() << "cDxr3Interface::PlayAudioFrame(uint8_t* pBuf, int length): Not written = " << length - written << "\n"; + } + } + Unlock(); +} + +// ================================== +void cDxr3Interface::PlayAudioLpcmFrame(uint8_t* pBuf, int length) +{ + if (length > (LPCM_HEADER_LENGTH + 2)) + { + uint8_t* pFrame = new uint8_t[length - LPCM_HEADER_LENGTH]; + assert(!((length - LPCM_HEADER_LENGTH) % 2)); // only even number of bytes are allowed + + for (int i = LPCM_HEADER_LENGTH; i < length; i += 2) + { + pFrame[i - LPCM_HEADER_LENGTH] = pBuf[i + 1]; + pFrame[i - LPCM_HEADER_LENGTH + 1] = pBuf[i]; + } + + int codedSpeed = (pBuf[5] >> 4) & 0x03; + int speed = 0; + + switch (codedSpeed) + { + case 1: + speed = 96000; + break; + + case 2: + speed = 44100; + break; + + case 3: + speed = 32000; + break; + + default: + speed = 48000; + break; + } + + SetAudioSpeed(speed); + PlayAudioFrame(pFrame, length - LPCM_HEADER_LENGTH); + delete[] pFrame; + } +} + +// external device access +// ================================== +// release devices, so mplayer-plugin, for instance, +// can access the dxr3 +void cDxr3Interface::ExternalReleaseDevices() +{ + Lock(); + + if (!m_ExternalReleased) + { + if (m_fdControl > 0) close(m_fdControl); + if (m_fdVideo > 0) close(m_fdVideo); + if (m_fdSpu > 0) close(m_fdSpu); + if (m_fdAudio > 0) close(m_fdAudio); + m_fdControl = m_fdVideo = m_fdSpu = m_fdAudio = -1; + + m_ExternalReleased = true; + + delete m_pClock; + m_pClock = 0; + } + + Unlock(); +} + +// ================================== +// reopen devices for using in the dxr3 plugin +void cDxr3Interface::ExternalReopenDevices() +{ + Lock(); + + if (m_ExternalReleased) + { + // open control stream + m_fdControl = Dxr3Open("", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + + // open 'multimedia' streams + m_fdVideo = Dxr3Open("_mv", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdAudio = Dxr3Open("_ma", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdSpu = Dxr3Open("_sp", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + + if (m_fdControl < 0 || m_fdVideo < 0 || m_fdAudio < 0 || m_fdSpu <0) + { + ExternalReleaseDevices(); + } + else + { + m_pClock = new cDxr3SysClock(m_fdControl, m_fdVideo, m_fdSpu); + if (!m_pClock) + { + cLog::Instance() << "Unable to allocate memory for m_pClock in cDxr3Interface\n"; + exit(1); + } + + SetChannelCount(1); + m_ExternalReleased = false; + } + + Resuscitation(); + } + + Unlock(); +} + + +// tools +// ================================== +// play blackframe on tv +void cDxr3Interface::PlayBlackFrame() +{ + extern char blackframe[]; + extern int blackframeLength; + + Lock(); + + if (!m_ExternalReleased) + { + if (write(m_fdVideo, blackframe, blackframeLength) < 0) Resuscitation(); + if (write(m_fdVideo, blackframe, blackframeLength) < 0) Resuscitation(); + if (write(m_fdVideo, blackframe, blackframeLength) < 0) Resuscitation(); + } + m_horizontal = 720; + + Unlock(); +} + +// ================================== +void cDxr3Interface::ReOpenAudio() +{ + Lock(); + + if (!m_ExternalReleased) + { + if (m_fdAudio > 0) + { + int bufsize = 0; + ioctl(m_fdAudio, SNDCTL_DSP_GETODELAY, &bufsize); + usleep(bufsize / 192 * 1000); + + delete m_pClock; + close(m_fdAudio); + + m_fdAudio = open("/dev/em8300_ma-0", O_WRONLY | O_SYNC); + + + uint32_t tmpAudioDataRate = m_audioDataRate; + uint32_t tmpAudioChannelCount = m_audioChannelCount; + m_audioDataRate = m_audioChannelCount = 0; + m_pClock = new cDxr3SysClock(m_fdControl, m_fdVideo, m_fdSpu); + SetAudioSpeed(tmpAudioDataRate); + SetChannelCount(tmpAudioChannelCount); + } + } + + Unlock(); +} + +#if VDRVERSNUM < 10307 +// ================================== +cOsdBase* cDxr3Interface::NewOsd(int x, int y) +{ + return new cDxr3Osd(x, y); +} +#endif + +// ================================== +// uploadroutine for microcode +void cDxr3Interface::UploadMicroCode() +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::UploadMicroCode: uploading..."; + } + + em8300_microcode_t em8300_microcode; + const char* MICRO_CODE_FILE = "/usr/share/misc/em8300.uc"; + struct stat s; + int UCODE = open(MICRO_CODE_FILE, O_RDONLY); + + if (UCODE <0) + { + cLog::Instance() << "Unable to open microcode file " << MICRO_CODE_FILE << " for reading\n"; + exit(1); + } + + if (fstat(UCODE, &s ) <0) + { + cLog::Instance() << "Unable to fstat ucode file\n"; + exit(1); + } + + // read microcode + em8300_microcode.ucode = new char[s.st_size]; + if (em8300_microcode.ucode == NULL) + { + cLog::Instance() << "Unable to malloc() space for ucode\n"; + exit(1); + } + + if (read(UCODE,em8300_microcode.ucode,s.st_size) < 1) + { + cLog::Instance() << "Unable to read data from microcode file\n"; + // free memory to avoid memory leak + delete [] (char*) em8300_microcode.ucode; + exit(1); + } + + close(UCODE); + + em8300_microcode.ucode_size = s.st_size; + + // upload it + if( ioctl(m_fdControl, EM8300_IOCTL_INIT, &em8300_microcode) == -1) + { + cLog::Instance() << "Microcode upload to failed!! \n"; + // free memory to avoid memory leak + delete [] (char*) em8300_microcode.ucode; + exit(1); + } + delete [] (char*) em8300_microcode.ucode; + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "...done\n"; + } +} + +// ================================== +// config and setup device via ioctl calls +void cDxr3Interface::ConfigureDevice() +{ + uint32_t videomode = 0; + + // set video mode + if (cDxr3ConfigData::Instance().GetVideoMode() == PAL) + { + videomode = EM8300_VIDEOMODE_PAL; + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Videomode = PAL\n"; + } + } + else if (cDxr3ConfigData::Instance().GetVideoMode() == PAL60) + { + videomode = EM8300_VIDEOMODE_PAL60; + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Videomode = PAL60\n"; + } + } + else + { + videomode = EM8300_VIDEOMODE_NTSC; + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Videomode = NTSC\n"; + } + } + + // make ioctl + if (ioctl(m_fdControl, EM8300_IOCTL_SET_VIDEOMODE, &videomode) == -1) + { + cLog::Instance() << "Unable to set videomode\n"; + exit(1); + } + + // set audio mode + if (!cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + SetAudioAnalog(); + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Audiomode = Analog\n"; + } + } +} + +// ================================== +// reset whole hardware +void cDxr3Interface::Resuscitation() +{ + time_t startt = time(&startt); + time_t endt = 0; + m_ExternalReleased = true; + dsyslog("cDxr3Interface::Resuscitation Device failure detected"); + + UploadMicroCode(); + dsyslog("cDxr3Interface::Resuscitation Micro code upload successfully"); + +// NonBlockingCloseOpen(); + m_ExternalReleased = false; + + endt = time(&endt); + + dsyslog("cDxr3Interface::Resuscitation Reopening devices took %d", (int)(endt - startt)); + + if (endt - startt > 4) + { + exit(1); + } + + ConfigureDevice(); +} + +// ================================== +void cDxr3Interface::ResampleVolume(short* pcmbuf, int size) +{ + if (m_volume == 0) + { + memset(pcmbuf, 0, size); + } + else if (m_volume != 255) + { + int factor = (int)pow (2.0, (double)m_volume/32 + 8.0) - 1; + //int factor = (int)pow (2.0, (double)m_volume/16) - 1; + for (int i = 0; i < size / (int)sizeof(short); i++) + { + pcmbuf[i] = (((int)pcmbuf[i]) * factor) / 65536; + } + } +} + +// ================================== +void cDxr3Interface::ClearOsd() +{ + encodedata ed; + int controlstart= 0; + int x1 = 0; + int& i = ed.count = 0; + + // display duration... + ed.data[i++]= 0x00; + ed.data[i++]= 0x00; //durration before turn on command occurs + //in 90000/1024 units + // x1 + ed.data[i++]= x1 >> 8; //since this is the last command block, this + ed.data[i++]= x1 & 0xff; //points back to itself + + + // 0x01: start displaying + ed.data[i++]= 0x02; + + // 0xFF: end sequence + ed.data[i++]= 0xFF; + if (!i&1) + { + ed.data[i++]= 0xff; + } + + // x0 + ed.data[2]= (controlstart) >> 8; + ed.data[3]= (controlstart) & 0xff; + + // packet size + ed.data[0]= i >> 8; + ed.data[1]= i & 0xff; + + if (!m_ExternalReleased) + { + WriteSpu((const uint8_t*) &ed, (int) ed.count); + ClearButton(); + } +} + +// ================================== +void cDxr3Interface::WriteSpu(const uint8_t* pBuf, int length) +{ + Lock(); + + if (!m_ExternalReleased) + { + if (write(m_fdSpu, pBuf, length) < 0) Resuscitation(); + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::SetButton(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette) +{ + em8300_button_t button; + + button.color = palette >> 16; + button.contrast = palette & 0xFFFF; + button.top = sy; + button.bottom = ey; + button.left = sx; + button.right = ex; + + ioctl(m_fdSpu, EM8300_IOCTL_SPU_BUTTON, &button); +} + +// ================================== +void cDxr3Interface::ClearButton() +{ + em8300_button_t button; + + button.color = 0; + button.contrast = 0; + button.top = 1; + button.bottom = 2; + button.left = 1; + button.right = 2; + + ioctl(m_fdSpu, EM8300_IOCTL_SPU_BUTTON, &button); +} + +// ================================== +void cDxr3Interface::SetPalette(unsigned int *pal) +{ + ioctl(m_fdSpu, EM8300_IOCTL_SPU_SETPALETTE, (uint8_t*)pal); +} + +// helper functions for dxr3 main osd screen +// ================================== +// reset dxr3 card +void cDxr3Interface::ResetHardware() +{ + Lock(); + cLog::Instance() << "cDxr3Interface: Resting DXR3 hardware\n"; + Resuscitation(); + Unlock(); +} + +// ================================== +cMutex* cDxr3Interface::m_pMutex = new cMutex; diff --git a/dxr3interface.h b/dxr3interface.h new file mode 100644 index 0000000..d1df60e --- /dev/null +++ b/dxr3interface.h @@ -0,0 +1,136 @@ +#ifndef _DXR3_INTERFACE_H_ +#define _DXR3_INTERFACE_H_ + +#include +#include +#include +#include +#include + +#include "dxr3vdrincludes.h" +#include "dxr3log.h" +#include "dxr3configdata.h" +#include "dxr3sysclock.h" +#include "dxr3osd.h" + +// ================================== +class cFixedLengthFrame; + +// ================================== +// interafce to dxr3-card +class cDxr3Interface : public Singleton +{ +public: + cDxr3Interface(); + ~cDxr3Interface(); + + // main + void Start(); + void Stop(); + + // audio + void SetAudioAnalog(); + void SetAudioDigitalPCM(); + void SetAudioDigitalAC3(); + void SetVolume(int volume) { m_volume = volume;} + void SetAudioSpeed(uint32_t speed); + void SetChannelCount(uint32_t count); + void SetAudioSampleSize(uint32_t sampleSize); + + // clock + void SetSysClock(uint32_t scr); + uint32_t GetSysClock() const; + void SetPts(uint32_t pts); + void SetSpuPts(uint32_t pts); + + // state changes + void EnableSPU(); + void DisableSPU(); + void EnableVideo() { m_VideoActive = true; } + void DisableVideo() { m_VideoActive = false; } + void EnableAudio() { m_AudioActive = true; } + void DisableAudio(); + void EnableOverlay(); + void DisanleOverlay(); + + // set/get functions + uint32_t GetAspectRatio() const; + void SetAspectRatio(uint32_t ratio); + uint32_t GetHorizontalSize() const { return m_horizontal; } + void SetHorizontalSize(uint32_t horizontal) { m_horizontal = horizontal;}; + + // play functions + void SetPlayMode(); + void Pause(); + void SingleStep(); + void PlayVideoFrame(cFixedLengthFrame* pFrame, int times = 1); + void PlayVideoFrame(const uint8_t* pBuf, int length, int times = 1); + void PlayAudioFrame(cFixedLengthFrame* pFrame); + void PlayAudioFrame(uint8_t* pBuf, int length); + void PlayAudioLpcmFrame(uint8_t* pBuf, int length); + + // external device access + void ExternalReleaseDevices(); + void ExternalReopenDevices(); + bool IsExternalReleased() const { return m_ExternalReleased; } + + // tools + void PlayBlackFrame(); + void ReOpenAudio(); + + // osd/spu + #if VDRVERSNUM < 10307 + cOsdBase* NewOsd(int x, int y); + #endif + + void ClearOsd(); + void WriteSpu(const uint8_t* pBuf, int length); + void SetButton(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette); + void ClearButton(); + void SetPalette(unsigned int *pal = NULL); + + // overlay functions + + // helper functions for dxr3 main osd screen + void ResetHardware(); + +private: + // file handles + int m_fdControl; + int m_fdVideo; + int m_fdSpu; + int m_fdAudio; + + // dxr3 clock + cDxr3SysClock* m_pClock; + + uint32_t m_audioChannelCount; + uint32_t m_audioDataRate; + int m_aspectDelayCounter; + uint32_t m_aspectRatio; + uint32_t m_horizontal; + uint32_t m_audioSampleSize; + uint32_t m_audioMode; + uint32_t m_spuMode; + bool m_ExternalReleased; // is dxr3 used by e.g. mplayer? + int m_volume; + bool m_AudioActive; + bool m_VideoActive; + bool m_OverlayActive; + + // spu +// cDxr3InterfaceSpu m_SpuInterface; + + void UploadMicroCode(); + void ConfigureDevice(); + void ResampleVolume(short* pcmbuf, int size); + void Resuscitation(); + +protected: + static cMutex* m_pMutex; + + static void Lock() { cDxr3Interface::m_pMutex->Lock(); } + static void Unlock() { cDxr3Interface::m_pMutex->Unlock(); } +}; + +#endif /*_DXR3_INTERFACE_H_*/ diff --git a/dxr3interface_spu_encoder.c b/dxr3interface_spu_encoder.c new file mode 100644 index 0000000..59b1a33 --- /dev/null +++ b/dxr3interface_spu_encoder.c @@ -0,0 +1,620 @@ +/* + * spuenc.c - encodes an OSD bitmap as subpicture + * + * Assimilated and adapted by + * Stefan Schluenss + * Nov. 2002 + * + * Based on the subpicture encoding routines from MPlayer and + * the information given by + * Samuel Hocevar + * Michel Lespinasse + * and http://members.aol.com/mpucoder/DVD/spu.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "dxr3interface_spu_encoder.h" + +/* +ToDo: + - cSPUEncoder::encode_do_row: FIXME: watch this space for EOL +*/ + + +// ================================== +// dec. +cSpuData::~cSpuData() +{ + Clear(); +} + +// ================================== +// free buffer and set it to 0 +void cSpuData::Clear() +{ + if (data) + { + free(data); + count = malloc_size = 0; + } +} + +// ================================== +// wirte a byte to spu buffer +void cSpuData::WriteByte(uint8_t byte) +{ + if (count >= malloc_size) + { + data = (u_char*)realloc(data, malloc_size += 2048); + } + + data[count++] = byte; +} + +// ================================== +void cSpuData::WriteNibble(int *higher_nibble, uint8_t nibble) +{ +} + +// ================================== +void cSpuData::WriteRle(int *higher_nibble, int length, int color) +{ +} + + + + +// ================================== +cSPUEncoder::cSPUEncoder() +{ + // clear osd + memset(OSD_Screen, 0x00 ,OSDWIDTH * OSDHEIGHT); + memset(OSD_Screen2, 0x00 ,OSDWIDTH * OSDHEIGHT); + memset(OSD_Screen3, 0x00 ,OSDWIDTH * OSDHEIGHT); + + // set active area to 0 + //m_x0 = m_x1 = m_y0 = m_y1 = 0; +} + +// ================================== +// main function for the osd +// makes life nicer :) +int cSPUEncoder::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) +{ + u_char *cp; + unsigned char idx = 0; + int opacity = 0; +#if VDRVERSNUM >= 10307 + const tColor *col; +#else + eDvbColor *col; +#endif + + switch (cmd) + { + case OSD_SetWindow: + // (x0) set window with number 0 0) + { + m_lastwindow = x0; + return 0; + } + + return -1; + break; + + case OSD_Open: + // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) + // Opens OSD with this size and bit depth + // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" + m_windows[m_lastwindow].x0 = x0; + m_windows[m_lastwindow].y0 = y0; + m_windows[m_lastwindow].x1 = x1; + m_windows[m_lastwindow].y1 = y1; + + return 0; + break; + + case OSD_SetPalette: + // Spu->Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); + // (firstcolor{color},lastcolor{x0},data) + // Set a number of entries in the palette + // sets the entries "firstcolor" through "lastcolor" from the array "data" + // data has 4 byte for each color: + // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel + + #if VDRVERSNUM >= 10307 + col = (tColor*)data; + #else + eDvbColor *col; + col = (eDvbColor*)data; + #endif + + m_windows[m_lastwindow].NumColors = x0; + + for (int x = color, i = 0; x <= x0; x++,i++) + { + m_palManager.AddColor((int)*col & 0xFFFFFF); + + idx = m_palManager.GetIndex((int)*col & 0xFFFFFF); + if (m_palManager.HasChanged()) + { + cDxr3Interface::Instance().SetPalette(m_palManager.GetPalette()); + } + + opacity = ((*col & 0xFF000000) >> 24) * 0xF / 0xFF; + m_windows[m_lastwindow].colors[i] = (opacity << 4) | idx; + m_windows[m_lastwindow].opacity[i] = opacity; + col++; + } + + return 0; + break; + + case OSD_SetBlock: + // (x0,y0,x1,y1,increment{color},data) + // fills pixels x0,y0 through x1,y1 with the content of data[] + // inc contains the width of one line in the data block, + // inc<=0 uses blockwidth as linewidth + // returns 0 on success, -1 on clipping all pixel + + CopyBlockIntoOSD + ( + color, + m_windows[m_lastwindow].x0 + x0, + m_windows[m_lastwindow].y0 + y0, + m_windows[m_lastwindow].x0 + x1, + m_windows[m_lastwindow].y0 + y1, + (u_char *)data + ); + + // calculate osd size + CalculateActiveOsdArea(); + + //cLog::Instance() << "(" << m_x0 << ", " << m_x1 << ") - (" << m_y0 << ", " << m_y1 << ")"; + + m_encodeddata.count = 0; + EncodePixelbufRle(0,0, OSDWIDTH, OSDHEIGHT-1, OSD_Screen, 0, &m_encodeddata); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "OSD Datasize: " << m_encodeddata.count << "\n"; + } + + if (m_encodeddata.count <= DATASIZE) + { + cDxr3Interface::Instance().WriteSpu((uint8_t*) &m_encodeddata, m_encodeddata.count); + return 0; + } + else + { + cLog::Instance() << "Waring: SPU data (" << m_encodeddata.count << ") size exceeds limit\n"; + return -1; + } + break; + + case OSD_Close: + // clear colors from plattemanager + + #if VDRVERSNUM >= 10307 + if ((col = (tColor*)m_windows[m_lastwindow].colors) != NULL) + #else + if ((col = (eDvbColor*)m_windows[m_lastwindow].colors) != NULL) + #endif + { + for (int i = 0; i < m_windows[m_lastwindow].NumColors; ++i) + { + m_palManager.RemoveColor((int)(col[i]) & 0xFFFFFF); + } + } + + // clear osd + for (int i = m_windows[m_lastwindow].y0; i <= m_windows[m_lastwindow].y1; ++i) + { + cp = &OSD_Screen[i*OSDWIDTH + m_windows[m_lastwindow].x0]; + if ((cp+m_windows[m_lastwindow].x1-m_windows[m_lastwindow].x0+1) < &OSD_Screen[OSDWIDTH * OSDHEIGHT-1]) + { + for (int xx=0; xx <= (m_windows[m_lastwindow].x1-m_windows[m_lastwindow].x0); xx++) + { + *(cp+xx) = 0x00; + } + } + else + { + continue; + } + } + + // encode rle + m_encodeddata.count = 0; + EncodePixelbufRle(0,0, OSDWIDTH, OSDHEIGHT-1, OSD_Screen, 0, &m_encodeddata); + + // set windows position to 0 + m_windows[m_lastwindow].x0 = 0; + m_windows[m_lastwindow].y0 = 0; + m_windows[m_lastwindow].x1 = 0; + m_windows[m_lastwindow].y1 = 0; + + if (m_encodeddata.count <= DATASIZE) + { + cDxr3Interface::Instance().WriteSpu((uint8_t*) &m_encodeddata, m_encodeddata.count); + return 0; + } + else + { + cLog::Instance() << "Waring: SPU data (" << m_encodeddata.count << ") size exceeds limit\n"; + return -1; + } + + return 0; + break; + + case OSD_Clear: + // Sets all pixel to color 0 + // returns 0 on success + + // This should be done in cSPUEncoder::cSPUEncoder + + return 0; + break; + + // not needed - at the moment + case OSD_Show: + case OSD_Hide: + case OSD_Fill: + case OSD_SetColor: + case OSD_SetTrans: + case OSD_SetPixel: + case OSD_GetPixel: + case OSD_SetRow: + case OSD_FillRow: + case OSD_FillBlock: + case OSD_Line: + case OSD_Query: + case OSD_Test: + case OSD_Text: + case OSD_MoveWindow: + break; + }; + + return -1; +} + +// ================================== +// stamps window content into full osd bitmap +void cSPUEncoder::CopyBlockIntoOSD(int linewidth, int x0, int y0, int x1, int y1, u_char *data) +{ + int i; + int w; + u_char *cp; + u_char *sp = data; + + + // linewidth contains the width of one line in the data block, + // linewidth<=0 uses blockwidth as linewidth + if (linewidth <= 0) + { + w = m_windows[m_lastwindow].x1 - m_windows[m_lastwindow].x0; + } + else + { + w = linewidth; + } + + for (i = y0; i <= y1; ++i) + { + cp = &OSD_Screen[i*OSDWIDTH + x0]; + if ((cp+x1-x0+1) < &OSD_Screen[OSDWIDTH * OSDHEIGHT-1]) + { + for (int xx=0; xx <= (x1-x0); xx++) + { + *(cp+xx) = m_windows[m_lastwindow].colors[*(sp+xx) & 0x0f]; + } + } + else + { + continue; + } + sp += w; + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::EncodePixelbufRle(int x, int y, int w, int h, u_char *inbuf, int stride, encodedata *ed) +{ + pixbuf pb; + int i, row; + pb.x = w; + pb.y = h; + + if (cDxr3Interface::Instance().GetHorizontalSize() < 700) + { + double fac = (double)OSDWIDTH / (double)OSDWIDTH2; + ScaleOSD(fac, inbuf,10); + inbuf = OSD_Screen2; + } + + m_ColorManager = new cColorManager(); + + // Encode colors into highlight regions + m_ColorManager->EncodeColors(w, h, inbuf, OSD_Screen3); + inbuf = OSD_Screen3; + + pb.pixels = inbuf; + ed->count= 4; + ed->nibblewaiting= 0; + + row= 0; + for (i= 0; i < pb.y; i++) + { + encode_do_row(ed, &pb, row); + row+= 2; + if (row > pb.y) + { + row= 1; + ed->oddstart= ed->count; + } + } + encode_do_control(x,y, ed, &pb); + + delete m_ColorManager; +} + +// ================================== +void cSPUEncoder::ScaleOSD(double fac, unsigned char* buf, unsigned char NumColors) +{ + int y,x,s,d; + unsigned char dline[2 * OSDWIDTH + 10]; + + memset(OSD_Screen2, 0x00 ,OSDWIDTH * OSDHEIGHT); + + for (y = 0; y < OSDHEIGHT; y++) + { + memset(dline,0,2*OSDWIDTH+10); + + for (s=0,d=0; s < OSDWIDTH; s++,d+=2) + { + // stretch line to double width to 1440 + dline[d] = buf[y*OSDWIDTH + s]; + } + + for (d=1; d < (2*OSDWIDTH); d+=2) + { + #if VDRVERSNUM <= 10307 + // 'interpolate' values + if ((dline[d-1] == BLACK) || (dline[d+1] == BLACK)) + { + dline[d] = BLACK; + } + else if ((dline[d-1] == WHITE) || (dline[d+1] == WHITE)) + { + dline[d] = WHITE; + } + else if ((dline[d-1] == CYAN) || (dline[d+1] == CYAN)) + { + dline[d] = CYAN; + } + else + { + dline[d] = dline[d+1]; + } + #else /*VDRVERSNUM*/ + dline[d] = dline[d+1]; + #endif /*VDRVERSNUM*/ + } + + for (s=0, x = 0; x < OSDWIDTH2; x++,s+=3) + { + // now take every third pixel (1440/3=480) + OSD_Screen2[y * OSDWIDTH + x] = dline[s]; + } + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_put_nibble(encodedata* ed, u_char nibble) +{ + if (ed->nibblewaiting) + { + ed->data[ed->count++]|= nibble; + ed->nibblewaiting= 0; + } + else + { + ed->data[ed->count]= nibble<<4; + ed->nibblewaiting= 1; + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_pixels(encodedata* ed, int color, int number) +{ + if (number > 3) + { + if (number > 15) + { + encode_put_nibble(ed, 0); + if (number > 63) + { + encode_put_nibble(ed, (number & 0xC0)>>6); + } + } + encode_put_nibble(ed, (number & 0x3C)>>2); + } + encode_put_nibble(ed, ((number & 0xF)<<2) | color); +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_eol(encodedata* ed) +{ + if (ed->nibblewaiting) + { + ed->count++; + ed->nibblewaiting= 0; + } + ed->data[ed->count++]= 0x00; + ed->data[ed->count++]= 0x00; +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_do_row(encodedata* ed, pixbuf* pb, int row) +{ + int i= 0; + u_char* pix= pb->pixels + row * pb->x; + int color= *pix & 0x03; + int n= 0; /* the number of pixels of this color */ + + while (i++ < pb->x) + { + /* FIXME: watch this space for EOL */ + if ((*pix & 0x03) != color || n == 255 ) + { + encode_pixels( ed, color, n ); + color= *pix & 0x03; + n= 1; + } + else + { + n++; + } + pix++; + } + + /* this small optimization: (n>63) can save up to two bytes per line + * I wonder if this is compatible with all the hardware... */ + if (color == 0 && n > 63) + { + encode_eol( ed ); + } + else + { + encode_pixels( ed, color, n ); + } + + if (ed->nibblewaiting) + { + ed->count++; + ed->nibblewaiting= 0; + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_do_control(int x,int y, encodedata* ed, pixbuf* pb) +{ + int controlstart= ed->count; + int x1; + int i; + u_int top, left, bottom, right; + + top= y; //this forces the first bit to be visible on a TV + left= x; //you could actually pass in x/y and do some nice + + bottom= top + pb->y - 1; + right= left + pb->x - 1; + + /* start at x0+2*/ + i= controlstart; + + x1= (i); //marker for last command block address + + /* display duration... */ + ed->data[i++]= 0x00; + ed->data[i++]= 0x00; //duration before turn on command occurs (will not be used) + + /* x1 */ + ed->data[i++]= x1 >> 8; //since this is the last command block, this + ed->data[i++]= x1 & 0xff;//points back to itself + + /* 0x00: force displaying */ + ed->data[i++]= 0x00; + + /* 0x03: palette info */ + ed->data[i++]= 0x03; + ed->data[i++]= 0x01; + ed->data[i++]= 0x23; + + /* 0x04: transparency info (reversed) */ + ed->data[i++]= 0x04; // SET_CONTR + ed->data[i++]= 0xFF; + ed->data[i++]= 0x70; + + /* 0x05: coordinates */ + ed->data[i++]= 0x05; // SET_DAREA + ed->data[i++]= left >> 4; + ed->data[i++]= ((left&0xf)<<4)+(right>>8); + ed->data[i++]= (right&0xff); + ed->data[i++]= top >> 4; + ed->data[i++]= ((top&0xf)<<4)+(bottom>>8); + ed->data[i++]= (bottom&0xff); + + /* 0x06: both fields' offsets */ + ed->data[i++]= 0x06; // SET_DSPXA + ed->data[i++]= 0x00; + ed->data[i++]= 0x04; + ed->data[i++]= ed->oddstart >> 8; + ed->data[i++]= ed->oddstart & 0xff; + + int len; + unsigned char *spudata; + + spudata = m_ColorManager->GetSpuData(len); + + for (int si= 0; si < len; si++) + { + ed->data[i++] = *(spudata + si); + } + + /* 0xFF: end sequence */ + ed->data[i++]= 0xFF; + if (! i&1 ) + { + ed->data[i++]= 0xff; + } + + /* x0 */ + ed->data[2]= (controlstart) >> 8; + ed->data[3]= (controlstart) & 0xff; + + /* packet size */ + ed->data[0]= i >> 8; + ed->data[1]= i & 0xff; + + ed->count= i; +} + +// ================================== +// we _only_ write usefull data +void cSPUEncoder::CalculateActiveOsdArea() +{ + // reset + //m_x0 = m_x1 = m_y0 = m_y1 = 0; + + // calculate +/* for (int i = 1; i < 8; i++) + { + m_x0 = max(m_x0, m_windows[i].x0); + m_x1 = max(m_x1, m_windows[i].y0); + m_y0 = max(m_y0, m_windows[i].x1); + m_y1 = max(m_y1, m_windows[i].y1); + } +*/ +} diff --git a/dxr3interface_spu_encoder.h b/dxr3interface_spu_encoder.h new file mode 100644 index 0000000..bee994b --- /dev/null +++ b/dxr3interface_spu_encoder.h @@ -0,0 +1,153 @@ +/* + * dxr3interface_spu_encoder.h - encodes an OSD bitmap as subpicture + * + * Assimilated and adapted by + * Stefan Schluenss + * Nov. 2002 + * + * Based on the subpicture encoding routines from MPlayer and + * the information given by + * Samuel Hocevar + * Michel Lespinasse + * and http://members.aol.com/mpucoder/DVD/spu.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef _DXR3_INTERFACE_SPU_ENCODER_ +#define _DXR3_INTERFACE_SPU_ENCODER_ + +#include +#include +#include "dxr3vdrincludes.h" +#include "dxr3palettemanager.h" +#include "dxr3colormanager.h" +#include "dxr3interface.h" +#include "dxr3singleton.h" + +// ================================== +#define MAXWINDOWS 8 +#define DATASIZE 53220 +#define OSDWIDTH 720 +#define OSDWIDTH2 480 +#define OSDHEIGHT 576 + +// ================================== +// basic infos about one osd "window" +struct sOSD_Window +{ + size_t x0; + size_t y0; + size_t x1; + size_t y1; + + unsigned char colors[16]; + unsigned char opacity[16]; + + size_t NumColors; +}; + +// ================================== +// used to get active osd area +struct sRectal +{ + sRectal() : x0(0), x1(0), y0(0), y1(0) {} + + size_t x0; + size_t x1; + size_t y0; + size_t y1; +}; + +// ================================== +// our spu(data) with all needed routines +class cSpuData +{ +public: + cSpuData(): count(0), malloc_size(0) {} + ~cSpuData(); + + void Clear(); + u_char* GetData() const { return data; } + + // write operations + void WriteByte(uint8_t byte); + void WriteNibble(int *higher_nibble, uint8_t nibble); + void WriteRle(int *higher_nibble, int length, int color); + +private: + u_char *data; + size_t count; // the count of bytes written + size_t malloc_size; // size of data +}; + +// ================================== +struct pixbuf +{ + int x, y; + u_int rgb[4]; + u_char* pixels; +}; + +// ================================== +struct encodedata +{ + u_char data[DATASIZE]; + int count; // the count of bytes written + int oddstart; + int nibblewaiting; +}; + +// ================================== +class cSPUEncoder : public Singleton +{ +public: + cSPUEncoder(); + ~cSPUEncoder() {} + + int Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = 0); + +private: + cSPUEncoder(cSPUEncoder&); // no copy constructor + + // helper functions + void CopyBlockIntoOSD(int linewidth, int x0,int y0, int x1, int y1, u_char *data); + void EncodePixelbufRle(int x, int y, int w, int h, u_char *inbuf, int stride, encodedata *ed); + void ScaleOSD(double fac, unsigned char* buf, unsigned char NumColors=4); + void encode_put_nibble(encodedata* ed, u_char nibble); + void encode_pixels(encodedata* ed, int color, int number); + void encode_eol(encodedata* ed); + void encode_do_row(encodedata* ed, pixbuf* pb, int row); + void encode_do_control(int x,int y, encodedata* ed, pixbuf* pb); + + void CalculateActiveOsdArea(); + + sOSD_Window m_windows[8]; + cDxr3PaletteManager m_palManager; + cColorManager* m_ColorManager; + encodedata m_encodeddata; + int m_lastwindow; + + // our osd :) + u_char OSD_Screen[OSDWIDTH * OSDHEIGHT]; + u_char OSD_Screen2[OSDWIDTH * OSDHEIGHT]; + u_char OSD_Screen3[OSDWIDTH * OSDHEIGHT]; + + // 'active' osd sizes + sRectal m_active_osd; +}; + +#endif /*_DXR3_INTERFACE_SPU_ENCODER_*/ diff --git a/dxr3log.c b/dxr3log.c new file mode 100644 index 0000000..09f54c1 --- /dev/null +++ b/dxr3log.c @@ -0,0 +1,60 @@ +/* + * dxr3log.c + * + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "dxr3log.h" + +// ================================== +cLog::cLog() +{ + m_LogOpen = false; + m_ForeFlush = true; + + Open("dxr3plugin.log"); +} + +// ================================== +cLog::cLog(std::string Filename) +{ + m_LogOpen = false; + m_ForeFlush = true; + + Open(Filename); +} + +// ================================== +void cLog::Open(std::string Filename) +{ + m_LogStream.open(Filename.c_str()); + m_LogOpen = true; +} + +// ================================== +void cLog::Close() +{ + if (m_LogOpen) + { + // close file now + m_LogStream.flush(); + m_LogStream.close(); + + m_LogOpen = false; + } +} diff --git a/dxr3log.h b/dxr3log.h new file mode 100644 index 0000000..b09e86e --- /dev/null +++ b/dxr3log.h @@ -0,0 +1,94 @@ +/* + * dxr3log.h + * + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ + +#ifndef _DXR3_LOG_H_ +#define _DXR3_LOG_H_ + +#include +#include +#include "dxr3singleton.h" + +// ================================== +//! A log class. +/*! + With this nice util dxr3plugin generates and mange a log file. In this + file the developer/enduser can find informations and can find errors, + problems and ohter stuff. +*/ +class cLog : public Singleton +{ +public: + cLog(); // use default log file + cLog(std::string FileName); + + ~cLog() { Close(); } + + void SetForceFlush(const bool v) { m_ForeFlush = v; } + bool GetForceFlush() const { return m_ForeFlush; } + + // write type data to log file. + template + inline cLog& operator << ( Type item ) + { + if (m_LogOpen) + { + m_LogStream << item; + if (m_ForeFlush) m_LogStream.flush(); + } + return *this; + } + inline cLog& operator << ( size_t item ) + { + if (m_LogOpen) + { + m_LogStream << (unsigned int)item; + if (m_ForeFlush) m_LogStream.flush(); + } + return *this; + } + inline cLog& operator << ( bool item ) + { + if (m_LogOpen) + { + if (item == true) + { + m_LogStream << "true"; + } + else + { + m_LogStream << "false"; + } + if (m_ForeFlush) m_LogStream.flush(); + } + return *this; + } + +private: + std::ofstream m_LogStream; + bool m_LogOpen; + bool m_ForeFlush; + + void Open(std::string Filename); // with this function we open our logfile + void Close(); // with this function we close our logfile +}; + + +#endif /*_DXR3_LOG_H_*/ diff --git a/dxr3memcpy.c b/dxr3memcpy.c new file mode 100644 index 0000000..1866c95 --- /dev/null +++ b/dxr3memcpy.c @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2001-2003 the xine project + * + * This file is part of xine, a free video player. + * + * These are the MMX/MMX2/SSE optimized versions of memcpy + * + * This code was adapted from Linux Kernel sources by Nick Kurshev to + * the mplayer program. (http://mplayer.sourceforge.net) + * + */ + +#include +#include +#include + +#include "dxr3log.h" +#include "dxr3cpu.h" +#include "dxr3memcpy.h" + + +void *(* dxr3_memcpy)(void *to, const void *from, size_t len); + + +//#if defined(ARCH_X86) || defined(ARCH_X86_64) + +#ifndef _MSC_VER +// ================================== +// for small memory blocks (<256 bytes) this version is faster +#define small_memcpy(to,from,n)\ +{\ +register unsigned long int dummy;\ +__asm__ __volatile__(\ + "rep; movsb"\ + :"=&D"(to), "=&S"(from), "=&c"(dummy)\ + :"0" (to), "1" (from),"2" (n)\ + : "memory");\ +} + +// ================================== +// linux kernel __memcpy (from: /include/asm/string.h) +static __inline__ void * __memcpy ( + void * to, + const void * from, + size_t n) +{ +int d0, d1, d2; + + if( n < 4 ) { + small_memcpy(to,from,n); + } + else + __asm__ __volatile__( + "rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); + + return (to); +} + +#define SSE_MMREG_SIZE 16 +#define MMX_MMREG_SIZE 8 + +#define MMX1_MIN_LEN 0x800 /* 2K blocks */ +#define MIN_LEN 0x40 /* 64-byte blocks */ + +// ================================== +/* SSE note: i tried to move 128 bytes a time instead of 64 but it +didn't make any measureable difference. i'm using 64 for the sake of +simplicity. [MF] */ +static void * sse_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + /* PREFETCH has effect even for MOVSB instruction ;) */ + __asm__ __volatile__ ( + " prefetchnta (%0)\n" + " prefetchnta 32(%0)\n" + " prefetchnta 64(%0)\n" + " prefetchnta 96(%0)\n" + " prefetchnta 128(%0)\n" + " prefetchnta 160(%0)\n" + " prefetchnta 192(%0)\n" + " prefetchnta 224(%0)\n" + " prefetchnta 256(%0)\n" + " prefetchnta 288(%0)\n" + : : "r" (from) ); + + if(len >= MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(SSE_MMREG_SIZE-1); + if(delta) + { + delta=SSE_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + if(((unsigned long)from) & 15) + /* if SRC is misaligned */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "prefetchnta 352(%0)\n" + "movups (%0), %%xmm0\n" + "movups 16(%0), %%xmm1\n" + "movups 32(%0), %%xmm2\n" + "movups 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + else + /* + Only if SRC is aligned on 16-byte boundary. + It allows to use movaps instead of movups, which required data + to be aligned or a general-protection exception (#GP) is generated. + */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "prefetchnta 352(%0)\n" + "movaps (%0), %%xmm0\n" + "movaps 16(%0), %%xmm1\n" + "movaps 32(%0), %%xmm2\n" + "movaps 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + /* since movntq is weakly-ordered, a "sfence" + * is needed to become ordered again. */ + __asm__ __volatile__ ("sfence":::"memory"); + /* enables to use FPU */ + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +// ================================== +static void * mmx_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + if(len >= MMX1_MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1); + if(delta) + { + delta=MMX_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + for(; i>0; i--) + { + __asm__ __volatile__ ( + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movq %%mm0, (%1)\n" + "movq %%mm1, 8(%1)\n" + "movq %%mm2, 16(%1)\n" + "movq %%mm3, 24(%1)\n" + "movq %%mm4, 32(%1)\n" + "movq %%mm5, 40(%1)\n" + "movq %%mm6, 48(%1)\n" + "movq %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +// ================================== +static void * mmx2_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + /* PREFETCH has effect even for MOVSB instruction ;) */ + __asm__ __volatile__ ( + " prefetchnta (%0)\n" + " prefetchnta 32(%0)\n" + " prefetchnta 64(%0)\n" + " prefetchnta 96(%0)\n" + " prefetchnta 128(%0)\n" + " prefetchnta 160(%0)\n" + " prefetchnta 192(%0)\n" + " prefetchnta 224(%0)\n" + " prefetchnta 256(%0)\n" + " prefetchnta 288(%0)\n" + : : "r" (from) ); + + if(len >= MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1); + if(delta) + { + delta=MMX_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "prefetchnta 352(%0)\n" + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "movntq %%mm6, 48(%1)\n" + "movntq %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + /* since movntq is weakly-ordered, a "sfence" + * is needed to become ordered again. */ + __asm__ __volatile__ ("sfence":::"memory"); + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +// ================================== +static void *linux_kernel_memcpy(void *to, const void *from, size_t len) { + return __memcpy(to,from,len); +} +#endif /* _MSC_VER */ +//#endif /* ARCH_X86 */ + + + +// ================================== +// constr. +cDxr3MemcpyBench::cDxr3MemcpyBench(uint32_t config_flags) +{ + // + // add all aviable memcpy routines + // + + memcpy_routine routine; + + // glibc memcpy + routine.name = "glibc memcpy()"; + routine.function = memcpy; + routine.time = 0; + routine.cpu_require = 0; + m_methods.push_back(routine); + +// #ifdef ARCH_X86 + +// cLog::Instance() << "test\n"; + + // linux_kernel_memcpy + routine.name = "linux_kernel_memcpy()"; + routine.function = linux_kernel_memcpy; + routine.cpu_require = 0; + m_methods.push_back(routine); + + // MMX optimized memcpy() + routine.name = "MMX optimized memcpy()"; + routine.function = mmx_memcpy; + routine.cpu_require = CC_MMX; + m_methods.push_back(routine); + + // MMXEXT optimized memcpy() + routine.name = "MMXEXT optimized memcpy()"; + routine.function = mmx2_memcpy; + routine.cpu_require = CC_MMXEXT; + m_methods.push_back(routine); + + #ifndef __FreeBSD__ + + // SSE optimized memcpy() + routine.name = "SSE optimized memcpy()"; + routine.function = sse_memcpy; + routine.cpu_require = CC_MMXEXT|CC_SSE; + m_methods.push_back(routine); + + #endif /*__FreeBSD__*/ + +// #endif /*ARCH_X86*/ + + + // + // run benchmarking + // + + unsigned long long t = 0; + void *buf1, *buf2; + int j, best = -1; + + if ((buf1 = malloc(BUFSIZE)) == NULL) + return; + + if ((buf2 = malloc(BUFSIZE)) == NULL) + { + free(buf1); + return; + } + + cLog::Instance() << "\nBenchmarking memcpy() methods (smaller is better):\n"; + // make sure buffers are present on physical memory + memcpy(buf1,buf2,BUFSIZE); + + for (size_t i = 0; i < m_methods.size(); i++) + { + if ((config_flags & m_methods[i].cpu_require) != m_methods[i].cpu_require) + { + continue; + } + + // count 100 runs of the memcpy function + t = rdtsc(); + for (j = 0; j < 50; j++) + { + m_methods[i].function(buf2,buf1,BUFSIZE); + m_methods[i].function(buf1,buf2,BUFSIZE); + } + t = rdtsc() - t; + + m_methods[i].time = t; + + cLog::Instance() << m_methods[i].name.c_str() << ": " << (unsigned long long)t << "\n"; + + if (best == -1 || t < m_methods[best].time) + { + best = i; + } + } + cLog::Instance() << "\nBest one: " << m_methods[best].name.c_str() << "\n\n"; + + dxr3_memcpy = m_methods[best].function; + + + // clear unused memory + free(buf1); + free(buf2); +} + + +// ================================== +// neede for exact timing +unsigned long long int cDxr3MemcpyBench::rdtsc() +{ +// #ifdef ARCH_X86 + unsigned long long int x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +// #else + /* FIXME: implement an equivalent for using optimized memcpy on other + architectures */ +// return 0; +// #endif +} diff --git a/dxr3memcpy.h b/dxr3memcpy.h new file mode 100644 index 0000000..8ec863d --- /dev/null +++ b/dxr3memcpy.h @@ -0,0 +1,74 @@ +/***************************************************************************** + * memcpy.h: functions and definitions of the MMX/MMX2/SSE optimized versions + * of memcpy + ***************************************************************************** + * Copyright (C) 2001 Keuleu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + ***************************************************************************** + * + * Original code: + * + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + *****************************************************************************/ + +#ifndef _DXR3MEMCPY_H_ +#define _DXR3MEMCPY_H_ + +#include "dxr3vdrincludes.h" + +// ================================== +// size of buffer for benchmark +#define BUFSIZE 1024*1024 + +enum { + MEMCPY_PROBE = 0, + MEMCPY_GLIBC, + MEMCPY_KERNEL, + MEMCPY_MMX, + MEMCPY_MMXEXT, + MEMCPY_SSE +}; + +// ================================== +struct memcpy_routine +{ + string name; + void *(* function)(void *to, const void *from, size_t len); + unsigned long long time; + uint32_t cpu_require; // caps from dxr3cpu.h +}; + +// ================================== +// little class to to a nice benchmark +class cDxr3MemcpyBench +{ +public: + cDxr3MemcpyBench(uint32_t config_flags = 0); + +private: + unsigned long long int rdtsc(); + + vector m_methods; +}; + +// ================================== +// optimized/fast memcpy +extern void *(* dxr3_memcpy)(void *to, const void *from, size_t len); + +#endif /*_DXR3MEMCPY_H_*/ diff --git a/dxr3multichannelaudio.c b/dxr3multichannelaudio.c new file mode 100644 index 0000000..0bbb15e --- /dev/null +++ b/dxr3multichannelaudio.c @@ -0,0 +1,645 @@ +/* +* dxr3multichannelaudio.c: +* +* taken from the AC3overDVB Patch maintained by Stefan Huelswitt +* +* +*/ + +#include +#include "dxr3multichannelaudio.h" +#include "dxr3log.h" +#include + +//#define DEBUG(x...) printf(x) +#define DEBUG(x...) + +//#define ED(x...) printf(x) +#define ED(x...) + +#define aAC3 0x80 +#define aDTS 0x88 +#define aLPCM 0xA0 +#define aMPEG 0xC0 + +#define aVDR 0x0B // VDR specific audio substream +#define aSPU 0x20 // SPU stream + +#define PES_HDR_SIZE 6 // length of PES header +#define PTS_SIZE 5 // length of PTS data +#define MAX_FRAMECOUNT 1536 // max. LPCM payload size + +#define SYNC_SIZE 7 // how many bytes we need to sync on a audio header + +#define AC3_SIZE 6144 // size of AC3 IEC paket +#define DTS_SIZE 2048 // size of DTS IEC paket +#define IEC_HDR_SIZE 8 // size of IEC header + +// --- cAudioEncapsulator ------------------------------------------------------ + +class cAudioEncapsulator { +private: + int totalSize, frameCount; + cFrame *frame; + uchar *frameData; + // + uchar syncBuff[SYNC_SIZE]; + int have, length, skipped; + // + uchar ptsFlags; + const uchar *ptsData; + int ptsDelay; + // + void NewFrame(uchar PTSflags, const uchar *PTSdata); + void SyncFound(const uchar *data); +protected: + int streamType; + cRingBufferFrame *ringBuffer; + int fillup, firstBurst; + bool mute, muteData; + // + void StartFrame(int size, uchar PTSflags, const uchar *PTSdata); + void FinishFrame(void); + void PutData(const uchar *data, int len); + void SendIECpause(int type, uchar PTSflags, const uchar *PTSdata); + // + virtual int SyncInfo(const uchar *data)=0; + virtual void StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata)=0; + virtual void FinishIECFrame(void); +public: + cAudioEncapsulator(cRingBufferFrame *rb, int StreamType); + virtual ~cAudioEncapsulator(); + void Clear(void); + void Decode(const uchar *data, int len, uchar PTSflags, int PTSdelay, const uchar *PTSdata); + int StreamType() { return streamType; } + void Mute(bool Mute) { mute=Mute; } + }; + +cAudioEncapsulator::cAudioEncapsulator(cRingBufferFrame *rb, int StreamType) +{ + ringBuffer=rb; + streamType=StreamType; + frame=0; firstBurst=1; + Clear(); +} + +cAudioEncapsulator::~cAudioEncapsulator() +{ + delete frame; +} + +void cAudioEncapsulator::Clear(void) +{ + delete frame; + frame=0; frameCount=0; fillup=0; mute=muteData=false; + have=length=skipped=0; +} + +void cAudioEncapsulator::StartFrame(int size, uchar PTSflags, const uchar *PTSdata) +{ + if(frame) { + DEBUG("StartFrame() with unfinished frame!\n"); + FinishFrame(); + } + ED("StartFrame: size=%d ptsFlags=%d\n",size,PTSflags); + totalSize=size; + NewFrame(PTSflags,PTSdata); +} + +void cAudioEncapsulator::NewFrame(uchar PTSflags, const uchar *PTSdata) +{ + if(!totalSize) { + DEBUG("NewFrame: new frame requested, but totalSize=0\n"); + return; + } + static const int ptslen[] = { 0,0,PTS_SIZE,PTS_SIZE*2 }; + const int plen = ptslen[PTSflags]; + int len = min(totalSize, MAX_FRAMECOUNT); + ED("NewFrame: totalSize=%d frameCount=%d PTSflags=%d",totalSize,len,PTSflags); + totalSize -= len; + ED(" new totalSize=%d\n",totalSize); + len += (plen + 3 + 7); + frameCount = len+PES_HDR_SIZE; + frameData = MALLOC(uchar,frameCount); + if (frameData) { + frame = new cFrame(frameData, -frameCount, ftUnknown); + if (frame) { + uchar buf[10]; + // build the PES header + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x01; + buf[3] = 0xBD; // PRIVATE_STREAM1 + buf[4] = (len >> 8) & 0xFF; + buf[5] = len & 0xFF; + buf[6] = 0x84; + buf[7] = plen ? (PTSflags << 6) : 0; + buf[8] = plen; + PutData(buf,9); + + if (plen) PutData(PTSdata,plen); + + // build LPCM header + buf[0] = aLPCM; // substream ID + buf[1] = 0xFF; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x81; + PutData(buf,7); + return; + } + else { free(frameData); frameData=0; } + } + esyslog("Failed to build frame for audio encapsulation"); +} + +void cAudioEncapsulator::FinishFrame(void) +{ + if (frameCount) { + DEBUG("FinishFrame() with frameCount>0\n"); + PutData(0,frameCount); + } + if (frame && frameData) { + ED("FinishFrame: totalSize=%d\n",totalSize); + if (!ringBuffer->Put(frame)) { + esyslog("Ringbuffer overflow. Encapsulated audio frame lost"); + delete frame; + } + } + frame=0; frameData=0; frameCount=0; +} + +void cAudioEncapsulator::PutData(const uchar *data, int len) +{ + if(!muteData) { + if(!frameData) DEBUG("PutData() without frame\n"); + while (frameData && len > 0) { + int l = min(len,frameCount); + if(data) { + memcpy(frameData,data,l); + data += l; + } + else memset(frameData,0,l); + frameData += l; len -= l; frameCount -= l; + + ED("PutData: %s=%d len=%d frameCount=%d\n",data?"put":"zero",l,len,frameCount); + if (!frameCount) { + FinishFrame(); + if (totalSize > 0) NewFrame(0,0); + } + } + } +} + +void cAudioEncapsulator::SendIECpause(int type, uchar PTSflags, const uchar *PTSdata) +{ + StartFrame(AC3_SIZE,PTSflags,PTSdata); + uchar burst[IEC_HDR_SIZE]; + // prepare IEC 60958 data frame + burst[0] = 0xF8; + burst[1] = 0x72; + burst[2] = 0x4E; + burst[3] = 0x1F; + + switch (type) { + default: + case 0: + burst[4] = 7 << 5; // null frame, stream = 7 + burst[5] = 0x00; + burst[6] = 0x00; // No data therein + burst[7] = 0x00; + break; + case 1: + burst[4] = 0x00; // Audio ES Channel empty, wait + burst[5] = 0x03; // for DD Decoder or pause + burst[6] = 0x00; // Trailing frame size is 32 bits payload + burst[7] = 0x20; + break; + case -1: + burst[4] = 0x01; // User stop, skip or error + burst[5] = 0x03; + burst[6] = 0x08; // Trailing frame size is zero + burst[7] = 0x00; + break; + } + PutData(burst,sizeof(burst)); + PutData(0,AC3_SIZE-sizeof(burst)); + FinishFrame(); + muteData = true; +} + +void cAudioEncapsulator::FinishIECFrame(void) +{ + if(!muteData) { + ED("FinishIECFrame: fillup=%d\n",fillup); + if (fillup) PutData(0,fillup); + FinishFrame(); + } + muteData=false; fillup=0; +} + +void cAudioEncapsulator::SyncFound(const uchar *data) +{ + if(skipped) { + DEBUG("Decode: skipped %d bytes\n",skipped); + ED("skipped: "); for(int k=-skipped ; k<0 ; k++) ED("%02x ",data[k]); + ED("\ndata: "); for(int k=0 ; k<24 ; k++) ED("%02x ",data[k]); + ED("\n"); + skipped=0; + } + uchar pf=0; + ED("Decode: sync found ptsFlags=%d ptsDelay=%d\n",ptsFlags,ptsDelay); + if(ptsFlags && ptsDelay<=1) { + pf=ptsFlags; ptsFlags=0; + } + if(firstBurst || mute) { + SendIECpause(1,pf,ptsData); + if(firstBurst && ++firstBurst>10) firstBurst=0; + } + else StartIECFrame(data,length,pf,ptsData); + PutData(data,SYNC_SIZE); + have = SYNC_SIZE; +} + +void cAudioEncapsulator::Decode(const uchar *data, int len, uchar PTSflags, int PTSdelay, const uchar *PTSdata) +{ + ED("Decode: enter length=%d have=%d len=%d PTSflags=%d PTSdelay=%d\n",length,have,len,PTSflags,PTSdelay); + if(PTSflags) { + // if we are close to the end of an audio frame, but are already receiving + // the start of the next frame, assume a corrupted stream and finish the + // incomplete frame. + if(length && length-have<20 && !PTSdelay && SyncInfo(data)) { + int miss=length-have; + DEBUG("Decode: incomplete frame (stream corrupt?). syncing to next. miss=%d\n",miss); + PutData(0,miss); + FinishIECFrame(); + length=have=0; + } +/* + // we only send PTS info if we're nearly at frame start, except + // if we're signaled to delay the PTS + if(length && have>40) { + if(PTSdelay) ED("Decode: PTS delayed\n"); + else { + DEBUG("Decode: PTS info dropped length=%d have=%d\n",length,have); + PTSflags=0; + } + } +*/ + ptsFlags=PTSflags; ptsData=PTSdata; ptsDelay=PTSdelay; +// ED("Decode: saved PTS flags=%d delay=%d\n",ptsFlags,ptsDelay); + } + +#if 0 + { + printf("Decode: len=%d\n",len); + for(int i=0 ; i= 0x60) /* bsid >= 12 */ + return 0; + + int frmsizecod = buf[4] & 63; + if (frmsizecod >= 38) + return 0; + int bitrate = rate[frmsizecod >> 1]; + + switch (buf[4] & 0xC0) { + case 0: + return 4 * bitrate; + case 0x40: + return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); + case 0x80: + return 6 * bitrate; + default: + return 0; + } +} + +void cAudioEncapsulatorAC3::StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata) +{ + StartFrame(AC3_SIZE,PTSflags,PTSdata); + fillup = AC3_SIZE-IEC_HDR_SIZE-length; + + // prepare IEC 60958 data frame + uchar burst[IEC_HDR_SIZE]; + burst[0] = 0xF8; + burst[1] = 0x72; + burst[2] = 0x4E; + burst[3] = 0x1F; + burst[4] = (buf[5] & 0x07); // Pc1 + burst[5] = 0x01; // Pc2 AC-3 + burst[6] = ((length * 8) >> 8 ) & 0xFF; // Pd1 + burst[7] = (length * 8) & 0xFF; // Pd2 + PutData(burst,sizeof(burst)); +} + +// --- cAudioEncapsulatorDTS --------------------------------------------------- + +class cAudioEncapsulatorDTS : public cAudioEncapsulator { +private: + virtual int SyncInfo(const uchar *buf); + virtual void StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata); +public: + cAudioEncapsulatorDTS(cRingBufferFrame *rb, int StreamType); + }; + +cAudioEncapsulatorDTS::cAudioEncapsulatorDTS(cRingBufferFrame *rb, int StreamType) +: cAudioEncapsulator(rb, StreamType) +{} + +int cAudioEncapsulatorDTS::SyncInfo(const uchar *buf) +{ + if ((buf[0] != 0x7F) || + (buf[1] != 0xfE) || + (buf[2] != 0x80) || + (buf[3] != 0x01)) return 0; + + int length = ((buf[5] & 0x03) << 12) | + ((buf[6] & 0xFF) << 4) | + ((buf[7] & 0xF0) >> 4); + + return length + 1; +} + +void cAudioEncapsulatorDTS::StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata) +{ + uchar ac5_type = ((buf[4] & 0x01) << 6) | ((buf[5] >>2) & 0x3F); + uchar ac5_spdif_type; + switch(ac5_type) { + case 0x0F: + ac5_spdif_type = 0x0B; /* DTS */ + break; + case 0x1F: + ac5_spdif_type = 0x0C; /* DTS */ + break; + case 0x3F: + ac5_spdif_type = 0x0D; /* DTS */ + break; + default: + ac5_spdif_type = 0x00; /* DTS */ + esyslog("DTS: SPDIF type not detected: ac5 type = %X!\n", ac5_type); + break; + } + + if (length > DTS_SIZE-IEC_HDR_SIZE) { + DEBUG("DTS: length too long %d\n",length); + return; + } + + StartFrame(DTS_SIZE,PTSflags,PTSdata); + fillup = DTS_SIZE-IEC_HDR_SIZE-length; + + // prepare IEC 60958 data frame + uchar burst[IEC_HDR_SIZE]; + burst[0] = 0xF8; + burst[1] = 0x72; + burst[2] = 0x4E; + burst[3] = 0x1F; + burst[4] = 0x00; + burst[5] = ac5_spdif_type; /* DTS data */ + burst[6] = ((length * 8) >> 8 ) & 0xFF; /* ac5_length * 8 */ + burst[7] = (length * 8) & 0xFF; + PutData(burst,sizeof(burst)); +} + +// --- cMultichannelAudio ------------------------------------------------------ + +cMultichannelAudio::cMultichannelAudio(cRingBufferFrame *rb) +{ + encapsulator=0; ringBuffer=rb; + fixed=false; + if(!ringBuffer) DEBUG("multichannel: no ringbuffer!"); +} + +cMultichannelAudio::~cMultichannelAudio() +{ + delete encapsulator; +} + +void cMultichannelAudio::Clear() +{ + Lock(); + if(encapsulator) encapsulator->Clear(); + Unlock(); +} + +void cMultichannelAudio::Reset() +{ + Lock(); + delete encapsulator; encapsulator=0; + fixed=false; + Unlock(); +} + +/* +void cMultichannelAudio::Mute(bool Mute) +{ + Lock(); + if(encapsulator) encapsulator->Mute(Mute); + Unlock(); +} +*/ + +int cMultichannelAudio::Check(uchar *b, int length, uchar *header) +{ + Lock(); + int res=0; + ptsDelay=0; offset=0; ptsData=0; + + // get PTS information + ptsFlags=header[7]>>6; + if(ptsFlags) ptsData=&header[9]; + + // AC3 frames may span over multiple PES packets. Unfortunaly the continuation + // packets start with the aLPCM code sometimes. Some magic here to detect + // this case. + uchar subStreamType=b[0]; + if(subStreamType!=aVDR) subStreamType&=0xF8; + bool aligned=header[6]&4; + if(!aligned) { + uchar ost=encapsulator ? encapsulator->StreamType() : 0; + if(!ptsFlags) { + if((subStreamType!=aLPCM && subStreamType!=aSPU) || fixed) { + if(ost>0) { + ED("multichannel: crossing -> keep encapsulator\n"); + subStreamType=ost; + } + else { + ED("multichannel: crossing -> skip\n"); + res=1; goto out; // skip + } + } + } + else if(fixed && ost>0) { + ED("multichannel: fixed unaligned -> keep encapsulator\n"); + subStreamType=ost; + } + } + fixed=false; + + switch(subStreamType) { + case aDTS: + case aAC3: + offset=4; // skip the DVD stream infos + break; + default: + if(aligned || !ptsFlags) { + if(encapsulator) { + Reset(); + DEBUG("multichannel: interrupted encapsulator stream (unknown)\n"); + } + DEBUG("multichannel: unknown substream type %x (skipped)\n",subStreamType); + res=1; goto out; // skip + } + subStreamType=aVDR; + ED("multichannel: assuming aVDR for unknown substream type\n"); + // fall through + case aVDR: + fixed=true; + break; + case aLPCM: + if(encapsulator) { + Reset(); + DEBUG("multichannel: interrupted encapsulator stream (LPCM)\n"); + } + ED("multichannel: LPCM\n"); + res=2; goto out; // pass + case aSPU: + ED("multichannel: SPU stream (skipped)\n"); + res=1; goto out; // skip + } + + // If the SubStreamType has changed then select the right encapsulator + if(!encapsulator || encapsulator->StreamType()!=subStreamType) { + DEBUG("multichannel: new encapsulator %x\n",subStreamType); + Reset(); + switch(subStreamType) { + case aAC3: + case aVDR: // AC3 + encapsulator=new cAudioEncapsulatorAC3(ringBuffer,subStreamType); + break; + case aDTS: // Dts + encapsulator=new cAudioEncapsulatorDTS(ringBuffer,subStreamType); + break; + } + if(!encapsulator) { + DEBUG("multichannel: no encapsulator\n"); + res=1; goto out; // skip + } + } + +out: + ED("HEADER type=%x sub=%x ptsflags=%d length=%d\n",header[3],subStreamType,ptsFlags,length); + ED("head: "); for(int k=0 ; k<24 ; k++) ED("%02x ",header[k]); + ED("\ndata: "); for(int k=0 ; k<24 ; k++) ED("%02x ",b[k]); + ED("\n"); + + Unlock(); return res; +} + +void cMultichannelAudio::Encapsulate(uchar *b, int length) +{ + Lock(); + if(offset && ptsFlags) { // get start of the packet to which the PTS belong (DVD only) + if(offset>=2 && length>offset-2) ptsDelay|=b[offset-2]*256; + if(offset>=1 && length>offset-1) ptsDelay|=b[offset-1]; + } + if(length>=offset) { + if(encapsulator) + encapsulator->Decode(b+offset,length-offset,ptsFlags,ptsDelay,ptsData); + ptsFlags=0; ptsDelay=0; offset=0; ptsData=0; + } + else offset-=length; + Unlock(); +} + diff --git a/dxr3multichannelaudio.h b/dxr3multichannelaudio.h new file mode 100644 index 0000000..689f8f1 --- /dev/null +++ b/dxr3multichannelaudio.h @@ -0,0 +1,33 @@ +#ifndef _DXR3MULTICHANNELAUDIO_H_ +#define _DXR3MULTICHANNELAUDIO_H_ + +#include "dxr3vdrincludes.h" + +class cAudioEncapsulator; +class cRingBufferFrame; + +// ================================== +// Based on AC3overDVB Patch maintained +// by Stefan Huelswitt +class cMultichannelAudio : public cMutex +{ +private: + cAudioEncapsulator *encapsulator; + cRingBufferFrame *ringBuffer; + int ptsFlags, ptsDelay, offset; + uchar *ptsData; + bool fixed; + +public: + cMultichannelAudio(cRingBufferFrame *rb); + virtual ~cMultichannelAudio(); + + int Check(uchar *b, int length, uchar *header); + int Offset(void) { return offset; } + void Encapsulate(uchar *b, int length); + void Clear(); + void Reset(); + //void Mute(bool Mute); +}; + +#endif /*_DXR3MULTICHANNELAUDIO_H_*/ diff --git a/dxr3nextpts.c b/dxr3nextpts.c new file mode 100644 index 0000000..72b3e31 --- /dev/null +++ b/dxr3nextpts.c @@ -0,0 +1,4 @@ +#include "dxr3nextpts.h" + +// ================================== +cMutex* cDxr3NextPts::m_pMutex = new cMutex; diff --git a/dxr3nextpts.h b/dxr3nextpts.h new file mode 100644 index 0000000..0391a48 --- /dev/null +++ b/dxr3nextpts.h @@ -0,0 +1,42 @@ +/* + * dxr3nextpts.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3NEXTPTS_H_ +#define _DXR3NEXTPTS_H_ + +#include +#include +#include "dxr3vdrincludes.h" +#include "dxr3singleton.h" + +// ================================== +// pts program time stamp +// damit wird ermittelt welches audio frame zu welchem bild gehört +class cDxr3NextPts : public Singleton +{ +public: + cDxr3NextPts() {} + ~cDxr3NextPts() {} + + void SetNextPts(uint32_t pts) { Lock(); if (pts) m_nextPts = pts; Unlock(); } + uint32_t GetNextPts() { Lock(); uint32_t tmpPts = m_nextPts; Unlock(); return tmpPts;} + + void Clear() { Lock(); m_nextPts = 0; Unlock();} + +protected: + static cMutex* m_pMutex; + uint32_t m_nextPts; + + static void Lock() {cDxr3NextPts::m_pMutex->Lock();} + static void Unlock() {cDxr3NextPts::m_pMutex->Unlock();} + +private: + cDxr3NextPts(cDxr3NextPts&); // no copy constructor +}; + +#endif /*_DXR3NEXTPTS_H_*/ diff --git a/dxr3osd.c b/dxr3osd.c new file mode 100644 index 0000000..6bb5f43 --- /dev/null +++ b/dxr3osd.c @@ -0,0 +1,161 @@ +/* + * dxr3osd.c + * + * Copyright (C) 2002 Stefan Schluenss + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include + +#include "dxr3vdrincludes.h" +#include "dxr3interface.h" + +#include "dxr3osd.h" +#include "dxr3interface_spu_encoder.h" + +#if VDRVERSNUM >= 10307 + +//#include "dxr3osd_mpeg.h" +#include "dxr3osd_subpicture.h" + +// ================================== +cOsd *cDxr3OsdProvider::CreateOsd(int Left, int Top) +{ +// if (cDxr3ConfigData::Instance().GetMenuMode() == (eMenuMode)SUBPICTURE) +// { + // use subpicture + return new cDxr3SubpictureOsd(Left, Top); +/* } + else + { + // mpeg based menu system + return new cDxr3MpegOsd(Left, Top); + }*/ +} + +#else /*VDRVERSNUM*/ + +// ================================== +bool cDxr3Osd::SetWindow(cWindow *Window) +{ + if (Window) + { + // Window handles are counted 0...(MAXNUMWINDOWS - 1), but the actual window + // numbers in the driver are used from 1...MAXNUMWINDOWS. + int Handle = Window->Handle(); + if (0 <= Handle && Handle < MAXNUMWINDOWS) + { + Spu->Cmd(OSD_SetWindow, 0, Handle + 1); + return true; + } + esyslog("ERROR: illegal window handle: %d", Handle); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Osd::SetWindow: illegal window handle:" << Handle << "\n"; + } + } + return false; +} + +// ================================== +cDxr3Osd::cDxr3Osd(int x, int y) : cOsdBase(x, y) +{ + Spu = &cSPUEncoder::Instance(); +} + +// ================================== +cDxr3Osd::~cDxr3Osd() +{ + for (int i = 0; i < NumWindows(); i++) + { + CloseWindow(GetWindowNr(i)); + } +} + +// ================================== +bool cDxr3Osd::OpenWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_Open, Window->Bpp(), X0() + Window->X0(), Y0() + Window->Y0(), X0() + Window->X0() + Window->Width() - 1, Y0() + Window->Y0() + Window->Height() - 1, (void *)1); // initially hidden! + return true; + } + return false; +} + +// ================================== +void cDxr3Osd::CommitWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + + if (Window->Dirty(x1, y1, x2, y2)) + { + // commit colors: + int FirstColor = 0, LastColor = 0; + const eDvbColor *pal; + while ((pal = Window->NewColors(FirstColor, LastColor)) != NULL) + Spu->Cmd(OSD_SetPalette, FirstColor, LastColor, 0, 0, 0, pal); + // commit modified data: + Spu->Cmd(OSD_SetBlock, Window->Width(), x1, y1, x2, y2, Window->Data(x1, y1)); + } + } +} + +// ================================== +void cDxr3Osd::ShowWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_MoveWindow, 0, X0() + Window->X0(), Y0() + Window->Y0()); + } +} + +// ================================== +void cDxr3Osd::HideWindow(cWindow *Window, bool Hide) +{ + if (SetWindow(Window)) + { + Spu->Cmd(Hide ? OSD_Hide : OSD_Show, 0); + } +} + +// ================================== +void cDxr3Osd::CloseWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_Close); + } +} + +// ================================== +void cDxr3Osd::MoveWindow(cWindow *Window, int x, int y) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_MoveWindow, 0, X0() + x, Y0() + y); + } +} + +#endif /*VDRVERSNUM*/ diff --git a/dxr3osd.h b/dxr3osd.h new file mode 100644 index 0000000..234689e --- /dev/null +++ b/dxr3osd.h @@ -0,0 +1,42 @@ +#ifndef _DXR3_OSD_H_ +#define _DXR3_OSD_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3interface_spu_encoder.h" + +#if VDRVERSNUM >= 10307 + +// ================================== +// osd plugin provider +class cDxr3OsdProvider : public cOsdProvider +{ +public: + cDxr3OsdProvider() {} + virtual cOsd *CreateOsd(int Left, int Top); +}; + +#else /*VDRVERSNUM*/ + +// ================================== +// osd interface for =< vdr1,3,7 +class cDxr3Osd : public cOsdBase +{ +private: + cSPUEncoder* Spu; + + bool SetWindow(cWindow*); + +public: + cDxr3Osd(int x, int y); + ~cDxr3Osd(); + + virtual bool OpenWindow(cWindow *Window); + virtual void CommitWindow(cWindow *Window); + virtual void ShowWindow(cWindow *Window); + virtual void HideWindow(cWindow *Window, bool Hide); + virtual void CloseWindow(cWindow *Window); + virtual void MoveWindow(cWindow *Window, int x, int y); +}; + +#endif /*VDRVERSNUM*/ +#endif /*_DXR3_OSD_H_*/ diff --git a/dxr3osd_subpicture.c b/dxr3osd_subpicture.c new file mode 100644 index 0000000..e6dc154 --- /dev/null +++ b/dxr3osd_subpicture.c @@ -0,0 +1,174 @@ +#include "dxr3osd_subpicture.h" + +#if VDRVERSNUM >= 10307 + +#define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 + +// ================================== +cDxr3SubpictureOsd::cDxr3SubpictureOsd(int Left, int Top) : cOsd(Left, Top) +{ + shown = false; + Spu = &cSPUEncoder::Instance(); + + // must clear all windows here to avoid flashing effects - doesn't work if done + // in Flush() only for the windows that are actually used... + for (int i = 0; i < MAXNUMWINDOWS; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + Spu->Cmd(OSD_Clear); + } + +} + +// ================================== +cDxr3SubpictureOsd::~cDxr3SubpictureOsd() +{ + if (shown) + { + cBitmap *Bitmap; + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + Spu->Cmd(OSD_Close); + } + } +} + +// ================================== +eOsdError cDxr3SubpictureOsd::CanHandleAreas(const tArea *Areas, int NumAreas) +{ + + eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas); + if (Result == oeOk) + { + if (NumAreas > MAXNUMWINDOWS) + { + return oeTooManyAreas; + } + + for (int i = 0; i < NumAreas; i++) + { + if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8) + { + return oeBppNotSupported; + } + + if ((Areas[i].Width() & (8 / Areas[i].bpp - 1)) != 0) + { + return oeWrongAlignment; + } + } + } + return Result; +} + +// ================================== +void cDxr3SubpictureOsd::SaveRegion(int x1, int y1, int x2, int y2) +{ + // ToDo? +} + +// ================================== +void cDxr3SubpictureOsd::RestoreRegion() +{ + // ToDo? +} + +// ================================== +void cDxr3SubpictureOsd::Flush() +{ + cBitmap *Bitmap; + + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + + if (!shown) + { + Spu->Cmd(OSD_Open, Bitmap->Bpp(), Left() + Bitmap->X0(), Top() + Bitmap->Y0(), Left() + Bitmap->X0() + Bitmap->Width() - 1, Top() + Bitmap->Y0() + Bitmap->Height() - 1, (void *)1); // initially hidden! + } + + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + if (Bitmap->Dirty(x1, y1, x2, y2)) + { + //TODO Workaround: apparently the bitmap sent to the driver always has to be a multiple + //TODO of 8 bits wide, and (dx * dy) also has to be a multiple of 8. + //TODO Fix driver (should be able to handle any size bitmaps!) + + while ((x1 > 0 || x2 < Bitmap->Width() - 1) && ((x2 - x1) & 7) != 7) + { + if (x2 < Bitmap->Width() - 1) + { + x2++; + } + else if (x1 > 0) + { + x1--; + } + } + + //TODO "... / 2" <==> Bpp??? + while ((y1 > 0 || y2 < Bitmap->Height() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) + { + if (y2 < Bitmap->Height() - 1) + { + y2++; + } + else if (y1 > 0) + { + y1--; + } + } + + while ((x1 > 0 || x2 < Bitmap->Width() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) + { + if (x2 < Bitmap->Width() - 1) + { + x2++; + } + else if (x1 > 0) + { + x1--; + } + } + + // commit colors: + int NumColors; + const tColor *Colors = Bitmap->Colors(NumColors); + + if (Colors) + { + + // TODO this should be fixed in the driver! + tColor colors[NumColors]; + for (int i = 0; i < NumColors; i++) + { + // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): + colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); + } + + Colors = colors; + //TODO end of stuff that should be fixed in the driver + Spu->Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); + } + // commit modified data: + //Spu->Cmd(OSD_SetBlock, Bitmap->Width(), x1, y1, x2, y2, Bitmap->Data(x1, y1)); + Spu->Cmd(OSD_SetBlock, Bitmap->Width(), x1, y1, x2, y2, Bitmap->Data(x1, y1)); + } + Bitmap->Clean(); + } + + if (!shown) + { + // Showing the windows in a separate loop to avoid seeing them come up one after another + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + Spu->Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0()); + } + shown = true; + } +} + +#endif /*VDRVERSNUM*/ + diff --git a/dxr3osd_subpicture.h b/dxr3osd_subpicture.h new file mode 100644 index 0000000..6806c90 --- /dev/null +++ b/dxr3osd_subpicture.h @@ -0,0 +1,29 @@ +#ifndef _DXR3OSD_SUBPICTURE_H_ +#define _DXR3OSD_SUBPICTURE_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3interface_spu_encoder.h" + +#if VDRVERSNUM >= 10307 + +// ================================== +// osd interface for => vdr1,3,7 +class cDxr3SubpictureOsd : public cOsd +{ +private: + cSPUEncoder* Spu; + bool shown; + +public: + cDxr3SubpictureOsd(int Left, int Top/*, int SpuDev*/); + ~cDxr3SubpictureOsd(); + + eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); + void SaveRegion(int x1, int y1, int x2, int y2); + void RestoreRegion(void); + + void Flush(); +}; + +#endif /*VDRVERSNUM*/ +#endif /*_DXR3OSD_SUBPICTURE_H_*/ diff --git a/dxr3outputthread.c b/dxr3outputthread.c new file mode 100644 index 0000000..d4a4a8e --- /dev/null +++ b/dxr3outputthread.c @@ -0,0 +1,279 @@ +/* + * dxr3outputthread.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#include +#include +#include +#include +#include "dxr3outputthread.h" +#include "dxr3log.h" + +// ================================== +const int AUDIO_OFFSET = 4500; +#define SCR m_dxr3Device.GetSysClock() +// ================================== + +// ================================== +// constr. +cDxr3OutputThread::cDxr3OutputThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer) : +cThread(), m_dxr3Device(dxr3Device), m_buffer(buffer), m_bStopThread(false), m_bNeedResync(false) +{ +} + +// ================================== +// send stop signal +void cDxr3OutputThread::SetStopSignal() +{ + Lock(); + m_bStopThread = true; + Unlock(); +} + +// ================================== +// was stop signal send? +bool cDxr3OutputThread::GetStopSignal() +{ + bool ret = false; + Lock(); + ret = m_bStopThread; + Unlock(); + + return ret; +} + +// ================================== +// constr. +cDxr3AudioOutThread::cDxr3AudioOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer) : +cDxr3OutputThread(dxr3Device, buffer) +{ +} + +// ================================== +// thread action +void cDxr3AudioOutThread::Action() +{ + bool resync = false; + uint32_t pts = 0; + + cLog::Instance() << "cDxr3AudioOutThread::Action Thread started\n"; + + sched_param temp; + temp.sched_priority = 2; + + if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) + { + cLog::Instance() << "cDxr3AudioOutThread::Action(): Error can't set priority\n"; + } + + while (!GetStopSignal()) + { + pts = 0; + cFixedLengthFrame* pNext = m_buffer.Get(); + + if (pNext) pts = pNext->GetPts(); + + if (pts && abs((int)pts-(int)SCR) > 30000 || m_dxr3Device.IsExternalReleased()) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { + cLog::Instance() << "cDxr3AudioOutThread::Action " << "pts = " << pts << " scr = " << SCR << "\n"; + } + m_buffer.Clear(); + m_bNeedResync = true; + } + else if (pNext) + { + if (!pts || pts < SCR) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// if (pts) cLog::Instance() << "cDxr3AudioOutThread::Action pts " << pNext->GetPts() << " scr " << SCR << " delta " << (pts - SCR) << "\n"; + } + if (!pts && resync) + { + continue; + } + else + { + resync = false; + } + + if (pts && (pts < SCR) && ((SCR - pts) > 5000)) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action pts audio too small " << (SCR - pts) << "\n"; + } + m_dxr3Device.SetSysClock(pts+ 1 * AUDIO_OFFSET); + m_dxr3Device.PlayAudioFrame(pNext); + if (m_buffer.IsPolled()) + { + m_buffer.Clear(); + m_bNeedResync = true; + } + } + else + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action write audio\n"; + } + m_dxr3Device.PlayAudioFrame(pNext); + m_buffer.Pop(); + } + } + else + { + if (abs((int)pts - (int)SCR) < (AUDIO_OFFSET )) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// if (pts) cLog::Instance() << "cDxr3AudioOutThread::Action pts " << pNext->GetPts() << " scr " << SCR << " delta " << (pts - SCR) << "\n"; + } + m_dxr3Device.PlayAudioFrame(pNext); + m_buffer.Pop(); + } + } + } + + if ((pts > SCR && abs((int)pts - (int)SCR) > AUDIO_OFFSET)) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action Stopping audio " << SCR << " " << pts << "\n"; + } + + usleep(10000); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action Starting audio " << SCR << " " << pts << "\n"; + } + } + } +} + +// ================================== +// constr. +cDxr3VideoOutThread::cDxr3VideoOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer) : +cDxr3OutputThread(dxr3Device, buffer) +{ +} + +// ================================== +// thread action +void cDxr3VideoOutThread::Action() +{ + uint32_t pts = 0; + static uint32_t lastPts = 0; + + cLog::Instance() << "cDxr3VideoOutThread::Action Thread started\n"; + + sched_param temp; + temp.sched_priority = 1; + + if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action(): Error can't set priority\n"; + } + + while (!GetStopSignal()) + { + cFixedLengthFrame* pNext = m_buffer.Get(); + if (pNext) + { + pts = pNext->GetPts(); + if (pts == lastPts) pts = 0; + + if (pts > SCR && abs((int)pts - (int)SCR) < 7500) + { + m_dxr3Device.SetPts(pts); + } + + if (!pts || pts < SCR) + { + if (m_buffer.Available()) + { + m_dxr3Device.PlayVideoFrame(pNext); + m_buffer.Pop(); + } + } + else + { + if ((pts > SCR) && abs((int)pts - (int)SCR) < 7500) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action pts " << pts << " scr " << SCR << " delta " << (pts - SCR) << "\n"; + } + + m_dxr3Device.SetPts(pts); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action done\n"; + } + + if (m_buffer.Available() && pNext->GetData() && pNext->GetCount()) + { + m_dxr3Device.PlayVideoFrame(pNext); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action write\n"; + } + + m_buffer.Pop(); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action done pop\n"; + } + } + if (cDxr3ConfigData::Instance().GetDebug()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action done complete\n"; + } + } + else + { + if (pts < SCR) + { + m_dxr3Device.PlayVideoFrame(pNext); + m_buffer.Pop(); + } + } + } + + + if (m_dxr3Device.IsExternalReleased()) + { + m_bNeedResync = true; + m_buffer.Clear(); + } + + if ((pts > SCR && abs((int)pts - (int)SCR) > 7500 )) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action Stopping video " << SCR << " " << pts << "\n"; + } + + usleep(10000); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action Starting video " << SCR << " " << pts << "\n"; + } + } + } + } +} + + +#undef SCR diff --git a/dxr3outputthread.h b/dxr3outputthread.h new file mode 100644 index 0000000..1ed7dc6 --- /dev/null +++ b/dxr3outputthread.h @@ -0,0 +1,71 @@ +/* + * dxr3outputthread.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3OUTPUTTHREAD_H_ +#define _DXR3OUTPUTTHREAD_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3syncbuffer.h" +#include "dxr3audiodecoder.h" + +// ================================== +class cDxr3OutputThread : public cThread +{ +public: + cDxr3OutputThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer); + virtual ~cDxr3OutputThread() {Cancel();}; + + // virtual void Start(void) {cThread::Start()}; + void SetStopSignal(); + bool NeedResync() { return m_bNeedResync;}; + void ClearResyncRequest() { m_bNeedResync = false;}; + +protected: + virtual void Action() = 0; + bool GetStopSignal(); + + cDxr3Interface& m_dxr3Device; + cDxr3SyncBuffer& m_buffer; + bool m_bStopThread; + bool m_bNeedResync; + +private: + cDxr3OutputThread(cDxr3OutputThread&); // no copy contructor +}; + +// ================================== +class cDxr3AudioOutThread : public cDxr3OutputThread +{ +public: + cDxr3AudioOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer); + virtual ~cDxr3AudioOutThread() {} + +protected: + void Action(); + +private: +// cDxr3AudioOutThread(); // no standard constructor + cDxr3AudioOutThread(cDxr3AudioOutThread&); // no copy constructor +}; + +// ================================== +class cDxr3VideoOutThread : public cDxr3OutputThread +{ +public: + cDxr3VideoOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer); + virtual ~cDxr3VideoOutThread() {} + +protected: + void Action(); + +private: +// cDxr3VideoOutThread(); // no standard constructor + cDxr3VideoOutThread(cDxr3VideoOutThread&); // no copy constructor +}; + +#endif /*_DXR3OUTPUTTHREAD_H_*/ diff --git a/dxr3palettemanager.c b/dxr3palettemanager.c new file mode 100644 index 0000000..0769722 --- /dev/null +++ b/dxr3palettemanager.c @@ -0,0 +1,114 @@ +/* + * dxr3palettemanager.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +/* + ToDo: + - cDxr3PaletteManager: Should we use here std::vector? +*/ + +#include +#include "dxr3palettemanager.h" +#include "dxr3tools.h" + +// ================================== +cDxr3PaletteManager::cDxr3PaletteManager() +{ + memset(m_colors, 0, sizeof(int) * MAX_COLORS); + memset(m_users, 0, sizeof(int) * MAX_COLORS); + memset(m_pal, 0, sizeof(int) * MAX_COLORS); + m_changed = false; +}; + +// ================================== +void cDxr3PaletteManager::AddColor(int color) +{ + int freeIndex = MAX_COLORS; + bool found = false; + + for (int i = 0; i < MAX_COLORS && !found; ++i) + { + if (color == m_colors[i]) + { + if (m_users[i] == 0) m_changed = true; + ++m_users[i]; + found = true; + } + if (m_users[i] == 0 && freeIndex >= MAX_COLORS) + { + freeIndex = i; + } + } + if (!found && freeIndex < MAX_COLORS) + { + m_colors[freeIndex] = color; + m_users[freeIndex] = 1; + m_changed = true; + } +} + +// ================================== +void cDxr3PaletteManager::RemoveColor(int color) +{ + bool found = false; + for (int i = 0; i < MAX_COLORS && !found; ++i) + { + if (color == m_colors[i]) + { + if (m_users[i] > 0) --m_users[i]; + found = true; + } + } +} + +// ================================== +int cDxr3PaletteManager::GetIndex(int color) +{ + bool found = false; + int index = 0; + for (int i = 0; i < MAX_COLORS && !found; ++i) + { + if (color == m_colors[i]) + { + index = i; + found = true; + } + } + return index; +} + +// ================================== +int cDxr3PaletteManager::GetCount() +{ + return MAX_COLORS; +} + +// ================================== +int cDxr3PaletteManager::operator[](int index) +{ + assert(index < MAX_COLORS && index > 0); + return m_colors[index]; +} + +// ================================== +bool cDxr3PaletteManager::HasChanged() +{ + bool retval = m_changed; + m_changed = false; + return retval; +} + +// ================================== +uint32_t* cDxr3PaletteManager::GetPalette() +{ + for (int i = 0; i < MAX_COLORS; ++i) + { + m_pal[i] = Tools::Rgb2YCrCb(m_colors[i]); + } + + return m_pal; +} diff --git a/dxr3palettemanager.h b/dxr3palettemanager.h new file mode 100644 index 0000000..94253b8 --- /dev/null +++ b/dxr3palettemanager.h @@ -0,0 +1,39 @@ +/* + * dxr3palettemanager.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3PALETTEMANAGER_H_ +#define _DXR3PALETTEMANAGER_H_ + +#include +#include +#include + +// ================================== +class cDxr3PaletteManager +{ +public: + cDxr3PaletteManager(); + ~cDxr3PaletteManager() {}; + + void AddColor(int color); + void RemoveColor(int color); + int GetCount(); + int operator[](int index); + int GetIndex(int color); + bool HasChanged(); + uint32_t* GetPalette(); + +private: + static const int MAX_COLORS = 16; + int m_colors[MAX_COLORS]; + uint32_t m_pal[MAX_COLORS]; + int m_users[MAX_COLORS]; + bool m_changed; +}; + +#endif /*_DXR3PALETTEMANAGER_H_*/ diff --git a/dxr3pesframe.c b/dxr3pesframe.c new file mode 100644 index 0000000..c86002e --- /dev/null +++ b/dxr3pesframe.c @@ -0,0 +1,226 @@ +#include "dxr3pesframe.h" +#include "dxr3log.h" +#include +#include +#include +#include +#include + +// ================================== +bool cDxr3PesFrame::ExtractNextFrame(const uint8_t* pBuf, uint32_t length) throw (ePesFrameError) +{ + cDxr3SafeArray pesArray((uint8_t*)pBuf, length); + uint32_t pos = 0; + m_pNextStart = pBuf; + m_remainingLength = length; + + InitData(); + + try + { + if (length > 9) + { + for (; pos + 9 < length && !IsPesHeader(pesArray.SubArray(pos, 4)); pos++); + m_pPesStart = pBuf + pos; + + if ((pesArray[pos + 6] & 0xC0) == 0x80 /*|| (pesArray[pos + 6] & 0xC0) == 0x00*/) + { + if (pos + 9 + pesArray[pos + 8] < length) + { + m_pEsStart = pBuf + pos + 9 + pesArray[pos + 8]; + if ((((int)pesArray[pos + 4]) * (int)256 + (int)pesArray[pos + 5]) > 0) + { + m_esLength = ((int)pesArray[pos + 4]) * (int)256 + (int)pesArray[pos + 5] + (int)6 - (9 + (int)pesArray[pos + 8]); + if (pos + 9 + pesArray[pos + 8] + m_esLength <= length) + { + m_bValid = true; + m_pNextStart = m_pEsStart + m_esLength; + m_remainingLength = pBuf + length - (m_pEsStart + m_esLength); + if (pesArray[pos + 6] >> 6 == 2 && pesArray[pos + 7] >> 7 != 0) + { + ExtractPts(pesArray.SubArray(pos + 9, 5)); + } + if (m_pesDataType == PES_VIDEO_DATA) + { + int retval = ExtractVideoData(pesArray.SubArray(pos + 9 + pesArray[pos + 8], m_esLength)); + if (m_videoFrameType != UNKNOWN_FRAME && retval) m_offset = retval + pos + 9 + pesArray[pos + 8]; + } + } + } + } + } + else + { + uint32_t fpos = pos + 6; + m_esLength = ((int)pesArray[pos + 4]) * (int)256 + (int)pesArray[pos + 5]; + if (length >= pos + 6 + m_esLength) + { + while (pesArray[fpos] == 0xff) ++fpos; // skip stuffing bytes + if ((pesArray[fpos] & 0xC0) == 0x40) fpos += 2; // skip std buffer scale and size + if ((pesArray[fpos] & 0xF0) == 0x20) + { + // pts only + ExtractPts(pesArray.SubArray(fpos, 5)); + fpos += 5; + } + else if ((pesArray[fpos] & 0xF0) == 0x30) + { + // pts and dts + ExtractPts(pesArray.SubArray(fpos, 5)); + fpos += 10; + } + else + { + ++fpos; + } + + if (m_esLength) m_esLength = m_esLength - (fpos - pos - 6); + m_pEsStart = pBuf + fpos; + m_pNextStart = m_pEsStart + m_esLength; + m_remainingLength = pBuf + length - (m_pEsStart + m_esLength); + m_bValid = true; + if (m_pesDataType == PES_VIDEO_DATA) + { + int retval = ExtractVideoData(pesArray.SubArray(fpos, m_esLength)); + if (m_videoFrameType != UNKNOWN_FRAME && retval) m_offset = 0; + } + } + } + } + } + catch (cDxr3SafeArray::eSafeArrayException ex) + { + m_bValid = false; + cLog::Instance() << "*** PES_GENERAL_ERROR ****\n"; + throw(PES_GENERAL_ERROR); + } + + return m_bValid; + +} + +// ================================== +int cDxr3PesFrame::ExtractVideoData(cDxr3SafeArray esFrame) throw (cDxr3SafeArray::eSafeArrayException) { + int retval = 0; + for (uint32_t i = 0; esFrame.GetLength() > (uint32_t) 8 && i < esFrame.GetLength() - 8; i++) + { + if (esFrame[i] == 0 && esFrame[i+1] == 0 && esFrame[i+2] == 1) + { + // start code + if ((esFrame[i + 3] & 0xFF) == 0x00) + { + // extract frame type + if (m_offset == 0) retval = i + ; + switch ((esFrame[ i + 5] >> 3) & 0x7) + { + case 0x1: + m_videoFrameType = I_FRAME; + break; + + case 0x2: + m_videoFrameType = P_FRAME; + break; + + case 0x3: + m_videoFrameType = B_FRAME; + break; + + default: + m_videoFrameType = UNKNOWN_FRAME; + break; + } + } + else if ((esFrame[i + 3] & 0xFF) == 0xB3) + { + // aspect ratio + switch ((esFrame[i + 7]) & 0xF0) + { + case 0x20: + m_staticAspectRatio = m_aspectRatio = ASPECTRATIO_4_3; + break; + + case 0x30: + m_staticAspectRatio = m_aspectRatio = ASPECTRATIO_16_9; + break; + + default: + break; + } + m_staticHorizontalSize = m_horizontalSize = (esFrame[i + 5] & 0xF0) >> 4 | esFrame[i + 4] << 4; + } + } + } + return retval; +} + +// ================================== +void cDxr3PesFrame::ExtractPts(cDxr3SafeArray ptsData) throw (cDxr3SafeArray::eSafeArrayException) +{ + m_pts = ((ptsData[0] >> 1) & 0x07) << 29; + m_pts |= ptsData[1] << 21; + m_pts |= (ptsData[2] >> 1) << 14; + m_pts |= ptsData[3] << 6; + m_pts |= ptsData[4] >> 2; +} + +// ================================== +bool cDxr3PesFrame::IsPesHeader(cDxr3SafeArray header) throw (cDxr3SafeArray::eSafeArrayException) +{ + bool ret = false; + + if (!header[0] && !header[1] && header[2] == 0x01 ) + { + ret = true; + switch (header[3]) + { + case 0xC0 ... 0xDF: // audio stream + m_pesDataType = PES_AUDIO_DATA; + break; + + case 0xE0 ... 0xEF: // video stream + m_pesDataType = PES_VIDEO_DATA; + break; + + case 0xBD: // private stream 1 + m_pesDataType = PES_PRIVATE_DATA; + break; + + case 0xBA: + ret = false; + break; + + case 0xBE: // padding stream + ret = false; + break; + + case 0xBC: // program stream map + case 0xBF: // private stream 2 + case 0xF0: // ECM stream + case 0xF1: // EMM stream + case 0xF2: // DSMCC stream + case 0xF3: // 13522 stream + case 0xF4: // H.22.1 type A + case 0xF5: // H.22.1 type B + case 0xF6: // H.22.1 type C + case 0xF7: // H.22.1 type D + case 0xF8: // H.22.1 type E + case 0xF9: // ancillary stream + case 0xFA ... 0xFE: // reserved data stream + case 0xFF: // program stream directory + break; + default: + ret = false; + break; + } + m_streamId = header[3]; + } + + return ret; +} + +// ================================== +uint32_t cDxr3PesFrame::m_staticAspectRatio = EM8300_ASPECTRATIO_4_3; +uint32_t cDxr3PesFrame::m_staticHorizontalSize = 720; +const uint32_t cDxr3PesFrame::MAX_PES_HEADER_SIZE = 184; + diff --git a/dxr3pesframe.h b/dxr3pesframe.h new file mode 100644 index 0000000..e0d9034 --- /dev/null +++ b/dxr3pesframe.h @@ -0,0 +1,158 @@ +/* + * dxr3pesframe.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3PESFRAME_H_ +#define _DXR3PESFRAME_H_ + +#include +#include + +// ================================== +const int ASPECTRATIO_4_3 = 0; +const int ASPECTRATIO_16_9 = 1; + +// ================================== +enum eVideoFrameType +{ + I_FRAME, + P_FRAME, + B_FRAME, + UNKNOWN_FRAME +}; + +// ================================== +// XXX: Should we use here std:vector? +template +class cDxr3SafeArray +{ +public: + // ================================== + enum eSafeArrayException + { + SAFE_ARRAY_INDEX_OUT_OF_BOUND + }; + + cDxr3SafeArray(T* pBuf, uint32_t length) : m_pBuf(pBuf), m_length(length) {}; + cDxr3SafeArray(const cDxr3SafeArray& from) : m_pBuf(from.m_pBuf), m_length(from.m_length) {}; + virtual ~cDxr3SafeArray() {}; + + T& operator[](uint32_t index) throw (eSafeArrayException) { if (index >= m_length) throw(SAFE_ARRAY_INDEX_OUT_OF_BOUND); return m_pBuf[index];}; + cDxr3SafeArray SubArray(uint32_t offset, uint32_t length) { if (offset + length > m_length) throw(SAFE_ARRAY_INDEX_OUT_OF_BOUND); return cDxr3SafeArray(m_pBuf + offset, length);}; + + uint32_t GetLength(void) { return m_length; }; +protected: + T* m_pBuf; + uint32_t m_length; + +private: + cDxr3SafeArray(); // no standard constructor +}; + + +// ================================== +// pes - packetized elementary stream +class cDxr3PesFrame +{ +public: + + // ================================== + enum ePesDataType + { + PES_AUDIO_DATA, + PES_VIDEO_DATA, + PES_PRIVATE_DATA, + PES_UNKNOWN_DATA + }; + + // ================================== + enum ePesFrameError + { + PES_GENERAL_ERROR + }; + +public: + cDxr3PesFrame() : m_pesDataType(PES_UNKNOWN_DATA), m_bValid(false), m_pPesStart(0), m_pEsStart(0) + , m_esLength(0), m_pts(0), m_videoFrameType(UNKNOWN_FRAME), m_aspectRatio(m_staticAspectRatio) + , m_horizontalSize(m_staticHorizontalSize), m_streamId(0), m_pNextStart(0), m_remainingLength(0) + , m_offset(0) {}; + + virtual ~cDxr3PesFrame() {} + + bool ExtractNextFrame(const uint8_t* pBuf, uint32_t length) throw (ePesFrameError); + + ePesDataType GetPesDataType(void) const { assert(m_bValid); return m_pesDataType; }; + const uint8_t* GetPesStart(void) const { assert(m_bValid); return m_pPesStart; }; + const uint8_t* GetEsStart(void) const { assert(m_bValid); return m_pEsStart; }; + uint32_t GetEsLength(void) const { assert(m_bValid); return m_esLength; }; + + const uint8_t* GetNextStart(void) const { return m_pNextStart;}; + uint32_t GetRemainingLength(void) const { return m_remainingLength;}; + + uint32_t GetPts(void) const { assert(m_bValid); return m_pts; }; + + eVideoFrameType GetFrameType(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_videoFrameType;}; + uint32_t GetAspectRatio(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_aspectRatio;}; + uint32_t GetHorizontalSize(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_horizontalSize;}; + uint8_t GetStreamId(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_streamId;}; + int GetOffset(void) const { assert(m_bValid); return m_offset;}; + + bool IsValid(void) { return m_bValid; }; + +protected: + bool IsPesHeader(cDxr3SafeArray header) throw (cDxr3SafeArray::eSafeArrayException); + void ExtractPts(cDxr3SafeArray ptsData) throw (cDxr3SafeArray::eSafeArrayException); + int ExtractVideoData(cDxr3SafeArray esFrame) throw (cDxr3SafeArray::eSafeArrayException); + + void InitData(void) + { + m_pesDataType = PES_UNKNOWN_DATA; + m_bValid = false; + m_pPesStart = 0; + m_pEsStart = 0; + m_esLength = 0; + m_pts = 0; + m_videoFrameType = UNKNOWN_FRAME; + m_aspectRatio = m_staticAspectRatio; + m_horizontalSize = m_staticHorizontalSize; + m_streamId = 0; + m_pNextStart = 0; + m_remainingLength = 0; + m_offset = 0; + } + + ePesDataType m_pesDataType; + bool m_bValid; + const uint8_t* m_pPesStart; + const uint8_t* m_pEsStart; + uint32_t m_esLength; + uint32_t m_pts; + + eVideoFrameType m_videoFrameType; + uint32_t m_aspectRatio; + uint32_t m_horizontalSize; + uint8_t m_streamId; + + const uint8_t* m_pNextStart; + uint32_t m_remainingLength; + int m_offset; + + static uint32_t m_staticAspectRatio; + static uint32_t m_staticHorizontalSize; + +protected: + static const uint32_t MAX_PES_HEADER_SIZE; + +private: + cDxr3PesFrame(cDxr3PesFrame&); // no copy constructor + +}; + + +#endif /*_DXR3PESFRAME_H_*/ + + diff --git a/dxr3singleton.h b/dxr3singleton.h new file mode 100644 index 0000000..6db2c26 --- /dev/null +++ b/dxr3singleton.h @@ -0,0 +1,43 @@ +/* + * dxr3singleton.h + * + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ + +#ifndef _DXR3_SINGLETON_H_ +#define _DXR3_SINGLETON_H_ + +// ================================== +// This template makes it easy to make +// global things +template +class Singleton +{ + protected: + Singleton() {} + virtual ~Singleton() {} + + public: + static T& Instance() + { + static T m_Instance; + return m_Instance; + } +}; + +#endif /*_DXR3_SINGLETON_H_*/ diff --git a/dxr3spudecoder.c b/dxr3spudecoder.c new file mode 100644 index 0000000..7e56219 --- /dev/null +++ b/dxr3spudecoder.c @@ -0,0 +1,628 @@ +/* + * dxr3spudecoder.c + * + * Copyright (C) 2004 Christian Gmeiner + * + * Orginal: + * Copyright (C) 2001.2002 Andreas Schultz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ + +/* +ToDo: + - Line 175 +*/ + +#include +#include +#include +#include + +#include "dxr3spudecoder.h" +#include "dxr3interface.h" +#include "dxr3tools.h" +#include "dxr3log.h" + +// ================================== +#define CMD_SPU_MENU 0x00 +#define CMD_SPU_SHOW 0x01 +#define CMD_SPU_HIDE 0x02 +#define CMD_SPU_SET_PALETTE 0x03 +#define CMD_SPU_SET_ALPHA 0x04 +#define CMD_SPU_SET_SIZE 0x05 +#define CMD_SPU_SET_PXD_OFFSET 0x06 +#define CMD_SPU_EOF 0xff + +#define spuU32(i) ((spu[i] << 8) + spu[i+1]) + + +/* + * cDxr3Spubitmap: + * + * this is a bitmap of the full screen and two palettes + * the normal palette for the background and the highlight palette + * + * Inputs: + * - a SPU rle encoded image on creation, which will be decoded into + * the full screen indexed bitmap + * + * Output: + * - a minimal sized cDxr3SpuBitmap a given palette, the indexed bitmap + * will be scanned to get the smallest possible resulting bitmap considering + * transparencies + */ + + +// ================================== +void cDxr3SpuPalette::setPalette(const uint32_t * pal) +{ + for (int i = 0; i < 16; i++) + palette[i] = Tools::YUV2Rgb(pal[i]); +} + +// ================================== +#define setMin(a, b) if (a > b) a = b +#define setMax(a, b) if (a < b) a = b + +#define spuXres 720 +#define spuYres 576 + +#define revRect(r1, r2) { r1.x1 = r2.x2; r1.y1 = r2.y2; r1.x2 = r2.x1; r1.y2 = r2.y1; } + +// ================================== +cDxr3SpuBitmap::cDxr3SpuBitmap(sDxr3SpuRect size, uint8_t * fodd, uint8_t * eodd, uint8_t * feven, uint8_t * eeven) +{ + if (size.x1 < 0 || size.y1 < 0 || size.x2 >= spuXres + || size.y2 >= spuYres) + throw; + + bmpsize = size; + revRect(minsize[0], size); + revRect(minsize[1], size); + revRect(minsize[2], size); + revRect(minsize[3], size); + + if (!(bmp = new uint8_t[spuXres * spuYres * sizeof(uint8_t)])) + throw; + + memset(bmp, 0, spuXres * spuYres * sizeof(uint8_t)); + putFieldData(0, fodd, eodd); + putFieldData(1, feven, eeven); +} + +// ================================== +cDxr3SpuBitmap::~cDxr3SpuBitmap() +{ + delete[]bmp; +} + +// ================================== +cBitmap *cDxr3SpuBitmap::getBitmap(const aDxr3SpuPalDescr paldescr, const cDxr3SpuPalette & pal, sDxr3SpuRect & size) const +{ + int h = size.height(); + int w = size.width(); + + if (size.y1 + h >= spuYres) + { + h = spuYres - size.y1 - 1; + } + if (size.x1 + w >= spuXres) + { + w = spuXres - size.x1 - 1; + } + + if (w & 0x03) + { + w += 4 - (w & 0x03); + } + + cBitmap *ret = new cBitmap(w, h, 2); + + // set the palette + for (int i = 0; i < 4; i++) + { + uint32_t color = pal.getColor(paldescr[i].index, paldescr[i].trans); + ret->SetColor(i, (tColor) color); + } + + // set the content + for (int yp = 0; yp < h; yp++) + { + for (int xp = 0; xp < w; xp++) + { + uint8_t idx = bmp[(size.y1 + yp) * spuXres + size.x1 + xp]; + ret->SetIndex(xp, yp, idx); + } + } + return ret; +} + +// ================================== +// find the minimum non-transparent area +bool cDxr3SpuBitmap::getMinSize(const aDxr3SpuPalDescr paldescr, sDxr3SpuRect & size) const +{ + bool ret = false; + for (int i = 0; i < 4; i++) + { + if (paldescr[i].trans != 0) + { + if (!ret) + { + size = minsize[i]; + } + else + { + setMin(size.x1, minsize[i].x1); + setMin(size.y1, minsize[i].y1); + setMax(size.x2, minsize[i].x2); + setMax(size.y2, minsize[i].y2); + } + ret = true; + } + } +/* + if (ret && cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuBitmap::getMinSize: (" << size.x1 ", " << size.y1 << ") x (" << size.x2 << ", " << size.y2 << ")\n"; + } +*/ + return ret; +} + +// ================================== +void cDxr3SpuBitmap::putPixel(int xp, int yp, int len, uint8_t colorid) +{ + memset(bmp + spuXres * yp + xp, colorid, len); + setMin(minsize[colorid].x1, xp); + setMin(minsize[colorid].y1, yp); + setMax(minsize[colorid].x2, xp + len - 1); + setMax(minsize[colorid].y2, yp + len - 1); +} + +// ================================== +static uint8_t getBits(uint8_t * &data, uint8_t & bitf) +{ + uint8_t ret = *data; + if (bitf) + { + ret >>= 4; + } + else + { + data++; + } + + bitf ^= 1; + + return (ret & 0xf); +} + +// ================================== +void cDxr3SpuBitmap::putFieldData(int field, uint8_t * data, uint8_t * endp) +{ + int xp = bmpsize.x1; + int yp = bmpsize.y1 + field; + uint8_t bitf = 1; + + while (data < endp) + { + uint16_t vlc = getBits(data, bitf); + if (vlc < 0x0004) + { + vlc = (vlc << 4) | getBits(data, bitf); + if (vlc < 0x0010) + { + vlc = (vlc << 4) | getBits(data, bitf); + if (vlc < 0x0040) + { + vlc = (vlc << 4) | getBits(data, bitf); + } + } + } + + uint8_t color = vlc & 0x03; + int len = vlc >> 2; + + // if len == 0 -> end sequence - fill to end of line + len = len ? len : bmpsize.x2 - xp + 1; + putPixel(xp, yp, len, color); + xp += len; + + if (xp > bmpsize.x2) + { + // nextLine + if (!bitf) + data++; + bitf = 1; + xp = bmpsize.x1; + yp += 2; + if (yp > bmpsize.y2) + return; + } + } +} + +// ================================== +cDxr3SpuDecoder::cDxr3SpuDecoder() +{ + clean = true; + scaleMode = eSpuNormal; + spu = NULL; + osd = NULL; + spubmp = NULL; +} + +// ================================== +cDxr3SpuDecoder::~cDxr3SpuDecoder() +{ + delete spubmp; + delete spu; + delete osd; +} + +// ================================== +void cDxr3SpuDecoder::processSPU(uint32_t pts, uint8_t * buf) +{ + setTime(pts); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::processSPU: SPU pushData: pts: " << pts << "\n"; + } + + delete spubmp; + spubmp = NULL; + delete[]spu; + spu = buf; + spupts = pts; + + DCSQ_offset = cmdOffs(); + prev_DCSQ_offset = 0; + + clean = true; +} + +// ================================== +void cDxr3SpuDecoder::setScaleMode(cSpuDecoder::eScaleMode ScaleMode) +{ + scaleMode = ScaleMode; +} + +// ================================== +void cDxr3SpuDecoder::setPalette(uint32_t * pal) +{ + palette.setPalette(pal); +} + +// ================================== +void cDxr3SpuDecoder::setHighlight(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette) +{ + aDxr3SpuPalDescr pld; + for (int i = 0; i < 4; i++) + { + pld[i].index = 0xf & (palette >> (16 + 4 * i)); + pld[i].trans = 0xf & (palette >> (4 * i)); + } + + bool ne = hlpsize.x1 != sx || hlpsize.y1 != sy || + hlpsize.x2 != ex || hlpsize.y2 != ey || + pld[0] != hlpDescr[0] || pld[1] != hlpDescr[1] || + pld[2] != hlpDescr[2] || pld[3] != hlpDescr[3]; + + if (ne) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setHighlight: " << sx << ", " << sy << ", " << ex << ", " << ey << "\n"; + } + + hlpsize.x1 = sx; + hlpsize.y1 = sy; + hlpsize.x2 = ex; + hlpsize.y2 = ey; + memcpy(hlpDescr, pld, sizeof(aDxr3SpuPalDescr)); + highlight = true; + clean = false; + } +} + +// ================================== +void cDxr3SpuDecoder::clearHighlight() +{ + clean &= !highlight; + highlight = false; + hlpsize.x1 = -1; + hlpsize.y1 = -1; + hlpsize.x2 = -1; + hlpsize.y2 = -1; +} + +// ================================== +int cDxr3SpuDecoder::ScaleYcoord(int value) +{ + if (scaleMode == eSpuLetterBox) + { + int offset = cDevice::PrimaryDevice()->GetVideoSystem() == vsPAL ? 72 : 60; + return lround((value * 3.0) / 4.0) + offset; + } + return value; +} + +// ================================== +int cDxr3SpuDecoder::ScaleYres(int value) +{ + if (scaleMode == eSpuLetterBox) + { + return lround((value * 3.0) / 4.0); + } + return value; +} + +// ================================== +void cDxr3SpuDecoder::DrawBmp(sDxr3SpuRect & size, cBitmap * bmp) +{ + int x2 = size.x2; + while ((x2 - size.x1 + 1) & 0x03) + x2++; + tArea Area = { size.x1, size.y1, x2, size.y2, 2 }; + osd->SetAreas(&Area, 1); + if (x2 > size.x2) + osd->DrawRectangle(size.x2 + 1, size.y1, x2, size.y2, clrTransparent); + osd->DrawBitmap(size.x1, size.y1, *bmp); + delete bmp; +} + +// ================================== +void cDxr3SpuDecoder::Draw() +{ + Hide(); + + if (!spubmp) + { + return; + } + + cBitmap *fg = NULL; + cBitmap *bg = NULL; + sDxr3SpuRect bgsize; + sDxr3SpuRect hlsize; + + hlsize.x1 = hlpsize.x1; + hlsize.y1 = ScaleYcoord(hlpsize.y1); + hlsize.x2 = hlpsize.x2; + hlsize.y2 = ScaleYcoord(hlpsize.y2); + + if (highlight) + { + fg = spubmp->getBitmap(hlpDescr, palette, hlsize); + } + + if (spubmp->getMinSize(palDescr, bgsize)) + { + bg = spubmp->getBitmap(palDescr, palette, bgsize); + if (scaleMode == eSpuLetterBox) + { + // the coordinates have to be modified for letterbox + int y1 = ScaleYres(bgsize.y1) + bgsize.height(); + bgsize.y2 = y1 + bgsize.height(); + bgsize.y1 = y1; + } + } + + if (bg || fg) + { + if (osd == NULL) + if ((osd = cOsdProvider::NewOsd(0, 0)) == NULL) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::Draw: New OSD faild!\n"; + } + dsyslog("NewOsd failed\n"); + return; + } + + if (fg) + { + DrawBmp(hlsize, fg); + } + + if (bg) + { + DrawBmp(bgsize, bg); + } + + osd->Flush(); + } + + clean = true; +} + +// ================================== +void cDxr3SpuDecoder::Hide() +{ + delete osd; + osd = NULL; +} + +// ================================== +void cDxr3SpuDecoder::Empty() +{ + Hide(); + + delete spubmp; + spubmp = NULL; + + delete[]spu; + spu = NULL; + + clearHighlight(); + clean = true; +} + +// ================================== +int cDxr3SpuDecoder::setTime(uint32_t pts) +{ + if (!spu) + { + return 0; + } + + if (spu && !clean) + { + Draw(); + } + + while (DCSQ_offset != prev_DCSQ_offset) + { + // Display Control Sequences + int i = DCSQ_offset; + state = spNONE; + + uint32_t exec_time = spupts + spuU32(i) * 1024; + if ((pts != 0) && (exec_time > pts)) + { + return 0; + } + + if (pts != 0) + { + uint16_t feven = 0; + uint16_t fodd = 0; + + i += 2; + + prev_DCSQ_offset = DCSQ_offset; + DCSQ_offset = spuU32(i); + i += 2; + + while (spu[i] != CMD_SPU_EOF) + { + // Command Sequence + switch (spu[i]) + { + case CMD_SPU_SHOW: + // show subpicture + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: show subpicture\n"; + } + state = spSHOW; + i++; + break; + + case CMD_SPU_HIDE: + // hide subpicture + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: hide subpicture\n"; + } + state = spHIDE; + i++; + break; + + case CMD_SPU_SET_PALETTE: + // CLUT + palDescr[0].index = spu[i + 2] & 0xf; + palDescr[1].index = spu[i + 2] >> 4; + palDescr[2].index = spu[i + 1] & 0xf; + palDescr[3].index = spu[i + 1] >> 4; + i += 3; + break; + + case CMD_SPU_SET_ALPHA: + // transparency palette + palDescr[0].trans = spu[i + 2] & 0xf; + palDescr[1].trans = spu[i + 2] >> 4; + palDescr[2].trans = spu[i + 1] & 0xf; + palDescr[3].trans = spu[i + 1] >> 4; + i += 3; + break; + + case CMD_SPU_SET_SIZE: + // image coordinates + size.x1 = (spu[i + 1] << 4) | (spu[i + 2] >> 4); + size.x2 = ((spu[i + 2] & 0x0f) << 8) | spu[i + 3]; + + size.y1 = (spu[i + 4] << 4) | (spu[i + 5] >> 4); + size.y2 = ((spu[i + 5] & 0x0f) << 8) | spu[i + 6]; + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: (" << size.x1 << ", " << size.y1 <<") x (" << size.x2 << ", " << size.y2 <<")\n"; + } + i += 7; + break; + + case CMD_SPU_SET_PXD_OFFSET: + // image 1 / image 2 offsets + fodd = spuU32(i + 1); + feven = spuU32(i + 3); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: odd = " << fodd << " even = " << feven << "\n"; + } + i += 5; + break; + + case CMD_SPU_MENU: + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: spu menu\n"; + } + state = spMENU; + + i++; + break; + + default: + esyslog("invalid sequence in control header (%.2x)\n", spu[i]); + assert(0); + i++; + break; + } + } + if (fodd != 0 && feven != 0) + { + delete spubmp; + spubmp = new cDxr3SpuBitmap(size, spu + fodd, spu + feven, spu + feven, spu + cmdOffs()); + } + } + else if (!clean) + { + state = spSHOW; + } + + if (state == spSHOW || state == spMENU) + { + Draw(); + } + + if (state == spHIDE) + { + Hide(); + } + + if (pts == 0) + { + return 0; + } + } + + return 1; +} diff --git a/dxr3spudecoder.h b/dxr3spudecoder.h new file mode 100644 index 0000000..adaed7f --- /dev/null +++ b/dxr3spudecoder.h @@ -0,0 +1,138 @@ +#ifndef _DXR3SPUDECODER_H_ +#define _DXR3SPUDECODER_H_ + +#include "dxr3vdrincludes.h" +#include + +// ================================== +typedef struct sDxr3SpuPalDescr +{ + uint8_t index; + uint8_t trans; + + bool operator != (const sDxr3SpuPalDescr pd) const { + return index != pd.index && trans != pd.trans; + }; +} aDxr3SpuPalDescr[4]; + +// ================================== +struct sDxr3SpuRect +{ + int x1, y1; + int x2, y2; + + int width() + { + return x2 - x1 + 1; + }; + + int height() + { + return y2 - y1 + 1; + }; + + bool operator != (const sDxr3SpuRect r) const + { + return r.x1 != x1 || r.y1 != y1 || r.x2 != x2 || r.y2 != y2; + }; +}; + +// ================================== +class cDxr3SpuPalette +{ +private: + uint32_t palette[16]; + +public: + void setPalette(const uint32_t * pal); + uint32_t getColor(uint8_t idx, uint8_t trans) const; +}; + +// ================================== +class cDxr3SpuBitmap +{ +private: + sDxr3SpuRect bmpsize; + sDxr3SpuRect minsize[4]; + uint8_t *bmp; + + void putPixel(int xp, int yp, int len, uint8_t colorid); + void putFieldData(int field, uint8_t * data, uint8_t * endp); + +public: + cDxr3SpuBitmap(sDxr3SpuRect size, uint8_t * fodd, uint8_t * eodd, uint8_t * feven, uint8_t * eeven); + ~cDxr3SpuBitmap(); + + bool getMinSize(const aDxr3SpuPalDescr paldescr, sDxr3SpuRect & size) const; + cBitmap *getBitmap(const aDxr3SpuPalDescr paldescr, const cDxr3SpuPalette & pal, sDxr3SpuRect & size) const; +}; + +// ================================== +class cDxr3SpuDecoder : public cSpuDecoder +{ +public: + cDxr3SpuDecoder(); + ~cDxr3SpuDecoder(); + + int setTime(uint32_t pts); + + void setScaleMode(cSpuDecoder::eScaleMode ScaleMode); + void setPalette(uint32_t * pal); + void setHighlight(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette); + void clearHighlight(); + void Empty(); + void processSPU(uint32_t pts, uint8_t * buf); + + #if VDRVERSNUM >= 10311 + void Hide(); + void Draw(); + bool IsVisible() { return osd != NULL; } + #endif + +private: + cOsd * osd; + + // processing state + uint8_t *spu; + uint32_t spupts; + bool clean; + bool ready; + + enum spFlag { spNONE, spHIDE, spSHOW, spMENU }; + spFlag state; + + cSpuDecoder::eScaleMode scaleMode; + + // highligh area + bool highlight; + sDxr3SpuRect hlpsize; + aDxr3SpuPalDescr hlpDescr; + + // palette + cDxr3SpuPalette palette; + + // spu info's + sDxr3SpuRect size; + aDxr3SpuPalDescr palDescr; + + uint16_t DCSQ_offset; + uint16_t prev_DCSQ_offset; + + cDxr3SpuBitmap *spubmp; + + int cmdOffs() { return ((spu[2] << 8) | spu[3]); } + int spuSize() { return ((spu[0] << 8) | spu[1]); } + + int ScaleYcoord(int value); + int ScaleYres(int value); + void DrawBmp(sDxr3SpuRect & size, cBitmap * bmp); +}; + +// ================================== +inline uint32_t cDxr3SpuPalette::getColor(uint8_t idx, uint8_t trans) const +{ + uint8_t t = trans == 0x0f ? 0xff : trans << 4; + return palette[idx] | (t << 24); +} + +#endif /*_DXR3SPUDECODER_H_*/ diff --git a/dxr3syncbuffer.c b/dxr3syncbuffer.c new file mode 100644 index 0000000..8ea8ccd --- /dev/null +++ b/dxr3syncbuffer.c @@ -0,0 +1,420 @@ +/* + * dxr3syncbuffer.c + * + * Copyright (C) 2002-2004 Kai Möller + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ + +/* + ToDo: + - cDxr3SyncBuffer::Push: XXX This is only a workaround until a sufficient control algorithm is implemented +*/ + +#include +#include "dxr3syncbuffer.h" +#include "dxr3memcpy.h" + +const int DXR3_MAX_VIDEO_FRAME_LENGTH = 4096; +const int DXR3_MAX_AUDIO_FRAME_LENGTH = 4096; + +// ================================== +cFixedLengthFrame::cFixedLengthFrame(uint32_t length) : +m_count(0), m_length(length), m_pts(0), m_type(ftUnknown) { + + m_pData = new uint8_t[length]; + if (!m_pData) + { + cLog::Instance() << "Failed to allocate memory in cFixedLengthFrame (m_pData) - will stop now"; + exit(1); + } + + m_audioChannelCount = UNKNOWN_CHANNEL_COUNT; + m_audioDataRate = UNKNOWN_DATA_RATE; + m_videoAspectRatio = UNKNOWN_ASPECT_RATIO; +} + +// ================================== +cFixedLengthFrame::~cFixedLengthFrame() +{ + if (m_pData) + { + delete[] m_pData; + } +} + +// ================================== +void cFixedLengthFrame::CopyFrame(const uint8_t* pStart, int length, uint32_t pts, eFrameType type) +{ + if (length > m_length) + { + delete[] m_pData; + m_pData = new uint8_t[length]; + m_length = length; + } + m_type = type; + m_count = length; + m_pts = pts; + dxr3_memcpy((void*) m_pData,(void*) pStart, length); +} + +// ================================== +uint8_t* cFixedLengthFrame::GetData(void) +{ + return m_pData; +} + +// ================================== +int cFixedLengthFrame::GetCount(void) +{ + return m_count; +} + +// ================================== +uint32_t cFixedLengthFrame::GetPts(void) +{ + return m_pts; +} + +// ================================== +void cFixedLengthFrame::SetPts(uint32_t pts) +{ + m_pts = pts; +} + +// ================================== +uint32_t cFixedLengthFrame::m_staticAudioChannelCount = 0; +uint32_t cFixedLengthFrame::m_staticAudioDataRate = 0; + + + + +// ================================== +cDxr3SyncBuffer::cDxr3SyncBuffer(int frameCount, int frameLength, cDxr3Interface& dxr3Device) : cRingBuffer(frameCount, true), m_dxr3Device(dxr3Device) +{ + m_pBuffer = new cFixedLengthFrame[frameCount](frameLength); + + if (!m_pBuffer) + { + cLog::Instance() << "Failed to allocate memory in cDxr3SyncBuffer (m_pBuffer) - will stop now"; + exit(1); + } + + m_count = 0; + m_nextFree = 0; + m_next = 0; + m_bWaitPts = false; + m_waitPts = 0; + m_waitDelta = 0; + m_lastPts = 0; + m_bPutBlock = false; + m_bGetBlock = false; + m_bStartReceiver = false; + m_bStopped = false; + m_demuxMode = DXR3_DEMUX_TV_MODE; + m_bPollSync = false; + SetTimeouts(1000, 10); +} + +// ================================== +cDxr3SyncBuffer::~cDxr3SyncBuffer() +{ + if (m_pBuffer) + { + delete[] m_pBuffer; + } +} + +// ================================== +int cDxr3SyncBuffer::Available(void) +{ + int ret = 0; + Lock(); + ret = m_count; + Unlock(); + return ret; +} + +// ================================== +const int BUFFER_LIMIT = 5; +const int BUFFER_LIMIT_2 = 10; + +// ================================== +bool cDxr3SyncBuffer::Poll(int TimeoutMs) +{ + bool retVal = true; + uint32_t currTime = m_dxr3Device.GetSysClock(); + m_bPollSync = true; + if (m_demuxMode == DXR3_DEMUX_REPLAY_MODE) + { + if (Available() >= Size() - (Size()*BUFFER_LIMIT/100)) + { + m_bPollSync = true; + while ((Available() >= Size() - (Size()*BUFFER_LIMIT_2)/100) && ((m_dxr3Device.GetSysClock() - currTime) < ((uint32_t)TimeoutMs * (uint32_t)45))) + { + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + } + if (Available() >= Size() - (Size()*BUFFER_LIMIT_2)/100) + { + retVal = false; + } + } + } + + return retVal; +} + +// ================================== +cFixedLengthFrame* cDxr3SyncBuffer::Push(const uint8_t* pStart, int length, uint32_t pts, eFrameType type) throw (eSyncBufferException) +{ + int lastIndex = 0; + + switch (m_demuxMode) + { + case DXR3_DEMUX_TRICK_MODE: + break; + + case DXR3_DEMUX_TV_MODE: + case DXR3_DEMUX_REPLAY_MODE: + default: + + while ((Available() >= Size() - (Size()*10)/100)) + { + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + } + + Lock(); + if (pts == m_lastPts) + { + pts = 0; + } + else + { + m_lastPts = pts; + } + lastIndex = m_nextFree; + m_pBuffer[m_nextFree].CopyFrame(pStart, length, pts, type); + m_pBuffer[m_nextFree].SetChannelCount(UNKNOWN_CHANNEL_COUNT); + m_pBuffer[m_nextFree].SetDataRate(UNKNOWN_DATA_RATE); + m_pBuffer[m_nextFree].SetAspectRatio(UNKNOWN_ASPECT_RATIO); + m_nextFree++; + m_count++; + m_nextFree %= Size(); + + if (m_nextFree == m_next) + { + cLog::Instance() << "Buffer overrun\n"; +// cLog::Instance() << "cDxr3SyncBuffer::Push m_demuxMode: " << (int)m_demuxMode << endl; +// cLog::Instance() << "cDxr3SyncBuffer::Push Available(): " << Available() << endl; +// cLog::Instance() << "cDxr3SyncBuffer::Push Size(): " << Size() << endl; + + Clear(); // XXX This is only a workaround until a sufficient control algorithm is implemented + throw(SYNC_BUFFER_OVERRUN); + } + if (!m_bWaitPts) + { + if (m_bStartReceiver) + { + EnableGet(); + } + } + else + { + if (m_waitPts < m_dxr3Device.GetSysClock() || + m_waitPts - m_dxr3Device.GetSysClock() < m_waitDelta) + { + EnableGet(); + m_bWaitPts = false; + } + } + Unlock(); + break; + } + + return &m_pBuffer[lastIndex]; +} + +// ================================== +void cDxr3SyncBuffer::Pop(void) +{ + Lock(); + if (m_count) + { + uint32_t nextPts = 0; + uint32_t tmpBuffer = m_next; + for (int i = 0; i < m_count && nextPts == 0; ++i) + { + if (tmpBuffer) tmpBuffer = --tmpBuffer ? tmpBuffer : (Size() - 1); + nextPts = m_pBuffer[tmpBuffer].GetPts(); + } + if (nextPts != 30) + { + cDxr3NextPts::Instance().SetNextPts(nextPts); + } + + m_next++; + m_count--; + m_next %= Size(); + if (m_next == m_nextFree) + { + m_next = m_nextFree = m_count = 0; + } + } + EnablePut(); + Unlock(); +} + +// ================================== +cFixedLengthFrame* cDxr3SyncBuffer::Get(void) +{ + cFixedLengthFrame* pRet = 0; + + if (!m_bStopped) + { + while (!Available() || !m_bStartReceiver) + { + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + + Lock(); + if (m_nextFree != m_next) + { + pRet = &m_pBuffer[m_next]; + } + Unlock(); + } + else + { + WaitForGet(); + } + + return pRet; +} + +// ================================== +void cDxr3SyncBuffer::Clear(void) +{ + Lock(); + m_next = 0; + m_nextFree = 0; + m_count = 0; + m_lastPts = 0; + m_bWaitPts = false; + m_bStartReceiver = false; + m_bPollSync = false; + if (m_bPutBlock) + { + EnablePut(); + m_bPutBlock = false; + } + cFixedLengthFrame::Clear(); + cDxr3NextPts::Instance().Clear(); + Unlock(); +} + +// ================================== +void cDxr3SyncBuffer::WaitForSysClock(uint32_t pts, uint32_t delta) +{ + m_waitPts = pts; + m_waitDelta = delta; + if (!m_bPutBlock) + { + Lock(); + m_bWaitPts = true; + Unlock(); + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + else + { + usleep(1); //* (pts - pSysClock->GetSysClock())); + } +} + +// ================================== +void cDxr3SyncBuffer::WaitForNextPut(void) +{ + if (!m_bPutBlock) + { + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + else + { + usleep(1); + } +} + +// ================================== +void cDxr3SyncBuffer::Start(void) +{ + m_bStartReceiver = true; + m_bStopped = false; + if (Available()) + { + EnableGet(); + } +} + +// ================================== +void cDxr3SyncBuffer::WakeUp(void) +{ + Lock(); + if (m_bStartReceiver == true) + { + if (!m_bWaitPts) + { + EnableGet(); + } + else + { + if (m_waitPts < m_dxr3Device.GetSysClock() || + m_waitPts - m_dxr3Device.GetSysClock() < m_waitDelta) + { + EnableGet(); + m_bWaitPts = false; + } + } + } + Unlock(); +} + +// ================================== +void cDxr3SyncBuffer::WaitForReceiverStopped(void) +{ + if (!m_bGetBlock) + { + receiverStoppedMutex.Lock(); + receiverStopped.Wait(receiverStoppedMutex); + receiverStoppedMutex.Unlock(); + } +} + +// ================================== +void cDxr3SyncBuffer::ReceiverStopped(void) +{ + receiverStopped.Broadcast(); +} diff --git a/dxr3syncbuffer.h b/dxr3syncbuffer.h new file mode 100644 index 0000000..1598b62 --- /dev/null +++ b/dxr3syncbuffer.h @@ -0,0 +1,123 @@ +/* + * dxr3syncbuffer.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3SYNCBUFFER_H_ +#define _DXR3SYNCBUFFER_H_ + +#include + +#include "dxr3vdrincludes.h" +#include "dxr3interface.h" +#include "dxr3generaldefines.h" +#include "dxr3nextpts.h" +#include "dxr3log.h" + +// ================================== +const uint32_t UNKNOWN_CHANNEL_COUNT = 0xFFFFFFFF; +const uint32_t UNKNOWN_DATA_RATE = 0xFFFFFFFF; +const uint32_t UNKNOWN_ASPECT_RATIO = 0xFFFFFFFF; + +// ================================== +class cFixedLengthFrame +{ +public: + explicit cFixedLengthFrame(uint32_t length); + ~cFixedLengthFrame(); + + void CopyFrame(const uint8_t* pStart, int length, uint32_t pts, eFrameType type); + uint8_t* GetData(void); + int GetCount(void); + uint32_t GetPts(void); + void SetPts(uint32_t pts); + void SetChannelCount(uint32_t channelCount) {if (channelCount != UNKNOWN_CHANNEL_COUNT) m_staticAudioChannelCount = m_audioChannelCount = channelCount; else m_audioChannelCount = m_staticAudioChannelCount; }; + void SetDataRate(uint32_t dataRate) {if (m_audioDataRate != UNKNOWN_DATA_RATE) m_staticAudioDataRate = m_audioDataRate = dataRate; else m_audioDataRate = m_staticAudioDataRate;}; + void SetAspectRatio(uint32_t aspectRatio) {m_videoAspectRatio = aspectRatio;}; + uint32_t GetChannelCount(void) {return ((m_audioChannelCount == m_staticAudioChannelCount || !m_staticAudioChannelCount)? m_audioChannelCount : m_staticAudioChannelCount) ;}; + uint32_t GetDataRate(void) {return ((m_audioDataRate == m_staticAudioDataRate || !m_staticAudioDataRate) ? m_audioDataRate : m_staticAudioDataRate);}; + uint32_t GetAspectRatio(void) {return m_videoAspectRatio;}; + eFrameType GetFrameType(void) {return m_type;} + + static void Clear(void) {m_staticAudioDataRate = 0; m_staticAudioChannelCount = 0;}; + +protected: + uint8_t* m_pData; + int m_count; + int m_length; + uint32_t m_pts; + eFrameType m_type; + + uint32_t m_audioChannelCount; + uint32_t m_audioDataRate; + uint32_t m_videoAspectRatio; + + static uint32_t m_staticAudioChannelCount; + static uint32_t m_staticAudioDataRate; + +private: + cFixedLengthFrame(); // you are not allowed to use this constructor + cFixedLengthFrame(cFixedLengthFrame&); // no copy constructor + +}; + +// ================================== +class cDxr3SyncBuffer : public cRingBuffer +{ +public: + enum eSyncBufferException + { + SYNC_BUFFER_OVERRUN + }; +public: + cDxr3SyncBuffer(int frameCount, int frameLength, cDxr3Interface& dxr3Device); + ~cDxr3SyncBuffer(); + + virtual int Available(void); + cFixedLengthFrame* Push(const uint8_t* pStart, int length, uint32_t pts, eFrameType type = ftUnknown) throw (eSyncBufferException); + void Pop(void); + cFixedLengthFrame* Get(void); + void Clear(void); + void Stop(void) { m_bStopped = true;}; + void Start(void); + void WaitForSysClock(uint32_t pts, uint32_t delta); + void WaitForNextPut(void); + void WakeUp(void); + void WaitForReceiverStopped(void); + void SetDemuxMode(eDxr3DemuxMode demuxMode) {m_demuxMode = demuxMode;}; + eDxr3DemuxMode GetDemuxMode(void) {return m_demuxMode;}; + bool Poll(int TimeoutMs); + bool IsPolled(void) { return m_bPollSync;}; + uint32_t GetFillLevel(void) { return Available() * 100 / Size();}; + +protected: + void ReceiverStopped(void); + + cFixedLengthFrame* m_pBuffer; + int m_count; + int m_nextFree; + int m_next; + bool m_bWaitPts; + bool m_bPutBlock; + bool m_bGetBlock; + bool m_bStartReceiver; + bool m_bStopped; + uint32_t m_waitPts; + uint32_t m_waitDelta; + uint32_t m_lastPts; + eDxr3DemuxMode m_demuxMode; + + cCondVar receiverStopped; + cMutex receiverStoppedMutex; + cDxr3Interface& m_dxr3Device; + bool m_bPollSync; + +private: + cDxr3SyncBuffer(); // you are not allowed to use this constructor + cDxr3SyncBuffer(cDxr3SyncBuffer&); // no constructor +}; + +#endif /*_DXR3SYNCBUFFER_H_*/ diff --git a/dxr3sysclock.c b/dxr3sysclock.c new file mode 100644 index 0000000..9d7d050 --- /dev/null +++ b/dxr3sysclock.c @@ -0,0 +1,49 @@ +#include +#include "dxr3sysclock.h" + +// ================================== +void cDxr3SysClock::SetSysClock(uint32_t scr) +{ + uint32_t sc; + + mutex.Lock(); + ioctl(m_fdcontrol, EM8300_IOCTL_SCR_GET, &sc); + m_offset = scr - sc; + mutex.Unlock(); +} + +// ================================== +uint32_t cDxr3SysClock::GetSysClock(void) +{ + uint32_t sc; + uint32_t retval; + + mutex.Lock(); + ioctl(m_fdcontrol, EM8300_IOCTL_SCR_GET, &sc); + retval = sc + m_offset; + mutex.Unlock(); + + return retval; +} + +// ================================== +void cDxr3SysClock::SetPts(uint32_t pts) +{ + uint32_t newPts = 0; + + mutex.Lock(); + newPts = pts - m_offset; + ioctl(m_fdvideo, EM8300_IOCTL_VIDEO_SETPTS, &newPts); + mutex.Unlock(); +} + +// ================================== +void cDxr3SysClock::SetSpuPts(uint32_t pts) +{ + uint32_t newPts = 0; + + mutex.Lock(); + newPts = (pts - m_offset) << 1; // fix for DVD subtitles + ioctl(m_fdspu, EM8300_IOCTL_SPU_SETPTS, &newPts); + mutex.Unlock(); +} diff --git a/dxr3sysclock.h b/dxr3sysclock.h new file mode 100644 index 0000000..50c5540 --- /dev/null +++ b/dxr3sysclock.h @@ -0,0 +1,36 @@ +#ifndef _DXR3_SYSCLOCK_H_ +#define _DXR3_SYSCLOCK_H_ + +//#include +#include "dxr3vdrincludes.h" +#include + +// ================================== +// work with dxr3's clock +class cDxr3SysClock +{ +public: + cDxr3SysClock(int fd_control, int fd_video, int fd_spu) : m_fdcontrol(fd_control), + m_fdvideo(fd_video), m_fdspu(fd_spu), m_offset(0) {}; + + virtual ~cDxr3SysClock() {}; + +public: + void SetSysClock(uint32_t scr); + uint32_t GetSysClock(void); + void SetPts(uint32_t pts); + void SetSpuPts(uint32_t pts); + +protected: + int m_fdcontrol; + int m_fdvideo; + int m_fdspu; + uint32_t m_offset; + cMutex mutex; + +protected: + cDxr3SysClock(); // you are not allowed to use this contructor + cDxr3SysClock(cDxr3SysClock&); // no copy constructor +}; + +#endif /*_DXR3_SYSCLOCK_H_*/ diff --git a/dxr3tools.h b/dxr3tools.h new file mode 100644 index 0000000..ee8f9e3 --- /dev/null +++ b/dxr3tools.h @@ -0,0 +1,82 @@ +#ifndef _DXR3TOOLS_H_ +#define _DXR3TOOLS_H_ + +#include "dxr3vdrincludes.h" + +namespace Tools +{ + // ================================== + inline unsigned int Rgb2YCrCb(unsigned long rgb) + { + float Y,U,V; + float R,G,B; + unsigned int yuv = 0x0; + + B = ((rgb >> 16) & 0xFF); + G = ((rgb >> 8) & 0xFF); + R = (rgb & 0xFF); + + Y = (0.2578125 * R) + (0.50390625 * G) + (0.09765625 * B) + 16; + U = (0.4375 * R) - (0.3671875 * G) - (0.0703125 * B) + 128; + V =-(0.1484375 * R) - (0.2890625 * G) + (0.4375 * B) + 128; + + yuv = (int(Y) << 16) | (int(U) << 8) | int(V); + + return yuv; + } + + // ================================== + inline unsigned int YUV2Rgb(unsigned int yuv_color) + { + int Y, Cb, Cr; + int Ey, Epb, Epr; + int Eg, Eb, Er; + + Y = (yuv_color >> 16) & 0xff; + Cb = (yuv_color) & 0xff; + Cr = (yuv_color >> 8) & 0xff; + + Ey = (Y - 16); + Epb = (Cb - 128); + Epr = (Cr - 128); + /* ITU-R 709 + Eg = (298*Ey - 55*Epb - 137*Epr)/256; + Eb = (298*Ey + 543*Epb)/256; + Er = (298*Ey + 460*Epr)/256; + */ + /* FCC ~= mediaLib */ + Eg = (298 * Ey - 100 * Epb - 208 * Epr) / 256; + Eb = (298 * Ey + 516 * Epb) / 256; + Er = (298 * Ey + 408 * Epr) / 256; + + if (Eg > 255) + Eg = 255; + if (Eg < 0) + Eg = 0; + + if (Eb > 255) + Eb = 255; + if (Eb < 0) + Eb = 0; + + if (Er > 255) + Er = 255; + if (Er < 0) + Er = 0; + + return Eb | (Eg << 8) | (Er << 16); + } + + // ================================== + inline void WriteInfoToOsd(string x) + { + #if VDRVERSNUM <= 10306 + Interface->Info(x.c_str()); + #else + Skins.Message(mtInfo, x.c_str()); + #endif + } + +} + +#endif /*_DXR3TOOLS_H_*/ diff --git a/dxr3unixserversocket.c b/dxr3unixserversocket.c new file mode 100644 index 0000000..49816fa --- /dev/null +++ b/dxr3unixserversocket.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include + + +#include +#include +#include + +#include "dxr3unixserversocket.h" +#include "dxr3interface.h" +#include "dxr3log.h" + +using namespace std; + +#ifndef SOCKET_CHMOD +#define SOCKET_CHMOD 0660 +#endif + +// ================================== +cDxr3UnixServerSocket::cDxr3UnixServerSocket(const char* pFileName, int backlog) +{ + m_bConnected = false; + m_backlog = backlog; + m_addr.sun_family = AF_UNIX; + m_msgSize = 0; + + m_pFileName = pFileName; + strcpy(m_addr.sun_path, pFileName); + unlink(pFileName); + + + m_fdServerSocket = socket(PF_UNIX, SOCK_STREAM, 0); + if (m_fdServerSocket > -1) + { + if (bind(m_fdServerSocket, (sockaddr*)&m_addr, (socklen_t)sizeof(m_addr))) { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: binding socket failed\n"; + } + + if (listen(m_fdServerSocket, m_backlog)) + { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: Listen failed\n"; + } + + if (chmod(m_pFileName, SOCKET_CHMOD)) + { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: Chmod failed\n"; + } + } + else + { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: Unable to create socket\n"; + } +} + +// ================================== +bool cDxr3UnixServerSocket::WaitForConnection() +{ + cLog::Instance() << "cDxr3UnixServerSocket::WaitForConnection Waiting ...\n"; + if (m_fdServerSocket > -1) + { + m_fdConnectionSocket = accept(m_fdServerSocket, 0, 0); + if (m_fdConnectionSocket > -1) + { + m_bConnected = true; + cLog::Instance() << "cDxr3UnixServerSocket::WaitForConnection Connected\n"; + } + else + { + m_bConnected = false; + cLog::Instance() << "cDxr3UnixServerSocket::WaitForConnection failed\n"; + } + } + else + { + m_bConnected = false; + } + return m_bConnected; +} + +// ================================== +bool cDxr3UnixServerSocket::GetNextMessage() +{ + bool ret = false; + m_msgSize = 0; + memset(m_msg, 0, MAX_REC_SIZE); + + if (m_bConnected) + { + m_msgSize = read(m_fdConnectionSocket, m_msg, MAX_REC_SIZE - 1); + if (m_msgSize <= 0) + { + m_msgSize = 0; + m_bConnected = 0; + close(m_fdConnectionSocket); + cLog::Instance() << "cDxr3UnixServerSocket::GetNextMessage failed/connection closed\n"; + } + else + { + ret = true; + } + } + + if (ret) ProcessMessage(); + + return ret; +} + +// ================================== +bool cDxr3UnixServerSocket::IsConnected() +{ + return m_bConnected; +} + +// ================================== +cDxr3UnixServerSocket::~cDxr3UnixServerSocket() +{ + close(m_fdConnectionSocket); + close(m_fdServerSocket); + unlink(m_pFileName); +} + +// ================================== +void cDxr3StartStopSocket::SendStatus() +{ + if (cDxr3Interface::Instance().IsExternalReleased()) + { + string res("CloseDxr3DeviceRsp\n"); + write(m_fdConnectionSocket, res.c_str(), res.size()); + } + else + { + string res("OpenDxr3DeviceRsp\n"); + write(m_fdConnectionSocket, res.c_str(), res.size()); + } +} + +// ================================== +void cDxr3StartStopSocket::ProcessMessage(void) +{ + cLog::Instance() << "cDxr3StartStopSocket::ProcessMessage Rec: " << (const char*) m_msg << "\n"; + + if (string((const char*)m_msg) == string("OpenDxr3DeviceCmd")) + { + cDxr3Interface::Instance().ExternalReopenDevices(); + SendStatus(); + } + else if (string((const char*)m_msg) == string("CloseDxr3DeviceCmd")) + { + cDxr3Interface::Instance().ExternalReleaseDevices(); + SendStatus(); + } + else if (string((const char*)m_msg) == string("StatusDxr3DeviceCmd")) + { + SendStatus(); + } + else if (string((const char *)m_msg) == string("SaveDxr3DeviceCmd")) + { + m_bSavedState = cDxr3Interface::Instance().IsExternalReleased(); + SendStatus(); + } + else if (string((const char *)m_msg) == string("RestoreDxr3DeviceCmd")) + { + if (m_bSavedState) + { + cDxr3Interface::Instance().ExternalReleaseDevices(); + } + else + { + cDxr3Interface::Instance().ExternalReopenDevices(); + } + SendStatus(); + } + else + { + string res("Error\n"); + write(m_fdConnectionSocket, res.c_str(), res.size()); + } +} + +// ================================== +void cDxr3StartStopThread::Action() +{ + cDxr3StartStopSocket mySocket; + while (mySocket.WaitForConnection()) + { + while (mySocket.GetNextMessage()); + } +} diff --git a/dxr3unixserversocket.h b/dxr3unixserversocket.h new file mode 100644 index 0000000..3233995 --- /dev/null +++ b/dxr3unixserversocket.h @@ -0,0 +1,71 @@ +/* + * dxr3unixserversocket.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef __DXR3_UNIX_SERVER_SOCKET_H +#define __DXR3_UNIX_SERVER_SOCKET_H + +#include +#include +#include + + +#include "dxr3vdrincludes.h" + +class cDxr3UnixServerSocket { +public: + cDxr3UnixServerSocket(const char* pFileName = "/tmp/.dxr3-ux-sock", int backlog = 5); + virtual ~cDxr3UnixServerSocket(); + + bool WaitForConnection(void); + bool GetNextMessage(void); + bool IsConnected(void); +protected: + virtual void ProcessMessage(void) = 0; + + const char* m_pFileName; + bool m_bConnected; + int m_backlog; + int m_fdServerSocket; + int m_fdConnectionSocket; + sockaddr_un m_addr; + enum eDxr3socketMessageSize { MAX_REC_SIZE = 100 }; + uint8_t m_msg[MAX_REC_SIZE]; + uint8_t m_msgSize; + +private: + cDxr3UnixServerSocket(cDxr3UnixServerSocket&); // no copy constructor +}; + + +class cDxr3StartStopSocket : public cDxr3UnixServerSocket { +public: + cDxr3StartStopSocket() : m_bSavedState(false) {}; + virtual ~cDxr3StartStopSocket() {}; +protected: + void ProcessMessage(void); + void SendStatus(void); + + bool m_bSavedState; + +private: + cDxr3StartStopSocket(cDxr3StartStopSocket&); // no copy constructor +}; + + +class cDxr3StartStopThread : public cThread { +public: + cDxr3StartStopThread() {}; + virtual ~cDxr3StartStopThread() {}; +protected: + virtual void Action(void); + +private: + cDxr3StartStopThread(cDxr3StartStopThread&); // no copy constructor +}; + +#endif // __DXR3_UNIX_SERVER_SOCKET_H diff --git a/dxr3vdrincludes.h b/dxr3vdrincludes.h new file mode 100644 index 0000000..896718e --- /dev/null +++ b/dxr3vdrincludes.h @@ -0,0 +1,33 @@ +#ifndef _DXR3_VDRINCLUDES_H_ +#define _DXR3_VDRINCLUDES_H_ + +#include +#include +#include +using namespace std; + +#ifndef __STL_CONFIG_H +#define __STL_CONFIG_H +#define __DXR3_UNDEF_STL_CONFIG_AFTERWARDS +#endif + +// all includes from vdr +#if VDRVERSNUM >= 10307 + #include +#else + #include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __DXR3_UNDEF_STL_CONFIG_AFTERWARDS +#undef __STL_CONFIG_H +#endif + +#endif /*_DXR3_VDRINCLUDES_H_*/ -- cgit v1.2.3