diff options
50 files changed, 12239 insertions, 0 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..0da75f0 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,33 @@ +The following people have contributed to the development of this plugin in +one way or the another. Without their help, the plugin would not be as good +as it is now. + +Jon Burgess +Malcolm Caldwell +Martin Cap +Stuart Daines +Martin Dauskardt +Peter Dittmann +Gavin Hamill +Paavo Hartikainen +Tobias Haustein +Stefan Hülswitt +Thomas Husterer +Seppo Ingalsuo +Antti Järvinen +Atte Manninen +Lars Neufurth (donated some money for Christian's DD 5.1 system) +Andre Neumann +Luca Olivetti +Richard P. +Miika Pekkarinen +Teemu Rantanen +Jarkko Santala +Marco Schlüßler +Stephan Skrodzki +Ville Skyttä +Mikko Tuumanen +Sascha Volkenandt +Kimmo Vuorinen + +Thank you very much :) @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. @@ -0,0 +1,293 @@ +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 <linux/em8300.h> 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 <avcodec.h>) +- 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 <mplayer@jburgess.uklinux.net> +- added patch for DVD subtitles. Thanks to Stuart Daines <s.daines@ntlworld.com> +- fixed memory leak in dxr3osd.c - Thanks to Miika Pekkarinen <miipekk@ihme.org> +- 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 <pmml@netvita.pt> +- added Finnish language support - thanks to Hannu Savolainen <hannu@opensound.com> +- added Swedish language support - thanks to Tomas Prybil <tomas@prybil.se> +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 <pahartik@sci.fi> + + +2005-08-07: Version 0.2.3 + +- fixed output of anamorphic video when tv aspect is configured to 16:9 in + DVB setup menu (Seppo Ingalsuo) +- rewrote i18n support, improved Finnish translation and other bits + (Christian Gmeiner, Ville Skyttä) +- fixed void cDxr3Interface::SetAudioDigitalPCM() (Stephan Skrodzki) +- added many comments into source (Christian Gmeiner) +- using doxygen for docs (Christian Gmeiner) +- made path to microcode configurable in Makefile (Sascha Volkenandt) +- better default directories in Makefile (Christian Gmeiner, vdr-wiki.de folks) +- use std:: instead of namespace std + (bug #1044069, Christian Gmeiner, Ville Skyttä) +- fixed #includes: moved #include "dxr3osd.h" from dxr3interface.h to + dxr3interface.c, removed not needed #includes (Christian Gmeiner) +- added support for VDR 1.3.13 and later (Luca Olivetti, Peter Dittmann) +- fixed checking of return falues when opening the em8300-* fifos + (Christian Gmeiner, Ville Skyttä) +- removed explicit linking with zlib (Christian Gmeiner) +- compiles now with 3.4.x gcc's (Christian Gmeiner, Ville Skyttä) +- use $CXX for generating dependencies instead of hardcoded g++ (Ville Skyttä) +- added descriptions to audio and video output threads + (#1112673, Ville Skyttä) +- fixed audio and video thread deletion in demux device destructor + (#1112674, Ville Skyttä) +- made "all" the default target in Makefile (Ville Skyttä) +- avoid hang in pause mode with VDR >= 1.3.18 (Luca Olivetti) +- avoid high CPU usage in pause mode (Luca Olivetti, Klaus Schmidinger) +- improved GetSTC(): fixes DVB subtitles sync problems (Mikko Tuumanen) +- limit OSD flush rate: prevents OSD from going berserk due to being + refreshed too often, see plugin settings (Luca Olivetti, Ville Skyttä) +- borrow better OSD scaling routines from the Xine plugin (Luca Olivetti) +- improve original OSD scaler for small resolutions (#1014339, Luca Olivetti) +- improve error checking, eliminate some compiler warnings (Ville Skyttä) +- fix OSD going pink after returning from the MPlayer plugin; while at it, + remove dxr3palettemanager.* and use VDR's cPalette + (Ville Skyttä, Martin Cap, Luca Olivetti) +- remove unused dxr3unixserversocket.* from 0.2.x (Ville Skyttä) +- fix sound with the MP3 plugin and VDR >= 1.3.18 (Antti Järvinen) +- set aspect ratio and audio mode to unknown when releasing devices, fixes + the setup eg. after returning from the MPlayer plugin + (Luca Olivetti, Kimmo Vuorinen) +- rework OSD color management, fixes eg. color "bleeding" + (Luca Olivetti, Thomas Husterer) +- sync SPU decoder with VDR 1.3.23 (Ville Skyttä) +- register only needed ffmpeg codec(s) (Marco Schlüßler) +- fix crash at exit (Marco Schlüßler) +- add support for mandatory subtitles (Marco Schlüßler) +- avoid crashing with some corrupted streams (Jon Burgess) +- remove optimized memcpy routines and related stuff, just use the glibc + one (Ville Skyttä) +- clean up dead code for old VDR versions that hasn't worked for some time + anyway, VDR >= 1.3.11 is now required (Ville Skyttä) +- improve recovery and avoid lockups caused by bad streams (Jon Burgess) +- use VDR's facilities for logging (no more dxr3plugin.log), make it less + noisy (Ville Skyttä, Christian Gmeiner) +- add setup option for hiding the main menu entry (Ville Skyttä) +- implement stereo/left/right audio channel switching (Malcolm Caldwell) +- limit card number to sane values in config (Ville Skyttä) +- added Italian, Spanish and Catalan translations (Luca Olivetti) +- don't override OSD's {Save,Restore}Region with dummies (Luca Olivetti) @@ -0,0 +1,22 @@ +Prerequisites: + +- Get the DXR3 drivers from http://sourceforge.net/projects/dxr3 , + install, configure, test and verify the installation. +- Install the (latest) VDR developer version, or at least >= 1.3.11. +- The plugin needs the libavcodec library from http://ffmpeg.sourceforge.net/ + +Installation: + +- Get the latest dxr3-plugin version from + http://sourceforge.net/projects/dxr3plugin/ +- Unpack the package into "PLUGINS/SRC" directory. +- Make a symbolic link to this dxr3-plugin (ln -s vdr_dxr3_x.x.x dxr3). +- Check FFMDIR and EM8300 in Makefile. +- Check extra settings in Makefile: -DMICROCODE, -DUSE_XINE_SCALER +- 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". + +Supplemental patches: + +- See the patches/ directory. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3ab2e57 --- /dev/null +++ b/Makefile @@ -0,0 +1,101 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.19 2005/08/15 17:28:49 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 = /usr/local/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 = $(shell echo vdr-$(ARCHIVE) | sed -e 's/cvs$$/cvs'`date +%Y%m%d`/) + +### 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 += -D_GNU_SOURCE + +# where is the microcode for the dxr3 located? +DEFINES += -DMICROCODE=\"/usr/share/misc/em8300.uc\" + +# use OSD scaler borrowed from the Xine plugin? +# comment this out to use the traditional vdr-dxr3 scaler +DEFINES += -DUSE_XINE_SCALER + +### The object files (add further files here): + +OBJS = $(PLUGIN).o dxr3multichannelaudio.o dxr3sysclock.o dxr3colormanager.o dxr3syncbuffer.o dxr3audiodecoder.o \ +dxr3blackframe.o dxr3nextpts.o dxr3pesframe.o dxr3demuxdevice.o dxr3configdata.o \ +dxr3ffmpeg.o dxr3interface_spu_encoder.o dxr3i18n.o \ +dxr3interface.o dxr3device.o dxr3outputthread.o dxr3osd.o dxr3osd_subpicture.o dxr3spudecoder.o + +### Default target: + +all: libvdr-$(PLUGIN).so + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@ + @cp $@ $(LIBDIR)/$@.$(VDRVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) \ + --owner=root --group=root --exclude CVS $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ \#* + +#indent: +# emacs -batch --eval '(dolist (file command-line-args-left) (progn (find-file file) (c-indent-region (point-min) (point-max)) (save-buffer)))' *.h *.c @@ -0,0 +1,20 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Kai Moeller <dxr3_av@schluenss.de>, + Stefan Schluenss <dxr3_osd@schluenss.de>, + Christian Gmeiner <christian at visual-page.de>, + ...and numerous others, see CONTRIBUTORS. + +Project's home page: http://sourceforge.net/projects/dxr3plugin/ + +Mailing lists: http://sourceforge.net/mail/?group_id=112648 + +Latest version available at: See project home page + +Description: DXR3/Hollywood+ MPEG decoder card plugin which + allows using such a card as primary interface + for VDR. + +See the file COPYING for license information. +For installation instructions, see the file INSTALL. +See TODO for a list of work in progress items, bugs and some workarounds. @@ -0,0 +1,43 @@ +Known problems, bugs, and workarounds for this driver: +------------------------------------------------------ + +* The MP3 plugin's "show live TV" option while playing stuff doesn't work. + Workaround: none known, but the black screen isn't that bad if you + make the MP3 progress stuff/playlist visible... + +* VCD plugin does not work. + Workaround: use the MPlayer plugin to play VCDs. + +* No sound with the DVD plugin with VDR >= 1.3.18. + Workaround: use the MPlayer plugin to play DVDs. + Workaround 2: use VDR < 1.3.18. + +* When cutting recordings from some channels, the still picture is stuck + and won't move when you press 4 or 6 to fine tune the cutmarks. + Workaround: see vdr-iframe.patch in the patches/ directory or Reinhard + Nißl's http://home.vr-web.de/~rnissl/vdr-1.3.28-dvbplayer.patch (better) + +* If the TV aspect ratio does not automatically adjust according to the + video stream, and you have a ADV7170-based DXR3 and a PAL system, see + em8300-adv7170-wss.patch and vdr-dxr3-wss.patch in the patches/ dir. + +Other TODOs: +------------ + +* set bcs +* clean unneeded log entries +* stillpicture +* grab screenshot +* add much more comments! +* rewrite some parts of plugin like + - demuxer + - palettemanger + - colormanger + - spuencoder +* osd via + - ffmpeg + - vga overlay + +* optimize (is it worth it?) + Rgb2YCrCb + YUV2Rgb @@ -0,0 +1,241 @@ +/* + * 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.9 2005/08/15 17:28:49 austriancoder Exp $ + * + */ + +#include "dxr3vdrincludes.h" +#include "dxr3device.h" +#include "dxr3syncbuffer.h" +#include "dxr3configdata.h" +#include "dxr3interface.h" +#include "dxr3.h" +#include "dxr3i18n.h" + +static const char *VERSION = "0.2.3"; +static const char *DESCRIPTION = "Hardware MPEG decoder"; +static const char *MAINMENUENTRY = "DXR3"; + +#if VDRVERSNUM && VDRVERSNUM < 10311 +#error "This version of the DXR3 plugin needs VDR version >= 1.3.11" +#endif + +#define DXR3_MAX_CARDS 4 + +// ================================== +// 'message-handler' for the main screen +eOSState cDxr3OsdItem::ProcessKey(eKeys Key) +{ + if (Key == kOk) + { + switch (m_item) + { + case DXR3_RESET_HARDWARE: + cDxr3Interface::Instance().ResetHardware(); + if (cDxr3Device::InstanceP()) + cDxr3Device::InstanceP()->Reset(); + break; + + case DXR3_FORCE_LETTER_BOX: + cDxr3ConfigData::Instance().SetForceLetterBox(!cDxr3ConfigData::Instance().GetForceLetterBox()); + break; + + case DXR3_ANALOG_OUT: + cDxr3ConfigData::Instance().SetUseDigitalOut(0); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + if (cDxr3Device::InstanceP()) + cDxr3Device::InstanceP()->Reset(); + break; + + case DXR3_DIGITAL_OUT: + cDxr3ConfigData::Instance().SetUseDigitalOut(1); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + if (cDxr3Device::InstanceP()) + cDxr3Device::InstanceP()->Reset(); + break; + + case DXR3_AC3_OUT: + cDxr3ConfigData::Instance().SetAc3OutPut(!cDxr3ConfigData::Instance().GetAc3OutPut()); + if (cDxr3Device::InstanceP()) + cDxr3Device::InstanceP()->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("Card number"), + &newDxr3Card, 0, DXR3_MAX_CARDS - 1)); + newVideoMode = (int) cDxr3ConfigData::Instance().GetVideoMode(); + menuVideoModes[0] = tr("PAL"); + menuVideoModes[1] = tr("PAL60"); + menuVideoModes[2] = tr("NTSC"); + Add(new cMenuEditStraItem(tr("Video mode"), + &newVideoMode, 3, menuVideoModes)); + newHideMenu = cDxr3ConfigData::Instance().GetHideMenu(); + Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &newHideMenu)); + newOsdFlushRate = cDxr3ConfigData::Instance().GetOsdFlushRate(); + Add(new cMenuEditIntItem(tr("OSD flush rate (ms)"), + &newOsdFlushRate, 0, 255)); +} + +// ================================== +// 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("HideMenu", + cDxr3ConfigData::Instance().SetHideMenu(newHideMenu)); + SetupStore("OsdFlushRate", + cDxr3ConfigData::Instance().SetOsdFlushRate(newOsdFlushRate)); +} + +// ================================== +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 tr(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() +{ + RegisterI18n(Phrases); + + cDxr3Device::InstanceP(); + + return true; +} + +// ================================== +void cPluginDxr3::Housekeeping() +{ +} + +// ================================== +cMenuSetupPage* cPluginDxr3::SetupMenu() +{ + return new cMenuSetupDxr3(); +} + +// ================================== +bool cPluginDxr3::SetupParse(const char *Name, const char *Value) +{ + 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, "Dxr3VideoMode")) + { + cDxr3ConfigData::Instance().SetVideoMode((eVideoMode) atoi(Value)); + return true; + } + if (!strcasecmp(Name, "HideMenu")) + { + cDxr3ConfigData::Instance().SetHideMenu(atoi(Value)); + return true; + } + if (!strcasecmp(Name, "OsdFlushRate")) + { + cDxr3ConfigData::Instance().SetOsdFlushRate(atoi(Value)); + return true; + } + + return false; +} + +// ================================== +const char* cPluginDxr3::MainMenuEntry() +{ + return cDxr3ConfigData::Instance().GetHideMenu() ? + NULL : tr(MAINMENUENTRY); +} + +// ================================== +cOsdObject* cPluginDxr3::MainMenuAction() +{ + return new cDxr3OsdMenu; +} + +VDRPLUGINCREATOR(cPluginDxr3); // Don't touch this! + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: @@ -0,0 +1,97 @@ +#ifndef _DXR3_H_ +#define _DXR3_H_ + +// --- cMenuSetupDxr3 ------------------------------------------------------- + +// ================================== +// setup screen +class cMenuSetupDxr3 : public cMenuSetupPage +{ +public: + cMenuSetupDxr3(); + +protected: + virtual void Store(); + +private: + int newUseDigitalOut; + int newDxr3Card; + int newVideoMode; + const char *menuVideoModes[3]; + int newHideMenu; + int newOsdFlushRate; +}; + + +// ================================== +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(tr("DXR3 Adjustment")) + { + Clear(); + SetHasHotkeys(); + Add(new cDxr3OsdItem(hk(tr("Reset DXR3 hardware")), + DXR3_RESET_HARDWARE)); + Add(new cDxr3OsdItem(hk(tr("Toggle force letterbox")), + DXR3_FORCE_LETTER_BOX)); + + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + Add(new cDxr3OsdItem(hk(tr("Switch to analog audio output")), + DXR3_ANALOG_OUT)); + else + Add(new cDxr3OsdItem(hk(tr("Switch to digital audio 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(tr("AC3 output off")), DXR3_AC3_OUT)); + else if (cDxr3Interface::Instance().IsAc3Present()) + Add(new cDxr3OsdItem(hk(tr("AC3 output on")), DXR3_AC3_OUT)); + } + else + { + Add(new cDxr3OsdItem(hk(tr("Switch to digital audio output")), + DXR3_DIGITAL_OUT)); + } + */ + } +}; + +#endif /*_DXR3_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3audiodecoder.c b/dxr3audiodecoder.c new file mode 100644 index 0000000..67238d2 --- /dev/null +++ b/dxr3audiodecoder.c @@ -0,0 +1,316 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +/* + ToDo: + - cDxr3AudioDecoder::Init: Why are we always reinit the codec? +*/ + +#include <stdio.h> +#include "dxr3audiodecoder.h" +#include "dxr3pesframe.h" + +// ================================== +const int LPCM_HEADER_LENGTH = 7; + +// ================================== +//! constructor +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)) + { + dsyslog("dxr3: audiodecoder: found different audio header" + " (new: %#x, old: %#x), (re)initializing", + *((uint32_t*) lastHeader), *((uint32_t*) (buf+i))); + + 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<uint8_t *>(buf), length); + if (len < 0 || out_size < 0) + throw WRONG_LENGTH; + + if (Codec.codec_context.sample_rate != rate) + { + dsyslog("dxr3: audiodecoder: sample rate=%d", + Codec.codec_context.sample_rate); + if (rate != -1) throw UNEXPECTED_PARAMETER_CHANGE; + rate = Codec.codec_context.sample_rate; + } + if (Codec.codec_context.channels != channels + 1) + { + dsyslog("dxr3: audiodecoder: channels=%d", + Codec.codec_context.channels); + if (channels != -1) + throw UNEXPECTED_PARAMETER_CHANGE; + channels = (Codec.codec_context.channels == 2) ? 1 : 0; + } + 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: + esyslog("dxr3: audiodecoder: wrong length"); + break; + + case UNEXPECTED_PARAMETER_CHANGE: + esyslog("dxr3: audiodecoder: unexpected parameter change"); + break; + + default: + esyslog("dxr3: audiodecoder: unexpected exception"); + break; + } + esyslog("dxr3: audiodecoder: 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]; + // only even number of bytes are allowed + assert(!((length - LPCM_HEADER_LENGTH) % 2)); + + 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) + { + std::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; +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3audiodecoder.h b/dxr3audiodecoder.h new file mode 100644 index 0000000..4f86c7d --- /dev/null +++ b/dxr3audiodecoder.h @@ -0,0 +1,97 @@ +/* + * dxr3audiodecoder.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_AUDIODECODER_H_ +#define _DXR3_AUDIODECODER_H_ + +#include <stdlib.h> +#include <stdint.h> + +#include "dxr3ffmpeg.h" +#include "dxr3syncbuffer.h" +#include "dxr3multichannelaudio.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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3blackframe.c b/dxr3blackframe.c new file mode 100644 index 0000000..35c79bb --- /dev/null +++ b/dxr3blackframe.c @@ -0,0 +1,1294 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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); + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3colormanager.c b/dxr3colormanager.c new file mode 100644 index 0000000..044d254 --- /dev/null +++ b/dxr3colormanager.c @@ -0,0 +1,388 @@ +/*************************************************************************** + 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 <assert.h> + +#include "dxr3colormanager.h" +#include <vdr/tools.h> +#include <stdio.h> +#include <string.h> + +// ================================== +//! constructor +cColorManager::cColorManager() +{ + NrOfRegions = -1; + 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) +{ + // Calling method (cColorManager::EncodeColors) + // already checks MAX_NO_OF_REGIONS + curRegion = new yRegion(); + curRegion->Y1 = y; + NrOfRegions++; + hlr[NrOfRegions] = curRegion; + NewSection(0); //there's always at least a section +} + +// ================================== +// Closes the spu-highlight region +void cColorManager::CloseRegion(int y) +{ + curRegion->Y2 = y; +} + +// ================================== +void cColorManager::EncodeColors(int width, int height, unsigned char* map, + unsigned char* dmap) +{ + unsigned char color; + unsigned char oldcolor = 0xFF; + unsigned char ColorIndex; + int mapoffset = 0; + + OpenRegion(0); + for (int y = 0; y < height; ++y) + { + oldcolor = 0xFF; + FirstSection(); + for(int x = 0; x < width; ++x) + { + if (x > curSection->X2) + { + oldcolor = 0xFF; + NextSection(); + } + color = map[mapoffset + x]; + if (color == oldcolor) + dmap[mapoffset + x] = ColorIndex; + else + { + // try to map the color in the current region + if (AddColor(x, y, color, ColorIndex)) + { + // store as the highlight region index + dmap[mapoffset + x] = ColorIndex; + } + else + { + CloseRegion(y - 1); + if (NrOfRegions <= MAX_NO_OF_REGIONS - 1) + { + // retry with another region + OpenRegion(y); + x = -1; + oldcolor = 0xFF; + } + else + { + esyslog("dxr3: colormanager: too many regions (%d)" + " - giving up", NrOfRegions); + return; + } + } + } + } + mapoffset += width; + } + // close the last highlight region + CloseRegion(height); + +//#define colordebug +#ifdef colordebug + { + FILE *fp; + fp = fopen("OSD.dump","w+"); + u_char *pippo = dmap; + u_char *pippo2 = map; + int curregion = 0; + int cursection = 0; + + + for (int dumpy = 0; dumpy < height; dumpy++) + { + if(curregion < NrOfRegions) + { + if(hlr[curregion]->Y1 == dumpy) + { + fprintf(fp, "%i", hlr[curregion]->N); + for (int sec = 0; sec < hlr[curregion]->N; sec++) + fprintf(fp, ",%i", hlr[curregion]->Section[sec]->X1); + for (int dumpx = 0; dumpx < width; dumpx++) + fprintf(fp, "="); + fprintf(fp, "\n"); + curregion++; + } + } + + cursection = 0; + for (int dumpx = 0; dumpx < width; dumpx++) + { + if (curregion < NrOfRegions) + { + if (cursection < hlr[curregion]->N) + { + if (hlr[curregion]->Section[cursection]->X1 == dumpx) + { + fprintf(fp, "|"); + cursection++; + } + } + } + fprintf(fp, "%01X", *pippo2 & 0xF); + pippo2++; + } + fprintf(fp, "\n"); + + cursection = 0; + for (int dumpx = 0; dumpx < width; dumpx++) + { + if(curregion < NrOfRegions) + { + if (cursection < hlr[curregion]->N) + { + if (hlr[curregion]->Section[cursection]->X1 == dumpx) + { + fprintf(fp, "|"); + cursection++; + } + } + } + fprintf(fp, "%01X", *pippo & 0xF); + pippo++; + } + fprintf(fp, "\n"); + } + fclose(fp); + printf("**** dumped\n"); + } +#endif +} + +// ================================== +unsigned char cColorManager::AddColor(int x, int y, unsigned char color, + unsigned char &ColorIndex) { + + if (!curSection->HasColor(color, ColorIndex)) + { + // this color is new for this section + if (curSection->AllColorsUsed(curRegion->Y1==y)) + { + // no more free colors + if (y != curRegion->Y1) + { + // terminate region + return(0); + } + NewSection(x); + } + // and add new color + ColorIndex = curSection->AddColor(color); + } + return(1); +} + +// ================================== +void cColorManager::FirstSection(void) +{ + curSectionIndex = 0; + curSection = curRegion->Section[0]; +} + +// ================================== +void cColorManager::NextSection(void) +{ + curSectionIndex++; + if (curSectionIndex < curRegion->N) + curSection=curRegion->Section[curSectionIndex]; + // it shouldn't happen + else esyslog("dxr3: colormanager: ran out of sections"); +} + +// ================================== +// convert into SPU - hope is correct description +unsigned char* cColorManager::GetSpuData(int& len) +{ + 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); +} + +// ================================== +void cColorManager::NewSection(int x) +{ + int N = curRegion->N; + if (N >= MAX_NO_OF_SECTIONS - 1) { + esyslog("dxr3: colormanager: bummer, too many sections (%d)," + " reusing last one", N); + return; // reuse last section, not optimal but there's no other way out + } + curSection = new xSection(x); + curRegion->Section[N] = curSection; + if (N > 0) + curRegion->Section[N-1]->X2 = x - 1; + (curRegion->N)++; + curSectionIndex = N; +} + +// ================================== +xSection::xSection(int x) +{ + X1 = x; + X2 = 32767; + NrOfColors = 0; + for (int i = 0; i < 4; i++) + { + Opac[i] = 0xFF; + Colors[i] = 0; + } +} + +// ================================== +unsigned char xSection::AddColor(unsigned int color) +{ + unsigned char ColorIndex = 0; + + if (NrOfColors <= 3) + { + Colors[NrOfColors] = color; + Opac[NrOfColors] = color >> 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); +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3colormanager.h b/dxr3colormanager.h new file mode 100644 index 0000000..2a2553c --- /dev/null +++ b/dxr3colormanager.h @@ -0,0 +1,126 @@ +/*************************************************************************** + 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 <stdio.h> + +#define OSD_SPU_CM_DUMP 0 + +#define MAX_NO_OF_SECTIONS 15 +#define MAX_NO_OF_REGIONS 100 + + +// ================================== +class xSection +{ +public: + xSection(int x); + bool HasColor(unsigned int color, unsigned char &ColorIndex); + unsigned char AddColor(unsigned int color); + bool AllColorsUsed(bool FirstLine) { + //DIAG("AllColorsUsed: %d\n",NrOfColors); + return(NrOfColors >= (FirstLine ? 3 : 4)); + }; + 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); + +private: + yRegion *hlr[MAX_NO_OF_REGIONS]; + yRegion *curRegion; + int NrOfRegions; + unsigned char spudata[(4+6*MAX_NO_OF_SECTIONS)*MAX_NO_OF_REGIONS+7]; + xSection *curSection; + int curSectionIndex; + + /** Opens a new highlight region */ + void OpenRegion(int y); + /** Closes the spu-highlight region */ + void CloseRegion(int y); + + void NewSection(int x); + void FirstSection(void); + void NextSection(void); +}; + +#endif /*_DXR3COLORMANAGER_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3configdata.c b/dxr3configdata.c new file mode 100644 index 0000000..5b65ea4 --- /dev/null +++ b/dxr3configdata.c @@ -0,0 +1,47 @@ +/* + * dxr3configdata.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dxr3configdata.h" + +// ================================== +//! constructor +cDxr3ConfigData::cDxr3ConfigData() +{ + m_digitaloutput = 0; + m_ac3output = 0; + m_card = 0; + m_forceletterbox = 0; + m_videomode = PAL; + m_menumode = SUBPICTURE; + m_brightness = 500; + m_contrast = 500; + m_saturation = 500; + m_hidemenu = 0; + m_osdflushrate = 40; +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3configdata.h b/dxr3configdata.h new file mode 100644 index 0000000..07660e5 --- /dev/null +++ b/dxr3configdata.h @@ -0,0 +1,172 @@ +/* + * dxr3configdata.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_CONFIGDATA_H_ +#define _DXR3_CONFIGDATA_H_ + +#include "dxr3singleton.h" + +// ================================== +//! possible video modes +enum eVideoMode +{ + PAL = 0, ///< use PAL as videomode + PAL60, ///< use PAL60 as videomode + NTSC ///< use NTSC as videomode +}; + +// ================================== +// possible menu modes +enum eMenuMode +{ + SUBPICTURE = 0, + MPEG +}; + +// ================================== +//! global interface to access all config datas of this plugin +/* + With this singleton you can access very easy all possible + config settings of the plugin. +*/ +class cDxr3ConfigData : public Singleton<cDxr3ConfigData> +{ +public: + cDxr3ConfigData(); + ~cDxr3ConfigData() {} + + int GetUseDigitalOut() const + { + return m_digitaloutput; + } + int SetUseDigitalOut(int value) + { + return m_digitaloutput = value; + } + int GetDxr3Card() const + { + return m_card; + } + int SetDxr3Card(int value) + { + return m_card = value; + } + int GetForceLetterBox() const + { + return m_forceletterbox; + } + int SetForceLetterBox(int value) + { + return m_forceletterbox = value; + } + int GetAc3OutPut() const + { + return m_ac3output; + } + int SetAc3OutPut(int value) + { + return m_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 GetBrightness() const + { + return m_brightness; + } + int SetBrightness(int value) + { + return m_brightness = value; + } + int GetContrast() const + { + return m_contrast; + } + int SetContrast(int value) + { + return m_contrast = value; + } + int GetSaturation() const + { + return m_saturation; + } + int SetSaturation(int value) + { + return m_saturation = value; + } + + int GetHideMenu() const + { + return m_hidemenu; + } + int SetHideMenu(int value) + { + return m_hidemenu = value; + } + + unsigned int GetOsdFlushRate() const + { + return (unsigned) m_osdflushrate; + } + int SetOsdFlushRate(int value) + { + return m_osdflushrate = value; + } + +protected: + eVideoMode m_videomode; + eMenuMode m_menumode; + + int m_digitaloutput; + int m_ac3output; + int m_card; + int m_forceletterbox; + int m_brightness; + int m_contrast; + int m_saturation; + int m_hidemenu; + int m_osdflushrate; +}; + +#endif /*_DXR3_CONFIGDATA_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3demuxdevice.c b/dxr3demuxdevice.c new file mode 100644 index 0000000..762cf9d --- /dev/null +++ b/dxr3demuxdevice.c @@ -0,0 +1,710 @@ +/* + * dxr3demuxdevice.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include "dxr3demuxdevice.h" +#include <linux/em8300.h> +#include "dxr3pesframe.h" +#include "dxr3configdata.h" + +// ================================== +//! constructor +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) + { + esyslog("dxr3: fatal: unable to allocate memory for audio thread"); + exit(1); + } + m_pAudioThread->Start(); + + m_pVideoThread = new cDxr3VideoOutThread(dxr3Device, m_vBuf); + if (!m_pVideoThread) + { + esyslog("dxr3: fatal: unable to allocate memory for video thread"); + 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_pAudioThread) + { + delete m_pAudioThread; + } +} + +// ================================== +// 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(); +} + +// ================================== +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(); + + dsyslog("dxr3: demux: stillpicture length: %d", length); + + 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: + dsyslog("dxr3: demux: I-frame"); + 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.SetVerticalSize(pesFrame.GetVerticalSize()); + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), m_ReUseFrame); + break; + + case UNKNOWN_FRAME: + dsyslog("dxr3: demux: unknown frame"); + if (bPlaySuc) + { + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), m_ReUseFrame); + } + break; + + default: + dsyslog("dxr3: demux: default frame"); + 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()); + m_dxr3Device.SetVerticalSize(pesFrame.GetVerticalSize()); + while (!Poll(100)); + cFixedLengthFrame* pTempFrame = m_vBuf.Push(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, ftVideo); + if (!pTempFrame) /* Push Timeout */ + throw (cDxr3PesFrame::PES_GENERAL_ERROR); + + 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()); + m_dxr3Device.SetVerticalSize(pesFrame.GetVerticalSize()); + cFixedLengthFrame* pTempFrame = m_vBuf.Push(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, ftVideo); + if (!pTempFrame) /* Push Timeout */ + throw (cDxr3PesFrame::PES_GENERAL_ERROR); + + 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; + } +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3demuxdevice.h b/dxr3demuxdevice.h new file mode 100644 index 0000000..1d8441c --- /dev/null +++ b/dxr3demuxdevice.h @@ -0,0 +1,103 @@ +/* + * dxr3demuxdevice.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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); + + 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 + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3device.c b/dxr3device.c new file mode 100644 index 0000000..39467ed --- /dev/null +++ b/dxr3device.c @@ -0,0 +1,467 @@ +/* + * dxr3device.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dxr3device.h" +#include "dxr3configdata.h" +#include "dxr3interface.h" +#include "dxr3tools.h" +#include "dxr3osd.h" + +extern "C" +{ +#include <jpeglib.h> +} + +// ================================== +//! constructor +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) +{ + new cDxr3OsdProvider(); +} + +// replaying +// ================================== +//! does we have an mpeg2 devocer? +bool cDxr3Device::HasDecoder() const +{ + // sure we have one ;) + return true; +} + +// ================================== +//! can we replay vdr recordings? +bool cDxr3Device::CanReplay() const +{ + // also sure... + return true; +} + +// ================================== +bool cDxr3Device::SetPlayMode(ePlayMode PlayMode) +{ + if (PlayMode == pmExtern_THIS_SHOULD_BE_AVOIDED) + { + Tools::WriteInfoToOsd(tr("DXR3: releasing devices")); + 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(); + } + + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + if (cDxr3ConfigData::Instance().GetAc3OutPut() && m_CalledBySet) + { + isyslog("dxr3: Setting AC3 audio mode"); + cDxr3Interface::Instance().SetAudioDigitalAC3(); // !!! FIXME + } + else + { + isyslog("dxr3: Setting digital PCM audio mode"); + cDxr3Interface::Instance().SetAudioDigitalPCM(); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + } + } + else + { + isyslog("dxr3: Setting analog audio mode"); + cDxr3Interface::Instance().SetAudioAnalog(); + } + + return true; +} + +// ================================== +int64_t cDxr3Device::GetSTC() +{ + return cDxr3Interface::Instance().GetPts(); +} + +// ================================== +void cDxr3Device::TrickSpeed(int Speed) +{ + dsyslog("dxr3: device: tricspeed: %d", Speed); + + m_DemuxDevice.SetTrickMode(DXR3_FAST, Speed); + + /* + 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; + ///< free buffer + 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) +{ + if ((m_DemuxDevice.GetDemuxMode() == DXR3_DEMUX_TRICK_MODE && + m_DemuxDevice.GetTrickState() == DXR3_FREEZE) || + cDxr3Interface::Instance().IsExternalReleased()) + { +#if VDRVERSNUM >= 10314 + cCondWait::SleepMs(TimeoutMs); +#else + usleep(TimeoutMs * 1000); +#endif + return false; + } + 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 -1; + } + + 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 +#if VDRVERSNUM >= 10318 +int cDxr3Device::PlayAudio(const uchar *Data, int Length) +#else +void cDxr3Device::PlayAudio(const uchar *Data, int Length) +#endif +{ + int retLength = 0; +#if VDRVERSNUM >= 10318 + int origLength = Length; +#endif + + m_AC3Present = true; + + if ((m_DemuxDevice.GetDemuxMode() == DXR3_DEMUX_TRICK_MODE && + m_DemuxDevice.GetTrickState() == DXR3_FREEZE) || + cDxr3Interface::Instance().IsExternalReleased()) + { + //usleep(1000000); +#if VDRVERSNUM >= 10318 + return 0; +#else + return; +#endif + } + + 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(), true); + } + } + else + { + if (m_PlayMode == pmAudioOnly) + { + retLength = m_DemuxDevice.DemuxAudioPes((const uint8_t*) Data, Length); + } 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); + } + } + +#if VDRVERSNUM >= 10318 + return origLength; +#endif +} + +// 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) != 1) + { + LOG_ERROR_STR(FileName); + } + } + fclose(f); + } + else + { + return false; + } + + delete Data; + return true; +} + +// ================================== +void cDxr3Device::SetVideoFormat(bool VideoFormat16_9) +{ + // Do we need this function? +} + +// ================================== +//! sets volume for audio output +void cDxr3Device::SetVolumeDevice(int Volume) +{ + cDxr3Interface::Instance().SetVolume(Volume); +} + +// ================================== +//! sets audio channel for audio output (stero, mono left, mono right) +void cDxr3Device::SetAudioChannelDevice(int AudioChannel) +{ + cDxr3Interface::Instance().SetAudioChannel(AudioChannel); +} +int cDxr3Device::GetAudioChannelDevice(void) +{ + return cDxr3Interface::Instance().GetAudioChannel(); +} + +// ================================== +// get spudecoder +cSpuDecoder *cDxr3Device::GetSpuDecoder(void) +{ + if (!m_spuDecoder && IsPrimaryDevice()) + { + m_spuDecoder = new cDxr3SpuDecoder(); + } + return m_spuDecoder; +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3device.h b/dxr3device.h new file mode 100644 index 0000000..ca11ba6 --- /dev/null +++ b/dxr3device.h @@ -0,0 +1,105 @@ +/* + * dxr3device.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_DEVICE_H_ +#define _DXR3_DEVICE_H_ + +#include "dxr3interface.h" +#include "dxr3demuxdevice.h" +#include "dxr3spudecoder.h" +#include <string> + +// ================================== +// our device :) +/*! + cDxr3Device is the interface for VDR devices. + Is is the part, which VDR "talks" with our plugin. +*/ +class cDxr3Device : public cDevice, public Singleton<cDxr3Device> +{ +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); +#if VDRVERSNUM >= 10318 + virtual int PlayAudio(const uchar *Data, int Length); +#else + virtual void PlayAudio(const uchar *Data, int Length); +#endif + + // 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); + virtual void SetAudioChannelDevice(int AudioChannel); + virtual int GetAudioChannelDevice(void); + + // osd + virtual cSpuDecoder *GetSpuDecoder(); + + // 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; + std::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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3ffmpeg.c b/dxr3ffmpeg.c new file mode 100644 index 0000000..fcb6e2d --- /dev/null +++ b/dxr3ffmpeg.c @@ -0,0 +1,91 @@ +/* + * dxr3ffmpeg.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dxr3ffmpeg.h" +#include "dxr3configdata.h" +#include <vdr/tools.h> + +// ================================== +//! constructor +cDxr3Ffmepg::cDxr3Ffmepg() +{ + avcodec_init(); + // Register only codec(s) we'll need. + register_avcodec(&mp2_decoder); +} + +// ================================== +//! look if Codec is supported by ffmpeg +bool cDxr3Ffmepg::FindCodec(struct Dxr3Codec& Codec) +{ + // find codec + Codec.codec = avcodec_find_decoder(Codec.id); + + if (!Codec.codec) + { + esyslog("dxr3: ffmpeg: codec %#.5x not found - not supported" + " by FFmpeg?", Codec.id); + return false; + } + + // init codec_context + memset(&Codec.codec_context, 0, sizeof(Codec.codec_context)); + + return true; +} + +// ================================== +//! try to open Codec +bool cDxr3Ffmepg::OpenCodec(struct Dxr3Codec& Codec) +{ + // try to open codec + int result = avcodec_open(&Codec.codec_context, Codec.codec); + + if (result < 0) + { + esyslog("dxr3: ffmpeg: couldn't open codec %#.5x", Codec.id); + return false; + } + else + { + Codec.Open = true; + } + + return true; +} + +// ================================== +//! close codec +void cDxr3Ffmepg::CloseCodec(struct Dxr3Codec& Codec) +{ + if (Codec.Open) + { + avcodec_close(&Codec.codec_context); + Codec.Open = false; + } +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3ffmpeg.h b/dxr3ffmpeg.h new file mode 100644 index 0000000..98557c5 --- /dev/null +++ b/dxr3ffmpeg.h @@ -0,0 +1,75 @@ +/* + * dxr3ffmpeg.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_FFMPEG_H_ +#define _DXR3_FFMPEG_H_ + +extern "C" +{ +#include <avcodec.h> +} + +#include <string.h> +#include "dxr3singleton.h" + +// ================================== +//! a codec used by this plugin +struct Dxr3Codec +{ + Dxr3Codec() : Open(false) {} + + AVCodec* codec; ///< ffmpeg's AVCodec + AVCodecContext codec_context; ///< ffmpeg's AVCodecContext + enum CodecID id; ///< id's from ffmpeg, eg. CODEC_ID_MP2 + bool Open; ///< is codec open? +}; + +// ================================== +// class to work with ffmpeg +/*! + With cDxr3Ffmepg you can easily handle as many + codecs as you want. + At the moment we need this only for + the audiodecoder, but in future i want to use + it for ohter nice stuff :) +*/ +class cDxr3Ffmepg : public Singleton<cDxr3Ffmepg> +{ +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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3generaldefines.h b/dxr3generaldefines.h new file mode 100644 index 0000000..e0c1d35 --- /dev/null +++ b/dxr3generaldefines.h @@ -0,0 +1,54 @@ +/* + * dxr3generaldefines.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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 + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3i18n.c b/dxr3i18n.c new file mode 100644 index 0000000..1397183 --- /dev/null +++ b/dxr3i18n.c @@ -0,0 +1,607 @@ +/* + * dxr3i18n.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dxr3i18n.h" + +const char *i18n_name = 0; + +const tI18nPhrase Phrases[] = { + { + "DXR3", + "DXR3", + "", // Slovenski + "DXR3", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "DXR3-toiminnot", + "", // Polski + "DXR3", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "DXR3", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Hardware MPEG decoder", + "", // Deutsch + "", // Slovenski + "Decoder MPEG Hardware", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "MPEG-purkukortti", + "", // Polski + "Descodificador MPEG Hardware", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Descodificador MPEG Hardware", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "DXR3 Adjustment", + "DXR3 Einstellungen", + "", // Slovenski + "Opzioni DXR3", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "DXR3-toiminnot", + "", // Polski + "Opciones DXR3", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Opcions DXR3", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Digital audio output", + "Digitaler Audioausgang", + "", // Slovenski + "Uscita audio digitale", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Digitaalinen audioulostulo", + "", // Polski + "Salida audio digital", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Sortida àudio digital", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Card number", + "Karte", + "", // Slovenski + "Scheda", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Kortin järjestysnumero", + "", // Polski + "Tarjeta", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Targeta", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Video mode", + "Videomodus", + "", // Slovenski + "Modo Video", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Näyttötila", + "", // Polski + "Modalidad vídeo", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Modalitat vídeo", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "PAL", + "PAL", + "", // Slovenski + "PAL", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "PAL", + "", // Polski + "PAL", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "PAL", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "PAL60", + "PAL60", + "", // Slovenski + "PAL60", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "PAL60", + "", // Polski + "PAL60", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "PAL60", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "NTSC", + "NTSC", + "", // Slovenski + "NTSC", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "NTSC", + "", // Polski + "NTSC", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "NTSC", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Reset DXR3 hardware", + "Reset DXR3 Hardware", + "", // Slovenski + "Reset hardware DXR3", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Palauta kortti alkutilaan", + "", // Polski + "Reset hardware DXR3", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Reset hardware DXR3", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Toggle force letterbox", + "Letterbox erzwingen", + "", // Slovenski + "Commuta modo letterbox forzato ", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Letterbox-näyttötilan pakotus päälle/pois", + "", // Polski + "Conmuta modalidad letterbox forzada", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Commuta modalitat letterbox forçada", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Switch to analog audio output", + "Analoge Ausgabe", + "", // Slovenski + "Seleziona uscita audio analogica", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Kytke analoginen audioulostulo", + "", // Polski + "Selecciona salida audio analógica", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Selecciona sortida àudio analògica", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "AC3 output on", + "AC3 Ausgabe Ein", + "", // Slovenski + "Attiva uscita AC3", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "AC3-ulostulo päälle", + "", // Polski + "Activa salida AC3", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Activa sortida AC3", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "AC3 output off", + "AC3 Ausgabe Aus", + "", // Slovenski + "Disattiva uscita AC3", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "AC3-ulostulo pois", + "", // Polski + "Desactiva salida AC3", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Desactiva sortida AC3", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Switch to digital audio output", + "Digitaler Ausgang", + "", // Slovenski + "Seleziona uscita audio digitale", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Kytke digitaalinen audioulostulo", + "", // Polski + "Selecciona salida audio digital", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Selecciona sortida àudio digital", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "DXR3: releasing devices", + "DXR3: Releasing Devices", + "", // Slovenski + "DXR3: liberando dispositivo", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "DXR3: vapautetaan laitteet", + "", // Polski + "DXR3: liberando dispositivo", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "DXR3: alliberant dispositiu", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Color settings", + "Farbeinstellungen", + "", // Slovenski + "Regolazioni colore", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Väriasetukset", + "", // Polski + "Ajustes color", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Ajustaments color", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Brightness", + "Helligkeit", + "", // Slovenski + "Luminosità", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Kirkkaus", + "", // Polski + "Luminosidad", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Lluminositat", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Contrast", + "Kontrast", + "", // Slovenski + "Contrasto", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Kontrasti", + "", // Polski + "Contraste", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Contrast", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Saturation", + "Sättigung", + "", // Slovenski + "Saturazione", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Värikylläisyys", + "", // Polski + "Saturación", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Saturació", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "Hide main menu entry", + "Hauptmenüeintrag verstecken", + "", // Slovenski + "Nascondi voce menù", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Piilota valinta päävalikosta", + "", // Polski + "Esconde entrada menú", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Amaga entrada menú", + "ÁÚàëâì ÚÞÜÐÝÔã Ò ÓÛÐÒÝÞÜ ÜÕÝî", + "", // Hrvatski +#if VDRVERSNUM > 10312 + "Peida valik peamenüüs", +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { + "OSD flush rate (ms)", + "", // Deutsch + "", // Slovenski + "Tempo minimo rinfresco OSD (ms)", + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "Kuvaruutunäytön päivitysväli (ms)", + "", // Polski + "Tiempo mínimo refresco OSD (ms)", + "", // ÅëëçíéêÜ (Greek) + "", // Svenska + "", // Românã + "", // Magyar + "Temps mínim refresc OSD (ms)", + "", // ÀãááÚØÙ (Russian) + "", // Hrvatski +#if VDRVERSNUM > 10312 + "", // Eesti +#if VDRVERSNUM > 10315 + "", // Dansk +#endif +#endif + }, + { NULL } +}; + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3i18n.h b/dxr3i18n.h new file mode 100644 index 0000000..063e773 --- /dev/null +++ b/dxr3i18n.h @@ -0,0 +1,36 @@ +/* + * dxr3i18n.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_I18N_H_ +#define _DXR3_I18N_H_ + +#include <vdr/i18n.h> + +extern const tI18nPhrase Phrases[]; + +#endif /*_DXR3_I18N_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3interface.c b/dxr3interface.c new file mode 100644 index 0000000..9f735fa --- /dev/null +++ b/dxr3interface.c @@ -0,0 +1,1205 @@ +/* + * dxr3interface.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <assert.h> +#include <math.h> +#include <sys/soundcard.h> +#include <linux/dvb/audio.h> + +#include "dxr3interface.h" +#include "dxr3syncbuffer.h" +#include "dxr3osd.h" + +// ================================== +const int LPCM_HEADER_LENGTH = 7; +const int ZEROBUFFER_SIZE = 4096; +uint8_t zerobuffer[ZEROBUFFER_SIZE] = {0}; +const uint32_t UNKNOWN_AUDIO_MODE = 9; // default, unused value + +// ================================== +//! 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 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) + { + esyslog("dxr3: unable to open %s: %m", FileName); + } + return fd; +} + +// ================================== +//! constructor +cDxr3Interface::cDxr3Interface() : + m_fdControl(-1), m_fdVideo(-1), m_fdAudio(-1), m_fdSpu(-1) +{ + // open control stream + m_fdControl = Dxr3Open("", cDxr3ConfigData::Instance().GetDxr3Card(), + O_WRONLY | O_SYNC); + if (m_fdControl < 0) + { + esyslog("dxr3: please verify that the em8300 modules are loaded"); + exit(1); + } + + // 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 < 0 || m_fdAudio < 0 || m_fdSpu < 0) + { + + esyslog("dxr3: fatal: unable to open some em8300 devices"); + exit(1); + } + + // create clock + m_pClock = new cDxr3SysClock(m_fdControl, m_fdVideo, m_fdSpu); + + // everything ok? + if (!m_pClock) + { + esyslog("dxr3: fatal: unable to allocate memory for em8300 clock"); + exit(1); + } + + // set default values + m_AudioActive = false; + m_VideoActive = false; + m_OverlayActive = false; + m_ExternalReleased = false; + m_volume = 255; + m_audioChannel = AUDIO_STEREO; + m_horizontal = 720; + m_vertical = 576; + m_audioChannelCount = UNKNOWN_CHANNEL_COUNT; + m_audioDataRate = 0; + m_audioSampleSize = 0; + + m_audioMode = UNKNOWN_AUDIO_MODE; + m_aspectRatio = UNKNOWN_ASPECT_RATIO; + m_spuMode = EM8300_SPUMODE_OFF; + + // configure device based on settings + ConfigureDevice(); + + // get bcs values from driver + if (ioctl(m_fdControl, EM8300_IOCTL_GETBCS, &m_bcs) < 0) + { + esyslog("dxr3: failed to get brightness/contrast/saturation: %m"); + } + else + { + dsyslog("dxr3: intf: brightness=%d,contrast=%d,saturation=%d at init", + m_bcs.brightness, m_bcs.contrast, m_bcs.saturation); + } + + PlayBlackFrame(); + SetChannelCount(1); +} + +// ================================== +//! destructor +cDxr3Interface::~cDxr3Interface() +{ + // close filehandles + if (m_fdControl > -1) + { + close(m_fdControl); + } + if (m_fdVideo > -1) + { + close(m_fdVideo); + } + if (m_fdSpu > -1) + { + close(m_fdSpu); + } + if (m_fdAudio > -1) + { + 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) + { + esyslog("dxr3: unable to set analog audio mode: %m"); + } + 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) + { + esyslog("dxr3: unable to set digital PCM audio mode: %m"); + } + 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) + { + esyslog("dxr3: unable to set AC3 audio mode: %m"); + } + ReOpenAudio(); + } + + Unlock(); + } +} + +// ================================== +//! set audio speed +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) + { + esyslog("dxr3: unable to set DSP speed to %d: %m", speed); + } + } + } + m_audioDataRate = speed; + } +} + +// ================================== +//! set number of channels +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) + { + esyslog("dxr3: unable to set channel count to %d: %m", + count); + } + } + } + m_audioChannelCount = count; + } +} + +// ================================== +//! set audio sample size +void cDxr3Interface::SetAudioSampleSize(uint32_t sampleSize) +{ + if (!m_ExternalReleased) + { + if (ioctl(m_fdAudio, SNDCTL_DSP_SAMPLESIZE, sampleSize) < 0) + { + esyslog("dxr3: unable to set audio sample size to %d: %m", + sampleSize); + } + } + 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; +} + +// ================================== +int64_t cDxr3Interface::GetPts() +{ + return m_lastSeenPts << 1; +} + +// ================================== +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 processing 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) + { + esyslog("dxr3: unable to enable subpicture mode: %m"); + } + } + + 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) + { + esyslog("dxr3: unable to disable subpicture mode: %m"); + } + } + + Unlock(); +} + +// ================================== +//! disable audio output of dxr3 +void cDxr3Interface::DisableAudio() +{ + m_AudioActive = false; + + // we write 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 check if it is enabled already + 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) + { + //###### + esyslog("dxr3: unable to set overlay signal mode: %m"); + 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) + { + //###### + esyslog("dxr3: unable to set up overlay screen: %m"); + 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) + { + //###### + esyslog("dxr3: unable to set up overlay window: %m"); + return; + } + + m_OverlayActive = true; +} + +// ================================== +//! disable overlay mode of the dxr3 +void cDxr3Interface::DisanleOverlay() +{ + // is it already 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) + { + esyslog("dxr3: unable to get aspect ratio: %m"); + } + } + + Unlock(); + return ioval; +} + +// ================================== +//! set aspect ratio +void cDxr3Interface::SetAspectRatio(uint32_t ratio) +{ + static int requestCounter = 0; + + Lock(); + + if (cDxr3ConfigData::Instance().GetForceLetterBox()) + ratio = EM8300_ASPECTRATIO_16_9; + if (Setup.VideoFormat) + ratio = EM8300_ASPECTRATIO_4_3; + + 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) + { + esyslog("dxr3: unable to set aspect ratio: %m"); + } + 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) + { + esyslog("dxr3: unable to set play mode: %m"); + } + reg.microcode_register = 1; + reg.reg = 0; + reg.val = MVCOMMAND_SYNC; + + if (ioctl(m_fdControl, EM8300_IOCTL_WRITEREG, ®) < 0) + { + esyslog("dxr3: unable to start em8300 sync engine: %m"); + } + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::Pause() +{ + int ioval = EM8300_PLAYMODE_PAUSED; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) + { + esyslog("dxr3: unable to set pause mode: %m"); + } + } + + Unlock(); +} +// ================================== +void cDxr3Interface::SingleStep() +{ + int ioval = EM8300_PLAYMODE_SINGLESTEP; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) + { + esyslog("dxr3: unable to set single-step mode: %m"); + } + } + + 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) + { + dsyslog("dxr3: playvideoframe: times=%d", times); + } + + 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()); + uint32_t pts = pFrame->GetPts(); + if (pts > 0) m_lastSeenPts = pts; + } +} + +// ================================== +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? + int written = 0; + + if (m_AudioActive) + { + Lock(); + + SetAudioSpeed(pFrame->GetDataRate()); + SetChannelCount(pFrame->GetChannelCount()); + + if (!m_ExternalReleased) + { + if (!cDxr3ConfigData::Instance().GetAc3OutPut()) + ResampleVolume((short*)pFrame->GetData(), pFrame->GetCount()); + + written = write(m_fdAudio, pFrame->GetData(), pFrame->GetCount()); + if (written < 0) + { + esyslog("dxr3: unable to play audio frame: %m"); + // TODO: Resuscitation() ? + } + else if (written != pFrame->GetCount()) + { + esyslog("dxr3: unable to play whole audio frame, skipped" + " %d bytes", pFrame->GetCount() - written); + } + } + + 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) + { + esyslog("dxr3: unable to play audio frame: %m"); + Resuscitation(); + } + else if (written != length) + { + esyslog("dxr3: unable to play whole audio frame, skipped %d bytes", + length - written); + } + } + + 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]; + // only even number of bytes are allowed + assert(!((length - LPCM_HEADER_LENGTH) % 2)); + + 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 > -1) close(m_fdControl); + if (m_fdVideo > -1) close(m_fdVideo); + if (m_fdSpu > -1) close(m_fdSpu); + if (m_fdAudio > -1) close(m_fdAudio); + m_fdControl = m_fdVideo = m_fdSpu = m_fdAudio = -1; + m_aspectRatio = UNKNOWN_ASPECT_RATIO; + m_audioMode = UNKNOWN_AUDIO_MODE; + + 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) + { + esyslog("dxr3: fatal: failed to allocate memory for em8300" + " system clock in reopen"); + exit(1); + } + + SetChannelCount(1); + m_ExternalReleased = false; + } + + Resuscitation(); + } + + Unlock(); +} + + +// tools +// ================================== +//! play black frame 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; + m_vertical = 576; + + Unlock(); +} + +// ================================== +void cDxr3Interface::ReOpenAudio() +{ + Lock(); + + if (!m_ExternalReleased) + { + if (m_fdAudio > -1) + { + int bufsize = 0; + ioctl(m_fdAudio, SNDCTL_DSP_GETODELAY, &bufsize); + usleep(bufsize / 192 * 1000); + + delete m_pClock; + close(m_fdAudio); + + m_fdAudio = Dxr3Open("_ma", + cDxr3ConfigData::Instance().GetDxr3Card(), + 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(); +} + +// ================================== +//! uploadroutine for microcode +void cDxr3Interface::UploadMicroCode() +{ + em8300_microcode_t em8300_microcode; + struct stat s; + + // try to open it + // MICROCODE comes from makefile + int UCODE = open(MICROCODE, O_RDONLY); + + if (UCODE <0) + { + esyslog("dxr3: fatal: unable to open microcode file %s: %m", + MICROCODE); + exit(1); + } + + if (fstat(UCODE, &s ) <0) + { + esyslog("dxr3: fatal: unable to fstat microcode file %s: %m", + MICROCODE); + exit(1); + } + + // read microcode + em8300_microcode.ucode = new char[s.st_size]; + if (em8300_microcode.ucode == NULL) + { + esyslog("dxr3: fatal: unable to malloc() space for microcode"); + exit(1); + } + + if (read(UCODE,em8300_microcode.ucode,s.st_size) < 1) + { + esyslog("dxr3: fatal: unable to read microcode file %s: %m", + MICROCODE); + // 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) + { + esyslog("dxr3: fatal: microcode upload failed: %m"); + // free memory to avoid memory leak + delete [] (char*) em8300_microcode.ucode; + exit(1); + } + + // free memory to avoid memory leak + delete [] (char*) em8300_microcode.ucode; +} + +// ================================== +//! config and setup device via ioctl calls +void cDxr3Interface::ConfigureDevice() +{ + uint32_t videomode = 0; + + // set video mode + if (cDxr3ConfigData::Instance().GetVideoMode() == PAL) + { + dsyslog("dxr3: configure: video mode: PAL"); + videomode = EM8300_VIDEOMODE_PAL; + } + else if (cDxr3ConfigData::Instance().GetVideoMode() == PAL60) + { + dsyslog("dxr3: configure: video mode: PAL60"); + videomode = EM8300_VIDEOMODE_PAL60; + } + else + { + dsyslog("dxr3: configure: video mode: NTSC"); + videomode = EM8300_VIDEOMODE_NTSC; + } + + // make ioctl + if (ioctl(m_fdControl, EM8300_IOCTL_SET_VIDEOMODE, &videomode) == -1) + { + esyslog("dxr3: fatal: unable to set video mode: %m"); + exit(1); + } + + // set audio mode + if (!cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + dsyslog("dxr3: configure: audio mode: analog"); + SetAudioAnalog(); + } +} + +// ================================== +//! reset whole hardware +void cDxr3Interface::Resuscitation() +{ + time_t startt = time(&startt); + time_t endt = 0; + m_ExternalReleased = true; + + dsyslog("dxr3: resuscitation: device failure or user initiated reset"); + + UploadMicroCode(); + + //NonBlockingCloseOpen(); + m_ExternalReleased = false; + + endt = time(&endt); + + if (endt - startt > 4) + { + esyslog("dxr3: fatal: reopening devices took too long"); + exit(1); + } + dsyslog("dxr3: resuscitation: reopening devices took %ld seconds", + endt - startt); + + ConfigureDevice(); +} + +// ================================== +//! pcm resampling function +void cDxr3Interface::ResampleVolume(short* pcmbuf, int size) +{ + if (m_volume == 0) + { + memset(pcmbuf, 0, size); + } + if (m_volume < 255 || m_audioChannel != AUDIO_STEREO) + { + 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++) + { + if (m_audioChannel == AUDIO_MONO_RIGHT && !(i & 0x1)) + { + pcmbuf[i] = pcmbuf[i+1]; + } + if (m_audioChannel == AUDIO_MONO_LEFT && (i & 0x1)) + { + pcmbuf[i] = pcmbuf[i-1]; + } + else if (m_volume < 255) + { + 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(); + + isyslog("dxr3: hardware reset requested"); + Resuscitation(); + + Unlock(); +} + +// set brightness/contrast/saturation +// ================================== +//! set brightness +void cDxr3Interface::SetBrightness(int value) +{ + m_bcs.brightness = value; + + if (ioctl(m_fdControl, EM8300_IOCTL_SETBCS, &m_bcs) < 0) + { + esyslog("dxr3: unable to set brightness to %d: %m", value); + } +} + +// ================================== +//! set contrast +void cDxr3Interface::SetContrast(int value) +{ + m_bcs.contrast = value; + + if (ioctl(m_fdControl, EM8300_IOCTL_SETBCS, &m_bcs) < 0) + { + esyslog("dxr3: unable to set contrast to %d: %m", value); + } +} + +// ================================== +//! set saturation +void cDxr3Interface::SetSaturation(int value) +{ + m_bcs.saturation = value; + + if (ioctl(m_fdControl, EM8300_IOCTL_SETBCS, &m_bcs) < 0) + { + esyslog("dxr3: unable to set saturation to %d: %m", value); + } +} + +// ================================== +cMutex* cDxr3Interface::m_pMutex = new cMutex; + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3interface.h b/dxr3interface.h new file mode 100644 index 0000000..c6b0cf4 --- /dev/null +++ b/dxr3interface.h @@ -0,0 +1,221 @@ +/* + * dxr3interface.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_INTERFACE_H_ +#define _DXR3_INTERFACE_H_ + +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <linux/em8300.h> +#include <sys/ioctl.h> + +#include "dxr3vdrincludes.h" +#include "dxr3configdata.h" +#include "dxr3sysclock.h" + +// ================================== +class cFixedLengthFrame; + +// ================================== +//! interafce to dxr3-card +/*! + cDxr3Interface is the interface to the dxr3 + driver and so to the card, + so this is the layer between plugin and driver. +*/ +class cDxr3Interface : public Singleton<cDxr3Interface> +{ +public: + cDxr3Interface(); + ~cDxr3Interface(); + + // main + void Start(); + void Stop(); + + // audio + void SetAudioAnalog(); + void SetAudioDigitalPCM(); + void SetAudioDigitalAC3(); + void SetVolume(int volume) + { + m_volume = volume; + } + void SetAudioChannel(int audiochannel) + { + m_audioChannel = audiochannel; + } + int GetAudioChannel(void) + { + return m_audioChannel; + } + 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); + int64_t GetPts(); + + // 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; + }; + uint32_t GetVerticalSize() const + { + return m_vertical; + } + void SetVerticalSize(uint32_t vertical) + { + m_vertical = vertical; + }; + + // 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 + + 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(); + + // set brightness/contrast/saturation + void SetBrightness(int value); + void SetContrast(int value); + void SetSaturation(int value); + +private: + // file handles + int m_fdControl; ///< filehandle for contol fifo of dxr3 card + int m_fdVideo; ///< filehandle for video fifo of dxr3 card + int m_fdAudio; ///< filehandle for audio fifo of dxr3 card + int m_fdSpu; ///< filehandle for spu fifo of dxr3 card + uint32_t m_lastSeenPts; + + // dxr3 clock + cDxr3SysClock* m_pClock; ///< clock used for sync + + uint32_t m_audioChannelCount; ///< how many channels in the current audiostream + uint32_t m_audioDataRate; ///< which rate is used for the current audiostream + int m_aspectDelayCounter; + uint32_t m_aspectRatio; ///< current used aspect ratio + uint32_t m_horizontal; ///< horizontal size of current videostream + uint32_t m_vertical; ///< vertical size of current videostream + uint32_t m_audioSampleSize; ///< how big is the sample size for the current audiostream + uint32_t m_audioMode; + uint32_t m_spuMode; + bool m_ExternalReleased; ///< is dxr3 used by e.g. mplayer? + int m_volume; ///< volumevalue (0...255) + int m_audioChannel; ///> 0=stereo, 1=left, 2=right audio channel + bool m_AudioActive; ///< is audio active? + bool m_VideoActive; ///< is video active? + bool m_OverlayActive; ///< is overlay active? + + // bcs + em8300_bcs_t m_bcs; ///< BrightnessContrastSaturation values + + // spu + //cDxr3InterfaceSpu m_SpuInterface; + + void UploadMicroCode(); + void ConfigureDevice(); + void ResampleVolume(short* pcmbuf, int size); + void Resuscitation(); + +protected: + static cMutex* m_pMutex; ///< mutex for dxr3interface + + static void Lock() + { + cDxr3Interface::m_pMutex->Lock(); + } + static void Unlock() + { + cDxr3Interface::m_pMutex->Unlock(); + } +}; + +#endif /*_DXR3_INTERFACE_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3interface_spu_encoder.c b/dxr3interface_spu_encoder.c new file mode 100644 index 0000000..405da33 --- /dev/null +++ b/dxr3interface_spu_encoder.c @@ -0,0 +1,688 @@ +/* + * dxr3interface_spu_encoder.c - encodes an OSD bitmap as subpicture + * + * Assimilated and adapted by + * Stefan Schluenss <dxr3_osd@schluenss.de> + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "dxr3interface_spu_encoder.h" +#include "dxr3tools.h" + +/* + ToDo: + - cSPUEncoder::encode_do_row: FIXME: watch this space for EOL +*/ + + +#ifdef USE_XINE_SCALER +/*======================================================================= + * + * Scaling functions taken from the xine plugin + * + */ + +#include <math.h> +#include <signal.h> +#include <string> +#include <vdr/plugin.h> + +namespace XineScaler +{ + + template <const int yInc = 1, class T = int> + class cBresenham + { + const int m_dx; + const int m_dy; + + int m_eps; + T m_y; + + public: + cBresenham(const int dy, const int dx, const int eps, T const y0 = 0) + : m_dx(dx), m_dy(dy), m_eps(eps - m_dx), m_y(y0) + { + } + + int eps() const + { + return m_eps; + } + + T step() + { + m_eps += m_dy; + while (m_eps >= 0) + { + m_eps -= m_dx; + m_y += yInc; + } + return m_y; + } + + T step(int n) + { + if (n <= 0) + return m_y; + while (--n > 0) + step(); + return step(); + } + + T stepRelative(int n = 1) + { + T const y = m_y; + return step(n) - y; + } + }; + + static uint8_t *ScaleBitmapLQ(const uint8_t *src, uint8_t *dest, int x0, + int y0, int w, int h, int ws, int hs, int x1, + int y1, int w1, int h1, + const uint8_t transparentIndex) + { + uint8_t *const screen = new uint8_t[ OSDHEIGHT * OSDWIDTH ]; + { + int x1 = x0 + w; + int y1 = y0 + h; + int x2 = OSDWIDTH; + int y2 = OSDHEIGHT; + + if (x1 > x2) + x1 = x2; + + if (y1 > y2) + y1 = y2; + + uint8_t *dst = screen; + + for (int y = 0; y < y0; y++) + { + for (int x = 0; x < x2; x++) + *dst++ = transparentIndex; + } + + for (int y = y0; y < y1; y++) + { + for (int x = 0; x < x0; x++) + *dst++ = transparentIndex; + + for (int x = x0; x < x1; x++) + *dst++ = *src++; + + for (int x = x1; x < x2; x++) + *dst++ = transparentIndex; + } + + for (int y = y1; y < y2; y++) + { + for (int x = 0; x < x2; x++) + *dst++ = transparentIndex; + } + } + + uint8_t *scaled = dest; //new uint8_t[ hs * ws ]; + { + int x2 = x1 + w1; + int y2 = y1 + h1; + + if (x2 > ws) + { + x2 = ws; + w1 = x2 - x1; + if (w1 < 0) + w1 = 0; + } + + if (y2 > hs) + { + y2 = hs; + h1 = y2 - y1; + if (h1 < 0) + h1 = 0; + } + + cBresenham<OSDWIDTH, uint8_t *> yyBh(2 * OSDHEIGHT, 2 * hs, hs, screen); + uint8_t *screen0 = yyBh.step(y1); //(((2 * y1 + 1) * OSDHEIGHT / hs) / 2); + + cBresenham<> xxBh0(2 * OSDWIDTH, 2 * ws, ws); + xxBh0.step(x1); //(((2 * x1 + 1) * OSDWIDTH / ws) / 2); + + uint8_t *scaled0 = scaled + y1 * OSDWIDTH; //ws; ****** + + for (int y = y1; y < y2; y++) + { + cBresenham<> xxBh(xxBh0); + int xxx = xxBh.step(0); //(((2 * x1 + 1) * OSDWIDTH / ws) / 2); + + uint8_t *screen00 = screen0 + xxx; + uint8_t *scaled00 = scaled0 + x1; + + for (int x = x1; x < x2; x++) + { + *scaled00++ = *screen00; + screen00 += xxBh.stepRelative(); + } + + scaled0 += OSDWIDTH; //ws; ******* + screen0 = yyBh.step(); + } + } + + delete [] screen; + return scaled; + } + +}; + +/*======================================================================= + * + * End of scaling functions taken from the xine plugin + * + */ +#endif /* USE_XINE_SCALER */ + + +// ================================== +// 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; +} + + +//======================================== +//Sets the palette indexes to use for one +//window taking into account the global +//palette (with colors needed by all windows) + +void cSPUEncoder::SetPalette(int numWindow, cPalette* commonPalette, + cPalette* windowPalette) +{ + int NumColors; + const tColor *Colors = windowPalette->Colors(NumColors); + if (Colors) + { + for (int i = 0; i < NumColors; i++) + { + int idx = commonPalette->Index(Colors[i] & 0x00FFFFFF); + int opacity = ((Colors[i] & 0xFF000000) >> 24) * 0xF / 0xFF; + bitmapcolor[numWindow][i] = (opacity<<4) | idx; + } + } +} + +//======================================== +//Clears the OSD bitmap + +void cSPUEncoder::Clear(void) +{ + memset(OSD_Screen, 0, sizeof(OSD_Screen)); +} + +//============================================================= +//Sets the spu palette and flushes the OSD content into the spu +int cSPUEncoder::Flush(cPalette *Palette) +{ + int NumColors; + const tColor *Colors = Palette->Colors(NumColors); + if (Colors) + { + unsigned int palcolors[16]; + for (int i = 0; i < NumColors; i++) + { + // convert AARRGGBB to AABBGGRR (the driver expected the the + // colors the wrong way, so does Rgb2YCrCb and friends) + unsigned int color = ((Colors[i] & 0x0000FF) << 16) + | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); + palcolors[i] = Tools::Rgb2YCrCb(color); + } + cDxr3Interface::Instance().SetPalette(palcolors); + } + + // calculate osd size (actually dead code) + CalculateActiveOsdArea(); + + m_encodeddata.count = 0; + EncodePixelbufRle(0, 0, OSDWIDTH, OSDHEIGHT-1, OSD_Screen, 0, + &m_encodeddata); + + dsyslog("dxr3: cSPUEncoder::Flush: OSD data size: %d", + m_encodeddata.count); + + if (m_encodeddata.count <= DATASIZE) + { + cDxr3Interface::Instance().WriteSpu((uint8_t*) &m_encodeddata, + m_encodeddata.count); + return 0; + } + else + { + esyslog("dxr3: spu: warning: SPU data size (%d) exceeds limit (%d)", + m_encodeddata.count, DATASIZE); + return -1; + } +} + +// ================================== +// stamps window content into full osd bitmap +void cSPUEncoder::CopyBlockIntoOSD(int numWindow, int linewidth, int x0, + int y0, int x1, int y1, const tIndex *data) +{ + tIndex *cp; + const tIndex *sp = data; + + if (x1 >= OSDWIDTH) + x1 = OSDWIDTH - 1; + if (y1 >= OSDHEIGHT) + y1 = OSDHEIGHT - 1; + cp = &OSD_Screen[y0 * OSDWIDTH + x0]; + + for (int y = y0; y <= y1; y++) + { + for (int x = x0; x <= x1; x++) + { + *(cp++) = bitmapcolor[numWindow][*(sp++) & 0x0f]; + } + cp += OSDWIDTH - (x1 - x0 + 1); + sp += linewidth - (x1 - x0 + 1); + } +} + +// ================================== +// 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; + +#ifdef USE_XINE_SCALER + int ws = cDxr3Interface::Instance().GetHorizontalSize(); + int hs = cDxr3Interface::Instance().GetVerticalSize(); + if (ws < 720 || hs < 576) + inbuf = XineScaler::ScaleBitmapLQ(inbuf, OSD_Screen2, 0, 0, OSDWIDTH, + OSDHEIGHT, ws, hs, 0, 0, ws, hs, + 0 /* clrTransparent */); +#else + if (cDxr3Interface::Instance().GetHorizontalSize() < 700) + { + double fac = (double)OSDWIDTH / (double)OSDWIDTH2; + ScaleOSD(fac, inbuf, 10); + inbuf = OSD_Screen2; + } +#endif /* USE_XINE_SCALER */ + + 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; +} + +#ifndef USE_XINE_SCALER +// ================================== +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); + + if (cDxr3Interface::Instance().GetHorizontalSize() < 470) + { + for (y = 0; y < OSDHEIGHT; y++) + for (s = 0, d = 0; d < OSDWIDTH; s++, d += 2) + OSD_Screen2[y * OSDWIDTH + s] = buf[y * OSDWIDTH + d]; + } + else + { + 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) + { + dline[d] = dline[d + 1]; + } + + 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]; + } + } + } +} +#endif /* not USE_XINE_SCALER */ + +// ================================== +// 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); + //check that the highlight regions data wont overflow the buffer + if (i + len + 2 > DATASIZE) + { + ed->count = DATASIZE + 1; + return; + } + + 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; +} + +// ================================== +// Stop spu display +void cSPUEncoder::StopSpu(void) +{ + uint8_t ed[10]; + /* packet size */ + ed[0] = 0; + ed[1] = 10; + + /* pointer to the SP_DCSQT */ + ed[2] = 0; + ed[3] = 4; + + /* SP_DCSQT */ + /* display duration... */ + ed[4] = 0x00; + ed[5] = 0x00; //duration before turn on command occurs (will not be used) + + /* pointer to next command block */ + ed[6] = 0; //since this is the last command block, this + ed[7] = 4;//points back to itself + + /* 0x02: stop displaying */ + ed[8] = 0x02; + + /* 0xFF: end sequence */ + ed[9] = 0xFF; + cDxr3Interface::Instance().WriteSpu(ed, 10); +} + +// ================================== +// 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); + } + */ +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3interface_spu_encoder.h b/dxr3interface_spu_encoder.h new file mode 100644 index 0000000..b3f75cc --- /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 <dxr3_osd@schluenss.de> + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _DXR3_INTERFACE_SPU_ENCODER_ +#define _DXR3_INTERFACE_SPU_ENCODER_ + +#include <stdlib.h> +#include <linux/dvb/osd.h> +#include "dxr3vdrincludes.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 + +// ================================== +// 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<cSPUEncoder> +{ +public: + cSPUEncoder(); + ~cSPUEncoder() {} + + int Flush(cPalette *Palette); + void CopyBlockIntoOSD(int numWindow, int linewidth, + int x0,int y0, int x1, int y1, const tIndex *data); + void StopSpu(void); + void SetPalette(int numWindow, cPalette* commonPalette, + cPalette* windowPalette); + void Clear(void); + +private: + cSPUEncoder(cSPUEncoder&); // no copy constructor + + // helper functions + void EncodePixelbufRle(int x, int y, int w, int h, + u_char *inbuf, int stride, encodedata *ed); +#ifndef USE_XINE_SCALER + void ScaleOSD(double fac, unsigned char* buf, unsigned char NumColors=4); +#endif + 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(); + + int bitmapcolor[8][16]; + cColorManager* m_ColorManager; + encodedata m_encodeddata; + + // 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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3multichannelaudio.c b/dxr3multichannelaudio.c new file mode 100644 index 0000000..abab4b8 --- /dev/null +++ b/dxr3multichannelaudio.c @@ -0,0 +1,784 @@ +/* + * dxr3multichannelaudio.c: + * + * taken from the AC3overDVB Patch maintained by Stefan Huelswitt + * + * + */ + +#include <malloc.h> +#include "dxr3multichannelaudio.h" +#include <vdr/ringbuffer.h> + +//#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 needed 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 = std::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 = std::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 < len; ) + { + printf("%04x:", i); + for (int j = 0; j < 16 && i < len; j++) + printf(" %02x", data[i++]); + printf("\n"); + } + } +#endif + + int used = 0; + while (used < len) + { + if (!length) // we are still searching for a header sync + { + if (!have) // buffer is empty, work without buffering + { + if (used + SYNC_SIZE < len) + { + length = SyncInfo(&data[used]); + if (length) + { + ED("Decode: sync found at offset %d (len=%d)\n", + used, length); + SyncFound(&data[used]); + used += SYNC_SIZE; + ptsDelay -= SYNC_SIZE; + continue; + } + else + { + used++; + skipped++; + } + } + else // not enough data to try a sync, buffer the rest + { + ED("Decode: buffering started\n"); + have = len - used; + memcpy(syncBuff, &data[used], have); + used += have; + ptsDelay -= have; + } + } + else // unfortunately buffer is not empty, so continue with + // buffering until sync found + { + int need = std::min(SYNC_SIZE - have, len - used); + if (need) + { + memcpy(&syncBuff[have], &data[used], need); + have += need; + used += need; + ptsDelay -= need; + } + if (have == SYNC_SIZE) + { + length = SyncInfo(syncBuff); + if (length) + { + ED("Decode: (buffered) sync found at offset %d (len=%d)\n",used-7,length); + SyncFound(syncBuff); + continue; + } + else + { + memmove(syncBuff, syncBuff + 1, SYNC_SIZE - 1); + have--; + skipped++; + } + } + } + } + else // we have a header sync and are copying data + { + int need = std::min(length - have, len - used); + if (need) + { + ED("Decode: writing %d\n", need); + PutData(&data[used], need); + have += need; + used += need; + ptsDelay -= need; + if (have == length) + { + FinishIECFrame(); + length = have = 0; + continue; + } + } + } + } + ED("Decode: leave length=%d have=%d len=%d used=%d\n", + length, have, len, used); +} + +// --- cAudioEncapsulatorAC3 -------------------------------------------------- + +class cAudioEncapsulatorAC3 : public cAudioEncapsulator { +private: + virtual int SyncInfo(const uchar *buf); + virtual void StartIECFrame(const uchar *buf, int length, uchar PTSflags, + const uchar *PTSdata); +public: + cAudioEncapsulatorAC3(cRingBufferFrame *rb, int StreamType); +}; + +cAudioEncapsulatorAC3::cAudioEncapsulatorAC3(cRingBufferFrame *rb, + int StreamType) + : cAudioEncapsulator(rb, StreamType) +{} + +int cAudioEncapsulatorAC3::SyncInfo(const uchar *buf) +{ + static const int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, + 128, 160, 192, 224, 256, 320, 384, 448, + 512, 576, 640 }; + + if ((buf[0] != 0x0B) || (buf[1] != 0x77)) /* syncword */ + return 0; + if (buf[5] >= 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. Unfortunately 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(); +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3multichannelaudio.h b/dxr3multichannelaudio.h new file mode 100644 index 0000000..d2dd40c --- /dev/null +++ b/dxr3multichannelaudio.h @@ -0,0 +1,43 @@ +#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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3nextpts.c b/dxr3nextpts.c new file mode 100644 index 0000000..b30751d --- /dev/null +++ b/dxr3nextpts.c @@ -0,0 +1,32 @@ +/* + * dxr3nextpts.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dxr3nextpts.h" + +// ================================== +cMutex* cDxr3NextPts::m_pMutex = new cMutex; + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3nextpts.h b/dxr3nextpts.h new file mode 100644 index 0000000..7aaf4e3 --- /dev/null +++ b/dxr3nextpts.h @@ -0,0 +1,85 @@ +/* + * dxr3nextpts.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3NEXTPTS_H_ +#define _DXR3NEXTPTS_H_ + +#include <unistd.h> +#include <stdint.h> +#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<cDxr3NextPts> +{ +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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3osd.c b/dxr3osd.c new file mode 100644 index 0000000..2be8398 --- /dev/null +++ b/dxr3osd.c @@ -0,0 +1,48 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/em8300.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/unistd.h> + +#include "dxr3vdrincludes.h" +#include "dxr3interface.h" + +#include "dxr3osd.h" +#include "dxr3interface_spu_encoder.h" + +#include "dxr3osd_subpicture.h" + +// ================================== +// ! create osd at (Left, Top) +cOsd *cDxr3OsdProvider::CreateOsd(int Left, int Top) +{ + return new cDxr3SubpictureOsd(Left, Top); +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3osd.h b/dxr3osd.h new file mode 100644 index 0000000..53e5d0f --- /dev/null +++ b/dxr3osd.h @@ -0,0 +1,23 @@ +#ifndef _DXR3_OSD_H_ +#define _DXR3_OSD_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3interface_spu_encoder.h" + +// ================================== +// osd plugin provider +class cDxr3OsdProvider : public cOsdProvider +{ +public: + cDxr3OsdProvider() {} + virtual cOsd *CreateOsd(int Left, int Top); +}; + +#endif /*_DXR3_OSD_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3osd_subpicture.c b/dxr3osd_subpicture.c new file mode 100644 index 0000000..65f20c3 --- /dev/null +++ b/dxr3osd_subpicture.c @@ -0,0 +1,265 @@ +#include "dxr3osd_subpicture.h" + +// Enables some time measure debugging code +// (taken from the osdteletext plugin, thanks folks) +#ifdef timingdebug +#include <sys/timeb.h> +class cTime +{ + // Debugging: Simple class to measure time + timeb start; +public: + void Start() + { + ftime(&start); + } + void Stop(char *txt) + { + timeb t; + ftime(&t); + int s = t.time-start.time; + int ms = t.millitm - start.millitm; + if (ms<0) + { + s--; + ms += 1000; + } + printf("%s: %i.%03i\n", txt, s, ms); + } +}; +#endif + +#define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 + +// ================================== +//! constructor +cDxr3SubpictureOsd::cDxr3SubpictureOsd(int Left, int Top) : cOsd(Left, Top) +{ + shown = false; + Palette = new cPalette(4); +#if VDRVERSNUM >= 10318 + last = new cTimeMs(); + last->Set(-cDxr3ConfigData::Instance().GetOsdFlushRate()); +#else + last = time_ms() - cDxr3ConfigData::Instance().GetOsdFlushRate(); +#endif + Spu = &cSPUEncoder::Instance(); + + //Clears the OSD screen image + Spu->Clear(); +} + +// ================================== +cDxr3SubpictureOsd::~cDxr3SubpictureOsd() +{ + //Remove the OSD from the screen + Spu->StopSpu(); + delete Palette; +#if VDRVERSNUM >= 10318 + delete last; +#endif +} + +// ================================== +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::Flush() +{ +#if VDRVERSNUM >= 10318 + if (last->Elapsed() < cDxr3ConfigData::Instance().GetOsdFlushRate()) + return; + last->Set(); +#else + if (time_ms() - last < cDxr3ConfigData::Instance().GetOsdFlushRate()) + return; + last = time_ms(); +#endif + +#ifdef timingdebug + cTime t; + t.Start(); +#endif + + cBitmap *Bitmap; + int oldi; + int newi; + int i; + int indexfree[16]; + int firstfree = -1; + int indexnoassigned[16]; + int firstnoassigned = -1; + bool colfree[16]; + int NumNewColors; + int NumOldColors; + + //determine the palette used by all bitmaps (without alpha channel) + + cPalette *newPalette = new cPalette(4); + for (i = 0; i < 16; i++) + colfree[i]=true; + for (i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + int nc; + const tColor *col = Bitmap->Colors(nc); + if (col) + for (int kk = 0; kk < nc; kk++) + newPalette->Index(col[kk] & 0x00FFFFFF); + } + const tColor *newColors = newPalette->Colors(NumNewColors); + const tColor *oldColors = Palette->Colors(NumOldColors); + // colors already assigned + for (newi = 0; newi < NumNewColors; newi++) + { + for (oldi = 0; oldi < NumOldColors; oldi++) + { + if (newColors[newi] == oldColors[oldi]) + { + colfree[oldi] = false; + break; + } + } + if (oldi >= NumOldColors) + { + firstnoassigned++; + indexnoassigned[firstnoassigned] = newi; + } + } + // unused colors + for (i = 0; i < NumOldColors; i++) + { + if (colfree[i]) { + firstfree++; + indexfree[firstfree] = i; + } + } + // replace unused colors with unassigned ones + for (i = 0; i <= firstnoassigned; i++) + { + newi = indexnoassigned[i]; + if (firstfree >= 0) + { + Palette->SetColor(indexfree[firstfree], newColors[newi]); + firstfree--; + } else { + Palette->Index(newColors[newi]); + } + } + delete newPalette; + + // Shove the bitmaps to the OSD global bitmap + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + 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 of 8 bits wide, and (dx * dy) also has to be a + multiple of 8. Fix driver (should be able to handle any size + bitmaps!) + This isn't actually necessary with this plugin, but since other + plugins rely on this behaviour to work correctly, I left it + here. It doesn't hurt too much. + */ + +// http://article.gmane.org/gmane.linux.vdr/21572 +//#define optimize_bitmap_transfer +#ifdef optimize_bitmap_transfer + 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--; + } + } +#else + x1 = 0; + y1 = 0; + x2 = Bitmap->Width() - 1; + y2 = Bitmap->Height() - 1; +#endif + + Spu->SetPalette(i + 1, Palette, Bitmap); + int origx = Left() + Bitmap->X0(); + int origy = Top() + Bitmap->Y0(); + Spu->CopyBlockIntoOSD(i + 1, Bitmap->Width(), origx + x1, + origy + y1, origx + x2, origy + y2, + Bitmap->Data(x1, y1)); + Bitmap->Clean(); + } + } + + Spu->Flush(Palette); + shown = true; +#ifdef timingdebug + t.Stop("cDxr3SubpictureOsd::Flush"); +#endif +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3osd_subpicture.h b/dxr3osd_subpicture.h new file mode 100644 index 0000000..33a5a81 --- /dev/null +++ b/dxr3osd_subpicture.h @@ -0,0 +1,37 @@ +#ifndef _DXR3OSD_SUBPICTURE_H_ +#define _DXR3OSD_SUBPICTURE_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3interface_spu_encoder.h" + +// ================================== +// osd interface +class cDxr3SubpictureOsd : public cOsd +{ +private: + cSPUEncoder* Spu; ///< interface to cSPUEncoder + bool shown; ///< is the osd shown? + cPalette* Palette; ///< global palette (needed by all bitmaps) +#if VDRVERSNUM >= 10318 + cTimeMs *last; +#else + int last; +#endif + +public: + cDxr3SubpictureOsd(int Left, int Top/*, int SpuDev*/); + ~cDxr3SubpictureOsd(); + + eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); + + void Flush(); +}; + +#endif /*_DXR3OSD_SUBPICTURE_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3outputthread.c b/dxr3outputthread.c new file mode 100644 index 0000000..5bfc7ac --- /dev/null +++ b/dxr3outputthread.c @@ -0,0 +1,239 @@ +/* + * dxr3outputthread.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include "dxr3outputthread.h" + +// ================================== +const int AUDIO_OFFSET = 4500; +#define SCR m_dxr3Device.GetSysClock() +// ================================== + +// ================================== +//! constructor +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) +{ + SetDescription("DXR3 audio output"); +} + +//! destructor +cDxr3AudioOutThread::~cDxr3AudioOutThread() +{ + m_buffer.Stop(); + SetStopSignal(); + Cancel(3); +} + +// ================================== +//! thread action +void cDxr3AudioOutThread::Action() +{ + bool resync = false; + uint32_t pts = 0; + + 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()) + { + m_buffer.Clear(); + m_bNeedResync = true; + } + else if (pNext) + { + if (!pts || pts < SCR) + { + if (!pts && resync) + { + continue; + } + else + { + resync = false; + } + + if (pts && (pts < SCR) && ((SCR - pts) > 5000)) + { + m_dxr3Device.SetSysClock(pts + 1 * AUDIO_OFFSET); + m_dxr3Device.PlayAudioFrame(pNext); + if (m_buffer.IsPolled()) + { + m_buffer.Clear(); + m_bNeedResync = true; + } + } + else + { + m_dxr3Device.PlayAudioFrame(pNext); + m_buffer.Pop(); + } + } + else + { + if (abs((int)pts - (int)SCR) < (AUDIO_OFFSET )) + { + m_dxr3Device.PlayAudioFrame(pNext); + m_buffer.Pop(); + } + } + } + + if ((pts > SCR && abs((int)pts - (int)SCR) > AUDIO_OFFSET)) + { + usleep(10000); + } + } +} + +// ================================== +//! constr. +cDxr3VideoOutThread::cDxr3VideoOutThread(cDxr3Interface& dxr3Device, + cDxr3SyncBuffer& buffer) : + cDxr3OutputThread(dxr3Device, buffer) +{ + SetDescription("DXR3 video output"); +} + +//! destructor +cDxr3VideoOutThread::~cDxr3VideoOutThread() +{ + m_buffer.Stop(); + SetStopSignal(); + Cancel(3); +} + +// ================================== +//! thread action +void cDxr3VideoOutThread::Action() +{ + uint32_t pts = 0; + static uint32_t lastPts = 0; + + 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) + { + m_dxr3Device.SetPts(pts); + + if (m_buffer.Available() && pNext->GetData() && + pNext->GetCount()) + { + m_dxr3Device.PlayVideoFrame(pNext); + m_buffer.Pop(); + } + } + 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 )) + { + usleep(10000); + } + } + } +} + +#undef SCR + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3outputthread.h b/dxr3outputthread.h new file mode 100644 index 0000000..8ac46ee --- /dev/null +++ b/dxr3outputthread.h @@ -0,0 +1,104 @@ +/* + * dxr3outputthread.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3pesframe.c b/dxr3pesframe.c new file mode 100644 index 0000000..8bf5fe3 --- /dev/null +++ b/dxr3pesframe.c @@ -0,0 +1,273 @@ +/* + * dxr3pesframe.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dxr3pesframe.h" + +#include <linux/em8300.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <vdr/tools.h> + +// ================================== +bool cDxr3PesFrame::ExtractNextFrame(const uint8_t* pBuf, uint32_t length) + throw (ePesFrameError) +{ + cDxr3SafeArray<uint8_t> 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++); + if (pos + 9 >= length) + { + // Corrupt stream? + m_remainingLength = 0; + return m_bValid; + } + 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<uint8_t>::eSafeArrayException ex) + { + m_bValid = false; + esyslog("dxr3: general PES error"); + throw(PES_GENERAL_ERROR); + } + + return m_bValid; +} + +// ================================== +int cDxr3PesFrame::ExtractVideoData(cDxr3SafeArray<uint8_t> esFrame) + throw (cDxr3SafeArray<uint8_t>::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; + m_staticVerticalSize = m_verticalSize = ((esFrame[i + 5] & 0x0F) << 8) | (esFrame[i + 6]); + } + } + } + return retval; +} + +// ================================== +void cDxr3PesFrame::ExtractPts(cDxr3SafeArray<uint8_t> ptsData) + throw (cDxr3SafeArray<uint8_t>::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<uint8_t> header) + throw (cDxr3SafeArray<uint8_t>::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; +uint32_t cDxr3PesFrame::m_staticVerticalSize = 576; +const uint32_t cDxr3PesFrame::MAX_PES_HEADER_SIZE = 184; + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3pesframe.h b/dxr3pesframe.h new file mode 100644 index 0000000..26e334a --- /dev/null +++ b/dxr3pesframe.h @@ -0,0 +1,268 @@ +/* + * dxr3pesframe.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3PESFRAME_H_ +#define _DXR3PESFRAME_H_ + +#include <assert.h> +#include <stdint.h> + +// ================================== +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 T> +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_verticalSize(m_staticVerticalSize), + 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; + }; + uint32_t GetVerticalSize(void) const + { + assert(m_bValid); + assert(m_pesDataType == PES_VIDEO_DATA); + return m_verticalSize; + }; + 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<uint8_t> header) + throw (cDxr3SafeArray<uint8_t>::eSafeArrayException); + void ExtractPts(cDxr3SafeArray<uint8_t> ptsData) + throw (cDxr3SafeArray<uint8_t>::eSafeArrayException); + int ExtractVideoData(cDxr3SafeArray<uint8_t> esFrame) + throw (cDxr3SafeArray<uint8_t>::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_verticalSize = m_staticVerticalSize; + 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; + uint32_t m_verticalSize; + 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; + static uint32_t m_staticVerticalSize; + +protected: + static const uint32_t MAX_PES_HEADER_SIZE; + +private: + cDxr3PesFrame(cDxr3PesFrame&); // no copy constructor + +}; + +#endif /*_DXR3PESFRAME_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3singleton.h b/dxr3singleton.h new file mode 100644 index 0000000..b289328 --- /dev/null +++ b/dxr3singleton.h @@ -0,0 +1,59 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_SINGLETON_H_ +#define _DXR3_SINGLETON_H_ + +// ================================== +//! A singleton template. +/*! + Is a nice solution to use only + one instance of a class. +*/ +template<typename T> +class Singleton +{ +protected: + Singleton() {} + virtual ~Singleton() {} + +public: + static T& Instance() + { + static T m_Instance; + return m_Instance; + } + + static T* InstanceP() + { + static T* m_InstanceP = new T; + return m_InstanceP; + } +}; + +#endif /*_DXR3_SINGLETON_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3spudecoder.c b/dxr3spudecoder.c new file mode 100644 index 0000000..1013216 --- /dev/null +++ b/dxr3spudecoder.c @@ -0,0 +1,640 @@ +/* + * dxr3spudecoder.c + * + * Copyright (C) 2004 Christian Gmeiner + * + * Orginal: + * Copyright (C) 2001.2002 Andreas Schultz <aschultz@warp10.net> + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <assert.h> +#include <string.h> +#include <inttypes.h> +#include <math.h> + +#include "dxr3spudecoder.h" +#include "dxr3interface.h" +#include "dxr3tools.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_CHG_COLCON 0x07 +#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; + } + } + dsyslog("dxr3: getminsize: (%d,%d) x (%d,%d)", + size.x1, size.y1, size.x2, size.y2); + if (size.x1 > size.x2 || size.y1 > size.y2) + return false; + 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; + } + } +} + +// ================================== +// ! constructor +cDxr3SpuDecoder::cDxr3SpuDecoder() +{ + clean = true; + scaleMode = eSpuNormal; + spu = NULL; + osd = NULL; + spubmp = NULL; + allowedShow = true; +} + +// ================================== +cDxr3SpuDecoder::~cDxr3SpuDecoder() +{ + delete spubmp; + delete spu; + delete osd; +} + +// ================================== +// ! send spu data to dxr3 +#if VDRVERSNUM >= 10318 +void cDxr3SpuDecoder::processSPU(uint32_t pts, uint8_t * buf, bool AllowedShow) +#else +void cDxr3SpuDecoder::processSPU(uint32_t pts, uint8_t * buf) +#endif +{ + setTime(pts); + dsyslog("dxr3: spudec push: pts=%d", pts); + + delete spubmp; + spubmp = NULL; + delete[]spu; + spu = buf; + spupts = pts; + + DCSQ_offset = cmdOffs(); + prev_DCSQ_offset = 0; + + clean = true; +#if VDRVERSNUM >= 10318 + allowedShow = AllowedShow; +#endif +} + +// ================================== +// ! get scalemode +cSpuDecoder::eScaleMode cDxr3SpuDecoder::getScaleMode(void) +{ + return scaleMode; +} + +// ================================== +// ! set scalemode +void cDxr3SpuDecoder::setScaleMode(cSpuDecoder::eScaleMode ScaleMode) +{ + scaleMode = ScaleMode; +} + +// ================================== +// ! send palette to dxr3 +void cDxr3SpuDecoder::setPalette(uint32_t * pal) +{ + palette.setPalette(pal); +} + +// ================================== +// ! send highlight to dxr3 +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) + { + dsyslog("dxr3: spu highlight: %d, %d, %d, %d", sx, sy, ex, ey); + + hlpsize.x1 = sx; + hlpsize.y1 = sy; + hlpsize.x2 = ex; + hlpsize.y2 = ey; + memcpy(hlpDescr, pld, sizeof(aDxr3SpuPalDescr)); + highlight = true; + clean = false; + } +} + +// ================================== +// ! clear highlight +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; +} + +// ================================== +// ! draw nav, subtitles, ... +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) + { + esyslog("dxr3: could not instantiate new OSD"); + return; + } + + if (fg) + { + DrawBmp(hlsize, fg); + } + + if (bg) + { + DrawBmp(bgsize, bg); + } + + osd->Flush(); + } + + clean = true; +} + +// ================================== +// ! hide nav, subtitles, ... +void cDxr3SpuDecoder::Hide() +{ + delete osd; + osd = NULL; +} + +// ================================== +// ! clear highlight and osd +void cDxr3SpuDecoder::Empty() +{ + Hide(); + + delete spubmp; + spubmp = NULL; + + delete[]spu; + spu = NULL; + + clearHighlight(); + clean = true; +} + +// ================================== +// ! set pts +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 + dsyslog("dxr3: spu show"); + state = spSHOW; + i++; + break; + + case CMD_SPU_HIDE: + // hide subpicture + dsyslog("dxr3: spu hide"); + 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]; + + dsyslog("dxr3: spu size (%d,%d) x (%d,%d)", + size.x1, size.y1, size.x2, size.y2); + i += 7; + break; + + case CMD_SPU_SET_PXD_OFFSET: + // image 1 / image 2 offsets + fodd = spuU32(i + 1); + feven = spuU32(i + 3); + + dsyslog("dxr3: spu offset: odd=%d, even=%d", fodd, feven); + i += 5; + break; + + case CMD_SPU_CHG_COLCON: + { + int size = spuU32(i + 1); + i += 1 + size; + } + break; + + case CMD_SPU_MENU: + dsyslog("dxr3: spu menu"); + state = spMENU; + i++; + break; + + default: + esyslog("dxr3: invalid sequence in control header (%.2x)", + 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 && allowedShow) || state == spMENU) + { + Draw(); + } + + if (state == spHIDE) + { + Hide(); + } + + if (pts == 0) + { + return 0; + } + } + + return 1; +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3spudecoder.h b/dxr3spudecoder.h new file mode 100644 index 0000000..9f5adb1 --- /dev/null +++ b/dxr3spudecoder.h @@ -0,0 +1,190 @@ +/* + * dxr3spudecoder.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3SPUDECODER_H_ +#define _DXR3SPUDECODER_H_ + +#include "dxr3vdrincludes.h" +#include <inttypes.h> + +// ================================== +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); + + cSpuDecoder::eScaleMode getScaleMode(void); + 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(); +#if VDRVERSNUM >= 10318 + void processSPU(uint32_t pts, uint8_t * buf, bool AllowedShow); +#else + void processSPU(uint32_t pts, uint8_t * buf); +#endif + + void Hide(); + void Draw(); + bool IsVisible() + { + return osd != NULL; + } + +private: + cOsd * osd; + + // processing state + uint8_t *spu; + uint32_t spupts; + bool clean; + bool ready; + bool allowedShow; + + 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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3syncbuffer.c b/dxr3syncbuffer.c new file mode 100644 index 0000000..66be71b --- /dev/null +++ b/dxr3syncbuffer.c @@ -0,0 +1,496 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* + ToDo: + - cDxr3SyncBuffer::Push: XXX This is only a workaround until a + sufficient control algorithm is implemented +*/ + +#include <unistd.h> +#include <sys/time.h> +#include "dxr3syncbuffer.h" + +const int DXR3_MAX_VIDEO_FRAME_LENGTH = 4096; +const int DXR3_MAX_AUDIO_FRAME_LENGTH = 4096; + +// ================================== +//! constructor +cFixedLengthFrame::cFixedLengthFrame() : + m_count(0), m_length(0), m_pts(0), m_type(ftUnknown) +{ + + m_audioChannelCount = UNKNOWN_CHANNEL_COUNT; + m_audioDataRate = UNKNOWN_DATA_RATE; + m_videoAspectRatio = UNKNOWN_ASPECT_RATIO; +} + +// ================================== +cFixedLengthFrame::~cFixedLengthFrame() +{ + if (m_pData) + { + delete[] m_pData; + } +} + +// ================================== +// ! setup our frame +void cFixedLengthFrame::Init(uint32_t lenght) +{ + m_length = lenght; + m_pData = new uint8_t[lenght]; + + // allocation ok? + if (!m_pData) + { + esyslog("dxr3: fatal: unable to allocate memory for new frame"); + exit(1); + } +} + +// ================================== +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; + 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; + + +// ================================== +//! constructor +cDxr3SyncBuffer::cDxr3SyncBuffer(int frameCount, int frameLength, + cDxr3Interface& dxr3Device) : + cRingBuffer(frameCount, true), m_dxr3Device(dxr3Device) +{ + m_pBuffer = new cFixedLengthFrame[frameCount]; + + // got we a valid m_pBuffer? + if (!m_pBuffer) + { + esyslog("dxr3: fatal: unable to allocate memory for new frame"); + exit(1); + } + + // init our new m_pBuffer; + for (int i = 0; i < frameCount; i++) + { + m_pBuffer[i].Init(frameLength); + } + + // set some default values + 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; +#if VDRVERSNUM < 10313 + Lock(); +#endif + ret = m_count; +#if VDRVERSNUM < 10313 + Unlock(); +#endif + 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(); + struct timeval tv_start, tv; + m_bPollSync = true; + gettimeofday(&tv_start, NULL); + 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))) + { + int d_s, d_us, ms; + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + gettimeofday(&tv, NULL); + d_s = tv.tv_sec - tv_start.tv_sec; + d_us = tv.tv_usec - tv_start.tv_usec; + ms = d_s * 1000 + d_us / 1000; + if (ms > TimeoutMs * 2) { + esyslog("dxr3: sync: secondary timeout"); + break; + } + } + 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; + struct timeval tv_start, tv; + gettimeofday(&tv_start, NULL); + + 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)) + { + int d_s, d_us, ms; + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + gettimeofday(&tv, NULL); + d_s = tv.tv_sec - tv_start.tv_sec; + d_us = tv.tv_usec - tv_start.tv_usec; + ms = d_s * 1000 + d_us / 1000; + if (ms > 2000) { + esyslog("dxr3: sync: push timeout"); + return NULL; + } + } + +#if VDRVERSNUM < 10313 + Lock(); +#endif + 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) + { + esyslog("dxr3: sync: push buffer overrun"); + 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; + } + } +#if VDRVERSNUM < 10313 + Unlock(); +#endif + break; + } + + return &m_pBuffer[lastIndex]; +} + +// ================================== +void cDxr3SyncBuffer::Pop(void) +{ +#if VDRVERSNUM < 10313 + Lock(); +#endif + 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(); +#if VDRVERSNUM < 10313 + Unlock(); +#endif +} + +// ================================== +cFixedLengthFrame* cDxr3SyncBuffer::Get(void) +{ + cFixedLengthFrame* pRet = 0; + + if (!m_bStopped) + { + while ((!Available() || !m_bStartReceiver) && !m_bStopped) + { + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + +#if VDRVERSNUM < 10313 + Lock(); +#endif + if (m_nextFree != m_next) + { + pRet = &m_pBuffer[m_next]; + } +#if VDRVERSNUM < 10313 + Unlock(); +#endif + } + else + { + WaitForGet(); + } + + return pRet; +} + +// ================================== +void cDxr3SyncBuffer::Clear(void) +{ +#if VDRVERSNUM < 10313 + Lock(); +#endif + 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(); +#if VDRVERSNUM < 10313 + Unlock(); +#endif +} + +// ================================== +void cDxr3SyncBuffer::WaitForSysClock(uint32_t pts, uint32_t delta) +{ + m_waitPts = pts; + m_waitDelta = delta; + if (!m_bPutBlock) + { +#if VDRVERSNUM < 10313 + Lock(); +#endif + m_bWaitPts = true; +#if VDRVERSNUM < 10313 + Unlock(); +#endif + 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) +{ +#if VDRVERSNUM < 10313 + Lock(); +#endif + 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; + } + } + } +#if VDRVERSNUM < 10313 + Unlock(); +#endif +} + +// ================================== +void cDxr3SyncBuffer::WaitForReceiverStopped(void) +{ + if (!m_bGetBlock) + { + receiverStoppedMutex.Lock(); + receiverStopped.Wait(receiverStoppedMutex); + receiverStoppedMutex.Unlock(); + } +} + +// ================================== +void cDxr3SyncBuffer::ReceiverStopped(void) +{ + receiverStopped.Broadcast(); +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3syncbuffer.h b/dxr3syncbuffer.h new file mode 100644 index 0000000..01ae9b8 --- /dev/null +++ b/dxr3syncbuffer.h @@ -0,0 +1,198 @@ +/* + * dxr3syncbuffer.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3SYNCBUFFER_H_ +#define _DXR3SYNCBUFFER_H_ + +#include <stdint.h> + +#include "dxr3vdrincludes.h" +#include "dxr3interface.h" +#include "dxr3generaldefines.h" +#include "dxr3nextpts.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: + cFixedLengthFrame(); + ~cFixedLengthFrame(); + + void Init(uint32_t lenght); + + 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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3sysclock.c b/dxr3sysclock.c new file mode 100644 index 0000000..189ac0b --- /dev/null +++ b/dxr3sysclock.c @@ -0,0 +1,77 @@ +/* + * dxr3sysclock.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <sys/ioctl.h> +#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(); +} + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3sysclock.h b/dxr3sysclock.h new file mode 100644 index 0000000..0f1396e --- /dev/null +++ b/dxr3sysclock.h @@ -0,0 +1,66 @@ +/* + * dxr3sysclock.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_SYSCLOCK_H_ +#define _DXR3_SYSCLOCK_H_ + +#include "dxr3vdrincludes.h" +#include <linux/em8300.h> + +// ================================== +// 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_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3tools.h b/dxr3tools.h new file mode 100644 index 0000000..971859c --- /dev/null +++ b/dxr3tools.h @@ -0,0 +1,109 @@ +/* + * dxr3tools.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3TOOLS_H_ +#define _DXR3TOOLS_H_ + +#include "dxr3vdrincludes.h" + +namespace Tools +{ + // ================================== + //! convert Rgb to CrCb + 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; + } + + // ================================== + //! convert YUV to Rgb + 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); + } + + // ================================== + //! write a string via vdr to OSD + inline void WriteInfoToOsd(std::string x) + { + Skins.Message(mtInfo, x.c_str()); + } + +} + +#endif /*_DXR3TOOLS_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: diff --git a/dxr3vdrincludes.h b/dxr3vdrincludes.h new file mode 100644 index 0000000..23ce128 --- /dev/null +++ b/dxr3vdrincludes.h @@ -0,0 +1,58 @@ +/* + * dxr3vdrincludes.h + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _DXR3_VDRINCLUDES_H_ +#define _DXR3_VDRINCLUDES_H_ + +#include <string> +#include <algorithm> +#include <vector> + +#ifndef __STL_CONFIG_H +#define __STL_CONFIG_H +#define __DXR3_UNDEF_STL_CONFIG_AFTERWARDS +#endif + +// all includes from vdr +#include <vdr/osd.h> +#include <vdr/config.h> +#include <vdr/thread.h> +#include <vdr/ringbuffer.h> +#include <vdr/spu.h> +#include <vdr/tools.h> +#include <vdr/device.h> +#include <vdr/status.h> +#include <vdr/plugin.h> +#include <vdr/audio.h> + +#ifdef __DXR3_UNDEF_STL_CONFIG_AFTERWARDS +#undef __STL_CONFIG_H +#endif + +#endif /*_DXR3_VDRINCLUDES_H_*/ + +// Local variables: +// mode: c++ +// c-file-style: "stroustrup" +// c-file-offsets: ((inline-open . 0)) +// indent-tabs-mode: t +// End: |