diff options
author | austriancoder <austriancoder> | 2004-08-05 23:05:21 +0000 |
---|---|---|
committer | austriancoder <austriancoder> | 2004-08-05 23:05:21 +0000 |
commit | c47666d42f7972e1b51f9de61ce0fa27c72f3127 (patch) | |
tree | e34a87e37901b7f892fb6f330ccb15bcba30039b | |
download | vdr-plugin-dxr3-c47666d42f7972e1b51f9de61ce0fa27c72f3127.tar.gz vdr-plugin-dxr3-c47666d42f7972e1b51f9de61ce0fa27c72f3127.tar.bz2 |
initial import
58 files changed, 12157 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. @@ -0,0 +1,230 @@ +VDR Plugin 'dxr3' Revision History +---------------------------------- + +2002-08-04: Version 0.0.1 + +- Initial revision. + +2002-11-10: Version 0.1.0 + +- Rewritten Audio/Video-sync engine +- Changed OSD colors (but still limited to four colors) + +2002-11-12: Version 0.1.1 + +- Changed Makefile (needed for vdr 1.1.15) +- The plugin should now work smoother under heavy system load (e.g. network traffic) + +2002-12-23: Version 0.1.2 +- Compiles now with gcc3.2. +- Fixed unsigned / signed bug in output thread (dxr3outputthread.c) which led +to sporadic resync (still frame and jump of about 1s). +- OSD is now as colorful as vdr with DVB-s +- OSD rescaling for channels with a lower horizontal resolution + +2002-12-29: Version 0.1.3 +- SPU write is now protected with a mutex by using the Dxr3AbstractionDevice. +- Fixed horizontal size detection. +- Added usleep call during still picture to reduce cpu load. +- Removed calls to WaitForSysClock in dxr3outputthread.c which led to problems +during replay on some systems (Thanks to Atte Manninen for reporting this). +- Did some minor changes to dxr3outputthread.c which hopefully will increase +reliability. +- Changed osd scale rule. Scaling now only happens if the horizontal size is +smaller than 700. + +2003-01-05: Version 0.1.4 +- Small bugfix in dxr3demuxdevice.c + +2003-02-19: Version 0.1.5 +- Support for MP3 plugin. +- Support for radio channels. Requested by Richard P. (???) who send me a + sample code ... thanks. +- Some fixes to get along with corrupt pes data (which should actually be + solved in a lower layer). Thanks to Teemu Rantanen. +- Changed sync buffer size during replay to reduce "jumps" in cutted streams. + Thanks to Atte Manninen for the idea. +- Support for still frame handling. Now it is possible to move the editing + marks with visible corresponding i-frames. Unfortunately this doesn't seem to + work with finish dvb streams. +- Some tuning to reduce cpu load during replay. + +2003-02-25: Version 0.1.6 +- Added black frames between channel switches (which solves the frozen picture + 'problem' when using the mp3-plugin, too). +- Increased thread priority of output threads which improves live stream + quality on my system (K6II 350). + +2003-03-23: Version 0.1.7 +- Added unix domain server interface to close and reopen dxr3 devices without + stopping vdr (see dxr3_ux_client.pl script on how to use this). + Requested by Atte Manninen. + Thanks to Atte Manninen and Teemu Rantanen for testing and fixing some problems. +- Added support for external player mode. +- Some cosmetic changes. +- Some changes to reduce cpu load. +- Added workaround handling for osd crash (driver patch necessary; patch with + em8300_patch.diff). + Thanks to Teemu Rantanen and Malcolm Caldwell for testing this. +- Added buffered output for mp3-plugin audio data. This seems to improve audio + quality significantly. +- Reduced count of audio errors (wrong data rate). +- Changed channel switch behavior (to remove audio disturbances => channel switching + is a little bit slower now). +- Added exception handling for defect pes streams. +- Added more checks by introducing a new pes parsing class. +- Fixed buffer overrun problem. Because of the missing pll control a buffer overrun + happens after staying for a long time on the same channel. In older version + the output stopped after a buffer overrun. Now the buffer will be cleared and + the output will continue after about a second. +- New buffer handling in PlayVideo. + +2003-03-23: Version 0.1.7a +- Bugfix in A/V-engine for audio output with less dropouts + +2003-04-28: Version 0.1.8 +- Added support for dvd-plugin (subtitles doesn't work properly so far). +- Added setup parameter to define the dxr3-card which shall be used by vdr + (thanks to Tobias Haustein). +- Added setup parameter to force letter box mode (for wrong aspect ratio coded + in pes-stream). This parameter is not saved. +- Added support for video format setup parameter (no WSS support). +- Fixed external player support (thanks to Seppo Ingalsuo). +- Added volume support (thanks to Teemu Rantanen). +- Fixed I-Frame display problem (cutting and fast forward/backwards in some streams). + Those who have problems with fast forward/backward might want to patch + vdr (use vdr_iframe_patch.diff / for vdr-1.1.29). +- Reduced memory consumption. +- Fixed problem with digital output setup parameter. +- Fixed wrong bit error detection. +- Changed bit error handling. + +2003-04-28: Version 0.1.8a +- Second trial to fix external player support (thanks to Jarkko Santala) + +2003-05-07: Version 0.1.9 +- Added support for AC3 streams (based on classes of + the AC3overDVB Patch maintained by Stefan Huelswitt). +- Added DXR3 main menu entry. It's now possible to: + - Reset DXR3-hardware. + - Toggle Force LetterBox. + - Switch to Digital Output. + - Switch to AC3 Output (when already listening to digital output). +- Added short ac3 information text on channel switch. +- Reduced analog audio disturbances. +- Fixed audio initialization problem. + +2003-05-07: Version 0.2.0 +- Fixed compatibility problem with vdr version 1.1.31 and higher. +- Fixed analog audio problem (spurious disturbances). +- Added first cut mpeg1 support: It works quite good with vcd plugin. As far as I know + this doesn't work reliable together with analog plugin. Thanks to Gavin Hamill for + testing support and investigations with analog plugin. + No osd scaling for mpeg1 at the moment. +- Changed channel switch behavior with respect to mpeg1 support (it doesn't seem + to be possible to switch between mpeg1 and mpeg2 without closing and reopening the + video device). +- Improved lib sync. + +2003-08-10: Version 0.2.1 +- Added setup entry to switch between ntsc and pal. This setting becomes active + after restarting vdr and reseting the dxr3 card, respectively. +- Fixed uninitialized variable m_audioMode in dxr3abstractiondevice.c. Thanks + to Jon Burgess. +- Fixed incorrect ioctl-problem. Thanks to Jon Burgess. +- Fixed wrong scaled osd problem when starting vdr without live stream. +- Fixed external player problem when return to dxr3 output after using ac3 output. + Thanks to Jarkko Santala for reporting this one. +- Fixed wrong assert-call. Thanks to Andre Neumann. + +2004-01-04: Version 0.2.2 + +- Some initialization fixes. Thanks to Jon Burgess. +- Added patch from Teemu Rantanen to emergency exit if + the plugin is not able to recover from dxr3 driver crash. +- Fixed some osd problems (Elchi, Games, etc.). +- Changed Makefile to support vdr-1.3.0. + +2004-06-22: Version 0.2.3-alpha1 (only for vdr-portal.de) + +- we are using now <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> @@ -0,0 +1,18 @@ +Prerequisites: + +- Make sure your DXR3 card is running under linux. For more information look at the "http://dxr3.sourceforge.net" + You should modify the dxr3-driver by applying the delivered patch with "patch -p1 -R < em8300_patch.diff" in + the dxr3/modules directory. + +- Install the (latest) VDR developer version +- The plugin needs the libavcodec library from "http://ffmpeg.sourceforge.net" + +Installation: + +- Get the latest dxr3-plugin version from "http://www.schluenss.de/dxr3.html" +- Get the current CVS of the dxr3 drivers from dxr3.sf.net +- Unpack the package into "PLUGINS/SRC" directory +- Make a symbolic link to this dxr3-plugin (ln -s vdr_dxr3_x.x.x dxr3) +- Call "make plugins" in the VDR root directory +- Make sure your DXR3 driver modules are loaded and ready to run +- Start VDR with "vdr -Pdxr3" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7d9fa05 --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.1 2004/08/05 23:05:21 austriancoder Exp $ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = dxr3 + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: + +CXX = g++ +CXXFLAGS = -O2 -Wall -Woverloaded-virtual + +### The directory environment: + +##DVBDIR = ../../../../DVB +##VDRDIR = ../../.. +##LIBDIR = ../../lib +##TMPDIR = /tmp +##FFMDIR = ../../../../ffmpeg +### LIBMP3DIR = /usr/lib + +DVBDIR = /usr/src/linux +VDRDIR = /usr/include/vdr +LIBDIR = /usr/lib +TMPDIR = /tmp +FFMDIR = /usr/include/ffmpeg +EM8300 = /usr/include + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR (taken from VDR's "config.h"): + +VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -I$(FFMDIR) -I$(EM8300) +LIBS = -L$(FFMDIR)/libavcodec -lavcodec -ljpeg +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -DSOCKET_CHMOD=0660 +DEFINES += -D_GNU_SOURCE + +### The object files (add further files here): + +OBJS = $(PLUGIN).o dxr3multichannelaudio.o dxr3sysclock.o dxr3colormanager.o dxr3syncbuffer.o dxr3audiodecoder.o \ +dxr3blackframe.o dxr3palettemanager.o dxr3nextpts.o dxr3pesframe.o dxr3demuxdevice.o dxr3configdata.o \ +dxr3log.o dxr3ffmpeg.o dxr3interface_spu_encoder.o dxr3i18n.o \ +dxr3interface.o dxr3device.o dxr3outputthread.o dxr3osd.o dxr3osd_subpicture.o dxr3spudecoder.o dxr3unixserversocket.o \ +dxr3cpu.o dxr3memcpy.o + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +all: libvdr-$(PLUGIN).so + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -lz -shared $(OBJS) $(LIBS) -o $@ + @cp $@ $(LIBDIR)/$@.$(VDRVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ @@ -0,0 +1,14 @@ +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> + +Project's homepage: http://www.schluenss.de/DXR3.html + +Latest version available at: see homepage + +See the file COPYING for license information. + +Description: DXR3/Hollywod+ MPEG decoder card plugin which allows using such a + card as primary interface for VDR. + @@ -0,0 +1,189 @@ +/* +* dxr3.c: A plugin for the Video Disk Recorder +* +* See the README file for copyright information and how to reach the author. +* +* $Id: dxr3.c,v 1.1 2004/08/05 23:05:21 austriancoder Exp $ +*/ + + +#include "dxr3vdrincludes.h" +#include "dxr3device.h" +#include "dxr3syncbuffer.h" +#include "dxr3configdata.h" +#include "dxr3interface.h" +#include "dxr3.h" + +static const char *VERSION = "0.2.3-pre3-cvs"; +static const char *DESCRIPTION = "DXR3-MPEG decoder plugin"; +static const char *MAINMENUENTRY = "DXR3"; + +#include "dxr3cpu.h" + +// ================================== +// 'message-handler' for the main screen +eOSState cDxr3OsdItem::ProcessKey(eKeys Key) +{ + if (Key == kOk) + { + switch (m_item) + { + case DXR3_RESET_HARDWARE: + cDxr3Interface::Instance().ResetHardware(); + cDxr3Device::Instance().Reset(); + break; + + case DXR3_FORCE_LETTER_BOX: + cDxr3ConfigData::Instance().SetForceLetterBox(!cDxr3ConfigData::Instance().GetForceLetterBox()); + break; + + case DXR3_ANALOG_OUT: + cLog::Instance() << "Changing audio to analog\n"; + cDxr3ConfigData::Instance().SetUseDigitalOut(0); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + cDxr3Device::Instance().Reset(); + break; + + case DXR3_DIGITAL_OUT: + cLog::Instance() << "Changing audio to digital\n"; + cDxr3ConfigData::Instance().SetUseDigitalOut(1); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + cDxr3Device::Instance().Reset(); + break; + + case DXR3_AC3_OUT: + cLog::Instance() << "Changing audio to ac3\n"; + cDxr3ConfigData::Instance().SetAc3OutPut(!cDxr3ConfigData::Instance().GetAc3OutPut()); + cDxr3Device::Instance().Reset(); + break; + } + } + + return Key == kOk ? osBack : cOsdItem::ProcessKey(Key); +} + +// ================================== +// setup menu +cMenuSetupDxr3::cMenuSetupDxr3(void) +{ + newUseDigitalOut = cDxr3ConfigData::Instance().GetUseDigitalOut(); + Add(new cMenuEditBoolItem(tr("Digital audio output"), &newUseDigitalOut)); + newDxr3Card = cDxr3ConfigData::Instance().GetDxr3Card(); + Add(new cMenuEditIntItem(tr("DXR3 card"), &newDxr3Card)); + newVideoMode = (int) cDxr3ConfigData::Instance().GetVideoMode(); + Add(new cMenuEditStraItem(tr("DXR3 video mode"), &newVideoMode, 3, menuVideoModes)); + newDebug = (int) cDxr3ConfigData::Instance().GetDebug(); + Add(new cMenuEditBoolItem(tr("Debug mode"), &newDebug)); + newDebugLevel = (int) cDxr3ConfigData::Instance().GetDebugLevel(); + Add(new cMenuEditStraItem(tr("Debug level"), &newDebugLevel, 2, menuDebugModes)); +} + +// ================================== +// save menu values +void cMenuSetupDxr3::Store(void) +{ + SetupStore("UseDigitalOut", cDxr3ConfigData::Instance().SetUseDigitalOut(newUseDigitalOut)); + SetupStore("Dxr3Card", cDxr3ConfigData::Instance().SetDxr3Card(newDxr3Card)); + SetupStore("Dxr3VideoMode", cDxr3ConfigData::Instance().SetVideoMode((eVideoMode) newVideoMode)); + SetupStore("Dxr3Debug", cDxr3ConfigData::Instance().SetDebug(newDebug)); + SetupStore("Dxr3DebugLevel", cDxr3ConfigData::Instance().SetDebugLevel(newDebugLevel)); +} + +// ================================== +class cPluginDxr3 : public cPlugin +{ +private: + // Add any member variables or functions you may need here. +public: + cPluginDxr3(); + ~cPluginDxr3(); + const char *Version() { return VERSION; } + const char *Description() { return DESCRIPTION; } + const char *CommandLineHelp(); + bool ProcessArgs(int argc, char *argv[]); + bool Initialize(); + bool Start(); + void Housekeeping(); + cMenuSetupPage *SetupMenu(); + bool SetupParse(const char *Name, const char *Value); + const char* MainMenuEntry(); + cOsdObject* MainMenuAction(); +}; + +// ================================== +cPluginDxr3::cPluginDxr3() +{ + // Initialize any member varaiables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! + cDxr3ConfigData::Instance(); +} + +// ================================== +cPluginDxr3::~cPluginDxr3() +{ +} + +// ================================== +const char *cPluginDxr3::CommandLineHelp() +{ + return NULL; +} + +// ================================== +bool cPluginDxr3::ProcessArgs(int argc, char *argv[]) +{ + return true; +} + +// ================================== +bool cPluginDxr3::Start() +{ + return true; +} + +// ================================== +bool cPluginDxr3::Initialize() +{ + new cDxr3CPU(); + cDxr3Device::Instance(); + return true; +} + +// ================================== +void cPluginDxr3::Housekeeping() +{ +} + +// ================================== +cMenuSetupPage* cPluginDxr3::SetupMenu() +{ + return new cMenuSetupDxr3(); +} + +// ================================== +bool cPluginDxr3::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + if (!strcasecmp(Name, "UseDigitalOut")) { cDxr3ConfigData::Instance().SetUseDigitalOut(atoi(Value)); return true; } + if (!strcasecmp(Name, "Dxr3Card")) { cDxr3ConfigData::Instance().SetDxr3Card(atoi(Value)); return true; } + if (!strcasecmp(Name, "Dxr3Debug")) { cDxr3ConfigData::Instance().SetDebug(atoi(Value)); return true; } + if (!strcasecmp(Name, "Dxr3VideoMode")) { cDxr3ConfigData::Instance().SetVideoMode((eVideoMode) atoi(Value)); return true;} + if (!strcasecmp(Name, "Dxr3DebugLevel")) { cDxr3ConfigData::Instance().SetDebugLevel(atoi(Value)); return true;} + + return false; +} + +// ================================== +const char* cPluginDxr3::MainMenuEntry() +{ + return tr(MAINMENUENTRY); +} + +// ================================== +cOsdObject* cPluginDxr3::MainMenuAction() +{ + return new cDxr3OsdMenu; +} + +VDRPLUGINCREATOR(cPluginDxr3); // Don't touch this! @@ -0,0 +1,107 @@ +#ifndef _DXR3_H_ +#define _DXR3_H_ + +// --- cMenuSetupDxr3 ------------------------------------------------------- +const char* menuVideoModes[] = +{ + "PAL", + "PAL60", + "NTSC" +}; + +// debug modes +const char* menuDebugModes[] = +{ + "Low", + "Everything" +}; + +// ================================== +// setup screen +class cMenuSetupDxr3 : public cMenuSetupPage +{ +public: + cMenuSetupDxr3(); + +protected: + virtual void Store(); + +private: + int newUseDigitalOut; + int newDxr3Card; + int newVideoMode; + int newDebug; + int newDebugLevel; +}; + + +// ================================== +enum eDxr3OsdItem +{ + DXR3_RESET_HARDWARE, + DXR3_FORCE_LETTER_BOX, + DXR3_DIGITAL_OUT, + DXR3_ANALOG_OUT, + DXR3_AC3_OUT +}; + +// ================================== +// osd item +class cDxr3OsdItem : public cOsdItem +{ +public: + cDxr3OsdItem(const char* text, eDxr3OsdItem item) : cOsdItem(text), m_item(item) {} + + // process fb input + eOSState ProcessKey(eKeys Key); + +protected: + eDxr3OsdItem m_item; +}; + +// ================================== +// main screen +class cDxr3OsdMenu : public cOsdMenu +{ +public: + cDxr3OsdMenu(): cOsdMenu("DXR3 Adjustment") + { + Clear(); + SetHasHotkeys(); + Add(new cDxr3OsdItem(hk("Reset DXR3 Hardware"), DXR3_RESET_HARDWARE)); + Add(new cDxr3OsdItem(hk("Toggle Force LetterBox"), DXR3_FORCE_LETTER_BOX)); + + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + Add(new cDxr3OsdItem(hk("Analog Output"), DXR3_ANALOG_OUT)); + } + else + { + Add(new cDxr3OsdItem(hk("Digital Output"), DXR3_DIGITAL_OUT)); + } +/* + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + Add(new cDxr3OsdItem(hk("Analog Output"), DXR3_ANALOG_OUT)); + + if (cDxr3ConfigData::Instance().GetAc3OutPut()) + { + Add(new cDxr3OsdItem(hk("AC3 Output Off"), DXR3_AC3_OUT)); + } + else + { + if (cDxr3Interface::Instance().IsAc3Present()) + { + Add(new cDxr3OsdItem(hk("AC3 Output On"), DXR3_AC3_OUT)); + } + } + } + else + { + Add(new cDxr3OsdItem(hk("Digital Output"), DXR3_DIGITAL_OUT)); + } + */ + } +}; + +#endif /*_DXR3_H_*/ diff --git a/dxr3audiodecoder.c b/dxr3audiodecoder.c new file mode 100644 index 0000000..c7fb3a7 --- /dev/null +++ b/dxr3audiodecoder.c @@ -0,0 +1,296 @@ +/* + * dxr3audiodecoder.c + * + * Copyright (C) 2002-2004 Kai Möller + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +/* +ToDo: + - cDxr3AudioDecoder::Init: Why are we always reinit the codec? +*/ + + +#include <stdio.h> +#include "dxr3audiodecoder.h" +#include "dxr3pesframe.h" + +// ================================== +const int LPCM_HEADER_LENGTH = 7; + +// ================================== +// constr. +cDxr3AudioDecoder::cDxr3AudioDecoder() : rbuf(50000), ac3dtsDecoder(&rbuf) +{ + decoderOpened = false; + audioSynched = false; + volume = 255; + Codec.id = CODEC_ID_MP2; + + Init(); + + lastHeader[0] = 0xFF; + lastHeader[1] = lastHeader[2] = lastHeader[3] = 0; +}; + +// ================================== +// deconst. +cDxr3AudioDecoder::~cDxr3AudioDecoder() +{ + // close codec, if it is open + cDxr3Ffmepg::Instance().CloseCodec(Codec); +}; + +// ================================== +// (re)init ffmpeg codec +void cDxr3AudioDecoder::Init() +{ + // (re)init codec + cDxr3Ffmepg::Instance().CloseCodec(Codec); + if (cDxr3Ffmepg::Instance().FindCodec(Codec)) + { + cDxr3Ffmepg::Instance().OpenCodec(Codec); + rate = channels = -1; + frameSize = Codec.codec_context.frame_size; + decoderOpened = true; + foundHeader = false; + decodeAudio = true; + + //lastHeader[0] = 0xFF; + //lastHeader[1] = lastHeader[2] = lastHeader[3] = 0; + } + else + { + decoderOpened = false; + } +} + +// ================================== +// decode given buffer +void cDxr3AudioDecoder::Decode(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf) +{ + if (!decoderOpened) + { + // No decoder is open, so it + // is better to stop here. + return; + } + + int len; + int out_size; + + enum audioException + { + WRONG_LENGTH, + UNEXPECTED_PARAMETER_CHANGE + }; + + int i = 0; + for (i = 0; i < length-4 && !foundHeader; i++) + { + unsigned int tempHead = *((unsigned int*)(buf+i)); + if (HeadCheck(tempHead)) + { + if ((buf[i+2] & 0xFC) != (lastHeader[2] & 0xFC)) + { + cLog::Instance() << "cDxr3AudioDecoder::Decode Found different audio header -> init\n"; + cLog::Instance() << "cDxr3AduioDecoder::Decode Old header 0x" << hex << *((uint32_t*) lastHeader) << " new header 0x" << *((uint32_t*) (buf+i))<< dec << "\n"; + + Init(); + lastHeader[0] = buf[i]; + lastHeader[1] = buf[i+1]; + lastHeader[2] = buf[i+2]; + lastHeader[3] = buf[i+3]; + } + foundHeader = true; + } + } + + if (audioSynched) + { + // no header found + decodeAudio = true; + } + else + { + if (foundHeader && pts) + { + decodeAudio = true; + audioSynched = true; + } + } + + try + { + while (length > 0 && decodeAudio) + { + len = avcodec_decode_audio(&Codec.codec_context, (short *)(&pcmbuf), &out_size, + const_cast<uint8_t *>(buf), length); + if (len < 0 || out_size < 0) throw WRONG_LENGTH; + + if (Codec.codec_context.sample_rate != rate) + { + cLog::Instance() << "cDxr3AudioDecoder::Decode Sample rate = " << Codec.codec_context.sample_rate << "\n"; + if (rate != -1) throw UNEXPECTED_PARAMETER_CHANGE; + rate = Codec.codec_context.sample_rate; + } + if (Codec.codec_context.channels != channels+1 ) + { + if (channels != -1) throw UNEXPECTED_PARAMETER_CHANGE; + channels = (Codec.codec_context.channels == 2) ? 1 : 0; + cLog::Instance() << "cDxr3AudioDecoder::Decode channels = " << Codec.codec_context.channels << "\n"; + } + if (out_size) + { + cFixedLengthFrame* pTempFrame = aBuf.Push(pcmbuf, out_size, pts); + pTempFrame->SetChannelCount(channels); + pTempFrame->SetDataRate(rate); + } + length -= len; + buf += len; + } + } + catch (audioException ex) + { + switch (ex) + { + case WRONG_LENGTH: + cLog::Instance() << "cDxr3AudioDecoder::Decode wrong length\n"; + break; + + case UNEXPECTED_PARAMETER_CHANGE: + cLog::Instance() << "cDxr3AudioDecoder::Decode unexpected parameter change\n"; + break; + + default: + cLog::Instance() << "cDxr3AudioDecoder::Decode unexpeced exception\n"; + break; + } + dsyslog("cDxr3AudioDecoder::Decode skipping %d broken data bytes", length); + + Init(); + } +} + +// ================================== +// decode lpcm +void cDxr3AudioDecoder::DecodeLpcm(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf) +{ + if (length > (LPCM_HEADER_LENGTH + 2)) + { + uint8_t* pFrame = new uint8_t[length - LPCM_HEADER_LENGTH]; + assert(!((length - LPCM_HEADER_LENGTH) % 2)); // only even number of bytes are allowed + + for (int i = LPCM_HEADER_LENGTH; i < length; i += 2) + { + pFrame[i - LPCM_HEADER_LENGTH] = buf[i + 1]; + pFrame[i - LPCM_HEADER_LENGTH + 1] = buf[i]; + } + + int codedSpeed = (buf[5] >> 4) & 0x03; + int speed = 0; + + switch (codedSpeed) + { + case 1: + speed = 96000; + break; + + case 2: + speed = 44100; + break; + + case 3: + speed = 32000; + break; + + default: + speed = 48000; + break; + } + + cFixedLengthFrame* pTempFrame = aBuf.Push(pFrame, length - LPCM_HEADER_LENGTH, pts); + pTempFrame->SetChannelCount(1); + pTempFrame->SetDataRate(speed); + + delete[] pFrame; + } +} + +// ================================== +// decode ac3 +void cDxr3AudioDecoder::DecodeAc3Dts(const uint8_t* pPes, const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf) +{ + int headerLength = (int) (buf - pPes); + + uint8_t* pBuf = (uint8_t*) pPes; + ac3dtsDecoder.Check(pBuf + headerLength, length, pBuf); + ac3dtsDecoder.Encapsulate(pBuf + headerLength, length); + + cFrame* pFrame = 0; + while ((pFrame = rbuf.Get())) + { + if (pFrame && pFrame->Count()) + { + cDxr3PesFrame tempPes; + tempPes.ExtractNextFrame(pFrame->Data(), pFrame->Count()); + int pesHeaderLength = (int) (tempPes.GetEsStart() - tempPes.GetPesStart()); + uint8_t* pData = pFrame->Data() + pesHeaderLength + LPCM_HEADER_LENGTH; + + for (int i = 0; i < pFrame->Count() - pesHeaderLength - LPCM_HEADER_LENGTH; i += 2) + { + swap(pData[i], pData[i + 1]); + } + + aBuf.Push(pFrame->Data() + pesHeaderLength + LPCM_HEADER_LENGTH, pFrame->Count() - pesHeaderLength - 7, tempPes.GetPts()); + if (pFrame) rbuf.Drop(pFrame); + } + } +} + +// ================================== +// checking routine +bool cDxr3AudioDecoder::HeadCheck(unsigned long head) +{ + bool retval = false; + + uint8_t* phead = (uint8_t*) (&head); + if (phead[0] != 0xFF) + { + retval = false; + } + else if (phead[1] != 0xFC && phead[1] != 0xFE) + { + retval = false; + } + else if ((phead[2] & 0xF0) == 0xF0) + { + retval = false; + } + else if ((phead[2] & 0xC) == 0xC) + { + retval = false; + } + else + { + retval = true; + } + + return retval; +} diff --git a/dxr3audiodecoder.h b/dxr3audiodecoder.h new file mode 100644 index 0000000..32467e4 --- /dev/null +++ b/dxr3audiodecoder.h @@ -0,0 +1,53 @@ +#ifndef _DXR3_AUDIODECODER_H_ +#define _DXR3_AUDIODECODER_H_ + +#include <stdlib.h> +#include <stdint.h> + +#include "dxr3ffmpeg.h" +#include "dxr3syncbuffer.h" +#include "dxr3multichannelaudio.h" +#include "dxr3log.h" + +// ================================== +// decode audio to mp2 or use DD :) +class cDxr3AudioDecoder +{ +public: + cDxr3AudioDecoder(); + ~cDxr3AudioDecoder(); + + void Init(void); // init in const? + + void Decode(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf); + void DecodeLpcm(const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf); + void DecodeAc3Dts(const uint8_t* pPes, const uint8_t* buf, int length, uint32_t pts, cDxr3SyncBuffer &aBuf); + + int GetRate(void) const { return rate; } + int GetChannelCount(void) const { return channels; } + int GetFrameSize(void) const { return frameSize; } + void Reset(void) { ac3dtsDecoder.Clear(); rbuf.Clear(); } + +private: + bool HeadCheck(unsigned long head); + + struct Dxr3Codec Codec; + + cRingBufferFrame rbuf; + cMultichannelAudio ac3dtsDecoder; + + bool audioSynched; + bool decoderOpened; + uint8_t lastHeader[4]; + int rate; + int channels; + uint32_t frameSize; + uint8_t pcmbuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]; + int volume; + bool foundHeader; + bool decodeAudio; + + cDxr3AudioDecoder(cDxr3AudioDecoder&); // no copy constructor +}; + +#endif /*_DXR3_AUDIODECODER_H_*/ diff --git a/dxr3blackframe.c b/dxr3blackframe.c new file mode 100644 index 0000000..c21417b --- /dev/null +++ b/dxr3blackframe.c @@ -0,0 +1,1286 @@ +/* + * dxr3blackframe.c + * + * Copyright (C) 2002-2004 Kai Möller + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +// ================================== +// used when channel gets switched +char blackframe[] = + +{ 0x0, 0x0, 0x1, 0xb3, 0x2d, 0x2, 0x40, 0x23, 0x24, 0x9f, 0x23, 0x82, 0x10, 0x20, 0x20, 0x26, +0x20, 0x26, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x34, 0x30, 0x34, 0x36, 0x36, 0x36, 0x34, +0x34, 0x34, 0x34, 0x36, 0x36, 0x36, 0x3a, 0x3a, 0x3a, 0x44, 0x44, 0x44, 0x3a, 0x3a, 0x3a, +0x36, 0x36, 0x3a, 0x3a, 0x40, 0x40, 0x44, 0x44, 0x4a, 0x4c, 0x4a, 0x46, 0x46, 0x44, 0x46, +0x4c, 0x4c, 0x50, 0x50, 0x50, 0x60, 0x60, 0x5c, 0x5c, 0x70, 0x70, 0x74, 0x8a, 0x8a, 0xa7, +0x10, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, +0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19, 0x1a, +0x1a, 0x1a, 0x1a, 0x19, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1e, 0x1e, +0x1e, 0x1f, 0x1f, 0x21, 0x0, 0x0, 0x1, 0xb5, 0x14, 0x82, 0x0, 0x1, 0x0, 0x0, 0x0, +0x0, 0x1, 0xb8, 0x5a, 0x9, 0xc4, 0x80, 0x0, 0x0, 0x1, 0x0, 0x0, 0x4b, 0x9, 0xb0, +0x0, 0x0, 0x1, 0xb5, 0x8f, 0xff, 0xf7, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0xb, 0x7e, +0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xd4, 0x28, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x13, 0x7e, 0x1f, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x3, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xa8, 0x31, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1a, 0x83, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xc, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x35, 0x6, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xc, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0x13, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0x41, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x62, 0xb5, 0x4e, 0x81, +0x2a, 0x5, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x1, 0x7, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x8, 0xb, +0x7e, 0x1f, 0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x21, 0xea, 0x31, 0x6, 0x97, 0x54, 0x85, 0x18, 0x61, 0x80, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x9, +0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xa, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xb, 0xb, 0x7e, +0x1f, 0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc, 0xb, +0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x1, 0xd, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe, 0xb, 0x7e, 0x1f, +0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xf, 0xb, 0x7e, 0x1f, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x10, 0xb, 0xfe, 0x1f, 0x3, 0x4d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x11, 0xb, 0x7e, 0x1f, 0x68, 0xd0, 0x94, 0x48, 0xf5, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xc0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x12, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x13, 0xb, +0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x1, 0x14, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x1, 0x15, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x1, 0x16, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x17, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x1, 0x18, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x19, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x1, 0x1a, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1b, 0xb, 0x7e, 0x1f, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1c, 0xb, +0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x1d, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x1, 0x1e, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, +0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x1f, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, +0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x20, 0xb, 0xfe, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x21, 0xb, 0x7e, 0x1f, +0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, +0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, +0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x22, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, +0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, +0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, +0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, +0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, +0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, +0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, +0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, +0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, +0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, +0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, +0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, +0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, +0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, +0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, +0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, +0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x1, 0x23, 0xb, 0x7e, 0x1f, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, +0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, +0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, +0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, +0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, +0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, +0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x24, 0xb, 0x7e, 0x1f, 0x68, 0xd1, +0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, +0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, +0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, +0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, +0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, +0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, +0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, +0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, +0xd, 0xa3, 0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, +0x61, 0x86, 0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, +0x1a, 0x30, 0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, +0x46, 0x8d, 0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, +0xd1, 0xa3, 0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, +0xc3, 0x68, 0xd1, 0xa3, 0x46, 0x18, 0x6d, 0x1a, 0x34, 0x68, 0xc3, 0xd, 0xa3, 0x46, 0x8d, +0x18, 0x61, 0xb4, 0x68, 0xd1, 0xa3, 0xc, 0x36, 0x8d, 0x1a, 0x34, 0x61, 0x86, 0xd1, 0xa3, +0x46, 0x8c, 0x30, 0xda, 0x34, 0x68, 0xd1, 0x86, 0x1b, 0x46, 0x8d, 0x1a, 0x30, 0xc3, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0 }; + +int blackframeLength = sizeof(blackframe); diff --git a/dxr3colormanager.c b/dxr3colormanager.c new file mode 100644 index 0000000..50e3877 --- /dev/null +++ b/dxr3colormanager.c @@ -0,0 +1,378 @@ +/*************************************************************************** + dxr3colormanager.c - description + ------------------- + begin : Tue Oct 22 2002 + copyright : (C) 2002 by Stefan Schluenss + email : vdr@schluenss.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +/** + * Background: + * Each encoded pixel in the SPU could have one of the values 0,1,2,3. * + * These values + + Pixelvalue Maps + to index + 0 --> 4 --> + + + * The SPU data definition allows highlighting of rectangular areas. They * + * are defined by a starting and ending row. Whithin these rows one could * + * define a starting column for using a new color palette mapping. This * + * mapping will be used til the end of the line or up to the next column * + * defintion. + * Look at the picture below: + * + Row Col=5 Col=16 + n-2 ............................... + n-1 ............................... + n .....-------------------------- <- Highligh region starts here + .....| 6,3,1,2 | 0,2,8,9 + .....| 6,3,1,2 | 0,2,8,9 + .....| 6,3,1,2 | 0,2,8,9 + n+4 .....-------------------------- <- Highligh region ends here + n+5 ............................... + n+6 ............................... + + In the above example one region (from n to n+4) is defined with two * + highlight sections - one from column 5 up to 15 and the second from 16 * + til the end of the line. +**/ + + +#include <assert.h> + +#include "dxr3colormanager.h" +#include "dxr3memcpy.h" +#include <stdio.h> +#include <string.h> + +// ================================== +cColorManager::cColorManager() +{ + NrOfRegions = 0; + isopen = false; + for(int i = 0; i < MAX_NO_OF_REGIONS; i++) + hlr[i] = NULL; +} + +// ================================== +cColorManager::~cColorManager() +{ + for (int i = 0; i < NrOfRegions; i++) + { + if (hlr[i]) + { + delete(hlr[i]); + } + } +} + +// ================================== +// Opens a new highlight region +void cColorManager::OpenRegion(int y, int NrOfSecToCopy) +{ + hlr[NrOfRegions] = new yRegion(); + hlr[NrOfRegions]->Y1 = y; + isopen = true; + + if (NrOfSecToCopy > 0) + { + for (int i = 0; i < NrOfSecToCopy; i++) + { + hlr[NrOfRegions]->Section[i] = hlr[NrOfRegions - 1]->Section[i]; + } + } +} + +// ================================== +// Closes the spu-highlight region +void cColorManager::CloseRegion(int y) +{ + + hlr[NrOfRegions]->Y2 = y; + isopen = false; + + if (hlr[NrOfRegions]->N != 0) // skip this region if there is no section defined + { + if (NrOfRegions < MAX_NO_OF_SECTIONS -1) + { + NrOfRegions++; + } + } + +} + +// ================================== +void cColorManager::EncodeColors(int width, int height, unsigned char* map, unsigned char* dmap) +{ + unsigned char color = 0xFF, ccol = 0xFF; + unsigned char ColorIndex = 0xFF; + unsigned char buffer[1024] = {0}; + + for (int y = 0; y < height; ++y) + { + color = 0xFF; + for(int x = 0; x < width; ++x) + { + ccol = map[y * width + x]; + if (ccol != 0) MaxY = y; + if (ccol != color) + { + color = ccol; // save this color + if (!AddColor(x,y,color, ColorIndex)) + { + // add this color to highlight regions + color = 0xFF; + x = -1; + } + else + { + // color successfully added + buffer[x] = ColorIndex; + } + } + else + { + buffer[x] = ColorIndex;//*(dmap+(y * width + x)) = ColorIndex; + } + } + dxr3_memcpy(dmap+y*width, buffer,width); + } +} + +// ================================== +unsigned char cColorManager::AddColor(int x, int y, unsigned char color, unsigned char &ColorIndex) { + static int yold = -1; + xSection* Section = 0; + int SectionIndex = 0; + + if (isopen) + { + // there is an opened highlight-region + Section = GetSection(x, SectionIndex); + + // checks whether we have a section defined on the formerly line on this x-position + if (Section != NULL) + { + // there was a section + if (!Section->HasColor(color, ColorIndex)) + { + // this color is new for this section + if (Section->AllColorsUsed()) + { + // no more free colors + if (yold != y) + { + CloseRegion(y-1); + // terminate region + return(0); + yold = y; + // open new region + OpenRegion(y,SectionIndex+1); + } + // create new section + Section = NewSection(x); + } + // and add new color + ColorIndex = Section->AddColor(color); + } + } + else + { + // no section found (but region already open) + + // terminate region + CloseRegion(y-1); + yold = y; + // open new region + OpenRegion(y); + // create new section + Section = NewSection(x); + // and add new color + ColorIndex = Section->AddColor(color); + } + } + else + { + // currently no region open + yold = y; + + // open new region + OpenRegion(y); + // create new section + Section = NewSection(x); + // and add new color + ColorIndex = Section->AddColor(color); + } + return(1); +} + +// ================================== +xSection *cColorManager::GetSection(int x, int &n) +{ + int i; + n = 0; + + // for every section in the current region + for (i = 0; i < hlr[NrOfRegions]->N; i++) + { + if ((x <= hlr[NrOfRegions]->Section[i]->X2) && (x >= hlr[NrOfRegions]->Section[i]->X1)) // x-pos is in section + { + n = i; + return (hlr[NrOfRegions]->Section[i]); + } + } + return(NULL); +} + +/** Adds a new highlight region beginning from FIRST to LAST column */ +/** +void cColorManager::AddRegion(int first, int last, unsigned int color, unsigned int opac) +{ + DIAG("AddRegion(%d %d %x %x)\n",first, last, color, opac); + hlr[NrOfRegions]->AddSection(first, last, color, opac); +} +**/ + +// ================================== +// convert into SPU - hope is correct description +unsigned char* cColorManager::GetSpuData(int& len) +{ + if (isopen) // there is an opened highlight-region + CloseRegion(MaxY); + + if (NrOfRegions != 0) + { + int ptr = 0; + spudata[ptr++] = 0x07; // CHG_COLCON command + spudata[ptr++] = 0x00; // total size of parameter area + spudata[ptr++] = 0x00; // will be filled later + + + for(int i = 0; i < NrOfRegions;i++) + { + spudata[ptr++] = (hlr[i]->Y1 >> 8) & 0x0f; + spudata[ptr++] = (hlr[i]->Y1 & 0xff); + spudata[ptr++] = ( ( (hlr[i]->N) & 0x0f) << 4) | ((hlr[i]->Y2 >> 8) & 0x0f); + spudata[ptr++] = (hlr[i]->Y2 & 0xff); + + for(int c = 0; c < hlr[i]->N; c++) + { + spudata[ptr++] = hlr[i]->Section[c]->X1 >> 8; + spudata[ptr++] = hlr[i]->Section[c]->X1 & 0xff; + spudata[ptr++] = (hlr[i]->Section[c]->Colors[3] << 4) | (hlr[i]->Section[c]->Colors[2] & 0x0F); + spudata[ptr++] = (hlr[i]->Section[c]->Colors[1] << 4) | (hlr[i]->Section[c]->Colors[0] & 0x0F); + + spudata[ptr++] = (hlr[i]->Section[c]->Opac[3] << 4) | hlr[i]->Section[c]->Opac[2]; + spudata[ptr++] = (hlr[i]->Section[c]->Opac[1] << 4) | hlr[i]->Section[c]->Opac[0]; + } + } + spudata[ptr++] = 0x0f; // termination of parameter block + spudata[ptr++] = 0xff; + spudata[ptr++] = 0xff; + spudata[ptr++] = 0xff; + int size = ptr - 1; + spudata[1] = size >> 8; + spudata[2] = size & 0xff; + + len = ptr; + } + else + len = 0; + +#if OSD_SPU_CM_DUMP + FILE *fp; + fp = fopen("CM.dump","a+"); + fprintf(fp,"len:%03d ",len); + for (int i = 0; i < len; i++) + fprintf(fp,"%02X",*(spudata+i)); + fprintf(fp,"\n"); + fclose(fp); +#endif + + return(spudata); +} + +// ================================== +xSection *cColorManager::NewSection(int x) +{ + xSection* sec = new xSection(x); + int N = hlr[NrOfRegions]->N; + + hlr[NrOfRegions]->Section[hlr[NrOfRegions]->N] = sec; + if (N > 0) + hlr[NrOfRegions]->Section[hlr[NrOfRegions]->N - 1]->X2 = x-1; + (hlr[NrOfRegions]->N)++; + + return(sec); +} + +/** +// No descriptions */ +/** +void HLRegion::AddSection(int first, int last, unsigned int color, unsigned int opac) +{ + DIAG(" AddSection %d,%d %X,%X\n",first, last, color, opac); + Region[N] = new ColRegion(first, last, color, opac); + assert(N<MAX_NO_OF_REGIONS -1); + N++; + DIAG("HL N:%d\n",N); +} +**/ + +// ================================== +xSection::xSection(int x) +{ + X1 = x; + X2 = 0xFFF; + 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); +} + +/** No descriptions */ +void cColorManager::SetBgColor(unsigned int bgColor) +{ +// cColorManager::BgColor = bgColor; +} diff --git a/dxr3colormanager.h b/dxr3colormanager.h new file mode 100644 index 0000000..063252d --- /dev/null +++ b/dxr3colormanager.h @@ -0,0 +1,122 @@ +/*************************************************************************** + dxr3colormanager.h - description + ------------------- + begin : Tue Oct 22 2002 + copyright : (C) 2002 by Stefan Schluenss + email : vdr@schluenss.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _DXR3COLORMANAGER_H_ +#define _DXR3COLORMANAGER_H_ +/* +// ================================== +struct rectangular_area +{ + rectangular_area() : m_startrow(0), m_endrow(0), m_startcol(0), m_endcol(0) {} + +private: + size_t m_startrow; + size_t m_endrow; + size_t m_startcol; + size_t m_endcol; + + unsigned int Colors[4]; + unsigned int Opac[4]; +} + + + +*/ + + + +/**SPU-ColorManager + *@author Stefan Schluenss +*/ + +#include <stdio.h> + +#define OSD_SPU_CM_DUMP 0 + +#define MAX_NO_OF_SECTIONS 15 +#define MAX_NO_OF_REGIONS 30 + + +// ================================== +class xSection +{ +public: + xSection(int x); + bool HasColor(unsigned int color, unsigned char &ColorIndex); + unsigned char AddColor(unsigned int color); + bool AllColorsUsed() {/*DIAG("AllColorsUsed: %d\n",NrOfColors)*/;if(NrOfColors >= 4) return(true); else return (false); }; + int X1; + int X2; + int NrOfColors; + unsigned int Colors[4]; + unsigned int Opac[4]; +}; + +// ================================== +class yRegion +{ +public: + yRegion(): Y1(0), Y2(0), N(0) {} + + /** No descriptions */ + void AddSection(int first, int last, unsigned int color, unsigned int opac); + int Y1; + int Y2; + int N; + + xSection* Section[MAX_NO_OF_SECTIONS]; +}; + +// ================================== +class cColorManager +{ +public: + cColorManager(); + ~cColorManager(); + + void EncodeColors(int width, int height, unsigned char* smap, unsigned char* dmap); + + /** Sets a new color on the OSD */ + unsigned char AddColor(int x, int y, unsigned char color, unsigned char &ColorIndex); + + /** encodes the color information as highlight spu data*/ + unsigned char* GetSpuData(int &len); + + /** Adds a new highlight region beginning from FIRST to LAST column */ +// void AddRegion(int first, int last, unsigned int color, unsigned int opac=0xFFFF); + + /** No descriptions */ + void SetBgColor(unsigned int bgColor); + +private: // Private attributes + yRegion *hlr[MAX_NO_OF_REGIONS]; + int NrOfRegions; + bool isopen; + unsigned char spudata[2*4096]; + unsigned int BgCol; + int MaxY; + + /** Opens a new highlight region */ + void OpenRegion(int y, int NrOfSecToCopy = 0); + /** Closes the spu-highlight region */ + void CloseRegion(int y); + + xSection* NewSection(int x); + xSection *GetSection(int x, int &n); +}; + +#endif /*_DXR3COLORMANAGER_H_*/ diff --git a/dxr3configdata.c b/dxr3configdata.c new file mode 100644 index 0000000..ee46081 --- /dev/null +++ b/dxr3configdata.c @@ -0,0 +1,16 @@ +//#include <stdio.h> +#include "dxr3configdata.h" + +// ================================== +// constr. +cDxr3ConfigData::cDxr3ConfigData() +{ + UseDigitalOut = 0; + Dxr3Card = 0; + ForceLetterBox = 0; + Ac3OutPut = 0; + m_videoMode = PAL; + m_menuMode = SUBPICTURE; + m_debug = 1; + m_debuglevel = 0; +} diff --git a/dxr3configdata.h b/dxr3configdata.h new file mode 100644 index 0000000..672c3f9 --- /dev/null +++ b/dxr3configdata.h @@ -0,0 +1,76 @@ +#ifndef _DXR3_CONFIGDATA_H_ +#define _DXR3_CONFIGDATA_H_ + +//#include <stdio.h> + +#include "dxr3singleton.h" + +// ================================== +// possible video modes +enum eVideoMode +{ + PAL = 0, + PAL60, + NTSC +}; + +// ================================== +// possible menu modes +enum eMenuMode +{ + SUBPICTURE = 0, + MPEG +}; + +// ================================== +// possible debug levels +enum eDebugLevel +{ + LOW = 0, + EVERYTHING +}; + +// ================================== +// global interface to access all config +// datas of this plugin +class cDxr3ConfigData : public Singleton<cDxr3ConfigData> +{ +public: + cDxr3ConfigData(); + ~cDxr3ConfigData() {} + + int GetUseDigitalOut() const { return UseDigitalOut; } + int SetUseDigitalOut(int value) { return UseDigitalOut = value; } + int GetDxr3Card() const { return Dxr3Card; } + int SetDxr3Card(int value) { return Dxr3Card = value; } + int GetForceLetterBox() const { return ForceLetterBox; } + int SetForceLetterBox(int value) { return ForceLetterBox = value; } + int GetAc3OutPut() const { return Ac3OutPut; } + int SetAc3OutPut(int value) { return Ac3OutPut = value;} + + eVideoMode GetVideoMode() const { return m_videoMode;} + eVideoMode SetVideoMode(eVideoMode videoMode) { return m_videoMode = videoMode;} + eMenuMode GetMenuMode() const { return m_menuMode; } + eMenuMode SetMenuMode(eMenuMode menuMode) { return m_menuMode = menuMode; } + + int GetDebug() const { return m_debug; } + int SetDebug(int value) { return m_debug = value; } + int GetDebugLevel() const { return m_debuglevel; } + int SetDebugLevel(int value) { return m_debuglevel = value; } + + // some little helpers to save some writing + int GetDebugLow() const { return (m_debug && !m_debuglevel); } + int GetDebugEverything() const { if (m_debug == 1 && m_debuglevel == 0) { return 1; } else { return 0; } } + +protected: + int UseDigitalOut; + int Dxr3Card; + int ForceLetterBox; + int Ac3OutPut; + eVideoMode m_videoMode; + eMenuMode m_menuMode; + int m_debug; + int m_debuglevel; +}; + +#endif /*_DXR3_CONFIGDATA_H_*/ diff --git a/dxr3cpu.c b/dxr3cpu.c new file mode 100644 index 0000000..4666e89 --- /dev/null +++ b/dxr3cpu.c @@ -0,0 +1,127 @@ +/* +* dxr3cpu.c +* +* Copyright (C) 2004 Christian Gmeiner +* +* Taken from Nesseia-Renderengine Copyright (C) 2003-2004 Christian Gmeiner +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License +* as published by the Free Software Foundation; either version 2.1 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ + +#include "dxr3cpu.h" +#include "dxr3log.h" +#include "dxr3memcpy.h" + +// ================================== +// const. +cDxr3CPU::cDxr3CPU() +{ + unsigned long eax,ebx,edx,unused; + + // readout the vendor + cpuid(0,eax,ebx,unused,edx); + + // set Vendor to "" + memset(m_Info.Vendor, 0, 16); + + // connect the single register values to the vendor string + // maybe there is an better solution - i will google :) + *(unsigned long *)(m_Info.Vendor) = ebx; + *(unsigned long *)(m_Info.Vendor + 4) = edx; + *(unsigned long *)(m_Info.Vendor + 8) = unused; + + // check the features + // could we get the needed infos? + if (cpuid(1,eax,ebx,unused,edx)) + { + m_Info.MMX = ((edx & 1<<23) != 0); + m_Info.SSE = ((edx & 1<<25) != 0); + m_Info.SSE2= ((edx & 1<<26) != 0); + m_Info.RDTSC=((edx & 1<<4) != 0); /*0x10*/ + m_Info.HT = ((edx & 1<<28) !=0); // should we do here addinonal checks? + + // 3DNow is a litle bit harder to read out + // We read the ext. CPUID level 0x80000000 + if (cpuid(0x80000000,eax,ebx,unused,edx)) + { + // now in eax there is the max. supported extended CPUID level + // we check if theres an extended CPUID level support + if (eax >= 0x80000001) + { + // If we can access the extended CPUID level 0x80000001 we get the + // edx register + if (cpuid(0x80000001,eax,ebx,unused,edx)) + { + // Now we can mask some AMD specific cpu extensions + // 22 ... Extended MMX_MultimediaExtensions + m_Info.MMXEXT = ((edx & 1<<22) != 0); + m_Info.AMD64Bit = ((edx & 1<<29) != 0); + // 30 ... Extended 3DNOW_InstructionExtensions + m_Info.Now = ((edx & (1<<31)) != 0); + } + } + } + } + + // fill cabs + if (m_Info.MMX) + { + m_Info.caps = CC_MMX; + } + + if (m_Info.MMXEXT) + { + m_Info.caps |= CC_MMXEXT; + } + + if (m_Info.SSE) + { + m_Info.caps |= CC_SSE; + } + + if (m_Info.Now) + { + m_Info.caps |= CC_3DNOW; + } + + // print some infos about cpu + cLog::Instance() << "cpu vandor: " << m_Info.Vendor << "\n"; + cLog::Instance() << "cpu extensions:\n"; + cLog::Instance() << "mmx: " << m_Info.MMX << "\n"; + cLog::Instance() << "mmx-ext: " << m_Info.MMXEXT << "\n"; + cLog::Instance() << "sse: " << m_Info.SSE << "\n"; + cLog::Instance() << "sse2: " << m_Info.SSE2 << "\n"; + cLog::Instance() << "3dnow: " << m_Info.Now << "\n"; + + // now we select the best memcpy mehtode + cDxr3MemcpyBench Benchmark(m_Info.caps); +} + +// ================================== +// does the cpu support cpuid instructions +bool cDxr3CPU::CheckCPUIDPresence() +{ + // todo + return true; +} + +// ================================== +// cpuid function +bool cDxr3CPU::cpuid(unsigned long function, unsigned long& out_eax, unsigned long& out_ebx, unsigned long& out_ecx, unsigned long& out_edx) +{ + asm("cpuid": "=a" (out_eax), "=b" (out_ebx), "=c" (out_ecx), "=d" (out_edx) : "a" (function)); + return true; +} diff --git a/dxr3cpu.h b/dxr3cpu.h new file mode 100644 index 0000000..b18f510 --- /dev/null +++ b/dxr3cpu.h @@ -0,0 +1,107 @@ +/* + * dxr3cpu.h + * + * Copyright (C) 2004 Christian Gmeiner + * + * Taken (modifized) from Nesseia-Renderengine Copyright (C) 2003-2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _DXR3_CPU_H_ +#define _DXR3_CPU_H_ + +#include <inttypes.h> +#include "dxr3singleton.h" + +// ================================== +// all possible cabs +enum Cpu_cabs +{ + CC_MMX = 0x80000000, + CC_3DNOW = 0x40000000, + CC_MMXEXT = 0x20000000, + CC_SSE = 0x10000000, + CC_SSE2 = 0x08000000 +}; + +// ================================== +// Easy and fast access to all infos +struct CPUInformation +{ + CPUInformation() + { + AMD = false; + INTEL = false; + MMX = false; + MMXEXT = false; + SSE = false; + SSE2 = false; + Now = false; + RDTSC = false; + HT = false; + AMD64Bit = false; + } + + char Vendor[16]; + + bool AMD; // is it an AMD CPU? + bool INTEL; // is it an Intel CPU? + bool MMX; // is MMX-Technology supported? + bool MMXEXT; // are Extended MMX_MultimediaExtensions supported? + bool SSE; // is SSE-Technology supported? + bool SSE2; // is SSE2-Technology supported? + bool Now; // is 3DNow-Technology supported? + bool RDTSC; // is RDTSC-Technology supported? + bool HT; // is HyperThreading supported? + bool AMD64Bit; // is it a 64 bit machine? + + uint32_t caps; // all features represanted as caps +}; + +// ================================== +//! Grab some infos about the cpu(s) +/*! +If you want to know what the cpu of the +target machine can do, this class is for you :) +It is used intern for the math and memcpy part. +*/ +class cDxr3CPU : public Singleton<cDxr3CPU> +{ +public: + cDxr3CPU(); + ~cDxr3CPU() {} + + bool HasMMXSupport() const { return m_Info.MMX; } + bool HasSSESupport() const { return m_Info.SSE; } + bool HasSSE2Support() const { return m_Info.SSE2; } + bool Has3DNowSupport() const { return m_Info.Now; } + bool HasRDTSCSupport() const { return m_Info.RDTSC; } + bool HasHTSupport() const { return m_Info.HT; } + + inline CPUInformation GetInfos() const { return m_Info ;} + +private: + bool CheckCPUIDPresence(); + + // main function to get cpu(s) features + bool cpuid(unsigned long function, unsigned long& out_eax, unsigned long& out_ebx, unsigned long& out_ecx, unsigned long& out_edx); + + CPUInformation m_Info; +}; + + +#endif /*_DXR3_CPU_H_*/ diff --git a/dxr3demuxdevice.c b/dxr3demuxdevice.c new file mode 100644 index 0000000..d39b07b --- /dev/null +++ b/dxr3demuxdevice.c @@ -0,0 +1,662 @@ +/* + * dxr3demuxdevice.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include "dxr3demuxdevice.h" +#include <linux/em8300.h> +#include "dxr3log.h" +#include "dxr3pesframe.h" +#include "dxr3configdata.h" +#include "dxr3log.h" + +// ================================== +// constr. +cDxr3DemuxDevice::cDxr3DemuxDevice(cDxr3Interface& dxr3Device) : +m_dxr3Device(dxr3Device), +m_aBuf(AUDIO_MAX_BUFFER_SIZE, AUIDO_MAX_FRAME_SIZE, m_dxr3Device), +m_vBuf(VIDEO_MAX_BUFFER_SIZE, VIDEO_MAX_FRAME_SIZE, m_dxr3Device) +{ + m_ReUseFrame = 1; + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; + m_pAudioThread = new cDxr3AudioOutThread(dxr3Device, m_aBuf); + if (!m_pAudioThread) + { + cLog::Instance() << "cDxr3DemuxDevice::cDxr3DemuxDevice: failed to allocate memory\n"; + exit(1); + } + m_pAudioThread->Start(); + + m_pVideoThread = new cDxr3VideoOutThread(dxr3Device, m_vBuf); + if (!m_pVideoThread) + { + cLog::Instance() << "cDxr3DemuxDevice::cDxr3DemuxDevice: failed to allocate memory\n"; + exit(1); + } + m_pVideoThread->Start(); + m_aDecoder.Init(); +} + +// ================================== +cDxr3DemuxDevice::cDxr3DemuxDevice() : // dummy constructor +m_dxr3Device(cDxr3Interface::Instance()), +m_aBuf(AUDIO_MAX_BUFFER_SIZE, AUIDO_MAX_FRAME_SIZE, m_dxr3Device), +m_vBuf(VIDEO_MAX_BUFFER_SIZE, VIDEO_MAX_FRAME_SIZE, m_dxr3Device) +{ + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; +} + +// ================================== +// deconstr. +cDxr3DemuxDevice::~cDxr3DemuxDevice() +{ + if (!m_pVideoThread) + { + delete m_pVideoThread; + } + + if (!m_pVideoThread) + { + delete m_pVideoThread; + } +} + +// ================================== +// stop demuxing process +void cDxr3DemuxDevice::Stop() +{ + m_dxr3Device.DisableVideo(); + m_dxr3Device.DisableAudio(); + m_vBuf.Clear(); + m_aBuf.Clear(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + m_aDecoder.Init(); + m_vBuf.WaitForReceiverStopped(); + m_aBuf.WaitForReceiverStopped(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; + + m_dxr3Device.PlayBlackFrame(); + m_dxr3Device.ReOpenAudio(); +} + +// ================================== +void cDxr3DemuxDevice::Resync() +{ + m_dxr3Device.DisableVideo(); + m_dxr3Device.DisableAudio(); + m_vBuf.Clear(); + m_aBuf.Clear(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + m_aDecoder.Init(); + m_vBuf.WaitForReceiverStopped(); + m_aBuf.WaitForReceiverStopped(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; +} + +// ================================== +void cDxr3DemuxDevice::Clear() +{ + m_dxr3Device.DisableVideo(); + m_dxr3Device.DisableAudio(); + m_vBuf.Clear(); + m_aBuf.Clear(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + m_aDecoder.Init(); + m_vBuf.WaitForReceiverStopped(); + m_aBuf.WaitForReceiverStopped(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; +} + +// ================================== +void cDxr3DemuxDevice::Init() +{ + m_vBuf.Clear(); + m_aBuf.Clear(); + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_OFF_MODE; + m_aDecoder.Init(); +} + +// ================================== +void cDxr3DemuxDevice::SetTvMode() +{ + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_TV_MODE; + m_aBuf.SetDemuxMode(DXR3_DEMUX_TV_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_TV_MODE); + m_aBuf.Start(); + m_vBuf.Start(); +} + +// ================================== +void cDxr3DemuxDevice::SetAudioOnlyMode() +{ + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_demuxMode = DXR3_DEMUX_AUDIO_ONLY_MODE; + m_aBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_aBuf.Start(); + m_vBuf.Start(); +} + +// ================================== +void cDxr3DemuxDevice::SetReplayMode() +{ + if (m_demuxMode != DXR3_DEMUX_REPLAY_MODE) + { + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE && m_trickState == DXR3_FREEZE) + { + m_dxr3Device.SetPlayMode(); + m_dxr3Device.SetSysClock(m_stopScr); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + m_vBuf.WakeUp(); + m_aBuf.WakeUp(); + } + else + { + m_synchState = DXR3_DEMUX_UNSYNCHED; + m_aBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + } + } + m_demuxMode = DXR3_DEMUX_REPLAY_MODE; +} + +// ================================== +void cDxr3DemuxDevice::SetTrickMode(eDxr3TrickState trickState, int Speed) +{ + m_demuxMode = DXR3_DEMUX_TRICK_MODE; + m_trickState = trickState; + m_dxr3Device.DisableAudio(); + + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE && m_trickState == DXR3_FREEZE) + { + m_stopScr = m_dxr3Device.GetSysClock(); + // m_dxr3Device.Pause(); + m_vBuf.Stop(); + m_aBuf.Stop(); + } + else + { + m_vBuf.Clear(); + m_aBuf.Clear(); + } + + m_ReUseFrame = 1;//Speed; +} + +// ================================== +void cDxr3DemuxDevice::SetVideoOnlyMode() +{ + m_demuxMode = DXR3_DEMUX_VIDEO_ONLY_MODE; + m_dxr3Device.DisableAudio(); + + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE && m_trickState == DXR3_FREEZE) + { + m_stopScr = m_dxr3Device.GetSysClock(); + // m_dxr3Device.Pause(); + m_vBuf.Stop(); + m_aBuf.Stop(); + } + else + { + m_vBuf.Clear(); + m_aBuf.Clear(); + } + m_dxr3Device.SetPlayMode(); + +} + +#if VDRVERSNUM < 10307 +// ================================== +cOsdBase* cDxr3DemuxDevice::NewOsd(int x, int y) +{ + return m_dxr3Device.NewOsd(x, y); +} +#endif + +// ================================== +void cDxr3DemuxDevice::StillPicture(const uint8_t* buf, int length) +{ + m_vBuf.Clear(); + m_aBuf.Clear(); + m_demuxMode = DXR3_DEMUX_TRICK_MODE; + m_trickState = DXR3_FREEZE; + m_dxr3Device.SingleStep(); + + cLog::Instance() << "StillPicture: len = " << length << "\n"; + + DemuxPes(buf, length); + DemuxPes(buf, length); + DemuxPes(buf, length); +} + +// ================================== +int cDxr3DemuxDevice::DemuxPes(const uint8_t* buf, int length, bool bAc3Dts) +{ + uint32_t pts = 0; + static uint32_t aPts = 0; + static uint32_t vPts = 0; + static uint32_t lastPts = 0; + static bool bPlaySuc = false; + static bool bPlayedFrame = false; + int origLength = length; + + int scr = 0; + int pcr = 0; + + scr = m_dxr3Device.GetSysClock(); + + // printf("vBuf size = %d\n", m_vBuf.Available()); + // printf("aBuf size = %d\n", m_aBuf.Available()); + /* + if (cDxr3ConfigData::Instance().GetAc3OutPut()) { + cDxr3AbsDevice::Instance().SetAudioDigitalAC3(); // !!! FIXME + } + */ + + if (m_pAudioThread->NeedResync() || m_pVideoThread->NeedResync()) + { + Resync(); + if (m_demuxMode == DXR3_DEMUX_REPLAY_MODE) + { + SetReplayMode(); + } + m_aBuf.Clear(); + m_vBuf.Clear(); + m_pAudioThread->ClearResyncRequest(); + m_pVideoThread->ClearResyncRequest(); + m_aDecoder.Reset(); + lastPts = 0; + aPts = 0; + vPts = 0; + bPlaySuc = false; + } + + if (m_demuxMode == DXR3_DEMUX_OFF_MODE) + { + m_demuxMode = DXR3_DEMUX_TV_MODE; + m_synchState = DXR3_DEMUX_UNSYNCHED; + + lastPts = 0; + aPts = 0; + vPts = 0; + bPlaySuc = false; + /* + if (cDxr3ConfigData::Instance().GetAc3OutPut()) { + cDxr3AbsDevice::Instance().SetAudioDigitalAC3(); // !!! FIXME + } + */ + } + + // find start code + try + { + cDxr3PesFrame pesFrame; + + pesFrame.ExtractNextFrame(buf, length); + + while (pesFrame.IsValid()) + { + if (pesFrame.GetEsLength() > (uint32_t) VIDEO_MAX_FRAME_SIZE) { throw (cDxr3PesFrame::PES_GENERAL_ERROR);}; + if (pesFrame.GetPts() != lastPts) + { + pts = lastPts = pesFrame.GetPts(); + } + else + { + pts = 0; + } + + if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_VIDEO_DATA) + { + // m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength())); + + if (m_demuxMode == DXR3_DEMUX_TRICK_MODE) + { + switch (pesFrame.GetFrameType()) + { + case I_FRAME: + cLog::Instance() << "i - frame\n"; + m_dxr3Device.SingleStep(); + bPlaySuc = true; + // if (bPlayedFrame) return length; + bPlayedFrame = true; + // usleep(30000); // otherwise there is problem with audio (driver bug?) + m_dxr3Device.SetHorizontalSize(pesFrame.GetHorizontalSize()); + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), m_ReUseFrame); + break; + + case UNKNOWN_FRAME: + cLog::Instance() << "frame unknown\n"; + if (bPlaySuc) + { + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), m_ReUseFrame); + } + break; + + default: + cLog::Instance() << "default frame\n"; + if (bPlaySuc) + { + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetOffset()), m_ReUseFrame); + } + + bPlaySuc = false; + break; + } + + } + else if (m_demuxMode == DXR3_DEMUX_VIDEO_ONLY_MODE) + { + m_dxr3Device.PlayVideoFrame(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength())); + } + else if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + m_dxr3Device.SetHorizontalSize(pesFrame.GetHorizontalSize()); + while(!Poll(100)); + cFixedLengthFrame* pTempFrame = m_vBuf.Push(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, ftVideo); + pTempFrame->SetAspectRatio(pesFrame.GetAspectRatio()); + + m_aBuf.WakeUp(); + + if (m_vBuf.GetFillLevel() > 5 && m_synchState != DXR3_DEMUX_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + pcr = vPts - PRE_BUFFER_LENGTH; + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + else + { + if (pesFrame.GetFrameType() == I_FRAME) + { + vPts = pts; + + m_dxr3Device.SetHorizontalSize(pesFrame.GetHorizontalSize()); + cFixedLengthFrame* pTempFrame = m_vBuf.Push(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, ftVideo); + pTempFrame->SetAspectRatio(pesFrame.GetAspectRatio()); + + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_VIDEO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + + } + else if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_AUDIO_DATA + && m_demuxMode != DXR3_DEMUX_VIDEO_ONLY_MODE + && !cDxr3ConfigData::Instance().GetAc3OutPut()) + { + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + if (pts && m_synchState != DXR3_DEMUX_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + pcr = aPts - PRE_BUFFER_LENGTH; + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + while(!Poll(100)); + m_aDecoder.Decode(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, m_aBuf); + + } + else + { + if (pts) + { + aPts = pts; + + m_aDecoder.Decode(pesFrame.GetEsStart(), (int) (pesFrame.GetEsLength()), pts, m_aBuf); + + if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + } + else if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_PRIVATE_DATA + && m_demuxMode != DXR3_DEMUX_VIDEO_ONLY_MODE + && !cDxr3ConfigData::Instance().GetAc3OutPut() + && !bAc3Dts) + { + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + m_aDecoder.DecodeLpcm(pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + } + else + { + if (pts) + { + aPts = pts; + m_aDecoder.DecodeLpcm(pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + + if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + } + else if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_PRIVATE_DATA + && m_demuxMode != DXR3_DEMUX_VIDEO_ONLY_MODE + && cDxr3ConfigData::Instance().GetAc3OutPut() + && bAc3Dts) + { + if (m_synchState == DXR3_DEMUX_AUDIO_SYNCHED || m_synchState == DXR3_DEMUX_SYNCHED) + { + m_aDecoder.DecodeAc3Dts(pesFrame.GetPesStart(), pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + } + else + { + if (pts) + { + aPts = pts; + m_aDecoder.DecodeAc3Dts(pesFrame.GetPesStart(), pesFrame.GetEsStart(), pesFrame.GetEsLength(), pts, m_aBuf); + + if (m_synchState == DXR3_DEMUX_VIDEO_SYNCHED) + { + m_synchState = DXR3_DEMUX_SYNCHED; + } + else + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + } + if (m_synchState == DXR3_DEMUX_SYNCHED) + { + if (!vPts) vPts = aPts; + if (aPts < vPts) + { + pcr = aPts - PRE_BUFFER_LENGTH; + } + else + { + pcr = vPts - PRE_BUFFER_LENGTH; + } + m_dxr3Device.SetSysClock(pcr); + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + } + } + + } + + if (pesFrame.IsValid()) + { + pesFrame.ExtractNextFrame(pesFrame.GetNextStart(), pesFrame.GetRemainingLength()); + } + + } + + length -= pesFrame.GetRemainingLength(); + + // if (m_demuxMode == DXR3_DEMUX_TRICK_MODE) return origLength; + return length; + } + catch (cDxr3PesFrame::ePesFrameError err) + { + dsyslog("cDxr3DemuxDevice::DemuxPes() ePesFrameError skipping data and resync"); + Resync(); + return origLength; + } + catch (cDxr3SyncBuffer::eSyncBufferException err) + { + Stop(); + return origLength; + } +} + +// ================================== +int cDxr3DemuxDevice::DemuxAudioPes(const uint8_t* buf, int length) +{ + static int syncCounter = 0; + int origLength = length; + + m_demuxMode = DXR3_DEMUX_AUDIO_ONLY_MODE; + m_aBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + m_vBuf.SetDemuxMode(DXR3_DEMUX_REPLAY_MODE); + + try + { + cDxr3PesFrame pesFrame; + + pesFrame.ExtractNextFrame(buf, length); + + while (pesFrame.IsValid()) + { + if (pesFrame.GetPesDataType() == cDxr3PesFrame::PES_PRIVATE_DATA) + { + if (m_synchState != DXR3_DEMUX_AUDIO_SYNCHED && syncCounter > 2) + { + m_synchState = DXR3_DEMUX_AUDIO_SYNCHED; + m_dxr3Device.SetPlayMode(); + m_dxr3Device.EnableVideo(); + m_dxr3Device.EnableAudio(); + m_vBuf.Start(); + m_aBuf.Start(); + } + if (m_synchState != DXR3_DEMUX_AUDIO_SYNCHED && syncCounter <= 2) + { + syncCounter++; + } + while (!m_aBuf.Poll(100)); + m_aDecoder.DecodeLpcm(pesFrame.GetEsStart(), pesFrame.GetEsLength(), 0, m_aBuf); + + } + + if (pesFrame.IsValid()) + { + pesFrame.ExtractNextFrame(pesFrame.GetNextStart(), pesFrame.GetRemainingLength()); + } + } + + length -= pesFrame.GetRemainingLength(); + + return length; + } + catch (cDxr3PesFrame::ePesFrameError err) + { + dsyslog("cDxr3DemuxDevice::DemuxAudioPes() ePesFrameError skipping data and resync"); + Stop(); + return origLength; + } +} diff --git a/dxr3demuxdevice.h b/dxr3demuxdevice.h new file mode 100644 index 0000000..0bd6add --- /dev/null +++ b/dxr3demuxdevice.h @@ -0,0 +1,75 @@ +/* + * dxr3demuxdevice.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef __DXR3_DEMUX_DEVICE_H +#define __DXR3_DEMUX_DEVICE_H + +#include "dxr3vdrincludes.h" +#include "dxr3generaldefines.h" +#include "dxr3syncbuffer.h" +#include "dxr3audiodecoder.h" +#include "dxr3outputthread.h" + +const int AUDIO_MAX_BUFFER_SIZE = 200; +const int VIDEO_MAX_BUFFER_SIZE = 500; + +const int AUIDO_MAX_FRAME_SIZE = 5000; +const int VIDEO_MAX_FRAME_SIZE = 3000; +const uint32_t PRE_BUFFER_LENGTH = 0; + +// ================================== +// extract video and audio +class cDxr3DemuxDevice +{ +public: + cDxr3DemuxDevice(); + cDxr3DemuxDevice(cDxr3Interface& dxr3Device); + ~cDxr3DemuxDevice(); + +public: + void Stop(void); + void Resync(void); + void Clear(void); + void Init(void); + void SetTvMode(void); + void SetAudioOnlyMode(void); + void SetVideoOnlyMode(void); + void SetReplayMode(void); + void SetTrickMode(eDxr3TrickState trickState, int Speed = 1); + + #if VDRVERSNUM < 10307 + cOsdBase* NewOsd(int x, int y); + #endif + + int DemuxPes(const uint8_t* buf, int length, bool bAc3Dts = false); + int DemuxAudioPes(const uint8_t* buf, int length); + void StillPicture(const uint8_t* buf, int length); + + eDxr3DemuxMode GetDemuxMode(void) { return m_demuxMode;}; + eDxr3TrickState GetTrickState(void) { return m_trickState;}; + bool Poll(int TimeoutMs){ return m_aBuf.Poll(TimeoutMs) && m_vBuf.Poll(TimeoutMs); }; + // { return m_demuxMode == DXR3_DEMUX_AUDIO_ONLY_MODE ? m_aBuf.Poll(TimeoutMs) : m_aBuf.Poll(TimeoutMs); }; + +protected: + cDxr3Interface& m_dxr3Device; + cDxr3SyncBuffer m_aBuf; + cDxr3SyncBuffer m_vBuf; + eDxr3DemuxSynchState m_synchState; + eDxr3DemuxMode m_demuxMode; + eDxr3TrickState m_trickState; + cDxr3AudioDecoder m_aDecoder; + cDxr3AudioOutThread* m_pAudioThread; + cDxr3VideoOutThread* m_pVideoThread; + uint32_t m_stopScr; + int m_ReUseFrame; // how often a frame should be used + +private: + cDxr3DemuxDevice(cDxr3DemuxDevice&); // no copy constructor +}; + +#endif // __DXR3_DEMUX_DEVICE_H diff --git a/dxr3device.c b/dxr3device.c new file mode 100644 index 0000000..b7e2553 --- /dev/null +++ b/dxr3device.c @@ -0,0 +1,472 @@ +#include "dxr3device.h" +#include "dxr3configdata.h" +#include "dxr3interface.h" +#include "dxr3tools.h" +#include "dxr3log.h" + +extern "C" +{ + #include <jpeglib.h> +} + +// ================================== +cDxr3Device::cDxr3Device() : m_DemuxDevice(cDxr3Interface::Instance()) +{ + m_Offset = 0; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); + m_spuDecoder = NULL; + m_AC3Present = false; + m_CalledBySet = false; +} + +// ================================== +cDxr3Device::~cDxr3Device() +{ + if (m_spuDecoder) + { + delete m_spuDecoder; + } +} + +// ================================== +void cDxr3Device::MakePrimaryDevice(bool On) +{ +#if VDRVERSNUM >= 10307 + new cDxr3OsdProvider(); +#endif +} + +// replaying +// ================================== +bool cDxr3Device::HasDecoder() const +{ + // sure we have one ;) + return true; +} + +// ================================== +bool cDxr3Device::CanReplay() const +{ + // also sure... + return true; +} + +// ================================== +bool cDxr3Device::SetPlayMode(ePlayMode PlayMode) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + switch (PlayMode) + { + case pmNone: + cLog::Instance() << "cDxr3Device::SetPlayMode audio/video from decoder\n"; + break; + + case pmAudioVideo: + cLog::Instance() << "cDxr3Device::SetPlayMode audio/video from player\n"; + break; + + case pmAudioOnly: + cLog::Instance() << "cDxr3Device::SetPlayMode audio only from player, video from decoder\n"; + break; + + case pmAudioOnlyBlack: + cLog::Instance() << "cDxr3Device::SetPlayMode audio only from player, no video (black screen)\n"; + break; + + case pmExtern_THIS_SHOULD_BE_AVOIDED: + cLog::Instance() << "cDxr3Device::SetPlayMode this should be avoided\n"; + break; + + #if VDRVERSNUM >= 10307 + case pmVideoOnly: + cLog::Instance() << "cDxr3Device::SetPlayMode video only from player, audio from decoder\n"; + break; + #endif + } + } + + if (PlayMode == pmExtern_THIS_SHOULD_BE_AVOIDED) + { + Tools::WriteInfoToOsd("Dxr3: Releasing devices\n"); + cDxr3Interface::Instance().ExternalReleaseDevices(); + } + else + { + cDxr3Interface::Instance().ExternalReopenDevices(); + } + + // should this relay be here? + m_Offset = 0; + m_AC3Present = false; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); + + if (PlayMode == pmAudioOnlyBlack) + { + m_PlayMode = pmAudioOnly; + } + else + { + m_PlayMode = PlayMode; + } + + if (m_PlayMode == pmAudioVideo) + { + m_DemuxDevice.SetReplayMode(); + } + + if (m_PlayMode == pmNone) + { + m_DemuxDevice.Stop(); + } + + cLog::Instance() << "Setting audio mode..."; + + if (cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + if (cDxr3ConfigData::Instance().GetAc3OutPut() && m_CalledBySet) + { + cDxr3Interface::Instance().SetAudioDigitalAC3(); // !!! FIXME + cLog::Instance() << "ac3\n"; + } + else + { + cDxr3Interface::Instance().SetAudioDigitalPCM(); + cDxr3ConfigData::Instance().SetAc3OutPut(0); + cLog::Instance() << "digital pcm\n"; + } + } + else + { + cDxr3Interface::Instance().SetAudioAnalog(); + cLog::Instance() << "analog\n"; + } + + return true; +} + +// ================================== +int64_t cDxr3Device::GetSTC() +{ + return cDxr3Interface::Instance().GetSysClock(); +} + +// ================================== +void cDxr3Device::TrickSpeed(int Speed) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::TrickSpeed(int Speed): " << Speed << "\n"; + } + + + m_DemuxDevice.SetTrickMode(DXR3_FAST, Speed); + + +/* + switch (Speed) + { + case 6: + cLog::Instance() << "Trickspeed: 1x vorwärts\n"; + break; + + case 3: + cLog::Instance() << "Trickspeed: 2x vorwärts\n"; + break; + + case 1: + cLog::Instance() << "Trickspeed: 3x vorwärts\n"; + break; + }; +*/ +/* + 6 ... 1x vowärts + 3 ... 2x vowärts + 1 ... 2x vowärts + + 6 ... 1x rückwärts + 3 ... 2x rückwärts + 1 ... 3x rückwärts + + 8 ... 1x vorwörts, wenn Pause gedrückt +*/ + + /* +#define EM8300_PLAYMODE_PAUSED 1 +#define EM8300_PLAYMODE_SLOWFORWARDS 2 +#define EM8300_PLAYMODE_SLOWBACKWARDS 3 +#define EM8300_PLAYMODE_SINGLESTEP 4 + */ + /* + if (Speed == 8) + { + cDxr3Interface::Instance().SingleStep(); + } + else + { + m_DemuxDevice.SetTrickMode(DXR3_FAST); + }*/ +} + +// ================================== +// clear our demux buffer +void cDxr3Device::Clear() +{ + m_DemuxDevice.Clear(); + m_Offset = 0; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); +} + +// ================================== +// play a recording +void cDxr3Device::Play() +{ + m_DemuxDevice.SetReplayMode(); + m_Offset = 0; + m_strBuf.erase(m_strBuf.begin(), m_strBuf.end()); +} + +// ================================== +// puts the device into "freeze frame" mode +void cDxr3Device::Freeze() +{ + m_DemuxDevice.SetTrickMode(DXR3_FREEZE); +} + +// ================================== +void cDxr3Device::Mute() +{ + m_DemuxDevice.SetTrickMode(DXR3_FAST); +} + +// ================================== +// displays the given I-frame as a still picture. +void cDxr3Device::StillPicture(const uchar *Data, int Length) +{ + m_DemuxDevice.StillPicture(Data, Length); +} + +// ================================== +bool cDxr3Device::Poll(cPoller &Poller, int TimeoutMs) +{ + return m_DemuxDevice.Poll(TimeoutMs); // Poller.Poll(TimeoutMs); +} + +// ================================== +// actually plays the given data block as video +int cDxr3Device::PlayVideo(const uchar *Data, int Length) +{ + int retLength = 0; + int origLength = Length; + + if ((m_DemuxDevice.GetDemuxMode() == DXR3_DEMUX_TRICK_MODE && + m_DemuxDevice.GetTrickState() == DXR3_FREEZE) || cDxr3Interface::Instance().IsExternalReleased()) + { + // Why is here so a huge time waster? + //usleep(1000000); + return 0; + } + + if (m_strBuf.length()) + { + m_strBuf.append((const char*)Data, Length); + + if (m_PlayMode == pmAudioOnly) + { + retLength = m_DemuxDevice.DemuxAudioPes((const uint8_t*)m_strBuf.data(), m_strBuf.length()); + } + else + { + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)m_strBuf.data(), m_strBuf.length()); + } + } + else + { + if (m_PlayMode == pmAudioOnly) + { + retLength = m_DemuxDevice.DemuxAudioPes((const uint8_t*)Data, Length); + } + else + { + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)Data, Length); + } + } + + Length -= retLength; + + if (m_strBuf.length()) + { + m_strBuf.erase(m_strBuf.length() - retLength, retLength); + } + else + { + if (Length) + { + m_strBuf.append((const char*)(Data + retLength), Length); + } + } + + return origLength; +} + +// ================================== +// plays additional audio streams, like Dolby Digital +void cDxr3Device::PlayAudio(const uchar *Data, int Length) +{ + int retLength = 0; + + #if VDRVERSNUM < 10307 + if (!m_AC3Present) + { + Interface->Write(Interface->Width() / 2, 0, "AC3", clrRed); + } + #endif + + m_AC3Present = true; + + if ((m_DemuxDevice.GetDemuxMode() == DXR3_DEMUX_TRICK_MODE && + m_DemuxDevice.GetTrickState() == DXR3_FREEZE) || cDxr3Interface::Instance().IsExternalReleased()) + { + //usleep(1000000); + return; + } + + if (m_strBuf.length()) + { + m_strBuf.append((const char*)Data, Length); + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)m_strBuf.data(), m_strBuf.length(), true); + } + else + { + retLength = m_DemuxDevice.DemuxPes((const uint8_t*)Data, Length, true); + } + + Length -= retLength; + + if (m_strBuf.length()) + { + m_strBuf.erase(m_strBuf.length() - retLength, retLength); + } + else + { + if (Length) + { + m_strBuf.append((const char*)(Data + retLength), Length); + } + } +} + +// addition functions +// ================================== +// capture a single frame as an image +bool cDxr3Device::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) +{ + int w = SizeX; + int h = SizeY; + unsigned char *Data = new unsigned char[w*h*3]; + memset(Data, 0, w*h*3); + + // we could get a I-Frame and save it + //m_DemuxDevice.StillPicture(Data, 100*1024); + + isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, w, h); + FILE *f = fopen(FileName, "wb"); + if (f) + { + if (Jpeg) + { + // write JPEG file: + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = w; + cinfo.image_height = h; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, Quality, true); + jpeg_start_compress(&cinfo, true); + + int rs = w * 3; + JSAMPROW rp[h]; + for (int k = 0; k < h; k++) + { + rp[k] = &Data[rs * k]; + } + jpeg_write_scanlines(&cinfo, rp, h); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + } + else + { + // write PNM file: + if (fprintf(f, "P6\n%d\n%d\n255\n", w, h) < 0 || fwrite(Data, w * h * 3, 1, f) < 0) + { + LOG_ERROR_STR(FileName); + } + } + fclose(f); + } + else + { + return false; + } + + delete Data; + return true; +} + +// ================================== +void cDxr3Device::SetVideoFormat(bool VideoFormat16_9) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::SetPlayMode(ePlayMode PlayMode)() done\n"; + } + // Do we need this function? +} + +// ================================== +// sets volume for audio output +void cDxr3Device::SetVolumeDevice(int Volume) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "change volume to " << Volume << " \n"; + } + cDxr3Interface::Instance().SetVolume(Volume); +} + +// ================================== +// get spudecoder +cSpuDecoder *cDxr3Device::GetSpuDecoder(void) +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::GetSpuDecoder"; + } + + if (!m_spuDecoder && IsPrimaryDevice()) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Device::GetSpuDecoder: ok"; + } + m_spuDecoder = new cDxr3SpuDecoder(); + } + return m_spuDecoder; +} + +#if VDRVERSNUM < 10307 +// ================================== +// return osd +cOsdBase *cDxr3Device::NewOsd(int x, int y) +{ + return m_DemuxDevice.NewOsd(x, y); +} +#endif + diff --git a/dxr3device.h b/dxr3device.h new file mode 100644 index 0000000..69ad28d --- /dev/null +++ b/dxr3device.h @@ -0,0 +1,65 @@ +#ifndef _DXR3_DEVICE_H_ +#define _DXR3_DEVICE_H_ + +#include "dxr3interface.h" +#include "dxr3log.h" +#include "dxr3demuxdevice.h" +#include "dxr3spudecoder.h" +#include <string> +using namespace std; + +// ================================== +// our device :) +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); + virtual void PlayAudio(const uchar *Data, int Length); + + // addition functions + virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + virtual void SetVideoFormat(bool VideoFormat16_9); + virtual void SetVolumeDevice(int Volume); + + // osd + virtual cSpuDecoder *GetSpuDecoder(); + #if VDRVERSNUM < 10307 + virtual cOsdBase* NewOsd(int x, int y); + #endif + + // helper function + void Reset() { m_CalledBySet = true; SetPlayMode(m_PlayMode); m_CalledBySet = false; } + +protected: + ePlayMode m_PlayMode; + cDxr3DemuxDevice m_DemuxDevice; + bool m_AC3Present; + bool m_CalledBySet; + string m_strBuf; + int m_Offset; + + //virtual bool SetPlayMode(ePlayMode PlayMode); + //uint8_t m_pBuffer[MAX_VIDEO_BUFFER_SIZE]; + //cDxr3StartStopThread* m_pStartStopThread; + cDxr3SpuDecoder* m_spuDecoder; +}; + +#endif /*_DXR3_DEVICE_H_*/ diff --git a/dxr3ffmpeg.c b/dxr3ffmpeg.c new file mode 100644 index 0000000..e35319a --- /dev/null +++ b/dxr3ffmpeg.c @@ -0,0 +1,72 @@ +/* + * dxr3audiodecoder.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#include "dxr3ffmpeg.h" + +#include "dxr3configdata.h" +#include "dxr3log.h" + +// ================================== +cDxr3Ffmepg::cDxr3Ffmepg() +{ + avcodec_init(); + avcodec_register_all(); +} + +// ================================== +bool cDxr3Ffmepg::FindCodec(struct Dxr3Codec& Codec) +{ + // find codec + Codec.codec = avcodec_find_decoder(Codec.id); + + if (!Codec.codec) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Ffmepg::OpenCodec(struct Dxr3Codec& Codec) codec not found (" << Codec.id << ")\n"; + } + return false; + } + + // init codec_context + memset(&Codec.codec_context, 0, sizeof(Codec.codec_context)); + + return true; +} + +// ================================== +bool cDxr3Ffmepg::OpenCodec(struct Dxr3Codec& Codec) +{ + // try to open codec + int result = avcodec_open(&Codec.codec_context, Codec.codec); + + if (result < 0) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Ffmepg::OpenCodec(struct Dxr3Codec& Codec) coudnt open codec (" << Codec.id << ")\n"; + } + return false; + } + else + { + Codec.Open = true; + } + + return true; +} + +// ================================== +void cDxr3Ffmepg::CloseCodec(struct Dxr3Codec& Codec) +{ + if (Codec.Open) + { + avcodec_close(&Codec.codec_context); + Codec.Open = false; + } +} diff --git a/dxr3ffmpeg.h b/dxr3ffmpeg.h new file mode 100644 index 0000000..7795f74 --- /dev/null +++ b/dxr3ffmpeg.h @@ -0,0 +1,42 @@ +#ifndef _DXR3_FFMPEG_H_ +#define _DXR3_FFMPEG_H_ + +extern "C" +{ + #include <avcodec.h> +}; + +//#include <stdlib.h> +//#include <stdint.h> +#include <string.h> +#include "dxr3singleton.h" + +// ================================== +// a codec used by this plugin +struct Dxr3Codec +{ + Dxr3Codec() : Open(false) {} + + AVCodec* codec; + AVCodecContext codec_context; + enum CodecID id; + bool Open; +}; + +// ================================== +// class to work with ffmpeg +class cDxr3Ffmepg : public Singleton<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_*/ diff --git a/dxr3generaldefines.h b/dxr3generaldefines.h new file mode 100644 index 0000000..29a0ae6 --- /dev/null +++ b/dxr3generaldefines.h @@ -0,0 +1,37 @@ +/* + * dxr3generaldefines.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef __DXR3_GENERAL_DEFINES_H +#define __DXR3_GENERAL_DEFINES_H + +enum eDxr3DemuxSynchState { + DXR3_DEMUX_AUDIO_SYNCHED, + DXR3_DEMUX_VIDEO_SYNCHED, + DXR3_DEMUX_SYNCHED, + DXR3_DEMUX_UNSYNCHED +}; + +enum eDxr3DemuxMode { + DXR3_DEMUX_TV_MODE, + DXR3_DEMUX_REPLAY_MODE, + DXR3_DEMUX_AUDIO_ONLY_MODE, + DXR3_DEMUX_VIDEO_ONLY_MODE, + DXR3_DEMUX_TRICK_MODE, + DXR3_DEMUX_OFF_MODE +}; + +enum eDxr3TrickState { + DXR3_FAST, + DXR3_SLOW, + DXR3_FREEZE, +}; + + + + +#endif // __DXR3_GENERAL_DEFINES_H diff --git a/dxr3i18n.c b/dxr3i18n.c new file mode 100644 index 0000000..2c91e33 --- /dev/null +++ b/dxr3i18n.c @@ -0,0 +1,804 @@ +#include "dxr3i18n.h" + +const char *i18n_name = 0; + +// vdr 1.1.32 -> 16 +// vdr 1.3.2 -> 17 +// vdr 1.3.7 -> 18 + +// Digital audio output +// DXR3 card +// DXR3 video mode +// DXR3 menu mode +// Reset DXR3 Hardware +// Toggle Force LetterBox +// Analog Output +// AC3 Output On +// AC3 Output Off +// Digital Output +// Sub-Picutre +// MPEG +// Dxr3: Releasing devices + +// add +// Dxr3: Releasing devices +/* + * Translations provided by: + * + * Slovenian Miha Setina <mihasetina@softhome.net> and Matjaz Thaler <matjaz.thaler@guest.arnes.si> + * Italian Alberto Carraro <bertocar@tin.it> and Antonio Ospite <ospite@studenti.unina.it> + * Dutch Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com> and Hans Dingemans <hans.dingemans@tacticalops.nl> + * Portuguese Paulo Lopes <pmml@netvita.pt> + * French Jean-Claude Repetto <jc@repetto.org>, Olivier Jacques <jacquesolivier@hotmail.com> and Gregoire Favre <greg@magma.unil.ch> + * Norwegian Jørgen Tvedt <pjtvedt@online.no> and Truls Slevigen <truls@slevigen.no> + * Finnish Hannu Savolainen <hannu@opensound.com>, Jaakko Hyvätti <jaakko@hyvatti.iki.fi>, Niko Tarnanen <niko.tarnanen@hut.fi> and Rolf Ahrenberg <rahrenbe@cc.hut.fi> + * Polish Michael Rakowski <mrak@gmx.de> + * Spanish Ruben Nunez Francisco <ruben.nunez@tang-it.com> + * Greek Dimitrios Dimitrakos <mail@dimitrios.de> + * Swedish Tomas Prybil <tomas@prybil.se> and Jan Ekholm <chakie@infa.abo.fi> + * Romanian Paul Lacatus <paul@campina.iiruc.ro> + * Hungarian Istvan Koenigsberger <istvnko@hotmail.com> and Guido Josten <guido.josten@t-online.de> + * Catalanian Marc Rovira Vall <tm05462@salleURL.edu>, Ramon Roca <ramon.roca@xcombo.com> and Jordi Vilà <jvila@tinet.org> + * Russian Vyacheslav Dikonov <sdiconov@mail.ru> + * Croatian Drazen Dupor <drazen.dupor@dupor.com> + * + */ + + +#if VDRVERSNUM >= 10307 +// vdr 1.3.7 -> 18 languages + +/* +const tI18nPhrase Phrases[] = { + // The name of the language (this MUST be the first phrase!): + { "English", + "Deutsch", + "Slovenski", + "Italiano", + "Nederlands", + "Português", + "Français", + "Norsk", + "suomi", // this is not a typo - it's really lowercase! + "Polski", + "Español", + "ÅëëçíéêÜ", // Greek + "Svenska", + "Romaneste", + "Magyar", + "Català", + "ÀãááÚØÙ", // Russian + "Hrvatski", + }, +*/ + +const tI18nPhrase Phrases[] = { + { + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + }, + { + "Digital audio output", + "Digitaler Audioausgang", + "", // TODO + "", // TODO + "", // TODO + "Saída áudio digital", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 card", + "DXR3 Karte", + "", // TODO + "", // TODO + "", // TODO + "Placa DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 video mode", + "DXR3 Video-Modus", + "", // TODO + "", // TODO + "", // TODO + "Modo vídeo DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 menu mode", + "DXR3 Menü-Modus", + "", // TODO + "", // TODO + "", // TODO + "Modo menu DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Reset DXR3 Hardware", + "Resete DXR3 Hardware", + "", // TODO + "", // TODO + "", // TODO + "Reiniciar DXR3", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Toggle Force LetterBox", + "LetterBox erzwingen", + "", // TODO + "", // TODO + "", // TODO + "Activar Forçar LetterBox", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Analog Output", + "Analoge Ausgabe", + "", // TODO + "", // TODO + "", // TODO + "Saída Analógica", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output On", + "AC3 Ausgabe Ein", + "", // TODO + "", // TODO + "", // TODO + "Saída AC3 Activa", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output Off", + "AC3 Ausgabe Aus", + "", // TODO + "", // TODO + "", // TODO + "Saída AC3 Inactiva", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Digital Output", + "Digitaler Ausgang", + "", // TODO + "", // TODO + "", // TODO + "Saída Digital", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Imagem", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + }, + { "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + }, + { "DXR3: Releasing devices", + "DXR3: Releasing devices", + "", // TODO + "", // TODO + "", // TODO + "DXR3: A libertar dispositivos", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { NULL } +}; + + +#elif VDRVERSNUM <= 10302 +// vdr 1.1.32 -> 16 languages + +const tI18nPhrase Phrases[] = { + { + "Digital audio output", + "Digitaler Audioausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 card", + "DXR3 Karte", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 video mode", + "DXR3 Video-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 menu mode", + "DXR3 Menü-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Reset DXR3 Hardware", + "Resete DXR3 Hardware", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Toggle Force LetterBox", + "LetterBox erzwingen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Analog Output", + "Analoge Ausgabe", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output On", + "AC3 Ausgabe Ein", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output Off", + "AC3 Ausgabe Aus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Digital Output", + "Digitaler Ausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + }, + { "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + }, + { NULL } +}; + +#else +// vdr 1.3.2 -> 17 languages + +const tI18nPhrase Phrases[] = { + { + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + "DXR3", + }, + { + "Digital audio output", + "Digitaler Audioausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 card", + "DXR3 Karte", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 video mode", + "DXR3 Video-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DXR3 menu mode", + "DXR3 Menü-Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Reset DXR3 Hardware", + "Resete DXR3 Hardware", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Toggle Force LetterBox", + "LetterBox erzwingen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Analog Output", + "Analoge Ausgabe", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output On", + "AC3 Ausgabe Ein", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "AC3 Output Off", + "AC3 Ausgabe Aus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Digital Output", + "Digitaler Ausgang", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + "Sub-Picture", + }, + { "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + "MPEG", + }, + { NULL } +}; + +#endif diff --git a/dxr3i18n.h b/dxr3i18n.h new file mode 100644 index 0000000..990d2ee --- /dev/null +++ b/dxr3i18n.h @@ -0,0 +1,12 @@ +#ifndef _DXR3_I18N_H_ +#define _DXR3_I18N_H_ + +#include <vdr/i18n.h> + +extern const char *i18n_name; +extern const tI18nPhrase Phrases[]; + +#undef tr +#define tr(s) I18nTranslate(s, i18n_name) + +#endif /*_DXR3_I18N_H_*/ diff --git a/dxr3interface.c b/dxr3interface.c new file mode 100644 index 0000000..50302d6 --- /dev/null +++ b/dxr3interface.c @@ -0,0 +1,1072 @@ +#include <assert.h> +#include <math.h> +#include <sys/soundcard.h> +#include "dxr3interface.h" +#include "dxr3syncbuffer.h" + +#include "dxr3log.h" +#include "dxr3configdata.h" + +// ================================== +const int LPCM_HEADER_LENGTH = 7; +const int ZEROBUFFER_SIZE = 4096; +uint8_t zerobuffer[ZEROBUFFER_SIZE] = {0}; + +// ================================== +// helper function to generate name +static const char *Dxr3Name(const char *Name, int n) +{ + static char buffer[PATH_MAX]; + snprintf(buffer, sizeof(buffer), "/dev/em8300%s-%d", Name, n); + return buffer; +} + +// ================================== +// helper function to open the card #n +static int Dxr3Open(const char *Name, int n, int Mode) +{ + const char *FileName = Dxr3Name(Name, n); + int fd = open(FileName, Mode); + + if (fd < 0) + { + cLog::Instance() << "Unable to open " << FileName << "\n"; + } + return fd; +} + +// ================================== +cDxr3Interface::cDxr3Interface() +{ + // open control stream + m_fdControl = Dxr3Open("", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + if (!m_fdControl) + { + cLog::Instance() << "Unable to open the control stream!\n"; + cLog::Instance() << "Please check if the dxr3 modules are loaded!\n"; + } + + // upload microcode to dxr3 + UploadMicroCode(); + + // open 'multimedia' streams + m_fdVideo = Dxr3Open("_mv", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdAudio = Dxr3Open("_ma", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdSpu = Dxr3Open("_sp", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + + // everything ok? + if (!m_fdVideo || !m_fdAudio || !m_fdSpu) + { + cLog::Instance() << "Unable to open one of the 'mulitmedia' streams!\n"; + exit(1); + } + + m_pClock = new cDxr3SysClock(m_fdControl, m_fdVideo, m_fdSpu); + + if (!m_pClock) + { + cLog::Instance() << "Unable to allocate memory for m_pClock in cDxr3Interface\n"; + exit(1); + } + + // set default values + m_AudioActive = false; + m_VideoActive = false; + m_OverlayActive = false; + m_ExternalReleased = false; + m_volume = 255; + m_horizontal = 720; + m_audioChannelCount = UNKNOWN_CHANNEL_COUNT; + m_audioDataRate = 0; + m_audioSampleSize = 0; + + // default value 9 = unused value + m_audioMode = 9; + m_aspectRatio = UNKNOWN_ASPECT_RATIO; + m_spuMode = EM8300_SPUMODE_OFF; + + // configure device based on settings + ConfigureDevice(); + + PlayBlackFrame(); + SetChannelCount(1); +} + +// ================================== +cDxr3Interface::~cDxr3Interface() +{ + // close filehandles + if (m_fdControl) + { + close(m_fdControl); + } + if (m_fdVideo) + { + close(m_fdVideo); + } + if (m_fdSpu) + { + close(m_fdSpu); + } + if (m_fdAudio) + { + close(m_fdAudio); + } + + // free some memory + if (m_pClock) + { + delete m_pClock; + } +} + +// main +// ================================== +void cDxr3Interface::Start() +{ +} + +// ================================== +void cDxr3Interface::Stop() +{ +} + +// audio +// ================================== +// set audio-output to analog +void cDxr3Interface::SetAudioAnalog() +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_audioMode != EM8300_AUDIOMODE_ANALOG) + { + int prevMode = m_audioMode; + m_audioMode = ioval = EM8300_AUDIOMODE_ANALOG; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_AUDIOMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioAnalog Unable to set audiomode!\n"; + } + if (prevMode == EM8300_AUDIOMODE_DIGITALAC3) + { + ReOpenAudio(); + } + } + + Unlock(); +} + +// ================================== +// set audio-output to digital pcm +void cDxr3Interface::SetAudioDigitalPCM() +{ + int ioval = 0; + Lock(); + + if (m_ExternalReleased && m_audioMode != EM8300_AUDIOMODE_DIGITALPCM) + { + int prevMode = m_audioMode; + m_audioMode = ioval = EM8300_AUDIOMODE_DIGITALPCM; + + if (ioctl(m_fdControl, EM8300_IOCTL_SET_AUDIOMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioAnalog Unable to set audiomode!\n"; + } + if (prevMode == EM8300_AUDIOMODE_DIGITALAC3) + { + ReOpenAudio(); + } + } + + Unlock(); +} + +// ================================== +// set audio-output to digital ac3 +void cDxr3Interface::SetAudioDigitalAC3() +{ + if (m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + m_audioMode = ioval = EM8300_AUDIOMODE_DIGITALAC3; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_AUDIOMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioAnalog Unable to set audiomode!\n"; + } + ReOpenAudio(); + } + + Unlock(); + } +} + +// ================================== +void cDxr3Interface::SetAudioSpeed(uint32_t speed) +{ + if (m_audioDataRate != speed && speed != UNKNOWN_DATA_RATE) + { + if (!m_ExternalReleased) + { + if (m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + if(ioctl(m_fdAudio, SNDCTL_DSP_SPEED, &speed) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAudioSpeed Unable to set dsp speed\n"; + } + } + } + m_audioDataRate = speed; + } +} + +// ================================== +void cDxr3Interface::SetChannelCount(uint32_t count) +{ + if (m_audioChannelCount != count && count != UNKNOWN_CHANNEL_COUNT) + { + if (!m_ExternalReleased) + { + if (m_audioMode != EM8300_AUDIOMODE_DIGITALAC3) + { + if (ioctl(m_fdAudio, SNDCTL_DSP_STEREO, &count) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetChannelCount Unable to set channel count\n"; + } + } + } + m_audioChannelCount = count; + } +} + +// ================================== +void cDxr3Interface::SetAudioSampleSize(uint32_t sampleSize) +{ + if (!m_ExternalReleased) + { + if (ioctl(m_fdAudio, SNDCTL_DSP_SAMPLESIZE, sampleSize)) + { + cLog::Instance() <<"cDxr3AbsDevice::SetAudioSampleSize Unable to set audio sample size\n"; + } + } + m_audioSampleSize = sampleSize; +} + +// clock +// ================================== +void cDxr3Interface::SetSysClock(uint32_t scr) +{ + if (!m_ExternalReleased) + { + m_pClock->SetSysClock(scr); + } +} + +// ================================== +uint32_t cDxr3Interface::GetSysClock() const +{ + uint32_t ret = 0; + if (!m_ExternalReleased) + { + ret = m_pClock->GetSysClock(); + } + return ret; +} + +// ================================== +void cDxr3Interface::SetPts(uint32_t pts) +{ + if (!m_ExternalReleased) + { + m_pClock->SetPts(pts); + } +} + +// ================================== +void cDxr3Interface::SetSpuPts(uint32_t pts) +{ + pts = pts >> 1; + if (!m_ExternalReleased) + { + if (pts > m_pClock->GetSysClock() && pts - m_pClock->GetSysClock() < 100000) + { + m_pClock->SetSpuPts(pts); + } + } +} + +// state changes +// ================================== +// enable subpicture proeccesing of the dxr3 +void cDxr3Interface::EnableSPU() +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_spuMode != EM8300_SPUMODE_ON) + { + m_spuMode = ioval = EM8300_SPUMODE_ON; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_SPUMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::EnableSpu Unable to set subpicture mode!\n"; + } + } + + Unlock(); +} + +// ================================== +// disable subpicture proeccesing of the dxr3 +void cDxr3Interface::DisableSPU() +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased && m_spuMode != EM8300_SPUMODE_OFF) + { + m_spuMode = ioval = EM8300_SPUMODE_OFF; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_SPUMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::EnableSpu Unable to set subpicture mode!\n"; + } + } + + Unlock(); +} + +// ================================== +// disable audio output of dxr3 +void cDxr3Interface::DisableAudio() +{ + m_AudioActive = false; + + // we wirte zero buffers to dxr3 + if (!m_ExternalReleased) + { + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + if (write(m_fdAudio, zerobuffer, ZEROBUFFER_SIZE) < 0) Resuscitation(); + } +} + +// ================================== +// enable overlay mode of the dxr3 +void cDxr3Interface::EnableOverlay() +{ + // first we check, if it is enable yet + if (m_OverlayActive) + { + return; + } + + /* + #define EM8300_OVERLAY_SIGNAL_ONLY 1 + #define EM8300_OVERLAY_SIGNAL_WITH_VGA 2 + #define EM8300_OVERLAY_VGA_ONLY 3 + */ + + int ioval = EM8300_OVERLAY_SIGNAL_WITH_VGA; + // set overlay signal mode + if (ioctl(m_fdControl, EM8300_IOCTL_OVERLAY_SIGNALMODE, &ioval) < 0) + { + //###### + cLog::Instance() << "Singnalmode failed\n"; + return; + } + + // setup overlay screen + em8300_overlay_screen_t scr; + scr.xsize = 1024; + scr.ysize = 768; + + if (ioctl(m_fdControl, EM8300_IOCTL_OVERLAY_SETSCREEN, &scr) < 0) + { + //###### + cLog::Instance() << "seting up screen failed\n"; + return; + } + + // setup overlay window + em8300_overlay_window_t win; + win.xpos = 0; + win.ypos = 0; + win.width = 1024; + win.height = 768; + + if (ioctl(m_fdControl, EM8300_IOCTL_OVERLAY_SETWINDOW, &win) < 0) + { + //###### + cLog::Instance() << "seting up window failed\n"; + return; + } + + m_OverlayActive = true; +} + +// ================================== +// disable overlay mode of the dxr3 +void cDxr3Interface::DisanleOverlay() +{ + // is it allready disabled + if (!m_OverlayActive) + { + return; + } +} + +// set/get functions +// ================================== +// get aspect ratio +uint32_t cDxr3Interface::GetAspectRatio() const +{ + int ioval = 0; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_GET_ASPECTRATIO, &ioval) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::GetAspectRatio Unable to get aspect ratio\n"; + } + } + + Unlock(); + return ioval; +} + +// ================================== +void cDxr3Interface::SetAspectRatio(uint32_t ratio) +{ + static int requestCounter = 0; + + Lock(); + + if (cDxr3ConfigData::Instance().GetForceLetterBox()) ratio = EM8300_ASPECTRATIO_16_9; + + if (!m_ExternalReleased && ratio != UNKNOWN_ASPECT_RATIO) + { + if (ratio != m_aspectRatio && requestCounter > 50) + { + requestCounter = 0; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_ASPECTRATIO, &ratio) < 0) + { + cLog::Instance() << "cDxr3AbsDevice::SetAspectRatio Unable to set aspect ratio\n"; + } + else + { + m_aspectRatio = ratio; + } + } + else + { + if (ratio != m_aspectRatio) + { + ++requestCounter; + } + else + { + requestCounter = 0; + } + } + } + + Unlock(); +} + +// play functions +// ================================== +// set playing mode and start sync engine +void cDxr3Interface::SetPlayMode() +{ + em8300_register_t reg; + int ioval; + + Lock(); + + if (!m_ExternalReleased) + { + ioval = EM8300_SUBDEVICE_AUDIO; + ioctl(m_fdControl, EM8300_IOCTL_FLUSH, &ioval); + fsync(m_fdVideo); + + + ioval = EM8300_PLAYMODE_PLAY; + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3Device::SetPlayMode Unable to set playmode!\n"; + } + reg.microcode_register = 1; + reg.reg = 0; + reg.val = MVCOMMAND_SYNC; + + if (ioctl(m_fdControl, EM8300_IOCTL_WRITEREG, ®) < 0) + { + cLog::Instance() << "cDxr3Device::SetPlayMode Unable to start em8300 sync engine\n"; + } + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::Pause() +{ + int ioval = EM8300_PLAYMODE_PAUSED; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) + { + cLog::Instance() << "cDxr3Device::Pause Unable to set playmode!\n"; + } + } + + Unlock(); +} +// ================================== +void cDxr3Interface::SingleStep() +{ + int ioval = EM8300_PLAYMODE_SINGLESTEP; + Lock(); + + if (!m_ExternalReleased) + { + if (ioctl(m_fdControl, EM8300_IOCTL_SET_PLAYMODE, &ioval) < 0) { + cLog::Instance() << "cDxr3Device::Pause Unable to set playmode!\n"; + } + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::PlayVideoFrame(cFixedLengthFrame* pFrame, int times) +{ + int written = 0; + int count = 0; + + if (m_VideoActive) + { + Lock(); + + if (!m_ExternalReleased) + { + for (int i = 0; i < times; i++) + { + if (times > 1) + { + cLog::Instance() << "times: " << times << "\n"; + } + + while (written < pFrame->GetCount() && count >= 0) + { + if ((count = write(m_fdVideo, pFrame->GetData() + written, pFrame->GetCount() - written)) < 0) + { + // an error occured + Resuscitation(); + } + written += count; + } + + // reset + written = 0; + } + } + + Unlock(); + + SetAspectRatio(pFrame->GetAspectRatio()); + } +} + +// ================================== +void cDxr3Interface::PlayVideoFrame(const uint8_t* pBuf, int length, int times) +{ + Lock(); + + if (!m_ExternalReleased) + { + for (int i = 0; i < times; i++) + { + if (write(m_fdVideo, pBuf, length) < 0) Resuscitation(); + } + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::PlayAudioFrame(cFixedLengthFrame* pFrame) +{ + + // XXX: Call this only with we are not in external mode? + + if (m_AudioActive) + { + Lock(); + + SetAudioSpeed(pFrame->GetDataRate()); + SetChannelCount(pFrame->GetChannelCount()); + + if (!m_ExternalReleased) + { + if (!cDxr3ConfigData::Instance().GetAc3OutPut()) ResampleVolume((short*)pFrame->GetData(), pFrame->GetCount()); + write(m_fdAudio, pFrame->GetData(), pFrame->GetCount()); + } + + Unlock(); + } +} + +// ================================== +void cDxr3Interface::PlayAudioFrame(uint8_t* pBuf, int length) +{ + int written = 0; + Lock(); + + if (!m_ExternalReleased) + { + if (!cDxr3ConfigData::Instance().GetAc3OutPut()) ResampleVolume((short*)pBuf, length); + + if ((written = write(m_fdAudio, pBuf, length) < 0)) Resuscitation(); + if (written != length) + { + cLog::Instance() << "cDxr3Interface::PlayAudioFrame(uint8_t* pBuf, int length): Not written = " << length - written << "\n"; + } + } + Unlock(); +} + +// ================================== +void cDxr3Interface::PlayAudioLpcmFrame(uint8_t* pBuf, int length) +{ + if (length > (LPCM_HEADER_LENGTH + 2)) + { + uint8_t* pFrame = new uint8_t[length - LPCM_HEADER_LENGTH]; + assert(!((length - LPCM_HEADER_LENGTH) % 2)); // only even number of bytes are allowed + + for (int i = LPCM_HEADER_LENGTH; i < length; i += 2) + { + pFrame[i - LPCM_HEADER_LENGTH] = pBuf[i + 1]; + pFrame[i - LPCM_HEADER_LENGTH + 1] = pBuf[i]; + } + + int codedSpeed = (pBuf[5] >> 4) & 0x03; + int speed = 0; + + switch (codedSpeed) + { + case 1: + speed = 96000; + break; + + case 2: + speed = 44100; + break; + + case 3: + speed = 32000; + break; + + default: + speed = 48000; + break; + } + + SetAudioSpeed(speed); + PlayAudioFrame(pFrame, length - LPCM_HEADER_LENGTH); + delete[] pFrame; + } +} + +// external device access +// ================================== +// release devices, so mplayer-plugin, for instance, +// can access the dxr3 +void cDxr3Interface::ExternalReleaseDevices() +{ + Lock(); + + if (!m_ExternalReleased) + { + if (m_fdControl > 0) close(m_fdControl); + if (m_fdVideo > 0) close(m_fdVideo); + if (m_fdSpu > 0) close(m_fdSpu); + if (m_fdAudio > 0) close(m_fdAudio); + m_fdControl = m_fdVideo = m_fdSpu = m_fdAudio = -1; + + m_ExternalReleased = true; + + delete m_pClock; + m_pClock = 0; + } + + Unlock(); +} + +// ================================== +// reopen devices for using in the dxr3 plugin +void cDxr3Interface::ExternalReopenDevices() +{ + Lock(); + + if (m_ExternalReleased) + { + // open control stream + m_fdControl = Dxr3Open("", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + + // open 'multimedia' streams + m_fdVideo = Dxr3Open("_mv", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdAudio = Dxr3Open("_ma", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + m_fdSpu = Dxr3Open("_sp", cDxr3ConfigData::Instance().GetDxr3Card(), O_WRONLY | O_SYNC); + + if (m_fdControl < 0 || m_fdVideo < 0 || m_fdAudio < 0 || m_fdSpu <0) + { + ExternalReleaseDevices(); + } + else + { + m_pClock = new cDxr3SysClock(m_fdControl, m_fdVideo, m_fdSpu); + if (!m_pClock) + { + cLog::Instance() << "Unable to allocate memory for m_pClock in cDxr3Interface\n"; + exit(1); + } + + SetChannelCount(1); + m_ExternalReleased = false; + } + + Resuscitation(); + } + + Unlock(); +} + + +// tools +// ================================== +// play blackframe on tv +void cDxr3Interface::PlayBlackFrame() +{ + extern char blackframe[]; + extern int blackframeLength; + + Lock(); + + if (!m_ExternalReleased) + { + if (write(m_fdVideo, blackframe, blackframeLength) < 0) Resuscitation(); + if (write(m_fdVideo, blackframe, blackframeLength) < 0) Resuscitation(); + if (write(m_fdVideo, blackframe, blackframeLength) < 0) Resuscitation(); + } + m_horizontal = 720; + + Unlock(); +} + +// ================================== +void cDxr3Interface::ReOpenAudio() +{ + Lock(); + + if (!m_ExternalReleased) + { + if (m_fdAudio > 0) + { + int bufsize = 0; + ioctl(m_fdAudio, SNDCTL_DSP_GETODELAY, &bufsize); + usleep(bufsize / 192 * 1000); + + delete m_pClock; + close(m_fdAudio); + + m_fdAudio = open("/dev/em8300_ma-0", O_WRONLY | O_SYNC); + + + uint32_t tmpAudioDataRate = m_audioDataRate; + uint32_t tmpAudioChannelCount = m_audioChannelCount; + m_audioDataRate = m_audioChannelCount = 0; + m_pClock = new cDxr3SysClock(m_fdControl, m_fdVideo, m_fdSpu); + SetAudioSpeed(tmpAudioDataRate); + SetChannelCount(tmpAudioChannelCount); + } + } + + Unlock(); +} + +#if VDRVERSNUM < 10307 +// ================================== +cOsdBase* cDxr3Interface::NewOsd(int x, int y) +{ + return new cDxr3Osd(x, y); +} +#endif + +// ================================== +// uploadroutine for microcode +void cDxr3Interface::UploadMicroCode() +{ + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::UploadMicroCode: uploading..."; + } + + em8300_microcode_t em8300_microcode; + const char* MICRO_CODE_FILE = "/usr/share/misc/em8300.uc"; + struct stat s; + int UCODE = open(MICRO_CODE_FILE, O_RDONLY); + + if (UCODE <0) + { + cLog::Instance() << "Unable to open microcode file " << MICRO_CODE_FILE << " for reading\n"; + exit(1); + } + + if (fstat(UCODE, &s ) <0) + { + cLog::Instance() << "Unable to fstat ucode file\n"; + exit(1); + } + + // read microcode + em8300_microcode.ucode = new char[s.st_size]; + if (em8300_microcode.ucode == NULL) + { + cLog::Instance() << "Unable to malloc() space for ucode\n"; + exit(1); + } + + if (read(UCODE,em8300_microcode.ucode,s.st_size) < 1) + { + cLog::Instance() << "Unable to read data from microcode file\n"; + // free memory to avoid memory leak + delete [] (char*) em8300_microcode.ucode; + exit(1); + } + + close(UCODE); + + em8300_microcode.ucode_size = s.st_size; + + // upload it + if( ioctl(m_fdControl, EM8300_IOCTL_INIT, &em8300_microcode) == -1) + { + cLog::Instance() << "Microcode upload to failed!! \n"; + // free memory to avoid memory leak + delete [] (char*) em8300_microcode.ucode; + exit(1); + } + delete [] (char*) em8300_microcode.ucode; + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "...done\n"; + } +} + +// ================================== +// config and setup device via ioctl calls +void cDxr3Interface::ConfigureDevice() +{ + uint32_t videomode = 0; + + // set video mode + if (cDxr3ConfigData::Instance().GetVideoMode() == PAL) + { + videomode = EM8300_VIDEOMODE_PAL; + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Videomode = PAL\n"; + } + } + else if (cDxr3ConfigData::Instance().GetVideoMode() == PAL60) + { + videomode = EM8300_VIDEOMODE_PAL60; + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Videomode = PAL60\n"; + } + } + else + { + videomode = EM8300_VIDEOMODE_NTSC; + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Videomode = NTSC\n"; + } + } + + // make ioctl + if (ioctl(m_fdControl, EM8300_IOCTL_SET_VIDEOMODE, &videomode) == -1) + { + cLog::Instance() << "Unable to set videomode\n"; + exit(1); + } + + // set audio mode + if (!cDxr3ConfigData::Instance().GetUseDigitalOut()) + { + SetAudioAnalog(); + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Interface::ConfigureDevice: Audiomode = Analog\n"; + } + } +} + +// ================================== +// reset whole hardware +void cDxr3Interface::Resuscitation() +{ + time_t startt = time(&startt); + time_t endt = 0; + m_ExternalReleased = true; + dsyslog("cDxr3Interface::Resuscitation Device failure detected"); + + UploadMicroCode(); + dsyslog("cDxr3Interface::Resuscitation Micro code upload successfully"); + +// NonBlockingCloseOpen(); + m_ExternalReleased = false; + + endt = time(&endt); + + dsyslog("cDxr3Interface::Resuscitation Reopening devices took %d", (int)(endt - startt)); + + if (endt - startt > 4) + { + exit(1); + } + + ConfigureDevice(); +} + +// ================================== +void cDxr3Interface::ResampleVolume(short* pcmbuf, int size) +{ + if (m_volume == 0) + { + memset(pcmbuf, 0, size); + } + else if (m_volume != 255) + { + int factor = (int)pow (2.0, (double)m_volume/32 + 8.0) - 1; + //int factor = (int)pow (2.0, (double)m_volume/16) - 1; + for (int i = 0; i < size / (int)sizeof(short); i++) + { + pcmbuf[i] = (((int)pcmbuf[i]) * factor) / 65536; + } + } +} + +// ================================== +void cDxr3Interface::ClearOsd() +{ + encodedata ed; + int controlstart= 0; + int x1 = 0; + int& i = ed.count = 0; + + // display duration... + ed.data[i++]= 0x00; + ed.data[i++]= 0x00; //durration before turn on command occurs + //in 90000/1024 units + // x1 + ed.data[i++]= x1 >> 8; //since this is the last command block, this + ed.data[i++]= x1 & 0xff; //points back to itself + + + // 0x01: start displaying + ed.data[i++]= 0x02; + + // 0xFF: end sequence + ed.data[i++]= 0xFF; + if (!i&1) + { + ed.data[i++]= 0xff; + } + + // x0 + ed.data[2]= (controlstart) >> 8; + ed.data[3]= (controlstart) & 0xff; + + // packet size + ed.data[0]= i >> 8; + ed.data[1]= i & 0xff; + + if (!m_ExternalReleased) + { + WriteSpu((const uint8_t*) &ed, (int) ed.count); + ClearButton(); + } +} + +// ================================== +void cDxr3Interface::WriteSpu(const uint8_t* pBuf, int length) +{ + Lock(); + + if (!m_ExternalReleased) + { + if (write(m_fdSpu, pBuf, length) < 0) Resuscitation(); + } + + Unlock(); +} + +// ================================== +void cDxr3Interface::SetButton(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette) +{ + em8300_button_t button; + + button.color = palette >> 16; + button.contrast = palette & 0xFFFF; + button.top = sy; + button.bottom = ey; + button.left = sx; + button.right = ex; + + ioctl(m_fdSpu, EM8300_IOCTL_SPU_BUTTON, &button); +} + +// ================================== +void cDxr3Interface::ClearButton() +{ + em8300_button_t button; + + button.color = 0; + button.contrast = 0; + button.top = 1; + button.bottom = 2; + button.left = 1; + button.right = 2; + + ioctl(m_fdSpu, EM8300_IOCTL_SPU_BUTTON, &button); +} + +// ================================== +void cDxr3Interface::SetPalette(unsigned int *pal) +{ + ioctl(m_fdSpu, EM8300_IOCTL_SPU_SETPALETTE, (uint8_t*)pal); +} + +// helper functions for dxr3 main osd screen +// ================================== +// reset dxr3 card +void cDxr3Interface::ResetHardware() +{ + Lock(); + cLog::Instance() << "cDxr3Interface: Resting DXR3 hardware\n"; + Resuscitation(); + Unlock(); +} + +// ================================== +cMutex* cDxr3Interface::m_pMutex = new cMutex; diff --git a/dxr3interface.h b/dxr3interface.h new file mode 100644 index 0000000..d1df60e --- /dev/null +++ b/dxr3interface.h @@ -0,0 +1,136 @@ +#ifndef _DXR3_INTERFACE_H_ +#define _DXR3_INTERFACE_H_ + +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <linux/em8300.h> +#include <sys/ioctl.h> + +#include "dxr3vdrincludes.h" +#include "dxr3log.h" +#include "dxr3configdata.h" +#include "dxr3sysclock.h" +#include "dxr3osd.h" + +// ================================== +class cFixedLengthFrame; + +// ================================== +// interafce to dxr3-card +class cDxr3Interface : public Singleton<cDxr3Interface> +{ +public: + cDxr3Interface(); + ~cDxr3Interface(); + + // main + void Start(); + void Stop(); + + // audio + void SetAudioAnalog(); + void SetAudioDigitalPCM(); + void SetAudioDigitalAC3(); + void SetVolume(int volume) { m_volume = volume;} + void SetAudioSpeed(uint32_t speed); + void SetChannelCount(uint32_t count); + void SetAudioSampleSize(uint32_t sampleSize); + + // clock + void SetSysClock(uint32_t scr); + uint32_t GetSysClock() const; + void SetPts(uint32_t pts); + void SetSpuPts(uint32_t pts); + + // state changes + void EnableSPU(); + void DisableSPU(); + void EnableVideo() { m_VideoActive = true; } + void DisableVideo() { m_VideoActive = false; } + void EnableAudio() { m_AudioActive = true; } + void DisableAudio(); + void EnableOverlay(); + void DisanleOverlay(); + + // set/get functions + uint32_t GetAspectRatio() const; + void SetAspectRatio(uint32_t ratio); + uint32_t GetHorizontalSize() const { return m_horizontal; } + void SetHorizontalSize(uint32_t horizontal) { m_horizontal = horizontal;}; + + // play functions + void SetPlayMode(); + void Pause(); + void SingleStep(); + void PlayVideoFrame(cFixedLengthFrame* pFrame, int times = 1); + void PlayVideoFrame(const uint8_t* pBuf, int length, int times = 1); + void PlayAudioFrame(cFixedLengthFrame* pFrame); + void PlayAudioFrame(uint8_t* pBuf, int length); + void PlayAudioLpcmFrame(uint8_t* pBuf, int length); + + // external device access + void ExternalReleaseDevices(); + void ExternalReopenDevices(); + bool IsExternalReleased() const { return m_ExternalReleased; } + + // tools + void PlayBlackFrame(); + void ReOpenAudio(); + + // osd/spu + #if VDRVERSNUM < 10307 + cOsdBase* NewOsd(int x, int y); + #endif + + void ClearOsd(); + void WriteSpu(const uint8_t* pBuf, int length); + void SetButton(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette); + void ClearButton(); + void SetPalette(unsigned int *pal = NULL); + + // overlay functions + + // helper functions for dxr3 main osd screen + void ResetHardware(); + +private: + // file handles + int m_fdControl; + int m_fdVideo; + int m_fdSpu; + int m_fdAudio; + + // dxr3 clock + cDxr3SysClock* m_pClock; + + uint32_t m_audioChannelCount; + uint32_t m_audioDataRate; + int m_aspectDelayCounter; + uint32_t m_aspectRatio; + uint32_t m_horizontal; + uint32_t m_audioSampleSize; + uint32_t m_audioMode; + uint32_t m_spuMode; + bool m_ExternalReleased; // is dxr3 used by e.g. mplayer? + int m_volume; + bool m_AudioActive; + bool m_VideoActive; + bool m_OverlayActive; + + // spu +// cDxr3InterfaceSpu m_SpuInterface; + + void UploadMicroCode(); + void ConfigureDevice(); + void ResampleVolume(short* pcmbuf, int size); + void Resuscitation(); + +protected: + static cMutex* m_pMutex; + + static void Lock() { cDxr3Interface::m_pMutex->Lock(); } + static void Unlock() { cDxr3Interface::m_pMutex->Unlock(); } +}; + +#endif /*_DXR3_INTERFACE_H_*/ diff --git a/dxr3interface_spu_encoder.c b/dxr3interface_spu_encoder.c new file mode 100644 index 0000000..59b1a33 --- /dev/null +++ b/dxr3interface_spu_encoder.c @@ -0,0 +1,620 @@ +/* + * spuenc.c - encodes an OSD bitmap as subpicture + * + * Assimilated and adapted by + * Stefan Schluenss <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "dxr3interface_spu_encoder.h" + +/* +ToDo: + - cSPUEncoder::encode_do_row: FIXME: watch this space for EOL +*/ + + +// ================================== +// dec. +cSpuData::~cSpuData() +{ + Clear(); +} + +// ================================== +// free buffer and set it to 0 +void cSpuData::Clear() +{ + if (data) + { + free(data); + count = malloc_size = 0; + } +} + +// ================================== +// wirte a byte to spu buffer +void cSpuData::WriteByte(uint8_t byte) +{ + if (count >= malloc_size) + { + data = (u_char*)realloc(data, malloc_size += 2048); + } + + data[count++] = byte; +} + +// ================================== +void cSpuData::WriteNibble(int *higher_nibble, uint8_t nibble) +{ +} + +// ================================== +void cSpuData::WriteRle(int *higher_nibble, int length, int color) +{ +} + + + + +// ================================== +cSPUEncoder::cSPUEncoder() +{ + // clear osd + memset(OSD_Screen, 0x00 ,OSDWIDTH * OSDHEIGHT); + memset(OSD_Screen2, 0x00 ,OSDWIDTH * OSDHEIGHT); + memset(OSD_Screen3, 0x00 ,OSDWIDTH * OSDHEIGHT); + + // set active area to 0 + //m_x0 = m_x1 = m_y0 = m_y1 = 0; +} + +// ================================== +// main function for the osd +// makes life nicer :) +int cSPUEncoder::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) +{ + u_char *cp; + unsigned char idx = 0; + int opacity = 0; +#if VDRVERSNUM >= 10307 + const tColor *col; +#else + eDvbColor *col; +#endif + + switch (cmd) + { + case OSD_SetWindow: + // (x0) set window with number 0<x0<8 as current + if (x0 < 8 && x0 > 0) + { + m_lastwindow = x0; + return 0; + } + + return -1; + break; + + case OSD_Open: + // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) + // Opens OSD with this size and bit depth + // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" + m_windows[m_lastwindow].x0 = x0; + m_windows[m_lastwindow].y0 = y0; + m_windows[m_lastwindow].x1 = x1; + m_windows[m_lastwindow].y1 = y1; + + return 0; + break; + + case OSD_SetPalette: + // Spu->Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); + // (firstcolor{color},lastcolor{x0},data) + // Set a number of entries in the palette + // sets the entries "firstcolor" through "lastcolor" from the array "data" + // data has 4 byte for each color: + // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel + + #if VDRVERSNUM >= 10307 + col = (tColor*)data; + #else + eDvbColor *col; + col = (eDvbColor*)data; + #endif + + m_windows[m_lastwindow].NumColors = x0; + + for (int x = color, i = 0; x <= x0; x++,i++) + { + m_palManager.AddColor((int)*col & 0xFFFFFF); + + idx = m_palManager.GetIndex((int)*col & 0xFFFFFF); + if (m_palManager.HasChanged()) + { + cDxr3Interface::Instance().SetPalette(m_palManager.GetPalette()); + } + + opacity = ((*col & 0xFF000000) >> 24) * 0xF / 0xFF; + m_windows[m_lastwindow].colors[i] = (opacity << 4) | idx; + m_windows[m_lastwindow].opacity[i] = opacity; + col++; + } + + return 0; + break; + + case OSD_SetBlock: + // (x0,y0,x1,y1,increment{color},data) + // fills pixels x0,y0 through x1,y1 with the content of data[] + // inc contains the width of one line in the data block, + // inc<=0 uses blockwidth as linewidth + // returns 0 on success, -1 on clipping all pixel + + CopyBlockIntoOSD + ( + color, + m_windows[m_lastwindow].x0 + x0, + m_windows[m_lastwindow].y0 + y0, + m_windows[m_lastwindow].x0 + x1, + m_windows[m_lastwindow].y0 + y1, + (u_char *)data + ); + + // calculate osd size + CalculateActiveOsdArea(); + + //cLog::Instance() << "(" << m_x0 << ", " << m_x1 << ") - (" << m_y0 << ", " << m_y1 << ")"; + + m_encodeddata.count = 0; + EncodePixelbufRle(0,0, OSDWIDTH, OSDHEIGHT-1, OSD_Screen, 0, &m_encodeddata); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "OSD Datasize: " << m_encodeddata.count << "\n"; + } + + if (m_encodeddata.count <= DATASIZE) + { + cDxr3Interface::Instance().WriteSpu((uint8_t*) &m_encodeddata, m_encodeddata.count); + return 0; + } + else + { + cLog::Instance() << "Waring: SPU data (" << m_encodeddata.count << ") size exceeds limit\n"; + return -1; + } + break; + + case OSD_Close: + // clear colors from plattemanager + + #if VDRVERSNUM >= 10307 + if ((col = (tColor*)m_windows[m_lastwindow].colors) != NULL) + #else + if ((col = (eDvbColor*)m_windows[m_lastwindow].colors) != NULL) + #endif + { + for (int i = 0; i < m_windows[m_lastwindow].NumColors; ++i) + { + m_palManager.RemoveColor((int)(col[i]) & 0xFFFFFF); + } + } + + // clear osd + for (int i = m_windows[m_lastwindow].y0; i <= m_windows[m_lastwindow].y1; ++i) + { + cp = &OSD_Screen[i*OSDWIDTH + m_windows[m_lastwindow].x0]; + if ((cp+m_windows[m_lastwindow].x1-m_windows[m_lastwindow].x0+1) < &OSD_Screen[OSDWIDTH * OSDHEIGHT-1]) + { + for (int xx=0; xx <= (m_windows[m_lastwindow].x1-m_windows[m_lastwindow].x0); xx++) + { + *(cp+xx) = 0x00; + } + } + else + { + continue; + } + } + + // encode rle + m_encodeddata.count = 0; + EncodePixelbufRle(0,0, OSDWIDTH, OSDHEIGHT-1, OSD_Screen, 0, &m_encodeddata); + + // set windows position to 0 + m_windows[m_lastwindow].x0 = 0; + m_windows[m_lastwindow].y0 = 0; + m_windows[m_lastwindow].x1 = 0; + m_windows[m_lastwindow].y1 = 0; + + if (m_encodeddata.count <= DATASIZE) + { + cDxr3Interface::Instance().WriteSpu((uint8_t*) &m_encodeddata, m_encodeddata.count); + return 0; + } + else + { + cLog::Instance() << "Waring: SPU data (" << m_encodeddata.count << ") size exceeds limit\n"; + return -1; + } + + return 0; + break; + + case OSD_Clear: + // Sets all pixel to color 0 + // returns 0 on success + + // This should be done in cSPUEncoder::cSPUEncoder + + return 0; + break; + + // not needed - at the moment + case OSD_Show: + case OSD_Hide: + case OSD_Fill: + case OSD_SetColor: + case OSD_SetTrans: + case OSD_SetPixel: + case OSD_GetPixel: + case OSD_SetRow: + case OSD_FillRow: + case OSD_FillBlock: + case OSD_Line: + case OSD_Query: + case OSD_Test: + case OSD_Text: + case OSD_MoveWindow: + break; + }; + + return -1; +} + +// ================================== +// stamps window content into full osd bitmap +void cSPUEncoder::CopyBlockIntoOSD(int linewidth, int x0, int y0, int x1, int y1, u_char *data) +{ + int i; + int w; + u_char *cp; + u_char *sp = data; + + + // linewidth contains the width of one line in the data block, + // linewidth<=0 uses blockwidth as linewidth + if (linewidth <= 0) + { + w = m_windows[m_lastwindow].x1 - m_windows[m_lastwindow].x0; + } + else + { + w = linewidth; + } + + for (i = y0; i <= y1; ++i) + { + cp = &OSD_Screen[i*OSDWIDTH + x0]; + if ((cp+x1-x0+1) < &OSD_Screen[OSDWIDTH * OSDHEIGHT-1]) + { + for (int xx=0; xx <= (x1-x0); xx++) + { + *(cp+xx) = m_windows[m_lastwindow].colors[*(sp+xx) & 0x0f]; + } + } + else + { + continue; + } + sp += w; + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::EncodePixelbufRle(int x, int y, int w, int h, u_char *inbuf, int stride, encodedata *ed) +{ + pixbuf pb; + int i, row; + pb.x = w; + pb.y = h; + + if (cDxr3Interface::Instance().GetHorizontalSize() < 700) + { + double fac = (double)OSDWIDTH / (double)OSDWIDTH2; + ScaleOSD(fac, inbuf,10); + inbuf = OSD_Screen2; + } + + m_ColorManager = new cColorManager(); + + // Encode colors into highlight regions + m_ColorManager->EncodeColors(w, h, inbuf, OSD_Screen3); + inbuf = OSD_Screen3; + + pb.pixels = inbuf; + ed->count= 4; + ed->nibblewaiting= 0; + + row= 0; + for (i= 0; i < pb.y; i++) + { + encode_do_row(ed, &pb, row); + row+= 2; + if (row > pb.y) + { + row= 1; + ed->oddstart= ed->count; + } + } + encode_do_control(x,y, ed, &pb); + + delete m_ColorManager; +} + +// ================================== +void cSPUEncoder::ScaleOSD(double fac, unsigned char* buf, unsigned char NumColors) +{ + int y,x,s,d; + unsigned char dline[2 * OSDWIDTH + 10]; + + memset(OSD_Screen2, 0x00 ,OSDWIDTH * OSDHEIGHT); + + for (y = 0; y < OSDHEIGHT; y++) + { + memset(dline,0,2*OSDWIDTH+10); + + for (s=0,d=0; s < OSDWIDTH; s++,d+=2) + { + // stretch line to double width to 1440 + dline[d] = buf[y*OSDWIDTH + s]; + } + + for (d=1; d < (2*OSDWIDTH); d+=2) + { + #if VDRVERSNUM <= 10307 + // 'interpolate' values + if ((dline[d-1] == BLACK) || (dline[d+1] == BLACK)) + { + dline[d] = BLACK; + } + else if ((dline[d-1] == WHITE) || (dline[d+1] == WHITE)) + { + dline[d] = WHITE; + } + else if ((dline[d-1] == CYAN) || (dline[d+1] == CYAN)) + { + dline[d] = CYAN; + } + else + { + dline[d] = dline[d+1]; + } + #else /*VDRVERSNUM*/ + dline[d] = dline[d+1]; + #endif /*VDRVERSNUM*/ + } + + for (s=0, x = 0; x < OSDWIDTH2; x++,s+=3) + { + // now take every third pixel (1440/3=480) + OSD_Screen2[y * OSDWIDTH + x] = dline[s]; + } + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_put_nibble(encodedata* ed, u_char nibble) +{ + if (ed->nibblewaiting) + { + ed->data[ed->count++]|= nibble; + ed->nibblewaiting= 0; + } + else + { + ed->data[ed->count]= nibble<<4; + ed->nibblewaiting= 1; + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_pixels(encodedata* ed, int color, int number) +{ + if (number > 3) + { + if (number > 15) + { + encode_put_nibble(ed, 0); + if (number > 63) + { + encode_put_nibble(ed, (number & 0xC0)>>6); + } + } + encode_put_nibble(ed, (number & 0x3C)>>2); + } + encode_put_nibble(ed, ((number & 0xF)<<2) | color); +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_eol(encodedata* ed) +{ + if (ed->nibblewaiting) + { + ed->count++; + ed->nibblewaiting= 0; + } + ed->data[ed->count++]= 0x00; + ed->data[ed->count++]= 0x00; +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_do_row(encodedata* ed, pixbuf* pb, int row) +{ + int i= 0; + u_char* pix= pb->pixels + row * pb->x; + int color= *pix & 0x03; + int n= 0; /* the number of pixels of this color */ + + while (i++ < pb->x) + { + /* FIXME: watch this space for EOL */ + if ((*pix & 0x03) != color || n == 255 ) + { + encode_pixels( ed, color, n ); + color= *pix & 0x03; + n= 1; + } + else + { + n++; + } + pix++; + } + + /* this small optimization: (n>63) can save up to two bytes per line + * I wonder if this is compatible with all the hardware... */ + if (color == 0 && n > 63) + { + encode_eol( ed ); + } + else + { + encode_pixels( ed, color, n ); + } + + if (ed->nibblewaiting) + { + ed->count++; + ed->nibblewaiting= 0; + } +} + +// ================================== +// taken from mplayer (spuenc.c) +void cSPUEncoder::encode_do_control(int x,int y, encodedata* ed, pixbuf* pb) +{ + int controlstart= ed->count; + int x1; + int i; + u_int top, left, bottom, right; + + top= y; //this forces the first bit to be visible on a TV + left= x; //you could actually pass in x/y and do some nice + + bottom= top + pb->y - 1; + right= left + pb->x - 1; + + /* start at x0+2*/ + i= controlstart; + + x1= (i); //marker for last command block address + + /* display duration... */ + ed->data[i++]= 0x00; + ed->data[i++]= 0x00; //duration before turn on command occurs (will not be used) + + /* x1 */ + ed->data[i++]= x1 >> 8; //since this is the last command block, this + ed->data[i++]= x1 & 0xff;//points back to itself + + /* 0x00: force displaying */ + ed->data[i++]= 0x00; + + /* 0x03: palette info */ + ed->data[i++]= 0x03; + ed->data[i++]= 0x01; + ed->data[i++]= 0x23; + + /* 0x04: transparency info (reversed) */ + ed->data[i++]= 0x04; // SET_CONTR + ed->data[i++]= 0xFF; + ed->data[i++]= 0x70; + + /* 0x05: coordinates */ + ed->data[i++]= 0x05; // SET_DAREA + ed->data[i++]= left >> 4; + ed->data[i++]= ((left&0xf)<<4)+(right>>8); + ed->data[i++]= (right&0xff); + ed->data[i++]= top >> 4; + ed->data[i++]= ((top&0xf)<<4)+(bottom>>8); + ed->data[i++]= (bottom&0xff); + + /* 0x06: both fields' offsets */ + ed->data[i++]= 0x06; // SET_DSPXA + ed->data[i++]= 0x00; + ed->data[i++]= 0x04; + ed->data[i++]= ed->oddstart >> 8; + ed->data[i++]= ed->oddstart & 0xff; + + int len; + unsigned char *spudata; + + spudata = m_ColorManager->GetSpuData(len); + + for (int si= 0; si < len; si++) + { + ed->data[i++] = *(spudata + si); + } + + /* 0xFF: end sequence */ + ed->data[i++]= 0xFF; + if (! i&1 ) + { + ed->data[i++]= 0xff; + } + + /* x0 */ + ed->data[2]= (controlstart) >> 8; + ed->data[3]= (controlstart) & 0xff; + + /* packet size */ + ed->data[0]= i >> 8; + ed->data[1]= i & 0xff; + + ed->count= i; +} + +// ================================== +// we _only_ write usefull data +void cSPUEncoder::CalculateActiveOsdArea() +{ + // reset + //m_x0 = m_x1 = m_y0 = m_y1 = 0; + + // calculate +/* for (int i = 1; i < 8; i++) + { + m_x0 = max(m_x0, m_windows[i].x0); + m_x1 = max(m_x1, m_windows[i].y0); + m_y0 = max(m_y0, m_windows[i].x1); + m_y1 = max(m_y1, m_windows[i].y1); + } +*/ +} diff --git a/dxr3interface_spu_encoder.h b/dxr3interface_spu_encoder.h new file mode 100644 index 0000000..bee994b --- /dev/null +++ b/dxr3interface_spu_encoder.h @@ -0,0 +1,153 @@ +/* + * dxr3interface_spu_encoder.h - encodes an OSD bitmap as subpicture + * + * Assimilated and adapted by + * Stefan Schluenss <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef _DXR3_INTERFACE_SPU_ENCODER_ +#define _DXR3_INTERFACE_SPU_ENCODER_ + +#include <stdlib.h> +#include <linux/dvb/osd.h> +#include "dxr3vdrincludes.h" +#include "dxr3palettemanager.h" +#include "dxr3colormanager.h" +#include "dxr3interface.h" +#include "dxr3singleton.h" + +// ================================== +#define MAXWINDOWS 8 +#define DATASIZE 53220 +#define OSDWIDTH 720 +#define OSDWIDTH2 480 +#define OSDHEIGHT 576 + +// ================================== +// basic infos about one osd "window" +struct sOSD_Window +{ + size_t x0; + size_t y0; + size_t x1; + size_t y1; + + unsigned char colors[16]; + unsigned char opacity[16]; + + size_t NumColors; +}; + +// ================================== +// used to get active osd area +struct sRectal +{ + sRectal() : x0(0), x1(0), y0(0), y1(0) {} + + size_t x0; + size_t x1; + size_t y0; + size_t y1; +}; + +// ================================== +// our spu(data) with all needed routines +class cSpuData +{ +public: + cSpuData(): count(0), malloc_size(0) {} + ~cSpuData(); + + void Clear(); + u_char* GetData() const { return data; } + + // write operations + void WriteByte(uint8_t byte); + void WriteNibble(int *higher_nibble, uint8_t nibble); + void WriteRle(int *higher_nibble, int length, int color); + +private: + u_char *data; + size_t count; // the count of bytes written + size_t malloc_size; // size of data +}; + +// ================================== +struct pixbuf +{ + int x, y; + u_int rgb[4]; + u_char* pixels; +}; + +// ================================== +struct encodedata +{ + u_char data[DATASIZE]; + int count; // the count of bytes written + int oddstart; + int nibblewaiting; +}; + +// ================================== +class cSPUEncoder : public Singleton<cSPUEncoder> +{ +public: + cSPUEncoder(); + ~cSPUEncoder() {} + + int Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = 0); + +private: + cSPUEncoder(cSPUEncoder&); // no copy constructor + + // helper functions + void CopyBlockIntoOSD(int linewidth, int x0,int y0, int x1, int y1, u_char *data); + void EncodePixelbufRle(int x, int y, int w, int h, u_char *inbuf, int stride, encodedata *ed); + void ScaleOSD(double fac, unsigned char* buf, unsigned char NumColors=4); + void encode_put_nibble(encodedata* ed, u_char nibble); + void encode_pixels(encodedata* ed, int color, int number); + void encode_eol(encodedata* ed); + void encode_do_row(encodedata* ed, pixbuf* pb, int row); + void encode_do_control(int x,int y, encodedata* ed, pixbuf* pb); + + void CalculateActiveOsdArea(); + + sOSD_Window m_windows[8]; + cDxr3PaletteManager m_palManager; + cColorManager* m_ColorManager; + encodedata m_encodeddata; + int m_lastwindow; + + // our osd :) + u_char OSD_Screen[OSDWIDTH * OSDHEIGHT]; + u_char OSD_Screen2[OSDWIDTH * OSDHEIGHT]; + u_char OSD_Screen3[OSDWIDTH * OSDHEIGHT]; + + // 'active' osd sizes + sRectal m_active_osd; +}; + +#endif /*_DXR3_INTERFACE_SPU_ENCODER_*/ diff --git a/dxr3log.c b/dxr3log.c new file mode 100644 index 0000000..09f54c1 --- /dev/null +++ b/dxr3log.c @@ -0,0 +1,60 @@ +/* + * dxr3log.c + * + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "dxr3log.h" + +// ================================== +cLog::cLog() +{ + m_LogOpen = false; + m_ForeFlush = true; + + Open("dxr3plugin.log"); +} + +// ================================== +cLog::cLog(std::string Filename) +{ + m_LogOpen = false; + m_ForeFlush = true; + + Open(Filename); +} + +// ================================== +void cLog::Open(std::string Filename) +{ + m_LogStream.open(Filename.c_str()); + m_LogOpen = true; +} + +// ================================== +void cLog::Close() +{ + if (m_LogOpen) + { + // close file now + m_LogStream.flush(); + m_LogStream.close(); + + m_LogOpen = false; + } +} diff --git a/dxr3log.h b/dxr3log.h new file mode 100644 index 0000000..b09e86e --- /dev/null +++ b/dxr3log.h @@ -0,0 +1,94 @@ +/* + * dxr3log.h + * + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _DXR3_LOG_H_ +#define _DXR3_LOG_H_ + +#include <fstream> +#include <string> +#include "dxr3singleton.h" + +// ================================== +//! A log class. +/*! + With this nice util dxr3plugin generates and mange a log file. In this + file the developer/enduser can find informations and can find errors, + problems and ohter stuff. +*/ +class cLog : public Singleton<cLog> +{ +public: + cLog(); // use default log file + cLog(std::string FileName); + + ~cLog() { Close(); } + + void SetForceFlush(const bool v) { m_ForeFlush = v; } + bool GetForceFlush() const { return m_ForeFlush; } + + // write type data to log file. + template <class Type> + inline cLog& operator << ( Type item ) + { + if (m_LogOpen) + { + m_LogStream << item; + if (m_ForeFlush) m_LogStream.flush(); + } + return *this; + } + inline cLog& operator << ( size_t item ) + { + if (m_LogOpen) + { + m_LogStream << (unsigned int)item; + if (m_ForeFlush) m_LogStream.flush(); + } + return *this; + } + inline cLog& operator << ( bool item ) + { + if (m_LogOpen) + { + if (item == true) + { + m_LogStream << "true"; + } + else + { + m_LogStream << "false"; + } + if (m_ForeFlush) m_LogStream.flush(); + } + return *this; + } + +private: + std::ofstream m_LogStream; + bool m_LogOpen; + bool m_ForeFlush; + + void Open(std::string Filename); // with this function we open our logfile + void Close(); // with this function we close our logfile +}; + + +#endif /*_DXR3_LOG_H_*/ diff --git a/dxr3memcpy.c b/dxr3memcpy.c new file mode 100644 index 0000000..1866c95 --- /dev/null +++ b/dxr3memcpy.c @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2001-2003 the xine project + * + * This file is part of xine, a free video player. + * + * These are the MMX/MMX2/SSE optimized versions of memcpy + * + * This code was adapted from Linux Kernel sources by Nick Kurshev to + * the mplayer program. (http://mplayer.sourceforge.net) + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "dxr3log.h" +#include "dxr3cpu.h" +#include "dxr3memcpy.h" + + +void *(* dxr3_memcpy)(void *to, const void *from, size_t len); + + +//#if defined(ARCH_X86) || defined(ARCH_X86_64) + +#ifndef _MSC_VER +// ================================== +// for small memory blocks (<256 bytes) this version is faster +#define small_memcpy(to,from,n)\ +{\ +register unsigned long int dummy;\ +__asm__ __volatile__(\ + "rep; movsb"\ + :"=&D"(to), "=&S"(from), "=&c"(dummy)\ + :"0" (to), "1" (from),"2" (n)\ + : "memory");\ +} + +// ================================== +// linux kernel __memcpy (from: /include/asm/string.h) +static __inline__ void * __memcpy ( + void * to, + const void * from, + size_t n) +{ +int d0, d1, d2; + + if( n < 4 ) { + small_memcpy(to,from,n); + } + else + __asm__ __volatile__( + "rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); + + return (to); +} + +#define SSE_MMREG_SIZE 16 +#define MMX_MMREG_SIZE 8 + +#define MMX1_MIN_LEN 0x800 /* 2K blocks */ +#define MIN_LEN 0x40 /* 64-byte blocks */ + +// ================================== +/* SSE note: i tried to move 128 bytes a time instead of 64 but it +didn't make any measureable difference. i'm using 64 for the sake of +simplicity. [MF] */ +static void * sse_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + /* PREFETCH has effect even for MOVSB instruction ;) */ + __asm__ __volatile__ ( + " prefetchnta (%0)\n" + " prefetchnta 32(%0)\n" + " prefetchnta 64(%0)\n" + " prefetchnta 96(%0)\n" + " prefetchnta 128(%0)\n" + " prefetchnta 160(%0)\n" + " prefetchnta 192(%0)\n" + " prefetchnta 224(%0)\n" + " prefetchnta 256(%0)\n" + " prefetchnta 288(%0)\n" + : : "r" (from) ); + + if(len >= MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(SSE_MMREG_SIZE-1); + if(delta) + { + delta=SSE_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + if(((unsigned long)from) & 15) + /* if SRC is misaligned */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "prefetchnta 352(%0)\n" + "movups (%0), %%xmm0\n" + "movups 16(%0), %%xmm1\n" + "movups 32(%0), %%xmm2\n" + "movups 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + else + /* + Only if SRC is aligned on 16-byte boundary. + It allows to use movaps instead of movups, which required data + to be aligned or a general-protection exception (#GP) is generated. + */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "prefetchnta 352(%0)\n" + "movaps (%0), %%xmm0\n" + "movaps 16(%0), %%xmm1\n" + "movaps 32(%0), %%xmm2\n" + "movaps 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + /* since movntq is weakly-ordered, a "sfence" + * is needed to become ordered again. */ + __asm__ __volatile__ ("sfence":::"memory"); + /* enables to use FPU */ + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +// ================================== +static void * mmx_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + if(len >= MMX1_MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1); + if(delta) + { + delta=MMX_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + for(; i>0; i--) + { + __asm__ __volatile__ ( + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movq %%mm0, (%1)\n" + "movq %%mm1, 8(%1)\n" + "movq %%mm2, 16(%1)\n" + "movq %%mm3, 24(%1)\n" + "movq %%mm4, 32(%1)\n" + "movq %%mm5, 40(%1)\n" + "movq %%mm6, 48(%1)\n" + "movq %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +// ================================== +static void * mmx2_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; + + /* PREFETCH has effect even for MOVSB instruction ;) */ + __asm__ __volatile__ ( + " prefetchnta (%0)\n" + " prefetchnta 32(%0)\n" + " prefetchnta 64(%0)\n" + " prefetchnta 96(%0)\n" + " prefetchnta 128(%0)\n" + " prefetchnta 160(%0)\n" + " prefetchnta 192(%0)\n" + " prefetchnta 224(%0)\n" + " prefetchnta 256(%0)\n" + " prefetchnta 288(%0)\n" + : : "r" (from) ); + + if(len >= MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1); + if(delta) + { + delta=MMX_MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + for(; i>0; i--) + { + __asm__ __volatile__ ( + "prefetchnta 320(%0)\n" + "prefetchnta 352(%0)\n" + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "movntq %%mm6, 48(%1)\n" + "movntq %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + /* since movntq is weakly-ordered, a "sfence" + * is needed to become ordered again. */ + __asm__ __volatile__ ("sfence":::"memory"); + __asm__ __volatile__ ("emms":::"memory"); + } + /* + * Now do the tail of the block + */ + if(len) __memcpy(to, from, len); + return retval; +} + +// ================================== +static void *linux_kernel_memcpy(void *to, const void *from, size_t len) { + return __memcpy(to,from,len); +} +#endif /* _MSC_VER */ +//#endif /* ARCH_X86 */ + + + +// ================================== +// constr. +cDxr3MemcpyBench::cDxr3MemcpyBench(uint32_t config_flags) +{ + // + // add all aviable memcpy routines + // + + memcpy_routine routine; + + // glibc memcpy + routine.name = "glibc memcpy()"; + routine.function = memcpy; + routine.time = 0; + routine.cpu_require = 0; + m_methods.push_back(routine); + +// #ifdef ARCH_X86 + +// cLog::Instance() << "test\n"; + + // linux_kernel_memcpy + routine.name = "linux_kernel_memcpy()"; + routine.function = linux_kernel_memcpy; + routine.cpu_require = 0; + m_methods.push_back(routine); + + // MMX optimized memcpy() + routine.name = "MMX optimized memcpy()"; + routine.function = mmx_memcpy; + routine.cpu_require = CC_MMX; + m_methods.push_back(routine); + + // MMXEXT optimized memcpy() + routine.name = "MMXEXT optimized memcpy()"; + routine.function = mmx2_memcpy; + routine.cpu_require = CC_MMXEXT; + m_methods.push_back(routine); + + #ifndef __FreeBSD__ + + // SSE optimized memcpy() + routine.name = "SSE optimized memcpy()"; + routine.function = sse_memcpy; + routine.cpu_require = CC_MMXEXT|CC_SSE; + m_methods.push_back(routine); + + #endif /*__FreeBSD__*/ + +// #endif /*ARCH_X86*/ + + + // + // run benchmarking + // + + unsigned long long t = 0; + void *buf1, *buf2; + int j, best = -1; + + if ((buf1 = malloc(BUFSIZE)) == NULL) + return; + + if ((buf2 = malloc(BUFSIZE)) == NULL) + { + free(buf1); + return; + } + + cLog::Instance() << "\nBenchmarking memcpy() methods (smaller is better):\n"; + // make sure buffers are present on physical memory + memcpy(buf1,buf2,BUFSIZE); + + for (size_t i = 0; i < m_methods.size(); i++) + { + if ((config_flags & m_methods[i].cpu_require) != m_methods[i].cpu_require) + { + continue; + } + + // count 100 runs of the memcpy function + t = rdtsc(); + for (j = 0; j < 50; j++) + { + m_methods[i].function(buf2,buf1,BUFSIZE); + m_methods[i].function(buf1,buf2,BUFSIZE); + } + t = rdtsc() - t; + + m_methods[i].time = t; + + cLog::Instance() << m_methods[i].name.c_str() << ": " << (unsigned long long)t << "\n"; + + if (best == -1 || t < m_methods[best].time) + { + best = i; + } + } + cLog::Instance() << "\nBest one: " << m_methods[best].name.c_str() << "\n\n"; + + dxr3_memcpy = m_methods[best].function; + + + // clear unused memory + free(buf1); + free(buf2); +} + + +// ================================== +// neede for exact timing +unsigned long long int cDxr3MemcpyBench::rdtsc() +{ +// #ifdef ARCH_X86 + unsigned long long int x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +// #else + /* FIXME: implement an equivalent for using optimized memcpy on other + architectures */ +// return 0; +// #endif +} diff --git a/dxr3memcpy.h b/dxr3memcpy.h new file mode 100644 index 0000000..8ec863d --- /dev/null +++ b/dxr3memcpy.h @@ -0,0 +1,74 @@ +/***************************************************************************** + * memcpy.h: functions and definitions of the MMX/MMX2/SSE optimized versions + * of memcpy + ***************************************************************************** + * Copyright (C) 2001 Keuleu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + ***************************************************************************** + * + * Original code: + * + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + *****************************************************************************/ + +#ifndef _DXR3MEMCPY_H_ +#define _DXR3MEMCPY_H_ + +#include "dxr3vdrincludes.h" + +// ================================== +// size of buffer for benchmark +#define BUFSIZE 1024*1024 + +enum { + MEMCPY_PROBE = 0, + MEMCPY_GLIBC, + MEMCPY_KERNEL, + MEMCPY_MMX, + MEMCPY_MMXEXT, + MEMCPY_SSE +}; + +// ================================== +struct memcpy_routine +{ + string name; + void *(* function)(void *to, const void *from, size_t len); + unsigned long long time; + uint32_t cpu_require; // caps from dxr3cpu.h +}; + +// ================================== +// little class to to a nice benchmark +class cDxr3MemcpyBench +{ +public: + cDxr3MemcpyBench(uint32_t config_flags = 0); + +private: + unsigned long long int rdtsc(); + + vector<memcpy_routine> m_methods; +}; + +// ================================== +// optimized/fast memcpy +extern void *(* dxr3_memcpy)(void *to, const void *from, size_t len); + +#endif /*_DXR3MEMCPY_H_*/ diff --git a/dxr3multichannelaudio.c b/dxr3multichannelaudio.c new file mode 100644 index 0000000..0bbb15e --- /dev/null +++ b/dxr3multichannelaudio.c @@ -0,0 +1,645 @@ +/* +* dxr3multichannelaudio.c: +* +* taken from the AC3overDVB Patch maintained by Stefan Huelswitt +* +* +*/ + +#include <malloc.h> +#include "dxr3multichannelaudio.h" +#include "dxr3log.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 we need to sync on a audio header + +#define AC3_SIZE 6144 // size of AC3 IEC paket +#define DTS_SIZE 2048 // size of DTS IEC paket +#define IEC_HDR_SIZE 8 // size of IEC header + +// --- cAudioEncapsulator ------------------------------------------------------ + +class cAudioEncapsulator { +private: + int totalSize, frameCount; + cFrame *frame; + uchar *frameData; + // + uchar syncBuff[SYNC_SIZE]; + int have, length, skipped; + // + uchar ptsFlags; + const uchar *ptsData; + int ptsDelay; + // + void NewFrame(uchar PTSflags, const uchar *PTSdata); + void SyncFound(const uchar *data); +protected: + int streamType; + cRingBufferFrame *ringBuffer; + int fillup, firstBurst; + bool mute, muteData; + // + void StartFrame(int size, uchar PTSflags, const uchar *PTSdata); + void FinishFrame(void); + void PutData(const uchar *data, int len); + void SendIECpause(int type, uchar PTSflags, const uchar *PTSdata); + // + virtual int SyncInfo(const uchar *data)=0; + virtual void StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata)=0; + virtual void FinishIECFrame(void); +public: + cAudioEncapsulator(cRingBufferFrame *rb, int StreamType); + virtual ~cAudioEncapsulator(); + void Clear(void); + void Decode(const uchar *data, int len, uchar PTSflags, int PTSdelay, const uchar *PTSdata); + int StreamType() { return streamType; } + void Mute(bool Mute) { mute=Mute; } + }; + +cAudioEncapsulator::cAudioEncapsulator(cRingBufferFrame *rb, int StreamType) +{ + ringBuffer=rb; + streamType=StreamType; + frame=0; firstBurst=1; + Clear(); +} + +cAudioEncapsulator::~cAudioEncapsulator() +{ + delete frame; +} + +void cAudioEncapsulator::Clear(void) +{ + delete frame; + frame=0; frameCount=0; fillup=0; mute=muteData=false; + have=length=skipped=0; +} + +void cAudioEncapsulator::StartFrame(int size, uchar PTSflags, const uchar *PTSdata) +{ + if(frame) { + DEBUG("StartFrame() with unfinished frame!\n"); + FinishFrame(); + } + ED("StartFrame: size=%d ptsFlags=%d\n",size,PTSflags); + totalSize=size; + NewFrame(PTSflags,PTSdata); +} + +void cAudioEncapsulator::NewFrame(uchar PTSflags, const uchar *PTSdata) +{ + if(!totalSize) { + DEBUG("NewFrame: new frame requested, but totalSize=0\n"); + return; + } + static const int ptslen[] = { 0,0,PTS_SIZE,PTS_SIZE*2 }; + const int plen = ptslen[PTSflags]; + int len = min(totalSize, MAX_FRAMECOUNT); + ED("NewFrame: totalSize=%d frameCount=%d PTSflags=%d",totalSize,len,PTSflags); + totalSize -= len; + ED(" new totalSize=%d\n",totalSize); + len += (plen + 3 + 7); + frameCount = len+PES_HDR_SIZE; + frameData = MALLOC(uchar,frameCount); + if (frameData) { + frame = new cFrame(frameData, -frameCount, ftUnknown); + if (frame) { + uchar buf[10]; + // build the PES header + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x01; + buf[3] = 0xBD; // PRIVATE_STREAM1 + buf[4] = (len >> 8) & 0xFF; + buf[5] = len & 0xFF; + buf[6] = 0x84; + buf[7] = plen ? (PTSflags << 6) : 0; + buf[8] = plen; + PutData(buf,9); + + if (plen) PutData(PTSdata,plen); + + // build LPCM header + buf[0] = aLPCM; // substream ID + buf[1] = 0xFF; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x81; + PutData(buf,7); + return; + } + else { free(frameData); frameData=0; } + } + esyslog("Failed to build frame for audio encapsulation"); +} + +void cAudioEncapsulator::FinishFrame(void) +{ + if (frameCount) { + DEBUG("FinishFrame() with frameCount>0\n"); + PutData(0,frameCount); + } + if (frame && frameData) { + ED("FinishFrame: totalSize=%d\n",totalSize); + if (!ringBuffer->Put(frame)) { + esyslog("Ringbuffer overflow. Encapsulated audio frame lost"); + delete frame; + } + } + frame=0; frameData=0; frameCount=0; +} + +void cAudioEncapsulator::PutData(const uchar *data, int len) +{ + if(!muteData) { + if(!frameData) DEBUG("PutData() without frame\n"); + while (frameData && len > 0) { + int l = min(len,frameCount); + if(data) { + memcpy(frameData,data,l); + data += l; + } + else memset(frameData,0,l); + frameData += l; len -= l; frameCount -= l; + + ED("PutData: %s=%d len=%d frameCount=%d\n",data?"put":"zero",l,len,frameCount); + if (!frameCount) { + FinishFrame(); + if (totalSize > 0) NewFrame(0,0); + } + } + } +} + +void cAudioEncapsulator::SendIECpause(int type, uchar PTSflags, const uchar *PTSdata) +{ + StartFrame(AC3_SIZE,PTSflags,PTSdata); + uchar burst[IEC_HDR_SIZE]; + // prepare IEC 60958 data frame + burst[0] = 0xF8; + burst[1] = 0x72; + burst[2] = 0x4E; + burst[3] = 0x1F; + + switch (type) { + default: + case 0: + burst[4] = 7 << 5; // null frame, stream = 7 + burst[5] = 0x00; + burst[6] = 0x00; // No data therein + burst[7] = 0x00; + break; + case 1: + burst[4] = 0x00; // Audio ES Channel empty, wait + burst[5] = 0x03; // for DD Decoder or pause + burst[6] = 0x00; // Trailing frame size is 32 bits payload + burst[7] = 0x20; + break; + case -1: + burst[4] = 0x01; // User stop, skip or error + burst[5] = 0x03; + burst[6] = 0x08; // Trailing frame size is zero + burst[7] = 0x00; + break; + } + PutData(burst,sizeof(burst)); + PutData(0,AC3_SIZE-sizeof(burst)); + FinishFrame(); + muteData = true; +} + +void cAudioEncapsulator::FinishIECFrame(void) +{ + if(!muteData) { + ED("FinishIECFrame: fillup=%d\n",fillup); + if (fillup) PutData(0,fillup); + FinishFrame(); + } + muteData=false; fillup=0; +} + +void cAudioEncapsulator::SyncFound(const uchar *data) +{ + if(skipped) { + DEBUG("Decode: skipped %d bytes\n",skipped); + ED("skipped: "); for(int k=-skipped ; k<0 ; k++) ED("%02x ",data[k]); + ED("\ndata: "); for(int k=0 ; k<24 ; k++) ED("%02x ",data[k]); + ED("\n"); + skipped=0; + } + uchar pf=0; + ED("Decode: sync found ptsFlags=%d ptsDelay=%d\n",ptsFlags,ptsDelay); + if(ptsFlags && ptsDelay<=1) { + pf=ptsFlags; ptsFlags=0; + } + if(firstBurst || mute) { + SendIECpause(1,pf,ptsData); + if(firstBurst && ++firstBurst>10) firstBurst=0; + } + else StartIECFrame(data,length,pf,ptsData); + PutData(data,SYNC_SIZE); + have = SYNC_SIZE; +} + +void cAudioEncapsulator::Decode(const uchar *data, int len, uchar PTSflags, int PTSdelay, const uchar *PTSdata) +{ + ED("Decode: enter length=%d have=%d len=%d PTSflags=%d PTSdelay=%d\n",length,have,len,PTSflags,PTSdelay); + if(PTSflags) { + // if we are close to the end of an audio frame, but are already receiving + // the start of the next frame, assume a corrupted stream and finish the + // incomplete frame. + if(length && length-have<20 && !PTSdelay && SyncInfo(data)) { + int miss=length-have; + DEBUG("Decode: incomplete frame (stream corrupt?). syncing to next. miss=%d\n",miss); + PutData(0,miss); + FinishIECFrame(); + length=have=0; + } +/* + // we only send PTS info if we're nearly at frame start, except + // if we're signaled to delay the PTS + if(length && have>40) { + if(PTSdelay) ED("Decode: PTS delayed\n"); + else { + DEBUG("Decode: PTS info dropped length=%d have=%d\n",length,have); + PTSflags=0; + } + } +*/ + ptsFlags=PTSflags; ptsData=PTSdata; ptsDelay=PTSdelay; +// ED("Decode: saved PTS flags=%d delay=%d\n",ptsFlags,ptsDelay); + } + +#if 0 + { + printf("Decode: len=%d\n",len); + for(int i=0 ; i<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 { // unfortunaly buffer is not empty, so continue with buffering until sync found + int need=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 = 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. Unfortunaly the continuation + // packets start with the aLPCM code sometimes. Some magic here to detect + // this case. + uchar subStreamType=b[0]; + if(subStreamType!=aVDR) subStreamType&=0xF8; + bool aligned=header[6]&4; + if(!aligned) { + uchar ost=encapsulator ? encapsulator->StreamType() : 0; + if(!ptsFlags) { + if((subStreamType!=aLPCM && subStreamType!=aSPU) || fixed) { + if(ost>0) { + ED("multichannel: crossing -> keep encapsulator\n"); + subStreamType=ost; + } + else { + ED("multichannel: crossing -> skip\n"); + res=1; goto out; // skip + } + } + } + else if(fixed && ost>0) { + ED("multichannel: fixed unaligned -> keep encapsulator\n"); + subStreamType=ost; + } + } + fixed=false; + + switch(subStreamType) { + case aDTS: + case aAC3: + offset=4; // skip the DVD stream infos + break; + default: + if(aligned || !ptsFlags) { + if(encapsulator) { + Reset(); + DEBUG("multichannel: interrupted encapsulator stream (unknown)\n"); + } + DEBUG("multichannel: unknown substream type %x (skipped)\n",subStreamType); + res=1; goto out; // skip + } + subStreamType=aVDR; + ED("multichannel: assuming aVDR for unknown substream type\n"); + // fall through + case aVDR: + fixed=true; + break; + case aLPCM: + if(encapsulator) { + Reset(); + DEBUG("multichannel: interrupted encapsulator stream (LPCM)\n"); + } + ED("multichannel: LPCM\n"); + res=2; goto out; // pass + case aSPU: + ED("multichannel: SPU stream (skipped)\n"); + res=1; goto out; // skip + } + + // If the SubStreamType has changed then select the right encapsulator + if(!encapsulator || encapsulator->StreamType()!=subStreamType) { + DEBUG("multichannel: new encapsulator %x\n",subStreamType); + Reset(); + switch(subStreamType) { + case aAC3: + case aVDR: // AC3 + encapsulator=new cAudioEncapsulatorAC3(ringBuffer,subStreamType); + break; + case aDTS: // Dts + encapsulator=new cAudioEncapsulatorDTS(ringBuffer,subStreamType); + break; + } + if(!encapsulator) { + DEBUG("multichannel: no encapsulator\n"); + res=1; goto out; // skip + } + } + +out: + ED("HEADER type=%x sub=%x ptsflags=%d length=%d\n",header[3],subStreamType,ptsFlags,length); + ED("head: "); for(int k=0 ; k<24 ; k++) ED("%02x ",header[k]); + ED("\ndata: "); for(int k=0 ; k<24 ; k++) ED("%02x ",b[k]); + ED("\n"); + + Unlock(); return res; +} + +void cMultichannelAudio::Encapsulate(uchar *b, int length) +{ + Lock(); + if(offset && ptsFlags) { // get start of the packet to which the PTS belong (DVD only) + if(offset>=2 && length>offset-2) ptsDelay|=b[offset-2]*256; + if(offset>=1 && length>offset-1) ptsDelay|=b[offset-1]; + } + if(length>=offset) { + if(encapsulator) + encapsulator->Decode(b+offset,length-offset,ptsFlags,ptsDelay,ptsData); + ptsFlags=0; ptsDelay=0; offset=0; ptsData=0; + } + else offset-=length; + Unlock(); +} + diff --git a/dxr3multichannelaudio.h b/dxr3multichannelaudio.h new file mode 100644 index 0000000..689f8f1 --- /dev/null +++ b/dxr3multichannelaudio.h @@ -0,0 +1,33 @@ +#ifndef _DXR3MULTICHANNELAUDIO_H_ +#define _DXR3MULTICHANNELAUDIO_H_ + +#include "dxr3vdrincludes.h" + +class cAudioEncapsulator; +class cRingBufferFrame; + +// ================================== +// Based on AC3overDVB Patch maintained +// by Stefan Huelswitt +class cMultichannelAudio : public cMutex +{ +private: + cAudioEncapsulator *encapsulator; + cRingBufferFrame *ringBuffer; + int ptsFlags, ptsDelay, offset; + uchar *ptsData; + bool fixed; + +public: + cMultichannelAudio(cRingBufferFrame *rb); + virtual ~cMultichannelAudio(); + + int Check(uchar *b, int length, uchar *header); + int Offset(void) { return offset; } + void Encapsulate(uchar *b, int length); + void Clear(); + void Reset(); + //void Mute(bool Mute); +}; + +#endif /*_DXR3MULTICHANNELAUDIO_H_*/ diff --git a/dxr3nextpts.c b/dxr3nextpts.c new file mode 100644 index 0000000..72b3e31 --- /dev/null +++ b/dxr3nextpts.c @@ -0,0 +1,4 @@ +#include "dxr3nextpts.h" + +// ================================== +cMutex* cDxr3NextPts::m_pMutex = new cMutex; diff --git a/dxr3nextpts.h b/dxr3nextpts.h new file mode 100644 index 0000000..0391a48 --- /dev/null +++ b/dxr3nextpts.h @@ -0,0 +1,42 @@ +/* + * dxr3nextpts.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3NEXTPTS_H_ +#define _DXR3NEXTPTS_H_ + +#include <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_*/ diff --git a/dxr3osd.c b/dxr3osd.c new file mode 100644 index 0000000..6bb5f43 --- /dev/null +++ b/dxr3osd.c @@ -0,0 +1,161 @@ +/* + * dxr3osd.c + * + * Copyright (C) 2002 Stefan Schluenss + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <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" + +#if VDRVERSNUM >= 10307 + +//#include "dxr3osd_mpeg.h" +#include "dxr3osd_subpicture.h" + +// ================================== +cOsd *cDxr3OsdProvider::CreateOsd(int Left, int Top) +{ +// if (cDxr3ConfigData::Instance().GetMenuMode() == (eMenuMode)SUBPICTURE) +// { + // use subpicture + return new cDxr3SubpictureOsd(Left, Top); +/* } + else + { + // mpeg based menu system + return new cDxr3MpegOsd(Left, Top); + }*/ +} + +#else /*VDRVERSNUM*/ + +// ================================== +bool cDxr3Osd::SetWindow(cWindow *Window) +{ + if (Window) + { + // Window handles are counted 0...(MAXNUMWINDOWS - 1), but the actual window + // numbers in the driver are used from 1...MAXNUMWINDOWS. + int Handle = Window->Handle(); + if (0 <= Handle && Handle < MAXNUMWINDOWS) + { + Spu->Cmd(OSD_SetWindow, 0, Handle + 1); + return true; + } + esyslog("ERROR: illegal window handle: %d", Handle); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3Osd::SetWindow: illegal window handle:" << Handle << "\n"; + } + } + return false; +} + +// ================================== +cDxr3Osd::cDxr3Osd(int x, int y) : cOsdBase(x, y) +{ + Spu = &cSPUEncoder::Instance(); +} + +// ================================== +cDxr3Osd::~cDxr3Osd() +{ + for (int i = 0; i < NumWindows(); i++) + { + CloseWindow(GetWindowNr(i)); + } +} + +// ================================== +bool cDxr3Osd::OpenWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_Open, Window->Bpp(), X0() + Window->X0(), Y0() + Window->Y0(), X0() + Window->X0() + Window->Width() - 1, Y0() + Window->Y0() + Window->Height() - 1, (void *)1); // initially hidden! + return true; + } + return false; +} + +// ================================== +void cDxr3Osd::CommitWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + + if (Window->Dirty(x1, y1, x2, y2)) + { + // commit colors: + int FirstColor = 0, LastColor = 0; + const eDvbColor *pal; + while ((pal = Window->NewColors(FirstColor, LastColor)) != NULL) + Spu->Cmd(OSD_SetPalette, FirstColor, LastColor, 0, 0, 0, pal); + // commit modified data: + Spu->Cmd(OSD_SetBlock, Window->Width(), x1, y1, x2, y2, Window->Data(x1, y1)); + } + } +} + +// ================================== +void cDxr3Osd::ShowWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_MoveWindow, 0, X0() + Window->X0(), Y0() + Window->Y0()); + } +} + +// ================================== +void cDxr3Osd::HideWindow(cWindow *Window, bool Hide) +{ + if (SetWindow(Window)) + { + Spu->Cmd(Hide ? OSD_Hide : OSD_Show, 0); + } +} + +// ================================== +void cDxr3Osd::CloseWindow(cWindow *Window) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_Close); + } +} + +// ================================== +void cDxr3Osd::MoveWindow(cWindow *Window, int x, int y) +{ + if (SetWindow(Window)) + { + Spu->Cmd(OSD_MoveWindow, 0, X0() + x, Y0() + y); + } +} + +#endif /*VDRVERSNUM*/ diff --git a/dxr3osd.h b/dxr3osd.h new file mode 100644 index 0000000..234689e --- /dev/null +++ b/dxr3osd.h @@ -0,0 +1,42 @@ +#ifndef _DXR3_OSD_H_ +#define _DXR3_OSD_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3interface_spu_encoder.h" + +#if VDRVERSNUM >= 10307 + +// ================================== +// osd plugin provider +class cDxr3OsdProvider : public cOsdProvider +{ +public: + cDxr3OsdProvider() {} + virtual cOsd *CreateOsd(int Left, int Top); +}; + +#else /*VDRVERSNUM*/ + +// ================================== +// osd interface for =< vdr1,3,7 +class cDxr3Osd : public cOsdBase +{ +private: + cSPUEncoder* Spu; + + bool SetWindow(cWindow*); + +public: + cDxr3Osd(int x, int y); + ~cDxr3Osd(); + + virtual bool OpenWindow(cWindow *Window); + virtual void CommitWindow(cWindow *Window); + virtual void ShowWindow(cWindow *Window); + virtual void HideWindow(cWindow *Window, bool Hide); + virtual void CloseWindow(cWindow *Window); + virtual void MoveWindow(cWindow *Window, int x, int y); +}; + +#endif /*VDRVERSNUM*/ +#endif /*_DXR3_OSD_H_*/ diff --git a/dxr3osd_subpicture.c b/dxr3osd_subpicture.c new file mode 100644 index 0000000..e6dc154 --- /dev/null +++ b/dxr3osd_subpicture.c @@ -0,0 +1,174 @@ +#include "dxr3osd_subpicture.h" + +#if VDRVERSNUM >= 10307 + +#define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 + +// ================================== +cDxr3SubpictureOsd::cDxr3SubpictureOsd(int Left, int Top) : cOsd(Left, Top) +{ + shown = false; + Spu = &cSPUEncoder::Instance(); + + // must clear all windows here to avoid flashing effects - doesn't work if done + // in Flush() only for the windows that are actually used... + for (int i = 0; i < MAXNUMWINDOWS; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + Spu->Cmd(OSD_Clear); + } + +} + +// ================================== +cDxr3SubpictureOsd::~cDxr3SubpictureOsd() +{ + if (shown) + { + cBitmap *Bitmap; + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + Spu->Cmd(OSD_Close); + } + } +} + +// ================================== +eOsdError cDxr3SubpictureOsd::CanHandleAreas(const tArea *Areas, int NumAreas) +{ + + eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas); + if (Result == oeOk) + { + if (NumAreas > MAXNUMWINDOWS) + { + return oeTooManyAreas; + } + + for (int i = 0; i < NumAreas; i++) + { + if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8) + { + return oeBppNotSupported; + } + + if ((Areas[i].Width() & (8 / Areas[i].bpp - 1)) != 0) + { + return oeWrongAlignment; + } + } + } + return Result; +} + +// ================================== +void cDxr3SubpictureOsd::SaveRegion(int x1, int y1, int x2, int y2) +{ + // ToDo? +} + +// ================================== +void cDxr3SubpictureOsd::RestoreRegion() +{ + // ToDo? +} + +// ================================== +void cDxr3SubpictureOsd::Flush() +{ + cBitmap *Bitmap; + + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + + if (!shown) + { + Spu->Cmd(OSD_Open, Bitmap->Bpp(), Left() + Bitmap->X0(), Top() + Bitmap->Y0(), Left() + Bitmap->X0() + Bitmap->Width() - 1, Top() + Bitmap->Y0() + Bitmap->Height() - 1, (void *)1); // initially hidden! + } + + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + if (Bitmap->Dirty(x1, y1, x2, y2)) + { + //TODO Workaround: apparently the bitmap sent to the driver always has to be a multiple + //TODO of 8 bits wide, and (dx * dy) also has to be a multiple of 8. + //TODO Fix driver (should be able to handle any size bitmaps!) + + while ((x1 > 0 || x2 < Bitmap->Width() - 1) && ((x2 - x1) & 7) != 7) + { + if (x2 < Bitmap->Width() - 1) + { + x2++; + } + else if (x1 > 0) + { + x1--; + } + } + + //TODO "... / 2" <==> Bpp??? + while ((y1 > 0 || y2 < Bitmap->Height() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) + { + if (y2 < Bitmap->Height() - 1) + { + y2++; + } + else if (y1 > 0) + { + y1--; + } + } + + while ((x1 > 0 || x2 < Bitmap->Width() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) + { + if (x2 < Bitmap->Width() - 1) + { + x2++; + } + else if (x1 > 0) + { + x1--; + } + } + + // commit colors: + int NumColors; + const tColor *Colors = Bitmap->Colors(NumColors); + + if (Colors) + { + + // TODO this should be fixed in the driver! + tColor colors[NumColors]; + for (int i = 0; i < NumColors; i++) + { + // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): + colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); + } + + Colors = colors; + //TODO end of stuff that should be fixed in the driver + Spu->Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); + } + // commit modified data: + //Spu->Cmd(OSD_SetBlock, Bitmap->Width(), x1, y1, x2, y2, Bitmap->Data(x1, y1)); + Spu->Cmd(OSD_SetBlock, Bitmap->Width(), x1, y1, x2, y2, Bitmap->Data(x1, y1)); + } + Bitmap->Clean(); + } + + if (!shown) + { + // Showing the windows in a separate loop to avoid seeing them come up one after another + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + { + Spu->Cmd(OSD_SetWindow, 0, i + 1); + Spu->Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0()); + } + shown = true; + } +} + +#endif /*VDRVERSNUM*/ + diff --git a/dxr3osd_subpicture.h b/dxr3osd_subpicture.h new file mode 100644 index 0000000..6806c90 --- /dev/null +++ b/dxr3osd_subpicture.h @@ -0,0 +1,29 @@ +#ifndef _DXR3OSD_SUBPICTURE_H_ +#define _DXR3OSD_SUBPICTURE_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3interface_spu_encoder.h" + +#if VDRVERSNUM >= 10307 + +// ================================== +// osd interface for => vdr1,3,7 +class cDxr3SubpictureOsd : public cOsd +{ +private: + cSPUEncoder* Spu; + bool shown; + +public: + cDxr3SubpictureOsd(int Left, int Top/*, int SpuDev*/); + ~cDxr3SubpictureOsd(); + + eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); + void SaveRegion(int x1, int y1, int x2, int y2); + void RestoreRegion(void); + + void Flush(); +}; + +#endif /*VDRVERSNUM*/ +#endif /*_DXR3OSD_SUBPICTURE_H_*/ diff --git a/dxr3outputthread.c b/dxr3outputthread.c new file mode 100644 index 0000000..d4a4a8e --- /dev/null +++ b/dxr3outputthread.c @@ -0,0 +1,279 @@ +/* + * dxr3outputthread.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <pthread.h> +#include "dxr3outputthread.h" +#include "dxr3log.h" + +// ================================== +const int AUDIO_OFFSET = 4500; +#define SCR m_dxr3Device.GetSysClock() +// ================================== + +// ================================== +// constr. +cDxr3OutputThread::cDxr3OutputThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer) : +cThread(), m_dxr3Device(dxr3Device), m_buffer(buffer), m_bStopThread(false), m_bNeedResync(false) +{ +} + +// ================================== +// send stop signal +void cDxr3OutputThread::SetStopSignal() +{ + Lock(); + m_bStopThread = true; + Unlock(); +} + +// ================================== +// was stop signal send? +bool cDxr3OutputThread::GetStopSignal() +{ + bool ret = false; + Lock(); + ret = m_bStopThread; + Unlock(); + + return ret; +} + +// ================================== +// constr. +cDxr3AudioOutThread::cDxr3AudioOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer) : +cDxr3OutputThread(dxr3Device, buffer) +{ +} + +// ================================== +// thread action +void cDxr3AudioOutThread::Action() +{ + bool resync = false; + uint32_t pts = 0; + + cLog::Instance() << "cDxr3AudioOutThread::Action Thread started\n"; + + sched_param temp; + temp.sched_priority = 2; + + if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) + { + cLog::Instance() << "cDxr3AudioOutThread::Action(): Error can't set priority\n"; + } + + while (!GetStopSignal()) + { + pts = 0; + cFixedLengthFrame* pNext = m_buffer.Get(); + + if (pNext) pts = pNext->GetPts(); + + if (pts && abs((int)pts-(int)SCR) > 30000 || m_dxr3Device.IsExternalReleased()) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { + cLog::Instance() << "cDxr3AudioOutThread::Action " << "pts = " << pts << " scr = " << SCR << "\n"; + } + m_buffer.Clear(); + m_bNeedResync = true; + } + else if (pNext) + { + if (!pts || pts < SCR) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// if (pts) cLog::Instance() << "cDxr3AudioOutThread::Action pts " << pNext->GetPts() << " scr " << SCR << " delta " << (pts - SCR) << "\n"; + } + if (!pts && resync) + { + continue; + } + else + { + resync = false; + } + + if (pts && (pts < SCR) && ((SCR - pts) > 5000)) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action pts audio too small " << (SCR - pts) << "\n"; + } + m_dxr3Device.SetSysClock(pts+ 1 * AUDIO_OFFSET); + m_dxr3Device.PlayAudioFrame(pNext); + if (m_buffer.IsPolled()) + { + m_buffer.Clear(); + m_bNeedResync = true; + } + } + else + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action write audio\n"; + } + m_dxr3Device.PlayAudioFrame(pNext); + m_buffer.Pop(); + } + } + else + { + if (abs((int)pts - (int)SCR) < (AUDIO_OFFSET )) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// if (pts) cLog::Instance() << "cDxr3AudioOutThread::Action pts " << pNext->GetPts() << " scr " << SCR << " delta " << (pts - SCR) << "\n"; + } + m_dxr3Device.PlayAudioFrame(pNext); + m_buffer.Pop(); + } + } + } + + if ((pts > SCR && abs((int)pts - (int)SCR) > AUDIO_OFFSET)) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action Stopping audio " << SCR << " " << pts << "\n"; + } + + usleep(10000); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3AudioOutThread::Action Starting audio " << SCR << " " << pts << "\n"; + } + } + } +} + +// ================================== +// constr. +cDxr3VideoOutThread::cDxr3VideoOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer) : +cDxr3OutputThread(dxr3Device, buffer) +{ +} + +// ================================== +// thread action +void cDxr3VideoOutThread::Action() +{ + uint32_t pts = 0; + static uint32_t lastPts = 0; + + cLog::Instance() << "cDxr3VideoOutThread::Action Thread started\n"; + + sched_param temp; + temp.sched_priority = 1; + + if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action(): Error can't set priority\n"; + } + + while (!GetStopSignal()) + { + cFixedLengthFrame* pNext = m_buffer.Get(); + if (pNext) + { + pts = pNext->GetPts(); + if (pts == lastPts) pts = 0; + + if (pts > SCR && abs((int)pts - (int)SCR) < 7500) + { + m_dxr3Device.SetPts(pts); + } + + if (!pts || pts < SCR) + { + if (m_buffer.Available()) + { + m_dxr3Device.PlayVideoFrame(pNext); + m_buffer.Pop(); + } + } + else + { + if ((pts > SCR) && abs((int)pts - (int)SCR) < 7500) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action pts " << pts << " scr " << SCR << " delta " << (pts - SCR) << "\n"; + } + + m_dxr3Device.SetPts(pts); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action done\n"; + } + + if (m_buffer.Available() && pNext->GetData() && pNext->GetCount()) + { + m_dxr3Device.PlayVideoFrame(pNext); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action write\n"; + } + + m_buffer.Pop(); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action done pop\n"; + } + } + if (cDxr3ConfigData::Instance().GetDebug()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action done complete\n"; + } + } + else + { + if (pts < SCR) + { + m_dxr3Device.PlayVideoFrame(pNext); + m_buffer.Pop(); + } + } + } + + + if (m_dxr3Device.IsExternalReleased()) + { + m_bNeedResync = true; + m_buffer.Clear(); + } + + if ((pts > SCR && abs((int)pts - (int)SCR) > 7500 )) + { + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action Stopping video " << SCR << " " << pts << "\n"; + } + + usleep(10000); + + if (cDxr3ConfigData::Instance().GetDebugEverything()) + { +// cLog::Instance() << "cDxr3VideoOutThread::Action Starting video " << SCR << " " << pts << "\n"; + } + } + } + } +} + + +#undef SCR diff --git a/dxr3outputthread.h b/dxr3outputthread.h new file mode 100644 index 0000000..1ed7dc6 --- /dev/null +++ b/dxr3outputthread.h @@ -0,0 +1,71 @@ +/* + * dxr3outputthread.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3OUTPUTTHREAD_H_ +#define _DXR3OUTPUTTHREAD_H_ + +#include "dxr3vdrincludes.h" +#include "dxr3syncbuffer.h" +#include "dxr3audiodecoder.h" + +// ================================== +class cDxr3OutputThread : public cThread +{ +public: + cDxr3OutputThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer); + virtual ~cDxr3OutputThread() {Cancel();}; + + // virtual void Start(void) {cThread::Start()}; + void SetStopSignal(); + bool NeedResync() { return m_bNeedResync;}; + void ClearResyncRequest() { m_bNeedResync = false;}; + +protected: + virtual void Action() = 0; + bool GetStopSignal(); + + cDxr3Interface& m_dxr3Device; + cDxr3SyncBuffer& m_buffer; + bool m_bStopThread; + bool m_bNeedResync; + +private: + cDxr3OutputThread(cDxr3OutputThread&); // no copy contructor +}; + +// ================================== +class cDxr3AudioOutThread : public cDxr3OutputThread +{ +public: + cDxr3AudioOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer); + virtual ~cDxr3AudioOutThread() {} + +protected: + void Action(); + +private: +// cDxr3AudioOutThread(); // no standard constructor + cDxr3AudioOutThread(cDxr3AudioOutThread&); // no copy constructor +}; + +// ================================== +class cDxr3VideoOutThread : public cDxr3OutputThread +{ +public: + cDxr3VideoOutThread(cDxr3Interface& dxr3Device, cDxr3SyncBuffer& buffer); + virtual ~cDxr3VideoOutThread() {} + +protected: + void Action(); + +private: +// cDxr3VideoOutThread(); // no standard constructor + cDxr3VideoOutThread(cDxr3VideoOutThread&); // no copy constructor +}; + +#endif /*_DXR3OUTPUTTHREAD_H_*/ diff --git a/dxr3palettemanager.c b/dxr3palettemanager.c new file mode 100644 index 0000000..0769722 --- /dev/null +++ b/dxr3palettemanager.c @@ -0,0 +1,114 @@ +/* + * dxr3palettemanager.c: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +/* + ToDo: + - cDxr3PaletteManager: Should we use here std::vector? +*/ + +#include <string.h> +#include "dxr3palettemanager.h" +#include "dxr3tools.h" + +// ================================== +cDxr3PaletteManager::cDxr3PaletteManager() +{ + memset(m_colors, 0, sizeof(int) * MAX_COLORS); + memset(m_users, 0, sizeof(int) * MAX_COLORS); + memset(m_pal, 0, sizeof(int) * MAX_COLORS); + m_changed = false; +}; + +// ================================== +void cDxr3PaletteManager::AddColor(int color) +{ + int freeIndex = MAX_COLORS; + bool found = false; + + for (int i = 0; i < MAX_COLORS && !found; ++i) + { + if (color == m_colors[i]) + { + if (m_users[i] == 0) m_changed = true; + ++m_users[i]; + found = true; + } + if (m_users[i] == 0 && freeIndex >= MAX_COLORS) + { + freeIndex = i; + } + } + if (!found && freeIndex < MAX_COLORS) + { + m_colors[freeIndex] = color; + m_users[freeIndex] = 1; + m_changed = true; + } +} + +// ================================== +void cDxr3PaletteManager::RemoveColor(int color) +{ + bool found = false; + for (int i = 0; i < MAX_COLORS && !found; ++i) + { + if (color == m_colors[i]) + { + if (m_users[i] > 0) --m_users[i]; + found = true; + } + } +} + +// ================================== +int cDxr3PaletteManager::GetIndex(int color) +{ + bool found = false; + int index = 0; + for (int i = 0; i < MAX_COLORS && !found; ++i) + { + if (color == m_colors[i]) + { + index = i; + found = true; + } + } + return index; +} + +// ================================== +int cDxr3PaletteManager::GetCount() +{ + return MAX_COLORS; +} + +// ================================== +int cDxr3PaletteManager::operator[](int index) +{ + assert(index < MAX_COLORS && index > 0); + return m_colors[index]; +} + +// ================================== +bool cDxr3PaletteManager::HasChanged() +{ + bool retval = m_changed; + m_changed = false; + return retval; +} + +// ================================== +uint32_t* cDxr3PaletteManager::GetPalette() +{ + for (int i = 0; i < MAX_COLORS; ++i) + { + m_pal[i] = Tools::Rgb2YCrCb(m_colors[i]); + } + + return m_pal; +} diff --git a/dxr3palettemanager.h b/dxr3palettemanager.h new file mode 100644 index 0000000..94253b8 --- /dev/null +++ b/dxr3palettemanager.h @@ -0,0 +1,39 @@ +/* + * dxr3palettemanager.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3PALETTEMANAGER_H_ +#define _DXR3PALETTEMANAGER_H_ + +#include <assert.h> +#include <stdlib.h> +#include <stdint.h> + +// ================================== +class cDxr3PaletteManager +{ +public: + cDxr3PaletteManager(); + ~cDxr3PaletteManager() {}; + + void AddColor(int color); + void RemoveColor(int color); + int GetCount(); + int operator[](int index); + int GetIndex(int color); + bool HasChanged(); + uint32_t* GetPalette(); + +private: + static const int MAX_COLORS = 16; + int m_colors[MAX_COLORS]; + uint32_t m_pal[MAX_COLORS]; + int m_users[MAX_COLORS]; + bool m_changed; +}; + +#endif /*_DXR3PALETTEMANAGER_H_*/ diff --git a/dxr3pesframe.c b/dxr3pesframe.c new file mode 100644 index 0000000..c86002e --- /dev/null +++ b/dxr3pesframe.c @@ -0,0 +1,226 @@ +#include "dxr3pesframe.h" +#include "dxr3log.h" +#include <linux/em8300.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.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++); + 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; + cLog::Instance() << "*** PES_GENERAL_ERROR ****\n"; + 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; + } + } + } + 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; +const uint32_t cDxr3PesFrame::MAX_PES_HEADER_SIZE = 184; + diff --git a/dxr3pesframe.h b/dxr3pesframe.h new file mode 100644 index 0000000..e0d9034 --- /dev/null +++ b/dxr3pesframe.h @@ -0,0 +1,158 @@ +/* + * dxr3pesframe.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3PESFRAME_H_ +#define _DXR3PESFRAME_H_ + +#include <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_streamId(0), m_pNextStart(0), m_remainingLength(0) + , m_offset(0) {}; + + virtual ~cDxr3PesFrame() {} + + bool ExtractNextFrame(const uint8_t* pBuf, uint32_t length) throw (ePesFrameError); + + ePesDataType GetPesDataType(void) const { assert(m_bValid); return m_pesDataType; }; + const uint8_t* GetPesStart(void) const { assert(m_bValid); return m_pPesStart; }; + const uint8_t* GetEsStart(void) const { assert(m_bValid); return m_pEsStart; }; + uint32_t GetEsLength(void) const { assert(m_bValid); return m_esLength; }; + + const uint8_t* GetNextStart(void) const { return m_pNextStart;}; + uint32_t GetRemainingLength(void) const { return m_remainingLength;}; + + uint32_t GetPts(void) const { assert(m_bValid); return m_pts; }; + + eVideoFrameType GetFrameType(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_videoFrameType;}; + uint32_t GetAspectRatio(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_aspectRatio;}; + uint32_t GetHorizontalSize(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_horizontalSize;}; + uint8_t GetStreamId(void) const { assert(m_bValid); assert(m_pesDataType == PES_VIDEO_DATA); return m_streamId;}; + int GetOffset(void) const { assert(m_bValid); return m_offset;}; + + bool IsValid(void) { return m_bValid; }; + +protected: + bool IsPesHeader(cDxr3SafeArray<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_streamId = 0; + m_pNextStart = 0; + m_remainingLength = 0; + m_offset = 0; + } + + ePesDataType m_pesDataType; + bool m_bValid; + const uint8_t* m_pPesStart; + const uint8_t* m_pEsStart; + uint32_t m_esLength; + uint32_t m_pts; + + eVideoFrameType m_videoFrameType; + uint32_t m_aspectRatio; + uint32_t m_horizontalSize; + uint8_t m_streamId; + + const uint8_t* m_pNextStart; + uint32_t m_remainingLength; + int m_offset; + + static uint32_t m_staticAspectRatio; + static uint32_t m_staticHorizontalSize; + +protected: + static const uint32_t MAX_PES_HEADER_SIZE; + +private: + cDxr3PesFrame(cDxr3PesFrame&); // no copy constructor + +}; + + +#endif /*_DXR3PESFRAME_H_*/ + + diff --git a/dxr3singleton.h b/dxr3singleton.h new file mode 100644 index 0000000..6db2c26 --- /dev/null +++ b/dxr3singleton.h @@ -0,0 +1,43 @@ +/* + * dxr3singleton.h + * + * Copyright (C) 2004 Christian Gmeiner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _DXR3_SINGLETON_H_ +#define _DXR3_SINGLETON_H_ + +// ================================== +// This template makes it easy to make +// global things +template<typename T> +class Singleton +{ + protected: + Singleton() {} + virtual ~Singleton() {} + + public: + static T& Instance() + { + static T m_Instance; + return m_Instance; + } +}; + +#endif /*_DXR3_SINGLETON_H_*/ diff --git a/dxr3spudecoder.c b/dxr3spudecoder.c new file mode 100644 index 0000000..7e56219 --- /dev/null +++ b/dxr3spudecoder.c @@ -0,0 +1,628 @@ +/* + * dxr3spudecoder.c + * + * Copyright (C) 2004 Christian Gmeiner + * + * Orginal: + * Copyright (C) 2001.2002 Andreas Schultz <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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* +ToDo: + - Line 175 +*/ + +#include <assert.h> +#include <string.h> +#include <inttypes.h> +#include <math.h> + +#include "dxr3spudecoder.h" +#include "dxr3interface.h" +#include "dxr3tools.h" +#include "dxr3log.h" + +// ================================== +#define CMD_SPU_MENU 0x00 +#define CMD_SPU_SHOW 0x01 +#define CMD_SPU_HIDE 0x02 +#define CMD_SPU_SET_PALETTE 0x03 +#define CMD_SPU_SET_ALPHA 0x04 +#define CMD_SPU_SET_SIZE 0x05 +#define CMD_SPU_SET_PXD_OFFSET 0x06 +#define CMD_SPU_EOF 0xff + +#define spuU32(i) ((spu[i] << 8) + spu[i+1]) + + +/* + * cDxr3Spubitmap: + * + * this is a bitmap of the full screen and two palettes + * the normal palette for the background and the highlight palette + * + * Inputs: + * - a SPU rle encoded image on creation, which will be decoded into + * the full screen indexed bitmap + * + * Output: + * - a minimal sized cDxr3SpuBitmap a given palette, the indexed bitmap + * will be scanned to get the smallest possible resulting bitmap considering + * transparencies + */ + + +// ================================== +void cDxr3SpuPalette::setPalette(const uint32_t * pal) +{ + for (int i = 0; i < 16; i++) + palette[i] = Tools::YUV2Rgb(pal[i]); +} + +// ================================== +#define setMin(a, b) if (a > b) a = b +#define setMax(a, b) if (a < b) a = b + +#define spuXres 720 +#define spuYres 576 + +#define revRect(r1, r2) { r1.x1 = r2.x2; r1.y1 = r2.y2; r1.x2 = r2.x1; r1.y2 = r2.y1; } + +// ================================== +cDxr3SpuBitmap::cDxr3SpuBitmap(sDxr3SpuRect size, uint8_t * fodd, uint8_t * eodd, uint8_t * feven, uint8_t * eeven) +{ + if (size.x1 < 0 || size.y1 < 0 || size.x2 >= spuXres + || size.y2 >= spuYres) + throw; + + bmpsize = size; + revRect(minsize[0], size); + revRect(minsize[1], size); + revRect(minsize[2], size); + revRect(minsize[3], size); + + if (!(bmp = new uint8_t[spuXres * spuYres * sizeof(uint8_t)])) + throw; + + memset(bmp, 0, spuXres * spuYres * sizeof(uint8_t)); + putFieldData(0, fodd, eodd); + putFieldData(1, feven, eeven); +} + +// ================================== +cDxr3SpuBitmap::~cDxr3SpuBitmap() +{ + delete[]bmp; +} + +// ================================== +cBitmap *cDxr3SpuBitmap::getBitmap(const aDxr3SpuPalDescr paldescr, const cDxr3SpuPalette & pal, sDxr3SpuRect & size) const +{ + int h = size.height(); + int w = size.width(); + + if (size.y1 + h >= spuYres) + { + h = spuYres - size.y1 - 1; + } + if (size.x1 + w >= spuXres) + { + w = spuXres - size.x1 - 1; + } + + if (w & 0x03) + { + w += 4 - (w & 0x03); + } + + cBitmap *ret = new cBitmap(w, h, 2); + + // set the palette + for (int i = 0; i < 4; i++) + { + uint32_t color = pal.getColor(paldescr[i].index, paldescr[i].trans); + ret->SetColor(i, (tColor) color); + } + + // set the content + for (int yp = 0; yp < h; yp++) + { + for (int xp = 0; xp < w; xp++) + { + uint8_t idx = bmp[(size.y1 + yp) * spuXres + size.x1 + xp]; + ret->SetIndex(xp, yp, idx); + } + } + return ret; +} + +// ================================== +// find the minimum non-transparent area +bool cDxr3SpuBitmap::getMinSize(const aDxr3SpuPalDescr paldescr, sDxr3SpuRect & size) const +{ + bool ret = false; + for (int i = 0; i < 4; i++) + { + if (paldescr[i].trans != 0) + { + if (!ret) + { + size = minsize[i]; + } + else + { + setMin(size.x1, minsize[i].x1); + setMin(size.y1, minsize[i].y1); + setMax(size.x2, minsize[i].x2); + setMax(size.y2, minsize[i].y2); + } + ret = true; + } + } +/* + if (ret && cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuBitmap::getMinSize: (" << size.x1 ", " << size.y1 << ") x (" << size.x2 << ", " << size.y2 << ")\n"; + } +*/ + return ret; +} + +// ================================== +void cDxr3SpuBitmap::putPixel(int xp, int yp, int len, uint8_t colorid) +{ + memset(bmp + spuXres * yp + xp, colorid, len); + setMin(minsize[colorid].x1, xp); + setMin(minsize[colorid].y1, yp); + setMax(minsize[colorid].x2, xp + len - 1); + setMax(minsize[colorid].y2, yp + len - 1); +} + +// ================================== +static uint8_t getBits(uint8_t * &data, uint8_t & bitf) +{ + uint8_t ret = *data; + if (bitf) + { + ret >>= 4; + } + else + { + data++; + } + + bitf ^= 1; + + return (ret & 0xf); +} + +// ================================== +void cDxr3SpuBitmap::putFieldData(int field, uint8_t * data, uint8_t * endp) +{ + int xp = bmpsize.x1; + int yp = bmpsize.y1 + field; + uint8_t bitf = 1; + + while (data < endp) + { + uint16_t vlc = getBits(data, bitf); + if (vlc < 0x0004) + { + vlc = (vlc << 4) | getBits(data, bitf); + if (vlc < 0x0010) + { + vlc = (vlc << 4) | getBits(data, bitf); + if (vlc < 0x0040) + { + vlc = (vlc << 4) | getBits(data, bitf); + } + } + } + + uint8_t color = vlc & 0x03; + int len = vlc >> 2; + + // if len == 0 -> end sequence - fill to end of line + len = len ? len : bmpsize.x2 - xp + 1; + putPixel(xp, yp, len, color); + xp += len; + + if (xp > bmpsize.x2) + { + // nextLine + if (!bitf) + data++; + bitf = 1; + xp = bmpsize.x1; + yp += 2; + if (yp > bmpsize.y2) + return; + } + } +} + +// ================================== +cDxr3SpuDecoder::cDxr3SpuDecoder() +{ + clean = true; + scaleMode = eSpuNormal; + spu = NULL; + osd = NULL; + spubmp = NULL; +} + +// ================================== +cDxr3SpuDecoder::~cDxr3SpuDecoder() +{ + delete spubmp; + delete spu; + delete osd; +} + +// ================================== +void cDxr3SpuDecoder::processSPU(uint32_t pts, uint8_t * buf) +{ + setTime(pts); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::processSPU: SPU pushData: pts: " << pts << "\n"; + } + + delete spubmp; + spubmp = NULL; + delete[]spu; + spu = buf; + spupts = pts; + + DCSQ_offset = cmdOffs(); + prev_DCSQ_offset = 0; + + clean = true; +} + +// ================================== +void cDxr3SpuDecoder::setScaleMode(cSpuDecoder::eScaleMode ScaleMode) +{ + scaleMode = ScaleMode; +} + +// ================================== +void cDxr3SpuDecoder::setPalette(uint32_t * pal) +{ + palette.setPalette(pal); +} + +// ================================== +void cDxr3SpuDecoder::setHighlight(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette) +{ + aDxr3SpuPalDescr pld; + for (int i = 0; i < 4; i++) + { + pld[i].index = 0xf & (palette >> (16 + 4 * i)); + pld[i].trans = 0xf & (palette >> (4 * i)); + } + + bool ne = hlpsize.x1 != sx || hlpsize.y1 != sy || + hlpsize.x2 != ex || hlpsize.y2 != ey || + pld[0] != hlpDescr[0] || pld[1] != hlpDescr[1] || + pld[2] != hlpDescr[2] || pld[3] != hlpDescr[3]; + + if (ne) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setHighlight: " << sx << ", " << sy << ", " << ex << ", " << ey << "\n"; + } + + hlpsize.x1 = sx; + hlpsize.y1 = sy; + hlpsize.x2 = ex; + hlpsize.y2 = ey; + memcpy(hlpDescr, pld, sizeof(aDxr3SpuPalDescr)); + highlight = true; + clean = false; + } +} + +// ================================== +void cDxr3SpuDecoder::clearHighlight() +{ + clean &= !highlight; + highlight = false; + hlpsize.x1 = -1; + hlpsize.y1 = -1; + hlpsize.x2 = -1; + hlpsize.y2 = -1; +} + +// ================================== +int cDxr3SpuDecoder::ScaleYcoord(int value) +{ + if (scaleMode == eSpuLetterBox) + { + int offset = cDevice::PrimaryDevice()->GetVideoSystem() == vsPAL ? 72 : 60; + return lround((value * 3.0) / 4.0) + offset; + } + return value; +} + +// ================================== +int cDxr3SpuDecoder::ScaleYres(int value) +{ + if (scaleMode == eSpuLetterBox) + { + return lround((value * 3.0) / 4.0); + } + return value; +} + +// ================================== +void cDxr3SpuDecoder::DrawBmp(sDxr3SpuRect & size, cBitmap * bmp) +{ + int x2 = size.x2; + while ((x2 - size.x1 + 1) & 0x03) + x2++; + tArea Area = { size.x1, size.y1, x2, size.y2, 2 }; + osd->SetAreas(&Area, 1); + if (x2 > size.x2) + osd->DrawRectangle(size.x2 + 1, size.y1, x2, size.y2, clrTransparent); + osd->DrawBitmap(size.x1, size.y1, *bmp); + delete bmp; +} + +// ================================== +void cDxr3SpuDecoder::Draw() +{ + Hide(); + + if (!spubmp) + { + return; + } + + cBitmap *fg = NULL; + cBitmap *bg = NULL; + sDxr3SpuRect bgsize; + sDxr3SpuRect hlsize; + + hlsize.x1 = hlpsize.x1; + hlsize.y1 = ScaleYcoord(hlpsize.y1); + hlsize.x2 = hlpsize.x2; + hlsize.y2 = ScaleYcoord(hlpsize.y2); + + if (highlight) + { + fg = spubmp->getBitmap(hlpDescr, palette, hlsize); + } + + if (spubmp->getMinSize(palDescr, bgsize)) + { + bg = spubmp->getBitmap(palDescr, palette, bgsize); + if (scaleMode == eSpuLetterBox) + { + // the coordinates have to be modified for letterbox + int y1 = ScaleYres(bgsize.y1) + bgsize.height(); + bgsize.y2 = y1 + bgsize.height(); + bgsize.y1 = y1; + } + } + + if (bg || fg) + { + if (osd == NULL) + if ((osd = cOsdProvider::NewOsd(0, 0)) == NULL) + { + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::Draw: New OSD faild!\n"; + } + dsyslog("NewOsd failed\n"); + return; + } + + if (fg) + { + DrawBmp(hlsize, fg); + } + + if (bg) + { + DrawBmp(bgsize, bg); + } + + osd->Flush(); + } + + clean = true; +} + +// ================================== +void cDxr3SpuDecoder::Hide() +{ + delete osd; + osd = NULL; +} + +// ================================== +void cDxr3SpuDecoder::Empty() +{ + Hide(); + + delete spubmp; + spubmp = NULL; + + delete[]spu; + spu = NULL; + + clearHighlight(); + clean = true; +} + +// ================================== +int cDxr3SpuDecoder::setTime(uint32_t pts) +{ + if (!spu) + { + return 0; + } + + if (spu && !clean) + { + Draw(); + } + + while (DCSQ_offset != prev_DCSQ_offset) + { + // Display Control Sequences + int i = DCSQ_offset; + state = spNONE; + + uint32_t exec_time = spupts + spuU32(i) * 1024; + if ((pts != 0) && (exec_time > pts)) + { + return 0; + } + + if (pts != 0) + { + uint16_t feven = 0; + uint16_t fodd = 0; + + i += 2; + + prev_DCSQ_offset = DCSQ_offset; + DCSQ_offset = spuU32(i); + i += 2; + + while (spu[i] != CMD_SPU_EOF) + { + // Command Sequence + switch (spu[i]) + { + case CMD_SPU_SHOW: + // show subpicture + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: show subpicture\n"; + } + state = spSHOW; + i++; + break; + + case CMD_SPU_HIDE: + // hide subpicture + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: hide subpicture\n"; + } + state = spHIDE; + i++; + break; + + case CMD_SPU_SET_PALETTE: + // CLUT + palDescr[0].index = spu[i + 2] & 0xf; + palDescr[1].index = spu[i + 2] >> 4; + palDescr[2].index = spu[i + 1] & 0xf; + palDescr[3].index = spu[i + 1] >> 4; + i += 3; + break; + + case CMD_SPU_SET_ALPHA: + // transparency palette + palDescr[0].trans = spu[i + 2] & 0xf; + palDescr[1].trans = spu[i + 2] >> 4; + palDescr[2].trans = spu[i + 1] & 0xf; + palDescr[3].trans = spu[i + 1] >> 4; + i += 3; + break; + + case CMD_SPU_SET_SIZE: + // image coordinates + size.x1 = (spu[i + 1] << 4) | (spu[i + 2] >> 4); + size.x2 = ((spu[i + 2] & 0x0f) << 8) | spu[i + 3]; + + size.y1 = (spu[i + 4] << 4) | (spu[i + 5] >> 4); + size.y2 = ((spu[i + 5] & 0x0f) << 8) | spu[i + 6]; + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: (" << size.x1 << ", " << size.y1 <<") x (" << size.x2 << ", " << size.y2 <<")\n"; + } + i += 7; + break; + + case CMD_SPU_SET_PXD_OFFSET: + // image 1 / image 2 offsets + fodd = spuU32(i + 1); + feven = spuU32(i + 3); + + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: odd = " << fodd << " even = " << feven << "\n"; + } + i += 5; + break; + + case CMD_SPU_MENU: + if (cDxr3ConfigData::Instance().GetDebug()) + { + cLog::Instance() << "cDxr3SpuDecoder::setTime: spu menu\n"; + } + state = spMENU; + + i++; + break; + + default: + esyslog("invalid sequence in control header (%.2x)\n", spu[i]); + assert(0); + i++; + break; + } + } + if (fodd != 0 && feven != 0) + { + delete spubmp; + spubmp = new cDxr3SpuBitmap(size, spu + fodd, spu + feven, spu + feven, spu + cmdOffs()); + } + } + else if (!clean) + { + state = spSHOW; + } + + if (state == spSHOW || state == spMENU) + { + Draw(); + } + + if (state == spHIDE) + { + Hide(); + } + + if (pts == 0) + { + return 0; + } + } + + return 1; +} diff --git a/dxr3spudecoder.h b/dxr3spudecoder.h new file mode 100644 index 0000000..adaed7f --- /dev/null +++ b/dxr3spudecoder.h @@ -0,0 +1,138 @@ +#ifndef _DXR3SPUDECODER_H_ +#define _DXR3SPUDECODER_H_ + +#include "dxr3vdrincludes.h" +#include <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); + + void setScaleMode(cSpuDecoder::eScaleMode ScaleMode); + void setPalette(uint32_t * pal); + void setHighlight(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t palette); + void clearHighlight(); + void Empty(); + void processSPU(uint32_t pts, uint8_t * buf); + + #if VDRVERSNUM >= 10311 + void Hide(); + void Draw(); + bool IsVisible() { return osd != NULL; } + #endif + +private: + cOsd * osd; + + // processing state + uint8_t *spu; + uint32_t spupts; + bool clean; + bool ready; + + enum spFlag { spNONE, spHIDE, spSHOW, spMENU }; + spFlag state; + + cSpuDecoder::eScaleMode scaleMode; + + // highligh area + bool highlight; + sDxr3SpuRect hlpsize; + aDxr3SpuPalDescr hlpDescr; + + // palette + cDxr3SpuPalette palette; + + // spu info's + sDxr3SpuRect size; + aDxr3SpuPalDescr palDescr; + + uint16_t DCSQ_offset; + uint16_t prev_DCSQ_offset; + + cDxr3SpuBitmap *spubmp; + + int cmdOffs() { return ((spu[2] << 8) | spu[3]); } + int spuSize() { return ((spu[0] << 8) | spu[1]); } + + int ScaleYcoord(int value); + int ScaleYres(int value); + void DrawBmp(sDxr3SpuRect & size, cBitmap * bmp); +}; + +// ================================== +inline uint32_t cDxr3SpuPalette::getColor(uint8_t idx, uint8_t trans) const +{ + uint8_t t = trans == 0x0f ? 0xff : trans << 4; + return palette[idx] | (t << 24); +} + +#endif /*_DXR3SPUDECODER_H_*/ diff --git a/dxr3syncbuffer.c b/dxr3syncbuffer.c new file mode 100644 index 0000000..8ea8ccd --- /dev/null +++ b/dxr3syncbuffer.c @@ -0,0 +1,420 @@ +/* + * dxr3syncbuffer.c + * + * Copyright (C) 2002-2004 Kai Möller + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* + ToDo: + - cDxr3SyncBuffer::Push: XXX This is only a workaround until a sufficient control algorithm is implemented +*/ + +#include <unistd.h> +#include "dxr3syncbuffer.h" +#include "dxr3memcpy.h" + +const int DXR3_MAX_VIDEO_FRAME_LENGTH = 4096; +const int DXR3_MAX_AUDIO_FRAME_LENGTH = 4096; + +// ================================== +cFixedLengthFrame::cFixedLengthFrame(uint32_t length) : +m_count(0), m_length(length), m_pts(0), m_type(ftUnknown) { + + m_pData = new uint8_t[length]; + if (!m_pData) + { + cLog::Instance() << "Failed to allocate memory in cFixedLengthFrame (m_pData) - will stop now"; + exit(1); + } + + m_audioChannelCount = UNKNOWN_CHANNEL_COUNT; + m_audioDataRate = UNKNOWN_DATA_RATE; + m_videoAspectRatio = UNKNOWN_ASPECT_RATIO; +} + +// ================================== +cFixedLengthFrame::~cFixedLengthFrame() +{ + if (m_pData) + { + delete[] m_pData; + } +} + +// ================================== +void cFixedLengthFrame::CopyFrame(const uint8_t* pStart, int length, uint32_t pts, eFrameType type) +{ + if (length > m_length) + { + delete[] m_pData; + m_pData = new uint8_t[length]; + m_length = length; + } + m_type = type; + m_count = length; + m_pts = pts; + dxr3_memcpy((void*) m_pData,(void*) pStart, length); +} + +// ================================== +uint8_t* cFixedLengthFrame::GetData(void) +{ + return m_pData; +} + +// ================================== +int cFixedLengthFrame::GetCount(void) +{ + return m_count; +} + +// ================================== +uint32_t cFixedLengthFrame::GetPts(void) +{ + return m_pts; +} + +// ================================== +void cFixedLengthFrame::SetPts(uint32_t pts) +{ + m_pts = pts; +} + +// ================================== +uint32_t cFixedLengthFrame::m_staticAudioChannelCount = 0; +uint32_t cFixedLengthFrame::m_staticAudioDataRate = 0; + + + + +// ================================== +cDxr3SyncBuffer::cDxr3SyncBuffer(int frameCount, int frameLength, cDxr3Interface& dxr3Device) : cRingBuffer(frameCount, true), m_dxr3Device(dxr3Device) +{ + m_pBuffer = new cFixedLengthFrame[frameCount](frameLength); + + if (!m_pBuffer) + { + cLog::Instance() << "Failed to allocate memory in cDxr3SyncBuffer (m_pBuffer) - will stop now"; + exit(1); + } + + m_count = 0; + m_nextFree = 0; + m_next = 0; + m_bWaitPts = false; + m_waitPts = 0; + m_waitDelta = 0; + m_lastPts = 0; + m_bPutBlock = false; + m_bGetBlock = false; + m_bStartReceiver = false; + m_bStopped = false; + m_demuxMode = DXR3_DEMUX_TV_MODE; + m_bPollSync = false; + SetTimeouts(1000, 10); +} + +// ================================== +cDxr3SyncBuffer::~cDxr3SyncBuffer() +{ + if (m_pBuffer) + { + delete[] m_pBuffer; + } +} + +// ================================== +int cDxr3SyncBuffer::Available(void) +{ + int ret = 0; + Lock(); + ret = m_count; + Unlock(); + return ret; +} + +// ================================== +const int BUFFER_LIMIT = 5; +const int BUFFER_LIMIT_2 = 10; + +// ================================== +bool cDxr3SyncBuffer::Poll(int TimeoutMs) +{ + bool retVal = true; + uint32_t currTime = m_dxr3Device.GetSysClock(); + m_bPollSync = true; + if (m_demuxMode == DXR3_DEMUX_REPLAY_MODE) + { + if (Available() >= Size() - (Size()*BUFFER_LIMIT/100)) + { + m_bPollSync = true; + while ((Available() >= Size() - (Size()*BUFFER_LIMIT_2)/100) && ((m_dxr3Device.GetSysClock() - currTime) < ((uint32_t)TimeoutMs * (uint32_t)45))) + { + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + } + if (Available() >= Size() - (Size()*BUFFER_LIMIT_2)/100) + { + retVal = false; + } + } + } + + return retVal; +} + +// ================================== +cFixedLengthFrame* cDxr3SyncBuffer::Push(const uint8_t* pStart, int length, uint32_t pts, eFrameType type) throw (eSyncBufferException) +{ + int lastIndex = 0; + + switch (m_demuxMode) + { + case DXR3_DEMUX_TRICK_MODE: + break; + + case DXR3_DEMUX_TV_MODE: + case DXR3_DEMUX_REPLAY_MODE: + default: + + while ((Available() >= Size() - (Size()*10)/100)) + { + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + } + + Lock(); + if (pts == m_lastPts) + { + pts = 0; + } + else + { + m_lastPts = pts; + } + lastIndex = m_nextFree; + m_pBuffer[m_nextFree].CopyFrame(pStart, length, pts, type); + m_pBuffer[m_nextFree].SetChannelCount(UNKNOWN_CHANNEL_COUNT); + m_pBuffer[m_nextFree].SetDataRate(UNKNOWN_DATA_RATE); + m_pBuffer[m_nextFree].SetAspectRatio(UNKNOWN_ASPECT_RATIO); + m_nextFree++; + m_count++; + m_nextFree %= Size(); + + if (m_nextFree == m_next) + { + cLog::Instance() << "Buffer overrun\n"; +// cLog::Instance() << "cDxr3SyncBuffer::Push m_demuxMode: " << (int)m_demuxMode << endl; +// cLog::Instance() << "cDxr3SyncBuffer::Push Available(): " << Available() << endl; +// cLog::Instance() << "cDxr3SyncBuffer::Push Size(): " << Size() << endl; + + Clear(); // XXX This is only a workaround until a sufficient control algorithm is implemented + throw(SYNC_BUFFER_OVERRUN); + } + if (!m_bWaitPts) + { + if (m_bStartReceiver) + { + EnableGet(); + } + } + else + { + if (m_waitPts < m_dxr3Device.GetSysClock() || + m_waitPts - m_dxr3Device.GetSysClock() < m_waitDelta) + { + EnableGet(); + m_bWaitPts = false; + } + } + Unlock(); + break; + } + + return &m_pBuffer[lastIndex]; +} + +// ================================== +void cDxr3SyncBuffer::Pop(void) +{ + Lock(); + if (m_count) + { + uint32_t nextPts = 0; + uint32_t tmpBuffer = m_next; + for (int i = 0; i < m_count && nextPts == 0; ++i) + { + if (tmpBuffer) tmpBuffer = --tmpBuffer ? tmpBuffer : (Size() - 1); + nextPts = m_pBuffer[tmpBuffer].GetPts(); + } + if (nextPts != 30) + { + cDxr3NextPts::Instance().SetNextPts(nextPts); + } + + m_next++; + m_count--; + m_next %= Size(); + if (m_next == m_nextFree) + { + m_next = m_nextFree = m_count = 0; + } + } + EnablePut(); + Unlock(); +} + +// ================================== +cFixedLengthFrame* cDxr3SyncBuffer::Get(void) +{ + cFixedLengthFrame* pRet = 0; + + if (!m_bStopped) + { + while (!Available() || !m_bStartReceiver) + { + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + + Lock(); + if (m_nextFree != m_next) + { + pRet = &m_pBuffer[m_next]; + } + Unlock(); + } + else + { + WaitForGet(); + } + + return pRet; +} + +// ================================== +void cDxr3SyncBuffer::Clear(void) +{ + Lock(); + m_next = 0; + m_nextFree = 0; + m_count = 0; + m_lastPts = 0; + m_bWaitPts = false; + m_bStartReceiver = false; + m_bPollSync = false; + if (m_bPutBlock) + { + EnablePut(); + m_bPutBlock = false; + } + cFixedLengthFrame::Clear(); + cDxr3NextPts::Instance().Clear(); + Unlock(); +} + +// ================================== +void cDxr3SyncBuffer::WaitForSysClock(uint32_t pts, uint32_t delta) +{ + m_waitPts = pts; + m_waitDelta = delta; + if (!m_bPutBlock) + { + Lock(); + m_bWaitPts = true; + Unlock(); + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + else + { + usleep(1); //* (pts - pSysClock->GetSysClock())); + } +} + +// ================================== +void cDxr3SyncBuffer::WaitForNextPut(void) +{ + if (!m_bPutBlock) + { + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + else + { + usleep(1); + } +} + +// ================================== +void cDxr3SyncBuffer::Start(void) +{ + m_bStartReceiver = true; + m_bStopped = false; + if (Available()) + { + EnableGet(); + } +} + +// ================================== +void cDxr3SyncBuffer::WakeUp(void) +{ + Lock(); + if (m_bStartReceiver == true) + { + if (!m_bWaitPts) + { + EnableGet(); + } + else + { + if (m_waitPts < m_dxr3Device.GetSysClock() || + m_waitPts - m_dxr3Device.GetSysClock() < m_waitDelta) + { + EnableGet(); + m_bWaitPts = false; + } + } + } + Unlock(); +} + +// ================================== +void cDxr3SyncBuffer::WaitForReceiverStopped(void) +{ + if (!m_bGetBlock) + { + receiverStoppedMutex.Lock(); + receiverStopped.Wait(receiverStoppedMutex); + receiverStoppedMutex.Unlock(); + } +} + +// ================================== +void cDxr3SyncBuffer::ReceiverStopped(void) +{ + receiverStopped.Broadcast(); +} diff --git a/dxr3syncbuffer.h b/dxr3syncbuffer.h new file mode 100644 index 0000000..1598b62 --- /dev/null +++ b/dxr3syncbuffer.h @@ -0,0 +1,123 @@ +/* + * dxr3syncbuffer.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef _DXR3SYNCBUFFER_H_ +#define _DXR3SYNCBUFFER_H_ + +#include <stdint.h> + +#include "dxr3vdrincludes.h" +#include "dxr3interface.h" +#include "dxr3generaldefines.h" +#include "dxr3nextpts.h" +#include "dxr3log.h" + +// ================================== +const uint32_t UNKNOWN_CHANNEL_COUNT = 0xFFFFFFFF; +const uint32_t UNKNOWN_DATA_RATE = 0xFFFFFFFF; +const uint32_t UNKNOWN_ASPECT_RATIO = 0xFFFFFFFF; + +// ================================== +class cFixedLengthFrame +{ +public: + explicit cFixedLengthFrame(uint32_t length); + ~cFixedLengthFrame(); + + void CopyFrame(const uint8_t* pStart, int length, uint32_t pts, eFrameType type); + uint8_t* GetData(void); + int GetCount(void); + uint32_t GetPts(void); + void SetPts(uint32_t pts); + void SetChannelCount(uint32_t channelCount) {if (channelCount != UNKNOWN_CHANNEL_COUNT) m_staticAudioChannelCount = m_audioChannelCount = channelCount; else m_audioChannelCount = m_staticAudioChannelCount; }; + void SetDataRate(uint32_t dataRate) {if (m_audioDataRate != UNKNOWN_DATA_RATE) m_staticAudioDataRate = m_audioDataRate = dataRate; else m_audioDataRate = m_staticAudioDataRate;}; + void SetAspectRatio(uint32_t aspectRatio) {m_videoAspectRatio = aspectRatio;}; + uint32_t GetChannelCount(void) {return ((m_audioChannelCount == m_staticAudioChannelCount || !m_staticAudioChannelCount)? m_audioChannelCount : m_staticAudioChannelCount) ;}; + uint32_t GetDataRate(void) {return ((m_audioDataRate == m_staticAudioDataRate || !m_staticAudioDataRate) ? m_audioDataRate : m_staticAudioDataRate);}; + uint32_t GetAspectRatio(void) {return m_videoAspectRatio;}; + eFrameType GetFrameType(void) {return m_type;} + + static void Clear(void) {m_staticAudioDataRate = 0; m_staticAudioChannelCount = 0;}; + +protected: + uint8_t* m_pData; + int m_count; + int m_length; + uint32_t m_pts; + eFrameType m_type; + + uint32_t m_audioChannelCount; + uint32_t m_audioDataRate; + uint32_t m_videoAspectRatio; + + static uint32_t m_staticAudioChannelCount; + static uint32_t m_staticAudioDataRate; + +private: + cFixedLengthFrame(); // you are not allowed to use this constructor + cFixedLengthFrame(cFixedLengthFrame&); // no copy constructor + +}; + +// ================================== +class cDxr3SyncBuffer : public cRingBuffer +{ +public: + enum eSyncBufferException + { + SYNC_BUFFER_OVERRUN + }; +public: + cDxr3SyncBuffer(int frameCount, int frameLength, cDxr3Interface& dxr3Device); + ~cDxr3SyncBuffer(); + + virtual int Available(void); + cFixedLengthFrame* Push(const uint8_t* pStart, int length, uint32_t pts, eFrameType type = ftUnknown) throw (eSyncBufferException); + void Pop(void); + cFixedLengthFrame* Get(void); + void Clear(void); + void Stop(void) { m_bStopped = true;}; + void Start(void); + void WaitForSysClock(uint32_t pts, uint32_t delta); + void WaitForNextPut(void); + void WakeUp(void); + void WaitForReceiverStopped(void); + void SetDemuxMode(eDxr3DemuxMode demuxMode) {m_demuxMode = demuxMode;}; + eDxr3DemuxMode GetDemuxMode(void) {return m_demuxMode;}; + bool Poll(int TimeoutMs); + bool IsPolled(void) { return m_bPollSync;}; + uint32_t GetFillLevel(void) { return Available() * 100 / Size();}; + +protected: + void ReceiverStopped(void); + + cFixedLengthFrame* m_pBuffer; + int m_count; + int m_nextFree; + int m_next; + bool m_bWaitPts; + bool m_bPutBlock; + bool m_bGetBlock; + bool m_bStartReceiver; + bool m_bStopped; + uint32_t m_waitPts; + uint32_t m_waitDelta; + uint32_t m_lastPts; + eDxr3DemuxMode m_demuxMode; + + cCondVar receiverStopped; + cMutex receiverStoppedMutex; + cDxr3Interface& m_dxr3Device; + bool m_bPollSync; + +private: + cDxr3SyncBuffer(); // you are not allowed to use this constructor + cDxr3SyncBuffer(cDxr3SyncBuffer&); // no constructor +}; + +#endif /*_DXR3SYNCBUFFER_H_*/ diff --git a/dxr3sysclock.c b/dxr3sysclock.c new file mode 100644 index 0000000..9d7d050 --- /dev/null +++ b/dxr3sysclock.c @@ -0,0 +1,49 @@ +#include <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(); +} diff --git a/dxr3sysclock.h b/dxr3sysclock.h new file mode 100644 index 0000000..50c5540 --- /dev/null +++ b/dxr3sysclock.h @@ -0,0 +1,36 @@ +#ifndef _DXR3_SYSCLOCK_H_ +#define _DXR3_SYSCLOCK_H_ + +//#include <stdint.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_*/ diff --git a/dxr3tools.h b/dxr3tools.h new file mode 100644 index 0000000..ee8f9e3 --- /dev/null +++ b/dxr3tools.h @@ -0,0 +1,82 @@ +#ifndef _DXR3TOOLS_H_ +#define _DXR3TOOLS_H_ + +#include "dxr3vdrincludes.h" + +namespace Tools +{ + // ================================== + inline unsigned int Rgb2YCrCb(unsigned long rgb) + { + float Y,U,V; + float R,G,B; + unsigned int yuv = 0x0; + + B = ((rgb >> 16) & 0xFF); + G = ((rgb >> 8) & 0xFF); + R = (rgb & 0xFF); + + Y = (0.2578125 * R) + (0.50390625 * G) + (0.09765625 * B) + 16; + U = (0.4375 * R) - (0.3671875 * G) - (0.0703125 * B) + 128; + V =-(0.1484375 * R) - (0.2890625 * G) + (0.4375 * B) + 128; + + yuv = (int(Y) << 16) | (int(U) << 8) | int(V); + + return yuv; + } + + // ================================== + inline unsigned int YUV2Rgb(unsigned int yuv_color) + { + int Y, Cb, Cr; + int Ey, Epb, Epr; + int Eg, Eb, Er; + + Y = (yuv_color >> 16) & 0xff; + Cb = (yuv_color) & 0xff; + Cr = (yuv_color >> 8) & 0xff; + + Ey = (Y - 16); + Epb = (Cb - 128); + Epr = (Cr - 128); + /* ITU-R 709 + Eg = (298*Ey - 55*Epb - 137*Epr)/256; + Eb = (298*Ey + 543*Epb)/256; + Er = (298*Ey + 460*Epr)/256; + */ + /* FCC ~= mediaLib */ + Eg = (298 * Ey - 100 * Epb - 208 * Epr) / 256; + Eb = (298 * Ey + 516 * Epb) / 256; + Er = (298 * Ey + 408 * Epr) / 256; + + if (Eg > 255) + Eg = 255; + if (Eg < 0) + Eg = 0; + + if (Eb > 255) + Eb = 255; + if (Eb < 0) + Eb = 0; + + if (Er > 255) + Er = 255; + if (Er < 0) + Er = 0; + + return Eb | (Eg << 8) | (Er << 16); + } + + // ================================== + inline void WriteInfoToOsd(string x) + { + #if VDRVERSNUM <= 10306 + Interface->Info(x.c_str()); + #else + Skins.Message(mtInfo, x.c_str()); + #endif + } + +} + +#endif /*_DXR3TOOLS_H_*/ diff --git a/dxr3unixserversocket.c b/dxr3unixserversocket.c new file mode 100644 index 0000000..49816fa --- /dev/null +++ b/dxr3unixserversocket.c @@ -0,0 +1,190 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> + + +#include <iostream> +#include <cstring> +#include <string> + +#include "dxr3unixserversocket.h" +#include "dxr3interface.h" +#include "dxr3log.h" + +using namespace std; + +#ifndef SOCKET_CHMOD +#define SOCKET_CHMOD 0660 +#endif + +// ================================== +cDxr3UnixServerSocket::cDxr3UnixServerSocket(const char* pFileName, int backlog) +{ + m_bConnected = false; + m_backlog = backlog; + m_addr.sun_family = AF_UNIX; + m_msgSize = 0; + + m_pFileName = pFileName; + strcpy(m_addr.sun_path, pFileName); + unlink(pFileName); + + + m_fdServerSocket = socket(PF_UNIX, SOCK_STREAM, 0); + if (m_fdServerSocket > -1) + { + if (bind(m_fdServerSocket, (sockaddr*)&m_addr, (socklen_t)sizeof(m_addr))) { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: binding socket failed\n"; + } + + if (listen(m_fdServerSocket, m_backlog)) + { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: Listen failed\n"; + } + + if (chmod(m_pFileName, SOCKET_CHMOD)) + { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: Chmod failed\n"; + } + } + else + { + cLog::Instance() << "cDxr3UnixServerSocket::cDxr3UnixServerSocket Error: Unable to create socket\n"; + } +} + +// ================================== +bool cDxr3UnixServerSocket::WaitForConnection() +{ + cLog::Instance() << "cDxr3UnixServerSocket::WaitForConnection Waiting ...\n"; + if (m_fdServerSocket > -1) + { + m_fdConnectionSocket = accept(m_fdServerSocket, 0, 0); + if (m_fdConnectionSocket > -1) + { + m_bConnected = true; + cLog::Instance() << "cDxr3UnixServerSocket::WaitForConnection Connected\n"; + } + else + { + m_bConnected = false; + cLog::Instance() << "cDxr3UnixServerSocket::WaitForConnection failed\n"; + } + } + else + { + m_bConnected = false; + } + return m_bConnected; +} + +// ================================== +bool cDxr3UnixServerSocket::GetNextMessage() +{ + bool ret = false; + m_msgSize = 0; + memset(m_msg, 0, MAX_REC_SIZE); + + if (m_bConnected) + { + m_msgSize = read(m_fdConnectionSocket, m_msg, MAX_REC_SIZE - 1); + if (m_msgSize <= 0) + { + m_msgSize = 0; + m_bConnected = 0; + close(m_fdConnectionSocket); + cLog::Instance() << "cDxr3UnixServerSocket::GetNextMessage failed/connection closed\n"; + } + else + { + ret = true; + } + } + + if (ret) ProcessMessage(); + + return ret; +} + +// ================================== +bool cDxr3UnixServerSocket::IsConnected() +{ + return m_bConnected; +} + +// ================================== +cDxr3UnixServerSocket::~cDxr3UnixServerSocket() +{ + close(m_fdConnectionSocket); + close(m_fdServerSocket); + unlink(m_pFileName); +} + +// ================================== +void cDxr3StartStopSocket::SendStatus() +{ + if (cDxr3Interface::Instance().IsExternalReleased()) + { + string res("CloseDxr3DeviceRsp\n"); + write(m_fdConnectionSocket, res.c_str(), res.size()); + } + else + { + string res("OpenDxr3DeviceRsp\n"); + write(m_fdConnectionSocket, res.c_str(), res.size()); + } +} + +// ================================== +void cDxr3StartStopSocket::ProcessMessage(void) +{ + cLog::Instance() << "cDxr3StartStopSocket::ProcessMessage Rec: " << (const char*) m_msg << "\n"; + + if (string((const char*)m_msg) == string("OpenDxr3DeviceCmd")) + { + cDxr3Interface::Instance().ExternalReopenDevices(); + SendStatus(); + } + else if (string((const char*)m_msg) == string("CloseDxr3DeviceCmd")) + { + cDxr3Interface::Instance().ExternalReleaseDevices(); + SendStatus(); + } + else if (string((const char*)m_msg) == string("StatusDxr3DeviceCmd")) + { + SendStatus(); + } + else if (string((const char *)m_msg) == string("SaveDxr3DeviceCmd")) + { + m_bSavedState = cDxr3Interface::Instance().IsExternalReleased(); + SendStatus(); + } + else if (string((const char *)m_msg) == string("RestoreDxr3DeviceCmd")) + { + if (m_bSavedState) + { + cDxr3Interface::Instance().ExternalReleaseDevices(); + } + else + { + cDxr3Interface::Instance().ExternalReopenDevices(); + } + SendStatus(); + } + else + { + string res("Error\n"); + write(m_fdConnectionSocket, res.c_str(), res.size()); + } +} + +// ================================== +void cDxr3StartStopThread::Action() +{ + cDxr3StartStopSocket mySocket; + while (mySocket.WaitForConnection()) + { + while (mySocket.GetNextMessage()); + } +} diff --git a/dxr3unixserversocket.h b/dxr3unixserversocket.h new file mode 100644 index 0000000..3233995 --- /dev/null +++ b/dxr3unixserversocket.h @@ -0,0 +1,71 @@ +/* + * dxr3unixserversocket.h: + * + * See the main source file 'dxr3.c' for copyright information and + * how to reach the author. + * + */ + +#ifndef __DXR3_UNIX_SERVER_SOCKET_H +#define __DXR3_UNIX_SERVER_SOCKET_H + +#include <stdint.h> +#include <sys/socket.h> +#include <sys/un.h> + + +#include "dxr3vdrincludes.h" + +class cDxr3UnixServerSocket { +public: + cDxr3UnixServerSocket(const char* pFileName = "/tmp/.dxr3-ux-sock", int backlog = 5); + virtual ~cDxr3UnixServerSocket(); + + bool WaitForConnection(void); + bool GetNextMessage(void); + bool IsConnected(void); +protected: + virtual void ProcessMessage(void) = 0; + + const char* m_pFileName; + bool m_bConnected; + int m_backlog; + int m_fdServerSocket; + int m_fdConnectionSocket; + sockaddr_un m_addr; + enum eDxr3socketMessageSize { MAX_REC_SIZE = 100 }; + uint8_t m_msg[MAX_REC_SIZE]; + uint8_t m_msgSize; + +private: + cDxr3UnixServerSocket(cDxr3UnixServerSocket&); // no copy constructor +}; + + +class cDxr3StartStopSocket : public cDxr3UnixServerSocket { +public: + cDxr3StartStopSocket() : m_bSavedState(false) {}; + virtual ~cDxr3StartStopSocket() {}; +protected: + void ProcessMessage(void); + void SendStatus(void); + + bool m_bSavedState; + +private: + cDxr3StartStopSocket(cDxr3StartStopSocket&); // no copy constructor +}; + + +class cDxr3StartStopThread : public cThread { +public: + cDxr3StartStopThread() {}; + virtual ~cDxr3StartStopThread() {}; +protected: + virtual void Action(void); + +private: + cDxr3StartStopThread(cDxr3StartStopThread&); // no copy constructor +}; + +#endif // __DXR3_UNIX_SERVER_SOCKET_H diff --git a/dxr3vdrincludes.h b/dxr3vdrincludes.h new file mode 100644 index 0000000..896718e --- /dev/null +++ b/dxr3vdrincludes.h @@ -0,0 +1,33 @@ +#ifndef _DXR3_VDRINCLUDES_H_ +#define _DXR3_VDRINCLUDES_H_ + +#include <string> +#include <algorithm> +#include <vector> +using namespace std; + +#ifndef __STL_CONFIG_H +#define __STL_CONFIG_H +#define __DXR3_UNDEF_STL_CONFIG_AFTERWARDS +#endif + +// all includes from vdr +#if VDRVERSNUM >= 10307 + #include <vdr/osd.h> +#else + #include <vdr/osdbase.h> +#endif +#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> + +#ifdef __DXR3_UNDEF_STL_CONFIG_AFTERWARDS +#undef __STL_CONFIG_H +#endif + +#endif /*_DXR3_VDRINCLUDES_H_*/ |