From 31e8f79474f5d06d6f185543d490e63fff9f87ac Mon Sep 17 00:00:00 2001 From: dborth Date: Wed, 12 Aug 2009 06:06:50 +0000 Subject: [PATCH] add missing files --- smpeg/src/audio/AUTHORS | 4 + smpeg/src/audio/COPYING.LIB | 481 ++++ smpeg/src/audio/MPEGaudio.cpp | 354 +++ smpeg/src/audio/README | 4 + smpeg/src/audio/README.LIB | 60 + smpeg/src/audio/bitwindow.cpp | 64 + smpeg/src/audio/filter.cpp | 338 +++ smpeg/src/audio/filter_2.cpp | 354 +++ smpeg/src/audio/hufftable.cpp | 587 ++++ smpeg/src/audio/mpeglayer1.cpp | 111 + smpeg/src/audio/mpeglayer2.cpp | 766 ++++++ smpeg/src/audio/mpeglayer3.cpp | 1900 +++++++++++++ smpeg/src/audio/mpegtable.cpp | 194 ++ smpeg/src/audio/mpegtoraw.cpp | 516 ++++ smpeg/src/video/COPYRIGHT | 20 + smpeg/src/video/MPEGvideo.cpp | 609 +++++ smpeg/src/video/README | 4 + smpeg/src/video/decoders.cpp | 1004 +++++++ smpeg/src/video/decoders.h | 637 +++++ smpeg/src/video/dither.h | 53 + smpeg/src/video/floatdct.cpp | 121 + smpeg/src/video/gdith.cpp | 424 +++ smpeg/src/video/jrevdct.cpp | 1617 +++++++++++ smpeg/src/video/mmxflags_asm.S | 55 + smpeg/src/video/mmxidct_asm.S | 697 +++++ smpeg/src/video/motionvec.cpp | 234 ++ smpeg/src/video/parseblock.cpp | 693 +++++ smpeg/src/video/proto.h | 215 ++ smpeg/src/video/readfile.cpp | 184 ++ smpeg/src/video/util.cpp | 499 ++++ smpeg/src/video/util.h | 395 +++ smpeg/src/video/vhar128.cpp | 272 ++ smpeg/src/video/vhar128.h | 30 + smpeg/src/video/video.cpp | 4682 ++++++++++++++++++++++++++++++++ smpeg/src/video/video.h | 460 ++++ 35 files changed, 18638 insertions(+) create mode 100644 smpeg/src/audio/AUTHORS create mode 100644 smpeg/src/audio/COPYING.LIB create mode 100644 smpeg/src/audio/MPEGaudio.cpp create mode 100644 smpeg/src/audio/README create mode 100644 smpeg/src/audio/README.LIB create mode 100644 smpeg/src/audio/bitwindow.cpp create mode 100644 smpeg/src/audio/filter.cpp create mode 100644 smpeg/src/audio/filter_2.cpp create mode 100644 smpeg/src/audio/hufftable.cpp create mode 100644 smpeg/src/audio/mpeglayer1.cpp create mode 100644 smpeg/src/audio/mpeglayer2.cpp create mode 100644 smpeg/src/audio/mpeglayer3.cpp create mode 100644 smpeg/src/audio/mpegtable.cpp create mode 100644 smpeg/src/audio/mpegtoraw.cpp create mode 100644 smpeg/src/video/COPYRIGHT create mode 100644 smpeg/src/video/MPEGvideo.cpp create mode 100644 smpeg/src/video/README create mode 100644 smpeg/src/video/decoders.cpp create mode 100644 smpeg/src/video/decoders.h create mode 100644 smpeg/src/video/dither.h create mode 100644 smpeg/src/video/floatdct.cpp create mode 100644 smpeg/src/video/gdith.cpp create mode 100644 smpeg/src/video/jrevdct.cpp create mode 100644 smpeg/src/video/mmxflags_asm.S create mode 100644 smpeg/src/video/mmxidct_asm.S create mode 100644 smpeg/src/video/motionvec.cpp create mode 100644 smpeg/src/video/parseblock.cpp create mode 100644 smpeg/src/video/proto.h create mode 100644 smpeg/src/video/readfile.cpp create mode 100644 smpeg/src/video/util.cpp create mode 100644 smpeg/src/video/util.h create mode 100644 smpeg/src/video/vhar128.cpp create mode 100644 smpeg/src/video/vhar128.h create mode 100644 smpeg/src/video/video.cpp create mode 100644 smpeg/src/video/video.h diff --git a/smpeg/src/audio/AUTHORS b/smpeg/src/audio/AUTHORS new file mode 100644 index 0000000..3a9a1e4 --- /dev/null +++ b/smpeg/src/audio/AUTHORS @@ -0,0 +1,4 @@ + +jwj95@eve.kaist.ac.kr +jwj95@nownuri.net Woo-jae Jung + diff --git a/smpeg/src/audio/COPYING.LIB b/smpeg/src/audio/COPYING.LIB new file mode 100644 index 0000000..e17b0a8 --- /dev/null +++ b/smpeg/src/audio/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/smpeg/src/audio/MPEGaudio.cpp b/smpeg/src/audio/MPEGaudio.cpp new file mode 100644 index 0000000..65a8777 --- /dev/null +++ b/smpeg/src/audio/MPEGaudio.cpp @@ -0,0 +1,354 @@ +/* + SMPEG - SDL MPEG Player Library + Copyright (C) 1999 Loki Entertainment Software + + - Modified by Michel Darricau from eProcess for popcorn - + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* A class based on the MPEG stream class, used to parse and play audio */ + +//using namespace std; + +#include "MPEGaudio.h" +#include "MPEGstream.h" + +MPEGaudio:: MPEGaudio(MPEGstream *stream, bool initSDL) : sdl_audio(initSDL) +{ + /* Initialize MPEG audio */ + mpeg = stream; + initialize(); + + /* Just be paranoid. If all goes well, this will be set to true */ + valid_stream = false; + + /* Analyze the MPEG audio stream */ + if ( loadheader() ) { + SDL_AudioSpec wanted; + WantedSpec(&wanted); + + /* Calculate the samples per frame */ + samplesperframe = 32*wanted.channels; + if( layer == 3 ) { + samplesperframe *= 18; + if ( version == 0 ) { + samplesperframe *= 2; + } + } else { + samplesperframe *= SCALEBLOCK; + if ( layer == 2 ) { + samplesperframe *= 3; + } + } + if ( sdl_audio ) { + /* Open the audio, get actual audio hardware format and convert */ + bool audio_active; + SDL_AudioSpec actual; + audio_active = (SDL_OpenAudio(&wanted, &actual) == 0); + if ( audio_active ) { + ActualSpec(&actual); + valid_stream = true; + } else { + SetError(SDL_GetError()); + } + SDL_PauseAudio(0); + } else { /* The stream is always valid if we don't initialize SDL */ + valid_stream = true; + } + Volume(100); + } + + /* For using system timestamp */ + for (int i=0; ifreq = frequencies[version][frequency]; +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + wanted->format = AUDIO_S16LSB; +#else + wanted->format = AUDIO_S16MSB; +#endif + if ( outputstereo ) { + wanted->channels = 2; + } else { + wanted->channels = 1; + } + wanted->samples = 4096; + wanted->callback = Play_MPEGaudioSDL; + wanted->userdata = this; + return true; +} + +void +MPEGaudio:: ActualSpec(const SDL_AudioSpec *actual) +{ + /* Splay can optimize some of the conversion */ + if ( actual->channels == 1 && outputstereo ) { + forcetomonoflag = true; + } + if ( actual->channels == 2 && !outputstereo ) { + forcetostereoflag = true; + samplesperframe *= 2; + } + /* FIXME: Create an audio conversion block */ + if ( (actual->freq/100) == ((frequencies[version][frequency]/2)/100) ) { + downfrequency = 1; + } else if ( actual->freq != frequencies[version][frequency] ) { +#ifdef VERBOSE_WARNINGS + fprintf(stderr, "Warning: wrong audio frequency (wanted %d, got %d)\n", + frequencies[version][frequency], actual->freq); +#else + ; +#endif + } + if ( actual->format != AUDIO_S16SYS ) + { + if ( (actual->format^0x1000) == AUDIO_S16SYS ) { + swapendianflag = true; + } else { + fprintf(stderr, "Warning: incorrect audio format\n"); + } + } + rate_in_s=((double)((actual->format&0xFF)/8)*actual->channels*actual->freq); + stereo=((actual->channels-1) > 0); +} + +#ifdef THREADED_AUDIO +void +MPEGaudio:: StartDecoding(void) +{ + decoding = true; + /* Create the ring buffer to hold audio */ + if ( ! ring ) { + ring = new MPEG_ring(samplesperframe*2); + } + if ( ! decode_thread ) { + decode_thread = SDL_CreateThread(Decode_MPEGaudio, this); + } +} +void +MPEGaudio:: StopDecoding(void) +{ + decoding = false; + if ( decode_thread ) { + force_exit = true; + if( ring ) ring->ReleaseThreads(); + SDL_WaitThread(decode_thread, NULL); + decode_thread = NULL; + } + if ( ring ) { + delete ring; + ring = NULL; + } +} +#endif + +/* MPEG actions */ +double +MPEGaudio:: Time(void) +{ + double now; + + if ( frag_time ) { + now = (play_time + (double)(SDL_GetTicks() - frag_time)/1000.0); + } else { + now = play_time; + } + return now; +} +void +MPEGaudio:: Play(void) +{ + ResetPause(); + if ( valid_stream ) { +#ifdef THREADED_AUDIO + StartDecoding(); +#endif + playing = true; + } +} +void +MPEGaudio:: Stop(void) +{ + if ( valid_stream ) { + if ( sdl_audio ) + SDL_LockAudio(); + + playing = false; + + if ( sdl_audio ) + SDL_UnlockAudio(); + } + ResetPause(); +} +void +MPEGaudio:: Rewind(void) +{ + Stop(); + +#ifdef THREADED_AUDIO + /* Stop the decode thread */ + StopDecoding(); +#endif + + clearrawdata(); + decodedframe = 0; + currentframe = 0; + frags_playing = 0; +} +void +MPEGaudio:: ResetSynchro(double time) +{ + play_time = time; + frag_time = 0; + + /* Reinit the timestamp FIFO */ + for (int i=0; i 0) + { + seconds -= (float) samplesperframe / ((float) frequencies[version][frequency]*(1+inputstereo)); + if(!loadheader()) break; + } + } +void +MPEGaudio:: Volume(int vol) +{ + if ( (vol >= 0) && (vol <= 100) ) { + volume = (vol*SDL_MIX_MAXVOLUME)/100; + } +} + /* Michel Darricau from eProcess conflict name in popcorn */ +MPEGstatus +MPEGaudio:: GetStatus(void) +{ + if ( valid_stream ) { + /* Has decoding stopped because of end of stream? */ + if ( mpeg->eof() && (decodedframe <= currentframe) ) { + return(MPEG_STOPPED); + } + /* Have we been told to play? */ + if ( playing ) { + return(MPEG_PLAYING); + } else { + return(MPEG_STOPPED); + } + } else { + return(MPEG_ERROR); + } +} + +bool +MPEGaudio:: GetAudioInfo(MPEG_AudioInfo *info) +{ + if ( info ) { + info->mpegversion = version; + info->mode = mode; + info->frequency = frequencies[version][frequency]; + info->layer = layer; + info->bitrate = bitrate[version][layer-1][bitrateindex]; + info->current_frame = currentframe; + } + return true; +} +bool +MPEGaudio:: fillbuffer(int size) + { + bitindex=0; + _buffer_pos = mpeg->pos; + return(mpeg->copy_data(_buffer, size) > 0); + }; + +void +MPEGaudio:: sync(void) +{ + bitindex=(bitindex+7)&0xFFFFFFF8; +} + +bool +MPEGaudio:: issync(void) +{ + return (bitindex&7) != 0; +} + +int +MPEGaudio::getbyte(void) +{ + int r=(unsigned char)_buffer[bitindex>>3]; + + bitindex+=8; + return r; +} + +int +MPEGaudio::getbit(void) +{ + register int r=(_buffer[bitindex>>3]>>(7-(bitindex&7)))&1; + + bitindex++; + return r; +} + +int +MPEGaudio::getbits8(void) +{ + register unsigned short a; + { int offset=bitindex>>3; + + a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]); + } + a<<=(bitindex&7); + bitindex+=8; + return (int)((unsigned int)(a>>8)); +} + +int +MPEGaudio::getbits9(int bits) +{ + register unsigned short a; + { int offset=bitindex>>3; + + a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]); + } + a<<=(bitindex&7); + bitindex+=bits; + return (int)((unsigned int)(a>>(16-bits))); +} diff --git a/smpeg/src/audio/README b/smpeg/src/audio/README new file mode 100644 index 0000000..ce17bbb --- /dev/null +++ b/smpeg/src/audio/README @@ -0,0 +1,4 @@ + +This code is based on Splay 0.8.2, available from: + http://my.netian.com/~polarb/ + diff --git a/smpeg/src/audio/README.LIB b/smpeg/src/audio/README.LIB new file mode 100644 index 0000000..aab999e --- /dev/null +++ b/smpeg/src/audio/README.LIB @@ -0,0 +1,60 @@ +mpegsound README.LIB(International) + +MPEG/WAVE player library + +This library have NO WARRANTY. You can use this under Library GPL. +This library uses part from vplay, maplay 1.2 for linux, maplay 1.2+ for Win95. + +This is library which can make program play MPEG-1/2 audio and Wave file easily. +Detail is in ChangeLog + +CAUTION + The current implementation was tested with little endian architecture. + Bigendian is implemented. But I don't test. + Hackers... please help me! + + What's the difference? + For example; + unsigned char a[4]={0x11,0x22,0x33,0x44}; + unsigned int *b=(unsigned int *)&a; + + Little endian (Intel) : 0x44332211 + Big endian : 0x11223344 + + The classes 'mpegtoraw' and 'bitwindow' are endian dependent. + + OTHER ENDIAN PROBLEM + Some machines can access integer type variables when they are aligned + at 4-bytes. If endian problem is solved. It cause serious problem. + + I have exploited the linear properties of 2 and 3 dimensional arrays. + like for example; + + int a[4][4]; + + a[1][0]==a[0][4] is true. + + Of course, It may occur boundary problem. But it may make player faster! + +IMPROVED + Using mpg123 code, I improved performance of this library. + Thank you for authors of mpg123 + +ENGLISH PROBLEM + I release README with International (English) and Korean (my native lang) +The Korean version should be ok, but the english version have many spelling +mistakes and confusing words and sentences. Please forgive me and help me +correct the english. + +PROBLEM? + Please send me bug report or patches.(Please comment where is changed) + to: + jwj95@eve.kaist.ac.kr + jwj95@nownuri.net + +THANKS FOR this document. + Tommy Thorn + + + + diff --git a/smpeg/src/audio/bitwindow.cpp b/smpeg/src/audio/bitwindow.cpp new file mode 100644 index 0000000..6f2e67d --- /dev/null +++ b/smpeg/src/audio/bitwindow.cpp @@ -0,0 +1,64 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Bitwindow.cc +// It's bit reservior for MPEG layer 3 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "MPEGaudio.h" + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define _KEY 0 +#else +#define _KEY 3 +#endif + +int Mpegbitwindow::getbits(int bits) +{ + union + { + char store[4]; + int current; + }u; + int bi; + + if(!bits)return 0; + + u.current=0; + bi=(bitindex&7); + // u.store[_KEY]=buffer[(bitindex>>3)&(WINDOWSIZE-1)]<>3]<>3)&(WINDOWSIZE-1)]; + u.store[_KEY]=buffer[bitindex>>3]; + bitindex+=8; + bi=8; + } + + if(bits>=bi) + { + u.current<<=bi; + bits-=bi; + bi=0; + } + else + { + u.current<<=bits; + bi-=bits; + bits=0; + } + } + bitindex-=bi; + + return (u.current>>8); +} diff --git a/smpeg/src/audio/filter.cpp b/smpeg/src/audio/filter.cpp new file mode 100644 index 0000000..9eed5ea --- /dev/null +++ b/smpeg/src/audio/filter.cpp @@ -0,0 +1,338 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Filter.cc +// Subbandsynthesis routines from maplay 1.2 for Linux +// I've modified some macros for reducing source code. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "MPEGaudio.h" + +void MPEGaudio::computebuffer(REAL *fraction,REAL buffer[2][CALCBUFFERSIZE]) +{ + REAL p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pa,pb,pc,pd,pe,pf; + REAL q0,q1,q2,q3,q4,q5,q6,q7,q8,q9,qa,qb,qc,qd,qe,qf; + REAL *out1,*out2; + + out1=buffer[currentcalcbuffer]+calcbufferoffset; + out2=buffer[currentcalcbuffer^1]+calcbufferoffset; +#define OUT1(v,t) out1[(32-(v))*16] =(-(out1[(v)*16]=t)) +#define OUT2(v) out2[(96-(v)-32)*16]=out2[((v)-32)*16] + + // compute new values via a fast cosine transform: + { + register REAL *x=fraction; + + p0=x[ 0]+x[31];p1=x[ 1]+x[30];p2=x[ 2]+x[29];p3=x[ 3]+x[28]; + p4=x[ 4]+x[27];p5=x[ 5]+x[26];p6=x[ 6]+x[25];p7=x[ 7]+x[24]; + p8=x[ 8]+x[23];p9=x[ 9]+x[22];pa=x[10]+x[21];pb=x[11]+x[20]; + pc=x[12]+x[19];pd=x[13]+x[18];pe=x[14]+x[17];pf=x[15]+x[16]; + } + + + q0=p0+pf;q1=p1+pe;q2=p2+pd;q3=p3+pc; + q4=p4+pb;q5=p5+pa;q6=p6+p9;q7=p7+p8; + q8=hcos_32[0]*(p0-pf);q9=hcos_32[1]*(p1-pe); + qa=hcos_32[2]*(p2-pd);qb=hcos_32[3]*(p3-pc); + qc=hcos_32[4]*(p4-pb);qd=hcos_32[5]*(p5-pa); + qe=hcos_32[6]*(p6-p9);qf=hcos_32[7]*(p7-p8); + + p0=q0+q7;p1=q1+q6;p2=q2+q5;p3=q3+q4; + p4=hcos_16[0]*(q0-q7);p5=hcos_16[1]*(q1-q6); + p6=hcos_16[2]*(q2-q5);p7=hcos_16[3]*(q3-q4); + p8=q8+qf;p9=q9+qe;pa=qa+qd;pb=qb+qc; + pc=hcos_16[0]*(q8-qf);pd=hcos_16[1]*(q9-qe); + pe=hcos_16[2]*(qa-qd);pf=hcos_16[3]*(qb-qc); + + q0=p0+p3;q1=p1+p2;q2=hcos_8[0]*(p0-p3);q3=hcos_8[1]*(p1-p2); + q4=p4+p7;q5=p5+p6;q6=hcos_8[0]*(p4-p7);q7=hcos_8[1]*(p5-p6); + q8=p8+pb;q9=p9+pa;qa=hcos_8[0]*(p8-pb);qb=hcos_8[1]*(p9-pa); + qc=pc+pf;qd=pd+pe;qe=hcos_8[0]*(pc-pf);qf=hcos_8[1]*(pd-pe); + + p0=q0+q1;p1=hcos_4*(q0-q1);p2=q2+q3;p3=hcos_4*(q2-q3); + p4=q4+q5;p5=hcos_4*(q4-q5);p6=q6+q7;p7=hcos_4*(q6-q7); + p8=q8+q9;p9=hcos_4*(q8-q9);pa=qa+qb;pb=hcos_4*(qa-qb); + pc=qc+qd;pd=hcos_4*(qc-qd);pe=qe+qf;pf=hcos_4*(qe-qf); + + { + register REAL tmp; + + tmp=p6+p7; + OUT2(36)=-(p5+tmp); + OUT2(44)=-(p4+tmp); + tmp=pb+pf; + OUT1(10,tmp); + OUT1(6,pd+tmp); + tmp=pe+pf; + OUT2(46)=-(p8+pc+tmp); + OUT2(34)=-(p9+pd+tmp); + tmp+=pa+pb; + OUT2(38)=-(pd+tmp); + OUT2(42)=-(pc+tmp); + OUT1(2,p9+pd+pf); + OUT1(4,p5+p7); + OUT2(48)=-p0; + out2[0]=-(out1[0]=p1); + OUT1( 8,p3); + OUT1(12,p7); + OUT1(14,pf); + OUT2(40)=-(p2+p3); + } + + { + register REAL *x=fraction; + + p0=hcos_64[ 0]*(x[ 0]-x[31]);p1=hcos_64[ 1]*(x[ 1]-x[30]); + p2=hcos_64[ 2]*(x[ 2]-x[29]);p3=hcos_64[ 3]*(x[ 3]-x[28]); + p4=hcos_64[ 4]*(x[ 4]-x[27]);p5=hcos_64[ 5]*(x[ 5]-x[26]); + p6=hcos_64[ 6]*(x[ 6]-x[25]);p7=hcos_64[ 7]*(x[ 7]-x[24]); + p8=hcos_64[ 8]*(x[ 8]-x[23]);p9=hcos_64[ 9]*(x[ 9]-x[22]); + pa=hcos_64[10]*(x[10]-x[21]);pb=hcos_64[11]*(x[11]-x[20]); + pc=hcos_64[12]*(x[12]-x[19]);pd=hcos_64[13]*(x[13]-x[18]); + pe=hcos_64[14]*(x[14]-x[17]);pf=hcos_64[15]*(x[15]-x[16]); + } + + q0=p0+pf;q1=p1+pe;q2=p2+pd;q3=p3+pc; + q4=p4+pb;q5=p5+pa;q6=p6+p9;q7=p7+p8; + q8=hcos_32[0]*(p0-pf);q9=hcos_32[1]*(p1-pe); + qa=hcos_32[2]*(p2-pd);qb=hcos_32[3]*(p3-pc); + qc=hcos_32[4]*(p4-pb);qd=hcos_32[5]*(p5-pa); + qe=hcos_32[6]*(p6-p9);qf=hcos_32[7]*(p7-p8); + + p0=q0+q7;p1=q1+q6;p2=q2+q5;p3=q3+q4; + p4=hcos_16[0]*(q0-q7);p5=hcos_16[1]*(q1-q6); + p6=hcos_16[2]*(q2-q5);p7=hcos_16[3]*(q3-q4); + p8=q8+qf;p9=q9+qe;pa=qa+qd;pb=qb+qc; + pc=hcos_16[0]*(q8-qf);pd=hcos_16[1]*(q9-qe); + pe=hcos_16[2]*(qa-qd);pf=hcos_16[3]*(qb-qc); + + q0=p0+p3;q1=p1+p2;q2=hcos_8[0]*(p0-p3);q3=hcos_8[1]*(p1-p2); + q4=p4+p7;q5=p5+p6;q6=hcos_8[0]*(p4-p7);q7=hcos_8[1]*(p5-p6); + q8=p8+pb;q9=p9+pa;qa=hcos_8[0]*(p8-pb);qb=hcos_8[1]*(p9-pa); + qc=pc+pf;qd=pd+pe;qe=hcos_8[0]*(pc-pf);qf=hcos_8[1]*(pd-pe); + + p0=q0+q1;p1=hcos_4*(q0-q1); + p2=q2+q3;p3=hcos_4*(q2-q3); + p4=q4+q5;p5=hcos_4*(q4-q5); + p6=q6+q7;p7=hcos_4*(q6-q7); + p8=q8+q9;p9=hcos_4*(q8-q9); + pa=qa+qb;pb=hcos_4*(qa-qb); + pc=qc+qd;pd=hcos_4*(qc-qd); + pe=qe+qf;pf=hcos_4*(qe-qf); + + { + REAL tmp; + + tmp=pd+pf; + OUT1(5,p5+p7+pb+tmp); + tmp+=p9; + OUT1(1,p1+tmp); + OUT2(33)=-(p1+pe+tmp); + tmp+=p5+p7; + OUT1(3,tmp); + OUT2(35)=-(p6+pe+tmp); + tmp=pa+pb+pc+pd+pe+pf; + OUT2(39)=-(p2+p3+tmp-pc); + OUT2(43)=-(p4+p6+p7+tmp-pd); + OUT2(37)=-(p5+p6+p7+tmp-pc); + OUT2(41)=-(p2+p3+tmp-pd); + tmp=p8+pc+pe+pf; + OUT2(47)=-(p0+tmp); + OUT2(45)=-(p4+p6+p7+tmp); + tmp=pb+pf; + OUT1(11,p7+tmp); + tmp+=p3; + OUT1( 9,tmp); + OUT1( 7,pd+tmp); + OUT1(13,p7+pf); + OUT1(15,pf); + } +} + + +#define SAVE \ + raw=(int)(r*scalefactor); \ + if(raw>MAXSCALE)raw=MAXSCALE;else if(rawMAXSCALE)raw=MAXSCALE;else if(rawMAXSCALE)raw=MAXSCALE;else if(rawMAXSCALE)raw=MAXSCALE;else if(rawMAXSCALE)raw=MAXSCALE;else if(rawMAXSCALE)raw=MAXSCALE;else if(raw 2184) { +//printf("fraction LS OverFlow code %d -> 2184 (1)\n", code); + code=2184; + } + s=group[LS][i]+code; + + fraction[LS][0][i]=s[0]; + fraction[LS][1][i]=s[1]; + fraction[LS][2][i]=s[2]; + } + else + { + fraction[LS][0][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + fraction[LS][1][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + fraction[LS][2][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + } + } + else fraction[LS][0][i]=fraction[LS][1][i]=fraction[LS][2][i]=0.0; + + if(inputstereo && bitalloc[RS][i]) + { + if(group[RS][i]) + { + const REAL *s; + int code=getbits(codelength[RS][i]); + + code+=code<<1; + if (code > 2184) { +//printf("fraction LS OverFlow code %d -> 2184 (2)\n", code); + code=2184; + } + s=group[RS][i]+code; + + fraction[RS][0][i]=s[0]; + fraction[RS][1][i]=s[1]; + fraction[RS][2][i]=s[2]; + } + else + { + fraction[RS][0][i]= + REAL(getbits(codelength[RS][i]))*factor[RS][i]-1.0; + fraction[RS][1][i]= + REAL(getbits(codelength[RS][i]))*factor[RS][i]-1.0; + fraction[RS][2][i]= + REAL(getbits(codelength[RS][i]))*factor[RS][i]-1.0; + } + } + else fraction[RS][0][i]=fraction[RS][1][i]=fraction[RS][2][i]=0.0; + } + + for(;i>2][i]; + fraction[LS][0][i]*=t; + fraction[LS][1][i]*=t; + fraction[LS][2][i]*=t; + } + + if(bitalloc[RS][i]) + { + if(!group[RS][i]) + { + fraction[RS][0][i]=(fraction[RS][0][i]+d[RS][i])*c[RS][i]; + fraction[RS][1][i]=(fraction[RS][1][i]+d[RS][i])*c[RS][i]; + fraction[RS][2][i]=(fraction[RS][2][i]+d[RS][i])*c[RS][i]; + } + + register REAL t=scalefactor[RS][l>>2][i]; + fraction[RS][0][i]*=t; + fraction[RS][1][i]*=t; + fraction[RS][2][i]*=t; + } + } + else + for(i=0;i>2][i]; + fraction[LS][0][i]*=t; + fraction[LS][1][i]*=t; + fraction[LS][2][i]*=t; + } + + for(;i +#include + +#include "MPEGaudio.h" +#if defined(_WIN32) && defined(_MSC_VER) +// disable warnings about double to float conversions +#pragma warning(disable: 4244 4305) +#endif + +inline void Mpegbitwindow::wrap(void) +{ + int p=bitindex>>3; + point&=(WINDOWSIZE-1); + + if(p>=point) + { + for(register int i=4;ipart2_3_length =getbits(12); + gi->big_values =getbits(9); + gi->global_gain =getbits(8); + gi->scalefac_compress =getbits(4); + gi->window_switching_flag=getbit(); + if(gi->window_switching_flag) + { + gi->block_type =getbits(2); + gi->mixed_block_flag=getbit(); + + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + + gi->subblock_gain[0]=getbits(3); + gi->subblock_gain[1]=getbits(3); + gi->subblock_gain[2]=getbits(3); + + /* Set region_count parameters since they are implicit in this case. */ + if(gi->block_type==0) + { + /* printf("Side info bad: block_type == 0 in split block.\n"); + exit(0); */ + return false; + } + else if (gi->block_type==2 && gi->mixed_block_flag==0) + gi->region0_count=8; /* MI 9; */ + else gi->region0_count=7; /* MI 8; */ + gi->region1_count=20-(gi->region0_count); + } + else + { + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + gi->table_select[2] =getbits(5); + gi->region0_count =getbits(4); + gi->region1_count =getbits(3); + gi->block_type =0; + } + gi->preflag =getbit(); + gi->scalefac_scale =getbit(); + gi->count1table_select=getbit(); + + gi->generalflag=gi->window_switching_flag && (gi->block_type==2); + + if(!inputstereo || ch)break; + } + + return true; +} + +bool MPEGaudio::layer3getsideinfo_2(void) +{ + sideinfo.main_data_begin=getbits(8); + + if(!inputstereo)sideinfo.private_bits=getbit(); + else sideinfo.private_bits=getbits(2); + + for(int ch=0;;ch++) + { + layer3grinfo *gi=&(sideinfo.ch[ch].gr[0]); + + gi->part2_3_length =getbits(12); + gi->big_values =getbits(9); + gi->global_gain =getbits(8); + gi->scalefac_compress =getbits(9); + gi->window_switching_flag=getbit(); + if(gi->window_switching_flag) + { + gi->block_type =getbits(2); + gi->mixed_block_flag=getbit(); + + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + + gi->subblock_gain[0]=getbits(3); + gi->subblock_gain[1]=getbits(3); + gi->subblock_gain[2]=getbits(3); + + /* Set region_count parameters since they are implicit in this case. */ + if(gi->block_type==0) + { + /* printf("Side info bad: block_type == 0 in split block.\n"); + exit(0); */ + return false; + } + else if (gi->block_type==2 && gi->mixed_block_flag==0) + gi->region0_count=8; /* MI 9; */ + else gi->region0_count=7; /* MI 8; */ + gi->region1_count=20-(gi->region0_count); + } + else + { + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + gi->table_select[2] =getbits(5); + gi->region0_count =getbits(4); + gi->region1_count =getbits(3); + gi->block_type =0; + } + gi->scalefac_scale =getbit(); + gi->count1table_select=getbit(); + + gi->generalflag=gi->window_switching_flag && (gi->block_type==2); + + if(!inputstereo || ch)break; + } + + return true; +} + +void MPEGaudio::layer3getscalefactors(int ch,int gr) +{ + static int slen[2][16]={{0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4}, + {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}}; + + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + register layer3scalefactor *sf=(&scalefactors[ch]); + int l0,l1; + + { + int scale_comp=gi->scalefac_compress; + + l0=slen[0][scale_comp]; + l1=slen[1][scale_comp]; + } + if(gi->generalflag) + { + if(gi->mixed_block_flag) + { /* MIXED */ /* NEW-ag 11/25 */ + sf->l[0]=wgetbits9(l0);sf->l[1]=wgetbits9(l0); + sf->l[2]=wgetbits9(l0);sf->l[3]=wgetbits9(l0); + sf->l[4]=wgetbits9(l0);sf->l[5]=wgetbits9(l0); + sf->l[6]=wgetbits9(l0);sf->l[7]=wgetbits9(l0); + + sf->s[0][ 3]=wgetbits9(l0);sf->s[1][ 3]=wgetbits9(l0); + sf->s[2][ 3]=wgetbits9(l0); + sf->s[0][ 4]=wgetbits9(l0);sf->s[1][ 4]=wgetbits9(l0); + sf->s[2][ 4]=wgetbits9(l0); + sf->s[0][ 5]=wgetbits9(l0);sf->s[1][ 5]=wgetbits9(l0); + sf->s[2][ 5]=wgetbits9(l0); + + sf->s[0][ 6]=wgetbits9(l1);sf->s[1][ 6]=wgetbits9(l1); + sf->s[2][ 6]=wgetbits9(l1); + sf->s[0][ 7]=wgetbits9(l1);sf->s[1][ 7]=wgetbits9(l1); + sf->s[2][ 7]=wgetbits9(l1); + sf->s[0][ 8]=wgetbits9(l1);sf->s[1][ 8]=wgetbits9(l1); + sf->s[2][ 8]=wgetbits9(l1); + sf->s[0][ 9]=wgetbits9(l1);sf->s[1][ 9]=wgetbits9(l1); + sf->s[2][ 9]=wgetbits9(l1); + sf->s[0][10]=wgetbits9(l1);sf->s[1][10]=wgetbits9(l1); + sf->s[2][10]=wgetbits9(l1); + sf->s[0][11]=wgetbits9(l1);sf->s[1][11]=wgetbits9(l1); + sf->s[2][11]=wgetbits9(l1); + + sf->s[0][12]=sf->s[1][12]=sf->s[2][12]=0; + } + else + { /* SHORT*/ + sf->s[0][ 0]=wgetbits9(l0);sf->s[1][ 0]=wgetbits9(l0); + sf->s[2][ 0]=wgetbits9(l0); + sf->s[0][ 1]=wgetbits9(l0);sf->s[1][ 1]=wgetbits9(l0); + sf->s[2][ 1]=wgetbits9(l0); + sf->s[0][ 2]=wgetbits9(l0);sf->s[1][ 2]=wgetbits9(l0); + sf->s[2][ 2]=wgetbits9(l0); + sf->s[0][ 3]=wgetbits9(l0);sf->s[1][ 3]=wgetbits9(l0); + sf->s[2][ 3]=wgetbits9(l0); + sf->s[0][ 4]=wgetbits9(l0);sf->s[1][ 4]=wgetbits9(l0); + sf->s[2][ 4]=wgetbits9(l0); + sf->s[0][ 5]=wgetbits9(l0);sf->s[1][ 5]=wgetbits9(l0); + sf->s[2][ 5]=wgetbits9(l0); + + sf->s[0][ 6]=wgetbits9(l1);sf->s[1][ 6]=wgetbits9(l1); + sf->s[2][ 6]=wgetbits9(l1); + sf->s[0][ 7]=wgetbits9(l1);sf->s[1][ 7]=wgetbits9(l1); + sf->s[2][ 7]=wgetbits9(l1); + sf->s[0][ 8]=wgetbits9(l1);sf->s[1][ 8]=wgetbits9(l1); + sf->s[2][ 8]=wgetbits9(l1); + sf->s[0][ 9]=wgetbits9(l1);sf->s[1][ 9]=wgetbits9(l1); + sf->s[2][ 9]=wgetbits9(l1); + sf->s[0][10]=wgetbits9(l1);sf->s[1][10]=wgetbits9(l1); + sf->s[2][10]=wgetbits9(l1); + sf->s[0][11]=wgetbits9(l1);sf->s[1][11]=wgetbits9(l1); + sf->s[2][11]=wgetbits9(l1); + + sf->s[0][12]=sf->s[1][12]=sf->s[2][12]=0; + } + } + else + { /* LONG types 0,1,3 */ + if(gr==0) + { + sf->l[ 0]=wgetbits9(l0);sf->l[ 1]=wgetbits9(l0); + sf->l[ 2]=wgetbits9(l0);sf->l[ 3]=wgetbits9(l0); + sf->l[ 4]=wgetbits9(l0);sf->l[ 5]=wgetbits9(l0); + sf->l[ 6]=wgetbits9(l0);sf->l[ 7]=wgetbits9(l0); + sf->l[ 8]=wgetbits9(l0);sf->l[ 9]=wgetbits9(l0); + sf->l[10]=wgetbits9(l0); + sf->l[11]=wgetbits9(l1);sf->l[12]=wgetbits9(l1); + sf->l[13]=wgetbits9(l1);sf->l[14]=wgetbits9(l1); + sf->l[15]=wgetbits9(l1); + sf->l[16]=wgetbits9(l1);sf->l[17]=wgetbits9(l1); + sf->l[18]=wgetbits9(l1);sf->l[19]=wgetbits9(l1); + sf->l[20]=wgetbits9(l1); + } + else + { + if(sideinfo.ch[ch].scfsi[0]==0) + { + sf->l[ 0]=wgetbits9(l0);sf->l[ 1]=wgetbits9(l0); + sf->l[ 2]=wgetbits9(l0);sf->l[ 3]=wgetbits9(l0); + sf->l[ 4]=wgetbits9(l0);sf->l[ 5]=wgetbits9(l0); + } + if(sideinfo.ch[ch].scfsi[1]==0) + { + sf->l[ 6]=wgetbits9(l0);sf->l[ 7]=wgetbits9(l0); + sf->l[ 8]=wgetbits9(l0);sf->l[ 9]=wgetbits9(l0); + sf->l[10]=wgetbits9(l0); + } + if(sideinfo.ch[ch].scfsi[2]==0) + { + sf->l[11]=wgetbits9(l1);sf->l[12]=wgetbits9(l1); + sf->l[13]=wgetbits9(l1);sf->l[14]=wgetbits9(l1); + sf->l[15]=wgetbits9(l1); + } + if(sideinfo.ch[ch].scfsi[3]==0) + { + sf->l[16]=wgetbits9(l1);sf->l[17]=wgetbits9(l1); + sf->l[18]=wgetbits9(l1);sf->l[19]=wgetbits9(l1); + sf->l[20]=wgetbits9(l1); + } + } + sf->l[21]=sf->l[22]=0; + } +} + +void MPEGaudio::layer3getscalefactors_2(int ch) +{ + static int sfbblockindex[6][3][4]= + { + {{ 6, 5, 5, 5},{ 9, 9, 9, 9},{ 6, 9, 9, 9}}, + {{ 6, 5, 7, 3},{ 9, 9,12, 6},{ 6, 9,12, 6}}, + {{11,10, 0, 0},{18,18, 0, 0},{15,18, 0, 0}}, + {{ 7, 7, 7, 0},{12,12,12, 0},{ 6,15,12, 0}}, + {{ 6, 6, 6, 3},{12, 9, 9, 6},{ 6,12, 9, 6}}, + {{ 8, 8, 5, 0},{15,12, 9, 0},{ 6,18, 9, 0}} + }; + + int sb[54]; + layer3grinfo *gi=&(sideinfo.ch[ch].gr[0]); + register layer3scalefactor *sf=(&scalefactors[ch]); + + { + int blocktypenumber,sc; + int blocknumber; + int slen[4]; + + if(gi->block_type==2)blocktypenumber=1+gi->mixed_block_flag; + else blocktypenumber=0; + + sc=gi->scalefac_compress; + if(!((extendedmode==1 || extendedmode==3) && (ch==1))) + { + if(sc<400) + { + slen[0]=(sc>>4)/5; + slen[1]=(sc>>4)%5; + slen[2]=(sc%16)>>2; + slen[3]=(sc%4); + gi->preflag=0; + blocknumber=0; + } + else if(sc<500) + { + sc-=400; + slen[0]=(sc>>2)/5; + slen[1]=(sc>>2)%5; + slen[2]=sc%4; + slen[3]=0; + gi->preflag=0; + blocknumber=1; + } + else // if(sc<512) + { + sc-=500; + slen[0]=sc/3; + slen[1]=sc%3; + slen[2]=0; + slen[3]=0; + gi->preflag=1; + blocknumber=2; + } + } + else + { + sc>>=1; + if(sc<180) + { + slen[0]=sc/36; + slen[1]=(sc%36)/6; + slen[2]=(sc%36)%6; + slen[3]=0; + gi->preflag=0; + blocknumber=3; + } + else if(sc<244) + { + sc-=180; + slen[0]=(sc%64)>>4; + slen[1]=(sc%16)>>2; + slen[2]=sc%4; + slen[3]=0; + gi->preflag=0; + blocknumber=4; + } + else // if(sc<255) + { + sc-=244; + slen[0]=sc/3; + slen[1]=sc%3; + slen[2]= + slen[3]=0; + gi->preflag=0; + blocknumber=5; + } + } + + { + int i,j,k,*si; + + si=sfbblockindex[blocknumber][blocktypenumber]; + for(i=0;i<45;i++)sb[i]=0; + + for(k=i=0;i<4;i++) + for(j=0;jwindow_switching_flag && (gi->block_type==2)) + { + if(gi->mixed_block_flag) + { + for(sfb=0;sfb<8;sfb++)sf->l[sfb]=sb[k++]; + sfb=3; + } + else sfb=0; + + for(;sfb<12;sfb++) + for(window=0;window<3;window++) + sf->s[window][sfb]=sb[k++]; + + sf->s[0][12]=sf->s[1][12]=sf->s[2][12]=0; + } + else + { + for(sfb=0;sfb<21;sfb++) + sf->l[sfb]=sb[k++]; + sf->l[21]=sf->l[22]=0; + } + } +} + + +typedef unsigned int HUFFBITS; +#define MXOFF 250 + +/* do the huffman-decoding */ +/* note! for counta,countb -the 4 bit value is returned in y, discard x */ +// Huffman decoder for tablename<32 +void MPEGaudio::huffmandecoder_1(const HUFFMANCODETABLE *h,int *x,int *y) +{ + HUFFBITS level=(1<<(sizeof(HUFFBITS)*8-1)); + int point=0; + + /* Lookup in Huffman table. */ + for(;;) + { + if(h->val[point][0]==0) + { /*end of tree*/ + int xx,yy; + + xx=h->val[point][1]>>4; + yy=h->val[point][1]&0xf; + + if(h->linbits) + { + if((h->xlen)==(unsigned)xx)xx+=wgetbits(h->linbits); + if(xx)if(wgetbit())xx=-xx; + if((h->ylen)==(unsigned)yy)yy+=wgetbits(h->linbits); + if(yy)if(wgetbit())yy=-yy; + } + else + { + if(xx)if(wgetbit())xx=-xx; + if(yy)if(wgetbit())yy=-yy; + } + *x=xx;*y=yy; + break; + } + + point+=h->val[point][wgetbit()]; + + level>>=1; + if(!(level || ((unsigned)pointtreelen))) + { + register int xx,yy; + + xx=(h->xlen<<1);// set x and y to a medium value as a simple concealment + yy=(h->ylen<<1); + + // h->xlen and h->ylen can't be 1 under tablename 32 + // if(xx) + if(wgetbit())xx=-xx; + // if(yy) + if(wgetbit())yy=-yy; + + *x=xx;*y=yy; + break; + } + } +} + +// Huffman decoder tablenumber>=32 +void MPEGaudio::huffmandecoder_2(const HUFFMANCODETABLE *h, + int *x,int *y,int *v,int *w) +{ + HUFFBITS level=(1<<(sizeof(HUFFBITS)*8-1)); + int point=0; + + /* Lookup in Huffman table. */ + for(;;) + { + if(h->val[point][0]==0) + { /*end of tree*/ + register int t=h->val[point][1]; + + if(t&8)*v=1-(wgetbit()<<1); else *v=0; + if(t&4)*w=1-(wgetbit()<<1); else *w=0; + if(t&2)*x=1-(wgetbit()<<1); else *x=0; + if(t&1)*y=1-(wgetbit()<<1); else *y=0; + break; + } + point+=h->val[point][wgetbit()]; + level>>=1; + if(!(level || ((unsigned)pointtreelen))) + { + *v=1-(wgetbit()<<1); + *w=1-(wgetbit()<<1); + *x=1-(wgetbit()<<1); + *y=1-(wgetbit()<<1); + break; + } + } +} + +typedef struct +{ + int l[23]; + int s[14]; +}SFBANDINDEX; + +static SFBANDINDEX sfBandIndextable[2][3]= +{ + // MPEG 1 + {{{0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576}, + {0,4,8,12,16,22,30,40,52,66,84,106,136,192}}, + {{0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576}, + {0,4,8,12,16,22,28,38,50,64,80,100,126,192}}, + {{0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576}, + {0,4,8,12,16,22,30,42,58,78,104,138,180,192}}}, + + // MPEG 2 + {{{0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {0,4,8,12,18,24,32,42,56,74,100,132,174,192}}, + {{0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576}, + {0,4,8,12,18,26,36,48,62,80,104,136,180,192}}, + {{0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {0,4,8,12,18,26,36,48,62,80,104,134,174,192}}} +}; + + +void MPEGaudio::layer3huffmandecode(int ch,int gr,int out[SBLIMIT][SSLIMIT]) +{ + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + int part2_3_end=layer3part2start+(gi->part2_3_length); + int region1Start,region2Start; + int i,e=gi->big_values<<1; + + /* Find region boundary for short block case. */ + if(gi->generalflag) + { + /* Region2. */ + region1Start=36; /* sfb[9/3]*3=36 */ + region2Start=576;/* No Region2 for short block case. */ + } + else + { /* Find region boundary for long block case. */ + region1Start=sfBandIndextable[version][frequency].l[gi->region0_count+1]; + region2Start=sfBandIndextable[version][frequency].l[gi->region0_count+ + gi->region1_count+2]; + } + + /* Read bigvalues area. */ + for(i=0;itable_select[0]]; + if(region1Start>e)end=e; else end=region1Start; + } + else if(itable_select[1]]; + if(region2Start>e)end=e; else end=region2Start; + } + else + { + h=&ht[gi->table_select[2]]; + end=e; + } + + if(h->treelen) + while(icount1table_select+32]; + while(bitwindow.gettotalbit()=ARRAYSIZE) + { + bitwindow.rewind(bitwindow.gettotalbit()-part2_3_end); + return; + } + } + + for(;iglobal_gain]; + REAL *TO_FOUR_THIRDS=TO_FOUR_THIRDSTABLE+FOURTHIRDSTABLENUMBER; + + /* choose correct scalefactor band per block type, initalize boundary */ + /* and apply formula per block type */ + + if(!gi->generalflag) + { /* LONG blocks: 0,1,3 */ + int next_cb_boundary; + int cb=-1,index=0; + REAL factor; + + do + { + next_cb_boundary=sfBandIndex->l[(++cb)+1]; + factor=globalgain* + layer3twopow2(gi->scalefac_scale,gi->preflag, + pretab[cb],scalefactors[ch].l[cb]); + for(;indexmixed_block_flag) + { + int cb=0,index=0; + int cb_width; + + do + { + cb_width=(sfBandIndex->s[cb+1]-sfBandIndex->s[cb])>>1; + + for(register int k=0;k<3;k++) + { + register REAL factor; + register int count=cb_width; + + factor=globalgain* + layer3twopow2_1(gi->subblock_gain[k],gi->scalefac_scale, + scalefactors[ch].s[k][cb]); + do{ + out[0][index]=factor*TO_FOUR_THIRDS[in[0][index]];index++; + out[0][index]=factor*TO_FOUR_THIRDS[in[0][index]];index++; + }while(--count); + } + cb++; + }while(indexl[1]; /* LONG blocks: 0,1,3 */ + int index; + + /* Compute overall (global) scaling. */ + { + for(int sb=0;sbl[8]) + { + next_cb_boundary=sfBandIndex->s[4]; + next_cb_boundary=MUL3(next_cb_boundary); + cb=3; + cb_width=sfBandIndex->s[4]-sfBandIndex->s[3]; + cb_begin=sfBandIndex->s[3]; + cb_begin=MUL3(cb_begin); + } + else if(indexl[8]) + next_cb_boundary=sfBandIndex->l[(++cb)+1]; + else + { + next_cb_boundary=sfBandIndex->s[(++cb)+1]; + next_cb_boundary=MUL3(next_cb_boundary); + cb_begin=sfBandIndex->s[cb]; + cb_width=sfBandIndex->s[cb+1]-cb_begin; + cb_begin=MUL3(cb_begin); + } + } + /* LONG block types 0,1,3 & 1st 2 subbands of switched blocks */ + out[0][index]*=layer3twopow2(gi->scalefac_scale,gi->preflag, + pretab[cb],scalefactors[ch].l[cb]); + } + + for(;indexl[8]) + { + next_cb_boundary=sfBandIndex->s[4]; + next_cb_boundary=MUL3(next_cb_boundary); + cb=3; + cb_width=sfBandIndex->s[4]-sfBandIndex->s[3]; + cb_begin=sfBandIndex->s[3]; + cb_begin=(cb_begin<<2)-cb_begin; + } + else if(indexl[8]) + next_cb_boundary=sfBandIndex->l[(++cb)+1]; + else + { + next_cb_boundary=sfBandIndex->s[(++cb)+1]; + next_cb_boundary=MUL3(next_cb_boundary); + cb_begin=sfBandIndex->s[cb]; + cb_width=sfBandIndex->s[cb+1]-cb_begin; + cb_begin=MUL3(cb_begin); + } + } + { + int t_index=(index-cb_begin)/cb_width; + out[0][index]*=layer3twopow2_1(gi->subblock_gain[t_index], + gi->scalefac_scale, + scalefactors[ch].s[t_index][cb]); + } + } + } +} + +void MPEGaudio::layer3fixtostereo(int gr,REAL in[2][SBLIMIT][SSLIMIT]) +{ + layer3grinfo *gi=&(sideinfo.ch[0].gr[gr]); + SFBANDINDEX *sfBandIndex=&(sfBandIndextable[version][frequency]); + + int ms_stereo=(mode==joint) && (extendedmode & 0x2); + int i_stereo =(mode==joint) && (extendedmode & 0x1); + + if(!inputstereo) + { /* mono , bypass xr[0][][] to lr[0][][]*/ + // memcpy(out[0][0],in[0][0],ARRAYSIZE*REALSIZE); + return; + } + + if(i_stereo) + { + int i; + int is_pos[ARRAYSIZE]; + RATIOS is_ratio[ARRAYSIZE]; + RATIOS *ratios; + + if(version)ratios=rat_2[gi->scalefac_compress%2]; + else ratios=rat_1; + + /* initialization */ + for(i=0;igeneralflag) + { + if(gi->mixed_block_flag) // Part I + { + int max_sfb=0; + + for(int j=0;j<3;j++) + { + int sfb,sfbcnt=2; + + for(sfb=12;sfb>=3;sfb--) + { + int lines; + + i=sfBandIndex->s[sfb]; + lines=sfBandIndex->s[sfb+1]-i; + i=MUL3(i)+(j+1)*lines-1; + for(;lines>0;lines--,i--) + if(in[1][0][i]!=0.0f) + { + sfbcnt=sfb; + sfb=0;break; // quit loop + } + } + sfb=sfbcnt+1; + + if(sfb>max_sfb)max_sfb=sfb; + + for(;sfb<12;sfb++) + { + int k,t; + + t=sfBandIndex->s[sfb]; + k=sfBandIndex->s[sfb+1]-t; + i=MUL3(t)+j*k; + + t=scalefactors[1].s[j][sfb]; + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + sfb=sfBandIndex->s[10]; + sfb=MUL3(sfb)+j*(sfBandIndex->s[11]-sfb); + + { + int k,t; + + t=sfBandIndex->s[11]; + k=sfBandIndex->s[12]-t; + i=MUL3(t)+j*k; + + t=is_pos[sfb]; + if(t!=7) + { + RATIOS r=is_ratio[sfb]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + } + + if(max_sfb<=3) + { + { + REAL temp; + int k; + + temp=in[1][0][0];in[1][0][0]=1.0; + for(k=3*SSLIMIT-1;in[1][0][k]==0.0;k--); + in[1][0][0]=temp; + for(i=0;sfBandIndex->l[i]<=k;i++); + } + { + int sfb=i; + + i=sfBandIndex->l[i]; + for(;sfb<8;sfb++) + { + int t=scalefactors[1].l[sfb]; + int k=sfBandIndex->l[sfb+1]-sfBandIndex->l[sfb]; + + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else for(;k>0;k--,i++)is_pos[i]=t; + } + } + } + } + else // Part II + { + for(int j=0;j<3;j++) + { + int sfb; + int sfbcnt=-1; + + for(sfb=12;sfb>=0;sfb--) + { + int lines; + + { + int t; + + t=sfBandIndex->s[sfb]; + lines=sfBandIndex->s[sfb+1]-t; + i=MUL3(t)+(j+1)*lines-1; + } + + for(;lines>0;lines--,i--) + if(in[1][0][i]!=0.0f) + { + sfbcnt=sfb; + sfb=0;break; // quit loop + } + } + + for(sfb=sfbcnt+1;sfb<12;sfb++) + { + int k,t; + + t=sfBandIndex->s[sfb]; + k=sfBandIndex->s[sfb+1]-t; + i=MUL3(t)+j*k; + + t=scalefactors[1].s[j][sfb]; + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else for(;k>0;k--,i++)is_pos[i]=t; + } + + { + int t1=sfBandIndex->s[10], + t2=sfBandIndex->s[11]; + int k,tt; + + tt=MUL3(t1)+j*(t2-t1); + k =sfBandIndex->s[12]-t2; + if(is_pos[tt]!=7) + { + RATIOS r=is_ratio[tt]; + int t=is_pos[tt]; + + i =MUL3(t1)+j*k; + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=7; + } + } + } + } + else // ms-stereo (Part III) + { + { + REAL temp; + int k; + + temp=in[1][0][0];in[1][0][0]=1.0; + for(k=ARRAYSIZE-1;in[1][0][k]==0.0;k--); + in[1][0][0]=temp; + for(i=0;sfBandIndex->l[i]<=k;i++); + } + + { + int sfb; + + sfb=i; + i=sfBandIndex->l[i]; + for(;sfb<21;sfb++) + { + int k,t; + + k=sfBandIndex->l[sfb+1]-sfBandIndex->l[sfb]; + t=scalefactors[1].l[sfb]; + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + } + + if (i <= sfBandIndex->l[21]) { + int k,t,tt; + + tt=sfBandIndex->l[20]; + k=576-sfBandIndex->l[21]; + t=is_pos[tt]; + if(t!=7) + { + RATIOS r=is_ratio[tt]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + } + + if(ms_stereo) + { + i=ARRAYSIZE-1; + do{ + if(is_pos[i]==7) + { + register REAL t=in[LS][0][i]; + in[LS][0][i]=(t+in[RS][0][i])*0.7071068f; + in[RS][0][i]=(t-in[RS][0][i])*0.7071068f; + } + else + { + in[RS][0][i]=in[LS][0][i]*is_ratio[i].r; + in[LS][0][i]*=is_ratio[i].l; + } + }while(i--); + } + else + { + i=ARRAYSIZE-1; + do{ + if(is_pos[i]!=7) + { + in[RS][0][i]=in[LS][0][i]*is_ratio[i].r; + in[LS][0][i]*=is_ratio[i].l; + } + }while(i--); + } + } + else + { + if(ms_stereo) + { + int i=ARRAYSIZE-1; + do{ + register REAL t=in[LS][0][i]; + + in[LS][0][i]=(t+in[RS][0][i])*0.7071068f; + in[RS][0][i]=(t-in[RS][0][i])*0.7071068f; + }while(i--); + } + } + + // channels==2 +} + +inline void layer3reorder_1(int version,int frequency, + REAL in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]) +{ + SFBANDINDEX *sfBandIndex=&(sfBandIndextable[version][frequency]); + int sfb,sfb_start,sfb_lines; + + /* NO REORDER FOR LOW 2 SUBBANDS */ + out[0][ 0]=in[0][ 0];out[0][ 1]=in[0][ 1];out[0][ 2]=in[0][ 2]; + out[0][ 3]=in[0][ 3];out[0][ 4]=in[0][ 4];out[0][ 5]=in[0][ 5]; + out[0][ 6]=in[0][ 6];out[0][ 7]=in[0][ 7];out[0][ 8]=in[0][ 8]; + out[0][ 9]=in[0][ 9];out[0][10]=in[0][10];out[0][11]=in[0][11]; + out[0][12]=in[0][12];out[0][13]=in[0][13];out[0][14]=in[0][14]; + out[0][15]=in[0][15];out[0][16]=in[0][16];out[0][17]=in[0][17]; + + out[1][ 0]=in[1][ 0];out[1][ 1]=in[1][ 1];out[1][ 2]=in[1][ 2]; + out[1][ 3]=in[1][ 3];out[1][ 4]=in[1][ 4];out[1][ 5]=in[1][ 5]; + out[1][ 6]=in[1][ 6];out[1][ 7]=in[1][ 7];out[1][ 8]=in[1][ 8]; + out[1][ 9]=in[1][ 9];out[1][10]=in[1][10];out[1][11]=in[1][11]; + out[1][12]=in[1][12];out[1][13]=in[1][13];out[1][14]=in[1][14]; + out[1][15]=in[1][15];out[1][16]=in[1][16];out[1][17]=in[1][17]; + + + /* REORDERING FOR REST SWITCHED SHORT */ + for(sfb=3,sfb_start=sfBandIndex->s[3], + sfb_lines=sfBandIndex->s[4]-sfb_start; + sfb<13; + sfb++,sfb_start=sfBandIndex->s[sfb], + (sfb_lines=sfBandIndex->s[sfb+1]-sfb_start)) + { + for(int freq=0;freqs[1]; + sfb<13; + sfb++,sfb_start=sfBandIndex->s[sfb], + (sfb_lines=sfBandIndex->s[sfb+1]-sfb_start)) + { + for(int freq=0;freqgeneralflag) + { + if(gi->mixed_block_flag) + { + fprintf(stderr,"Notchecked!"); + layer3reorder_1 (version,frequency,in,out); // Not checked... + layer3antialias_1(out); + } + else + layer3reorder_2(version,frequency,in,out); + } + else + layer3antialias_2(in,out); +} + +static void dct36(REAL *inbuf,REAL *prevblk1,REAL *prevblk2,REAL *wi,REAL *out) +{ +#define MACRO0(v) { \ + REAL tmp; \ + out2[9+(v)]=(tmp=sum0+sum1)*wi[27+(v)]; \ + out2[8-(v)]=tmp * wi[26-(v)]; } \ + sum0-=sum1; \ + ts[SBLIMIT*(8-(v))]=out1[8-(v)]+sum0*wi[8-(v)]; \ + ts[SBLIMIT*(9+(v))]=out1[9+(v)]+sum0*wi[9+(v)]; +#define MACRO1(v) { \ + REAL sum0,sum1; \ + sum0=tmp1a+tmp2a; \ + sum1=(tmp1b+tmp2b)*hsec_36[(v)]; \ + MACRO0(v); } +#define MACRO2(v) { \ + REAL sum0,sum1; \ + sum0=tmp2a-tmp1a; \ + sum1=(tmp2b-tmp1b) * hsec_36[(v)]; \ + MACRO0(v); } + + { + register REAL *in = inbuf; + + in[17]+=in[16];in[16]+=in[15];in[15]+=in[14];in[14]+=in[13]; + in[13]+=in[12];in[12]+=in[11];in[11]+=in[10];in[10]+=in[ 9]; + in[ 9]+=in[ 8];in[ 8]+=in[ 7];in[ 7]+=in[ 6];in[ 6]+=in[ 5]; + in[ 5]+=in[ 4];in[ 4]+=in[ 3];in[ 3]+=in[ 2];in[ 2]+=in[ 1]; + in[ 1]+=in[ 0]; + + in[17]+=in[15];in[15]+=in[13];in[13]+=in[11];in[11]+=in[ 9]; + in[ 9]+=in[ 7];in[7] +=in[ 5];in[ 5]+=in[ 3];in[ 3]+=in[ 1]; + + { + register REAL *c = cos_18; + register REAL *out2 = prevblk2; + register REAL *out1 = prevblk1; + register REAL *ts = out; + + REAL ta33,ta66,tb33,tb66; + + ta33=in[2*3+0]*c[3]; + ta66=in[2*6+0]*c[6]; + tb33=in[2*3+1]*c[3]; + tb66=in[2*6+1]*c[6]; + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a= in[2*1+0]*c[1]+ta33 +in[2*5+0]*c[5]+in[2*7+0]*c[7]; + tmp1b= in[2*1+1]*c[1]+tb33 +in[2*5+1]*c[5]+in[2*7+1]*c[7]; + tmp2a=in[2*0+0]+in[2*2+0]*c[2]+in[2*4+0]*c[4]+ta66 +in[2*8+0]*c[8]; + tmp2b=in[2*0+1]+in[2*2+1]*c[2]+in[2*4+1]*c[4]+tb66 +in[2*8+1]*c[8]; + MACRO1(0); + MACRO2(8); + } + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a=(in[2*1+0]-in[2*5+0]-in[2*7+0])*c[3]; + tmp1b=(in[2*1+1]-in[2*5+1]-in[2*7+1])*c[3]; + tmp2a=(in[2*2+0]-in[2*4+0]-in[2*8+0])*c[6]-in[2*6+0]+in[2*0+0]; + tmp2b=(in[2*2+1]-in[2*4+1]-in[2*8+1])*c[6]-in[2*6+1]+in[2*0+1]; + MACRO1(1); + MACRO2(7); + } + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a= in[2*1+0]*c[5]-ta33 -in[2*5+0]*c[7]+in[2*7+0]*c[1]; + tmp1b= in[2*1+1]*c[5]-tb33 -in[2*5+1]*c[7]+in[2*7+1]*c[1]; + tmp2a=in[2*0+0]-in[2*2+0]*c[8]-in[2*4+0]*c[2]+ta66 +in[2*8+0]*c[4]; + tmp2b=in[2*0+1]-in[2*2+1]*c[8]-in[2*4+1]*c[2]+tb66 +in[2*8+1]*c[4]; + MACRO1(2); + MACRO2(6); + } + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a= in[2*1+0]*c[7]-ta33 +in[2*5+0]*c[1]-in[2*7+0]*c[5]; + tmp1b= in[2*1+1]*c[7]-tb33 +in[2*5+1]*c[1]-in[2*7+1]*c[5]; + tmp2a=in[2*0+0]-in[2*2+0]*c[4]+in[2*4+0]*c[8]+ta66 -in[2*8+0]*c[2]; + tmp2b=in[2*0+1]-in[2*2+1]*c[4]+in[2*4+1]*c[8]+tb66 -in[2*8+1]*c[2]; + MACRO1(3); + MACRO2(5); + } + + { + REAL sum0,sum1; + sum0= in[2*0+0]-in[2*2+0]+in[2*4+0]-in[2*6+0]+in[2*8+0]; + sum1=(in[2*0+1]-in[2*2+1]+in[2*4+1]-in[2*6+1]+in[2*8+1])*hsec_36[4]; + MACRO0(4); + } + } + } +} + + +static void dct12(REAL *in,REAL *prevblk1,REAL *prevblk2,register REAL *wi,register REAL *out) +{ +#define DCT12_PART1 \ + in5=in[5*3]; \ + in5+=(in4=in[4*3]); \ + in4+=(in3=in[3*3]); \ + in3+=(in2=in[2*3]); \ + in2+=(in1=in[1*3]); \ + in1+=(in0=in[0*3]); \ + \ + in5+=in3;in3+=in1; \ + \ + in2*=cos1_6; \ + in3*=cos1_6; + +#define DCT12_PART2 \ + in0+=in4*cos2_6; \ + \ + in4=in0+in2; \ + in0-=in2; \ + \ + in1+=in5*cos2_6; \ + \ + in5=(in1+in3)*hsec_12[0]; \ + in1=(in1-in3)*hsec_12[2]; \ + \ + in3=in4+in5; \ + in4-=in5; \ + \ + in2=in0+in1; \ + in0-=in1; + + { + REAL in0,in1,in2,in3,in4,in5; + register REAL *pb1=prevblk1; + out[SBLIMIT*0]=pb1[0];out[SBLIMIT*1]=pb1[1];out[SBLIMIT*2]=pb1[2]; + out[SBLIMIT*3]=pb1[3];out[SBLIMIT*4]=pb1[4];out[SBLIMIT*5]=pb1[5]; + + DCT12_PART1; + + { + REAL tmp0,tmp1=(in0-in4); + { + register REAL tmp2=(in1-in5)*hsec_12[1]; + tmp0=tmp1+tmp2; + tmp1-=tmp2; + } + out[(17-1)*SBLIMIT]=pb1[17-1]+tmp0*wi[11-1]; + out[(12+1)*SBLIMIT]=pb1[12+1]+tmp0*wi[ 6+1]; + out[(6 +1)*SBLIMIT]=pb1[6 +1]+tmp1*wi[ 1 ]; + out[(11-1)*SBLIMIT]=pb1[11-1]+tmp1*wi[ 5-1]; + } + + DCT12_PART2; + out[(17-0)*SBLIMIT]=pb1[17-0]+in2*wi[11-0]; + out[(12+0)*SBLIMIT]=pb1[12+0]+in2*wi[ 6+0]; + out[(12+2)*SBLIMIT]=pb1[12+2]+in3*wi[ 6+2]; + out[(17-2)*SBLIMIT]=pb1[17-2]+in3*wi[11-2]; + + out[( 6+0)*SBLIMIT]=pb1[ 6+0]+in0*wi[0]; + out[(11-0)*SBLIMIT]=pb1[11-0]+in0*wi[5-0]; + out[( 6+2)*SBLIMIT]=pb1[ 6+2]+in4*wi[2]; + out[(11-2)*SBLIMIT]=pb1[11-2]+in4*wi[5-2]; + } + + in++; + { + REAL in0,in1,in2,in3,in4,in5; + register REAL *pb2 = prevblk2; + + DCT12_PART1; + + { + REAL tmp0,tmp1=(in0-in4); + { + REAL tmp2=(in1-in5)*hsec_12[1]; + tmp0=tmp1+tmp2; + tmp1-=tmp2; + } + pb2[5-1]=tmp0*wi[11-1]; + pb2[0+1]=tmp0*wi[6+1]; + out[(12+1)*SBLIMIT]+=tmp1*wi[1]; + out[(17-1)*SBLIMIT]+=tmp1*wi[5-1]; + } + + DCT12_PART2; + + pb2[5-0]=in2*wi[11-0]; + pb2[0+0]=in2*wi[6+0]; + pb2[0+2]=in3*wi[6+2]; + pb2[5-2]=in3*wi[11-2]; + + out[(12+0)*SBLIMIT]+=in0*wi[0]; + out[(17-0)*SBLIMIT]+=in0*wi[5-0]; + out[(12+2)*SBLIMIT]+=in4*wi[2]; + out[(17-2)*SBLIMIT]+=in4*wi[5-2]; + } + + in++; + { + REAL in0,in1,in2,in3,in4,in5; + register REAL *pb2 = prevblk2; + pb2[12]=pb2[13]=pb2[14]=pb2[15]=pb2[16]=pb2[17]=0.0; + + DCT12_PART1; + + { + REAL tmp0,tmp1=(in0-in4); + { + REAL tmp2=(in1-in5)*hsec_12[1]; + tmp0=tmp1+tmp2; + tmp1-=tmp2; + } + pb2[11-1]=tmp0*wi[11-1]; + pb2[ 6+1]=tmp0*wi[6+1]; + pb2[ 0+1]+=tmp1*wi[1]; + pb2[ 5-1]+=tmp1*wi[5-1]; + } + + DCT12_PART2; + pb2[11-0]=in2*wi[11-0]; + pb2[ 6+0]=in2*wi[ 6+0]; + pb2[ 6+2]=in3*wi[ 6+2]; + pb2[11-2]=in3*wi[11-2]; + + pb2[ 0+0]+=in0*wi[0 ]; + pb2[ 5-0]+=in0*wi[5-0]; + pb2[ 0+2]+=in4*wi[2 ]; + pb2[ 5-2]+=in4*wi[5-2]; + } +} + +void MPEGaudio::layer3hybrid(int ch,int gr,REAL in[SBLIMIT][SSLIMIT], + REAL out[SSLIMIT][SBLIMIT]) +{ + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + int bt1,bt2; + REAL *prev1,*prev2; + + prev1=prevblck[ch][currentprevblock][0]; + prev2=prevblck[ch][currentprevblock^1][0]; + + bt1 = gi->mixed_block_flag ? 0 : gi->block_type; + bt2 = gi->block_type; + + { + REAL *ci=(REAL *)in, + *co=(REAL *)out; + int i; + + if(downfrequency)i=(SBLIMIT/2)-2; + else i=SBLIMIT-2; + + if(bt2==2) + { + if(!bt1) + { + dct36(ci,prev1,prev2,win[0],co); + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct36(ci,prev1,prev2,win[0],co); + } + else + { + dct12(ci,prev1,prev2,win[2],co); + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct12(ci,prev1,prev2,win[2],co); + } + + do{ + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct12(ci,prev1,prev2,win[2],co); + }while(--i); + } + else + { + dct36(ci,prev1,prev2,win[bt1],co); + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct36(ci,prev1,prev2,win[bt1],co); + + do + { + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct36(ci,prev1,prev2,win[bt2],co); + }while(--i); + } + } +} + +#define NEG(a) (a)=-(a) + +void MPEGaudio::extractlayer3(void) +{ + if(version) + { + extractlayer3_2(); + return; + } + + { + int main_data_end,flush_main; + int bytes_to_discard; + + layer3getsideinfo(); + + if(issync()) + { + for(register int i=layer3slots;i>0;i--) // read main data. + bitwindow.putbyte(getbyte()); + } + else + { + for(register int i=layer3slots;i>0;i--) // read main data. + bitwindow.putbyte(getbits8()); + } + + main_data_end=bitwindow.gettotalbit()>>3;// of previous frame + if (main_data_end < 0) // Fix from Michael Vogt + { + return; + } + + if((flush_main=(bitwindow.gettotalbit() & 0x7))) + { + bitwindow.forward(8-flush_main); + main_data_end++; + } + + bytes_to_discard=layer3framestart-(main_data_end+sideinfo.main_data_begin); + if(main_data_end>WINDOWSIZE) + { + layer3framestart-=WINDOWSIZE; + bitwindow.rewind(WINDOWSIZE*8); + } + + layer3framestart+=layer3slots; + + bitwindow.wrap(); + + if(bytes_to_discard<0)return; + bitwindow.forward(bytes_to_discard<<3); + } + + for(int gr=0;gr<2;gr++) + { + union + { + int is [SBLIMIT][SSLIMIT]; + REAL hin [2][SBLIMIT][SSLIMIT]; + }b1; + union + { + REAL ro [2][SBLIMIT][SSLIMIT]; + REAL lr [2][SBLIMIT][SSLIMIT]; + REAL hout [2][SSLIMIT][SBLIMIT]; + }b2; + + + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors (LS,gr); + layer3huffmandecode (LS,gr ,b1.is); + layer3dequantizesample(LS,gr,b1.is,b2.ro[LS]); + if(inputstereo) + { + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors (RS,gr); + layer3huffmandecode (RS,gr ,b1.is); + layer3dequantizesample(RS,gr,b1.is,b2.ro[RS]); + } + + layer3fixtostereo(gr,b2.ro); // b2.ro -> b2.lr + + currentprevblock^=1; + layer3reorderandantialias(LS,gr,b2.lr[LS],b1.hin[LS]); + layer3hybrid (LS,gr,b1.hin[LS],b2.hout[LS]); + if(outputstereo) + { + layer3reorderandantialias(RS,gr,b2.lr[RS],b1.hin[RS]); + layer3hybrid (RS,gr,b1.hin[RS],b2.hout[RS]); + + register int i=2*SSLIMIT*SBLIMIT-1; + do{ + NEG(b2.hout[0][0][i ]);NEG(b2.hout[0][0][i- 2]); + NEG(b2.hout[0][0][i- 4]);NEG(b2.hout[0][0][i- 6]); + NEG(b2.hout[0][0][i- 8]);NEG(b2.hout[0][0][i-10]); + NEG(b2.hout[0][0][i-12]);NEG(b2.hout[0][0][i-14]); + NEG(b2.hout[0][0][i-16]);NEG(b2.hout[0][0][i-18]); + NEG(b2.hout[0][0][i-20]);NEG(b2.hout[0][0][i-22]); + NEG(b2.hout[0][0][i-24]);NEG(b2.hout[0][0][i-26]); + NEG(b2.hout[0][0][i-28]);NEG(b2.hout[0][0][i-30]); + }while((i-=2*SBLIMIT)>0); + } + else + { + register int i=SSLIMIT*SBLIMIT-1; + do{ + NEG(b2.hout[0][0][i ]);NEG(b2.hout[0][0][i- 2]); + NEG(b2.hout[0][0][i- 4]);NEG(b2.hout[0][0][i- 6]); + NEG(b2.hout[0][0][i- 8]);NEG(b2.hout[0][0][i-10]); + NEG(b2.hout[0][0][i-12]);NEG(b2.hout[0][0][i-14]); + NEG(b2.hout[0][0][i-16]);NEG(b2.hout[0][0][i-18]); + NEG(b2.hout[0][0][i-20]);NEG(b2.hout[0][0][i-22]); + NEG(b2.hout[0][0][i-24]);NEG(b2.hout[0][0][i-26]); + NEG(b2.hout[0][0][i-28]);NEG(b2.hout[0][0][i-30]); + }while((i-=2*SBLIMIT)>0); + } + + for(int ss=0;ss0;i--) // read main data. + bitwindow.putbyte(getbyte()); + } + else + { + for(register int i=layer3slots;i>0;i--) // read main data. + bitwindow.putbyte(getbits8()); + } + bitwindow.wrap(); + + main_data_end=bitwindow.gettotalbit()>>3;// of previous frame + + if((flush_main=(bitwindow.gettotalbit() & 0x7))) + { + bitwindow.forward(8-flush_main); + main_data_end++; + } + + bytes_to_discard=layer3framestart-main_data_end-sideinfo.main_data_begin; + if(main_data_end>WINDOWSIZE) + { + layer3framestart-=WINDOWSIZE; + bitwindow.rewind(WINDOWSIZE*8); + } + + layer3framestart+=layer3slots; + + if(bytes_to_discard<0) return; + bitwindow.forward(bytes_to_discard<<3); + } + + // for(int gr=0;gr<2;gr++) + { + union + { + int is [SBLIMIT][SSLIMIT]; + REAL hin [2][SBLIMIT][SSLIMIT]; + }b1; + union + { + REAL ro [2][SBLIMIT][SSLIMIT]; + REAL lr [2][SBLIMIT][SSLIMIT]; + REAL hout [2][SSLIMIT][SBLIMIT]; + }b2; + + + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors_2(LS); + layer3huffmandecode (LS,0 ,b1.is); + layer3dequantizesample (LS,0,b1.is,b2.ro[LS]); + if(inputstereo) + { + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors_2(RS); + layer3huffmandecode (RS,0 ,b1.is); + layer3dequantizesample (RS,0,b1.is,b2.ro[RS]); + } + + layer3fixtostereo(0,b2.ro); // b2.ro -> b2.lr + + currentprevblock^=1; + layer3reorderandantialias(LS,0,b2.lr[LS],b1.hin[LS]); + layer3hybrid (LS,0,b1.hin[LS],b2.hout[LS]); + if(outputstereo) + { + layer3reorderandantialias(RS,0,b2.lr[RS],b1.hin[RS]); + layer3hybrid (RS,0,b1.hin[RS],b2.hout[RS]); + + register int i=2*SSLIMIT*SBLIMIT-1; + do{ + NEG(b2.hout[0][0][i-16]);NEG(b2.hout[0][0][i-18]); + NEG(b2.hout[0][0][i-20]);NEG(b2.hout[0][0][i-22]); + NEG(b2.hout[0][0][i-24]);NEG(b2.hout[0][0][i-26]); + NEG(b2.hout[0][0][i-28]);NEG(b2.hout[0][0][i-30]); + }while((i-=2*SBLIMIT)>0); + } + else + { + register int i=SSLIMIT*SBLIMIT-1; + do{ + NEG(b2.hout[0][0][i-16]);NEG(b2.hout[0][0][i-18]); + NEG(b2.hout[0][0][i-20]);NEG(b2.hout[0][0][i-22]); + NEG(b2.hout[0][0][i-24]);NEG(b2.hout[0][0][i-26]); + NEG(b2.hout[0][0][i-28]);NEG(b2.hout[0][0][i-30]); + }while((i-=2*SBLIMIT)>0); + } + + for(int ss=0;ss +#include +#include +#include + +#include "MPEGaudio.h" +#include "MPEGstream.h" +#if defined(_WIN32) +#include +#endif + +#define MY_PI 3.14159265358979323846 + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define _KEY 0 +#else +#define _KEY 3 +#endif + +int MPEGaudio::getbits( int bits ) +{ + union + { + char store[4]; + int current; + } u; + int bi; + + if( ! bits ) + return 0; + + u.current = 0; + bi = (bitindex & 7); + u.store[ _KEY ] = _buffer[ bitindex >> 3 ] << bi; + bi = 8 - bi; + bitindex += bi; + + while( bits ) + { + if( ! bi ) + { + u.store[ _KEY ] = _buffer[ bitindex >> 3 ]; + bitindex += 8; + bi = 8; + } + + if( bits >= bi ) + { + u.current <<= bi; + bits -= bi; + bi = 0; + } + else + { + u.current <<= bits; + bi -= bits; + bits = 0; + } + } + bitindex -= bi; + + return( u.current >> 8 ); +} + + +// Convert mpeg to raw +// Mpeg headder class +void MPEGaudio::initialize() +{ + static bool initialized = false; + + register int i; + register REAL *s1,*s2; + REAL *s3,*s4; + + last_speed = 0; + stereo = true; + forcetomonoflag = false; + forcetostereoflag = false; + swapendianflag = false; + downfrequency = 0; + + scalefactor=SCALE; + calcbufferoffset=15; + currentcalcbuffer=0; + + s1 = calcbufferL[0]; + s2 = calcbufferR[0]; + s3 = calcbufferL[1]; + s4 = calcbufferR[1]; + for(i=CALCBUFFERSIZE-1;i>=0;i--) + { + calcbufferL[0][i]=calcbufferL[1][i]= + calcbufferR[0][i]=calcbufferR[1][i]=0.0; + } + + if( ! initialized ) + { + for(i=0;i<16;i++) hcos_64[i] = (float) + (1.0/(2.0*cos(MY_PI*double(i*2+1)/64.0))); + for(i=0;i< 8;i++) hcos_32[i] = (float) + (1.0/(2.0*cos(MY_PI*double(i*2+1)/32.0))); + for(i=0;i< 4;i++) hcos_16[i] = (float) + (1.0/(2.0*cos(MY_PI*double(i*2+1)/16.0))); + for(i=0;i< 2;i++) hcos_8 [i] = (float) + (1.0/(2.0*cos(MY_PI*double(i*2+1)/ 8.0))); + hcos_4 = (float)(1.0f / (2.0f * cos( MY_PI * 1.0 / 4.0 ))); + initialized = true; + } + + layer3initialize(); + +#ifdef THREADED_AUDIO + decode_thread = NULL; + ring = NULL; +#endif + Rewind(); + ResetSynchro(0); +}; + + +bool MPEGaudio::loadheader() +{ + register int c; + bool flag; + + flag = false; + do + { + if( (c = mpeg->copy_byte()) < 0 ) + break; + + if( c == 0xff ) + { + while( ! flag ) + { + if( (c = mpeg->copy_byte()) < 0 ) + { + flag = true; + break; + } + if( (c & 0xf0) == 0xf0 ) + { + flag = true; + break; + } + else if( c != 0xff ) + { + break; + } + } + } + } while( ! flag ); + + if( c < 0 ) + return false; + + + // Analyzing + + c &= 0xf; + protection = c & 1; + layer = 4 - ((c >> 1) & 3); + version = (_mpegversion) ((c >> 3) ^ 1); + + c = mpeg->copy_byte() >> 1; + padding = (c & 1); + c >>= 1; + frequency = (_frequency) (c&3); + if (frequency == 3) + return false; + c >>= 2; + bitrateindex = (int) c; + if( bitrateindex == 15 ) + return false; + + c = ((unsigned int)mpeg->copy_byte()) >> 4; + extendedmode = c & 3; + mode = (_mode) (c >> 2); + + + // Making information + + inputstereo = (mode == single) ? 0 : 1; + + forcetomonoflag = (!stereo && inputstereo); + forcetostereoflag = (stereo && !inputstereo); + + if(forcetomonoflag) + outputstereo=0; + else + outputstereo=inputstereo; + + channelbitrate=bitrateindex; + if(inputstereo) + { + if(channelbitrate==4) + channelbitrate=1; + else + channelbitrate-=4; + } + + if(channelbitrate==1 || channelbitrate==2) + tableindex=0; + else + tableindex=1; + + if(layer==1) + subbandnumber=MAXSUBBAND; + else + { + if(!tableindex) + if(frequency==frequency32000)subbandnumber=12; else subbandnumber=8; + else if(frequency==frequency48000|| + (channelbitrate>=3 && channelbitrate<=5)) + subbandnumber=27; + else subbandnumber=30; + } + + if(mode==single)stereobound=0; + else if(mode==joint)stereobound=(extendedmode+1)<<2; + else stereobound=subbandnumber; + + if(stereobound>subbandnumber)stereobound=subbandnumber; + + // framesize & slots + if(layer==1) + { + framesize=(12000*bitrate[version][0][bitrateindex])/ + frequencies[version][frequency]; + if(frequency==frequency44100 && padding)framesize++; + framesize<<=2; + } + else + { + framesize=(144000*bitrate[version][layer-1][bitrateindex])/ + (frequencies[version][frequency]<timestamp){ + if (mpeg->timestamp_pos <= _buffer_pos) + last_timestamp = *timestamp = mpeg->timestamp; + } + else + *timestamp = -1; + + if ( layer == 3 ) extractlayer3(); + else if( layer == 2 ) extractlayer2(); + else if( layer == 1 ) extractlayer1(); + + /* Handle swapping data endianness */ + if ( swapendianflag ) { + Sint16 *p; + + p = rawdata+rawdatawriteoffset; + while ( p > rawdata ) { + --p; + *p = SDL_Swap16(*p); + } + } + + /* Handle expanding to stereo output */ + if ( forcetostereoflag ) { + Sint16 *in, *out; + + in = rawdata+rawdatawriteoffset; + rawdatawriteoffset *= 2; + out = rawdata+rawdatawriteoffset; + while ( in > rawdata ) { + --in; + *(--out) = *in; + *(--out) = *in; + } + } + + // Sam 10/5 - If there is no data, don't increment frames + if ( rawdatawriteoffset ) { + ++decodedframe; +#ifndef THREADED_AUDIO + ++currentframe; +#endif + } + } + + return(true); +} + +#ifdef THREADED_AUDIO +int Decode_MPEGaudio(void *udata) +{ + MPEGaudio *audio = (MPEGaudio *)udata; + double timestamp; + +#if defined(_WIN32) + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); +#endif + + audio->force_exit = false; + while ( audio->decoding && ! audio->mpeg->eof() && !audio->force_exit ) { + audio->rawdata = (Sint16 *)audio->ring->NextWriteBuffer(); + + if ( audio->rawdata ) { + audio->rawdatawriteoffset = 0; + /* Sam 10/5/2000 - Added while to prevent empty buffer in ring */ + while ( audio->run(1, ×tamp) && + (audio->rawdatawriteoffset == 0) ) { + /* Keep looping */ ; + } + if((Uint32)audio->rawdatawriteoffset*2 <= audio->ring->BufferSize()) + audio->ring->WriteDone(audio->rawdatawriteoffset*2, timestamp); + } + } + + audio->decoding = false; + return(0); +} +#endif /* THREADED_AUDIO */ + +// Helper function for SDL audio +int Play_MPEGaudio(MPEGaudio *audio, Uint8 *stream, int len) +{ + int volume; + long copylen; + int mixed = 0; + + /* Michel Darricau from eProcess conflict name in popcorn */ + /* Bail if audio isn't playing */ + if ( audio->GetStatus() != MPEG_PLAYING ) { + return(0); + } + volume = audio->volume; + + /* Increment the current play time (assuming fixed frag size) */ + switch (audio->frags_playing++) { + // Vivien: Well... the theorical way seems good to me :-) + case 0: /* The first audio buffer is being filled */ + break; + case 1: /* The first audio buffer is starting playback */ + audio->frag_time = SDL_GetTicks(); + break; + default: /* A buffer has completed, filling a new one */ + audio->frag_time = SDL_GetTicks(); + audio->play_time += ((double)len)/audio->rate_in_s; + break; + } + + /* Copy the audio data to output */ +#ifdef THREADED_AUDIO + Uint8 *rbuf; + assert(audio); + assert(audio->ring); + do { + /* this is empirical, I don't realy know how to find out when + a certain piece of audio has finished playing or even if + the timestamps refer to the time when the frame starts + playing or then the frame ends playing, but as is works + quite right */ + copylen = audio->ring->NextReadBuffer(&rbuf); + if ( copylen > len ) { + SDL_MixAudio(stream, rbuf, len, volume); + mixed += len; + audio->ring->ReadSome(len); + len = 0; + for (int i=0; i < N_TIMESTAMPS -1; i++) + audio->timestamp[i] = audio->timestamp[i+1]; + audio->timestamp[N_TIMESTAMPS-1] = audio->ring->ReadTimeStamp(); + } else { + SDL_MixAudio(stream, rbuf, copylen, volume); + mixed += copylen; + ++audio->currentframe; + audio->ring->ReadDone(); +//fprintf(stderr, "-"); + len -= copylen; + stream += copylen; + } + if (audio->timestamp[0] != -1){ + double timeshift = audio->Time() - audio->timestamp[0]; + double correction = 0; + assert(audio->timestamp >= 0); + if (fabs(timeshift) > 1.0){ + correction = -timeshift; +#ifdef DEBUG_TIMESTAMP_SYNC + fprintf(stderr, "audio jump %f\n", timeshift); +#endif + } else + correction = -timeshift/100; +#ifdef USE_TIMESTAMP_SYNC + audio->play_time += correction; +#endif +#ifdef DEBUG_TIMESTAMP_SYNC + fprintf(stderr, "\raudio: time:%8.3f shift:%8.4f", + audio->Time(), timeshift); +#endif + audio->timestamp[0] = -1; + } + } while ( copylen && (len > 0) && ((audio->currentframe < audio->decodedframe) || audio->decoding) + && !audio->force_exit ); + +#else + /* The length is interpreted as being in samples */ + len /= 2; + + /* Copy in any saved data */ + if ( audio->rawdatawriteoffset >= audio->rawdatareadoffset) { + copylen = (audio->rawdatawriteoffset-audio->rawdatareadoffset); + assert(copylen >= 0); + if ( copylen >= len ) { + SDL_MixAudio(stream, (Uint8 *)&audio->spillover[audio->rawdatareadoffset], + len*2, volume); + mixed += len*2; + audio->rawdatareadoffset += len; + goto finished_mixing; + } + SDL_MixAudio(stream, (Uint8 *)&audio->spillover[audio->rawdatareadoffset], + copylen*2, volume); + mixed += copylen*2; + len -= copylen; + stream += copylen*2; + } + + /* Copy in any new data */ + audio->rawdata = (Sint16 *)stream; + audio->rawdatawriteoffset = 0; + audio->run(len/audio->samplesperframe); + mixed += audio->rawdatawriteoffset*2; + len -= audio->rawdatawriteoffset; + stream += audio->rawdatawriteoffset*2; + + /* Write a save buffer for remainder */ + audio->rawdata = audio->spillover; + audio->rawdatawriteoffset = 0; + if ( audio->run(1) ) { + assert(audio->rawdatawriteoffset > len); + SDL_MixAudio(stream, (Uint8 *) audio->spillover, len*2, volume); + mixed += len*2; + audio->rawdatareadoffset = len; + } else { + audio->rawdatareadoffset = 0; + } +finished_mixing: +#endif + return(mixed); +} +void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len) +{ + MPEGaudio *audio = (MPEGaudio *)udata; + Play_MPEGaudio(audio, stream, len); +} + +// EOF diff --git a/smpeg/src/video/COPYRIGHT b/smpeg/src/video/COPYRIGHT new file mode 100644 index 0000000..04fdb6e --- /dev/null +++ b/smpeg/src/video/COPYRIGHT @@ -0,0 +1,20 @@ +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ diff --git a/smpeg/src/video/MPEGvideo.cpp b/smpeg/src/video/MPEGvideo.cpp new file mode 100644 index 0000000..c015d89 --- /dev/null +++ b/smpeg/src/video/MPEGvideo.cpp @@ -0,0 +1,609 @@ +/* + SMPEG - SDL MPEG Player Library + Copyright (C) 1999 Loki Entertainment Software + + - Modified by Michel Darricau from eProcess for popcorn - + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + + +/* + Changes to make the code reentrant: + Got rid of setjmp, longjmp + deglobalized: EOF_flag, FilmState, curVidStream, bitOffset, bitLength, + bitBuffer, sys_layer, input, seekValue, window, X Windows globals (to + xinfo), curBits, ditherType, matched_depth, totNumFrames, realTimeStart + + Additional changes: + Ability to play >1 movie (w/out CONTROLS) + Make sure we do a full frame for each movie + DISABLE_DITHER #ifdef to avoid compiling dithering code + Changes to deal with non-MPEG streams + Now deals with NO_DITHER, PPM_DITHER and noDisplayFlag==1 + CONTROLS version now can deal with >1 movie + -lsh@cs.brown.edu (Loring Holden) +*/ + + +#include +#include + +#include "video.h" +#include "proto.h" +#include "dither.h" +#include "util.h" + +#include "MPEGvideo.h" +#include "MPEGfilter.h" + +/*--------------------------------------------------------------*/ + + +/* Define buffer length. */ +#define BUF_LENGTH 80000 + + +/* TODO: Eliminate these globals so multiple movies can be played. */ + +/* Quiet flag (verbose). */ +int quietFlag = 1; + +/* Framerate, -1: specified in stream (default) + 0: as fast as possible + N (N>0): N frames/sec + */ +#ifdef TIME_MPEG +int framerate = 0; +#else +int framerate = -1; +#endif + +/* Flag for high quality at the expense of speed */ +#ifdef QUALITY +int qualityFlag = 1; +#else +int qualityFlag = 0; +#endif + +/*--------------------------------------------------------------*/ + +MPEGvideo::MPEGvideo(MPEGstream *stream) +{ + Uint32 start_code; + MPEGstream_marker *marker; + + /* Set the MPEG data stream */ + mpeg = stream; + time_source = NULL; + + /* Set default playback variables */ + _thread = NULL; + _dst = NULL; + _mutex = NULL; + _stream = NULL; + + /* Mark the data to leave the stream unchanged */ + /* after parsing */ + marker = mpeg->new_marker(0); + + /* Get the width and height of the video */ + start_code = mpeg->copy_byte(); + start_code <<= 8; + start_code |= mpeg->copy_byte(); + start_code <<= 8; + start_code |= mpeg->copy_byte(); + while ( ! mpeg->eof() && (start_code != SEQ_START_CODE) ) { + start_code <<= 8; + start_code |= mpeg->copy_byte(); + } + if ( start_code == SEQ_START_CODE ) { + Uint8 buf[4]; + + /* Get the width and height of the video */ + mpeg->copy_data(buf, 4); + _w = (buf[0]<<4)|(buf[1]>>4); /* 12 bits of width */ + _h = ((buf[1]&0xF)<<8)|buf[2]; /* 12 bits of height */ + switch(buf[3]&0xF) /* 4 bits of fps */ + { + case 1: _fps = 23.97f; break; + case 2: _fps = 24.00f; break; + case 3: _fps = 25.00f; break; + case 4: _fps = 29.97f; break; + case 5: _fps = 30.00f; break; + case 6: _fps = 50.00f; break; + case 7: _fps = 59.94f; break; + case 8: _fps = 60.00f; break; + case 9: _fps = 15.00f; break; + default: _fps = 30.00f; break; + } + } else { + _w = 0; + _h = 0; + _fps = 0.00; + SetError("Not a valid MPEG video stream"); + } + /* Rewind back to the old position */ + mpeg->seek_marker(marker); + mpeg->delete_marker(marker); + + /* Keep original width and height in _ow and _oh */ + _ow = _w; + _oh = _h; + + /* Now round up width and height to a multiple */ + /* of a macroblock size (16 pixels) to keep the */ + /* video decoder happy */ + _w = (_w + 15) & ~15; + _h = (_h + 15) & ~15; + + /* Set the default playback area */ + _dstrect.x = 0; + _dstrect.y = 0; + _dstrect.w = 0; + _dstrect.h = 0; + + /* Set the source area */ + _srcrect.x = 0; + _srcrect.y = 0; + _srcrect.w = _ow; + _srcrect.h = _oh; + + _image = 0; + _filter = SMPEGfilter_null(); + _filter_mutex = SDL_CreateMutex(); +// printf("[MPEGvideo::MPEGvideo]_filter_mutex[%lx] = SDL_CreateMutex()\n",_filter_mutex); +} + +MPEGvideo:: ~MPEGvideo() +{ + /* Stop it before we free everything */ + Stop(); + + /* Free actual video stream */ + if( _stream ) + DestroyVidStream( _stream ); + + /* Free overlay */ + if(_image) SDL_FreeYUVOverlay(_image); + + /* Release filter */ + SDL_DestroyMutex(_filter_mutex); + _filter->destroy(_filter); +} + +/* Simple thread play function */ +int Play_MPEGvideo( void *udata ) +{ + MPEGvideo *mpeg = (MPEGvideo *)udata; + + /* Get the time the playback started */ + mpeg->_stream->realTimeStart += ReadSysClock(); + +#ifdef TIME_MPEG + int start_frames, stop_frames; + int total_frames; + Uint32 start_time, stop_time; + float total_time; + + start_frames = mpeg->_stream->totNumFrames; + start_time = SDL_GetTicks(); +#endif + mpeg->force_exit = false; + while( mpeg->playing && !mpeg->force_exit ) + { + int mark = mpeg->_stream->totNumFrames; + + /* make sure we do a whole frame */ + while( (mark == mpeg->_stream->totNumFrames) && mpeg->playing && !mpeg->force_exit ) + { + mpegVidRsrc( 0, mpeg->_stream, 0 ); + } + + if( mpeg->_stream->film_has_ended || mpeg->force_exit ) + { + mpeg->playing = false; + } + } + /* Get the time the playback stopped */ + mpeg->_stream->realTimeStart -= ReadSysClock(); +#ifdef TIME_MPEG + stop_time = SDL_GetTicks(); + stop_frames = mpeg->_stream->totNumFrames; + total_frames = (stop_frames-start_frames); + total_time = (float)(stop_time-start_time)/1000.0; + if ( total_time > 0 ) { + printf("%d frames in %2.2f seconds (%2.2f FPS)\n", + total_frames, total_time, (float)total_frames/total_time); + } +#endif + return(0); +} + +void +MPEGvideo:: Play(void) +{ + ResetPause(); + if ( _stream ) { + if ( playing ) { + Stop(); + } + playing = true; +#ifdef DISABLE_VIDEO_CALLBACK_THREAD + Play_MPEGvideo(this); +#else + _thread = SDL_CreateThread( Play_MPEGvideo, this ); + if ( !_thread ) { + playing = false; + } +#endif + } +} + +void +MPEGvideo:: Stop(void) +{ + if ( _thread ) { + force_exit = true; + SDL_WaitThread(_thread, NULL); + _thread = NULL; + } + + playing = false; + + ResetPause(); +} + +void +MPEGvideo:: Rewind(void) +{ + Stop(); + if ( _stream ) { + /* Reinitialize vid_stream pointers */ + ResetVidStream( _stream ); +#ifdef ANALYSIS + init_stats(); +#endif + } +} + +void +MPEGvideo:: ResetSynchro(double time) +{ + if( _stream ) + { + _stream->_jumpFrame = -1; + _stream->realTimeStart = -time; + play_time = time; + if (time > 0) { + double oneframetime; + if (_stream->_oneFrameTime == 0) + oneframetime = 1.0 / _stream->_smpeg->_fps; + else + oneframetime = _stream->_oneFrameTime; + + /* time -> frame */ + _stream->totNumFrames = (int)(time / oneframetime); + + /* Set Current Frame To 0 & Frame Adjust Frag Set */ + _stream->current_frame = 0; + _stream->need_frameadjust=true; + } + } +} + + +void +MPEGvideo::Skip(float seconds) +{ + int frame; + + /* Called only when there is no timestamp info in the MPEG */ + /* This is quite slow however */ + printf("Video: Skipping %f seconds...\n", seconds); + frame = (int) (_fps * seconds); + + if( _stream ) + { + _stream->_jumpFrame = frame; + while( (_stream->totNumFrames < frame) && + ! _stream->film_has_ended ) + { + mpegVidRsrc( 0, _stream, 0 ); + } + ResetSynchro(0); + } +} + + /* Michel Darricau from eProcess conflict name in popcorn */ +MPEGstatus +MPEGvideo:: GetStatus(void) +{ + if ( _stream ) { + if( !_thread || (_stream->film_has_ended ) ) { + return MPEG_STOPPED; + } else { + return MPEG_PLAYING; + } + } + return MPEG_ERROR; +} + +bool +MPEGvideo:: GetVideoInfo(MPEG_VideoInfo *info) +{ + if ( info ) { + info->width = _ow; + info->height = _oh; + if ( _stream ) { + info->current_frame = _stream->current_frame; +#ifdef CALCULATE_FPS + + /* Get the appropriate indices for the timestamps */ + /* Calculate the frames-per-second from the timestamps */ + if ( _stream->frame_time[_stream->timestamp_index] ) { + double *timestamps; + double time_diff; + int this_index; + int last_index; + + timestamps = _stream->frame_time; + last_index = _stream->timestamp_index; + this_index = last_index - 1; + if ( this_index < 0 ) { + this_index = FPS_WINDOW-1; + } + time_diff = timestamps[this_index] - timestamps[last_index]; + info->current_fps = (double)FPS_WINDOW / time_diff; + } else { + info->current_fps = 0.0; + } +#else + info->current_fps = _stream->totNumFrames / + (ReadSysClock() - _stream->realTimeStart); +#endif + } else { + info->current_frame = 0; + info->current_fps = 0.0; + } + } + return(!WasError()); +} + +/* + Returns zero if fails. + + surf - Surface to play movie on. + lock - lock is held while MPEG stream is playing + callback - called on every frame, for display update +*/ +bool +MPEGvideo:: SetDisplay(SDL_Surface *dst, SDL_mutex *lock, + MPEG_DisplayCallback callback) +{ + _mutex = lock; + _dst = dst; + _callback = callback; + if ( _image ) { + SDL_FreeYUVOverlay(_image); + } + _image = SDL_CreateYUVOverlay(_srcrect.w, _srcrect.h, SDL_YV12_OVERLAY, dst); + if ( _image == NULL ) { + return false; + } + + if ( !_dstrect.w || !_dstrect.h ) { + _dstrect.w = dst->w; + _dstrect.h = dst->h; + } + + if ( !_stream ) { + decodeInitTables(); + + InitCrop(); + InitIDCT(); + + _stream = NewVidStream( (unsigned int) BUF_LENGTH ); + if( _stream ) { + _stream->_smpeg = this; + _stream->ditherType = FULL_COLOR_DITHER; + _stream->matched_depth = dst->format->BitsPerPixel; + + if( mpegVidRsrc( 0, _stream, 1 ) == NULL ) { + SetError("Not an MPEG video stream"); + return false; + } + } + + if ( ! InitPictImages(_stream, _w, _h, _dst) ) + return false; + } + return true; +} + + +/* If this is being called during play, the calling program is responsible + for clearing the old area and coordinating with the update callback. +*/ +void +MPEGvideo:: MoveDisplay( int x, int y ) +{ + SDL_mutexP( _mutex ); + _dstrect.x = x; + _dstrect.y = y; + SDL_mutexV( _mutex ); +} + +void +MPEGvideo:: ScaleDisplayXY( int w, int h ) +{ + SDL_mutexP( _mutex ); + _dstrect.w = w; + _dstrect.h = h; + SDL_mutexV( _mutex ); +} + +void +MPEGvideo:: SetDisplayRegion(int x, int y, int w, int h) +{ + SDL_mutexP( _mutex ); + _srcrect.x = x; + _srcrect.y = y; + _srcrect.w = w; + _srcrect.h = h; + + if(_image) + { + SDL_FreeYUVOverlay(_image); + _image = SDL_CreateYUVOverlay(_srcrect.w, _srcrect.h, SDL_YV12_OVERLAY, _dst); + /* !!! FIXME: Uhh...what if this one fails? */ + } + + SDL_mutexV( _mutex ); +} + +/* API CHANGE: This function no longer takes a destination surface and x/y + You must use SetDisplay() and MoveDisplay() to set those attributes. +*/ +void +MPEGvideo:: RenderFrame( int frame ) +{ + _stream->need_frameadjust = true; + + if( _stream->current_frame > frame ) { + mpeg->rewind_stream(); + mpeg->next_packet(); + Rewind(); + } + + _stream->_jumpFrame = frame; + + while( (_stream->current_frame < frame) && + ! _stream->film_has_ended ) + { + mpegVidRsrc( 0, _stream, 0 ); + } + + _stream->_jumpFrame = -1; +} + +void +MPEGvideo:: RenderFinal(SDL_Surface *dst, int x, int y) +{ + SDL_Surface *saved_dst; + int saved_x, saved_y; + + /* This operation can only be performed when stopped */ + Stop(); + + /* Set (and save) the destination and location */ + saved_dst = _dst; + saved_x = _dstrect.x; + saved_y = _dstrect.y; + SetDisplay(dst, _mutex, _callback); + MoveDisplay(x, y); + + if ( ! _stream->film_has_ended ) { + /* Search for the last "group of pictures" start code */ + Uint32 start_code; + MPEGstream_marker * marker, * oldmarker; + + marker = 0; + start_code = mpeg->copy_byte(); + start_code <<= 8; + start_code |= mpeg->copy_byte(); + start_code <<= 8; + start_code |= mpeg->copy_byte(); + + while ( ! mpeg->eof() ) { + start_code <<= 8; + start_code |= mpeg->copy_byte(); + if ( start_code == GOP_START_CODE ) { + oldmarker = marker; + marker = mpeg->new_marker(-4); + if( oldmarker ) mpeg->delete_marker( oldmarker ); + mpeg->garbage_collect(); + } + } + + /* Set the stream to the last spot marked */ + if ( ! mpeg->seek_marker( marker ) ) { + mpeg->rewind_stream(); + mpeg->next_packet(); + } + + mpeg->delete_marker( marker ); + _stream->buf_length = 0; + _stream->bit_offset = 0; + + /* Process all frames without displaying any */ + _stream->_skipFrame = 1; + + RenderFrame( INT_MAX ); + + mpeg->garbage_collect(); + } + + /* Display the frame */ + DisplayFrame(_stream); + + /* Restore the destination and location */ + SetDisplay(saved_dst, _mutex, _callback); + MoveDisplay(saved_x, saved_y); +} + +/* EOF */ diff --git a/smpeg/src/video/README b/smpeg/src/video/README new file mode 100644 index 0000000..93b95e5 --- /dev/null +++ b/smpeg/src/video/README @@ -0,0 +1,4 @@ + +This code is based on mpeg_play, available from: + http://bmrc.berkeley.edu/frame/research/mpeg/ + diff --git a/smpeg/src/video/decoders.cpp b/smpeg/src/video/decoders.cpp new file mode 100644 index 0000000..6c00f7c --- /dev/null +++ b/smpeg/src/video/decoders.cpp @@ -0,0 +1,1004 @@ +/* + * decoders.c + * + * This file contains all the routines for Huffman decoding required in + * MPEG + * + */ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include +#include +#include "decoders.h" +#include "util.h" +#include "video.h" +#include "proto.h" + +/* + Changes to make the code reentrant: + curVidStream now not global - DecodeDCT* functioned #ifdef'd out + (are they needed?) + Additional changes: + none + -lsh@cs.brown.edu (Loring Holden) + */ + +/* Decoding table for macroblock_address_increment */ +mb_addr_inc_entry mb_addr_inc[2048]; + +/* Decoding table for macroblock_type in predictive-coded pictures */ +mb_type_entry mb_type_P[64]; + +/* Decoding table for macroblock_type in bidirectionally-coded pictures */ +mb_type_entry mb_type_B[64]; + +/* Decoding table for motion vectors */ +motion_vectors_entry motion_vectors[2048]; + +/* Decoding table for coded_block_pattern */ + +const coded_block_pattern_entry coded_block_pattern[512] = +{ {(unsigned int)ERROR, 0}, {(unsigned int)ERROR, 0}, {39, 9}, {27, 9}, {59, 9}, {55, 9}, {47, 9}, {31, 9}, + {58, 8}, {58, 8}, {54, 8}, {54, 8}, {46, 8}, {46, 8}, {30, 8}, {30, 8}, + {57, 8}, {57, 8}, {53, 8}, {53, 8}, {45, 8}, {45, 8}, {29, 8}, {29, 8}, + {38, 8}, {38, 8}, {26, 8}, {26, 8}, {37, 8}, {37, 8}, {25, 8}, {25, 8}, + {43, 8}, {43, 8}, {23, 8}, {23, 8}, {51, 8}, {51, 8}, {15, 8}, {15, 8}, + {42, 8}, {42, 8}, {22, 8}, {22, 8}, {50, 8}, {50, 8}, {14, 8}, {14, 8}, + {41, 8}, {41, 8}, {21, 8}, {21, 8}, {49, 8}, {49, 8}, {13, 8}, {13, 8}, + {35, 8}, {35, 8}, {19, 8}, {19, 8}, {11, 8}, {11, 8}, {7, 8}, {7, 8}, + {34, 7}, {34, 7}, {34, 7}, {34, 7}, {18, 7}, {18, 7}, {18, 7}, {18, 7}, + {10, 7}, {10, 7}, {10, 7}, {10, 7}, {6, 7}, {6, 7}, {6, 7}, {6, 7}, + {33, 7}, {33, 7}, {33, 7}, {33, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {9, 7}, {9, 7}, {9, 7}, {9, 7}, {5, 7}, {5, 7}, {5, 7}, {5, 7}, + {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, + {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, + {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, + {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, + {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, + {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, + {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, + {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, + {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, + {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, + {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, + {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, + {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, + {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, + {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, + {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, + {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, + {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, + {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, + {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, + {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, + {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, + {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, + {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, + {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, + {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, + {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3} +}; + +/* Decoding tables for dct_dc_size_luminance */ +const dct_dc_size_entry dct_dc_size_luminance[32] = +{ {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}, {(unsigned int)ERROR, 0} +}; + +const dct_dc_size_entry dct_dc_size_luminance1[16] = +{ {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, + {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} +}; + +/* Decoding table for dct_dc_size_chrominance */ +const dct_dc_size_entry dct_dc_size_chrominance[32] = +{ {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}, {(unsigned int)ERROR, 0} +}; + +const dct_dc_size_entry dct_dc_size_chrominance1[32] = +{ {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, + {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, + {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, + {8, 8}, {8, 8}, {8, 8}, {8, 8}, {9, 9}, {9, 9}, {10, 10}, {11, 10} +}; + +/* DCT coeff tables. */ + +const unsigned short int dct_coeff_tbl_0[256] = +{ +0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, +0x052f, 0x051f, 0x050f, 0x04ff, +0x183f, 0x402f, 0x3c2f, 0x382f, +0x342f, 0x302f, 0x2c2f, 0x7c1f, +0x781f, 0x741f, 0x701f, 0x6c1f, +0x028e, 0x028e, 0x027e, 0x027e, +0x026e, 0x026e, 0x025e, 0x025e, +0x024e, 0x024e, 0x023e, 0x023e, +0x022e, 0x022e, 0x021e, 0x021e, +0x020e, 0x020e, 0x04ee, 0x04ee, +0x04de, 0x04de, 0x04ce, 0x04ce, +0x04be, 0x04be, 0x04ae, 0x04ae, +0x049e, 0x049e, 0x048e, 0x048e, +0x01fd, 0x01fd, 0x01fd, 0x01fd, +0x01ed, 0x01ed, 0x01ed, 0x01ed, +0x01dd, 0x01dd, 0x01dd, 0x01dd, +0x01cd, 0x01cd, 0x01cd, 0x01cd, +0x01bd, 0x01bd, 0x01bd, 0x01bd, +0x01ad, 0x01ad, 0x01ad, 0x01ad, +0x019d, 0x019d, 0x019d, 0x019d, +0x018d, 0x018d, 0x018d, 0x018d, +0x017d, 0x017d, 0x017d, 0x017d, +0x016d, 0x016d, 0x016d, 0x016d, +0x015d, 0x015d, 0x015d, 0x015d, +0x014d, 0x014d, 0x014d, 0x014d, +0x013d, 0x013d, 0x013d, 0x013d, +0x012d, 0x012d, 0x012d, 0x012d, +0x011d, 0x011d, 0x011d, 0x011d, +0x010d, 0x010d, 0x010d, 0x010d, +0x282c, 0x282c, 0x282c, 0x282c, +0x282c, 0x282c, 0x282c, 0x282c, +0x242c, 0x242c, 0x242c, 0x242c, +0x242c, 0x242c, 0x242c, 0x242c, +0x143c, 0x143c, 0x143c, 0x143c, +0x143c, 0x143c, 0x143c, 0x143c, +0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, +0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, +0x085c, 0x085c, 0x085c, 0x085c, +0x085c, 0x085c, 0x085c, 0x085c, +0x047c, 0x047c, 0x047c, 0x047c, +0x047c, 0x047c, 0x047c, 0x047c, +0x046c, 0x046c, 0x046c, 0x046c, +0x046c, 0x046c, 0x046c, 0x046c, +0x00fc, 0x00fc, 0x00fc, 0x00fc, +0x00fc, 0x00fc, 0x00fc, 0x00fc, +0x00ec, 0x00ec, 0x00ec, 0x00ec, +0x00ec, 0x00ec, 0x00ec, 0x00ec, +0x00dc, 0x00dc, 0x00dc, 0x00dc, +0x00dc, 0x00dc, 0x00dc, 0x00dc, +0x00cc, 0x00cc, 0x00cc, 0x00cc, +0x00cc, 0x00cc, 0x00cc, 0x00cc, +0x681c, 0x681c, 0x681c, 0x681c, +0x681c, 0x681c, 0x681c, 0x681c, +0x641c, 0x641c, 0x641c, 0x641c, +0x641c, 0x641c, 0x641c, 0x641c, +0x601c, 0x601c, 0x601c, 0x601c, +0x601c, 0x601c, 0x601c, 0x601c, +0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, +0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, +0x581c, 0x581c, 0x581c, 0x581c, +0x581c, 0x581c, 0x581c, 0x581c, +}; + +const unsigned short int dct_coeff_tbl_1[16] = +{ +0x00bb, 0x202b, 0x103b, 0x00ab, +0x084b, 0x1c2b, 0x541b, 0x501b, +0x009b, 0x4c1b, 0x481b, 0x045b, +0x0c3b, 0x008b, 0x182b, 0x441b, +}; + +const unsigned short int dct_coeff_tbl_2[4] = +{ +0x4019, 0x1429, 0x0079, 0x0839, +}; + +const unsigned short int dct_coeff_tbl_3[4] = +{ +0x0449, 0x3c19, 0x3819, 0x1029, +}; + +const unsigned short int dct_coeff_next[256] = +{ +0xffff, 0xffff, 0xffff, 0xffff, +0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, +0x0826, 0x0826, 0x2416, 0x2416, +0x0046, 0x0046, 0x2016, 0x2016, +0x1c15, 0x1c15, 0x1c15, 0x1c15, +0x1815, 0x1815, 0x1815, 0x1815, +0x0425, 0x0425, 0x0425, 0x0425, +0x1415, 0x1415, 0x1415, 0x1415, +0x3417, 0x0067, 0x3017, 0x2c17, +0x0c27, 0x0437, 0x0057, 0x2817, +0x0034, 0x0034, 0x0034, 0x0034, +0x0034, 0x0034, 0x0034, 0x0034, +0x1014, 0x1014, 0x1014, 0x1014, +0x1014, 0x1014, 0x1014, 0x1014, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +}; + +const unsigned short int dct_coeff_first[256] = +{ +0xffff, 0xffff, 0xffff, 0xffff, +0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, +0x0826, 0x0826, 0x2416, 0x2416, +0x0046, 0x0046, 0x2016, 0x2016, +0x1c15, 0x1c15, 0x1c15, 0x1c15, +0x1815, 0x1815, 0x1815, 0x1815, +0x0425, 0x0425, 0x0425, 0x0425, +0x1415, 0x1415, 0x1415, 0x1415, +0x3417, 0x0067, 0x3017, 0x2c17, +0x0c27, 0x0437, 0x0057, 0x2817, +0x0034, 0x0034, 0x0034, 0x0034, +0x0034, 0x0034, 0x0034, 0x0034, +0x1014, 0x1014, 0x1014, 0x1014, +0x1014, 0x1014, 0x1014, 0x1014, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +}; + +/* Macro for filling up the decoding table for mb_addr_inc */ +#define ASSIGN1(start, end, step, val, num) \ + for (i = start; i < end; i+= step) { \ + for (j = 0; j < step; j++) { \ + mb_addr_inc[i+j].value = val; \ + mb_addr_inc[i+j].num_bits = num; \ + } \ + val--; \ + } + + + +/* + *-------------------------------------------------------------- + * + * init_mb_addr_inc -- + * + * Initialize the VLC decoding table for macro_block_address_increment + * + * Results: + * The decoding table for macro_block_address_increment will + * be filled; illegal values will be filled as ERROR. + * + * Side effects: + * The global array mb_addr_inc will be filled. + * + *-------------------------------------------------------------- + */ +static void +init_mb_addr_inc() +{ + int i, j, val; + + for (i = 0; i < 8; i++) { + mb_addr_inc[i].value = ERROR; + mb_addr_inc[i].num_bits = 0; + } + + mb_addr_inc[8].value = MACRO_BLOCK_ESCAPE; + mb_addr_inc[8].num_bits = 11; + + for (i = 9; i < 15; i++) { + mb_addr_inc[i].value = ERROR; + mb_addr_inc[i].num_bits = 0; + } + + mb_addr_inc[15].value = MACRO_BLOCK_STUFFING; + mb_addr_inc[15].num_bits = 11; + + for (i = 16; i < 24; i++) { + mb_addr_inc[i].value = ERROR; + mb_addr_inc[i].num_bits = 0; + } + + val = 33; + + ASSIGN1(24, 36, 1, val, 11); + ASSIGN1(36, 48, 2, val, 10); + ASSIGN1(48, 96, 8, val, 8); + ASSIGN1(96, 128, 16, val, 7); + ASSIGN1(128, 256, 64, val, 5); + ASSIGN1(256, 512, 128, val, 4); + ASSIGN1(512, 1024, 256, val, 3); + ASSIGN1(1024, 2048, 1024, val, 1); +} + + +/* Macro for filling up the decoding table for mb_type */ +#define ASSIGN2(start, end, quant, motion_forward, motion_backward, pattern, intra, num, mb_type) \ + for (i = start; i < end; i ++) { \ + mb_type[i].mb_quant = quant; \ + mb_type[i].mb_motion_forward = motion_forward; \ + mb_type[i].mb_motion_backward = motion_backward; \ + mb_type[i].mb_pattern = pattern; \ + mb_type[i].mb_intra = intra; \ + mb_type[i].num_bits = num; \ + } + + + +/* + *-------------------------------------------------------------- + * + * init_mb_type_P -- + * + * Initialize the VLC decoding table for macro_block_type in + * predictive-coded pictures. + * + * Results: + * The decoding table for macro_block_type in predictive-coded + * pictures will be filled; illegal values will be filled as ERROR. + * + * Side effects: + * The global array mb_type_P will be filled. + * + *-------------------------------------------------------------- + */ +static void +init_mb_type_P() +{ + int i; + + mb_type_P[0].mb_quant = mb_type_P[0].mb_motion_forward + = mb_type_P[0].mb_motion_backward = mb_type_P[0].mb_pattern + = mb_type_P[0].mb_intra = ERROR; + mb_type_P[0].num_bits = 0; + + ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_P) + ASSIGN2(2, 4, 1, 0, 0, 1, 0, 5, mb_type_P) + ASSIGN2(4, 6, 1, 1, 0, 1, 0, 5, mb_type_P); + ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_P); + ASSIGN2(8, 16, 0, 1, 0, 0, 0, 3, mb_type_P); + ASSIGN2(16, 32, 0, 0, 0, 1, 0, 2, mb_type_P); + ASSIGN2(32, 64, 0, 1, 0, 1, 0, 1, mb_type_P); +} + + + + +/* + *-------------------------------------------------------------- + * + * init_mb_type_B -- + * + * Initialize the VLC decoding table for macro_block_type in + * bidirectionally-coded pictures. + * + * Results: + * The decoding table for macro_block_type in bidirectionally-coded + * pictures will be filled; illegal values will be filled as ERROR. + * + * Side effects: + * The global array mb_type_B will be filled. + * + *-------------------------------------------------------------- + */ +static void +init_mb_type_B() +{ + int i; + + mb_type_B[0].mb_quant = mb_type_B[0].mb_motion_forward + = mb_type_B[0].mb_motion_backward = mb_type_B[0].mb_pattern + = mb_type_B[0].mb_intra = ERROR; + mb_type_B[0].num_bits = 0; + + ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_B); + ASSIGN2(2, 3, 1, 0, 1, 1, 0, 6, mb_type_B); + ASSIGN2(3, 4, 1, 1, 0, 1, 0, 6, mb_type_B); + ASSIGN2(4, 6, 1, 1, 1, 1, 0, 5, mb_type_B); + ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_B); + ASSIGN2(8, 12, 0, 1, 0, 0, 0, 4, mb_type_B); + ASSIGN2(12, 16, 0, 1, 0, 1, 0, 4, mb_type_B); + ASSIGN2(16, 24, 0, 0, 1, 0, 0, 3, mb_type_B); + ASSIGN2(24, 32, 0, 0, 1, 1, 0, 3, mb_type_B); + ASSIGN2(32, 48, 0, 1, 1, 0, 0, 2, mb_type_B); + ASSIGN2(48, 64, 0, 1, 1, 1, 0, 2, mb_type_B); +} + + +/* Macro for filling up the decoding tables for motion_vectors */ +#define ASSIGN3(start, end, step, val, num) \ + for (i = start; i < end; i+= step) { \ + for (j = 0; j < step / 2; j++) { \ + motion_vectors[i+j].code = val; \ + motion_vectors[i+j].num_bits = num; \ + } \ + for (j = step / 2; j < step; j++) { \ + motion_vectors[i+j].code = -val; \ + motion_vectors[i+j].num_bits = num; \ + } \ + val--; \ + } + + + +/* + *-------------------------------------------------------------- + * + * init_motion_vectors -- + * + * Initialize the VLC decoding table for the various motion + * vectors, including motion_horizontal_forward_code, + * motion_vertical_forward_code, motion_horizontal_backward_code, + * and motion_vertical_backward_code. + * + * Results: + * The decoding table for the motion vectors will be filled; + * illegal values will be filled as ERROR. + * + * Side effects: + * The global array motion_vector will be filled. + * + *-------------------------------------------------------------- + */ +static void +init_motion_vectors() +{ + int i, j, val = 16; + + for (i = 0; i < 24; i++) { + motion_vectors[i].code = ERROR; + motion_vectors[i].num_bits = 0; + } + + ASSIGN3(24, 36, 2, val, 11); + ASSIGN3(36, 48, 4, val, 10); + ASSIGN3(48, 96, 16, val, 8); + ASSIGN3(96, 128, 32, val, 7); + ASSIGN3(128, 256, 128, val, 5); + ASSIGN3(256, 512, 256, val, 4); + ASSIGN3(512, 1024, 512, val, 3); + ASSIGN3(1024, 2048, 1024, val, 1); +} + + + +extern void init_pre_idct(); + + +/* + *-------------------------------------------------------------- + * + * decodeInitTables -- + * + * Initialize all the tables for VLC decoding; this must be + * called when the system is set up before any decoding can + * take place. + * + * Results: + * All the decoding tables will be filled accordingly. + * + * Side effects: + * The corresponding global array for each decoding table + * will be filled. + * + *-------------------------------------------------------------- + */ +void decodeInitTables() +{ + init_mb_addr_inc(); + init_mb_type_P(); + init_mb_type_B(); + init_motion_vectors(); + +#ifdef FLOATDCT + if (qualityFlag) + init_float_idct(); + else +#endif + init_pre_idct(); + +#ifdef ANALYSIS + { + init_stats(); + } +#endif +} + +#if OLDCODE + +/* + *-------------------------------------------------------------- + * + * DecodeDCTDCSizeLum -- + * + * Huffman Decoder for dct_dc_size_luminance; location where + * the result of decoding will be placed is passed as argument. + * The decoded values are obtained by doing a table lookup on + * dct_dc_size_luminance. + * + * Results: + * The decoded value for dct_dc_size_luminance or ERROR for + * unbound values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +void +decodeDCTDCSizeLum(value) +unsigned int *value; +{ + unsigned int index; + + show_bits5(index); + + if (index < 31) { + *value = dct_dc_size_luminance[index].value; + flush_bits(dct_dc_size_luminance[index].num_bits); + } + else { + show_bits9(index); + index -= 0x1f0; + *value = dct_dc_size_luminance1[index].value; + flush_bits(dct_dc_size_luminance1[index].num_bits); + } +} + + + + +/* + *-------------------------------------------------------------- + * + * DecodeDCTDCSizeChrom -- + * + * Huffman Decoder for dct_dc_size_chrominance; location where + * the result of decoding will be placed is passed as argument. + * The decoded values are obtained by doing a table lookup on + * dct_dc_size_chrominance. + * + * Results: + * The decoded value for dct_dc_size_chrominance or ERROR for + * unbound values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +void +decodeDCTDCSizeChrom(value) +unsigned int *value; +{ + unsigned int index; + + show_bits5(index); + + if (index < 31) { + *value = dct_dc_size_chrominance[index].value; + flush_bits(dct_dc_size_chrominance[index].num_bits); + } + else { + show_bits10(index); + index -= 0x3e0; + *value = dct_dc_size_chrominance1[index].value; + flush_bits(dct_dc_size_chrominance1[index].num_bits); + } +} + + + +/* + *-------------------------------------------------------------- + * + * decodeDCTCoeff -- + * + * Huffman Decoder for dct_coeff_first and dct_coeff_next; + * locations where the results of decoding: run and level, are to + * be placed and also the type of DCT coefficients, either + * dct_coeff_first or dct_coeff_next, are being passed as argument. + * + * The decoder first examines the next 8 bits in the input stream, + * and perform according to the following cases: + * + * '0000 0000' - examine 8 more bits (i.e. 16 bits total) and + * perform a table lookup on dct_coeff_tbl_0. + * One more bit is then examined to determine the sign + * of level. + * + * '0000 0001' - examine 4 more bits (i.e. 12 bits total) and + * perform a table lookup on dct_coeff_tbl_1. + * One more bit is then examined to determine the sign + * of level. + * + * '0000 0010' - examine 2 more bits (i.e. 10 bits total) and + * perform a table lookup on dct_coeff_tbl_2. + * One more bit is then examined to determine the sign + * of level. + * + * '0000 0011' - examine 2 more bits (i.e. 10 bits total) and + * perform a table lookup on dct_coeff_tbl_3. + * One more bit is then examined to determine the sign + * of level. + * + * otherwise - perform a table lookup on dct_coeff_tbl. If the + * value of run is not ESCAPE, extract one more bit + * to determine the sign of level; otherwise 6 more + * bits will be extracted to obtain the actual value + * of run , and then 8 or 16 bits to get the value of level. + * + * + * + * Results: + * The decoded values of run and level or ERROR for unbound values + * are placed in the locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +static void +decodeDCTCoeff(dct_coeff_tbl, run, level) +unsigned short int *dct_coeff_tbl; +unsigned int *run; +int *level; +{ + unsigned int temp, index /*, num_bits */; + unsigned int value, next32bits, flushed; + + /* + * Grab the next 32 bits and use it to improve performance of + * getting the bits to parse. Thus, calls are translated as: + * + * show_bitsX <--> next32bits >> (32-X) + * get_bitsX <--> val = next32bits >> (32-flushed-X); + * flushed += X; + * next32bits &= bitMask[flushed]; + * flush_bitsX <--> flushed += X; + * next32bits &= bitMask[flushed]; + * + */ + show_bits32(next32bits); + flushed = 0; + + /* show_bits8(index); */ + index = next32bits >> 24; + + if (index > 3) { + value = dct_coeff_tbl[index]; + *run = (value & RUN_MASK) >> RUN_SHIFT; + if (*run == END_OF_BLOCK) { + *level = END_OF_BLOCK; + } + else { + /* num_bits = (value & NUM_MASK) + 1; */ + /* flush_bits(num_bits); */ + flushed = (value & NUM_MASK) + 1; + next32bits &= bitMask[flushed]; + if (*run != ESCAPE) { + *level = (value & LEVEL_MASK) >> LEVEL_SHIFT; + /* get_bits1(value); */ + /* if (value) *level = -*level; */ + if (next32bits >> (31-flushed)) *level = -*level; + flushed++; + /* next32bits &= bitMask[flushed]; last op before update */ +#ifdef NO_GRIFF_MODS +#else + /* CG: moved into if case 12jul2000 */ + /* Update bitstream... */ + flush_bits(flushed); +#endif + } + else { /* *run == ESCAPE */ + /* get_bits14(temp); */ + temp = next32bits >> (18-flushed); + flushed += 14; + next32bits &= bitMask[flushed]; + *run = temp >> 8; + temp &= 0xff; + if (temp == 0) { + /* get_bits8(*level); */ + *level = next32bits >> (24-flushed); + flushed += 8; + /* next32bits &= bitMask[flushed]; last op before update */ +#ifdef NO_GRIFF_MODS + assert(*level >= 128); +#else + /* CG: Try to overcome the assertion and incorrect decoding in + * case of lost packets. 12jul2000 */ + if (*level >= 128) { + flush_bits(flushed); + } + else { + *run = END_OF_BLOCK; + *level = END_OF_BLOCK; + } +#endif + } else if (temp != 128) { + /* Grab sign bit */ + *level = ((int) (temp << 24)) >> 24; +#ifdef NO_GRIFF_MODS +#else + /* CG: moved into else case 12jul2000 */ + /* Update bitstream... */ + flush_bits(flushed); +#endif + } else { + /* get_bits8(*level); */ + *level = next32bits >> (24-flushed); + flushed += 8; + /* next32bits &= bitMask[flushed]; last op before update */ + *level = *level - 256; +#ifdef NO_GRIFF_MODS + assert(*level <= -128 && *level >= -255); +#else + /* CG: Try to overcome the assertion and incorrect decoding in + * case of lost packets. 12jul2000 */ + if (*level <= -128 && *level >= -255) { + flush_bits(flushed); + } + else { + *run = END_OF_BLOCK; + *level = END_OF_BLOCK; + } +#endif + } + } +#ifdef NO_GRIFF_MODS + /* Update bitstream... */ + flush_bits(flushed); +#endif + } + } + else { + if (index == 2) { + /* show_bits10(index); */ + index = next32bits >> 22; + value = dct_coeff_tbl_2[index & 3]; + } + else if (index == 3) { + /* show_bits10(index); */ + index = next32bits >> 22; + value = dct_coeff_tbl_3[index & 3]; + } + else if (index) { /* index == 1 */ + /* show_bits12(index); */ + index = next32bits >> 20; + value = dct_coeff_tbl_1[index & 15]; + } + else { /* index == 0 */ + /* show_bits16(index); */ + index = next32bits >> 16; + value = dct_coeff_tbl_0[index & 255]; + } + *run = (value & RUN_MASK) >> RUN_SHIFT; + *level = (value & LEVEL_MASK) >> LEVEL_SHIFT; + + /* + * Fold these operations together to make it fast... + */ + /* num_bits = (value & NUM_MASK) + 1; */ + /* flush_bits(num_bits); */ + /* get_bits1(value); */ + /* if (value) *level = -*level; */ + + flushed = (value & NUM_MASK) + 2; + if ((next32bits >> (32-flushed)) & 0x1) *level = -*level; + + /* Update bitstream ... */ + flush_bits(flushed); + } +} + + +/* + *-------------------------------------------------------------- + * + * decodeDCTCoeffFirst -- + * + * Huffman Decoder for dct_coeff_first. Locations for the + * decoded results: run and level, are being passed as + * arguments. Actual work is being done by calling DecodeDCTCoeff, + * with the table dct_coeff_first. + * + * Results: + * The decoded values of run and level for dct_coeff_first or + * ERROR for unbound values are placed in the locations given. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +void +decodeDCTCoeffFirst(run, level) +unsigned int *run; +int *level; +{ + decodeDCTCoeff(dct_coeff_first, run, level); +} + + + + +/* + *-------------------------------------------------------------- + * + * decodeDCTCoeffNext -- + * + * Huffman Decoder for dct_coeff_first. Locations for the + * decoded results: run and level, are being passed as + * arguments. Actual work is being done by calling DecodeDCTCoeff, + * with the table dct_coeff_next. + * + * Results: + * The decoded values of run and level for dct_coeff_next or + * ERROR for unbound values are placed in the locations given. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +void +decodeDCTCoeffNext(run, level) +unsigned int *run; +int *level; +{ + decodeDCTCoeff(dct_coeff_next, run, level); +} +#endif diff --git a/smpeg/src/video/decoders.h b/smpeg/src/video/decoders.h new file mode 100644 index 0000000..7209d94 --- /dev/null +++ b/smpeg/src/video/decoders.h @@ -0,0 +1,637 @@ +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ +/* + * decoders.h + * + * This file contains the declarations of structures required for Huffman + * decoding + * + */ + +/* Include util.h for bit i/o parsing macros. */ + +#include "util.h" + +/* Code for unbound values in decoding tables */ +#define ERROR (-1) +#define DCT_ERROR 63 + +#define MACRO_BLOCK_STUFFING 34 +#define MACRO_BLOCK_ESCAPE 35 + +/* Two types of DCT Coefficients */ +#define DCT_COEFF_FIRST 0 +#define DCT_COEFF_NEXT 1 + +/* Special values for DCT Coefficients */ +#define END_OF_BLOCK 62 +#define ESCAPE 61 + +/* Structure for an entry in the decoding table of + * macroblock_address_increment */ +typedef struct { + int value; /* value for macroblock_address_increment */ + int num_bits; /* length of the Huffman code */ +} mb_addr_inc_entry; + +/* Decoding table for macroblock_address_increment */ +extern mb_addr_inc_entry mb_addr_inc[2048]; + + +/* Structure for an entry in the decoding table of macroblock_type */ +typedef struct { + unsigned int mb_quant; /* macroblock_quant */ + unsigned int mb_motion_forward; /* macroblock_motion_forward */ + unsigned int mb_motion_backward; /* macroblock_motion_backward */ + unsigned int mb_pattern; /* macroblock_pattern */ + unsigned int mb_intra; /* macroblock_intra */ + int num_bits; /* length of the Huffman code */ +} mb_type_entry; + +/* Decoding table for macroblock_type in predictive-coded pictures */ +extern mb_type_entry mb_type_P[64]; + +/* Decoding table for macroblock_type in bidirectionally-coded pictures */ +extern mb_type_entry mb_type_B[64]; + + +/* Structures for an entry in the decoding table of coded_block_pattern */ +typedef struct { + unsigned int cbp; /* coded_block_pattern */ + int num_bits; /* length of the Huffman code */ +} coded_block_pattern_entry; + +/* External declaration of coded block pattern table. */ + +extern const coded_block_pattern_entry coded_block_pattern[512]; + + + +/* Structure for an entry in the decoding table of motion vectors */ +typedef struct { + int code; /* value for motion_horizontal_forward_code, + * motion_vertical_forward_code, + * motion_horizontal_backward_code, or + * motion_vertical_backward_code. + */ + int num_bits; /* length of the Huffman code */ +} motion_vectors_entry; + + +/* Decoding table for motion vectors */ +extern motion_vectors_entry motion_vectors[2048]; + + +/* Structure for an entry in the decoding table of dct_dc_size */ +typedef struct { + unsigned int value; /* value of dct_dc_size (luminance or chrominance) */ + int num_bits; /* length of the Huffman code */ +} dct_dc_size_entry; + +/* External declaration of dct dc size lumiance table. */ + +extern const dct_dc_size_entry dct_dc_size_luminance[32]; +extern const dct_dc_size_entry dct_dc_size_luminance1[16]; + +/* External declaration of dct dc size chrom table. */ + +extern const dct_dc_size_entry dct_dc_size_chrominance[32]; +extern const dct_dc_size_entry dct_dc_size_chrominance1[32]; + + +/* DCT coeff tables. */ + +#define RUN_MASK 0xfc00 +#define LEVEL_MASK 0x03f0 +#define NUM_MASK 0x000f +#define RUN_SHIFT 10 +#define LEVEL_SHIFT 4 + +/* External declaration of dct coeff tables. */ + +extern const unsigned short int dct_coeff_tbl_0[256]; +extern const unsigned short int dct_coeff_tbl_1[16]; +extern const unsigned short int dct_coeff_tbl_2[4]; +extern const unsigned short int dct_coeff_tbl_3[4]; +extern const unsigned short int dct_coeff_next[256]; +extern const unsigned short int dct_coeff_first[256]; + +#define DecodeDCTDCSizeLum(macro_val) \ +{ \ + unsigned int index; \ + \ + show_bits5(index); \ + \ + if (index < 31) { \ + macro_val = dct_dc_size_luminance[index].value; \ + flush_bits(dct_dc_size_luminance[index].num_bits); \ + } \ + else { \ + show_bits9(index); \ + index -= 0x1f0; \ + macro_val = dct_dc_size_luminance1[index].value; \ + flush_bits(dct_dc_size_luminance1[index].num_bits); \ + } \ +} + +#define DecodeDCTDCSizeChrom(macro_val) \ +{ \ + unsigned int index; \ + \ + show_bits5(index); \ + \ + if (index < 31) { \ + macro_val = dct_dc_size_chrominance[index].value; \ + flush_bits(dct_dc_size_chrominance[index].num_bits); \ + } \ + else { \ + show_bits10(index); \ + index -= 0x3e0; \ + macro_val = dct_dc_size_chrominance1[index].value; \ + flush_bits(dct_dc_size_chrominance1[index].num_bits); \ + } \ +} + +#ifdef NO_GRIFF_MODS +#define DecodeDCTCoeff(dct_coeff_tbl, run, level) \ +{ \ + unsigned int temp, index; \ + unsigned int value, next32bits, flushed; \ + \ + /* \ + * Grab the next 32 bits and use it to improve performance of \ + * getting the bits to parse. Thus, calls are translated as: \ + * \ + * show_bitsX <--> next32bits >> (32-X) \ + * get_bitsX <--> val = next32bits >> (32-flushed-X); \ + * flushed += X; \ + * next32bits &= bitMask[flushed]; \ + * flush_bitsX <--> flushed += X; \ + * next32bits &= bitMask[flushed]; \ + * \ + * I've streamlined the code a lot, so that we don't have to mask \ + * out the low order bits and a few of the extra adds are removed. \ + */ \ + show_bits32(next32bits); \ + \ + /* show_bits8(index); */ \ + index = next32bits >> 24; \ + \ + if (index > 3) { \ + value = dct_coeff_tbl[index]; \ + run = value >> RUN_SHIFT; \ + if (run != END_OF_BLOCK) { \ + /* num_bits = (value & NUM_MASK) + 1; */ \ + /* flush_bits(num_bits); */ \ + if (run != ESCAPE) { \ + /* get_bits1(value); */ \ + /* if (value) level = -level; */ \ + flushed = (value & NUM_MASK) + 2; \ + level = (value & LEVEL_MASK) >> LEVEL_SHIFT; \ + value = next32bits >> (32-flushed); \ + value &= 0x1; \ + if (value) level = -level; \ + /* next32bits &= ((~0) >> flushed); last op before update */ \ + } \ + else { /* run == ESCAPE */ \ + /* Get the next six into run, and next 8 into temp */ \ + /* get_bits14(temp); */ \ + flushed = (value & NUM_MASK) + 1; \ + temp = next32bits >> (18-flushed); \ + /* Normally, we'd ad 14 to flushed, but I've saved a few \ + * instr by moving the add below */ \ + temp &= 0x3fff; \ + run = temp >> 8; \ + temp &= 0xff; \ + if (temp == 0) { \ + /* get_bits8(level); */ \ + level = next32bits >> (10-flushed); \ + level &= 0xff; \ + flushed += 22; \ + assert(level >= 128); \ + } else if (temp != 128) { \ + /* Grab sign bit */ \ + flushed += 14; \ + level = ((int) (temp << 24)) >> 24; \ + } else { \ + /* get_bits8(level); */ \ + level = next32bits >> (10-flushed); \ + level &= 0xff; \ + flushed += 22; \ + level = level - 256; \ + assert(level <= -128 && level >= -255); \ + } \ + } \ + /* Update bitstream... */ \ + flush_bits(flushed); \ + assert (flushed <= 32); \ + } \ + } \ + else { \ + switch (index) { \ + case 2: { \ + /* show_bits10(index); */ \ + index = next32bits >> 22; \ + value = dct_coeff_tbl_2[index & 3]; \ + break; \ + } \ + case 3: { \ + /* show_bits10(index); */ \ + index = next32bits >> 22; \ + value = dct_coeff_tbl_3[index & 3]; \ + break; \ + } \ + case 1: { \ + /* show_bits12(index); */ \ + index = next32bits >> 20; \ + value = dct_coeff_tbl_1[index & 15]; \ + break; \ + } \ + default: { /* index == 0 */ \ + /* show_bits16(index); */ \ + index = next32bits >> 16; \ + value = dct_coeff_tbl_0[index & 255]; \ + }} \ + run = value >> RUN_SHIFT; \ + level = (value & LEVEL_MASK) >> LEVEL_SHIFT; \ + \ + /* \ + * Fold these operations together to make it fast... \ + */ \ + /* num_bits = (value & NUM_MASK) + 1; */ \ + /* flush_bits(num_bits); */ \ + /* get_bits1(value); */ \ + /* if (value) level = -level; */ \ + \ + flushed = (value & NUM_MASK) + 2; \ + value = next32bits >> (32-flushed); \ + value &= 0x1; \ + if (value) level = -level; \ + \ + /* Update bitstream ... */ \ + flush_bits(flushed); \ + assert (flushed <= 32); \ + } \ +} +#else /* NO_GRIFF_MODS */ +#define DecodeDCTCoeff(dct_coeff_tbl, run, level) \ +{ \ + unsigned int temp, index; \ + unsigned int value, next32bits, flushed; \ + \ + /* \ + * Grab the next 32 bits and use it to improve performance of \ + * getting the bits to parse. Thus, calls are translated as: \ + * \ + * show_bitsX <--> next32bits >> (32-X) \ + * get_bitsX <--> val = next32bits >> (32-flushed-X); \ + * flushed += X; \ + * next32bits &= bitMask[flushed]; \ + * flush_bitsX <--> flushed += X; \ + * next32bits &= bitMask[flushed]; \ + * \ + * I've streamlined the code a lot, so that we don't have to mask \ + * out the low order bits and a few of the extra adds are removed. \ + */ \ + show_bits32(next32bits); \ + \ + /* show_bits8(index); */ \ + index = next32bits >> 24; \ + \ + if (index > 3) { \ + value = dct_coeff_tbl[index]; \ + run = value >> RUN_SHIFT; \ + if (run != END_OF_BLOCK) { \ + /* num_bits = (value & NUM_MASK) + 1; */ \ + /* flush_bits(num_bits); */ \ + if (run != ESCAPE) { \ + /* get_bits1(value); */ \ + /* if (value) level = -level; */ \ + flushed = (value & NUM_MASK) + 2; \ + level = (value & LEVEL_MASK) >> LEVEL_SHIFT; \ + value = next32bits >> (32-flushed); \ + value &= 0x1; \ + if (value) level = -level; \ + /* next32bits &= ((~0) >> flushed); last op before update */ \ + \ + /* Update bitstream... */ \ + flush_bits(flushed); \ + assert (flushed <= 32); \ + } \ + else { /* run == ESCAPE */ \ + /* Get the next six into run, and next 8 into temp */ \ + /* get_bits14(temp); */ \ + flushed = (value & NUM_MASK) + 1; \ + temp = next32bits >> (18-flushed); \ + /* Normally, we'd ad 14 to flushed, but I've saved a few \ + * instr by moving the add below */ \ + temp &= 0x3fff; \ + run = temp >> 8; \ + temp &= 0xff; \ + if (temp == 0) { \ + /* get_bits8(level); */ \ + level = next32bits >> (10-flushed); \ + level &= 0xff; \ + flushed += 22; \ + /* CG: 12jul2000 - assert(level >= 128); */ \ + if (level >= 128) { \ + /* Update bitstream... */ \ + flush_bits(flushed); \ + assert (flushed <= 32); \ + } else { \ + run = END_OF_BLOCK; \ + level = END_OF_BLOCK; \ + } \ + } else if (temp != 128) { \ + /* Grab sign bit */ \ + flushed += 14; \ + level = ((int) (temp << 24)) >> 24; \ + /* Update bitstream... */ \ + flush_bits(flushed); \ + assert (flushed <= 32); \ + } else { \ + /* get_bits8(level); */ \ + level = next32bits >> (10-flushed); \ + level &= 0xff; \ + flushed += 22; \ + level = level - 256; \ + /* CG: 12jul2000 - assert(level <= -128 && level >= -255); */ \ + if ( level <= -128 && level >= -255) { \ + /* Update bitstream... */ \ + flush_bits(flushed); \ + assert (flushed <= 32); \ + } else { \ + run = END_OF_BLOCK; \ + level = END_OF_BLOCK; \ + } \ + } \ + } \ + } \ + } \ + else { \ + switch (index) { \ + case 2: { \ + /* show_bits10(index); */ \ + index = next32bits >> 22; \ + value = dct_coeff_tbl_2[index & 3]; \ + break; \ + } \ + case 3: { \ + /* show_bits10(index); */ \ + index = next32bits >> 22; \ + value = dct_coeff_tbl_3[index & 3]; \ + break; \ + } \ + case 1: { \ + /* show_bits12(index); */ \ + index = next32bits >> 20; \ + value = dct_coeff_tbl_1[index & 15]; \ + break; \ + } \ + default: { /* index == 0 */ \ + /* show_bits16(index); */ \ + index = next32bits >> 16; \ + value = dct_coeff_tbl_0[index & 255]; \ + }} \ + run = value >> RUN_SHIFT; \ + level = (value & LEVEL_MASK) >> LEVEL_SHIFT; \ + \ + /* \ + * Fold these operations together to make it fast... \ + */ \ + /* num_bits = (value & NUM_MASK) + 1; */ \ + /* flush_bits(num_bits); */ \ + /* get_bits1(value); */ \ + /* if (value) level = -level; */ \ + \ + flushed = (value & NUM_MASK) + 2; \ + value = next32bits >> (32-flushed); \ + value &= 0x1; \ + if (value) level = -level; \ + \ + /* Update bitstream ... */ \ + flush_bits(flushed); \ + assert (flushed <= 32); \ + } \ +} +#endif /* NO_GRIFF_MODS */ + +#define DecodeDCTCoeffFirst(runval, levelval) \ +{ \ + DecodeDCTCoeff(dct_coeff_first, runval, levelval); \ +} + +#define DecodeDCTCoeffNext(runval, levelval) \ +{ \ + DecodeDCTCoeff(dct_coeff_next, runval, levelval); \ +} + +/* + *-------------------------------------------------------------- + * + * DecodeMBAddrInc -- + * + * Huffman Decoder for macro_block_address_increment; the location + * in which the result will be placed is being passed as argument. + * The decoded value is obtained by doing a table lookup on + * mb_addr_inc. + * + * Results: + * The decoded value for macro_block_address_increment or ERROR + * for unbound values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +#define DecodeMBAddrInc(val) \ +{ \ + unsigned int index; \ + show_bits11(index); \ + val = mb_addr_inc[index].value; \ + flush_bits(mb_addr_inc[index].num_bits); \ +} + +/* + *-------------------------------------------------------------- + * + * DecodeMotionVectors -- + * + * Huffman Decoder for the various motion vectors, including + * motion_horizontal_forward_code, motion_vertical_forward_code, + * motion_horizontal_backward_code, motion_vertical_backward_code. + * Location where the decoded result will be placed is being passed + * as argument. The decoded values are obtained by doing a table + * lookup on motion_vectors. + * + * Results: + * The decoded value for the motion vector or ERROR for unbound + * values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +#define DecodeMotionVectors(value) \ +{ \ + unsigned int index; \ + show_bits11(index); \ + value = motion_vectors[index].code; \ + flush_bits(motion_vectors[index].num_bits); \ +} +/* + *-------------------------------------------------------------- + * + * DecodeMBTypeB -- + * + * Huffman Decoder for macro_block_type in bidirectionally-coded + * pictures;locations in which the decoded results: macroblock_quant, + * macroblock_motion_forward, macro_block_motion_backward, + * macroblock_pattern, macro_block_intra, will be placed are + * being passed as argument. The decoded values are obtained by + * doing a table lookup on mb_type_B. + * + * Results: + * The various decoded values for macro_block_type in + * bidirectionally-coded pictures or ERROR for unbound values will + * be placed in the locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +#define DecodeMBTypeB(quant, motion_fwd, motion_bwd, pat, intra) \ +{ \ + unsigned int index; \ + \ + show_bits6(index); \ + \ + quant = mb_type_B[index].mb_quant; \ + motion_fwd = mb_type_B[index].mb_motion_forward; \ + motion_bwd = mb_type_B[index].mb_motion_backward; \ + pat = mb_type_B[index].mb_pattern; \ + intra = mb_type_B[index].mb_intra; \ + flush_bits(mb_type_B[index].num_bits); \ +} +/* + *-------------------------------------------------------------- + * + * DecodeMBTypeI -- + * + * Huffman Decoder for macro_block_type in intra-coded pictures; + * locations in which the decoded results: macroblock_quant, + * macroblock_motion_forward, macro_block_motion_backward, + * macroblock_pattern, macro_block_intra, will be placed are + * being passed as argument. + * + * Results: + * The various decoded values for macro_block_type in intra-coded + * pictures or ERROR for unbound values will be placed in the + * locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +#define DecodeMBTypeI(quant, motion_fwd, motion_bwd, pat, intra) \ +{ \ + unsigned int index; \ + static int quantTbl[4] = {ERROR, 1, 0, 0}; \ + \ + show_bits2(index); \ + \ + motion_fwd = 0; \ + motion_bwd = 0; \ + pat = 0; \ + intra = 1; \ + quant = quantTbl[index]; \ + if (index) { \ + flush_bits (1 + quant); \ + } \ +} +/* + *-------------------------------------------------------------- + * + * DecodeMBTypeP -- + * + * Huffman Decoder for macro_block_type in predictive-coded pictures; + * locations in which the decoded results: macroblock_quant, + * macroblock_motion_forward, macro_block_motion_backward, + * macroblock_pattern, macro_block_intra, will be placed are + * being passed as argument. The decoded values are obtained by + * doing a table lookup on mb_type_P. + * + * Results: + * The various decoded values for macro_block_type in + * predictive-coded pictures or ERROR for unbound values will be + * placed in the locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +#define DecodeMBTypeP(quant, motion_fwd, motion_bwd, pat, intra) \ +{ \ + unsigned int index; \ + \ + show_bits6(index); \ + \ + quant = mb_type_P[index].mb_quant; \ + motion_fwd = mb_type_P[index].mb_motion_forward; \ + motion_bwd = mb_type_P[index].mb_motion_backward; \ + pat = mb_type_P[index].mb_pattern; \ + intra = mb_type_P[index].mb_intra; \ + \ + flush_bits(mb_type_P[index].num_bits); \ +} +/* + *-------------------------------------------------------------- + * + * DecodeCBP -- + * + * Huffman Decoder for coded_block_pattern; location in which the + * decoded result will be placed is being passed as argument. The + * decoded values are obtained by doing a table lookup on + * coded_block_pattern. + * + * Results: + * The decoded value for coded_block_pattern or ERROR for unbound + * values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +#define DecodeCBP(coded_bp) \ +{ \ + unsigned int index; \ + \ + show_bits9(index); \ + coded_bp = coded_block_pattern[index].cbp; \ + flush_bits(coded_block_pattern[index].num_bits); \ +} diff --git a/smpeg/src/video/dither.h b/smpeg/src/video/dither.h new file mode 100644 index 0000000..541e88c --- /dev/null +++ b/smpeg/src/video/dither.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +extern int LUM_RANGE; +extern int CR_RANGE; +extern int CB_RANGE; + + +#define CB_BASE 1 +#define CR_BASE (CB_BASE*CB_RANGE) +#define LUM_BASE (CR_BASE*CR_RANGE) + +extern unsigned char pixel[256]; +extern unsigned long wpixel[256]; +extern int *lum_values; +extern int *cr_values; +extern int *cb_values; + +#define Min(x,y) (((x) < (y)) ? (x) : (y)) +#define Max(x,y) (((x) > (y)) ? (x) : (y)) + +#define GAMMA_CORRECTION(x) ((int)(pow((x) / 255.0, 1.0 / gammaCorrect) * 255.0)) +#define CHROMA_CORRECTION256(x) ((x) >= 128 \ + ? 128 + Min(127, (int)(((x) - 128.0) * chromaCorrect)) \ + : 128 - Min(128, (int)((128.0 - (x)) * chromaCorrect))) +#define CHROMA_CORRECTION128(x) ((x) >= 0 \ + ? Min(127, (int)(((x) * chromaCorrect))) \ + : Max(-128, (int)(((x) * chromaCorrect)))) +#define CHROMA_CORRECTION256D(x) ((x) >= 128 \ + ? 128.0 + Min(127.0, (((x) - 128.0) * chromaCorrect)) \ + : 128.0 - Min(128.0, (((128.0 - (x)) * chromaCorrect)))) +#define CHROMA_CORRECTION128D(x) ((x) >= 0 \ + ? Min(127.0, ((x) * chromaCorrect)) \ + : Max(-128.0, ((x) * chromaCorrect))) + diff --git a/smpeg/src/video/floatdct.cpp b/smpeg/src/video/floatdct.cpp new file mode 100644 index 0000000..13106ba --- /dev/null +++ b/smpeg/src/video/floatdct.cpp @@ -0,0 +1,121 @@ +/* idctref.c, Inverse Discrete Fourier Transform, double precision */ + +/* Copyright (C) 1994, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +/* Perform IEEE 1180 reference (64-bit floating point, separable 8x1 + * direct matrix multiply) Inverse Discrete Cosine Transform +*/ + + +/* Here we use math.h to generate constants. Compiler results may + vary a little */ + +#include + +#ifndef __STDC__ +#define _ANSI_ARGS_(x) () +#else +#define _ANSI_ARGS_(x) x +#endif + +#define RB "rb" +#define WB "wb" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef PI +# ifdef M_PI +# define PI M_PI +# else +# define PI 3.14159265358979323846 +# endif +#endif + +/* global declarations */ +void init_float_idct _ANSI_ARGS_((void)); +void float_idct _ANSI_ARGS_((short *block)); + +/* private data */ + +/* cosine transform matrix for 8x1 IDCT */ +static double c[8][8]; + +/* initialize DCT coefficient matrix */ + +void init_float_idct() +{ + int freq, time; + double scale; + + for (freq=0; freq < 8; freq++) + { + scale = (freq == 0) ? sqrt(0.125) : 0.5; + for (time=0; time<8; time++) + c[freq][time] = scale*cos((PI/8.0)*freq*(time + 0.5)); + } +} + +/* perform IDCT matrix multiply for 8x8 coefficient block */ + +void float_idct( short* block ) +{ + int i, j, k, v; + double partial_product; + double tmp[64]; + + for (i=0; i<8; i++) + for (j=0; j<8; j++) + { + partial_product = 0.0; + + for (k=0; k<8; k++) + partial_product+= c[k][j]*block[8*i+k]; + + tmp[8*i+j] = partial_product; + } + + /* Transpose operation is integrated into address mapping by switching + loop order of i and j */ + + for (j=0; j<8; j++) + for (i=0; i<8; i++) + { + partial_product = 0.0; + + for (k=0; k<8; k++) + partial_product+= c[k][i]*tmp[8*k+j]; + + v = (int) floor( partial_product + 0.5 ); + block[8*i+j] = (v<-256) ? -256 : ((v>255) ? 255 : v); + } +} + + +/* EOF */ diff --git a/smpeg/src/video/gdith.cpp b/smpeg/src/video/gdith.cpp new file mode 100644 index 0000000..1f5990b --- /dev/null +++ b/smpeg/src/video/gdith.cpp @@ -0,0 +1,424 @@ +/* + * gdith.c -- + * + * Procedures dealing with grey-scale and mono dithering, + * as well as X Windows set up procedures. + * + */ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include +#include "video.h" +#include "proto.h" +#include "dither.h" +#include "SDL_timer.h" + +#ifdef USE_ATI +#include "vhar128.h" +#endif + +#ifdef __STDC__ +#include +#include +#endif + + +/* + Changes to make the code reentrant: + X variables now passed in xinfo: display, ximage,cmap,window, gc, etc + De-globalized: ditherType, matched_depth, totNumFrames + vid_stream->film_has_ended instead of FilmState + + Additional changes: + Now can name and position each movie window individually + DISABLE_DITHER cpp define - do not include dither code if defined + NOFRAMECOUNT cpp define - do not count frames when running without + controls + Short circuit InitColorDisplay if not displaying anything + ExistingWindow default now 0 + -lsh@cs.brown.edu (Loring Holden) +*/ + +/* Frame Rate Info */ +extern int framerate; + +/* Video rates table */ +/* Cheat on Vid rates, round to 30, and use 30 if illegal value + Except for 9, where Xing means 15, and given their popularity, we'll + be nice and do it */ +static double VidRateNum[16]={ 30, 23.97, 24, 25, 29.97, 30, 50, 59.94, + 60, 15, 30, 30, 30, 15, 30, 30 }; + +#ifdef CALCULATE_FPS +static inline void TimestampFPS( VidStream* vid_stream ) +{ + MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg; + + vid_stream->frame_time[vid_stream->timestamp_index] = mpeg->Time(); + ++vid_stream->timestamp_index; + if ( vid_stream->timestamp_index == FPS_WINDOW ) { + vid_stream->timestamp_index = 0; + } +} +#endif + +/* + Do frame rate control. Returns _skipFrame +*/ +#define LOOSE_MPEG_SCHEDULING +#ifdef LOOSE_MPEG_SCHEDULING +#define MAX_FRAME_SKIP 4 +#define MAX_FUDGE_TIME (MAX_FRAME_SKIP*vid_stream->_oneFrameTime) +#else +#ifdef TIGHT_MPEG_SCHEDULING +#define MAX_FRAME_SKIP 1 +#define MAX_FUDGE_TIME (MAX_FRAME_SKIP*vid_stream->_oneFrameTime) +#else +#define MAX_FRAME_SKIP 3 +#define MAX_FUDGE_TIME (MAX_FRAME_SKIP*vid_stream->_oneFrameTime) +#endif /* TIGHT_MPEG_SCHEDULING */ +#endif /* LOOSE_MPEG_SCHEDULING */ +#define FUDGE_TIME (((MAX_FRAME_SKIP+1)/2)*vid_stream->_oneFrameTime) + +/* This results in smoother framerate, but more dropped frames on + systems that can play most of the video fine, but have problems + with jerkiness in a few spots. +*/ +//#define SLOW_START_SCHEDULING +#define SLOW_START_INCREMENT 0.3 + +/* Define this to debug the frame scheduler */ +//#define DEBUG_MPEG_SCHEDULING + +inline double CurrentTime( VidStream* vid_stream ) +{ + MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg; + double now; + + if ( mpeg->TimeSource() ) { + now = mpeg->TimeSource()->Time(); + } else { + now = ReadSysClock() - vid_stream->realTimeStart; + } + return now; +} + +int MPEGvideo::timeSync( VidStream* vid_stream ) +{ + static double correction = -1; + + /* Update the number of frames displayed */ + vid_stream->totNumFrames++; + vid_stream->current_frame++; + + /* Do we need to initialize framerate? */ + if ( vid_stream->rate_deal < 0 ) { + switch( framerate ) { + case -1: /* Go with stream Value */ + vid_stream->rate_deal = VidRateNum[ vid_stream->picture_rate ]; + break; + + case 0: /* as fast as possible */ + vid_stream->rate_deal = 0; + break; + + default: + vid_stream->rate_deal = framerate; + break; + } + if ( vid_stream->rate_deal ) { + vid_stream->_oneFrameTime = 1.0 / vid_stream->rate_deal; + } + } + + /* Update the current play time */ + play_time += vid_stream->_oneFrameTime; + + /* Synchronize using system timestamps */ + if(vid_stream->current && vid_stream->current->show_time > 0){ +#ifdef DEBUG_TIMESTAMP_SYNC + fprintf(stderr, "video: time:%.3f shift:%.3f\r", + play_time, + play_time - vid_stream->current->show_time); +#endif + if(correction == -1) +#ifdef STRANGE_SYNC_TEST + /* this forces us to maintain the offset we have at the begining + all the time, and is only usefull for testing */ + correction = play_time - vid_stream->current->show_time; +#else + correction = 0; +#endif +#ifdef USE_TIMESTAMP_SYNC + play_time = vid_stream->current->show_time + correction ; +#endif + vid_stream->current->show_time = -1; + } + + /* If we are looking for a particular frame... */ + if( vid_stream->_jumpFrame > -1 ) + { + if ( vid_stream->totNumFrames != vid_stream->_jumpFrame ) { + vid_stream->_skipFrame = 1; + } else { + vid_stream->_skipFrame = 0; + } + return vid_stream->_skipFrame; + } + + /* If we're already behind, don't check timing */ + if ( vid_stream->_skipFrame > 0 ) + { + return --vid_stream->_skipFrame; + } + + /* See if we need to skip frames, based on timing */ + if ( vid_stream->rate_deal ) { + static const double TIMESLICE = 0.01; // Seconds per OS timeslice + double time_behind; + + /* Calculate the frame time relative to real time */ + time_behind = CurrentTime(vid_stream) - Time(); + +#ifdef DEBUG_MPEG_SCHEDULING +printf("Frame %d: frame time: %f, real time: %f, time behind: %f\n", vid_stream->totNumFrames, Time(), CurrentTime(vid_stream), time_behind); +#endif + + /* Allow up to MAX_FUDGE_TIME of delay in output */ + if ( time_behind < -TIMESLICE ) { + time_behind = -time_behind; + vid_stream->_skipCount = 0; +#ifdef DEBUG_MPEG_SCHEDULING +printf("Ahead! Sleeping %f\n", time_behind-TIMESLICE); +#endif + SDL_Delay((Uint32)((time_behind-TIMESLICE)*1000)); + } else + if ( time_behind < FUDGE_TIME ) { + if ( vid_stream->_skipCount > 0 ) { + vid_stream->_skipCount /= 2; + } +#ifdef DEBUG_MPEG_SCHEDULING +printf("Just right.\n"); +#endif + } else + if ( time_behind < MAX_FUDGE_TIME ) { + if ( vid_stream->_skipCount > 0 ) { + vid_stream->_skipCount--; + } + vid_stream->_skipFrame = 1+(int)(vid_stream->_skipCount/2); +#ifdef DEBUG_MPEG_SCHEDULING +printf("A little behind, skipping %d frames\n", vid_stream->_skipFrame); +#endif + } else { + /* time_behind >= MAX_FUDGE_TIME */ + if ( (time_behind > (MAX_FUDGE_TIME*2)) && + (vid_stream->_skipCount == MAX_FRAME_SKIP) ) { +#ifdef DEBUG_MPEG_SCHEDULING +printf("Way too far behind, losing time sync...\n"); +#endif +#if 0 // This results in smoother video, but sync's terribly on slow machines + play_time = CurrentTime(vid_stream) - (MAX_FUDGE_TIME*2); +#endif + } +#ifdef SLOW_START_SCHEDULING + vid_stream->_skipCount += SLOW_START_INCREMENT; +#else + vid_stream->_skipCount += 1.0; +#endif + if( vid_stream->_skipCount > MAX_FRAME_SKIP ) { + vid_stream->_skipCount = MAX_FRAME_SKIP; + } + vid_stream->_skipFrame = (int)(vid_stream->_skipCount+0.9); +#ifdef DEBUG_MPEG_SCHEDULING +printf("A lot behind, skipping %d frames\n", vid_stream->_skipFrame); +#endif + } + } + return(vid_stream->_skipFrame); +} + +/* Do the hard work of copying from the video stream working buffer to the + screen display and then calling the update callback. +*/ +void MPEGvideo::DisplayFrame( VidStream * vid_stream ) +{ + SMPEG_FilterInfo info; + + if ( !_image ) { + return; + } + + if ( _filter_mutex ) + SDL_mutexP( _filter_mutex ); + + /* Get a pointer to _image pixels */ + if ( SDL_LockYUVOverlay( _image ) ) { + return; + } + + /* Compute additionnal info for the filter */ + if((_filter->flags & SMPEG_FILTER_INFO_PIXEL_ERROR) && vid_stream->current->mb_qscale) + { + register int x, y; + register Uint16 * ptr; + + /* Compute quantization error for each pixel */ + info.yuv_pixel_square_error = (Uint16 *) malloc(_w*_h*12/8*sizeof(Uint16)); + + ptr = info.yuv_pixel_square_error; + for(y = 0; y < _h; y++) + for(x = 0; x < _w; x++) + *ptr++ = (Uint16) (((Uint32) vid_stream->noise_base_matrix[x & 7][y & 7] * + vid_stream->current->mb_qscale[((y>>4) * (_w>>4)) + (x >> 4)]) >> 8); + } + + if((_filter->flags & SMPEG_FILTER_INFO_MB_ERROR) && vid_stream->current->mb_qscale) + { + /* Retreive macroblock quantization error info */ + info.yuv_mb_square_error = (Uint16 *)vid_stream->current->mb_qscale; + } + + if( _filter ) + { + SDL_Overlay src; + Uint16 pitches[3]; + Uint8 *pixels[3]; + + /* Fill in an SDL YV12 overlay structure for the source */ +#ifdef USE_ATI + vhar128_lockimage(vid_stream->ati_handle, vid_stream->current->image, &src); +#else + src.format = SDL_YV12_OVERLAY; + src.w = _w; + src.h = _h; + src.planes = 3; + pitches[0] = _w; + pitches[1] = _w / 2; + pitches[2] = _w / 2; + src.pitches = pitches; + pixels[0] = (Uint8 *)vid_stream->current->image; + pixels[1] = (Uint8 *)vid_stream->current->image + pitches[0] * _h; + pixels[2] = (Uint8 *)vid_stream->current->image + pitches[0] * _h + + pitches[1] * _h / 2; + src.pixels = pixels; +#endif + + _filter->callback(_image, &src, &_srcrect, &info, _filter->data ); + +#ifdef USE_ATI + vhar128_unlockimage(vid_stream->ati_handle, vid_stream->current->image, &src); +#endif + } + + /* Now display the image */ + if ( _mutex ) + SDL_mutexP( _mutex ); + + SDL_DisplayYUVOverlay(_image, &_dstrect); + + if ( _callback ) + _callback(_dst, _dstrect.x, _dstrect.y, _dstrect.w, _dstrect.h); + + SDL_UnlockYUVOverlay( _image ); + + if( _filter ) + { + if( _filter->flags & SMPEG_FILTER_INFO_PIXEL_ERROR ) + free(info.yuv_pixel_square_error); + } + + if ( _filter_mutex ) + SDL_mutexV( _filter_mutex ); + + if ( _mutex ) + SDL_mutexV( _mutex ); +} + +/* + *-------------------------------------------------------------- + * + * ExecuteDisplay -- + * + * Actually displays display plane in previously created window. + * + * Results: + * None. + * + * Side effects: + * Updates video frame timing control + * + *-------------------------------------------------------------- + */ + + +void MPEGvideo::ExecuteDisplay( VidStream* vid_stream ) +{ + if( ! vid_stream->_skipFrame ) + { + DisplayFrame(vid_stream); + +#ifdef CALCULATE_FPS + TimestampFPS(vid_stream); +#endif + } + timeSync( vid_stream ); +} + + +SMPEG_Filter * +MPEGvideo:: Filter(SMPEG_Filter * filter) +{ + SMPEG_Filter * old_filter; + + old_filter = _filter; + if ( _filter_mutex ) + SDL_mutexP( _filter_mutex ); + _filter = filter; + if ( _filter_mutex ) + SDL_mutexV( _filter_mutex ); + + return(old_filter); +} + +/* EOF */ diff --git a/smpeg/src/video/jrevdct.cpp b/smpeg/src/video/jrevdct.cpp new file mode 100644 index 0000000..a49ccb5 --- /dev/null +++ b/smpeg/src/video/jrevdct.cpp @@ -0,0 +1,1617 @@ +/* + * jrevdct.c + * + * Copyright (C) 1991, 1992, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the basic inverse-DCT transformation subroutine. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + * + * I've made lots of modifications to attempt to take advantage of the + * sparse nature of the DCT matrices we're getting. Although the logic + * is cumbersome, it's straightforward and the resulting code is much + * faster. + * + * A better way to do this would be to pass in the DCT block as a sparse + * matrix, perhaps with the difference cases encoded. + */ + +#include +#include "video.h" +#include "proto.h" + +#define GLOBAL /* a function referenced thru EXTERNs */ + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* + * This routine is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * A 2-D IDCT can be done by 1-D IDCT on each row followed by 1-D IDCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#ifdef EIGHT_BIT_SAMPLES +#define PASS1_BITS 2 +#else +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +#define ONE ((INT32) 1) + +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * IMPORTANT: if your compiler doesn't do this arithmetic at compile time, + * you will pay a significant penalty in run time. In that case, figure + * the correct integer constant values and insert them by hand. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* When adding two opposite-signed fixes, the 0.5 cancels */ +#define FIX2(x) ((INT32) ((x) * CONST_SCALE)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply; + * this provides a useful speedup on many machines. + * There is no way to specify a 16x16->32 multiply in portable C, but + * some C compilers will do the right thing if you provide the correct + * combination of casts. + * NB: for 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#ifdef EIGHT_BIT_SAMPLES +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif +#endif + +#ifndef MULTIPLY /* default definition */ +#define MULTIPLY(var,const) ((var) * (const)) +#endif + +#ifndef NO_SPARSE_DCT +#define SPARSE_SCALE_FACTOR 8 +#endif + +/* Precomputed idct value arrays. */ + +static DCTELEM PreIDCT[64][64]; + + +/* + *-------------------------------------------------------------- + * + * init_pre_idct -- + * + * Pre-computes singleton coefficient IDCT values. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void init_pre_idct() +{ + int i; + + for (i=0; i<64; i++) { + memset((char *) PreIDCT[i], 0, 64*sizeof(DCTELEM)); + PreIDCT[i][i] = 1 << SPARSE_SCALE_FACTOR; + j_rev_dct(PreIDCT[i]); + } +} + +#ifndef NO_SPARSE_DCT + + + +/* + *-------------------------------------------------------------- + * + * j_rev_dct_sparse -- + * + * Performs the inverse DCT on one block of coefficients. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void j_rev_dct_sparse( DCTBLOCK data, int pos ) +{ + short int val; + register int *dp; + register int v; + int quant; + +#ifdef SPARSE_AC + register DCTELEM *dataptr; + DCTELEM *ndataptr; + int coeff, rr; + DCTBLOCK tmpdata, tmp2data; + DCTELEM *tmpdataptr, *tmp2dataptr; + int printFlag = 1; +#endif + + + /* If DC Coefficient. */ + + if (pos == 0) { + dp = (int *)data; + v = *data; + quant = 8; + + /* Compute 32 bit value to assign. This speeds things up a bit */ + if (v < 0) { + val = -v; + val += (quant >> 1); + val /= quant; + val = -val; + } + else { + val = (v + (quant >> 1)) / quant; + } + + v = ((val & 0xffff) | (val << 16)); + + dp[0] = v; dp[1] = v; dp[2] = v; dp[3] = v; + dp[4] = v; dp[5] = v; dp[6] = v; dp[7] = v; + dp[8] = v; dp[9] = v; dp[10] = v; dp[11] = v; + dp[12] = v; dp[13] = v; dp[14] = v; dp[15] = v; + dp[16] = v; dp[17] = v; dp[18] = v; dp[19] = v; + dp[20] = v; dp[21] = v; dp[22] = v; dp[23] = v; + dp[24] = v; dp[25] = v; dp[26] = v; dp[27] = v; + dp[28] = v; dp[29] = v; dp[30] = v; dp[31] = v; + + return; + } + + /* Some other coefficient. */ + +#ifdef SPARSE_AC + dataptr = (DCTELEM *)data; + coeff = dataptr[pos]; + ndataptr = PreIDCT[pos]; + + printf (" \n"); + printf ("COEFFICIENT = %3d, POSITION = %2d\n", coeff, pos); + + for (v=0; v<64; v++) { + memcpy((char *) tmpdata, data, 64*sizeof(DCTELEM)); + } + tmpdataptr = (DCTELEM *)tmpdata; + + for (v=0; v<64; v++) { + memcpy((char *) tmp2data, data, 64*sizeof(DCTELEM)); + } + tmp2dataptr = (DCTELEM *)tmp2data; + +#ifdef DEBUG + printf ("original DCTBLOCK:\n"); + for (rr=0; rr<8; rr++) { + for (v=0; v<8; v++) { + if (dataptr[8*rr+v] != tmpdataptr[8*rr+v]) + fprintf(stderr, "Error in copy\n"); + printf ("%3d ", dataptr[8*rr+v]); + } + printf("\n"); + } +#endif + + printf("\n"); + + for (rr=0; rr<4; rr++) { + dataptr[0] = (ndataptr[0] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[1] = (ndataptr[1] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[2] = (ndataptr[2] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[3] = (ndataptr[3] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[4] = (ndataptr[4] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[5] = (ndataptr[5] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[6] = (ndataptr[6] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[7] = (ndataptr[7] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[8] = (ndataptr[8] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[9] = (ndataptr[9] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[10] = (ndataptr[10] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[11] = (ndataptr[11] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[12] = (ndataptr[12] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[13] = (ndataptr[13] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[14] = (ndataptr[14] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr[15] = (ndataptr[15] * coeff) >> SPARSE_SCALE_FACTOR; + dataptr += 16; + ndataptr += 16; + } + + dataptr = (DCTELEM *) data; + +#ifdef DEBUG + printf ("sparse IDCT:\n"); + for (rr=0; rr<8; rr++) { + for (v=0; v<8; v++) { + printf ("%3d ", dataptr[8*rr+v]); + } + printf("\n"); + } + printf("\n"); +#endif /* DEBUG */ +#else /* NO_SPARSE_AC */ +#ifdef FLOATDCT + if (qualityFlag) + float_idct(data); + else +#endif /* FLOATDCT */ + j_rev_dct(data); +#endif /* SPARSE_AC */ + return; + +} + +#else + +/* + *-------------------------------------------------------------- + * + * j_rev_dct_sparse -- + * + * Performs the original inverse DCT on one block of + * coefficients. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void j_rev_dct_sparse( DCTBLOCK data, int pos ) +{ + j_rev_dct(data); +} +#endif /* SPARSE_DCT */ + + +#ifndef FIVE_DCT + +#ifndef ORIG_DCT + + +/* + *-------------------------------------------------------------- + * + * j_rev_dct -- + * + * The inverse DCT function. + * + * Results: + * None. + * + * Side effects: + * None. + * + * Profiling results: + * This function only takes about 0.01ms per call, but is called many + * many times, taking about 30% of the total time used by playback. + * + *-------------------------------------------------------------- + */ + +void j_rev_dct( DCTBLOCK data ) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + INT32 d0, d1, d2, d3, d4, d5, d6, d7; + register DCTELEM *dataptr; + int rowctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any row in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * row DCT calculations can be simplified this way. + */ + + register int *idataptr = (int*)dataptr; + d0 = dataptr[0]; + d1 = dataptr[1]; + if ((d1 == 0) && (idataptr[1] | idataptr[2] | idataptr[3]) == 0) { + /* AC terms all zero */ + if (d0) { + /* Compute a 32 bit value to assign. */ + DCTELEM dcval = (DCTELEM) (d0 << PASS1_BITS); + register int v = (dcval & 0xffff) | (dcval << 16); + + idataptr[0] = v; + idataptr[1] = v; + idataptr[2] = v; + idataptr[3] = v; + } + + dataptr += DCTSIZE; /* advance pointer to next row */ + continue; + } + d2 = dataptr[2]; + d3 = dataptr[3]; + d4 = dataptr[4]; + d5 = dataptr[5]; + d6 = dataptr[6]; + d7 = dataptr[7]; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + if (d6) { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + } + } else { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = (d0 + d4) << CONST_BITS; + tmp11 = tmp12 = (d0 - d4) << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = d4 << CONST_BITS; + tmp11 = tmp12 = -tmp10; + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = 0; + } + } + } + } + + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + if (d7) { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z2 = d5 + d3; + z3 = d7 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ + z2 = d5 + d3; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 = z1 + z4; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z4 = d5 + d1; + z5 = MULTIPLY(d7 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 = z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ + z5 = MULTIPLY(d7 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z3; + tmp1 += z4; + tmp2 = z2 + z3; + tmp3 = z1 + z4; + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 = z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ + z3 = d7 + d3; + z5 = MULTIPLY(z3, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp2 = MULTIPLY(d3, FIX(0.509795579)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX2(0.785694958)); + + tmp0 += z3; + tmp1 = z2 + z5; + tmp2 += z3; + tmp3 = z1 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z5 = MULTIPLY(z1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(1.662939224)); + tmp3 = MULTIPLY(d1, FIX2(1.111140466)); + z1 = MULTIPLY(z1, FIX2(0.275899379)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + tmp0 += z1; + tmp1 = z4 + z5; + tmp2 = z3 + z5; + tmp3 += z1; + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ + tmp0 = MULTIPLY(d7, - FIX2(1.387039845)); + tmp1 = MULTIPLY(d7, FIX(1.175875602)); + tmp2 = MULTIPLY(d7, - FIX2(0.785694958)); + tmp3 = MULTIPLY(d7, FIX2(0.275899379)); + } + } + } + } else { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 = z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z5 = MULTIPLY(z2, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX2(1.662939225)); + tmp2 = MULTIPLY(d3, FIX2(1.111140466)); + z2 = MULTIPLY(z2, - FIX2(1.387039845)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + tmp0 = z3 + z5; + tmp1 += z2; + tmp2 += z2; + tmp3 = z4 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ + z4 = d5 + d1; + z5 = MULTIPLY(z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + tmp3 = MULTIPLY(d1, FIX2(0.601344887)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(z4, FIX2(0.785694958)); + + tmp0 = z1 + z5; + tmp1 += z4; + tmp2 = z2 + z5; + tmp3 += z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ + tmp0 = MULTIPLY(d5, FIX(1.175875602)); + tmp1 = MULTIPLY(d5, FIX2(0.275899380)); + tmp2 = MULTIPLY(d5, - FIX2(1.387039845)); + tmp3 = MULTIPLY(d5, FIX2(0.785694958)); + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ + z5 = d3 + d1; + + tmp2 = MULTIPLY(d3, - FIX(1.451774981)); + tmp3 = MULTIPLY(d1, (FIX(0.211164243) - 1)); + z1 = MULTIPLY(d1, FIX(1.061594337)); + z2 = MULTIPLY(d3, - FIX(2.172734803)); + z4 = MULTIPLY(z5, FIX(0.785694958)); + z5 = MULTIPLY(z5, FIX(1.175875602)); + + tmp0 = z1 - z4; + tmp1 = z2 + z4; + tmp2 += z5; + tmp3 += z5; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d3, - FIX2(0.785694958)); + tmp1 = MULTIPLY(d3, - FIX2(1.387039845)); + tmp2 = MULTIPLY(d3, - FIX2(0.275899379)); + tmp3 = MULTIPLY(d3, FIX(1.175875602)); + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d1, FIX2(0.275899379)); + tmp1 = MULTIPLY(d1, FIX2(0.785694958)); + tmp2 = MULTIPLY(d1, FIX(1.175875602)); + tmp3 = MULTIPLY(d1, FIX2(1.387039845)); + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = tmp1 = tmp2 = tmp3 = 0; + } + } + } + } + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + dataptr = data; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Columns of zeroes can be exploited in the same way as we did with rows. + * However, the row calculation has created many nonzero AC terms, so the + * simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + + d0 = dataptr[DCTSIZE*0]; + d1 = dataptr[DCTSIZE*1]; + d2 = dataptr[DCTSIZE*2]; + d3 = dataptr[DCTSIZE*3]; + d4 = dataptr[DCTSIZE*4]; + d5 = dataptr[DCTSIZE*5]; + d6 = dataptr[DCTSIZE*6]; + d7 = dataptr[DCTSIZE*7]; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + if (d6) { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, -FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + } + } else { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = (d0 + d4) << CONST_BITS; + tmp11 = tmp12 = (d0 - d4) << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = d4 << CONST_BITS; + tmp11 = tmp12 = -tmp10; + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = (INT32)MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32)MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = 0; + } + } + } + } + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + if (d7) { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z2 = d5 + d3; + z3 = d7 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ + z2 = d5 + d3; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 = z1 + z4; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z4 = d5 + d1; + z5 = MULTIPLY(d7 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 = z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ + z5 = MULTIPLY(d5 + d7, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z3; + tmp1 += z4; + tmp2 = z2 + z3; + tmp3 = z1 + z4; + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 = z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ + z3 = d7 + d3; + z5 = MULTIPLY(z3, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + tmp2 = MULTIPLY(d3, FIX(0.509795579)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX2(0.785694958)); + + tmp0 += z3; + tmp1 = z2 + z5; + tmp2 += z3; + tmp3 = z1 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z5 = MULTIPLY(z1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(1.662939224)); + tmp3 = MULTIPLY(d1, FIX2(1.111140466)); + z1 = MULTIPLY(z1, FIX2(0.275899379)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + tmp0 += z1; + tmp1 = z4 + z5; + tmp2 = z3 + z5; + tmp3 += z1; + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ + tmp0 = MULTIPLY(d7, - FIX2(1.387039845)); + tmp1 = MULTIPLY(d7, FIX(1.175875602)); + tmp2 = MULTIPLY(d7, - FIX2(0.785694958)); + tmp3 = MULTIPLY(d7, FIX2(0.275899379)); + } + } + } + } else { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 = z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z5 = MULTIPLY(z2, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX2(1.662939225)); + tmp2 = MULTIPLY(d3, FIX2(1.111140466)); + z2 = MULTIPLY(z2, - FIX2(1.387039845)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + tmp0 = z3 + z5; + tmp1 += z2; + tmp2 += z2; + tmp3 = z4 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ + z4 = d5 + d1; + z5 = MULTIPLY(z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + tmp3 = MULTIPLY(d1, FIX2(0.601344887)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(z4, FIX2(0.785694958)); + + tmp0 = z1 + z5; + tmp1 += z4; + tmp2 = z2 + z5; + tmp3 += z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ + tmp0 = MULTIPLY(d5, FIX(1.175875602)); + tmp1 = MULTIPLY(d5, FIX2(0.275899380)); + tmp2 = MULTIPLY(d5, - FIX2(1.387039845)); + tmp3 = MULTIPLY(d5, FIX2(0.785694958)); + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ + z5 = d3 + d1; + + tmp2 = MULTIPLY(d3, - FIX(1.451774981)); + tmp3 = MULTIPLY(d1, (FIX(0.211164243) - 1)); + z1 = MULTIPLY(d1, FIX(1.061594337)); + z2 = MULTIPLY(d3, - FIX(2.172734803)); + z4 = MULTIPLY(z5, FIX(0.785694958)); + z5 = MULTIPLY(z5, FIX(1.175875602)); + + tmp0 = z1 - z4; + tmp1 = z2 + z4; + tmp2 += z5; + tmp3 += z5; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d3, - FIX2(0.785694958)); + tmp1 = MULTIPLY(d3, - FIX2(1.387039845)); + tmp2 = MULTIPLY(d3, - FIX2(0.275899379)); + tmp3 = MULTIPLY(d3, FIX(1.175875602)); + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d1, FIX2(0.275899379)); + tmp1 = MULTIPLY(d1, FIX2(0.785694958)); + tmp2 = MULTIPLY(d1, FIX(1.175875602)); + tmp3 = MULTIPLY(d1, FIX2(1.387039845)); + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = tmp1 = tmp2 = tmp3 = 0; + } + } + } + } + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3); + + dataptr++; /* advance pointer to next column */ + } +} + +#else + + + +/* + *-------------------------------------------------------------- + * + * j_rev_dct -- + * + * The original inverse DCT function. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void j_rev_dct( DCTBLOCK data ) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + register DCTELEM *dataptr; + int rowctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any row in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * row DCT calculations can be simplified this way. + */ + + if ((dataptr[1] | dataptr[2] | dataptr[3] | dataptr[4] | + dataptr[5] | dataptr[6] | dataptr[7]) == 0) { + /* AC terms all zero */ + DCTELEM dcval = (DCTELEM) (dataptr[0] << PASS1_BITS); + + dataptr[0] = dcval; + dataptr[1] = dcval; + dataptr[2] = dcval; + dataptr[3] = dcval; + dataptr[4] = dcval; + dataptr[5] = dcval; + dataptr[6] = dcval; + dataptr[7] = dcval; + + dataptr += DCTSIZE; /* advance pointer to next row */ + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) dataptr[2]; + z3 = (INT32) dataptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); + + tmp0 = ((INT32) dataptr[0] + (INT32) dataptr[4]) << CONST_BITS; + tmp1 = ((INT32) dataptr[0] - (INT32) dataptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) dataptr[7]; + tmp1 = (INT32) dataptr[5]; + tmp2 = (INT32) dataptr[3]; + tmp3 = (INT32) dataptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + dataptr = data; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Columns of zeroes can be exploited in the same way as we did with rows. + * However, the row calculation has created many nonzero AC terms, so the + * simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_COLUMN_TEST + if ((dataptr[DCTSIZE*1] | dataptr[DCTSIZE*2] | dataptr[DCTSIZE*3] | + dataptr[DCTSIZE*4] | dataptr[DCTSIZE*5] | dataptr[DCTSIZE*6] | + dataptr[DCTSIZE*7]) == 0) { + /* AC terms all zero */ + DCTELEM dcval = (DCTELEM) DESCALE((INT32) dataptr[0], PASS1_BITS+3); + + dataptr[DCTSIZE*0] = dcval; + dataptr[DCTSIZE*1] = dcval; + dataptr[DCTSIZE*2] = dcval; + dataptr[DCTSIZE*3] = dcval; + dataptr[DCTSIZE*4] = dcval; + dataptr[DCTSIZE*5] = dcval; + dataptr[DCTSIZE*6] = dcval; + dataptr[DCTSIZE*7] = dcval; + + dataptr++; /* advance pointer to next column */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) dataptr[DCTSIZE*2]; + z3 = (INT32) dataptr[DCTSIZE*6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); + + tmp0 = ((INT32) dataptr[DCTSIZE*0] + (INT32) dataptr[DCTSIZE*4]) << CONST_BITS; + tmp1 = ((INT32) dataptr[DCTSIZE*0] - (INT32) dataptr[DCTSIZE*4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) dataptr[DCTSIZE*7]; + tmp1 = (INT32) dataptr[DCTSIZE*5]; + tmp2 = (INT32) dataptr[DCTSIZE*3]; + tmp3 = (INT32) dataptr[DCTSIZE*1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3); + + dataptr++; /* advance pointer to next column */ + } +} + + +#endif /* ORIG_DCT */ +#endif /* FIVE_DCT */ diff --git a/smpeg/src/video/mmxflags_asm.S b/smpeg/src/video/mmxflags_asm.S new file mode 100644 index 0000000..c48ae41 --- /dev/null +++ b/smpeg/src/video/mmxflags_asm.S @@ -0,0 +1,55 @@ + +#if defined(i386) && defined(USE_MMX) + +.text + .align 4 +.globl cpu_flags + .type cpu_flags,@function +cpu_flags: + pushfl + popl %eax + + movl %eax,%ecx + + xorl $0x040000,%eax + pushl %eax + + popfl + pushfl + + popl %eax + xorl %ecx,%eax + jz cpu_flags.L1 # Processor is 386 + + pushl %ecx + popfl + + movl %ecx,%eax + xorl $0x200000,%eax + + pushl %eax + popfl + pushfl + + popl %eax + xorl %ecx,%eax + je cpu_flags.L1 + + pushl %ebx + + movl $1,%eax + cpuid + movl %edx,%eax + + popl %ebx + +cpu_flags.L1: + ret +.Lfe1: + .size cpu_flags,.Lfe1-cpu_flags + +#endif /* i386 && USE_MMX */ + +#ifdef __ELF__ +.section .note.GNU-stack,"",%progbits +#endif diff --git a/smpeg/src/video/mmxidct_asm.S b/smpeg/src/video/mmxidct_asm.S new file mode 100644 index 0000000..5a2bc06 --- /dev/null +++ b/smpeg/src/video/mmxidct_asm.S @@ -0,0 +1,697 @@ + + +#if defined(i386) && defined(USE_MMX) + + +/* + * the input data is tranposed and each 16 bit element in the 8x8 matrix + * is left aligned: + * for example in 11...1110000 format + * If the iDCT is of I macroblock then 0.5 needs to be added to the;DC Component + * (element[0][0] of the matrix) + */ + +/* extrn re_matrix */ + +.data + .align 16 + .type preSC,@object +preSC: .short 16384,22725,21407,19266,16384,12873,8867,4520 + .short 22725,31521,29692,26722,22725,17855,12299,6270 + .short 21407,29692,27969,25172,21407,16819,11585,5906 + .short 19266,26722,25172,22654,19266,15137,10426,5315 + .short 16384,22725,21407,19266,16384,12873,8867,4520 + .short 12873,17855,16819,15137,25746,20228,13933,7103 + .short 17734,24598,23170,20853,17734,13933,9597,4892 + .short 18081,25080,23624,21261,18081,14206,9785,4988 + .size preSC,128 + .align 8 + .type x0005000200010001,@object + .size x0005000200010001,8 +x0005000200010001: + .long 0x00010001,0x00050002 + .align 8 + .type x5a825a825a825a82,@object + .size x5a825a825a825a82,8 +x5a825a825a825a82: + .long 0x5a825a82, 0x5a825a82 + .align 8 + .type x539f539f539f539f,@object + .size x539f539f539f539f,8 +x539f539f539f539f: + .long 0x539f539f,0x539f539f + .align 8 + .type x4546454645464546,@object + .size x4546454645464546,8 +x4546454645464546: + .long 0x45464546,0x45464546 + .align 8 + .type x61f861f861f861f8,@object + .size x61f861f861f861f8,8 +x61f861f861f861f8: + .long 0x61f861f8,0x61f861f8 + .align 8 + .type scratch1,@object + .size scratch1,8 +scratch1: + .long 0,0 + .align 8 + .type scratch3,@object + .size scratch3,8 +scratch3: + .long 0,0 + .align 8 + .type scratch5,@object + .size scratch5,8 +scratch5: + .long 0,0 + .align 8 + .type scratch7,@object + .size scratch7,8 +scratch7: + .long 0,0 + .type x0,@object + .size x0,8 +x0: + .long 0,0 + .align 8 + +.text + .align 4 + +#ifdef __PIC__ +# undef __i686 /* gcc define gets in our way */ +# define MUNG(sym) sym ## @GOTOFF(%ebx) +# define INIT_PIC() \ + call __i686.get_pc_thunk.bx ; \ + addl $_GLOBAL_OFFSET_TABLE_, %ebx +#else +# define MUNG(sym) sym +# define INIT_PIC() +#endif + +.globl IDCT_mmx + .type IDCT_mmx,@function +IDCT_mmx: + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + INIT_PIC() + movl 8(%ebp),%esi /* source matrix */ + leal MUNG(preSC), %ecx +/* column 0: even part + * use V4, V12, V0, V8 to produce V22..V25 + */ + movq 8*12(%ecx), %mm0 /* maybe the first mul can be done together */ + /* with the dequantization in iHuff module */ + pmulhw 8*12(%esi), %mm0 /* V12 */ + movq 8*4(%ecx), %mm1 + pmulhw 8*4(%esi), %mm1 /* V4 */ + movq (%ecx), %mm3 + psraw $1, %mm0 /* t64=t66 */ + pmulhw (%esi), %mm3 /* V0 */ + movq 8*8(%ecx), %mm5 /* duplicate V4 */ + movq %mm1, %mm2 /* added 11/1/96 */ + pmulhw 8*8(%esi),%mm5 /* V8 */ + psubsw %mm0, %mm1 /* V16 */ + pmulhw MUNG(x5a825a825a825a82), %mm1 /* 23170 ->V18 */ + paddsw %mm0, %mm2 /* V17 */ + movq %mm2, %mm0 /* duplicate V17 */ + psraw $1, %mm2 /* t75=t82 */ + psraw $2, %mm0 /* t72 */ + movq %mm3, %mm4 /* duplicate V0 */ + paddsw %mm5, %mm3 /* V19 */ + psubsw %mm5, %mm4 /* V20 ;mm5 free */ +/* moved from the block below */ + movq 8*10(%ecx), %mm7 + psraw $1, %mm3 /* t74=t81 */ + movq %mm3, %mm6 /* duplicate t74=t81 */ + psraw $2, %mm4 /* t77=t79 */ + psubsw %mm0, %mm1 /* V21 ; mm0 free */ + paddsw %mm2, %mm3 /* V22 */ + movq %mm1, %mm5 /* duplicate V21 */ + paddsw %mm4, %mm1 /* V23 */ + movq %mm3, 8*4(%esi) /* V22 */ + psubsw %mm5, %mm4 /* V24; mm5 free */ + movq %mm1, 8*12(%esi) /* V23 */ + psubsw %mm2, %mm6 /* V25; mm2 free */ + movq %mm4, (%esi) /* V24 */ +/* keep mm6 alive all along the next block */ + /* movq %mm6, 8*8(%esi) V25 */ +/* column 0: odd part + * use V2, V6, V10, V14 to produce V31, V39, V40, V41 + */ +/* moved above: movq 8*10(%ecx), %mm7 */ + + pmulhw 8*10(%esi), %mm7 /* V10 */ + movq 8*6(%ecx), %mm0 + pmulhw 8*6(%esi), %mm0 /* V6 */ + movq 8*2(%ecx), %mm5 + movq %mm7, %mm3 /* duplicate V10 */ + pmulhw 8*2(%esi), %mm5 /* V2 */ + movq 8*14(%ecx), %mm4 + psubsw %mm0, %mm7 /* V26 */ + pmulhw 8*14(%esi), %mm4 /* V14 */ + paddsw %mm0, %mm3 /* V29 ; free mm0 */ + movq %mm7, %mm1 /* duplicate V26 */ + psraw $1, %mm3 /* t91=t94 */ + pmulhw MUNG(x539f539f539f539f),%mm7 /* V33 */ + psraw $1, %mm1 /* t96 */ + movq %mm5, %mm0 /* duplicate V2 */ + psraw $2, %mm4 /* t85=t87 */ + paddsw %mm4,%mm5 /* V27 */ + psubsw %mm4, %mm0 /* V28 ; free mm4 */ + movq %mm0, %mm2 /* duplicate V28 */ + psraw $1, %mm5 /* t90=t93 */ + pmulhw MUNG(x4546454645464546),%mm0 /* V35 */ + psraw $1, %mm2 /* t97 */ + movq %mm5, %mm4 /* duplicate t90=t93 */ + psubsw %mm2, %mm1 /* V32 ; free mm2 */ + pmulhw MUNG(x61f861f861f861f8),%mm1 /* V36 */ + psllw $1, %mm7 /* t107 */ + paddsw %mm3, %mm5 /* V31 */ + psubsw %mm3, %mm4 /* V30 ; free mm3 */ + pmulhw MUNG(x5a825a825a825a82),%mm4 /* V34 */ + nop + psubsw %mm1, %mm0 /* V38 */ + psubsw %mm7, %mm1 /* V37 ; free mm7 */ + psllw $1, %mm1 /* t114 */ +/* move from the next block */ + movq %mm6, %mm3 /* duplicate V25 */ +/* move from the next block */ + movq 8*4(%esi), %mm7 /* V22 */ + psllw $1, %mm0 /* t110 */ + psubsw %mm5, %mm0 /* V39 (mm5 needed for next block) */ + psllw $2, %mm4 /* t112 */ +/* moved from the next block */ + movq 8*12(%esi), %mm2 /* V23 */ + psubsw %mm0, %mm4 /* V40 */ + paddsw %mm4, %mm1 /* V41; free mm0 */ +/* moved from the next block */ + psllw $1, %mm2 /* t117=t125 */ +/* column 0: output butterfly */ +/* moved above: + * movq %mm6, %mm3 duplicate V25 + * movq 8*4(%esi), %mm7 V22 + * movq 8*12(%esi), %mm2 V23 + * psllw $1, %mm2 t117=t125 + */ + psubsw %mm1, %mm6 /* tm6 */ + paddsw %mm1, %mm3 /* tm8; free mm1 */ + movq %mm7, %mm1 /* duplicate V22 */ + paddsw %mm5, %mm7 /* tm0 */ + movq %mm3, 8*8(%esi) /* tm8; free mm3 */ + psubsw %mm5, %mm1 /* tm14; free mm5 */ + movq %mm6, 8*6(%esi) /* tm6; free mm6 */ + movq %mm2, %mm3 /* duplicate t117=t125 */ + movq (%esi), %mm6 /* V24 */ + paddsw %mm0, %mm2 /* tm2 */ + movq %mm7, (%esi) /* tm0; free mm7 */ + psubsw %mm0, %mm3 /* tm12; free mm0 */ + movq %mm1, 8*14(%esi) /* tm14; free mm1 */ + psllw $1, %mm6 /* t119=t123 */ + movq %mm2, 8*2(%esi) /* tm2; free mm2 */ + movq %mm6, %mm0 /* duplicate t119=t123 */ + movq %mm3, 8*12(%esi) /* tm12; free mm3 */ + paddsw %mm4, %mm6 /* tm4 */ +/* moved from next block */ + movq 8*5(%ecx), %mm1 + psubsw %mm4, %mm0 /* tm10; free mm4 */ +/* moved from next block */ + pmulhw 8*5(%esi), %mm1 /* V5 */ + movq %mm6, 8*4(%esi) /* tm4; free mm6 */ + movq %mm0, 8*10(%esi) /* tm10; free mm0 */ +/* column 1: even part + * use V5, V13, V1, V9 to produce V56..V59 + */ +/* moved to prev block: + * movq 8*5(%ecx), %mm1 + * pmulhw 8*5(%esi), %mm1 V5 + */ + movq 8*13(%ecx), %mm7 + psllw $1, %mm1 /* t128=t130 */ + pmulhw 8*13(%esi), %mm7 /* V13 */ + movq %mm1, %mm2 /* duplicate t128=t130 */ + movq 8(%ecx), %mm3 + pmulhw 8(%esi), %mm3 /* V1 */ + movq 8*9(%ecx), %mm5 + psubsw %mm7, %mm1 /* V50 */ + pmulhw 8*9(%esi), %mm5 /* V9 */ + paddsw %mm7, %mm2 /* V51 */ + pmulhw MUNG(x5a825a825a825a82), %mm1 /* 23170 ->V52 */ + movq %mm2, %mm6 /* duplicate V51 */ + psraw $1, %mm2 /* t138=t144 */ + movq %mm3, %mm4 /* duplicate V1 */ + psraw $2, %mm6 /* t136 */ + paddsw %mm5, %mm3 /* V53 */ + psubsw %mm5, %mm4 /* V54 ;mm5 free */ + movq %mm3, %mm7 /* duplicate V53 */ +/* moved from next block */ + movq 8*11(%ecx), %mm0 + psraw $1, %mm4 /* t140=t142 */ + psubsw %mm6, %mm1 /* V55 ; mm6 free */ + paddsw %mm2, %mm3 /* V56 */ + movq %mm4, %mm5 /* duplicate t140=t142 */ + paddsw %mm1, %mm4 /* V57 */ + movq %mm3, 8*5(%esi) /* V56 */ + psubsw %mm1, %mm5 /* V58; mm1 free */ + movq %mm4, 8*13(%esi) /* V57 */ + psubsw %mm2, %mm7 /* V59; mm2 free */ + movq %mm5, 8*9(%esi) /* V58 */ +/* keep mm7 alive all along the next block + * movq %mm7, 8(%esi) V59 + * moved above + * movq 8*11(%ecx), %mm0 + */ + pmulhw 8*11(%esi), %mm0 /* V11 */ + movq 8*7(%ecx), %mm6 + pmulhw 8*7(%esi), %mm6 /* V7 */ + movq 8*15(%ecx), %mm4 + movq %mm0, %mm3 /* duplicate V11 */ + pmulhw 8*15(%esi), %mm4 /* V15 */ + movq 8*3(%ecx), %mm5 + psllw $1, %mm6 /* t146=t152 */ + pmulhw 8*3(%esi), %mm5 /* V3 */ + paddsw %mm6, %mm0 /* V63 */ +/* note that V15 computation has a correction step: + * this is a 'magic' constant that rebiases the results to be closer to the + * expected result. this magic constant can be refined to reduce the error + * even more by doing the correction step in a later stage when the number + * is actually multiplied by 16 + */ + paddw MUNG(x0005000200010001), %mm4 + psubsw %mm6, %mm3 /* V60 ; free mm6 */ + psraw $1, %mm0 /* t154=t156 */ + movq %mm3, %mm1 /* duplicate V60 */ + pmulhw MUNG(x539f539f539f539f), %mm1 /* V67 */ + movq %mm5, %mm6 /* duplicate V3 */ + psraw $2, %mm4 /* t148=t150 */ + paddsw %mm4, %mm5 /* V61 */ + psubsw %mm4, %mm6 /* V62 ; free mm4 */ + movq %mm5, %mm4 /* duplicate V61 */ + psllw $1, %mm1 /* t169 */ + paddsw %mm0, %mm5 /* V65 -> result */ + psubsw %mm0, %mm4 /* V64 ; free mm0 */ + pmulhw MUNG(x5a825a825a825a82), %mm4 /* V68 */ + psraw $1, %mm3 /* t158 */ + psubsw %mm6, %mm3 /* V66 */ + movq %mm5, %mm2 /* duplicate V65 */ + pmulhw MUNG(x61f861f861f861f8), %mm3 /* V70 */ + psllw $1, %mm6 /* t165 */ + pmulhw MUNG(x4546454645464546), %mm6 /* V69 */ + psraw $1, %mm2 /* t172 */ +/* moved from next block */ + movq 8*5(%esi), %mm0 /* V56 */ + psllw $1, %mm4 /* t174 */ +/* moved from next block */ + psraw $1, %mm0 /* t177=t188 */ + nop + psubsw %mm3, %mm6 /* V72 */ + psubsw %mm1, %mm3 /* V71 ; free mm1 */ + psubsw %mm2, %mm6 /* V73 ; free mm2 */ +/* moved from next block */ + psraw $1, %mm5 /* t178=t189 */ + psubsw %mm6, %mm4 /* V74 */ +/* moved from next block */ + movq %mm0, %mm1 /* duplicate t177=t188 */ + paddsw %mm4, %mm3 /* V75 */ +/* moved from next block */ + paddsw %mm5, %mm0 /* tm1 */ +/* location + * 5 - V56 + * 13 - V57 + * 9 - V58 + * X - V59, mm7 + * X - V65, mm5 + * X - V73, mm6 + * X - V74, mm4 + * X - V75, mm3 + * free mm0, mm1 & mm2 + * moved above + * movq 8*5(%esi), %mm0 V56 + * psllw $1, %mm0 t177=t188 ! new !! + * psllw $1, %mm5 t178=t189 ! new !! + * movq %mm0, %mm1 duplicate t177=t188 + * paddsw %mm5, %mm0 tm1 + */ + movq 8*13(%esi), %mm2 /* V57 */ + psubsw %mm5, %mm1 /* tm15; free mm5 */ + movq %mm0, 8(%esi) /* tm1; free mm0 */ + psraw $1, %mm7 /* t182=t184 ! new !! */ +/* save the store as used directly in the transpose + * movq %mm1, 120(%esi) tm15; free mm1 + */ + movq %mm7, %mm5 /* duplicate t182=t184 */ + psubsw %mm3, %mm7 /* tm7 */ + paddsw %mm3, %mm5 /* tm9; free mm3 */ + movq 8*9(%esi), %mm0 /* V58 */ + movq %mm2, %mm3 /* duplicate V57 */ + movq %mm7, 8*7(%esi) /* tm7; free mm7 */ + psubsw %mm6, %mm3 /* tm13 */ + paddsw %mm6, %mm2 /* tm3 ; free mm6 */ +/* moved up from the transpose */ + movq %mm3, %mm7 +/* moved up from the transpose */ + punpcklwd %mm1, %mm3 + movq %mm0, %mm6 /* duplicate V58 */ + movq %mm2, 8*3(%esi) /* tm3; free mm2 */ + paddsw %mm4, %mm0 /* tm5 */ + psubsw %mm4, %mm6 /* tm11; free mm4 */ +/* moved up from the transpose */ + punpckhwd %mm1, %mm7 + movq %mm0, 8*5(%esi) /* tm5; free mm0 */ +/* moved up from the transpose */ + movq %mm5, %mm2 +/* transpose - M4 part + * --------- --------- + * | M1 | M2 | | M1'| M3'| + * --------- --> --------- + * | M3 | M4 | | M2'| M4'| + * --------- --------- + * Two alternatives: use full mmword approach so the following code can be + * scheduled before the transpose is done without stores, or use the faster + * half mmword stores (when possible) + */ + movd %mm3, 8*9+4(%esi) /* MS part of tmt9 */ + punpcklwd %mm6, %mm5 + movd %mm7, 8*13+4(%esi) /* MS part of tmt13 */ + punpckhwd %mm6, %mm2 + movd %mm5, 8*9(%esi) /* LS part of tmt9 */ + punpckhdq %mm3, %mm5 /* free mm3 */ + movd %mm2, 8*13(%esi) /* LS part of tmt13 */ + punpckhdq %mm7, %mm2 /* free mm7 */ +/* moved up from the M3 transpose */ + movq 8*8(%esi), %mm0 +/* moved up from the M3 transpose */ + movq 8*10(%esi), %mm1 +/* moved up from the M3 transpose */ + movq %mm0, %mm3 +/* shuffle the rest of the data, and write it with 2 mmword writes */ + movq %mm5, 8*11(%esi) /* tmt11 */ +/* moved up from the M3 transpose */ + punpcklwd %mm1, %mm0 + movq %mm2, 8*15(%esi) /* tmt15 */ +/* moved up from the M3 transpose */ + punpckhwd %mm1, %mm3 +/* transpose - M3 part + * moved up to previous code section + * movq 8*8(%esi), %mm0 + * movq 8*10(%esi), %mm1 + * movq %mm0, %mm3 + * punpcklwd %mm1, %mm0 + * punpckhwd %mm1, %mm3 + */ + movq 8*12(%esi), %mm6 + movq 8*14(%esi), %mm4 + movq %mm6, %mm2 +/* shuffle the data and write the lower parts of the transposed in 4 dwords */ + punpcklwd %mm4, %mm6 + movq %mm0, %mm1 + punpckhdq %mm6, %mm1 + movq %mm3, %mm7 + punpckhwd %mm4, %mm2 /* free mm4 */ + punpckldq %mm6, %mm0 /* free mm6 */ +/* moved from next block */ + movq 8*13(%esi), %mm4 /* tmt13 */ + punpckldq %mm2, %mm3 + punpckhdq %mm2, %mm7 /* free mm2 */ +/* moved from next block */ + movq %mm3, %mm5 /* duplicate tmt5 */ +/* column 1: even part (after transpose) +* moved above +* movq %mm3, %mm5 duplicate tmt5 +* movq 8*13(%esi), %mm4 tmt13 +*/ + psubsw %mm4, %mm3 /* V134 */ + pmulhw MUNG(x5a825a825a825a82), %mm3 /* 23170 ->V136 */ + movq 8*9(%esi), %mm6 /* tmt9 */ + paddsw %mm4, %mm5 /* V135 ; mm4 free */ + movq %mm0, %mm4 /* duplicate tmt1 */ + paddsw %mm6, %mm0 /* V137 */ + psubsw %mm6, %mm4 /* V138 ; mm6 free */ + psllw $2, %mm3 /* t290 */ + psubsw %mm5, %mm3 /* V139 */ + movq %mm0, %mm6 /* duplicate V137 */ + paddsw %mm5, %mm0 /* V140 */ + movq %mm4, %mm2 /* duplicate V138 */ + paddsw %mm3, %mm2 /* V141 */ + psubsw %mm3, %mm4 /* V142 ; mm3 free */ + movq %mm0, 8*9(%esi) /* V140 */ + psubsw %mm5, %mm6 /* V143 ; mm5 free */ +/* moved from next block */ + movq 8*11(%esi), %mm0 /* tmt11 */ + movq %mm2, 8*13(%esi) /* V141 */ +/* moved from next block */ + movq %mm0, %mm2 /* duplicate tmt11 */ +/* column 1: odd part (after transpose) */ +/* moved up to the prev block + * movq 8*11(%esi), %mm0 tmt11 + * movq %mm0, %mm2 duplicate tmt11 + */ + movq 8*15(%esi), %mm5 /* tmt15 */ + psubsw %mm7, %mm0 /* V144 */ + movq %mm0, %mm3 /* duplicate V144 */ + paddsw %mm7, %mm2 /* V147 ; free mm7 */ + pmulhw MUNG(x539f539f539f539f), %mm0 /* 21407-> V151 */ + movq %mm1, %mm7 /* duplicate tmt3 */ + paddsw %mm5, %mm7 /* V145 */ + psubsw %mm5, %mm1 /* V146 ; free mm5 */ + psubsw %mm1, %mm3 /* V150 */ + movq %mm7, %mm5 /* duplicate V145 */ + pmulhw MUNG(x4546454645464546), %mm1 /* 17734-> V153 */ + psubsw %mm2, %mm5 /* V148 */ + pmulhw MUNG(x61f861f861f861f8), %mm3 /* 25080-> V154 */ + psllw $2, %mm0 /* t311 */ + pmulhw MUNG(x5a825a825a825a82), %mm5 /* 23170-> V152 */ + paddsw %mm2, %mm7 /* V149 ; free mm2 */ + psllw $1, %mm1 /* t313 */ + nop /* without the nop - freeze here for one clock */ + movq %mm3, %mm2 /* duplicate V154 */ + psubsw %mm0, %mm3 /* V155 ; free mm0 */ + psubsw %mm2, %mm1 /* V156 ; free mm2 */ +/* moved from the next block */ + movq %mm6, %mm2 /* duplicate V143 */ +/* moved from the next block */ + movq 8*13(%esi), %mm0 /* V141 */ + psllw $1, %mm1 /* t315 */ + psubsw %mm7, %mm1 /* V157 (keep V149) */ + psllw $2, %mm5 /* t317 */ + psubsw %mm1, %mm5 /* V158 */ + psllw $1, %mm3 /* t319 */ + paddsw %mm5, %mm3 /* V159 */ +/* column 1: output butterfly (after transform) + * moved to the prev block + * movq %mm6, %mm2 duplicate V143 + * movq 8*13(%esi), %mm0 V141 + */ + psubsw %mm3, %mm2 /* V163 */ + paddsw %mm3, %mm6 /* V164 ; free mm3 */ + movq %mm4, %mm3 /* duplicate V142 */ + psubsw %mm5, %mm4 /* V165 ; free mm5 */ + movq %mm2, MUNG(scratch7) /* out7 */ + psraw $4, %mm6 + psraw $4, %mm4 + paddsw %mm5, %mm3 /* V162 */ + movq 8*9(%esi), %mm2 /* V140 */ + movq %mm0, %mm5 /* duplicate V141 */ +/* in order not to perculate this line up, + * we read 72(%esi) very near to this location + */ + movq %mm6, 8*9(%esi) /* out9 */ + paddsw %mm1, %mm0 /* V161 */ + movq %mm3, MUNG(scratch5) /* out5 */ + psubsw %mm1, %mm5 /* V166 ; free mm1 */ + movq %mm4, 8*11(%esi) /* out11 */ + psraw $4, %mm5 + movq %mm0, MUNG(scratch3) /* out3 */ + movq %mm2, %mm4 /* duplicate V140 */ + movq %mm5, 8*13(%esi) /* out13 */ + paddsw %mm7, %mm2 /* V160 */ +/* moved from the next block */ + movq 8(%esi), %mm0 + psubsw %mm7, %mm4 /* V167 ; free mm7 */ +/* moved from the next block */ + movq 8*3(%esi), %mm7 + psraw $4, %mm4 + movq %mm2, MUNG(scratch1) /* out1 */ +/* moved from the next block */ + movq %mm0, %mm1 + movq %mm4, 8*15(%esi) /* out15 */ +/* moved from the next block */ + punpcklwd %mm7, %mm0 +/* transpose - M2 parts + * moved up to the prev block + * movq 8(%esi), %mm0 + * movq 8*3(%esi), %mm7 + * movq %mm0, %mm1 + * punpcklwd %mm7, %mm0 + */ + movq 8*5(%esi), %mm5 + punpckhwd %mm7, %mm1 + movq 8*7(%esi), %mm4 + movq %mm5, %mm3 +/* shuffle the data and write the lower parts of the trasposed in 4 dwords */ + movd %mm0, 8*8(%esi) /* LS part of tmt8 */ + punpcklwd %mm4, %mm5 + movd %mm1, 8*12(%esi) /* LS part of tmt12 */ + punpckhwd %mm4, %mm3 + movd %mm5, 8*8+4(%esi) /* MS part of tmt8 */ + punpckhdq %mm5, %mm0 /* tmt10 */ + movd %mm3, 8*12+4(%esi) /* MS part of tmt12 */ + punpckhdq %mm3, %mm1 /* tmt14 */ +/* transpose - M1 parts */ + movq (%esi), %mm7 + movq 8*2(%esi), %mm2 + movq %mm7, %mm6 + movq 8*4(%esi), %mm5 + punpcklwd %mm2, %mm7 + movq 8*6(%esi), %mm4 + punpckhwd %mm2, %mm6 /* free mm2 */ + movq %mm5, %mm3 + punpcklwd %mm4, %mm5 + punpckhwd %mm4, %mm3 /* free mm4 */ + movq %mm7, %mm2 + movq %mm6, %mm4 + punpckldq %mm5, %mm7 /* tmt0 */ + punpckhdq %mm5, %mm2 /* tmt2 ; free mm5 */ +/* shuffle the rest of the data, and write it with 2 mmword writes */ + punpckldq %mm3, %mm6 /* tmt4 */ +/* moved from next block */ + movq %mm2, %mm5 /* duplicate tmt2 */ + punpckhdq %mm3, %mm4 /* tmt6 ; free mm3 */ +/* moved from next block */ + movq %mm0, %mm3 /* duplicate tmt10 */ +/* column 0: odd part (after transpose) + *moved up to prev block + * movq %mm0, %mm3 duplicate tmt10 + * movq %mm2, %mm5 duplicate tmt2 + */ + psubsw %mm4, %mm0 /* V110 */ + paddsw %mm4, %mm3 /* V113 ; free mm4 */ + movq %mm0, %mm4 /* duplicate V110 */ + paddsw %mm1, %mm2 /* V111 */ + pmulhw MUNG(x539f539f539f539f), %mm0 /* 21407-> V117 */ + psubsw %mm1, %mm5 /* V112 ; free mm1 */ + psubsw %mm5, %mm4 /* V116 */ + movq %mm2, %mm1 /* duplicate V111 */ + pmulhw MUNG(x4546454645464546), %mm5 /* 17734-> V119 */ + psubsw %mm3, %mm2 /* V114 */ + pmulhw MUNG(x61f861f861f861f8), %mm4 /* 25080-> V120 */ + paddsw %mm3, %mm1 /* V115 ; free mm3 */ + pmulhw MUNG(x5a825a825a825a82), %mm2 /* 23170-> V118 */ + psllw $2, %mm0 /* t266 */ + movq %mm1, (%esi) /* save V115 */ + psllw $1, %mm5 /* t268 */ + psubsw %mm4, %mm5 /* V122 */ + psubsw %mm0, %mm4 /* V121 ; free mm0 */ + psllw $1, %mm5 /* t270 */ + psubsw %mm1, %mm5 /* V123 ; free mm1 */ + psllw $2, %mm2 /* t272 */ + psubsw %mm5, %mm2 /* V124 (keep V123) */ + psllw $1, %mm4 /* t274 */ + movq %mm5, 8*2(%esi) /* save V123 ; free mm5 */ + paddsw %mm2, %mm4 /* V125 (keep V124) */ +/* column 0: even part (after transpose) */ + movq 8*12(%esi), %mm0 /* tmt12 */ + movq %mm6, %mm3 /* duplicate tmt4 */ + psubsw %mm0, %mm6 /* V100 */ + paddsw %mm0, %mm3 /* V101 ; free mm0 */ + pmulhw MUNG(x5a825a825a825a82), %mm6 /* 23170 ->V102 */ + movq %mm7, %mm5 /* duplicate tmt0 */ + movq 8*8(%esi), %mm1 /* tmt8 */ + paddsw %mm1, %mm7 /* V103 */ + psubsw %mm1, %mm5 /* V104 ; free mm1 */ + movq %mm7, %mm0 /* duplicate V103 */ + psllw $2, %mm6 /* t245 */ + paddsw %mm3, %mm7 /* V106 */ + movq %mm5, %mm1 /* duplicate V104 */ + psubsw %mm3, %mm6 /* V105 */ + psubsw %mm3, %mm0 /* V109; free mm3 */ + paddsw %mm6, %mm5 /* V107 */ + psubsw %mm6, %mm1 /* V108 ; free mm6 */ +/* column 0: output butterfly (after transform) */ + movq %mm1, %mm3 /* duplicate V108 */ + paddsw %mm2, %mm1 /* out4 */ + psraw $4, %mm1 + psubsw %mm2, %mm3 /* out10 ; free mm2 */ + psraw $4, %mm3 + movq %mm0, %mm6 /* duplicate V109 */ + movq %mm1, 8*4(%esi) /* out4 ; free mm1 */ + psubsw %mm4, %mm0 /* out6 */ + movq %mm3, 8*10(%esi) /* out10 ; free mm3 */ + psraw $4, %mm0 + paddsw %mm4, %mm6 /* out8 ; free mm4 */ + movq %mm7, %mm1 /* duplicate V106 */ + movq %mm0, 8*6(%esi) /* out6 ; free mm0 */ + psraw $4, %mm6 + movq (%esi), %mm4 /* V115 */ + movq %mm6, 8*8(%esi) /* out8 ; free mm6 */ + movq %mm5, %mm2 /* duplicate V107 */ + movq 8*2(%esi), %mm3 /* V123 */ + paddsw %mm4, %mm7 /* out0 */ +/* moved up from next block */ + movq MUNG(scratch3), %mm0 + psraw $4, %mm7 +/* moved up from next block */ + movq MUNG(scratch5), %mm6 + psubsw %mm4, %mm1 /* out14 ; free mm4 */ + paddsw %mm3, %mm5 /* out2 */ + psraw $4, %mm1 + movq %mm7, (%esi) /* out0 ; free mm7 */ + psraw $4, %mm5 + movq %mm1, 8*14(%esi) /* out14 ; free mm1 */ + psubsw %mm3, %mm2 /* out12 ; free mm3 */ + movq %mm5, 8*2(%esi) /* out2 ; free mm5 */ + psraw $4, %mm2 +/* moved up to the prev block */ + movq MUNG(scratch7), %mm4 +/* moved up to the prev block */ + psraw $4, %mm0 + movq %mm2, 8*12(%esi) /* out12 ; free mm2 */ +/* moved up to the prev block */ + psraw $4, %mm6 +/* move back the data to its correct place +* moved up to the prev block + * movq MUNG(scratch3), %mm0 + * movq MUNG(scratch5), %mm6 + * movq MUNG(scratch7), %mm4 + * psraw $4, %mm0 + * psraw $4, %mm6 +*/ + movq MUNG(scratch1), %mm1 + psraw $4, %mm4 + movq %mm0, 8*3(%esi) /* out3 */ + psraw $4, %mm1 + movq %mm6, 8*5(%esi) /* out5 */ + movq %mm4, 8*7(%esi) /* out7 */ + movq %mm1, 8(%esi) /* out1 */ + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + movl %ebp,%esp + popl %ebp + ret +.Lfe1: + .size IDCT_mmx,.Lfe1-IDCT_mmx + +#ifdef __PIC__ + .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits +.globl __i686.get_pc_thunk.bx + .hidden __i686.get_pc_thunk.bx + .type __i686.get_pc_thunk.bx,@function + __i686.get_pc_thunk.bx: + movl (%esp), %ebx + ret +#endif + +#endif /* i386 && USE_MMX */ + +#ifdef __ELF__ +.section .note.GNU-stack,"",%progbits +#endif diff --git a/smpeg/src/video/motionvec.cpp b/smpeg/src/video/motionvec.cpp new file mode 100644 index 0000000..9f17a73 --- /dev/null +++ b/smpeg/src/video/motionvec.cpp @@ -0,0 +1,234 @@ +/* + * motionvector.c -- + * + * Procedures to compute motion vectors. + * + */ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "util.h" +#include "video.h" +#include "proto.h" + +/* + Changes to make the code reentrant: + deglobalize curVidStream + Additional changes: + none + -lsh@cs.brown.edu (Loring Holden) +*/ + + +/* + *-------------------------------------------------------------- + * + * ComputeVector -- + * + * Computes motion vector given parameters previously parsed + * and reconstructed. + * + * Results: + * Reconstructed motion vector info is put into recon_* parameters + * passed to this function. Also updated previous motion vector + * information. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +#define ComputeVector(recon_right_ptr, recon_down_ptr, recon_right_prev, recon_down_prev, f, full_pel_vector, motion_h_code, motion_v_code, motion_h_r, motion_v_r) \ + \ +{ \ + int comp_h_r, comp_v_r; \ + int right_little, right_big, down_little, down_big; \ + int max, min, new_vector; \ + \ + /* The following procedure for the reconstruction of motion vectors \ + is a direct and simple implementation of the instructions given \ + in the mpeg December 1991 standard draft. \ + */ \ + \ + if (f == 1 || motion_h_code == 0) \ + comp_h_r = 0; \ + else \ + comp_h_r = f - 1 - motion_h_r; \ + \ + if (f == 1 || motion_v_code == 0) \ + comp_v_r = 0; \ + else \ + comp_v_r = f - 1 - motion_v_r; \ + \ + right_little = motion_h_code * f; \ + if (right_little == 0) \ + right_big = 0; \ + else { \ + if (right_little > 0) { \ + right_little = right_little - comp_h_r; \ + right_big = right_little - 32 * f; \ + } \ + else { \ + right_little = right_little + comp_h_r; \ + right_big = right_little + 32 * f; \ + } \ + } \ + \ + down_little = motion_v_code * f; \ + if (down_little == 0) \ + down_big = 0; \ + else { \ + if (down_little > 0) { \ + down_little = down_little - comp_v_r; \ + down_big = down_little - 32 * f; \ + } \ + else { \ + down_little = down_little + comp_v_r; \ + down_big = down_little + 32 * f; \ + } \ + } \ + \ + max = 16 * f - 1; \ + min = -16 * f; \ + \ + new_vector = recon_right_prev + right_little; \ + \ + if (new_vector <= max && new_vector >= min) \ + *recon_right_ptr = recon_right_prev + right_little; \ + /* just new_vector */ \ + else \ + *recon_right_ptr = recon_right_prev + right_big; \ + recon_right_prev = *recon_right_ptr; \ + if (full_pel_vector) \ + *recon_right_ptr = *recon_right_ptr << 1; \ + \ + new_vector = recon_down_prev + down_little; \ + if (new_vector <= max && new_vector >= min) \ + *recon_down_ptr = recon_down_prev + down_little; \ + /* just new_vector */ \ + else \ + *recon_down_ptr = recon_down_prev + down_big; \ + recon_down_prev = *recon_down_ptr; \ + if (full_pel_vector) \ + *recon_down_ptr = *recon_down_ptr << 1; \ +} + + +/* + *-------------------------------------------------------------- + * + * ComputeForwVector -- + * + * Computes forward motion vector by calling ComputeVector + * with appropriate parameters. + * + * Results: + * Reconstructed motion vector placed in recon_right_for_ptr and + * recon_down_for_ptr. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void ComputeForwVector( int* recon_right_for_ptr, int* recon_down_for_ptr, + VidStream* the_stream ) +{ + + Pict *picture; + Macroblock *mblock; + + picture = &(the_stream->picture); + mblock = &(the_stream->mblock); + + ComputeVector(recon_right_for_ptr, recon_down_for_ptr, + mblock->recon_right_for_prev, + mblock->recon_down_for_prev, + (int) picture->forw_f, + picture->full_pel_forw_vector, + mblock->motion_h_forw_code, mblock->motion_v_forw_code, + mblock->motion_h_forw_r, mblock->motion_v_forw_r); +} + + +/* + *-------------------------------------------------------------- + * + * ComputeBackVector -- + * + * Computes backward motion vector by calling ComputeVector + * with appropriate parameters. + * + * Results: + * Reconstructed motion vector placed in recon_right_back_ptr and + * recon_down_back_ptr. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void ComputeBackVector( int* recon_right_back_ptr, int* recon_down_back_ptr, + VidStream* the_stream ) +{ + Pict *picture; + Macroblock *mblock; + + picture = &(the_stream->picture); + mblock = &(the_stream->mblock); + + ComputeVector(recon_right_back_ptr, recon_down_back_ptr, + mblock->recon_right_back_prev, + mblock->recon_down_back_prev, + (int) picture->back_f, + picture->full_pel_back_vector, + mblock->motion_h_back_code, mblock->motion_v_back_code, + mblock->motion_h_back_r, mblock->motion_v_back_r); + +} + + +/* EOF */ diff --git a/smpeg/src/video/parseblock.cpp b/smpeg/src/video/parseblock.cpp new file mode 100644 index 0000000..965b783 --- /dev/null +++ b/smpeg/src/video/parseblock.cpp @@ -0,0 +1,693 @@ +/* + * parseblock.c -- + * + * Procedures to read in the values of a block and store them + * in a place where the player can use them. + * + */ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#define NO_SANITY_CHECKS +#include +#include +#include "util.h" +#include "video.h" +#include "proto.h" +#include "decoders.h" +#ifdef USE_MMX +extern "C" { +extern unsigned int cpu_flags(void); +extern void IDCT_mmx(DCTBLOCK data); +}; +#define mmx_ok() (cpu_flags() & 0x800000) +#endif + + +/* + Changes to make the code reentrant: + deglobalized: curBits, bitOffset, bitLength, bitBuffer, curVidStream, + zigzag_direct now a const int variable initialized once + -lsh@cs.brown.edu (Loring Holden) + */ + +/* External declarations. */ +#ifdef DCPREC +extern int dcprec; +#endif + +/* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */ + +#define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1)) + + +#ifdef USE_MMX + +/* This is global for the ditherer as well */ +int mmx_available = 0; + +static const int zigzag_direct_nommx[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, + 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, + 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63}; + + +static const int zigzag_direct_mmx[64] = { + + 0*8+0/* 0*/, 1*8+0/* 1*/, 0*8+1/* 8*/, 0*8+2/*16*/, 1*8+1/* 9*/, 2*8+0/* 2*/, 3*8+0/* 3*/, 2*8+1/*10*/, + 1*8+2/*17*/, 0*8+3/*24*/, 0*8+4/*32*/, 1*8+3/*25*/, 2*8+2/*18*/, 3*8+1/*11*/, 4*8+0/* 4*/, 5*8+0/* 5*/, + 4*8+1/*12*/, 5*8+2/*19*/, 2*8+3/*26*/, 1*8+4/*33*/, 0*8+5/*40*/, 0*8+6/*48*/, 1*8+5/*41*/, 2*8+4/*34*/, + 3*8+3/*27*/, 4*8+2/*20*/, 5*8+1/*13*/, 6*8+0/* 6*/, 7*8+0/* 7*/, 6*8+1/*14*/, 5*8+2/*21*/, 4*8+3/*28*/, + 3*8+4/*35*/, 2*8+5/*42*/, 1*8+6/*49*/, 0*8+7/*56*/, 1*8+7/*57*/, 2*8+6/*50*/, 3*8+5/*43*/, 4*8+4/*36*/, + 5*8+3/*29*/, 6*8+2/*22*/, 7*8+1/*15*/, 7*8+2/*23*/, 6*8+3/*30*/, 5*8+4/*37*/, 4*8+5/*44*/, 3*8+6/*51*/, + 2*8+7/*58*/, 3*8+7/*59*/, 4*8+6/*52*/, 5*8+5/*45*/, 6*8+4/*38*/, 7*8+3/*31*/, 7*8+4/*39*/, 6*8+5/*46*/, + 7*8+6/*53*/, 4*8+7/*60*/, 5*8+7/*61*/, 6*8+6/*54*/, 7*8+5/*47*/, 7*8+6/*55*/, 6*8+7/*62*/, 7*8+7/*63*/ +}; + +static int zigzag_direct[256]; + +void InitIDCT(void) +{ + int i; + char *use_mmx; + + use_mmx = getenv("SMPEG_USE_MMX"); + if ( use_mmx ) { + mmx_available = atoi(use_mmx); + } else { + mmx_available = mmx_ok(); + } + if (mmx_available) { +//printf("Using MMX IDCT algorithm!\n"); + for(i=0;i<64;i++) { + zigzag_direct[i]=zigzag_direct_mmx[i]; + } + } else { + for(i=0;i<64;i++) { + zigzag_direct[i]=zigzag_direct_nommx[i]; + } + } + while ( i < 256 ) + zigzag_direct[i++] = 0; +} + +#else +/* Array mapping zigzag to array pointer offset. */ +const int zigzag_direct[64] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, + 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, + 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + +void InitIDCT(void) +{ + return; +} +#endif + +/* + *-------------------------------------------------------------- + * + * ParseReconBlock -- + * + * Parse values for block structure from bitstream. + * n is an indication of the position of the block within + * the macroblock (i.e. 0-5) and indicates the type of + * block (i.e. luminance or chrominance). Reconstructs + * coefficients from values parsed and puts in + * block.dct_recon array in vid stream structure. + * sparseFlag is set when the block contains only one + * coeffictient and is used by the IDCT. + * + * Results: + * + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +#define DCT_recon blockPtr->dct_recon +#define DCT_dc_y_past blockPtr->dct_dc_y_past +#define DCT_dc_cr_past blockPtr->dct_dc_cr_past +#define DCT_dc_cb_past blockPtr->dct_dc_cb_past + +#define DECODE_DCT_COEFF_FIRST DecodeDCTCoeffFirst +#define DECODE_DCT_COEFF_NEXT DecodeDCTCoeffNext + + +/* + * Profiling results: + * This function only takes about 0.01ms per call, but is called many + * many times, taking about 15% of the total time used by playback. + * + *-------------------------------------------------------------- + */ +void ParseReconBlock( int n, VidStream* vid_stream ) +{ + Block *blockPtr = &vid_stream->block; + int coeffCount=0; + + if (vid_stream->buf_length < 100) + correct_underflow(vid_stream); + + int diff; + int size, level=0, i, run, pos, coeff; +#ifdef USE_ATI + long int *reconptr; +#else + short int *reconptr; +#endif + unsigned char *iqmatrixptr, *niqmatrixptr; + int qscale; + +#ifdef USE_ATI + reconptr = DCT_recon[n]; + memset(reconptr, 0, 130*sizeof(reconptr[0])); +#else + reconptr = DCT_recon[0]; + +#if 0 + /* + * Hand coded version of memset that's a little faster... + * Old call: + * memset((char *) DCT_recon, 0, 64*sizeof(short int)); + */ + { + INT32 *p; + p = (INT32 *) reconptr; + + p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = p[8] = p[9] = + p[10] = p[11] = p[12] = p[13] = p[14] = p[15] = p[16] = p[17] = p[18] = + p[19] = p[20] = p[21] = p[22] = p[23] = p[24] = p[25] = p[26] = p[27] = + p[28] = p[29] = p[30] = p[31] = 0; + + } +#else + memset(reconptr, 0, 64*sizeof(reconptr[0])); +#endif +#endif + + if (vid_stream->mblock.mb_intra) { + + if (n < 4) { + + /* + * Get the luminance bits. This code has been hand optimized to + * get by the normal bit parsing routines. We get some speedup + * by grabbing the next 16 bits and parsing things locally. + * Thus, calls are translated as: + * + * show_bitsX <--> next16bits >> (16-X) + * get_bitsX <--> val = next16bits >> (16-flushed-X); + * flushed += X; + * next16bits &= bitMask[flushed]; + * flush_bitsX <--> flushed += X; + * next16bits &= bitMask[flushed]; + * + * I've streamlined the code a lot, so that we don't have to mask + * out the low order bits and a few of the extra adds are removed. + * bsmith + */ + unsigned int next16bits, index, flushed; + + show_bits16(next16bits); + index = next16bits >> (16-5); + if (index < 31) { + size = dct_dc_size_luminance[index].value; + flushed = dct_dc_size_luminance[index].num_bits; + } else { + index = next16bits >> (16-9); + index -= 0x1f0; + size = dct_dc_size_luminance1[index].value; + flushed = dct_dc_size_luminance1[index].num_bits; + } + next16bits &= bitMask[16+flushed]; + + if (size != 0) { + flushed += size; + diff = next16bits >> (16-flushed); + if (!(diff & bitTest[32-size])) { + diff = rBitMask[size] | (diff + 1); + } + diff <<= 3; + } else { + diff = 0; + } + flush_bits(flushed); + +#ifdef USE_ATI + if ( (n == 0) && ((vid_stream->mblock.mb_address - + vid_stream->mblock.past_intra_addr) > 1) ) { + DCT_dc_y_past = diff; + } else { + DCT_dc_y_past += diff; + } + *reconptr++ = 0; + *reconptr++ = DCT_dc_y_past; +#else + if ( (n == 0) && ((vid_stream->mblock.mb_address - + vid_stream->mblock.past_intra_addr) > 1) ) { + coeff = diff + 1024; + } else { + coeff = diff + DCT_dc_y_past; + } + DCT_dc_y_past = coeff; +#endif + } else { /* n = 4 or 5 */ + + /* + * Get the chrominance bits. This code has been hand optimized to + * as described above + */ + + unsigned int next16bits, index, flushed; + + show_bits16(next16bits); + index = next16bits >> (16-5); + if (index < 31) { + size = dct_dc_size_chrominance[index].value; + flushed = dct_dc_size_chrominance[index].num_bits; + } else { + index = next16bits >> (16-10); + index -= 0x3e0; + size = dct_dc_size_chrominance1[index].value; + flushed = dct_dc_size_chrominance1[index].num_bits; + } + next16bits &= bitMask[16+flushed]; + + if (size != 0) { + flushed += size; + diff = next16bits >> (16-flushed); + if (!(diff & bitTest[32-size])) { + diff = rBitMask[size] | (diff + 1); + } + diff <<= 3; + } else { + diff = 0; + } + flush_bits(flushed); + +#ifdef USE_ATI + *reconptr++ = 0; + + if(n == 5) { + if (vid_stream->mblock.mb_address - + vid_stream->mblock.past_intra_addr > 1) { + DCT_dc_cr_past = diff; + } else { + DCT_dc_cr_past += diff; + } + *reconptr++ = DCT_dc_cr_past; + } else { + if (vid_stream->mblock.mb_address - + vid_stream->mblock.past_intra_addr > 1) { + DCT_dc_cb_past = diff; + } else { + DCT_dc_cb_past += diff; + } + *reconptr++ = DCT_dc_cb_past; + } +#else + + /* We test 5 first; a result of the mixup of Cr and Cb */ + coeff = diff; + if (n == 5) { + if (vid_stream->mblock.mb_address - + vid_stream->mblock.past_intra_addr > 1) { + coeff += 1024; + } else { + coeff += DCT_dc_cr_past; + } + DCT_dc_cr_past = coeff; + } else { + if (vid_stream->mblock.mb_address - + vid_stream->mblock.past_intra_addr > 1) { + coeff += 1024; + } else { + coeff += DCT_dc_cb_past; + } + DCT_dc_cb_past = coeff; + } +#endif + } + +#ifndef USE_ATI + *reconptr = coeff; +#ifdef USE_MMX + if ( mmx_available ) { + *reconptr <<= 4; + } +#endif /* USE_MMX */ +#endif /* USE_ATI */ + + pos = 0; + coeffCount = (coeff != 0); + + i = 0; + + if (vid_stream->picture.code_type != 4) { + + qscale = vid_stream->slice.quant_scale; + iqmatrixptr = vid_stream->intra_quant_matrix[0]; + + while(1) { + + DECODE_DCT_COEFF_NEXT(run, level); + + if (run >= END_OF_BLOCK) break; + + i = i + run + 1; + + pos = zigzag_direct[i&0x3f]; + + /* quantizes and oddifies each coefficient */ + if (level < 0) { + coeff = ((level<<1) * qscale * + ((int) (iqmatrixptr[pos]))) / 16; + coeff += (1 - (coeff & 1)); + } else { + coeff = ((level<<1) * qscale * + ((int) (*(iqmatrixptr+pos)))) >> 4; + coeff -= (1 - (coeff & 1)); + } + +#ifdef USE_ATI + *reconptr++ = run; + *reconptr++ = coeff; +#else + +#ifdef USE_MMX + if ( mmx_available ) + coeff *= 16; +#endif + +#ifdef QUANT_CHECK + printf ("coeff: %d\n", coeff); +#endif + + reconptr[pos] = coeff; + coeffCount++; +#endif /* USE_ATI */ + } + +#ifdef QUANT_CHECK + printf ("\n"); +#endif + +#ifdef USE_ATI + /* mark end of block */ + *reconptr++ = 0xFFFFFFFF; +#endif + +#ifdef ANALYSIS + { + extern unsigned int *mbCoeffPtr; + mbCoeffPtr[pos]++; + } +#endif + + flush_bits(2); + goto end; + } + } else { /* non-intra-coded macroblock */ + + niqmatrixptr = vid_stream->non_intra_quant_matrix[0]; + qscale = vid_stream->slice.quant_scale; + + DECODE_DCT_COEFF_FIRST(run, level); + + i = run; + + pos = zigzag_direct[i&0x3f]; + + /* quantizes and oddifies each coefficient */ + if (level < 0) { + coeff = (((level<<1) - 1) * qscale * + ((int) (niqmatrixptr[pos]))) / 16; + if ((coeff & 1) == 0) {coeff = coeff + 1;} + } else { + coeff = (((level<<1) + 1) * qscale * + ((int) (*(niqmatrixptr+pos)))) >> 4; + coeff = (coeff-1) | 1; /* equivalent to: if ((coeff&1)==0) coeff = coeff - 1; */ + } + +#ifdef USE_ATI + *reconptr++ = run; + *reconptr++ = coeff; +#else + +#ifdef USE_MMX + if ( mmx_available ) + coeff *= 16; +#endif + + reconptr[pos] = coeff; + if (coeff) { + coeffCount = 1; + } +#endif /* USE_ATI */ + + if (vid_stream->picture.code_type != 4) { + + while(1) { + + DECODE_DCT_COEFF_NEXT(run, level); + + if (run >= END_OF_BLOCK) { + break; + } + + i = i+run+1; + + pos = zigzag_direct[i&0x3f]; + + if (level < 0) { + coeff = (((level<<1) - 1) * qscale * + ((int) (niqmatrixptr[pos]))) / 16; + if ((coeff & 1) == 0) {coeff = coeff + 1;} + } else { + coeff = (((level<<1) + 1) * qscale * + ((int) (*(niqmatrixptr+pos)))) >> 4; + coeff = (coeff-1) | 1; /* equivalent to: if ((coeff&1)==0) coeff = coeff - 1; */ + } + +#ifdef USE_ATI + *reconptr++ = run; + *reconptr++ = coeff; +#else + +#ifdef USE_MMX + if ( mmx_available ) + coeff *= 16; +#endif + reconptr[pos] = coeff; + coeffCount++; +#endif /* USE_ATI */ + } /* end while */ + +#ifdef USE_ATI + /* mark end of block */ + *reconptr++ = 0xFFFFFFFF; +#endif + +#ifdef ANALYSIS + { + extern unsigned int *mbCoeffPtr; + mbCoeffPtr[pos]++; + } +#endif + + flush_bits(2); + + goto end; + } /* end if (vid_stream->picture.code_type != 4) */ + } + + end: + +#ifdef USE_ATI + return; +#else + + if( ! vid_stream->_skipFrame || (vid_stream->picture.code_type != B_TYPE) ) + { + if( coeffCount == 1 ) + { +#ifdef USE_MMX + if ( mmx_available ) + IDCT_mmx(reconptr); + else + j_rev_dct_sparse (reconptr, pos); +#else + j_rev_dct_sparse (reconptr, pos); +#endif + } + else + { +#ifdef FLOATDCT + if (qualityFlag) + { + float_idct(reconptr); + } + else +#endif +#ifdef USE_MMX + if ( mmx_available ) + IDCT_mmx(reconptr); + else + j_rev_dct(reconptr); +#else + j_rev_dct(reconptr); +#endif + } + } +#ifdef USE_MMX + if ( mmx_available ) { + __asm__ ("emms"); + } +#endif +#endif +} + +#undef DCT_recon +#undef DCT_dc_y_past +#undef DCT_dc_cr_past +#undef DCT_dc_cb_past + + +/* + *-------------------------------------------------------------- + * + * ParseAwayBlock -- + * + * Parses off block values, throwing them away. + * Used with grayscale dithering. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void ParseAwayBlock( int n, VidStream* vid_stream ) +{ + unsigned int diff; + unsigned int size, run; + int level; + + if (vid_stream->buf_length < 100) + correct_underflow(vid_stream); + + if (vid_stream->mblock.mb_intra) { + + /* If the block is a luminance block... */ + + if (n < 4) { + + /* Parse and decode size of first coefficient. */ + + DecodeDCTDCSizeLum(size); + + /* Parse first coefficient. */ + + if (size != 0) { + get_bitsn(size, diff); + } + } + + /* Otherwise, block is chrominance block... */ + + else { + + /* Parse and decode size of first coefficient. */ + + DecodeDCTDCSizeChrom(size); + + /* Parse first coefficient. */ + + if (size != 0) { + get_bitsn(size, diff); + } + } + } + + /* Otherwise, block is not intracoded... */ + + else { + + /* Decode and set first coefficient. */ + + DECODE_DCT_COEFF_FIRST(run, level); + } + + /* If picture is not D type (i.e. I, P, or B)... */ + + if (vid_stream->picture.code_type != 4) { + + /* While end of macroblock has not been reached... */ + + while (1) { + + /* Get the dct_coeff_next */ + + DECODE_DCT_COEFF_NEXT(run, level); + + if (run >= END_OF_BLOCK) break; + } + + /* End_of_block */ + + flush_bits(2); + } +} + + +/* EOF */ diff --git a/smpeg/src/video/proto.h b/smpeg/src/video/proto.h new file mode 100644 index 0000000..50ab1e5 --- /dev/null +++ b/smpeg/src/video/proto.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifdef WIN32 +#define __STDC__ 1 +#endif +#ifdef __STDC__ +# define P(s) s +#include /* used by almost all modules */ +#else +# define P(s) () +#endif + +/* util.c */ +void correct_underflow P((VidStream *vid_stream )); +int next_bits P((int num , unsigned int mask , VidStream *vid_stream )); +char *get_ext_data P((VidStream *vid_stream )); +int next_start_code P((VidStream *vid_stream)); +char *get_extra_bit_info P((VidStream *vid_stream )); + +/* video.c */ +void init_stats P((void )); +void PrintAllStats P((VidStream *vid_stream )); +double ReadSysClock P((void )); +void PrintTimeInfo P(( VidStream *vid_stream )); +void InitCrop P((void )); +void InitIDCT P((void )); +VidStream *NewVidStream P((unsigned int buffer_len )); +void ResetVidStream P((VidStream *vid )); +void DestroyVidStream P((VidStream *astream )); +PictImage *NewPictImage P(( VidStream *vid_stream )); +bool InitPictImages P(( VidStream *vid_stream, int w, int h, SDL_Surface *dst )); +void DestroyPictImage P(( VidStream *vid_stream, PictImage *apictimage )); +VidStream *mpegVidRsrc P((TimeStamp time_stamp,VidStream *vid_stream, int first )); +void SetBFlag P((BOOLEAN val )); +void SetPFlag P((BOOLEAN val )); + +/* parseblock.c */ +void ParseReconBlock P((int n, VidStream *vid_stream )); +void ParseAwayBlock P((int n , VidStream *vid_stream )); + +/* motionvec.c */ +void ComputeForwVector P((int *recon_right_for_ptr , int *recon_down_for_ptr , VidStream *the_stream )); +void ComputeBackVector P((int *recon_right_back_ptr , int *recon_down_back_ptr, VidStream *the_stream )); + +/* decoders.c */ +void decodeInitTables P((void )); +void decodeDCTDCSizeLum P((unsigned int *value )); +void decodeDCTDCSizeChrom P((unsigned int *value )); +void decodeDCTCoeffFirst P((unsigned int *run , int *level )); +void decodeDCTCoeffNext P((unsigned int *run , int *level )); + +/* gdith.c */ +void InitColor P((void )); + +/* fs2.c */ +void InitFS2Dither P((void )); +void FS2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *disp , int rows , int cols )); + +/* fs2fast.c */ +void InitFS2FastDither P((void )); +void FS2FastDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); + +/* fs4.c */ +void InitFS4Dither P((void )); +void FS4DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *disp , int rows , int cols )); + +/* hybrid.c */ +void InitHybridDither P((void )); +void HybridDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); + +/* hybriderr.c */ +void InitHybridErrorDither P((void )); +void HybridErrorDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); + +/* gray.c */ +void GrayDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); +void Gray2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); +void Gray16DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); +void Gray216DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); +void Gray32DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); +void Gray232DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); + +/* mono.c */ +void MonoThresholdImage(unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int h, int w); +void MonoDitherImage(unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int h, int w); + +/* jrevdct.c */ +void init_pre_idct P((void )); +void j_rev_dct_sparse P((DCTBLOCK data , int pos )); +void j_rev_dct P((DCTBLOCK data )); +void j_rev_dct_sparse P((DCTBLOCK data , int pos )); +void j_rev_dct P((DCTBLOCK data )); + +/* floatdct.c */ +void init_float_idct P((void )); +void float_idct P((short* block )); + +/* 16bit.c */ +void InitColorDither P(( int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask )); +void Color16DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod )); +void Color16DitherImageMMX P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod )); +void Color32DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod )); +void Color32DitherImageMMX P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod )); +void Color16DitherImageModInterlace P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int start )); +void Color32DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int rows , int cols )); +void ScaleColor16DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int scale )); +void ScaleColor32DitherImageMod P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int scale )); +void ScaleColor16DitherImageModInterlace P((unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod, int start, int scale )); +void Twox2Color32DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int rows , int cols )); + +/* ordered.c */ +void InitOrderedDither P((void )); +void OrderedDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); + +/* ordered2.c */ +void InitOrdered2Dither P((void )); +void Ordered2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); + +/* mb_ordered.c */ +void InitMBOrderedDither P((void )); +void MBOrderedDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w, char *ditherFlags )); +void MBOrderedDitherDisplayCopy P((VidStream *vid_stream , int mb_addr , int motion_forw , int r_right_forw , int r_down_forw , int motion_back , int r_right_back , int r_down_back , unsigned char *past , unsigned char *future )); + +/* readfile.c */ +void SeekStream P((VidStream *vid_stream )); +void clear_data_stream P(( VidStream *vid_stream)); +int get_more_data P(( VidStream *vid_stream )); +int pure_get_more_data P((unsigned int *buf_start , int max_length , int *length_ptr , unsigned int **buf_ptr, VidStream *vid_stream )); +int read_sys P(( VidStream *vid_stream, unsigned int start )); +int ReadStartCode P(( unsigned int *startCode, VidStream *vid_stream )); + +int ReadPackHeader P(( + double *systemClockTime, + unsigned long *muxRate, + VidStream *vid_stream )); + +int ReadSystemHeader P(( VidStream *vid_stream )); + +int find_start_code P(( FILE *input )); + +int ReadPacket P(( unsigned char packetID, VidStream *vid_stream )); + +void ReadTimeStamp P(( + unsigned char *inputBuffer, + unsigned char *hiBit, + unsigned long *low4Bytes)); + +void ReadSTD P(( + unsigned char *inputBuffer, + unsigned char *stdBufferScale, + unsigned long *stdBufferSize)); + +void ReadRate P(( + unsigned char *inputBuffer, + unsigned long *rate)); + +int MakeFloatClockTime P(( + unsigned char hiBit, + unsigned long low4Bytes, + double *floatClockTime)); + + +#ifndef NOCONTROLS +/* ctrlbar.c */ +double StopWatch P((int action )); +bool WindowMapped P((Display *dsp, XEvent *xev, char *window )); +bool IfEventType P((Display *dsp, XEvent *xev, char *type )); +void MakeControlBar P(( XInfo *xinfo )); +void UpdateFrameTotal P((Display *display)); +void UpdateControlDisplay P((Display *display)); +void ControlBar P((VidStream **vid_stream, XInfo *xinfo, int numMovies )); +void ControlLoop P((VidStream **theStream, XInfo *xinfo, int numStreams )); +#endif /* !NOCONTROLS */ + +#undef P diff --git a/smpeg/src/video/readfile.cpp b/smpeg/src/video/readfile.cpp new file mode 100644 index 0000000..3e963d5 --- /dev/null +++ b/smpeg/src/video/readfile.cpp @@ -0,0 +1,184 @@ +/* + * readfile.c -- + * + * Procedures concerned with reading data and parsing + * start codes from MPEG files. + * + */ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include +#ifdef __STDC__ +#include +#include +#endif +#include +#include + +#include "SDL_endian.h" +#include "video.h" +#include "proto.h" +#include "util.h" +#include "dither.h" + + +/* + Changes to make the code reentrant: + deglobalized: totNumFrames, realTimeStart, stream id vars, Prase_done, + swap, seekValue, input, EOF_flag, ReadPacket statics, sys_layer, + bitOffset, bitLength, bitBuffer, curVidStream + removed: [aud,sys,vid]Bytes + Additional changes: + get rid on ANSI C complaints about shifting + -lsh@cs.brown.edu (Loring Holden) + */ + +/* + *-------------------------------------------------------------- + * + * get_more_data -- + * + * Called by get_more_data to read in more data from + * video MPG files (non-system-layer) + * + * Results: + * Input buffer updated, buffer length updated. + * Returns 1 if data read, 0 if EOF, -1 if error. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +get_more_data( VidStream* vid_stream ) +{ + unsigned int *buf_start; + int length, num_read, i; + unsigned int request; + unsigned char *buffer, *mark; + unsigned int *lmark; + Sint32 timestamp_offset; + Uint32 data_pos; + + if (vid_stream->EOF_flag) return 0; + + buf_start = vid_stream->buf_start; + length = vid_stream->buf_length; + buffer = (unsigned char *) vid_stream->buffer; + + if (length > 0) { + memcpy((unsigned char *) buf_start, buffer, (unsigned int) (length*4)); + mark = ((unsigned char *) (buf_start + length)); + } + else { + mark = (unsigned char *) buf_start; + length = 0; + } + + request = (vid_stream->max_buf_length-length)*4; + + data_pos = vid_stream->_smpeg->mpeg->pos; + num_read = vid_stream->_smpeg->mpeg->copy_data((Uint8 *)mark, request); + + vid_stream->timestamp = vid_stream->_smpeg->mpeg->timestamp; + timestamp_offset = vid_stream->_smpeg->mpeg->timestamp_pos - data_pos; + vid_stream->timestamp_mark = (unsigned int *)(mark+timestamp_offset); + vid_stream->timestamp_used = false; + + /* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */ + { + int num_read_rounded; + unsigned char *index; + + num_read_rounded = 4*(num_read/4); + + /* this can happen only if num_readbuffer = buf_start; + + /* Make 32 bits after end equal to 0 and 32 + * bits after that equal to seq end code + * in order to prevent messy data from infinite + * recursion. + */ + + *(buf_start + length) = 0x0; + *(buf_start + length+1) = SEQ_END_CODE; + + vid_stream->EOF_flag = 1; + return 0; + } + + lmark = (unsigned int *) mark; + + num_read = num_read/4; + + for (i = 0; i < num_read; i++) { + *lmark = SDL_SwapBE32(*lmark); + lmark++; + } + + vid_stream->buffer = buf_start; + vid_stream->buf_length = length + num_read; + + return 1; +} + +/* EOF */ diff --git a/smpeg/src/video/util.cpp b/smpeg/src/video/util.cpp new file mode 100644 index 0000000..8b73d6b --- /dev/null +++ b/smpeg/src/video/util.cpp @@ -0,0 +1,499 @@ +/* + * util.c -- + * + * Miscellaneous utility procedures. + * + */ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "MPEG.h" + +#include +#include "video.h" +#include "proto.h" +#include "util.h" +#ifndef NOCONTROLS +#include "ctrlbar.h" +#endif + +/* + Changes to make the code reentrant: + de-globalized: totNumFrames, realTimeStart, vid_stream, sys_layer, + bitOffset, bitLength, bitBuffer, curVidStream + setjmp/longjmp replaced + + Additional changes: + only call DestroyVidStream up in mpegVidRsrc, not in correct_underflow + + -lsh@cs.brown.edu (Loring Holden) + */ + +/* Bit masks used by bit i/o operations. */ + +unsigned int nBitMask[] = { 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, + 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000, + 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, + 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, + 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, + 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00, + 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, + 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe}; + +unsigned int bitMask[] = { 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff, + 0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff, + 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff, + 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, + 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff, + 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff, + 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f, + 0x0000000f, 0x00000007, 0x00000003, 0x00000001}; + +unsigned int rBitMask[] = { 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8, + 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, + 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, + 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, + 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, + 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, + 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000, + 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000}; + +unsigned int bitTest[] = { 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001}; + + +/* + *-------------------------------------------------------------- + * + * correct_underflow -- + * + * Called when buffer does not have sufficient data to + * satisfy request for bits. + * Calls get_more_data, an application specific routine + * required to fill the buffer with more data. + * + * Results: + * None really. + * + * Side effects: + * buf_length and buffer fields may be changed. + * + *-------------------------------------------------------------- + */ + +void correct_underflow( VidStream* vid_stream ) +{ + int status; + + status = get_more_data(vid_stream); + + if (status < 0) { + if (!quietFlag) { + fprintf (stderr, "\n"); + perror("Unexpected read error."); + } + exit(1); + } + else if ((status == 0) && (vid_stream->buf_length < 1)) { + if (!quietFlag) { + fprintf(stderr, "\nImproper or missing sequence end code.\n"); + } +#ifdef ANALYSIS + PrintAllStats(vid_stream); +#endif + + vid_stream->film_has_ended=TRUE; + return; + } +#ifdef UTIL2 + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; +#else + vid_stream->curBits = *vid_stream->buffer; +#endif + +} + + +/* + *-------------------------------------------------------------- + * + * next_bits -- + * + * Compares next num bits to low order position in mask. + * Buffer pointer is NOT advanced. + * + * Results: + * TRUE, FALSE, or error code. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int next_bits( int num, unsigned int mask, VidStream* vid_stream ) +{ + unsigned int stream; + int ret_value; + +#if 0 + /* If no current stream, return error. */ + if (vid_stream == NULL) + return NO_VID_STREAM; +#endif + + /* Get next num bits, no buffer pointer advance. */ + + show_bitsn(num, stream); + + /* Compare bit stream and mask. Set return value toTRUE if equal, FALSE if + differs. + */ + + if (mask == stream) { + ret_value = TRUE; + } else ret_value = FALSE; + + /* Return return value. */ + return ret_value; +} + + +/* + *-------------------------------------------------------------- + * + * get_ext_data -- + * + * Assumes that bit stream is at begining of extension + * data. Parses off extension data into dynamically + * allocated space until start code is hit. + * + * Results: + * Pointer to dynamically allocated memory containing + * extension data. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +char* get_ext_data( VidStream* vid_stream ) +{ + unsigned int size, marker; + char *dataPtr; + unsigned int data; + + /* Set initial ext data buffer size. */ + + size = EXT_BUF_SIZE; + + /* Allocate ext data buffer. */ + + dataPtr = (char *) malloc(size); + + /* Initialize marker to keep place in ext data buffer. */ + + marker = 0; + + /* While next data is not start code... */ + while (!next_bits(24, 0x000001, vid_stream)) { + + /* Get next byte of ext data. */ + + get_bits8(data); + + /* Put ext data into ext data buffer. Advance marker. */ + + dataPtr[marker] = (char) data; + marker++; + + /* If end of ext data buffer reached, resize data buffer. */ + + if (marker == size) { + size += EXT_BUF_SIZE; + dataPtr = (char *) realloc(dataPtr, size); + } + } + + /* Realloc data buffer to free any extra space. */ + + dataPtr = (char *) realloc(dataPtr, marker); + + /* Return pointer to ext data buffer. */ + return dataPtr; +} + + +/* + *-------------------------------------------------------------- + * + * next_start_code -- + * + * Parses off bitstream until start code reached. When done + * next 4 bytes of bitstream will be start code. Bit offset + * reset to 0. + * + * Results: + * Status code. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +int next_start_code( VidStream* vid_stream ) +{ + int state; + int byteoff; + unsigned int data; + +#if 0 + /* If no current stream, return error. */ + if (vid_stream== NULL) + return NO_VID_STREAM; +#endif + + /* If insufficient buffer length, correct underflow. */ + + if (vid_stream->buf_length < 4) { + correct_underflow(vid_stream); + } + + /* If bit offset not zero, reset and advance buffer pointer. */ + + byteoff = vid_stream->bit_offset % 8; + + if (byteoff != 0) { + flush_bits((8-byteoff)); + } + + /* Set state = 0. */ + + state = 0; + + /* While buffer has data ... */ + + while(vid_stream->buf_length > 0) { + + /* If insufficient data exists, correct underflow. */ + + + if (vid_stream->buf_length < 4) { + correct_underflow(vid_stream); + } + + /* If next byte is zero... */ + + get_bits8(data); + + if (data == 0) { + + /* If state < 2, advance state. */ + + if (state < 2) state++; + } + + /* If next byte is one... */ + + else if (data == 1) { + + /* If state == 2, advance state (i.e. start code found). */ + + if (state == 2) state++; + + /* Otherwise, reset state to zero. */ + + else state = 0; + } + + /* Otherwise byte is neither 1 or 0, reset state to 0. */ + + else { + state = 0; + } + + /* If state == 3 (i.e. start code found)... */ + + if (state == 3) { + + /* Set buffer pointer back and reset length & bit offsets so + * next bytes will be beginning of start code. + */ + + vid_stream->bit_offset = vid_stream->bit_offset - 24; + +#ifdef ANALYSIS + bitCount -= 24; +#endif + + if (vid_stream->bit_offset < 0) { + vid_stream->bit_offset = 32 + vid_stream->bit_offset; + vid_stream->buf_length++; + vid_stream->buffer--; +#ifdef UTIL2 + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; +#else + vid_stream->curBits = *vid_stream->buffer; +#endif + } + else { +#ifdef UTIL2 + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; +#else + vid_stream->curBits = *vid_stream->buffer; +#endif + } + +#ifdef NO_GRIFF_MODS + /* Return success. */ + return OK; +#else /* NO_GRIFF_MODS */ + show_bits32(data); + if ( data==SEQ_START_CODE || + data==GOP_START_CODE || + data==PICTURE_START_CODE || + (data>=SLICE_MIN_START_CODE && data<=SLICE_MAX_START_CODE) || + data==EXT_START_CODE || + data==USER_START_CODE ) + { + /* Return success. */ + return OK; + } + else + { + flush_bits32; + } +#endif /* NO_GRIFF_MODS */ + } + } + + /* Return underflow error. */ + return STREAM_UNDERFLOW; +} + + +/* + *-------------------------------------------------------------- + * + * get_extra_bit_info -- + * + * Parses off extra bit info stream into dynamically + * allocated memory. Extra bit info is indicated by + * a flag bit set to 1, followed by 8 bits of data. + * This continues until the flag bit is zero. Assumes + * that bit stream set to first flag bit in extra + * bit info stream. + * + * Results: + * Pointer to dynamically allocated memory with extra + * bit info in it. Flag bits are NOT included. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +char* get_extra_bit_info( VidStream* vid_stream ) +{ + unsigned int size, marker; + char *dataPtr; + unsigned int data; + + /* Get first flag bit. */ + get_bits1(data); + + /* If flag is false, return NULL pointer (i.e. no extra bit info). */ + + if (!data) return NULL; + + /* Initialize size of extra bit info buffer and allocate. */ + + size = EXT_BUF_SIZE; + dataPtr = (char *) malloc(size); + + /* Reset marker to hold place in buffer. */ + + marker = 0; + + /* While flag bit is true. */ + + while (data) { + + /* Get next 8 bits of data. */ + get_bits8(data); + + /* Place in extra bit info buffer. */ + + dataPtr[marker] = (char) data; + marker++; + + /* If buffer is full, reallocate. */ + + if (marker == size) { + size += EXT_BUF_SIZE; + dataPtr = (char *) realloc(dataPtr, size); + } + + /* Get next flag bit. */ + get_bits1(data); + } + + /* Reallocate buffer to free extra space. */ + + dataPtr = (char *) realloc(dataPtr, marker); + + /* Return pointer to extra bit info buffer. */ + return dataPtr; +} + + +/* EOF */ diff --git a/smpeg/src/video/util.h b/smpeg/src/video/util.h new file mode 100644 index 0000000..47c3d32 --- /dev/null +++ b/smpeg/src/video/util.h @@ -0,0 +1,395 @@ +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + Changes to make the code reentrant: + deglobalized: curBits, curVidStream + deglobalized: bitOffset, bitLength, bitBuffer in vid_stream, not used + here + Additional changes: + -lsh@cs.brown.edu (Loring Holden) + */ + +/* Status codes for bit stream i/o operations. */ + +#include "MPEG.h" + +#define NO_VID_STREAM (-1) +#define STREAM_UNDERFLOW (-2) +#define OK 1 + +/* Size increment of extension data buffers. */ + +#define EXT_BUF_SIZE 1024 + +/* External declarations for bitstream i/o operations. */ +extern unsigned int bitMask[]; +extern unsigned int nBitMask[]; +extern unsigned int rBitMask[]; +extern unsigned int bitTest[]; + +/* Macro for updating bit counter if analysis tool is on. */ +#ifdef ANALYSIS +#define UPDATE_COUNT(numbits) bitCount += numbits +#else +#define UPDATE_COUNT(numbits) +#endif + +#ifdef NO_SANITY_CHECKS +#define get_bits1(result) \ +{ \ + UPDATE_COUNT(1); \ + result = ((vid_stream->curBits & 0x80000000) != 0); \ + vid_stream->curBits <<= 1; \ + vid_stream->bit_offset++; \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->bit_offset = 0; \ + vid_stream->buffer++; \ + vid_stream->curBits = *vid_stream->buffer; \ + vid_stream->buf_length--; \ + } \ +} + +#define get_bits2(result) \ +{ \ + UPDATE_COUNT(2); \ + vid_stream->bit_offset += 2; \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->bit_offset -= 32; \ + vid_stream->buffer++; \ + vid_stream->buf_length--; \ + if (vid_stream->bit_offset) { \ + vid_stream->curBits |= \ + (*vid_stream->buffer >> (2 - vid_stream->bit_offset)); \ + } \ + result = ((vid_stream->curBits & 0xc0000000) >> 30); \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; \ + } \ + \ + result = ((vid_stream->curBits & 0xc0000000) >> 30); \ + vid_stream->curBits <<= 2; \ +} + +#define get_bitsX(num, mask, shift, result) \ +{ \ + UPDATE_COUNT(num); \ + vid_stream->bit_offset += num; \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->bit_offset -= 32; \ + vid_stream->buffer++; \ + vid_stream->buf_length--; \ + if (vid_stream->bit_offset) { \ + vid_stream->curBits |= (*vid_stream->buffer >> \ + (num - vid_stream->bit_offset)); \ + } \ + result = ((vid_stream->curBits & mask) >> shift); \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; \ + } \ + else { \ + result = ((vid_stream->curBits & mask) >> shift); \ + vid_stream->curBits <<= num; \ + } \ +} +#else + +#define get_bits1(result) \ +{ \ + /* Check for underflow. */ \ + \ + if (vid_stream->buf_length < 2) { \ + correct_underflow(vid_stream); \ + } \ + UPDATE_COUNT(1); \ + result = ((vid_stream->curBits & 0x80000000) != 0); \ + vid_stream->curBits <<= 1; \ + vid_stream->bit_offset++; \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->bit_offset = 0; \ + vid_stream->buffer++; \ + vid_stream->curBits = *vid_stream->buffer; \ + vid_stream->buf_length--; \ + } \ +} + +#define get_bits2(result) \ +{ \ + /* Check for underflow. */ \ + \ + if (vid_stream->buf_length < 2) { \ + correct_underflow(vid_stream); \ + } \ + UPDATE_COUNT(2); \ + vid_stream->bit_offset += 2; \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->bit_offset -= 32; \ + vid_stream->buffer++; \ + vid_stream->buf_length--; \ + if (vid_stream->bit_offset) { \ + vid_stream->curBits |= (*vid_stream->buffer >> \ + (2 - vid_stream->bit_offset)); \ + } \ + result = ((vid_stream->curBits & 0xc0000000) >> 30); \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; \ + } \ + \ + result = ((vid_stream->curBits & 0xc0000000) >> 30); \ + vid_stream->curBits <<= 2; \ +} + +#define get_bitsX(num, mask, shift, result) \ +{ \ + /* Check for underflow. */ \ + \ + if (vid_stream->buf_length < 2) { \ + correct_underflow(vid_stream); \ + } \ + UPDATE_COUNT(num); \ + vid_stream->bit_offset += num; \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->bit_offset -= 32; \ + vid_stream->buffer++; \ + vid_stream->buf_length--; \ + if (vid_stream->bit_offset) { \ + vid_stream->curBits |= (*vid_stream->buffer >> \ + (num - vid_stream->bit_offset)); \ + } \ + result = ((vid_stream->curBits & mask) >> shift); \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; \ + } \ + else { \ + result = ((vid_stream->curBits & mask) >> shift); \ + vid_stream->curBits <<= num; \ + } \ +} +#endif + +#define get_bits3(result) get_bitsX(3, 0xe0000000, 29, result) +#define get_bits4(result) get_bitsX(4, 0xf0000000, 28, result) +#define get_bits5(result) get_bitsX(5, 0xf8000000, 27, result) +#define get_bits6(result) get_bitsX(6, 0xfc000000, 26, result) +#define get_bits7(result) get_bitsX(7, 0xfe000000, 25, result) +#define get_bits8(result) get_bitsX(8, 0xff000000, 24, result) +#define get_bits9(result) get_bitsX(9, 0xff800000, 23, result) +#define get_bits10(result) get_bitsX(10, 0xffc00000, 22, result) +#define get_bits11(result) get_bitsX(11, 0xffe00000, 21, result) +#define get_bits12(result) get_bitsX(12, 0xfff00000, 20, result) +#define get_bits14(result) get_bitsX(14, 0xfffc0000, 18, result) +#define get_bits16(result) get_bitsX(16, 0xffff0000, 16, result) +#define get_bits18(result) get_bitsX(18, 0xffffc000, 14, result) +#define get_bits32(result) get_bitsX(32, 0xffffffff, 0, result) + +#define get_bitsn(num, result) get_bitsX((num), nBitMask[num], (32-(num)), result) + +#ifdef NO_SANITY_CHECKS +#define show_bits32(result) \ +{ \ + if (vid_stream->bit_offset) { \ + result = vid_stream->curBits | (*(vid_stream->buffer+1) >> \ + (32 - vid_stream->bit_offset)); \ + } \ + else { \ + result = vid_stream->curBits; \ + } \ +} + +#define show_bitsX(num, mask, shift, result) \ +{ \ + int bO; \ + bO = vid_stream->bit_offset + num; \ + if (bO > 32) { \ + bO -= 32; \ + result = ((vid_stream->curBits & mask) >> shift) | \ + (*(vid_stream->buffer+1) >> (shift + (num - bO))); \ + } \ + else { \ + result = ((vid_stream->curBits & mask) >> shift); \ + } \ +} + +#else +#define show_bits32(result) \ +{ \ + /* Check for underflow. */ \ + if (vid_stream->buf_length < 2) { \ + correct_underflow(vid_stream); \ + } \ + if (vid_stream->bit_offset) { \ + result = vid_stream->curBits | (*(vid_stream->buffer+1) >> \ + (32 - vid_stream->bit_offset)); \ + } \ + else { \ + result = vid_stream->curBits; \ + } \ +} + +#define show_bitsX(num, mask, shift, result) \ +{ \ + int bO; \ + \ + /* Check for underflow. */ \ + if (vid_stream->buf_length < 2) { \ + correct_underflow(vid_stream); \ + } \ + bO = vid_stream->bit_offset + num; \ + if (bO > 32) { \ + bO -= 32; \ + result = ((vid_stream->curBits & mask) >> shift) | \ + (*(vid_stream->buffer+1) >> (shift + (num - bO))); \ + } \ + else { \ + result = ((vid_stream->curBits & mask) >> shift); \ + } \ +} +#endif + +#define show_bits1(result) show_bitsX(1, 0x80000000, 31, result) +#define show_bits2(result) show_bitsX(2, 0xc0000000, 30, result) +#define show_bits3(result) show_bitsX(3, 0xe0000000, 29, result) +#define show_bits4(result) show_bitsX(4, 0xf0000000, 28, result) +#define show_bits5(result) show_bitsX(5, 0xf8000000, 27, result) +#define show_bits6(result) show_bitsX(6, 0xfc000000, 26, result) +#define show_bits7(result) show_bitsX(7, 0xfe000000, 25, result) +#define show_bits8(result) show_bitsX(8, 0xff000000, 24, result) +#define show_bits9(result) show_bitsX(9, 0xff800000, 23, result) +#define show_bits10(result) show_bitsX(10, 0xffc00000, 22, result) +#define show_bits11(result) show_bitsX(11, 0xffe00000, 21, result) +#define show_bits12(result) show_bitsX(12, 0xfff00000, 20, result) +#define show_bits13(result) show_bitsX(13, 0xfff80000, 19, result) +#define show_bits14(result) show_bitsX(14, 0xfffc0000, 18, result) +#define show_bits15(result) show_bitsX(15, 0xfffe0000, 17, result) +#define show_bits16(result) show_bitsX(16, 0xffff0000, 16, result) +#define show_bits17(result) show_bitsX(17, 0xffff8000, 15, result) +#define show_bits18(result) show_bitsX(18, 0xffffc000, 14, result) +#define show_bits19(result) show_bitsX(19, 0xffffe000, 13, result) +#define show_bits20(result) show_bitsX(20, 0xfffff000, 12, result) +#define show_bits21(result) show_bitsX(21, 0xfffff800, 11, result) +#define show_bits22(result) show_bitsX(22, 0xfffffc00, 10, result) +#define show_bits23(result) show_bitsX(23, 0xfffffe00, 9, result) +#define show_bits24(result) show_bitsX(24, 0xffffff00, 8, result) +#define show_bits25(result) show_bitsX(25, 0xffffff80, 7, result) +#define show_bits26(result) show_bitsX(26, 0xffffffc0, 6, result) +#define show_bits27(result) show_bitsX(27, 0xffffffe0, 5, result) +#define show_bits28(result) show_bitsX(28, 0xfffffff0, 4, result) +#define show_bits29(result) show_bitsX(29, 0xfffffff8, 3, result) +#define show_bits30(result) show_bitsX(30, 0xfffffffc, 2, result) +#define show_bits31(result) show_bitsX(31, 0xfffffffe, 1, result) + +#define show_bitsn(num,result) show_bitsX((num), (0xffffffff << (32-(num))), (32-(num)), result) + +#ifdef NO_SANITY_CHECKS +#define flush_bits32 \ +{ \ + UPDATE_COUNT(32); \ + \ + vid_stream->buffer++; \ + vid_stream->buf_length--; \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset;\ +} + + +#define flush_bits(num) \ +{ \ + vid_stream->bit_offset += num; \ + \ + UPDATE_COUNT(num); \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->bit_offset -= 32; \ + vid_stream->buffer++; \ + vid_stream->buf_length--; \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset;\ + } \ + else { \ + vid_stream->curBits <<= num; \ + } \ +} +#else +#define flush_bits32 \ +{ \ + if (vid_stream == NULL) { \ + /* Deal with no vid stream here. */ \ + } \ + \ + if (vid_stream->buf_length < 2) { \ + correct_underflow(vid_stream); \ + } \ + \ + UPDATE_COUNT(32); \ + \ + vid_stream->buffer++; \ + vid_stream->buf_length--; \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset;\ +} + +#define flush_bits(num) \ +{ \ + if (vid_stream== NULL) { \ + /* Deal with no vid stream here. */ \ + } \ + \ + if (vid_stream->buf_length < 2) { \ + correct_underflow(vid_stream); \ + } \ + \ + UPDATE_COUNT(num); \ + \ + vid_stream->bit_offset += num; \ + \ + if (vid_stream->bit_offset & 0x20) { \ + vid_stream->buf_length--; \ + vid_stream->bit_offset -= 32; \ + vid_stream->buffer++; \ + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset;\ + } \ + else { \ + vid_stream->curBits <<= num; \ + } \ +} +#endif + +#define UTIL2 diff --git a/smpeg/src/video/vhar128.cpp b/smpeg/src/video/vhar128.cpp new file mode 100644 index 0000000..84ecd79 --- /dev/null +++ b/smpeg/src/video/vhar128.cpp @@ -0,0 +1,272 @@ +#ifdef USE_ATI +#include +#include +#include +#include +#include "vhar128.h" + +/* #define DEBUG_R128VHA */ + +#define I_FRAME 1 +#define P_FRAME 2 +#define B_FRAME 3 +#define D_FRAME 4 + +struct vhar128_image { + OVDESCRIPTION * overlay; +}; + +struct private_yuvhwdata { + OVSURFACE * surface; +}; + +/* Translate error code to something readable */ +static void vhar128_perror(char * string, int error_code) +{ + switch(error_code) + { + case VHAERR_INVALIDPARAMS: + fprintf(stderr, "%s: (ATI) Invalid parameters\n", string); + break; + case VHAERR_UNSUPPORTED: + fprintf(stderr, "%s: (ATI) Unsupported feature\n", string); + break; + case VHAERR_INVALIDHANDLE: + fprintf(stderr, "%s: (ATI) Invalid handle\n", string); + break; + case VHAERR_OUTOFMEMORY: + fprintf(stderr, "%s: (ATI) Out of memory\n", string); + break; + case VHA_OK: + fprintf(stderr, "%s: (ATI) Success\n", string); + break; + default: + fprintf(stderr, "%s: (ATI) Undocumented error\n", string); + break; + } +} + +/* Check and initialize hardware */ +unsigned int vhar128_new() +{ + VHA_HARDWAREQUERY vhaQuery; + + /* Initialize hardware access */ + ATIHAP_InitHWAccess(); + + /* Query hardware information */ + memset(&vhaQuery, 0, sizeof(VHA_HARDWAREQUERY)); + vhaQuery.uSize = sizeof(VHA_HARDWAREQUERY); + vhaQuery.uCards = 0; + vhaQuery.ulCodedWidth = 0; + vhaQuery.ulCodedHeight = 0; + VHA_HardwareQuery(&vhaQuery); + +#ifdef DEBUG_R128VHA + printf("VHA_HardwareQuery :\n"); + printf("uHandle = %d\n", vhaQuery.uHandle); + if(vhaQuery.ulHWCaps & VHA_HWCAPS_IDCTMC) + printf("Hardware supports iScan, iDCT, and MC.\n"); + if(vhaQuery.ulHWCaps & VHA_HWCAPS_SUBPIC) + printf("Hardware supports Sub-picture.\n"); + printf("ulMinOvlyBuffer = %d\n", vhaQuery.ulMinOvlyBuffer); + printf("ulMaxOvlyBuffer = %d\n", vhaQuery.ulMaxOvlyBuffer); +#endif + + return(vhaQuery.uHandle); +} + +/* Create a new overlay */ +struct vhar128_image * vhar128_newimage(unsigned int handle, unsigned long width, unsigned long height) +{ + struct vhar128_image * image; + + image = (struct vhar128_image *) malloc(sizeof *image); + + image->overlay = (OVDESCRIPTION *) malloc(sizeof *image->overlay); + memset(image->overlay, 0, sizeof(OVDESCRIPTION)); + image->overlay->uSize = sizeof(OVDESCRIPTION); + image->overlay->ulOVFormat = OV_FORMAT_YUV12; + image->overlay->uWidth = width; + image->overlay->uHeight = height; + CreateOVSurface(handle, image->overlay); + + return(image); +} + +/* Lock overlay */ +void vhar128_lockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * ov) +{ + struct private_yuvhwdata * hwdata; + +#ifdef DEBUG_R128VHA + /* show locked overlay */ + SetOVSurface(handle, image->overlay); +#endif + + hwdata = (struct private_yuvhwdata *) malloc(sizeof *hwdata); + hwdata->surface = (OVSURFACE *) malloc(sizeof *hwdata->surface); + hwdata->surface->uSize = sizeof(OVSURFACE); + + LockOVSurface(handle, image->overlay, hwdata->surface); + + /* create an SDL_Overlay from the information in the ATI overlay */ + ov->format = SDL_YV12_OVERLAY; + ov->w = image->overlay->uWidth; + ov->h = image->overlay->uHeight; + ov->planes = 3; + ov->pitches = (Uint16 *) malloc(ov->planes * sizeof(Uint16)); + ov->pitches[0] = hwdata->surface->uPitchPlane1; + ov->pitches[1] = hwdata->surface->uPitchPlane3; + ov->pitches[2] = hwdata->surface->uPitchPlane2; + ov->pixels = (Uint8 **) malloc(ov->planes * sizeof(void *)); + ov->pixels[0] = (Uint8 *) hwdata->surface->pSurfPlane1; + ov->pixels[1] = (Uint8 *) hwdata->surface->pSurfPlane3; + ov->pixels[2] = (Uint8 *) hwdata->surface->pSurfPlane2; + ov->hwdata = hwdata; +} + +/* Unlock the overlay */ +void vhar128_unlockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * ov) +{ + UnlockOVSurface(handle, image->overlay, ov->hwdata->surface); + free(ov->pitches); + free(ov->pixels); + free(ov->hwdata->surface); + free(ov->hwdata); +} + +/* Destroy the overlay */ +void vhar128_destroyimage(unsigned int handle, struct vhar128_image * image) +{ + DestroyOVSurface(handle, image->overlay); + free(image->overlay); + free(image); +} + +/* Setup hardware decoding */ +int vhar128_init(unsigned int handle, unsigned long width, unsigned long height, struct vhar128_image *ring[], int ring_size) +{ + VHA_INIT vhaInit; + register int i; + + memset(&vhaInit, 0, sizeof(VHA_INIT)); + + /* obtain yv12 offset and send it to vha */ + for(i = 0; i < ring_size; i++) + { + vhaInit.yv12[i].ulOffsetY = ring[i]->overlay->OVOffset.ulOfsPlane1; + vhaInit.yv12[i].ulOffsetU = ring[i]->overlay->OVOffset.ulOfsPlane2; + vhaInit.yv12[i].ulOffsetV = ring[i]->overlay->OVOffset.ulOfsPlane3; + vhaInit.yv12[i].ulPitchY = ring[i]->overlay->OVOffset.uPitchPlane1; + vhaInit.yv12[i].ulPitchUV = ring[i]->overlay->OVOffset.uPitchPlane2; + } + vhaInit.ulNumYV12Buffer = ring_size; + vhaInit.uSize = sizeof(VHA_INIT); + vhaInit.ulHWSupports = VHA_HWCAPS_IDCTMC; + vhaInit.ulCodedWidth = width; + vhaInit.ulCodedHeight = height; + +#ifdef DEBUG_R128VHA + /* set region for showing ATI overlay on the screen */ + { + RCTL rSrc, rDst, rView; + + rView.left = rView.top = 0; + rView.right = width; + rView.bottom = height; + rSrc.left = rSrc.top = 0; + rSrc.right = width; + rSrc.bottom = height; + rDst.left = 0; + rDst.top = 0; + rDst.right = width; + rDst.bottom = height; + + UpdateOVPosition(handle, &rSrc, &rDst, &rView, OV_SHOW); + + SetOVSurface(handle, ring[0]->overlay); + } +#endif + + return(VHA_Init(handle, &vhaInit)); +} + +/* Setup decoding of a new picture */ +int vhar128_newdecode(unsigned int handle, int back, int forw, int current) +{ + VHA_NEWDECODE vhaND; + int retval; + + memset(&vhaND, 0, sizeof(VHA_NEWDECODE)); + vhaND.uSize = sizeof(VHA_NEWDECODE); + vhaND.BackwardRefFrame[0] = vhaND.BackwardRefFrame[1] = back; + vhaND.ForwardRefFrame[0] = vhaND.ForwardRefFrame[1] = forw; + vhaND.DecodeFrame = current; + vhaND.PictureStructure = VHA_PS_FRAME_PICTURE; + + if((retval = VHA_NewDecode(handle, &vhaND)) != VHA_OK) + vhar128_perror("vhar128_newdecode", retval); + + return(retval); +} + +/* Send a macroblock to the hardware */ +int vhar128_macroblock(unsigned int handle, int mb_x, int mb_y, int intra, int back, int forw, int mv_back_x, int mv_back_y, int mv_forw_x, int mv_forw_y, long runlevel[6][130]) +{ + VHA_MACROBLOCK vhaMB; + int retval; + + memset(&vhaMB, 0, sizeof(VHA_MACROBLOCK)); + vhaMB.ulSize = sizeof(VHA_MACROBLOCK); + + memcpy(vhaMB.RunLevel, runlevel, 6*130*sizeof(long)); + + vhaMB.mb_x = mb_x; + vhaMB.mb_y = mb_y; + vhaMB.mbType = (intra)?VHA_MBT_INTRA:0; + if(forw) vhaMB.mbType |= VHA_MBT_MOTION_FORWARD; + if(back) vhaMB.mbType |= VHA_MBT_MOTION_BACKWARD; + vhaMB.PredictionType = VHA_PT_FRAME_BASED; + vhaMB.ScanType = SCAN_ZIG_ZAG; + vhaMB.dct_type = 0; + vhaMB.vector[0][0][0] = mv_forw_x; + vhaMB.vector[0][0][1] = mv_forw_y; + vhaMB.vector[0][1][0] = mv_back_x; + vhaMB.vector[0][1][1] = mv_back_y; + + if((retval = VHA_Macroblock(handle, &vhaMB)) != VHA_OK) + vhar128_perror("vhar128_macroblock", retval); + + return(retval); +} + +/* Flush all macroblocks */ +int vhar128_flush(unsigned int handle) +{ + VHA_DECODECOMMAND vhaDC; + int retval; + + memset(&vhaDC, 0, sizeof(VHA_DECODECOMMAND)); + vhaDC.uSize = sizeof(VHA_DECODECOMMAND); + vhaDC.ulCommand = VHA_CMD_FLUSH; + + if((retval = VHA_DecodeCommand(handle, &vhaDC)) != VHA_OK) + vhar128_perror("vhar128_flush", retval); + + return(retval); +} + +/* Close hardware decoding */ +void vhar128_close(unsigned int handle) +{ + VHA_Close(handle); +} + +/* Close hardware access */ +void vhar128_delete() +{ + ATIHAP_CloseHWAccess(); +} + +#endif diff --git a/smpeg/src/video/vhar128.h b/smpeg/src/video/vhar128.h new file mode 100644 index 0000000..e3346b6 --- /dev/null +++ b/smpeg/src/video/vhar128.h @@ -0,0 +1,30 @@ +/* ATI Rage128 video hardware acceleration */ +#ifndef _VHAR128_H_ +#define _VHAR128_H_ + +#include "SDL.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vhar128_image; + +unsigned int vhar128_new(); +int vhar128_init(unsigned int handle, unsigned long width, unsigned long height, struct vhar128_image *ring[], int ring_size); +int vhar128_newdecode(unsigned int handle, int back, int forw, int current); +int vhar128_macroblock(unsigned int handle, int mb_x, int mb_y, int intra, int back, int forw, int mv_back_x, int mv_back_y, int mv_forw_x, int mv_forw_y, long runlevel[6][130]); + +int vhar128_flush(unsigned int handle); +void vhar128_close(unsigned int handle); +void vhar128_delete(); + +struct vhar128_image * vhar128_newimage(unsigned int handle, unsigned long width, unsigned long height); +void vhar128_lockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * surface); +void vhar128_unlockimage(unsigned int handle, struct vhar128_image * image, SDL_Overlay * surface); +void vhar128_destroyimage(unsigned int handle, struct vhar128_image * image); + +#ifdef __cplusplus +}; +#endif +#endif /* _VHAR128_H_ */ diff --git a/smpeg/src/video/video.cpp b/smpeg/src/video/video.cpp new file mode 100644 index 0000000..9c52577 --- /dev/null +++ b/smpeg/src/video/video.cpp @@ -0,0 +1,4682 @@ +/* + * video.c -- + * + * This file contains C code that implements the video decoder model. + * + */ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* We use FULL_COLOR_DITHER code for SMPEG */ +#define DISABLE_DITHER + +/* Correct bad motion information */ +#define LOOSE_MPEG + +/* If hardware accelerated, prevent use of dither code */ +#ifdef USE_ATI +#ifndef DISABLE_DITHER +#define DISABLE_DITHER +#endif +#endif + +#include +#include +#include +#include + +#include "decoders.h" +#include "video.h" +#include "util.h" +#include "proto.h" + +#ifdef USE_ATI +#include "vhar128.h" +#endif + +/* Declarations of functions. */ +#ifndef USE_ATI +static void ReconIMBlock( VidStream*, int bnum ); +static void ReconPMBlock( VidStream*, int bnum, + int recon_right_for, int recon_down_for, int zflag ); +static void ReconBMBlock( VidStream*, int bnum, + int recon_right_back, int recon_down_back, int zflag ); +static void ReconBiMBlock( VidStream*, int bnum, + int recon_right_for, int recon_down_for, int recon_right_back, + int recon_down_back, int zflag ); +static void ReconSkippedBlock( unsigned char *source, unsigned char *dest, + int row, int col, int row_size, int right, int down, + int right_half, int down_half, int width ); +#endif /* USE_ATI */ +static void DoPictureDisplay( VidStream* ); +static int ParseSeqHead( VidStream* ); +static int ParseGOP( VidStream* ); +static int ParsePicture( VidStream*, TimeStamp ); +static int ParseSlice( VidStream* ); +static int ParseMacroBlock( VidStream* ); +static void ProcessSkippedPFrameMBlocks( VidStream* ); +static void ProcessSkippedBFrameMBlocks( VidStream* ); + +/* + Changes to make the code reentrant: + de-globalized: totNumFrames, realTimeStart, matched_depth, ditherType, + curBits, ReconPMBlock statics, first, [lc]max[xy], ditherFlags, + vid_stream, Parse_done, seekValue, ReadPack static, sys_layer, + bitOffset, bitLength, bitBuffer, curVidStream, + X globals to xinfo (window, et al) + use vid_stream->film_has_ended instead of FilmState + lookup tables only initialized once, global as possible + (default_intra_matrix, zigzag, zigzag_direct, scan) + get rid of setjmp, long jmp + Additional changes: + if DISABLE_DITHER defined then do not compile dithering code + -lsh@cs.brown.edu (Loring Holden) + */ + +/* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */ + +#define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1)) + +/* Set up array for fast conversion from zig zag order to row/column + coordinates. +*/ +const int zigzag[64][2] = +{ + { 0, 0 }, { 1, 0 }, { 0, 1 }, { 0, 2 }, { 1, 1 }, + { 2, 0 }, { 3, 0 }, { 2, 1 }, { 1, 2 }, { 0, 3 }, + { 0, 4 }, { 1, 3 }, { 2, 2 }, { 3, 1 }, { 4, 0 }, + { 5, 0 }, { 4, 1 }, { 3, 2 }, { 2, 3 }, { 1, 4 }, + { 0, 5 }, { 0, 6 }, { 1, 5 }, { 2, 4 }, { 3, 3 }, + { 4, 2 }, { 5, 1 }, { 6, 0 }, { 7, 0 }, { 6, 1 }, + { 5, 2 }, { 4, 3 }, { 3, 4 }, { 2, 5 }, { 1, 6 }, + { 0, 7 }, { 1, 7 }, { 2, 6 }, { 3, 5 }, { 4, 4 }, + { 5, 3 }, { 6, 2 }, { 7, 1 }, { 7, 2 }, { 6, 3 }, + { 5, 4 }, { 4, 5 }, { 3, 6 }, { 2, 7 }, { 3, 7 }, + { 4, 6 }, { 5, 5 }, { 6, 4 }, { 7, 3 }, { 7, 4 }, + { 6, 5 }, { 5, 6 }, { 4, 7 }, { 5, 7 }, { 6, 6 }, + { 7, 5 }, { 7, 6 }, { 6, 7 }, { 7, 7 } +}; + +/* Set up array for fast conversion from row/column coordinates to + zig zag order. +*/ +const int scan[8][8] = +{ + { 0, 1, 5, 6, 14, 15, 27, 28 }, + { 2, 4, 7, 13, 16, 26, 29, 42 }, + { 3, 8, 12, 17, 25, 30, 41, 43 }, + { 9, 11, 18, 24, 31, 40, 44, 53 }, + { 10, 19, 23, 32, 39, 45, 52, 54 }, + { 20, 22, 33, 38, 46, 51, 55, 60 }, + { 21, 34, 37, 47, 50, 56, 59, 61 }, + { 35, 36, 48, 49, 57, 58, 62, 63 } +}; + +/* Max lum, chrom indices for illegal block checking. */ + + +#ifdef USE_CROP_TABLE +/* + * We use a lookup table to make sure values stay in the 0..255 range. + * Since this is cropping (ie, x = (x < 0)?0:(x>255)?255:x; ), wee call this + * table the "crop table". + * MAX_NEG_CROP is the maximum neg/pos value we can handle. + */ + +#define MAX_NEG_CROP 2048 +#define NUM_CROP_ENTRIES (2048+2*MAX_NEG_CROP) +static unsigned char cropTbl[NUM_CROP_ENTRIES]; + +#define crop(x) cm[x] +#else +static inline unsigned char crop(int x) +{ + if(x<=0) + return 0; + if(x>=255) + return 255; + return x; +} +#endif /* USE_CROP_TABLE */ + +/* + The following accounts for time and size spent in various parsing acitivites + if ANALYSIS has been defined. +*/ + +#ifdef ANALYSIS + + +unsigned int bitCount = 0; + +/* #define SHOWMB_FLAG */ +/* #define SHOWEACHFLAG */ + +typedef struct { + int frametype; + unsigned int totsize; + unsigned int number; + unsigned int i_mbsize; + unsigned int p_mbsize; + unsigned int b_mbsize; + unsigned int bi_mbsize; + unsigned int i_mbnum; + unsigned int p_mbnum; + unsigned int b_mbnum; + unsigned int bi_mbnum; + unsigned int i_mbcbp[64]; + unsigned int p_mbcbp[64]; + unsigned int b_mbcbp[64]; + unsigned int bi_mbcbp[64]; + unsigned int i_mbcoeff[64]; + unsigned int p_mbcoeff[64]; + unsigned int b_mbcoeff[64]; + unsigned int bi_mbcoeff[64]; + double tottime; +} Statval; + +Statval stat_a[4]; +unsigned int pictureSizeCount; +unsigned int mbSizeCount; +unsigned int *mbCBPPtr, *mbCoeffPtr, *mbSizePtr; +unsigned int cacheHit[8][8]; +unsigned int cacheMiss[8][8]; + +static void +init_stat_struct(astat) + Statval *astat; +{ + int j; + + astat->frametype = 0; + astat->totsize = 0; + astat->number = 0; + astat->i_mbsize = 0; + astat->p_mbsize = 0; + astat->b_mbsize = 0; + astat->bi_mbsize = 0; + astat->i_mbnum = 0; + astat->p_mbnum = 0; + astat->b_mbnum = 0; + astat->bi_mbnum = 0; + + for (j = 0; j < 64; j++) { + + astat->i_mbcbp[j] = 0; + astat->p_mbcbp[j] = 0; + astat->b_mbcbp[j] = 0; + astat->bi_mbcbp[j] = 0; + astat->i_mbcoeff[j] = 0; + astat->p_mbcoeff[j] = 0; + astat->b_mbcoeff[j] = 0; + astat->bi_mbcoeff[j] = 0; + } + astat->tottime = 0.0; +} + +void +init_stats() +{ + int i, j; + + for (i = 0; i < 4; i++) { + init_stat_struct(&(stat_a[i])); + stat_a[i].frametype = i; + } + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + cacheHit[i][j] = 0; + cacheMiss[i][j] = 0; + } + } + + bitCount = 0; +} + +static void +PrintOneStat() +{ + int i; + + printf("\n"); + switch (stat_a[0].frametype) { + case I_TYPE: + printf("I FRAME\n"); + break; + case P_TYPE: + printf("P FRAME\n"); + break; + case B_TYPE: + printf("B FRAME\n"); + break; + } + + printf("Size: %d bytes + %d bits\n", stat_a[0].totsize / 8, stat_a[0].totsize % 8); + if (stat_a[0].i_mbnum > 0) { + printf("\tI Macro Block Stats:\n"); + printf("\t%d I Macroblocks\n", stat_a[0].i_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[0].i_mbsize / (8 * stat_a[0].i_mbnum), + (stat_a[0].i_mbsize * stat_a[0].i_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].i_mbcbp[i], + stat_a[0].i_mbcbp[i + 1], stat_a[0].i_mbcbp[i + 2], stat_a[0].i_mbcbp[i + 3], + stat_a[0].i_mbcbp[i + 4], stat_a[0].i_mbcbp[i + 5], stat_a[0].i_mbcbp[i + 6], + stat_a[0].i_mbcbp[i + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].i_mbcoeff[i], + stat_a[0].i_mbcoeff[i + 1], stat_a[0].i_mbcoeff[i + 2], + stat_a[0].i_mbcoeff[i + 3], stat_a[0].i_mbcoeff[i + 4], + stat_a[0].i_mbcoeff[i + 5], stat_a[0].i_mbcoeff[i + 6], + stat_a[0].i_mbcoeff[i + 7]); + } + } + if (stat_a[0].p_mbnum > 0) { + printf("\tP Macro Block Stats:\n"); + printf("\t%d P Macroblocks\n", stat_a[0].p_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[0].p_mbsize / (8 * stat_a[0].p_mbnum), + (stat_a[0].p_mbsize / stat_a[0].p_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].p_mbcbp[i], + stat_a[0].p_mbcbp[i + 1], stat_a[0].p_mbcbp[i + 2], stat_a[0].p_mbcbp[i + 3], + stat_a[0].p_mbcbp[i + 4], stat_a[0].p_mbcbp[i + 5], stat_a[0].p_mbcbp[i + 6], + stat_a[0].p_mbcbp[i + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].p_mbcoeff[i], + stat_a[0].p_mbcoeff[i + 1], stat_a[0].p_mbcoeff[i + 2], + stat_a[0].p_mbcoeff[i + 3], stat_a[0].p_mbcoeff[i + 4], + stat_a[0].p_mbcoeff[i + 5], stat_a[0].p_mbcoeff[i + 6], + stat_a[0].p_mbcoeff[i + 7]); + } + } + if (stat_a[0].b_mbnum > 0) { + printf("\tB Macro Block Stats:\n"); + printf("\t%d B Macroblocks\n", stat_a[0].b_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[0].b_mbsize / (8 * stat_a[0].b_mbnum), + (stat_a[0].b_mbsize / stat_a[0].b_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].b_mbcbp[i], + stat_a[0].b_mbcbp[i + 1], stat_a[0].b_mbcbp[i + 2], stat_a[0].b_mbcbp[i + 3], + stat_a[0].b_mbcbp[i + 4], stat_a[0].b_mbcbp[i + 5], stat_a[0].b_mbcbp[i + 6], + stat_a[0].b_mbcbp[i + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].b_mbcoeff[i], + stat_a[0].b_mbcoeff[i + 1], stat_a[0].b_mbcoeff[i + 2], + stat_a[0].b_mbcoeff[i + 3], stat_a[0].b_mbcoeff[i + 4], + stat_a[0].b_mbcoeff[i + 5], stat_a[0].b_mbcoeff[i + 6], + stat_a[0].b_mbcoeff[i + 7]); + } + } + if (stat_a[0].bi_mbnum > 0) { + printf("\tBi Macro Block Stats:\n"); + printf("\t%d Bi Macroblocks\n", stat_a[0].bi_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[0].bi_mbsize / (8 * stat_a[0].bi_mbnum), + (stat_a[0].bi_mbsize * stat_a[0].bi_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].bi_mbcbp[i], + stat_a[0].bi_mbcbp[i + 1], stat_a[0].bi_mbcbp[i + 2], stat_a[0].bi_mbcbp[i + 3], + stat_a[0].bi_mbcbp[i + 4], stat_a[0].bi_mbcbp[i + 5], stat_a[0].bi_mbcbp[i + 6], + stat_a[0].bi_mbcbp[i + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (i = 0; i < 64; i += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].bi_mbcoeff[i], + stat_a[0].bi_mbcoeff[i + 1], stat_a[0].bi_mbcoeff[i + 2], + stat_a[0].bi_mbcoeff[i + 3], stat_a[0].bi_mbcoeff[i + 4], + stat_a[0].bi_mbcoeff[i + 5], stat_a[0].bi_mbcoeff[i + 6], + stat_a[0].bi_mbcoeff[i + 7]); + } + } + printf("\nTime to Decode: %g secs.\n", stat_a[0].tottime); + printf("****************\n"); +} + +void +PrintAllStats(vid_stream) +VidStream *vid_stream; +{ + int i, j; + unsigned int supertot, supernum; + double supertime; + + printf("\n"); + printf("General Info: \n"); + printf("Width: %d\nHeight: %d\n", vid_stream->mb_width * 16, vid_stream->mb_height * 16); + + for (i = 1; i < 4; i++) { + + if (stat_a[i].number == 0) + continue; + + switch (i) { + case 1: + printf("I FRAMES\n"); + break; + case 2: + printf("P FRAMES\n"); + break; + case 3: + printf("B FRAMES\n"); + break; + } + + printf("Number: %d\n", stat_a[i].number); + printf("Avg. Size: %d bytes + %d bits\n", + stat_a[i].totsize / (8 * stat_a[i].number), (stat_a[i].totsize / stat_a[i].number) % 8); + if (stat_a[i].i_mbnum > 0) { + printf("\tI Macro Block Stats:\n"); + printf("\t%d I Macroblocks\n", stat_a[i].i_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[i].i_mbsize / (8 * stat_a[i].i_mbnum), + (stat_a[i].i_mbsize / stat_a[i].i_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].i_mbcbp[j], + stat_a[i].i_mbcbp[j + 1], stat_a[i].i_mbcbp[j + 2], stat_a[i].i_mbcbp[j + 3], + stat_a[i].i_mbcbp[j + 4], stat_a[i].i_mbcbp[j + 5], stat_a[i].i_mbcbp[j + 6], + stat_a[i].i_mbcbp[j + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].i_mbcoeff[j], + stat_a[i].i_mbcoeff[j + 1], stat_a[i].i_mbcoeff[j + 2], + stat_a[i].i_mbcoeff[j + 3], stat_a[i].i_mbcoeff[j + 4], + stat_a[i].i_mbcoeff[j + 5], stat_a[i].i_mbcoeff[j + 6], + stat_a[i].i_mbcoeff[j + 7]); + } + } + if (stat_a[i].p_mbnum > 0) { + printf("\tP Macro Block Stats:\n"); + printf("\t%d P Macroblocks\n", stat_a[i].p_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[i].p_mbsize / (8 * stat_a[i].p_mbnum), + (stat_a[i].p_mbsize / stat_a[i].p_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].p_mbcbp[j], + stat_a[i].p_mbcbp[j + 1], stat_a[i].p_mbcbp[j + 2], stat_a[i].p_mbcbp[j + 3], + stat_a[i].p_mbcbp[j + 4], stat_a[i].p_mbcbp[j + 5], stat_a[i].p_mbcbp[j + 6], + stat_a[i].p_mbcbp[j + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].p_mbcoeff[j], + stat_a[i].p_mbcoeff[j + 1], stat_a[i].p_mbcoeff[j + 2], + stat_a[i].p_mbcoeff[j + 3], stat_a[i].p_mbcoeff[j + 4], + stat_a[i].p_mbcoeff[j + 5], stat_a[i].p_mbcoeff[j + 6], + stat_a[i].p_mbcoeff[j + 7]); + } + } + if (stat_a[i].b_mbnum > 0) { + printf("\tB Macro Block Stats:\n"); + printf("\t%d B Macroblocks\n", stat_a[i].b_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[i].b_mbsize / (8 * stat_a[i].b_mbnum), + (stat_a[i].b_mbsize * stat_a[i].b_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].b_mbcbp[j], + stat_a[i].b_mbcbp[j + 1], stat_a[i].b_mbcbp[j + 2], stat_a[i].b_mbcbp[j + 3], + stat_a[i].b_mbcbp[j + 4], stat_a[i].b_mbcbp[j + 5], stat_a[i].b_mbcbp[j + 6], + stat_a[i].b_mbcbp[j + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].b_mbcoeff[j], + stat_a[i].b_mbcoeff[j + 1], stat_a[i].b_mbcoeff[j + 2], + stat_a[i].b_mbcoeff[j + 3], stat_a[i].b_mbcoeff[j + 4], + stat_a[i].b_mbcoeff[j + 5], stat_a[i].b_mbcoeff[j + 6], + stat_a[i].b_mbcoeff[j + 7]); + } + } + if (stat_a[i].bi_mbnum > 0) { + printf("\tBi Macro Block Stats:\n"); + printf("\t%d Bi Macroblocks\n", stat_a[i].bi_mbnum); + printf("\tAvg. Size: %d bytes + %d bits\n", + stat_a[i].bi_mbsize / (8 * stat_a[i].bi_mbnum), + (stat_a[i].bi_mbsize * stat_a[i].bi_mbnum) % 8); + printf("\t\tCoded Block Pattern Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].bi_mbcbp[j], + stat_a[i].bi_mbcbp[j + 1], stat_a[i].bi_mbcbp[j + 2], stat_a[i].bi_mbcbp[j + 3], + stat_a[i].bi_mbcbp[j + 4], stat_a[i].bi_mbcbp[j + 5], stat_a[i].bi_mbcbp[j + 6], + stat_a[i].bi_mbcbp[j + 7]); + } + printf("\n\t\tNumber of Coefficients/Block Histogram:\n"); + for (j = 0; j < 64; j += 8) { + printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].bi_mbcoeff[j], + stat_a[i].bi_mbcoeff[j + 1], stat_a[i].bi_mbcoeff[j + 2], + stat_a[i].bi_mbcoeff[j + 3], stat_a[i].bi_mbcoeff[j + 4], + stat_a[i].bi_mbcoeff[j + 5], stat_a[i].bi_mbcoeff[j + 6], + stat_a[i].bi_mbcoeff[j + 7]); + } + } + printf("\nAvg. Time to Decode: %f secs.\n", + (stat_a[i].tottime / ((double) stat_a[i].number))); + printf("\n"); + printf("*************************\n\n"); + } + + supertot = stat_a[1].totsize + stat_a[2].totsize + stat_a[3].totsize; + supernum = stat_a[1].number + stat_a[2].number + stat_a[3].number; + supertime = stat_a[1].tottime + stat_a[2].tottime + stat_a[3].tottime; + + printf("Total Number of Frames: %d\n", supernum); + printf("Avg Frame Size: %d bytes %d bits\n", + supertot / (8 * supernum), (supertot / supernum) % 8); + printf("Total Time Decoding: %g secs.\n", supertime); + printf("Avg Decoding Time/Frame: %g secs.\n", supertime / ((double) supernum)); + printf("Avg Decoding Frames/Sec: %g secs.\n", ((double) supernum) / supertime); + printf("\n"); + + printf("Cache Hits/Miss\n"); + for (i = 0; i < 8; i++) { + printf("%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\n", + cacheHit[i][0], cacheMiss[i][0], cacheHit[i][1], cacheMiss[i][1], + cacheHit[i][2], cacheMiss[i][2], cacheHit[i][3], cacheMiss[i][3]); + printf("%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\n", + cacheHit[i][4], cacheMiss[i][4], cacheHit[i][5], cacheMiss[i][5], + cacheHit[i][6], cacheMiss[i][6], cacheHit[i][7], cacheMiss[i][7]); + } + +} + +static void +CollectStats() +{ + int i, j; + + i = stat_a[0].frametype; + + stat_a[i].totsize += stat_a[0].totsize; + stat_a[i].number += stat_a[0].number; + stat_a[i].i_mbsize += stat_a[0].i_mbsize; + stat_a[i].p_mbsize += stat_a[0].p_mbsize; + stat_a[i].b_mbsize += stat_a[0].b_mbsize; + stat_a[i].bi_mbsize += stat_a[0].bi_mbsize; + stat_a[i].i_mbnum += stat_a[0].i_mbnum; + stat_a[i].p_mbnum += stat_a[0].p_mbnum; + stat_a[i].b_mbnum += stat_a[0].b_mbnum; + stat_a[i].bi_mbnum += stat_a[0].bi_mbnum; + + for (j = 0; j < 64; j++) { + + stat_a[i].i_mbcbp[j] += stat_a[0].i_mbcbp[j]; + stat_a[i].p_mbcbp[j] += stat_a[0].p_mbcbp[j]; + stat_a[i].b_mbcbp[j] += stat_a[0].b_mbcbp[j]; + stat_a[i].bi_mbcbp[j] += stat_a[0].bi_mbcbp[j]; + stat_a[i].i_mbcoeff[j] += stat_a[0].i_mbcoeff[j]; + stat_a[i].p_mbcoeff[j] += stat_a[0].p_mbcoeff[j]; + stat_a[i].b_mbcoeff[j] += stat_a[0].b_mbcoeff[j]; + stat_a[i].bi_mbcoeff[j] += stat_a[0].bi_mbcoeff[j]; + } + + stat_a[i].tottime += stat_a[0].tottime; + + init_stat_struct(&(stat_a[0])); +} + +static unsigned int +bitCountRead() +{ + return bitCount; +} + +static void +StartTime() +{ + stat_a[0].tottime = ReadSysClock(); +} + +static void +EndTime() +{ + stat_a[0].tottime = ReadSysClock() - stat_a[0].tottime; +} +#endif + + +/* + *-------------------------------------------------------------- + * + * ReadSysClock -- + * + * Computes the current time according to the system clock. + * + * Results: + * The current time according to the system clock. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +ReadSysClock() +{ + return(SDL_GetTicks()/1000.0); +} + +/* + *-------------------------------------------------------------- + * + * InitCrop -- + * + * Initializes cropTbl - this was taken from newVidStream so + * that it wasn't done for each new video stream + * + * Results: + * None + * + * Side effects: + * cropTbl will be initialized + * + *-------------------------------------------------------------- + */ +void +InitCrop() +{ +#ifdef USE_CROP_TABLE + int i; + + /* Initialize crop table. */ + for (i = (-MAX_NEG_CROP); i < NUM_CROP_ENTRIES - MAX_NEG_CROP; i++) { + if (i <= 0) { + cropTbl[i + MAX_NEG_CROP] = 0; +#ifdef TWELVE_BITS + } else if (i >= 2047) { + cropTbl[i + MAX_NEG_CROP] = 2047; +#endif + } else if (i >= 255) { + cropTbl[i + MAX_NEG_CROP] = 255; + } else { + cropTbl[i + MAX_NEG_CROP] = i; + } + } +#endif /* USE_CROP_TABLE */ +} + + + +/* + *-------------------------------------------------------------- + * + * NewVidStream -- + * + * Allocates and initializes a VidStream structure. Takes + * as parameter requested size for buffer length. + * + * Results: + * A pointer to the new VidStream structure. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +VidStream* NewVidStream( unsigned int buffer_len ) +{ + int i, j; + VidStream* vs; + static const unsigned char default_intra_matrix[64] = + { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 + }; + + /* Check for legal buffer length. */ + + if( buffer_len < 4 ) + return NULL; + + /* Make buffer length multiple of 4. */ + + buffer_len = (buffer_len + 3) >> 2; + + /* Allocate memory for vs structure. */ + + vs = (VidStream *) malloc(sizeof(VidStream)); + memset( vs, 0, (sizeof *vs) ); + + /* Initialize pointers to extension and user data. */ + + vs->group.ext_data = vs->group.user_data = + vs->picture.extra_info = vs->picture.user_data = + vs->picture.ext_data = vs->slice.extra_info = + vs->ext_data = vs->user_data = NULL; + + /* Copy default intra matrix. */ + + for( i = 0; i < 8; i++ ) + { + for( j = 0; j < 8; j++ ) + { + vs->intra_quant_matrix[i][j] = default_intra_matrix[i * 8 + j]; + } + } + + /* Initialize non intra quantization matrix. */ + + for( i = 0; i < 8; i++ ) + { + for( j = 0; j < 8; j++ ) + { + vs->non_intra_quant_matrix[i][j] = 16; + } + } + + /* Initialize noise base matrix */ + for( i = 0; i < 8; i++ ) + for( j = 0; j < 8; j++ ) + vs->noise_base_matrix[i][j] = (short) vs->non_intra_quant_matrix[i][j]; + + j_rev_dct((short *) vs->noise_base_matrix); + + for( i = 0; i < 8; i++ ) + for( j = 0; j < 8; j++ ) + vs->noise_base_matrix[i][j] *= vs->noise_base_matrix[i][j]; + + /* Initialize pointers to image spaces. */ + + vs->current = vs->past = vs->future = NULL; + for( i = 0; i < RING_BUF_SIZE; i++ ) + { + vs->ring[i] = NULL; + } + + /* Create buffer. */ + + vs->buf_start = (unsigned int *) malloc(buffer_len * 4); + + /* + * Set max_buf_length to one less than actual length to deal with messy + * data without proper seq. end codes. + */ + + vs->max_buf_length = buffer_len - 1; + + /* Initialize fields that used to be global */ + vs->ditherFlags = NULL; + vs->rate_deal = -1; + + /* Reset everything for start of display */ + ResetVidStream(vs); + +#ifdef USE_ATI + /* Initialize Rage128 hardware */ + vs->ati_handle = vhar128_new(); +#endif + + /* Return structure. */ + + return vs; +} + + +/* + *-------------------------------------------------------------- + * + * ResetVidStream -- + * + * Re-initializes a VidStream structure. Takes + * as parameter a pointer to the VidStream to reset. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void ResetVidStream( VidStream* vid ) +{ + int i; + + /* Initialize pointers to image spaces. */ + vid->current = vid->past = vid->future = NULL; + + /* Initialize rings */ + for (i = 0; i < RING_BUF_SIZE; i++) { + if ( vid->ring[i] ) + vid->ring[i]->locked = 0; /* Unlock */ + } + + /* Initialize bitstream i/o fields. */ + vid->bit_offset = 0; + vid->buf_length = 0; + vid->buffer = vid->buf_start; + vid->curBits = 0; + + /* We are at the beginning of the film, so film has not ended */ + vid->film_has_ended = FALSE; + + /* Reset number of frames to zero */ + vid->totNumFrames=0; +#ifdef CALCULATE_FPS + for ( i=0; iframe_time[i] = 0.0; + vid->timestamp_index = 0; +#endif + + /* Fields added by KR for synchronization */ + vid->_skipFrame = 0; + vid->_skipCount = 0; + vid->_jumpFrame = -1; + vid->realTimeStart = 0; + + /* Reset EOF_flag to 0 */ + vid->EOF_flag = FALSE; + + vid->current_frame=0; + vid->need_frameadjust=false; +} + + +/* + *-------------------------------------------------------------- + * + * DestroyVidStream -- + * + * Deallocates a VidStream structure. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void DestroyVidStream( VidStream* astream ) +{ + int i; + + if( astream->ext_data != NULL ) + free(astream->ext_data); + + if( astream->user_data != NULL ) + free(astream->user_data); + + if( astream->group.ext_data != NULL ) + free(astream->group.ext_data); + + if( astream->group.user_data != NULL ) + free(astream->group.user_data); + + if( astream->picture.extra_info != NULL ) + free(astream->picture.extra_info); + + if( astream->picture.ext_data != NULL ) + free(astream->picture.ext_data); + + if( astream->picture.user_data != NULL ) + free(astream->picture.user_data); + + if( astream->slice.extra_info != NULL ) + free(astream->slice.extra_info); + + if( astream->buf_start != NULL ) + free(astream->buf_start); + + for( i = 0; i < RING_BUF_SIZE; i++ ) + { + if( astream->ring[i] != NULL ) + { + DestroyPictImage( astream, astream->ring[i] ); + astream->ring[i] = NULL; + } + } + + if( astream->ditherFlags != NULL ) + free( astream->ditherFlags ); + +#ifdef USE_ATI + vhar128_close(astream->ati_handle); +#endif + +#ifdef USE_ATI + vhar128_delete(); +#endif + + free( (char*) astream ); +} + + + +/* + *-------------------------------------------------------------- + * + * NewPictImage -- + * + * Allocates and initializes a PictImage structure. + * The width and height of the image space are passed in + * as parameters. + * + * Results: + * A pointer to the new PictImage structure. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +PictImage* NewPictImage( VidStream* vid_stream, int w, int h, SDL_Surface *dst ) +{ + PictImage* pi; + + /* Allocate memory space for pi structure. */ + + pi = (PictImage *) malloc(sizeof(PictImage)); + + /* Create a YV12 image (Y + V + U) */ +#ifdef USE_ATI + pi->image = vhar128_newimage(vid_stream->ati_handle, w, h); +#else + pi->image = (unsigned char *) malloc(w*h*12/8); + pi->luminance = (unsigned char *)pi->image; + pi->Cr = pi->luminance + (w*h); + pi->Cb = pi->luminance + (w*h) + (w*h)/4; +#endif + + /* Alloc space for filter info */ + pi->mb_qscale = (unsigned short int *) malloc(vid_stream->mb_width * vid_stream->mb_height * sizeof(unsigned int)); + + /* Reset locked flag. */ + + pi->locked = 0; + + /* Return pointer to pi structure. */ + + return pi; +} + +bool InitPictImages( VidStream* vid_stream, int w, int h, SDL_Surface* dst ) +{ + int i; + + vid_stream->current = vid_stream->past = vid_stream->future = NULL; + for (i = 0; i < RING_BUF_SIZE; i++) { + if ( vid_stream->ring[i] ) { + DestroyPictImage(vid_stream, vid_stream->ring[i]); + } + vid_stream->ring[i] = NewPictImage( vid_stream, w, h, dst ); + if ( ! vid_stream->ring[i] ) + return false; + } + +#ifdef USE_ATI + struct vhar128_image * ring[RING_BUF_SIZE]; + + for (i = 0; i < RING_BUF_SIZE; i++) { + ring[i] = vid_stream->ring[i]->image; + } + + vhar128_init(vid_stream->ati_handle, w, h, ring, RING_BUF_SIZE); +#endif + + return true; +} + +/* + *-------------------------------------------------------------- + * + * DestroyPictImage -- + * + * Deallocates a PictImage structure. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void DestroyPictImage( VidStream* vid_stream, PictImage* apictimage ) +{ +#ifdef USE_ATI + vhar128_destroyimage(vid_stream->ati_handle, apictimage->image); +#else + if (apictimage->image != NULL) free(apictimage->image); +#endif + + free(apictimage->mb_qscale); + free(apictimage); +} + + +/* + *-------------------------------------------------------------- + * + * mpegVidRsrc -- + * + * Parses bit stream until MB_QUANTUM number of + * macroblocks have been decoded or current slice or + * picture ends, whichever comes first. If the start + * of a frame is encountered, the frame is time stamped + * with the value passed in time_stamp. If the value + * passed in buffer is not null, the video stream buffer + * is set to buffer and the length of the buffer is + * expected in value passed in through length. + * + * Results: + * A pointer to the video stream structure used. + * + * Side effects: + * Bit stream is irreversibly parsed. If a picture is completed, + * a function is called to display the frame at the correct time. + * + *-------------------------------------------------------------- + */ + +VidStream* mpegVidRsrc( TimeStamp time_stamp, VidStream* vid_stream, int first ) +{ + unsigned int data; + int i, status; + + /* + * If called for the first time, find start code, make sure it is a + * sequence start code. + */ + + if( first ) + { + vid_stream->num_left = 0; + vid_stream->leftover_bytes = 0; + vid_stream->Parse_done = FALSE; + + next_start_code(vid_stream); /* sets curBits */ + show_bits32(data); + if( data != SEQ_START_CODE ) + { + vid_stream->_smpeg->SetError("Invalid sequence in video stream"); + /* Let whoever called NewVidStream call DestroyVidStream - KR + DestroyVidStream( vid_stream ); + */ + return 0; + } + } + else + { +#ifdef UTIL2 + vid_stream->curBits = *vid_stream->buffer << vid_stream->bit_offset; +#else + vid_stream->curBits = *vid_stream->buffer; +#endif + } + + /* Get next 32 bits (size of start codes). */ + + show_bits32(data); + + /* Check for end of file */ + if(vid_stream->EOF_flag) + { + /* Set ended flag first so that ExecuteDisplay may check it. */ + + vid_stream->film_has_ended = TRUE; + + if( vid_stream->future != NULL ) + { + vid_stream->current = vid_stream->future; + vid_stream->_smpeg->ExecuteDisplay( vid_stream ); + } + +#ifdef ANALYSIS + PrintAllStats(vid_stream); +#endif + goto done; + } + + /* + * Process according to start code (or parse macroblock if not a start code + * at all). + */ + + switch( data ) + { + case SEQ_END_CODE: + case 0x000001b9: /* handle ISO_11172_END_CODE too */ + +#ifdef VERBOSE_DEBUG + printf("SEQ_END_CODE\n"); +#endif + flush_bits32; + goto done; + break; + + case SEQ_START_CODE: + + /* Sequence start code. Parse sequence header. */ + +#ifdef VERBOSE_DEBUG + printf("SEQ_START_CODE\n"); +#endif + if( ParseSeqHead( vid_stream ) != PARSE_OK ) + { + fprintf( stderr, "mpegVidRsrc ParseSeqHead\n" ); + goto error; + } + + /* + * Return after sequence start code so that application above can use + * info in header. + */ + goto done; + + + case GOP_START_CODE: + + /* Group of Pictures start code. Parse gop header. */ + +#ifdef VERBOSE_DEBUG + printf("GOP_START_CODE\n"); +#endif + if( ParseGOP(vid_stream) != PARSE_OK ) + { + fprintf( stderr, "mpegVidRsrc ParseGOP\n" ); + goto error; + } + /* need adjust current_frame (after Seek) */ + if (vid_stream->need_frameadjust) { + int prev; + prev = vid_stream->totNumFrames; + vid_stream->current_frame = (int) + ( + vid_stream->group.tc_hours * 3600 * vid_stream->rate_deal + + vid_stream->group.tc_minutes * 60 * vid_stream->rate_deal + + vid_stream->group.tc_seconds * vid_stream->rate_deal + + vid_stream->group.tc_pictures); + vid_stream->need_frameadjust=false; + vid_stream->totNumFrames=vid_stream->current_frame; +#if 0 + printf("Adjusted Frame %d -> %d\n",prev,vid_stream->current_frame); +#endif + } + goto done; + + + case PICTURE_START_CODE: + + /* Picture start code. Parse picture header and first slice header. */ + +#ifdef VERBOSE_DEBUG + printf("PICTURE_START_CODE\n"); +#endif + if (vid_stream->timestamp_mark < vid_stream->buffer + && !vid_stream->timestamp_used){ + vid_stream->timestamp_used = true; + status = ParsePicture( vid_stream, vid_stream->timestamp ); + } else + status = ParsePicture( vid_stream, -1); + + if((vid_stream->picture.code_type == B_TYPE) && + vid_stream->_skipFrame && (vid_stream->_jumpFrame < 0)) + { + status = SKIP_PICTURE; + } + + if( !vid_stream->current ) + status = SKIP_PICTURE; + + if( status == SKIP_PICTURE ) + { + //fprintf( stderr, "%d\r", vid_stream->totNumFrames ); + + next_start_code( vid_stream ); + + while( ! next_bits( 32, PICTURE_START_CODE, vid_stream ) ) + { + if( next_bits( 32, GOP_START_CODE, vid_stream) ) + break; + else if( next_bits( 32, SEQ_END_CODE, vid_stream ) ) + break; + + flush_bits( 24 ); + next_start_code( vid_stream ); + } + + vid_stream->_smpeg->timeSync( vid_stream ); + goto done; + } + else if( status != PARSE_OK ) + { + fprintf( stderr, "mpegVidRsrc ParsePicture\n" ); + goto error; + } + + + if( ParseSlice(vid_stream) != PARSE_OK ) + { + fprintf( stderr, "mpegVidRsrc ParseSlice\n" ); + goto error; + } + break; + + + case SEQUENCE_ERROR_CODE: + +#ifdef VERBOSE_DEBUG + printf("SEQUENCE_ERROR_CODE\n"); +#endif + flush_bits32; + next_start_code(vid_stream); + goto done; + + + default: + + /* No base picture for decoding */ + if( !vid_stream->current ) + { + flush_bits32; + next_start_code(vid_stream); +#ifdef VERBOSE_DEBUG + printf("No base picture, flushing to next start code\n"); +#endif + goto done; + } + + /* Check for slice start code. */ + + if( (data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE) ) + { + /* Slice start code. Parse slice header. */ + if( ParseSlice(vid_stream) != PARSE_OK ) + { + fprintf( stderr, "mpegVidRsrc ParseSlice\n" ); + goto error; + } + } +#ifdef VERBOSE_DEBUG + else + fprintf(stderr, "Unknown data [%x] - not slice start code!\n", data); +#endif + break; + } + + + /* Parse next MB_QUANTUM macroblocks. */ + + for( i = 0; i < MB_QUANTUM; i++ ) + { + /* Check to see if actually a startcode and not a macroblock. */ + + if( ! next_bits( 23, 0x00000000, vid_stream ) && + ! vid_stream->film_has_ended ) + { + /* Not start code. Parse Macroblock. */ + + if (ParseMacroBlock(vid_stream) != PARSE_OK) + { +#ifdef VERBOSE_WARNINGS + fprintf( stderr, "mpegVidRsrc ParseMacroBlock\n" ); +#endif + goto error; + } + } + else + { + /* Not macroblock, actually start code. Get start code. */ + + next_start_code(vid_stream); + show_bits32(data); + + /* + * If start code is outside range of slice start codes, frame is + * complete, display frame. + */ + + if( ((dataSLICE_MAX_START_CODE)) && + (data != SEQUENCE_ERROR_CODE) ) + { + DoPictureDisplay( vid_stream ); + } + goto done; + } + } + + + /* Check if we just finished a picture on the MB_QUANTUMth macroblock */ + + if( next_bits( 23, 0x00000000, vid_stream ) ) + { + next_start_code(vid_stream); + show_bits32(data); + if( (data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE) ) + { + DoPictureDisplay( vid_stream ); + } + } + + goto done; + +error: + + next_start_code( vid_stream ); + return vid_stream; + +done: + + return vid_stream; +} + + +/* + *-------------------------------------------------------------- + * + * ParseSeqHead -- + * + * Assumes bit stream is at the begining of the sequence + * header start code. Parses off the sequence header. + * + * Results: + * Fills the vid_stream structure with values derived and + * decoded from the sequence header. Allocates the pict image + * structures based on the dimensions of the image space + * found in the sequence header. + * + * Side effects: + * Bit stream irreversibly parsed off. + * + *-------------------------------------------------------------- + */ +static int ParseSeqHead( VidStream* vid_stream ) +{ + unsigned int data; + int i, j; +#ifndef DISABLE_DITHER + int ditherType=vid_stream->ditherType; +#endif + + /* Flush off sequence start code. */ + + flush_bits32; + + /* Get horizontal size of image space. */ + + get_bits12(data); + vid_stream->h_size = (data + 15) & ~15; + + /* Get vertical size of image space. */ + + get_bits12(data); + vid_stream->v_size = (data + 15) & ~15; + + /* Calculate macroblock width and height of image space. */ + + vid_stream->mb_width = (vid_stream->h_size + 15) / 16; + vid_stream->mb_height = (vid_stream->v_size + 15) / 16; + +#ifndef DISABLE_DITHER + /* If dither type is MBORDERED allocate ditherFlags. */ + if (ditherType == MBORDERED_DITHER) { + vid_stream->ditherFlags = + (char *) malloc(vid_stream->mb_width*vid_stream->mb_height); + } +#endif + + /* Parse of aspect ratio code. */ + + get_bits4(data); + vid_stream->aspect_ratio = (unsigned char) data; + + /* Parse off picture rate code. */ + + get_bits4(data); + vid_stream->picture_rate = (unsigned char) data; + + /* Parse off bit rate. */ + + get_bits18(data); + vid_stream->bit_rate = data; + + /* Flush marker bit. */ + + flush_bits(1); + + /* Parse off vbv buffer size. */ + + get_bits10(data); + vid_stream->vbv_buffer_size = data; + +#ifdef not_def + /* Lets not bother with this. Only increases memory image */ + if (data*1024>vid_stream->max_buf_length) { + unsigned int *newbuf; + int sz=1024*data+1; + /* If they actually want a bigger buffer than we default to, + let them have it! (if we can) */ + newbuf = (unsigned int *) realloc(vid_stream->buf_start, (unsigned int) 4*sz); + if (newbuf!=(unsigned int *)NULL) { + vid_stream->max_buf_length=sz; + vid_stream->buffer= + (vid_stream->buffer-vid_stream->buf_start)+newbuf; + vid_stream->buf_start=newbuf; + }} +#endif + + /* Parse off contrained parameter flag. */ + + get_bits1(data); + if (data) { + vid_stream->const_param_flag = TRUE; + } else + vid_stream->const_param_flag = FALSE; + + /* + * If intra_quant_matrix_flag set, parse off intra quant matrix values. + */ + + get_bits1(data); + if (data) { + for (i = 0; i < 64; i++) { + get_bits8(data); + + vid_stream->intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] = + (unsigned char) data; + } + } + /* + * If non intra quant matrix flag set, parse off non intra quant matrix + * values. + */ + + get_bits1(data); + if (data) { + for (i = 0; i < 64; i++) { + get_bits8(data); + + vid_stream->non_intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] = + (unsigned char) data; + } + } + + /* Adjust noise base matrix according to non_intra matrix */ + for( i = 0; i < 8; i++ ) + for( j = 0; j < 8; j++ ) + vid_stream->noise_base_matrix[i][j] = (short) vid_stream->non_intra_quant_matrix[i][j]; + + j_rev_dct((short *) vid_stream->noise_base_matrix); + + for( i = 0; i < 8; i++ ) + for( j = 0; j < 8; j++ ) + vid_stream->noise_base_matrix[i][j] *= vid_stream->noise_base_matrix[i][j]; + + /* Go to next start code. */ + + next_start_code(vid_stream); + + /* + * If next start code is extension start code, parse off extension data. + */ + + if (next_bits(32, EXT_START_CODE, vid_stream)) { + flush_bits32; + if (vid_stream->ext_data != NULL) { + free(vid_stream->ext_data); + vid_stream->ext_data = NULL; + } + vid_stream->ext_data = get_ext_data(vid_stream); + } + /* If next start code is user start code, parse off user data. */ + + if (next_bits(32, USER_START_CODE, vid_stream)) { + flush_bits32; + if (vid_stream->user_data != NULL) { + free(vid_stream->user_data); + vid_stream->user_data = NULL; + } + vid_stream->user_data = get_ext_data(vid_stream); + } + return PARSE_OK; +} + + +/* + *-------------------------------------------------------------- + * + * ParseGOP -- + * + * Parses of group of pictures header from bit stream + * associated with vid_stream. + * + * Results: + * Values in gop header placed into video stream structure. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +static int ParseGOP( VidStream* vid_stream ) +{ + unsigned int data; + + /* Flush group of pictures start code. */ + + flush_bits32; + + /* Parse off drop frame flag. */ + + get_bits1(data); + if (data) { + vid_stream->group.drop_flag = TRUE; + } else + vid_stream->group.drop_flag = FALSE; + + /* Parse off hour component of time code. */ + + get_bits5(data); + vid_stream->group.tc_hours = data; + + /* Parse off minute component of time code. */ + + get_bits6(data); + vid_stream->group.tc_minutes = data; + + /* Flush marker bit. */ + + flush_bits(1); + + /* Parse off second component of time code. */ + + get_bits6(data); + vid_stream->group.tc_seconds = data; + + /* Parse off picture count component of time code. */ + + get_bits6(data); + vid_stream->group.tc_pictures = data; + + /* Parse off closed gop and broken link flags. */ + + get_bits2(data); + if (data > 1) { + vid_stream->group.closed_gop = TRUE; + if (data > 2) { + vid_stream->group.broken_link = TRUE; + } else + vid_stream->group.broken_link = FALSE; + } else { + vid_stream->group.closed_gop = FALSE; + if (data) { + vid_stream->group.broken_link = TRUE; + } else + vid_stream->group.broken_link = FALSE; + } + + /* Goto next start code. */ + + next_start_code(vid_stream); + + /* If next start code is extension data, parse off extension data. */ + + if (next_bits(32, EXT_START_CODE, vid_stream)) { + flush_bits32; + if (vid_stream->group.ext_data != NULL) { + free(vid_stream->group.ext_data); + vid_stream->group.ext_data = NULL; + } + vid_stream->group.ext_data = get_ext_data(vid_stream); + } + /* If next start code is user data, parse off user data. */ + + if (next_bits(32, USER_START_CODE,vid_stream)) { + flush_bits32; + if (vid_stream->group.user_data != NULL) { + free(vid_stream->group.user_data); + vid_stream->group.user_data = NULL; + } + vid_stream->group.user_data = get_ext_data(vid_stream); + } + return PARSE_OK; +} + + +/* + *-------------------------------------------------------------- + * + * ParsePicture -- + * + * Parses picture header. Marks picture to be presented + * at particular time given a time stamp. + * + * Results: + * Values from picture header put into video stream structure. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +static int ParsePicture( VidStream* vid_stream, TimeStamp time_stamp ) +{ + unsigned int data; + int i; + + /* Flush header start code. */ + flush_bits32; + + /* This happens if there is a picture code before a sequence start */ + if (vid_stream->ring[0] == NULL) { + printf("Warning: picture block before sequence header block\n"); + return SKIP_PICTURE; + } + + /* Parse off temporal reference. */ + get_bits10(data); + vid_stream->picture.temp_ref = data; + + /* Parse of picture type. */ + get_bits3(data); + vid_stream->picture.code_type = data; + + if ((vid_stream->picture.code_type == B_TYPE) && + ((vid_stream->future == NULL) || + ((vid_stream->past == NULL) && !(vid_stream->group.closed_gop)))) + /* According to 2-D.5.1 (p D-18) this is ok, if the refereneces are OK */ + return SKIP_PICTURE; + + if ((vid_stream->picture.code_type == P_TYPE) && (vid_stream->future == NULL)) + return SKIP_PICTURE; + +#ifdef ANALYSIS + StartTime(); + stat_a[0].frametype = vid_stream->picture.code_type; + stat_a[0].number = 1; + stat_a[0].totsize = 45; + pictureSizeCount = bitCountRead(); +#endif + + /* Parse off vbv buffer delay value. */ + get_bits16(data); + vid_stream->picture.vbv_delay = data; + + /* If P or B type frame... */ + + if ((vid_stream->picture.code_type == P_TYPE) || + (vid_stream->picture.code_type == B_TYPE)) { + + /* Parse off forward vector full pixel flag. */ + get_bits1(data); + if (data) { + vid_stream->picture.full_pel_forw_vector = TRUE; + } else { + vid_stream->picture.full_pel_forw_vector = FALSE; + } + + /* Parse of forw_r_code. */ + get_bits3(data); + + /* Decode forw_r_code into forw_r_size and forw_f. */ + + vid_stream->picture.forw_r_size = data - 1; + vid_stream->picture.forw_f = (1 << vid_stream->picture.forw_r_size); + } + /* If B type frame... */ + + if (vid_stream->picture.code_type == B_TYPE) { + + /* Parse off back vector full pixel flag. */ + get_bits1(data); + if (data) + vid_stream->picture.full_pel_back_vector = TRUE; + else + vid_stream->picture.full_pel_back_vector = FALSE; + + /* Parse off back_r_code. */ + get_bits3(data); + + /* Decode back_r_code into back_r_size and back_f. */ + + vid_stream->picture.back_r_size = data - 1; + vid_stream->picture.back_f = (1 << vid_stream->picture.back_r_size); + } + /* Get extra bit picture info. */ + + if (vid_stream->picture.extra_info != NULL) { + free(vid_stream->picture.extra_info); + vid_stream->picture.extra_info = NULL; + } + vid_stream->picture.extra_info = get_extra_bit_info(vid_stream); + + /* Goto next start code. */ + next_start_code(vid_stream); + + /* If start code is extension start code, parse off extension data. */ + + if (next_bits(32, EXT_START_CODE, vid_stream)) { + flush_bits32; + + if (vid_stream->picture.ext_data != NULL) { + free(vid_stream->picture.ext_data); + vid_stream->picture.ext_data = NULL; + } + vid_stream->picture.ext_data = get_ext_data(vid_stream); + } + /* If start code is user start code, parse off user data. */ + + if (next_bits(32, USER_START_CODE, vid_stream)) { + flush_bits32; + + if (vid_stream->picture.user_data != NULL) { + free(vid_stream->picture.user_data); + vid_stream->picture.user_data = NULL; + } + vid_stream->picture.user_data = get_ext_data(vid_stream); + } + + /* Find a pict image structure in ring buffer not currently locked. */ + + i = 0; + + while (vid_stream->ring[i]->locked != 0) { + if (++i >= RING_BUF_SIZE) { + perror("Fatal error. Ring buffer full."); + exit(1); + } + } + + /* Set current pict image structure to the one just found in ring. */ + + vid_stream->current = vid_stream->ring[i]; + + /* Set time stamp. */ + + vid_stream->current->show_time = time_stamp; + + /* Reset past macroblock address field. */ + + vid_stream->mblock.past_mb_addr = -1; + +#ifdef USE_ATI + int back, forw, current; + + back = forw = -1; + current = i; + + /* Look for indexes of future and past frames */ + for(i = 0; i < RING_BUF_SIZE; i++) + { + if(vid_stream->future == vid_stream->ring[i]) forw = i; + if(vid_stream->past == vid_stream->ring[i]) back = i; + } + + /* Start decoding a new frame */ + switch(vid_stream->picture.code_type) + { + case B_TYPE: + vhar128_newdecode(vid_stream->ati_handle, forw, back, current); + break; + case P_TYPE: + vhar128_newdecode(vid_stream->ati_handle, -1, forw, current); + break; + case I_TYPE: + vhar128_newdecode(vid_stream->ati_handle, -1, -1, current); + break; + } +#endif + + return PARSE_OK; +} + + +/* + *-------------------------------------------------------------- + * + * ParseSlice -- + * + * Parses off slice header. + * + * Results: + * Values found in slice header put into video stream structure. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +static int ParseSlice( VidStream* vid_stream ) +{ + unsigned int data; + + /* Flush slice start code. */ + + flush_bits(24); + + /* Parse off slice vertical position. */ + + get_bits8(data); + vid_stream->slice.vert_pos = data; + + /* Parse off quantization scale. */ + + get_bits5(data); + vid_stream->slice.quant_scale = data; + + /* Parse off extra bit slice info. */ + + if (vid_stream->slice.extra_info != NULL) { + free(vid_stream->slice.extra_info); + vid_stream->slice.extra_info = NULL; + } + vid_stream->slice.extra_info = get_extra_bit_info(vid_stream); + + /* Reset past intrablock address. */ + + vid_stream->mblock.past_intra_addr = -2; + + /* Reset previous recon motion vectors. */ + + vid_stream->mblock.recon_right_for_prev = 0; + vid_stream->mblock.recon_down_for_prev = 0; + vid_stream->mblock.recon_right_back_prev = 0; + vid_stream->mblock.recon_down_back_prev = 0; + + /* Reset macroblock address. */ + + vid_stream->mblock.mb_address = ((vid_stream->slice.vert_pos - 1) * + vid_stream->mb_width) - 1; + + /* Reset past dct dc y, cr, and cb values. */ + +#ifdef USE_ATI + vid_stream->block.dct_dc_y_past = 0; + vid_stream->block.dct_dc_cr_past = 0; + vid_stream->block.dct_dc_cb_past = 0; +#else + vid_stream->block.dct_dc_y_past = 1024 << 3; + vid_stream->block.dct_dc_cr_past = 1024 << 3; + vid_stream->block.dct_dc_cb_past = 1024 << 3; +#endif + + return PARSE_OK; +} + + +/* + *-------------------------------------------------------------- + * + * ParseMacroBlock -- + * + * Parseoff macroblock. Reconstructs DCT values. Applies + * inverse DCT, reconstructs motion vectors, calculates and + * set pixel values for macroblock in current pict image + * structure. + * + * Results: + * Here's where everything really happens. Welcome to the + * heart of darkness. + * + * Side effects: + * Bit stream irreversibly parsed off. + * + *-------------------------------------------------------------- + */ + +static int ParseMacroBlock( VidStream* vid_stream ) +{ + int addr_incr; + unsigned int data; + int mask, i, recon_right_for, recon_down_for, recon_right_back, + recon_down_back; + int zero_block_flag; + BOOLEAN mb_quant = 0, mb_motion_forw = 0, mb_motion_back = 0, + mb_pattern = 0; +#ifndef DISABLE_DITHER + int no_dith_flag = 0; + int ditherType = vid_stream->ditherType; +#endif + +#ifdef ANALYSIS + mbSizeCount = bitCountRead(); +#endif + +#ifdef USE_ATI + /* Empty macroblock */ + vid_stream->block.dct_recon[0][0] = 0xFFFFFFFF; + vid_stream->block.dct_recon[1][0] = 0xFFFFFFFF; + vid_stream->block.dct_recon[2][0] = 0xFFFFFFFF; + vid_stream->block.dct_recon[3][0] = 0xFFFFFFFF; + vid_stream->block.dct_recon[4][0] = 0xFFFFFFFF; + vid_stream->block.dct_recon[5][0] = 0xFFFFFFFF; +#endif + + /* + * Parse off macroblock address increment and add to macroblock address. + */ + do + { + unsigned int ind; + + show_bits11(ind); + DecodeMBAddrInc(addr_incr); + + if (mb_addr_inc[ind].num_bits==0) + { + addr_incr = 1; + } + if (addr_incr == MB_ESCAPE) + { + vid_stream->mblock.mb_address += 33; + addr_incr = MB_STUFFING; + } + } while (addr_incr == MB_STUFFING); + vid_stream->mblock.mb_address += addr_incr; + + if( vid_stream->mblock.mb_address > (int) (vid_stream->mb_height * + vid_stream->mb_width - 1) ) + return SKIP_TO_START_CODE; + if( vid_stream->mblock.mb_address < 0 ) + return SKIP_TO_START_CODE; + + /* + * If macroblocks have been skipped, process skipped macroblocks. + */ + + if (vid_stream->mblock.mb_address - vid_stream->mblock.past_mb_addr > 1) { + if (vid_stream->picture.code_type == P_TYPE) + ProcessSkippedPFrameMBlocks(vid_stream); + else if (vid_stream->picture.code_type == B_TYPE) + ProcessSkippedBFrameMBlocks(vid_stream); + } + /* Set past macroblock address to current macroblock address. */ + vid_stream->mblock.past_mb_addr = vid_stream->mblock.mb_address; + + /* Based on picture type decode macroblock type. */ + switch (vid_stream->picture.code_type) { + case I_TYPE: + DecodeMBTypeI(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern, + vid_stream->mblock.mb_intra); + break; + + case P_TYPE: + DecodeMBTypeP(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern, + vid_stream->mblock.mb_intra); + break; + + case B_TYPE: + DecodeMBTypeB(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern, + vid_stream->mblock.mb_intra); + break; + case D_TYPE: + fprintf(stderr, "ERROR: MPEG-1 Streams with D-frames are not supported\n"); + exit(1); + } + + /* If quantization flag set, parse off new quantization scale. */ + + if (mb_quant == TRUE) { + get_bits5(data); + vid_stream->slice.quant_scale = data; + } + /* If forward motion vectors exist... */ + if (mb_motion_forw == TRUE) { + + /* Parse off and decode horizontal forward motion vector. */ + DecodeMotionVectors(vid_stream->mblock.motion_h_forw_code); + + /* If horiz. forward r data exists, parse off. */ + + if ((vid_stream->picture.forw_f != 1) && + (vid_stream->mblock.motion_h_forw_code != 0)) { + get_bitsn(vid_stream->picture.forw_r_size, data); + vid_stream->mblock.motion_h_forw_r = data; + } + /* Parse off and decode vertical forward motion vector. */ + DecodeMotionVectors(vid_stream->mblock.motion_v_forw_code); + + /* If vert. forw. r data exists, parse off. */ + + if ((vid_stream->picture.forw_f != 1) && + (vid_stream->mblock.motion_v_forw_code != 0)) { + get_bitsn(vid_stream->picture.forw_r_size, data); + vid_stream->mblock.motion_v_forw_r = data; + } + } + /* If back motion vectors exist... */ + if (mb_motion_back == TRUE) { + + /* Parse off and decode horiz. back motion vector. */ + DecodeMotionVectors(vid_stream->mblock.motion_h_back_code); + + /* If horiz. back r data exists, parse off. */ + + if ((vid_stream->picture.back_f != 1) && + (vid_stream->mblock.motion_h_back_code != 0)) { + get_bitsn(vid_stream->picture.back_r_size, data); + vid_stream->mblock.motion_h_back_r = data; + } + /* Parse off and decode vert. back motion vector. */ + DecodeMotionVectors(vid_stream->mblock.motion_v_back_code); + + /* If vert. back r data exists, parse off. */ + + if ((vid_stream->picture.back_f != 1) && + (vid_stream->mblock.motion_v_back_code != 0)) { + get_bitsn(vid_stream->picture.back_r_size, data); + vid_stream->mblock.motion_v_back_r = data; + } + } +#ifdef ANALYSIS + if (vid_stream->mblock.mb_intra) { + stat_a[0].i_mbnum++; + mbCBPPtr = stat_a[0].i_mbcbp; + mbCoeffPtr = stat_a[0].i_mbcoeff; + mbSizePtr = &(stat_a[0].i_mbsize); + } else if (mb_motion_back && mb_motion_forw) { + stat_a[0].bi_mbnum++; + mbCBPPtr = stat_a[0].bi_mbcbp; + mbCoeffPtr = stat_a[0].bi_mbcoeff; + mbSizePtr = &(stat_a[0].bi_mbsize); + } else if (mb_motion_back) { + stat_a[0].b_mbnum++; + mbCBPPtr = stat_a[0].b_mbcbp; + mbCoeffPtr = stat_a[0].b_mbcoeff; + mbSizePtr = &(stat_a[0].b_mbsize); + } else { + stat_a[0].p_mbnum++; + mbCBPPtr = stat_a[0].p_mbcbp; + mbCoeffPtr = stat_a[0].p_mbcoeff; + mbSizePtr = &(stat_a[0].p_mbsize); + } +#endif + + /* If mblock pattern flag set, parse and decode CBP (code block pattern). */ + if (mb_pattern == TRUE) { + DecodeCBP(vid_stream->mblock.cbp); + } + /* Otherwise, set CBP to zero. */ + else + vid_stream->mblock.cbp = 0; + + +#ifdef ANALYSIS + mbCBPPtr[vid_stream->mblock.cbp]++; +#endif + + /* Reconstruct motion vectors depending on picture type. */ + if (vid_stream->picture.code_type == P_TYPE) { + + /* + * If no forw motion vectors, reset previous and current vectors to 0. + */ + + if (!mb_motion_forw) { + recon_right_for = 0; + recon_down_for = 0; + vid_stream->mblock.recon_right_for_prev = 0; + vid_stream->mblock.recon_down_for_prev = 0; + } + /* + * Otherwise, compute new forw motion vectors. Reset previous vectors to + * current vectors. + */ + + else { + ComputeForwVector(&recon_right_for, &recon_down_for, vid_stream); + } + } + if (vid_stream->picture.code_type == B_TYPE) { + + /* Reset prev. and current vectors to zero if mblock is intracoded. */ + + if (vid_stream->mblock.mb_intra) { + vid_stream->mblock.recon_right_for_prev = 0; + vid_stream->mblock.recon_down_for_prev = 0; + vid_stream->mblock.recon_right_back_prev = 0; + vid_stream->mblock.recon_down_back_prev = 0; + } else { + + /* If no forw vectors, current vectors equal prev. vectors. */ + + if (!mb_motion_forw) { + recon_right_for = vid_stream->mblock.recon_right_for_prev; + recon_down_for = vid_stream->mblock.recon_down_for_prev; + } + /* + * Otherwise compute forw. vectors. Reset prev vectors to new values. + */ + + else { + ComputeForwVector(&recon_right_for, &recon_down_for, vid_stream); + } + + /* If no back vectors, set back vectors to prev back vectors. */ + + if (!mb_motion_back) { + recon_right_back = vid_stream->mblock.recon_right_back_prev; + recon_down_back = vid_stream->mblock.recon_down_back_prev; + } + /* Otherwise compute new vectors and reset prev. back vectors. */ + + else { + ComputeBackVector(&recon_right_back, &recon_down_back, vid_stream); + } + + /* + * Store vector existence flags in structure for possible skipped + * macroblocks to follow. + */ + + vid_stream->mblock.bpict_past_forw = mb_motion_forw; + vid_stream->mblock.bpict_past_back = mb_motion_back; + } + } + +#ifndef DISABLE_DITHER + /* For each possible block in macroblock. */ + if (ditherType == GRAY_DITHER || + ditherType == GRAY2_DITHER || + ditherType == GRAY256_DITHER || + ditherType == GRAY2562_DITHER || + ditherType == MONO_DITHER || + ditherType == MONO_THRESHOLD) { + for (mask = 32, i = 0; i < 4; mask >>= 1, i++) { + + /* If block exists... */ + if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) { + zero_block_flag = 0; + ParseReconBlock(i, vid_stream); + } else { + zero_block_flag = 1; + } + + /* If macroblock is intra coded... */ + if (vid_stream->mblock.mb_intra) { + ReconIMBlock(vid_stream, i); + } else if (mb_motion_forw && mb_motion_back) { + ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for, + recon_right_back, recon_down_back, zero_block_flag); + } else if (mb_motion_forw || (vid_stream->picture.code_type == P_TYPE)) { + ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for, + zero_block_flag); + } else if (mb_motion_back) { + ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back, + zero_block_flag); + } + } + /* Kill the Chrominance blocks... */ + if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x2)) { + ParseAwayBlock(4, vid_stream); + } + if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x1)) { + ParseAwayBlock(5, vid_stream); + } + } else { + if ((ditherType == MBORDERED_DITHER) && + (vid_stream->mblock.cbp == 0) && + (vid_stream->picture.code_type == 3) && + (!vid_stream->mblock.mb_intra) && + (!(mb_motion_forw && mb_motion_back))) { + MBOrderedDitherDisplayCopy(vid_stream, vid_stream->mblock.mb_address, + mb_motion_forw, recon_right_for, recon_down_for, + mb_motion_back, recon_right_back, recon_down_back, + vid_stream->past->display, vid_stream->future->display); + vid_stream->ditherFlags[vid_stream->mblock.mb_address] = 0; + no_dith_flag = 1; + } + else { +#endif + for (mask = 32, i = 0; i < 6; mask >>= 1, i++) { + + /* If block exists... */ + if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) { + zero_block_flag = 0; + ParseReconBlock(i, vid_stream); + } else { + zero_block_flag = 1; + } + +#ifndef USE_ATI + /* If macroblock is intra coded... */ + if (vid_stream->mblock.mb_intra) { + ReconIMBlock(vid_stream, i); + } else if (mb_motion_forw && mb_motion_back) { + ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for, + recon_right_back, recon_down_back, zero_block_flag); + } else if (mb_motion_forw || (vid_stream->picture.code_type == P_TYPE)) { + ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for, + zero_block_flag); + } else if (mb_motion_back) { + ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back, + zero_block_flag); + } +#endif + } + +#ifdef USE_ATI + vhar128_macroblock(vid_stream->ati_handle, + (vid_stream->mblock.mb_address % vid_stream->mb_width) << 4, + (vid_stream->mblock.mb_address / vid_stream->mb_width) << 4, + vid_stream->mblock.mb_intra, + mb_motion_back, mb_motion_forw, + recon_right_back, recon_down_back, + recon_right_for, recon_down_for, + vid_stream->block.dct_recon); +#endif + +#ifndef DISABLE_DITHER + } + } +#endif + +#ifndef DISABLE_DITHER + if ((ditherType == MBORDERED_DITHER) && (!no_dith_flag)) { + if ((vid_stream->picture.code_type == 2) && + (vid_stream->mblock.cbp == 0) && + (!vid_stream->mblock.mb_intra)) { + MBOrderedDitherDisplayCopy(vid_stream, vid_stream->mblock.mb_address, + 1, recon_right_for, recon_down_for, + 0, 0, 0, + vid_stream->future->display, + (unsigned char *) NULL); + vid_stream->ditherFlags[vid_stream->mblock.mb_address] = 0; + } + else { + vid_stream->ditherFlags[vid_stream->mblock.mb_address] = 1; + } + } +#endif + + /* If D Type picture, flush marker bit. */ + if (vid_stream->picture.code_type == 4) + flush_bits(1); + + /* If macroblock was intracoded, set macroblock past intra address. */ + if (vid_stream->mblock.mb_intra) + vid_stream->mblock.past_intra_addr = + vid_stream->mblock.mb_address; + + /* Store macroblock error for filter info */ + if (vid_stream->mblock.mb_intra) + vid_stream->current->mb_qscale[vid_stream->mblock.mb_address] = 0; + else + vid_stream->current->mb_qscale[vid_stream->mblock.mb_address] = vid_stream->slice.quant_scale; + +#ifdef ANALYSIS + *mbSizePtr += bitCountRead() - mbSizeCount; +#endif + return PARSE_OK; +} + +/* software decoder follows */ +#ifndef USE_ATI +/* + *-------------------------------------------------------------- + * + * ReconIMBlock -- + * + * Reconstructs intra coded macroblock. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +#if defined(USE_CROP_TABLE) && !defined(NDEBUG) +/* If people really want to see such things, check 'em */ +#define myassert(x,expression)\ + if (!(expression)) {\ + fprintf (stderr,"Bad crop value (%d) at line %d\n", x, __LINE__);\ + next_start_code(vid_stream); return;} +#define assertCrop(x) myassert(x,((x) >= -MAX_NEG_CROP) && \ + ((x) <= 2048+MAX_NEG_CROP)) +#else +#define assertCrop(x) +#endif + +static void ReconIMBlock( VidStream* vid_stream, int bnum ) +{ + int mb_row, mb_col, row, col, row_size, rr; + unsigned char *dest; + + /* Calculate macroblock row and column from address. */ + + mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; + mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; + + /* If block is luminance block... */ + + if (bnum < 4) { + + /* Calculate row and col values for upper left pixel of block. */ + + row = mb_row * 16; + col = mb_col * 16; + if (bnum > 1) + row += 8; + if (bnum % 2) + col += 8; + + /* Set dest to luminance plane of current pict image. */ + + dest = vid_stream->current->luminance; + + /* Establish row size. */ + + row_size = vid_stream->mb_width * 16; + } + /* Otherwise if block is Cr block... */ + /* Cr first because of the earlier mixup */ + + else if (bnum == 5) { + + /* Set dest to Cr plane of current pict image. */ + + dest = vid_stream->current->Cr; + + /* Establish row size. */ + + row_size = vid_stream->mb_width * 8; + + /* Calculate row,col for upper left pixel of block. */ + + row = mb_row * 8; + col = mb_col * 8; + } + /* Otherwise block is Cb block, and ... */ + + else { + + /* Set dest to Cb plane of current pict image. */ + + dest = vid_stream->current->Cb; + + /* Establish row size. */ + + row_size = vid_stream->mb_width * 8; + + /* Calculate row,col for upper left pixel value of block. */ + + row = mb_row * 8; + col = mb_col * 8; + } + + /* + * For each pixel in block, set to cropped reconstructed value from inverse + * dct. + */ + { + short *sp = &vid_stream->block.dct_recon[0][0]; +#ifdef USE_CROP_TABLE + unsigned char *cm = cropTbl + MAX_NEG_CROP; +#endif + dest += row * row_size + col; + for (rr = 0; rr < 4; rr++, sp += 16, dest += row_size) { + dest[0] = crop(sp[0]); + assertCrop(sp[0]); + dest[1] = crop(sp[1]); + assertCrop(sp[1]); + dest[2] = crop(sp[2]); + assertCrop(sp[2]); + dest[3] = crop(sp[3]); + assertCrop(sp[3]); + dest[4] = crop(sp[4]); + assertCrop(sp[4]); + dest[5] = crop(sp[5]); + assertCrop(sp[5]); + dest[6] = crop(sp[6]); + assertCrop(sp[6]); + dest[7] = crop(sp[7]); + assertCrop(sp[7]); + + dest += row_size; + dest[0] = crop(sp[8]); + assertCrop(sp[8]); + dest[1] = crop(sp[9]); + assertCrop(sp[9]); + dest[2] = crop(sp[10]); + assertCrop(sp[10]); + dest[3] = crop(sp[11]); + assertCrop(sp[11]); + dest[4] = crop(sp[12]); + assertCrop(sp[12]); + dest[5] = crop(sp[13]); + assertCrop(sp[13]); + dest[6] = crop(sp[14]); + assertCrop(sp[14]); + dest[7] = crop(sp[15]); + assertCrop(sp[15]); + } + } +} + + +/* + *-------------------------------------------------------------- + * + * ReconPMBlock -- + * + * Reconstructs forward predicted macroblocks. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void ReconPMBlock( VidStream* vid_stream, int bnum, + int recon_right_for, int recon_down_for, int zflag ) +{ + int mb_row, mb_col, row, col, row_size, rr; + unsigned char *dest, *past = 0; + unsigned char *rindex1, *rindex2, *rindex3, *rindex4; + unsigned char *index; + short int *blockvals; + +#ifdef LOOSE_MPEG + int maxx, maxy, cc; + int illegalBlock = 0; + int row_start, row_end, rfirst, rlast, col_start, col_end, cfirst, clast; +#endif + + /* Calculate macroblock row and column from address. */ + + mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; + mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; + + if (bnum < 4) { + + /* Calculate right_for, down_for motion vectors. */ + + vid_stream->right_for = recon_right_for >> 1; + vid_stream->down_for = recon_down_for >> 1; + vid_stream->right_half_for = recon_right_for & 0x1; + vid_stream->down_half_for = recon_down_for & 0x1; + + /* Set dest to luminance plane of current pict image. */ + + dest = vid_stream->current->luminance; + + if (vid_stream->picture.code_type == B_TYPE) { + if (vid_stream->past != NULL) + past = vid_stream->past->luminance; + } else { + + /* Set predictive frame to current future frame. */ + + if (vid_stream->future != NULL) + past = vid_stream->future->luminance; + } + + /* Establish row size. */ + + row_size = vid_stream->mb_width << 4; + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 4; + col = mb_col << 4; + if (bnum > 1) + row += 8; + if (bnum % 2) + col += 8; + +#ifdef LOOSE_MPEG + /* Check for block illegality. */ + + maxx = vid_stream->mb_width*16-1; + maxy = vid_stream->mb_height*16-1; + + if (row + vid_stream->down_for + vid_stream->down_half_for + 7 > maxy) illegalBlock |= 0x4; + else if (row + vid_stream->down_for < 0) illegalBlock |= 0x1; + + if (col + vid_stream->right_for + vid_stream->right_half_for + 7 > maxx) illegalBlock |= 0x2; + else if (col + vid_stream->right_for < 0) illegalBlock |= 0x8; + +#endif + } + /* Otherwise, block is NOT luminance block, ... */ + + else { + + /* Construct motion vectors. */ + + recon_right_for /= 2; + recon_down_for /= 2; + vid_stream->right_for = recon_right_for >> 1; + vid_stream->down_for = recon_down_for >> 1; + vid_stream->right_half_for = recon_right_for & 0x1; + vid_stream->down_half_for = recon_down_for & 0x1; + + /* Establish row size. */ + + row_size = vid_stream->mb_width << 3; + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 3; + col = mb_col << 3; + +#ifdef LOOSE_MPEG + /* Check for block illegality. */ + + maxx = vid_stream->mb_width*8-1; + maxy = vid_stream->mb_height*8-1; + + if (row + vid_stream->down_for + vid_stream->down_half_for + 7 > maxy) illegalBlock |= 0x4; + else if (row + vid_stream->down_for < 0) illegalBlock |= 0x1; + + if (col + vid_stream->right_for + vid_stream->right_half_for + 7 > maxx) illegalBlock |= 0x2; + else if (col + vid_stream->right_for < 0) illegalBlock |= 0x8; + +#endif + + /* If block is Cr block... */ + /* 5 first because order was mixed up in earlier versions */ + + if (bnum == 5) { + + /* Set dest to Cr plane of current pict image. */ + + dest = vid_stream->current->Cr; + + if (vid_stream->picture.code_type == B_TYPE) { + + if (vid_stream->past != NULL) + past = vid_stream->past->Cr; + } else { + if (vid_stream->future != NULL) + past = vid_stream->future->Cr; + } + } + /* Otherwise, block is Cb block... */ + + else { + + /* Set dest to Cb plane of current pict image. */ + + dest = vid_stream->current->Cb; + + if (vid_stream->picture.code_type == B_TYPE) { + if (vid_stream->past != NULL) + past = vid_stream->past->Cb; + } else { + if (vid_stream->future != NULL) + past = vid_stream->future->Cb; + } + } + } + + /* For each pixel in block... */ + +#ifdef LOOSE_MPEG + + if (illegalBlock) { + if (illegalBlock & 0x1) { + row_start = 0; + row_end = row+vid_stream->down_for+8; + rfirst = rlast = 8 - row_end; + } + else if (illegalBlock & 0x4) { + row_start = row + vid_stream->down_for; + row_end = maxy+1; + rlast = row_end - row_start - 1; + rfirst = 0; + } + else { + row_start = row+vid_stream->down_for; + row_end = row_start+8; + rfirst = 0; + } + + if (illegalBlock & 0x8) { + col_start = 0; + col_end = col + vid_stream->right_for + 8; + cfirst = clast = 8 - col_end; + } + else if (illegalBlock & 0x2) { + col_start = col + vid_stream->right_for; + col_end = maxx + 1; + clast = col_end - col_start - 1; + cfirst = 0; + } + else { + col_start = col + vid_stream->right_for; + col_end = col_start + 8; + cfirst = 0; + } + + for (rr = row_start; rr < row_end; rr++) { + rindex1 = past + (rr * row_size) + col_start; + index = dest + ((row + rfirst) * row_size) + col + cfirst; + for (cc = col_start; cc < col_end; cc++) { + *index++ = *rindex1++; + } + } + + if (illegalBlock & 0x1) { + for (rr = rlast -1; rr >=0; rr--) { + index = dest + ((row + rr) * row_size) + col; + rindex1 = dest + ((row + rlast) * row_size) + col; + for (cc = 0; cc < 8; cc ++) { + *index++ = *rindex1++; + } + } + } + else if (illegalBlock & 0x4) { + for (rr = rlast+1; rr < 8; rr++) { + index = dest + ((row + rr) * row_size) + col; + rindex1 = dest + ((row + rlast) * row_size) + col; + for (cc = 0; cc < 8; cc ++) { + *index++ = *rindex1++; + } + } + } + + if (illegalBlock & 0x2) { + for (cc = clast+1; cc < 8; cc++) { + index = dest + (row * row_size) + (col + cc); + rindex1 = dest + (row * row_size) + (col + clast); + for (rr = 0; rr < 8; rr++) { + *index = *rindex1; + index += row_size; + rindex1 += row_size; + } + } + } + else if (illegalBlock & 0x8) { + for (cc = clast-1; cc >= 0; cc--) { + index = dest + (row * row_size) + (col + cc); + rindex1 = dest + (row * row_size) + (col + clast); + for (rr = 0; rr < 8; rr++) { + *index = *rindex1; + index += row_size; + rindex1 += row_size; + } + } + } + + if (!zflag) { + for (rr = 0; rr < 8; rr++) { + index = dest + (row*row_size) + col; + blockvals = &(vid_stream->block.dct_recon[rr][0]); + index[0] += blockvals[0]; + index[1] += blockvals[1]; + index[2] += blockvals[2]; + index[3] += blockvals[3]; + index[4] += blockvals[4]; + index[5] += blockvals[5]; + index[6] += blockvals[6]; + index[7] += blockvals[7]; + } + } + } + else { + +#endif + + index = dest + (row * row_size) + col; + rindex1 = past + (row + vid_stream->down_for) * row_size + + col + vid_stream->right_for; + + blockvals = &(vid_stream->block.dct_recon[0][0]); + + /* + * Calculate predictive pixel value based on motion vectors and copy to + * dest plane. + */ + + if ((!vid_stream->down_half_for) && (!vid_stream->right_half_for)) { +#ifdef USE_CROP_TABLE + unsigned char *cm = cropTbl + MAX_NEG_CROP; +#endif + if (!zflag) + for (rr = 0; rr < 4; rr++) { + index[0] = crop((int) rindex1[0] + (int) blockvals[0]); + index[1] = crop((int) rindex1[1] + (int) blockvals[1]); + index[2] = crop((int) rindex1[2] + (int) blockvals[2]); + index[3] = crop((int) rindex1[3] + (int) blockvals[3]); + index[4] = crop((int) rindex1[4] + (int) blockvals[4]); + index[5] = crop((int) rindex1[5] + (int) blockvals[5]); + index[6] = crop((int) rindex1[6] + (int) blockvals[6]); + index[7] = crop((int) rindex1[7] + (int) blockvals[7]); + index += row_size; + rindex1 += row_size; + + index[0] = crop((int) rindex1[0] + (int) blockvals[8]); + index[1] = crop((int) rindex1[1] + (int) blockvals[9]); + index[2] = crop((int) rindex1[2] + (int) blockvals[10]); + index[3] = crop((int) rindex1[3] + (int) blockvals[11]); + index[4] = crop((int) rindex1[4] + (int) blockvals[12]); + index[5] = crop((int) rindex1[5] + (int) blockvals[13]); + index[6] = crop((int) rindex1[6] + (int) blockvals[14]); + index[7] = crop((int) rindex1[7] + (int) blockvals[15]); + blockvals += 16; + index += row_size; + rindex1 += row_size; + } + else { + if (vid_stream->right_for & 0x1) { + /* No alignment, use bye copy */ + for (rr = 0; rr < 4; rr++) { + index[0] = rindex1[0]; + index[1] = rindex1[1]; + index[2] = rindex1[2]; + index[3] = rindex1[3]; + index[4] = rindex1[4]; + index[5] = rindex1[5]; + index[6] = rindex1[6]; + index[7] = rindex1[7]; + index += row_size; + rindex1 += row_size; + + index[0] = rindex1[0]; + index[1] = rindex1[1]; + index[2] = rindex1[2]; + index[3] = rindex1[3]; + index[4] = rindex1[4]; + index[5] = rindex1[5]; + index[6] = rindex1[6]; + index[7] = rindex1[7]; + index += row_size; + rindex1 += row_size; + } + } else if (vid_stream->right_for & 0x2) { + /* Half-word bit aligned, use 16 bit copy */ + short *src = (short *)rindex1; + short *dest = (short *)index; + row_size >>= 1; + for (rr = 0; rr < 4; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_size; + src += row_size; + + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_size; + src += row_size; + } + } else { + /* Word aligned, use 32 bit copy */ + int *src = (int *)rindex1; + int *dest = (int *)index; + row_size >>= 2; + for (rr = 0; rr < 4; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest += row_size; + src += row_size; + + dest[0] = src[0]; + dest[1] = src[1]; + dest += row_size; + src += row_size; + } + } + } + } else { +#ifdef USE_CROP_TABLE + unsigned char *cm = cropTbl + MAX_NEG_CROP; +#endif + rindex2 = rindex1 + vid_stream->right_half_for + + (vid_stream->down_half_for * row_size); + + /* if one of the two is zero, then quality makes no difference */ + if ((!vid_stream->right_half_for) || + (!vid_stream->down_half_for) || (!qualityFlag)) { + + if (!zflag) { + for (rr = 0; rr < 4; rr++) { + index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[0]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[1]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[2]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[3]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[4]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[5]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[6]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[7]); + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + + index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[8]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[9]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[10]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[11]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[12]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[13]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[14]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[15]); + blockvals += 16; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + } + } else { /* zflag */ + for (rr = 0; rr < 8; rr++) { + index[0] = (int) (rindex1[0] + rindex2[0] + 1) >> 1; + index[1] = (int) (rindex1[1] + rindex2[1] + 1) >> 1; + index[2] = (int) (rindex1[2] + rindex2[2] + 1) >> 1; + index[3] = (int) (rindex1[3] + rindex2[3] + 1) >> 1; + index[4] = (int) (rindex1[4] + rindex2[4] + 1) >> 1; + index[5] = (int) (rindex1[5] + rindex2[5] + 1) >> 1; + index[6] = (int) (rindex1[6] + rindex2[6] + 1) >> 1; + index[7] = (int) (rindex1[7] + rindex2[7] + 1) >> 1; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + } + } + } else { /* qualityFlag on and both vectors are non-zero */ + rindex3 = rindex1 + vid_stream->right_half_for; + rindex4 = rindex1 + (vid_stream->down_half_for * row_size); + if (!zflag) { + for (rr = 0; rr < 4; rr++) { + index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[0]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[1]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[2]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[3]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[4]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[5]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[6]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[7]); + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + rindex3 += row_size; + rindex4 += row_size; + + index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[8]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[9]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[10]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[11]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[12]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[13]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[14]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[15]); + blockvals += 16; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + rindex3 += row_size; + rindex4 += row_size; + } + } else { /* zflag */ + for (rr = 0; rr < 8; rr++) { + index[0] = (int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2; + index[1] = (int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2; + index[2] = (int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2; + index[3] = (int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2; + index[4] = (int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2; + index[5] = (int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2; + index[6] = (int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2; + index[7] = (int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + rindex3 += row_size; + rindex4 += row_size; + } + } + } + + } +#ifdef LOOSE_MPEG + } +#endif +} + + +/* + *-------------------------------------------------------------- + * + * ReconBMBlock -- + * + * Reconstructs back predicted macroblocks. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void ReconBMBlock( VidStream* vid_stream, int bnum, + int recon_right_back, int recon_down_back, int zflag ) +{ + int mb_row, mb_col, row, col, row_size, rr; + unsigned char *dest, *future = 0; + int right_back, down_back, right_half_back, down_half_back; + unsigned char *rindex1, *rindex2, *rindex3, *rindex4; + unsigned char *index; + short int *blockvals; + +#ifdef LOOSE_MPEG + int illegalBlock = 0; + int maxx, maxy, cc; + int row_start, row_end, rlast, rfirst, col_start, col_end, clast, cfirst; +#endif + + /* Calculate macroblock row and column from address. */ + + mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; + mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; + + /* If block is luminance block... */ + + if (bnum < 4) { + + /* Calculate right_back, down_back motion vectors. */ + + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + /* Set dest to luminance plane of current pict image. */ + + dest = vid_stream->current->luminance; + + /* + * If future frame exists, set future to luminance plane of future frame. + */ + + if (vid_stream->future != NULL) + future = vid_stream->future->luminance; + + /* Establish row size. */ + + row_size = vid_stream->mb_width << 4; + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 4; + col = mb_col << 4; + if (bnum > 1) + row += 8; + if (bnum % 2) + col += 8; + +#ifdef LOOSE_MPEG + + /* Check for block illegality. */ + + maxx = vid_stream->mb_width*16-1; + maxy = vid_stream->mb_height*16-1; + + if (row + down_back + down_half_back + 7 > maxy) illegalBlock |= 0x4; + else if (row + down_back < 0) illegalBlock |= 0x1; + + if (col + right_back + right_half_back + 7 > maxx) illegalBlock |= 0x2; + else if (col + right_back < 0) illegalBlock |= 0x8; + +#endif + + } + /* Otherwise, block is NOT luminance block, ... */ + + else { + + /* Construct motion vectors. */ + + recon_right_back /= 2; + recon_down_back /= 2; + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + /* Establish row size. */ + + row_size = vid_stream->mb_width << 3; + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 3; + col = mb_col << 3; + +#ifdef LOOSE_MPEG + + /* Check for block illegality. */ + + maxx = vid_stream->mb_width*8-1; + maxy = vid_stream->mb_height*8-1; + + if (row + down_back + down_half_back + 7 > maxy) illegalBlock |= 0x4; + else if (row + down_back < 0) illegalBlock |= 0x1; + + if (col + right_back + right_half_back + 7 > maxx) illegalBlock |= 0x2; + else if (col + right_back < 0) illegalBlock |= 0x8; + +#endif + + /* If block is Cr block... */ + /* They were switched earlier, so 5 is first - eyhung */ + + if (bnum == 5) { + + /* Set dest to Cr plane of current pict image. */ + + dest = vid_stream->current->Cr; + + /* + * If future frame exists, set future to Cr plane of future image. + */ + + if (vid_stream->future != NULL) + future = vid_stream->future->Cr; + } + /* Otherwise, block is Cb block... */ + + else { + + /* Set dest to Cb plane of current pict image. */ + + dest = vid_stream->current->Cb; + + /* + * If future frame exists, set future to Cb plane of future frame. + */ + + if (vid_stream->future != NULL) + future = vid_stream->future->Cb; + } + } + + /* For each pixel in block do... */ + +#ifdef LOOSE_MPEG + + if (illegalBlock) { + if (illegalBlock & 0x1) { + row_start = 0; + row_end = row+down_back+8; + rfirst = rlast = 8 - row_end; + } + else if (illegalBlock & 0x4) { + row_start = row + down_back; + row_end = maxy+1; + rlast = row_end - row_start - 1; + rfirst = 0; + } + else { + row_start = row+down_back; + row_end = row_start+8; + rfirst = 0; + } + + if (illegalBlock & 0x8) { + col_start = 0; + col_end = col + right_back + 8; + cfirst = clast = 8 - col_end; + } + else if (illegalBlock & 0x2) { + col_start = col + right_back; + col_end = maxx + 1; + clast = col_end - col_start - 1; + cfirst = 0; + } + else { + col_start = col + right_back; + col_end = col_start + 8; + cfirst = 0; + } + + for (rr = row_start; rr < row_end; rr++) { + rindex1 = future + (rr * row_size) + col_start; + index = dest + ((row + rfirst) * row_size) + col + cfirst; + for (cc = col_start; cc < col_end; cc++) { + *index++ = *rindex1++; + } + } + + if (illegalBlock & 0x1) { + for (rr = rlast -1; rr >=0; rr--) { + index = dest + ((row + rr) * row_size) + col; + rindex1 = dest + ((row + rlast) * row_size) + col; + for (cc = 0; cc < 8; cc ++) { + *index++ = *rindex1++; + } + } + } + else if (illegalBlock & 0x4) { + for (rr = rlast+1; rr < 8; rr++) { + index = dest + ((row + rr) * row_size) + col; + rindex1 = dest + ((row + rlast) * row_size) + col; + for (cc = 0; cc < 8; cc ++) { + *index++ = *rindex1++; + } + } + } + + if (illegalBlock & 0x2) { + for (cc = clast+1; cc < 8; cc++) { + index = dest + (row * row_size) + (col + cc); + rindex1 = dest + (row * row_size) + (col + clast); + for (rr = 0; rr < 8; rr++) { + *index = *rindex1; + index += row_size; + rindex1 += row_size; + } + } + } + else if (illegalBlock & 0x8) { + for (cc = clast-1; cc >= 0; cc--) { + index = dest + (row * row_size) + (col + cc); + rindex1 = dest + (row * row_size) + (col + clast); + for (rr = 0; rr < 8; rr++) { + *index = *rindex1; + index += row_size; + rindex1 += row_size; + } + } + } + + if (!zflag) { + for (rr = 0; rr < 8; rr++) { + index = dest + (row*row_size) + col; + blockvals = &(vid_stream->block.dct_recon[rr][0]); + index[0] += blockvals[0]; + index[1] += blockvals[1]; + index[2] += blockvals[2]; + index[3] += blockvals[3]; + index[4] += blockvals[4]; + index[5] += blockvals[5]; + index[6] += blockvals[6]; + index[7] += blockvals[7]; + } + } + } + else { + +#endif + + index = dest + (row * row_size) + col; + rindex1 = future + (row + down_back) * row_size + col + right_back; + + blockvals = &(vid_stream->block.dct_recon[0][0]); + + if ((!right_half_back) && (!down_half_back)) { +#ifdef USE_CROP_TABLE + unsigned char *cm = cropTbl + MAX_NEG_CROP; +#endif + if (!zflag) + for (rr = 0; rr < 4; rr++) { + index[0] = crop((int) rindex1[0] + (int) blockvals[0]); + index[1] = crop((int) rindex1[1] + (int) blockvals[1]); + index[2] = crop((int) rindex1[2] + (int) blockvals[2]); + index[3] = crop((int) rindex1[3] + (int) blockvals[3]); + index[4] = crop((int) rindex1[4] + (int) blockvals[4]); + index[5] = crop((int) rindex1[5] + (int) blockvals[5]); + index[6] = crop((int) rindex1[6] + (int) blockvals[6]); + index[7] = crop((int) rindex1[7] + (int) blockvals[7]); + index += row_size; + rindex1 += row_size; + + index[0] = crop((int) rindex1[0] + (int) blockvals[8]); + index[1] = crop((int) rindex1[1] + (int) blockvals[9]); + index[2] = crop((int) rindex1[2] + (int) blockvals[10]); + index[3] = crop((int) rindex1[3] + (int) blockvals[11]); + index[4] = crop((int) rindex1[4] + (int) blockvals[12]); + index[5] = crop((int) rindex1[5] + (int) blockvals[13]); + index[6] = crop((int) rindex1[6] + (int) blockvals[14]); + index[7] = crop((int) rindex1[7] + (int) blockvals[15]); + blockvals += 16; + index += row_size; + rindex1 += row_size; + } + else { + if (right_back & 0x1) { + /* No alignment, use bye copy */ + for (rr = 0; rr < 4; rr++) { + index[0] = rindex1[0]; + index[1] = rindex1[1]; + index[2] = rindex1[2]; + index[3] = rindex1[3]; + index[4] = rindex1[4]; + index[5] = rindex1[5]; + index[6] = rindex1[6]; + index[7] = rindex1[7]; + index += row_size; + rindex1 += row_size; + + index[0] = rindex1[0]; + index[1] = rindex1[1]; + index[2] = rindex1[2]; + index[3] = rindex1[3]; + index[4] = rindex1[4]; + index[5] = rindex1[5]; + index[6] = rindex1[6]; + index[7] = rindex1[7]; + index += row_size; + rindex1 += row_size; + } + } else if (right_back & 0x2) { + /* Half-word bit aligned, use 16 bit copy */ + short *src = (short *)rindex1; + short *dest = (short *)index; + row_size >>= 1; + for (rr = 0; rr < 4; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_size; + src += row_size; + + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_size; + src += row_size; + } + } else { + /* Word aligned, use 32 bit copy */ + int *src = (int *)rindex1; + int *dest = (int *)index; + row_size >>= 2; + for (rr = 0; rr < 4; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest += row_size; + src += row_size; + + dest[0] = src[0]; + dest[1] = src[1]; + dest += row_size; + src += row_size; + } + } + } + } else { +#ifdef USE_CROP_TABLE + unsigned char *cm = cropTbl + MAX_NEG_CROP; +#endif + rindex2 = rindex1 + right_half_back + (down_half_back * row_size); + if (!qualityFlag) { + + if (!zflag) { + for (rr = 0; rr < 4; rr++) { + index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[0]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[1]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[2]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[3]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[4]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[5]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[6]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[7]); + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + + index[0] = crop(((int) (rindex1[0] + rindex2[0] + 1) >> 1) + blockvals[8]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + 1) >> 1) + blockvals[9]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + 1) >> 1) + blockvals[10]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + 1) >> 1) + blockvals[11]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + 1) >> 1) + blockvals[12]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + 1) >> 1) + blockvals[13]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + 1) >> 1) + blockvals[14]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + 1) >> 1) + blockvals[15]); + blockvals += 16; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + } + } else { /* zflag */ + for (rr = 0; rr < 8; rr++) { + index[0] = (int) (rindex1[0] + rindex2[0] + 1) >> 1; + index[1] = (int) (rindex1[1] + rindex2[1] + 1) >> 1; + index[2] = (int) (rindex1[2] + rindex2[2] + 1) >> 1; + index[3] = (int) (rindex1[3] + rindex2[3] + 1) >> 1; + index[4] = (int) (rindex1[4] + rindex2[4] + 1) >> 1; + index[5] = (int) (rindex1[5] + rindex2[5] + 1) >> 1; + index[6] = (int) (rindex1[6] + rindex2[6] + 1) >> 1; + index[7] = (int) (rindex1[7] + rindex2[7] + 1) >> 1; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + } + } + } else { /* qualityFlag on */ + rindex3 = rindex1 + right_half_back; + rindex4 = rindex1 + (down_half_back * row_size); + if (!zflag) { + for (rr = 0; rr < 4; rr++) { + index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[0]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[1]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[2]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[3]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[4]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[5]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[6]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[7]); + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + rindex3 += row_size; + rindex4 += row_size; + + index[0] = crop(((int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2) + blockvals[8]); + index[1] = crop(((int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2) + blockvals[9]); + index[2] = crop(((int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2) + blockvals[10]); + index[3] = crop(((int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2) + blockvals[11]); + index[4] = crop(((int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2) + blockvals[12]); + index[5] = crop(((int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2) + blockvals[13]); + index[6] = crop(((int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2) + blockvals[14]); + index[7] = crop(((int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2) + blockvals[15]); + blockvals += 16; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + rindex3 += row_size; + rindex4 += row_size; + } + } else { /* zflag */ + for (rr = 0; rr < 8; rr++) { + index[0] = (int) (rindex1[0] + rindex2[0] + rindex3[0] + rindex4[0] + 2) >> 2; + index[1] = (int) (rindex1[1] + rindex2[1] + rindex3[1] + rindex4[1] + 2) >> 2; + index[2] = (int) (rindex1[2] + rindex2[2] + rindex3[2] + rindex4[2] + 2) >> 2; + index[3] = (int) (rindex1[3] + rindex2[3] + rindex3[3] + rindex4[3] + 2) >> 2; + index[4] = (int) (rindex1[4] + rindex2[4] + rindex3[4] + rindex4[4] + 2) >> 2; + index[5] = (int) (rindex1[5] + rindex2[5] + rindex3[5] + rindex4[5] + 2) >> 2; + index[6] = (int) (rindex1[6] + rindex2[6] + rindex3[6] + rindex4[6] + 2) >> 2; + index[7] = (int) (rindex1[7] + rindex2[7] + rindex3[7] + rindex4[7] + 2) >> 2; + index += row_size; + rindex1 += row_size; + rindex2 += row_size; + rindex3 += row_size; + rindex4 += row_size; + } + } + } + + } +#ifdef LOOSE_MPEG + } +#endif +} + + +/* + *-------------------------------------------------------------- + * + * ReconBiMBlock -- + * + * Reconstructs bidirectionally predicted macroblocks. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void ReconBiMBlock( VidStream* vid_stream, int bnum, + int recon_right_for, int recon_down_for, int recon_right_back, + int recon_down_back, int zflag ) +{ + int mb_row, mb_col, row, col, row_size, rr; + unsigned char *dest, *past=NULL, *future=NULL; + int right_for, down_for, right_half_for, down_half_for; + int right_back, down_back, right_half_back, down_half_back; + unsigned char *index, *rindex1, *bindex1; + short int *blockvals; + int forw_row_start, back_row_start, forw_col_start, back_col_start; + +#ifdef LOOSE_MPEG + int lmaxx = vid_stream->mb_width*16-1; + int lmaxy = vid_stream->mb_height*16-1; + int cmaxx = vid_stream->mb_width*8-1; + int cmaxy = vid_stream->mb_height*8-1; +#endif + +#ifdef LOOSE_MPEG + int illegal_forw = 0; + int illegal_back = 0; +#endif + + /* Calculate macroblock row and column from address. */ + + mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; + mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; + + /* If block is luminance block... */ + + if (bnum < 4) { + + /* + * Calculate right_for, down_for, right_half_for, down_half_for, + * right_back, down_bakc, right_half_back, and down_half_back, motion + * vectors. + */ + + right_for = recon_right_for >> 1; + down_for = recon_down_for >> 1; + right_half_for = recon_right_for & 0x1; + down_half_for = recon_down_for & 0x1; + + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + /* Set dest to luminance plane of current pict image. */ + + dest = vid_stream->current->luminance; + + /* If past frame exists, set past to luminance plane of past frame. */ + + if (vid_stream->past != NULL) + past = vid_stream->past->luminance; + + /* + * If future frame exists, set future to luminance plane of future frame. + */ + + if (vid_stream->future != NULL) + future = vid_stream->future->luminance; + + /* Establish row size. */ + + row_size = (vid_stream->mb_width << 4); + + /* Calculate row,col of upper left pixel in block. */ + + row = (mb_row << 4); + col = (mb_col << 4); + if (bnum > 1) + row += 8; + if (bnum & 0x01) + col += 8; + +#ifdef LOOSE_MPEG + + /* Check for illegal pred. blocks. */ + + + /* Illegal forward Y block, right component */ + if (col + right_for + right_half_for + 7 > lmaxx) + { + if(col > lmaxx) // fix mb column + col = lmaxx & ~15; + if(col + right_for + 7 > lmaxx) // fix full component + right_for = lmaxx - col - 7; + if(col + right_for + right_half_for + 7 > lmaxx) // fix half component + right_half_for = 0; + } + else if (col + right_for < 0) + { + if(col < 0) // fix mb column + col = 0; + if(col + right_for < 0) // fix full component + right_for = 0; + } + + /* Illegal forward Y block, down component */ + if (row + down_for + down_half_for + 7 > lmaxy) + { + if(row > lmaxy) // fix mb row + row = lmaxy & ~15; + if(row + down_for + 7 > lmaxy) // fix full component + down_for = lmaxy - row - 7; + if(row + down_for + down_half_for + 7 > lmaxy) // fix half component + down_half_for = 0; + } + else if (row + down_for < 0) + { + if(row < 0) // fix mb row + row = 0; + if(row + down_for < 0) // fix full component + down_for = 0; + } + + + /* Illegal backward Y block, right component */ + if (col + right_back + right_half_back + 7 > lmaxx) + { + if(col > lmaxx) // fix mb column + col = lmaxx & ~15; + if(col + right_back + 7 > lmaxx) // fix full component + right_back = lmaxx - col - 7; + if(col + right_back + right_half_back + 7 > lmaxx) // fix half component + right_half_back = 0; + } + else if (col + right_back < 0) + { + if(col < 0) // fix mb column + col = 0; + if(col + right_back < 0) // fix full component + right_back = 0; + } + + /* Illegal backward Y block, down component */ + if (row + down_back + down_half_back + 7 > lmaxy) + { + if(row > lmaxy) // fix mb row + row = lmaxy & ~15; + if(row + down_back + 7 > lmaxy) // fix full component + down_back = lmaxy - row - 7; + if(row + down_back + down_half_back + 7 > lmaxy) // fix half component + down_half_back = 0; + } + else if (row + down_back < 0) + { + if(row < 0) // fix mb row + row = 0; + if(row + down_back < 0) // fix full component + down_back = 0; + } + +#endif + + forw_col_start = col + right_for; + forw_row_start = row + down_for; + + back_col_start = col + right_back; + back_row_start = row + down_back; + + } + /* Otherwise, block is NOT luminance block, ... */ + + else { + + /* Construct motion vectors. */ + + recon_right_for /= 2; + recon_down_for /= 2; + right_for = recon_right_for >> 1; + down_for = recon_down_for >> 1; + right_half_for = recon_right_for & 0x1; + down_half_for = recon_down_for & 0x1; + + recon_right_back /= 2; + recon_down_back /= 2; + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + /* Establish row size. */ + + row_size = (vid_stream->mb_width << 3); + + /* Calculate row,col of upper left pixel in block. */ + + row = (mb_row << 3); + col = (mb_col << 3); + +#ifdef LOOSE_MPEG + + /* Check for illegal pred. blocks. */ + + + /* Illegal forward C block, right component */ + if (col + right_for + right_half_for + 7 > cmaxx) + { + if(col > cmaxx) // fix mb column + col = cmaxx & ~15; + if(col + right_for + 7 > cmaxx) // fix full component + right_for = cmaxx - col - 7; + if(col + right_for + right_half_for + 7 > cmaxx) // fix half component + right_half_for = 0; + } + else if (col + right_for < 0) + { + if(col < 0) // fix mb column + col = 0; + if(col + right_for < 0) // fix full component + right_for = 0; + } + + /* Illegal forward C block, down component */ + if (row + down_for + down_half_for + 7 > cmaxy) + { + if(row > cmaxy) // fix mb row + row = cmaxy & ~15; + if(row + down_for + 7 > cmaxy) // fix full component + down_for = cmaxy - row - 7; + if(row + down_for + down_half_for + 7 > cmaxy) // fix half component + down_half_for = 0; + } + else if (row + down_for < 0) + { + if(row < 0) // fix mb row + row = 0; + if(row + down_for < 0) // fix full component + down_for = 0; + } + + + /* Illegal backward C block, right component */ + if (col + right_back + right_half_back + 7 > cmaxx) + { + if(col > cmaxx) // fix mb column + col = cmaxx & ~15; + if(col + right_back + 7 > cmaxx) // fix full component + right_back = cmaxx - col - 7; + if(col + right_back + right_half_back + 7 > cmaxx) // fix half component + right_half_back = 0; + } + else if (col + right_back < 0) + { + if(col < 0) // fix mb column + col = 0; + if(col + right_back < 0) // fix full component + right_back = 0; + } + + /* Illegal backward C block, down component */ + if (row + down_back + down_half_back + 7 > cmaxy) + { + if(row > cmaxy) // fix mb row + row = cmaxy & ~15; + if(row + down_back + 7 > cmaxy) // fix full component + down_back = cmaxy - row - 7; + if(row + down_back + down_half_back + 7 > cmaxy) // fix half component + down_half_back = 0; + } + else if (row + down_back < 0) + { + if(row < 0) // fix mb row + row = 0; + if(row + down_back < 0) // fix full component + down_back = 0; + } + +#endif + + forw_col_start = col + right_for; + forw_row_start = row + down_for; + + back_col_start = col + right_back; + back_row_start = row + down_back; + + /* If block is Cr block... */ + /* Switched earlier, so we test Cr first - eyhung */ + + if (bnum == 5) { + + /* Set dest to Cr plane of current pict image. */ + + dest = vid_stream->current->Cr; + + /* If past frame exists, set past to Cr plane of past image. */ + + if (vid_stream->past != NULL) + past = vid_stream->past->Cr; + + /* + * If future frame exists, set future to Cr plane of future image. + */ + + if (vid_stream->future != NULL) + future = vid_stream->future->Cr; + } + /* Otherwise, block is Cb block... */ + + else { + + /* Set dest to Cb plane of current pict image. */ + + dest = vid_stream->current->Cb; + + /* If past frame exists, set past to Cb plane of past frame. */ + + if (vid_stream->past != NULL) + past = vid_stream->past->Cb; + + /* + * If future frame exists, set future to Cb plane of future frame. + */ + + if (vid_stream->future != NULL) + future = vid_stream->future->Cb; + } + } + + /* For each pixel in block... */ + + index = dest + (row * row_size) + col; + +#ifdef LOOSE_MPEG + if (illegal_forw) + rindex1 = future + back_row_start * row_size + back_col_start; + else +#endif + rindex1 = past + forw_row_start * row_size + forw_col_start; + +#ifdef LOOSE_MPEG + if (illegal_back) + bindex1 = past + forw_row_start * row_size + forw_col_start; + else +#endif + bindex1 = future + back_row_start * row_size + back_col_start; + + blockvals = (short int *) &(vid_stream->block.dct_recon[0][0]); + + { +#ifdef USE_CROP_TABLE + unsigned char *cm = cropTbl + MAX_NEG_CROP; +#endif + if (!zflag) + for (rr = 0; rr < 4; rr++) { + index[0] = crop(((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[0]); + index[1] = crop(((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[1]); + index[2] = crop(((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[2]); + index[3] = crop(((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[3]); + index[4] = crop(((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[4]); + index[5] = crop(((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[5]); + index[6] = crop(((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[6]); + index[7] = crop(((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[7]); + index += row_size; + rindex1 += row_size; + bindex1 += row_size; + + index[0] = crop(((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[8]); + index[1] = crop(((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[9]); + index[2] = crop(((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[10]); + index[3] = crop(((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[11]); + index[4] = crop(((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[12]); + index[5] = crop(((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[13]); + index[6] = crop(((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[14]); + index[7] = crop(((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[15]); + blockvals += 16; + index += row_size; + rindex1 += row_size; + bindex1 += row_size; + } + + else + for (rr = 0; rr < 4; rr++) { + index[0] = (int) (rindex1[0] + bindex1[0]) >> 1; + index[1] = (int) (rindex1[1] + bindex1[1]) >> 1; + index[2] = (int) (rindex1[2] + bindex1[2]) >> 1; + index[3] = (int) (rindex1[3] + bindex1[3]) >> 1; + index[4] = (int) (rindex1[4] + bindex1[4]) >> 1; + index[5] = (int) (rindex1[5] + bindex1[5]) >> 1; + index[6] = (int) (rindex1[6] + bindex1[6]) >> 1; + index[7] = (int) (rindex1[7] + bindex1[7]) >> 1; + index += row_size; + rindex1 += row_size; + bindex1 += row_size; + + index[0] = (int) (rindex1[0] + bindex1[0]) >> 1; + index[1] = (int) (rindex1[1] + bindex1[1]) >> 1; + index[2] = (int) (rindex1[2] + bindex1[2]) >> 1; + index[3] = (int) (rindex1[3] + bindex1[3]) >> 1; + index[4] = (int) (rindex1[4] + bindex1[4]) >> 1; + index[5] = (int) (rindex1[5] + bindex1[5]) >> 1; + index[6] = (int) (rindex1[6] + bindex1[6]) >> 1; + index[7] = (int) (rindex1[7] + bindex1[7]) >> 1; + index += row_size; + rindex1 += row_size; + bindex1 += row_size; + } + } +} + +#endif /* USE_ATI */ + +/* + *-------------------------------------------------------------- + * + * ProcessSkippedPFrameMBlocks -- + * + * Processes skipped macroblocks in P frames. + * + * Results: + * Calculates pixel values for luminance, Cr, and Cb planes + * in current pict image for skipped macroblocks. + * + * Side effects: + * Pixel values in pict image changed. + * + *-------------------------------------------------------------- + */ + +static void ProcessSkippedPFrameMBlocks( VidStream* vid_stream ) +{ + int row_size, half_row, mb_row, mb_col, row, col, rr; + int addr, row_incr, half_row_incr, crow, ccol; + int *dest, *src, *dest1, *src1; +#ifndef DISABLE_DITHER + int ditherType=vid_stream->ditherType; +#endif + + /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ + + row_size = vid_stream->mb_width << 4; + half_row = (row_size >> 1); + row_incr = row_size >> 2; + half_row_incr = half_row >> 2; + + /* For each skipped macroblock, do... */ + + for (addr = vid_stream->mblock.past_mb_addr + 1; + addr < vid_stream->mblock.mb_address; addr++) { + + /* Calculate macroblock row and col. */ + + mb_row = addr / vid_stream->mb_width; + mb_col = addr % vid_stream->mb_width; + + /* Calculate upper left pixel row,col for luminance plane. */ + + row = mb_row << 4; + col = mb_col << 4; + +#ifdef USE_ATI + vhar128_macroblock(vid_stream->ati_handle, + col, + row, + 0, /* skipped block are empty non-intra blocks */ + 1, 0, /* P frames are based on past picture */ + 0, 0, /* backward motion is null */ + 0, 0, /* forward motion is null */ + vid_stream->block.dct_recon); +#else + + /* For each row in macroblock luminance plane... */ + + dest = (int *)(vid_stream->current->luminance + (row * row_size) + col); + src = (int *)(vid_stream->future->luminance + (row * row_size) + col); + + for (rr = 0; rr < 8; rr++) { + + /* Copy pixel values from last I or P picture. */ + + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_incr; + src += row_incr; + + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_incr; + src += row_incr; + } + + /* + * Divide row,col to get upper left pixel of macroblock in Cr and Cb + * planes. + */ + + crow = row >> 1; + ccol = col >> 1; + + /* For each row in Cr, and Cb planes... */ + + dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol); + src = (int *)(vid_stream->future->Cr + (crow * half_row) + ccol); + dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol); + src1 = (int *)(vid_stream->future->Cb + (crow * half_row) + ccol); + + for (rr = 0; rr < 4; rr++) { + + /* Copy pixel values from last I or P picture. */ + + dest[0] = src[0]; + dest[1] = src[1]; + + dest1[0] = src1[0]; + dest1[1] = src1[1]; + + dest += half_row_incr; + src += half_row_incr; + dest1 += half_row_incr; + src1 += half_row_incr; + + dest[0] = src[0]; + dest[1] = src[1]; + + dest1[0] = src1[0]; + dest1[1] = src1[1]; + + dest += half_row_incr; + src += half_row_incr; + dest1 += half_row_incr; + src1 += half_row_incr; + } + +#ifndef DISABLE_DITHER + if (ditherType == MBORDERED_DITHER) { + MBOrderedDitherDisplayCopy(vid_stream, addr, + 1, 0, 0, 0, 0, 0, + vid_stream->future->display, + (unsigned char *) NULL); + vid_stream->ditherFlags[addr] = 0; + } +#endif +#endif /* USE_ATI */ + } + + vid_stream->mblock.recon_right_for_prev = 0; + vid_stream->mblock.recon_down_for_prev = 0; +} + + +/* + *-------------------------------------------------------------- + * + * ProcessSkippedBFrameMBlocks -- + * + * Processes skipped macroblocks in B frames. + * + * Results: + * Calculates pixel values for luminance, Cr, and Cb planes + * in current pict image for skipped macroblocks. + * + * Side effects: + * Pixel values in pict image changed. + * + *-------------------------------------------------------------- + */ + +static void ProcessSkippedBFrameMBlocks( VidStream* vid_stream ) +{ + int row_size, half_row, mb_row, mb_col, row, col, rr; + int right_half_for = 0, down_half_for = 0; + int c_right_half_for = 0, c_down_half_for = 0; + int right_half_back = 0, down_half_back = 0; + int c_right_half_back = 0, c_down_half_back = 0; + int addr, right_for = 0, down_for = 0; + int recon_right_for, recon_down_for; + int recon_right_back, recon_down_back; + int right_back = 0, down_back = 0; + int c_right_for = 0, c_down_for = 0; + int c_right_back = 0, c_down_back = 0; + unsigned char forw_lum[256]; + unsigned char forw_cr[64], forw_cb[64]; + unsigned char back_lum[256], back_cr[64], back_cb[64]; + int row_incr, half_row_incr; + int ccol, crow; +#ifndef DISABLE_DITHER + int ditherType=vid_stream->ditherType; +#endif +#ifdef LOOSE_MPEG + int lmaxx = vid_stream->mb_width*16-1; + int lmaxy = vid_stream->mb_height*16-1; + int cmaxx = vid_stream->mb_width*8-1; + int cmaxy = vid_stream->mb_height*8-1; +#endif + + /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ + + row_size = vid_stream->mb_width << 4; + half_row = (row_size >> 1); + row_incr = row_size >> 2; + half_row_incr = half_row >> 2; + + /* Establish motion vector codes based on full pixel flag. */ + + if (vid_stream->picture.full_pel_forw_vector) { + recon_right_for = vid_stream->mblock.recon_right_for_prev << 1; + recon_down_for = vid_stream->mblock.recon_down_for_prev << 1; + } else { + recon_right_for = vid_stream->mblock.recon_right_for_prev; + recon_down_for = vid_stream->mblock.recon_down_for_prev; + } + + if (vid_stream->picture.full_pel_back_vector) { + recon_right_back = vid_stream->mblock.recon_right_back_prev << 1; + recon_down_back = vid_stream->mblock.recon_down_back_prev << 1; + } else { + recon_right_back = vid_stream->mblock.recon_right_back_prev; + recon_down_back = vid_stream->mblock.recon_down_back_prev; + } + +#ifdef USE_ATI + + /* For each skipped macroblock do ... */ + for (addr = vid_stream->mblock.past_mb_addr + 1; + addr < vid_stream->mblock.mb_address; addr++) { + + vhar128_macroblock(vid_stream->ati_handle, + (addr % vid_stream->mb_width) << 4, + (addr / vid_stream->mb_width) << 4, + 0, /* skipped blocks are empty non-intra blocks */ + vid_stream->mblock.bpict_past_back, + vid_stream->mblock.bpict_past_forw, + recon_right_back, recon_down_back, /* backward motion */ + recon_right_for, recon_down_for, /* forward motion */ + vid_stream->block.dct_recon); + } + +#else + + /* If only one motion vector, do display copy, else do full + calculation. + */ + +#ifndef DISABLE_DITHER + if (ditherType == MBORDERED_DITHER) { + if (vid_stream->mblock.bpict_past_forw && + !vid_stream->mblock.bpict_past_back) { + for (addr = vid_stream->mblock.past_mb_addr+1; + addr < vid_stream->mblock.mb_address; addr++) { + + MBOrderedDitherDisplayCopy(vid_stream, addr, + 1, recon_right_for, recon_down_for, + 0, 0, 0, vid_stream->past->display, + vid_stream->future->display); + vid_stream->ditherFlags[addr] = 0; + } + return; + } + if (vid_stream->mblock.bpict_past_back && + !vid_stream->mblock.bpict_past_forw) { + for (addr = vid_stream->mblock.past_mb_addr+1; + addr < vid_stream->mblock.mb_address; addr++) { + + MBOrderedDitherDisplayCopy(vid_stream, addr, + 0, 0, 0, + 1, recon_right_back, recon_down_back, + vid_stream->past->display, vid_stream->future->display); + vid_stream->ditherFlags[addr] = 0; + } + return; + } + } +#endif + + /* Calculate motion vectors. */ + + if (vid_stream->mblock.bpict_past_forw) { + right_for = recon_right_for >> 1; + down_for = recon_down_for >> 1; + right_half_for = recon_right_for & 0x1; + down_half_for = recon_down_for & 0x1; + + recon_right_for /= 2; + recon_down_for /= 2; + c_right_for = recon_right_for >> 1; + c_down_for = recon_down_for >> 1; + c_right_half_for = recon_right_for & 0x1; + c_down_half_for = recon_down_for & 0x1; + + } + if (vid_stream->mblock.bpict_past_back) { + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + recon_right_back /= 2; + recon_down_back /= 2; + c_right_back = recon_right_back >> 1; + c_down_back = recon_down_back >> 1; + c_right_half_back = recon_right_back & 0x1; + c_down_half_back = recon_down_back & 0x1; + + } + /* For each skipped macroblock, do... */ + + for (addr = vid_stream->mblock.past_mb_addr + 1; + addr < vid_stream->mblock.mb_address; addr++) { + + /* Calculate macroblock row and col. */ + + mb_row = addr / vid_stream->mb_width; + mb_col = addr % vid_stream->mb_width; + + /* Calculate upper left pixel row,col for luminance plane. */ + + row = mb_row << 4; + col = mb_col << 4; + crow = row / 2; + ccol = col / 2; + +#ifdef LOOSE_MPEG + + /* Check for illegal blocks. */ + + /* Illegal forward Y block, right component */ + if (col + right_for + right_half_for + 7 > lmaxx) + { + if(col > lmaxx) // fix mb column + col = lmaxx & ~15; + if(col + right_for + 7 > lmaxx) // fix full component + right_for = lmaxx - col - 7; + if(col + right_for + right_half_for + 7 > lmaxx) // fix half component + right_half_for = 0; + } + else if (col + right_for < 0) + { + if(col < 0) // fix mb column + col = 0; + if(col + right_for < 0) // fix full component + right_for = 0; + } + + /* Illegal forward Y block, down component */ + if (row + down_for + down_half_for + 7 > lmaxy) + { + if(row > lmaxy) // fix mb row + row = lmaxy & ~15; + if(row + down_for + 7 > lmaxy) // fix full component + down_for = lmaxy - row - 7; + if(row + down_for + down_half_for + 7 > lmaxy) // fix half component + down_half_for = 0; + } + else if (row + down_for < 0) + { + if(row < 0) // fix mb row + row = 0; + if(row + down_for < 0) // fix full component + down_for = 0; + } + + + /* Illegal backward Y block, right component */ + if (col + right_back + right_half_back + 7 > lmaxx) + { + if(col > lmaxx) // fix mb column + col = lmaxx & ~15; + if(col + right_back + 7 > lmaxx) // fix full component + right_back = lmaxx - col - 7; + if(col + right_back + right_half_back + 7 > lmaxx) // fix half component + right_half_back = 0; + } + else if (col + right_back < 0) + { + if(col < 0) // fix mb column + col = 0; + if(col + right_back < 0) // fix full component + right_back = 0; + } + + /* Illegal backward Y block, down component */ + if (row + down_back + down_half_back + 7 > lmaxy) + { + if(row > lmaxy) // fix mb row + row = lmaxy & ~15; + if(row + down_back + 7 > lmaxy) // fix full component + down_back = lmaxy - row - 7; + if(row + down_back + down_half_back + 7 > lmaxy) // fix half component + down_half_back = 0; + } + else if (row + down_back < 0) + { + if(row < 0) // fix mb row + row = 0; + if(row + down_back < 0) // fix full component + down_back = 0; + } + + + /* Illegal forward C block, right component */ + if (ccol + c_right_for + c_right_half_for + 7 > cmaxx) + { + if(ccol > cmaxx) // fix mb column + ccol = cmaxx & ~15; + if(ccol + c_right_for + 7 > cmaxx) // fix full component + c_right_for = cmaxx - ccol - 7; + if(ccol + c_right_for + c_right_half_for + 7 > cmaxx) // fix half component + c_right_half_for = 0; + } + else if (ccol + c_right_for < 0) + { + if(ccol < 0) // fix mb column + ccol = 0; + if(ccol + c_right_for < 0) // fix full component + c_right_for = 0; + } + + /* Illegal forward C block, down component */ + if (crow + c_down_for + c_down_half_for + 7 > cmaxy) + { + if(crow > cmaxy) // fix mb row + crow = cmaxy & ~15; + if(crow + c_down_for + 7 > cmaxy) // fix full component + c_down_for = cmaxy - crow - 7; + if(crow + c_down_for + c_down_half_for + 7 > cmaxy) // fix half component + c_down_half_for = 0; + } + else if (crow + c_down_for < 0) + { + if(crow < 0) // fix mb row + crow = 0; + if(crow + c_down_for < 0) // fix full component + c_down_for = 0; + } + + /* Illegal backward C block, right component */ + if (ccol + c_right_back + c_right_half_back + 7 > cmaxx) + { + if(ccol > cmaxx) // fix mb column + ccol = cmaxx & ~15; + if(ccol + c_right_back + 7 > cmaxx) // fix full component + c_right_back = cmaxx - ccol - 7; + if(ccol + c_right_back + c_right_half_back + 7 > cmaxx) // fix half component + c_right_half_back = 0; + } + else if (ccol + c_right_back < 0) + { + if(ccol < 0) // fix mb column + ccol = 0; + if(ccol + c_right_back < 0) // fix full component + c_right_back = 0; + } + + /* Illegal backward C block, down component */ + if (crow + c_down_back + c_down_half_back + 7 > cmaxy) + { + if(crow > cmaxy) // fix mb row + crow = cmaxy & ~15; + if(crow + c_down_back + 7 > cmaxy) // fix full component + c_down_back = cmaxy - crow - 7; + if(crow + c_down_back + c_down_half_back + 7 > cmaxy) // fix half component + c_down_half_back = 0; + } + else if (crow + c_down_back < 0) + { + if(crow < 0) // fix mb row + crow = 0; + if(crow + c_down_back < 0) // fix full component + c_down_back = 0; + } + +#endif + + /* If forward predicted, calculate prediction values. */ + + if (vid_stream->mblock.bpict_past_forw) { + + ReconSkippedBlock(vid_stream->past->luminance, forw_lum, + row, col, row_size, right_for, down_for, + right_half_for, down_half_for, 16); + ReconSkippedBlock(vid_stream->past->Cr, forw_cr, crow, + ccol, half_row, + c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8); + ReconSkippedBlock(vid_stream->past->Cb, forw_cb, crow, + ccol, half_row, + c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8); + } + /* If back predicted, calculate prediction values. */ + + if (vid_stream->mblock.bpict_past_back) { + ReconSkippedBlock(vid_stream->future->luminance, back_lum, + row, col, row_size, right_back, down_back, + right_half_back, down_half_back, 16); + ReconSkippedBlock(vid_stream->future->Cr, back_cr, crow, + ccol, half_row, + c_right_back, c_down_back, + c_right_half_back, c_down_half_back, 8); + ReconSkippedBlock(vid_stream->future->Cb, back_cb, crow, + ccol, half_row, + c_right_back, c_down_back, + c_right_half_back, c_down_half_back, 8); + } + if (vid_stream->mblock.bpict_past_forw && + !vid_stream->mblock.bpict_past_back) { + + int *dest, *dest1; + int *src, *src1; + dest = (int *)(vid_stream->current->luminance + (row * row_size) + col); + src = (int *)forw_lum; + + for (rr = 0; rr < 16; rr++) { + + /* memcpy(dest, forw_lum+(rr<<4), 16); */ + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_incr; + src += 4; + } + + dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol); + dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol); + src = (int *)forw_cr; + src1 = (int *)forw_cb; + + for (rr = 0; rr < 8; rr++) { + /* + * memcpy(dest, forw_cr+(rr<<3), 8); memcpy(dest1, forw_cb+(rr<<3), + * 8); + */ + + dest[0] = src[0]; + dest[1] = src[1]; + + dest1[0] = src1[0]; + dest1[1] = src1[1]; + + dest += half_row_incr; + dest1 += half_row_incr; + src += 2; + src1 += 2; + } + } else if (vid_stream->mblock.bpict_past_back && + !vid_stream->mblock.bpict_past_forw) { + + int *src, *src1; + int *dest, *dest1; + dest = (int *)(vid_stream->current->luminance + (row * row_size) + col); + src = (int *)back_lum; + + for (rr = 0; rr < 16; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_incr; + src += 4; + } + + + dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol); + dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol); + src = (int *)back_cr; + src1 = (int *)back_cb; + + for (rr = 0; rr < 8; rr++) { + /* + * memcpy(dest, back_cr+(rr<<3), 8); memcpy(dest1, back_cb+(rr<<3), + * 8); + */ + + dest[0] = src[0]; + dest[1] = src[1]; + + dest1[0] = src1[0]; + dest1[1] = src1[1]; + + dest += half_row_incr; + dest1 += half_row_incr; + src += 2; + src1 += 2; + } + } else { + + unsigned char *src1, *src2, *src1a, *src2a; + unsigned char *dest, *dest1; + dest = vid_stream->current->luminance + (row * row_size) + col; + src1 = forw_lum; + src2 = back_lum; + + for (rr = 0; rr < 16; rr++) { + dest[0] = (int) (src1[0] + src2[0]) >> 1; + dest[1] = (int) (src1[1] + src2[1]) >> 1; + dest[2] = (int) (src1[2] + src2[2]) >> 1; + dest[3] = (int) (src1[3] + src2[3]) >> 1; + dest[4] = (int) (src1[4] + src2[4]) >> 1; + dest[5] = (int) (src1[5] + src2[5]) >> 1; + dest[6] = (int) (src1[6] + src2[6]) >> 1; + dest[7] = (int) (src1[7] + src2[7]) >> 1; + dest[8] = (int) (src1[8] + src2[8]) >> 1; + dest[9] = (int) (src1[9] + src2[9]) >> 1; + dest[10] = (int) (src1[10] + src2[10]) >> 1; + dest[11] = (int) (src1[11] + src2[11]) >> 1; + dest[12] = (int) (src1[12] + src2[12]) >> 1; + dest[13] = (int) (src1[13] + src2[13]) >> 1; + dest[14] = (int) (src1[14] + src2[14]) >> 1; + dest[15] = (int) (src1[15] + src2[15]) >> 1; + dest += row_size; + src1 += 16; + src2 += 16; + } + + + dest = vid_stream->current->Cr + (crow * half_row) + ccol; + dest1 = vid_stream->current->Cb + (crow * half_row) + ccol; + src1 = forw_cr; + src2 = back_cr; + src1a = forw_cb; + src2a = back_cb; + + for (rr = 0; rr < 8; rr++) { + dest[0] = (int) (src1[0] + src2[0]) >> 1; + dest[1] = (int) (src1[1] + src2[1]) >> 1; + dest[2] = (int) (src1[2] + src2[2]) >> 1; + dest[3] = (int) (src1[3] + src2[3]) >> 1; + dest[4] = (int) (src1[4] + src2[4]) >> 1; + dest[5] = (int) (src1[5] + src2[5]) >> 1; + dest[6] = (int) (src1[6] + src2[6]) >> 1; + dest[7] = (int) (src1[7] + src2[7]) >> 1; + dest += half_row; + src1 += 8; + src2 += 8; + + dest1[0] = (int) (src1a[0] + src2a[0]) >> 1; + dest1[1] = (int) (src1a[1] + src2a[1]) >> 1; + dest1[2] = (int) (src1a[2] + src2a[2]) >> 1; + dest1[3] = (int) (src1a[3] + src2a[3]) >> 1; + dest1[4] = (int) (src1a[4] + src2a[4]) >> 1; + dest1[5] = (int) (src1a[5] + src2a[5]) >> 1; + dest1[6] = (int) (src1a[6] + src2a[6]) >> 1; + dest1[7] = (int) (src1a[7] + src2a[7]) >> 1; + dest1 += half_row; + src1a += 8; + src2a += 8; + } + } + +#ifndef DISABLE_DITHER + if (ditherType == MBORDERED_DITHER) { + vid_stream->ditherFlags[addr] = 1; + } +#endif + } +#endif /* USE_ATI */ +} + + +#ifndef USE_ATI + +/* + *-------------------------------------------------------------- + * + * ReconSkippedBlock -- + * + * Reconstructs predictive block for skipped macroblocks + * in B Frames. + * + * Results: + * No return values. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void ReconSkippedBlock( unsigned char *source, unsigned char *dest, + int row, int col, int row_size, int right, int down, + int right_half, int down_half, int width ) +{ + int rr; + unsigned char *source2; + + source += ((row + down) * row_size) + col + right; + + if (width == 16) { + if ((!right_half) && (!down_half)) { + if (right & 0x1) { + /* No alignment, use bye copy */ + for (rr = 0; rr < 16; rr++) { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + dest[4] = source[4]; + dest[5] = source[5]; + dest[6] = source[6]; + dest[7] = source[7]; + dest[8] = source[8]; + dest[9] = source[9]; + dest[10] = source[10]; + dest[11] = source[11]; + dest[12] = source[12]; + dest[13] = source[13]; + dest[14] = source[14]; + dest[15] = source[15]; + dest += 16; + source += row_size; + } + } else if (right & 0x2) { + /* Half-word bit aligned, use 16 bit copy */ + short *src = (short *)source; + short *d = (short *)dest; + row_size >>= 1; + for (rr = 0; rr < 16; rr++) { + d[0] = src[0]; + d[1] = src[1]; + d[2] = src[2]; + d[3] = src[3]; + d[4] = src[4]; + d[5] = src[5]; + d[6] = src[6]; + d[7] = src[7]; + d += 8; + src += row_size; + } + } else { + /* Word aligned, use 32 bit copy */ + int *src = (int *)source; + int *d = (int *)dest; + row_size >>= 2; + for (rr = 0; rr < 16; rr++) { + d[0] = src[0]; + d[1] = src[1]; + d[2] = src[2]; + d[3] = src[3]; + d += 4; + src += row_size; + } + } + } else { + source2 = source + right_half + (row_size * down_half); + for (rr = 0; rr < width; rr++) { + dest[0] = (int) (source[0] + source2[0]) >> 1; + dest[1] = (int) (source[1] + source2[1]) >> 1; + dest[2] = (int) (source[2] + source2[2]) >> 1; + dest[3] = (int) (source[3] + source2[3]) >> 1; + dest[4] = (int) (source[4] + source2[4]) >> 1; + dest[5] = (int) (source[5] + source2[5]) >> 1; + dest[6] = (int) (source[6] + source2[6]) >> 1; + dest[7] = (int) (source[7] + source2[7]) >> 1; + dest[8] = (int) (source[8] + source2[8]) >> 1; + dest[9] = (int) (source[9] + source2[9]) >> 1; + dest[10] = (int) (source[10] + source2[10]) >> 1; + dest[11] = (int) (source[11] + source2[11]) >> 1; + dest[12] = (int) (source[12] + source2[12]) >> 1; + dest[13] = (int) (source[13] + source2[13]) >> 1; + dest[14] = (int) (source[14] + source2[14]) >> 1; + dest[15] = (int) (source[15] + source2[15]) >> 1; + dest += width; + source += row_size; + source2 += row_size; + } + } + } else { /* (width == 8) */ + assert(width == 8); + if ((!right_half) && (!down_half)) { + if (right & 0x1) { + for (rr = 0; rr < width; rr++) { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + dest[4] = source[4]; + dest[5] = source[5]; + dest[6] = source[6]; + dest[7] = source[7]; + dest += 8; + source += row_size; + } + } else if (right & 0x02) { + short *d = (short *)dest; + short *src = (short *)source; + row_size >>= 1; + for (rr = 0; rr < width; rr++) { + d[0] = src[0]; + d[1] = src[1]; + d[2] = src[2]; + d[3] = src[3]; + d += 4; + src += row_size; + } + } else { + int *d = (int *)dest; + int *src = (int *)source; + row_size >>= 2; + for (rr = 0; rr < width; rr++) { + d[0] = src[0]; + d[1] = src[1]; + d += 2; + src += row_size; + } + } + } else { + source2 = source + right_half + (row_size * down_half); + for (rr = 0; rr < width; rr++) { + dest[0] = (int) (source[0] + source2[0]) >> 1; + dest[1] = (int) (source[1] + source2[1]) >> 1; + dest[2] = (int) (source[2] + source2[2]) >> 1; + dest[3] = (int) (source[3] + source2[3]) >> 1; + dest[4] = (int) (source[4] + source2[4]) >> 1; + dest[5] = (int) (source[5] + source2[5]) >> 1; + dest[6] = (int) (source[6] + source2[6]) >> 1; + dest[7] = (int) (source[7] + source2[7]) >> 1; + dest += width; + source += row_size; + source2 += row_size; + } + } + } +} + +#endif /* USE_ATI */ + +/* + *-------------------------------------------------------------- + * + * DoPictureDisplay -- + * + * Converts image from Lum, Cr, Cb to colormap space. Puts + * image in lum plane. Updates past and future frame + * pointers. Dithers image. Sends to display mechanism. + * + * Results: + * Pict image structure locked if displaying or if frame + * is needed as past or future reference. + * + * Side effects: + * Lum plane pummelled. + * + *-------------------------------------------------------------- + */ + +static void DoPictureDisplay( VidStream *vid_stream ) +{ +#ifdef ANALYSIS + EndTime(); + stat_a[0].totsize += bitCountRead() - pictureSizeCount; +#ifdef SHOWEACHFLAG + PrintOneStat(); +#endif + CollectStats(); +#endif + +#ifdef USE_ATI + /* Flush the macroblocks to the hardware decoder */ + vhar128_flush( vid_stream->ati_handle ); +#endif + + /* Update past and future references if needed. */ + + if( (vid_stream->picture.code_type == I_TYPE) || + (vid_stream->picture.code_type == P_TYPE) ) + { + if( vid_stream->future == NULL ) + { + vid_stream->future = vid_stream->current; + vid_stream->future->locked |= FUTURE_LOCK; + } + else + { + if( vid_stream->past != NULL ) + { + vid_stream->past->locked &= ~PAST_LOCK; + } + vid_stream->past = vid_stream->future; + vid_stream->past->locked &= ~FUTURE_LOCK; + vid_stream->past->locked |= PAST_LOCK; + vid_stream->future = vid_stream->current; + vid_stream->future->locked |= FUTURE_LOCK; + vid_stream->current = vid_stream->past; + + vid_stream->_smpeg->ExecuteDisplay( vid_stream ); + } + } + else + { + vid_stream->_smpeg->ExecuteDisplay( vid_stream ); + } +} + +/* EOF */ diff --git a/smpeg/src/video/video.h b/smpeg/src/video/video.h new file mode 100644 index 0000000..be56028 --- /dev/null +++ b/smpeg/src/video/video.h @@ -0,0 +1,460 @@ +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef MPEG_LIB_VIDEO_HEADER +#define MPEG_LIB_VIDEO_HEADER +#include + +/* + Changes to make the code reentrant: + deglobalized: ditherFlags, totNumFrames, realTimeStart, matched_depth, + filename, ditherType, curBits, ReconPMBlock statics, stream id + variables, Parse_done, swap, seekValue, input, EOF_flag, ReadPacket + statics, sys_layer, curVidStream, curVidStream, jmb_buf env (removed) + X globals now in xinfo: ditherType, visual, depth (also name), hints, + owncmFlag, et al + now const: scan + film_has_ended instead of FilmState + Additional changes: + if DISABLE_DITHER defined, don't compile dithering code + -lsh@cs.brown.edu (Loring Holden) + */ + +#include "MPEGvideo.h" +#include "MPEGaudio.h" + +typedef Sint32 INT32; +typedef Sint16 INT16; +typedef Sint8 INT8; +typedef Uint32 UINT32; +typedef Uint16 UINT16; +typedef Uint8 UINT8; + +/* Define Parsing error codes. */ + +#define SKIP_PICTURE (-10) +#define SKIP_TO_START_CODE (-1) +#define PARSE_OK 1 + +/* Define BOOLEAN, TRUE, and FALSE. */ + +#define BOOLEAN int +#define TRUE 1 +#define FALSE 0 + +/* Set ring buffer size. */ + +#define RING_BUF_SIZE 5 + +/* Macros for picture code type. */ + +#define I_TYPE 1 +#define P_TYPE 2 +#define B_TYPE 3 +#define D_TYPE 4 + +/* Start codes. */ + +#define SEQ_END_CODE 0x000001b7 +#define SEQ_START_CODE 0x000001b3 +#define GOP_START_CODE 0x000001b8 +#define PICTURE_START_CODE 0x00000100 +#define SLICE_MIN_START_CODE 0x00000101 +#define SLICE_MAX_START_CODE 0x000001af +#define EXT_START_CODE 0x000001b5 +#define USER_START_CODE 0x000001b2 +#define SEQUENCE_ERROR_CODE 0x000001b4 + +/* Number of macroblocks to process in one call to mpegVidRsrc. */ + +#define MB_QUANTUM 100 + +/* Macros used with macroblock address decoding. */ + +#define MB_STUFFING 34 +#define MB_ESCAPE 35 + +/* Lock flags for pict images. */ + +#define DISPLAY_LOCK 0x01 +#define PAST_LOCK 0x02 +#define FUTURE_LOCK 0x04 + +#define HYBRID_DITHER 0 +#define HYBRID2_DITHER 1 +#define FS4_DITHER 2 +#define FS2_DITHER 3 +#define FS2FAST_DITHER 4 +#define Twox2_DITHER 5 +#define GRAY_DITHER 6 +#define FULL_COLOR_DITHER 7 +#define NO_DITHER 8 +#define ORDERED_DITHER 9 +#define MONO_DITHER 10 +#define MONO_THRESHOLD 11 +#define ORDERED2_DITHER 12 +#define MBORDERED_DITHER 13 +#define GRAY256_DITHER 14 +#define PPM_DITHER 15 +#define FULL_COLOR2_DITHER 16 +#define GRAY2_DITHER 17 +#define GRAY2562_DITHER 18 + +#ifdef DISABLE_DITHER +#define IS_2x2_DITHER(a) (0) +#else +#define IS_2x2_DITHER(a) ((a) == Twox2_DITHER || (a) == FULL_COLOR2_DITHER || (a) == GRAY2_DITHER || (a) == (GRAY2562_DITHER)) +#endif + +/* Brown - changed to const int because it is a help variable */ +extern const int scan[][8]; + +/* Structure with reconstructed pixel values. */ + +typedef struct pict_image { +#ifdef USE_ATI + struct vhar128_image *image; +#else + unsigned char *image; /* YV12 format image */ + unsigned char *luminance; /* Luminance plane. */ + unsigned char *Cr; /* Cr plane. */ + unsigned char *Cb; /* Cb plane. */ +#endif + unsigned short int *mb_qscale; /* macroblock info */ + int locked; /* Lock flag. */ + TimeStamp show_time; /* Presentation time. */ +} PictImage; + +/* Group of pictures structure. */ + +typedef struct GoP { + BOOLEAN drop_flag; /* Flag indicating dropped frame. */ + unsigned int tc_hours; /* Hour component of time code. */ + unsigned int tc_minutes; /* Minute component of time code. */ + unsigned int tc_seconds; /* Second component of time code. */ + unsigned int tc_pictures; /* Picture counter of time code. */ + BOOLEAN closed_gop; /* Indicates no pred. vectors to + previous group of pictures. */ + BOOLEAN broken_link; /* B frame unable to be decoded. */ + char *ext_data; /* Extension data. */ + char *user_data; /* User data. */ +} GoP; + +/* Picture structure. */ + +typedef struct pict { + unsigned int temp_ref; /* Temporal reference. */ + unsigned int code_type; /* Frame type: P, B, I */ + unsigned int vbv_delay; /* Buffer delay. */ + BOOLEAN full_pel_forw_vector; /* Forw. vectors specified in full + pixel values flag. */ + unsigned int forw_r_size; /* Used for vector decoding. */ + unsigned int forw_f; /* Used for vector decoding. */ + BOOLEAN full_pel_back_vector; /* Back vectors specified in full + pixel values flag. */ + unsigned int back_r_size; /* Used in decoding. */ + unsigned int back_f; /* Used in decoding. */ + char *extra_info; /* Extra bit picture info. */ + char *ext_data; /* Extension data. */ + char *user_data; /* User data. */ +} Pict; + +/* Slice structure. */ + +typedef struct slice { + unsigned int vert_pos; /* Vertical position of slice. */ + unsigned int quant_scale; /* Quantization scale. */ + char *extra_info; /* Extra bit slice info. */ +} Slice; + +/* Macroblock structure. */ + +typedef struct macroblock { + int mb_address; /* Macroblock address. */ + int past_mb_addr; /* Previous mblock address. */ + int motion_h_forw_code; /* Forw. horiz. motion vector code. */ + unsigned int motion_h_forw_r; /* Used in decoding vectors. */ + int motion_v_forw_code; /* Forw. vert. motion vector code. */ + unsigned int motion_v_forw_r; /* Used in decdoinge vectors. */ + int motion_h_back_code; /* Back horiz. motion vector code. */ + unsigned int motion_h_back_r; /* Used in decoding vectors. */ + int motion_v_back_code; /* Back vert. motion vector code. */ + unsigned int motion_v_back_r; /* Used in decoding vectors. */ + unsigned int cbp; /* Coded block pattern. */ + BOOLEAN mb_intra; /* Intracoded mblock flag. */ + BOOLEAN bpict_past_forw; /* Past B frame forw. vector flag. */ + BOOLEAN bpict_past_back; /* Past B frame back vector flag. */ + int past_intra_addr; /* Addr of last intracoded mblock. */ + int recon_right_for_prev; /* Past right forw. vector. */ + int recon_down_for_prev; /* Past down forw. vector. */ + int recon_right_back_prev; /* Past right back vector. */ + int recon_down_back_prev; /* Past down back vector. */ +} Macroblock; + +/* Block structure. */ + +typedef struct block { +#ifdef USE_ATI + long int dct_recon[6][130]; /* Reconstructed dct runs & levels */ +#else + short int dct_recon[8][8]; /* Reconstructed dct coeff matrix. */ +#endif + short int dct_dc_y_past; /* Past lum. dc dct coefficient. */ + short int dct_dc_cr_past; /* Past cr dc dct coefficient. */ + short int dct_dc_cb_past; /* Past cb dc dct coefficient. */ +} Block; + +/* Video stream structure. */ + +typedef struct vid_stream { + unsigned int h_size; /* Horiz. size in pixels. */ + unsigned int v_size; /* Vert. size in pixels. */ + unsigned int mb_height; /* Vert. size in mblocks. */ + unsigned int mb_width; /* Horiz. size in mblocks. */ + unsigned char aspect_ratio; /* Code for aspect ratio. */ + unsigned char picture_rate; /* Code for picture rate. */ + unsigned int bit_rate; /* Bit rate. */ + unsigned int vbv_buffer_size; /* Minimum buffer size. */ + BOOLEAN const_param_flag; /* Contrained parameter flag. */ + unsigned char intra_quant_matrix[8][8]; /* Quantization matrix for + intracoded frames. */ + unsigned char non_intra_quant_matrix[8][8]; /* Quanitization matrix for + non intracoded frames. */ + char *ext_data; /* Extension data. */ + char *user_data; /* User data. */ + GoP group; /* Current group of pict. */ + Pict picture; /* Current picture. */ + Slice slice; /* Current slice. */ + Macroblock mblock; /* Current macroblock. */ + Block block; /* Current block. */ + int state; /* State of decoding. */ + int bit_offset; /* Bit offset in stream. */ + unsigned int *buffer; /* Pointer to next byte in + buffer. */ + int buf_length; /* Length of remaining buffer.*/ + unsigned int *buf_start; /* Pointer to buffer start. */ + +/* VC - beginning of added variables for noise computation */ + short noise_base_matrix[8][8]; /* Square quantization error */ +/* VC - end of added variables */ + +/* Brown - beginning of added variables that used to be static or global */ + int max_buf_length; /* Max length of buffer. */ + int film_has_ended; /* Boolean - film has ended */ + unsigned int num_left; /* from ReadPacket - leftover */ + unsigned int leftover_bytes; /* from ReadPacket - leftover */ + int EOF_flag; /* stream is EOF */ + BOOLEAN Parse_done; /* from read_sys */ + int right_for,down_for; /* From ReconPMBlock, video.c */ + int right_half_for, down_half_for; + unsigned int curBits; /* current bits */ + int matched_depth; /* depth of displayed movie */ + int ditherType; /* What type of dithering */ + char *ditherFlags; /* flags for MB Ordered dither*/ + int totNumFrames; /* Total Number of Frames */ + double realTimeStart; /* When did the movie start? */ +/* Brown - end of added variables */ + + PictImage *past; /* Past predictive frame. */ + PictImage *future; /* Future predictive frame. */ + PictImage *current; /* Current frame. */ + PictImage *ring[RING_BUF_SIZE]; /* Ring buffer of frames. */ + +/* KR - beginning of added variables */ + double rate_deal; + int _skipFrame; + double _skipCount; + int _jumpFrame; + double _oneFrameTime; + MPEGvideo* _smpeg; +/* KR - end of added variables */ + +/* SL - beginning of added variables for FPS calculation */ +//#define CALCULATE_FPS +#define FPS_WINDOW 60 +#ifdef CALCULATE_FPS + double frame_time[FPS_WINDOW]; + int timestamp_index; +#endif +/* SL - end of added variables */ +/* begining of added variables for system stream based sync */ + double timestamp; + unsigned int *timestamp_mark; + bool timestamp_used; +/* begining of added variables */ + bool need_frameadjust; + int current_frame; + +#ifdef USE_ATI + unsigned int ati_handle; +#endif + +} VidStream; + +/* Declaration of global display pointer. */ + +/* Quiet mode flag. */ +extern int quietFlag; + +/* Flag controlling the "Press return" prompt */ +extern int requireKeypressFlag; + +/* Flag controlling speed vs. quality */ +extern int qualityFlag; + +/* Gamma correction stuff */ +extern int gammaCorrectFlag; +extern double gammaCorrect; + +/* Chroma correction stuff */ +extern int chromaCorrectFlag; +extern double chromaCorrect; + +/* Definition of Contant integer scale factor. */ + +#define CONST_BITS 13 + +/* Misc DCT definitions */ +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ + +#define GLOBAL /* a function referenced thru EXTERNs */ + +typedef short DCTELEM; +typedef DCTELEM DCTBLOCK[DCTSIZE2]; + + +#ifdef ANALYSIS +extern unsigned int bitCount; +extern int showEachFlag; +extern unsigned int cacheHit[8][8]; +extern unsigned int cacheMiss[8][8]; +#endif + +#if !defined(__MIPSEL__) && (defined(MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(__mipsel) || defined(__mipsel__)) +#define __MIPSEL__ 1 +#endif + +#if !defined(__MIPSEB__) && (defined(MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || defined(__mipseb) || defined(__mipseb__)) +#define __MIPSEB__ 1 +#endif + +#if !defined(__SPARC__) && (defined(SPARC) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc) || defined(__sparc__)) +#define __SPARC__ 1 +#endif + +#if !defined(__alpha__) && (defined(ALPHA) || defined(__ALPHA) || defined(__ALPHA__) || defined(__alpha)) +#define __alpha__ 1 +#endif + +#if !defined(__680x0__) && (defined(__680x0) || defined(__680x0__)) +#define __680x0__ 1 +#endif + +#if !defined(__AIX__) && (defined(AIX) || defined(_AIX) || defined(__AIX) || defined(__AIX__)) +#define __AIX__ 1 +#endif + +#if !defined(__RS6000__) && (defined(__AIX__) || defined(RS6000) || defined(_RS6000) || defined(__RS6000) || defined(__RS6000__)) +#define __RS6000__ 1 +#endif + +#if !defined(__HPUX__) && (defined(HPUX) || defined(_HPUX) || defined(__HPUX) || defined(__HPUX__)) +#define __HPUX__ 1 +#endif +#if !defined(__HPUX__) && (defined(hpux) || defined(_hpux) || defined(__hpux) || defined(__hpux__)) +#define __HPUX__ 1 +#endif + +#if !defined(__VAX__) && (defined(VAX) || defined (__VAX)) +#define __VAX__ 1 +#endif + +#if !defined(__SCO__) && (defined(SCO) || defined(__SCO) || defined(sco) || defined(__sco__)) +#define __SCO__ 1 +#endif + +#if defined(__i386__) || defined(__VAX__) || defined(__MIPSEL__) || defined(__alpha__) || defined(__SCO__) +#undef BIG_ENDIAN_ARCHITECTURE +#define LITTLE_ENDIAN_ARCHITECTURE 1 +#endif + +#if defined(__RS6000__) || defined(__SPARC__) || defined(__mc68000__) || defined(__HPUX__) || defined(__MIPSEB__) || defined(convex) || defined(__convex__) || defined(__powerpc__) +#undef LITTLE_ENDIAN_ARCHITECTURE +#define BIG_ENDIAN_ARCHITECTURE 1 +#endif + +#if !defined(LITTLE_ENDIAN_ARCHITECTURE) && !defined(BIG_ENDIAN_ARCHITECTURE) +#ifdef WIN32 +#undef BIG_ENDIAN_ARCHITECTURE +#define LITTLE_ENDIAN_ARCHITECTURE +#else +#ifdef __BIG_ENDIAN__ +#undef LITTLE_ENDIAN_ARCHITECTURE +#define BIG_ENDIAN_ARCHITECTURE 1 +#else +#include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#undef BIG_ENDIAN_ARCHITECTURE +#define LITTLE_ENDIAN_ARCHITECTURE 1 +#endif +#if __BYTE_ORDER == __BIG_ENDIAN +#undef LITTLE_ENDIAN_ARCHITECTURE +#define BIG_ENDIAN_ARCHITECTURE 1 +#endif +#endif +#endif +#endif + +#if !defined(LITTLE_ENDIAN_ARCHITECTURE) && !defined(BIG_ENDIAN_ARCHITECTURE) +#error Unknown endianism of architecture +#endif + +#ifdef __alpha__ +#define SIXTYFOUR_BIT +#endif + +/* Warnings that may help in debugging MPEG streams */ +//#define VERBOSE_WARNINGS +//#define VERBOSE_DEBUG + +#endif /* video.h already included */