summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps/libv4l')
-rw-r--r--v4l2-apps/libv4l/COPYING.LIB510
-rw-r--r--v4l2-apps/libv4l/ChangeLog247
-rw-r--r--v4l2-apps/libv4l/Makefile16
-rw-r--r--v4l2-apps/libv4l/README141
-rw-r--r--v4l2-apps/libv4l/README.multi-threading12
-rw-r--r--v4l2-apps/libv4l/TODO12
-rw-r--r--v4l2-apps/libv4l/include/libv4l1.h73
-rw-r--r--v4l2-apps/libv4l/include/libv4l2.h110
-rw-r--r--v4l2-apps/libv4l/include/libv4lconvert.h88
-rw-r--r--v4l2-apps/libv4l/libv4l1/Makefile83
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1-priv.h83
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1.c837
-rw-r--r--v4l2-apps/libv4l/libv4l1/log.c145
-rw-r--r--v4l2-apps/libv4l/libv4l1/v4l1compat.c127
-rw-r--r--v4l2-apps/libv4l/libv4l2/Makefile82
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2-priv.h95
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2.c1145
-rw-r--r--v4l2-apps/libv4l/libv4l2/log.c148
-rw-r--r--v4l2-apps/libv4l/libv4l2/v4l2convert.c166
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/Makefile70
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/bayer.c613
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/flip.c107
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/jidctflt.c286
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h166
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c737
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/pac207.c418
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/rgbyuv.c316
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/sn9c10x.c287
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/spca501.c126
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/spca561-decompress.c1003
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h121
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c2463
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h74
33 files changed, 10907 insertions, 0 deletions
diff --git a/v4l2-apps/libv4l/COPYING.LIB b/v4l2-apps/libv4l/COPYING.LIB
new file mode 100644
index 000000000..1dd325d2b
--- /dev/null
+++ b/v4l2-apps/libv4l/COPYING.LIB
@@ -0,0 +1,510 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ 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 Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+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 other code 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.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ 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, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser 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.
+^L
+ 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.
+^L
+ 6. As an exception to the Sections above, you may also combine 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) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) 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.
+
+ d) 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.
+
+ e) 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 materials to be 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.
+^L
+ 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 with
+this License.
+^L
+ 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 Lesser 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.
+^L
+ 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
+^L
+ 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.
+
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+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.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog
new file mode 100644
index 000000000..dd53eced9
--- /dev/null
+++ b/v4l2-apps/libv4l/ChangeLog
@@ -0,0 +1,247 @@
+libv4l-0.5.0
+------------
+* Add support for enumerating framesizes and frameintervals of emulated
+ formats when the driver supports it for the real format
+* Make sure the video device always gets opened RW even if the application
+ asks for RO
+* Add Genius E-Messenger 112 (093a:2476) to list of cams which have their
+ sensor upside down
+
+libv4l-0.4.3
+------------
+* Add suport for YUYV and YVYU packed pixel formats (Jean-Francois Moine)
+* Prefer compressed pixformats for resolutions > 176x144
+
+libv4l-0.4.2
+------------
+* The bayer pixel order in gspca's sonixb driver was different from that in
+ the sn9c102 driver from the mainline kernel, a recent gspca patch fixes
+ this, adjust libv4l to match (and make it work properly with the sn9c102
+ driver).
+
+libv4l-0.4.1
+------------
+* When the driver supports read() and we are not converting let the driver
+ handle read() instead of emulating it with mmap mode
+* Fix errors and warnings when compiling with ICC (Gregor Jasny)
+* Add support to libv4lconvert for rotating images 90 (for Pixart 7302 cams)
+ or 180 (Philips SPC200NC / Philips SPC300NC) degrees
+* Add support for Pixart custom JPEG format
+* Hide non public symbols (Gregor Jasny)
+* Fix and enable x86_64 asm jpeg decompress helper functions (Gregor Jasny)
+
+libv4l-0.4.0
+------------
+* Be more relaxed in our checks for mixing read and mmap access, we were
+ being more strict in this then certain kernel drivers (bttv) making xawtv
+ unhappy
+* With some drivers the buffers must be mapped before queuing, so when
+ converting map the (real) buffers before calling the qbuf ioctl
+* Add support for conversion to RGB24 (before we only supported BGR24) based
+ on a patch by Jean-Francois Moine
+* When the hardware supports a format natively prefer using the native
+ version over converting from another supported format
+* Various Makefile and pkgconfig file improvements by Gregor Jasny (Debian)
+* Drop the appl-patches dir, all application patches are now available and
+ tracked here: http://linuxtv.org/v4lwiki/index.php/Libv4l_Progress
+
+
+libv4l-0.3.9
+------------
+* Not only see /dev/video* but also /dev/v4l/* as video devices
+ (only affects libv4l1 and the wrappers) patch from Brandon Philips
+* Silence the creation of the .pc files in the Makefiles (Brandon Philips)
+* Part of the copyright headers refered GPL instead of LGPL due to a copy
+ and paste error (Brandon Philips)
+
+
+libv4l-0.3.8
+------------
+* work around wrong REQUEST_BUFFERS ioctl return code from certain drivers
+* add pkg-config (.pc) files for easier detection if libv4l is available
+* check capabilities for streaming, if the driver cannot do streaming don't
+ insert ourselves between the application and the driver
+* intercept get capabilites and report read capability (which we always offer)
+* query buffer: indicate the mapping state of our (fake) buffer in the flags
+
+
+libv4l-0.3.7
+------------
+* Add spca505/6 and spca508 cam specific formats (YUYV per line variations)
+
+
+libv4l-0.3.6
+------------
+* Add missing COPYING.LIB file
+
+
+libv4l-0.3.5
+------------
+* Make JPEG decoding more robust
+
+
+libv4l-0.3.4 (the brownpaperbag release)
+----------------------------------------
+* The mmap64 support in 0.3.3, has caused a bug in libv4l1 when running on
+ 32 bit systems (who uses those now a days?), this bug caused v4l1
+ compatibility to not work at all, this release fixes this
+* Some apps (xawtv, kopete) use an ioctl wrapper internally for various
+ reasons. This wrappers request argument is an int, but the real ioctl's
+ request argument is an unsigned long. Passing the VIDIOC_xxx defines through
+ to the wrapper, and then to the real ioctl, causes the request to get sign
+ extended on 64 bit args. The kernel seems to ignore the upper 32 bits,
+ causing the sign extension to not make a difference. libv4l now also
+ ignores the upper 32 bits of the libv4lx_ioctl request argument on 64 bit
+ archs
+* Add a bugfix patch for kopete in the appl-patches dir, currently it assumes
+ that it got the width and height it asked for when doing a S_FMT, which is a
+ wrong assumption
+
+
+libv4l-0.3.3
+------------
+* Add open64 and mmap64 wrappers to the LD_PRELOAD wrapper libs, so that
+ they also work for applications compiled with FILE_OFFSET_BITS=64, this
+ fixes using them with v4l-info
+* While looking at xawtv in general, found a few bugs in xawtv itself, added
+ a patch to fix those to the appl-patches dir
+* Talking about the appl-patches dir, restore that as it accidentally got
+ dropped from 0.3.2
+* Be more verbose in various places when it comes to logging (esp errors)
+* Change v4lconvert_enum_fmt code a bit, so that it is easier to add more
+ supported destination formats to libv4lconvert
+* Don't return -EINVAL from try_fmt when we cannot convert because the cam
+ doesn't have any formats we know. Instead just return as format whatever the
+ cam returns from try_fmt, this new behavior is compliant with the v4l2
+ api as documented
+
+libv4l-0.3.2
+------------
+* Add support for converting from sn9c10x compressed data
+* Add support for converting from pac207 compressed data
+* Add "make install" Makefile target
+
+libv4l-0.3.1
+------------
+* Only serialize V4L2_BUF_TYPE_VIDEO_CAPTURE type ioctls
+* Do not return an uninitialized variable as result code for GPICT
+ (fixes vlc, but see below)
+* Add an apps-patches directory which includes:
+ * vlc-0.8.6-libv4l1.patch, modify vlc's v4l1 plugin to directly call into
+ libv4l1, in the end we want all apps todo this as its better then
+ LD_PRELOAD tricks, but for vlc this is needed as vlc's plugin system
+ causes LD_PRELOAD to not work on symbols in the plugins
+ * camorama-0.19-fixes.patch, small bugfixes to camorama's v4l1 support,
+ this patch only fixes _real_ bugs in camorama and does not change it to
+ work with v4l1compat. Although it does work better with these bugs fixed
+ :) With this patch and LD_PRELOAD=<path>/v4l1compat.so it works
+ flawless.
+
+
+libv4l-0.3
+----------
+* add extern "C" magic to public header files for c++ usage (Gregor Jasny)
+* Make libv4l1 and libv4l2 multithread use safe, see README.multi-threading
+* Add v4lx_dup() calls (and intercept dup() from the wrappers) this fixes
+ use with gstreamer's v4l2 plugin (tested with cheese)
+* Hopefully definitely fix compile errors on systems with a broken videodev2.h
+
+libv4l-0.2
+----------
+*** API change ***
+* Change v4lconvert api so that the v4lconvert struct always gets allocated
+ by the library, this to make it opaque, so that we can avoid future API
+ and ABI changes
+* Add support for yuv420 -> bgr24 conversion
+* When converting from v4l2 pixelformat to v4l12 palette return
+ VIDEO_PALETTE_YUV420P instead of VIDEO_PALETTE_YUV420 for
+ V4L2_PIX_FMT_YUV420 as that is what most apps seem to expect
+* override kernel v4l1 compat min / max size with our own more accurate values
+* fix v4l1 munmap bug where it didn't recognise the buffer being unmapped was
+ our fake buffer (fixes gstreamer v4l1 support, checked with cheese)
+* add support for reporting the emulated pixelformats with ENUM_FMT, this
+ defaults to off, and can be activated by passing a flag to enable it to
+ v4l2_fd_open. This gets enabled by default the wrappers.
+* v4l2: mmap the real device buffers before doing conversion when DQBUF gets
+ called before the application has called mmap (avoid crash).
+
+
+libv4l-0.1
+----------
+* major shuffle / rewrite now split into libv4l1, libv4l2, libv4lconvert
+ and 2 wrappers for binary compatibility
+* rewritten LGPL bayer decoding
+* many many other changes and fixes
+
+
+v4l1-compat-0.6 (V4L2 apps stay working)
+----------------------------------------
+* Do not go into emulation mode of rgb24 immediately, but only after a
+ GPICT ioctl which has not been preceded by a SPICT ioctl, AKA do not get
+ in the way of V4L2 read calls by doing conversion on them
+* Do not get in the way of mmap calls made by V4L2 applications
+* Fix swapping of red and blue in bayer -> bgr24 decode routine
+* Remember the v4l1 palette asked for with SPICT and return that, as
+ otherwise we loose information when going v4l1 -> v4l2 -> v4l1, for example
+ YUV420P becomes YUV420, which are separate in v4l1.
+
+
+v4l1-compat-0.5 (perfect camorama)
+----------------------------------
+* Allow changing of format after the buffers have been mapped, by tearing
+ down the entire house, changing the fundament and then rebuilding it.
+ Now changing the capture resolution in camorama works!
+* Fix jpeg decoding error reporting
+* Allow jpeg's with a height which is a multiple of 8 (was 16)
+* Remove a number of pretty new VIDIOCXXX -> string mappings from log.c,
+ fixing compiling with somewhat older kernels
+
+
+v4l1-compat 0.4
+---------------
+* Do not even try to change the format in v4l1_compat_set_format(), unless
+ _really_ necessary.
+* Cleanup ambigious use of src_format (no functional changes)
+* Drop the mmap hack for zerocopy access under certain conditions, one of them
+ that the cam can deliver the requested format. Although avoiding the
+ memcpy in this scenarios is a good thing todo, there were several issues
+ with the 0.3 implementation of this, fixing all these means adding lots of
+ special cases all over the code. So instead we just drop support and
+ always do atleast a memcpy (or a conversion). If an application cannot
+ live with the speed penalty this imposes it should be ported to v4l2.
+* Now that we've gotten rid of the zerocopy mmap hack, we can safely allow
+ mixing read and mmap based IO.
+* Explictly include linux/ioctl.h, to fix compile with kernel headers where
+ linux/videodev.h doesn't.
+
+
+v4l1-compat 0.3
+---------------
+* Don't allow multiple opens, in theory our code can handle it, but not all
+ v4l2 devices like it (ekiga does it and uvc doesn't like it).
+
+
+v4l1-compat 0.2
+---------------
+* When mmap gets passed an fd of -1 (anonymous map) don't look for it in our
+ list of managed fds, as we use -1 to mark unused entries (fixes ekiga
+ crashing). Also check for an fd of -1 in the other calls we intercept.
+* In close() start with removing the fd from our list of managed fds, this must
+ be done first, because as soon as we've done the actual close syscall, the
+ fd maybe returned by an open in another thread and we don't want to intercept
+ calls to this new fd.
+* Make unknown v4l1 palette types a normal level log messages instead of an
+ error.
+* When an applicaiton changes the width / height through the CMCAPTURE ioctl
+ remember the new width and height.
+* If the devices initial v4l2 pixformat has no corresponding v4l1 palette, try
+ setting a format which does (and which we emulate when necessary) so that
+ applicactions which just query the current format (GPICT) and then take
+ whatever they get will work (partially fixes camorama)
+* Implement our own SWIN instead of using kernel compat layer, for more
+ flexibility and better error checking
+
+
+v4l1-compat 0.1
+---------------
+* Initial public release.
diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile
new file mode 100644
index 000000000..4c99c3167
--- /dev/null
+++ b/v4l2-apps/libv4l/Makefile
@@ -0,0 +1,16 @@
+LIB_RELEASE=0
+V4L2_LIB_VERSION=$(LIB_RELEASE).5.0
+
+all clean install:
+ $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
+ $(MAKE) -C libv4l2 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
+ $(MAKE) -C libv4l1 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
+
+export: clean
+ mkdir /tmp/libv4l-$(V4L2_LIB_VERSION)
+ cp -a . /tmp/libv4l-$(V4L2_LIB_VERSION)/
+ cd /tmp/ && \
+ tar cvf /tmp/libv4l-$(V4L2_LIB_VERSION).tar\
+ libv4l-$(V4L2_LIB_VERSION)
+ gzip /tmp/libv4l-$(V4L2_LIB_VERSION).tar
+ rm -rf /tmp/libv4l-$(V4L2_LIB_VERSION)
diff --git a/v4l2-apps/libv4l/README b/v4l2-apps/libv4l/README
new file mode 100644
index 000000000..3a2059224
--- /dev/null
+++ b/v4l2-apps/libv4l/README
@@ -0,0 +1,141 @@
+Introduction
+------------
+
+libv4l is a collection of libraries which adds a thin abstraction layer on
+top of video4linux2 devices. The purpose of this (thin) layer is to make it
+easy for application writers to support a wide variety of devices without
+having to write seperate code for different devices in the same class.
+
+All libv4l components are licensed under the GNU Lesser General Public
+License version 2 or (at your option) any later version.
+
+libv4l consists of 3 different libraries:
+
+
+libv4lconvert
+-------------
+
+libv4lconvert offers functions to convert from any (known) pixelformat
+to V4l2_PIX_FMT_BGR24 or V4l2_PIX_FMT_YUV420.
+
+Currently the following source formats are supported:
+jpeg, mjpeg, bayer (all 4 variants: bggr, rggb, gbrg, grbg),
+spca501 (chip specific yuv 420 with interlaced components),
+spca561 (chip specific compressed gbrg bayer)
+For more details on the v4lconvert_ functions see libv4lconvert.h .
+
+
+libv4l1
+-------
+
+This offers functions like v4l1_open, v4l1_ioctl, etc. which can by used to
+quickly make v4l1 applications work with v4l2 devices. These functions work
+exactly like the normal open/close/etc, except that libv4l1 does full emulation
+of the v4l1 api on top of v4l2 drivers, in case of v4l1 drivers it will just
+pass calls through. For more details on the v4l1_ functions see libv4l1.h .
+
+
+libv4l2
+-------
+
+This offers functions like v4l2_open, v4l2_ioctl, etc. which can by used to
+quickly make v4l2 applications work with v4l2 devices with weird formats.
+libv4l2 mostly passes calls directly through to the v4l2 driver. When the
+app does a TRY_FMT / S_FMT with a not supported format libv4l2 will get in
+the middle and emulate the format (if an app wants to know which formats the
+hardware can _really_ do it should use ENUM_FMT, not randomly try a bunch of
+S_FMT's). For more details on the v4l2_ functions see libv4l2.h .
+
+
+wrappers
+--------
+
+The functionality provided by libv4l1 for v4l1 apps and libv4l2 for v4l2 apps
+can also be used by existing apps without modifying them. For this purpose
+2 wrapper libraries are provided which can be preloaded before starting the
+application using the LD_PRELOAD environment variable. These wrappers will
+then intercept calls to open/close/ioctl/etc. and if these calls directed
+towards a video device the wrapper will redirect the call to the libv4lX
+counterparts.
+
+The preloadable libv4l1 wrapper which adds v4l2 device compatibility to v4l1
+applications is called v4l1compat.so. The preloadable libv4l2 wrapper which
+adds support for various pixelformats to v4l2 applications is called
+v4l2convert.so.
+
+Example usage (after install in default location):
+$ export LD_PRELOAD=/usr/local/lib/libv4l/v4l1compat.so
+$ camorama
+
+
+Installation Instructions
+-------------------------
+
+Simple type the following commands from the libv4l-x.y.z directory
+(adjusting PREFIX as desired):
+make
+make install PREFIX=/usr/local
+
+Note: make install also supports the DESTDIR=... paramter for installation
+into chroots.
+
+
+FAQ
+---
+
+Q: Why libv4l, whats wrong with directly accessing v4l2 devices ?
+Q: Do we really need yet another library ?
+A: Current webcam using applications like ekiga contain code to handle many
+different specific pixelformats webcam's use, but that code only supports a
+small subset of all native webcam (compressed) pixelformats. Other current
+v4l2 applications do not support anything but rgb pixelformats (xawtv for
+example) and this will not work with most webcams at all.
+
+With gspca being ported to v4l2 and thus decoding to normal formats being
+removed from the device driver as this really belongs in userspace, ekiga
+would need to be extended with many more often chip dependent formats, like
+the bayer compression used by the spca561 and the (different) compression used
+by the pac207 and the (again different) compression used by the sn9c102. Adding
+support for all these formats should not be done at the application level, as
+then it needs to be written for each application seperately. Licensing issues
+with the decompressors will then also become a problem as just cut and pasting
+from one application to another is bound to hit license incompatibilities.
+
+So clearly this belongs in a library, and in a library with a license which
+allows this code to be used from as many different applications as possible.
+Hence libv4l was born.
+
+Q: Under which license may I use and distribute libv4l?
+A: All libv4l components are licensed under the GNU Library General Publishing
+License version 2 or (at your option) any later version. See the included
+COPYING.LIB file.
+
+Q: Okay so I get the use of having a libv4lconvert, but why libv4l1 ?
+A: Many v4l2 drivers do not offer full v4l1 compatibility. They often do not
+implemented the CGMBUF ioctl and v4l1 style mmap call. Adding support to all
+these drivers for this is a lot of work and more importantly unnecessary
+adds code to kernel space.
+
+Also even if the CGMBUF ioctl and v4l1 style mmap are supported, then most
+cams still deliver pixelformats which v4l1 applications do not understand.
+
+This libv4l1 was born as an easy way to get v4l1 applications to work with
+v4l2 devices without requiring full v4l1 emulation (including format
+conversion) in the kernel, and without requiring major changes to the
+applications.
+
+
+Q: Why should I use libv4l2 in my app instead of direct device access
+combined with libv4lconvert?
+
+libv4l2 is mainly meant for quickly and easily adding support for more
+pixelformats to existing v4l2 applications. So if you feel better directly
+accessing the device in combination with libv4lconvert thats fine too.
+
+Notice that libv4l2 also does emulation of the read() call on devices which
+do not support it in the driver. In the background this uses mmap buffers
+(even on devices which do support the read call). This mmap gives libv4lconvert
+zero-copy access to the captured frame, and then it can write the converted
+data directly to the buffer the application provided to v4l2_read(). Thus
+another reason to use liv4l2 is to get the no memcpy advantage of the mmap
+capture method combined with the simplicity of making a simple read() call.
diff --git a/v4l2-apps/libv4l/README.multi-threading b/v4l2-apps/libv4l/README.multi-threading
new file mode 100644
index 000000000..93b393c8c
--- /dev/null
+++ b/v4l2-apps/libv4l/README.multi-threading
@@ -0,0 +1,12 @@
+libv4lconvert is not safe for using one convert instance as returned by
+v4lconvert_create from multiple threads, if you want to use one v4lconvert
+instance from multiple threads you must provide your own locking and make
+sure no simultanious calls are made.
+
+libv4l1 and libv4l2 are safe for multithread use *under* *the* *following*
+*conditions* :
+
+* when using v4lx_fd_open, do not make any v4lx_ calls to the passed fd until
+ v4lx_fd_open has completed
+
+* all v4lx_ calls must be completed before calling v4lx_close
diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO
new file mode 100644
index 000000000..f3f9ff527
--- /dev/null
+++ b/v4l2-apps/libv4l/TODO
@@ -0,0 +1,12 @@
+-add support for setting / getting the number of read buffers
+
+-add code to v4l2_read to not return frames more then say 5 seconds old
+
+-add support for libv4l1 for non pure capture (combined capture and overlay)
+ devices so that atleast CGMBUF emulation (but no conversion, as thats
+ impossible for overlays) can be done, so that it will no longer be
+ necessary to implement CGMBUF in the kernel for each driver.
+
+-check v4l2_field during conversion
+
+-add conversion from bgr24 to yuv420
diff --git a/v4l2-apps/libv4l/include/libv4l1.h b/v4l2-apps/libv4l/include/libv4l1.h
new file mode 100644
index 000000000..c878cc198
--- /dev/null
+++ b/v4l2-apps/libv4l/include/libv4l1.h
@@ -0,0 +1,73 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4L1_H
+#define __LIBV4L1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+/* Point this to a FILE opened for writing when you want to log error and
+ status messages to a file, when NULL errors will get send to stderr */
+LIBV4L_PUBLIC extern FILE *v4l1_log_file;
+
+/* Just like your regular open/close/etc, except that when opening a v4l2
+ capture only device, full v4l1 emulation is done including emulating the
+ often not implemented in v4l2 drivers CGMBUF ioctl and v4l1 style mmap call
+ in userspace.
+
+ Format conversion is done if necessary when capturing. That is if you
+ (try to) set a capture format which is not supported by the cam, but is
+ supported by libv4lconvert then SPICT will succeed and on SYNC / read the
+ data will be converted for you and returned in the request format.
+
+ Note that currently libv4l1 depends on the kernel v4l1 compatibility layer
+ for: 1) Devices which are not capture only, 2) Emulation of many basic
+ v4l1 ioctl's which require no driver specific handling.
+
+ Note that no functionality is added to v4l1 devices, so if for example an
+ obscure v4l1 device is opened which only supports some weird capture format
+ then libv4l1 will not be of any help (in this case it would be best to get
+ the driver converted to v4l2, as v4l2 has been designed to include weird
+ capture formats, like hw specific bayer compression methods).
+*/
+
+LIBV4L_PUBLIC int v4l1_open (const char *file, int oflag, ...);
+LIBV4L_PUBLIC int v4l1_close(int fd);
+LIBV4L_PUBLIC int v4l1_dup(int fd);
+LIBV4L_PUBLIC int v4l1_ioctl (int fd, unsigned long int request, ...);
+LIBV4L_PUBLIC ssize_t v4l1_read (int fd, void* buffer, size_t n);
+LIBV4L_PUBLIC void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset);
+LIBV4L_PUBLIC int v4l1_munmap(void *_start, size_t length);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/v4l2-apps/libv4l/include/libv4l2.h b/v4l2-apps/libv4l/include/libv4l2.h
new file mode 100644
index 000000000..b05b57cb6
--- /dev/null
+++ b/v4l2-apps/libv4l/include/libv4l2.h
@@ -0,0 +1,110 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4L2_H
+#define __LIBV4L2_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+/* Point this to a FILE opened for writing when you want to log error and
+ status messages to a file, when NULL errors will get send to stderr */
+LIBV4L_PUBLIC extern FILE *v4l2_log_file;
+
+/* Just like your regular open/close/etc, except that format conversion is
+ done if necessary when capturing. That is if you (try to) set a capture
+ format which is not supported by the cam, but is supported by libv4lconvert,
+ then the try_fmt / set_fmt will succeed as if the cam supports the format
+ and on dqbuf / read the data will be converted for you and returned in
+ the request format.
+
+ Another difference is that you can make v4l2_read() calls even on devices
+ which do not support the regular read() method.
+
+ Note that libv4l2 normally does not interfere with enum_fmt, so enum_fmt
+ will still return the actual formats the hardware supports, and not any
+ formats which may be emulated on top of that. If you pass the
+ V4L2_ENABLE_ENUM_FMT_EMULATION flag to v4l2_fd_open (as the v4l2convert.so
+ wrapper does) then enum_fmt will also report support for the formats to
+ which conversion is possible.
+
+ Note the device name passed to v4l2_open must be of a video4linux2 device,
+ if it is anything else (including a video4linux1 device), v4l2_open will
+ fail.
+*/
+
+LIBV4L_PUBLIC int v4l2_open (const char *file, int oflag, ...);
+LIBV4L_PUBLIC int v4l2_close(int fd);
+LIBV4L_PUBLIC int v4l2_dup(int fd);
+LIBV4L_PUBLIC int v4l2_ioctl (int fd, unsigned long int request, ...);
+LIBV4L_PUBLIC ssize_t v4l2_read (int fd, void* buffer, size_t n);
+LIBV4L_PUBLIC void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset);
+LIBV4L_PUBLIC int v4l2_munmap(void *_start, size_t length);
+
+
+/* Misc utility functions */
+
+/* This function takes a value of 0 - 65535, and then scales that range to
+ the actual range of the given v4l control id, and then if the cid exists
+ and is not locked sets the cid to the scaled value.
+
+ Normally returns 0, even if the cid did not exist or was locked, returns
+ non 0 when an other error occured. */
+LIBV4L_PUBLIC int v4l2_set_control(int fd, int cid, int value);
+
+/* This function returns a value of 0 - 65535, scaled to from the actual range
+ of the given v4l control id. when the cid does not exist, could not be
+ accessed for some reason, or some error occured 0 is returned. */
+LIBV4L_PUBLIC int v4l2_get_control(int fd, int cid);
+
+
+/* "low level" access functions, these functions allow somewhat lower level
+ access to libv4l2 (currently there only is v4l2_fd_open here) */
+
+/* Flags for v4l2_fd_open's v4l2_flags argument */
+
+/* Disable all format conversion done by libv4l2 (reduces libv4l2 functionality
+ to offering v4l2_read() even on devices which don't implement read()) */
+#define V4L2_DISABLE_CONVERSION 0x01
+/* Report not only real but also emulated formats with the ENUM_FMT ioctl */
+#define V4L2_ENABLE_ENUM_FMT_EMULATION 02
+
+/* v4l2_fd_open: open an already opened fd for further use through
+ v4l2lib and possibly modify libv4l2's default behavior through the
+ v4l2_flags argument.
+
+ Returns fd on success, -1 if the fd is not suitable for use through libv4l2
+ (note the fd is left open in this case). */
+LIBV4L_PUBLIC int v4l2_fd_open(int fd, int v4l2_flags);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h
new file mode 100644
index 000000000..626c43473
--- /dev/null
+++ b/v4l2-apps/libv4l/include/libv4lconvert.h
@@ -0,0 +1,88 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4LCONVERT_H
+#define __LIBV4LCONVERT_H
+
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+/* end broken header workaround includes */
+#include <linux/videodev2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+struct v4lconvert_data;
+
+LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd);
+LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data);
+
+/* With regards to dest_fmt just like VIDIOC_TRY_FMT, except that the try
+ format will succeed and return the requested V4L2_PIX_FMT_foo in dest_fmt if
+ the cam has a format from which v4lconvert can convert to dest_fmt.
+ The real format to which the cam should be set is returned through src_fmt
+ when not NULL. */
+LIBV4L_PUBLIC int v4lconvert_try_format(struct v4lconvert_data *data,
+ struct v4l2_format *dest_fmt, /* in / out */
+ struct v4l2_format *src_fmt /* out */
+);
+
+/* Just like VIDIOC_ENUM_FMT, except that the emulated formats are added at
+ the end of the list */
+LIBV4L_PUBLIC int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt);
+
+/* Is conversion necessary or can the app use the data directly? */
+LIBV4L_PUBLIC int v4lconvert_needs_conversion(struct v4lconvert_data *data,
+ const struct v4l2_format *src_fmt, /* in */
+ const struct v4l2_format *dest_fmt); /* in */
+
+/* return value of -1 on error, otherwise the amount of bytes written to
+ dest */
+LIBV4L_PUBLIC int v4lconvert_convert(struct v4lconvert_data *data,
+ const struct v4l2_format *src_fmt, /* in */
+ const struct v4l2_format *dest_fmt, /* in */
+ unsigned char *src, int src_size, unsigned char *dest, int dest_size);
+
+/* get a string describing the last error*/
+LIBV4L_PUBLIC const char *v4lconvert_get_error_message(struct v4lconvert_data *data);
+
+/* Just like VIDIOC_ENUM_FRAMESIZE, except that the framesizes of emulated
+ formats can be enumerated as well. */
+LIBV4L_PUBLIC int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
+ struct v4l2_frmsizeenum *frmsize);
+
+/* Just like VIDIOC_ENUM_FRAMEINTERVALS, except that the intervals of emulated
+ formats can be enumerated as well. */
+LIBV4L_PUBLIC int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
+ struct v4l2_frmivalenum *frmival);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile
new file mode 100644
index 000000000..27848477e
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/Makefile
@@ -0,0 +1,83 @@
+override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
+
+CFLAGS := -g -O1
+CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
+
+LIBS = -lpthread
+
+V4L1_OBJS = libv4l1.o log.o
+V4L1COMPAT = v4l1compat.so
+V4L1COMPAT_O = v4l1compat.o libv4l1.so
+TARGETS = $(V4L1_LIB) libv4l1.pc
+INCLUDES = ../include/libv4l1.h
+
+ifeq ($(LINKTYPE),static)
+V4L1_LIB = libv4l1.a
+else
+V4L1_LIB = libv4l1.so
+V4L1_OBJS += ../libv4l2/libv4l2.so
+TARGETS += $(V4L1COMPAT)
+override CPPFLAGS += -fPIC
+endif
+
+ifeq ($(LIB_RELEASE),)
+LIB_RELEASE = 0
+endif
+
+ifeq ($(PREFIX),)
+PREFIX = /usr/local
+endif
+
+ifeq ($(LIBDIR),)
+LIBDIR = $(PREFIX)/lib
+endif
+
+all: $(TARGETS)
+
+
+$(V4L1_LIB): $(V4L1_OBJS)
+
+$(V4L1COMPAT): $(V4L1COMPAT_O) $(V4L1_LIB)
+
+libv4l1.pc:
+ @echo prefix=$(PREFIX) > libv4l1.pc
+ @echo libdir=$(LIBDIR) >> libv4l1.pc
+ @echo >> libv4l1.pc
+ @echo 'Name: libv4l1' >> libv4l1.pc
+ @echo 'Description: v4l1 compatibility library' >> libv4l1.pc
+ @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4l1.pc
+ @echo 'Requires: libv4l2' >> libv4l1.pc
+ @echo 'Libs: -L$${libdir} -lv4l1' >> libv4l1.pc
+ @echo 'Libs.private: -lpthread' >> libv4l1.pc
+ @echo 'Cflags: -I$${prefix}/include' >> libv4l1.pc
+
+install: all
+ mkdir -p $(DESTDIR)$(PREFIX)/include
+ install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include
+ifeq ($(LINKTYPE),static)
+ mkdir -p $(DESTDIR)$(LIBDIR)
+ install -m 644 $(V4L1_LIB) $(DESTDIR)$(LIBDIR)
+else
+ mkdir -p $(DESTDIR)$(LIBDIR)/libv4l
+ install -m 755 $(V4L1_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR)
+ cd $(DESTDIR)$(LIBDIR) && \
+ ln -f -s $(V4L1_LIB).$(LIB_RELEASE) $(V4L1_LIB)
+ install -m 755 $(V4L1COMPAT).$(LIB_RELEASE) \
+ $(DESTDIR)$(LIBDIR)/libv4l/$(V4L1COMPAT)
+endif
+ mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
+ install -m 644 libv4l1.pc $(DESTDIR)$(LIBDIR)/pkgconfig
+
+clean::
+ rm -f *.a *.so* *.o *.d libv4l1.pc log *~
+
+%.o: %.c
+ $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+%.so:
+ $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS)
+ ln -f -s $@.$(LIB_RELEASE) $@
+
+%.a:
+ $(AR) cqs $@ $^
+
diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h
new file mode 100644
index 000000000..651599255
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h
@@ -0,0 +1,83 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4L1_PRIV_H
+#define __LIBV4L1_PRIV_H
+
+#include <stdio.h>
+#include <pthread.h>
+
+/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */
+#ifdef __NR_mmap2
+#define SYS_mmap2 __NR_mmap2
+#define MMAP2_PAGE_SHIFT 12
+#else
+#define SYS_mmap2 SYS_mmap
+#define MMAP2_PAGE_SHIFT 0
+#endif
+
+#define V4L1_MAX_DEVICES 16
+#define V4L1_NO_FRAMES 4
+#define V4L1_FRAME_BUF_SIZE (4096 * 4096)
+
+extern FILE *v4l1_log_file;
+
+#define V4L1_LOG_ERR(...) \
+ do { \
+ if (v4l1_log_file) { \
+ fprintf(v4l1_log_file, "libv4l1: error " __VA_ARGS__); \
+ fflush(v4l1_log_file); \
+ } else \
+ fprintf(stderr, "libv4l1: error " __VA_ARGS__); \
+ } while(0)
+
+#define V4L1_LOG_WARN(...) \
+ do { \
+ if (v4l1_log_file) { \
+ fprintf(v4l1_log_file, "libv4l1: warning " __VA_ARGS__); \
+ fflush(v4l1_log_file); \
+ } else \
+ fprintf(stderr, "libv4l1: warning " __VA_ARGS__); \
+ } while(0)
+
+#define V4L1_LOG(...) \
+ do { \
+ if (v4l1_log_file) { \
+ fprintf(v4l1_log_file, "libv4l1: " __VA_ARGS__); \
+ fflush(v4l1_log_file); \
+ } \
+ } while(0)
+
+struct v4l1_dev_info {
+ int fd;
+ int flags;
+ int open_count;
+ int v4l1_frame_buf_map_count;
+ pthread_mutex_t stream_lock;
+ unsigned int depth;
+ unsigned int v4l1_pal; /* VIDEO_PALETTE */
+ unsigned int v4l2_pixfmt; /* V4L2_PIX_FMT */
+ unsigned int min_width, min_height, max_width, max_height;
+ unsigned int width, height;
+ unsigned char *v4l1_frame_pointer;
+};
+
+/* From log.c */
+void v4l1_log_ioctl(unsigned long int request, void *arg, int result);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c
new file mode 100644
index 000000000..797c8768a
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c
@@ -0,0 +1,837 @@
+/*
+# libv4l1 userspace v4l1 api emulation for v4l2 devices
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* MAKING CHANGES TO THIS FILE?? READ THIS FIRST!!!
+
+ Important note to people making changes to this file: All functions
+ (v4l1_close, v4l1_ioctl, etc.) are designed to function as their regular
+ counterpart when they get passed a fd that is not "registered" by libv4l1,
+ there are 2 reasons for this:
+ 1) This allows us to get completely out of the way when dealing with non
+ capture only devices, or non v4l2 devices.
+ 2) libv4l1 is the base of the v4l1compat.so wrapper lib, which is a .so
+ which can be LD_PRELOAD-ed and the overrules the libc's open/close/etc,
+ and when opening /dev/videoX or /dev/v4l/ calls v4l1_open. Because we
+ behave as the regular counterpart when the fd is not known (instead of
+ say throwing an error), v4l1compat.so can simply call the v4l1_ prefixed
+ function for all wrapped functions. This way the wrapper does not have
+ to keep track of which fd's are being handled by libv4l1, as libv4l1
+ already keeps track of this itself.
+
+ This also means that libv4l1 may not use any of the regular functions
+ it mimics, as for example open could be a symbol in v4l1compat.so, which
+ in turn will call v4l1_open, so therefor v4l1_open (for example) may not
+ use the regular open()!
+*/
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <asm/types.h>
+#include <linux/ioctl.h>
+/* end broken header workaround includes */
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <libv4l2.h>
+#include "libv4l1.h"
+#include "libv4l1-priv.h"
+
+#define V4L1_SUPPORTS_ENUMINPUT 0x01
+#define V4L1_SUPPORTS_ENUMSTD 0x02
+#define V4L1_PIX_FMT_TOUCHED 0x04
+#define V4L1_PIX_SIZE_TOUCHED 0x08
+
+static pthread_mutex_t v4l1_open_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct v4l1_dev_info devices[V4L1_MAX_DEVICES] = { { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }};
+static int devices_used = 0;
+
+static unsigned int palette_to_pixelformat(unsigned int palette)
+{
+ switch (palette) {
+ case VIDEO_PALETTE_GREY:
+ return V4L2_PIX_FMT_GREY;
+ case VIDEO_PALETTE_RGB555:
+ return V4L2_PIX_FMT_RGB555;
+ case VIDEO_PALETTE_RGB565:
+ return V4L2_PIX_FMT_RGB565;
+ case VIDEO_PALETTE_RGB24:
+ return V4L2_PIX_FMT_BGR24;
+ case VIDEO_PALETTE_RGB32:
+ return V4L2_PIX_FMT_BGR32;
+ case VIDEO_PALETTE_YUYV:
+ return V4L2_PIX_FMT_YUYV;
+ case VIDEO_PALETTE_YUV422:
+ return V4L2_PIX_FMT_YUYV;
+ case VIDEO_PALETTE_UYVY:
+ return V4L2_PIX_FMT_UYVY;
+ case VIDEO_PALETTE_YUV410P:
+ return V4L2_PIX_FMT_YUV410;
+ case VIDEO_PALETTE_YUV420:
+ case VIDEO_PALETTE_YUV420P:
+ return V4L2_PIX_FMT_YUV420;
+ case VIDEO_PALETTE_YUV411P:
+ return V4L2_PIX_FMT_YUV411P;
+ case VIDEO_PALETTE_YUV422P:
+ return V4L2_PIX_FMT_YUV422P;
+ }
+ return 0;
+}
+
+static unsigned int pixelformat_to_palette(unsigned int pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_GREY:
+ return VIDEO_PALETTE_GREY;
+ case V4L2_PIX_FMT_RGB555:
+ return VIDEO_PALETTE_RGB555;
+ case V4L2_PIX_FMT_RGB565:
+ return VIDEO_PALETTE_RGB565;
+ case V4L2_PIX_FMT_BGR24:
+ return VIDEO_PALETTE_RGB24;
+ case V4L2_PIX_FMT_BGR32:
+ return VIDEO_PALETTE_RGB32;
+ case V4L2_PIX_FMT_YUYV:
+ return VIDEO_PALETTE_YUYV;
+ case V4L2_PIX_FMT_UYVY:
+ return VIDEO_PALETTE_UYVY;
+ case V4L2_PIX_FMT_YUV410:
+ case V4L2_PIX_FMT_YUV420:
+ return VIDEO_PALETTE_YUV420P;
+ case V4L2_PIX_FMT_YUV411P:
+ return VIDEO_PALETTE_YUV411P;
+ case V4L2_PIX_FMT_YUV422P:
+ return VIDEO_PALETTE_YUV422P;
+ }
+ return 0;
+}
+
+static int v4l1_set_format(int index, unsigned int width,
+ unsigned int height, int v4l1_pal, int width_height_may_differ)
+{
+ int result;
+ unsigned int v4l2_pixfmt;
+ struct v4l2_format fmt2 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+
+ if (v4l1_pal != -1) {
+ v4l2_pixfmt = palette_to_pixelformat(v4l1_pal);
+ if (!v4l2_pixfmt) {
+ V4L1_LOG("Unknown v4l1 palette number: %d\n", v4l1_pal);
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ v4l2_pixfmt = devices[index].v4l2_pixfmt;
+ v4l1_pal = devices[index].v4l1_pal;
+ }
+
+ /* Do we need to change the resolution / format ? */
+ if (width == devices[index].width && height == devices[index].height &&
+ v4l2_pixfmt == devices[index].v4l2_pixfmt)
+ return 0;
+
+ /* Get current settings, apply our changes and try the new setting */
+ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_G_FMT, &fmt2))) {
+ int saved_err = errno;
+ V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ fmt2.fmt.pix.pixelformat = v4l2_pixfmt;
+ fmt2.fmt.pix.width = width;
+ fmt2.fmt.pix.height = height;
+ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, &fmt2)))
+ {
+ int saved_err = errno;
+ V4L1_LOG("error trying pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ /* Check if we get what we asked for */
+ if (fmt2.fmt.pix.pixelformat != v4l2_pixfmt || (!width_height_may_differ &&
+ (fmt2.fmt.pix.width != width || fmt2.fmt.pix.height != height))) {
+ V4L1_LOG("requested fmt, width, height combo not available\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Maybe after the TRY_FMT things haven't changed after all ? */
+ if (fmt2.fmt.pix.width == devices[index].width &&
+ fmt2.fmt.pix.height == devices[index].height &&
+ fmt2.fmt.pix.pixelformat == devices[index].v4l2_pixfmt) {
+ devices[index].v4l1_pal = v4l1_pal;
+ return 0;
+ }
+
+ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_S_FMT, &fmt2))) {
+ int saved_err = errno;
+ V4L1_LOG_ERR("setting pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ devices[index].width = fmt2.fmt.pix.width;
+ devices[index].height = fmt2.fmt.pix.height;
+ devices[index].v4l2_pixfmt = v4l2_pixfmt;
+ devices[index].v4l1_pal = v4l1_pal;
+ devices[index].depth = ((fmt2.fmt.pix.bytesperline << 3) +
+ (fmt2.fmt.pix.width - 1)) / fmt2.fmt.pix.width;
+
+ return result;
+}
+
+static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2)
+{
+ int i;
+ struct v4l2_fmtdesc fmtdesc2 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+
+ devices[index].min_width = -1;
+ devices[index].min_height = -1;
+ devices[index].max_width = 0;
+ devices[index].max_height = 0;
+
+ for (i = 0; ; i++) {
+ fmtdesc2.index = i;
+
+ if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2))
+ break;
+
+ fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat;
+ fmt2->fmt.pix.width = 48;
+ fmt2->fmt.pix.height = 32;
+
+ if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
+ if (fmt2->fmt.pix.width < devices[index].min_width)
+ devices[index].min_width = fmt2->fmt.pix.width;
+ if (fmt2->fmt.pix.height < devices[index].min_height)
+ devices[index].min_height = fmt2->fmt.pix.height;
+ }
+
+ fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat;
+ fmt2->fmt.pix.width = 100000;
+ fmt2->fmt.pix.height = 100000;
+
+ if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
+ if (fmt2->fmt.pix.width > devices[index].max_width)
+ devices[index].max_width = fmt2->fmt.pix.width;
+ if (fmt2->fmt.pix.height > devices[index].max_height)
+ devices[index].max_height = fmt2->fmt.pix.height;
+ }
+ }
+}
+
+
+int v4l1_open (const char *file, int oflag, ...)
+{
+ int index, fd;
+ char *lfname;
+ struct v4l2_capability cap2;
+ struct v4l2_format fmt2;
+ struct v4l2_input input2;
+ struct v4l2_standard standard2;
+ int v4l_device = 0;
+
+ /* check if we're opening a video4linux2 device */
+ if (!strncmp(file, "/dev/video", 10) || !strncmp(file, "/dev/v4l/", 9)) {
+ /* Some apps open the device read only, but we need rw rights as the
+ buffers *MUST* be mapped rw */
+ oflag = (oflag & ~O_ACCMODE) | O_RDWR;
+ v4l_device = 1;
+ }
+
+ /* original open code */
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = syscall(SYS_open, file, oflag, mode);
+
+ va_end(ap);
+ } else
+ fd = syscall(SYS_open, file, oflag);
+ /* end of original open code */
+
+ if (fd == -1 || !v4l_device)
+ return fd;
+
+ /* check that this is an v4l2 device, no need to emulate v4l1 on
+ a v4l1 device */
+ if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap2))
+ return fd;
+
+ /* IMPROVEME */
+ /* we only support simple video capture devices which do not do overlay */
+ if ((cap2.capabilities & 0x0F) != V4L2_CAP_VIDEO_CAPTURE)
+ return fd;
+
+ /* If no log file was set by the app, see if one was specified through the
+ environment */
+ if (!v4l1_log_file && (lfname = getenv("LIBV4L1_LOG_FILENAME")))
+ v4l1_log_file = fopen(lfname, "w");
+
+ /* redirect libv4l2 log messages to our logfile if no libv4l2 logfile is
+ specified */
+ if (!v4l2_log_file)
+ v4l2_log_file = v4l1_log_file;
+
+ /* Get initial width, height and pixelformat */
+ fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt2)) {
+ int saved_err = errno;
+ V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno));
+ syscall(SYS_close, fd);
+ errno = saved_err;
+ return -1;
+ }
+
+ /* Register with libv4l2, as we use that todo format conversion and read()
+ emulation for us */
+ if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) {
+ int saved_err = errno;
+ syscall(SYS_close, fd);
+ errno = saved_err;
+ return -1;
+ }
+
+ /* So we have a device on which we can (and want to) emulate v4l1, register
+ it in our devices array */
+ pthread_mutex_lock(&v4l1_open_mutex);
+ for (index = 0; index < V4L1_MAX_DEVICES; index++)
+ if(devices[index].fd == -1) {
+ devices[index].fd = fd;
+ break;
+ }
+ pthread_mutex_unlock(&v4l1_open_mutex);
+
+ if (index == V4L1_MAX_DEVICES) {
+ V4L1_LOG_ERR("attempting to open more then %d video devices\n",
+ V4L1_MAX_DEVICES);
+ v4l2_close(fd);
+ errno = EBUSY;
+ return -1;
+ }
+
+ if (index >= devices_used)
+ devices_used = index + 1;
+
+ devices[index].flags = 0;
+ devices[index].open_count = 1;
+ devices[index].v4l1_frame_buf_map_count = 0;
+ devices[index].v4l1_frame_pointer = MAP_FAILED;
+ devices[index].width = fmt2.fmt.pix.width;
+ devices[index].height = fmt2.fmt.pix.height;
+ devices[index].v4l2_pixfmt = fmt2.fmt.pix.pixelformat;
+ devices[index].v4l1_pal = pixelformat_to_palette(fmt2.fmt.pix.pixelformat);
+ devices[index].depth = ((fmt2.fmt.pix.bytesperline << 3) +
+ (fmt2.fmt.pix.width - 1)) / fmt2.fmt.pix.width;
+
+ v4l1_find_min_and_max_size(index, &fmt2);
+
+ /* Check ENUM_INPUT and ENUM_STD support */
+ input2.index = 0;
+ if (v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2) == 0)
+ devices[index].flags |= V4L1_SUPPORTS_ENUMINPUT;
+
+ standard2.index = 0;
+ if (v4l2_ioctl(fd, VIDIOC_ENUMSTD, &input2) == 0)
+ devices[index].flags |= V4L1_SUPPORTS_ENUMSTD;
+
+ V4L1_LOG("open: %d\n", fd);
+
+ return fd;
+}
+
+/* Is this an fd for which we are emulating v4l1 ? */
+static int v4l1_get_index(int fd)
+{
+ int index;
+
+ /* We never handle fd -1 */
+ if (fd == -1)
+ return -1;
+
+ for (index = 0; index < devices_used; index++)
+ if (devices[index].fd == fd)
+ break;
+
+ if (index == devices_used)
+ return -1;
+
+ return index;
+}
+
+
+int v4l1_close(int fd) {
+ int index, result;
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_close, fd);
+
+ /* Abuse stream_lock to stop 2 closes from racing and trying to free the
+ resources twice */
+ pthread_mutex_lock(&devices[index].stream_lock);
+ devices[index].open_count--;
+ result = devices[index].open_count != 0;
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ if (result)
+ return v4l2_close(fd);
+
+ /* Free resources */
+ if (devices[index].v4l1_frame_pointer != MAP_FAILED) {
+ if (devices[index].v4l1_frame_buf_map_count)
+ V4L1_LOG("v4l1 capture buffer still mapped: %d times on close()\n",
+ devices[index].v4l1_frame_buf_map_count);
+ else
+ syscall(SYS_munmap, devices[index].v4l1_frame_pointer,
+ V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE);
+ devices[index].v4l1_frame_pointer = MAP_FAILED;
+ }
+
+ /* Remove the fd from our list of managed fds before closing it, because as
+ soon as we've done the actual close the fd maybe returned by an open in
+ another thread and we don't want to intercept calls to this new fd. */
+ devices[index].fd = -1;
+
+ result = v4l2_close(fd);
+
+ V4L1_LOG("close: %d\n", fd);
+
+ return result;
+}
+
+int v4l1_dup(int fd)
+{
+ int index;
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_dup, fd);
+
+ devices[index].open_count++;
+
+ return v4l2_dup(fd);
+}
+
+
+int v4l1_ioctl (int fd, unsigned long int request, ...)
+{
+ void *arg;
+ va_list ap;
+ int result, index, saved_err, stream_locked = 0;
+
+ va_start (ap, request);
+ arg = va_arg (ap, void *);
+ va_end (ap);
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_ioctl, fd, request, arg);
+
+ /* Appearantly the kernel and / or glibc ignore the 32 most significant bits
+ when long = 64 bits, and some applications pass an int holding the req to
+ ioctl, causing it to get sign extended, depending upon this behavior */
+ request = (unsigned int)request;
+
+ /* do we need to take the stream lock for this ioctl? */
+ switch (request) {
+ case VIDIOCSPICT:
+ case VIDIOCGPICT:
+ case VIDIOCSWIN:
+ case VIDIOCGWIN:
+ case VIDIOCGMBUF:
+ case VIDIOCMCAPTURE:
+ case VIDIOCSYNC:
+ case VIDIOC_S_FMT:
+ pthread_mutex_lock(&devices[index].stream_lock);
+ stream_locked = 1;
+ }
+
+ switch (request) {
+
+ case VIDIOCGCAP:
+ {
+ struct video_capability *cap = arg;
+
+ result = syscall(SYS_ioctl, fd, request, arg);
+
+ /* override kernel v4l1 compat min / max size with our own more
+ accurate values */
+ cap->minwidth = devices[index].min_width;
+ cap->minheight = devices[index].min_height;
+ cap->maxwidth = devices[index].max_width;
+ cap->maxheight = devices[index].max_height;
+ }
+ break;
+
+ case VIDIOCSPICT:
+ {
+ struct video_picture *pic = arg;
+
+ devices[index].flags |= V4L1_PIX_FMT_TOUCHED;
+
+ v4l2_set_control(fd, V4L2_CID_BRIGHTNESS, pic->brightness);
+ v4l2_set_control(fd, V4L2_CID_HUE, pic->hue);
+ v4l2_set_control(fd, V4L2_CID_CONTRAST, pic->contrast);
+ v4l2_set_control(fd, V4L2_CID_SATURATION, pic->colour);
+ v4l2_set_control(fd, V4L2_CID_WHITENESS, pic->whiteness);
+
+ result = v4l1_set_format(index, devices[index].width,
+ devices[index].height, pic->palette, 0);
+ }
+ break;
+
+ case VIDIOCGPICT:
+ {
+ struct video_picture *pic = arg;
+
+ /* If our v4l2 pixformat has no corresponding v4l1 palette, and the
+ app has not touched the pixformat sofar, try setting a palette which
+ does (and which we emulate when necessary) so that applications
+ which just query the current format and then take whatever they get
+ will work */
+ if (!(devices[index].flags & V4L1_PIX_FMT_TOUCHED) &&
+ !pixelformat_to_palette(devices[index].v4l2_pixfmt))
+ v4l1_set_format(index, devices[index].width,
+ devices[index].height,
+ VIDEO_PALETTE_RGB24,
+ (devices[index].flags &
+ V4L1_PIX_SIZE_TOUCHED) ? 0 : 1);
+
+ devices[index].flags |= V4L1_PIX_FMT_TOUCHED;
+
+ pic->depth = devices[index].depth;
+ pic->palette = devices[index].v4l1_pal;
+ pic->hue = v4l2_get_control(devices[index].fd, V4L2_CID_HUE);
+ pic->colour = v4l2_get_control(devices[index].fd, V4L2_CID_SATURATION);
+ pic->contrast = v4l2_get_control(devices[index].fd, V4L2_CID_CONTRAST);
+ pic->whiteness = v4l2_get_control(devices[index].fd,
+ V4L2_CID_WHITENESS);
+ pic->brightness = v4l2_get_control(devices[index].fd,
+ V4L2_CID_BRIGHTNESS);
+
+ result = 0;
+ }
+ break;
+
+ case VIDIOCSWIN:
+ {
+ struct video_window *win = arg;
+
+ devices[index].flags |= V4L1_PIX_SIZE_TOUCHED;
+
+ result = v4l1_set_format(index, win->width, win->height, -1, 1);
+ if (result == 0) {
+ win->width = devices[index].width;
+ win->height = devices[index].height;
+ }
+ }
+ break;
+
+ case VIDIOCGWIN:
+ devices[index].flags |= V4L1_PIX_SIZE_TOUCHED;
+ result = syscall(SYS_ioctl, fd, request, arg);
+ break;
+
+ case VIDIOCGCHAN:
+ {
+ struct v4l2_input input2;
+ struct video_channel *chan = arg;
+
+ if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) &&
+ (devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) {
+ result = syscall(SYS_ioctl, fd, request, arg);
+ break;
+ }
+
+ /* Set some defaults */
+ chan->tuners = 0;
+ chan->flags = 0;
+ chan->type = VIDEO_TYPE_CAMERA;
+ chan->norm = 0;
+
+ /* In case of no ENUMSTD support, ignore the norm member of the
+ channel struct */
+ if (devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) {
+ input2.index = chan->channel;
+ result = v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2);
+ if (result == 0) {
+ snprintf(chan->name, sizeof(chan->name), "%s", (char*)input2.name);
+ if (input2.type == V4L2_INPUT_TYPE_TUNER) {
+ chan->tuners = 1;
+ chan->type = VIDEO_TYPE_TV;
+ chan->flags = VIDEO_VC_TUNER;
+ }
+ }
+ break;
+ }
+
+ /* No ENUMINPUT support, fake it (assume its a Camera in this case) */
+ if (chan->channel == 0) {
+ snprintf(chan->name, sizeof(chan->name), "Camera");
+ result = 0;
+ } else {
+ errno = EINVAL;
+ result = -1;
+ }
+ }
+ break;
+
+ case VIDIOCSCHAN:
+ {
+ struct video_channel *chan = arg;
+ if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) &&
+ (devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) {
+ result = syscall(SYS_ioctl, fd, request, arg);
+ break;
+ }
+ /* In case of no ENUMSTD support, ignore the norm member of the
+ channel struct */
+ if (devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) {
+ result = v4l2_ioctl(fd, VIDIOC_S_INPUT, &chan->channel);
+ break;
+ }
+ /* No ENUMINPUT support, fake it (assume its a Camera in this case) */
+ if (chan->channel == 0) {
+ result = 0;
+ } else {
+ errno = EINVAL;
+ result = -1;
+ }
+ }
+ break;
+
+ case VIDIOCGMBUF:
+ /* When VIDIOCGMBUF is done, we don't necessarrily know the format the
+ application wants yet (with some apps this is passed for the first
+ time through VIDIOCMCAPTURE), so we just create an anonymous mapping
+ that should be large enough to hold any sort of frame. Note this only
+ takes virtual memory, and does not use memory until actually used. */
+ {
+ int i;
+ struct video_mbuf *mbuf = arg;
+
+ mbuf->size = V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE;
+ mbuf->frames = V4L1_NO_FRAMES;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = i * V4L1_FRAME_BUF_SIZE;
+ }
+
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
+ devices[index].v4l1_frame_pointer = (void *)syscall(SYS_mmap2, NULL,
+ (size_t)mbuf->size,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
+ saved_err = errno;
+ V4L1_LOG_ERR("allocating v4l1 buffer: %s\n", strerror(errno));
+ errno = saved_err;
+ result = -1;
+ break;
+ }
+ V4L1_LOG("allocated v4l1 buffer @ %p\n",
+ devices[index].v4l1_frame_pointer);
+ }
+ result = 0;
+ }
+ break;
+
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap *map = arg;
+
+ devices[index].flags |= V4L1_PIX_FMT_TOUCHED |
+ V4L1_PIX_SIZE_TOUCHED;
+
+ result = v4l1_set_format(index, map->width, map->height,
+ map->format, 0);
+ }
+ break;
+
+ case VIDIOCSYNC:
+ {
+ int *frame_index = arg;
+
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED ||
+ *frame_index < 0 || *frame_index >= V4L1_NO_FRAMES) {
+ errno = EINVAL;
+ result = -1;
+ break;
+ }
+
+ result = v4l2_read(devices[index].fd,
+ devices[index].v4l1_frame_pointer +
+ *frame_index * V4L1_FRAME_BUF_SIZE,
+ V4L1_FRAME_BUF_SIZE);
+ result = (result > 0) ? 0:result;
+ }
+ break;
+
+ /* We are passing through v4l2 calls to libv4l2 for applications which are
+ using v4l2 through libv4l1 (possible with the v4l1compat.so wrapper).
+
+ So the application could be calling VIDIOC_S_FMT, in this case update
+ our own bookkeeping of the cam's format. Note that this really only is
+ relevant if an application is mixing and matching v4l1 and v4l2 calls,
+ which is crazy, but better safe then sorry. */
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *fmt2 = arg;
+
+ result = v4l2_ioctl(fd, request, arg);
+
+ if (result == 0 && fmt2->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (devices[index].v4l2_pixfmt != fmt2->fmt.pix.pixelformat) {
+ devices[index].v4l2_pixfmt = fmt2->fmt.pix.pixelformat;
+ devices[index].v4l1_pal =
+ pixelformat_to_palette(fmt2->fmt.pix.pixelformat);
+ }
+ devices[index].width = fmt2->fmt.pix.width;
+ devices[index].height = fmt2->fmt.pix.height;
+ }
+ }
+ break;
+
+ default:
+ /* Pass through libv4l2 for applications which are using v4l2 through
+ libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
+ result = v4l2_ioctl(fd, request, arg);
+ }
+
+ if (stream_locked)
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ saved_err = errno;
+ v4l1_log_ioctl(request, arg, result);
+ errno = saved_err;
+
+ return result;
+}
+
+
+ssize_t v4l1_read(int fd, void* buffer, size_t n)
+{
+ int index;
+ ssize_t result;
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_read, fd, buffer, n);
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+ result = v4l2_read(fd, buffer, n);
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ return result;
+}
+
+
+void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset)
+{
+ int index;
+ void *result;
+
+ /* Check if the mmap data matches our answer to VIDIOCGMBUF, if not
+ pass through libv4l2 for applications which are using v4l2 through
+ libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
+ if ((index = v4l1_get_index(fd)) == -1 || start || offset ||
+ length != (V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE))
+ return v4l2_mmap(start, length, prot, flags, fd, offset);
+
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ /* It could be that we get called with an mmap which seems to match what
+ we expect, but no VIDIOCGMBUF has been done yet, then it is certainly not
+ for us so pass it through */
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
+ result = v4l2_mmap(start, length, prot, flags, fd, offset);
+ goto leave;
+ }
+
+ devices[index].v4l1_frame_buf_map_count++;
+
+ V4L1_LOG("v4l1 buffer @ %p mapped by application\n",
+ devices[index].v4l1_frame_pointer);
+
+ result = devices[index].v4l1_frame_pointer;
+
+leave:
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ return result;
+}
+
+int v4l1_munmap(void *_start, size_t length)
+{
+ int index;
+ unsigned char *start = _start;
+
+ /* Is this memory ours? */
+ if (start != MAP_FAILED &&
+ length == (V4L1_FRAME_BUF_SIZE * V4L1_NO_FRAMES)) {
+ for (index = 0; index < devices_used; index++)
+ if (devices[index].fd != -1 &&
+ start == devices[index].v4l1_frame_pointer)
+ break;
+
+ if (index != devices_used) {
+ int unmapped = 0;
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ /* Redo our checks now that we have the lock, things may have changed */
+ if (start == devices[index].v4l1_frame_pointer) {
+ if (devices[index].v4l1_frame_buf_map_count > 0)
+ devices[index].v4l1_frame_buf_map_count--;
+
+ unmapped = 1;
+ }
+
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ if (unmapped) {
+ V4L1_LOG("v4l1 buffer munmap %p, %d\n", start, (int)length);
+ return 0;
+ }
+ }
+ }
+
+ V4L1_LOG("v4l1 unknown munmap %p, %d\n", start, (int)length);
+
+ /* If not pass through libv4l2 for applications which are using v4l2 through
+ libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
+ return v4l2_munmap(start, length);
+}
diff --git a/v4l2-apps/libv4l/libv4l1/log.c b/v4l2-apps/libv4l/libv4l1/log.c
new file mode 100644
index 000000000..9ff0cea46
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/log.c
@@ -0,0 +1,145 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/ioctl.h>
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <asm/types.h>
+/* end broken header workaround includes */
+#include <linux/videodev.h>
+#include "libv4l1-priv.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+FILE *v4l1_log_file = NULL;
+
+static const char *v4l1_ioctls[] = {
+ [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
+ [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
+ [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
+ [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
+ [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
+ [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
+ [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
+ [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
+ [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
+ [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
+ [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
+ [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
+ [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
+ [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
+ [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
+ [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
+ [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
+ [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
+ [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
+ [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
+ [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
+ [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
+ [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
+ [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
+ [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
+ [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
+ [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
+ [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
+ [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT",
+};
+
+void v4l1_log_ioctl(unsigned long int request, void *arg, int result)
+{
+ const char *ioctl_str = "unknown";
+ char buf[40];
+
+ if (!v4l1_log_file)
+ return;
+
+ /* Don't log v4l2 ioctl's as unknown we pass them to libv4l2 which will
+ log them for us */
+ if (_IOC_TYPE(request) == 'V')
+ return;
+
+ if (_IOC_TYPE(request) == 'v' && _IOC_NR(request) < ARRAY_SIZE(v4l1_ioctls))
+ ioctl_str = v4l1_ioctls[_IOC_NR(request)];
+ else {
+ snprintf(buf, sizeof(buf), "unknown request: %c %d\n",
+ (int)_IOC_TYPE(request), (int)_IOC_NR(request));
+ ioctl_str = buf;
+ }
+
+ fprintf(v4l1_log_file, "request == %s\n", ioctl_str);
+
+ switch(request)
+ {
+ case VIDIOCGCAP:fprintf(v4l1_log_file,"name %s\n",( (struct video_capability*)arg)->name );
+ fprintf(v4l1_log_file,"type %d\n",( (struct video_capability*)arg)->type );
+ fprintf(v4l1_log_file,"channels %d\n",( (struct video_capability*)arg)->channels );
+ fprintf(v4l1_log_file,"audios %d\n",( (struct video_capability*)arg)->audios );
+ fprintf(v4l1_log_file,"maxwidth %d\n",( (struct video_capability*)arg)->maxwidth );
+ fprintf(v4l1_log_file,"maxheight %d\n",( (struct video_capability*)arg)->maxheight );
+ fprintf(v4l1_log_file,"minwidth %d\n",( (struct video_capability*)arg)->minwidth );
+ fprintf(v4l1_log_file,"minheight %d\n",( (struct video_capability*)arg)->minheight );
+ break;
+ case VIDIOCGWIN:
+ case VIDIOCSWIN:
+ fprintf(v4l1_log_file,"width\t%u\n",
+ ((struct video_window *)arg)->width);
+ fprintf(v4l1_log_file,"height\t%u\n",
+ ((struct video_window *)arg)->height);
+ break;
+
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
+ fprintf(v4l1_log_file,"channel %d\n",( (struct video_channel*)arg)->channel );
+ fprintf(v4l1_log_file,"name %s\n",( (struct video_channel*)arg)->name );
+ break;
+
+ case VIDIOCGPICT:
+ case VIDIOCSPICT:
+ fprintf(v4l1_log_file,"brightness %d\n",( (int)((struct video_picture*)arg)->brightness) );
+ fprintf(v4l1_log_file,"hue %d\n",( (int)((struct video_picture*)arg)->hue) );
+ fprintf(v4l1_log_file,"colour %d\n",( (int)((struct video_picture*)arg)->colour) );
+ fprintf(v4l1_log_file,"contrast %d\n",( (int)((struct video_picture*)arg)->contrast) );
+ fprintf(v4l1_log_file,"whiteness %d\n",( (int)((struct video_picture*)arg)->whiteness) );
+ fprintf(v4l1_log_file,"depth %d\n",( (int)((struct video_picture*)arg)->depth) );
+ fprintf(v4l1_log_file,"palette %d\n",( (int)((struct video_picture*)arg)->palette) );
+ break;
+
+ case VIDIOCCAPTURE: fprintf(v4l1_log_file,"on/off? %d\n", *((int *)arg) );
+ break;
+
+ case VIDIOCSYNC: fprintf(v4l1_log_file,"sync %d\n", *((int *)arg) );
+ break;
+
+ case VIDIOCMCAPTURE:
+ fprintf(v4l1_log_file,"frame %u\n",( (struct video_mmap*)arg)->frame );
+ fprintf(v4l1_log_file,"width %d\n",( (struct video_mmap*)arg)->width );
+ fprintf(v4l1_log_file,"height %d\n",( (struct video_mmap*)arg)->height );
+ fprintf(v4l1_log_file,"format %u\n",( (struct video_mmap*)arg)->format );
+ break;
+
+ case VIDIOCGMBUF:
+ fprintf(v4l1_log_file,"size %d\n",( (struct video_mbuf*)arg)->size );
+ fprintf(v4l1_log_file,"frames %d\n",( (struct video_mbuf*)arg)->frames );
+ break;
+ }
+ fprintf(v4l1_log_file, "result == %d\n", result);
+ fflush(v4l1_log_file);
+}
diff --git a/v4l2-apps/libv4l/libv4l1/v4l1compat.c b/v4l2-apps/libv4l/libv4l1/v4l1compat.c
new file mode 100644
index 000000000..e4293d2f9
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/v4l1compat.c
@@ -0,0 +1,127 @@
+/*
+# open/close/ioctl/mmap/munmap library call wrapper doing v4l1 api emulation
+# for v4l2 devices
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define _LARGEFILE64_SOURCE 1
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <libv4l1.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+/* Check that open/read/mmap is not a define */
+#if defined open || defined read || defined mmap
+#error open/read/mmap is a prepocessor macro !!
+#endif
+
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
+{
+ int fd;
+
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = v4l1_open(file, oflag, mode);
+
+ va_end(ap);
+ } else
+ fd = v4l1_open(file, oflag);
+
+ return fd;
+}
+
+LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...)
+{
+ int fd;
+
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = v4l1_open(file, oflag | O_LARGEFILE, mode);
+
+ va_end(ap);
+ } else
+ fd = v4l1_open(file, oflag | O_LARGEFILE);
+
+ return fd;
+}
+
+LIBV4L_PUBLIC int close(int fd) {
+ return v4l1_close(fd);
+}
+
+LIBV4L_PUBLIC int dup(int fd)
+{
+ return v4l1_dup(fd);
+}
+
+LIBV4L_PUBLIC int ioctl (int fd, unsigned long int request, ...)
+{
+ void *arg;
+ va_list ap;
+
+ va_start (ap, request);
+ arg = va_arg (ap, void *);
+ va_end (ap);
+
+ return v4l1_ioctl (fd, request, arg);
+}
+
+LIBV4L_PUBLIC ssize_t read(int fd, void* buffer, size_t n)
+{
+ return v4l1_read (fd, buffer, n);
+}
+
+LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off_t offset)
+{
+ return v4l1_mmap(start, length, prot, flags, fd, offset);
+}
+
+LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset)
+{
+ return v4l1_mmap(start, length, prot, flags, fd, offset);
+}
+
+LIBV4L_PUBLIC int munmap(void *start, size_t length)
+{
+ return v4l1_munmap(start, length);
+}
+
diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile
new file mode 100644
index 000000000..648d27c0c
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l2/Makefile
@@ -0,0 +1,82 @@
+override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
+
+CFLAGS := -g -O1
+CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
+
+LIBS = -lpthread
+
+V4L2_OBJS = libv4l2.o log.o
+V4L2CONVERT = v4l2convert.so
+V4L2CONVERT_O = v4l2convert.o libv4l2.so
+TARGETS = $(V4L2_LIB) libv4l2.pc
+INCLUDES = ../include/libv4l2.h
+
+ifeq ($(LINKTYPE),static)
+V4L2_LIB = libv4l2.a
+else
+V4L2_LIB = libv4l2.so
+V4L2_OBJS += ../libv4lconvert/libv4lconvert.so
+TARGETS += $(V4L2CONVERT)
+override CPPFLAGS += -fPIC
+endif
+
+ifeq ($(LIB_RELEASE),)
+LIB_RELEASE = 0
+endif
+
+ifeq ($(PREFIX),)
+PREFIX = /usr/local
+endif
+
+ifeq ($(LIBDIR),)
+LIBDIR = $(PREFIX)/lib
+endif
+
+all: $(TARGETS)
+
+$(V4L2_LIB): $(V4L2_OBJS)
+
+$(V4L2CONVERT): $(V4L2CONVERT_O) $(V4L2_LIB)
+
+libv4l2.pc:
+ @echo prefix=$(PREFIX) > libv4l2.pc
+ @echo libdir=$(LIBDIR) >> libv4l2.pc
+ @echo >> libv4l2.pc
+ @echo 'Name: libv4l2' >> libv4l2.pc
+ @echo 'Description: v4l2 device access library' >> libv4l2.pc
+ @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4l2.pc
+ @echo 'Requires: libv4lconvert' >> libv4l2.pc
+ @echo 'Libs: -L$${libdir} -lv4l2' >> libv4l2.pc
+ @echo 'Libs.private: -lpthread' >> libv4l2.pc
+ @echo 'Cflags: -I$${prefix}/include' >> libv4l2.pc
+
+install: all
+ mkdir -p $(DESTDIR)$(PREFIX)/include
+ install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include
+ifeq ($(LINKTYPE),static)
+ mkdir -p $(DESTDIR)$(LIBDIR)
+ install -m 644 $(V4L2_LIB) $(DESTDIR)$(LIBDIR)
+else
+ mkdir -p $(DESTDIR)$(LIBDIR)/libv4l
+ install -m 755 $(V4L2_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR)
+ cd $(DESTDIR)$(LIBDIR) && \
+ ln -f -s $(V4L2_LIB).$(LIB_RELEASE) $(V4L2_LIB)
+ install -m 755 $(V4L2CONVERT).$(LIB_RELEASE) \
+ $(DESTDIR)$(LIBDIR)/libv4l/$(V4L2CONVERT)
+endif
+ mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
+ install -m 644 libv4l2.pc $(DESTDIR)$(LIBDIR)/pkgconfig
+
+clean::
+ rm -f *.a *.so* *.o *.d libv4l2.pc log *~
+
+%.o: %.c
+ $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+%.so:
+ $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS)
+ ln -f -s $@.$(LIB_RELEASE) $@
+
+%.a:
+ $(AR) cqs $@ $^
+
diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h
new file mode 100644
index 000000000..8724832e1
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h
@@ -0,0 +1,95 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4L2_PRIV_H
+#define __LIBV4L2_PRIV_H
+
+#include <stdio.h>
+#include <pthread.h>
+#include <libv4lconvert.h> /* includes videodev2.h for us */
+
+/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */
+#ifdef __NR_mmap2
+#define SYS_mmap2 __NR_mmap2
+#define MMAP2_PAGE_SHIFT 12
+#else
+#define SYS_mmap2 SYS_mmap
+#define MMAP2_PAGE_SHIFT 0
+#endif
+
+#define V4L2_MAX_DEVICES 16
+/* Warning when making this larger the frame_queued and frame_mapped members of
+ the v4l2_dev_info struct can no longer be a bitfield, so the code needs to
+ be adjusted! */
+#define V4L2_MAX_NO_FRAMES 32
+#define V4L2_DEFAULT_NREADBUFFERS 4
+#define V4L2_FRAME_BUF_SIZE (4096 * 4096)
+
+#define V4L2_LOG_ERR(...) \
+ do { \
+ if (v4l2_log_file) { \
+ fprintf(v4l2_log_file, "libv4l2: error " __VA_ARGS__); \
+ fflush(v4l2_log_file); \
+ } else \
+ fprintf(stderr, "libv4l2: error " __VA_ARGS__); \
+ } while(0)
+
+#define V4L2_LOG_WARN(...) \
+ do { \
+ if (v4l2_log_file) { \
+ fprintf(v4l2_log_file, "libv4l2: warning " __VA_ARGS__); \
+ fflush(v4l2_log_file); \
+ } else \
+ fprintf(stderr, "libv4l2: warning " __VA_ARGS__); \
+ } while(0)
+
+#define V4L2_LOG(...) \
+ do { \
+ if (v4l2_log_file) { \
+ fprintf(v4l2_log_file, "libv4l2: " __VA_ARGS__); \
+ fflush(v4l2_log_file); \
+ } \
+ } while(0)
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+struct v4l2_dev_info {
+ int fd;
+ int flags;
+ int open_count;
+ /* actually format of the cam */
+ struct v4l2_format src_fmt;
+ /* fmt as seen by the application (iow after conversion) */
+ struct v4l2_format dest_fmt;
+ pthread_mutex_t stream_lock;
+ unsigned int no_frames;
+ unsigned int nreadbuffers;
+ struct v4lconvert_data *convert;
+ unsigned char *convert_mmap_buf;
+ /* Frame bookkeeping is only done when in read or mmap-conversion mode */
+ unsigned char *frame_pointers[V4L2_MAX_NO_FRAMES];
+ int frame_sizes[V4L2_MAX_NO_FRAMES];
+ int frame_queued; /* 1 status bit per frame */
+ /* mapping tracking of our fake (converting mmap) frame buffers */
+ unsigned char frame_map_count[V4L2_MAX_NO_FRAMES];
+};
+
+/* From log.c */
+void v4l2_log_ioctl(unsigned long int request, void *arg, int result);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c
new file mode 100644
index 000000000..b4a10afac
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c
@@ -0,0 +1,1145 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* MAKING CHANGES TO THIS FILE?? READ THIS FIRST!!!
+
+ This file implements libv4l2, which offers v4l2_ prefixed versions of
+ open/close/etc. The API is 100% the same as directly opening /dev/videoX
+ using regular open/close/etc, the big difference is that format conversion
+ is done if necessary when capturing. That is if you (try to) set a capture
+ format which is not supported by the cam, but is supported by libv4lconvert,
+ then the try_fmt / set_fmt will succeed as if the cam supports the format
+ and on dqbuf / read the data will be converted for you and returned in
+ the request format.
+
+ Important note to people making changes to this file: All functions
+ (v4l2_close, v4l2_ioctl, etc.) are designed to function as their regular
+ counterpart when they get passed a fd that is not "registered" by libv4l2,
+ there are 2 reasons for this:
+ 1) This allows us to get completely out of the way when dealing with non
+ capture devices.
+ 2) libv4l2 is the base of the v4l2convert.so wrapper lib, which is a .so
+ which can be LD_PRELOAD-ed and the overrules the libc's open/close/etc,
+ and when opening /dev/videoX or /dev/v4l/ calls v4l2_open. Because we
+ behave as the regular counterpart when the fd is not known (instead of say
+ throwing an error), v4l2convert.so can simply call the v4l2_ prefixed
+ function for all wrapped functions (except for v4l2_open which will fail
+ when not called on a v4l2 device). This way the wrapper does not have to
+ keep track of which fd's are being handled by libv4l2, as libv4l2 already
+ keeps track of this itself.
+
+ This also means that libv4l2 may not use any of the regular functions
+ it mimics, as for example open could be a symbol in v4l2convert.so, which
+ in turn will call v4l2_open, so therefor v4l2_open (for example) may not
+ use the regular open()!
+
+ Another important note: libv4l2 does conversion for capture usage only, if
+ any calls are made which are passed a v4l2_buffer or v4l2_format with a
+ v4l2_buf_type which is different from V4L2_BUF_TYPE_VIDEO_CAPTURE, then
+ the v4l2_ methods behave exactly the same as their regular counterparts.
+ When modifications are made, one should be carefull that this behavior is
+ preserved.
+*/
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include "libv4l2.h"
+#include "libv4l2-priv.h"
+
+/* Note these flags are stored together with the flags passed to v4l2_fd_open()
+ in v4l2_dev_info's flags member, so care should be taken that the do not
+ use the same bits! */
+#define V4L2_STREAMON 0x0100
+#define V4L2_BUFFERS_REQUESTED_BY_READ 0x0200
+#define V4L2_STREAM_CONTROLLED_BY_READ 0x0400
+#define V4L2_SUPPORTS_READ 0x0800
+
+#define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u
+
+static pthread_mutex_t v4l2_open_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct v4l2_dev_info devices[V4L2_MAX_DEVICES] = { { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }};
+static int devices_used = 0;
+
+
+static int v4l2_request_read_buffers(int index)
+{
+ int result;
+ struct v4l2_requestbuffers req;
+
+ /* Note we re-request the buffers if they are already requested as the format
+ and thus the needed buffersize may have changed. */
+ req.count = (devices[index].no_frames)? devices[index].no_frames:
+ devices[index].nreadbuffers;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+ if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req)) < 0){
+ int saved_err = errno;
+ V4L2_LOG_ERR("requesting %u buffers: %s\n", req.count, strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ if (!devices[index].no_frames && req.count)
+ devices[index].flags |= V4L2_BUFFERS_REQUESTED_BY_READ;
+
+ devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES);
+ return 0;
+}
+
+static void v4l2_unrequest_read_buffers(int index)
+{
+ struct v4l2_requestbuffers req;
+
+ if (!(devices[index].flags & V4L2_BUFFERS_REQUESTED_BY_READ) ||
+ devices[index].no_frames == 0)
+ return;
+
+ /* (Un)Request buffers, note not all driver support this, and those
+ who do not support it don't need it. */
+ req.count = 0;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+ if(syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req) < 0)
+ return;
+
+ devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES);
+ if (devices[index].no_frames == 0)
+ devices[index].flags &= ~V4L2_BUFFERS_REQUESTED_BY_READ;
+}
+
+static int v4l2_map_buffers(int index)
+{
+ int result = 0;
+ unsigned int i;
+ struct v4l2_buffer buf;
+
+ for (i = 0; i < devices[index].no_frames; i++) {
+ if (devices[index].frame_pointers[i] != MAP_FAILED)
+ continue;
+
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, &buf);
+ if (result) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno));
+ errno = saved_err;
+ break;
+ }
+
+ devices[index].frame_pointers[i] = (void *)syscall(SYS_mmap2, NULL,
+ (size_t)buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, devices[index].fd,
+ (__off_t)(buf.m.offset >> MMAP2_PAGE_SHIFT));
+ if (devices[index].frame_pointers[i] == MAP_FAILED) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("mmapping buffer %u: %s\n", i, strerror(errno));
+ errno = saved_err;
+ result = -1;
+ break;
+ }
+ V4L2_LOG("mapped buffer %u at %p\n", i,
+ devices[index].frame_pointers[i]);
+
+ devices[index].frame_sizes[i] = buf.length;
+ }
+
+ return result;
+}
+
+static void v4l2_unmap_buffers(int index)
+{
+ unsigned int i;
+
+ /* unmap the buffers */
+ for (i = 0; i < devices[index].no_frames; i++) {
+ if (devices[index].frame_pointers[i] != MAP_FAILED) {
+ syscall(SYS_munmap, devices[index].frame_pointers[i],
+ devices[index].frame_sizes[i]);
+ devices[index].frame_pointers[i] = MAP_FAILED;
+ V4L2_LOG("unmapped buffer %u\n", i);
+ }
+ }
+}
+
+static int v4l2_streamon(int index)
+{
+ int result;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (!(devices[index].flags & V4L2_STREAMON)) {
+ if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_STREAMON,
+ &type))) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("turning on stream: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+ devices[index].flags |= V4L2_STREAMON;
+ }
+
+ return 0;
+}
+
+static int v4l2_streamoff(int index)
+{
+ int result;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (devices[index].flags & V4L2_STREAMON) {
+ if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_STREAMOFF,
+ &type))) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("turning off stream: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+ devices[index].flags &= ~V4L2_STREAMON;
+
+ /* Stream off also unqueues all our buffers! */
+ devices[index].frame_queued = 0;
+ }
+
+ return 0;
+}
+
+static int v4l2_queue_read_buffer(int index, int buffer_index)
+{
+ int result;
+ struct v4l2_buffer buf;
+
+ if (devices[index].frame_queued & (1 << buffer_index))
+ return 0;
+
+ memset(&buf, 0, sizeof(buf));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = buffer_index;
+ if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, &buf))) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("queuing buf %d: %s\n", buffer_index, strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ devices[index].frame_queued |= 1 << buffer_index;
+ return 0;
+}
+
+static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf,
+ unsigned char *dest, int dest_size)
+{
+ const int max_tries = 10;
+ int result, tries = max_tries;
+
+ /* Make sure we have the real v4l2 buffers mapped */
+ if ((result = v4l2_map_buffers(index)))
+ return result;
+
+ do {
+ if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf))) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ devices[index].frame_queued &= ~(1 << buf->index);
+
+ result = v4lconvert_convert(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt,
+ devices[index].frame_pointers[buf->index],
+ buf->bytesused, dest ? dest : (devices[index].convert_mmap_buf +
+ buf->index * V4L2_FRAME_BUF_SIZE), dest_size);
+
+ if (result < 0) {
+ int saved_err = errno;
+
+ if(errno == EAGAIN)
+ V4L2_LOG("warning error while converting frame data: %s\n",
+ v4lconvert_get_error_message(devices[index].convert));
+ else
+ V4L2_LOG_ERR("converting / decoding frame data: %s\n",
+ v4lconvert_get_error_message(devices[index].convert));
+
+ v4l2_queue_read_buffer(index, buf->index);
+ errno = saved_err;
+ }
+ tries--;
+ } while (result < 0 && errno == EAGAIN && tries);
+
+ if (result < 0 && errno == EAGAIN) {
+ V4L2_LOG_ERR("got %d consecutive frame decode errors, last error: %s\n",
+ max_tries, v4lconvert_get_error_message(devices[index].convert));
+ }
+
+ return result;
+}
+
+static int v4l2_queue_read_buffers(int index)
+{
+ unsigned int i;
+ int last_error = EIO, queued = 0;
+
+ for (i = 0; i < devices[index].no_frames; i++) {
+ /* Don't queue unmapped buffers (should never happen) */
+ if (devices[index].frame_pointers[i] != MAP_FAILED) {
+ if (v4l2_queue_read_buffer(index, i)) {
+ last_error = errno;
+ continue;
+ }
+ queued++;
+ }
+ }
+
+ if (!queued) {
+ errno = last_error;
+ return -1;
+ }
+ return 0;
+}
+
+static int v4l2_activate_read_stream(int index)
+{
+ int result;
+
+ if ((result = v4l2_request_read_buffers(index)))
+ return result;
+
+ if ((result = v4l2_map_buffers(index)))
+ return result;
+
+ if ((result = v4l2_queue_read_buffers(index)))
+ return result;
+
+ devices[index].flags |= V4L2_STREAM_CONTROLLED_BY_READ;
+
+ return result = v4l2_streamon(index);
+}
+
+static int v4l2_deactivate_read_stream(int index)
+{
+ int result;
+
+ if ((result = v4l2_streamoff(index)))
+ return result;
+
+ /* No need to unqueue our buffers, streamoff does that for us */
+
+ v4l2_unmap_buffers(index);
+
+ v4l2_unrequest_read_buffers(index);
+
+ devices[index].flags &= ~V4L2_STREAM_CONTROLLED_BY_READ;
+
+ return 0;
+}
+
+static int v4l2_buffers_mapped(int index)
+{
+ unsigned int i;
+
+ if (devices[index].src_fmt.fmt.pix.pixelformat ==
+ devices[index].dest_fmt.fmt.pix.pixelformat) {
+ /* Normal (no conversion) mode */
+ struct v4l2_buffer buf;
+
+ for (i = 0; i < devices[index].no_frames; i++) {
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+ if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, &buf)) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno));
+ errno = saved_err;
+ break;
+ }
+ if (buf.flags & V4L2_BUF_FLAG_MAPPED)
+ break;
+ }
+ } else {
+ /* Conversion mode */
+ for (i = 0; i < devices[index].no_frames; i++)
+ if (devices[index].frame_map_count[i])
+ break;
+ }
+
+ if (i != devices[index].no_frames)
+ V4L2_LOG("v4l2_buffers_mapped(): buffers still mapped\n");
+
+ return i != devices[index].no_frames;
+}
+
+
+int v4l2_open (const char *file, int oflag, ...)
+{
+ int fd;
+
+ /* original open code */
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = syscall(SYS_open, file, oflag, mode);
+
+ va_end(ap);
+ }
+ else
+ fd = syscall(SYS_open, file, oflag);
+ /* end of original open code */
+
+ if (fd == -1)
+ return fd;
+
+ if (v4l2_fd_open(fd, 0) == -1) {
+ int saved_err = errno;
+ syscall(SYS_close, fd);
+ errno = saved_err;
+ return -1;
+ }
+
+ return fd;
+}
+
+int v4l2_fd_open(int fd, int v4l2_flags)
+{
+ int i, index;
+ char *lfname;
+ struct v4l2_capability cap;
+ struct v4l2_format fmt;
+ struct v4lconvert_data *convert;
+
+ /* If no log file was set by the app, see if one was specified through the
+ environment */
+ if (!v4l2_log_file && (lfname = getenv("LIBV4L2_LOG_FILENAME")))
+ v4l2_log_file = fopen(lfname, "w");
+
+ /* check that this is an v4l2 device */
+ if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap)) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno));
+ errno = saved_err;
+ return -1;
+ }
+
+ /* we only add functionality for video capture devices, and we do not
+ handle devices which don't do mmap */
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
+ !(cap.capabilities & V4L2_CAP_STREAMING))
+ return fd;
+
+ /* Get current cam format */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt)) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ return -1;
+ }
+
+ /* init libv4lconvert */
+ if (!(convert = v4lconvert_create(fd)))
+ return -1;
+
+ /* So we have a v4l2 capture device, register it in our devices array */
+ pthread_mutex_lock(&v4l2_open_mutex);
+ for (index = 0; index < V4L2_MAX_DEVICES; index++)
+ if(devices[index].fd == -1) {
+ devices[index].fd = fd;
+ break;
+ }
+ pthread_mutex_unlock(&v4l2_open_mutex);
+
+ if (index == V4L2_MAX_DEVICES) {
+ V4L2_LOG_ERR("attempting to open more then %d video devices\n",
+ V4L2_MAX_DEVICES);
+ errno = EBUSY;
+ return -1;
+ }
+
+ devices[index].flags = v4l2_flags;
+ if (cap.capabilities & V4L2_CAP_READWRITE)
+ devices[index].flags |= V4L2_SUPPORTS_READ;
+ devices[index].open_count = 1;
+ devices[index].src_fmt = fmt;
+ devices[index].dest_fmt = fmt;
+
+ pthread_mutex_init(&devices[index].stream_lock, NULL);
+
+ devices[index].no_frames = 0;
+ devices[index].nreadbuffers = V4L2_DEFAULT_NREADBUFFERS;
+ devices[index].convert = convert;
+ devices[index].convert_mmap_buf = MAP_FAILED;
+ for (i = 0; i < V4L2_MAX_NO_FRAMES; i++) {
+ devices[index].frame_pointers[i] = MAP_FAILED;
+ devices[index].frame_map_count[i] = 0;
+ }
+ devices[index].frame_queued = 0;
+
+ if (index >= devices_used)
+ devices_used = index + 1;
+
+ V4L2_LOG("open: %d\n", fd);
+
+ return fd;
+}
+
+/* Is this an fd for which we are emulating v4l1 ? */
+static int v4l2_get_index(int fd)
+{
+ int index;
+
+ /* We never handle fd -1 */
+ if (fd == -1)
+ return -1;
+
+ for (index = 0; index < devices_used; index++)
+ if (devices[index].fd == fd)
+ break;
+
+ if (index == devices_used)
+ return -1;
+
+ return index;
+}
+
+
+int v4l2_close(int fd)
+{
+ int index, result;
+
+ if ((index = v4l2_get_index(fd)) == -1)
+ return syscall(SYS_close, fd);
+
+ /* Abuse stream_lock to stop 2 closes from racing and trying to free the
+ resources twice */
+ pthread_mutex_lock(&devices[index].stream_lock);
+ devices[index].open_count--;
+ result = devices[index].open_count != 0;
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ if (result)
+ return 0;
+
+ /* Free resources */
+ v4l2_unmap_buffers(index);
+ v4lconvert_destroy(devices[index].convert);
+ if (devices[index].convert_mmap_buf != MAP_FAILED) {
+ if (v4l2_buffers_mapped(index))
+ V4L2_LOG_WARN("v4l2 mmap buffers still mapped on close()\n");
+ else
+ syscall(SYS_munmap, devices[index].convert_mmap_buf,
+ devices[index].no_frames * V4L2_FRAME_BUF_SIZE);
+ devices[index].convert_mmap_buf = MAP_FAILED;
+ }
+
+ /* Remove the fd from our list of managed fds before closing it, because as
+ soon as we've done the actual close the fd maybe returned by an open in
+ another thread and we don't want to intercept calls to this new fd. */
+ devices[index].fd = -1;
+
+ /* Since we've marked the fd as no longer used, and freed the resources,
+ redo the close in case it was interrupted */
+ do {
+ result = syscall(SYS_close, fd);
+ } while (result == -1 && errno == EINTR);
+
+ V4L2_LOG("close: %d\n", fd);
+
+ return result;
+}
+
+int v4l2_dup(int fd)
+{
+ int index;
+
+ if ((index = v4l2_get_index(fd)) == -1)
+ return syscall(SYS_dup, fd);
+
+ devices[index].open_count++;
+
+ return fd;
+}
+
+static int v4l2_check_buffer_change_ok(int index)
+{
+ v4l2_unmap_buffers(index);
+
+ /* Check if the app itself still is using the stream */
+ if (v4l2_buffers_mapped(index) ||
+ (!(devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) &&
+ ((devices[index].flags & V4L2_STREAMON) ||
+ devices[index].frame_queued))) {
+ V4L2_LOG("v4l2_check_buffer_change_ok(): stream busy\n");
+ errno = EBUSY;
+ return -1;
+ }
+
+ /* We may change from convert to non conversion mode and
+ v4l2_unrequest_read_buffers may change the no_frames, so free the
+ convert mmap buffer */
+ syscall(SYS_munmap, devices[index].convert_mmap_buf,
+ devices[index].no_frames * V4L2_FRAME_BUF_SIZE);
+ devices[index].convert_mmap_buf = MAP_FAILED;
+
+ if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) {
+ V4L2_LOG("deactivating read-stream for settings change\n");
+ return v4l2_deactivate_read_stream(index);
+ }
+
+ return 0;
+}
+
+int v4l2_ioctl (int fd, unsigned long int request, ...)
+{
+ void *arg;
+ va_list ap;
+ int result, converting, index, saved_err;
+ int is_capture_request = 0, stream_needs_locking = 0;
+
+ va_start (ap, request);
+ arg = va_arg (ap, void *);
+ va_end (ap);
+
+ if ((index = v4l2_get_index(fd)) == -1)
+ return syscall(SYS_ioctl, fd, request, arg);
+
+ /* Appearantly the kernel and / or glibc ignore the 32 most significant bits
+ when long = 64 bits, and some applications pass an int holding the req to
+ ioctl, causing it to get sign extended, depending upon this behavior */
+ request = (unsigned int)request;
+
+ /* Is this a capture request and do we need to take the stream lock? */
+ switch (request) {
+ case VIDIOC_QUERYCAP:
+ is_capture_request = 1;
+ break;
+ case VIDIOC_ENUM_FMT:
+ if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION))
+ is_capture_request = 1;
+ break;
+ case VIDIOC_ENUM_FRAMESIZES:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
+ if (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION)
+ is_capture_request = 1;
+ break;
+ case VIDIOC_TRY_FMT:
+ if (((struct v4l2_format *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ is_capture_request = 1;
+ break;
+ case VIDIOC_S_FMT:
+ case VIDIOC_G_FMT:
+ if (((struct v4l2_format *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ is_capture_request = 1;
+ stream_needs_locking = 1;
+ }
+ break;
+ case VIDIOC_REQBUFS:
+ if (((struct v4l2_requestbuffers *)arg)->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ is_capture_request = 1;
+ stream_needs_locking = 1;
+ }
+ break;
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+ if (((struct v4l2_buffer *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ is_capture_request = 1;
+ stream_needs_locking = 1;
+ }
+ break;
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ if (*((enum v4l2_buf_type *)arg) == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ is_capture_request = 1;
+ stream_needs_locking = 1;
+ }
+ }
+
+ if (!is_capture_request) {
+ result = syscall(SYS_ioctl, fd, request, arg);
+ saved_err = errno;
+ v4l2_log_ioctl(request, arg, result);
+ errno = saved_err;
+ return result;
+ }
+
+
+ if (stream_needs_locking)
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ converting = v4lconvert_needs_conversion(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt);
+
+ switch (request) {
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYCAP, cap);
+ if (result == 0)
+ /* We always support read() as we fake it using mmap mode */
+ cap->capabilities |= V4L2_CAP_READWRITE;
+ }
+ break;
+
+ case VIDIOC_ENUM_FMT:
+ result = v4lconvert_enum_fmt(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_ENUM_FRAMESIZES:
+ result = v4lconvert_enum_framesizes(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_ENUM_FRAMEINTERVALS:
+ result = v4lconvert_enum_frameintervals(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_TRY_FMT:
+ result = v4lconvert_try_format(devices[index].convert, arg, NULL);
+ break;
+
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format src_fmt, *dest_fmt = arg;
+
+ if (!memcmp(&devices[index].dest_fmt, dest_fmt, sizeof(*dest_fmt))) {
+ result = 0;
+ break;
+ }
+
+ if (devices[index].flags & V4L2_DISABLE_CONVERSION) {
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT,
+ dest_fmt);
+ src_fmt = *dest_fmt;
+ } else {
+ result = v4lconvert_try_format(devices[index].convert, dest_fmt,
+ &src_fmt);
+ }
+
+ if (result)
+ break;
+
+ if (src_fmt.fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat &&
+ v4l2_log_file) {
+ int pixfmt = src_fmt.fmt.pix.pixelformat;
+
+ fprintf(v4l2_log_file, "VIDIOC_S_FMT converting from: %c%c%c%c\n",
+ pixfmt & 0xff,
+ (pixfmt >> 8) & 0xff,
+ (pixfmt >> 16) & 0xff,
+ pixfmt >> 24);
+ }
+
+ /* Maybe after try format has adjusted width/height etc, to whats
+ available nothing has changed (on the cam side) ? */
+ if (!memcmp(&devices[index].src_fmt, &src_fmt, sizeof(src_fmt))) {
+ devices[index].dest_fmt = *dest_fmt;
+ result = 0;
+ break;
+ }
+
+ if ((result = v4l2_check_buffer_change_ok(index)))
+ break;
+
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_S_FMT, &src_fmt);
+ if (result) {
+ saved_err = errno;
+ V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno));
+ /* Report to the app dest_fmt has not changed */
+ *dest_fmt = devices[index].dest_fmt;
+ errno = saved_err;
+ break;
+ }
+
+ devices[index].src_fmt = src_fmt;
+ devices[index].dest_fmt = *dest_fmt;
+ }
+ break;
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format* fmt = arg;
+
+ *fmt = devices[index].dest_fmt;
+ result = 0;
+ }
+ break;
+
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *req = arg;
+
+ /* IMPROVEME (maybe?) add support for userptr's? */
+ if (req->memory != V4L2_MEMORY_MMAP) {
+ errno = EINVAL;
+ result = -1;
+ break;
+ }
+
+ if ((result = v4l2_check_buffer_change_ok(index)))
+ break;
+
+ /* No more buffers then we can manage please */
+ if (req->count > V4L2_MAX_NO_FRAMES)
+ req->count = V4L2_MAX_NO_FRAMES;
+
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, req);
+ if (result < 0)
+ break;
+ result = 0; /* some drivers return the number of buffers on success */
+
+ devices[index].no_frames = MIN(req->count, V4L2_MAX_NO_FRAMES);
+ devices[index].flags &= ~V4L2_BUFFERS_REQUESTED_BY_READ;
+ }
+ break;
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+
+ if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ)
+ if ((result = v4l2_deactivate_read_stream(index)))
+ break;
+
+ /* Do a real query even when converting to let the driver fill in
+ things like buf->field */
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, buf);
+ if (result || !converting)
+ break;
+
+ buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
+ buf->length = V4L2_FRAME_BUF_SIZE;
+ if (devices[index].frame_map_count[buf->index])
+ buf->flags |= V4L2_BUF_FLAG_MAPPED;
+ else
+ buf->flags &= ~V4L2_BUF_FLAG_MAPPED;
+ }
+ break;
+
+ case VIDIOC_QBUF:
+ if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ)
+ if ((result = v4l2_deactivate_read_stream(index)))
+ break;
+
+ /* With some drivers the buffers must be mapped before queuing */
+ if (converting)
+ if ((result = v4l2_map_buffers(index)))
+ break;
+
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, arg);
+ break;
+
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+
+ if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ)
+ if ((result = v4l2_deactivate_read_stream(index)))
+ break;
+
+ if (!converting) {
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf);
+ if (result) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+ break;
+ }
+
+ /* An application can do a DQBUF before mmap-ing in the buffer,
+ but we need the buffer _now_ to write our converted data
+ to it! */
+ if (devices[index].convert_mmap_buf == MAP_FAILED) {
+ devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2,
+ (size_t)(
+ devices[index].no_frames *
+ V4L2_FRAME_BUF_SIZE),
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE,
+ -1, 0);
+ if (devices[index].convert_mmap_buf == MAP_FAILED) {
+ saved_err = errno;
+ V4L2_LOG_ERR("allocating conversion buffer\n");
+ errno = saved_err;
+ result = -1;
+ break;
+ }
+ }
+
+ result = v4l2_dequeue_and_convert(index, buf, 0, V4L2_FRAME_BUF_SIZE);
+ if (result < 0)
+ break;
+
+ buf->bytesused = result;
+ buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
+ buf->length = V4L2_FRAME_BUF_SIZE;
+ if (devices[index].frame_map_count[buf->index])
+ buf->flags |= V4L2_BUF_FLAG_MAPPED;
+ else
+ buf->flags &= ~V4L2_BUF_FLAG_MAPPED;
+
+ result = 0;
+ }
+ break;
+
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ)
+ if ((result = v4l2_deactivate_read_stream(index)))
+ break;
+
+ if (request == VIDIOC_STREAMON)
+ result = v4l2_streamon(index);
+ else
+ result = v4l2_streamoff(index);
+ break;
+
+ default:
+ result = syscall(SYS_ioctl, fd, request, arg);
+ }
+
+ if (stream_needs_locking)
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ saved_err = errno;
+ v4l2_log_ioctl(request, arg, result);
+ errno = saved_err;
+
+ return result;
+}
+
+
+ssize_t v4l2_read (int fd, void* dest, size_t n)
+{
+ ssize_t result;
+ int index;
+ struct v4l2_buffer buf;
+
+ if ((index = v4l2_get_index(fd)) == -1)
+ return syscall(SYS_read, fd, dest, n);
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ /* When not converting and the device supports read let the kernel handle
+ it */
+ if ((devices[index].flags & V4L2_SUPPORTS_READ) &&
+ !v4lconvert_needs_conversion(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt)) {
+ result = syscall(SYS_read, fd, dest, n);
+ goto leave;
+ }
+
+ if (!(devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ)) {
+ if ((devices[index].flags & V4L2_STREAMON) ||
+ devices[index].frame_queued) {
+ errno = EBUSY;
+ result = -1;
+ goto leave;
+ }
+ if ((result = v4l2_activate_read_stream(index)))
+ goto leave;
+ }
+
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ result = v4l2_dequeue_and_convert(index, &buf, dest, n);
+
+ if (result >= 0)
+ v4l2_queue_read_buffer(index, buf.index);
+
+leave:
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ return result;
+}
+
+void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset)
+{
+ int index;
+ unsigned int buffer_index;
+ void *result;
+
+ if ((index = v4l2_get_index(fd)) == -1 ||
+ /* Check if the mmap data matches our answer to QUERY_BUF, if it doesn't
+ let the kernel handle it (to allow for mmap based non capture use) */
+ start || length != V4L2_FRAME_BUF_SIZE ||
+ ((unsigned int)offset & ~0xFFu) != V4L2_MMAP_OFFSET_MAGIC) {
+ if (index != -1)
+ V4L2_LOG("Passing mmap(%p, %d, ..., %x, through to the driver\n",
+ start, (int)length, (int)offset);
+
+ if (offset & ((1 << MMAP2_PAGE_SHIFT) - 1)) {
+ errno = EINVAL;
+ return MAP_FAILED;
+ }
+
+ return (void *)syscall(SYS_mmap2, start, length, prot, flags, fd,
+ (__off_t)(offset >> MMAP2_PAGE_SHIFT));
+ }
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ buffer_index = offset & 0xff;
+ if (buffer_index >= devices[index].no_frames ||
+ /* Got magic offset and not converting ?? */
+ !v4lconvert_needs_conversion(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt)) {
+ errno = EINVAL;
+ result = MAP_FAILED;
+ goto leave;
+ }
+
+ if (devices[index].convert_mmap_buf == MAP_FAILED) {
+ devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, NULL,
+ (size_t)(
+ devices[index].no_frames *
+ V4L2_FRAME_BUF_SIZE),
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE,
+ -1, 0);
+ if (devices[index].convert_mmap_buf == MAP_FAILED) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("allocating conversion buffer\n");
+ errno = saved_err;
+ result = MAP_FAILED;
+ goto leave;
+ }
+ }
+
+ devices[index].frame_map_count[buffer_index]++;
+
+ result = devices[index].convert_mmap_buf +
+ buffer_index * V4L2_FRAME_BUF_SIZE;
+
+ V4L2_LOG("Fake (conversion) mmap buf %u, seen by app at: %p\n",
+ buffer_index, result);
+
+leave:
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ return result;
+}
+
+int v4l2_munmap(void *_start, size_t length)
+{
+ int index;
+ unsigned int buffer_index;
+ unsigned char *start = _start;
+
+ /* Is this memory ours? */
+ if (start != MAP_FAILED && length == V4L2_FRAME_BUF_SIZE) {
+ for (index = 0; index < devices_used; index++)
+ if (devices[index].fd != -1 &&
+ devices[index].convert_mmap_buf != MAP_FAILED &&
+ start >= devices[index].convert_mmap_buf &&
+ (start - devices[index].convert_mmap_buf) % length == 0)
+ break;
+
+ if (index != devices_used) {
+ int unmapped = 0;
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ buffer_index = (start - devices[index].convert_mmap_buf) / length;
+
+ /* Redo our checks now that we have the lock, things may have changed */
+ if (devices[index].convert_mmap_buf != MAP_FAILED &&
+ start >= devices[index].convert_mmap_buf &&
+ (start - devices[index].convert_mmap_buf) % length == 0 &&
+ buffer_index < devices[index].no_frames) {
+ if (devices[index].frame_map_count[buffer_index] > 0)
+ devices[index].frame_map_count[buffer_index]--;
+ unmapped = 1;
+ }
+
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ if (unmapped) {
+ V4L2_LOG("v4l2 fake buffer munmap %p, %d\n", start, (int)length);
+ return 0;
+ }
+ }
+ }
+
+ V4L2_LOG("v4l2 unknown munmap %p, %d\n", start, (int)length);
+
+ return syscall(SYS_munmap, _start, length);
+}
+
+/* Misc utility functions */
+int v4l2_set_control(int fd, int cid, int value)
+{
+ struct v4l2_queryctrl qctrl = { .id = cid };
+ struct v4l2_control ctrl = { .id = cid };
+ int result;
+
+ if ((result = syscall(SYS_ioctl, fd, VIDIOC_QUERYCTRL, &qctrl)))
+ return result;
+
+ if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED) &&
+ !(qctrl.flags & V4L2_CTRL_FLAG_GRABBED)) {
+ if (qctrl.type == V4L2_CTRL_TYPE_BOOLEAN)
+ ctrl.value = value? 1:0;
+ else
+ ctrl.value = (value * (qctrl.maximum - qctrl.minimum) + 32767) / 65535 +
+ qctrl.minimum;
+
+ result = syscall(SYS_ioctl, fd, VIDIOC_S_CTRL, &ctrl);
+ }
+
+ return result;
+}
+
+int v4l2_get_control(int fd, int cid)
+{
+ struct v4l2_queryctrl qctrl = { .id = cid };
+ struct v4l2_control ctrl = { .id = cid };
+
+ if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCTRL, &qctrl))
+ return 0;
+
+ if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+ return 0;
+
+ if (syscall(SYS_ioctl, fd, VIDIOC_G_CTRL, &ctrl))
+ return 0;
+
+ return ((ctrl.value - qctrl.minimum) * 65535 +
+ (qctrl.maximum - qctrl.minimum) / 2) /
+ (qctrl.maximum - qctrl.minimum);
+}
diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c
new file mode 100644
index 000000000..6237d55ec
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l2/log.c
@@ -0,0 +1,148 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/ioctl.h>
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <asm/types.h>
+/* end broken header workaround includes */
+#include <linux/videodev2.h>
+#include "libv4l2.h"
+#include "libv4l2-priv.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+FILE *v4l2_log_file = NULL;
+
+static const char *v4l2_ioctls[] = {
+ /* start v4l2 ioctls */
+ [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
+ [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
+ [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
+ [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
+ [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
+ [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
+ [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
+ [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
+ [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
+ [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
+ [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
+ [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
+ [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
+ [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
+ [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM",
+ [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM",
+ [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD",
+ [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD",
+ [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD",
+ [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT",
+ [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL",
+ [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL",
+ [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER",
+ [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER",
+ [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO",
+ [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO",
+ [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL",
+ [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU",
+ [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT",
+ [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT",
+ [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT",
+ [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT",
+ [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT",
+ [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT",
+ [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT",
+ [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR",
+ [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR",
+ [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY",
+ [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY",
+ [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
+ [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
+ [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
+ [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
+ [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
+ [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
+ [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT",
+ [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO",
+ [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT",
+ [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY",
+ [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY",
+ [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
+ [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
+ [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS",
+};
+
+void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
+{
+ const char *ioctl_str;
+ char buf[40];
+
+ if (!v4l2_log_file)
+ return;
+
+ if (_IOC_TYPE(request) == 'V' && _IOC_NR(request) < ARRAY_SIZE(v4l2_ioctls))
+ ioctl_str = v4l2_ioctls[_IOC_NR(request)];
+ else {
+ snprintf(buf, sizeof(buf), "unknown request: %c %d\n",
+ (int)_IOC_TYPE(request), (int)_IOC_NR(request));
+ ioctl_str = buf;
+ }
+
+ fprintf(v4l2_log_file, "request == %s\n", ioctl_str);
+
+ switch (request) {
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format* fmt = arg;
+ int pixfmt = fmt->fmt.pix.pixelformat;
+
+ if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ fprintf(v4l2_log_file, " pixelformat: %c%c%c%c %ux%u\n",
+ pixfmt & 0xff,
+ (pixfmt >> 8) & 0xff,
+ (pixfmt >> 16) & 0xff,
+ pixfmt >> 24,
+ fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ fprintf(v4l2_log_file, " field: %d bytesperline: %d imagesize%d\n",
+ (int)fmt->fmt.pix.field, (int)fmt->fmt.pix.bytesperline,
+ (int)fmt->fmt.pix.sizeimage);
+ fprintf(v4l2_log_file, " colorspace: %d, priv: %x\n",
+ (int)fmt->fmt.pix.colorspace, (int)fmt->fmt.pix.priv);
+ }
+ }
+ break;
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *req = arg;
+
+ fprintf(v4l2_log_file, " count: %u type: %d memory: %d\n",
+ req->count, (int)req->type, (int)req->memory);
+ }
+ break;
+ }
+
+ fprintf(v4l2_log_file, "result == %d\n", result);
+ fflush(v4l2_log_file);
+}
diff --git a/v4l2-apps/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/libv4l/libv4l2/v4l2convert.c
new file mode 100644
index 000000000..307a03ce5
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l2/v4l2convert.c
@@ -0,0 +1,166 @@
+/*
+# open/close/ioctl/mmap/munmap library call wrapper doing format conversion
+# for v4l2 applications which want to be able to simply capture bgr24 / yuv420
+# from v4l2 devices with more exotic frame formats.
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define _LARGEFILE64_SOURCE 1
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <asm/types.h>
+#include <linux/ioctl.h>
+/* end broken header workaround includes */
+#include <linux/videodev2.h>
+#include <libv4l2.h>
+
+/* Check that open/read/mmap is not a define */
+#if defined open || defined read || defined mmap
+#error open/read/mmap is a prepocessor macro !!
+#endif
+
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
+{
+ int fd;
+ struct v4l2_capability cap;
+ int v4l_device = 0;
+
+ /* check if we're opening a video4linux2 device */
+ if (!strncmp(file, "/dev/video", 10) || !strncmp(file, "/dev/v4l/", 9)) {
+ /* Some apps open the device read only, but we need rw rights as the
+ buffers *MUST* be mapped rw */
+ oflag = (oflag & ~O_ACCMODE) | O_RDWR;
+ v4l_device = 1;
+ }
+
+ /* original open code */
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = syscall(SYS_open, file, oflag, mode);
+
+ va_end(ap);
+ } else
+ fd = syscall(SYS_open, file, oflag);
+ /* end of original open code */
+
+ if (fd == -1 || !v4l_device)
+ return fd;
+
+ /* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */
+ if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap))
+ return fd;
+
+ /* libv4l2 only adds functionality to capture capable devices */
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+ return fd;
+
+ /* Try to Register with libv4l2 (in case of failure pass the fd to the
+ application as is) */
+ v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
+
+ return fd;
+}
+
+LIBV4L_PUBLIC int open64(const char *file, int oflag, ...)
+{
+ int fd;
+
+ /* original open code */
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = open(file, oflag | O_LARGEFILE, mode);
+
+ va_end(ap);
+ } else
+ fd = open(file, oflag | O_LARGEFILE);
+ /* end of original open code */
+
+ return fd;
+}
+
+LIBV4L_PUBLIC int close(int fd)
+{
+ return v4l2_close(fd);
+}
+
+LIBV4L_PUBLIC int dup(int fd)
+{
+ return v4l2_dup(fd);
+}
+
+LIBV4L_PUBLIC int ioctl (int fd, unsigned long int request, ...)
+{
+ void *arg;
+ va_list ap;
+
+ va_start (ap, request);
+ arg = va_arg (ap, void *);
+ va_end (ap);
+
+ return v4l2_ioctl (fd, request, arg);
+}
+
+LIBV4L_PUBLIC ssize_t read (int fd, void* buffer, size_t n)
+{
+ return v4l2_read (fd, buffer, n);
+}
+
+LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off_t offset)
+{
+ return v4l2_mmap(start, length, prot, flags, fd, offset);
+}
+
+LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset)
+{
+ return v4l2_mmap(start, length, prot, flags, fd, offset);
+}
+
+LIBV4L_PUBLIC int munmap(void *start, size_t length)
+{
+ return v4l2_munmap(start, length);
+}
+
diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile
new file mode 100644
index 000000000..641d19d6e
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/Makefile
@@ -0,0 +1,70 @@
+override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
+
+CFLAGS := -g -O1
+CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
+
+ifeq ($(LINKTYPE),static)
+CONVERT_LIB = libv4lconvert.a
+else
+CONVERT_LIB = libv4lconvert.so
+override CPPFLAGS += -fPIC
+endif
+
+CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o flip.o \
+ jidctflt.o spca561-decompress.o rgbyuv.o spca501.o bayer.o
+TARGETS = $(CONVERT_LIB) libv4lconvert.pc
+INCLUDES = ../include/libv4lconvert.h
+
+ifeq ($(LIB_RELEASE),)
+LIB_RELEASE = 0
+endif
+
+ifeq ($(PREFIX),)
+PREFIX = /usr/local
+endif
+
+ifeq ($(LIBDIR),)
+LIBDIR = $(PREFIX)/lib
+endif
+
+all: $(TARGETS)
+
+$(CONVERT_LIB): $(CONVERT_OBJS)
+
+libv4lconvert.pc:
+ @echo prefix=$(PREFIX) > libv4lconvert.pc
+ @echo libdir=$(LIBDIR) >> libv4lconvert.pc
+ @echo >> libv4lconvert.pc
+ @echo 'Name: libv4lconvert' >> libv4lconvert.pc
+ @echo 'Description: v4l format conversion library' >> libv4lconvert.pc
+ @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4lconvert.pc
+ @echo 'Libs: -L$${libdir} -lv4lconvert' >> libv4lconvert.pc
+ @echo 'Cflags: -I$${prefix}/include' >> libv4lconvert.pc
+
+install: all
+ mkdir -p $(DESTDIR)$(PREFIX)/include
+ install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include
+ mkdir -p $(DESTDIR)$(LIBDIR)
+ifeq ($(LINKTYPE),static)
+ mkdir -p $(DESTDIR)$(LIBDIR)
+ install -m 644 $(CONVERT_LIB) $(DESTDIR)$(LIBDIR)
+else
+ install -m 755 $(CONVERT_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR)
+ cd $(DESTDIR)$(LIBDIR) && \
+ ln -f -s $(CONVERT_LIB).$(LIB_RELEASE) $(CONVERT_LIB)
+endif
+ mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
+ install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig
+
+clean::
+ rm -f *.a *.so* *.o *.d libv4lconvert.pc log *~
+
+%.o: %.c
+ $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+%.so:
+ $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^
+ ln -f -s $@.$(LIB_RELEASE) $@
+
+%.a:
+ $(AR) cqs $@ $^
diff --git a/v4l2-apps/libv4l/libv4lconvert/bayer.c b/v4l2-apps/libv4l/libv4lconvert/bayer.c
new file mode 100644
index 000000000..ca7bb486f
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/bayer.c
@@ -0,0 +1,613 @@
+/*
+ * lib4lconvert, video4linux2 format conversion lib
+ * (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Note: original bayer_to_bgr24 code from :
+ * 1394-Based Digital Camera Control Library
+ *
+ * Bayer pattern decoding functions
+ *
+ * Written by Damien Douxchamps and Frederic Devernay
+ *
+ * Note that the original bayer.c in libdc1394 supports many different
+ * bayer decode algorithms, for lib4lconvert the one in this file has been
+ * chosen (and optimized a bit) and the other algorithm's have been removed,
+ * see bayer.c from libdc1394 for all supported algorithms
+ */
+
+#include <string.h>
+#include "libv4lconvert-priv.h"
+
+/**************************************************************
+ * Color conversion functions for cameras that can *
+ * output raw-Bayer pattern images, such as some Basler and *
+ * Point Grey camera. Most of the algos presented here come *
+ * from http://www-ise.stanford.edu/~tingchen/ and have been *
+ * converted from Matlab to C and extended to all elementary *
+ * patterns. *
+ **************************************************************/
+
+/* insprired by OpenCV's Bayer decoding */
+static void v4lconvert_border_bayer_line_to_bgr24(
+ const unsigned char* bayer, const unsigned char* adjacent_bayer,
+ unsigned char *bgr, int width, int start_with_green, int blue_line)
+{
+ int t0, t1;
+
+ if (start_with_green) {
+ /* First pixel */
+ if (blue_line) {
+ *bgr++ = bayer[1];
+ *bgr++ = bayer[0];
+ *bgr++ = adjacent_bayer[0];
+ } else {
+ *bgr++ = adjacent_bayer[0];
+ *bgr++ = bayer[0];
+ *bgr++ = bayer[1];
+ }
+ /* Second pixel */
+ t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
+ t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
+ if (blue_line) {
+ *bgr++ = bayer[1];
+ *bgr++ = t0;
+ *bgr++ = t1;
+ } else {
+ *bgr++ = t1;
+ *bgr++ = t0;
+ *bgr++ = bayer[1];
+ }
+ bayer++;
+ adjacent_bayer++;
+ width -= 2;
+ } else {
+ /* First pixel */
+ t0 = (bayer[1] + adjacent_bayer[0] + 1) >> 1;
+ if (blue_line) {
+ *bgr++ = bayer[0];
+ *bgr++ = t0;
+ *bgr++ = adjacent_bayer[1];
+ } else {
+ *bgr++ = adjacent_bayer[1];
+ *bgr++ = t0;
+ *bgr++ = bayer[0];
+ }
+ width--;
+ }
+
+ if (blue_line) {
+ for ( ; width > 2; width -= 2) {
+ t0 = (bayer[0] + bayer[2] + 1) >> 1;
+ *bgr++ = t0;
+ *bgr++ = bayer[1];
+ *bgr++ = adjacent_bayer[1];
+ bayer++;
+ adjacent_bayer++;
+
+ t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
+ t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
+ *bgr++ = bayer[1];
+ *bgr++ = t0;
+ *bgr++ = t1;
+ bayer++;
+ adjacent_bayer++;
+ }
+ } else {
+ for ( ; width > 2; width -= 2) {
+ t0 = (bayer[0] + bayer[2] + 1) >> 1;
+ *bgr++ = adjacent_bayer[1];
+ *bgr++ = bayer[1];
+ *bgr++ = t0;
+ bayer++;
+ adjacent_bayer++;
+
+ t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
+ t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
+ *bgr++ = t1;
+ *bgr++ = t0;
+ *bgr++ = bayer[1];
+ bayer++;
+ adjacent_bayer++;
+ }
+ }
+
+ if (width == 2) {
+ /* Second to last pixel */
+ t0 = (bayer[0] + bayer[2] + 1) >> 1;
+ if (blue_line) {
+ *bgr++ = t0;
+ *bgr++ = bayer[1];
+ *bgr++ = adjacent_bayer[1];
+ } else {
+ *bgr++ = adjacent_bayer[1];
+ *bgr++ = bayer[1];
+ *bgr++ = t0;
+ }
+ /* Last pixel */
+ t0 = (bayer[1] + adjacent_bayer[2] + 1) >> 1;
+ if (blue_line) {
+ *bgr++ = bayer[2];
+ *bgr++ = t0;
+ *bgr++ = adjacent_bayer[1];
+ } else {
+ *bgr++ = adjacent_bayer[1];
+ *bgr++ = t0;
+ *bgr++ = bayer[2];
+ }
+ } else {
+ /* Last pixel */
+ if (blue_line) {
+ *bgr++ = bayer[0];
+ *bgr++ = bayer[1];
+ *bgr++ = adjacent_bayer[1];
+ } else {
+ *bgr++ = adjacent_bayer[1];
+ *bgr++ = bayer[1];
+ *bgr++ = bayer[0];
+ }
+ }
+}
+
+/* From libdc1394, which on turn was based on OpenCV's Bayer decoding */
+static void bayer_to_rgbbgr24(const unsigned char *bayer,
+ unsigned char *bgr, int width, int height, unsigned int pixfmt,
+ int start_with_green, int blue_line)
+{
+ /* render the first line */
+ v4lconvert_border_bayer_line_to_bgr24(bayer, bayer + width, bgr, width,
+ start_with_green, blue_line);
+ bgr += width * 3;
+
+ /* reduce height by 2 because of the special case top/bottom line */
+ for (height -= 2; height; height--) {
+ int t0, t1;
+ /* (width - 2) because of the border */
+ const unsigned char *bayerEnd = bayer + (width - 2);
+
+ if (start_with_green) {
+ /* OpenCV has a bug in the next line, which was
+ t0 = (bayer[0] + bayer[width * 2] + 1) >> 1; */
+ t0 = (bayer[1] + bayer[width * 2 + 1] + 1) >> 1;
+ /* Write first pixel */
+ t1 = (bayer[0] + bayer[width * 2] + bayer[width + 1] + 1) / 3;
+ if (blue_line) {
+ *bgr++ = t0;
+ *bgr++ = t1;
+ *bgr++ = bayer[width];
+ } else {
+ *bgr++ = bayer[width];
+ *bgr++ = t1;
+ *bgr++ = t0;
+ }
+
+ /* Write second pixel */
+ t1 = (bayer[width] + bayer[width + 2] + 1) >> 1;
+ if (blue_line) {
+ *bgr++ = t0;
+ *bgr++ = bayer[width + 1];
+ *bgr++ = t1;
+ } else {
+ *bgr++ = t1;
+ *bgr++ = bayer[width + 1];
+ *bgr++ = t0;
+ }
+ bayer++;
+ } else {
+ /* Write first pixel */
+ t0 = (bayer[0] + bayer[width * 2] + 1) >> 1;
+ if (blue_line) {
+ *bgr++ = t0;
+ *bgr++ = bayer[width];
+ *bgr++ = bayer[width + 1];
+ } else {
+ *bgr++ = bayer[width + 1];
+ *bgr++ = bayer[width];
+ *bgr++ = t0;
+ }
+ }
+
+ if (blue_line) {
+ for (; bayer <= bayerEnd - 2; bayer += 2) {
+ t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
+ bayer[width * 2 + 2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[width] +
+ bayer[width + 2] + bayer[width * 2 + 1] +
+ 2) >> 2;
+ *bgr++ = t0;
+ *bgr++ = t1;
+ *bgr++ = bayer[width + 1];
+
+ t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
+ t1 = (bayer[width + 1] + bayer[width + 3] +
+ 1) >> 1;
+ *bgr++ = t0;
+ *bgr++ = bayer[width + 2];
+ *bgr++ = t1;
+ }
+ } else {
+ for (; bayer <= bayerEnd - 2; bayer += 2) {
+ t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
+ bayer[width * 2 + 2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[width] +
+ bayer[width + 2] + bayer[width * 2 + 1] +
+ 2) >> 2;
+ *bgr++ = bayer[width + 1];
+ *bgr++ = t1;
+ *bgr++ = t0;
+
+ t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
+ t1 = (bayer[width + 1] + bayer[width + 3] +
+ 1) >> 1;
+ *bgr++ = t1;
+ *bgr++ = bayer[width + 2];
+ *bgr++ = t0;
+ }
+ }
+
+ if (bayer < bayerEnd) {
+ /* write second to last pixel */
+ t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
+ bayer[width * 2 + 2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[width] +
+ bayer[width + 2] + bayer[width * 2 + 1] +
+ 2) >> 2;
+ if (blue_line) {
+ *bgr++ = t0;
+ *bgr++ = t1;
+ *bgr++ = bayer[width + 1];
+ } else {
+ *bgr++ = bayer[width + 1];
+ *bgr++ = t1;
+ *bgr++ = t0;
+ }
+ /* write last pixel */
+ t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
+ if (blue_line) {
+ *bgr++ = t0;
+ *bgr++ = bayer[width + 2];
+ *bgr++ = bayer[width + 1];
+ } else {
+ *bgr++ = bayer[width + 1];
+ *bgr++ = bayer[width + 2];
+ *bgr++ = t0;
+ }
+ bayer++;
+ } else {
+ /* write last pixel */
+ t0 = (bayer[0] + bayer[width * 2] + 1) >> 1;
+ t1 = (bayer[1] + bayer[width * 2 + 1] + bayer[width] + 1) / 3;
+ if (blue_line) {
+ *bgr++ = t0;
+ *bgr++ = t1;
+ *bgr++ = bayer[width + 1];
+ } else {
+ *bgr++ = bayer[width + 1];
+ *bgr++ = t1;
+ *bgr++ = t0;
+ }
+ }
+
+ /* skip 2 border pixels */
+ bayer += 2;
+
+ blue_line = !blue_line;
+ start_with_green = !start_with_green;
+ }
+
+ /* render the last line */
+ v4lconvert_border_bayer_line_to_bgr24(bayer + width, bayer, bgr, width,
+ !start_with_green, !blue_line);
+}
+
+void v4lconvert_bayer_to_rgb24(const unsigned char *bayer,
+ unsigned char *bgr, int width, int height, unsigned int pixfmt)
+{
+ bayer_to_rgbbgr24(bayer, bgr, width, height, pixfmt,
+ pixfmt == V4L2_PIX_FMT_SGBRG8 /* start with green */
+ || pixfmt == V4L2_PIX_FMT_SGRBG8,
+ pixfmt != V4L2_PIX_FMT_SBGGR8 /* blue line */
+ && pixfmt != V4L2_PIX_FMT_SGBRG8);
+}
+
+void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
+ unsigned char *bgr, int width, int height, unsigned int pixfmt)
+{
+ bayer_to_rgbbgr24(bayer, bgr, width, height, pixfmt,
+ pixfmt == V4L2_PIX_FMT_SGBRG8 /* start with green */
+ || pixfmt == V4L2_PIX_FMT_SGRBG8,
+ pixfmt == V4L2_PIX_FMT_SBGGR8 /* blue line */
+ || pixfmt == V4L2_PIX_FMT_SGBRG8);
+}
+
+static void v4lconvert_border_bayer_line_to_y(
+ const unsigned char* bayer, const unsigned char* adjacent_bayer,
+ unsigned char *y, int width, int start_with_green, int blue_line)
+{
+ int t0, t1;
+
+ if (start_with_green) {
+ /* First pixel */
+ if (blue_line) {
+ *y++ = (8453*adjacent_bayer[0] + 16594*bayer[0] + 3223*bayer[1] + 524288)
+ >> 15;
+ } else {
+ *y++ = (8453*bayer[1] + 16594*bayer[0] + 3223*adjacent_bayer[0] + 524288)
+ >> 15;
+ }
+ /* Second pixel */
+ t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
+ t1 = adjacent_bayer[0] + adjacent_bayer[2];
+ if (blue_line) {
+ *y++ = (4226*t1 + 5531*t0 + 3223*bayer[1] + 524288) >> 15;
+ } else {
+ *y++ = (8453*bayer[1] + 5531*t0 + 1611*t1 + 524288) >> 15;
+ }
+ bayer++;
+ adjacent_bayer++;
+ width -= 2;
+ } else {
+ /* First pixel */
+ t0 = bayer[1] + adjacent_bayer[0];
+ if (blue_line) {
+ *y++ = (8453*adjacent_bayer[1] + 8297*t0 + 3223*bayer[0] + 524288)
+ >> 15;
+ } else {
+ *y++ = (8453*bayer[0] + 8297*t0 + 3223*adjacent_bayer[1] + 524288)
+ >> 15;
+ }
+ width--;
+ }
+
+ if (blue_line) {
+ for ( ; width > 2; width -= 2) {
+ t0 = bayer[0] + bayer[2];
+ *y++ = (8453*adjacent_bayer[1] + 16594*bayer[1] + 1611*t0 + 524288)
+ >> 15;
+ bayer++;
+ adjacent_bayer++;
+
+ t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
+ t1 = adjacent_bayer[0] + adjacent_bayer[2];
+ *y++ = (4226*t1 + 5531*t0 + 3223*bayer[1] + 524288) >> 15;
+ bayer++;
+ adjacent_bayer++;
+ }
+ } else {
+ for ( ; width > 2; width -= 2) {
+ t0 = bayer[0] + bayer[2];
+ *y++ = (4226*t0 + 16594*bayer[1] + 3223*adjacent_bayer[1] + 524288)
+ >> 15;
+ bayer++;
+ adjacent_bayer++;
+
+ t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
+ t1 = adjacent_bayer[0] + adjacent_bayer[2];
+ *y++ = (8453*bayer[1] + 5531*t0 + 1611*t1 + 524288) >> 15;
+ bayer++;
+ adjacent_bayer++;
+ }
+ }
+
+ if (width == 2) {
+ /* Second to last pixel */
+ t0 = bayer[0] + bayer[2];
+ if (blue_line) {
+ *y++ = (8453*adjacent_bayer[1] + 16594*bayer[1] + 1611*t0 + 524288)
+ >> 15;
+ } else {
+ *y++ = (4226*t0 + 16594*bayer[1] + 3223*adjacent_bayer[1] + 524288)
+ >> 15;
+ }
+ /* Last pixel */
+ t0 = bayer[1] + adjacent_bayer[2];
+ if (blue_line) {
+ *y++ = (8453*adjacent_bayer[1] + 8297*t0 + 3223*bayer[2] + 524288)
+ >> 15;
+ } else {
+ *y++ = (8453*bayer[2] + 8297*t0 + 3223*adjacent_bayer[1] + 524288)
+ >> 15;
+ }
+ } else {
+ /* Last pixel */
+ if (blue_line) {
+ *y++ = (8453*adjacent_bayer[1] + 16594*bayer[1] + 3223*bayer[0] + 524288)
+ >> 15;
+ } else {
+ *y++ = (8453*bayer[0] + 16594*bayer[1] + 3223*adjacent_bayer[1] + 524288)
+ >> 15;
+ }
+ }
+}
+
+void v4lconvert_bayer_to_yuv420(const unsigned char *bayer,
+ unsigned char *yuv, int width, int height, unsigned int pixfmt)
+{
+ int blue_line = 0, start_with_green = 0, x, y;
+ unsigned char *ydst = yuv;
+ unsigned char *udst = yuv + width * height;
+ unsigned char *vdst = udst + width * height / 4;
+
+ /* First calculate the u and v planes 2x2 pixels at a time */
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_SBGGR8:
+ for (y = 0; y < height; y += 2) {
+ for (x = 0; x < width; x += 2) {
+ int b, g, r;
+ b = bayer[x];
+ g = bayer[x+1];
+ g += bayer[x+width];
+ r = bayer[x+width+1];
+ *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+ *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
+ }
+ bayer += 2 * width;
+ }
+ blue_line = 1;
+ break;
+
+ case V4L2_PIX_FMT_SRGGB8:
+ for (y = 0; y < height; y += 2) {
+ for (x = 0; x < width; x += 2) {
+ int b, g, r;
+ r = bayer[x];
+ g = bayer[x+1];
+ g += bayer[x+width];
+ b = bayer[x+width+1];
+ *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+ *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
+ }
+ bayer += 2 * width;
+ }
+ break;
+
+ case V4L2_PIX_FMT_SGBRG8:
+ for (y = 0; y < height; y += 2) {
+ for (x = 0; x < width; x += 2) {
+ int b, g, r;
+ g = bayer[x];
+ b = bayer[x+1];
+ r = bayer[x+width];
+ g += bayer[x+width+1];
+ *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+ *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
+ }
+ bayer += 2 * width;
+ }
+ blue_line = 1;
+ start_with_green = 1;
+ break;
+
+ case V4L2_PIX_FMT_SGRBG8:
+ for (y = 0; y < height; y += 2) {
+ for (x = 0; x < width; x += 2) {
+ int b, g, r;
+ g = bayer[x];
+ r = bayer[x+1];
+ b = bayer[x+width];
+ g += bayer[x+width+1];
+ *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+ *vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
+ }
+ bayer += 2 * width;
+ }
+ start_with_green = 1;
+ break;
+ }
+
+ bayer -= width * height;
+
+ /* render the first line */
+ v4lconvert_border_bayer_line_to_y(bayer, bayer + width, ydst, width,
+ start_with_green, blue_line);
+ ydst += width;
+
+ /* reduce height by 2 because of the border */
+ for (height -= 2; height; height--) {
+ int t0, t1;
+ /* (width - 2) because of the border */
+ const unsigned char *bayerEnd = bayer + (width - 2);
+
+ if (start_with_green) {
+ t0 = bayer[1] + bayer[width * 2 + 1];
+ /* Write first pixel */
+ t1 = bayer[0] + bayer[width * 2] + bayer[width + 1];
+ if (blue_line)
+ *ydst++ = (8453*bayer[width] + 5516*t1 + 1661*t0 + 524288) >> 15;
+ else
+ *ydst++ = (4226*t0 + 5516*t1 + 3223*bayer[width] + 524288) >> 15;
+
+ /* Write second pixel */
+ t1 = bayer[width] + bayer[width + 2];
+ if (blue_line)
+ *ydst++ = (4226*t1 + 16594*bayer[width+1] + 1611*t0 + 524288) >> 15;
+ else
+ *ydst++ = (4226*t0 + 16594*bayer[width+1] + 1611*t1 + 524288) >> 15;
+ bayer++;
+ } else {
+ /* Write first pixel */
+ t0 = bayer[0] + bayer[width * 2];
+ if (blue_line) {
+ *ydst++ = (8453*bayer[width+1] + 16594*bayer[width] + 1661*t0 +
+ 524288) >> 15;
+ } else {
+ *ydst++ = (4226*t0 + 16594*bayer[width] + 3223*bayer[width+1] +
+ 524288) >> 15;
+ }
+ }
+
+ if (blue_line) {
+ for (; bayer <= bayerEnd - 2; bayer += 2) {
+ t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
+ t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
+ *ydst++ = (8453*bayer[width+1] + 4148*t1 + 806*t0 + 524288) >> 15;
+
+ t0 = bayer[2] + bayer[width * 2 + 2];
+ t1 = bayer[width + 1] + bayer[width + 3];
+ *ydst++ = (4226*t1 + 16594*bayer[width+2] + 1611*t0 + 524288) >> 15;
+ }
+ } else {
+ for (; bayer <= bayerEnd - 2; bayer += 2) {
+ t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
+ t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
+ *ydst++ = (2113*t0 + 4148*t1 + 3223*bayer[width+1] + 524288) >> 15;
+
+ t0 = bayer[2] + bayer[width * 2 + 2];
+ t1 = bayer[width + 1] + bayer[width + 3];
+ *ydst++ = (4226*t0 + 16594*bayer[width+2] + 1611*t1 + 524288) >> 15;
+ }
+ }
+
+ if (bayer < bayerEnd) {
+ /* Write second to last pixel */
+ t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
+ t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
+ if (blue_line)
+ *ydst++ = (8453*bayer[width+1] + 4148*t1 + 806*t0 + 524288) >> 15;
+ else
+ *ydst++ = (2113*t0 + 4148*t1 + 3223*bayer[width+1] + 524288) >> 15;
+
+ /* write last pixel */
+ t0 = bayer[2] + bayer[width * 2 + 2];
+ if (blue_line) {
+ *ydst++ = (8453*bayer[width+1] + 16594*bayer[width+2] + 1661*t0 +
+ 524288) >> 15;
+ } else {
+ *ydst++ = (4226*t0 + 16594*bayer[width+2] + 3223*bayer[width+1] +
+ 524288) >> 15;
+ }
+ bayer++;
+ } else {
+ /* write last pixel */
+ t0 = bayer[0] + bayer[width * 2];
+ t1 = bayer[1] + bayer[width * 2 + 1] + bayer[width];
+ if (blue_line)
+ *ydst++ = (8453*bayer[width+1] + 5516*t1 + 1661*t0 + 524288) >> 15;
+ else
+ *ydst++ = (4226*t0 + 5516*t1 + 3223*bayer[width+1] + 524288) >> 15;
+ }
+
+ /* skip 2 border pixels */
+ bayer += 2;
+
+ blue_line = !blue_line;
+ start_with_green = !start_with_green;
+ }
+
+ /* render the last line */
+ v4lconvert_border_bayer_line_to_y(bayer + width, bayer, ydst, width,
+ !start_with_green, !blue_line);
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c
new file mode 100644
index 000000000..cd3468a89
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/flip.c
@@ -0,0 +1,107 @@
+/*
+
+# RGB / YUV flip/rotate routines
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "libv4lconvert-priv.h"
+
+void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i;
+
+ src += 3 * width * height - 3;
+
+ for (i = 0; i < width * height; i++) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst += 3;
+ src -= 3;
+ }
+}
+
+void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i;
+
+ /* First flip x and y of the Y plane */
+ src += width * height - 1;
+ for (i = 0; i < width * height; i++)
+ *dst++ = *src--;
+
+ /* Now flip the U plane */
+ src += width * height * 5 / 4;
+ for (i = 0; i < width * height / 4; i++)
+ *dst++ = *src--;
+
+ /* Last flip the V plane */
+ src += width * height / 2;
+ for (i = 0; i < width * height / 4; i++)
+ *dst++ = *src--;
+}
+
+void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight)
+{
+ int x, y;
+#define srcwidth destheight
+#define srcheight destwidth
+
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = ((srcheight - x - 1) * srcwidth + y) * 3;
+ *dst++ = src[offset++];
+ *dst++ = src[offset++];
+ *dst++ = src[offset];
+ }
+}
+
+void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight)
+{
+ int x, y;
+
+ /* Y-plane */
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = (srcheight - x - 1) * srcwidth + y;
+ *dst++ = src[offset];
+ }
+
+ /* U-plane */
+ src += srcwidth * srcheight;
+ destwidth /= 2;
+ destheight /= 2;
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = (srcheight - x - 1) * srcwidth + y;
+ *dst++ = src[offset];
+ }
+
+ /* V-plane */
+ src += srcwidth * srcheight;
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = (srcheight - x - 1) * srcwidth + y;
+ *dst++ = src[offset];
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/jidctflt.c b/v4l2-apps/libv4l/libv4lconvert/jidctflt.c
new file mode 100644
index 000000000..532abc7ea
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/jidctflt.c
@@ -0,0 +1,286 @@
+/*
+ * jidctflt.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ *
+ * The authors make NO WARRANTY or representation, either express or implied,
+ * with respect to this software, its quality, accuracy, merchantability, or
+ * fitness for a particular purpose. This software is provided "AS IS", and you,
+ * its user, assume the entire risk as to its quality and accuracy.
+ *
+ * This software is copyright (C) 1991-1998, Thomas G. Lane.
+ * All Rights Reserved except as specified below.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * software (or portions thereof) for any purpose, without fee, subject to these
+ * conditions:
+ * (1) If any part of the source code for this software is distributed, then this
+ * README file must be included, with this copyright and no-warranty notice
+ * unaltered; and any additions, deletions, or changes to the original files
+ * must be clearly indicated in accompanying documentation.
+ * (2) If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the work of
+ * the Independent JPEG Group".
+ * (3) Permission for use of this software is granted only if the user accepts
+ * full responsibility for any undesirable consequences; the authors accept
+ * NO LIABILITY for damages of any kind.
+ *
+ * These conditions apply to any software derived from or based on the IJG code,
+ * not just to the unmodified library. If you use our work, you ought to
+ * acknowledge us.
+ *
+ * Permission is NOT granted for the use of any IJG author's name or company name
+ * in advertising or publicity relating to this software or products derived from
+ * it. This software may be referred to only as "the Independent JPEG Group's
+ * software".
+ *
+ * We specifically permit and encourage the use of this software as the basis of
+ * commercial products, provided that all warranty or liability claims are
+ * assumed by the product vendor.
+ *
+ *
+ * This file contains a floating-point implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * This implementation should be more accurate than either of the integer
+ * IDCT implementations. However, it may not give the same results on all
+ * machines because of differences in roundoff behavior. Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values. However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#include <stdint.h>
+#include "tinyjpeg-internal.h"
+
+#define FAST_FLOAT float
+#define DCTSIZE 8
+#define DCTSIZE2 (DCTSIZE*DCTSIZE)
+
+#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
+
+#if defined(__GNUC__) && (defined(__i686__) || defined(__x86_64__))
+
+static inline unsigned char descale_and_clamp(int x, int shift)
+{
+ __asm__ (
+ "add %3,%1\n"
+ "\tsar %2,%1\n"
+ "\tsub $-128,%1\n"
+ "\tcmovl %5,%1\n" /* Use the sub to compare to 0 */
+ "\tcmpl %4,%1\n"
+ "\tcmovg %4,%1\n"
+ : "=r"(x)
+ : "0"(x), "Ic"((unsigned char)shift), "ir"(1U<<(shift-1)), "r" (0xff), "r" (0)
+ );
+ return x;
+}
+
+#else
+static inline unsigned char descale_and_clamp(int x, int shift)
+{
+ x += (1UL<<(shift-1));
+ if (x<0)
+ x = (x >> shift) | ((~(0UL)) << (32-(shift)));
+ else
+ x >>= shift;
+ x += 128;
+ if (x>255)
+ return 255;
+ else if (x<0)
+ return 0;
+ else
+ return x;
+}
+#endif
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+void
+tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride)
+{
+ FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+ FAST_FLOAT z5, z10, z11, z12, z13;
+ int16_t *inptr;
+ FAST_FLOAT *quantptr;
+ FAST_FLOAT *wsptr;
+ uint8_t *outptr;
+ int ctr;
+ FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = compptr->DCT;
+ quantptr = compptr->Q_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* 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 column 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
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
+
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
+ tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ wsptr[DCTSIZE*0] = tmp0 + tmp7;
+ wsptr[DCTSIZE*7] = tmp0 - tmp7;
+ wsptr[DCTSIZE*1] = tmp1 + tmp6;
+ wsptr[DCTSIZE*6] = tmp1 - tmp6;
+ wsptr[DCTSIZE*2] = tmp2 + tmp5;
+ wsptr[DCTSIZE*5] = tmp2 - tmp5;
+ wsptr[DCTSIZE*4] = tmp3 + tmp4;
+ wsptr[DCTSIZE*3] = tmp3 - tmp4;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3. */
+
+ wsptr = workspace;
+ outptr = output_buf;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * And testing floats for zero is relatively expensive, so we don't bother.
+ */
+
+ /* Even part */
+
+ tmp10 = wsptr[0] + wsptr[4];
+ tmp11 = wsptr[0] - wsptr[4];
+
+ tmp13 = wsptr[2] + wsptr[6];
+ tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = wsptr[5] + wsptr[3];
+ z10 = wsptr[5] - wsptr[3];
+ z11 = wsptr[1] + wsptr[7];
+ z12 = wsptr[1] - wsptr[7];
+
+ tmp7 = z11 + z13;
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
+ tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7;
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ /* Final output stage: scale down by a factor of 8 and range-limit */
+
+ outptr[0] = descale_and_clamp((int)(tmp0 + tmp7), 3);
+ outptr[7] = descale_and_clamp((int)(tmp0 - tmp7), 3);
+ outptr[1] = descale_and_clamp((int)(tmp1 + tmp6), 3);
+ outptr[6] = descale_and_clamp((int)(tmp1 - tmp6), 3);
+ outptr[2] = descale_and_clamp((int)(tmp2 + tmp5), 3);
+ outptr[5] = descale_and_clamp((int)(tmp2 - tmp5), 3);
+ outptr[4] = descale_and_clamp((int)(tmp3 + tmp4), 3);
+ outptr[3] = descale_and_clamp((int)(tmp3 - tmp4), 3);
+
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ outptr += stride;
+ }
+}
+
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
new file mode 100644
index 000000000..0c4eff6ce
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -0,0 +1,166 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4LCONVERT_PRIV_H
+#define __LIBV4LCONVERT_PRIV_H
+
+#include <stdio.h>
+#include "libv4lconvert.h"
+#include "tinyjpeg.h"
+
+#ifndef V4L2_PIX_FMT_SPCA501
+#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S','5','0','1') /* YUYV per line */
+#endif
+
+#ifndef V4L2_PIX_FMT_SPCA505
+#define V4L2_PIX_FMT_SPCA505 v4l2_fourcc('S','5','0','5') /* YYUV per line */
+#endif
+
+#ifndef V4L2_PIX_FMT_SPCA508
+#define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S','5','0','8') /* YUVY per line */
+#endif
+
+#ifndef V4L2_PIX_FMT_SPCA561
+#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S','5','6','1')
+#endif
+
+#ifndef V4L2_PIX_FMT_PAC207
+#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P','2','0','7')
+#endif
+
+#ifndef V4L2_PIX_FMT_PJPG
+#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G')
+#endif
+
+#ifndef V4L2_PIX_FMT_SGBRG8
+#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G','B','R','G')
+#endif
+
+#ifndef V4L2_PIX_FMT_SGRBG8
+#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G','R','B','G')
+#endif
+
+#ifndef V4L2_PIX_FMT_SRGGB8
+#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R','G','G','B')
+#endif
+
+#ifndef V4L2_PIX_FMT_YVYU
+#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U')
+#endif
+
+#define V4LCONVERT_ERROR_MSG_SIZE 256
+#define V4LCONVERT_MAX_FRAMESIZES 16
+
+#define V4LCONVERT_ERR(...) \
+ snprintf(data->error_msg, V4LCONVERT_ERROR_MSG_SIZE, \
+ "v4l-convert: error " __VA_ARGS__)
+
+/* Card flags */
+#define V4LCONVERT_UPSIDE_DOWN 0x01
+
+/* Pixformat flags */
+#define V4LCONVERT_COMPRESSED 0x01
+
+struct v4lconvert_data {
+ int fd;
+ int flags; /* bitfield */
+ int supported_src_formats; /* bitfield */
+ unsigned int no_formats;
+ char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
+ struct jdec_private *jdec;
+ struct v4l2_frmsizeenum framesizes[V4LCONVERT_MAX_FRAMESIZES];
+ unsigned int no_framesizes;
+};
+
+struct v4lconvert_flags_info {
+ const char *card;
+ int flags;
+};
+
+struct v4lconvert_pixfmt {
+ unsigned int fmt;
+ int flags;
+};
+
+void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yuyv_to_bgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_decode_sn9c10x(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_decode_pac207(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_bayer_to_rgb24(const unsigned char *bayer,
+ unsigned char *rgb, int width, int height, unsigned int pixfmt);
+
+void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
+ unsigned char *rgb, int width, int height, unsigned int pixfmt);
+
+void v4lconvert_bayer_to_yuv420(const unsigned char *bayer,
+ unsigned char *yuv, int width, int height, unsigned int pixfmt);
+
+void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight);
+
+void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight);
+
+void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
new file mode 100644
index 000000000..93bc67c7e
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
@@ -0,0 +1,737 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <unistd.h>
+#include "libv4lconvert.h"
+#include "libv4lconvert-priv.h"
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
+
+/* Note for proper functioning of v4lconvert_enum_fmt the first entries in
+ supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
+#define SUPPORTED_DST_PIXFMTS \
+ { V4L2_PIX_FMT_RGB24, 0 }, \
+ { V4L2_PIX_FMT_BGR24, 0 }, \
+ { V4L2_PIX_FMT_YUV420, 0 }
+
+static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
+ unsigned int pixelformat);
+
+/* Note uncompressed formats must go first so that they are prefered by
+ v4lconvert_try_format for low resolutions */
+static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
+ SUPPORTED_DST_PIXFMTS,
+ { V4L2_PIX_FMT_YUYV, 0 },
+ { V4L2_PIX_FMT_YVYU, 0 },
+ { V4L2_PIX_FMT_SBGGR8, 0 },
+ { V4L2_PIX_FMT_SGBRG8, 0 },
+ { V4L2_PIX_FMT_SGRBG8, 0 },
+ { V4L2_PIX_FMT_SRGGB8, 0 },
+ { V4L2_PIX_FMT_SPCA501, 0 },
+ { V4L2_PIX_FMT_SPCA505, 0 },
+ { V4L2_PIX_FMT_SPCA508, 0 },
+ { V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED },
+};
+
+static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
+ SUPPORTED_DST_PIXFMTS
+};
+
+/* List of cams which need special flags */
+static const struct v4lconvert_flags_info v4lconvert_flags[] = {
+ { "SPC 200NC ", V4LCONVERT_UPSIDE_DOWN },
+ { "SPC 300NC ", V4LCONVERT_UPSIDE_DOWN },
+ { "USB Camera (0471:0325)", V4LCONVERT_UPSIDE_DOWN }, /* SPC200NC */
+ { "USB Camera (0471:0326)", V4LCONVERT_UPSIDE_DOWN }, /* SPC300NC */
+ { "USB Camera (093a:2476)", V4LCONVERT_UPSIDE_DOWN }, /* Genius E-M 112 */
+};
+
+struct v4lconvert_data *v4lconvert_create(int fd)
+{
+ int i, j;
+ struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
+ struct v4l2_capability cap;
+
+ if (!data)
+ return NULL;
+
+ data->fd = fd;
+ data->jdec = NULL;
+
+ /* Check supported formats */
+ for (i = 0; ; i++) {
+ struct v4l2_fmtdesc fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+
+ fmt.index = i;
+
+ if (syscall(SYS_ioctl, fd, VIDIOC_ENUM_FMT, &fmt))
+ break;
+
+ for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
+ if (fmt.pixelformat == supported_src_pixfmts[j].fmt) {
+ data->supported_src_formats |= 1 << j;
+ break;
+ }
+
+ v4lconvert_get_framesizes(data, fmt.pixelformat);
+ }
+
+ data->no_formats = i;
+
+ /* Check if this cam has any special flags */
+ if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) {
+ for (i = 0; i < ARRAY_SIZE(v4lconvert_flags); i++)
+ if (!strcmp((const char *)v4lconvert_flags[i].card, (char *)cap.card)) {
+ data->flags = v4lconvert_flags[i].flags;
+ break;
+ }
+ }
+
+ return data;
+}
+
+void v4lconvert_destroy(struct v4lconvert_data *data)
+{
+ if (data->jdec) {
+ unsigned char *comps[3] = { NULL, NULL, NULL };
+ tinyjpeg_set_components(data->jdec, comps, 3);
+ tinyjpeg_free(data->jdec);
+ }
+ free(data);
+}
+
+static int v4lconvert_supported_dst_format(unsigned int pixelformat)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
+ if (supported_dst_pixfmts[i].fmt == pixelformat)
+ break;
+
+ return i != ARRAY_SIZE(supported_dst_pixfmts);
+}
+
+/* See libv4lconvert.h for description of in / out parameters */
+int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
+{
+ int i, no_faked_fmts = 0;
+ unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)];
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ fmt->index < data->no_formats ||
+ !data->supported_src_formats)
+ return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FMT, fmt);
+
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
+ if (!(data->supported_src_formats & (1 << i))) {
+ faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
+ no_faked_fmts++;
+ }
+
+ i = fmt->index - data->no_formats;
+ if (i >= no_faked_fmts) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fmt->flags = 0;
+ fmt->pixelformat = faked_fmts[i];
+ fmt->description[0] = faked_fmts[i] & 0xff;
+ fmt->description[1] = (faked_fmts[i] >> 8) & 0xff;
+ fmt->description[2] = (faked_fmts[i] >> 16) & 0xff;
+ fmt->description[3] = faked_fmts[i] >> 24;
+ fmt->description[4] = '\0';
+ memset(fmt->reserved, 0, 4);
+
+ return 0;
+}
+
+/* See libv4lconvert.h for description of in / out parameters */
+int v4lconvert_try_format(struct v4lconvert_data *data,
+ struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
+{
+ int i;
+ unsigned int closest_fmt_size_diff = -1;
+ unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat;
+ struct v4l2_format try_fmt, closest_fmt = { .type = 0 };
+
+ /* Can we do conversion to the requested format & type? */
+ if (!v4lconvert_supported_dst_format(desired_pixfmt) ||
+ dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ int ret = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt);
+ if (src_fmt)
+ *src_fmt = *dest_fmt;
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
+ /* is this format supported? */
+ if (!(data->supported_src_formats & (1 << i)))
+ continue;
+
+ try_fmt = *dest_fmt;
+ try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
+
+ if (!syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, &try_fmt))
+ {
+ if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) {
+ int size_x_diff = abs((int)try_fmt.fmt.pix.width -
+ (int)dest_fmt->fmt.pix.width);
+ int size_y_diff = abs((int)try_fmt.fmt.pix.height -
+ (int)dest_fmt->fmt.pix.height);
+ unsigned int size_diff = size_x_diff * size_x_diff +
+ size_y_diff * size_y_diff;
+ if (size_diff < closest_fmt_size_diff ||
+ (size_diff == closest_fmt_size_diff &&
+ (supported_src_pixfmts[i].fmt == desired_pixfmt ||
+ ((try_fmt.fmt.pix.width > 176 || try_fmt.fmt.pix.height > 144) &&
+ (supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED))))) {
+ closest_fmt_size_diff = size_diff;
+ closest_fmt = try_fmt;
+ }
+ }
+ }
+ }
+
+ if (closest_fmt.type == 0) {
+ int ret = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt);
+ if (src_fmt)
+ *src_fmt = *dest_fmt;
+ return ret;
+ }
+
+ *dest_fmt = closest_fmt;
+
+ /* Are we converting? */
+ if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt) {
+ dest_fmt->fmt.pix.pixelformat = desired_pixfmt;
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ dest_fmt->fmt.pix.bytesperline = dest_fmt->fmt.pix.width * 3;
+ dest_fmt->fmt.pix.sizeimage = dest_fmt->fmt.pix.width *
+ dest_fmt->fmt.pix.height * 3;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ dest_fmt->fmt.pix.bytesperline = dest_fmt->fmt.pix.width;
+ dest_fmt->fmt.pix.sizeimage = (dest_fmt->fmt.pix.width *
+ dest_fmt->fmt.pix.height * 3) / 2;
+ break;
+ }
+ }
+
+ if (src_fmt)
+ *src_fmt = closest_fmt;
+
+ return 0;
+}
+
+/* Is conversion necessary ? */
+int v4lconvert_needs_conversion(struct v4lconvert_data *data,
+ const struct v4l2_format *src_fmt, /* in */
+ const struct v4l2_format *dest_fmt) /* in */
+{
+ if(memcmp(src_fmt, dest_fmt, sizeof(*src_fmt)))
+ return 1; /* Formats differ */
+
+ if (!(data->flags & V4LCONVERT_UPSIDE_DOWN))
+ return 0; /* Formats identical and we don't need flip */
+
+ /* Formats are identical, but we need flip, do we support the dest_fmt? */
+ if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))
+ return 0; /* Needs flip but we cannot do it :( */
+ else
+ return 1; /* Needs flip and thus conversion */
+}
+
+int v4lconvert_convert(struct v4lconvert_data *data,
+ const struct v4l2_format *src_fmt, /* in */
+ const struct v4l2_format *dest_fmt, /* in */
+ unsigned char *src, int src_size, unsigned char *_dest, int dest_size)
+{
+ unsigned int header_width, header_height;
+ int result, needed, rotate = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE;
+ unsigned char *components[3];
+ unsigned char *dest = _dest;
+
+ /* Special case when no conversion is needed */
+ if (!v4lconvert_needs_conversion(data, src_fmt, dest_fmt)) {
+ int to_copy = MIN(dest_size, src_size);
+ memcpy(dest, src, to_copy);
+ return to_copy;
+ }
+
+ /* sanity check, is the dest buffer large enough? */
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ needed = dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ needed = (dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3) / 2;
+ break;
+ default:
+ V4LCONVERT_ERR("Unknown dest format in conversion\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (dest_size < needed) {
+ V4LCONVERT_ERR("destination buffer too small\n");
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (data->flags & V4LCONVERT_UPSIDE_DOWN) {
+ rotate = 180;
+ dest = alloca(needed);
+ }
+
+ switch (src_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_PJPG:
+ jpeg_flags |= TINYJPEG_FLAGS_PIXART_JPEG;
+ /* Fall through */
+ case V4L2_PIX_FMT_MJPEG:
+ case V4L2_PIX_FMT_JPEG:
+ if (!data->jdec) {
+ data->jdec = tinyjpeg_init();
+ if (!data->jdec) {
+ V4LCONVERT_ERR("out of memory!\n");
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ tinyjpeg_set_flags(data->jdec, jpeg_flags);
+ if (tinyjpeg_parse_header(data->jdec, src, src_size)) {
+ V4LCONVERT_ERR("parsing JPEG header: %s\n",
+ tinyjpeg_get_errorstring(data->jdec));
+ errno = EIO;
+ return -1;
+ }
+ tinyjpeg_get_size(data->jdec, &header_width, &header_height);
+
+ if (header_width != dest_fmt->fmt.pix.width ||
+ header_height != dest_fmt->fmt.pix.height) {
+ /* Check for (pixart) rotated JPEG */
+ if (header_width == dest_fmt->fmt.pix.height ||
+ header_height == dest_fmt->fmt.pix.width) {
+ if (!rotate)
+ dest = alloca(needed);
+ rotate += 90;
+ } else {
+ V4LCONVERT_ERR("unexpected width / height in JPEG header"
+ "expected: %ux%u, header: %ux%u\n",
+ dest_fmt->fmt.pix.width, dest_fmt->fmt.pix.height,
+ header_width, header_height);
+ errno = EIO;
+ return -1;
+ }
+ }
+
+ components[0] = dest;
+ components[1] = components[0] + dest_fmt->fmt.pix.width *
+ dest_fmt->fmt.pix.height;
+ components[2] = components[1] + (dest_fmt->fmt.pix.width *
+ dest_fmt->fmt.pix.height) / 4;
+
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ tinyjpeg_set_components(data->jdec, components, 1);
+ result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_RGB24);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ tinyjpeg_set_components(data->jdec, components, 1);
+ result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_BGR24);
+ break;
+ default:
+ tinyjpeg_set_components(data->jdec, components, 3);
+ result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P);
+ break;
+ }
+
+ if (result) {
+ /* Pixart webcam's seem to regulary generate corrupt frames, which
+ are best thrown away to avoid flashes in the video stream. Tell
+ the upper layer this is an intermediate fault and it should try
+ again with a new buffer by setting errno to EAGAIN */
+ if (src_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_PJPG) {
+ V4LCONVERT_ERR("Error decompressing JPEG: %s",
+ tinyjpeg_get_errorstring(data->jdec));
+ errno = EAGAIN;
+ return -1;
+ } else {
+ /* If the JPEG header checked out ok and we get an error during actual
+ decompression, log the error, but don't return an errorcode to the
+ application, so that the user gets what we managed to decompress */
+ fprintf(stderr, "libv4lconvert: Error decompressing JPEG: %s",
+ tinyjpeg_get_errorstring(data->jdec));
+ }
+ }
+ break;
+
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_bayer_to_rgb24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_bayer_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat);
+ break;
+ default:
+ v4lconvert_bayer_to_yuv420(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat);
+ break;
+ }
+ break;
+
+ /* YUYV line by line formats */
+ case V4L2_PIX_FMT_SPCA501:
+ case V4L2_PIX_FMT_SPCA505:
+ case V4L2_PIX_FMT_SPCA508:
+ {
+ unsigned char tmpbuf[dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height *
+ 3 / 2];
+ unsigned char *my_dst = (dest_fmt->fmt.pix.pixelformat !=
+ V4L2_PIX_FMT_YUV420) ? tmpbuf : dest;
+
+ switch (src_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SPCA501:
+ v4lconvert_spca501_to_yuv420(src, my_dst, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_SPCA505:
+ v4lconvert_spca505_to_yuv420(src, my_dst, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_SPCA508:
+ v4lconvert_spca508_to_yuv420(src, my_dst, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_yuv420_to_rgb24(tmpbuf, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_yuv420_to_bgr24(tmpbuf, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+ }
+
+ /* compressed bayer formats */
+ case V4L2_PIX_FMT_SPCA561:
+ case V4L2_PIX_FMT_SN9C10X:
+ case V4L2_PIX_FMT_PAC207:
+ {
+ unsigned char tmpbuf[dest_fmt->fmt.pix.width*dest_fmt->fmt.pix.height];
+ unsigned int bayer_fmt = 0;
+
+ switch (src_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SPCA561:
+ v4lconvert_decode_spca561(src, tmpbuf, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ bayer_fmt = V4L2_PIX_FMT_SGBRG8;
+ break;
+ case V4L2_PIX_FMT_SN9C10X:
+ v4lconvert_decode_sn9c10x(src, tmpbuf, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ bayer_fmt = V4L2_PIX_FMT_SBGGR8;
+ break;
+ case V4L2_PIX_FMT_PAC207:
+ v4lconvert_decode_pac207(src, tmpbuf, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ bayer_fmt = V4L2_PIX_FMT_SBGGR8;
+ break;
+ }
+
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_bayer_to_rgb24(tmpbuf, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height, bayer_fmt);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_bayer_to_bgr24(tmpbuf, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height, bayer_fmt);
+ break;
+ default:
+ v4lconvert_bayer_to_yuv420(tmpbuf, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height, bayer_fmt);
+ break;
+ }
+ break;
+ }
+
+ case V4L2_PIX_FMT_RGB24:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_swap_rgb(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ printf("FIXME add rgb24 -> yuv420 conversion\n");
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_swap_rgb(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ printf("FIXME add bgr24 -> yuv420 conversion\n");
+ break;
+ }
+ break;
+
+ case V4L2_PIX_FMT_YUV420:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_yuv420_to_rgb24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_yuv420_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+
+ case V4L2_PIX_FMT_YUYV:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_yuyv_to_rgb24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_yuyv_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ default:
+ v4lconvert_yuyv_to_yuv420(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+
+ case V4L2_PIX_FMT_YVYU:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_yvyu_to_rgb24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_yvyu_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ default:
+ v4lconvert_yvyu_to_yuv420(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+
+ default:
+ V4LCONVERT_ERR("Unknown src format in conversion\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Note when rotating dest is our temporary buffer to which our conversion
+ was done and _dest is the real dest! If the formats are identical no
+ conversion has been done! */
+ if (rotate && dest_fmt->fmt.pix.pixelformat == src_fmt->fmt.pix.pixelformat)
+ dest = src;
+
+ switch (rotate) {
+ case 0:
+ break;
+ case 90:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rotate90_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ v4lconvert_rotate90_yuv420(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+ case 180:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rotate180_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ v4lconvert_rotate180_yuv420(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+ default:
+ printf("FIXME add %d degrees rotation\n", rotate);
+ }
+
+ return needed;
+}
+
+const char *v4lconvert_get_error_message(struct v4lconvert_data *data)
+{
+ return data->error_msg;
+}
+
+static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
+ unsigned int pixelformat)
+{
+ int i, j, match;
+ struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat };
+
+ for (i = 0; ; i++) {
+ frmsize.index = i;
+ if (syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
+ break;
+
+ /* We got a framesize, check we don't have the same one already */
+ match = 0;
+ for (j = 0; j < data->no_framesizes && !match; j++) {
+ if (frmsize.type != data->framesizes[j].type)
+ continue;
+
+ switch(frmsize.type) {
+ case V4L2_FRMSIZE_TYPE_DISCRETE:
+ if(!memcmp(&frmsize.discrete, &data->framesizes[j].discrete,
+ sizeof(frmsize.discrete)))
+ match = 1;
+ break;
+ case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+ case V4L2_FRMSIZE_TYPE_STEPWISE:
+ if(!memcmp(&frmsize.stepwise, &data->framesizes[j].stepwise,
+ sizeof(frmsize.stepwise)))
+ match = 1;
+ break;
+ }
+ }
+ /* Add this framesize if it is not already in our list */
+ if (!match) {
+ if (data->no_framesizes == V4LCONVERT_MAX_FRAMESIZES) {
+ fprintf(stderr,
+ "libv4lconvert: warning more framesizes then I can handle!\n");
+ return;
+ }
+ data->framesizes[data->no_framesizes].type = frmsize.type;
+ switch(frmsize.type) {
+ case V4L2_FRMSIZE_TYPE_DISCRETE:
+ data->framesizes[data->no_framesizes].discrete = frmsize.discrete;
+ break;
+ case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+ case V4L2_FRMSIZE_TYPE_STEPWISE:
+ data->framesizes[data->no_framesizes].stepwise = frmsize.stepwise;
+ break;
+ }
+ data->no_framesizes++;
+ }
+ }
+}
+
+int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
+ struct v4l2_frmsizeenum *frmsize)
+{
+ if (!v4lconvert_supported_dst_format(frmsize->pixel_format))
+ return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
+
+ if (frmsize->index >= data->no_framesizes) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ frmsize->type = data->framesizes[frmsize->index].type;
+ switch(frmsize->type) {
+ case V4L2_FRMSIZE_TYPE_DISCRETE:
+ frmsize->discrete = data->framesizes[frmsize->index].discrete;
+ break;
+ case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+ case V4L2_FRMSIZE_TYPE_STEPWISE:
+ frmsize->stepwise = data->framesizes[frmsize->index].stepwise;
+ break;
+ }
+
+ return 0;
+}
+
+int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
+ struct v4l2_frmivalenum *frmival)
+{
+ int res;
+ struct v4l2_format src_fmt, dest_fmt;
+
+ if (!v4lconvert_supported_dst_format(frmival->pixel_format))
+ return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
+
+ /* Check which format we will be using to convert to frmival->pixel_format */
+ memset(&dest_fmt, 0, sizeof(dest_fmt));
+ dest_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dest_fmt.fmt.pix.pixelformat = frmival->pixel_format;
+ dest_fmt.fmt.pix.width = frmival->width;
+ dest_fmt.fmt.pix.height = frmival->height;
+ if ((res = v4lconvert_try_format(data, &dest_fmt, &src_fmt)))
+ return res;
+
+ /* Check the requested format is supported exactly as requested */
+ if (dest_fmt.fmt.pix.pixelformat != frmival->pixel_format ||
+ dest_fmt.fmt.pix.width != frmival->width ||
+ dest_fmt.fmt.pix.height != frmival->height) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Enumerate the frameintervals of the source format we will be using */
+ frmival->pixel_format = src_fmt.fmt.pix.pixelformat;
+ frmival->width = src_fmt.fmt.pix.width;
+ frmival->height = src_fmt.fmt.pix.height;
+ res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
+
+ /* Restore the requested format in the frmival struct */
+ frmival->pixel_format = dest_fmt.fmt.pix.pixelformat;
+ frmival->width = dest_fmt.fmt.pix.width;
+ frmival->height = dest_fmt.fmt.pix.height;
+
+ return res;
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/pac207.c b/v4l2-apps/libv4l/libv4lconvert/pac207.c
new file mode 100644
index 000000000..97ef4ebc0
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/pac207.c
@@ -0,0 +1,418 @@
+/*
+
+# PAC207 decoder
+# Bertrik.Sikken. Thomas Kaiser (C) 2005
+# Copyright (C) 2003 2004 2005 Michel Xhaard
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Note this code was originally licensed under the GNU GPL instead of the
+# GNU LGPL, its license has been changed with permission, see the permission
+# mails at the end of this file.
+
+*/
+
+#include <string.h>
+#include "libv4lconvert-priv.h"
+
+#define CLIP(color) (unsigned char)(((color)>0xFF)?0xff:(((color)<0)?0:(color)))
+
+/* FIXME not threadsafe */
+static int decoder_initialized = 0;
+
+static struct {
+ unsigned char is_abs;
+ unsigned char len;
+ signed char val;
+} table[256];
+
+static void init_pixart_decoder(void)
+{
+ int i;
+ int is_abs, val, len;
+ for (i = 0; i < 256; i++) {
+ is_abs = 0;
+ val = 0;
+ len = 0;
+ if ((i & 0xC0) == 0) {
+ /* code 00 */
+ val = 0;
+ len = 2;
+ } else if ((i & 0xC0) == 0x40) {
+ /* code 01 */
+ val = -5;
+ len = 2;
+ } else if ((i & 0xC0) == 0x80) {
+ /* code 10 */
+ val = +5;
+ len = 2;
+ } else if ((i & 0xF0) == 0xC0) {
+ /* code 1100 */
+ val = -10;
+ len = 4;
+ } else if ((i & 0xF0) == 0xD0) {
+ /* code 1101 */
+ val = +10;
+ len = 4;
+ } else if ((i & 0xF8) == 0xE0) {
+ /* code 11100 */
+ val = -15;
+ len = 5;
+ } else if ((i & 0xF8) == 0xE8) {
+ /* code 11101 */
+ val = +15;
+ len = 5;
+ } else if ((i & 0xFC) == 0xF0) {
+ /* code 111100 */
+ val = -20;
+ len = 6;
+ } else if ((i & 0xFC) == 0xF4) {
+ /* code 111101 */
+ val = +20;
+ len = 6;
+ } else if ((i & 0xF8) == 0xF8) {
+ /* code 11111xxxxxx */
+ is_abs = 1;
+ val = 0;
+ len = 5;
+ }
+ table[i].is_abs = is_abs;
+ table[i].val = val;
+ table[i].len = len;
+ }
+ decoder_initialized = 1;
+}
+
+static inline unsigned char getByte(const unsigned char *inp,
+ unsigned int bitpos)
+{
+ const unsigned char *addr;
+ addr = inp + (bitpos >> 3);
+ return (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
+}
+
+static inline unsigned short getShort(const unsigned char *pt)
+{
+ return ((pt[0] << 8) | pt[1]);
+}
+
+static int
+pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width)
+{
+ int col;
+ int val;
+ int bitpos;
+ unsigned char code;
+
+ if (!decoder_initialized)
+ init_pixart_decoder();
+
+ /* first two pixels are stored as raw 8-bit */
+ *outp++ = inp[2];
+ *outp++ = inp[3];
+ bitpos = 32;
+
+ /* main decoding loop */
+ for (col = 2; col < width; col++) {
+ /* get bitcode */
+
+ code = getByte(inp, bitpos);
+ bitpos += table[code].len;
+
+ /* calculate pixel value */
+ if (table[code].is_abs) {
+ /* absolute value: get 6 more bits */
+ code = getByte(inp, bitpos);
+ bitpos += 6;
+ *outp++ = code & 0xFC;
+ } else {
+ /* relative to left pixel */
+ val = outp[-2] + table[code].val;
+ *outp++ = CLIP(val);
+ }
+ }
+
+ /* return line length, rounded up to next 16-bit word */
+ return 2 * ((bitpos + 15) / 16);
+}
+
+void v4lconvert_decode_pac207(const unsigned char *inp, unsigned char *outp,
+ int width, int height)
+{
+/* we should received a whole frame with header and EOL marker
+in myframe->data and return a GBRG pattern in frame->tmpbuffer
+remove the header then copy line by line EOL is set with 0x0f 0xf0 marker
+or 0x1e 0xe1 for compressed line*/
+ unsigned short word;
+ int row;
+
+ /* iterate over all rows */
+ for (row = 0; row < height; row++) {
+ word = getShort(inp);
+ switch (word) {
+ case 0x0FF0:
+ memcpy(outp, inp + 2, width);
+ inp += (2 + width);
+ break;
+ case 0x1EE1:
+ inp += pac_decompress_row(inp, outp, width);
+ break;
+
+ case 0x2DD2: /* prefix for "stronger" compressed lines, currently the
+ kernel driver programs the cam so that we should not
+ get any of these */
+
+ default: /* corrupt frame */
+ /* FIXME add error reporting */
+ return;
+ }
+ outp += width;
+ }
+
+ return;
+}
+
+
+
+
+/*
+Return-Path: <thomas@kaiser-linux.li>
+Received: from koko.hhs.nl ([145.52.2.16] verified)
+ by hhs.nl (CommuniGate Pro SMTP 4.3.6)
+ with ESMTP id 88906346 for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 01:17:00 +0200
+Received: from exim (helo=koko)
+ by koko.hhs.nl with local-smtp (Exim 4.62)
+ (envelope-from <thomas@kaiser-linux.li>)
+ id 1KBeEW-0001qu-H6
+ for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 01:17:00 +0200
+Received: from [192.87.102.74] (port=41049 helo=filter6-ams.mf.surf.net)
+ by koko.hhs.nl with esmtp (Exim 4.62)
+ (envelope-from <thomas@kaiser-linux.li>)
+ id 1KBeEV-0001qn-2T
+ for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 01:17:00 +0200
+Received: from smtp0.lie-comtel.li (smtp0.lie-comtel.li [217.173.238.80])
+ by filter6-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5PNGwSF007539
+ for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 01:16:58 +0200
+Received: from localhost (localhost.lie-comtel.li [127.0.0.1])
+ by smtp0.lie-comtel.li (Postfix) with ESMTP id DDB609FEC1D;
+ Thu, 26 Jun 2008 00:16:56 +0100 (GMT-1)
+X-Virus-Scanned: Virus scanned by amavis at smtp.lie-comtel.li
+Received: from [192.168.0.16] (217-173-228-198.cmts.powersurf.li [217.173.228.198])
+ by smtp0.lie-comtel.li (Postfix) with ESMTP id 80B589FEC19;
+ Thu, 26 Jun 2008 00:16:56 +0100 (GMT-1)
+Message-ID: <4862D211.3000802@kaiser-linux.li>
+Date: Thu, 26 Jun 2008 01:17:37 +0200
+From: Thomas Kaiser <thomas@kaiser-linux.li>
+User-Agent: Thunderbird 2.0.0.14 (X11/20080505)
+MIME-Version: 1.0
+To: Hans de Goede <j.w.r.degoede@hhs.nl>
+CC: Thomas Kaiser <spca5xx@kaiser-linux.li>, bertrik@zonnet.nl,
+ mxhaard@magic.fr
+Subject: Re: pac207 bayer decompression algorithm license question
+References: <4862C0A4.3060003@hhs.nl>
+In-Reply-To: <4862C0A4.3060003@hhs.nl>
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+X-Canit-CHI2: 0.00
+X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
+X-Spam-Score: 0.00 () [Tag at 8.00]
+X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
+X-Canit-Stats-ID: 88604132 - 38b3b44cd798
+X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.74
+X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 25062008 #787666, status: clean
+
+Hello Hans
+
+Hans de Goede wrote:
+> Hi,
+>
+> As you may have seen on the mailinglist, I've created a userspace
+> library to handle cam specific format handling in userspace where it
+> belongs, see:
+> http://hansdegoede.livejournal.com/
+Yes, I saw it on the mail list and I think it is a good idea :-)
+>
+> I would like to also add support for decompressing the pac207's
+> compressed bayer to this lib (and remove it from the kernel driver)
+> for this I need permission to relicense the decompress code under the
+> LGPL (version 2 or later).
+Actually, this was done by Bertrik Sikken (bertrik@zonnet.nl), Michel
+Xhaard (mxhaard@magic.fr) and me. But Bertrik was the one who found out
+how to decode the lines :-)
+>
+> Can you give me permission for this, or if the code is not yours put
+> me in contact with someone who can?
+For me it's no problem to release it with LGPL. Maybe you have to ask
+the other one's also.
+>
+> Thanks & Regards,
+>
+> Hans
+
+Rgeards, Thomas
+*/
+
+/*
+Return-Path: <mxhaard@magic.fr>
+Received: from koko.hhs.nl ([145.52.2.16] verified)
+ by hhs.nl (CommuniGate Pro SMTP 4.3.6)
+ with ESMTP id 88910192 for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 09:15:37 +0200
+Received: from exim (helo=koko)
+ by koko.hhs.nl with local-smtp (Exim 4.62)
+ (envelope-from <mxhaard@magic.fr>)
+ id 1KBlhh-0006Fi-Oe
+ for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 09:15:37 +0200
+Received: from [194.171.167.220] (port=54180 helo=filter4-til.mf.surf.net)
+ by koko.hhs.nl with esmtp (Exim 4.62)
+ (envelope-from <mxhaard@magic.fr>)
+ id 1KBlhh-0006Fd-FY
+ for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 09:15:37 +0200
+Received: from smtp4-g19.free.fr (smtp4-g19.free.fr [212.27.42.30])
+ by filter4-til.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5Q7FY1I006360
+ for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 09:15:34 +0200
+Received: from smtp4-g19.free.fr (localhost.localdomain [127.0.0.1])
+ by smtp4-g19.free.fr (Postfix) with ESMTP id 51C683EA0E7;
+ Thu, 26 Jun 2008 09:15:34 +0200 (CEST)
+Received: from [192.168.1.11] (lns-bzn-54-82-251-105-53.adsl.proxad.net [82.251.105.53])
+ by smtp4-g19.free.fr (Postfix) with ESMTP id 1149E3EA0C7;
+ Thu, 26 Jun 2008 09:15:34 +0200 (CEST)
+From: Michel Xhaard <mxhaard@magic.fr>
+To: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: Re: pac207 bayer decompression algorithm license question
+Date: Thu, 26 Jun 2008 11:15:32 +0200
+User-Agent: KMail/1.9.5
+Cc: bertrik@zonnet.nl, spca5xx@kaiser-linux.li,
+ "Jean-Francois Moine" <moinejf@free.fr>
+References: <48633F02.3040108@hhs.nl>
+In-Reply-To: <48633F02.3040108@hhs.nl>
+MIME-Version: 1.0
+Content-Type: text/plain;
+ charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+Message-Id: <200806261115.32909.mxhaard@magic.fr>
+X-Canit-CHI2: 0.00
+X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
+X-Spam-Score: 0.00 () [Tag at 8.00]
+X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
+X-Canit-Stats-ID: 88656338 - 0dde233cb8b5
+X-Scanned-By: CanIt (www . roaringpenguin . com) on 194.171.167.220
+X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 26062008 #787720, status: clean
+
+Le jeudi 26 juin 2008 09:02, Hans de Goede a =E9crit=A0:
+> Hi,
+>
+> As you may have seen on the mailinglist, I've created a userspace library
+> to handle cam specific format handling in userspace, see:
+> http://hansdegoede.livejournal.com/
+>
+> I would like to also add support for decompressing the pac207's compressed
+> bayer to this lib (and remove it from the kernel driver) and I've heard
+> from Thomas Kaiser that you are a co-author of the decompression code. In
+> order to add support for decompressing pac207 compressed bayer to libv4l I
+> need permission to relicense the decompression code under the LGPL (versi=
+on
+> 2 or later).
+>
+> Can you give me permission for this?
+>
+> Thanks & Regards,
+>
+> Hans
+>
+>
+>
+> p.s.
+>
+> Thomas has already given permission.
+
+=46or me it is ok and a good idea for all free world familly ;-).
+Bests regards
+=2D-=20
+Michel Xhaard
+http://mxhaard.free.fr
+*/
+
+/*
+Return-Path: <bertrik@sikken.nl>
+Received: from koko.hhs.nl ([145.52.2.16] verified)
+ by hhs.nl (CommuniGate Pro SMTP 4.3.6)
+ with ESMTP id 88940205 for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 22:03:30 +0200
+Received: from exim (helo=koko)
+ by koko.hhs.nl with local-smtp (Exim 4.62)
+ (envelope-from <bertrik@sikken.nl>)
+ id 1KBxgo-0003Dj-ET
+ for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 22:03:30 +0200
+Received: from [192.87.102.69] (port=51992 helo=filter1-ams.mf.surf.net)
+ by koko.hhs.nl with esmtp (Exim 4.62)
+ (envelope-from <bertrik@sikken.nl>)
+ id 1KBxgo-0003Dd-5i
+ for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 22:03:30 +0200
+Received: from pelian.kabelfoon.nl (pelian3.kabelfoon.nl [62.45.45.106])
+ by filter1-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5QK3ThE007720
+ for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 22:03:29 +0200
+Received: from [192.168.1.1] (062-015-045-062.dynamic.caiway.nl [62.45.15.62])
+ by pelian.kabelfoon.nl (Postfix) with ESMTP id 9239B428100
+ for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 22:03:29 +0200 (CEST)
+Message-ID: <4863F611.80104@sikken.nl>
+Date: Thu, 26 Jun 2008 22:03:29 +0200
+From: Bertrik Sikken <bertrik@sikken.nl>
+User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
+MIME-Version: 1.0
+To: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: Re: pac207 bayer decompression algorithm license question
+References: <48633F02.3040108@hhs.nl>
+In-Reply-To: <48633F02.3040108@hhs.nl>
+X-Enigmail-Version: 0.95.6
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+X-Canit-CHI2: 0.00
+X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
+X-Spam-Score: 0.00 () [Tag at 8.00]
+X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
+X-Canit-Stats-ID: 88938005 - ef1f0836ffc7
+X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.69
+X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 26062008 #787877, status: clean
+
+Hallo Hans,
+
+Hans de Goede wrote:
+> Hi,
+>
+> As you may have seen on the mailinglist, I've created a userspace
+> library to
+> handle cam specific format handling in userspace, see:
+> http://hansdegoede.livejournal.com/
+
+O leuk, zoiets is naar mijn idee precies wat er nodig is voor webcam
+support onder linux. Ik ben een jaar of 3 geleden heel actief geweest
+met een aantal webcams, maar doe er tegenwoordig helemaal niets meer
+aan.
+
+> I would like to also add support for decompressing the pac207's compressed
+> bayer to this lib (and remove it from the kernel driver) and I've heard
+> from Thomas Kaiser that you are a co-author of the decompression code.
+> In order to add support for decompressing pac207 compressed bayer to
+> libv4l I need
+> permission to relicense the decompression code under the LGPL (version 2
+> or later).
+>
+> Can you give me permission for this?
+
+Ja, vind ik goed.
+
+Vriendelijke groet,
+Bertrik
+*/
diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
new file mode 100644
index 000000000..0f26b227a
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
@@ -0,0 +1,316 @@
+/*
+
+# RGB <-> YUV conversion routines
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "libv4lconvert-priv.h"
+
+#define RGB2YUV(r,g,b,y,u,v) \
+ (y) = (( 8453*(r) + 16594*(g) + 3223*(b) + 524288) >> 15); \
+ (u) = (( -4878*(r) - 9578*(g) + 14456*(b) + 4210688) >> 15); \
+ (v) = (( 14456*(r) - 12105*(g) - 2351*(b) + 4210688) >> 15)
+
+#define YUV2R(y, u, v) ({ \
+ int r = (y) + ((((v)-128)*1436) >> 10); r > 255 ? 255 : r < 0 ? 0 : r; })
+#define YUV2G(y, u, v) ({ \
+ int g = (y) - ((((u)-128)*352 + ((v)-128)*731) >> 10); g > 255 ? 255 : g < 0 ? 0 : g; })
+#define YUV2B(y, u, v) ({ \
+ int b = (y) + ((((u)-128)*1814) >> 10); b > 255 ? 255 : b < 0 ? 0 : b; })
+
+#define CLIP(color) (unsigned char)(((color)>0xFF)?0xff:(((color)<0)?0:(color)))
+
+void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int i,j;
+
+ const unsigned char *ysrc = src;
+ const unsigned char *usrc = src + width * height;
+ const unsigned char *vsrc = usrc + (width * height) / 4;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+#if 1 /* fast slightly less accurate multiplication free code */
+ int u1 = (((*usrc - 128) << 7) + (*usrc - 128)) >> 6;
+ int rg = (((*usrc - 128) << 1) + (*usrc - 128) +
+ ((*vsrc - 128) << 2) + ((*vsrc - 128) << 1)) >> 3;
+ int v1 = (((*vsrc - 128) << 1) + (*vsrc - 128)) >> 1;
+
+ *dest++ = CLIP(*ysrc + u1);
+ *dest++ = CLIP(*ysrc - rg);
+ *dest++ = CLIP(*ysrc + v1);
+ ysrc++;
+
+ *dest++ = CLIP(*ysrc + u1);
+ *dest++ = CLIP(*ysrc - rg);
+ *dest++ = CLIP(*ysrc + v1);
+#else
+ *dest++ = YUV2B(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2G(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2R(*ysrc, *usrc, *vsrc);
+ ysrc++;
+
+ *dest++ = YUV2B(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2G(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2R(*ysrc, *usrc, *vsrc);
+#endif
+ ysrc++;
+ usrc++;
+ vsrc++;
+ }
+ /* Rewind u and v for next line */
+ if (i&1) {
+ usrc -= width / 2;
+ vsrc -= width / 2;
+ }
+ }
+}
+
+void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int i,j;
+
+ const unsigned char *ysrc = src;
+ const unsigned char *usrc = src + width * height;
+ const unsigned char *vsrc = usrc + (width * height) / 4;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+#if 1 /* fast slightly less accurate multiplication free code */
+ int u1 = (((*usrc - 128) << 7) + (*usrc - 128)) >> 6;
+ int rg = (((*usrc - 128) << 1) + (*usrc - 128) +
+ ((*vsrc - 128) << 2) + ((*vsrc - 128) << 1)) >> 3;
+ int v1 = (((*vsrc - 128) << 1) + (*vsrc - 128)) >> 1;
+
+ *dest++ = CLIP(*ysrc + v1);
+ *dest++ = CLIP(*ysrc - rg);
+ *dest++ = CLIP(*ysrc + u1);
+ ysrc++;
+
+ *dest++ = CLIP(*ysrc + v1);
+ *dest++ = CLIP(*ysrc - rg);
+ *dest++ = CLIP(*ysrc + u1);
+#else
+ *dest++ = YUV2R(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2G(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2B(*ysrc, *usrc, *vsrc);
+ ysrc++;
+
+ *dest++ = YUV2R(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2G(*ysrc, *usrc, *vsrc);
+ *dest++ = YUV2B(*ysrc, *usrc, *vsrc);
+#endif
+ ysrc++;
+ usrc++;
+ vsrc++;
+ }
+ /* Rewind u and v for next line */
+ if (i&1) {
+ usrc -= width / 2;
+ vsrc -= width / 2;
+ }
+ }
+}
+
+void v4lconvert_yuyv_to_bgr24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[1];
+ int v = src[3];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + u1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + v1);
+
+ *dest++ = CLIP(src[2] + u1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + v1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[1];
+ int v = src[3];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + v1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + u1);
+
+ *dest++ = CLIP(src[2] + v1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + u1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int i, j;
+ const unsigned char *src1;
+ unsigned char *vdest;
+
+ /* copy the Y values */
+ src1 = src;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = src1[0];
+ *dest++ = src1[2];
+ src1 += 4;
+ }
+ }
+
+ /* copy the U and V values */
+ src++; /* point to V */
+ src1 = src + width * 2; /* next line */
+ vdest = dest + width * height / 4;
+ for (i = 0; i < height; i += 2) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = ((int) src[0] + src1[0]) / 2; /* U */
+ *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
+ src += 4;
+ src1 += 4;
+ }
+ src = src1;
+ src1 += width * 2;
+ }
+}
+
+void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[3];
+ int v = src[1];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + u1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + v1);
+
+ *dest++ = CLIP(src[2] + u1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + v1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[3];
+ int v = src[1];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + v1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + u1);
+
+ *dest++ = CLIP(src[2] + v1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + u1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int i, j;
+ const unsigned char *src1;
+ unsigned char *vdest;
+
+ /* copy the Y values */
+ src1 = src;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = src1[0];
+ *dest++ = src1[2];
+ src1 += 4;
+ }
+ }
+
+ /* copy the U and V values */
+ src++; /* point to V */
+ src1 = src + width * 2; /* next line */
+ vdest = dest + width * height / 4;
+ for (i = 0; i < height; i += 2) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = ((int) src[2] + src1[2]) / 2; /* U */
+ *vdest++ = ((int) src[0] + src1[0]) / 2; /* V */
+ src += 4;
+ src1 += 4;
+ }
+ src = src1;
+ src1 += width * 2;
+ }
+}
+
+void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i;
+
+ for (i = 0; i < (width * height); i++) {
+ unsigned char tmp0, tmp1;
+ tmp0 = *src++;
+ tmp1 = *src++;
+ *dst++ = *src++;
+ *dst++ = tmp1;
+ *dst++ = tmp0;
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/sn9c10x.c b/v4l2-apps/libv4l/libv4lconvert/sn9c10x.c
new file mode 100644
index 000000000..4ea526d49
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/sn9c10x.c
@@ -0,0 +1,287 @@
+/*
+# sonix decoder
+# Bertrik.Sikken. (C) 2005
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Note this code was originally licensed under the GNU GPL instead of the
+# GNU LGPL, its license has been changed with permission, see the permission
+# mail at the end of this file.
+*/
+
+#include "libv4lconvert-priv.h"
+
+#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x))
+
+typedef struct {
+ int is_abs;
+ int len;
+ int val;
+ int unk;
+} code_table_t;
+
+
+/* local storage */
+/* FIXME not thread safe !! */
+static code_table_t table[256];
+static int init_done = 0;
+
+/* global variable */
+static int sonix_unknown = 0;
+
+/*
+ sonix_decompress_init
+ =====================
+ pre-calculates a locally stored table for efficient huffman-decoding.
+
+ Each entry at index x in the table represents the codeword
+ present at the MSB of byte x.
+
+*/
+static void sonix_decompress_init(void)
+{
+ int i;
+ int is_abs, val, len, unk;
+
+ for (i = 0; i < 256; i++) {
+ is_abs = 0;
+ val = 0;
+ len = 0;
+ unk = 0;
+ if ((i & 0x80) == 0) {
+ /* code 0 */
+ val = 0;
+ len = 1;
+ }
+ else if ((i & 0xE0) == 0x80) {
+ /* code 100 */
+ val = +4;
+ len = 3;
+ }
+ else if ((i & 0xE0) == 0xA0) {
+ /* code 101 */
+ val = -4;
+ len = 3;
+ }
+ else if ((i & 0xF0) == 0xD0) {
+ /* code 1101 */
+ val = +11;
+ len = 4;
+ }
+ else if ((i & 0xF0) == 0xF0) {
+ /* code 1111 */
+ val = -11;
+ len = 4;
+ }
+ else if ((i & 0xF8) == 0xC8) {
+ /* code 11001 */
+ val = +20;
+ len = 5;
+ }
+ else if ((i & 0xFC) == 0xC0) {
+ /* code 110000 */
+ val = -20;
+ len = 6;
+ }
+ else if ((i & 0xFC) == 0xC4) {
+ /* code 110001xx: unknown */
+ val = 0;
+ len = 8;
+ unk = 1;
+ }
+ else if ((i & 0xF0) == 0xE0) {
+ /* code 1110xxxx */
+ is_abs = 1;
+ val = (i & 0x0F) << 4;
+ len = 8;
+ }
+ table[i].is_abs = is_abs;
+ table[i].val = val;
+ table[i].len = len;
+ table[i].unk = unk;
+ }
+
+ sonix_unknown = 0;
+ init_done = 1;
+}
+
+
+/*
+ sonix_decompress
+ ================
+ decompresses an image encoded by a SN9C101 camera controller chip.
+
+ IN width
+ height
+ inp pointer to compressed frame (with header already stripped)
+ OUT outp pointer to decompressed frame
+
+ Returns 0 if the operation was successful.
+ Returns <0 if operation failed.
+
+*/
+void v4lconvert_decode_sn9c10x(const unsigned char *inp, unsigned char *outp,
+ int width, int height)
+{
+ int row, col;
+ int val;
+ int bitpos;
+ unsigned char code;
+ const unsigned char *addr;
+
+ if (!init_done)
+ sonix_decompress_init();
+
+ bitpos = 0;
+ for (row = 0; row < height; row++) {
+
+ col = 0;
+
+ /* first two pixels in first two rows are stored as raw 8-bit */
+ if (row < 2) {
+ addr = inp + (bitpos >> 3);
+ code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
+ bitpos += 8;
+ *outp++ = code;
+
+ addr = inp + (bitpos >> 3);
+ code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
+ bitpos += 8;
+ *outp++ = code;
+
+ col += 2;
+ }
+
+ while (col < width) {
+ /* get bitcode from bitstream */
+ addr = inp + (bitpos >> 3);
+ code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
+
+ /* update bit position */
+ bitpos += table[code].len;
+
+ /* update code statistics */
+ sonix_unknown += table[code].unk;
+
+ /* calculate pixel value */
+ val = table[code].val;
+ if (!table[code].is_abs) {
+ /* value is relative to top and left pixel */
+ if (col < 2) {
+ /* left column: relative to top pixel */
+ val += outp[-2*width];
+ }
+ else if (row < 2) {
+ /* top row: relative to left pixel */
+ val += outp[-2];
+ }
+ else {
+ /* main area: average of left pixel and top pixel */
+ val += (outp[-2] + outp[-2*width]) / 2;
+ }
+ }
+
+ /* store pixel */
+ *outp++ = CLAMP(val);
+ col++;
+ }
+ }
+}
+
+/*
+Return-Path: <bertrik@sikken.nl>
+Received: from koko.hhs.nl ([145.52.2.16] verified)
+ by hhs.nl (CommuniGate Pro SMTP 4.3.6)
+ with ESMTP id 89132066 for j.w.r.degoede@hhs.nl; Thu, 03 Jul 2008 15:19:55 +0200
+Received: from exim (helo=koko)
+ by koko.hhs.nl with local-smtp (Exim 4.62)
+ (envelope-from <bertrik@sikken.nl>)
+ id 1KEOj5-0000nq-KR
+ for j.w.r.degoede@hhs.nl; Thu, 03 Jul 2008 15:19:55 +0200
+Received: from [192.87.102.69] (port=33783 helo=filter1-ams.mf.surf.net)
+ by koko.hhs.nl with esmtp (Exim 4.62)
+ (envelope-from <bertrik@sikken.nl>)
+ id 1KEOj5-0000nj-7r
+ for j.w.r.degoede@hhs.nl; Thu, 03 Jul 2008 15:19:55 +0200
+Received: from cardassian.kabelfoon.nl (cardassian3.kabelfoon.nl [62.45.45.105])
+ by filter1-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m63DJsKW032598
+ for <j.w.r.degoede@hhs.nl>; Thu, 3 Jul 2008 15:19:54 +0200
+Received: from [192.168.1.1] (044-013-045-062.dynamic.caiway.nl [62.45.13.44])
+ by cardassian.kabelfoon.nl (Postfix) with ESMTP id 77761341D9A
+ for <j.w.r.degoede@hhs.nl>; Thu, 3 Jul 2008 15:19:54 +0200 (CEST)
+Message-ID: <486CD1F9.8000307@sikken.nl>
+Date: Thu, 03 Jul 2008 15:19:53 +0200
+From: Bertrik Sikken <bertrik@sikken.nl>
+User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
+MIME-Version: 1.0
+To: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: Re: pac207 bayer decompression algorithm license question
+References: <48633F02.3040108@hhs.nl> <4863F611.80104@sikken.nl> <486CC6AF.7050509@hhs.nl>
+In-Reply-To: <486CC6AF.7050509@hhs.nl>
+X-Enigmail-Version: 0.95.6
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+X-Canit-CHI2: 0.00
+X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
+X-Spam-Score: 0.00 () [Tag at 8.00]
+X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
+X-Canit-Stats-ID: 90943081 - 6a9ff19e8165
+X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.69
+X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 03072008 #811719, status: clean
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+Hans de Goede wrote:
+| Bertrik Sikken wrote:
+|> Hallo Hans,
+|>
+|> Hans de Goede wrote:
+|>> I would like to also add support for decompressing the pac207's
+|>> compressed
+|>> bayer to this lib (and remove it from the kernel driver) and I've
+|>> heard from Thomas Kaiser that you are a co-author of the
+|>> decompression code. In order to add support for decompressing pac207
+|>> compressed bayer to libv4l I need
+|>> permission to relicense the decompression code under the LGPL
+|>> (version 2 or later).
+|>>
+|>> Can you give me permission for this?
+|>
+|> Ja, vind ik goed.
+|>
+|
+| Thanks!
+|
+| I'm currently working on adding support for the sn9c10x bayer
+| compression to libv4l too, and I noticed this was written by you too.
+|
+| May I have your permission to relicense the sn9c10x bayer decompression
+| code under the LGPL (version 2 or later)?
+
+I hereby grant you permission to relicense the sn9c10x bayer
+decompression code under the LGPL (version 2 or later).
+
+Kind regards,
+Bertrik
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.7 (MingW32)
+Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
+
+iD8DBQFIbNH5ETD6mlrWxPURAipvAJ9sv1ZpHyb81NMFejr6x0wqHX3i7QCfRDoB
+jZi2e5lUjEh5KvS0dqXbi9I=
+=KQfR
+-----END PGP SIGNATURE-----
+*/
diff --git a/v4l2-apps/libv4l/libv4lconvert/spca501.c b/v4l2-apps/libv4l/libv4lconvert/spca501.c
new file mode 100644
index 000000000..9157629e3
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/spca501.c
@@ -0,0 +1,126 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libv4lconvert-priv.h"
+
+/* YUYV per line */
+void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i,j;
+ unsigned long *lsrc = (unsigned long *)src;
+
+ for (i = 0; i < height; i += 2) {
+ /* -128 - 127 --> 0 - 255 and copy first line Y */
+ unsigned long *ldst = (unsigned long *)(dst + i * width);
+ for (j = 0; j < width; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy 1 line U */
+ ldst = (unsigned long *)(dst + width * height + i * width / 4);
+ for (j = 0; j < width/2; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy second line Y */
+ ldst = (unsigned long *)(dst + i * width + width);
+ for (j = 0; j < width; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy 1 line V */
+ ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
+ for (j = 0; j < width/2; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+ }
+}
+
+/* YYUV per line */
+void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i,j;
+ unsigned long *lsrc = (unsigned long *)src;
+
+ for (i = 0; i < height; i += 2) {
+ /* -128 - 127 --> 0 - 255 and copy 2 lines of Y */
+ unsigned long *ldst = (unsigned long *)(dst + i * width);
+ for (j = 0; j < width*2; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy 1 line U */
+ ldst = (unsigned long *)(dst + width * height + i * width / 4);
+ for (j = 0; j < width/2; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy 1 line V */
+ ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
+ for (j = 0; j < width/2; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+ }
+}
+
+/* YUVY per line */
+void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i,j;
+ unsigned long *lsrc = (unsigned long *)src;
+
+ for (i = 0; i < height; i += 2) {
+ /* -128 - 127 --> 0 - 255 and copy first line Y */
+ unsigned long *ldst = (unsigned long *)(dst + i * width);
+ for (j = 0; j < width; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy 1 line U */
+ ldst = (unsigned long *)(dst + width * height + i * width / 4);
+ for (j = 0; j < width/2; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy 1 line V */
+ ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
+ for (j = 0; j < width/2; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+
+ /* -128 - 127 --> 0 - 255 and copy second line Y */
+ ldst = (unsigned long *)(dst + i * width + width);
+ for (j = 0; j < width; j += sizeof(long)) {
+ *ldst = *lsrc++;
+ *ldst++ ^= 0x8080808080808080ULL;
+ }
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/spca561-decompress.c b/v4l2-apps/libv4l/libv4lconvert/spca561-decompress.c
new file mode 100644
index 000000000..01eed4ec5
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/spca561-decompress.c
@@ -0,0 +1,1003 @@
+/*
+
+# Spca561decoder (C) 2005 Andrzej Szombierski [qq@kuku.eu.org]
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Note this code was originally licensed under the GNU GPL instead of the
+# GNU LGPL, its license has been changed with permission, see the permission
+# mail at the end of this file.
+
+*/
+
+/*
+ * Decoder for compressed spca561 images
+ * It was developed for "Labtec WebCam Elch 2(SPCA561A)" (046d:0929)
+ * but it might work with other spca561 cameras
+ */
+#include <string.h>
+#include "libv4lconvert-priv.h"
+
+/*fixme: not reentrant */
+static unsigned int bit_bucket;
+static const unsigned char *input_ptr;
+
+static inline void refill(int *bitfill)
+{
+ if (*bitfill < 8) {
+ bit_bucket = (bit_bucket << 8) | *(input_ptr++);
+ *bitfill += 8;
+ }
+}
+
+static inline int nbits(int *bitfill, int n)
+{
+ bit_bucket = (bit_bucket << 8) | *(input_ptr++);
+ *bitfill -= n;
+ return (bit_bucket >> (*bitfill & 0xff)) & ((1 << n) - 1);
+}
+
+static inline int _nbits(int *bitfill, int n)
+{
+ *bitfill -= n;
+ return (bit_bucket >> (*bitfill & 0xff)) & ((1 << n) - 1);
+}
+
+static int fun_A(int *bitfill)
+{
+ int ret;
+ static int tab[] = {
+ 12, 13, 14, 15, 16, 17, 18, 19, -12, -13, -14, -15,
+ -16, -17, -18, -19, -19
+ };
+
+ ret = tab[nbits(bitfill, 4)];
+
+ refill(bitfill);
+ return ret;
+}
+static int fun_B(int *bitfill)
+{
+ static int tab1[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 16, 17,
+ 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30
+ };
+ static int tab[] =
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -5,
+ -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17,
+ -18, -19
+ };
+ unsigned int tmp;
+
+ tmp = nbits(bitfill, 7) - 68;
+ refill(bitfill);
+ if (tmp > 47)
+ return 0xff;
+ return tab[tab1[tmp]];
+}
+static int fun_C(int *bitfill, int gkw)
+{
+ static int tab1[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 12, 13,
+ 14,
+ 15, 16, 17, 18, 19, 20, 21, 22
+ };
+ static int tab[] =
+ { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -9, -10, -11,
+ -12, -13, -14, -15, -16, -17, -18, -19
+ };
+ unsigned int tmp;
+
+ if (gkw == 0xfe) {
+ if (nbits(bitfill, 1) == 0)
+ return 7;
+ else
+ return -8;
+ }
+
+ if (gkw != 0xff)
+ return 0xff;
+
+ tmp = nbits(bitfill, 7) - 72;
+ if (tmp > 43)
+ return 0xff;
+
+ refill(bitfill);
+ return tab[tab1[tmp]];
+}
+static int fun_D(int *bitfill, int gkw)
+{
+ if (gkw == 0xfd) {
+ if (nbits(bitfill, 1) == 0)
+ return 12;
+ return -13;
+ }
+
+ if (gkw == 0xfc) {
+ if (nbits(bitfill, 1) == 0)
+ return 13;
+ return -14;
+ }
+
+ if (gkw == 0xfe) {
+ switch (nbits(bitfill, 2)) {
+ case 0:
+ return 14;
+ case 1:
+ return -15;
+ case 2:
+ return 15;
+ case 3:
+ return -16;
+ }
+ }
+
+ if (gkw == 0xff) {
+ switch (nbits(bitfill, 3)) {
+ case 4:
+ return 16;
+ case 5:
+ return -17;
+ case 6:
+ return 17;
+ case 7:
+ return -18;
+ case 2:
+ return _nbits(bitfill, 1) ? 0xed : 0x12;
+ case 3:
+ (*bitfill)--;
+ return 18;
+ }
+ return 0xff;
+ }
+ return gkw;
+}
+
+static int fun_E(int cur_byte, int *bitfill)
+{
+ static int tab0[] = { 0, -1, 1, -2, 2, -3, 3, -4 };
+ static int tab1[] = { 4, -5, 5, -6, 6, -7, 7, -8 };
+ static int tab2[] = { 8, -9, 9, -10, 10, -11, 11, -12 };
+ static int tab3[] = { 12, -13, 13, -14, 14, -15, 15, -16 };
+ static int tab4[] = { 16, -17, 17, -18, 18, -19, 19, -19 };
+
+ if ((cur_byte & 0xf0) >= 0x80) {
+ *bitfill -= 4;
+ return tab0[(cur_byte >> 4) & 7];
+ }
+ if ((cur_byte & 0xc0) == 0x40) {
+ *bitfill -= 5;
+ return tab1[(cur_byte >> 3) & 7];
+
+ }
+ if ((cur_byte & 0xe0) == 0x20) {
+ *bitfill -= 6;
+ return tab2[(cur_byte >> 2) & 7];
+
+ }
+ if ((cur_byte & 0xf0) == 0x10) {
+ *bitfill -= 7;
+ return tab3[(cur_byte >> 1) & 7];
+
+ }
+ if ((cur_byte & 0xf8) == 8) {
+ *bitfill -= 8;
+ return tab4[cur_byte & 7];
+ }
+ return 0xff;
+}
+
+static int fun_F(int cur_byte, int *bitfill)
+{
+ *bitfill -= 5;
+ switch (cur_byte & 0xf8) {
+ case 0x80:
+ return 0;
+ case 0x88:
+ return -1;
+ case 0x90:
+ return 1;
+ case 0x98:
+ return -2;
+ case 0xa0:
+ return 2;
+ case 0xa8:
+ return -3;
+ case 0xb0:
+ return 3;
+ case 0xb8:
+ return -4;
+ case 0xc0:
+ return 4;
+ case 0xc8:
+ return -5;
+ case 0xd0:
+ return 5;
+ case 0xd8:
+ return -6;
+ case 0xe0:
+ return 6;
+ case 0xe8:
+ return -7;
+ case 0xf0:
+ return 7;
+ case 0xf8:
+ return -8;
+ }
+
+ *bitfill -= 1;
+ switch (cur_byte & 0xfc) {
+ case 0x40:
+ return 8;
+ case 0x44:
+ return -9;
+ case 0x48:
+ return 9;
+ case 0x4c:
+ return -10;
+ case 0x50:
+ return 10;
+ case 0x54:
+ return -11;
+ case 0x58:
+ return 11;
+ case 0x5c:
+ return -12;
+ case 0x60:
+ return 12;
+ case 0x64:
+ return -13;
+ case 0x68:
+ return 13;
+ case 0x6c:
+ return -14;
+ case 0x70:
+ return 14;
+ case 0x74:
+ return -15;
+ case 0x78:
+ return 15;
+ case 0x7c:
+ return -16;
+ }
+
+ *bitfill -= 1;
+ switch (cur_byte & 0xfe) {
+ case 0x20:
+ return 16;
+ case 0x22:
+ return -17;
+ case 0x24:
+ return 17;
+ case 0x26:
+ return -18;
+ case 0x28:
+ return 18;
+ case 0x2a:
+ return -19;
+ case 0x2c:
+ return 19;
+ }
+
+ *bitfill += 7;
+ return 0xff;
+}
+
+static int internal_spca561_decode(int width, int height,
+ const unsigned char *inbuf,
+ unsigned char *outbuf)
+{
+ /* buffers */
+ static int accum[8 * 8 * 8];
+ static int i_hits[8 * 8 * 8];
+
+ const int nbits_A[] =
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5,
+ 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ };
+ const int tab_A[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 11, -11, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
+ 10, 10,
+ 255, 254, -4,
+ -4, -5, -5, -6, -6, -7, -7, -8, -8, -9, -9, -10, -10, -1,
+ -1, -1,
+ -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3,
+ 3, 3, 3,
+ -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3,
+ -3, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1,
+ 1
+ };
+
+ const int nbits_B[] =
+ { 0, 8, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2,
+ 2, 2,
+ 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2,
+ 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2,
+ 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ };
+ const int tab_B[] =
+ { 0xff, -4, 3, 3, -3, -3, -3, -3, 2, 2, 2, 2, 2, 2, 2, 2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ const int nbits_C[] =
+ { 0, 0, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2,
+ 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2,
+ 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2,
+ 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2,
+ 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ };
+ const int tab_C[] =
+ { 0xff, 0xfe, 6, -7, 5, 5, -6, -6, 4, 4, 4, 4, -5, -5, -5, -5,
+ 3, 3, 3, 3, 3, 3, 3, 3, -4, -4, -4, -4, -4, -4, -4, -4, 2,
+ 2, 2, 2,
+ 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, -3, -3, -3, -3, -3, -3, -3, -3,
+ -3, -3,
+ -3, -3, -3,
+ -3, -3, -3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2,
+ -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2,
+ -2, -2,
+ -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1,
+ };
+
+ const int nbits_D[] =
+ { 0, 0, 0, 0, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5,
+ 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+ };
+ const int tab_D[] =
+ { 0xff, 0xfe, 0xfd, 0xfc, 10, -11, 11, -12, 8, 8, -9, -9, 9, 9,
+ -10, -10, 6, 6, 6, 6, -7, -7, -7, -7, 7, 7, 7, 7, -8, -8,
+ -8, -8,
+ 4, 4, 4, 4,
+ 4, 4, 4, 4, -5, -5, -5, -5, -5, -5, -5, -5, 5, 5, 5, 5, 5,
+ 5, 5, 5,
+ -6, -6,
+ -6, -6, -6, -6, -6, -6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2,
+ 2, 2, -3,
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
+ 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -4, -4, -4, -4, -4, -4, -4,
+ -4, -4,
+ -4, -4, -4,
+ -4, -4, -4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ -1, -1,
+ -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1,
+ 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2,
+ -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2,
+ -2, -2
+ };
+
+ /* a_curve[19 + i] = ... [-19..19] => [-160..160] */
+ const int a_curve[] =
+ { -160, -144, -128, -112, -98, -88, -80, -72, -64, -56, -48,
+ -40, -32, -24, -18, -12, -8, -5, -2, 0, 2, 5, 8, 12, 18,
+ 24, 32,
+ 40, 48, 56, 64,
+ 72, 80, 88, 98, 112, 128, 144, 160
+ };
+ /* clamp0_255[256 + i] = min(max(i,255),0) */
+ const unsigned char clamp0_255[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27,
+ 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50,
+ 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73,
+ 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96,
+ 97, 98, 99, 100, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ 114,
+ 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132,
+ 133, 134, 135, 136, 137,
+ 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150,
+ 151, 152, 153, 154, 155,
+ 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+ 168,
+ 169, 170, 171, 172, 173,
+ 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
+ 186,
+ 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204,
+ 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+ 222,
+ 223, 224, 225, 226, 227,
+ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240,
+ 241, 242, 243, 244, 245,
+ 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255,
+ 255
+ };
+ /* abs_clamp15[19 + i] = min(abs(i), 15) */
+ const int abs_clamp15[] =
+ { 15, 15, 15, 15, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
+ 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 15, 15,
+ 15
+ };
+ /* diff_encoding[256 + i] = ... */
+ const int diff_encoding[] =
+ { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7,
+ 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5,
+ 5, 5, 5, 5, 5, 3, 3,
+ 3, 3, 1, 1, 0, 2, 2, 4, 4, 4, 4, 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, 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, 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,
+ 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, 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, 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,
+ 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, 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
+ };
+
+ int block;
+ int bitfill = 0;
+ int xwidth = width + 6;
+ int off_up_right = 2 - 2 * xwidth;
+ int off_up_left = -2 - 2 * xwidth;
+ int pixel_U = 0, saved_pixel_UR = 0;
+ int pixel_x = 0, pixel_y = 2;
+ unsigned char *output_ptr = outbuf;
+
+ memset(i_hits, 0, sizeof(i_hits));
+ memset(accum, 0, sizeof(accum));
+
+ memcpy(outbuf + xwidth * 2 + 3, inbuf + 0x14, width);
+ memcpy(outbuf + xwidth * 3 + 3, inbuf + 0x14 + width, width);
+
+ input_ptr = inbuf + 0x14 + width * 2;
+ output_ptr = outbuf + (xwidth) * 4 + 3;
+
+ bit_bucket = 0;
+
+ for (block = 0; block < ((height - 2) * width) / 32; ++block) {
+ int b_it, var_7 = 0;
+ int cur_byte;
+
+ refill(&bitfill);
+
+ cur_byte = (bit_bucket >> (bitfill & 7)) & 0xff;
+
+ if ((cur_byte & 0x80) == 0) {
+ var_7 = 0;
+ bitfill--;
+ } else if ((cur_byte & 0xC0) == 0x80) {
+ var_7 = 1;
+ bitfill -= 2;
+ } else if ((cur_byte & 0xc0) == 0xc0) {
+ var_7 = 2;
+ bitfill -= 2;
+ }
+
+ for (b_it = 0; b_it < 32; b_it++) {
+ int index;
+ int pixel_L, pixel_UR, pixel_UL;
+ int multiplier;
+ int dL, dC, dR;
+ int gkw; /* God knows what */
+
+ refill(&bitfill);
+ cur_byte = bit_bucket >> (bitfill & 7) & 0xff;
+
+ pixel_L = output_ptr[-2];
+ pixel_UR = output_ptr[off_up_right];
+ pixel_UL = output_ptr[off_up_left];
+
+ dL = diff_encoding[0x100 + pixel_UL - pixel_L];
+ dC = diff_encoding[0x100 + pixel_U - pixel_UL];
+ dR = diff_encoding[0x100 + pixel_UR - pixel_U];
+
+ if (pixel_x < 2) {
+ pixel_L = pixel_UL = pixel_U =
+ output_ptr[-xwidth * 2];
+ pixel_UR = output_ptr[off_up_right];
+ dL = dC = 0;
+ dR = diff_encoding[0x100 + pixel_UR -
+ pixel_U];
+ } else if (pixel_x > width - 3)
+ dR = 0;
+
+ multiplier = 4;
+ index = dR + dC * 8 + dL * 64;
+
+ if (pixel_L + pixel_U * 2 <= 144
+ && (pixel_y & 1) == 0
+ && (b_it & 3) == 0 && (dR < 5) && (dC < 5)
+ && (dL < 5)) {
+ multiplier = 1;
+ } else if (pixel_L <= 48
+ && dL <= 4 && dC <= 4 && dL >= 1
+ && dC >= 1) {
+ multiplier = 2;
+ } else if (var_7 == 1) {
+ multiplier = 2;
+ } else if (dC + dL >= 11 || var_7 == 2) {
+ multiplier = 8;
+ }
+
+ if (i_hits[index] < 7) {
+ bitfill -= nbits_A[cur_byte];
+ gkw = tab_A[cur_byte];
+ if (gkw == 0xfe)
+ gkw = fun_A(&bitfill);
+ } else if (i_hits[index] >= accum[index]) {
+ bitfill -= nbits_B[cur_byte];
+ gkw = tab_B[cur_byte];
+ if (cur_byte == 0)
+ gkw = fun_B(&bitfill);
+ } else if (i_hits[index] * 2 >= accum[index]) {
+ bitfill -= nbits_C[cur_byte];
+ gkw = tab_C[cur_byte];
+ if (cur_byte < 2)
+ gkw = fun_C(&bitfill, gkw);
+ } else if (i_hits[index] * 4 >= accum[index]) {
+ bitfill -= nbits_D[cur_byte];
+ gkw = tab_D[cur_byte];
+ if (cur_byte < 4)
+ gkw = fun_D(&bitfill, gkw);
+ } else if (i_hits[index] * 8 >= accum[index]) {
+ gkw = fun_E(cur_byte, &bitfill);
+ } else {
+ gkw = fun_F(cur_byte, &bitfill);
+ }
+
+ if (gkw == 0xff)
+ return -3;
+
+ {
+ int tmp1, tmp2;
+
+ tmp1 =
+ (pixel_U + pixel_L) * 3 - pixel_UL * 2;
+ tmp1 += (tmp1 < 0) ? 3 : 0;
+ tmp2 = a_curve[19 + gkw] * multiplier;
+ tmp2 += (tmp2 < 0) ? 1 : 0;
+
+ *(output_ptr++) =
+ clamp0_255[0x100 + (tmp1 >> 2) -
+ (tmp2 >> 1)];
+ }
+ pixel_U = saved_pixel_UR;
+ saved_pixel_UR = pixel_UR;
+
+ if (++pixel_x == width) {
+ output_ptr += 6;
+ pixel_x = 0;
+ pixel_y++;
+ }
+
+ accum[index] += abs_clamp15[19 + gkw];
+
+ if (i_hits[index]++ == 15) {
+ i_hits[index] = 8;
+ accum[index] /= 2;
+ }
+ }
+ }
+ return 0;
+}
+
+/* FIXME, change internal_spca561_decode not to need the extra border
+ around its dest buffer */
+void v4lconvert_decode_spca561(const unsigned char *inbuf,
+ unsigned char *outbuf, int width, int height)
+{
+ int i;
+ static unsigned char tmpbuf[650 * 490];
+ if (internal_spca561_decode(width, height, inbuf, tmpbuf) != 0)
+ return;
+ for (i = 0; i < height; i++)
+ memcpy(outbuf + i * width,
+ tmpbuf + (i + 2) * (width + 6) + 3, width);
+}
+
+/*************** License Change Permission Notice ***************
+
+Return-Path: <qq@kuku.eu.org>
+Received: from koko.hhs.nl ([145.52.2.16] verified)
+ by hhs.nl (CommuniGate Pro SMTP 4.3.6)
+ with ESMTP id 88574071 for j.w.r.degoede@hhs.nl; Mon, 16 Jun 2008 16:36:24 +0200
+Received: from exim (helo=koko)
+ by koko.hhs.nl with local-smtp (Exim 4.62)
+ (envelope-from <qq@kuku.eu.org>)
+ id 1K8Fom-0002iJ-3K
+ for j.w.r.degoede@hhs.nl; Mon, 16 Jun 2008 16:36:24 +0200
+Received: from [192.87.102.74] (port=41377 helo=filter6-ams.mf.surf.net)
+ by koko.hhs.nl with esmtp (Exim 4.62)
+ (envelope-from <qq@kuku.eu.org>)
+ id 1K8Fol-0002iC-Qo
+ for j.w.r.degoede@hhs.nl; Mon, 16 Jun 2008 16:36:23 +0200
+Received: from kuku.eu.org (pa90.wielkopole.sdi.tpnet.pl [217.99.123.90])
+ by filter6-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5GEa55r001787
+ for <j.w.r.degoede@hhs.nl>; Mon, 16 Jun 2008 16:36:06 +0200
+Received: (qmail 2243 invoked by uid 500); 16 Jun 2008 14:29:37 -0000
+Date: Mon, 16 Jun 2008 16:29:37 +0200 (CEST)
+From: Andrzej Szombierski <qq@kuku.eu.org>
+To: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: Re: spca561 decoder license question
+In-Reply-To: <485673B6.4050003@hhs.nl>
+Message-ID: <Pine.LNX.4.44L.0806161614560.7665-100000@kuku.eu.org>
+References: <485673B6.4050003@hhs.nl>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=iso-8859-2
+Content-Transfer-Encoding: QUOTED-PRINTABLE
+X-Canit-CHI2: 0.00
+X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
+X-Spam-Score: 2.00 (**) [Tag at 6.00] RBL(uceprotect-blacklist.surfnet.nl,2.0)
+X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
+X-Canit-Stats-ID: 85673281 - 37e52c8b07bc
+X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.74
+X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 16062008 #776409, status: clean
+
+On Mon, 16 Jun 2008, Hans de Goede wrote:
+
+> Hi,
+>=20
+> I don't know if you're still subscribed to the spca devel mailing list, s=
+o let=20
+> me start with a short intro.
+>
+> I'm a Linux enthusiast / developer currently helping Jean-Fran=E7ois Moin=
+e with=20
+> porting gspca to video4linux2 and cleaning up the code to get it ready fo=
+r=20
+> mainline kernel inclusion.
+>=20
+> As part of this process the decompression code for all supported cams mus=
+t be=20
+> moved to userspace, as doing in kernel decompression is considered unwant=
+ed by=20
+> the mainline people (I agree) as it should be done in userspace.
+>
+
+Sounds reasonable.
+=20
+> As such I'm working on a library which does decompression of custom cam f=
+ormats=20
+> in userspace.
+>
+
+Nice. I hope that the library won't be limited to spca-supported webcams,=
+=20
+and as an application developer I would be able to just request RGB data=20
+from any /dev/video*, right?
+
+> I do not want to license this library as GPL (as the current spca code is=
+), as=20
+> it should be usable by as much software as possible. Instead I want to li=
+cense=20
+> it under the LGPL version 2.1 or later.
+
+Also sounds reasonable.
+
+>=20
+> So my question us my I have your permission to relicense your spca561=20
+> decompression code under the LGPL?
+>=20
+
+Yes, of course.=20
+
+> Thanks & Regards,
+>=20
+> Hans
+>=20
+>
+
+--=20
+:: Andrzej Szombierski :: qq@kuku.eu.org :: http://kuku.eu.org ::
+:: anszom@bezkitu.com :: radio bez kitu :: http://bezkitu.com ::
+
+*/
diff --git a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h
new file mode 100644
index 000000000..26844c28a
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg-internal.h
@@ -0,0 +1,121 @@
+/*
+ * Small jpeg decoder library (Internal header)
+ *
+ * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the author nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __TINYJPEG_INTERNAL_H_
+#define __TINYJPEG_INTERNAL_H_
+
+#include <setjmp.h>
+
+#define SANITY_CHECK 1
+
+struct jdec_private;
+
+#define HUFFMAN_HASH_NBITS 9
+#define HUFFMAN_HASH_SIZE (1UL<<HUFFMAN_HASH_NBITS)
+#define HUFFMAN_HASH_MASK (HUFFMAN_HASH_SIZE-1)
+
+#define HUFFMAN_TABLES 4
+#define COMPONENTS 3
+#define JPEG_MAX_WIDTH 2048
+#define JPEG_MAX_HEIGHT 2048
+
+struct huffman_table
+{
+ /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol,
+ * if the symbol is <0, then we need to look into the tree table */
+ short int lookup[HUFFMAN_HASH_SIZE];
+ /* code size: give the number of bits of a symbol is encoded */
+ unsigned char code_size[HUFFMAN_HASH_SIZE];
+ /* some place to store value that is not encoded in the lookup table
+ * IMPROVEME: Calculate if 256 value is enough to store all values
+ */
+ uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256];
+};
+
+struct component
+{
+ unsigned int Hfactor;
+ unsigned int Vfactor;
+ float *Q_table; /* Pointer to the quantisation table to use */
+ struct huffman_table *AC_table;
+ struct huffman_table *DC_table;
+ short int previous_DC; /* Previous DC coefficient */
+ short int DCT[64]; /* DCT coef */
+#if SANITY_CHECK
+ unsigned int cid;
+#endif
+};
+
+
+typedef void (*decode_MCU_fct) (struct jdec_private *priv);
+typedef void (*convert_colorspace_fct) (struct jdec_private *priv);
+
+struct jdec_private
+{
+ /* Public variables */
+ uint8_t *components[COMPONENTS];
+ unsigned int width, height; /* Size of the image */
+ unsigned int flags;
+
+ /* Private variables */
+ const unsigned char *stream_begin, *stream_end;
+ unsigned int stream_length;
+
+ const unsigned char *stream; /* Pointer to the current stream */
+ unsigned int reservoir, nbits_in_reservoir;
+
+ struct component component_infos[COMPONENTS];
+ float Q_tables[COMPONENTS][64]; /* quantization tables */
+ struct huffman_table HTDC[HUFFMAN_TABLES]; /* DC huffman tables */
+ struct huffman_table HTAC[HUFFMAN_TABLES]; /* AC huffman tables */
+ int default_huffman_table_initialized;
+ int restart_interval;
+ int restarts_to_go; /* MCUs left in this restart interval */
+ int last_rst_marker_seen; /* Rst marker is incremented each time */
+
+ /* Temp space used after the IDCT to store each components */
+ uint8_t Y[64*4], Cr[64], Cb[64];
+
+ jmp_buf jump_state;
+ /* Internal Pointer use for colorspace conversion, do not modify it !!! */
+ uint8_t *plane[COMPONENTS];
+
+ char error_string[256];
+};
+
+#define IDCT tinyjpeg_idct_float
+void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride);
+
+#endif
+
diff --git a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c
new file mode 100644
index 000000000..fc9efbeb2
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.c
@@ -0,0 +1,2463 @@
+/*
+ * Small jpeg decoder library
+ *
+ * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the author nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "tinyjpeg.h"
+#include "tinyjpeg-internal.h"
+
+enum std_markers {
+ DQT = 0xDB, /* Define Quantization Table */
+ SOF = 0xC0, /* Start of Frame (size information) */
+ DHT = 0xC4, /* Huffman Table */
+ SOI = 0xD8, /* Start of Image */
+ SOS = 0xDA, /* Start of Scan */
+ RST = 0xD0, /* Reset Marker d0 -> .. */
+ RST7 = 0xD7, /* Reset Marker .. -> d7 */
+ EOI = 0xD9, /* End of Image */
+ DRI = 0xDD, /* Define Restart Interval */
+ APP0 = 0xE0,
+};
+
+#define cY 0
+#define cCb 1
+#define cCr 2
+
+#define BLACK_Y 0
+#define BLACK_U 127
+#define BLACK_V 127
+
+#if DEBUG
+#if LOG2FILE
+
+#define trace(fmt, args...) do { \
+ FILE *f = fopen("/tmp/jpeg.log", "a"); \
+ fprintf(f, fmt, ## args); \
+ fflush(f); \
+ fclose(f); \
+} while(0)
+
+#else
+
+#define trace(fmt, args...) do { \
+ fprintf(stderr, fmt, ## args); \
+ fflush(stderr); \
+} while(0)
+#endif
+
+#else
+#define trace(fmt, args...) do { } while (0)
+#endif
+
+#define error(fmt, args...) do { \
+ snprintf(priv->error_string, sizeof(priv->error_string), fmt, ## args); \
+ return -1; \
+} while(0)
+
+
+#if 0
+static char *print_bits(unsigned int value, char *bitstr)
+{
+ int i, j;
+ i=31;
+ while (i>0)
+ {
+ if (value & (1UL<<i))
+ break;
+ i--;
+ }
+ j=0;
+ while (i>=0)
+ {
+ bitstr[j++] = (value & (1UL<<i))?'1':'0';
+ i--;
+ }
+ bitstr[j] = 0;
+ return bitstr;
+}
+
+static void print_next_16bytes(int offset, const unsigned char *stream)
+{
+ trace("%4.4x: %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+ offset,
+ stream[0], stream[1], stream[2], stream[3],
+ stream[4], stream[5], stream[6], stream[7],
+ stream[8], stream[9], stream[10], stream[11],
+ stream[12], stream[13], stream[14], stream[15]);
+}
+
+#endif
+
+
+static const unsigned char zigzag[64] =
+{
+ 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
+};
+
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+static const unsigned char bits_dc_luminance[17] =
+{
+ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+static const unsigned char val_dc_luminance[] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const unsigned char bits_dc_chrominance[17] =
+{
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+static const unsigned char val_dc_chrominance[] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const unsigned char bits_ac_luminance[17] =
+{
+ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+static const unsigned char val_ac_luminance[] =
+{
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+static const unsigned char bits_ac_chrominance[17] =
+{
+ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+};
+
+static const unsigned char val_ac_chrominance[] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+const unsigned char pixart_quantization[][64] = {
+ {
+ 0x07, 0x07, 0x08, 0x0a, 0x09, 0x07, 0x0d, 0x0b,
+ 0x0c, 0x0d, 0x11, 0x10, 0x0f, 0x12, 0x17, 0x27,
+ 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+ 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+ 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+ 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+ 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+ 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+ },
+ {
+ 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+ 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ },
+};
+
+/*
+ * 4 functions to manage the stream
+ *
+ * fill_nbits: put at least nbits in the reservoir of bits.
+ * But convert any 0xff,0x00 into 0xff
+ * get_nbits: read nbits from the stream, and put it in result,
+ * bits is removed from the stream and the reservoir is filled
+ * automaticaly. The result is signed according to the number of
+ * bits.
+ * look_nbits: read nbits from the stream without marking as read.
+ * skip_nbits: read nbits from the stream but do not return the result.
+ *
+ * stream: current pointer in the jpeg data (read bytes per bytes)
+ * nbits_in_reservoir: number of bits filled into the reservoir
+ * reservoir: register that contains bits information. Only nbits_in_reservoir
+ * is valid.
+ * nbits_in_reservoir
+ * <-- 17 bits -->
+ * Ex: 0000 0000 1010 0000 1111 0000 <== reservoir
+ * ^
+ * bit 1
+ * To get two bits from this example
+ * result = (reservoir >> 15) & 3
+ *
+ */
+#define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
+ while (nbits_in_reservoir<nbits_wanted) \
+ { \
+ unsigned char c; \
+ if (stream >= priv->stream_end) { \
+ snprintf(priv->error_string, sizeof(priv->error_string), \
+ "fill_nbits error: need %u more bits\n", \
+ nbits_wanted - nbits_in_reservoir); \
+ longjmp(priv->jump_state, -EIO); \
+ } \
+ c = *stream++; \
+ reservoir <<= 8; \
+ if (c == 0xff && *stream == 0x00) \
+ stream++; \
+ reservoir |= c; \
+ nbits_in_reservoir+=8; \
+ } \
+} while(0);
+
+/* Signed version !!!! */
+#define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \
+ fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+ nbits_in_reservoir -= (nbits_wanted); \
+ reservoir &= ((1U<<nbits_in_reservoir)-1); \
+ if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \
+ result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \
+} while(0);
+
+#define look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \
+ fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+} while(0);
+
+/* To speed up the decoding, we assume that the reservoir have enough bit
+ * slow version:
+ * #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
+ * fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ * nbits_in_reservoir -= (nbits_wanted); \
+ * reservoir &= ((1U<<nbits_in_reservoir)-1); \
+ * } while(0);
+ */
+#define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
+ nbits_in_reservoir -= (nbits_wanted); \
+ reservoir &= ((1U<<nbits_in_reservoir)-1); \
+} while(0);
+
+
+/* Special Pixart versions of the *_nbits functions, these remove the special
+ ff ff ff xx sequences pixart cams insert from the bitstream */
+#define pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) \
+do { \
+ while (nbits_in_reservoir<nbits_wanted) \
+ { \
+ unsigned char c; \
+ if (stream >= priv->stream_end) { \
+ snprintf(priv->error_string, sizeof(priv->error_string), \
+ "fill_nbits error: need %u more bits\n", \
+ nbits_wanted - nbits_in_reservoir); \
+ longjmp(priv->jump_state, -EIO); \
+ } \
+ c = *stream++; \
+ reservoir <<= 8; \
+ if (c == 0xff) { \
+ switch (stream[0]) { \
+ case 0x00: \
+ stream++; \
+ break; \
+ case 0xd9: /* EOF marker */ \
+ stream++; \
+ if (stream != priv->stream_end) { \
+ snprintf(priv->error_string, sizeof(priv->error_string), \
+ "Pixart JPEG error: premature EOF\n"); \
+ longjmp(priv->jump_state, -EIO); \
+ } \
+ break; \
+ case 0xff: \
+ if (stream[1] == 0xff && (stream[2] < 7 || stream[2] == 0xff)) { \
+ stream += 3; \
+ c = *stream++; \
+ break; \
+ } \
+ /* Error fall through */ \
+ default: \
+ snprintf(priv->error_string, sizeof(priv->error_string), \
+ "Pixart JPEG error: invalid JPEG marker: 0xff 0x%02x 0x%02x 0x%02x\n", \
+ (unsigned int)stream[0], (unsigned int)stream[1], \
+ (unsigned int)stream[2]); \
+ longjmp(priv->jump_state, -EIO); \
+ } \
+ } \
+ reservoir |= c; \
+ nbits_in_reservoir+=8; \
+ } \
+} while(0);
+
+/* Signed version !!!! */
+#define pixart_get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \
+do { \
+ pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+ nbits_in_reservoir -= (nbits_wanted); \
+ reservoir &= ((1U<<nbits_in_reservoir)-1); \
+ if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \
+ result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \
+} while(0);
+
+#define pixart_look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \
+do { \
+ pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+} while(0);
+
+/* Note skip_nbits is identical for both */
+
+
+#define be16_to_cpu(x) (((x)[0]<<8)|(x)[1])
+
+static void resync(struct jdec_private *priv);
+
+/**
+ * Get the next (valid) huffman code in the stream.
+ *
+ * To speedup the procedure, we look HUFFMAN_HASH_NBITS bits and the code is
+ * lower than HUFFMAN_HASH_NBITS we have automaticaly the length of the code
+ * and the value by using two lookup table.
+ * Else if the value is not found, just search (linear) into an array for each
+ * bits is the code is present.
+ *
+ * If the code is not present for any reason, -1 is return.
+ */
+static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table *huffman_table)
+{
+ int value, hcode;
+ unsigned int extra_nbits, nbits;
+ uint16_t *slowtable;
+
+ look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode);
+ value = huffman_table->lookup[hcode];
+ if (value >= 0)
+ {
+ unsigned int code_size = huffman_table->code_size[value];
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size);
+ return value;
+ }
+
+ /* Decode more bits each time ... */
+ for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++)
+ {
+ nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits;
+
+ look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode);
+ slowtable = huffman_table->slowtable[extra_nbits];
+ /* Search if the code is in this array */
+ while (slowtable[0]) {
+ if (slowtable[0] == hcode) {
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits);
+ return slowtable[1];
+ }
+ slowtable+=2;
+ }
+ }
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "unknown huffman code: %08x\n", (unsigned int)hcode);
+ longjmp(priv->jump_state, -EIO);
+ return 0;
+}
+
+/* identical as above but with *_nbits replaced with pixart_*_nbits */
+static int pixart_get_next_huffman_code(struct jdec_private *priv,
+ struct huffman_table *huffman_table)
+{
+ int value, hcode;
+ unsigned int extra_nbits, nbits;
+ uint16_t *slowtable;
+
+ pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode);
+ value = huffman_table->lookup[hcode];
+ if (value >= 0)
+ {
+ unsigned int code_size = huffman_table->code_size[value];
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size);
+ return value;
+ }
+
+ /* Decode more bits each time ... */
+ for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++)
+ {
+ nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits;
+
+ pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode);
+ slowtable = huffman_table->slowtable[extra_nbits];
+ /* Search if the code is in this array */
+ while (slowtable[0]) {
+ if (slowtable[0] == hcode) {
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits);
+ return slowtable[1];
+ }
+ slowtable+=2;
+ }
+ }
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "unknown huffman code: %08x\n", (unsigned int)hcode);
+ longjmp(priv->jump_state, -EIO);
+ return 0;
+}
+
+
+
+/**
+ *
+ * Decode a single block that contains the DCT coefficients.
+ * The table coefficients is already dezigzaged at the end of the operation.
+ *
+ */
+static void process_Huffman_data_unit(struct jdec_private *priv, int component)
+{
+ unsigned char j;
+ unsigned int huff_code;
+ unsigned char size_val, count_0;
+
+ struct component *c = &priv->component_infos[component];
+ short int DCT[64];
+
+ /* Initialize the DCT coef table */
+ memset(DCT, 0, sizeof(DCT));
+
+ /* DC coefficient decoding */
+ huff_code = get_next_huffman_code(priv, c->DC_table);
+ if (huff_code) {
+ get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]);
+ DCT[0] += c->previous_DC;
+ c->previous_DC = DCT[0];
+ } else {
+ DCT[0] = c->previous_DC;
+ }
+
+
+ /* AC coefficient decoding */
+ j = 1;
+ while (j<64)
+ {
+ huff_code = get_next_huffman_code(priv, c->AC_table);
+
+ size_val = huff_code & 0xF;
+ count_0 = huff_code >> 4;
+
+ if (size_val == 0)
+ { /* RLE */
+ if (count_0 == 0)
+ break; /* EOB found, go out */
+ else if (count_0 == 0xF)
+ j += 16; /* skip 16 zeros */
+ }
+ else
+ {
+ j += count_0; /* skip count_0 zeroes */
+ if (j < 64) {
+ get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
+ j++;
+ }
+ }
+ }
+
+ if (j > 64) {
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "error: more then 63 AC components (%d) in huffman unit\n", (int)j);
+ longjmp(priv->jump_state, -EIO);
+ }
+
+ for (j = 0; j < 64; j++)
+ c->DCT[j] = DCT[zigzag[j]];
+}
+
+/* identical as above both with *_nbits replaced with pixart_*_nbits */
+static void pixart_process_Huffman_data_unit(struct jdec_private *priv, int component)
+{
+ unsigned char j;
+ unsigned int huff_code;
+ unsigned char size_val, count_0;
+
+ struct component *c = &priv->component_infos[component];
+ short int DCT[64];
+
+ /* Initialize the DCT coef table */
+ memset(DCT, 0, sizeof(DCT));
+
+ /* DC coefficient decoding */
+ huff_code = pixart_get_next_huffman_code(priv, c->DC_table);
+ if (huff_code) {
+ pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]);
+ DCT[0] += c->previous_DC;
+ c->previous_DC = DCT[0];
+ } else {
+ DCT[0] = c->previous_DC;
+ }
+
+
+ /* AC coefficient decoding */
+ j = 1;
+ while (j<64)
+ {
+ huff_code = pixart_get_next_huffman_code(priv, c->AC_table);
+
+ size_val = huff_code & 0xF;
+ count_0 = huff_code >> 4;
+
+ if (size_val == 0)
+ { /* RLE */
+ if (count_0 == 0)
+ break; /* EOB found, go out */
+ else if (count_0 == 0xF)
+ j += 16; /* skip 16 zeros */
+ }
+ else
+ {
+ j += count_0; /* skip count_0 zeroes */
+ if (j < 64 ) {
+ pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
+ j++;
+ }
+ }
+ }
+
+ if (j > 64) {
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "error: more then 63 AC components (%d) in huffman unit\n", (int)j);
+ longjmp(priv->jump_state, -EIO);
+ }
+
+ for (j = 0; j < 64; j++)
+ c->DCT[j] = DCT[zigzag[j]];
+}
+
+
+/*
+ * Takes two array of bits, and build the huffman table for size, and code
+ *
+ * lookup will return the symbol if the code is less or equal than HUFFMAN_HASH_NBITS.
+ * code_size will be used to known how many bits this symbol is encoded.
+ * slowtable will be used when the first lookup didn't give the result.
+ */
+static int build_huffman_table(struct jdec_private *priv, const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
+{
+ unsigned int i, j, code, code_size, val, nbits;
+ unsigned char huffsize[257], *hz;
+ unsigned int huffcode[257], *hc;
+ int next_free_entry;
+ int slowtable_used[16-HUFFMAN_HASH_NBITS];
+
+ /*
+ * Build a temp array
+ * huffsize[X] => numbers of bits to write vals[X]
+ */
+ hz = huffsize;
+ for (i=1; i<=16; i++)
+ {
+ for (j=1; j<=bits[i]; j++)
+ *hz++ = i;
+ }
+ *hz = 0;
+
+ memset(table->lookup, 0xff, sizeof(table->lookup));
+ for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
+ slowtable_used[i] = 0;
+
+ /* Build a temp array
+ * huffcode[X] => code used to write vals[X]
+ */
+ code = 0;
+ hc = huffcode;
+ hz = huffsize;
+ nbits = *hz;
+ while (*hz)
+ {
+ while (*hz == nbits) {
+ *hc++ = code++;
+ hz++;
+ }
+ code <<= 1;
+ nbits++;
+ }
+
+ /*
+ * Build the lookup table, and the slowtable if needed.
+ */
+ next_free_entry = -1;
+ for (i=0; huffsize[i]; i++)
+ {
+ val = vals[i];
+ code = huffcode[i];
+ code_size = huffsize[i];
+
+ trace("val=%2.2x code=%8.8x codesize=%2.2d\n", i, code, code_size);
+
+ table->code_size[val] = code_size;
+ if (code_size <= HUFFMAN_HASH_NBITS)
+ {
+ /*
+ * Good: val can be put in the lookup table, so fill all value of this
+ * column with value val
+ */
+ int repeat = 1UL<<(HUFFMAN_HASH_NBITS - code_size);
+ code <<= HUFFMAN_HASH_NBITS - code_size;
+ while ( repeat-- )
+ table->lookup[code++] = val;
+
+ }
+ else
+ {
+ /* Perhaps sorting the array will be an optimization */
+ int slowtable_index = code_size-HUFFMAN_HASH_NBITS-1;
+
+ if (slowtable_used[slowtable_index] == 254)
+ error("slow Huffman table overflow\n");
+
+ table->slowtable[slowtable_index][slowtable_used[slowtable_index]]
+ = code;
+ table->slowtable[slowtable_index][slowtable_used[slowtable_index] + 1]
+ = val;
+ slowtable_used[slowtable_index] += 2;
+ }
+ }
+
+ for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
+ table->slowtable[i][slowtable_used[i]] = 0;
+
+ return 0;
+}
+
+static int build_default_huffman_tables(struct jdec_private *priv)
+{
+ if ( (priv->flags & TINYJPEG_FLAGS_MJPEG_TABLE)
+ && priv->default_huffman_table_initialized)
+ return 0;
+
+ if (build_huffman_table(priv, bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]))
+ return -1;
+ if (build_huffman_table(priv, bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]))
+ return -1;
+
+ if (build_huffman_table(priv, bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]))
+ return -1;
+ if (build_huffman_table(priv, bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]))
+ return -1;
+
+ priv->default_huffman_table_initialized = 1;
+ return 0;
+}
+
+
+
+/*******************************************************************************
+ *
+ * Colorspace conversion routine
+ *
+ *
+ * Note:
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ * R = Y + 1.40200 * Cr
+ * G = Y - 0.34414 * Cb - 0.71414 * Cr
+ * B = Y + 1.77200 * Cb
+ *
+ ******************************************************************************/
+
+static unsigned char clamp(int i)
+{
+ if (i<0)
+ return 0;
+ else if (i>255)
+ return 255;
+ else
+ return i;
+}
+
+
+/**
+ * YCrCb -> YUV420P (1x1)
+ * .---.
+ * | 1 |
+ * `---'
+ */
+static void YCrCB_to_YUV420P_1x1(struct jdec_private *priv)
+{
+ const unsigned char *s, *y;
+ unsigned char *p;
+ int i,j;
+
+ p = priv->plane[0];
+ y = priv->Y;
+ for (i=0; i<8; i++)
+ {
+ memcpy(p, y, 8);
+ p+=priv->width;
+ y+=8;
+ }
+
+ p = priv->plane[1];
+ s = priv->Cb;
+ for (i=0; i<8; i+=2)
+ {
+ for (j=0; j<8; j+=2, s+=2)
+ *p++ = *s;
+ s += 8; /* Skip one line */
+ p += priv->width/2 - 4;
+ }
+
+ p = priv->plane[2];
+ s = priv->Cr;
+ for (i=0; i<8; i+=2)
+ {
+ for (j=0; j<8; j+=2, s+=2)
+ *p++ = *s;
+ s += 8; /* Skip one line */
+ p += priv->width/2 - 4;
+ }
+}
+
+/**
+ * YCrCb -> YUV420P (2x1)
+ * .-------.
+ * | 1 | 2 |
+ * `-------'
+ */
+static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv)
+{
+ unsigned char *p;
+ const unsigned char *s, *y1;
+ unsigned int i;
+
+ p = priv->plane[0];
+ y1 = priv->Y;
+ for (i=0; i<8; i++)
+ {
+ memcpy(p, y1, 16);
+ p += priv->width;
+ y1 += 16;
+ }
+
+ p = priv->plane[1];
+ s = priv->Cb;
+ for (i=0; i<8; i+=2)
+ {
+ memcpy(p, s, 8);
+ s += 16; /* Skip one line */
+ p += priv->width/2;
+ }
+
+ p = priv->plane[2];
+ s = priv->Cr;
+ for (i=0; i<8; i+=2)
+ {
+ memcpy(p, s, 8);
+ s += 16; /* Skip one line */
+ p += priv->width/2;
+ }
+}
+
+
+/**
+ * YCrCb -> YUV420P (1x2)
+ * .---.
+ * | 1 |
+ * |---|
+ * | 2 |
+ * `---'
+ */
+static void YCrCB_to_YUV420P_1x2(struct jdec_private *priv)
+{
+ const unsigned char *s, *y;
+ unsigned char *p;
+ int i,j;
+
+ p = priv->plane[0];
+ y = priv->Y;
+ for (i=0; i<16; i++)
+ {
+ memcpy(p, y, 8);
+ p+=priv->width;
+ y+=8;
+ }
+
+ p = priv->plane[1];
+ s = priv->Cb;
+ for (i=0; i<8; i++)
+ {
+ for (j=0; j<8; j+=2, s+=2)
+ *p++ = *s;
+ p += priv->width/2 - 4;
+ }
+
+ p = priv->plane[2];
+ s = priv->Cr;
+ for (i=0; i<8; i++)
+ {
+ for (j=0; j<8; j+=2, s+=2)
+ *p++ = *s;
+ p += priv->width/2 - 4;
+ }
+}
+
+/**
+ * YCrCb -> YUV420P (2x2)
+ * .-------.
+ * | 1 | 2 |
+ * |---+---|
+ * | 3 | 4 |
+ * `-------'
+ */
+static void YCrCB_to_YUV420P_2x2(struct jdec_private *priv)
+{
+ unsigned char *p;
+ const unsigned char *s, *y1;
+ unsigned int i;
+
+ p = priv->plane[0];
+ y1 = priv->Y;
+ for (i=0; i<16; i++)
+ {
+ memcpy(p, y1, 16);
+ p += priv->width;
+ y1 += 16;
+ }
+
+ p = priv->plane[1];
+ s = priv->Cb;
+ for (i=0; i<8; i++)
+ {
+ memcpy(p, s, 8);
+ s += 8;
+ p += priv->width/2;
+ }
+
+ p = priv->plane[2];
+ s = priv->Cr;
+ for (i=0; i<8; i++)
+ {
+ memcpy(p, s, 8);
+ s += 8;
+ p += priv->width/2;
+ }
+}
+
+/**
+ * YCrCb -> RGB24 (1x1)
+ * .---.
+ * | 1 |
+ * `---'
+ */
+static void YCrCB_to_RGB24_1x1(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = priv->width*3 - 8*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ y = (*Y++) << SCALEBITS;
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+
+ }
+
+ p += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/**
+ * YCrCb -> BGR24 (1x1)
+ * .---.
+ * | 1 |
+ * `---'
+ */
+static void YCrCB_to_BGR24_1x1(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = priv->width*3 - 8*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ y = (*Y++) << SCALEBITS;
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+
+ }
+
+ p += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+/**
+ * YCrCb -> RGB24 (2x1)
+ * .-------.
+ * | 1 | 2 |
+ * `-------'
+ */
+static void YCrCB_to_RGB24_2x1(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = priv->width*3 - 16*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ y = (*Y++) << SCALEBITS;
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+
+ y = (*Y++) << SCALEBITS;
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+
+ }
+
+ p += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/*
+ * YCrCb -> BGR24 (2x1)
+ * .-------.
+ * | 1 | 2 |
+ * `-------'
+ */
+static void YCrCB_to_BGR24_2x1(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = priv->width*3 - 16*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ y = (*Y++) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+
+ y = (*Y++) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+
+ }
+
+ p += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/**
+ * YCrCb -> RGB24 (1x2)
+ * .---.
+ * | 1 |
+ * |---|
+ * | 2 |
+ * `---'
+ */
+static void YCrCB_to_RGB24_1x2(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p, *p2;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ p2 = priv->plane[0] + priv->width*3;
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = 2*priv->width*3 - 8*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ y = (*Y++) << SCALEBITS;
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+
+ y = (Y[8-1]) << SCALEBITS;
+ r = (y + add_r) >> SCALEBITS;
+ *p2++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p2++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p2++ = clamp(b);
+
+ }
+ Y += 8;
+ p += offset_to_next_row;
+ p2 += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/*
+ * YCrCb -> BGR24 (1x2)
+ * .---.
+ * | 1 |
+ * |---|
+ * | 2 |
+ * `---'
+ */
+static void YCrCB_to_BGR24_1x2(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p, *p2;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ p2 = priv->plane[0] + priv->width*3;
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = 2*priv->width*3 - 8*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ y = (*Y++) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+
+ y = (Y[8-1]) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p2++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p2++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p2++ = clamp(r);
+
+ }
+ Y += 8;
+ p += offset_to_next_row;
+ p2 += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+/**
+ * YCrCb -> RGB24 (2x2)
+ * .-------.
+ * | 1 | 2 |
+ * |---+---|
+ * | 3 | 4 |
+ * `-------'
+ */
+static void YCrCB_to_RGB24_2x2(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p, *p2;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ p2 = priv->plane[0] + priv->width*3;
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = (priv->width*3*2) - 16*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ y = (*Y++) << SCALEBITS;
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+
+ y = (*Y++) << SCALEBITS;
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+
+ y = (Y[16-2]) << SCALEBITS;
+ r = (y + add_r) >> SCALEBITS;
+ *p2++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p2++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p2++ = clamp(b);
+
+ y = (Y[16-1]) << SCALEBITS;
+ r = (y + add_r) >> SCALEBITS;
+ *p2++ = clamp(r);
+ g = (y + add_g) >> SCALEBITS;
+ *p2++ = clamp(g);
+ b = (y + add_b) >> SCALEBITS;
+ *p2++ = clamp(b);
+ }
+ Y += 16;
+ p += offset_to_next_row;
+ p2 += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+/*
+ * YCrCb -> BGR24 (2x2)
+ * .-------.
+ * | 1 | 2 |
+ * |---+---|
+ * | 3 | 4 |
+ * `-------'
+ */
+static void YCrCB_to_BGR24_2x2(struct jdec_private *priv)
+{
+ const unsigned char *Y, *Cb, *Cr;
+ unsigned char *p, *p2;
+ int i,j;
+ int offset_to_next_row;
+
+#define SCALEBITS 10
+#define ONE_HALF (1UL << (SCALEBITS-1))
+#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+ p = priv->plane[0];
+ p2 = priv->plane[0] + priv->width*3;
+ Y = priv->Y;
+ Cb = priv->Cb;
+ Cr = priv->Cr;
+ offset_to_next_row = (priv->width*3*2) - 16*3;
+ for (i=0; i<8; i++) {
+
+ for (j=0; j<8; j++) {
+
+ int y, cb, cr;
+ int add_r, add_g, add_b;
+ int r, g , b;
+
+ cb = *Cb++ - 128;
+ cr = *Cr++ - 128;
+ add_r = FIX(1.40200) * cr + ONE_HALF;
+ add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+ add_b = FIX(1.77200) * cb + ONE_HALF;
+
+ y = (*Y++) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+
+ y = (*Y++) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p++ = clamp(r);
+
+ y = (Y[16-2]) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p2++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p2++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p2++ = clamp(r);
+
+ y = (Y[16-1]) << SCALEBITS;
+ b = (y + add_b) >> SCALEBITS;
+ *p2++ = clamp(b);
+ g = (y + add_g) >> SCALEBITS;
+ *p2++ = clamp(g);
+ r = (y + add_r) >> SCALEBITS;
+ *p2++ = clamp(r);
+ }
+ Y += 16;
+ p += offset_to_next_row;
+ p2 += offset_to_next_row;
+ }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+
+/**
+ * YCrCb -> Grey (1x1)
+ * .---.
+ * | 1 |
+ * `---'
+ */
+static void YCrCB_to_Grey_1x1(struct jdec_private *priv)
+{
+ const unsigned char *y;
+ unsigned char *p;
+ unsigned int i;
+ int offset_to_next_row;
+
+ p = priv->plane[0];
+ y = priv->Y;
+ offset_to_next_row = priv->width;
+
+ for (i=0; i<8; i++) {
+ memcpy(p, y, 8);
+ y+=8;
+ p += offset_to_next_row;
+ }
+}
+
+/**
+ * YCrCb -> Grey (2x1)
+ * .-------.
+ * | 1 | 2 |
+ * `-------'
+ */
+static void YCrCB_to_Grey_2x1(struct jdec_private *priv)
+{
+ const unsigned char *y;
+ unsigned char *p;
+ unsigned int i;
+
+ p = priv->plane[0];
+ y = priv->Y;
+
+ for (i=0; i<8; i++) {
+ memcpy(p, y, 16);
+ y += 16;
+ p += priv->width;
+ }
+}
+
+
+/**
+ * YCrCb -> Grey (1x2)
+ * .---.
+ * | 1 |
+ * |---|
+ * | 2 |
+ * `---'
+ */
+static void YCrCB_to_Grey_1x2(struct jdec_private *priv)
+{
+ const unsigned char *y;
+ unsigned char *p;
+ unsigned int i;
+
+ p = priv->plane[0];
+ y = priv->Y;
+
+ for (i=0; i<16; i++) {
+ memcpy(p, y, 8);
+ y += 8;
+ p += priv->width;
+ }
+}
+
+/**
+ * YCrCb -> Grey (2x2)
+ * .-------.
+ * | 1 | 2 |
+ * |---+---|
+ * | 3 | 4 |
+ * `-------'
+ */
+static void YCrCB_to_Grey_2x2(struct jdec_private *priv)
+{
+ const unsigned char *y;
+ unsigned char *p;
+ unsigned int i;
+
+ p = priv->plane[0];
+ y = priv->Y;
+
+ for (i=0; i<16; i++) {
+ memcpy(p, y, 16);
+ y += 16;
+ p += priv->width;
+ }
+}
+
+
+/*
+ * Decode all the 3 components for 1x1
+ */
+static void decode_MCU_1x1_3planes(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 8);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+ IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+ IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 1x1 directly in 1 color
+ */
+static void decode_MCU_1x1_1plane(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 8);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+ IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+ IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+
+/*
+ * Decode a 2x1
+ * .-------.
+ * | 1 | 2 |
+ * `-------'
+ */
+static void decode_MCU_2x1_3planes(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+ IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+ IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+static void pixart_decode_MCU_2x1_3planes(struct jdec_private *priv)
+{
+ unsigned char marker;
+
+ pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream,
+ 8, marker);
+ /* I think the marker indicates which quantization table to use, iow
+ a Pixart JPEG may have a different quantization table per MCU, most
+ MCU's have 0x44 as marker for which our special Pixart quantization
+ tables are correct. Unfortunately with a 7302 some blocks also have 0x48,
+ and sometimes even other values. As 0x48 is quite common too, we really
+ need to find out the correct table for that, as currently the blocks
+ with a 0x48 marker look wrong. During normal operation the marker stays
+ within the range below, if it gets out of this range we're most likely
+ decoding garbage */
+ if (marker < 0x20 || marker > 0x7f) {
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "Pixart JPEG error: invalid MCU marker: 0x%02x\n",
+ (unsigned int)marker);
+ longjmp(priv->jump_state, -EIO);
+ }
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, 8);
+
+ // Y
+ pixart_process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 16);
+ pixart_process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+
+ // Cb
+ pixart_process_Huffman_data_unit(priv, cCb);
+ IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+ // Cr
+ pixart_process_Huffman_data_unit(priv, cCr);
+ IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 2x1
+ * .-------.
+ * | 1 | 2 |
+ * `-------'
+ */
+static void decode_MCU_2x1_1plane(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+}
+
+
+/*
+ * Decode a 2x2
+ * .-------.
+ * | 1 | 2 |
+ * |---+---|
+ * | 3 | 4 |
+ * `-------'
+ */
+static void decode_MCU_2x2_3planes(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+ IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+ IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 2x2 directly in GREY format (8bits)
+ * .-------.
+ * | 1 | 2 |
+ * |---+---|
+ * | 3 | 4 |
+ * `-------'
+ */
+static void decode_MCU_2x2_1plane(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+}
+
+/*
+ * Decode a 1x2 mcu
+ * .---.
+ * | 1 |
+ * |---|
+ * | 2 |
+ * `---'
+ */
+static void decode_MCU_1x2_3planes(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 8);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+64, 8);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+ IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+ IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 1x2 mcu
+ * .---.
+ * | 1 |
+ * |---|
+ * | 2 |
+ * `---'
+ */
+static void decode_MCU_1x2_1plane(struct jdec_private *priv)
+{
+ // Y
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 8);
+ process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+64, 8);
+
+ // Cb
+ process_Huffman_data_unit(priv, cCb);
+
+ // Cr
+ process_Huffman_data_unit(priv, cCr);
+}
+
+static void print_SOF(const unsigned char *stream)
+{
+ int width, height, nr_components, precision;
+#if DEBUG
+ const char *nr_components_to_string[] = {
+ "????",
+ "Grayscale",
+ "????",
+ "YCbCr",
+ "CYMK"
+ };
+#endif
+
+ precision = stream[2];
+ height = be16_to_cpu(stream+3);
+ width = be16_to_cpu(stream+5);
+ nr_components = stream[7];
+
+ trace("> SOF marker\n");
+ trace("Size:%dx%d nr_components:%d (%s) precision:%d\n",
+ width, height,
+ nr_components, nr_components_to_string[nr_components],
+ precision);
+}
+
+/*******************************************************************************
+ *
+ * JPEG/JFIF Parsing functions
+ *
+ * Note: only a small subset of the jpeg file format is supported. No markers,
+ * nor progressive stream is supported.
+ *
+ ******************************************************************************/
+
+static void build_quantization_table(float *qtable, const unsigned char *ref_table)
+{
+ /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct.
+ * For float AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ * What's actually stored is 1/divisor so that the inner loop can
+ * use a multiplication rather than a division.
+ */
+ int i, j;
+ static const double aanscalefactor[8] = {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+ const unsigned char *zz = zigzag;
+
+ for (i=0; i<8; i++) {
+ for (j=0; j<8; j++) {
+ *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
+ }
+ }
+
+}
+
+static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
+{
+ int qi;
+ float *table;
+ const unsigned char *dqt_block_end;
+
+ trace("> DQT marker\n");
+ dqt_block_end = stream + be16_to_cpu(stream);
+ stream += 2; /* Skip length */
+
+ while (stream < dqt_block_end)
+ {
+ qi = *stream++;
+#if SANITY_CHECK
+ if (qi>>4)
+ error("16 bits quantization table is not supported\n");
+ if (qi >= COMPONENTS)
+ error("No more than %d quantization tables supported (got %d)\n",
+ COMPONENTS, qi + 1);
+#endif
+ table = priv->Q_tables[qi];
+ build_quantization_table(table, stream);
+ stream += 64;
+ }
+ trace("< DQT marker\n");
+ return 0;
+}
+
+static int parse_SOF(struct jdec_private *priv, const unsigned char *stream)
+{
+ int i, width, height, nr_components, cid, sampling_factor;
+ int Q_table;
+ struct component *c;
+
+ trace("> SOF marker\n");
+ print_SOF(stream);
+
+ height = be16_to_cpu(stream+3);
+ width = be16_to_cpu(stream+5);
+ nr_components = stream[7];
+#if SANITY_CHECK
+ if (stream[2] != 8)
+ error("Precision other than 8 is not supported\n");
+ if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT)
+ error("Width and Height (%dx%d) seems suspicious\n", width, height);
+ if (nr_components != 3)
+ error("We only support YUV images\n");
+ if (height%8)
+ error("Height need to be a multiple of 8 (current height is %d)\n", height);
+ if (width%16)
+ error("Width need to be a multiple of 16 (current Width is %d)\n", width);
+#endif
+ stream += 8;
+ for (i=0; i<nr_components; i++) {
+ cid = *stream++;
+ sampling_factor = *stream++;
+ Q_table = *stream++;
+ c = &priv->component_infos[i];
+#if SANITY_CHECK
+ c->cid = cid;
+#endif
+ c->Vfactor = sampling_factor&0xf;
+ c->Hfactor = sampling_factor>>4;
+ c->Q_table = priv->Q_tables[Q_table];
+ trace("Component:%d factor:%dx%d Quantization table:%d\n",
+ cid, c->Hfactor, c->Hfactor, Q_table );
+
+ }
+ priv->width = width;
+ priv->height = height;
+
+ trace("< SOF marker\n");
+
+ return 0;
+}
+
+static int parse_SOS(struct jdec_private *priv, const unsigned char *stream)
+{
+ unsigned int i, cid, table;
+ unsigned int nr_components = stream[2];
+
+ trace("> SOS marker\n");
+
+#if SANITY_CHECK
+ if (nr_components != 3)
+ error("We only support YCbCr image\n");
+#endif
+
+ stream += 3;
+ for (i=0;i<nr_components;i++) {
+ cid = *stream++;
+ table = *stream++;
+#if SANITY_CHECK
+ if ((table&0xf) >= HUFFMAN_TABLES)
+ error("We do not support more than %d AC Huffman table\n",
+ HUFFMAN_TABLES);
+ if ((table>>4) >= HUFFMAN_TABLES)
+ error("We do not support more than %d DC Huffman table\n",
+ HUFFMAN_TABLES);
+ if (cid != priv->component_infos[i].cid)
+ error("SOS cid order (%u:%u) isn't compatible with the SOF marker (%u:%u)\n",
+ i, cid, i, priv->component_infos[i].cid);
+ trace("ComponentId:%u tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);
+#endif
+ priv->component_infos[i].AC_table = &priv->HTAC[table&0xf];
+ priv->component_infos[i].DC_table = &priv->HTDC[table>>4];
+ }
+ priv->stream = stream+3;
+
+ /* ITU-T T.81 (9/92) chapter E.1.3 clearly states that RSTm is to be set to 0 at the beginning of each scan */
+ priv->last_rst_marker_seen = 0;
+
+ trace("< SOS marker\n");
+
+ return 0;
+}
+
+static int parse_DHT(struct jdec_private *priv, const unsigned char *stream)
+{
+ unsigned int count, i;
+ unsigned char huff_bits[17];
+ int length, index;
+
+ length = be16_to_cpu(stream) - 2;
+ stream += 2; /* Skip length */
+
+ trace("> DHT marker (length=%d)\n", length);
+
+ while (length>0) {
+ index = *stream++;
+
+ /* We need to calculate the number of bytes 'vals' will takes */
+ huff_bits[0] = 0;
+ count = 0;
+ for (i=1; i<17; i++) {
+ huff_bits[i] = *stream++;
+ count += huff_bits[i];
+ }
+#if SANITY_CHECK
+ if (count > 1024)
+ error("No more than 1024 bytes is allowed to describe a huffman table\n");
+ if ( (index &0xf) >= HUFFMAN_TABLES)
+ error("No mode than %d Huffman tables is supported\n", HUFFMAN_TABLES);
+ trace("Huffman table %s n%d\n", (index&0xf0)?"AC":"DC", index&0xf);
+ trace("Length of the table: %d\n", count);
+#endif
+
+ if (index & 0xf0 ) {
+ if (build_huffman_table(priv, huff_bits, stream, &priv->HTAC[index&0xf]))
+ return -1;
+ } else {
+ if (build_huffman_table(priv, huff_bits, stream, &priv->HTDC[index&0xf]))
+ return -1;
+ }
+
+ length -= 1;
+ length -= 16;
+ length -= count;
+ stream += count;
+ }
+ trace("< DHT marker\n");
+ return 0;
+}
+
+static int parse_DRI(struct jdec_private *priv, const unsigned char *stream)
+{
+ unsigned int length;
+
+ trace("> DRI marker\n");
+
+ length = be16_to_cpu(stream);
+
+#if SANITY_CHECK
+ if (length != 4)
+ error("Length of DRI marker need to be 4\n");
+#endif
+
+ priv->restart_interval = be16_to_cpu(stream+2);
+
+#if DEBUG
+ trace("Restart interval = %d\n", priv->restart_interval);
+#endif
+
+ trace("< DRI marker\n");
+
+ return 0;
+}
+
+
+
+static void resync(struct jdec_private *priv)
+{
+ int i;
+
+ /* Init DC coefficients */
+ for (i=0; i<COMPONENTS; i++)
+ priv->component_infos[i].previous_DC = 0;
+
+ priv->reservoir = 0;
+ priv->nbits_in_reservoir = 0;
+ if (priv->restart_interval > 0)
+ priv->restarts_to_go = priv->restart_interval;
+ else
+ priv->restarts_to_go = -1;
+}
+
+static int find_next_rst_marker(struct jdec_private *priv)
+{
+ int rst_marker_found = 0;
+ int marker;
+ const unsigned char *stream = priv->stream;
+
+ /* Parse marker */
+ while (!rst_marker_found)
+ {
+ while (*stream++ != 0xff)
+ {
+ if (stream >= priv->stream_end)
+ error("EOF while search for a RST marker.\n");
+ }
+ /* Skip any padding ff byte (this is normal) */
+ while (*stream == 0xff)
+ stream++;
+
+ marker = *stream++;
+ if ((RST+priv->last_rst_marker_seen) == marker)
+ rst_marker_found = 1;
+ else if (marker >= RST && marker <= RST7)
+ error("Wrong Reset marker found, abording\n");
+ else if (marker == EOI)
+ return 0;
+ }
+
+ priv->stream = stream;
+ priv->last_rst_marker_seen++;
+ priv->last_rst_marker_seen &= 7;
+
+ return 0;
+}
+
+static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
+{
+ int chuck_len;
+ int marker;
+ int sof_marker_found = 0;
+ int dqt_marker_found = 0;
+ int sos_marker_found = 0;
+ int dht_marker_found = 0;
+ const unsigned char *next_chunck;
+
+ /* Parse marker */
+ while (!sos_marker_found)
+ {
+ if (*stream++ != 0xff)
+ goto bogus_jpeg_format;
+ /* Skip any padding ff byte (this is normal) */
+ while (*stream == 0xff)
+ stream++;
+
+ marker = *stream++;
+ chuck_len = be16_to_cpu(stream);
+ next_chunck = stream + chuck_len;
+ switch (marker)
+ {
+ case SOF:
+ if (parse_SOF(priv, stream) < 0)
+ return -1;
+ sof_marker_found = 1;
+ break;
+ case DQT:
+ if (parse_DQT(priv, stream) < 0)
+ return -1;
+ dqt_marker_found = 1;
+ break;
+ case SOS:
+ if (parse_SOS(priv, stream) < 0)
+ return -1;
+ sos_marker_found = 1;
+ break;
+ case DHT:
+ if (parse_DHT(priv, stream) < 0)
+ return -1;
+ dht_marker_found = 1;
+ break;
+ case DRI:
+ if (parse_DRI(priv, stream) < 0)
+ return -1;
+ break;
+ default:
+ trace("> Unknown marker %2.2x\n", marker);
+ break;
+ }
+
+ stream = next_chunck;
+ }
+
+ if ( !sof_marker_found ||
+ (!dqt_marker_found && !(priv->flags & TINYJPEG_FLAGS_PIXART_JPEG)))
+ goto bogus_jpeg_format;
+
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) {
+ if (!priv->default_huffman_table_initialized) {
+ build_quantization_table(priv->Q_tables[0], pixart_quantization[0]);
+ build_quantization_table(priv->Q_tables[1], pixart_quantization[1]);
+ }
+
+ /* Pixart JPEG data starts with one unknown / unused byte */
+ priv->stream++;
+ }
+
+ if (!dht_marker_found) {
+ trace("No Huffman table loaded, using the default one\n");
+ if (build_default_huffman_tables(priv))
+ return -1;
+ }
+
+#ifdef SANITY_CHECK
+ if ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor)
+ || (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor))
+ error("Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n");
+ if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor)
+ || (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor))
+ error("Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n");
+ if ( (priv->component_infos[cCb].Hfactor!=1)
+ || (priv->component_infos[cCr].Hfactor!=1)
+ || (priv->component_infos[cCb].Vfactor!=1)
+ || (priv->component_infos[cCr].Vfactor!=1))
+ error("Sampling other than 1x1 for Cr and Cb is not supported\n");
+#endif
+
+ return 0;
+bogus_jpeg_format:
+ error("Bogus jpeg format\n");
+ return -1;
+}
+
+/*******************************************************************************
+ *
+ * Functions exported of the library.
+ *
+ * Note: Some applications can access directly to internal pointer of the
+ * structure. It's is not recommended, but if you have many images to
+ * uncompress with the same parameters, some functions can be called to speedup
+ * the decoding.
+ *
+ ******************************************************************************/
+
+/**
+ * Allocate a new tinyjpeg decoder object.
+ *
+ * Before calling any other functions, an object need to be called.
+ */
+struct jdec_private *tinyjpeg_init(void)
+{
+ struct jdec_private *priv;
+
+ priv = (struct jdec_private *)calloc(1, sizeof(struct jdec_private));
+ if (priv == NULL)
+ return NULL;
+ return priv;
+}
+
+/**
+ * Free a tinyjpeg object.
+ *
+ * No others function can be called after this one.
+ */
+void tinyjpeg_free(struct jdec_private *priv)
+{
+ int i;
+ for (i=0; i<COMPONENTS; i++) {
+ if (priv->components[i])
+ free(priv->components[i]);
+ priv->components[i] = NULL;
+ }
+ free(priv);
+}
+
+/**
+ * Initialize the tinyjpeg object and prepare the decoding of the stream.
+ *
+ * Check if the jpeg can be decoded with this jpeg decoder.
+ * Fill some table used for preprocessing.
+ */
+int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size)
+{
+ int ret;
+
+ /* Identify the file */
+ if ((buf[0] != 0xFF) || (buf[1] != SOI))
+ error("Not a JPG file ?\n");
+
+ priv->stream_begin = buf+2;
+ priv->stream_length = size-2;
+ priv->stream_end = priv->stream_begin + priv->stream_length;
+
+ ret = parse_JFIF(priv, priv->stream_begin);
+
+ return ret;
+}
+
+static const decode_MCU_fct decode_mcu_3comp_table[4] = {
+ decode_MCU_1x1_3planes,
+ decode_MCU_1x2_3planes,
+ decode_MCU_2x1_3planes,
+ decode_MCU_2x2_3planes,
+};
+
+static const decode_MCU_fct pixart_decode_mcu_3comp_table[4] = {
+ NULL,
+ NULL,
+ pixart_decode_MCU_2x1_3planes,
+ NULL,
+};
+
+static const decode_MCU_fct decode_mcu_1comp_table[4] = {
+ decode_MCU_1x1_1plane,
+ decode_MCU_1x2_1plane,
+ decode_MCU_2x1_1plane,
+ decode_MCU_2x2_1plane,
+};
+
+static const convert_colorspace_fct convert_colorspace_yuv420p[4] = {
+ YCrCB_to_YUV420P_1x1,
+ YCrCB_to_YUV420P_1x2,
+ YCrCB_to_YUV420P_2x1,
+ YCrCB_to_YUV420P_2x2,
+};
+
+static const convert_colorspace_fct convert_colorspace_rgb24[4] = {
+ YCrCB_to_RGB24_1x1,
+ YCrCB_to_RGB24_1x2,
+ YCrCB_to_RGB24_2x1,
+ YCrCB_to_RGB24_2x2,
+};
+
+static const convert_colorspace_fct convert_colorspace_bgr24[4] = {
+ YCrCB_to_BGR24_1x1,
+ YCrCB_to_BGR24_1x2,
+ YCrCB_to_BGR24_2x1,
+ YCrCB_to_BGR24_2x2,
+};
+
+static const convert_colorspace_fct convert_colorspace_grey[4] = {
+ YCrCB_to_Grey_1x1,
+ YCrCB_to_Grey_1x2,
+ YCrCB_to_Grey_2x1,
+ YCrCB_to_Grey_2x2,
+};
+
+/**
+ * Decode and convert the jpeg image into @pixfmt@ image
+ *
+ * Note: components will be automaticaly allocated if no memory is attached.
+ */
+int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
+{
+ unsigned int x, y, xstride_by_mcu, ystride_by_mcu;
+ unsigned int bytes_per_blocklines[3], bytes_per_mcu[3];
+ decode_MCU_fct decode_MCU;
+ const decode_MCU_fct *decode_mcu_table;
+ const convert_colorspace_fct *colorspace_array_conv;
+ convert_colorspace_fct convert_to_pixfmt;
+
+ if (setjmp(priv->jump_state))
+ return -1;
+
+ /* To keep gcc happy initialize some array */
+ bytes_per_mcu[1] = 0;
+ bytes_per_mcu[2] = 0;
+ bytes_per_blocklines[1] = 0;
+ bytes_per_blocklines[2] = 0;
+
+ decode_mcu_table = decode_mcu_3comp_table;
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG)
+ decode_mcu_table = pixart_decode_mcu_3comp_table;
+
+ switch (pixfmt) {
+ case TINYJPEG_FMT_YUV420P:
+ colorspace_array_conv = convert_colorspace_yuv420p;
+ if (priv->components[0] == NULL)
+ priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);
+ if (priv->components[1] == NULL)
+ priv->components[1] = (uint8_t *)malloc(priv->width * priv->height/4);
+ if (priv->components[2] == NULL)
+ priv->components[2] = (uint8_t *)malloc(priv->width * priv->height/4);
+ bytes_per_blocklines[0] = priv->width;
+ bytes_per_blocklines[1] = priv->width/4;
+ bytes_per_blocklines[2] = priv->width/4;
+ bytes_per_mcu[0] = 8;
+ bytes_per_mcu[1] = 4;
+ bytes_per_mcu[2] = 4;
+ break;
+
+ case TINYJPEG_FMT_RGB24:
+ colorspace_array_conv = convert_colorspace_rgb24;
+ if (priv->components[0] == NULL)
+ priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);
+ bytes_per_blocklines[0] = priv->width * 3;
+ bytes_per_mcu[0] = 3*8;
+ break;
+
+ case TINYJPEG_FMT_BGR24:
+ colorspace_array_conv = convert_colorspace_bgr24;
+ if (priv->components[0] == NULL)
+ priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);
+ bytes_per_blocklines[0] = priv->width * 3;
+ bytes_per_mcu[0] = 3*8;
+ break;
+
+ case TINYJPEG_FMT_GREY:
+ decode_mcu_table = decode_mcu_1comp_table;
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG)
+ error("Greyscale output not support for PIXART JPEG's\n");
+ colorspace_array_conv = convert_colorspace_grey;
+ if (priv->components[0] == NULL)
+ priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);
+ bytes_per_blocklines[0] = priv->width;
+ bytes_per_mcu[0] = 8;
+ break;
+
+ default:
+ error("Bad pixel format\n");
+ }
+
+ xstride_by_mcu = ystride_by_mcu = 8;
+ if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {
+ decode_MCU = decode_mcu_table[0];
+ convert_to_pixfmt = colorspace_array_conv[0];
+ trace("Use decode 1x1 sampling\n");
+ } else if (priv->component_infos[cY].Hfactor == 1) {
+ decode_MCU = decode_mcu_table[1];
+ convert_to_pixfmt = colorspace_array_conv[1];
+ ystride_by_mcu = 16;
+ trace("Use decode 1x2 sampling (not supported)\n");
+ } else if (priv->component_infos[cY].Vfactor == 2) {
+ decode_MCU = decode_mcu_table[3];
+ convert_to_pixfmt = colorspace_array_conv[3];
+ xstride_by_mcu = 16;
+ ystride_by_mcu = 16;
+ trace("Use decode 2x2 sampling\n");
+ } else {
+ decode_MCU = decode_mcu_table[2];
+ convert_to_pixfmt = colorspace_array_conv[2];
+ xstride_by_mcu = 16;
+ trace("Use decode 2x1 sampling\n");
+ }
+
+ if (decode_MCU == NULL)
+ error("no decode MCU function for this JPEG format (PIXART?)\n");
+
+ resync(priv);
+
+ /* Don't forget to that block can be either 8 or 16 lines */
+ bytes_per_blocklines[0] *= ystride_by_mcu;
+ bytes_per_blocklines[1] *= ystride_by_mcu;
+ bytes_per_blocklines[2] *= ystride_by_mcu;
+
+ bytes_per_mcu[0] *= xstride_by_mcu/8;
+ bytes_per_mcu[1] *= xstride_by_mcu/8;
+ bytes_per_mcu[2] *= xstride_by_mcu/8;
+
+ /* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */
+ for (y=0; y < priv->height/ystride_by_mcu; y++)
+ {
+ //trace("Decoding row %d\n", y);
+ priv->plane[0] = priv->components[0] + (y * bytes_per_blocklines[0]);
+ priv->plane[1] = priv->components[1] + (y * bytes_per_blocklines[1]);
+ priv->plane[2] = priv->components[2] + (y * bytes_per_blocklines[2]);
+ for (x=0; x < priv->width; x+=xstride_by_mcu)
+ {
+ decode_MCU(priv);
+ convert_to_pixfmt(priv);
+ priv->plane[0] += bytes_per_mcu[0];
+ priv->plane[1] += bytes_per_mcu[1];
+ priv->plane[2] += bytes_per_mcu[2];
+ if (priv->restarts_to_go>0)
+ {
+ priv->restarts_to_go--;
+ if (priv->restarts_to_go == 0)
+ {
+ priv->stream -= (priv->nbits_in_reservoir/8);
+ resync(priv);
+ if (find_next_rst_marker(priv) < 0)
+ return -1;
+ }
+ }
+ }
+ }
+
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) {
+ /* Additional sanity check for funky Pixart format */
+ if ((priv->stream_end - priv->stream) > 5)
+ error("Pixart JPEG error, stream does not end with EOF marker\n");
+ }
+
+ return 0;
+}
+
+const char *tinyjpeg_get_errorstring(struct jdec_private *priv)
+{
+ return priv->error_string;
+}
+
+void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height)
+{
+ *width = priv->width;
+ *height = priv->height;
+}
+
+int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components)
+{
+ int i;
+ for (i=0; priv->components[i] && i<COMPONENTS; i++)
+ components[i] = priv->components[i];
+ return 0;
+}
+
+int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents)
+{
+ unsigned int i;
+ if (ncomponents > COMPONENTS)
+ ncomponents = COMPONENTS;
+ for (i=0; i<ncomponents; i++)
+ priv->components[i] = components[i];
+ return 0;
+}
+
+int tinyjpeg_set_flags(struct jdec_private *priv, int flags)
+{
+ int oldflags = priv->flags;
+ priv->flags = flags;
+ return oldflags;
+}
+
diff --git a/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h
new file mode 100644
index 000000000..b0096f0de
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/tinyjpeg.h
@@ -0,0 +1,74 @@
+/*
+ * Small jpeg decoder library (header file)
+ *
+ * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the author nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __JPEGDEC_H__
+#define __JPEGDEC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct jdec_private;
+
+/* Flags that can be set by any applications */
+#define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1)
+#define TINYJPEG_FLAGS_PIXART_JPEG (1<<2)
+
+/* Format accepted in outout */
+enum tinyjpeg_fmt {
+ TINYJPEG_FMT_GREY = 1,
+ TINYJPEG_FMT_BGR24,
+ TINYJPEG_FMT_RGB24,
+ TINYJPEG_FMT_YUV420P,
+};
+
+struct jdec_private *tinyjpeg_init(void);
+void tinyjpeg_free(struct jdec_private *priv);
+
+int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size);
+int tinyjpeg_decode(struct jdec_private *priv, int pixel_format);
+const char *tinyjpeg_get_errorstring(struct jdec_private *priv);
+void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height);
+int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components);
+int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents);
+int tinyjpeg_set_flags(struct jdec_private *priv, int flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+