Check in veejay 1.3

git-svn-id: svn://code.dyne.org/veejay/trunk@1135 eb8d1916-c9e9-0310-b8de-cf0c9472ead5
This commit is contained in:
Niels Elburg
2008-11-01 03:35:28 +00:00
parent df26a2bb24
commit 6b05bbb5c3
625 changed files with 168856 additions and 0 deletions

27
veejay-1.3/README Normal file
View File

@@ -0,0 +1,27 @@
10x0 0x x10x0x10x0x10x 10x0x10x0x10x0 x0x1 x0x1 10x0 x0x1
0x10x0 0x0x x10x0x10x0x10x 10x0x10x0x10x0 x0x1 10x0x10x 10x0x1 10x0x1
0x0x10 0x0x10 x10x 10x0 x0x1 10x0x10x x0x10x 10x0
0x0x10x0 0x0x10 x10x0x10x0x1 10x0x10x0x10 x0x1 0x10 0x0 x10x0x10
0x10x0 x10x0x x10x0x10x0x10x 10x0x10x0x10 x0x1 0x10x0x10x0 x10x0x10
10x0x1 x0x10x x10x 10x0 x0x1 0x10x0x10x0 0x0x
x0x10x0x10x0x1 x10x 10x0 x10x x0x1 0x10x0x10x0x10 0x0x
x10x0x10x0 x10x0x10x0x10x 10x0x10x0x10x0 x10x 10x0 0x0x 0x10 0x0x
0x0x10 x10x0x10x0x10x 10x0x10x0x10x0 0x010x0 0x0x 0x10 0x0x
version 1.3
November 2008
=========================================
:: Veejay, a visual instrument for GNU ::
http://veejayhq.net
http://veejay.dyne.org
Package contents:
veejay-server

View File

@@ -0,0 +1,30 @@
veejay contributors:
====================
(in no particular order)
Jeff Carpenter
David Denny
Daniel Jircik
Pilo Chambert
Matthijs van Henten
Dursun Koca
Peter de Man
Stefan Thieme
Andrew Wood
Kyle Davenport
Daniel Rohr
Rupert Reddington
Toni (from Germany)
Thomas Reinhold
Maciek Szczesniak
authors:
======================
Niels Elburg <nelburg@looze.net >

View File

@@ -0,0 +1,504 @@
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.
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.
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.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also 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.
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.
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.
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
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 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!

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,234 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006 Free Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that the
`configure' script does not know about. Run `./configure --help' for
details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out automatically,
but needs to determine by the type of machine the package will run on.
Usually, assuming the package is built to be run on the _same_
architectures, `configure' can figure that out, but if it prints a
message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share, you
can create a site shell script called `config.site' that gives default
values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@@ -0,0 +1,52 @@
# Process with automake to produce Makefile.in
SUBDIRS = aclib bio2jack libOSC libhash libvjmsg libvjmem
SUBDIRS += libvevo liblzo libgoom libvje libsample libvjnet libyuv libel libstream liblavjpeg libsamplerec
SUBDIRS += veejay
SUBDIRS += man
EXTRA_DIST = \
autogen.sh\
depcomp \
cpuinfo.sh \
autogen.sh \
gveejay-paths.sh.in
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = veejay.pc
DISTCLEANFILES = \
veejay-config.h \
veejay.pc \
confdefs.h \
config.cache \
config.status \
config.log \
gveejay-paths.h
MAINTAINERCLEANFILES = \
compile \
depcomp \
install-sh \
missing \
mkinstalldirs \
Makefile.in \
aclocal.m4 \
config.guess \
config.h.in \
config.sub \
configure \
ltmain.sh \
stamp-h.in
## make rpms
rpm: Makefile
$(MAKE) dist
rpmbuild -ta --clean $(PACKAGE)-$(VERSION).tar.gz
## make debs
deb: Makefile dist
-chmod -R +w $(PACKAGE)-$(VERSION)
rm -rf $(PACKAGE)-$(VERSION)
tar xzf $(PACKAGE)-$(VERSION).tar.gz
cd $(PACKAGE)-$(VERSION); dpkg-buildpackage -rfakeroot

View File

View File

@@ -0,0 +1,198 @@
10x0 0x x10x0x10x0x10x 10x0x10x0x10x0 x0x1 x0x1 10x0 x0x1
0x10x0 0x0x x10x0x10x0x10x 10x0x10x0x10x0 x0x1 10x0x10x 10x0x1 10x0x1
0x0x10 0x0x10 x10x 10x0 x0x1 10x0x10x x0x10x 10x0
0x0x10x0 0x0x10 x10x0x10x0x1 10x0x10x0x10 x0x1 0x10 0x0 x10x0x10
0x10x0 x10x0x x10x0x10x0x10x 10x0x10x0x10 x0x1 0x10x0x10x0 x10x0x10
10x0x1 x0x10x x10x 10x0 x0x1 0x10x0x10x0 0x0x
x0x10x0x10x0x1 x10x 10x0 x10x x0x1 0x10x0x10x0x10 0x0x
x10x0x10x0 x10x0x10x0x10x 10x0x10x0x10x0 x10x 10x0 0x0x 0x10 0x0x
0x0x10 x10x0x10x0x10x 10x0x10x0x10x0 0x010x0 0x0x 0x10 0x0x
version 1.3
November 2008
=========================================
:: Veejay, a visual instrument for GNU ::
http://veejayhq.net
http://veejay.dyne.org
Veejay - a 'visual' instrument and realtime video sampler
Veejay is a visual instrument and real-time video sampler.
It allows you to "play" the video like you would play a piano.
While playing, you can record the resulting video directly to disk (video sampling).
FEATURE OVERVIEW
General
-------
# Free Software (GNU GPL) (1)
# Servent architecture (2)
# Soft realtime (3)
# Frame accurate (4)
# Loop based editing (5)
# Native YUV processing
# Crash recovery
Media
-----
# Codecs: MJPEG,MPNG, DV, YUV (raw)
# Containers: AVI , Quicktime, rawDV
# Devices: USB webcams, DV1394, TV capture cards, etc.
# Support for unlimited capture devices
# Support for Image files (PNG ,JPEG,TIFF,etc)
Editing
-------
# 132 built-in FX , many unique and original FX filters
# FX chain (20 slots)
# All FX parameters can be animated.
# Mix up to two layers per FX slot
# Non destructive edit decision lists (cut/copy/paste/crop video)
# Simple text editor
# Sample editor
# Sequence editor
# Live disk recorder (sampling)
# Full deck save/restore
# Live clip loading
# Live sample sequencing
Trickplay
---------
# VIMS event recording/playback (6)
# Various looping modes including bounce looping
# Playback speed and direction
# Video scratching
# Change in-and out points of a sample (marker)
# Slow motion audio / video (7)
# Fast motion audio / video
# Dynamic framerate
# Random frame play
# Random sample play
# Access up to 4096 video samples instantly
Output
------
# Audio trough Jack (low latency audio server) (8)
# SDL and OpenGL video
# Headless
# YUV4MPEG streaming
# Network streaming (unicast and multicast)
# Preview rendering
Interaction
-----------
# Programmable keyboard interface
# VIMS (tcp/ip)
# OSC (udp)
# PureData trough sendVIMS external
Viewing
-------
# Full screen or windowed mode
# Perspective and foward projection (9)
Additional
----------
# Support for FreeFrame plugins
# Support for Frei0r plugins
(1) Free Software
A matter of liberty, not price. You should think of “free” as in free speech.
Free software is the matter of the users freedom to run, copy, distribute, study, change and improve the software.
(2) A servent architecture is a peer-to-peer network mode with both functionalities of a
server and a client. The setup is designed so that each veejay-node can send and receive video,
allowing for the creation and maintenance of ad-hoc veejay-networks.
Reloaded , veejay's graphical interface, is a thin client and can be run from another computer
to track one or more veejay servers.
(3) Soft realtime: A system is realtime if the correctness of the application not only depends on
the logical correctness but also upon the time at which it was performed.
Veejay tolerates such lateness and responds by dropping video frames.
You can instruct veejay to ignore the time aspect of the video and render all frames, effectivly
turning the server into a frame producer.
(4) VIMS: Veejay Internal Message System. Control data is distributed via this message system,
each message consists of an 'event selector' with a list of arguments. VIMS is the lowest
level control interface available. The keyboard interface and OSC server are built on top of it.
Also all veejay clients communicate usings VIMS.
(5) Loop based editing: Loops are (short) sections of video (up to any length) that are repeated
continuously. While playing, you can change the properties of the video sample, add filters to it
and record it on the fly to a new sample (which can be used instantly).
(6) Frame accurate: In veejay, every frame is a key-frame (a whole image).
As a consequence, veejay has no support for video codecs that make use of difference frames.
(7) In trickplay mode, veejay will always resample the audio analogous to varying the speed
of an analogue tape recorder . Halve the speed results in the pitch going down an octave.
Slow motion video is produced by linearly interpolating in-between frames and
faster motion is accomplished by skipping video frames or, if playing without audio,
by changing the framerate dynamically.
(8) JACK: A low latency audio server that can connect a number of different applications to an audio device,
allowing them to share audio between themselves.
(9) Perspective Viewing: You can define a quadrilateral to which the rendered image will be mapped.
This is usefull for setups where the image borders fall outside the projection screen area, or where
the projector/camera has a (wide) angle to the projection.
Last but not least, it can be used for on-body projection performances.
Install
=======
See file 'INSTALL'
See doc/Howto_Compile.html
See doc/Howto_Compile_on_Ubuntu.html
Documentation
=============
See the directory 'doc' in this package, it contains usefull documentation.
Running
=======
Start 1 or more Veejay servers:
$ veejay my-movie-A.avi
$ veejay -p 4490 my-movie-B.avi
CONTACT / FEEDBACK & HELP
=========================
http://veejayhq.net
BUG REPORTS / BLEEDING EDGE SOURCE CODE
=======================================
Please use the ticket system !
http://veejay.dyne.org
http://veejayhq.net
ENJOY! And let us know about your performances/installations with veejay!

View File

@@ -0,0 +1,16 @@
1. Extend viewport menu for mouse wheel scaling of points and quad
2. Find functionality to mirror points in one click (pixmap rendering as sdl osd button?)
3. Find functionality to use only 2 points to find the other 2
4. Re-write vj-composite
1. Backing, push a frame to the viewport
2. Render input source to backing viewport and take output as input
3. Render input source to viewport
5. Mind different resolutions and keep track of sampling
6. Reduce calls to vj_yuv_get444_template, vj_yuv_get_template, VJFrame *malloc()
7. remove viewport in reloaded
-

View File

@@ -0,0 +1,20 @@
# # Process this file with automake to produce Makefile.in.
AM_CPPFLAGS = \
$(PTHREAD_CFLAGS) \
-I$(top_srcdir)
noinst_LTLIBRARIES = libac.la
libac_la_SOURCES = \
accore.c \
average.c \
imgconvert.c \
img_rgb_packed.c \
img_yuv_mixed.c \
img_yuv_packed.c \
img_yuv_planar.c \
img_yuv_rgb.c \
memcpy.c \
rescale.c

View File

@@ -0,0 +1,97 @@
/*
* ac.h -- main aclib include
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#ifndef ACLIB_AC_H
#define ACLIB_AC_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
/*************************************************************************/
/* CPU acceleration support flags, for use with ac_init(): */
#define AC_IA32ASM 0x0001 /* x86-32: standard assembly (no MMX) */
#define AC_AMD64ASM 0x0002 /* x86-64: standard assembly (no MMX) */
#define AC_CMOVE 0x0004 /* x86: CMOVcc instruction */
#define AC_MMX 0x0008 /* x86: MMX instructions */
#define AC_MMXEXT 0x0010 /* x86: MMX extended instructions (AMD) */
#define AC_3DNOW 0x0020 /* x86: 3DNow! instructions (AMD) */
#define AC_3DNOWEXT 0x0040 /* x86: 3DNow! instructions (AMD) */
#define AC_SSE 0x0080 /* x86: SSE instructions */
#define AC_SSE2 0x0100 /* x86: SSE2 instructions */
#define AC_SSE3 0x0200 /* x86: SSE3 instructions */
#define AC_NONE 0 /* No acceleration (vanilla C functions) */
#define AC_ALL (~0) /* All available acceleration */
/* Endianness flag: */
#define AC_LITTLE_ENDIAN 1
#define AC_BIG_ENDIAN 2
/*************************************************************************/
/* Library initialization function--MUST be called before any other aclib
* functions are used! `accel' selects the accelerations to enable:
* AC_NONE, AC_ALL, or a combination of the other AC_* flags above. The
* value will always be masked to the acceleration options available on the
* actual CPU, as returned by ac_cpuinfo(). Returns 1 on success, 0 on
* failure. This function can be called multiple times to change the set
* of acceleration features to be used. */
extern int ac_init(int accel);
/* Returns the set of acceleration features supported by this CPU. */
extern int ac_cpuinfo(void);
/* Returns the endianness of this CPU (AC_BIG_ENDIAN or AC_LITTLE_ENDIAN). */
extern int ac_endian(void);
/* Utility routine to convert a set of flags to a descriptive string. The
* string is stored in a static buffer overwritten each call. */
extern const char *ac_flagstotext(int accel);
/*************************************************************************/
/* Acceleration-enabled functions: */
/* Optimized memcpy(). The copy direction is guaranteed to be ascending
* (so ac_memcpy(ptr, ptr+1, size) will work). */
extern void *ac_memcpy(void *dest, const void *src, size_t size);
/* Average of two sets of data */
extern void ac_average(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes);
/* Weighted average of two sets of data (weight1+weight2 should be 65536) */
extern void ac_rescale(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes,
uint32_t weight1, uint32_t weight2);
/* Image format manipulation is available in aclib/imgconvert.h */
/*************************************************************************/
#endif /* ACLIB_AC_H */
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,42 @@
/*
* ac_internal.h -- internal include file for aclib functions
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#ifndef ACLIB_AC_INTERNAL_H
#define ACLIB_AC_INTERNAL_H
/* Compiler hint that a condition is unlikely */
#ifdef __GNUC__
# define UNLIKELY(x) (__builtin_expect((x) != 0, 0))
#else
# define UNLIKELY(x) (x)
#endif
/* Are _all_ of the given acceleration flags (`test') available? */
#define HAS_ACCEL(accel,test) (((accel) & (test)) == (test))
/* Initialization subfunctions */
extern int ac_average_init(int accel);
extern int ac_imgconvert_init(int accel);
extern int ac_memcpy_init(int accel);
extern int ac_rescale_init(int accel);
#endif /* ACLIB_AC_INTERNAL_H */
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,225 @@
/*
* accore.c -- core aclib functions
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "ac_internal.h"
#include "imgconvert.h"
#include <stdio.h>
#include <string.h>
#if defined(ARCH_X86) || defined(ARCH_X86_64)
static int cpuinfo_x86(void);
#endif
/*************************************************************************/
/* Library initialization function. Determines CPU features, then calls
* all initialization subfunctions with appropriate flags. Returns 1 on
* success, 0 on failure. This function can be called multiple times to
* change the set of acceleration features to be used. */
int ac_init(int accel)
{
accel &= ac_cpuinfo();
if (!ac_average_init(accel)
|| !ac_imgconvert_init(accel)
|| !ac_memcpy_init(accel)
|| !ac_rescale_init(accel)
) {
return 0;
}
return 1;
}
/*************************************************************************/
/* Returns the set of acceleration features supported by this CPU. */
int ac_cpuinfo(void)
{
#if defined(ARCH_X86) || defined(ARCH_X86_64)
return cpuinfo_x86();
#else
return 0;
#endif
}
/*************************************************************************/
/* Returns the endianness of this CPU (AC_BIG_ENDIAN or AC_LITTLE_ENDIAN). */
int ac_endian(void)
{
volatile int test;
test = 1;
if (*((uint8_t *)&test))
return AC_LITTLE_ENDIAN;
else
return AC_BIG_ENDIAN;
}
/*************************************************************************/
/* Utility routine to convert a set of flags to a descriptive string. The
* string is stored in a static buffer overwritten each call. `filter'
* selects whether to filter out flags not supported by the CPU. */
const char *ac_flagstotext(int accel)
{
static char retbuf[1000];
if (!accel)
return "none";
snprintf(retbuf, sizeof(retbuf), "%s%s%s%s%s%s%s%s%s",
accel & AC_SSE3 ? " sse3" : "",
accel & AC_SSE2 ? " sse2" : "",
accel & AC_SSE ? " sse" : "",
accel & AC_3DNOWEXT ? " 3dnowext" : "",
accel & AC_3DNOW ? " 3dnow" : "",
accel & AC_MMXEXT ? " mmxext" : "",
accel & AC_MMX ? " mmx" : "",
accel & AC_CMOVE ? " cmove" : "",
accel & (AC_IA32ASM|AC_AMD64ASM) ? " asm" : "");
return *retbuf ? retbuf+1 : retbuf; /* skip initial space */
}
/*************************************************************************/
/*************************************************************************/
/* Private functions to return acceleration flags corresponding to available
* CPU features for various CPUs. Currently only x86 is supported. */
/*************************************************************************/
#if defined(ARCH_X86) || defined(ARCH_X86_64)
#ifdef ARCH_X86_64
# define EAX "%%rax"
# define EBX "%%rbx"
# define ESI "%%rsi"
# define PUSHF "pushfq"
# define POPF "popfq"
#else
# define EAX "%%eax"
# define EBX "%%ebx"
# define ESI "%%esi"
# define PUSHF "pushfl"
# define POPF "popfl"
#endif
/* Macro to execute the CPUID instruction with EAX = func. Results are
* placed in ret_a (EAX), ret_b (EBX), ret_c (ECX), and ret_d (EDX), which
* must be lvalues. Note that we save and restore EBX (RBX on x86-64)
* because it is the PIC register. */
#define CPUID(func,ret_a,ret_b,ret_c,ret_d) \
asm("mov "EBX", "ESI"; cpuid; xchg "EBX", "ESI \
: "=a" (ret_a), "=S" (ret_b), "=c" (ret_c), "=d" (ret_d) \
: "a" (func))
/* Various CPUID flags. The second word of the macro name indicates the
* function (1: function 1, X1: function 0x80000001) and register (D: EDX)
* to which the value belongs. */
#define CPUID_1D_CMOVE (1UL<<15)
#define CPUID_1D_MMX (1UL<<23)
#define CPUID_1D_SSE (1UL<<25)
#define CPUID_1D_SSE2 (1UL<<26)
#define CPUID_1C_SSE3 (1UL<< 0)
#define CPUID_X1D_AMD_MMXEXT (1UL<<22) /* AMD only */
#define CPUID_X1D_AMD_3DNOW (1UL<<31) /* AMD only */
#define CPUID_X1D_AMD_3DNOWEXT (1UL<<30) /* AMD only */
#define CPUID_X1D_CYRIX_MMXEXT (1UL<<24) /* Cyrix only */
static int cpuinfo_x86(void)
{
uint32_t eax, ebx, ecx, edx;
uint32_t cpuid_max, cpuid_ext_max; /* Maximum CPUID function numbers */
char cpu_vendor[13]; /* 12-byte CPU vendor string + trailing null */
uint32_t cpuid_1D, cpuid_1C, cpuid_X1D;
int accel;
/* First see if the CPUID instruction is even available. We try to
* toggle bit 21 (ID) of the flags register; if the bit changes, then
* CPUID is available. */
asm(PUSHF" \n\
pop "EAX" \n\
mov %%eax, %%edx \n\
xor $0x200000, %%eax \n\
push "EAX" \n\
"POPF" \n\
"PUSHF" \n\
pop "EAX" \n\
xor %%edx, %%eax"
: "=a" (eax) : : "edx");
if (!eax)
return 0;
/* Determine the maximum function number available, and save the vendor
* string */
CPUID(0, cpuid_max, ebx, ecx, edx);
*((uint32_t *)(cpu_vendor )) = ebx;
*((uint32_t *)(cpu_vendor+4)) = edx;
*((uint32_t *)(cpu_vendor+8)) = ecx;
cpu_vendor[12] = 0;
cpuid_ext_max = 0; /* FIXME: how do early CPUs respond to 0x80000000? */
CPUID(0x80000000, cpuid_ext_max, ebx, ecx, edx);
/* Read available features */
cpuid_1D = cpuid_1C = cpuid_X1D = 0;
if (cpuid_max >= 1)
CPUID(1, eax, ebx, cpuid_1C, cpuid_1D);
if (cpuid_ext_max >= 0x80000001)
CPUID(0x80000001, eax, ebx, ecx, cpuid_X1D);
/* Convert to acceleration flags */
#ifdef ARCH_X86_64
accel = AC_AMD64ASM; /* but not IA32! (register size issues) */
#else
accel = AC_IA32ASM;
#endif
if (cpuid_1D & CPUID_1D_CMOVE)
accel |= AC_CMOVE;
if (cpuid_1D & CPUID_1D_MMX)
accel |= AC_MMX;
if (cpuid_1D & CPUID_1D_SSE)
accel |= AC_SSE;
if (cpuid_1D & CPUID_1D_SSE2)
accel |= AC_SSE2;
if (cpuid_1C & CPUID_1C_SSE3)
accel |= AC_SSE3;
if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
if (cpuid_X1D & CPUID_X1D_AMD_MMXEXT)
accel |= AC_MMXEXT;
if (cpuid_X1D & CPUID_X1D_AMD_3DNOW)
accel |= AC_3DNOW;
if (cpuid_X1D & CPUID_X1D_AMD_3DNOWEXT)
accel |= AC_3DNOWEXT;
} else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
if (cpuid_X1D & CPUID_X1D_CYRIX_MMXEXT)
accel |= AC_MMXEXT;
}
/* And return */
return accel;
}
#endif /* ARCH_X86 || ARCH_X86_64 */
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,243 @@
/*
* average.c -- average two sets of byte data
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "ac_internal.h"
static void average(const uint8_t *, const uint8_t *, uint8_t *, int);
static void (*average_ptr)(const uint8_t *, const uint8_t *, uint8_t *, int)
= average;
/*************************************************************************/
/* External interface */
void ac_average(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes)
{
(*average_ptr)(src1, src2, dest, bytes);
}
/*************************************************************************/
/*************************************************************************/
/* Vanilla C version */
static void average(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes)
{
int i;
for (i = 0; i < bytes; i++)
dest[i] = (src1[i]+src2[i]+1) / 2;
}
/*************************************************************************/
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86) /* i.e. not x86_64 */
static void average_mmx(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes)
{
if (bytes >= 8) {
asm("\
pxor %%mm7, %%mm7 \n\
movq %%mm7, %%mm6 \n\
pcmpeqw %%mm5, %%mm5 \n\
psubw %%mm5, %%mm6 # Put 0x0001*4 in MM6 \n\
0: \n\
movq -8(%%esi,%%eax), %%mm0 \n\
movq %%mm0, %%mm1 \n\
punpcklbw %%mm7, %%mm0 \n\
punpckhbw %%mm7, %%mm1 \n\
movq -8(%%edx,%%eax), %%mm2 \n\
movq %%mm2, %%mm3 \n\
punpcklbw %%mm7, %%mm2 \n\
punpckhbw %%mm7, %%mm3 \n\
paddw %%mm2, %%mm0 \n\
paddw %%mm6, %%mm0 \n\
psrlw $1, %%mm0 \n\
paddw %%mm3, %%mm1 \n\
paddw %%mm6, %%mm1 \n\
psrlw $1, %%mm1 \n\
packuswb %%mm1, %%mm0 \n\
movq %%mm0, -8(%%edi,%%eax) \n\
subl $8, %%eax \n\
jnz 0b \n\
emms"
: /* no outputs */
: "S" (src1), "d" (src2), "D" (dest), "a" (bytes & ~7));
}
if (UNLIKELY(bytes & 7)) {
average(src1+(bytes & ~7), src2+(bytes & ~7), dest+(bytes & ~7),
bytes & 7);
}
}
#endif /* HAVE_ASM_MMX && ARCH_X86 */
/*************************************************************************/
#if defined(HAVE_ASM_SSE) && defined(ARCH_X86)
/* SSE has PAVGB */
static void average_sse(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes)
{
if (bytes >= 8) {
asm("\
testl $~0x1F, %%eax \n\
jz 1f \n\
0: \n\
movq -32(%%esi,%%eax), %%mm0 \n\
movq -24(%%esi,%%eax), %%mm1 \n\
movq -16(%%esi,%%eax), %%mm2 \n\
movq -8(%%esi,%%eax), %%mm3 \n\
movq -32(%%edx,%%eax), %%mm4 \n\
pavgb %%mm4, %%mm0 \n\
movq -24(%%edx,%%eax), %%mm5 \n\
pavgb %%mm5, %%mm1 \n\
movq -16(%%edx,%%eax), %%mm6 \n\
pavgb %%mm6, %%mm2 \n\
movq -8(%%edx,%%eax), %%mm7 \n\
pavgb %%mm7, %%mm3 \n\
movntq %%mm0, -32(%%edi,%%eax) \n\
movntq %%mm1, -24(%%edi,%%eax) \n\
movntq %%mm2, -16(%%edi,%%eax) \n\
movntq %%mm3, -8(%%edi,%%eax) \n\
subl $32, %%eax \n\
testl $~0x1F, %%eax \n\
jnz 0b \n\
testl %%eax, %%eax \n\
jz 2f \n\
1: \n\
movq -8(%%esi,%%eax), %%mm0 \n\
movq -8(%%edx,%%eax), %%mm1 \n\
pavgb %%mm1, %%mm0 \n\
movntq %%mm0, -8(%%edi,%%eax) \n\
subl $8, %%eax \n\
jnz 1b \n\
2: \n\
emms \n\
sfence"
: /* no outputs */
: "S" (src1), "d" (src2), "D" (dest), "a" (bytes & ~7));
}
if (UNLIKELY(bytes & 7)) {
average(src1+(bytes & ~7), src2+(bytes & ~7), dest+(bytes & ~7),
bytes & 7);
}
}
#endif /* HAVE_ASM_SSE && ARCH_X86 */
/*************************************************************************/
#if defined(HAVE_ASM_SSE2)
#if defined(ARCH_X86_64)
# define EAX "%%rax"
# define EDX "%%rdx"
# define ESI "%%rsi"
# define EDI "%%rdi"
#else
# define EAX "%%eax"
# define EDX "%%edx"
# define ESI "%%esi"
# define EDI "%%edi"
#endif
static void average_sse2(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes)
{
if (bytes >= 8) {
asm("\
testl $~0x3F, %%eax \n\
jz 1f \n\
0: \n\
movdqu -64("ESI","EAX"), %%xmm0 \n\
movdqu -48("ESI","EAX"), %%xmm1 \n\
movdqu -32("ESI","EAX"), %%xmm2 \n\
movdqu -16("ESI","EAX"), %%xmm3 \n\
movdqu -64("EDX","EAX"), %%xmm4 \n\
pavgb %%xmm4, %%xmm0 \n\
movdqu -48("EDX","EAX"), %%xmm5 \n\
pavgb %%xmm5, %%xmm1 \n\
movdqu -32("EDX","EAX"), %%xmm6 \n\
pavgb %%xmm6, %%xmm2 \n\
movdqu -16("EDX","EAX"), %%xmm7 \n\
pavgb %%xmm7, %%xmm3 \n\
# Note that movntdq requires 16-byte alignment, which we're \n\
# not guaranteed \n\
movdqu %%xmm0, -64("EDI","EAX") \n\
movdqu %%xmm1, -48("EDI","EAX") \n\
movdqu %%xmm2, -32("EDI","EAX") \n\
movdqu %%xmm3, -16("EDI","EAX") \n\
subl $64, %%eax \n\
testl $~0x3F, %%eax \n\
jnz 0b \n\
testl %%eax, %%eax \n\
jz 2f \n\
1: \n\
movq -8("ESI","EAX"), %%mm0 \n\
movq -8("EDX","EAX"), %%mm1 \n\
pavgb %%mm1, %%mm0 \n\
movq %%mm0, -8("EDI","EAX") \n\
subl $8, %%eax \n\
jnz 1b \n\
2: \n\
emms"
: /* no outputs */
: "S" (src1), "d" (src2), "D" (dest), "a" (bytes & ~7));
}
if (UNLIKELY(bytes & 7)) {
average(src1+(bytes & ~7), src2+(bytes & ~7), dest+(bytes & ~7),
bytes & 7);
}
}
#endif /* HAVE_ASM_SSE2 */
/*************************************************************************/
/*************************************************************************/
/* Initialization routine. */
int ac_average_init(int accel)
{
average_ptr = average;
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86)
if (HAS_ACCEL(accel, AC_MMX))
average_ptr = average_mmx;
#endif
#if defined(HAVE_ASM_SSE) && defined(ARCH_X86)
if (HAS_ACCEL(accel, AC_SSE))
average_ptr = average_sse;
#endif
#if defined(HAVE_ASM_SSE2)
if (HAS_ACCEL(accel, AC_SSE2))
average_ptr = average_sse2;
#endif
return 1;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,40 @@
/*
* img_internal.h - imgconvert internal use header
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#ifndef ACLIB_IMG_INTERNAL_H
#define ACLIB_IMG_INTERNAL_H
/* Type of a conversion function */
typedef int (*ConversionFunc)(uint8_t **src, uint8_t **dest,
int width, int height);
/* Function to register a conversion */
extern int register_conversion(ImageFormat srcfmt, ImageFormat destfmt,
ConversionFunc function);
/* Initialization routines */
extern int ac_imgconvert_init(int accel);
extern int ac_imgconvert_init_yuv_planar(int accel);
extern int ac_imgconvert_init_yuv_packed(int accel);
extern int ac_imgconvert_init_yuv_mixed(int accel);
extern int ac_imgconvert_init_yuv_rgb(int accel);
extern int ac_imgconvert_init_rgb_packed(int accel);
#endif /* ACLIB_IMG_INTERNAL_H */
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,596 @@
/*
* img_x86_common.h - common x86/x86-64 assembly macros
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#ifndef ACLIB_IMG_X86_COMMON_H
#define ACLIB_IMG_X86_COMMON_H
/*************************************************************************/
/* Register names for pointers */
#ifdef ARCH_X86_64
# define EAX "%%rax"
# define EBX "%%rbx"
# define ECX "%%rcx"
# define EDX "%%rdx"
# define ESP "%%rsp"
# define EBP "%%rbp"
# define ESI "%%rsi"
# define EDI "%%rdi"
#else
# define EAX "%%eax"
# define EBX "%%ebx"
# define ECX "%%ecx"
# define EDX "%%edx"
# define ESP "%%esp"
# define EBP "%%ebp"
# define ESI "%%esi"
# define EDI "%%edi"
#endif
/* Data for isolating particular bytes. Used by the SWAP32 macros; if you
* use them, make sure to define DEFINE_MASK_DATA before including this
* file! */
#ifdef DEFINE_MASK_DATA
static const struct { uint32_t n[64]; } __attribute__((aligned(16))) mask_data = {{
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
0x0000FF00, 0x0000FF00, 0x0000FF00, 0x0000FF00,
0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF,
0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000,
0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF,
0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00,
0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF,
0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,
0xFF0000FF, 0xFF0000FF, 0xFF0000FF, 0xFF0000FF,
0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
0xFF00FFFF, 0xFF00FFFF, 0xFF00FFFF, 0xFF00FFFF,
0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000,
0xFFFF00FF, 0xFFFF00FF, 0xFFFF00FF, 0xFFFF00FF,
0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
}};
#endif
/*************************************************************************/
/* Basic assembly macros, used for odd-count loops */
/* Swap bytes in pairs of 16-bit values */
#define X86_SWAP16_2 \
"movl -4("ESI","ECX",4), %%eax \n\
movl %%eax, %%edx \n\
shll $8, %%eax \n\
andl $0xFF00FF00, %%eax \n\
shrl $8, %%edx \n\
andl $0x00FF00FF, %%edx \n\
orl %%edx, %%eax \n\
movl %%eax, -4("EDI","ECX",4)"
/* Swap words in a 32-bit value */
#define X86_SWAP32 \
"movl -4("ESI","ECX",4), %%eax \n\
roll $16, %%eax \n\
movl %%eax, -4("EDI","ECX",4)"
/* Swap bytes 0 and 2 of a 32-bit value */
#define X86_SWAP32_02 \
"movw -4("ESI","ECX",4), %%ax \n\
movw -2("ESI","ECX",4), %%dx \n\
xchg %%dl, %%al \n\
movw %%ax, -4("EDI","ECX",4) \n\
movw %%dx, -2("EDI","ECX",4)"
/* Swap bytes 1 and 3 of a 32-bit value */
#define X86_SWAP32_13 \
"movw -4("ESI","ECX",4), %%ax \n\
movw -2("ESI","ECX",4), %%dx \n\
xchg %%dh, %%ah \n\
movw %%ax, -4("EDI","ECX",4) \n\
movw %%dx, -2("EDI","ECX",4)"
/* Reverse the order of bytes in a 32-bit value */
#define X86_REV32 \
"movl -4("ESI","ECX",4), %%eax \n\
xchg %%ah, %%al \n\
roll $16, %%eax \n\
xchg %%ah, %%al \n\
movl %%eax, -4("EDI","ECX",4)"
/* The same, using the BSWAP instruction */
#define X86_REV32_BSWAP \
"movl -4("ESI","ECX",4), %%eax \n\
bswap %%eax \n\
movl %%eax, -4("EDI","ECX",4)"
/* Rotate a 32-bit value left 8 bits */
#define X86_ROL32 \
"movl -4("ESI","ECX",4), %%eax \n\
roll $8, %%eax \n\
movl %%eax, -4("EDI","ECX",4)"
/* Rotate a 32-bit value right 8 bits */
#define X86_ROR32 \
"movl -4("ESI","ECX",4), %%eax \n\
rorl $8, %%eax \n\
movl %%eax, -4("EDI","ECX",4)"
/*************************************************************************/
/* Basic assembly routines. Sizes are all given in 32-bit units. */
#define ASM_SWAP16_2_X86(size) \
asm("0: "X86_SWAP16_2" \n\
subl $1, %%ecx \n\
jnz 0b" \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax", "edx")
#define ASM_SWAP32_X86(size) \
asm("0: "X86_SWAP32" \n\
subl $1, %%ecx \n\
jnz 0b" \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax", "edx")
#define ASM_SWAP32_02_X86(size) \
asm("0: "X86_SWAP32_02" \n\
subl $1, %%ecx \n\
jnz 0b" \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax", "edx")
#define ASM_SWAP32_13_X86(size) \
asm("0: "X86_SWAP32_13" \n\
subl $1, %%ecx \n\
jnz 0b" \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax", "edx")
#define ASM_REV32_X86(size) \
asm("0: "X86_REV32" \n\
subl $1, %%ecx \n\
jnz 0b" \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax")
#define ASM_ROL32_X86(size) \
asm("0: "X86_ROL32" \n\
subl $1, %%ecx \n\
jnz 0b" \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax")
#define ASM_ROR32_X86(size) \
asm("0: "X86_ROR32" \n\
subl $1, %%ecx \n\
jnz 0b" \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax")
/*************************************************************************/
/*************************************************************************/
/* Wrapper for SIMD loops. This generates the body of an asm() construct
* (the string only, not the input/output/clobber lists) given the data
* block size (number of data units processed per SIMD loop iteration),
* instructions to save and restore unclobberable registers (such as EBX),
* and the bodies of the odd-count and main loops. The data count is
* assumed to be preloaded in ECX. Parameters are:
* blocksize: number of units of data processed per SIMD loop (must be
* a power of 2); can be a constant or a numerical
* expression containing only constants
* push_regs: string constant containing instructions to push registers
* that must be saved over the small loop
* pop_regs: string constant containing instructions to pop registers
* saved by `push_regs' (restored before the main loop)
* small_loop: loop for handling data elements one at a time (when the
* count is not a multiple of `blocksize'
* main_loop: main SIMD loop for processing data
* emms: EMMS/SFENCE instructions to end main loop with, as needed
*/
#define SIMD_LOOP_WRAPPER(blocksize,push_regs,pop_regs,small_loop,main_loop,emms) \
/* Always save ECX--GCC may rely on it being unmodified */ \
"push "ECX"; " \
/* Check whether the count is a multiple of the blocksize (this \
* can cause branch mispredicts but seems to be faster overall) */ \
"testl $(("#blocksize")-1), %%ecx; " \
"jz 1f; " \
/* It's not--run the small loop to align the count */ \
push_regs"; " \
"0: " \
small_loop"; " \
"subl $1, %%ecx; " \
"testl $(("#blocksize")-1), %%ecx; " \
"jnz 0b; " \
pop_regs"; " \
/* Make sure there's some data left */ \
"testl %%ecx, %%ecx; " \
"jz 2f; " \
/* Now run the main SIMD loop */ \
"1: " \
main_loop"; " \
"subl $("#blocksize"), %%ecx; " \
"jnz 1b; " \
/* Clear MMX state and/or SFENCE, as needed */ \
emms"; " \
/* Restore ECX and finish */ \
"2: " \
"pop "ECX";"
/*************************************************************************/
/* MMX- and SSE2-optimized swap/rotate routines. These routines are
* identical save for data size, so we use common macros to implement them,
* with register names and data offsets replaced by parameters to the
* macros. */
#define ASM_SIMD_MMX(name,size) \
name((size), 64, \
"movq", "movq", "movq", "", \
"%%mm0", "%%mm1", "%%mm2", "%%mm3", \
"%%mm4", "%%mm5", "%%mm6", "%%mm7")
#define ASM_SIMD_SSE2(name,size) \
name((size), 128, \
"movdqu", "movdqa", "movdqu", "", \
"%%xmm0", "%%xmm1", "%%xmm2", "%%xmm3",\
"%%xmm4", "%%xmm5", "%%xmm6", "%%xmm7")
#define ASM_SIMD_SSE2_ALIGNED(name,size) \
name((size), 128, \
"movdqa", "movdqa", "movntdq", "sfence",\
"%%xmm0", "%%xmm1", "%%xmm2", "%%xmm3",\
"%%xmm4", "%%xmm5", "%%xmm6", "%%xmm7")
#define ASM_SWAP16_2_MMX(size) ASM_SIMD_MMX(ASM_SWAP16_2_SIMD,(size))
#define ASM_SWAP16_2_SSE2(size) ASM_SIMD_SSE2(ASM_SWAP16_2_SIMD,(size))
#define ASM_SWAP16_2_SSE2A(size) ASM_SIMD_SSE2_ALIGNED(ASM_SWAP16_2_SIMD,(size))
#define ASM_SWAP32_MMX(size) ASM_SIMD_MMX(ASM_SWAP32_SIMD,(size))
#define ASM_SWAP32_SSE2(size) ASM_SIMD_SSE2(ASM_SWAP32_SIMD,(size))
#define ASM_SWAP32_SSE2A(size) ASM_SIMD_SSE2_ALIGNED(ASM_SWAP32_SIMD,(size))
#define ASM_SWAP32_02_MMX(size) ASM_SIMD_MMX(ASM_SWAP32_02_SIMD,(size))
#define ASM_SWAP32_02_SSE2(size) ASM_SIMD_SSE2(ASM_SWAP32_02_SIMD,(size))
#define ASM_SWAP32_02_SSE2A(size) ASM_SIMD_SSE2_ALIGNED(ASM_SWAP32_02_SIMD,(size))
#define ASM_SWAP32_13_MMX(size) ASM_SIMD_MMX(ASM_SWAP32_13_SIMD,(size))
#define ASM_SWAP32_13_SSE2(size) ASM_SIMD_SSE2(ASM_SWAP32_13_SIMD,(size))
#define ASM_SWAP32_13_SSE2A(size) ASM_SIMD_SSE2_ALIGNED(ASM_SWAP32_13_SIMD,(size))
#define ASM_REV32_MMX(size) ASM_SIMD_MMX(ASM_REV32_SIMD,(size))
#define ASM_REV32_SSE2(size) ASM_SIMD_SSE2(ASM_REV32_SIMD,(size))
#define ASM_REV32_SSE2A(size) ASM_SIMD_SSE2_ALIGNED(ASM_REV32_SIMD,(size))
#define ASM_ROL32_MMX(size) ASM_SIMD_MMX(ASM_ROL32_SIMD,(size))
#define ASM_ROL32_SSE2(size) ASM_SIMD_SSE2(ASM_ROL32_SIMD,(size))
#define ASM_ROL32_SSE2A(size) ASM_SIMD_SSE2_ALIGNED(ASM_ROL32_SIMD,(size))
#define ASM_ROR32_MMX(size) ASM_SIMD_MMX(ASM_ROR32_SIMD,(size))
#define ASM_ROR32_SSE2(size) ASM_SIMD_SSE2(ASM_ROR32_SIMD,(size))
#define ASM_ROR32_SSE2A(size) ASM_SIMD_SSE2_ALIGNED(ASM_ROR32_SIMD,(size))
/*************************************************************************/
/* Actual implementations. Note that unrolling the SIMD loops doesn't seem
* to be a win (only 2-3% improvement at most), and in fact can lose by a
* bit in short loops. */
#define ASM_SWAP16_2_SIMD(size,regsize,ldq,movq,stq,sfence,MM0,MM1,MM2,MM3,MM4,MM5,MM6,MM7) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ (regsize)/32, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ X86_SWAP16_2, \
/* main_loop */ \
ldq" -("#regsize"/8)("ESI","ECX",4), "MM0" \n\
# MM0: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM1" # MM1: 7 6 5 4 3 2 1 0 \n\
psrlw $8, "MM0" # MM0: - 7 - 5 - 3 - 1 \n\
psllw $8, "MM1" # MM1: 6 - 4 - 2 - 0 - \n\
por "MM1", "MM0" # MM0: 6 7 4 5 2 3 0 1 \n\
"stq" "MM0", -("#regsize"/8)("EDI","ECX",4)", \
/* emms */ "emms; "sfence) \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax", "edx")
#define ASM_SWAP32_SIMD(size,regsize,ldq,movq,stq,sfence,MM0,MM1,MM2,MM3,MM4,MM5,MM6,MM7) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ (regsize)/32, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ X86_SWAP32, \
/* main_loop */ \
ldq" -("#regsize"/8)("ESI","ECX",4), "MM0" \n\
# MM0: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM1" # MM1: 7 6 5 4 3 2 1 0 \n\
psrld $16, "MM0" # MM0: - - 7 6 - - 3 2 \n\
pslld $16, "MM1" # MM1: 5 4 - - 1 0 - - \n\
por "MM1", "MM0" # MM0: 5 4 7 6 1 0 3 2 \n\
"stq" "MM0", -("#regsize"/8)("EDI","ECX",4)", \
/* emms */ "emms; "sfence) \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax")
#define ASM_SWAP32_02_SIMD(size,regsize,ldq,movq,stq,sfence,MM0,MM1,MM2,MM3,MM4,MM5,MM6,MM7) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ (regsize)/32, \
/* push_regs */ "push "EDX, \
/* pop_regs */ "pop "EDX, \
/* small_loop */ X86_SWAP32_02, \
/* main_loop */ \
ldq" -("#regsize"/8)("ESI","ECX",4), "MM0" \n\
# MM0: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM1" # MM1: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM2" # MM2: 7 6 5 4 3 2 1 0 \n\
pand 16("EDX"), "MM1" # MM1: - - - 4 - - - 0 \n\
pslld $16, "MM1" # MM1: - 4 - - - 0 - - \n\
pand 64("EDX"), "MM2" # MM2: - 6 - - - 2 - - \n\
psrld $16, "MM2" # MM2: - - - 6 - - - 2 \n\
pand 160("EDX"), "MM0" # MM0: 7 - 5 - 3 - 1 - \n\
por "MM1", "MM0" # MM0: 7 4 5 - 3 0 1 - \n\
por "MM2", "MM0" # MM0: 7 4 5 6 3 0 1 2 \n\
"stq" "MM0", -("#regsize"/8)("EDI","ECX",4)", \
/* emms */ "emms; "sfence) \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size), "d" (&mask_data), \
"m" (mask_data) \
: "eax")
#define ASM_SWAP32_13_SIMD(size,regsize,ldq,movq,stq,sfence,MM0,MM1,MM2,MM3,MM4,MM5,MM6,MM7) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ (regsize)/32, \
/* push_regs */ "push "EDX, \
/* pop_regs */ "pop "EDX, \
/* small_loop */ X86_SWAP32_13, \
/* main_loop */ \
ldq" -("#regsize"/8)("ESI","ECX",4), "MM0" \n\
# MM0: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM1" # MM1: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM2" # MM2: 7 6 5 4 3 2 1 0 \n\
pand 32("EDX"), "MM1" # MM1: - - 5 - - - 1 - \n\
pslld $16, "MM1" # MM1: 5 - - - 1 - - - \n\
pand 128("EDX"), "MM2" # MM2: 7 - - - 3 - - - \n\
psrld $16, "MM2" # MM2: - - 7 - - - 3 - \n\
pand 80("EDX"), "MM0" # MM0: - 6 - 4 - 2 - 0 \n\
por "MM1", "MM0" # MM0: 5 6 - 4 1 2 - 0 \n\
por "MM2", "MM0" # MM0: 5 6 7 4 1 2 3 0 \n\
"stq" "MM0", -("#regsize"/8)("EDI","ECX",4)", \
/* emms */ "emms; "sfence) \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size), "d" (&mask_data), \
"m" (mask_data) \
: "eax");
#define ASM_REV32_SIMD(size,regsize,ldq,movq,stq,sfence,MM0,MM1,MM2,MM3,MM4,MM5,MM6,MM7) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ (regsize)/32, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ X86_REV32_BSWAP, \
/* main_loop */ \
ldq" -("#regsize"/8)("ESI","ECX",4), "MM0" \n\
# MM0: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM1" # MM1: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM2" # MM2: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM3" # MM3: 7 6 5 4 3 2 1 0 \n\
psrld $24, "MM0" # MM0: - - - 7 - - - 3 \n\
pand 32("EDX"), "MM2" # MM2: - - 5 - - - 1 - \n\
psrld $8, "MM1" # MM1: - 7 6 5 - 3 2 1 \n\
pand 32("EDX"), "MM1" # MM1: - - 6 - - - 2 - \n\
pslld $8, "MM2" # MM2: - 5 - - - 1 - - \n\
pslld $24, "MM3" # MM3: 4 - - - 0 - - - \n\
por "MM1", "MM0" # MM0: - - 6 7 - - 2 3 \n\
por "MM2", "MM0" # MM0: - 5 6 7 - 1 2 3 \n\
por "MM3", "MM0" # MM0: 4 5 6 7 0 1 2 3 \n\
"stq" "MM0", -("#regsize"/8)("EDI","ECX",4)", \
/* emms */ "emms; "sfence) \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size), "d" (&mask_data), \
"m" (mask_data) \
: "eax")
#define ASM_ROL32_SIMD(size,regsize,ldq,movq,stq,sfence,MM0,MM1,MM2,MM3,MM4,MM5,MM6,MM7) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ (regsize)/32, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ X86_ROL32, \
/* main_loop */ \
ldq" -("#regsize"/8)("ESI","ECX",4), "MM0" \n\
# MM0: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM1" # MM1: 7 6 5 4 3 2 1 0 \n\
pslld $8, "MM0" # MM0: 6 5 4 - 2 1 0 - \n\
psrld $24, "MM1" # MM1: - - - 7 - - - 3 \n\
por "MM1", "MM0" # MM0: 6 5 4 7 2 1 0 3 \n\
"stq" "MM0", -("#regsize"/8)("EDI","ECX",4)", \
/* emms */ "emms; "sfence) \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax")
#define ASM_ROR32_SIMD(size,regsize,ldq,movq,stq,sfence,MM0,MM1,MM2,MM3,MM4,MM5,MM6,MM7) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ (regsize)/32, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ X86_ROR32, \
/* main_loop */ \
ldq" -("#regsize"/8)("ESI","ECX",4), "MM0" \n\
# MM0: 7 6 5 4 3 2 1 0 \n\
"movq" "MM0", "MM1" # MM1: 7 6 5 4 3 2 1 0 \n\
psrld $8, "MM0" # MM0: - 7 6 5 - 3 2 1 \n\
pslld $24, "MM1" # MM1: 4 - - - 0 - - - \n\
por "MM1", "MM0" # MM0: 4 7 6 5 0 3 2 1 \n\
"stq" "MM0", -("#regsize"/8)("EDI","ECX",4)", \
/* emms */ "emms; "sfence) \
: /* no outputs */ \
: "S" (src[0]), "D" (dest[0]), "c" (size) \
: "eax")
/*************************************************************************/
/* SSE2 macros to load 8 24- or 32-bit RGB pixels into XMM0/1/2 (R/G/B) as
* 16-bit values, used for RGB->YUV and RGB->grayscale conversions.
* ZERO is the number of the XMM register containing all zeroes. */
#define SSE2_LOAD_RGB24(ZERO) \
"movl -21("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm0 # XMM0: ----- ----- ----- xBGR1 \n\
pshufd $0x39, %%xmm0, %%xmm0 # XMM0: xBGR1 ----- ----- ----- \n\
movl -18("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm0 # XMM0: xBGR1 ----- ----- xBGR2 \n\
pshufd $0x39, %%xmm0, %%xmm0 # XMM0: xBGR2 xBGR1 ----- ----- \n\
movl -15("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm0 # XMM0: xBGR2 xBGR1 ----- xBGR3 \n\
pshufd $0x39, %%xmm0, %%xmm0 # XMM0: xBGR3 xBGR2 xBGR1 ----- \n\
movl -24("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm0 # XMM0: xBGR3 xBGR2 xBGR1 xBGR0 \n\
movl -9("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm1 # XMM1: ----- ----- ----- xBGR5 \n\
pshufd $0x39, %%xmm1, %%xmm1 # XMM1: xBGR5 ----- ----- ----- \n\
movl -6("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm1 # XMM1: xBGR5 ----- ----- xBGR6 \n\
pshufd $0x39, %%xmm1, %%xmm1 # XMM1: xBGR6 xBGR5 ----- ----- \n\
movl -3("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm1 # XMM1: xBGR6 xBGR5 ----- xBGR7 \n\
pshufd $0x39, %%xmm1, %%xmm1 # XMM1: xBGR7 xBGR6 xBGR5 ----- \n\
movl -12("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm1 # XMM1: xBGR7 xBGR6 xBGR5 xBGR4 \n"\
SSE2_MASSAGE_RGBA32(ZERO)
#define SSE2_LOAD_BGR24(ZERO) \
"movl -21("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm0 # XMM0: ----- ----- ----- xRGB1 \n\
pshufd $0x39, %%xmm0, %%xmm0 # XMM0: xRGB1 ----- ----- ----- \n\
movl -18("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm0 # XMM0: xRGB1 ----- ----- xRGB2 \n\
pshufd $0x39, %%xmm0, %%xmm0 # XMM0: xRGB2 xRGB1 ----- ----- \n\
movl -15("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm0 # XMM0: xRGB2 xRGB1 ----- xRGB3 \n\
pshufd $0x39, %%xmm0, %%xmm0 # XMM0: xRGB3 xRGB2 xRGB1 ----- \n\
movl -24("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm0 # XMM0: xRGB3 xRGB2 xRGB1 xRGB0 \n\
movl -9("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm1 # XMM1: ----- ----- ----- xRGB5 \n\
pshufd $0x39, %%xmm1, %%xmm1 # XMM1: xRGB5 ----- ----- ----- \n\
movl -6("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm1 # XMM1: xRGB5 ----- ----- xRGB6 \n\
pshufd $0x39, %%xmm1, %%xmm1 # XMM1: xRGB6 xRGB5 ----- ----- \n\
movl -3("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm1 # XMM1: xRGB6 xRGB5 ----- xRGB7 \n\
pshufd $0x39, %%xmm1, %%xmm1 # XMM1: xRGB7 xRGB6 xRGB5 ----- \n\
movl -12("ESI","EBX"), %%eax \n\
movd %%eax, %%xmm2 \n\
por %%xmm2, %%xmm1 # XMM1: xRGB7 xRGB6 xRGB5 xRGB4 \n"\
SSE2_MASSAGE_BGRA32(ZERO)
#define SSE2_LOAD_RGBA32(ZERO) "\
movdqu -32("ESI","ECX",4),%%xmm0 #XMM0: ABGR3 ABGR2 ABGR1 ABGR0 \n\
movdqu -16("ESI","ECX",4),%%xmm1 #XMM1: ABGR7 ABGR6 ABGR5 ABGR4 \n"\
SSE2_MASSAGE_RGBA32(ZERO)
#define SSE2_MASSAGE_RGBA32(ZERO) "\
movdqa %%xmm0, %%xmm2 # XMM2: ABGR3 ABGR2 ABGR1 ABGR0 \n\
punpcklbw %%xmm1, %%xmm0 # X0.l: A4 A0 B4 B0 G4 G0 R4 R0 \n\
punpckhbw %%xmm1, %%xmm2 # X2.l: A6 A2 B6 B2 G6 G2 R6 R2 \n\
movdqa %%xmm0, %%xmm1 # X1.l: A4 A0 B4 B0 G4 G0 R4 R0 \n\
punpcklbw %%xmm2, %%xmm0 # X0.l: G6 G4 G2 G0 R6 R4 R2 R0 \n\
punpckhbw %%xmm2, %%xmm1 # X1.l: G7 G5 G3 G1 R7 R5 R3 R1 \n\
movdqa %%xmm0, %%xmm2 # X2.l: G6 G4 G2 G0 R6 R4 R2 R0 \n\
punpcklbw %%xmm1, %%xmm0 # XMM0: G7.......G0 R7.......R0 \n\
punpckhbw %%xmm1, %%xmm2 # XMM2: A7.......A0 B7.......B0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: G7.......G0 R7.......R0 \n\
punpcklbw %%xmm4, %%xmm0 # XMM0: R7 R6 R5 R4 R3 R2 R1 R0 \n\
punpckhbw %%xmm4, %%xmm1 # XMM1: G7 G6 G5 G4 G3 G2 G1 G0 \n\
punpcklbw %%xmm4, %%xmm2 # XMM2: B7 B6 B5 B4 B3 B2 B1 B0 \n"
#define SSE2_LOAD_BGRA32(ZERO) "\
movdqu -32("ESI","ECX",4),%%xmm0 #XMM0: ARGB3 ARGB2 ARGB1 ARGB0 \n\
movdqu -16("ESI","ECX",4),%%xmm1 #XMM1: ARGB7 ARGB6 ARGB5 ARGB4 \n"\
SSE2_MASSAGE_BGRA32(ZERO)
#define SSE2_MASSAGE_BGRA32(ZERO) "\
movdqa %%xmm0, %%xmm2 # XMM2: ARGB3 ARGB2 ARGB1 ARGB0 \n\
punpcklbw %%xmm1, %%xmm2 # X2.l: A4 A0 R4 R0 G4 G0 B4 B0 \n\
punpckhbw %%xmm1, %%xmm0 # X0.l: A6 A2 R6 R2 G6 G2 B6 B2 \n\
movdqa %%xmm2, %%xmm1 # X1.l: A4 A0 R4 R0 G4 G0 B4 B0 \n\
punpcklbw %%xmm0, %%xmm2 # X2.l: G6 G4 G2 G0 B6 B4 B2 B0 \n\
punpckhbw %%xmm0, %%xmm1 # X1.l: G7 G5 G3 G1 B7 B5 B3 B1 \n\
movdqa %%xmm2, %%xmm0 # X0.l: G6 G4 G2 G0 B6 B4 B2 B0 \n\
punpcklbw %%xmm1, %%xmm2 # XMM2: G7.......G0 B7.......B0 \n\
punpckhbw %%xmm1, %%xmm0 # XMM0: A7.......A0 R7.......R0 \n\
movdqa %%xmm2, %%xmm1 # XMM1: G7.......G0 B7.......B0 \n\
punpcklbw %%xmm4, %%xmm0 # XMM0: R7 R6 R5 R4 R3 R2 R1 R0 \n\
punpckhbw %%xmm4, %%xmm1 # XMM1: G7 G6 G5 G4 G3 G2 G1 G0 \n\
punpcklbw %%xmm4, %%xmm2 # XMM2: B7 B6 B5 B4 B3 B2 B1 B0 \n"
#define SSE2_LOAD_ARGB32(ZERO) "\
movdqu -32("ESI","ECX",4),%%xmm0 #XMM0: BGRA3 BGRA2 BGRA1 BGRA0 \n\
movdqu -16("ESI","ECX",4),%%xmm1 #XMM1: BGRA7 BGRA6 BGRA5 BGRA4 \n"\
SSE2_MASSAGE_ARGB32(ZERO)
#define SSE2_MASSAGE_ARGB32(ZERO) "\
movdqa %%xmm0, %%xmm2 # XMM2: BGRA3 BGRA2 BGRA1 BGRA0 \n\
punpcklbw %%xmm1, %%xmm0 # X0.l: B4 B0 G4 G0 R4 R0 A4 A0 \n\
punpckhbw %%xmm1, %%xmm2 # X2.l: B6 B2 G6 G2 R6 R2 A6 A2 \n\
movdqa %%xmm0, %%xmm1 # X1.l: B4 B0 G4 G0 R4 R0 A4 A0 \n\
punpcklbw %%xmm2, %%xmm0 # X0.l: R6 R4 R2 R0 A6 A4 A2 A0 \n\
punpckhbw %%xmm2, %%xmm1 # X1.l: R7 R5 R3 R1 A7 A5 A3 A1 \n\
movdqa %%xmm0, %%xmm2 # X2.l: R6 R4 R2 R0 A6 A4 A2 A0 \n\
punpcklbw %%xmm1, %%xmm0 # XMM0: R7.......G0 A7.......A0 \n\
punpckhbw %%xmm1, %%xmm2 # XMM2: B7.......G0 G7.......G0 \n\
movdqa %%xmm2, %%xmm1 # XMM1: B7.......B0 G7.......G0 \n\
punpckhbw %%xmm4, %%xmm0 # XMM0: R7 R6 R5 R4 R3 R2 R1 R0 \n\
punpcklbw %%xmm4, %%xmm1 # XMM1: G7 G6 G5 G4 G3 G2 G1 G0 \n\
punpckhbw %%xmm4, %%xmm2 # XMM2: B7 B6 B5 B4 B3 B2 B1 B0 \n"
#define SSE2_LOAD_ABGR32(ZERO) "\
movdqu -32("ESI","ECX",4),%%xmm0 #XMM0: RGBA3 RGBA2 RGBA1 RGBA0 \n\
movdqu -16("ESI","ECX",4),%%xmm1 #XMM1: RGBA7 RGBA6 RGBA5 RGBA4 \n"\
SSE2_MASSAGE_ABGR32(ZERO)
#define SSE2_MASSAGE_ABGR32(ZERO) "\
movdqa %%xmm0, %%xmm2 # XMM2: RGBA3 RGBA2 RGBA1 RGBA0 \n\
punpcklbw %%xmm1, %%xmm2 # X2.l: R4 R0 G4 G0 B4 B0 A4 A0 \n\
punpckhbw %%xmm1, %%xmm0 # X0.l: R6 R2 G6 G2 B6 B2 A6 A2 \n\
movdqa %%xmm2, %%xmm1 # X1.l: R4 R0 G4 G0 B4 B0 A4 A0 \n\
punpcklbw %%xmm0, %%xmm2 # X2.l: B6 B4 B2 B0 A6 A4 A2 A0 \n\
punpckhbw %%xmm0, %%xmm1 # X1.l: B7 B5 B3 B1 A7 A5 A3 A1 \n\
movdqa %%xmm2, %%xmm0 # X0.l: B6 B4 B2 B0 A6 A4 A2 A0 \n\
punpcklbw %%xmm1, %%xmm2 # XMM2: B7.......B0 A7.......A0 \n\
punpckhbw %%xmm1, %%xmm0 # XMM0: R7.......R0 G7.......G0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: R7.......R0 G7.......G0 \n\
punpckhbw %%xmm4, %%xmm0 # XMM0: R7 R6 R5 R4 R3 R2 R1 R0 \n\
punpcklbw %%xmm4, %%xmm1 # XMM1: G7 G6 G5 G4 G3 G2 G1 G0 \n\
punpckhbw %%xmm4, %%xmm2 # XMM2: B7 B6 B5 B4 B3 B2 B1 B0 \n"
/*************************************************************************/
#endif /* ACLIB_IMG_X86_COMMON_H */
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,912 @@
/*
* img_yuv_packed.c - YUV planar<->packed image format conversion routines
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "imgconvert.h"
#include "img_internal.h"
/*************************************************************************/
/*************************************************************************/
/* Standard C implementations */
/*************************************************************************/
/* Wrappers for UYVY and YVYU */
/* Note: we rely on YUY2<->{UYVY,YVYU} working for src==dest */
/* FIXME: when converting from UYVY/YVYU, src is destroyed! */
static int uyvy_yvyu_wrapper(uint8_t **src, ImageFormat srcfmt,
uint8_t **dest, ImageFormat destfmt,
int width, int height)
{
if (srcfmt == IMG_UYVY || srcfmt == IMG_YVYU)
return ac_imgconvert(src, srcfmt, src, IMG_YUY2, width, height)
&& ac_imgconvert(src, IMG_YUY2, dest, destfmt, width, height);
else
return ac_imgconvert(src, srcfmt, dest, IMG_YUY2, width, height)
&& ac_imgconvert(dest, IMG_YUY2, dest, destfmt, width, height);
}
static int yuv420p_uyvy(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV420P, dest, IMG_UYVY, width, height); }
static int yuv420p_yvyu(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV420P, dest, IMG_YVYU, width, height); }
static int yuv411p_uyvy(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV411P, dest, IMG_UYVY, width, height); }
static int yuv411p_yvyu(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV411P, dest, IMG_YVYU, width, height); }
static int yuv422p_uyvy(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV422P, dest, IMG_UYVY, width, height); }
static int yuv422p_yvyu(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV422P, dest, IMG_YVYU, width, height); }
static int yuv444p_uyvy(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV444P, dest, IMG_UYVY, width, height); }
static int yuv444p_yvyu(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YUV444P, dest, IMG_YVYU, width, height); }
static int uyvy_yuv420p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_UYVY, dest, IMG_YUV420P, width, height); }
static int yvyu_yuv420p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YVYU, dest, IMG_YUV420P, width, height); }
static int uyvy_yuv411p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_UYVY, dest, IMG_YUV411P, width, height); }
static int yvyu_yuv411p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YVYU, dest, IMG_YUV411P, width, height); }
static int uyvy_yuv422p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_UYVY, dest, IMG_YUV422P, width, height); }
static int yvyu_yuv422p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YVYU, dest, IMG_YUV422P, width, height); }
static int uyvy_yuv444p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_UYVY, dest, IMG_YUV444P, width, height); }
static int yvyu_yuv444p(uint8_t **src, uint8_t **dest, int width, int height)
{ return uyvy_yvyu_wrapper(src, IMG_YVYU, dest, IMG_YUV444P, width, height); }
/*************************************************************************/
static int yuv420p_yuy2(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
for (y = 0; y < (height & ~1); y++) {
for (x = 0; x < (width & ~1); x += 2) {
dest[0][(y*width+x)*2 ] = src[0][y*width+x];
dest[0][(y*width+x)*2+1] = src[1][(y/2)*(width/2)+x/2];
dest[0][(y*width+x)*2+2] = src[0][y*width+x+1];
dest[0][(y*width+x)*2+3] = src[2][(y/2)*(width/2)+x/2];
}
}
return 1;
}
static int yuv411p_yuy2(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
for (y = 0; y < height; y++) {
for (x = 0; x < (width & ~1); x += 2) {
dest[0][(y*width+x)*2 ] = src[0][y*width+x];
dest[0][(y*width+x)*2+1] = src[1][y*(width/4)+x/4];
dest[0][(y*width+x)*2+2] = src[0][y*width+x+1];
dest[0][(y*width+x)*2+3] = src[2][y*(width/4)+x/4];
}
}
return 1;
}
static int yuv422p_yuy2(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < (width/2)*height; i++) {
dest[0][i*4 ] = src[0][i*2];
dest[0][i*4+1] = src[1][i];
dest[0][i*4+2] = src[0][i*2+1];
dest[0][i*4+3] = src[2][i];
}
return 1;
}
static int yuv444p_yuy2(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < (width/2)*height; i++) {
dest[0][i*4 ] = src[0][i*2];
dest[0][i*4+1] = (src[1][i*2] + src[1][i*2+1]) / 2;
dest[0][i*4+2] = src[0][i*2+1];
dest[0][i*4+3] = (src[2][i*2] + src[2][i*2+1]) / 2;
}
return 1;
}
/*************************************************************************/
static int yuy2_yuv420p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
for (y = 0; y < (height & ~1); y++) {
for (x = 0; x < (width & ~1); x += 2) {
dest[0][y*width+x ] = src[0][(y*width+x)*2 ];
dest[0][y*width+x+1] = src[0][(y*width+x)*2+2];
if (y%2 == 0) {
dest[1][(y/2)*(width/2)+x/2] = src[0][(y*width+x)*2+1];
dest[2][(y/2)*(width/2)+x/2] = src[0][(y*width+x)*2+3];
} else {
dest[1][(y/2)*(width/2)+x/2] =
(dest[1][(y/2)*(width/2)+x/2] + src[0][(y*width+x)*2+1] + 1) / 2;
dest[2][(y/2)*(width/2)+x/2] =
(dest[2][(y/2)*(width/2)+x/2] + src[0][(y*width+x)*2+3] + 1) / 2;
}
}
}
return 1;
}
static int yuy2_yuv411p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
for (y = 0; y < height; y++) {
for (x = 0; x < (width & ~3); x += 4) {
dest[0][y*width+x] = src[0][(y*width+x)*2 ];
dest[0][y*width+x+1] = src[0][(y*width+x)*2+2];
dest[0][y*width+x+2] = src[0][(y*width+x)*2+4];
dest[0][y*width+x+3] = src[0][(y*width+x)*2+6];
dest[1][y*(width/4)+x/4] = (src[0][(y*width+x)*2+1]
+ src[0][(y*width+x)*2+5] + 1) / 2;
dest[2][y*(width/4)+x/4] = (src[0][(y*width+x)*2+3]
+ src[0][(y*width+x)*2+7] + 1) / 2;
}
}
return 1;
}
static int yuy2_yuv422p(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < (width/2)*height; i++) {
dest[0][i*2] = src[0][i*4 ];
dest[1][i] = src[0][i*4+1];
dest[0][i*2+1] = src[0][i*4+2];
dest[2][i] = src[0][i*4+3];
}
return 1;
}
static int yuy2_yuv444p(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < (width & ~1)*height; i += 2) {
dest[0][i] = src[0][i*2 ];
dest[1][i] = src[0][i*2+1];
dest[1][i+1] = src[0][i*2+1];
dest[0][i+1] = src[0][i*2+2];
dest[2][i] = src[0][i*2+3];
dest[2][i+1] = src[0][i*2+3];
}
return 1;
}
/*************************************************************************/
static int y8_yuy2(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < width*height; i++) {
dest[0][i*2 ] = src[0][i];
dest[0][i*2+1] = 128;
}
return 1;
}
static int y8_uyvy(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < width*height; i++) {
dest[0][i*2 ] = 128;
dest[0][i*2+1] = src[0][i];
}
return 1;
}
static int yuy2_y8(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < width*height; i++)
dest[0][i] = src[0][i*2];
return 1;
}
static int uyvy_y8(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < width*height; i++)
dest[0][i] = src[0][i*2+1];
return 1;
}
/*************************************************************************/
/*************************************************************************/
#if defined(HAVE_ASM_SSE2)
/* SSE2 routines. See comments in img_x86_common.h for why we don't bother
* unrolling the loops. */
/* Common macros/data for x86 code */
#include "img_x86_common.h"
/* YUV420P (1 row) or YUV422P -> YUY2 (unit: 2 pixels) */
#define YUV42XP_YUY2 \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "push "EBX, \
/* pop_regs */ "pop "EBX, \
/* small_loop */ \
"movb -1("EDX","ECX"), %%bh \n\
movb -1("ESI","ECX",2), %%bl \n\
shll $16, %%ebx \n\
movb -1("EAX","ECX"), %%bh \n\
movb -2("ESI","ECX",2), %%bl \n\
movl %%ebx, -4("EDI","ECX",4)", \
/* main_loop */ \
"movdqu -16("ESI","ECX",2),%%xmm0 #XM0: YF YE YD ..... Y2 Y1 Y0 \n\
movq -8("EAX","ECX"), %%xmm2 # XMM2: U7 U6 U5 U4 U3 U2 U1 U0 \n\
movq -8("EDX","ECX"), %%xmm3 # XMM3: V7 V6 V5 V4 V3 V2 V1 V0 \n\
punpcklbw %%xmm3, %%xmm2 # XMM2: V7 U7 V6 ..... U1 V0 U0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: YF YE YD ..... Y2 Y1 Y0 \n\
punpcklbw %%xmm2, %%xmm0 # XMM0: V3 Y7 U3 ..... Y1 U0 Y0 \n\
punpckhbw %%xmm2, %%xmm1 # XMM1: V7 YF U7 ..... Y9 U4 Y8 \n\
movdqu %%xmm0, -32("EDI","ECX",4) \n\
movdqu %%xmm1, -16("EDI","ECX",4)", \
/* emms */ "emms")
/* YUV411P -> YUY2 (unit: 4 pixels) */
#define YUV411P_YUY2 \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 4, \
/* push_regs */ "push "EBX, \
/* pop_regs */ "pop "EBX, \
/* small_loop */ \
"movb -1("EDX","ECX"), %%bh \n\
movb -1("ESI","ECX",4), %%bl \n\
shll $16, %%ebx \n\
movb -1("EAX","ECX"), %%bh \n\
movb -2("ESI","ECX",4), %%bl \n\
movl %%ebx, -4("EDI","ECX",8) \n\
movb -1("EDX","ECX"), %%bh \n\
movb -3("ESI","ECX",4), %%bl \n\
shll $16, %%ebx \n\
movb -1("EAX","ECX"), %%bh \n\
movb -4("ESI","ECX",4), %%bl \n\
movl %%ebx, -8("EDI","ECX",8)", \
/* main_loop */ \
"movdqu -16("ESI","ECX",4),%%xmm0 #XM0: YF YE YD ..... Y2 Y1 Y0 \n\
movd -4("EAX","ECX"), %%xmm2 # XMM2: U3 U2 U1 U0 \n\
punpcklbw %%xmm2, %%xmm2 # XMM2: U3 U3 U2 U2 U1 U1 U0 U0 \n\
movd -4("EDX","ECX"), %%xmm3 # XMM3: V3 V2 V1 V0 \n\
punpcklbw %%xmm3, %%xmm3 # XMM3: V3 V3 V2 V2 V1 V1 V0 V0 \n\
punpcklbw %%xmm3, %%xmm2 # XMM2: V3 U3 V3 ..... U0 V0 U0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: YF YE YD ..... Y2 Y1 Y0 \n\
punpcklbw %%xmm2, %%xmm0 # XMM0: V1 Y7 U1 ..... Y1 U0 Y0 \n\
punpckhbw %%xmm2, %%xmm1 # XMM1: V3 YF U3 ..... Y9 U2 Y8 \n\
movdqu %%xmm0, -32("EDI","ECX",8) \n\
movdqu %%xmm1, -16("EDI","ECX",8)", \
/* emms */ "emms")
/* YUV444P -> YUY2 (unit: 2 pixels) */
#define YUV444P_YUY2 \
/* Load 0x00FF*8 into XMM7 for masking */ \
"pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "push "EBX"; push "EBP, \
/* pop_regs */ "pop "EBP"; pop "EBX, \
/* small_loop */ \
"movzbl -1("EDX","ECX",2), %%ebx \n\
movzbl -2("EDX","ECX",2), %%ebp \n\
addl %%ebp, %%ebx \n\
shrl $1, %%ebx \n\
movb %%bl, -1("EDI","ECX",4) \n\
movb -1("ESI","ECX",2), %%bl \n\
movb %%bl, -2("EDI","ECX",4) \n\
movzbl -1("EAX","ECX",2), %%ebx \n\
movzbl -2("EAX","ECX",2), %%ebp \n\
addl %%ebp, %%ebx \n\
shrl $1, %%ebx \n\
movb %%bl, -3("EDI","ECX",4) \n\
movb -2("ESI","ECX",2), %%bl \n\
movb %%bl, -4("EDI","ECX",4)", \
/* main_loop */ \
"movdqu -16("ESI","ECX",2),%%xmm0 #XM0: YF YE YD ..... Y2 Y1 Y0 \n\
movdqu -16("EAX","ECX",2), %%xmm2 #XM2: UF UE UD ..... U2 U1 U0 \n\
movdqu -16("EDX","ECX",2), %%xmm3 #XM3: VF VE VD ..... V2 V1 V0 \n\
movdqa %%xmm2, %%xmm4 # XMM4: UF UE UD ..... U2 U1 U0 \n\
pand %%xmm7, %%xmm2 # XMM2: -- UE -- ..... U2 -- U0 \n\
psrlw $8, %%xmm4 # XMM4: -- UF -- ..... U3 -- U1 \n\
pavgw %%xmm4, %%xmm2 # XMM2: -- u7 -- ..... u1 -- u0 \n\
movdqa %%xmm3, %%xmm5 # XMM4: UF UE UD ..... U2 U1 U0 \n\
pand %%xmm7, %%xmm3 # XMM3: -- VE -- ..... V2 -- V0 \n\
psrlw $8, %%xmm5 # XMM5: -- VF -- ..... V3 -- V1 \n\
pavgw %%xmm5, %%xmm3 # XMM3: -- v7 -- ..... v1 -- v0 \n\
psllw $8, %%xmm3 # XMM3: v7 -- v6 ..... -- v0 -- \n\
por %%xmm3, %%xmm2 # XMM2: v7 u7 v6 ..... u1 v0 u0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: YF YE YD ..... Y2 Y1 Y0 \n\
punpcklbw %%xmm2, %%xmm0 # XMM0: v3 Y7 u3 ..... Y1 u0 Y0 \n\
punpckhbw %%xmm2, %%xmm1 # XMM1: v7 YF u7 ..... Y9 u4 Y8 \n\
movdqu %%xmm0, -32("EDI","ECX",4) \n\
movdqu %%xmm1, -16("EDI","ECX",4)", \
/* emms */ "emms")
/* YUY2 -> YUV420P (U row) (unit: 2 pixels) */
#define YUY2_YUV420P_U \
/* Load 0x00FF*8 into XMM7 for masking */ \
"pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 4, \
/* push_regs */ "push "EBX"; push "EBP, \
/* pop_regs */ "pop "EBP"; pop "EBX, \
/* small_loop */ \
"movb -4("ESI","ECX",4), %%bl \n\
movb %%bl, -2("EDI","ECX",2) \n\
movb -2("ESI","ECX",4), %%bl \n\
movb %%bl, -1("EDI","ECX",2) \n\
movzbl -3("ESI","ECX",4), %%ebx \n\
movzbl -3("EAX","ECX",4), %%ebp \n\
addl %%ebp, %%ebx \n\
shrl $1, %%ebx \n\
movb %%bl, -1("EDX","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",4),%%xmm0 #XM0: V3 Y7 U3 ..... Y1 U0 Y0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: V3 Y7 U3 ..... Y1 U0 Y0 \n\
movdqu -16("EAX","ECX",4),%%xmm2 #XMM2: Vd Yh Ud ..... Yb Ua Ya \n\
pand %%xmm7, %%xmm0 # XMM0: -- Y7 -- ..... Y1 -- Y0 \n\
packuswb %%xmm0, %%xmm0 # XMM0: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\
psrlw $8, %%xmm1 # XMM1: -- V3 -- ..... V0 -- U0 \n\
psrlw $8, %%xmm2 # XMM2: -- Vd -- ..... Va -- Ua \n\
pavgw %%xmm2, %%xmm1 # XMM1: -- v3 -- ..... v0 -- u0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: v3 u3 v2 u2 v1 u1 v0 u0 \n\
pand %%xmm7, %%xmm1 # XMM1: -- u3 -- u2 -- u1 -- u0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: u3 u2 u1 u0 \n\
movq %%xmm0, -8("EDI","ECX",2) \n\
movd %%xmm1, -4("EDX","ECX")", \
/* emms */ "emms")
/* YUY2 -> YUV420P (V row) (unit: 2 pixels) */
#define YUY2_YUV420P_V \
/* Load 0x00FF*8 into XMM7 for masking */ \
"pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 4, \
/* push_regs */ "push "EBX"; push "EBP, \
/* pop_regs */ "pop "EBP"; pop "EBX, \
/* small_loop */ \
"movb -4("ESI","ECX",4), %%bl \n\
movb %%bl, -2("EDI","ECX",2) \n\
movb -2("ESI","ECX",4), %%bl \n\
movb %%bl, -1("EDI","ECX",2) \n\
movzbl -1("ESI","ECX",4), %%ebx \n\
movzbl -1("EAX","ECX",4), %%ebp \n\
addl %%ebp, %%ebx \n\
shrl $1, %%ebx \n\
movb %%bl, -1("EDX","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",4),%%xmm0 #XM0: V3 Y7 U3 ..... Y1 U0 Y0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: V3 Y7 U3 ..... Y1 U0 Y0 \n\
movdqu -16("EAX","ECX",4),%%xmm2 #XMM2: Vd Yh Ud ..... Yb Ua Ya \n\
pand %%xmm7, %%xmm0 # XMM0: -- Y7 -- ..... Y1 -- Y0 \n\
packuswb %%xmm0, %%xmm0 # XMM0: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\
psrlw $8, %%xmm1 # XMM1: -- V3 -- ..... V0 -- U0 \n\
psrlw $8, %%xmm2 # XMM2: -- Vd -- ..... Va -- Ua \n\
pavgw %%xmm1, %%xmm2 # XMM2: -- v3 -- ..... v0 -- u0 \n\
packuswb %%xmm2, %%xmm2 # XMM2: v3 u3 v2 u2 v1 u1 v0 u0 \n\
psrlw $8, %%xmm2 # XMM2: -- v3 -- v2 -- v1 -- v0 \n\
packuswb %%xmm2, %%xmm2 # XMM2: v3 v2 v1 v0 \n\
movq %%xmm0, -8("EDI","ECX",2) \n\
movd %%xmm2, -4("EDX","ECX")", \
/* emms */ "emms")
/* YUY2 -> YUV411P (unit: 4 pixels) */
#define YUY2_YUV411P \
/* Load 0x000..000FFFFFFFF into XMM6, 0x00FF*8 into XMM7 for masking */ \
"pcmpeqd %%xmm6, %%xmm6; psrldq $12, %%xmm6;" \
"pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 2, \
/* push_regs */ "push "EBX"; push "EBP, \
/* pop_regs */ "pop "EBP"; pop "EBX, \
/* small_loop */ \
"movb -8("ESI","ECX",8), %%bl \n\
movb %%bl, -4("EDI","ECX",4) \n\
movb -6("ESI","ECX",8), %%bl \n\
movb %%bl, -3("EDI","ECX",4) \n\
movb -4("ESI","ECX",8), %%bl \n\
movb %%bl, -2("EDI","ECX",4) \n\
movb -2("ESI","ECX",8), %%bl \n\
movb %%bl, -1("EDI","ECX",4) \n\
movzbl -7("ESI","ECX",8), %%ebx \n\
movzbl -3("ESI","ECX",8), %%ebp \n\
addl %%ebp, %%ebx \n\
shrl $1, %%ebx \n\
movb %%bl, -1("EAX","ECX") \n\
movzbl -5("ESI","ECX",8), %%ebx \n\
movzbl -1("ESI","ECX",8), %%ebp \n\
addl %%ebp, %%ebx \n\
shrl $1, %%ebx \n\
movb %%bl, -1("EDX","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",8),%%xmm0 #XM0: V3 Y7 U3 ..... Y1 U0 Y0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: V3 Y7 U3 ..... Y1 U0 Y0 \n\
pand %%xmm7, %%xmm0 # XMM0: -- Y7 -- ..... Y1 -- Y0 \n\
packuswb %%xmm0, %%xmm0 # XMM0: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\
psrlw $8, %%xmm1 # XMM1: -- V3 -- ..... V0 -- U0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: V3 U3 V2 U2 V1 U1 V0 U0 \n\
movdqa %%xmm1, %%xmm2 # XMM2: V3 U3 V2 U2 V1 U1 V0 U0 \n\
pand %%xmm7, %%xmm1 # XMM1: -- U3 -- U2 -- U1 -- U0 \n\
psrlw $8, %%xmm2 # XMM2: -- V3 -- V2 -- V1 -- V0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: U3 U2 U1 U0 \n\
packuswb %%xmm2, %%xmm2 # XMM2: V3 V2 V1 V0 \n\
pand %%xmm6, %%xmm1 # XMM1: -- -- -- -- U3 U2 U1 U0 \n\
psllq $32, %%xmm2 # XMM2: V3 V2 V1 V0 -- -- -- -- \n\
por %%xmm1, %%xmm2 # XMM2: V3 V2 V1 V0 U3 U2 U1 U0 \n\
movdqa %%xmm2, %%xmm1 # XMM1: V3 V2 V1 V0 U3 U2 U1 U0 \n\
pand %%xmm7, %%xmm1 # XMM1: -- V2 -- V0 -- U2 -- U0 \n\
psrlw $8, %%xmm2 # XMM2: -- V3 -- V1 -- U3 -- U1 \n\
pavgw %%xmm2, %%xmm1 # XMM1: -- v1 -- v0 -- u1 -- u0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: v1 v0 u1 u0 \n\
movq %%xmm0, -8("EDI","ECX",4) \n\
movd %%xmm1, %%ebx \n\
movw %%bx, -2("EAX","ECX") \n\
shrl $16, %%ebx; \n\
movw %%bx, -2("EDX","ECX")", \
/* emms */ "emms")
/* YUY2 -> YUV422P (unit: 2 pixels) */
#define YUY2_YUV422P \
/* Load 0x00FF*8 into XMM7 for masking */ \
"pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 4, \
/* push_regs */ "push "EBX, \
/* pop_regs */ "pop "EBX, \
/* small_loop */ \
"movb -4("ESI","ECX",4), %%bl \n\
movb %%bl, -2("EDI","ECX",2) \n\
movb -2("ESI","ECX",4), %%bl \n\
movb %%bl, -1("EDI","ECX",2) \n\
movb -3("ESI","ECX",4), %%bl \n\
movb %%bl, -1("EAX","ECX") \n\
movb -1("ESI","ECX",4), %%bl \n\
movb %%bl, -1("EDX","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",4),%%xmm0 #XM0: V3 Y7 U3 ..... Y1 U0 Y0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: V3 Y7 U3 ..... Y1 U0 Y0 \n\
pand %%xmm7, %%xmm0 # XMM0: -- Y7 -- ..... Y1 -- Y0 \n\
packuswb %%xmm0, %%xmm0 # XMM0: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\
psrlw $8, %%xmm1 # XMM1: -- V3 -- ..... V0 -- U0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: V3 U3 V2 U2 V1 U1 V0 U0 \n\
movdqa %%xmm1, %%xmm2 # XMM2: V3 U3 V2 U2 V1 U1 V0 U0 \n\
pand %%xmm7, %%xmm1 # XMM1: -- U3 -- U2 -- U1 -- U0 \n\
psrlw $8, %%xmm2 # XMM2: -- V3 -- V2 -- V1 -- V0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: U3 U2 U1 U0 \n\
packuswb %%xmm2, %%xmm2 # XMM2: V3 V2 V1 V0 \n\
movq %%xmm0, -8("EDI","ECX",2) \n\
movd %%xmm1, -4("EAX","ECX") \n\
movd %%xmm2, -4("EDX","ECX")", \
/* emms */ "emms")
/* YUY2 -> YUV444P (unit: 2 pixels) */
#define YUY2_YUV444P \
/* Load 0x00FF*8 into XMM7 for masking */ \
"pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 4, \
/* push_regs */ "push "EBX, \
/* pop_regs */ "pop "EBX, \
/* small_loop */ \
"movb -4("ESI","ECX",4), %%bl \n\
movb %%bl, -2("EDI","ECX",2) \n\
movb -2("ESI","ECX",4), %%bl \n\
movb %%bl, -1("EDI","ECX",2) \n\
movb -3("ESI","ECX",4), %%bl \n\
movb %%bl, -2("EAX","ECX",2) \n\
movb %%bl, -1("EAX","ECX",2) \n\
movb -1("ESI","ECX",4), %%bl \n\
movb %%bl, -2("EDX","ECX",2) \n\
movb %%bl, -1("EDX","ECX",2)", \
/* main_loop */ \
"movdqu -16("ESI","ECX",4),%%xmm0 #XM0: V3 Y7 U3 ..... Y1 U0 Y0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: V3 Y7 U3 ..... Y1 U0 Y0 \n\
pand %%xmm7, %%xmm0 # XMM0: -- Y7 -- ..... Y1 -- Y0 \n\
packuswb %%xmm0, %%xmm0 # XMM0: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\
psrlw $8, %%xmm1 # XMM1: -- V3 -- ..... V0 -- U0 \n\
packuswb %%xmm1, %%xmm1 # XMM1: V3 U3 V2 U2 V1 U1 V0 U0 \n\
movdqa %%xmm1, %%xmm2 # XMM2: V3 U3 V2 U2 V1 U1 V0 U0 \n\
pand %%xmm7, %%xmm1 # XMM1: -- U3 -- U2 -- U1 -- U0 \n\
psrlw $8, %%xmm2 # XMM2: -- V3 -- V2 -- V1 -- V0 \n\
movdqa %%xmm1, %%xmm3 # XMM3: -- U3 -- U2 -- U1 -- U0 \n\
psllw $8, %%xmm3 # XMM3: U3 -- U2 -- U1 -- U0 -- \n\
por %%xmm3, %%xmm1 # XMM1: U3 U3 U2 U2 U1 U1 U0 U0 \n\
movdqa %%xmm2, %%xmm3 # XMM3: -- V3 -- V2 -- V1 -- V0 \n\
psllw $8, %%xmm3 # XMM3: V3 -- V2 -- V1 -- V0 -- \n\
por %%xmm3, %%xmm2 # XMM1: V3 V3 V2 V2 V1 V1 V0 V0 \n\
movq %%xmm0, -8("EDI","ECX",2) \n\
movq %%xmm1, -8("EAX","ECX",2) \n\
movq %%xmm2, -8("EDX","ECX",2)", \
/* emms */ "emms")
/* Y8 -> YUY2/YVYU (unit: 1 pixel) */
#define Y8_YUY2 \
/* Load 0x80*16 into XMM7 for interlacing U/V */ \
"pcmpeqd %%xmm7, %%xmm7; psllw $7, %%xmm7; packsswb %%xmm7, %%xmm7;"\
SIMD_LOOP_WRAPPER( \
/* blocksize */ 16, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movb -1("ESI","ECX"), %%al \n\
movb %%al, -2("EDI","ECX",2) \n\
movb $0x80, -1("EDI","ECX",2)", \
/* main_loop */ \
"movdqu -16("ESI","ECX"),%%xmm0 # XMM0: YF YE YD ..... Y2 Y1 Y0 \n\
movdqa %%xmm0, %%xmm1 # XMM1: YF YE YD ..... Y2 Y1 Y0 \n\
punpcklbw %%xmm7, %%xmm0 # XMM0: 80 Y7 80 ..... Y1 80 Y0 \n\
movdqu %%xmm0, -32("EDI","ECX",2) \n\
punpckhbw %%xmm7, %%xmm1 # XMM1: 80 YF 80 ..... Y9 80 Y8 \n\
movdqu %%xmm1, -16("EDI","ECX",2)", \
/* emms */ "emms")
/* Y8 -> UYVY (unit: 1 pixel) */
#define Y8_UYVY \
/* Load 0x80*16 into XMM7 for interlacing U/V */ \
"pcmpeqd %%xmm7, %%xmm7; psllw $7, %%xmm7; packsswb %%xmm7, %%xmm7;"\
SIMD_LOOP_WRAPPER( \
/* blocksize */ 16, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movb -1("ESI","ECX"), %%al \n\
movb %%al, -1("EDI","ECX",2) \n\
movb $0x80, -2("EDI","ECX",2)", \
/* main_loop */ \
"movdqu -16("ESI","ECX"),%%xmm0 # XMM0: YF YE YD ..... Y2 Y1 Y0 \n\
movdqa %%xmm7, %%xmm1 # XMM1: 80 80 80 ..... 80 80 80 \n\
punpcklbw %%xmm0, %%xmm1 # XMM1: Y7 80 Y6 ..... 80 Y0 80 \n\
movdqu %%xmm1, -32("EDI","ECX",2) \n\
movdqa %%xmm7, %%xmm2 # XMM2: 80 80 80 ..... 80 80 80 \n\
punpckhbw %%xmm0, %%xmm2 # XMM0: YF 80 YE ..... 80 Y8 80 \n\
movdqu %%xmm2, -16("EDI","ECX",2)", \
/* emms */ "emms")
/* YUY2/YVYU -> Y8 (unit: 1 pixel) */
#define YUY2_Y8 \
/* Load 0x00FF*8 into XMM7 for masking */ \
"pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movb -2("ESI","ECX",2), %%al \n\
movb %%al, -1("EDI","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",2),%%xmm0 #XM0: V3 Y7 U3 ..... Y1 U0 Y0 \n\
pand %%xmm7, %%xmm0 # XMM0: -- Y7 -- ..... Y1 -- Y0 \n\
packuswb %%xmm0, %%xmm0 # XMM0: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\
movq %%xmm0, -8("EDI","ECX")", \
/* emms */ "emms")
/* UYVY -> Y8 (unit: 1 pixel) */
#define UYVY_Y8 \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movb -1("ESI","ECX",2), %%al \n\
movb %%al, -1("EDI","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",2),%%xmm0 #XM0: Y7 V3 Y6 ..... V0 Y0 U0 \n\
psrlw $8, %%xmm0 # XMM0: -- Y7 -- ..... Y1 -- Y0 \n\
packuswb %%xmm0, %%xmm0 # XMM0: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\
movq %%xmm0, -8("EDI","ECX")", \
/* emms */ "emms")
/*************************************************************************/
static int yuv420p_yuy2_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
for (y = 0; y < (height & ~1); y++) {
asm(YUV42XP_YUY2
: /* no outputs */
: "S" (src[0]+y*width), "a" (src[1]+(y/2)*(width/2)),
"d" (src[2]+(y/2)*(width/2)), "D" (dest[0]+y*width*2),
"c" (width/2));
}
return 1;
}
static int yuv411p_yuy2_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
if (!(width & 3)) {
asm(YUV411P_YUY2
: /* no outputs */
: "S" (src[0]), "a" (src[1]), "d" (src[2]), "D" (dest[0]),
"c" ((width/4)*height));
} else {
int y;
for (y = 0; y < height; y++) {
asm(YUV411P_YUY2
: /* no outputs */
: "S" (src[0]+y*width), "a" (src[1]+y*(width/4)),
"d" (src[2]+y*(width/4)), "D" (dest[0]+y*width*2),
"c" (width/4));
}
}
return 1;
}
static int yuv422p_yuy2_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
if (!(width & 1)) {
asm(YUV42XP_YUY2
: /* no outputs */
: "S" (src[0]), "a" (src[1]), "d" (src[2]), "D" (dest[0]),
"c" ((width/2)*height));
} else {
int y;
for (y = 0; y < height; y++) {
asm(YUV42XP_YUY2
: /* no outputs */
: "S" (src[0]+y*width), "a" (src[1]+y*(width/2)),
"d" (src[2]+y*(width/2)), "D" (dest[0]+y*width*2),
"c" (width/2));
}
}
return 1;
}
static int yuv444p_yuy2_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
if (!(width & 1)) {
asm(YUV444P_YUY2
: /* no outputs */
: "S" (src[0]), "a" (src[1]), "d" (src[2]), "D" (dest[0]),
"c" ((width/2)*height));
} else {
int y;
for (y = 0; y < height; y++) {
asm(YUV444P_YUY2
: /* no outputs */
: "S" (src[0]+y*width), "a" (src[1]+y*(width/2)),
"d" (src[2]+y*(width/2)), "D" (dest[0]+y*width*2),
"c" (width/2));
}
}
return 1;
}
/*************************************************************************/
static int yuy2_yuv420p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
for (y = 0; y < (height & ~1); y += 2) {
asm(YUY2_YUV420P_U
: /* no outputs */
: "S" (src[0]+y*width*2), "a" (src[0]+(y+1)*width*2),
"D" (dest[0]+y*width), "d" (dest[1]+(y/2)*(width/2)),
"c" (width/2));
asm(YUY2_YUV420P_V
: /* no outputs */
: "S" (src[0]+(y+1)*width*2), "a" (src[0]+y*width*2),
"D" (dest[0]+(y+1)*width), "d" (dest[2]+(y/2)*(width/2)),
"c" (width/2));
}
return 1;
}
static int yuy2_yuv411p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
if (!(width & 3)) {
asm(YUY2_YUV411P
: /* no outputs */
: "S" (src[0]), "D" (dest[0]), "a" (dest[1]), "d" (dest[2]),
"c" ((width/4)*height));
} else {
int y;
for (y = 0; y < height; y++) {
asm(YUY2_YUV411P
: /* no outputs */
: "S" (src[0]+y*width*2), "D" (dest[0]+y*width),
"a" (dest[1]+y*(width/4)), "d" (dest[2]+y*(width/4)),
"c" (width/4));
}
}
return 1;
}
static int yuy2_yuv422p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
if (!(width & 1)) {
asm(YUY2_YUV422P
: /* no outputs */
: "S" (src[0]), "D" (dest[0]), "a" (dest[1]), "d" (dest[2]),
"c" ((width/2)*height));
} else {
int y;
for (y = 0; y < height; y++) {
asm(YUY2_YUV422P
: /* no outputs */
: "S" (src[0]+y*width*2), "D" (dest[0]+y*width),
"a" (dest[1]+y*(width/2)), "d" (dest[2]+y*(width/2)),
"c" (width/2));
}
}
return 1;
}
static int yuy2_yuv444p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
if (!(width & 1)) {
asm(YUY2_YUV444P
: /* no outputs */
: "S" (src[0]), "D" (dest[0]), "a" (dest[1]), "d" (dest[2]),
"c" ((width/2)*height));
} else {
int y;
for (y = 0; y < height; y++) {
asm(YUY2_YUV444P
: /* no outputs */
: "S" (src[0]+y*width*2), "D" (dest[0]+y*width),
"a" (dest[1]+y*width), "d" (dest[2]+y*width),
"c" (width/2));
}
}
return 1;
}
/*************************************************************************/
static int y8_yuy2_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
asm(Y8_YUY2
: /* no outputs */
: "S" (src[0]), "D" (dest[0]), "c" (width*height)
: "eax");
return 1;
}
static int y8_uyvy_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
asm(Y8_UYVY
: /* no outputs */
: "S" (src[0]), "D" (dest[0]), "c" (width*height)
: "eax");
return 1;
}
static int yuy2_y8_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
asm(YUY2_Y8
: /* no outputs */
: "S" (src[0]), "D" (dest[0]), "c" (width*height)
: "eax");
return 1;
}
static int uyvy_y8_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
asm(UYVY_Y8
: /* no outputs */
: "S" (src[0]), "D" (dest[0]), "c" (width*height)
: "eax");
return 1;
}
/*************************************************************************/
#endif /* HAVE_ASM_SSE2 */
/*************************************************************************/
/*************************************************************************/
/* Initialization */
int ac_imgconvert_init_yuv_mixed(int accel)
{
if (!register_conversion(IMG_YUV420P, IMG_YUY2, yuv420p_yuy2)
|| !register_conversion(IMG_YUV411P, IMG_YUY2, yuv411p_yuy2)
|| !register_conversion(IMG_YUV422P, IMG_YUY2, yuv422p_yuy2)
|| !register_conversion(IMG_YUV444P, IMG_YUY2, yuv444p_yuy2)
|| !register_conversion(IMG_Y8, IMG_YUY2, y8_yuy2)
|| !register_conversion(IMG_YUV420P, IMG_UYVY, yuv420p_uyvy)
|| !register_conversion(IMG_YUV411P, IMG_UYVY, yuv411p_uyvy)
|| !register_conversion(IMG_YUV422P, IMG_UYVY, yuv422p_uyvy)
|| !register_conversion(IMG_YUV444P, IMG_UYVY, yuv444p_uyvy)
|| !register_conversion(IMG_Y8, IMG_UYVY, y8_uyvy)
|| !register_conversion(IMG_YUV420P, IMG_YVYU, yuv420p_yvyu)
|| !register_conversion(IMG_YUV411P, IMG_YVYU, yuv411p_yvyu)
|| !register_conversion(IMG_YUV422P, IMG_YVYU, yuv422p_yvyu)
|| !register_conversion(IMG_YUV444P, IMG_YVYU, yuv444p_yvyu)
|| !register_conversion(IMG_Y8, IMG_YVYU, y8_yuy2)
|| !register_conversion(IMG_YUY2, IMG_YUV420P, yuy2_yuv420p)
|| !register_conversion(IMG_YUY2, IMG_YUV411P, yuy2_yuv411p)
|| !register_conversion(IMG_YUY2, IMG_YUV422P, yuy2_yuv422p)
|| !register_conversion(IMG_YUY2, IMG_YUV444P, yuy2_yuv444p)
|| !register_conversion(IMG_YUY2, IMG_Y8, yuy2_y8)
|| !register_conversion(IMG_UYVY, IMG_YUV420P, uyvy_yuv420p)
|| !register_conversion(IMG_UYVY, IMG_YUV411P, uyvy_yuv411p)
|| !register_conversion(IMG_UYVY, IMG_YUV422P, uyvy_yuv422p)
|| !register_conversion(IMG_UYVY, IMG_YUV444P, uyvy_yuv444p)
|| !register_conversion(IMG_UYVY, IMG_Y8, uyvy_y8)
|| !register_conversion(IMG_YVYU, IMG_YUV420P, yvyu_yuv420p)
|| !register_conversion(IMG_YVYU, IMG_YUV411P, yvyu_yuv411p)
|| !register_conversion(IMG_YVYU, IMG_YUV422P, yvyu_yuv422p)
|| !register_conversion(IMG_YVYU, IMG_YUV444P, yvyu_yuv444p)
|| !register_conversion(IMG_YVYU, IMG_Y8, yuy2_y8)
) {
return 0;
}
#if defined(HAVE_ASM_SSE2)
if (accel & AC_SSE2) {
if (!register_conversion(IMG_YUV420P, IMG_YUY2, yuv420p_yuy2_sse2)
|| !register_conversion(IMG_YUV411P, IMG_YUY2, yuv411p_yuy2_sse2)
|| !register_conversion(IMG_YUV422P, IMG_YUY2, yuv422p_yuy2_sse2)
|| !register_conversion(IMG_YUV444P, IMG_YUY2, yuv444p_yuy2_sse2)
|| !register_conversion(IMG_Y8, IMG_YUY2, y8_yuy2_sse2)
|| !register_conversion(IMG_Y8, IMG_UYVY, y8_uyvy_sse2)
|| !register_conversion(IMG_Y8, IMG_YVYU, y8_yuy2_sse2)
|| !register_conversion(IMG_YUY2, IMG_YUV420P, yuy2_yuv420p_sse2)
|| !register_conversion(IMG_YUY2, IMG_YUV411P, yuy2_yuv411p_sse2)
|| !register_conversion(IMG_YUY2, IMG_YUV422P, yuy2_yuv422p_sse2)
|| !register_conversion(IMG_YUY2, IMG_YUV444P, yuy2_yuv444p_sse2)
|| !register_conversion(IMG_YUY2, IMG_Y8, yuy2_y8_sse2)
|| !register_conversion(IMG_UYVY, IMG_Y8, uyvy_y8_sse2)
|| !register_conversion(IMG_YVYU, IMG_Y8, yuy2_y8_sse2)
) {
return 0;
}
}
#endif /* ARCH_X86 || ARCH_X86_64 */
return 1;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,290 @@
/*
* img_yuv_packed.c - YUV packed image format conversion routines
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "imgconvert.h"
#include "img_internal.h"
/*************************************************************************/
/*************************************************************************/
/* Standard C implementations */
/*************************************************************************/
/* Identity transformation, works when src==dest */
static int yuv16_copy(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height*2);
return 1;
}
/* Used for YUY2->UYVY and UYVY->YUY2, works when src==dest */
static int yuv16_swap16(uint8_t **src, uint8_t **dest, int width, int height)
{
uint16_t *srcp = (uint16_t *)src[0];
uint16_t *destp = (uint16_t *)dest[0];
int i;
for (i = 0; i < width*height; i++)
destp[i] = srcp[i]>>8 | srcp[i]<<8;
return 1;
}
/* Used for YUY2->YVYU and YVYU->YUY2, works when src==dest */
static int yuv16_swapuv(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < width*height/2; i++) {
uint8_t tmp = src[0][i*4+1];
dest[0][i*4 ] = src[0][i*4 ];
dest[0][i*4+1] = src[0][i*4+3];
dest[0][i*4+2] = src[0][i*4+2];
dest[0][i*4+3] = tmp;
}
return 1;
}
/*************************************************************************/
static int uyvy_yvyu(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < width*height/2; i++) {
dest[0][i*4 ] = src[0][i*4+1];
dest[0][i*4+1] = src[0][i*4+2];
dest[0][i*4+2] = src[0][i*4+3];
dest[0][i*4+3] = src[0][i*4 ];
}
return 1;
}
static int yvyu_uyvy(uint8_t **src, uint8_t **dest, int width, int height)
{
int i;
for (i = 0; i < width*height/2; i++) {
dest[0][i*4 ] = src[0][i*4+3];
dest[0][i*4+1] = src[0][i*4 ];
dest[0][i*4+2] = src[0][i*4+1];
dest[0][i*4+3] = src[0][i*4+2];
}
return 1;
}
/*************************************************************************/
/*************************************************************************/
#if defined(ARCH_X86) || defined(ARCH_X86_64)
/* Common macros/data for x86 code */
#define DEFINE_MASK_DATA
#include "img_x86_common.h"
/*************************************************************************/
/* Basic assembly routines */
static int yuv16_swap16_x86(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_SWAP16_2_X86(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
static int yuv16_swapuv_x86(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_SWAP32_13_X86(width*height/2);
return 1;
}
static int uyvy_yvyu_x86(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_ROR32_X86(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
static int yvyu_uyvy_x86(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_ROL32_X86(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
/*************************************************************************/
/* MMX routines */
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86) /* i.e. not x86_64 */
static int yuv16_swap16_mmx(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_SWAP16_2_MMX(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
static int yuv16_swapuv_mmx(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_SWAP32_13_MMX(width*height/2);
return 1;
}
static int uyvy_yvyu_mmx(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_ROR32_MMX(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
static int yvyu_uyvy_mmx(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_ROL32_MMX(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
#endif /* HAVE_ASM_MMX && ARCH_X86 */
/*************************************************************************/
/* SSE2 routines */
#if defined(HAVE_ASM_SSE2)
static int yuv16_swap16_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_SWAP16_2_SSE2(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
static int yuv16_swapuv_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_SWAP32_13_SSE2(width*height/2);
return 1;
}
static int uyvy_yvyu_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_ROR32_SSE2(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
static int yvyu_uyvy_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ASM_ROL32_SSE2(width*height/2);
if (width*height % 1)
((uint16_t *)(dest[0]))[width*height-1] =
src[0][width*height*2-2]<<8 | src[0][width*height*2-1];
return 1;
}
#endif /* HAVE_ASM_SSE2 */
/*************************************************************************/
#endif /* ARCH_X86 || ARCH_X86_64 */
/*************************************************************************/
/*************************************************************************/
/* Initialization */
int ac_imgconvert_init_yuv_packed(int accel)
{
if (!register_conversion(IMG_YUY2, IMG_YUY2, yuv16_copy)
|| !register_conversion(IMG_YUY2, IMG_UYVY, yuv16_swap16)
|| !register_conversion(IMG_YUY2, IMG_YVYU, yuv16_swapuv)
|| !register_conversion(IMG_UYVY, IMG_YUY2, yuv16_swap16)
|| !register_conversion(IMG_UYVY, IMG_UYVY, yuv16_copy)
|| !register_conversion(IMG_UYVY, IMG_YVYU, uyvy_yvyu)
|| !register_conversion(IMG_YVYU, IMG_YUY2, yuv16_swapuv)
|| !register_conversion(IMG_YVYU, IMG_UYVY, yvyu_uyvy)
|| !register_conversion(IMG_YVYU, IMG_YVYU, yuv16_copy)
) {
return 0;
}
#if defined(ARCH_X86) || defined(ARCH_X86_64)
if (accel & (AC_IA32ASM | AC_AMD64ASM)) {
if (!register_conversion(IMG_YUY2, IMG_UYVY, yuv16_swap16_x86)
|| !register_conversion(IMG_YUY2, IMG_YVYU, yuv16_swapuv_x86)
|| !register_conversion(IMG_UYVY, IMG_YUY2, yuv16_swap16_x86)
|| !register_conversion(IMG_UYVY, IMG_YVYU, uyvy_yvyu_x86)
|| !register_conversion(IMG_YVYU, IMG_YUY2, yuv16_swapuv_x86)
|| !register_conversion(IMG_YVYU, IMG_UYVY, yvyu_uyvy_x86)
) {
return 0;
}
}
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86)
if (accel & AC_MMX) {
if (!register_conversion(IMG_YUY2, IMG_UYVY, yuv16_swap16_mmx)
|| !register_conversion(IMG_YUY2, IMG_YVYU, yuv16_swapuv_mmx)
|| !register_conversion(IMG_UYVY, IMG_YUY2, yuv16_swap16_mmx)
|| !register_conversion(IMG_UYVY, IMG_YVYU, uyvy_yvyu_mmx)
|| !register_conversion(IMG_YVYU, IMG_YUY2, yuv16_swapuv_mmx)
|| !register_conversion(IMG_YVYU, IMG_UYVY, yvyu_uyvy_mmx)
) {
return 0;
}
}
#endif
#if defined(HAVE_ASM_SSE2)
if (accel & AC_SSE2) {
if (!register_conversion(IMG_YUY2, IMG_UYVY, yuv16_swap16_sse2)
|| !register_conversion(IMG_YUY2, IMG_YVYU, yuv16_swapuv_sse2)
|| !register_conversion(IMG_UYVY, IMG_YUY2, yuv16_swap16_sse2)
|| !register_conversion(IMG_UYVY, IMG_YVYU, uyvy_yvyu_sse2)
|| !register_conversion(IMG_YVYU, IMG_YUY2, yuv16_swapuv_sse2)
|| !register_conversion(IMG_YVYU, IMG_UYVY, yvyu_uyvy_sse2)
) {
return 0;
}
}
#endif
#endif /* ARCH_X86 || ARCH_X86_64 */
return 1;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,771 @@
/*
* img_yuv_planar.c - YUV planar image format conversion routines
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "imgconvert.h"
#include "img_internal.h"
#include <string.h>
/*************************************************************************/
/*************************************************************************/
/* Standard C implementations */
/*************************************************************************/
/* Identity transformations */
static int yuv420p_copy(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
ac_memcpy(dest[1], src[1], (width/2)*(height/2));
ac_memcpy(dest[2], src[2], (width/2)*(height/2));
return 1;
}
static int yuv411p_copy(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
ac_memcpy(dest[1], src[1], (width/4)*height);
ac_memcpy(dest[2], src[2], (width/4)*height);
return 1;
}
static int yuv422p_copy(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
ac_memcpy(dest[1], src[1], (width/2)*height);
ac_memcpy(dest[2], src[2], (width/2)*height);
return 1;
}
static int yuv444p_copy(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
ac_memcpy(dest[1], src[1], width*height);
ac_memcpy(dest[2], src[2], width*height);
return 1;
}
static int y8_copy(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
return 1;
}
/*************************************************************************/
static int yuv420p_yuv411p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
for (x = 0; x < (width/2 & ~1); x += 2) {
dest[1][y*(width/4)+x/2] = (src[1][(y/2)*(width/2)+x]
+ src[1][(y/2)*(width/2)+x+1] + 1) / 2;
dest[2][y*(width/4)+x/2] = (src[2][(y/2)*(width/2)+x]
+ src[2][(y/2)*(width/2)+x+1] + 1) / 2;
}
ac_memcpy(dest[1]+(y+1)*(width/4), dest[1]+y*(width/4), width/4);
ac_memcpy(dest[2]+(y+1)*(width/4), dest[2]+y*(width/4), width/4);
}
return 1;
}
static int yuv420p_yuv422p(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
ac_memcpy(dest[1]+(y )*(width/2), src[1]+(y/2)*(width/2), width/2);
ac_memcpy(dest[1]+(y+1)*(width/2), src[1]+(y/2)*(width/2), width/2);
ac_memcpy(dest[2]+(y )*(width/2), src[2]+(y/2)*(width/2), width/2);
ac_memcpy(dest[2]+(y+1)*(width/2), src[2]+(y/2)*(width/2), width/2);
}
return 1;
}
static int yuv420p_yuv444p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y += 2) {
for (x = 0; x < width; x += 2) {
dest[1][y*width+x ] =
dest[1][y*width+x+1] = src[1][(y/2)*(width/2)+(x/2)];
dest[2][y*width+x ] =
dest[2][y*width+x+1] = src[2][(y/2)*(width/2)+(x/2)];
}
ac_memcpy(dest[1]+(y+1)*width, dest[1]+y*width, width);
ac_memcpy(dest[2]+(y+1)*width, dest[2]+y*width, width);
}
return 1;
}
/*************************************************************************/
static int yuv411p_yuv420p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
for (x = 0; x < ((width/2) & ~1); x += 2) {
dest[1][(y/2)*(width/2)+x] = (src[1][y*(width/4)+x/2]
+ src[1][(y+1)*(width/4)+x/2] + 1) / 2;
dest[2][(y/2)*(width/2)+x] = (src[2][y*(width/4)+x/2]
+ src[2][(y+1)*(width/4)+x/2] + 1) / 2;
dest[1][(y/2)*(width/2)+x+1] = dest[1][(y/2)*(width/2)+x];
dest[2][(y/2)*(width/2)+x+1] = dest[2][(y/2)*(width/2)+x];
}
}
return 1;
}
static int yuv411p_yuv422p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y++) {
for (x = 0; x < ((width/2) & ~1); x += 2) {
dest[1][y*(width/2)+x ] = src[1][y*(width/4)+x/2];
dest[1][y*(width/2)+x+1] = src[1][y*(width/4)+x/2];
dest[2][y*(width/2)+x ] = src[2][y*(width/4)+x/2];
dest[2][y*(width/2)+x+1] = src[2][y*(width/4)+x/2];
}
}
return 1;
}
static int yuv411p_yuv444p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y++) {
for (x = 0; x < (width & ~3); x += 4) {
dest[1][y*width+x ] = src[1][y*(width/4)+x/4];
dest[1][y*width+x+1] = src[1][y*(width/4)+x/4];
dest[1][y*width+x+2] = src[1][y*(width/4)+x/4];
dest[1][y*width+x+3] = src[1][y*(width/4)+x/4];
dest[2][y*width+x ] = src[2][y*(width/4)+x/4];
dest[2][y*width+x+1] = src[2][y*(width/4)+x/4];
dest[2][y*width+x+2] = src[2][y*(width/4)+x/4];
dest[2][y*width+x+3] = src[2][y*(width/4)+x/4];
}
}
return 1;
}
/*************************************************************************/
static int yuv422p_yuv420p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
for (x = 0; x < width/2; x++) {
dest[1][(y/2)*(width/2)+x] = (src[1][y*(width/2)+x]
+ src[1][(y+1)*(width/2)+x] + 1) / 2;
dest[2][(y/2)*(width/2)+x] = (src[2][y*(width/2)+x]
+ src[2][(y+1)*(width/2)+x] + 1) / 2;
}
}
return 1;
}
static int yuv422p_yuv411p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y++) {
for (x = 0; x < ((width/2) & ~1); x += 2) {
dest[1][y*(width/4)+x/2] = (src[1][y*(width/2)+x]
+ src[1][y*(width/2)+x+1] + 1) / 2;
dest[2][y*(width/4)+x/2] = (src[2][y*(width/2)+x]
+ src[2][y*(width/2)+x+1] + 1) / 2;
}
}
return 1;
}
static int yuv422p_yuv444p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y++) {
for (x = 0; x < (width & ~1); x += 2) {
dest[1][y*width+x ] = src[1][y*(width/2)+x/2];
dest[1][y*width+x+1] = src[1][y*(width/2)+x/2];
dest[2][y*width+x ] = src[2][y*(width/2)+x/2];
dest[2][y*width+x+1] = src[2][y*(width/2)+x/2];
}
}
return 1;
}
/*************************************************************************/
static int yuv444p_yuv420p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
for (x = 0; x < (width & ~1); x += 2) {
dest[1][(y/2)*(width/2)+x/2] = (src[1][y*width+x]
+ src[1][y*width+x+1]
+ src[1][(y+1)*width+x]
+ src[1][(y+1)*width+x+1] + 2) / 4;
dest[2][(y/2)*(width/2)+x/2] = (src[2][y*width+x]
+ src[2][y*width+x+1]
+ src[2][(y+1)*width+x]
+ src[2][(y+1)*width+x+1] + 2) / 4;
}
}
return 1;
}
static int yuv444p_yuv411p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y++) {
for (x = 0; x < (width & ~3); x += 4) {
dest[1][y*(width/4)+x/4] = (src[1][y*width+x]
+ src[1][y*width+x+1]
+ src[1][y*width+x+2]
+ src[1][y*width+x+3] + 2) / 4;
dest[2][y*(width/4)+x/4] = (src[2][y*width+x]
+ src[2][y*width+x+1]
+ src[2][y*width+x+2]
+ src[2][y*width+x+3] + 2) / 4;
}
}
return 1;
}
static int yuv444p_yuv422p(uint8_t **src, uint8_t **dest, int width, int height)
{
int x, y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y++) {
for (x = 0; x < (width & ~1); x += 2) {
dest[1][y*(width/2)+x/2] = (src[1][y*width+x]
+ src[1][y*width+x+1] + 1) / 2;
dest[2][y*(width/2)+x/2] = (src[2][y*width+x]
+ src[2][y*width+x+1] + 1) / 2;
}
}
return 1;
}
/*************************************************************************/
/* We treat Y8 as a planar format */
static int yuvp_y8(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
return 1;
}
static int y8_yuv420p(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
memset(dest[1], 128, (width/2)*(height/2));
memset(dest[2], 128, (width/2)*(height/2));
return 1;
}
static int y8_yuv411p(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
memset(dest[1], 128, (width/4)*height);
memset(dest[2], 128, (width/4)*height);
return 1;
}
static int y8_yuv422p(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
memset(dest[1], 128, (width/2)*height);
memset(dest[2], 128, (width/2)*height);
return 1;
}
static int y8_yuv444p(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
memset(dest[1], 128, width*height);
memset(dest[2], 128, width*height);
return 1;
}
/*************************************************************************/
/*************************************************************************/
#if defined(HAVE_ASM_SSE2)
/* SSE2 routines. See comments in img_x86_common.h for why we don't bother
* unrolling the loops. */
/* Common macros/data for x86 code */
#include "img_x86_common.h"
/* Average 2 bytes horizontally (e.g. 422P->411P) (unit: 2 source bytes) */
#define AVG_2H(src,dest,count) \
asm("pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" /* XMM7: 0x00FF*8 */ \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movzbl -2("ESI","ECX",2), %%eax \n\
movzbl -1("ESI","ECX",2), %%edx \n\
addl %%edx, %%eax \n\
shrl $1, %%eax \n\
movb %%al, -1("EDI","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",2),%%xmm0 #XMM0:FEDCBA9876543210 \n\
movdqa %%xmm0, %%xmm1 # XMM1: FEDCBA9876543210 \n\
pand %%xmm7, %%xmm0 # XMM0: E C A 8 6 4 2 0 \n\
psrlw $8, %%xmm1 # XMM1: F D B 9 7 5 3 1 \n\
pavgw %%xmm1, %%xmm0 # XMM0: w v u t s r q p (avgs) \n\
packuswb %%xmm0, %%xmm0 # XMM0: wvutsrqpwvutsrqp \n\
movq %%xmm0, -8("EDI","ECX")", \
/* emms */ "emms") \
: /* no outputs */ \
: "S" (src), "D" (dest), "c" (count) \
: "eax", "edx")
/* Average 4 bytes horizontally (e.g. 444P->411P) (unit: 4 source bytes) */
#define AVG_4H(src,dest,count) \
asm("pcmpeqd %%xmm7, %%xmm7; psrld $24, %%xmm7;" /* XMM7: 0x000000FF*4 */ \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 4, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movzbl -4("ESI","ECX",4), %%eax \n\
movzbl -3("ESI","ECX",4), %%edx \n\
addl %%edx, %%eax \n\
movzbl -2("ESI","ECX",4), %%edx \n\
addl %%edx, %%eax \n\
movzbl -1("ESI","ECX",4), %%edx \n\
addl %%edx, %%eax \n\
shrl $2, %%eax \n\
movb %%al, -1("EDI","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",4),%%xmm0 #XMM0:FEDCBA9876543210 \n\
movdqa %%xmm0, %%xmm1 # XMM1: FEDCBA9876543210 \n\
movdqa %%xmm0, %%xmm2 # XMM2: FEDCBA9876543210 \n\
movdqa %%xmm0, %%xmm3 # XMM3: FEDCBA9876543210 \n\
pand %%xmm7, %%xmm0 # XMM0: C 8 4 0 \n\
psrld $8, %%xmm1 # XMM1: FED BA9 765 321 \n\
pand %%xmm7, %%xmm1 # XMM1: D 9 5 1 \n\
psrld $16, %%xmm2 # XMM2: FE BA 76 32 \n\
pand %%xmm7, %%xmm2 # XMM2: E A 6 2 \n\
psrld $24, %%xmm3 # XMM3: F B 7 3 \n\
pavgw %%xmm1, %%xmm0 # XMM0: C+D 8+9 4+5 0+1 (avgs) \n\
pavgw %%xmm3, %%xmm2 # XMM2: E+F A+B 6+7 2+3 (avgs) \n\
pavgw %%xmm2, %%xmm0 # XMM0: s r q p (avgs) \n\
packuswb %%xmm0, %%xmm0 # XMM0: s r q p s r q p \n\
packuswb %%xmm0, %%xmm0 # XMM0: srqpsrqpsrqpsrqp \n\
movd %%xmm0, -4("EDI","ECX")", \
/* emms */ "emms") \
: /* no outputs */ \
: "S" (src), "D" (dest), "c" (count) \
: "eax", "edx")
/* Repeat 2 bytes horizontally (e.g. 422P->444P) (unit: 1 source byte) */
#define REP_2H(src,dest,count) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movb -1("ESI","ECX"), %%al \n\
movb %%al, %%ah \n\
movw %%ax, -2("EDI","ECX",2)", \
/* main_loop */ \
"movq -8("ESI","ECX"), %%xmm0 # XMM0: 76543210 \n\
punpcklbw %%xmm0, %%xmm0 # XMM0: 7766554433221100 \n\
movdqu %%xmm0, -16("EDI","ECX",2)", \
/* emms */ "emms") \
: /* no outputs */ \
: "S" (src), "D" (dest), "c" (count) \
: "eax")
/* Repeat 4 bytes horizontally (e.g. 411P->444P) (unit: 1 source byte) */
#define REP_4H(src,dest,count) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ 4, \
/* push_regs */ "", \
/* pop_regs */ "", \
/* small_loop */ \
"movzbl -1("ESI","ECX"), %%eax \n\
movb %%al, %%ah \n\
movl %%eax, %%edx \n\
shll $16, %%eax \n\
orl %%edx, %%eax \n\
movl %%eax, -4("EDI","ECX",4)", \
/* main_loop */ \
"movd -4("ESI","ECX"), %%xmm0 # XMM0: 3210 \n\
punpcklbw %%xmm0, %%xmm0 # XMM0: 33221100 \n\
punpcklwd %%xmm0, %%xmm0 # XMM0: 3333222211110000 \n\
movdqu %%xmm0, -16("EDI","ECX",4)", \
/* emms */ "emms") \
: /* no outputs */ \
: "S" (src), "D" (dest), "c" (count) \
: "eax", "edx")
/* Average 2 bytes vertically and double horizontally (411P->420P)
* (unit: 1 source byte) */
#define AVG_411_420(src1,src2,dest,count) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "push "EBX, \
/* pop_regs */ "pop "EBX, \
/* small_loop */ \
"movzbl -1("ESI","ECX"), %%eax \n\
movzbl -1("EDX","ECX"), %%ebx \n\
addl %%ebx, %%eax \n\
shrl $1, %%eax \n\
movb %%al, %%ah \n\
movw %%ax, -2("EDI","ECX",2)", \
/* main_loop */ \
"movq -8("ESI","ECX"), %%xmm0 \n\
movq -8("EDX","ECX"), %%xmm1 \n\
pavgb %%xmm1, %%xmm0 \n\
punpcklbw %%xmm0, %%xmm0 \n\
movdqu %%xmm0, -16("EDI","ECX",2)", \
/* emms */ "emms") \
: /* no outputs */ \
: "S" (src1), "d" (src2), "D" (dest), "c" (count) \
: "eax")
/* Average 2 bytes vertically (422P->420P) (unit: 1 source byte) */
#define AVG_422_420(src1,src2,dest,count) \
asm(SIMD_LOOP_WRAPPER( \
/* blocksize */ 16, \
/* push_regs */ "push "EBX, \
/* pop_regs */ "pop "EBX, \
/* small_loop */ \
"movzbl -1("ESI","ECX"), %%eax \n\
movzbl -1("EDX","ECX"), %%ebx \n\
addl %%ebx, %%eax \n\
shrl $1, %%eax \n\
movb %%al, -1("EDI","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX"), %%xmm0 \n\
movdqu -16("EDX","ECX"), %%xmm1 \n\
pavgb %%xmm1, %%xmm0 \n\
movdqu %%xmm0, -16("EDI","ECX")", \
/* emms */ "emms") \
: /* no outputs */ \
: "S" (src1), "d" (src2), "D" (dest), "c" (count) \
: "eax")
/* Average 4 bytes, 2 horizontally and 2 vertically (444P->420P)
* (unit: 2 source bytes) */
#define AVG_444_420(src1,src2,dest,count) \
asm("pcmpeqd %%xmm7, %%xmm7; psrlw $8, %%xmm7;" /* XMM7: 0x00FF*8 */ \
SIMD_LOOP_WRAPPER( \
/* blocksize */ 8, \
/* push_regs */ "push "EBX, \
/* pop_regs */ "pop "EBX, \
/* small_loop */ \
"movzbl -2("ESI","ECX",2), %%eax \n\
movzbl -1("ESI","ECX",2), %%ebx \n\
addl %%ebx, %%eax \n\
movzbl -2("EDX","ECX",2), %%ebx \n\
addl %%ebx, %%eax \n\
movzbl -1("EDX","ECX",2), %%ebx \n\
addl %%ebx, %%eax \n\
shrl $2, %%eax \n\
movb %%al, -1("EDI","ECX")", \
/* main_loop */ \
"movdqu -16("ESI","ECX",2), %%xmm0 \n\
movdqu -16("EDX","ECX",2), %%xmm2 \n\
movdqa %%xmm0, %%xmm1 \n\
pand %%xmm7, %%xmm0 \n\
psrlw $8, %%xmm1 \n\
pavgw %%xmm1, %%xmm0 \n\
movdqa %%xmm2, %%xmm3 \n\
pand %%xmm7, %%xmm2 \n\
psrlw $8, %%xmm3 \n\
pavgw %%xmm3, %%xmm2 \n\
pavgw %%xmm2, %%xmm0 \n\
packuswb %%xmm0, %%xmm0 \n\
movq %%xmm0, -8("EDI","ECX")", \
/* emms */ "emms") \
: /* no outputs */ \
: "S" (src1), "d" (src2), "D" (dest), "c" (count))
/*************************************************************************/
static int yuv420p_yuv411p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
AVG_2H(src[1]+(y/2)*(width/2), dest[1]+y*(width/4), width/4);
ac_memcpy(dest[1]+(y+1)*(width/4), dest[1]+y*(width/4), width/4);
AVG_2H(src[2]+(y/2)*(width/2), dest[2]+y*(width/4), width/4);
ac_memcpy(dest[2]+(y+1)*(width/4), dest[2]+y*(width/4), width/4);
}
return 1;
}
static int yuv420p_yuv444p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < height; y += 2) {
REP_2H(src[1]+(y/2)*(width/2), dest[1]+y*width, width/2);
ac_memcpy(dest[1]+(y+1)*width, dest[1]+y*width, width);
REP_2H(src[2]+(y/2)*(width/2), dest[2]+y*width, width/2);
ac_memcpy(dest[2]+(y+1)*width, dest[2]+y*width, width);
}
return 1;
}
/*************************************************************************/
static int yuv411p_yuv420p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
AVG_411_420(src[1]+y*(width/4), src[1]+(y+1)*(width/4),
dest[1]+(y/2)*(width/2), width/4);
AVG_411_420(src[2]+y*(width/4), src[2]+(y+1)*(width/4),
dest[2]+(y/2)*(width/2), width/4);
}
return 1;
}
static int yuv411p_yuv422p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
if (!(width & 3)) {
/* Fast version, no bytes at end of row to skip */
REP_2H(src[1], dest[1], (width/4)*height);
REP_2H(src[2], dest[2], (width/4)*height);
} else {
/* Slow version, loop through each row */
int y;
for (y = 0; y < height; y++) {
REP_2H(src[1]+y*(width/4), dest[1]+y*(width/2), width/4);
REP_2H(src[2]+y*(width/4), dest[2]+y*(width/2), width/4);
}
}
return 1;
}
static int yuv411p_yuv444p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
if (!(width & 3)) {
/* Fast version, no bytes at end of row to skip */
REP_4H(src[1], dest[1], (width/4)*height);
REP_4H(src[2], dest[2], (width/4)*height);
} else {
/* Slow version, loop through each row */
int y;
for (y = 0; y < height; y++) {
REP_4H(src[1]+y*(width/4), dest[1]+y*width, width/4);
REP_4H(src[2]+y*(width/4), dest[2]+y*width, width/4);
}
}
return 1;
}
/*************************************************************************/
static int yuv422p_yuv420p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
AVG_422_420(src[1]+y*(width/2), src[1]+(y+1)*(width/2),
dest[1]+(y/2)*(width/2), width/2);
AVG_422_420(src[2]+y*(width/2), src[2]+(y+1)*(width/2),
dest[2]+(y/2)*(width/2), width/2);
}
return 1;
}
static int yuv422p_yuv411p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
if (!(width & 3)) {
/* Fast version, no bytes at end of row to skip */
AVG_2H(src[1], dest[1], (width/4)*height);
AVG_2H(src[2], dest[2], (width/4)*height);
} else {
/* Slow version, loop through each row */
int y;
for (y = 0; y < height; y++) {
AVG_2H(src[1]+y*(width/2), dest[1]+y*(width/4), width/4);
AVG_2H(src[2]+y*(width/2), dest[2]+y*(width/4), width/4);
}
}
return 1;
}
static int yuv422p_yuv444p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
if (!(width & 1)) {
/* Fast version, no bytes at end of row to skip */
REP_2H(src[1], dest[1], (width/2)*height);
REP_2H(src[2], dest[2], (width/2)*height);
} else {
/* Slow version, loop through each row */
int y;
for (y = 0; y < height; y++) {
REP_2H(src[1]+y*(width/2), dest[1]+y*width, width/2);
REP_2H(src[2]+y*(width/2), dest[2]+y*width, width/2);
}
}
return 1;
}
/*************************************************************************/
static int yuv444p_yuv420p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
int y;
ac_memcpy(dest[0], src[0], width*height);
for (y = 0; y < (height & ~1); y += 2) {
AVG_444_420(src[1]+y*width, src[1]+(y+1)*width,
dest[1]+(y/2)*(width/2), width/2);
AVG_444_420(src[2]+y*width, src[2]+(y+1)*width,
dest[2]+(y/2)*(width/2), width/2);
}
return 1;
}
static int yuv444p_yuv411p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
if (!(width & 3)) {
/* Fast version, no bytes at end of row to skip */
AVG_4H(src[1], dest[1], (width/4)*height);
AVG_4H(src[2], dest[2], (width/4)*height);
} else {
/* Slow version, loop through each row */
int y;
for (y = 0; y < height; y++) {
AVG_4H(src[1]+y*width, dest[1]+y*(width/4), width/4);
AVG_4H(src[2]+y*width, dest[2]+y*(width/4), width/4);
}
}
return 1;
}
static int yuv444p_yuv422p_sse2(uint8_t **src, uint8_t **dest, int width, int height)
{
ac_memcpy(dest[0], src[0], width*height);
if (!(width & 1)) {
/* Fast version, no bytes at end of row to skip */
AVG_2H(src[1], dest[1], (width/2)*height);
AVG_2H(src[2], dest[2], (width/2)*height);
} else {
/* Slow version, loop through each row */
int y;
for (y = 0; y < height; y++) {
AVG_2H(src[1]+y*width, dest[1]+y*(width/2), width/2);
AVG_2H(src[2]+y*width, dest[2]+y*(width/2), width/2);
}
}
return 1;
}
/*************************************************************************/
#endif /* HAVE_ASM_SSE2 */
/*************************************************************************/
/*************************************************************************/
/* Initialization */
int ac_imgconvert_init_yuv_planar(int accel)
{
if (!register_conversion(IMG_YUV420P, IMG_YUV420P, yuv420p_copy)
|| !register_conversion(IMG_YUV420P, IMG_YUV411P, yuv420p_yuv411p)
|| !register_conversion(IMG_YUV420P, IMG_YUV422P, yuv420p_yuv422p)
|| !register_conversion(IMG_YUV420P, IMG_YUV444P, yuv420p_yuv444p)
|| !register_conversion(IMG_YUV420P, IMG_Y8, yuvp_y8)
|| !register_conversion(IMG_YUV411P, IMG_YUV420P, yuv411p_yuv420p)
|| !register_conversion(IMG_YUV411P, IMG_YUV411P, yuv411p_copy)
|| !register_conversion(IMG_YUV411P, IMG_YUV422P, yuv411p_yuv422p)
|| !register_conversion(IMG_YUV411P, IMG_YUV444P, yuv411p_yuv444p)
|| !register_conversion(IMG_YUV411P, IMG_Y8, yuvp_y8)
|| !register_conversion(IMG_YUV422P, IMG_YUV420P, yuv422p_yuv420p)
|| !register_conversion(IMG_YUV422P, IMG_YUV411P, yuv422p_yuv411p)
|| !register_conversion(IMG_YUV422P, IMG_YUV422P, yuv422p_copy)
|| !register_conversion(IMG_YUV422P, IMG_YUV444P, yuv422p_yuv444p)
|| !register_conversion(IMG_YUV422P, IMG_Y8, yuvp_y8)
|| !register_conversion(IMG_YUV444P, IMG_YUV420P, yuv444p_yuv420p)
|| !register_conversion(IMG_YUV444P, IMG_YUV411P, yuv444p_yuv411p)
|| !register_conversion(IMG_YUV444P, IMG_YUV422P, yuv444p_yuv422p)
|| !register_conversion(IMG_YUV444P, IMG_YUV444P, yuv444p_copy)
|| !register_conversion(IMG_YUV444P, IMG_Y8, yuvp_y8)
|| !register_conversion(IMG_Y8, IMG_YUV420P, y8_yuv420p)
|| !register_conversion(IMG_Y8, IMG_YUV411P, y8_yuv411p)
|| !register_conversion(IMG_Y8, IMG_YUV422P, y8_yuv422p)
|| !register_conversion(IMG_Y8, IMG_YUV444P, y8_yuv444p)
|| !register_conversion(IMG_Y8, IMG_Y8, y8_copy)
) {
return 0;
}
#if defined(HAVE_ASM_SSE2)
if (accel & AC_SSE2) {
if (!register_conversion(IMG_YUV420P, IMG_YUV411P, yuv420p_yuv411p_sse2)
|| !register_conversion(IMG_YUV420P, IMG_YUV444P, yuv420p_yuv444p_sse2)
|| !register_conversion(IMG_YUV411P, IMG_YUV420P, yuv411p_yuv420p_sse2)
|| !register_conversion(IMG_YUV411P, IMG_YUV422P, yuv411p_yuv422p_sse2)
|| !register_conversion(IMG_YUV411P, IMG_YUV444P, yuv411p_yuv444p_sse2)
|| !register_conversion(IMG_YUV422P, IMG_YUV420P, yuv422p_yuv420p_sse2)
|| !register_conversion(IMG_YUV422P, IMG_YUV411P, yuv422p_yuv411p_sse2)
|| !register_conversion(IMG_YUV422P, IMG_YUV444P, yuv422p_yuv444p_sse2)
|| !register_conversion(IMG_YUV444P, IMG_YUV420P, yuv444p_yuv420p_sse2)
|| !register_conversion(IMG_YUV444P, IMG_YUV411P, yuv444p_yuv411p_sse2)
|| !register_conversion(IMG_YUV444P, IMG_YUV422P, yuv444p_yuv422p_sse2)
) {
return 0;
}
}
#endif /* ARCH_X86 || ARCH_X86_64 */
return 1;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
/*
* imgconvert.c - image format conversion routines
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "imgconvert.h"
#include "img_internal.h"
#include <stdio.h>
#include <stdlib.h>
/*************************************************************************/
static struct {
ImageFormat srcfmt, destfmt;
ConversionFunc func;
} *conversions;
static int n_conversions = 0;
/*************************************************************************/
/*************************************************************************/
/* Image conversion routine. src and dest are arrays of pointers to planes
* (for packed formats with only one plane, just use `&data'); srcfmt and
* destfmt specify the source and destination image formats (IMG_*).
* width and height are in pixels. Returns 1 on success, 0 on failure. */
int ac_imgconvert(uint8_t **src, ImageFormat srcfmt,
uint8_t **dest, ImageFormat destfmt,
int width, int height)
{
int i;
/* Hack to handle YV12 easily, because conversion routines don't get
* format tags */
uint8_t *newsrc[3], *newdest[3];
if (srcfmt == IMG_YV12) {
srcfmt = IMG_YUV420P;
newsrc[0] = src[0];
newsrc[1] = src[2];
newsrc[2] = src[1];
src = newsrc;
}
if (destfmt == IMG_YV12) {
destfmt = IMG_YUV420P;
newdest[0] = dest[0];
newdest[1] = dest[2];
newdest[2] = dest[1];
dest = newdest;
}
for (i = 0; i < n_conversions; i++) {
if (conversions[i].srcfmt==srcfmt && conversions[i].destfmt==destfmt)
return (*conversions[i].func)(src, dest, width, height);
}
return 0;
}
/*************************************************************************/
/*************************************************************************/
/* Internal use only! */
int ac_imgconvert_init(int accel)
{
if (!ac_imgconvert_init_yuv_planar(accel)
|| !ac_imgconvert_init_yuv_packed(accel)
|| !ac_imgconvert_init_yuv_mixed(accel)
|| !ac_imgconvert_init_yuv_rgb(accel)
|| !ac_imgconvert_init_rgb_packed(accel)
) {
fprintf(stderr, "ac_imgconvert_init() failed");
return 0;
}
return 1;
}
int register_conversion(ImageFormat srcfmt, ImageFormat destfmt,
ConversionFunc function)
{
int i;
for (i = 0; i < n_conversions; i++) {
if (conversions[i].srcfmt==srcfmt && conversions[i].destfmt==destfmt) {
conversions[i].func = function;
return 1;
}
}
if (!(conversions = realloc(conversions,
(n_conversions+1) * sizeof(*conversions)))) {
fprintf(stderr, "register_conversion(): out of memory\n");
return 0;
}
conversions[n_conversions].srcfmt = srcfmt;
conversions[n_conversions].destfmt = destfmt;
conversions[n_conversions].func = function;
n_conversions++;
return 1;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,105 @@
/*
* imgconvert.h - defines for image format conversion routines
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#ifndef ACLIB_IMGCONVERT_H
#define ACLIB_IMGCONVERT_H
/*************************************************************************/
/* Image format defines */
typedef enum {
IMG_UNKNOWN = 0, /* Unknown/unset (dummy value, guaranteed to be 0) */
/* YUV formats */
IMG_YUV_BASE = 0x1000,
IMG_YUV420P, /* YUV planar, 1 U/V per 2x2 Y pixels */
IMG_YV12, /* YUV420P with U and V reversed */
IMG_YUV411P, /* YUV planar, 1 U/V per 4x1 Y pixels */
IMG_YUV422P, /* YUV planar, 1 U/V per 2x1 Y pixels */
IMG_YUV444P, /* YUV planar, 1 U/V per 1x1 Y pixels */
IMG_YUY2, /* YUV packed, 1 U/V per 2x1 Y pixels, Y:U:Y:V */
IMG_UYVY, /* YUV packed, 1 U/V per 2x1 Y pixels, U:Y:V:Y */
IMG_YVYU, /* YUV packed, 1 U/V per 2x1 Y pixels, Y:V:Y:U */
IMG_Y8, /* Y-only 8-bit data */
IMG_YUV_LAST,
/* RGB formats */
IMG_RGB_BASE = 0x2000,
IMG_RGB24, /* RGB packed, 8 bits per component, R:G:B */
IMG_BGR24, /* RGB packed, 8 bits per component, B:G:R */
IMG_RGBA32, /* RGB+alpha packed, 8 bits per component, R:G:B:A */
IMG_ABGR32, /* RGB+alpha packed, 8 bits per component, A:B:G:R */
IMG_ARGB32, /* RGB+alpha packed, 8 bits per component, A:R:G:B */
IMG_BGRA32, /* RGB+alpha packed, 8 bits per component, B:G:R:A */
IMG_GRAY8, /* Grayscale 8-bit data */
IMG_RGB_LAST,
} ImageFormat;
/* Alias */
#define IMG_NONE IMG_UNKNOWN
/* Default YUV and RGB formats */
#define IMG_YUV_DEFAULT IMG_YUV420P
#define IMG_RGB_DEFAULT IMG_RGB24
/* Is the given image format a YUV/RGB one? */
#define IS_YUV_FORMAT(fmt) ((fmt) > IMG_YUV_BASE && (fmt) < IMG_YUV_LAST)
#define IS_RGB_FORMAT(fmt) ((fmt) > IMG_RGB_BASE && (fmt) < IMG_RGB_LAST)
/* U/V plane size for YUV planar formats (Y plane size is always w*h) */
#define UV_PLANE_SIZE(fmt,w,h) \
((fmt)==IMG_YUV420P ? ((w)/2)*((h)/2) : \
(fmt)==IMG_YV12 ? ((w)/2)*((h)/2) : \
(fmt)==IMG_YUV411P ? ((w)/4)* (h) : \
(fmt)==IMG_YUV422P ? ((w)/2)* (h) : \
(fmt)==IMG_YUV444P ? (w) * (h) : 0)
/* Macro to initialize an array of planes from a buffer */
#define YUV_INIT_PLANES(planes,buffer,fmt,w,h) \
((planes)[0] = (buffer), \
(planes)[1] = (planes)[0] + (w)*(h), \
(planes)[2] = (planes)[1] + UV_PLANE_SIZE((fmt),(w),(h)))
#if 0
/* Structure describing an image. FIXME: not currently used--this should
* eventually replace the (planes,format) pairs passed to ac_imgconvert. */
typedef struct {
ImageFormat format; /* Format of image data */
int width, height; /* Size of image */
uint8_t *planes[4]; /* Data planes (use planes[0] for packed data) */
int stride[4]; /* Length of one row in each plane, incl. padding */
} Image;
#endif
/*************************************************************************/
/* Initialization routine. Returns 1 on success, 0 on failure. */
extern int ac_imgconvert_init(int accel);
/* Conversion routine. Returns 1 on success, 0 on failure. */
extern int ac_imgconvert(uint8_t **src, /* Array of source planes */
ImageFormat srcfmt, /* Source image format */
uint8_t **dest, /* Array of dest planes */
ImageFormat destfmt, /* Destination image format */
int width, /* Image width in pixels */
int height /* Image height in pixels */
);
/*************************************************************************/
#endif /* ACLIB_IMGCONVERT_H */
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,507 @@
/*
* memcpy.c - optimized memcpy() routines for aclib
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "ac_internal.h"
#include <string.h>
/* Use memmove because memcpy isn't guaranteed to be ascending */
static void *(*memcpy_ptr)(void *, const void *, size_t) = memmove;
/*************************************************************************/
/* External interface */
void *ac_memcpy(void *dest, const void *src, size_t size)
{
return (*memcpy_ptr)(dest, src, size);
}
/*************************************************************************/
/*************************************************************************/
/* Note the check for ARCH_X86 here: this is to prevent compilation of this
* code on x86_64, since all x86_64 processors support SSE2, and because
* this code is not set up to use the 64-bit registers for addressing on
* x86_64. */
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86)
/* MMX-optimized routine, intended for PMMX/PII processors.
* Nonstandard instructions used:
* (CPUID.MMX) MOVQ
*/
static void *memcpy_mmx(void *dest, const void *src, size_t bytes)
{
asm("\
PENTIUM_LINE_SIZE = 32 # PMMX/PII cache line size \n\
PENTIUM_CACHE_SIZE = 8192 # PMMX/PII total cache size \n\
# Use only half because writes may touch the cache too (PII) \n\
PENTIUM_CACHE_BLOCK = (PENTIUM_CACHE_SIZE/2 - PENTIUM_LINE_SIZE) \n\
\n\
push %%ebx # Save PIC register \n\
push %%edi # Save destination for return value \n\
cld # MOVS* should ascend \n\
\n\
mov $64, %%ebx # Constant \n\
\n\
cmp %%ebx, %%ecx \n\
jb mmx.memcpy_last # Just use movs if <64 bytes \n\
\n\
# First align destination address to a multiple of 8 bytes \n\
mov $8, %%eax # EAX <- (8-dest) & 7 \n\
sub %%edi, %%eax \n\
and $0b111, %%eax # ... which is the number of bytes to copy\n\
lea 0f, %%edx # Use a computed jump--faster than a loop\n\
sub %%eax, %%edx \n\
jmp *%%edx # Execute 0-7 MOVSB's \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
0: sub %%eax, %%ecx # Update count \n\
\n\
# Now copy data in blocks \n\
0: mov %%ecx, %%edx # EDX <- ECX >> 6 (cache lines to copy) \n\
shr $6, %%edx \n\
jz mmx.memcpy_last # <64 bytes left? Skip to end \n\
cmp $PENTIUM_CACHE_BLOCK/64, %%edx \n\
jb 1f # Limit size of block \n\
mov $PENTIUM_CACHE_BLOCK/64, %%edx \n\
1: mov %%edx, %%eax # EAX <- EDX << 6 (bytes to copy) \n\
shl $6, %%eax \n\
sub %%eax, %%ecx # Update remaining count \n\
add %%eax, %%esi # Point to end of region to be block-copied\n\
2: test %%eax, -32(%%esi) # Touch each cache line in reverse order\n\
test %%eax, -64(%%esi) \n\
sub %%ebx, %%esi # Update pointer \n\
sub %%ebx, %%eax # And loop \n\
jnz 2b \n\
# Note that ESI now points to the beginning of the block \n\
3: movq (%%esi), %%mm0 # Do the actual copy, 64 bytes at a time\n\
movq 8(%%esi), %%mm1 \n\
movq 16(%%esi), %%mm2 \n\
movq 24(%%esi), %%mm3 \n\
movq 32(%%esi), %%mm4 \n\
movq 40(%%esi), %%mm5 \n\
movq 48(%%esi), %%mm6 \n\
movq 56(%%esi), %%mm7 \n\
movq %%mm0, (%%edi) \n\
movq %%mm1, 8(%%edi) \n\
movq %%mm2, 16(%%edi) \n\
movq %%mm3, 24(%%edi) \n\
movq %%mm4, 32(%%edi) \n\
movq %%mm5, 40(%%edi) \n\
movq %%mm6, 48(%%edi) \n\
movq %%mm7, 56(%%edi) \n\
add %%ebx, %%esi # Update pointers \n\
add %%ebx, %%edi \n\
dec %%edx # And loop \n\
jnz 3b \n\
jmp 0b \n\
\n\
mmx.memcpy_last: \n\
# Copy last <64 bytes, using the computed jump trick \n\
mov %%ecx, %%eax # EAX <- ECX>>2 \n\
shr $2, %%eax \n\
lea 0f, %%edx \n\
sub %%eax, %%edx \n\
jmp *%%edx # Execute 0-15 MOVSD's \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
0: and $0b11, %%ecx # ECX <- ECX & 3 \n\
lea 0f, %%edx \n\
sub %%ecx, %%edx \n\
jmp *%%edx # Execute 0-3 MOVSB's \n\
movsb \n\
movsb \n\
movsb \n\
0: \n\
# All done! \n\
emms # Clean up MMX state \n\
pop %%edi # Restore destination (return value) \n\
pop %%ebx # Restore PIC register \n\
" : /* no outputs */
: "D" (dest), "S" (src), "c" (bytes)
: "%eax", "%edx"
);
return dest;
}
#endif /* HAVE_ASM_MMX && ARCH_X86 */
/*************************************************************************/
#if defined(HAVE_ASM_SSE) && defined(ARCH_X86)
/* SSE-optimized routine. Backported from AMD64 routine below.
* Nonstandard instructions used:
* (CPUID.CMOVE) CMOVA
* (CPUID.MMX) MOVQ
* (CPUID.SSE) MOVNTQ
*/
static void *memcpy_sse(void *dest, const void *src, size_t bytes)
{
asm("\
push %%ebx # Save PIC register \n\
push %%edi # Save destination for return value \n\
cld # MOVS* should ascend \n\
\n\
cmp $64, %%ecx # Skip block copy for small blocks \n\
jb sse.memcpy_last \n\
\n\
mov $128, %%ebx # Constant used later \n\
\n\
# First align destination address to a multiple of 8 bytes \n\
mov $8, %%eax # EAX <- (8-dest) & 7 \n\
sub %%edi, %%eax \n\
and $0b111, %%eax # ... which is the number of bytes to copy\n\
lea 0f, %%edx # Use a computed jump--faster than a loop\n\
sub %%eax, %%edx \n\
jmp *%%edx # Execute 0-7 MOVSB's \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
0: sub %%eax, %%ecx # Update count \n\
\n\
cmp $0x10040, %%ecx # Is this a large block? (0x10040 is an \n\
# arbitrary value where prefetching and \n\
# write combining seem to start becoming\n\
# faster) \n\
jae sse.memcpy_bp # Yup, use prefetch copy \n\
\n\
sse.memcpy_small: # Small block copy routine--no prefetch \n"
#if 0
" mov %%ecx, %%edx # EDX <- bytes to copy / 8 \n\
shr $3, %%edx \n\
mov %%edx, %%eax # Leave remainder in ECX for later \n\
shl $3, %%eax \n\
sub %%eax, %%ecx \n\
.align 16 \n\
0: movq (%%esi), %%mm0 # Copy 8 bytes of data \n\
movq %%mm0, (%%edi) \n\
add $8, %%esi # Update pointers \n\
add $8, %%edi \n\
dec %%edx # And loop \n\
jg 0b \n\
jmp sse.memcpy_last # Copy any remaining bytes \n\
\n\
nop # Align loops below \n"
#else
" # It appears that a simple rep movs is faster than cleverness \n\
# with movq... \n\
mov %%ecx, %%edx # EDX <- ECX & 3 \n\
and $0b11, %%edx \n\
shr $2, %%ecx # ECX <- ECX >> 2 \n\
rep movsl # Copy away! \n\
mov %%edx, %%ecx # Take care of last 0-3 bytes \n\
rep movsb \n\
jmp sse.memcpy_end # And exit \n\
\n\
.align 16 \n\
nop \n\
nop \n"
#endif
"sse.memcpy_bp: # Block prefetch copy routine \n\
0: mov %%ecx, %%edx # EDX: temp counter \n\
shr $6, %%edx # Divide by cache line size (64 bytes) \n\
cmp %%ebx, %%edx # ... and cap at 128 (8192 bytes) \n\
cmova %%ebx, %%edx \n\
shl $3, %%edx # EDX <- cache lines to copy * 8 \n\
mov %%edx, %%eax # EAX <- cache lines to preload * 8 \n\
# (also used as memory offset) \n\
1: test %%eax, -64(%%esi,%%eax,8) # Preload cache lines in pairs \n\
test %%eax, -128(%%esi,%%eax,8) # (going backwards) \n\
# (note that test %%eax,... seems to be faster than prefetchnta \n\
# on x86) \n\
sub $16, %%eax # And loop \n\
jg 1b \n\
\n\
# Then copy--forward, which seems to be faster than reverse for \n\
# certain alignments \n\
xor %%eax, %%eax \n\
2: movq (%%esi,%%eax,8), %%mm0 # Copy 8 bytes and loop \n\
movntq %%mm0, (%%edi,%%eax,8) \n\
inc %%eax \n\
cmp %%edx, %%eax \n\
jb 2b \n\
\n\
# Finally, update pointers and count, and loop \n\
shl $3, %%edx # EDX <- bytes copied \n\
add %%edx, %%esi \n\
add %%edx, %%edi \n\
sub %%edx, %%ecx \n\
cmp $64, %%ecx # At least one cache line left? \n\
jae 0b # Yup, loop \n\
\n\
sse.memcpy_last: \n\
# Copy last <64 bytes, using the computed jump trick \n\
mov %%ecx, %%eax # EAX <- ECX>>2 \n\
shr $2, %%eax \n\
lea 0f, %%edx \n\
sub %%eax, %%edx \n\
jmp *%%edx # Execute 0-15 MOVSD's \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
movsd \n\
0: and $0b11, %%ecx # ECX <- ECX & 3 \n\
lea sse.memcpy_end, %%edx \n\
sub %%ecx, %%edx \n\
jmp *%%edx # Execute 0-3 MOVSB's \n\
movsb \n\
movsb \n\
movsb \n\
\n\
sse.memcpy_end: \n\
# All done! \n\
emms # Clean up after MMX instructions \n\
sfence # Flush the write buffer \n\
pop %%edi # Restore destination (return value) \n\
pop %%ebx # Restore PIC register \n\
" : /* no outputs */
: "D" (dest), "S" (src), "c" (bytes)
: "%eax", "%edx"
);
return dest;
}
#endif /* HAVE_ASM_SSE && ARCH_X86 */
/*************************************************************************/
#if defined(HAVE_ASM_SSE2) && defined(ARCH_X86_64)
/* AMD64-optimized routine, using SSE2. Derived from AMD64 optimization
* guide section 5.13: Appropriate Memory Copying Routines.
* Nonstandard instructions used:
* (CPUID.CMOVE) CMOVA
* (CPUID.SSE2) MOVDQA, MOVDQU, MOVNTDQ
*
* Note that this routine will also run more or less as-is (modulo register
* names and label(%%rip) references) on x86 CPUs, but tests have shown the
* SSE1 version above to be faster.
*/
/* The block copying code--macroized because we use two versions of it
* depending on whether the source is 16-byte-aligned or not. Pass either
* movdqa or movdqu (unquoted) for the parameter. */
#define AMD64_BLOCK_MEMCPY(movdq) \
" # First prefetch (note that if we end on an odd number of cache \n\
# lines, we skip prefetching the last one--faster that way than \n\
# prefetching line by line or treating it as a special case) \n\
0: mov %%ecx, %%edx # EDX: temp counter (always <32 bits) \n\
shr $6, %%edx # Divide by cache line size (64 bytes) \n\
cmp %%ebx, %%edx # ... and cap at 128 (8192 bytes) \n\
cmova %%ebx, %%edx \n\
shl $3, %%edx # EDX <- cache lines to copy * 8 \n\
mov %%edx, %%eax # EAX <- cache lines to preload * 8 \n\
# (also used as memory offset) \n\
1: prefetchnta -64(%%rsi,%%rax,8) # Preload cache lines in pairs \n\
prefetchnta -128(%%rsi,%%rax,8) # (going backwards) \n\
sub $16, %%eax # And loop \n\
jg 1b \n\
\n\
# Then copy--forward, which seems to be faster than reverse for \n\
# certain alignments \n\
xor %%eax, %%eax \n\
2: " #movdq " (%%rsi,%%rax,8), %%xmm0 # Copy 16 bytes and loop \n\
movntdq %%xmm0, (%%rdi,%%rax,8) \n\
add $2, %%eax \n\
cmp %%edx, %%eax \n\
jb 2b \n\
\n\
# Finally, update pointers and count, and loop \n\
shl $3, %%edx # EDX <- bytes copied \n\
add %%rdx, %%rsi \n\
add %%rdx, %%rdi \n\
sub %%rdx, %%rcx \n\
cmp $64, %%rcx # At least one cache line left? \n\
jae 0b # Yup, loop \n"
static void *memcpy_amd64(void *dest, const void *src, size_t bytes)
{
asm("\
push %%rdi # Save destination for return value \n\
cld # MOVS* should ascend \n\
\n\
cmp $64, %%rcx # Skip block copy for small blocks \n\
jb amd64.memcpy_last \n\
\n\
mov $128, %%ebx # Constant used later \n\
\n\
# First align destination address to a multiple of 16 bytes \n\
mov $8, %%eax # EAX <- (8-dest) & 7 \n\
sub %%edi, %%eax # (we don't care about the top 32 bits) \n\
and $0b111, %%eax # ... which is the number of bytes to copy\n\
lea 0f(%%rip), %%rdx # Use a computed jump--faster than a loop\n\
sub %%rax, %%rdx \n\
jmp *%%rdx # Execute 0-7 MOVSB's \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
0: sub %%rax, %%rcx # Update count \n\
test $0b1000, %%edi # Is destination not 16-byte aligned? \n\
je 1f \n\
movsq # Then move 8 bytes to align it \n\
sub $8, %%rcx \n\
\n\
1: cmp $0x38000, %%rcx # Is this a large block? (0x38000 is an \n\
# arbitrary value where prefetching and \n\
# write combining seem to start becoming\n\
# faster) \n\
jb amd64.memcpy_small # Nope, use small copy (no prefetch/WC) \n\
test $0b1111, %%esi # Is source also 16-byte aligned? \n\
# (use ESI to save a REX prefix byte) \n\
jnz amd64.memcpy_normal_bp # Nope, use slow copy \n\
jmp amd64.memcpy_fast_bp # Yup, use fast copy \n\
\n\
amd64.memcpy_small: # Small block copy routine--no prefetch \n\
mov %%ecx, %%edx # EDX <- bytes to copy / 16 \n\
shr $4, %%edx # (count known to fit in 32 bits) \n\
mov %%edx, %%eax # Leave remainder in ECX for later \n\
shl $4, %%eax \n\
sub %%eax, %%ecx \n\
.align 16 \n\
0: movdqu (%%rsi), %%xmm0 # Copy 16 bytes of data \n\
movdqa %%xmm0, (%%rdi) \n\
add $16, %%rsi # Update pointers \n\
add $16, %%rdi \n\
dec %%edx # And loop \n\
jnz 0b \n\
jmp amd64.memcpy_last # Copy any remaining bytes \n\
\n\
.align 16 \n\
nop \n\
nop \n\
amd64.memcpy_fast_bp: # Fast block prefetch loop \n"
AMD64_BLOCK_MEMCPY(movdqa)
" jmp amd64.memcpy_last # Copy any remaining bytes \n\
\n\
.align 16 \n\
nop \n\
nop \n\
amd64.memcpy_normal_bp: # Normal (unaligned) block prefetch loop\n"
AMD64_BLOCK_MEMCPY(movdqu)
" \n\
amd64.memcpy_last: \n\
# Copy last <64 bytes, using the computed jump trick \n\
mov %%ecx, %%eax # EAX <- ECX>>3 \n\
shr $3, %%eax \n\
lea 0f(%%rip), %%rdx \n\
add %%eax, %%eax # Watch out, MOVSQ is 2 bytes! \n\
sub %%rax, %%rdx \n\
jmp *%%rdx # Execute 0-7 MOVSQ's \n\
movsq \n\
movsq \n\
movsq \n\
movsq \n\
movsq \n\
movsq \n\
movsq \n\
0: and $0b111, %%ecx # ECX <- ECX & 7 \n\
lea 0f(%%rip), %%rdx \n\
sub %%rcx, %%rdx \n\
jmp *%%rdx # Execute 0-7 MOVSB's \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
movsb \n\
0: \n\
# All done! \n\
emms # Clean up after MMX instructions \n\
sfence # Flush the write buffer \n\
pop %%rdi # Restore destination (return value) \n\
" : /* no outputs */
: "D" (dest), "S" (src), "c" (bytes)
: "%rax", "%rbx", "%rdx"
);
return dest;
}
#endif /* HAVE_ASM_SSE2 && ARCH_X86_64 */
/*************************************************************************/
/* Initialization routine. */
int ac_memcpy_init(int accel)
{
memcpy_ptr = memmove;
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86)
if (HAS_ACCEL(accel, AC_MMX))
memcpy_ptr = memcpy_mmx;
#endif
#if defined(HAVE_ASM_SSE) && defined(ARCH_X86)
if (HAS_ACCEL(accel, AC_CMOVE|AC_SSE))
memcpy_ptr = memcpy_sse;
#endif
#if defined(HAVE_ASM_SSE2) && defined(ARCH_X86_64)
if (HAS_ACCEL(accel, AC_CMOVE|AC_SSE2))
memcpy_ptr = memcpy_amd64;
#endif
return 1;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,280 @@
/*
* rescale.c -- take the weighted average of two sets of byte data
* Written by Andrew Church <achurch@achurch.org>
*
* This file is part of transcode, a video stream processing tool.
* transcode is free software, distributable under the terms of the GNU
* General Public License (version 2 or later). See the file COPYING
* for details.
*/
#include "ac.h"
#include "ac_internal.h"
static void rescale(const uint8_t *, const uint8_t *, uint8_t *, int,
uint32_t, uint32_t);
static void (*rescale_ptr)(const uint8_t *, const uint8_t *, uint8_t *, int,
uint32_t, uint32_t) = rescale;
/*************************************************************************/
/* External interface */
void ac_rescale(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes, uint32_t weight1, uint32_t weight2)
{
if (weight1 >= 0x10000)
ac_memcpy(dest, src1, bytes);
else if (weight2 >= 0x10000)
ac_memcpy(dest, src2, bytes);
else
(*rescale_ptr)(src1, src2, dest, bytes, weight1, weight2);
}
/*************************************************************************/
/*************************************************************************/
/* Vanilla C version */
static void rescale(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes,
uint32_t weight1, uint32_t weight2)
{
int i;
for (i = 0; i < bytes; i++)
dest[i] = (src1[i]*weight1 + src2[i]*weight2 + 32768) >> 16;
}
/*************************************************************************/
/* MMX version */
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86) /* i.e. not x86_64 */
static void rescale_mmx(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes,
uint32_t weight1, uint32_t weight2)
{
if (bytes >= 8) {
/* First store weights in MM4/MM5 to relieve register pressure;
* save time by making 2 copies ahead of time in the general
* registers. Note that we divide by 2 for MMX due to the lack
* of an unsigned SIMD multiply instruction (PMULHUW). */
int half1 = weight1 / 2;
int half2 = weight2 / 2;
half2 += weight1 & weight2 & 1; // pick up the lost bit here
asm("movd %%eax, %%mm4; movd %%edx, %%mm5"
: : "a" (half1<<16|half1), "d" (half2<<16|half2));
asm("\
movq %%mm4, %%mm6 # MM6: 00 00 W1 W1 \n\
psllq $32, %%mm4 # MM4: W1 W1 00 00 \n\
por %%mm6, %%mm4 # MM4: W1 W1 W1 W1 \n\
movq %%mm5, %%mm7 # MM7: 00 00 W2 W2 \n\
psllq $32, %%mm5 # MM5: W2 W2 00 00 \n\
por %%mm7, %%mm5 # MM5: W2 W2 W2 W2 \n\
pxor %%mm7, %%mm7 # MM7: 00 00 00 00 \n\
pxor %%mm6, %%mm6 # Put 0x0020*4 in MM6 (rounding)\n\
pcmpeqw %%mm3, %%mm3 \n\
psubw %%mm3, %%mm6 \n\
psllw $5, %%mm6 \n\
0: \n\
movq -8(%%esi,%%ecx), %%mm0 \n\
movq %%mm0, %%mm1 \n\
punpcklbw %%mm7, %%mm0 \n\
psllw $7, %%mm0 # 9.7 fixed point \n\
pmulhw %%mm4, %%mm0 # Multiply to get 10.6 fixed \n\
punpckhbw %%mm7, %%mm1 \n\
psllw $7, %%mm1 \n\
pmulhw %%mm4, %%mm1 \n\
movq -8(%%edx,%%ecx), %%mm2 \n\
movq %%mm2, %%mm3 \n\
punpcklbw %%mm7, %%mm2 \n\
psllw $7, %%mm2 \n\
pmulhw %%mm5, %%mm2 \n\
punpckhbw %%mm7, %%mm3 \n\
psllw $7, %%mm3 \n\
pmulhw %%mm5, %%mm3 \n\
paddw %%mm2, %%mm0 \n\
paddw %%mm6, %%mm0 \n\
psrlw $6, %%mm0 \n\
paddw %%mm3, %%mm1 \n\
paddw %%mm6, %%mm1 \n\
psrlw $6, %%mm1 \n\
packuswb %%mm1, %%mm0 \n\
movq %%mm0, -8(%%edi,%%ecx) \n\
subl $8, %%ecx \n\
jnz 0b \n\
emms"
: /* no outputs */
: "S" (src1), "d" (src2), "D" (dest), "c" (bytes & ~7));
}
if (UNLIKELY(bytes & 7)) {
rescale(src1+(bytes & ~7), src2+(bytes & ~7), dest+(bytes & ~7),
bytes & 7, weight1, weight2);
}
}
#endif /* HAVE_ASM_MMX && ARCH_X86 */
/*************************************************************************/
/* MMXEXT version (also for SSE) */
#if (defined(HAVE_ASM_MMXEXT) || defined(HAVE_ASM_SSE)) && defined(ARCH_X86)
static void rescale_mmxext(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes,
uint32_t weight1, uint32_t weight2)
{
if (bytes >= 8) {
asm("movd %%eax, %%mm4; movd %%edx, %%mm5"
: : "a" (weight1), "d" (weight2));
asm("\
pshufw $0, %%mm4, %%mm4 # MM4: W1 W1 W1 W1 \n\
pshufw $0, %%mm5, %%mm5 # MM5: W2 W2 W2 W2 \n\
pxor %%mm6, %%mm6 # Put 0x0080*4 in MM6 (rounding)\n\
pcmpeqw %%mm7, %%mm7 \n\
psubw %%mm7, %%mm6 \n\
psllw $7, %%mm6 \n\
0: \n\
movq -8(%%esi,%%ecx), %%mm7 \n\
pxor %%mm0, %%mm0 # Load data into high bytes \n\
punpcklbw %%mm7, %%mm0 # (gives 8.8 fixed point) \n\
pmulhuw %%mm4, %%mm0 # Result: 0000..FF00 \n\
pxor %%mm1, %%mm1 \n\
punpckhbw %%mm7, %%mm1 \n\
pmulhuw %%mm4, %%mm1 \n\
movq -8(%%edx,%%ecx), %%mm7 \n\
pxor %%mm2, %%mm2 \n\
punpcklbw %%mm7, %%mm2 \n\
pmulhuw %%mm5, %%mm2 \n\
pxor %%mm3, %%mm3 \n\
punpckhbw %%mm7, %%mm3 \n\
pmulhuw %%mm5, %%mm3 \n\
paddw %%mm2, %%mm0 \n\
paddw %%mm6, %%mm0 \n\
psrlw $8, %%mm0 # Shift back down to 00..FF \n\
paddw %%mm3, %%mm1 \n\
paddw %%mm6, %%mm1 \n\
psrlw $8, %%mm1 \n\
packuswb %%mm1, %%mm0 \n\
movq %%mm0, -8(%%edi,%%ecx) \n\
subl $8, %%ecx \n\
jnz 0b \n\
emms"
: /* no outputs */
: "S" (src1), "d" (src2), "D" (dest), "c" (bytes & ~7));
}
if (UNLIKELY(bytes & 7)) {
rescale(src1+(bytes & ~7), src2+(bytes & ~7), dest+(bytes & ~7),
bytes & 7, weight1, weight2);
}
}
#endif /* (HAVE_ASM_MMXEXT || HAVE_ASM_SSE) && ARCH_X86 */
/*************************************************************************/
/* SSE2 version */
#if defined(HAVE_ASM_SSE2)
#ifdef ARCH_X86_64
# define ECX "%%rcx"
# define EDX "%%rdx"
# define ESI "%%rsi"
# define EDI "%%rdi"
#else
# define ECX "%%ecx"
# define EDX "%%edx"
# define ESI "%%esi"
# define EDI "%%edi"
#endif
static void rescale_sse2(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int bytes,
uint32_t weight1, uint32_t weight2)
{
if (bytes >= 16) {
asm("movd %%eax, %%xmm4; movd %%edx, %%xmm5"
: : "a" (weight1<<16|weight1), "d" (weight2<<16|weight2));
asm("\
pshufd $0, %%xmm4, %%xmm4 # XMM4: W1 W1 W1 W1 W1 W1 W1 W1 \n\
pshufd $0, %%xmm5, %%xmm5 # XMM5: W2 W2 W2 W2 W2 W2 W2 W2 \n\
pxor %%xmm6, %%xmm6 # Put 0x0080*4 in XMM6 (rounding)\n\
pcmpeqw %%xmm7, %%xmm7 \n\
psubw %%xmm7, %%xmm6 \n\
psllw $7, %%xmm6 \n\
0: \n\
movdqu -16("ESI","ECX"), %%xmm7 \n\
pxor %%xmm0, %%xmm0 \n\
punpcklbw %%xmm7, %%xmm0 \n\
pmulhuw %%xmm4, %%xmm0 \n\
pxor %%xmm1, %%xmm1 \n\
punpckhbw %%xmm7, %%xmm1 \n\
pmulhuw %%xmm4, %%xmm1 \n\
movdqu -16("EDX","ECX"), %%xmm7 \n\
pxor %%xmm2, %%xmm2 \n\
punpcklbw %%xmm7, %%xmm2 \n\
pmulhuw %%xmm5, %%xmm2 \n\
pxor %%xmm3, %%xmm3 \n\
punpckhbw %%xmm7, %%xmm3 \n\
pmulhuw %%xmm5, %%xmm3 \n\
paddw %%xmm2, %%xmm0 \n\
paddw %%xmm6, %%xmm0 \n\
psrlw $8, %%xmm0 \n\
paddw %%xmm3, %%xmm1 \n\
paddw %%xmm6, %%xmm1 \n\
psrlw $8, %%xmm1 \n\
packuswb %%xmm1, %%xmm0 \n\
movdqu %%xmm0, -16("EDI","ECX") \n\
subl $16, %%ecx \n\
jnz 0b \n\
emms"
: /* no outputs */
: "S" (src1), "d" (src2), "D" (dest), "c" (bytes & ~15));
}
if (UNLIKELY(bytes & 15)) {
rescale(src1+(bytes & ~15), src2+(bytes & ~15), dest+(bytes & ~15),
bytes & 15, weight1, weight2);
}
}
#endif /* HAVE_ASM_SSE2 */
/*************************************************************************/
/*************************************************************************/
/* Initialization routine. */
int ac_rescale_init(int accel)
{
rescale_ptr = rescale;
#if defined(HAVE_ASM_MMX) && defined(ARCH_X86)
if (HAS_ACCEL(accel, AC_MMX))
rescale_ptr = rescale_mmx;
#endif
#if (defined(HAVE_ASM_MMXEXT) || defined(HAVE_ASM_SSE)) && defined(ARCH_X86)
if (HAS_ACCEL(accel, AC_MMXEXT) || HAS_ACCEL(accel, AC_SSE))
rescale_ptr = rescale_mmxext;
#endif
#if defined(HAVE_ASM_SSE2)
if (HAS_ACCEL(accel, AC_SSE2))
rescale_ptr = rescale_sse2;
#endif
return 1;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/

View File

@@ -0,0 +1,48 @@
#!/usr/bin/perl -w
# Calculate conversion matrices for RGB<->YUV given Kb and Kr
die "Usage: $0 Kb Kr [scale]\n" if @ARGV < 2;
$scale = $ARGV[2] || 1;
$Kb = $ARGV[0];
$Kr = $ARGV[1];
$Kg = 1 - $Kr - $Kb;
$a11 = $Kr;
$a12 = $Kg;
$a13 = $Kb;
$a21 = -$Kr/(1-$Kb)/2;
$a22 = -$Kg/(1-$Kb)/2;
$a23 = 1/2;
$a31 = 1/2;
$a32 = -$Kg/(1-$Kr)/2;
$a33 = -$Kb/(1-$Kr)/2;
print "Y [R] = ".($a11*$scale)."\n";
print "Y [G] = ".($a12*$scale)."\n";
print "Y [B] = ".($a13*$scale)."\n";
print "Cb[R] = ".($a21*$scale)."\n";
print "Cb[G] = ".($a22*$scale)."\n";
print "Cb[B] = ".($a23*$scale)."\n";
print "Cr[R] = ".($a31*$scale)."\n";
print "Cr[G] = ".($a32*$scale)."\n";
print "Cr[B] = ".($a33*$scale)."\n";
$det = $a11*$a22*$a33 - $a11*$a23*$a32
+ $a12*$a23*$a31 - $a12*$a21*$a33
+ $a13*$a21*$a32 - $a13*$a22*$a31;
$b11 = (1/$det)*($a22*$a33-$a23*$a32);
$b12 = (1/$det)*($a13*$a32-$a12*$a33);
$b13 = (1/$det)*($a12*$a23-$a13*$a22);
$b21 = (1/$det)*($a23*$a31-$a21*$a33);
$b22 = (1/$det)*($a11*$a33-$a13*$a31);
$b23 = (1/$det)*($a13*$a21-$a11*$a23);
$b31 = (1/$det)*($a21*$a32-$a22*$a31);
$b32 = (1/$det)*($a12*$a31-$a11*$a32);
$b33 = (1/$det)*($a11*$a22-$a12*$a21);
map {$_ = 0 if abs($_) < 1e-10} ($b11,$b12,$b13,$b21,$b22,$b23,$b31,$b32,$b33);
print "R[Y ] = ".($b11*$scale)."\n";
print "R[Cb] = ".($b12*$scale)."\n";
print "R[Cr] = ".($b13*$scale)."\n";
print "G[Y ] = ".($b21*$scale)."\n";
print "G[Cb] = ".($b22*$scale)."\n";
print "G[Cr] = ".($b23*$scale)."\n";
print "B[Y ] = ".($b31*$scale)."\n";
print "B[Cb] = ".($b32*$scale)."\n";
print "B[Cr] = ".($b33*$scale)."\n";

View File

@@ -0,0 +1,5 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
autoreconf -v -f -i

View File

@@ -0,0 +1,4 @@
bio2jack - a library for porting blocked io(OSS/ALSA) apps to jack
---------------------------------------------------------
Chris Morgan <cmorgan@alum.wpi.edu>

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,6 @@
Installing bio2jack
----------------------
This library is intended only for static linking as it is small and there
is no need to require yet another library for a user to install. So
please, statically link to this library.

View File

@@ -0,0 +1,4 @@
noinst_LTLIBRARIES = libbio2jack4vj.la
INCLUDES=-I$(top_srcdir)/libvjmem -I$(top_srcdir)/libvjmsg
LIBS = @LIBS@ @PTHREAD_LIBS@ @JACK_LIBS@
libbio2jack4vj_la_SOURCES = bio2jack.c bio2jack.h

View File

@@ -0,0 +1,10 @@
bio2jack - NEWS
--------
9/12/2004 - Check out ChangeLog for news ;-)
10/26/2003 - Updated to the new jack api, fixed a bunch of bugs
Removed all blocking functions, blocking is BAD as it could potentially
hold off the callback function.
1/13/2003 - Continuing to refine the api by working on the xine plugin.
Fixed a few bugs in the code. Uploaded newer packages to
sourceforge.
12/31/2002 - Sourceforge project is setup.

View File

@@ -0,0 +1,30 @@
bio2jack
-----------
To Build:
----------
run ./autogen.sh
run ./configure
run make
enjoy ;-)
Bio(blocked i/o) 2 jack.
A library for enabling easy porting of blocked io(OSS/ALSA) applications to
the jack sound server(http://jackit.sourceforge.net). This library allows the
person porting the code to simply replace the calls into OSS/ALSA with
calls into interface functions of this library. The library buffers a
small amount of audio data and takes care of the rest of the jack
implementation including the linked list of audio data buffers and the jack
callback.
Interface functions:
TODO: once these become stable copy and paste from the header file
Currently these drivers use the bio2jack library:
---------------------------------------------------
xmms-jack: Written in conjunction with this library
xine:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2003-2004 Chris Morgan <cmorgan@alum.wpi.edu>
*
* 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
*/
#ifndef _H_JACK_OUT_H
#define _H_JACK_OUT_H
#include <jack/jack.h>
#ifdef __cplusplus
extern "C" {
#else
#define bool long
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define ERR_SUCCESS 0
#define ERR_OPENING_JACK 1
#define ERR_RATE_MISMATCH 2
#define ERR_BYTES_PER_OUTPUT_FRAME_INVALID 3
#define ERR_BYTES_PER_INPUT_FRAME_INVALID 4
#define ERR_TOO_MANY_OUTPUT_CHANNELS 5
#define ERR_PORT_NAME_OUTPUT_CHANNEL_MISMATCH 6
#define ERR_PORT_NOT_FOUND 7
#define ERR_TOO_MANY_INPUT_CHANNELS 8
#define ERR_PORT_NAME_INPUT_CHANNEL_MISMATCH 9
enum status_enum { PLAYING, PAUSED, STOPPED, CLOSED, RESET };
enum pos_enum { BYTES, MILLISECONDS };
#define PLAYED 1 /* played out of the speakers(estimated value but should be close */
#define WRITTEN_TO_JACK 2 /* amount written out to jack */
#define WRITTEN 3 /* amount written to the bio2jack device */
/**********************/
/* External functions */
void JACK_Init(void); /* call this before any other bio2jack calls */
void JACK_DoSampleRateConversion(bool value); /* whether the next device that's Open()d should do
sample rate conversion if necessary */
void JACK_SetSampleRateConversionFunction(int converter); /* which SRC converter function should be used
for the next Open()d device */
int JACK_Open(int *deviceID, unsigned int bits_per_sample, unsigned long *rate, int channels); /* Note: defaults to 0 input channels
if you need input (record) use OpenEx
instead */
int JACK_OpenEx(int *deviceID, unsigned int bits_per_channel,
unsigned long *rate,
unsigned int input_channels, unsigned int output_channels,
const char **jack_port_name, unsigned int jack_port_name_count,
unsigned long jack_port_flags);
int JACK_Close(int deviceID); /* return 0 for success */
void JACK_Reset(int deviceID); /* free all buffered data and reset several values in the device */
long JACK_Write(int deviceID, unsigned char *data, unsigned long bytes); /* returns the number of bytes written */
long JACK_Read(int deviceID, unsigned char *data, unsigned long bytes); /* returns the number of bytes read */
/* state setting values */
/* set/get the written/played/buffered value based on a byte or millisecond input value */
long JACK_GetPosition(int deviceID, enum pos_enum position, int type);
void JACK_SetPosition(int deviceID, enum pos_enum position, long value);
long JACK_GetJackLatency(int deviceID); /* deprectated, you probably want JACK_GetJackOutputLatency */
long JACK_GetJackOutputLatency(int deviceID); /* return the output latency in frames */
long JACK_GetJackInputLatency(int deviceID); /* return the input latency in frames */
int JACK_SetState(int deviceID, enum status_enum state); /* playing, paused, stopped */
enum status_enum JACK_GetState(int deviceID);
long JACK_GetMaxOutputBufferedBytes(int deviceID);
long JACK_GetMaxInputBufferedBytes(int deviceID);
/* bytes that jack requests during each callback */
unsigned long JACK_GetJackBufferedBytes(int deviceID);
/* Properties of the jack driver */
/* linear means 0 volume is silence, 100 is full volume */
/* dbAttenuation means 0 volume is 0dB attenuation */
/* Bio2jack defaults to linear */
/* Note: volume controls only effect output channels for now */
enum JACK_VOLUME_TYPE { linear, dbAttenuation };
enum JACK_VOLUME_TYPE JACK_SetVolumeEffectType(int deviceID,
enum JACK_VOLUME_TYPE type);
int JACK_SetAllVolume(int deviceID, unsigned int volume); /* returns 0 on success */
int JACK_SetVolumeForChannel(int deviceID, unsigned int channel, unsigned int volume);
void JACK_GetVolumeForChannel(int deviceID, unsigned int channel, unsigned int *volume);
unsigned long JACK_GetOutputBytesPerSecond(int deviceID); /* bytes_per_output_frame * sample_rate */
unsigned long JACK_GetInputBytesPerSecond(int deviceID); /* bytes_per_input_frame * sample_rate */
unsigned long JACK_GetBytesStored(int deviceID); /* bytes currently buffered in the output buffer */
unsigned long JACK_GetBytesFreeSpace(int deviceID); /* bytes of free space in the output buffer */
unsigned long JACK_GetBytesUsedSpace(int deviceID); /* bytes of space used in the input buffer */
unsigned long JACK_GetBytesPerOutputFrame(int deviceID);
unsigned long JACK_GetBytesPerInputFrame(int deviceID);
/* Note: these will probably be removed in a future release */
int JACK_GetNumInputChannels(int deviceID);
int JACK_GetNumOutputChannels(int deviceID);
long JACK_GetSampleRate(int deviceID); /* samples per second */
void JACK_SetClientName(char *name); /* sets the name that bio2jack will use when
creating a new jack client. name_%pid%_%deviceID%%counter%
will be used
NOTE: this defaults to name = bio2jack
NOTE: we limit the size of the client name to
jack_client_name_size() */
enum JACK_PORT_CONNECTION_MODE
{
CONNECT_ALL, /* connect to all avaliable ports */
CONNECT_OUTPUT, /* connect only to the ports we need for output */
CONNECT_NONE /* don't connect to any ports */
};
/* set the mode for port connections */
/* defaults to CONNECT_ALL */
void JACK_SetPortConnectionMode(enum JACK_PORT_CONNECTION_MODE mode);
long JACK_OutputStatus(int deviceID,long int *sec, long int *usec);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef JACK_OUT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,336 @@
#!/bin/sh
if test x"$CC" = x; then
CC=gcc
fi
if test $# -ne 1; then
echo "Please give the arch (ppc or x86) as an argument!" 1>&2
exit 1
fi
if test `uname -s` = Darwin; then
IsDarwin=yes
else
IsDarwin=no
fi
target=$1
cc_version=`$CC -dumpversion`
_cc_major=`echo $cc_version | cut -d'.' -f1`
_cc_minor=`echo $cc_version | cut -d'.' -f2`
if test $_cc_major -ge 4; then
_opt_mcpu="-mtune"
else
_opt_mcpu="-mcpu"
fi
do_cc()
{
$CC -o conftest conftest.c $@ >/dev/null 2>&1
}
extcheck()
{
cat > conftest.c <<EOF
#include <signal.h>
void catch() { exit(1); }
int main(void){
signal(SIGILL, catch);
__asm__ __volatile__ ("$1":::"memory");
exit(0);
}
EOF
do_cc
if test -x ./conftest; then
./conftest
if test $? -ne 0; then
return 1
fi
return 0
else
return 1
fi
}
do_x86()
{
CFLAGS=-O
if test $IsDarwin = yes; then
CFLAGS="$CFLAGS -fno-pic -Wl,-read_only_relocs -Wl,suppress"
fi
if test -r /proc/cpuinfo; then
_cpuinfo="cat /proc/cpuinfo"
else
$CC $CFLAGS -o cpuinfo utils/cpuinfo.c
_cpuinfo="./cpuinfo"
fi
# Cpu determination logic adapted from the MPlayer configure script.
pname=`$_cpuinfo | grep 'model name' | cut -d ':' -f 2 | head -n 1`
pvendor=`$_cpuinfo | grep 'vendor_id' | cut -d':' -f2 | cut -d' ' -f2 | head -n 1`
pfamily=`$_cpuinfo | grep 'cpu family' | cut -d':' -f2 | cut -d' ' -f2 | head -n 1`
pmodel=`$_cpuinfo | grep -v 'model name' | grep 'model' | cut -d':' -f2 | cut -d' ' -f2 | head -n 1`
pstep=`$_cpuinfo | grep 'stepping' | cut -d':' -f2 | cut -d' ' -f2 | head -n 1`
pparam=`$_cpuinfo | grep 'features' | cut -d':' -f2 | head -n 1`
if test -z "$pparam" ; then
pparam=`$_cpuinfo | grep 'flags' | cut -d ':' -f 2 | head -n 1`
fi
_mmx=no
_3dnow=no
_3dnowex=no
_mmx2=no
_sse=no
_sse2=no
_mtrr=no
for i in $pparam ; do
case "$i" in
3dnow) _3dnow=yes ;;
3dnowext) _3dnow=yes _3dnowex=yes ;;
mmx) _mmx=yes ;;
mmxext) _mmx2=yes ;;
mtrr|k6_mtrr|cyrix_arr) _mtrr=yes ;;
xmm|sse|kni) _sse=yes _mmx2=yes ;;
sse2) _sse2=yes ;;
esac
done
case "$pvendor" in
AuthenticAMD)
case "$pfamily" in
3)proc=i386
;;
4) proc=i486
;;
5) iproc=586
# models are: K5/SSA5 K5 K5 K5 ? ? K6 K6 K6-2 K6-3
# K6 model 13 are the K6-2+ and K6-III+
if test "$pmodel" -eq 9 -o "$pmodel" -eq 13; then
proc=k6-3
elif test "$pmodel" -ge 8; then
proc=k6-2
elif test "$pmodel" -ge 6; then
proc=k6
else
proc=i586
fi
;;
6) iproc=686
if test "$pmodel" -ge 7; then
proc=athlon-4
elif test "$pmodel" -ge 6; then
if test "$_sse" = yes && test "$pstep" -ge 2; then
proc=athlon-xp
else
proc=athlon-4
fi
elif test "$pmodel" -ge 4; then
proc=athlon-tbird
else
proc=athlon
fi
;;
15)
# Despite what the gcc into says 'athlon64' is not accepted as
# synonym for 'k8'
proc=k8
;;
*) proc=athlon-xp
;;
esac
;;
GenuineIntel)
case "$pfamily" in
3) proc=i386
;;
4) proc=i486
;;
5) iproc=586
if test "$pmodel" -eq 4 || test "$pmodel" -eq 8; then
proc=pentium-mmx # 4 is desktop, 8 is mobile
else
proc=i586
fi
;;
6) iproc=686
if test "$pmodel" -ge 15; then
proc=nocona
elif test "$pmodel" -ge 13; then
proc=pentium-m
elif test "$pmodel" -ge 7; then
proc=pentium3
elif test "$pmodel" -ge 3; then
proc=pentium2
else
proc=i686
fi
;;
15) proc=pentium4
;;
*) proc=pentium4
;;
esac
;;
unknown)
case "$pfamily" in
3) proc=i386
;;
4) proc=i486
;;
*) proc=i586
;;
esac
;;
*)
proc=i586
;;
esac
# check that gcc supports our CPU, if not, fall back to earlier ones
cat > conftest.c << EOF
int main(void) { return 0; }
EOF
if test "$proc" = "athlon64" ; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=athlon-xp
fi
if test "$proc" = "athlon-xp" || test "$proc" = "athlon-4" || test "$proc" = "athlon-tbird"; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=athlon
fi
if test "$proc" = "k6-3" || test "$proc" = "k6-2"; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=k6
fi
if test "$proc" = "k6"; then
do_cc -march=$proc $_opt_mcpu=$proc
if test $? -ne 0; then
if do_cc -march=i586 $_opt_mcpu=i686; then
proc=i586-i686
else
proc=i586
fi
fi
fi
if test "$proc" = "pentium4" || test "$proc" = "pentium3" || test "$proc" = "pentium2" || test "$proc" = "athlon"; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=i686
fi
if test "$proc" = "i686" || test "$proc" = "pentium-mmx"; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=i586
fi
if test "$proc" = "i586" ; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=i486
fi
if test "$proc" = "i486" ; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=i386
fi
if test "$proc" = "i386" ; then
do_cc -march=$proc $_opt_mcpu=$proc || proc=error
fi
if test "$proc" = "error" ; then
echo "Your $_cc does not even support \"i386\" for '-march' and $_opt_mcpu."
_mcpu=""
_march=""
elif test "$proc" = "i586-i686"; then
_march="-march=i586"
_mcpu="$_opt_mcpu=i686"
else
_march="-march=$proc"
_mcpu="$_opt_mcpu=$proc"
fi
if test $_cc_major -ge 3; then
extcheck "xorps %%xmm0, %%xmm0" || _gcc3_ext="$_gcc3_ext -mno-sse"
extcheck "xorpd %%xmm0, %%xmm0" || _gcc3_ext="$_gcc3_ext -mno-sse2"
if test x"$_gcc3_ext" != "x"; then
# if we had to disable sse/sse2 because the active kernel does not
# support this instruction set extension, we also have to tell
# gcc3 to not generate sse/sse2 instructions for normal C code
cat > conftest.c << EOF
int main(void) { return 0; }
EOF
do_cc $_march $_gcc3_ext && _march="$_march $_gcc3_ext"
fi
fi
echo $_march $_mcpu
rm -f conftest.c conftest cpuinfo
return 0
}
do_ppc()
{
# Linux on a PPC has /proc/info
# Darwin (OS/X) has the hostinfo command
# If neither of those we have no idea what to do - so do nothing.
if test -r /proc/cpuinfo; then
proc=`grep cpu /proc/cpuinfo | cut -d':' -f2 | cut -d',' -f1 | cut -b 2- | head -n 1`
elif test $IsDarwin = yes; then
proc=`hostinfo | grep "Processor type" | cut -f3 -d' ' | sed 's/ppc//'`
else
return 0
fi
case "$proc" in
601) _march="$_opt_mcpu=601" _mcpu='-mtune=601'
;;
603) _march="$_opt_mcpu=603" _mcpu='-mtune=603'
;;
603e|603ev) _march="$_opt_mcpu=603e" _mcpu='-mtune=603e'
;;
604|604e|604r|604ev) _march="$_opt_mcpu=604" _mcpu='-mtune=604'
;;
740|740/750|745/755) _march="$_opt_mcpu=740" _mcpu='-mtune=740'
;;
750|750CX) _march="$_opt_mcpu=750" _mcpu='-mtune=750'
;;
*) ;;
esac
# gcc 3.1(.1) and up supports 7400 and 7450
if test "$_cc_major" -ge "3" && test "$_cc_minor" -ge "1" || test "$_cc_major" -ge "4"; then
case "$proc" in
7400*|7410*) _march="$_opt_mcpu=7400" _mcpu='-mtune=7400' ;;
7450*|7455*) _march="$_opt_mcpu=7450" _mcpu='-mtune=7450' ;;
*) ;;
esac
fi
# gcc 3.2 and up supports 970
if test "$_cc_major" -ge "3" && test "$_cc_minor" -ge "3" || test "$_cc_major" -ge "4"; then
case "$proc" in
970*) if test $IsDarwin = yes; then
_march="$_opt_mcpu=G5 -mpowerpc64 -mpowerpc-gpopt -falign-loops=16 -force_cpusubtype_ALL" _mcpu='-mtune=G5'
else
_march="$_opt_mcpu=970" _mcpu='-mtune=970'
fi
;;
*) ;;
esac
fi
echo $_march $_mcpu
return 0
}
#
# The script that runs the various functions above
#
if test $target = x86; then
do_x86
elif test $target = ppc; then
do_ppc
fi

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,8 @@
Since version 0.9.3 veejay features a caching mechanism to load frames from disk into the system's memory. The cache size is limited to the amount of RAM available in your machine. If the cache is full, Veejay must decide which frames to discard. Veejay will discard the frame furthest away from the current position.
You can configure the cache with two commandline options:
-m / --memory [percentage of available RAM to use]
-j / --max_chain [maximum number of samples to cache]
The second option, '-j' is used to divide up the cache memory into a number of equal sized chunks. Veejay will cache by default up to 8 samples into your system's main memory, if you specified the -m option.

View File

@@ -0,0 +1,118 @@
Compiling Veejay ¶
Prerequisities ¶
Required:
* MJPEG Tools
* FFmpeg
* libxml2 for saving project data
* SDL for the video window
* libdv for playback of DV Video
* DirectFB for secundary head (TVOut)
* Jack for audio playback
* freetype2 for font rendering
* libjpegMMX for SIMD optimized JPEG decoding
* [http://www.gtk.org GTK-2.4 (GTK 2.6 recommended)
* [http://www.gnome.org GdkPixbuf (comes with Gnome)
* Cairo (needed for GVeejay Reloaded)
* GtkCairo (needed for GVeejay Reloaded)
* Libquicktime for Quicktime]
* openGL library (gl.h and libGL.so) for the video window
* Unicap API for more video input devices]
You should check with the package manager of your distribution to see if all development packages have been installed, among others this includes:
* libdv-dev
* cairo
* jack-dev
* glib >= 2.4 dev
* gtk >= 2.4 dev
* libglade >= 2.2 dev
* automake, autoconf, libtool, etc.
* linux kernel header files
If you are one of those lucky users with a distribution without any compiler pre-installed you will need to setup a build system by installing a gcc, automake, autoconf, etc etc.
* Compiling On Ubuntu: doc/HowtoUbuntu.txt
Preperation ¶
Configuration ¶
Before running configure, check if the PKG_CONFIG_PATH variable is setup correctly:
$ echo $PKG_CONFIG_PATH
If echo is silent, you must set the PKG_CONFIG_PATH to point to the directory containing all your .pc files (like for example libdv.pc or jack.pc )
$ find /usr -name libdv.pc
/usr/local/lib/pkgconfig/libdv.pc
$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
1. Get the sources from Veejay's repository:
$ svn co svn://dyne.org/veejay/trunk/veejay/current
2. Enter the source directory and run autogen.sh
$ cd veejay-current
$ sh autogen.sh
3. Run ./configure
$ ./configure
If you want to disable the graphical interfaces for some reason, use:
$ ./configure --without-gveejayreloaded --without-gveejay
Building ¶
Type 'make' to build veejay
$ make
Installing ¶
$ sudo make install
or
$ su
# make install
Running veejay ¶
Test if veejay works:
$ veejay -d -n
To run veejay without accelerated display:
$ veejay -O5 -d -n
To run veejay in verbose mode:
$ veejay -O5 -d -n -v
To run veejay with openGL display:
$ veejay -O4 -d -n
Start another terminal and type:
$ gveejayreloaded
or
$ gveejayreloaded -n
Stopping veejay ¶
Open another terminal
$ sayVIMS "600:;"
(or press CTRL-C in the terminal running veejay)

View File

@@ -0,0 +1,13 @@
First, you need to create a file to tell veejay where to find plugins.
$ mkdir ~/.veejay
$ vi ~/.veejay/plugins
The contents of the file can look like:
/usr/local/lib/freeframe
/usr/local/lib/frei0r-1
Veejay will pick up the plugins the next time you start it.

View File

@@ -0,0 +1,77 @@
Which packages do I need ? ¶
You will need about 200 megabytes of available diskspace, this includes the packages below and the space needed for building veejay.
* subversion
* cvs
* build-essentials
* autogen
* autotools-dev
* autoconf
* automake1.8
* libtool
* libsdl1.2-dev
* libjack0.100.0-dev
* libquicktime-dev
* libxml2-dev
* libglade2-dev
* libgtk2.0-dev
Which packages do I need to compile myself ? ¶
* mjpegtools
If there is a compile error in Region2D.hh, complaining about 'assert' insert a line in top of the file '#include <assert.h>'
* libunicap
* FFmpeg
* GTK Cairo
cvs -d :pserver:anoncvs@cvs.cairographics.org:/cvs/cairo co gtkcairo
cd gtkcairo
sh autogen.sh
./configure && make && sudo make install
WARNING ¶
I use ffmpeg from source, I suggest you do the same. There are unmet dependencies in libavcodec-dev and libavformat-dev that relate to ogg,vorbis,theora, *1394* packages in Ubuntu 6.06.
$ sudo apt-get remove libavcodec-dev libavformat-dev
$ svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk ffmpeg
$ cd ffmpeg
$ ./configure --help
Disable what you dont need, then:
$ ./configure --prefix=/usr --enable-shared ...
$ make && make install
And continue building veejay
Building veejay ¶
Check if the PKG_CONFIG_PATH variable has been set properly.
$ echo $PKG_CONFIG_PATH
If you just ran 'configure' and 'make' for mjpegtools,libunicap etc, check if the accompanying .pc files are in /usr/local/lib/pkgconfig
$ export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
To get the latest veejay:
$ svn co svn://dyne.org/veejay/trunk/veejay-current
To build a veejay optimized for speed:
$ sh autogen.sh
$ ./configure
$ make && sudo make install
To build a veejay to send usefull bugreports:
$ sh autogen.sh
$ ./configure --enable-debug
$ make && sudo make install

View File

@@ -0,0 +1,503 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<meta name="GENERATOR" content="SGML-Tools 1.0.9">
<title>Using sendVIMS to write simple control paches for veejay in
PureData</title>
</head>
<body>
<h1>Using sendVIMS to write simple control paches for veejay in PureData</h1>
<h2>M. van Henten cola at looze.net</h2>
V0.01 104-10-09
<hr><em>
<!--
sendVIMS
-->SendVIMS is a Puredata external written by Niels
Elburg and Tom Schouten. It is a control interface to veejay, a
realtime video processing package.
I will explain some of my work using both tools together.</em>
<hr>
<h2><a name="s1">1. Introduction</a></h2>
<p>
<!--
sendVIMS!introduction
--> SendVIMS is a Puredata external written
by Niels Elburg and Tom Schouten. It is a control interface to veejay,
a realtime video processing package. VIMS stands for 'Veejay's Internal
Messaging System.<br>
I have been working with veejay
for a long time now so I took my knowledge of what it could do and
built a few paches that will demonstrate the power of building
interactive controls for veejay. This might be interesting for the
newcomers to linux video, but also for the experienced who want to know
more about veejay, and puredata although it is not intended as step by
step guide on how to use PureData or veejay( Especially since I'm
rather new to PureData), but I will try to explain some basics on how
to get this working.
</p>
<h2>1.1 Copyright</h2>
<p>This document is Copyright &copy; 104-10-09 M. van Henten.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
any later version published by the Free Software Foundation with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
</p>
<h2>1.2 Disclaimer</h2>
<p>Use the information in this document at your own risk. I disavow any
potential liability for the contents of this document. Use of the
concepts, examples, and/or other content of this document is entirely
at your own risk.
</p>
<p>All copyrights are owned by their owners, unless specifically noted
otherwise. Use of a term in this document should not be regarded as
affecting the validity of any trademark or service mark.
</p>
<p>Naming of particular products or brands should not be seen as
endorsements.
</p>
<p>You are strongly recommended to take a backup of your system before
major installation and backups at regular intervals.
</p>
<h2>1.3 News</h2>
<p>9-10-2004
Started Writing first draft to this howto, after finishing up on some
basic patches.
</p>
<h2>1.4 Credits</h2>
<p>Many thanks to of course to Tom Schouten en Niels Elburg for
creating this tool, thanks to Niels for creating veejay after numerous
sessions of feature dreaming, and continue working on it to create more
then we ever fantasized about. </p>
<p>Also, much obliged to the people in te PureData community, who
helped me getting started in the first place.Thanks to Derek Holzer,
who introduced me to PD and showed me how easy and fun PD was.
</p>
<p>A thankyou should be in place for the people at BEK (
http://www.bek.no) Who brought a lot of video guys in the OS world
together, and made this collaboration possible in the first place.
</p>
<h2><a name="s2">2. Technologies</a></h2>
<p style="font-weight: bold;">2.1 Expected Skills<br>
</p>
<p>I assume that you know how to work with the linux commandline.
Veejay is ( up to this date) mainly a console application ( besides the
video bit of course) and you <span
style="font-weight: bold; font-style: italic;">need to type stuff</span><span
style="font-style: italic;"> </span>to get it working. If this is all
too strange for you, I would advice you to get know a bit more of linux
first, by reading some magazines, and some howto's ( <a
href="http://www.tldp.org">the linux documentation project</a> has a
lot of howto's) like the <a
href="http://tldp.org/HOWTO/DOS-Win-to-Linux-HOWTO.html">windows/dos
to linux howto</a>. <br>
</p>
<p><span style="font-weight: bold;">2.2 Veejay</span><br>
</p>
<p>First of all, you need to download and install a later version of
veejay.&nbsp; In this document, I used veejay-0.6.2. Any version before
0.5.9 will not work as expected, or not at all together with SendVims. <br>
</p>
<p>Veejay sources are located <a href="http://veejay.sourceforge.net">http://veejay.sourceforge.net</a>,
or go directly to the <a href="http://www.sf.net/projects/veejay">sourceforge
download area</a>.<br>
Installation is standard: open a shell, or terminal, unpack the package
somehwere, go into the newly created directory, and type:<br>
</p>
<p>./configure<br>
</p>
<p>when configure has finished, something like:<br>
</p>
<p>&nbsp;<small><span
style="font-family: courier new,courier,monospace;">veejay 0.6.2 build
configuration :</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;Build
configuration:</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
MMX
enabled&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: true</span><br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
MMX2
enabled&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: false</span><br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
SSE
enabled&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: true</span><br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
3DNow
enabled&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: false</span><br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
CMOV
enabled&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: true</span><br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
glibc support for &gt;2GB files&nbsp;&nbsp;&nbsp; : true</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;Required
dependencies:</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
POSIX Threads (pthread)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: true</span><br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
video4linux recording/playback&nbsp; : true</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Simple Direct Media Layer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : true</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
XML C library for Gnome libxml2 : true</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
libJPEG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: true</span><br style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;Optional
dependencies:</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
libDV (digital
video)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: true</span><br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Jack Audio Connection Kit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : true</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
DirectFB
support&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: false</span></small><br>
<br>
</p>
Should appear.<br>
<br>
Note that veejay depends on the <a href="http://www.xmlsoft.org/">XML
C library</a> ( it comes as part of the GNOME libraries and desktop)
and <a href="http://www.libsdl.org">SDL</a>, if you don't have these
packages you should install them. <a
href="http://libdv.sourceforge.net">Libdv</a> is optional, for being
able to play dv type 2 format avi's, <a
href="http://jackit.sourceforge.net">jack</a> is optional but needed
if you want to hear sound with your movies. <br>
<br>
Describing how to get jack working optimal is not within the scope of
this document, I can only say that if you have jack setup properly
veejay should be able to output sound. <br>
<br>
When this is done, do a "make" followed by a "make install".<br>
Veejay should now be installed. Get some movie to edit( you can borrow
one from me <a href="http://cola.looze.net/sendvims/video/">here</a>) <br>
<p style="font-weight: bold;">2.2 PureData</p>
<p>PureData is a whole story upon itself. Please read the installation
notes and documentation on <a href="http://www.puredata.org">http://www.puredata.org</a>.
You can verify if everything works by just running pd, goto help en
check out some of the example paches. Using the documentation&nbsp;
from within pd you should at least get some basic understanding.<br>
</p>
<p><span style="font-weight: bold;">2.3 SendVims</span><br>
</p>
<p>In this document I used sendVIMS-0.1. <br>
This is compied from the README in sendVIMS-0.1.tar.gz :<br>
<br>
</p>
<p><small><span style="font-family: courier new,courier,monospace;">sendVIMS
- very simple VeeJay client for pure data</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(C) 2002-2004 Niels Elburg &lt;elburg@hio.hen.nl&gt;</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(C) 2004 Tom Schouten &lt;doelie@zzz.kotnet.org&gt;</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">This is free
software covered under the terms of the</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">GNU GPL. See
the file COPYING for details.</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">building:</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">./configure
&amp;&amp; make &amp;&amp; make install</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">'make
install' copies these files to your pd directory:</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&lt;prefix&gt;/lib/pd/extra/sendVIMS.pd_linux</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">&lt;prefix&gt;/lib/pd/doc/5.reference/help-sendVIMS.pd</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">the default
&lt;prefix&gt; is /usr/local</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">running:</span><br
style="font-family: courier new,courier,monospace;">
<br style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">if the module
is in your pd path it will be loaded automaticly.</span></small><br>
</p>
<h2><a name="s3">3. Implementation</a></h2>
<p><span style="font-weight: bold;">3.1 Get veejay running</span><br>
</p>
<p>To start veejay, you need to start it with a video file. Veejay only
plays avi files, so no quicktime, or mpeg movies.<br>
Veejay only knows of two types of video codecs: mjpeg and DV type 2.0. <br>
So to get veejay running, you need at least one mjpeg or DV type 2.0
.avi file. These formats were chosen with some reasons, explained in
the veejay-howto. Converting into codecs and other formats is a whole
science upon itself, and I do intend to write a crash course into video
and linux in the future. For creating mjpeg avi's I use the <a
href="mjpeg.sourceforge.net">lavtools</a> and <a
href="www.mplayerhq.hu">mplayer</a>, and veejay itself.<br>
</p>
<p><a href="http://cola.looze.net/sendvims/video">You can grab a one
second mjpeg avi from here.</a><br>
</p>
<p>This is copyright free material I transcoded out of a movie from <a
href="http://www.archive.org">archive.org</a><br>
Start veejay by opening up a terminal window such as xterm and type: <br>
</p>
<p style="font-family: courier new,courier,monospace;"><small>veejay
mymovie.avi</small></p>
<p>If you used the example one second avi, it will briefly play the
whole movie and stop at the last frame. Move your mouse into the video
window. As long as the mouse pointer is inside the video window, you
can use the built in keyboard controls. press keypad-5, this pauzes
playback. now press keypad-1, to skip to the start of your movie. press
the [ key, this marks 'clip start', press keypad-3, to skip to the end
of the movie, and press the ] key, this marks the 'clip end'. You can
now sellect your clip by pressing the F1 key. the movie will
automatically keep looping. you can alterate loopmode by pressing
keypad-*. try some other keypad keys to see what they do. See 'man
veejay' for the other controls.<br>
</p>
<p><span style="font-weight: bold;">3.2 Running PD/SendVIMS</span><br>
</p>
<p>Open up a terminal window such as xterm and type:<br>
</p>
<p><small style="font-family: courier new,courier,monospace;">pd</small><br>
</p>
<p>You'll need the terminal to get some feedback from pd. From the file
menu of pd, choose 'new'. In the new window, choose 'put &gt; object'. <br>
A rectangular object appears under your mousepointer. Click somewhere
in the white area of the window, and type "sendVIMS" inside the object.
If you installed the sendVIMS external properly, you should read&nbsp;
in the terminal:<br>
</p>
<p><small><span style="font-family: courier new,courier,monospace;">sendVIMS:
version 0.1</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">sendVIMS: (c)
2004 Niels Elburg &amp; Tom Schouten</span><br
style="font-family: courier new,courier,monospace;">
<span style="font-family: courier new,courier,monospace;">sendVIMS:
connected to localhost:3490</span></small><br>
</p>
<p>That's it! you should now be able to right-click on the sendVIMS
object, and choose 'help' from the popup window. <br>
You are now properly set up to use sendVIMS and veejay. Please refer to
some of the examples I provide under 'examples' for more information.
You should note that my examples will work right away, even without
understanding PD in the first place, but they are not intended as a
tutorial on how to use PD. you should see the 'help' menu and various
resources around the web for that!.<br>
</p>
<p><br>
</p>
<h2><a name="s4">4. Troubleshooting</a></h2>
<p><span style="font-weight: bold;">
4.1 Veejay doesn't start!</span><br>
</p>
<p>You need to start veejay from a terminal, using a proper encoded avi
file. you can use the <a href="http://cola.looze.net/sendvims/video">demo</a>
file if you don't have one.<br>
Please refer to veejay documentation and maillinglist.<br>
</p>
<p><span style="font-weight: bold;">4.2 SendVIMS doesn't work, PD tells
me it can't create sendvims.</span><br>
</p>
<p>The sendVIMS-0.1 external is not installed. please install the
external and restart PD.<br>
</p>
<p><span style="font-weight: bold;">4.3 I have a different problem,
please help me.</span><br>
</p>
<p>If the problem is relevant to this document please <a
href="mailto:cola@looze.net">mail</a> me and I'll add it here. Try the
PD and veejay maillinglist otherwise.<br>
</p>
<h2><a name="s5">5. Further Information</a></h2>
<p><span style="font-weight: bold;">5.1 HOWTO's and documentation</span><br>
</p>
<p>The veejay howto can be found here: <a
href="http://veejay.sourceforge.net/veejay-HOWTO.html">http://veejay.sourceforge.net/veejay-HOWTO.html</a><br>
PureData documentation is here:&nbsp;&nbsp; <a
href="http://www.puredata.org">http://www.puredata.org</a><br>
</p>
<p>I have have been working on some more patches besides the ones in
the examples, they're on my personal homepage:<br>
<a href="http://cola.looze.net/sendvims/">http://cola.looze.net/sendvims/</a></p>
<p><br>
<span style="font-weight: bold;">5.2 Email, Mailinglists</span></p>
<p>Please post your questions to the veejay mailinglist, you can
subscribe <a href="http://sourceforge.net/mail/?group_id=47564">here</a>.<br>
<br>
</p>
<h2><a name="s6">6. Examples</a></h2>
<p><span style="font-weight: bold;">6.1 Basic Example: play, play
backwards.</span><br>
</p>
<p>In PD, you send a message by creating a message object, type the
message into that object, and connect the output of the message to the
sendVIMS object.<br>
</p>
<p><img src="VIMS-example-play.jpg" title=""
alt="Screenhost of example patch" style="width: 326px; height: 288px;"><br>
</p>
<p>In this example, I used PD aliasses: video.play.forward, and
video.play.backward. Normally, most VIMS messages are represented as
numbers, preceded by a 'p', for example, p100 stands for 'select and
play sample' followed by an argument. In the following example, you can
select different clips to play in veejay by changing the number inside
the number box. ( you can make diferent clips in veejay when in 'plain
video' mode, by pressing keypad '/'. Use keypad play controls to select
different frame positions, use the [ and ] keys to mark in and
outpoints of clips, use the function keys to select samples with the
keyboard controls).<br>
</p>
<p>6.2 Set the playing clip with an argument.<br>
</p>
<p><img src="VIMS-example-setframe.jpg" title=""
alt="Set the playing clip with an argument"
style="width: 326px; height: 288px;"><br>
</p>
<p>The $1 takes the number from the number box, and together with the
p100 message it gives the command "select and play sample $1" to
veejay. Note, that since PD doesn't know how many clips we have here,
we can select non-existing clips. We can give negative numbers. veejay
will give an error message.<br>
</p>
<p><span style="font-weight: bold;">6.3 Getting status output from
veejay.</span><br>
</p>
<p>This example shows how to get information you need from veejay: for
example the current frame. <br>
</p>
<p><img src="VIMS-example-getstatus.jpg" title=""
alt="Example of getting status information"
style="width: 326px; height: 288px;"><br>
</p>
<p>Now, there are two number boxes. When playing clips, the first
number box will display the current frame, but when playing in plain
video, the second box outputs the current frame. Veejay sends it's
status in one big string of numbers, seperated by spaces. all
information comes in at the same time. You can use the 'unpack' object
to split the information in smaller chunks. notice how many outputs it
has - there are lots of status messages to be read. I have made a patch
that helps me remember what goes where, and I include it as a subpatch
when working with sendVIMS. You can find it on my personal weppage: <a
href="http://cola.looze.net/sendvims">http://cola.looze.net/sendvims</a>.<br>
</p>
<p><span style="font-weight: bold;">6.4 Controlling video effects.</span><br>
</p>
<p>Veejay has many video effects. you can find out what kind of effects
on veejay's homepage, in the gallery section. For this next example,
you need two different clips. Assuming that you are working with the
example movie, press Keypad-5 for pauze, and Keypad-1 to go to the
start of the movie. Mark the beginning of your first clip here. Now, we
gently scrub to frame 12 in the movie using Keypad-9 - it skips one
frame ahead at a time - and mark the end of the first clip, and, on the
same frame, the beginning of the second clip, and at the last frame of
the movie, the end of the second clip( HINT: you could use the
"video.set.frame &lt;frame&gt;" message here instead).<br>
You should have two samples now, which you can select with the F1 and
F2 keys. Lets start with selecting the first clip and have a look at
the example:<br>
</p>
<p><img src="VIMS-example4-videomixer.jpg" title=""
alt="example of effect controls" style="width: 561px; height: 414px;"><br>
</p>
<p>The first message sets up the effect chain. Veejay can chain
multiple effects on top of eachother, like layers in an image editing
program. In this example, it sets effect 4 on current playing sample (
the number zero in the VIMS messages that control effects always stands
for the current playing clip, as a convenience. you could also replace
the number with a variable, and read it from veejay's output to know
the current clip).<br>
Effect 4 is the "Normal Overlay" effect, it simply mixes two video like
a videomixer.<br>
</p>
<p>The second message controls the clip the overlay effect mixes with.
Put it to 2 to mix with our second clip. <br>
The third message is a PD message, that controls the boundaries of the
slider. Normally, sliders have value 0 to 127 by default. the overlay
effect has only one controll, opacity, and it is mesured in value 0 to
255, so I want the slider to have boundaries ranging 0 to 255.<br>
The slider is connected to the third message: control parameter 0 of
the effect on chain-entry 3 of the current playing clip.<br>
The order of these values is typical: first, tell which sample to
select. second, what effect chain entry, third, which control
parameter, and last, the value of that parameter. <br>
You can make a dump of the effects numbers and the VIMS messages by
running:<br>
</p>
<p><small><span style="font-family: courier new,courier,monospace;">veejay
--dump-events -d &gt; veejay-events.txt<br>
</span></small></p>
<p>The last message, "connect localhost 3490" actually (re)connects the
sendVIMS object to veejay if not already connected. You can use the
message "disconnect" and "quit", too, have a look at the sendVIMS
helpfile.<br>
</p>
<p><span style="font-weight: bold;">6.5 More advanced playback control:
scrubbing.</span><br>
</p>
<p>This example shows two things: One slider can be used to set a new
play position in a clip, the other shows the play position in the
current clip.<br>
Both sliders get their boundaries updated with the starting position of
the clip and the ending position. This only works in the 'clip' mode,
not when playing in plain video.<br>
</p>
<p><img src="VIMS-example5-scrubbing.jpg" title=""
alt="Example of controlling play position with a slider"
style="width: 372px; height: 396px;"><br>
</p>
<p>From the status, the starting frame and the end frame of the current
playing clip are read, which sets the boundaries of both sliders. The
slider in the top of the patch controls message p089: set frame $1, the
slider in the bottom gets updated with the 'current frame of clip'
information.<br>
However, when switching from clip to plain video mode, this will no
longer work as the outputs get different status updates. Switching
between clips wil work perfectly however.<br>
</p>
<p>More advanced combinations are possible. PD offers a lot of
functionality, such as MIDI, joystick controls and controlling things
through sound. Some more examples of my work are on my personal
website. <br>
</p>
<p><br>
</p>
<p><br>
</p>
<p><br>
</p>
</body>
</html>

View File

@@ -0,0 +1,83 @@
Video files ¶
A video file consists out of TWO seperate elements:
* container
* codec
The container holds the digitally encoded data and the codec is capable of decoding/encoding this digitally encoded data.
Veejay supports the AVI and the Quicktime container , with the following codecs:
Quicktime:
* mpjeg,mjpa,jpeg,dmb1
* dvsd, dv, dvcp, dvhd
AVI
* mjpeg, mjpa,jpeg,jfif,dmb1
* dvsd, dv, dvcp, dvhd
* i420, i422, yv16, hfyu
Raw DV
* PAL / NTSC dvsd
Veejay can only deal with video files that consists entirely out of whole images (only I-frames). The codecs below will only work if all frames are I-frames. Otherwise, veejay will abort with an error message.
AVI / Quicktime:
* xvid, mp4v,divx,dxsd,mp4s,m4s2
* div3,mp43,mp42,mpg4
* avc1,h264,x264,davc,svq1,svq3,avc1
Wich codec to use ¶
MotionJPEG ( mjpeg) is the veejay codec of choice for most applications, it gives you a good tradeof between compression, quality and compatibility. If you want speed, use AVI yv16 or i420 while recording to new samples.
Tools that support MJPEG:
* http://cvs.cinelerra.org/Cinelerra
* http://www.kinodv.org/Kino
* http://ronald.bitfreak.net/lvs/Linux video studio
* http://mjpeg.sourceforge.net/mjpegtools
* http://www.mplayerhq.huMplayer, and mencoder
* http://lives.sf.net Lives
Wich resolutions to use ¶
Veejay can do:
* high definition (use MLZO/YUV avi)
* pal: 720x576 (recommended to use MLZO/YUV avi)
* ntsc: 720x480
* 1/4 pal: 360x288 (any)
* 1/4 ntsc: 360x240 (any)
If you load multiple video files on the commandline, make sure that all files have the same resolution and audio properties.
How to convert ¶
Veejay can convert dv video to mjpeg for you, however, I prefer to use mplayer for this, wich has more flexibility.
From "anything" mplayer can play to mjpeg, use:
$ mencoder -ovc lavc -oac pcm -lavcopts vcodec=mjpeg -o <outputfile> <inputfile>
To scale on the fly, use:
$ mencoder -ovc lavc -oac pcm -lavcopts vcodec=mjpeg -vf scale=352:288 -o <outputfile> <inputfile>
consult mplayer documentation about other options, such as cropping and filtering out blocks in video.
a quick hint for bulk encoding a bunch of capture.dv files:
$ for i in `ls *dv`;do mencoder -ovc lavc -oac pcm -lavcopts vcodec=mjpeg -o `echo $i | sed s/.dv/.avi/` $i; done;
What is this dummy mode ¶
Dummy mode opens up a 'color stream' to start veejay without a video file.
If you use a video file, veejay will take that file's properties as default settings for the whole session.

View File

@@ -0,0 +1,182 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

View File

@@ -0,0 +1,105 @@
Veejay can stream over the Network
=================================================
With -p you can give Veejay's port offset
TCP socket for sending commands: + 0 (sayVIMS -h)
TCP socket for receiving status: + 1 (gveejay)
TCP socket for querying commands:+ 2 (gveejay - editlist/sampellist etc)
UDP multicast frame sender : + 3 (input stream multicast/other applications)
UDP multicast for sending commands: + 4 (sayVIMS -g)
How to activate:
1. veejay movie1.avi
2. veejay movie2.avi -p 5000
(Both movie clips must have identical properties!!)
veejay 2 makes a connection with veejay 1
3. sayVIMS "245:localhost 3490;" -p 5000 -h localhost
4. move mouse to veejay2 video window and press 'ESC'
if everything is OK, the video will be playing.
5. stop veejay1 (CTRL-C)
6. veejay2 will show last frame (press ESC)
7. restart veejay1
8. press 'ESC' in veejay2 to resume streaming (auto-reconnect)
Veejay can stream over the Network (UDP / Multicast )
=====================================================
How to activate:
1. veejay -V 224.0.0.50 -p 5000 -v movie1.avi
2. veejay -d -W <movie1 width> -H <movie1 height>
3. sayVIMS -h localhost -p 3490 "246:5000 224.0.0.50;"
4. press F7 to activate newest created stream
Veejay can receive OSC (Open Sound Control) messages over Multicast protocol
============================================================================
How to activate:
1. veejay --multicast 224.0.0.30 movie1.avi
Note that you must have 'multicast' enabled in your kernel configuration.
Use the tool 'mcastOSC' in test/OSC to send OSC messages to all
veejay's you have started with --multicast (on multiple hosts!!)
2. export MCAST_ADDR=224.0.0.30
4. mcastOSC -r 3495
Veejay can send/receive VIMS (Veejay Internal Message System) packets
over Multicast protocol
=============================================================================
How to activate:
1. veejay --multicast-vims 224.0.0.32 movie1.avi
2. veejay --multicast-vims 224.0.0.32 movie2.avi
3. sayVIMS -g 224.0.0.32 -f test/vims/magicmirror-vims.txt
How to setup multicast?
=======================
1. enable 'multicast' in kernel configuration
2. type 'route add -net 224.0.0.0 netmask 255.255.255.0 dev eth0'
(or something similar, read the man page of route to figure out
what addresses are reserved for multicast)
What is multicast?
==================
Multicasts enables you to (ab)use the network topology to transmit
packets to multiple hosts.
Limitations
===========
1. Veejay can only stream to another veejay
2. All veejays must have identical video properties (fps,width,height, ... )
3. Veejay will drop frames when it cannot keep up (or when packets are dropped)
4. Audio is not supported
What header format?
===================
see libvjnet/packet.h for multicast packet definition
for peer-to-peer streaming, the first 11 bytes of the buffer indicate
width, height and format in plain ASCII: "%04d %04d %1d"

View File

@@ -0,0 +1,22 @@
Veejay's performace depends much on the memory bandwith, CPU and disk access.
For HDTV (1280x720) mjpeg, you need at least a 2.5 ghz. The faster the better.
For full PAL/NTSC resolutions (720x576 resp. 720x480) DV/Mjpeg you need at least a 1.5 ghz,
for lower resolution (352x288) you can do fine with a 500-800 mhz PC.
If you need to record without framedrop, you can do so by disabling audio and
disabling synchronization with the commandline options -a0 -c0
On newer PC's (pentium4) your best bet is working in RAW or MLZO (compressed)
YUV 4:2:0 / 4:2:2 On my pentium 4 , 3.0 ghz playing a AVI file that contains RAW YUV frames
uses about 3-4% for a full PAL movie and 10-12% for mixing 2 movies.
The tradeoff here is your diskspeed. You could use compression, this reduces the
size of the videofile anywhere between 0-30% .
Typical for laptops is slow diskspeed access, on my 1.8 ghz dell latitude laptop
the best I get is an average of about 20.0 mb/sec which is barely sufficient
for playing full PAL avi's containing RAW YUV.
(you can test yours with hdparm -T -t /dev/hdX)

View File

@@ -0,0 +1,110 @@
It is advised to read the howto and the MAN page as well.
You can launch veejay with
$ veejay -d
This should show some moving black/white footage. Most of the effects will be boring on this footage,
so you can try to open your video4linux device with
sayVIMS "240:0 1;" (device 0, channel 1)
Or, to use mplayer, create a FIFO first:
$ mkfifo stream.yuv
Use something like 'mplayer -vo yuv4mpeg -x 352 -y 288 -vf scale -zoom'
and open the stream in veejay's console:
sayVIMS "243:stream.yuv;"
Move your mouse pointer to the SDL window (so it dissapears) and press 'ESC' to
switch from the dummy footage to the last created or played video stream.
Try loading an AVI file with something like:
$ veejay -v mjpeg-video-file.avi
The '-v' commandline option generates extra debugging output.
By default, veejay uses a SDL window for displaying video. You can specify veejay to
write to STDOUT :
$ veejay -O3 -o stdout mjpeg-video-file.avi | yuvplay
In this mode, the console input and SDL keyboard functions are disabled. You must use
the sendVIMS commandline utility to interact with veejay or with an alternative utility like sendOSC.
Refer to the howto for more information.
Once you have loaded veejay (preferably with a videofile)
(see man veejay for an overview of both console input and SDL keyboard events)
press 'KP 1' , 'left bracket', 'KP 3', 'right bracket' , 'F1'
This will create a virtual clip (in memory) from your entire video file.
If you press 'KP divide' , veejay will return to plain video mode so you can create more clips.
If you press 'ESC' , veejay will switch from playing streams to playing clips or vice versa
Press F1 to F12 to select a clip,
press 1 to 9 to select a bank (1 = clips 1 to 12, 2 = clips 12 to 24, etc )
Once you are playing a clip/stream, simply press
'Cursor UP' , 'ENTER'
If you add a video effect, try pressing '-' and '=' to select another channel and '/' to
toggle between clip/stream sources
Veejay supports chaining of effects since day 0, a number of keys have some importance
'-' ,'=' and '/'
'END' for enabling/disabling the chain
'KP -' for selecting the previous entry
'KP +' for selecting the next entry
'ALT+END' for enabling/disabling the current selected entry
'ENTER' for adding an effect from the list to the chain
'DEL' for removing an effect from the chain
Also, you can press 'HOME' to see clip or stream information.
Try the keys 'A' to 'L' to increase/decrease playback speed.
Also, you can load some predefined custom effect chain templates that
will put a template on your effect chain when you press SHIFT + some alphabetic character
First, load an action file
$ veejay -l test/livecinema/action-file.xml
Or in veejay's console
> al test/livecinema/action-file.xml
(activate a stream or clip and) press SHIFT+S or SHIFT+B or SHIFT+ ...
Except all that, try this:
sayVIMS -h localhost -p 3490 "241:63;"
(press F7)
to open your dv1394 firewire device
or
sayVIMS -h localhost -p 3490 "240:0 1;"
(press F7)
to open your video4linux device /dev/video0, channel 1
Enjoy!

View File

@@ -0,0 +1,16 @@
Veejay is a live performance tool featuring simple non-linear editing and mixing from multiple sources. You can load multiple video clips, cut and paste portions of video/audio and save it as an EditList. Also, you can record new clips from existing clips or (live) streams. With these clips you can change playback speed (slow motion/acceleration), change the looptype and set markers.
With both clips and streams you can edit the effect chain and mix from multiple sources to one. Veejay has a 84+ effects, divided into two categories: Image and Video Effects, only with Video Effects you can select a channel to mix in.
Veejay has many frame blending methods, some of these are: Additive,Substractive,Difference Negate, Relative Addition and Selective Replacement. Next to blending, you can key on Luma and Chroma seperatly or combined or simply use Transitions or other effects.
Most edit and navigation commands are mapped to single key press commands, this allows you to control, depending on the playback mode, video navigation, the effect chain, effect parameters and clip properties at playback time.
Also, you can record a new clip on the fly from a live feed or from the video clip you are playing. If requested, the recorded videofile will be added to the edit descision list and activated as a new video clip. This is particular usefull for time-looping,rebouncing and rough clip scratching/editing
Veejay can be remotely controled through using OSC (Open Sound Control) or via its own internal message interface 'VIMS'. 'VIMS' allows you to create/load/save effect chain templates and to add customized events which can be triggered by a keypress or a remote message.
Veejay supports streaming from multiple video sources to one, this can be a Video4Linux device , a vloopback device or a yuv4mpeg stream. You can chain several veejays with effectv and vice versa to create some amazing footage.
veejay is licensed as Free Software (GNU).

View File

@@ -0,0 +1,318 @@
1. VIMS is Veejay's IMS (Internal Message System)
=================================================
All control data is distributed via VIMS. Each (atomical) message consists of an Action Identifier
and a list of zero or more Arguments which can be used to control Video Clips, Video Streams,
the Effect Chain and many other things.
VIMS allows events to be triggered through:
SDL Keyboard Event (libsdl)
OSC (OpenSoundControl)
IMP (Internal Message Protocol)
After intalling veejay, you will have a commandline utility 'sayVIMS'
This document describes what messages you can send to veejay through using VIMS
Inside of veejay's source package you will find a test/ directory containing various examples demonstrating
how to load an ActionFile, how to use Perl for batch like video processing and how to attach message bundles to
keyboard events.
Use the command
$ veejay -u -n |less
to see documentation generated by veejay on using Effects, VIMS and OSC.
If there is an error in the documentation, you have found a bug in veejay
and should report it :)
1.1 Message Format
==================
A message is described as:
<Action Identifer> : <Argument List> ;
Example:
080:;
099:0 0;
<Action Identifier>
The action identifier is a 3 digit number describing a Network Event
The colon is used to indicate the start of the Argument List and must be given.
<Argument List>
The Argument List is described by a printf() style formatted template
which describes the number and type of arguments to be used.
The semicolon must be given to indicate the end of this message
1.2 Bundled Messages
====================
A message bundle is a special message that contains an ordered list of at least 1 or more messages. Each message is executed from left to right (first in, first out) while parsing the bundle.
Example:
5032|BUN:002{361:0 3 56 230 93 0;361:0 4 1 7;}|
5033|BUN:003{361:0 3 56 230 93 0;361:0 4 1 7;361:0 5 1 7;}|
5034|BUN:003{361:0 3 56 230 93 0;361:0 4 1 7;361:0 5 1 8;}|
A message bundle is described as:
BUN: <Number of Messages> {
<Action Idenfifier> : <Argument List> ;
<Action Identifier> : <Argument List> ;
...
}
;
The token 'BUN:' indicates the start of a messaage bundle, the first 3 digit numeric value represents the total number of messages in the bundle. The '{' symbol indicates the start of a message block and is ended with '};' or just '}'.
1.3 Format of an Action File/Attaching Keys to Bundles
======================================================
<501 - 599> | <message bundle> |
The contents of some action file can be :
516|BUN:001{355:;}|
The message bundle BUN sends '355' for clear effect chain.
This message bundle is attached to action identifier 516.
A key is attached to this function trough using the GUI (GVeejay)
or by using:
DYNAMIC KEYMAPPING:
==================
"083:516 <sdl symbol> <modifier> <optional arguments>;"
The message bundle can be attached to a key , for example 'SHIFT + A' by sending
083:516 97 3;
Which attaches bundle '516' to SDL key '97' using a modifier '3', which is SHIFT.
Modifiers: 0 = none, 1 = alt , 2 = ctrl, 3 = shift
Keys : see SDLkeysym.h somewhere in include/SDL/
If the number 0 is used for an event number, a given key combination can be
unset (wiped) :
083:0 97 3;
Alternativly, you can bind keys to any action identifier. The complete
list can be viewd by typing veejay -u |less or with Gveejay.
083:20 97 0 4;
The example above sets key 'a' to 'change video speed to 4'
General description of VIMS messages
=====================================
Some reserved numbers:
clip id 0 : select currently playing clip
clip id -1 : select highest clip number
chain entry -1 : select current chain entry
stream id 0 : select currently playing stream
stream id -1 : select highest stream number
key modifier : 0 = normal, 1= alt , 2 = ctrl, 3 = shift
frame -1 : use highest possible frame number (usually num video frames)
playback mode : 0 = clip, 1 = stream, 2 = plain
data format : yv16 (yuv 4:2:2 raw) , mpeg4, divx, msmpeg4v3,
div3, dvvideo, dvsd, mjpeg, i420 and yv12 (yuv 4:2:0 raw)
loop type : 0 = no looping, 1 = normal loop, 2 = pingpong (bounce) loop
What follows now is a general description of argument formatting and its ordering.
In the future, veejay -u will describe all VIMS arguments as well.
I wont put it into this document, since auto documentation will work much better
(eliminating the need to update this documentation when things change).
all EditList commands, the arguments represent frame numbers (from 0 - max frames)
For example;
021:10 100; will copy frames 10-100 into a temporary buffer
020:100; will insert the frames 10-100 from the temporary buffer on frame 100
For all Clip commands, the first argument always represent the clip number except for 099
(create new clip) which takes 2 arguments ; starting and ending positions.
The arguments that may follow usually represent a number to describe either a property setting
(like speed, slow motion or looptype) and in other cases relative or real frame numbers.
Idem for Streams.
In general, for Chain commands the first argument is also the clip or stream number.
The second (or following arguments) usually represent the property setting or some value.
For example; 178 (fade in) takes 2 arguments. The first is to identify the clip number,
the second describes the duration (in frames) for the fade in.
181 (set effect with defaults) takes 3 arguments. Again, the first is to identify a clip or
stream, the second for the chain entry and the last for the effect number.
Idem for 182, but here starting from the 4th argument it takes preset values
2. OSC - Open Sound Control
============================
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
(quote from the website)
OpenSound Control ("OSC") is a protocol for communication among computers, sound synthesizers
and other multimedia devices that is optimized for modern networking technology.
Veejay starts up an OSC server that listens on port number VJ_PORT + 2 (usually 3492).
In the veejay/libOMC/send+dump you can compile a test application that sends OSC strings to veejay.
Bundled messages are handled automatically by libOMC
Type veejay -u |less to see an overview of all actions, it includes OSC. The OSC messages
are mapped onto its respective VIMS Action Identifiers.
EXAMPLES:
To create a new clip and play it:
/clip/new 100 200
/clip/select 0
To record from a clip and auto play the recording after 10 seconds of PAL video:
/clip/record/start 250 1
To add Effect 45 to the clip's Effect Chain
/clip/chain/entry/add 45
To fade in the Effect Chain in 4 seconds
/clip/chain/fade_in 100
To add Effect 45 on Entry 4 of clip 2's Effect Chain
/clip/chain/add 2 4 45
To play newest clip
/clip/select
To record from a clip and auto play the new clip after recording
/clip/record 100 1
currently, OSC support in veejay is meant for triggering only.
Some users have showed genuine interest in building user interfaces for Veejay using
this protocol. However, for such thing bi-directional communication is required
(i.e. current frame number, current playing clip, total number of clips, etc etc)
In veejay, VIMS provides a status port that can be read which will provide all kind
of status information but it is not mapped to OSC yet.
Also, in the veejay source package you will find a utility 'mcastOSC'
(which is not installed by default)
Build instructions (from veejay top source directory)
$ cd test/OSC
$ cd libOSC
$ make
$ cd ..
$ cd send+dump
$ make
Start veejay with -M or --multicast-osc , and use mcastOSC to control
all instances of veejay listening on the given multicast address.
(One tool to rule all).
SAVING/RESTORING Veejay states
===============================
Example configuration file (with most options)
<config>
<run_settings>
<port_num>3490</port_num>
<!- the port number veejay listens on ->
<SDLwidth>352</SDLwidth>
<SDLheight>288</SDLheight>
<!- SDL video window dimensions ->
<audio>1</audio>
<!- Start with audio turned on ->
<sync>1</sync>
<!- Try to keep in sync ->
<timer>2</timer>
<!- Use system clock ->
<output_fps>3</output_fps>
<!- Set a different output framerate (only affects playback) ->
<Xgeom_x>0</Xgeom_x>
<Xgeom_y>0</Xgeom_y>
<!- Use X geometry offset (from root window) ->
<bezerk>1</bezerk>
<!- Bezerk is enabled by default ->
<nocolor>0</nocolor>
<!- No colored console output ->
<chrominance_level>1</chrominance_level>
<!- YUV 4:2:2 ->
<output_width>352</output_width>
<output_height>288</output_height>
<!- Output video dimensions (real width and height) ->
<dummy_fps>0.000000</dummy_fps>
<video_norm>0</video_norm>
<dummy>0</dummy>
<mcast_osc>0</mcast_osc>
<!- Dont use OSC multicast send/receive ->
<mcast_vims>0</mcast_vims>
<!- Dont use VIMS multicast send/receive ->
<output_scaler>0</output_scaler>
<!- Dont use the software output scaler (depends on output_widhth ->
<!- and output_height ) ->
</run_settings>
</config>
Initially, you can setup veejay on the commandline and tell it to save
its settings in a configuration file.
veejay -z 1 -W 720 -H 576 /tmp/videofile.avi -p 5000
(in another terminal)
sayVIMS -h localhost -p 5000 "084:/tmp/config.tmp 1;"
In this file, not only the configuration is stored :
Bundled VIMS events, valid VIMS identifiers and Keymappings are
stored here.

View File

@@ -0,0 +1,23 @@
Veejay processing
=================
Veejay processes nativly in YUV, this is to keep colorspace conversions
to a minimum.
YUV 4:2:0 Planar ( 1 Cr and 1 Cb sample per 2x2 Y samples)
YUV 4:2:2 Planar ( 1 Cr and 1 Cr sample per 1x2 Y samples)
(both full range JPEG and clipped to 16-235 / 16-240)
Places where veejay uses software conversion:
Conversion from RGB to YUV is for webcam devices.
Conversion from YUV to RGB is for preview image
Some FX convert the frame to RGB
Why YUV ?
=========
- Many video codecs decode into some YUV flavour
- Many capture devices deliver YUV
- Software conversion of RGB <-> YUV is expensive
- Consumes less bandwith then RGB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,16 @@
INCLUDES = -I$(top_srcdir)/libOSC -I$(includedir)
AM_CFLAGS=$(OP_CFLAGS)
OSC_LIB_FILE = libOSC.la
noinst_LTLIBRARIES = $(OSC_LIB_FILE)
libOSC_la_CFLAGS = $(AM_CFLAGS)
libOSC_la_SOURCES = OSC-address-space.c \
OSC-callbacklist.c \
OSC-drop.c \
OSC-pattern-match.c \
OSC-priority-queue.c \
OSC-receive.c \
OSC-string-help.c \
OSC-common.c \
OSC-timetag.c \
NetworkReturnAddress.c

View File

View File

@@ -0,0 +1,58 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
NetworkReturnAddress.c
This version implements UDP return addresses on SGI
Matt Wright,
9/11/98
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/NetworkReturnAddress.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <libOSC/NetworkUDP.h>
int SizeOfNetworkReturnAddress(void) {
return sizeof(struct NetworkReturnAddressStruct);
}
Boolean NetworkSendReturnMessage(NetworkReturnAddressPtr addr,
int n,
void *buf) {
if (addr == 0) return FALSE;
return n == sendto(addr->sockfd, buf, n, 0, &(addr->cl_addr), addr->clilen);
}

View File

@@ -0,0 +1,52 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
NetworkReturnAddress.h
API that the OSC Kit uses to deal with network return addresses. You will
fill in parts of this file and write NetworkReturnAddress.c to implement
this API via whatever network services you use.
NB: This API is the only interface the Kit uses for dealing with network
addresses, but of course the part of the application that accepts incoming
packets needs to know about network return addresses so it can fill in the
correct return address when it receives a packet.
Matt Wright,
6/3/98
*/
/* Return sizeof(struct NetworkReturnAddressStruct). */
int SizeOfNetworkReturnAddress(void);
/* Send a packet back to the client, or do nothing if addr==0 */
Boolean NetworkSendReturnMessage(NetworkReturnAddressPtr addr,
int n,
void *buf);

View File

@@ -0,0 +1,7 @@
#include <netinet/in.h>
struct NetworkReturnAddressStruct {
struct sockaddr_in cl_addr;
int clilen;
int sockfd;
};

View File

@@ -0,0 +1,599 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-address-space.c
Matt Wright, 3/16/98
*/
#include <config.h>
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <string.h>
#include <stdio.h>
#define MAX_ALIASES_PER_CONTAINER 3
#define MAX_CHILDREN_PER_CONTAINER 20
#define MAX_METHODS_PER_CONTAINER 30
#define BASE_NUM_TO_REALLOCATE 10
struct OSCContainerStruct {
struct OSCContainerStruct *parent;
int numChildren;
Name childrenNames[MAX_CHILDREN_PER_CONTAINER];
struct OSCContainerStruct *children[MAX_CHILDREN_PER_CONTAINER];
int numMethods;
Name methodNames[MAX_METHODS_PER_CONTAINER];
OSCMethod methods[MAX_METHODS_PER_CONTAINER];
struct OSCContainerQueryResponseInfoStruct QueryResponseInfo;
struct OSCContainerStruct *next;
};
struct OSCMethodStruct {
methodCallback callback;
void *context;
struct OSCMethodQueryResponseInfoStruct QueryResponseInfo;
struct OSCMethodStruct *next;
};
/* Globals */
static Boolean Initialized = FALSE;
static OSCcontainer OSCTopLevelContainer;
static OSCcontainer freeContainers; /* Linked list via next field. */
static OSCMethod freeMethods; /* Linked list via next field. */
static void *(*RealTimeMemoryAllocator)(int numBytes);
/* Note: The free list of containers should actually be a "free forest", so
that all the subcontainers recursively under a freed container are
automatically freed.
FREE: just stick the freed subtree on the front of the list.
ALLOC: Take all the children of the first container on the list and
insert them in the free list, then return that first container.
*/
/************************ Initialization and Memory ************************/
static void MakeFreeContainersList(int n) {
int i;
for (i = 0; i+1 < n; ++i) {
freeContainers[i].next = &(freeContainers[i+1]);
}
freeContainers[n-1].next = 0;
}
static void MakeFreeMethodsList(int n) {
int i;
for (i = 0; i+1 < n; ++i) {
freeMethods[i].next = &(freeMethods[i+1]);
}
freeMethods[n-1].next = 0;
}
OSCcontainer OSCInitAddressSpace(struct OSCAddressSpaceMemoryTuner *t) {
int bytesNeeded;
if (Initialized)
fatal_error("OSCInitAddressSpace: already initialized!");
Initialized = TRUE;
RealTimeMemoryAllocator = t->RealTimeMemoryAllocator;
bytesNeeded = (1 + t->initNumContainers) * sizeof(*freeContainers);
freeContainers = (OSCcontainer) (*(t->InitTimeMemoryAllocator))(bytesNeeded);
if (freeContainers == 0) {
fatal_error("OSCInitAddressSpace: couldn't allocate %d bytes for %d containers",
bytesNeeded, t->initNumContainers);
}
OSCTopLevelContainer = &freeContainers[t->initNumContainers];
MakeFreeContainersList(t->initNumContainers);
bytesNeeded = t->initNumMethods * sizeof(*freeMethods);
freeMethods = (OSCMethod) (*(t->InitTimeMemoryAllocator))(bytesNeeded);
if (freeMethods == 0) {
fatal_error("OSCInitAddressSpace: couldn't allocate %d bytes for %d methods",
bytesNeeded, t->initNumMethods);
}
MakeFreeMethodsList(t->initNumMethods);
/* Initialize the top-level container */
OSCTopLevelContainer->parent = 0;
OSCTopLevelContainer->numChildren = 0;
OSCTopLevelContainer->numMethods = 0;
OSCTopLevelContainer->QueryResponseInfo.comment = "OSC top-level container";
OSCTopLevelContainer->next = 0;
return OSCTopLevelContainer;
}
/* Container and method memory management: linked lists of free objects */
static OSCcontainer AllocContainer(void) {
static int numExtraAllocs = 0;
OSCcontainer result;
if (freeContainers != 0) {
result = freeContainers;
freeContainers = freeContainers->next;
return result;
}
OSCWarning("Out of memory for containers; trying to allocate more in real time");
{
int num = BASE_NUM_TO_REALLOCATE * ++numExtraAllocs;
freeContainers = (*RealTimeMemoryAllocator)(num * sizeof(*freeContainers));
if (freeContainers == 0) {
OSCWarning("Real-time allocation failed");
return 0;
}
MakeFreeContainersList(num);
return AllocContainer();
}
}
//static void FreeContainer(OSCcontainer c) {
// c->next = freeContainers;
// freeContainers = c;
//}
static OSCMethod AllocMethod(void) {
static int numExtraAllocs = 0;
OSCMethod result;
if (freeMethods != 0) {
result = freeMethods;
freeMethods = freeMethods->next;
return result;
}
OSCWarning("Out of memory for methods; trying to allocate more in real time");
{
int num = BASE_NUM_TO_REALLOCATE * ++numExtraAllocs;
freeMethods = (*RealTimeMemoryAllocator)(num * sizeof(*freeMethods));
if (freeMethods == 0) {
OSCWarning("Real-time allocation failed");
return 0;
}
MakeFreeMethodsList(num);
return AllocMethod();
}
}
//static void FreeMethod(OSCMethod c) {
// c->next = freeMethods;
// freeMethods = c;
//}
/**************************** Containers ****************************/
/* Managing the tree of containers and subcontainers, with aliases */
void AddSubContainer(OSCcontainer parent, OSCcontainer child, Name name) {
if (parent->numChildren >= MAX_CHILDREN_PER_CONTAINER) {
fatal_error("AddSubContainer: exceeded MAX_CHILDREN_PER_CONTAINER (%d)\n"
"Increase the value in OSC-address-space.c and recompile.",
MAX_CHILDREN_PER_CONTAINER);
}
parent->childrenNames[parent->numChildren] = name;
parent->children[parent->numChildren] = child;
++(parent->numChildren);
}
Boolean OSCAddContainerAlias(OSCcontainer container, Name otherName) {
if (container->parent->numChildren >= MAX_CHILDREN_PER_CONTAINER) {
return FALSE;
}
AddSubContainer(container->parent, container, otherName);
return TRUE;
}
void RemoveSubContainer(OSCcontainer parent, OSCcontainer child) {
int i, numRemoved;
/* Remove every pointer to the container, even if it has multiple aliases */
numRemoved = 0;
for (i = 0; i < parent->numChildren; ++i) {
if (parent->children[i] != child) {
parent->children[i-numRemoved] = parent->children[i];
parent->childrenNames[i-numRemoved] = parent->childrenNames[i];
} else {
++numRemoved;
}
}
parent->numChildren -= numRemoved;
if (numRemoved == 0) {
fatal_error("RemoveSubContainer: subcontainer not found!\n");
}
}
Boolean OSCRemoveContainerAlias(OSCcontainer container, Name otherName) {
int i, j;
OSCcontainer parent = container->parent;
Boolean found = FALSE;
for (i = 0; i < parent->numChildren; ++i) {
if (parent->childrenNames[i] == otherName) {
if (parent->children[i] != container) {
fatal_error("OSCRemoveContainerAlias: %s is actually a sibling's name!",
otherName);
}
found = TRUE;
for (j = i+1; j < parent->numChildren; ++j) {
parent->children[j-1] = parent->children[j];
parent->childrenNames[j-1] = parent->childrenNames[j];
--(parent->numChildren);
}
}
}
if (!found) {
fatal_error("OSCRemoveContainerAlias: %s not found!", otherName);
}
/* Now make sure the child still exists under another name */
for (i = 0; i < parent->numChildren; ++i) {
if (parent->children[i] == container) return TRUE;
}
OSCWarning("OSCRemoveContainerAlias: %s was the last name for that subcontainer");
/* xxx should recursively free the container and its children... */
return TRUE;
}
OSCcontainer OSCNewContainer(Name name, OSCcontainer parent,
struct OSCContainerQueryResponseInfoStruct *QueryResponseInfo) {
OSCcontainer me;
me = AllocContainer();
if (me == 0) return 0;
if (strchr(name, '/') != NULL) {
OSCProblem("Container name \"%s\" contains a slash --- not good.",
name);
return 0;
}
me->parent = parent;
AddSubContainer(me->parent, me, name);
me->numChildren = 0;
me->numMethods = 0;
me->QueryResponseInfo = (*QueryResponseInfo);
return me;
}
static const char *ContainerName(OSCcontainer c) {
/* Return the first name associated with me in my parent's child list.
(Assume all later ones are aliases.) */
int i;
for (i = 0; i < c->parent->numChildren; ++i) {
if (c->parent->children[i] == c) {
return c->parent->childrenNames[i];
}
}
fatal_error("ContainerName: Container %p isn't in its parent's child list.", c);
return 0;
}
static int gasHelp(char *target, int maxlength, OSCcontainer c );
Boolean OSCGetAddressString(char *target, int maxLength, OSCcontainer c) {
int lenNeeded;
if (maxLength <= 1) return FALSE;
lenNeeded = gasHelp(target, maxLength-1, c) + 1; /* -1, +1 are for null char. */
if (lenNeeded > maxLength) {
OSCProblem("Address string too long (room for %d chars; need %d)",
maxLength, lenNeeded);
target[0] = '\0';
return FALSE;
}
return TRUE;
}
static int gasHelp(char *target, int maxLength, OSCcontainer c) {
int sublength, length;
const char *myName;
/* printf("*** gasHelp %s %d %p %s\n", target, maxLength, c, c->name); */
if (c == OSCTopLevelContainer) {
target[0] = '/';
target[1] = '\0';
return 1;
}
myName = ContainerName(c);
sublength = gasHelp(target, maxLength, c->parent);
length = sublength + strlen(myName) + 1; /* +1 is for trailing slash */
if (length > maxLength) {
return length;
}
strcpy(target+sublength, myName);
target[length-1] = '/';
target[length] = '\0';
return length;
}
/**************************** Methods ****************************/
#define LONG_ADDR_SIZE 1000 /* Just for error messages */
OSCMethod OSCNewMethod(Name name, OSCcontainer me, methodCallback callback,
void *context, struct OSCMethodQueryResponseInfoStruct *QueryResponseInfo) {
char addr[LONG_ADDR_SIZE];
OSCMethod m;
if (strchr(name, '/') != NULL) {
OSCProblem("Method name \"%s\" contains a slash --- not good.",
name);
return 0;
}
if (me->numMethods >= MAX_METHODS_PER_CONTAINER) {
addr[0] = '\0';
OSCGetAddressString(addr, LONG_ADDR_SIZE, me);
OSCProblem("OSCNewMethod: container %s already has %d methods; can't add another\n"
"Change MAX_METHODS_PER_CONTAINER in OSC-address-space.c and recompile.",
addr, me->numMethods);
return 0;
}
m = AllocMethod();
if (!m) return 0;
m->callback = callback;
m->context = context;
m->QueryResponseInfo = *QueryResponseInfo;
me->methodNames[me->numMethods] = name;
me->methods[me->numMethods] = m;
++(me->numMethods);
return m;
}
/**************************** Queries ****************************/
void OSCInitContainerQueryResponseInfo(struct OSCContainerQueryResponseInfoStruct *i) {
i->comment = 0;
}
void OSCInitMethodQueryResponseInfo(struct OSCMethodQueryResponseInfoStruct *i) {
i->description = 0;
i->pvq = 0;
}
/******************************* Debug ********************************/
static int ContainerAliases(OSCcontainer c, char *target) {
/* Write a space-delimited list of alias names in the given string,
and return the number */
int i, n;
if (c == OSCTopLevelContainer) return 0;
target[0] = '\0';
n = 0;
for (i = 0; i < c->parent->numChildren; ++i) {
if (c->parent->children[i] == c) {
if (n > 0) {
strcat(target, " ");
strcat(target, c->parent->childrenNames[i]);
}
++n;
}
}
if (n == 0) fatal_error("ContainerAliases: internal inconsistency");
return n-1;
}
#define BIG_ADDRESS 50
static void PrintHelp(OSCcontainer c) {
char addr[BIG_ADDRESS];
char aliasNames[1000];
int i, j, numAliases;
if (OSCGetAddressString(addr, BIG_ADDRESS, c) == FALSE) {
printf(" /.../%s", ContainerName(c));
} else {
printf(" %s", addr);
}
numAliases = ContainerAliases(c, aliasNames);
if (numAliases > 0) {
printf(" (%d aliases:%s)", numAliases, aliasNames);
}
printf("\n");
for (i = 0; i < c->numMethods; ++i) {
printf(" %s%s: %s\n", addr, c->methodNames[i],
c->methods[i]->QueryResponseInfo.description);
}
/* Forgive this quadratic kludge: */
for (i = 0; i < c->numChildren; ++i) {
int matches = 0;
for (j = 0; j < i; ++j) {
if (c->children[j] == c->children[i]) {
/* c->children[i] is just an alias to c->children[j],
which we already printed, so ignore it. */
matches ++;
}
}
if(matches == 0 ) PrintHelp(c->children[i]);
}
}
void OSCPrintWholeAddressSpace(void) {
printf("\n----- The OSC address space -----\n");
PrintHelp(OSCTopLevelContainer);
printf("...end of OSC address space.\n\n\n");
}
/***************************** Dispatching *****************************/
#include <libOSC/OSC-dispatch.h>
#include <libOSC/OSC-callbacklist.h>
#include <libOSC/OSC-pattern-match.h>
/* To do quick concatenation of singly-linked lists, we pass around
this data structure that points to the first and last elements: */
typedef struct callbackListEnds_struct {
callbackList begin;
callbackList end;
} callbackListEnds;
/* Helper proc. declarations */
static callbackListEnds DispatchSubMessage(char *pattern, OSCcontainer c);
static char *NextSlashOrNull(char *p);
callbackList OSCDispatchMessage(char *pattern) {
callbackListEnds result;
if (pattern[0] != '/') {
OSCProblem("Invalid address \"%s\" does not begin with /", pattern);
return 0;
}
result = DispatchSubMessage(pattern+1, OSCTopLevelContainer);
return result.begin;
}
#define LONG_ADDR_LEN 100
static callbackListEnds DispatchSubMessage(char *pattern, OSCcontainer c) {
callbackListEnds result;
char *nextSlash, *restOfPattern;
char offendingAddr[LONG_ADDR_LEN];
int i;
result.begin = result.end = 0;
nextSlash = NextSlashOrNull(pattern);
if (*nextSlash == '\0') {
/* Base case: the pattern names methods of this container. */
for (i = 0; i < c->numMethods; i++) {
if (PatternMatch(pattern, c->methodNames[i])) {
callbackList node = AllocCallbackListNode(c->methods[i]->callback,
c->methods[i]->context,
result.begin);
if (node == 0) {
/* Excuse the hairyness of the code to generate the error message. */
if (OSCGetAddressString(offendingAddr,
LONG_ADDR_LEN-strlen(c->methodNames[i]),
c)) {
strcat(offendingAddr, c->methodNames[i]);
} else {
strcpy(offendingAddr, c->methodNames[i]);
}
OSCWarning("No memory for callback node; not invoking %s",
offendingAddr);
} else {
if (result.end == 0) {
result.end = node;
}
result.begin = node;
}
}
}
} else {
/* Recursive case: in the middle of an address, so the job at this
step is to look for containers that match. We temporarily turn
the next slash into a null so pattern will be a null-terminated
string of the stuff between the slashes. */
*nextSlash = '\0';
restOfPattern = nextSlash + 1;
for (i = 0; i < c->numChildren; ++i) {
if (PatternMatch(pattern, c->childrenNames[i])) {
callbackListEnds subResult =
DispatchSubMessage(restOfPattern, c->children[i]);
if (result.end == 0) {
result = subResult;
} else {
subResult.end->next = result.begin;
result.begin = subResult.begin;
}
}
}
*nextSlash = '/';
}
return result;
}
static char *NextSlashOrNull(char *p) {
while (*p != '/' && *p != '\0') {
p++;
}
return p;
}

View File

@@ -0,0 +1,364 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-address-space.h
Matt Wright, 11/20/97
Version 2.0 5/28/98
C interface for registering the nodes in the OSC address space for an
application.
include OSC-timetag.h before this file
****************************** Introduction ******************************
The model is based on our original C++ design and consists of two kinds of
objects:
methods are the leaf nodes of the address space hierarchy. A complete OSC
address corresponds to a particular method, which has a corresponding
callback procedure that will be invoked to implement commands sent by an
OSC client.
containers are branch nodes of the address space hierarchy, and contain
methods and other containers. Each container has a single namespace;
it cannot contain a method and a subcontainer with the same name.
For example, let's examine the OSC message "/resonators/foo/decay 2.5". The
address of this message is "/resonators/foo/decay" and the message has a
single argument, 2.5. We'd say that the object corresponding to the prefix
"/resonators" is a container, and that it contains another container whose
address is "/resonators/foo". The "/resonators/foo" container has a method
"decay".
The memory model used by this module is pre-allocation of fixed-size objects
for containers, methods, and other internal objects. This preallocated
memory is dynamically managed internally by a custom high-performance memory
allocator. When the preallocated memory runs out, this module calls an
optional realtime memory allocator that you provide. If your memory allocator
gives this module more memory, it will add it to the pool of objects and
never free the memory. If your system does not have a realtime memory
allocator, provide a procedure that always returns 0.
*/
/*************************** Type Definitions ******************************/
/* Users of this module don't get to see what's inside these objects */
typedef struct OSCContainerStruct *OSCcontainer;
typedef struct OSCMethodStruct *OSCMethod;
/* This makes it easy to change the way we represent symbolic names: */
typedef const char *Name;
/************************ Initialization and Memory ************************/
/* You will fill an OSCAddressSpaceMemoryTuner struct with the parameters that
determine how memory will be allocated.
initNumContainers is the number of containers that will be allocated at
initialization time. This should be the maximum number of containers you
ever expect to have in your address space.
initNumMethods is the number of methods that will be allocated at
initialization time. If you register the same method callback procedure
multiple times at different places in the address space, each of these
locations counts as a separate method as far as memory allocation is
concerned.
The MemoryAllocator fields are procedures you will provide that allocate
memory. Like malloc(), they take the number of bytes as arguments and return
either a pointer to the new memory or 0 for failure. This memory will never
be freed.
The InitTimeMemoryAllocator will be called only at initialization time,
i.e., before OSCInitAddressSpace() returns. If it ever returns 0, that's
a fatal error.
The RealTimeMemoryAllocator will be called if, while the application is
running, the address space grows larger than can fit in what was allocated
at initialization time. If the RealTimeMemoryAllocator() returns 0, the
operation attempting to grow the address space will fail. If your system
does not have real-time memory allocation, RealTimeMemoryAllocator should
be a procedure that always returns 0.
*/
struct OSCAddressSpaceMemoryTuner {
int initNumContainers;
int initNumMethods;
void *(*InitTimeMemoryAllocator)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
};
/* Given an OSCAddressSpaceMemoryTuner, return the number of bytes of
memory that would be allocated if OSCInitAddressSpace() were called
on it. */
int OSCAddressSpaceMemoryThatWouldBeAllocated(struct OSCAddressSpaceMemoryTuner *t);
/* Call this before you call anything else. It returns the container that
corresponds to the address "/" and is the root of the address space tree.
*/
OSCcontainer OSCInitAddressSpace(struct OSCAddressSpaceMemoryTuner *t);
/**************************** Containers ****************************/
/* Here's how this system deals with the standard OSC queries addressed to
containers. This module handles the details of listening for these queries
and returning a correctly-formatted answer; all it needs from you is the
actual data that constitute the answers to these queries.
You pass this data in an OSCContainerQueryResponseInfo structure. Future versions
of this module may have new kinds of queries that they can deal with, so
the list of fields in this structure may grow. That's why your code should
call OSCInitContainerQueryResponseInfo() on your struct before putting new values
into it; this procedure will initialize all of the fields to 0, meaning
"don't have that information", which will cause the associated queries to
fail.
The "null" message, i.e., a message with a trailing slash, requesting the
list of addresses under a given container, is handled automatically.
*/
struct OSCContainerQueryResponseInfoStruct {
char *comment;
/* Other fields may go here */
};
void OSCInitContainerQueryResponseInfo(struct OSCContainerQueryResponseInfoStruct *i);
/* Allocate a new container and initialize it. Returns 0 if it cannot
allocate a new container, e.g., if you've exceeded the initNumContainers
limit of the OSCAddressSpaceMemoryTuner() and the RealTimeMemoryAllocator()
didn't return any new memory.
This procedure doesn't make a copy of the name string or any of the
contents of the OSCContainerQueryResponseInfoStruct. It does copy the fields
of the OSCContainerQueryResponseInfoStruct.
*/
OSCcontainer OSCNewContainer(Name name, OSCcontainer parent,
struct OSCContainerQueryResponseInfoStruct *queryInfo);
/* Remove a container from the address space. This also removes all the
container's methods and recursively removes all sub-containers. Memory
freed by removing a container is kept in this module's internal pool.
*/
void OSCRemoveContainer(OSCcontainer container);
/* Given a pointer to a container, and another name for that container, add or
remove that name as an alias for the container. Return FALSE for failure. */
Boolean OSCAddContainerAlias(OSCcontainer container, Name otherName);
Boolean OSCRemoveContainerAlias(OSCcontainer container, Name otherName);
/* Write the OSC address of the given container into the given string.
Return FALSE if the address won't fit in the string. */
Boolean OSCGetAddressString(char *target, int maxLength, OSCcontainer c);
/* Given an address (not a pattern!), return the single OSCcontainer it names,
or 0 if there is no container at that address */
OSCcontainer OSCLookUpContainer(Name address);
/**************************** Methods ****************************/
/* A methodCallback is a procedure that you write that will be called at the
time that an OSC message is to take effect. It will be called with 5
arguments:
- A context pointer that was registered with the methodNode
this is a method of. (Something like the C++ "this" pointer.)
- The number of bytes of argument data
- A pointer to the argument portion of the OSC message
- The time tag at which this message is supposed to take effect.
- A "return address" object you can use to send a message back to the
client that sent this message. This return channel is guaranteed
to be usable only during the invocation of your method, so your method
must use the return address immediately or ignore it, not store it away
for later use.
*/
typedef struct NetworkReturnAddressStruct *NetworkReturnAddressPtr;
/* removed const */
typedef void (*methodCallback)(void *context, int arglen, const void *args,
OSCTimeTag when, NetworkReturnAddressPtr returnAddr);
/* A ParamValQuerier is a procedure that the OSC system will call when the
user wants to know the current value of a parameter. It will be passed the
same context pointer as the associated method. It should write its return
value in the given buffer in the same format as the associated
methodCallback would expect its "args" argument, and should return the
length of data just like the method would expect in its "arglen" argument.
It doesn't have to worry about the address portion of the OSC message.
*/
typedef char OSCData; /* For pointers to OSC-formatted data */
typedef int (*ParamValQuerier)(OSCData *result, void *context);
/* This system deals with other standard per-method queries, such as
documentation, valid parameter types and ranges, units, default values,
etc., pretty much just like per-container queries.
*/
struct OSCMethodQueryResponseInfoStruct {
char *description;
ParamValQuerier pvq;
/* For each argument of the method:
min, max, default, units */
};
void OSCInitMethodQueryResponseInfo(struct OSCMethodQueryResponseInfoStruct *i);
/* Allocate a new method, initialize it, and add it to a container. Returns 0
for failure, e.g., if you've exceeded the initNumMethods limit of the
OSCAddressSpaceMemoryTuner() and the RealTimeMemoryAllocator() didn't return any
new memory.
This procedure doesn't make a copy of the name string or any of the
contents of the OSCMethodQueryResponseInfoStruct.
*/
OSCMethod OSCNewMethod(Name name, OSCcontainer container, methodCallback meth,
void *context, struct OSCMethodQueryResponseInfoStruct *queryInfo);
/******************************* Debug ********************************/
void OSCPrintWholeAddressSpace(void);
/**************************** Sample Code *****************************/
/* Here's a gross approximation of how your application will invoke the
procedures in this module. It registers an address space with
containers with addresses "/foo", "/foo/foochild", and "/bar",
and gives each of them "play" and "shuddup" messages.
#include "OSC-common.h"
#include "OSC-timetag.h"
#include "OSC-address-space.h"
typedef struct {
int playing;
int param;
float otherParam;
} Player;
void PlayCallback(void *context, int arglen, const void *vargs,
OSCTimeTag when, NetworkReturnAddressPtr ra) {
Player *p = context;
const int *args = vargs;
p->playing = 1;
if (arglen >= 4) {
p->param = args[0];
}
}
void ShuddupCallback(void *context, int arglen, const void *vargs,
OSCTimeTag when, NetworkReturnAddressPtr ra) {
Player *p = context;
const float *args = vargs;
p->playing = 0;
if (arglen >= 4) {
p->otherParam = args[0];
}
}
void *InitTimeMalloc(int numBytes) {
return malloc(numBytes);
}
void *NoRealTimeMalloc(int numBytes) {
return 0;
}
main() {
struct OSCAddressSpaceMemoryTuner oasmt;
OSCcontainer topLevelContainer, foo, foochild, bar;
struct OSCContainerQueryResponseInfoStruct ocqris;
struct OSCMethodQueryResponseInfoStruct omqris;
Player *players;
players = (Player *) malloc(3 * sizeof(*players));
if (!players) exit(1);
oasmt.initNumContainers = 10;
oasmt.initNumMethods = 10;
oasmt.InitTimeMemoryAllocator = InitTimeMalloc;
oasmt.RealTimeMemoryAllocator = NoRealTimeMalloc;
topLevelContainer = OSCInitAddressSpace(&oasmt);
OSCInitContainerQueryResponseInfo(&ocqris);
ocqris.comment = "Foo for you";
foo = OSCNewContainer("foo", topLevelContainer, &ocqris);
OSCInitContainerQueryResponseInfo(&ocqris);
ocqris.comment = "Beware the son of foo!";
foochild = OSCNewContainer("foochild", foo, &ocqris);
OSCInitContainerQueryResponseInfo(&ocqris);
ocqris.comment = "Belly up to the bar";
bar = OSCNewContainer("bar", topLevelContainer, &ocqris);
if (foo == 0 || foochild == 0 || bar == 0) {
fprintf(stderr, "Problem!\n");
exit(1);
}
OSCInitMethodQueryResponseInfo(&omqris);
OSCNewMethod("play", foo, PlayCallback, &(players[0]), &omqris);
OSCNewMethod("shuddup", foo, ShuddupCallback, &(players[0]), &omqris);
OSCNewMethod("play", foochild, PlayCallback, &(players[1]), &omqris);
OSCNewMethod("shuddup", foochild, ShuddupCallback, &(players[1]), &omqris);
OSCNewMethod("play", bar, PlayCallback, &(players[2]), &omqris);
OSCNewMethod("shuddup", bar, ShuddupCallback, &(players[2]), &omqris);
}
*/

View File

@@ -0,0 +1,95 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-callbacklist.c
Linked lists of methods
Matt Wright, 11/20/97
Allocator is a simple linked list of free nodes.
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/OSC-dispatch.h>
#include <libOSC/OSC-callbacklist.h>
static callbackList allNodes;
static callbackList freeNodes;
/* Call this before you call anything else */
Boolean InitCallbackListNodes(int numNodes, void *(*InitTimeMalloc)(int numBytes)) {
int i;
allNodes = (*InitTimeMalloc)(numNodes * sizeof(*allNodes));
if (allNodes == 0) return FALSE;
/* Initialize list of freeNodes */
freeNodes = &(allNodes[0]);
for (i = 0; i < numNodes-1; ++i) {
allNodes[i].next = &(allNodes[i+1]);
}
allNodes[numNodes-1].next = 0;
return TRUE;
}
callbackList AllocCallbackListNode(methodCallback callback, void *context,
struct callbackListNode *next) {
callbackList result;
if (freeNodes == 0) {
/* OSCProblem("Out of memory for callback lists!"); */
return 0;
}
result = freeNodes;
freeNodes = freeNodes->next;
result->callback = callback;
result->context = context;
result->next = next;
#ifdef DEBUG_CBL
printf("AllocCallbackListNode: returning %p (cb %p, context %p, next %p)\n",
result, result->callback, result->context, result->next);
#endif
return result;
}
void FreeCallbackListNode(callbackList cb) {
#ifdef DEBUG_CBL
printf("FreeCallbackListNode(%p)\n", cb);
#endif
cb->next = freeNodes;
freeNodes = cb;
}

View File

@@ -0,0 +1,49 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-callbacklist.h
Linked lists of methods
Matt Wright, 3/13/98
include "OSC-dispatch.h" before this file.
*/
/* Call this before you call anything else. */
Boolean InitCallbackListNodes(int numNodes, void *(*InitTimeMalloc)(int numBytes));
callbackList AllocCallbackListNode(methodCallback callback, void *context,
struct callbackListNode *next);
void FreeCallbackListNode(callbackList);

View File

@@ -0,0 +1,87 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-system-dependent.c
Matt Wright, 3/13/98
File of procedures OSC has to call that are not part of the OSC package
and that you, the developer adding OSC addressability to an application,
must write in a way that makes sense in the context of your system.
You should also look at OSC-timetag.c and see if there's a better way
to handle time tags on your system.
*/
#include <libOSC/OSC-common.h>
/* Printing stuff: for now, use stderr. Some cleverer stuff we could do:
- Make a silent mode where these don't do anything.
- Return error messages via OSC to some client
*/
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdint.h>
void fatal_error(char *s, ...) {
va_list ap;
fprintf(stderr, "Fatal error: ");
va_start(ap, s);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(-321);
}
void OSCProblem(char *s, ...) {
va_list ap;
fprintf(stderr, "OSC Problem: ");
va_start(ap, s);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
va_end(ap);
}
void OSCWarning(char *s, ...) {
/* va_list ap;
fprintf(stderr, "OSC Warning: ");
va_start(ap, s);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
va_end(ap);*/
}

View File

@@ -0,0 +1,60 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-common.h
Simple stuff to #include everywhere in the OSC package
by Matt Wright, 3/13/98
*/
/* Boolean type */
#ifndef TRUE
typedef int Boolean;
#define TRUE 1
#define FALSE 0
#endif
/* Fixed byte width types */
typedef int int4; /* 4 byte int */
/* Printing type procedures. All take printf-style format string */
/* Catastrophic failure: print message and halt system */
void fatal_error(char *s, ...);
/* Error message for user */
void OSCProblem(char *s, ...);
/* Warning for user */
void OSCWarning(char *s, ...);

View File

@@ -0,0 +1,52 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-dispatch.h
Given an OSC message pattern from an incoming message, match the
pattern against the OSC address space and produce a list of the
callbacks corresponding to all the addresses that were matched.
Matt Wright, 6/5/98
*/
/***************************** Dispatching *****************************/
typedef struct callbackListNode {
methodCallback callback;
void *context;
struct callbackListNode *next;
} *callbackList;
/* Given an OSC message pattern from an incoming message, match the
pattern against the OSC address space and produce a list of the
callbacks corresponding to all the addresses that were matched. */
callbackList OSCDispatchMessage(char *pattern);

View File

@@ -0,0 +1,58 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-drop.c
This implementation just prints a warning.
Matt Wright, 3/16/98
*/
#include <stdint.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/NetworkReturnAddress.h>
#include <libOSC/OSC-receive.h>
#include <libOSC/OSC-drop.h>
void DropPacket(OSCPacketBuffer p) {
OSCWarning("Packet dropped.");
}
void DropBundle(char *buf, int n, OSCPacketBuffer p) {
OSCWarning("Bundle dropped.");
}
void DropMessage(char *buf, int n, OSCPacketBuffer p) {
OSCWarning("Message dropped.");
}

View File

@@ -0,0 +1,43 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-drop.h
These procedures will be called on a packet, bundle, or message that's
being dropped for whatever reason. They can do nothing, print (or
otherwise inform the user of) a warning, save the offending data somewhere,
etc.
Matt Wright, 3/16/98
*/
void DropPacket(OSCPacketBuffer p);
void DropBundle(char *buf, int n, OSCPacketBuffer p);
void DropMessage(char *buf, int n, OSCPacketBuffer p);

View File

@@ -0,0 +1,70 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-internal-messages.h
Interface for having an application send OSC messages to itself
internally.
All these procedures return FALSE if unable to deliver the message.
Matt Wright, 3/17/98
*/
/* Send a message immediately, with no return address. This procedure
returns after the message has been sent (or has failed to be sent),
so the memory for address and args can be on the stack. Returns FALSE
if there's a problem; TRUE otherwise. */
Boolean OSCSendInternalMessage(char *address, int arglen, void *args);
/* Same thing, but with a return address supplied. */
Boolean OSCSendInternalMessageWithRSVP(char *address, int arglen, void *args,
NetworkReturnAddressPtr returnAddr);
/* Schedule some messages to occur at a given time. This allocates one of the
OSCPacketBuffer structures (see OSC-receive.h) to hold the addresses and argument
data until the messages take effect, so if you're going to call this, you
should take this use of packets into account in setting the
numReceiveBuffers argument to OSCInitReceive().
This provides an less general interface than OSC's bundle mechanism, because
the bundle of messages you provide cannot include subbundles.
The addresses, arglens, and args arguments are arrays of size numMessages.
There's no return address argument because you're not allowed to save a network
return address for later use.
*/
Boolean OSCScheduleInternalMessages(OSCTimeTag when, int numMessages,
char **addresses, int *arglens,
void **args);

View File

@@ -0,0 +1,193 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-pattern-match.c
Matt Wright, 3/16/98
Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-pattern-match.h>
#include <stdint.h>
#include <sys/time.h>
static const char *theWholePattern; /* Just for warning messages */
static Boolean MatchBrackets (const char *pattern, const char *test);
static Boolean MatchList (const char *pattern, const char *test);
Boolean PatternMatch (const char * pattern, const char * test) {
theWholePattern = pattern;
if (pattern == 0 || pattern[0] == 0) {
return test[0] == 0;
}
if (test[0] == 0) {
if (pattern[0] == '*')
return PatternMatch (pattern+1,test);
else
return FALSE;
}
switch (pattern[0]) {
case 0 : return test[0] == 0;
case '?' : return PatternMatch (pattern + 1, test + 1);
case '*' :
if (PatternMatch (pattern+1, test)) {
return TRUE;
} else {
return PatternMatch (pattern, test+1);
}
case ']' :
case '}' :
OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
return FALSE;
case '[' :
return MatchBrackets (pattern,test);
case '{' :
return MatchList (pattern,test);
case '\\' :
if (pattern[1] == 0) {
return test[0] == 0;
} else if (pattern[1] == test[0]) {
return PatternMatch (pattern+2,test+1);
} else {
return FALSE;
}
default :
if (pattern[0] == test[0]) {
return PatternMatch (pattern+1,test+1);
} else {
return FALSE;
}
}
}
/* we know that pattern[0] == '[' and test[0] != 0 */
static Boolean MatchBrackets (const char *pattern, const char *test) {
Boolean result;
Boolean negated = FALSE;
const char *p = pattern;
if (pattern[1] == 0) {
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
if (pattern[1] == '!') {
negated = TRUE;
p++;
}
while (*p != ']') {
if (*p == 0) {
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
if (p[1] == '-' && p[2] != 0) {
if (test[0] >= p[0] && test[0] <= p[2]) {
result = !negated;
goto advance;
}
}
if (p[0] == test[0]) {
result = !negated;
goto advance;
}
p++;
}
result = negated;
advance:
if (!result)
return FALSE;
while (*p != ']') {
if (*p == 0) {
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
p++;
}
return PatternMatch (p+1,test+1);
}
static Boolean MatchList (const char *pattern, const char *test) {
const char *restOfPattern, *tp = test;
for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
if (*restOfPattern == 0) {
OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
return FALSE;
}
}
restOfPattern++; /* skip close curly brace */
pattern++; /* skip open curly brace */
while (1) {
if (*pattern == ',') {
if (PatternMatch (restOfPattern, tp)) {
return TRUE;
} else {
tp = test;
++pattern;
}
} else if (*pattern == '}') {
return PatternMatch (restOfPattern, tp);
} else if (*pattern == *tp) {
++pattern;
++tp;
} else {
tp = test;
while (*pattern != ',' && *pattern != '}') {
pattern++;
}
if (*pattern == ',') {
pattern++;
}
}
}
}

View File

@@ -0,0 +1,35 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-pattern-match.h
*/
Boolean PatternMatch (const char *pattern, const char *test);

View File

@@ -0,0 +1,190 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-priority-queue.c
Priority queue used by OSC time tag scheduler
This is the most trivial implementation, an unsorted array of queued
objects, mostly for debug purposes.
Matt Wright, 9/17/98
*/
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-priority-queue.h>
#include <stdint.h>
#include <sys/time.h>
#define PRINT_PRIORITY_QUEUE
#ifdef DEBUG_OSC_PRIORITY_QUEUE
#define PRINT_PRIORITY_QUEUE
#endif
#if defined(PRINT_PRIORITY_QUEUE) || defined(DEBUG_OSC_PRIORITY_QUEUE)
#include <stdio.h>
void OSCQueuePrint(OSCQueue q);
#endif
#define CAPACITY 1000
struct OSCQueueStruct {
OSCSchedulableObject list[CAPACITY];
int n;
int scanIndex;
};
OSCQueue OSCNewQueue(int maxItems, void *(*InitTimeMalloc)(int numBytes)) {
OSCQueue result;
if (maxItems > CAPACITY) fatal_error("Increase CAPACITY in OSC-priority-queue.c");
result = (*InitTimeMalloc)(sizeof(*result));
if (result == 0) return 0;
result->n = 0;
#ifdef DEBUG_OSC_PRIORITY_QUEUE
OSCQueuePrint(result);
#endif
return result;
}
int OSCQueueInsert(OSCQueue q, OSCSchedulableObject new) {
if (q->n == CAPACITY) return FALSE;
q->list[q->n] = new;
++(q->n);
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueInsert: just inserted %p\n", new);
OSCQueuePrint(q);
#endif
return TRUE;
}
OSCTimeTag OSCQueueEarliestTimeTag(OSCQueue q) {
int i;
OSCTimeTag smallest = OSCTT_BiggestPossibleTimeTag();
for (i = 0; i < q->n; ++i) {
if (OSCTT_Compare(smallest, q->list[i]->timetag) > 0) {
smallest = q->list[i]->timetag;
}
}
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueEarliestTimeTag: about to return %llx\n", smallest);
OSCQueuePrint(q);
#endif
return smallest;
}
static void RemoveElement(int goner, OSCQueue q) {
int i;
--(q->n);
for (i = goner; i < q->n; ++i) {
q->list[i] = q->list[i+1];
}
}
OSCSchedulableObject OSCQueueRemoveEarliest(OSCQueue q) {
OSCSchedulableObject result;
int i, smallestIndex;
if (q->n == 0) {
OSCWarning("OSCQueueRemoveEarliest: empty queue");
return NULL;
}
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueRemoveEarliest: begin\n");
OSCQueuePrint(q);
#endif
smallestIndex = 0;
for (i = 1; i < q->n; ++i) {
if (OSCTT_Compare(q->list[smallestIndex]->timetag, q->list[i]->timetag) > 0) {
smallestIndex = i;
}
}
result = q->list[smallestIndex];
RemoveElement(smallestIndex, q);
#ifdef DEBUG_OSC_PRIORITY_QUEUE
printf("OSCQueueRemoveEarliest: done\n");
OSCQueuePrint(q);
#endif
return result;
}
#ifdef PRINT_PRIORITY_QUEUE
void OSCQueuePrint(OSCQueue q) {
int i;
printf("OSC Priority queue at %p has %d elements:\n", q, q->n);
for (i = 0; i < q->n; ++i) {
printf(" list[%2d] is %p, timetag = %llx\n", i, q->list[i], q->list[i]->timetag);
}
printf("\n\n");
}
#endif
void OSCQueueScanStart(OSCQueue q) {
q->scanIndex = 0;
}
OSCSchedulableObject OSCQueueScanNext(OSCQueue q) {
if (q->scanIndex >= q->n) return 0;
return (q->list[(q->scanIndex)++]);
}
void OSCQueueRemoveCurrentScanItem(OSCQueue q) {
/* Remember that q->scanIndex is the index of the *next*
item that will be returned, so the "current" item, i.e.,
the one most recently returned by OSCQueueScanNext(),
is q->scanIndex-1. */
RemoveElement(q->scanIndex-1, q);
--(q->scanIndex);
}
void CheckWholeQueue(void) {
}

View File

@@ -0,0 +1,90 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-priority-queue.h
Interface to priority queue used by OSC time tag scheduler
Matt Wright, 3/13/98
*/
/* include OSC-timetag.h before this file. */
/* This queue manages pointers to data objects. It doesn't care what's in the
objects except that the first element has to be an OSCTimeTag. So whatever
data you want to store, cast your pointer to it to a pointer to this type. */
typedef struct {
OSCTimeTag timetag;
/* There will be other stuff... */
} *OSCSchedulableObject;
typedef struct OSCQueueStruct *OSCQueue;
/* Make a new queue, or return 0 for failure. */
OSCQueue OSCNewQueue(int maxItems, void *(*InitTimeMalloc)(int numBytes));
/* Put something into the queue. Return FALSE if quque is full. */
Boolean OSCQueueInsert(OSCQueue q, OSCSchedulableObject o);
/* What's the time tag of the earliest item in the queue?
Return OSCTT_BiggestPossibleTimeTag() if queue is empty. */
OSCTimeTag OSCQueueEarliestTimeTag(OSCQueue q);
/* Remove the item from the front of the queue. Fatal error
if the queue is empty. */
OSCSchedulableObject OSCQueueRemoveEarliest(OSCQueue q);
/* Interface for examining items currently stored on the queue:
- To start, call OSCQueueScanStart().
- Then each subsequent call to OSCQueueScanNext() returns a pointer to an
OSCSchedulableObject that is stored on the queue, until
OSCQueueScanNext() returns 0 to indicate that all objects on the queue
have been scanned.
The objects returned by OSCQueueScanNext() come in chronological order (or
approximately chronological order, depending on the underlying queue data
structure).
If you call OSCQueueRemoveCurrentScanItem(), the object most recently
returned by OSCQueueScanNext() will be removed from the queue.
If there are any insertions or deletions to the queue, the sequence of
scanned objects must still include every object in the queue. This may
cause a particular object to be returned more than once by
OSCQueueScanNext().
*/
void OSCQueueScanStart(OSCQueue q);
OSCSchedulableObject OSCQueueScanNext(OSCQueue q);
void OSCQueueRemoveCurrentScanItem(OSCQueue q);

View File

@@ -0,0 +1,893 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
#define PARANOID 0
/*
OSC-receive.c
Matt Wright, 3/13/98, 6/3/98
Adapted from OSC-addressability.c (and seriously cleaned up!)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <sys/time.h>
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/NetworkReturnAddress.h>
#include <libOSC/OSC-receive.h>
#include <libOSC/OSC-priority-queue.h>
#include <libOSC/OSC-string-help.h>
#include <libOSC/OSC-drop.h>
#include <libOSC/OSC-dispatch.h>
#include <libOSC/NetworkUDP.h>
#include <libOSC/OSC-callbacklist.h>
#if defined(DEBUG_INTERNAL) || defined(DEBUG) || defined(DEBUG_PACKET_MEM) || defined(DEBUG_QD_MEM) || defined(DEBUG_8BYTE_ALIGN) || defined(SUSPECT_QD_PROB)
#include <stdio.h>
#endif
static int use_mcast_ = 0;
static char mcast_groupname[200];
struct {
OSCQueue TheQueue; /* The Priority Queue */
OSCTimeTag lastTimeTag; /* Best approximation to current time */
Boolean timePassed; /* TRUE if OSCInvokeMessagesThatAreReady() has been
called since the last time OSCBeProductiveWhileWaiting() was. */
int recvBufSize; /* Size of all receive buffers */
void *(*InitTimeMalloc)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
} globals;
/* Data structures */
struct OSCPacketBuffer_struct {
char *buf; /* Contents of network packet go here */
int n; /* Overall size of packet */
int refcount; /* # queued things using memory from this buffer */
struct OSCPacketBuffer_struct *nextFree; /* For linked list of free packets */
Boolean returnAddrOK; /* Because returnAddr points to memory we need to
store future return addresses, we set this
field to FALSE in situations where a packet
buffer "has no return address" instead of
setting returnAddr to 0 */
NetworkReturnAddressPtr returnAddr;
//void *returnAddr; /* Addr of client this packet is from */
/* This was of type NetworkReturnAddressPtr, but the constness
was making it impossible for me to initialize it. There's
probably a better way that I don't understand. */
};
/* These are the data objects that are inserted and removed from the
scheduler. The idea is that we can insert a single message or
an entire bundle on the scheduler, and we can leave it in various
states of being parsed and pattern matched. */
#define NOT_DISPATCHED_YET ((callbackList) -1)
typedef struct queuedDataStruct {
OSCTimeTag timetag; /* When this bundle or message is supposed to happen */
OSCPacketBuffer myPacket; /* Ptr. to buffer this is contained in */
enum {MESSAGE, BUNDLE} type;
union {
struct {
char *bytes;
int length;
} bundle;
struct {
char *messageName; /* Ptr. into receive buffer */
int length; /* Includes name and arugments */
void *args; /* 0 if not yet parsed */
int argLength;
callbackList callbacks; /* May be NOT_DISPATCHED_YET */
} message;
} data;
struct queuedDataStruct *nextFree; /* For linked list of free structures */
} queuedData;
/* Static procedure declatations */
static Boolean InitPackets(int receiveBufferSize, int clientAddrSize, int numReceiveBuffers);
static Boolean InitQueuedData(int numQueuedObjects);
static queuedData *AllocQD(void);
static void FreeQD(queuedData *qd);
static void CallWholeCallbackList(callbackList l, int argLength, void *args, OSCTimeTag when, NetworkReturnAddressPtr returnAddr);
static void InsertBundleOrMessage(char *buf, int n, OSCPacketBuffer packet, OSCTimeTag enclosingTimeTag);
static void ParseBundle(queuedData *qd);
static Boolean ParseMessage(queuedData *qd);
/* static void CheckPacketRefcount(OSCPacketBuffer packet); */
static void PacketAddRef(OSCPacketBuffer packet);
static void PacketRemoveRef(OSCPacketBuffer packet);
/**************************************************
Initialization and memory pre-allocation
**************************************************/
Boolean OSCInitReceive(struct OSCReceiveMemoryTuner *t) {
globals.recvBufSize = t->receiveBufferSize;
globals.InitTimeMalloc = t->InitTimeMemoryAllocator;
globals.RealTimeMemoryAllocator = t->RealTimeMemoryAllocator;
globals.TheQueue = OSCNewQueue(t->numQueuedObjects, t->InitTimeMemoryAllocator);
if (globals.TheQueue == 0) return FALSE;
globals.lastTimeTag = OSCTT_Immediately();
globals.timePassed = TRUE;
if (InitPackets(t->receiveBufferSize, SizeOfNetworkReturnAddress(),
t->numReceiveBuffers) == FALSE) return FALSE;
if (InitQueuedData(t->numQueuedObjects) == FALSE) return FALSE;
if (InitCallbackListNodes(t->numCallbackListNodes, t->InitTimeMemoryAllocator)
== FALSE) return FALSE;
return TRUE;
}
/**************************************************
Managing packet data structures
**************************************************/
static struct OSCPacketBuffer_struct *freePackets;
#ifdef DEBUG_PACKET_MEM
static void PrintPacketFreeList(void) {
struct OSCPacketBuffer_struct *p;
printf("- freePackets:");
if (freePackets == 0) {
printf(" [none]");
}
for (p = freePackets; p != 0; p = p->nextFree) {
printf(" %p", p);
}
printf("\n");
}
#endif
#define MIN_REASONABLE_RCV_BUFSIZE 128
void OSCFreeReceiver(void)
{
if( freePackets) free(freePackets);
if( globals.TheQueue ) free( globals.TheQueue );
}
static Boolean InitPackets(int receiveBufferSize, int clientAddrSize, int numReceiveBuffers) {
int i;
struct OSCPacketBuffer_struct *allPackets;
if (receiveBufferSize < MIN_REASONABLE_RCV_BUFSIZE) {
fatal_error("OSCInitReceive: receiveBufferSize of %d is unreasonably small.",
receiveBufferSize);
}
allPackets = (*(globals.InitTimeMalloc))(numReceiveBuffers * sizeof(*allPackets));
if (allPackets == 0) return FALSE;
for (i = 0; i < numReceiveBuffers; ++i) {
allPackets[i].returnAddr = (*(globals.InitTimeMalloc))(clientAddrSize);
if (allPackets[i].returnAddr == 0) return FALSE;
allPackets[i].buf = (*(globals.InitTimeMalloc))(receiveBufferSize);
if (allPackets[i].buf == 0) return FALSE;
allPackets[i].nextFree = &(allPackets[i+1]);
}
allPackets[numReceiveBuffers-1].nextFree = ((struct OSCPacketBuffer_struct *) 0);
freePackets = allPackets;
return TRUE;
}
char *OSCPacketBufferGetBuffer(OSCPacketBuffer p) {
return p->buf;
}
int *OSCPacketBufferGetSize(OSCPacketBuffer p) {
return &(p->n);
}
int OSCGetReceiveBufferSize(void) {
return globals.recvBufSize;
}
NetworkReturnAddressPtr OSCPacketBufferGetClientAddr(OSCPacketBuffer p) {
return p->returnAddr;
}
#ifdef DEBUG
void PrintPacket(OSCPacketBuffer p) {
printf("Packet %p. buf %p, n %d, refcount %d, nextFree %p\n",
p, p->buf, p->n, p->refcount, p->nextFree);
}
#endif
OSCPacketBuffer OSCAllocPacketBuffer(void) {
OSCPacketBuffer result;
if (freePackets == 0) {
/* Could try to call the real-time memory allocator here */
OSCWarning("OSCAllocPacketBuffer: no free packets!");
return 0;
}
result = freePackets;
freePackets = result->nextFree;
result->refcount = 0;
#ifdef DEBUG_PACKET_MEM
printf("OSCAllocPacketBuffer: allocating %p ", result);
PrintPacketFreeList();
#endif
return result;
}
void OSCFreePacket(OSCPacketBuffer p) {
#ifdef PARANOID
if (p->refcount != 0) {
OSCWarning("OSCFreePacket: %p's refcount is %d!\n", p, p->refcount);
}
#endif
p->nextFree = freePackets;
freePackets = p;
#ifdef DEBUG_PACKET_MEM
printf("OSCFreePacket: freed %p ", p);
PrintPacketFreeList();
#endif
}
/**************************************************
Dealing with OpenSoundControl packets and
making the messages take effect.
**************************************************/
static queuedData *freeQDList;
#ifdef DEBUG_QD_MEM
static void PrintQDFreeList(void) {
static queuedData *p;
printf("- freeQDList:");
if (freeQDList == 0) {
printf(" [none]");
}
for (p = freeQDList; p != 0; p = p->nextFree) {
printf(" %p", p);
}
printf("\n");
}
#endif
static Boolean InitQueuedData(int numQueuedObjects) {
int i;
queuedData *allQD;
allQD = (*(globals.InitTimeMalloc))(numQueuedObjects * (sizeof(*allQD)));
if (allQD == 0) return FALSE;
for (i = 0; i < numQueuedObjects; ++i) {
allQD[i].nextFree = &(allQD[i+1]);
}
allQD[numQueuedObjects-1].nextFree = 0;
freeQDList = &(allQD[0]);
return TRUE;
}
static queuedData *AllocQD(void) {
queuedData *result;
if (freeQDList == 0) {
/* Could try to call realtime malloc() */
OSCWarning("AllocQD: no QD objects free now; returning 0.");
return 0;
}
result = freeQDList;
freeQDList = freeQDList->nextFree;
return result;
}
static void FreeQD(queuedData *qd) {
qd->nextFree = freeQDList;
freeQDList = qd;
}
void OSCAcceptPacket(OSCPacketBuffer packet) {
if ((packet->n % 4) != 0) {
OSCProblem("OSC packet size (%d bytes) not a multiple of 4.", packet->n);
DropPacket(packet);
return;
}
#ifdef DEBUG
printf("OSCAcceptPacket(OSCPacketBuffer %p, buf %p, size %d)\n",
packet, packet->buf, packet->n);
#endif
/* If the packet came from the user, it's return address is OK. */
packet->returnAddrOK = TRUE;
InsertBundleOrMessage(packet->buf, packet->n, packet, OSCTT_Immediately());
#ifdef PARANOID
if (packet->refcount == 0) {
if (freePackets != packet) {
fatal_error("OSCAcceptPacket: packet refcount 0, but it's not the head of the free list!");
}
}
#endif
OSCInvokeAllMessagesThatAreReady(globals.lastTimeTag);
}
Boolean OSCBeProductiveWhileWaiting(void) {
/* Here's where we could be clever if an allocation fails.
(I.e., if we're out of QD objects, we should avoid
parsing bundles.) The code isn't that smart yet. */
queuedData *qd;
if (globals.timePassed) {
OSCQueueScanStart(globals.TheQueue);
}
while (1) {
qd = (queuedData *) OSCQueueScanNext(globals.TheQueue);
if (qd == 0) return FALSE;
if (qd->type == BUNDLE) {
ParseBundle(qd);
OSCQueueRemoveCurrentScanItem(globals.TheQueue);
return TRUE;
} else {
if (qd->data.message.callbacks == NOT_DISPATCHED_YET) {
if (ParseMessage(qd) == FALSE) {
/* Problem with this message - flush it. */
DropMessage(qd->data.message.messageName,
qd->data.message.length,
qd->myPacket);
OSCQueueRemoveCurrentScanItem(globals.TheQueue);
PacketRemoveRef(qd->myPacket);
FreeQD(qd);
}
return TRUE;
}
/* The item we found was an already-dispatched message,
so continue the while loop. */
}
}
}
Boolean OSCInvokeMessagesThatAreReady(OSCTimeTag now) {
queuedData *x;
OSCTimeTag thisTimeTag;
globals.lastTimeTag = now;
globals.timePassed = TRUE;
thisTimeTag = OSCQueueEarliestTimeTag(globals.TheQueue);
if (OSCTT_Compare(thisTimeTag, now) > 0) {
/* No messages ready yet. */
return FALSE;
}
#ifdef DEBUG
printf("OSCInvokeMessagesThatAreReady(%llx) - yes, some are ready; earliest %llx\n", now, thisTimeTag);
#endif
while (OSCTT_Compare(thisTimeTag, OSCQueueEarliestTimeTag(globals.TheQueue)) == 0) {
x = (queuedData *) OSCQueueRemoveEarliest(globals.TheQueue);
if (!x) return FALSE;
#ifdef DEBUG
printf("...Just removed earliest entry from queue: %p, TT %llx, %s\n",
x, x->timetag, x->type == MESSAGE ? "message" : "bundle");
if (x->type == MESSAGE) {
printf("...message %s, len %d, args %p, arglen %d, callbacks %p\n",
x->data.message.messageName, x->data.message.length, x->data.message.args,
x->data.message.argLength, x->data.message.callbacks);
} else {
if (x->data.bundle.length == 0) {
printf("...bundle is empty.\n");
} else {
printf("...bundle len %d, first count %d, first msg %s\n",
x->data.bundle.length, *((int *) x->data.bundle.bytes), x->data.bundle.bytes+4);
}
}
PrintPacket(x->myPacket);
#endif
if (x->type == BUNDLE) {
ParseBundle(x);
} else {
if (x->data.message.callbacks == NOT_DISPATCHED_YET) {
if (ParseMessage(x) == FALSE) {
/* Problem with this message - flush it. */
PacketRemoveRef(x->myPacket);
FreeQD(x);
continue;
}
}
CallWholeCallbackList(x->data.message.callbacks,
x->data.message.argLength,
x->data.message.args,
thisTimeTag,
x->myPacket->returnAddrOK ? x->myPacket->returnAddr : 0);
PacketRemoveRef(x->myPacket);
FreeQD(x);
}
}
#ifdef PARANOID
if (OSCTT_Compare(thisTimeTag, OSCQueueEarliestTimeTag(globals.TheQueue)) > 0) {
fatal_error("OSCInvokeMessagesThatAreReady: corrupt queue!\n"
" just did %llx; earliest in queue is now %llx",
thisTimeTag, OSCQueueEarliestTimeTag(globals.TheQueue));
}
#endif
return OSCTT_Compare(OSCQueueEarliestTimeTag(globals.TheQueue), now) <= 0;
}
void OSCInvokeAllMessagesThatAreReady(OSCTimeTag now) {
while (OSCInvokeMessagesThatAreReady(now)) {
/* Do nothing */
}
}
static void CallWholeCallbackList(callbackList l, int argLength, void *args, OSCTimeTag when,
NetworkReturnAddressPtr returnAddr) {
/* In a multithreaded application, this might run in a different thread
than the thread that deals with the priority queue. */
callbackList next;
while (l != 0) {
(*(l->callback))(l->context, argLength, args, when, returnAddr);
next = l->next;
FreeCallbackListNode(l);
l = next;
}
}
static void InsertBundleOrMessage(char *buf, int n, OSCPacketBuffer packet, OSCTimeTag enclosingTimeTag) {
Boolean IsBundle;
queuedData *qd;
/* We add the reference first thing so in case any of the upcoming
potential failure situations come we can call PacketRemoveRef, thereby
freeing the packet if necessary. */
PacketAddRef(packet);
if ((n % 4) != 0) {
OSCProblem("OSC message or bundle size (%d bytes) not a multiple of 4.", n);
DropMessage(buf, n, packet);
PacketRemoveRef(packet);
return;
}
if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
IsBundle = TRUE;
if (n < 16) {
OSCProblem("Bundle message too small (%d bytes) for time tag.", n);
DropBundle(buf, n, packet);
PacketRemoveRef(packet);
return;
}
} else {
IsBundle = FALSE;
}
qd = AllocQD();
if (qd == 0) {
OSCProblem("Not enough memory for queued data!");
DropBundle(buf, n, packet);
PacketRemoveRef(packet);
return;
}
qd->myPacket = packet;
qd->type = IsBundle ? BUNDLE : MESSAGE;
if (IsBundle) {
/* Be careful of 8-byte alignment when copying the time tag. Here's a good
way to get a bus error when buf happens not to be 8-byte aligned:
qd->timetag = *((OSCTimeTag *)(buf+8));
*/
memcpy(&(qd->timetag), buf+8, sizeof(OSCTimeTag));
if (OSCTT_Compare(qd->timetag, enclosingTimeTag) < 0) {
OSCProblem("Time tag of sub-bundle is before time tag of enclosing bundle.");
DropBundle(buf, n, packet);
PacketRemoveRef(packet);
FreeQD(qd);
return;
}
qd->data.bundle.bytes = buf + 16;
qd->data.bundle.length = n - 16;
} else {
qd->timetag = enclosingTimeTag;
qd->data.message.messageName = buf;
qd->data.message.length = n;
qd->data.message.callbacks = NOT_DISPATCHED_YET;
}
OSCQueueInsert(globals.TheQueue, (OSCSchedulableObject) qd);
}
static void ParseBundle(queuedData *qd) {
/* A queued bundle has been removed from the scheduler queue, and now it's
time to parse all the stuff inside it and schedule the enclosed
messages and bundles. Once all the contents of the bundle have been
parsed and scheduled, we trash the bundle, decrementing the packet
count and freeing the QD. */
int size;
int i = 0;
if (qd->type != BUNDLE) {
fatal_error("This can't happen: bundle isn't a bundle!");
}
while (i < qd->data.bundle.length) {
size = *((int *) (qd->data.bundle.bytes + i));
if ((size % 4) != 0) {
OSCProblem("Bad size count %d in bundle (not a multiple of 4).", size);
DropBundle(qd->data.bundle.bytes, qd->data.bundle.length, qd->myPacket);
goto bag;
}
if ((size + i + 4) > qd->data.bundle.length) {
OSCProblem("Bad size count %d in bundle (only %d bytes left in entire bundle).",
size, qd->data.bundle.length-i-4);
DropBundle(qd->data.bundle.bytes, qd->data.bundle.length, qd->myPacket);
goto bag;
}
/* Recursively handle element of bundle */
InsertBundleOrMessage(qd->data.bundle.bytes+i+4, size, qd->myPacket, qd->timetag);
i += 4 + size;
}
if (i != qd->data.bundle.length) {
fatal_error("This can't happen: internal logic error parsing bundle");
}
bag:
/* If we got here successfully, we've added to the packet's reference count for
each message or subbundle by calling InsertBundleOrMessage(), so we remove the one
reference for bundle that we just parsed. If we got here by "goto bag", there's a
problem with the bundle so we also want to lose the reference count. */
PacketRemoveRef(qd->myPacket);
FreeQD(qd);
}
static Boolean ParseMessage(queuedData *qd) {
/* Fill in all the information we'll need to execute the message as
quickly as possible when the time comes. This means figuring out where
the address ends and the arguments begin, and also pattern matching the
address to find the callbacks associated with it.
The message may be something we have to invoke now, or it may be some
message scheduled for the future that's just waiting on the queue; this
procedure doesn't care. */
char *args; /* char * so we can do pointer subtraction */
int messageLen;
char *DAAS_errormsg;
if (qd->type != MESSAGE) {
fatal_error("This can't happen: message isn't a message!");
}
args = OSCDataAfterAlignedString(qd->data.message.messageName,
qd->data.message.messageName+qd->data.message.length,
&DAAS_errormsg);
if (args == 0) {
OSCProblem("Bad message name string: %s\n", DAAS_errormsg);
DropMessage(qd->data.message.messageName, qd->data.message.length, qd->myPacket);
return FALSE;
}
qd->data.message.args = args;
messageLen = args - qd->data.message.messageName;
qd->data.message.argLength = qd->data.message.length - messageLen;
qd->data.message.callbacks = OSCDispatchMessage(qd->data.message.messageName);
if (qd->data.message.callbacks == 0) {
OSCWarning("Message pattern \"%s\" did not correspond to any address in the synth.",
qd->data.message.messageName);
return FALSE;
}
return TRUE;
}
static void PacketAddRef(OSCPacketBuffer packet) {
++(packet->refcount);
}
static void PacketRemoveRef(OSCPacketBuffer packet) {
--(packet->refcount);
if (packet->refcount == 0) {
OSCFreePacket(packet);
}
}
/**************************************************
Implementation of procedures declared in
OSC-internal-messages.h
**************************************************/
#include <libOSC/OSC-internal-messages.h>
Boolean OSCSendInternalMessage(char *address, int arglen, void *args) {
return OSCSendInternalMessageWithRSVP(address, arglen, args, 0);
}
Boolean OSCSendInternalMessageWithRSVP(char *address, int arglen, void *args,
NetworkReturnAddressPtr returnAddr) {
callbackList l = OSCDispatchMessage(address);
if (l == 0) return FALSE;
CallWholeCallbackList(l, arglen, args, OSCTT_Immediately(), returnAddr);
return TRUE;
}
Boolean OSCScheduleInternalMessages(OSCTimeTag when, int numMessages,
char **addresses, int *arglens, void **args) {
int i, bufSizeNeeded;
OSCPacketBuffer p;
queuedData *qd;
char *bufPtr;
/* Figure out how big of a buffer we'll need to hold this huge bundle.
We don't store the "#bundle" string or the time tag, just the 4-byte
size counts, the addresses, possible extra null padding for the
addresses, and the arguments. */
bufSizeNeeded = 0;
for (i = 0; i < numMessages; ++i) {
bufSizeNeeded += 4 + OSCPaddedStrlen(addresses[i]) + arglens[i];
}
if (bufSizeNeeded > OSCGetReceiveBufferSize()) {
return FALSE;
}
/* Now try to allocate the data objects to hold these messages */
qd = AllocQD();
if (qd == 0) return FALSE;
p = OSCAllocPacketBuffer();
if (p == 0) {
FreeQD(qd);
return FALSE;
}
/* Now fill in the buffer with a fake #bundle message. This is almost like
putting a real #bundle message in the buffer and then calling OSCAcceptPacket,
except that we save a little time and memory by not writing "#bundle" or the time tag,
and by pre-parsing the messages a little. Thus, this code duplicates a lot
of what's in InsertBundleOrMessage() */
bufPtr = p->buf;
for (i = 0; i < numMessages; ++i) {
/* First the size count of this bundle element */
*((int4 *) bufPtr) = OSCPaddedStrlen(addresses[i]) + arglens[i];
bufPtr += sizeof(int4);
/* Then the address */
bufPtr = OSCPaddedStrcpy(bufPtr, addresses[i]);
/* Then the arguments */
memcpy(bufPtr, args[i], arglens[i]);
bufPtr += arglens[i];
}
#ifdef PARANOID
if (bufPtr != p->buf+bufSizeNeeded) {
fatal_error("OSCScheduleInternalMessages: internal error");
}
#endif
/* Fill in the rest of the packet fields */
p->n = bufSizeNeeded;
p->returnAddrOK = FALSE;
PacketAddRef(p);
/* Now fill in the queuedData object */
qd->timetag = when;
qd->myPacket = p;
qd->type = BUNDLE;
qd->data.bundle.length = bufSizeNeeded;
qd->data.bundle.bytes = p->buf;
/* Now we can put it into the scheduling queue. */
OSCQueueInsert(globals.TheQueue, (OSCSchedulableObject) qd);
return TRUE;
}
Boolean NetworkPacketWaiting(OSCPacketBuffer packet) {
int n;
NetworkReturnAddressPtr na = OSCPacketBufferGetClientAddr(packet);
// if( use_mcast_ )
// {
fd_set fds;
struct timeval no_wait;
int status;
memset( &no_wait, 0, sizeof(no_wait));
FD_ZERO(&fds);
FD_SET( na->sockfd , &fds );
status = select( na->sockfd + 1, &fds, 0, 0, &no_wait );
if(status <= 0)
return FALSE;
if(FD_ISSET( na->sockfd, &fds ))
return TRUE;
// }
// else
// {
// if( ioctl( na->sockfd, FIONREAD, &n, 0)==-1) return FALSE;
// if( n==0 ) return FALSE;
// }
// return TRUE;
return FALSE;
}
Boolean NetworkReceivePacket( OSCPacketBuffer packet ) {
int n;
NetworkReturnAddressPtr na = OSCPacketBufferGetClientAddr(packet);
if( use_mcast_ )
{
n = recv( na->sockfd, packet->buf, 100, 0 );
if( n<= 0)
return FALSE;
packet->n = n;
}
else
{
n = recvfrom( na->sockfd, packet->buf, 100, 0,
(struct sockaddr*) &(na->cl_addr), &(na->clilen));
if(n<=0) {
return FALSE;
}
packet->n = n;
}
return TRUE;
}
void GoMultiCast( const char *group_name )
{
use_mcast_ = 1;
strncpy( mcast_groupname, group_name, strlen(group_name ));
}
int IsMultiCast( char *dst )
{
if(use_mcast_)
sprintf(dst, "%s", mcast_groupname );
return use_mcast_;
}
Boolean NetworkStartUDPServer(OSCPacketBuffer packet, int port_id) {
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(port_id);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset( &(my_addr.sin_zero), 0, 8);
if( use_mcast_ )
{
struct ip_mreq mcast_req;
int on = 1;
int err= 0;
memset( &mcast_req, 0, sizeof(mcast_req));
packet->returnAddr->sockfd = socket( AF_INET, SOCK_DGRAM, 0);
#ifdef SO_REUSEADDR
setsockopt( packet->returnAddr->sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
#endif
#ifdef SO_REUSEPORT
setsockopt( packet->returnAddr->sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
#endif
err = bind( packet->returnAddr->sockfd, (struct sockaddr*) &my_addr, sizeof( my_addr ));
if( err < 0 )
return FALSE;
mcast_req.imr_multiaddr.s_addr = inet_addr( mcast_groupname );
mcast_req.imr_interface.s_addr = htonl( INADDR_ANY );
setsockopt( packet->returnAddr->sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mcast_req, sizeof(mcast_req) );
}
else
{
packet->returnAddr->sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if( bind( packet->returnAddr->sockfd,
(struct sockaddr*) &my_addr,
sizeof(struct sockaddr)) == -1) return FALSE;
packet->returnAddr->clilen = sizeof(struct sockaddr);
}
return TRUE;
}

View File

@@ -0,0 +1,242 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC-receive.h
Matt Wright, 11/18/97
include OSC-timetag.h and NetworkReturnAddress.h before this file.
*/
/**************************************************
Initialization and memory pre-allocation
**************************************************/
/* The memory model used by this module is pre-allocation of fixed-size
objects for network buffers and other internal objects. This preallocated
memory is dynamically managed internally by a custom high-performance memory
allocator. When the preallocated memory runs out, this module calls an
optional realtime memory allocator that you provide. If your memory
allocator gives this module more memory, it will add it to the pool of
objects and never free the memory. If your system does not have a realtime
memory allocator, provide a procedure that always returns 0.
You will fill an OSCReceiveMemoryTuner struct with the parameters that
determine how memory will be allocated.
The MemoryAllocator fields are procedures you will provide that allocate
memory. Like malloc(), they take the number of bytes as arguments and return
either a pointer to the new memory or 0 for failure. This memory will never
be freed.
- The InitTimeMemoryAllocator will be called only at initialization time,
i.e., before OSCInitAddressSpace() returns. If it ever returns 0, that's
a fatal error.
- The RealTimeMemoryAllocator will be called if, while the application is
running, the address space grows larger than can fit in what was allocated
at initialization time. If the RealTimeMemoryAllocator() returns 0, the
operation attempting to grow the address space will fail. If your system
does not have real-time memory allocation, RealTimeMemoryAllocator should
be a procedure that always returns 0.
The remaining fields say how much memory to allocate at initialization time:
- receiveBufferSize is the maximum packet size that can be received. Is the
maximum UDP packet size 4096? OSC clients can send a query to this system
asking for this maximum packet size.
- numReceiveBuffers determines how many packets at a time can be sitting
on the scheduler with messages waiting to take effect. If all the
receive buffers are tied up like this, you won't be able to receive
new packets.
- numQueuedObjects is the number of messages and packets that can be sitting
on the scheduler waiting to take effect.
- Because a message pattern may be dispatched before the message takes effect,
we need memory to store the callback pointers corresponding to a message.
numCallbackListNodes is the number of callbacks that may be stored in this
fashion. It must be at least as large as the maximum number of methods that
any one message pattern may match, but if you want to take advantage of
pre-dispatching, this should be large enough to hold all the callbacks for
all the messages waiting in the scheduler.
*/
struct OSCReceiveMemoryTuner {
void *(*InitTimeMemoryAllocator)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
int receiveBufferSize;
int numReceiveBuffers;
int numQueuedObjects;
int numCallbackListNodes;
};
/* Given an OSCReceiveMemoryTuner, return the number of bytes of
memory that would be allocated if OSCInitReceive() were called
on it. */
int OSCReceiveMemoryThatWouldBeAllocated(struct OSCReceiveMemoryTuner *t);
/* Returns FALSE if it fails to initialize */
Boolean OSCInitReceive(struct OSCReceiveMemoryTuner *t);
/**************************************************
Managing packet data structures
**************************************************/
/* You don't get to know what's in an OSCPacketBuffer. */
typedef struct OSCPacketBuffer_struct *OSCPacketBuffer;
/* Get an unused packet. Returns 0 if none are free. If you get a packet
with this procedure, it is your responsibility either to call
OSCAcceptPacket() on it (in which case the internals of the OSC Kit free
the OSCPacketBuffer after the last message in it takes effect) or to call
OSCFreePacket() on it. */
OSCPacketBuffer OSCAllocPacketBuffer(void);
/* Free. This is called automatically after the last message that was
in the packet is invoked. You shouldn't need to call this unless
you get a packet with OSCAllocPacketBuffer() and then for some reason
decide not to call OSCAcceptPacket() on it. */
void OSCFreePacket(OSCPacketBuffer p);
void OSCFreeReceiver(void);
/* Whatever code actually gets packets from the network should use these
three selectors to access the fields in the packet structure that need
to be filled in with the data from the network. */
/* Selector to get the buffer from a packet. This buffer's size will be
equal to the receiveBufferSize you passed to OSCInitReceive(). */
char *OSCPacketBufferGetBuffer(OSCPacketBuffer p);
/* Selector to get a pointer to the int that's the size count for the
data currently in a packet. (Not the capacity of the packet's buffer,
but the size of the packet that's actually stored in the buffer.) */
int *OSCPacketBufferGetSize(OSCPacketBuffer);
/* Selector to get the client's network address from a packet. This buffer's
size will be equal to the clientAddrSize you passed to OSCInitReceive().
Note that the NetworkReturnAddressPtr type is full of "const"s, so your
code that fills in the return address will probably have to cast the return
value of this procedure to some non-const type to be able to write into it. */
NetworkReturnAddressPtr OSCPacketBufferGetClientAddr(OSCPacketBuffer p);
/* Returns the capacity of packet buffers (the receiveBufferSize you passed
to OSCInitReceive()). */
int OSCGetReceiveBufferSize(void);
/**************************************************
Dealing with OpenSoundControl packets and
making the messages take effect.
**************************************************/
/* Call this as soon as a packet comes in from the network.
It will take care of anything that has to happen immediately,
but put off as much as possible of the work of parsing the
packet. (This tries to be as fast as possible in case a
lot of packets come in.) */
void OSCAcceptPacket(OSCPacketBuffer packet);
/* Call this during an otherwise idle time. It goes through
everything that's sitting in the OSC scheduler waiting to
happen and does some of the work of parsing, pattern
matching, dispatching, etc., that will have to be done
at some point before the scheduled messages can take
effect.
The return value indicates whether there is more work of
this sort that could be done. (Each time you call this,
it does only a small unit of this kind of work. If it
returns TRUE and you still have time before the next thing
you have to do, call it again.) */
Boolean OSCBeProductiveWhileWaiting(void);
/* Call this whenever enough time has passed that you want to see which
messages are now ready and have them take effect. (For example, in a
synthesizer, you might call this once per synthesis frame, just before
synthesizing the audio for that frame.)
This procedure finds the earliest time tag of all the queued messages
and invokes *all* of the queued messages with that time tag. (OSC
guarantees that messages with the same tag take effect atomically.)
If there are more messages that are ready, but with a different time
tag, this procedure does not invoke them, but returns TRUE to indicate
that more messages are ready.
*/
Boolean OSCInvokeMessagesThatAreReady(OSCTimeTag now);
/* Same thing, but invokes all of the messages whose time has come. */
void OSCInvokeAllMessagesThatAreReady(OSCTimeTag now);
Boolean NetworkReceivePacket(OSCPacketBuffer packet);
Boolean NetworkStartUDPServer(OSCPacketBuffer packet, int port_id);
Boolean NetworkPacketWaiting(OSCPacketBuffer packet);
void GoMultiCast(const char *groupname);
int IsMultiCast( char *dst);
/**************************************************
How to use this stuff
**************************************************/
/* Here's a gross approximation of how your application will invoke the
procedures in this module:
while (1) {
OSCTimeTag now = CurrentTime();
do {
if (WeAreSoLateThatWeNeedToDelayOSCMessagesToAvoidACrisis()) break;
} while (OSCInvokeMessagesThatAreReady(now) == TRUE);
SynthesizeSomeSound();
if (NetworkPacketWaiting()) {
OSCPacketBuffer p = OSCAllocPacketBuffer();
if (!p) {
Bummer();
} else {
NetworkReceivePacket(p);
OSCAcceptPacket(p);
}
}
while (TimeLeftBeforeWeHaveDoSomething()) {
if (!OSCBeProductiveWhileWaiting()) break;
}
}
*/

View File

@@ -0,0 +1,123 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-string-help.c
Procedures that could be useful to programmers writing OSC methods that
take string arguments.
by Matt Wright, 3/19/98
*/
#include <libOSC/OSC-common.h> /* For Boolean */
#include <stdint.h>
#include <sys/time.h>
#define STRING_ALIGN_PAD 4
char *OSCDataAfterAlignedString(const char *string, const char *boundary, char **errorMsg) {
int i;
if ((boundary - string) %4 != 0) {
fatal_error("DataAfterAlignedString: bad boundary\n");
}
for (i = 0; string[i] != '\0'; i++) {
if (string + i >= boundary) {
(*errorMsg) = "DataAfterAlignedString: Unreasonably long string";
return 0;
}
}
/* Now string[i] is the first null character */
i++;
for (; (i % STRING_ALIGN_PAD) != 0; i++) {
if (string + i >= boundary) {
(*errorMsg) = "Unreasonably long string";
return 0;
}
if (string[i] != '\0') {
(*errorMsg) = "Incorrectly padded string.";
return 0;
}
}
return (char *) (string+i);
}
int OSCPaddedStrlen(const char *s) {
int i;
for (i = 0; *s != '\0'; s++, i++) {
/* do nothing */
}
/* Now i is the length with no null bytes. We need 1-4 null bytes,
to make the total length a multiple of 4. So we add 4, as if
we need 4 null bytes, then & 0xfffffffc to round down to the nearest
multiple of 4. */
return (i + 4) & 0xfffffffc;
}
char *OSCPaddedStrcpy(char *target, const char *source) {
while ( (*target++) = (*source++)) {
/* do nothing */
}
/* That copied one null byte */
while (((int) target) % 4 != 0) {
*target = '\0';
target++;
}
return target;
}
Boolean OSCParseStringList(const char *result[], int *numStrings, int maxStrings,
const char *args, int numBytes) {
int numFound;
const char *p;
const char *boundary = args + numBytes;
char *errorMessage;
p = args;
for (numFound = 0; numFound < maxStrings; ++numFound) {
if (p == boundary) {
*numStrings = numFound;
return TRUE;
}
result[numFound] = p;
p = OSCDataAfterAlignedString(p, boundary, &errorMessage);
if (p == 0) return FALSE;
}
return FALSE;
}

View File

@@ -0,0 +1,70 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/* OSC-string-help.h
Procedures that could be useful to programmers writing OSC methods that
take string arguments.
by Matt Wright, 3/19/98
*/
/* Use this to deal with OSC null-padded 4 byte-aligned strings
The argument is a block of data beginning with a string. The string
has (presumably) been padded with extra null characters so that the
overall length is a multiple of 4 bytes. Return a pointer to the next
byte after the null byte(s). The boundary argument points to the
character after the last valid character in the buffer---if the string
hasn't ended by there, something's wrong.
If the data looks wrong, return 0, and set *errorMsg */
char *OSCDataAfterAlignedString(const char *string, const char *boundary, char **errorMsg);
/* Given a normal C-style string with a single padding byte, return the
length of the string including the necessary 1-4 padding bytes.
(Basically strlen()+1 rounded up to the next multiple of 4.) */
int OSCPaddedStrlen(const char *s);
/* Copy a given C-style string into the given destination, including the
requisite padding byte(s). Unlike strcpy(), this returns a pointer to
the next character after the copied string's null bytes, like
what OSCDataAfterAlignedString() returns. */
char *OSCPaddedStrcpy(char *target, const char *source);
/* Given an args pointer that should be nothing but a list of strings, fill
result[] with pointers to the beginnings of each string, and set
*numStrings to be the number of strings found. maxStrings gives the size
of the result array. Return FALSE if any strings are malformatted or if
there are more than maxStrings many strings. */
Boolean OSCParseStringList(const char *result[], int *numStrings, int maxStrings,
const char *args, int numBytes);

View File

@@ -0,0 +1,56 @@
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef OSCH
#define OSCH
#ifndef TRUE
typedef int Boolean;
#define TRUE 1
#define FALSE 0
#endif
/* Fixed byte width types */
typedef int int4; /* 4 byte int */
typedef struct NetworkReturnAddressStruct_t {
struct sockaddr_in cl_addr; /* client information */
struct sockaddr_in my_addr; /* us */
int clilen;
int sockfd;
fd_set readfds;
struct timeval tv;
int fdmax;
} NetworkReturnAddressStruct;
typedef struct OSCPacketBuffer_struct {
char *buf; /* Contents of network packet go here */
int n; /* Overall size of packet */
int refcount; /* # queued things using memory from this buffer */
struct OSCPacketBuffer_struct *nextFree; /* For linked list of free packets */
Boolean returnAddrOK; /* Because returnAddr points to memory we need to
store future return addresses, we set this
field to FALSE in situations where a packet
buffer "has no return address" instead of
setting returnAddr to 0 */
void *returnAddr; /* Addr of client this packet is from */
/* This was of type NetworkReturnAddressPtr, but the constness
was making it impossible for me to initialize it. There's
probably a better way that I don't understand. */
} OSCPacketBuffer;
struct OSCReceiveMemoryTuner {
void *(*InitTimeMemoryAllocator)(int numBytes);
void *(*RealTimeMemoryAllocator)(int numBytes);
int receiveBufferSize;
int numReceiveBuffers;
int numQueuedObjects;
int numCallbackListNodes;
};
#endif

View File

@@ -0,0 +1,174 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC_timeTag.c: library for manipulating OSC time tags
Matt Wright, 5/29/97
Version 0.2 (9/11/98): cleaned up so no explicit type names in the .c file.
*/
#include <libOSC/OSC-timetag.h>
#include <stdint.h>
#include <sys/time.h>
#ifdef HAS8BYTEINT
#define TWO_TO_THE_32_FLOAT 4294967296.0f
OSCTimeTag OSCTT_Immediately(void) {
return (OSCTimeTag) 1;
}
OSCTimeTag OSCTT_BiggestPossibleTimeTag(void) {
return (OSCTimeTag) 0xffffffffffffffff;
}
OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
int8 offset = (int8) (secondsOffset * TWO_TO_THE_32_FLOAT);
/* printf("* OSCTT_PlusSeconds %llx plus %f seconds (i.e., %lld offset) is %llx\n", original,
secondsOffset, offset, original + offset); */
return original + offset;
}
int OSCTT_Compare(OSCTimeTag left, OSCTimeTag right) {
#if 0
printf("***** OSCTT_Compare(%llx, %llx): %d\n", left, right,
(left<right) ? -1 : ((left == right) ? 0 : 1));
#endif
if (left < right) {
return -1;
} else if (left == right) {
return 0;
} else {
return 1;
}
}
#ifdef __sgi
#include <sys/time.h>
#define SECONDS_FROM_1900_to_1970 2208988800 /* 17 leap years */
#define TWO_TO_THE_32_OVER_ONE_MILLION 4295
OSCTimeTag OSCTT_CurrentTime(void) {
uint8 result;
uint4 usecOffset;
struct timeval tv;
struct timezone tz;
BSDgettimeofday(&tv, &tz);
/* First get the seconds right */
result = (unsigned) SECONDS_FROM_1900_to_1970 +
(unsigned) tv.tv_sec -
(unsigned) 60 * tz.tz_minuteswest +
(unsigned) (tz.tz_dsttime ? 3600 : 0);
#if 0
/* No timezone, no DST version ... */
result = (unsigned) SECONDS_FROM_1900_to_1970 +
(unsigned) tv.tv_sec;
#endif
/* make seconds the high-order 32 bits */
result = result << 32;
/* Now get the fractional part. */
usecOffset = (unsigned) tv.tv_usec * (unsigned) TWO_TO_THE_32_OVER_ONE_MILLION;
/* printf("** %ld microsec is offset %x\n", tv.tv_usec, usecOffset); */
result += usecOffset;
/* printf("* OSCTT_CurrentTime is %llx\n", result); */
return result;
}
#else /* __sgi */
/* Instead of asking your operating system what time it is, it might be
clever to find out the current time at the instant your application
starts audio processing, and then keep track of the number of samples
output to know how much time has passed. */
/* Loser version for systems that have no ability to tell the current time: */
OSCTimeTag OSCTT_CurrentTime(void) {
return (OSCTimeTag) 1;
}
#endif /* __sgi */
#else /* Not HAS8BYTEINT */
OSCTimeTag OSCTT_CurrentTime(void) {
OSCTimeTag result;
result.seconds = 0;
result.fraction = 1;
return result;
}
OSCTimeTag OSCTT_BiggestPossibleTimeTag(void) {
OSCTimeTag result;
result.seconds = 0xffffffff;
result.fraction = 0xffffffff;
return result;
}
OSCTimeTag OSCTT_Immediately(void) {
OSCTimeTag result;
result.seconds = 0;
result.fraction = 1;
return result;
}
OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
OSCTimeTag result;
result.seconds = 0;
result.fraction = 1;
return result;
}
int OSCTT_Compare(OSCTimeTag left, OSCTimeTag right) {
/* Untested! */
int highResult = left.seconds - right.seconds;
if (highResult != 0) return highResult;
return left.fraction - right.fraction;
}
#endif /* HAS8BYTEINT */

View File

@@ -0,0 +1,91 @@
/*
Copyright <20> 1998. The Regents of the University of California (Regents).
All Rights Reserved.
Written by Matt Wright, The Center for New Music and Audio Technologies,
University of California, Berkeley.
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
The OpenSound Control WWW page is
http://www.cnmat.berkeley.edu/OpenSoundControl
*/
/*
OSC_timeTag.h: library for manipulating OSC time tags
Matt Wright, 5/29/97
Time tags in OSC have the same format as in NTP: 64 bit fixed point, with the
top 32 bits giving number of seconds sinve midnight 1/1/1900 and the bottom
32 bits giving fractional parts of a second. We represent this by an 8-byte
unsigned long if possible, or else a struct.
NB: On many architectures with 8-byte ints, it's illegal (like maybe a bus error)
to dereference a pointer to an 8 byte int that's not 8-byte aligned.
*/
#ifndef OSC_TIMETAG
#define OSC_TIMETAG
#ifdef __sgi
#define HAS8BYTEINT
/* You may have to change this typedef if there's some other
way to specify 8 byte ints on your system */
typedef long long int8;
typedef unsigned long long uint8;
typedef unsigned long uint4;
#else
/* You may have to redefine this typedef if ints on your system
aren't 4 bytes. */
typedef unsigned int uint4;
#endif
#ifdef HAS8BYTEINT
typedef uint8 OSCTimeTag;
#else
typedef struct {
uint4 seconds;
uint4 fraction;
} OSCTimeTag;
#endif
/* Return a time tag representing the current time (as of when this
procedure is called). */
OSCTimeTag OSCTT_CurrentTime(void);
/* Return the time tag 0x0000000000000001, indicating to the receiving device
that it should process the message immediately. */
OSCTimeTag OSCTT_Immediately(void);
/* Return the time tag 0xffffffffffffffff, a time so far in the future that
it's effectively infinity. */
OSCTimeTag OSCTT_BiggestPossibleTimeTag(void);
/* Given a time tag and a number of seconds to add to the time tag, return
the new time tag */
OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset);
/* Compare two time tags. Return negative if first is < second, 0 if
they're equal, and positive if first > second. */
int OSCTT_Compare(OSCTimeTag left, OSCTimeTag right);
#endif /* OSC_TIMETAG */

View File

@@ -0,0 +1,26 @@
#ifndef _LIBOSC_H_INCLUDED
#define _LIBOSC_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include <libOSC/OSC-common.h>
#include <libOSC/OSC-timetag.h>
#include <libOSC/OSC-address-space.h>
#include <libOSC/OSC-dispatch.h>
#include <libOSC/OSC-receive.h>
#include <libOSC/OSC-callbacklist.h>
#include <libOSC/OSC-drop.h>
#include <libOSC/OSC-internal-messages.h>
#include <libOSC/OSC-pattern-match.h>
#include <libOSC/OSC-priority-queue.h>
#include <libOSC/OSC-string-help.h>
#include <libOSC/NetworkReturnAddress.h>
#include <libOSC/NetworkUDP.h>
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,12 @@
# Makefile for veejay
MAINTAINERCLEANFILES = Makefile.in
AM_CFLAGS=$(OP_CFLAGS)
INCLUDES = -I$(top_srcdir) -I$(includedir) -I$(top_srcdir)/vjmem \
-I$(top_srcdir)/vjmsg \
$(MJPEGTOOLS_CFLAGS) $(FFMPEG_CFLAGS) $(PIXBUF_CFLAGS) \
$(LIBQUICKTIME_CFLAGS)
VJEL_LIB_FILE = libel.la
noinst_LTLIBRARIES = $(VJEL_LIB_FILE)
libel_la_SOURCES = vj-mmap.c elcache.c avilib.c lav_io.c vj-dv.c rawdv.c pixbuf.c vj-avcodec.c vj-el.c

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,464 @@
/*
* avilib.h
*
* Copyright (C) Thomas <20>streich - June 2001
* multiple audio track support Copyright (C) 2002 Thomas <20>streich
*
* Original code:
* Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
*
* This file is part of transcode, a video stream processing tool
*
* transcode is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* transcode is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libel/vj-mmap.h>
#ifndef AVILIB_H
#define AVILIB_H
#define AVI_MAX_TRACKS 8
typedef struct
{
off_t key;
off_t pos;
off_t len;
} video_index_entry;
typedef struct
{
off_t pos;
off_t len;
off_t tot;
} audio_index_entry;
// Index types
#define AVI_INDEX_OF_INDEXES 0x00 // when each entry in aIndex
// array points to an index chunk
#define AVI_INDEX_OF_CHUNKS 0x01 // when each entry in aIndex
// array points to a chunk in the file
#define AVI_INDEX_IS_DATA 0x80 // when each entry is aIndex is
// really the data
// bIndexSubtype codes for INDEX_OF_CHUNKS
//
#define AVI_INDEX_2FIELD 0x01 // when fields within frames
// are also indexed
typedef struct _avisuperindex_entry {
uint64_t qwOffset; // absolute file offset
uint32_t dwSize; // size of index chunk at this offset
uint32_t dwDuration; // time span in stream ticks
} avisuperindex_entry;
typedef struct _avistdindex_entry {
uint32_t dwOffset; // qwBaseOffset + this is absolute file offset
uint32_t dwSize; // bit 31 is set if this is NOT a keyframe
} avistdindex_entry;
// Standard index
typedef struct _avistdindex_chunk {
char fcc[4]; // ix##
uint32_t dwSize; // size of this chunk
uint16_t wLongsPerEntry; // must be sizeof(aIndex[0])/sizeof(DWORD)
uint8_t bIndexSubType; // must be 0
uint8_t bIndexType; // must be AVI_INDEX_OF_CHUNKS
uint32_t nEntriesInUse; //
char dwChunkId[4]; // '##dc' or '##db' or '##wb' etc..
uint64_t qwBaseOffset; // all dwOffsets in aIndex array are relative to this
uint32_t dwReserved3; // must be 0
avistdindex_entry *aIndex;
} avistdindex_chunk;
// Base Index Form 'indx'
typedef struct _avisuperindex_chunk {
char fcc[4];
uint32_t dwSize; // size of this chunk
uint16_t wLongsPerEntry; // size of each entry in aIndex array (must be 8 for us)
uint8_t bIndexSubType; // future use. must be 0
uint8_t bIndexType; // one of AVI_INDEX_* codes
uint32_t nEntriesInUse; // index of first unused member in aIndex array
char dwChunkId[4]; // fcc of what is indexed
uint32_t dwReserved[3]; // meaning differs for each index type/subtype.
// 0 if unused
avisuperindex_entry *aIndex; // where are the ix## chunks
avistdindex_chunk **stdindex; // the ix## chunks itself (array)
} avisuperindex_chunk;
typedef struct track_s
{
long a_fmt; /* Audio format, see #defines below */
long a_chans; /* Audio channels, 0 for no audio */
long a_rate; /* Rate in Hz */
long a_bits; /* bits per audio sample */
long mp3rate; /* mp3 bitrate kbs*/
long a_vbr; /* 0 == no Variable BitRate */
long padrate; /* byte rate used for zero padding */
long audio_strn; /* Audio stream number */
off_t audio_bytes; /* Total number of bytes of audio data */
long audio_chunks; /* Chunks of audio data in the file */
char audio_tag[4]; /* Tag of audio data */
long audio_posc; /* Audio position: chunk */
long audio_posb; /* Audio position: byte within chunk */
off_t a_codech_off; /* absolut offset of audio codec information */
off_t a_codecf_off; /* absolut offset of audio codec information */
audio_index_entry *audio_index;
avisuperindex_chunk *audio_superindex;
} track_t;
typedef struct
{
uint32_t bi_size;
uint32_t bi_width;
uint32_t bi_height;
uint16_t bi_planes;
uint16_t bi_bit_count;
uint32_t bi_compression;
uint32_t bi_size_image;
uint32_t bi_x_pels_per_meter;
uint32_t bi_y_pels_per_meter;
uint32_t bi_clr_used;
uint32_t bi_clr_important;
} alBITMAPINFOHEADER;
typedef struct __attribute__((__packed__))
{
uint16_t w_format_tag;
uint16_t n_channels;
uint32_t n_samples_per_sec;
uint32_t n_avg_bytes_per_sec;
uint16_t n_block_align;
uint16_t w_bits_per_sample;
uint16_t cb_size;
} alWAVEFORMATEX;
typedef struct __attribute__((__packed__))
{
uint32_t fcc_type;
uint32_t fcc_handler;
uint32_t dw_flags;
uint32_t dw_caps;
uint16_t w_priority;
uint16_t w_language;
uint32_t dw_scale;
uint32_t dw_rate;
uint32_t dw_start;
uint32_t dw_length;
uint32_t dw_initial_frames;
uint32_t dw_suggested_buffer_size;
uint32_t dw_quality;
uint32_t dw_sample_size;
uint32_t dw_left;
uint32_t dw_top;
uint32_t dw_right;
uint32_t dw_bottom;
uint32_t dw_edit_count;
uint32_t dw_format_change_count;
char sz_name[64];
} alAVISTREAMINFO;
typedef struct
{
long fdes; /* File descriptor of AVI file */
long mode; /* 0 for reading, 1 for writing */
long width; /* Width of a video frame */
long height; /* Height of a video frame */
double fps; /* Frames per second */
char compressor[8]; /* Type of compressor, 4 bytes + padding for 0 byte */
char compressor2[8]; /* Type of compressor, 4 bytes + padding for 0 byte */
long video_strn; /* Video stream number */
long video_frames; /* Number of video frames */
char video_tag[4]; /* Tag of video data */
long video_pos; /* Number of next frame to be read
(if index present) */
uint32_t max_len; /* maximum video chunk present */
track_t track[AVI_MAX_TRACKS]; // up to AVI_MAX_TRACKS audio tracks supported
off_t pos; /* position in file */
long n_idx; /* number of index entries actually filled */
long max_idx; /* number of index entries actually allocated */
off_t v_codech_off; /* absolut offset of video codec (strh) info */
off_t v_codecf_off; /* absolut offset of video codec (strf) info */
uint8_t (*idx)[16]; /* index entries (AVI idx1 tag) */
video_index_entry *video_index;
avisuperindex_chunk *video_superindex; /* index of indices */
int is_opendml; /* set to 1 if this is an odml file with multiple index chunks */
off_t last_pos; /* Position of last frame written */
uint32_t last_len; /* Length of last frame written */
int must_use_index; /* Flag if frames are duplicated */
off_t movi_start;
int total_frames; /* total number of frames if dmlh is present */
int anum; // total number of audio tracks
int aptr; // current audio working track
int comment_fd; // Read avi header comments from this fd
char *index_file; // read the avi index from this file
alBITMAPINFOHEADER *bitmap_info_header;
alWAVEFORMATEX *wave_format_ex[AVI_MAX_TRACKS];
void* extradata;
unsigned long extradata_size;
mmap_region_t *mmap_region;
off_t mmap_offset;
size_t mmap_size;
int ffmpeg_codec_id;
} avi_t;
#define AVI_MODE_WRITE 0
#define AVI_MODE_READ 1
/* The error codes delivered by avi_open_input_file */
#define AVI_ERR_SIZELIM 1 /* The write of the data would exceed
the maximum size of the AVI file.
This is more a warning than an error
since the file may be closed safely */
#define AVI_ERR_OPEN 2 /* Error opening the AVI file - wrong path
name or file nor readable/writable */
#define AVI_ERR_READ 3 /* Error reading from AVI File */
#define AVI_ERR_WRITE 4 /* Error writing to AVI File,
disk full ??? */
#define AVI_ERR_WRITE_INDEX 5 /* Could not write index to AVI file
during close, file may still be
usable */
#define AVI_ERR_CLOSE 6 /* Could not write header to AVI file
or not truncate the file during close,
file is most probably corrupted */
#define AVI_ERR_NOT_PERM 7 /* Operation not permitted:
trying to read from a file open
for writing or vice versa */
#define AVI_ERR_NO_MEM 8 /* malloc failed */
#define AVI_ERR_NO_AVI 9 /* Not an AVI file */
#define AVI_ERR_NO_HDRL 10 /* AVI file has no has no header list,
corrupted ??? */
#define AVI_ERR_NO_MOVI 11 /* AVI file has no has no MOVI list,
corrupted ??? */
#define AVI_ERR_NO_VIDS 12 /* AVI file contains no video data */
#define AVI_ERR_NO_IDX 13 /* The file has been opened with
getIndex==0, but an operation has been
performed that needs an index */
#define AVI_ERR_EMPTY 14 /* AVI file is empty (header only)*/
/* Possible Audio formats */
#ifndef WAVE_FORMAT_PCM
#define WAVE_FORMAT_UNKNOWN (0x0000)
#define WAVE_FORMAT_PCM (0x0001)
#define WAVE_FORMAT_ADPCM (0x0002)
#define WAVE_FORMAT_IBM_CVSD (0x0005)
#define WAVE_FORMAT_ALAW (0x0006)
#define WAVE_FORMAT_MULAW (0x0007)
#define WAVE_FORMAT_OKI_ADPCM (0x0010)
#define WAVE_FORMAT_DVI_ADPCM (0x0011)
#define WAVE_FORMAT_DIGISTD (0x0015)
#define WAVE_FORMAT_DIGIFIX (0x0016)
#define WAVE_FORMAT_YAMAHA_ADPCM (0x0020)
#define WAVE_FORMAT_DSP_TRUESPEECH (0x0022)
#define WAVE_FORMAT_GSM610 (0x0031)
#define IBM_FORMAT_MULAW (0x0101)
#define IBM_FORMAT_ALAW (0x0102)
#define IBM_FORMAT_ADPCM (0x0103)
#endif
avi_t* AVI_open_output_file(char * filename);
void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor);
int AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format);
int AVI_write_frame(avi_t *AVI, char *data, long bytes);
int AVI_dup_frame(avi_t *AVI);
int AVI_write_audio(avi_t *AVI, char *data, long bytes);
int AVI_append_audio(avi_t *AVI, char *data, long bytes);
long AVI_bytes_remain(avi_t *AVI);
int AVI_close(avi_t *AVI);
long AVI_bytes_written(avi_t *AVI);
avi_t *AVI_open_input_file(char *filename, int getIndex, int mmap_size);
avi_t *AVI_open_input_indexfile(char *filename, int getIndex, char *indexfile);
avi_t *AVI_open_fd(int fd, int getIndex, int mmap_size);
avi_t *AVI_open_indexfd(int fd, int getIndex, char *indexfile);
int avi_parse_input_file(avi_t *AVI, int getIndex);
int avi_parse_index_from_file(avi_t *AVI, char *filename);
long AVI_audio_mp3rate(avi_t *AVI);
long AVI_audio_padrate(avi_t *AVI);
long AVI_video_frames(avi_t *AVI);
int AVI_video_width(avi_t *AVI);
int AVI_video_height(avi_t *AVI);
double AVI_frame_rate(avi_t *AVI);
char* AVI_video_compressor(avi_t *AVI);
int AVI_audio_channels(avi_t *AVI);
int AVI_audio_bits(avi_t *AVI);
int AVI_audio_format(avi_t *AVI);
long AVI_audio_rate(avi_t *AVI);
long AVI_audio_bytes(avi_t *AVI);
long AVI_audio_chunks(avi_t *AVI);
int AVI_can_read_audio(avi_t *AVI);
long AVI_max_video_chunk(avi_t *AVI);
long AVI_frame_size(avi_t *AVI, long frame);
long AVI_audio_size(avi_t *AVI, long frame);
int AVI_seek_start(avi_t *AVI);
int AVI_set_video_position(avi_t *AVI, long frame);
long AVI_get_video_position(avi_t *AVI, long frame);
long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe);
int AVI_set_audio_position(avi_t *AVI, long byte);
int AVI_set_audio_bitrate(avi_t *AVI, long bitrate);
long AVI_get_audio_position_index(avi_t *AVI);
int AVI_set_audio_position_index(avi_t *AVI, long indexpos);
long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes);
long AVI_read_audio_chunk(avi_t *AVI, char *audbuf);
long AVI_audio_codech_offset(avi_t *AVI);
long AVI_audio_codecf_offset(avi_t *AVI);
long AVI_video_codech_offset(avi_t *AVI);
long AVI_video_codecf_offset(avi_t *AVI);
int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf,
char *audbuf, long max_audbuf,
long *len);
void AVI_print_error(char *str);
char *AVI_strerror(void);
char *AVI_syserror(void);
int AVI_scan(char *name);
int AVI_dump(char *name, int mode);
char *AVI_codec2str(short cc);
int AVI_file_check(char *import_file);
void AVI_info(avi_t *avifile);
uint64_t AVI_max_size(void);
int avi_update_header(avi_t *AVI);
int AVI_set_audio_track(avi_t *AVI, int track);
int AVI_get_audio_track(avi_t *AVI);
int AVI_audio_tracks(avi_t *AVI);
void AVI_set_audio_vbr(avi_t *AVI, long is_vbr);
long AVI_get_audio_vbr(avi_t *AVI);
void AVI_set_comment_fd(avi_t *AVI, int fd);
int AVI_get_comment_fd(avi_t *AVI);
struct riff_struct
{
uint8_t id[4]; /* RIFF */
uint32_t len;
uint8_t wave_id[4]; /* WAVE */
};
struct chunk_struct
{
uint8_t id[4];
uint32_t len;
};
struct common_struct
{
uint16_t wFormatTag;
uint16_t wChannels;
uint32_t dwSamplesPerSec;
uint32_t dwAvgBytesPerSec;
uint16_t wBlockAlign;
uint16_t wBitsPerSample; /* Only for PCM */
};
struct wave_header
{
struct riff_struct riff;
struct chunk_struct format;
struct common_struct common;
struct chunk_struct data;
};
// Simple WAV IO
int AVI_read_wave_header( int fd, struct wave_header * wave );
int AVI_write_wave_header( int fd, const struct wave_header * wave );
size_t AVI_read_wave_pcm_data( int fd, void * buffer, size_t buflen );
size_t AVI_write_wave_pcm_data( int fd, const void * buffer, size_t buflen );
int AVI_video_compressor_type(avi_t *AVI);
int AVI_fileno(avi_t *AVI);
struct AVIStreamHeader {
long fccType;
long fccHandler;
long dwFlags;
long dwPriority;
long dwInitialFrames;
long dwScale;
long dwRate;
long dwStart;
long dwLength;
long dwSuggestedBufferSize;
long dwQuality;
long dwSampleSize;
};
#endif

View File

@@ -0,0 +1,207 @@
/*
* Copyright (C) 2002-2006 Niels Elburg <nelburg@looze.net>
*
* This program is free software you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
/*
Cache frames from file to memory
*/
#include <config.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libvjmem/vjmem.h>
#include <libvjmsg/vj-msg.h>
#include <libel/elcache.h>
#ifdef STRICT_CHECKING
#include <assert.h>
#endif
typedef struct
{
int size;
int fmt;
long num;
void *buffer;
} cache_slot_t;
typedef struct
{
cache_slot_t **cache;
int len;
long *index;
} cache_t;
static int cache_free_slot(cache_t *v)
{
int i;
for( i = 0; i < v->len; i ++ )
if( v->index[i] == -1 ) return i;
return -1;
}
static long total_mem_used_ = 0;
static void cache_claim_slot(cache_t *v, int free_slot, uint8_t *linbuf, long frame_num,int buf_len, int decoder_id)
{
// create new node
cache_slot_t *data = (cache_slot_t*) vj_malloc(sizeof(cache_slot_t));
data->size = buf_len;
data->num = frame_num;
data->fmt = decoder_id;
data->buffer = vj_malloc( buf_len );
#ifdef STRICT_CHECKING
assert( v->index[free_slot] != frame_num );
#endif
// clear old buffer
if( v->index[free_slot] >= 0 )
{
cache_slot_t *del_slot = v->cache[free_slot];
total_mem_used_ -= del_slot->size;
free( del_slot->buffer );
free( del_slot );
v->cache[free_slot] = NULL;
}
veejay_memcpy( data->buffer, linbuf, buf_len );
v->index[ free_slot ] = frame_num;
v->cache[ free_slot ] = data;
total_mem_used_ += buf_len;
}
static int cache_find_slot( cache_t *v, long frame_num )
{
int i;
int k = 0;
long n = 0;
for( i = 0; i < v->len ; i ++ )
{
long d = abs( v->index[i] - frame_num );
if( d > n )
{ n = d; k = i ; }
}
return k;
}
static int cache_locate_slot( cache_t *v, long frame_num)
{
int i;
for( i = 0; i < v->len ; i ++ )
if( v->index[i] == frame_num )
return i;
return -1;
}
void *init_cache( unsigned int n_slots )
{
if(n_slots <= 0)
return NULL;
cache_t *v = (cache_t*) vj_calloc(sizeof(cache_t));
v->len = n_slots;
v->cache = (cache_slot_t**) vj_calloc(sizeof(cache_slot_t*) * v->len );
if(!v->cache)
{
free(v);
return NULL;
}
v->index = (long*) vj_malloc(sizeof(long) * v->len );
int n;
for( n = 0; n < v->len ; n ++ )
v->index[n] = -1;
return (void*) v;
}
void reset_cache(void *cache)
{
int i = 0;
cache_t *v = (cache_t*) cache;
for( i = 0; i < v->len; i ++ )
{
v->index[i] = -1;
if( v->cache[i] )
{
total_mem_used_ -= v->cache[i]->size;
if(v->cache[i]->buffer)
free(v->cache[i]->buffer);
free(v->cache[i]);
v->cache[i] = NULL;
}
}
}
int cache_avail_mb()
{
return ( total_mem_used_ == 0 ? 0 : total_mem_used_ / (1024 * 1024 ));
}
void free_cache(void *cache)
{
cache_t *v = (cache_t*) cache;
reset_cache( cache );
free(v->cache);
free(v->index);
free(v);
v = NULL;
}
void cache_frame( void *cache, uint8_t *linbuf, int buflen, long frame_num , int decoder_id)
{
cache_t *v = (cache_t*) cache;
#ifdef STRICT_CHECKING
assert( cache != NULL );
assert( linbuf != NULL );
assert( buflen > 0 );
assert( frame_num >= 0 );
#else
if( buflen <= 0 )
return;
#endif
int slot_num = cache_free_slot( cache );
if( slot_num == -1 )
slot_num = cache_find_slot( v, frame_num );
#ifdef STRICT_CHECKING
assert(slot_num >= 0 );
#endif
cache_claim_slot(v, slot_num, linbuf, frame_num, buflen, decoder_id);
}
uint8_t *get_cached_frame( void *cache, long frame_num, int *buf_len, int *decoder_id )
{
cache_t *v = (cache_t*) cache;
int slot = cache_locate_slot( v, frame_num );
if( slot == -1 )
return NULL;
cache_slot_t *data = v->cache[ slot ];
#ifdef STRICT_CHECKING
assert( data->size > 0 );
assert( data->buffer != NULL );
#endif
*buf_len = data->size;
*decoder_id = data->fmt;
#ifdef STRICT_CHECKING
assert( data->num == frame_num );
#endif
return (uint8_t*) data->buffer;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2002-2006 Niels Elburg <nelburg@looze.net>
*
* This program is free software you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef ELCACHE_H
#define ELCACHE_H
uint8_t *get_cached_frame( void *cache, long frame_num, int *buf_len, int *decoder_id );
void cache_frame( void *cache, uint8_t *linbuf, int buflen, long frame_num , int decoder_id);
void free_cache(void *cache);
void *init_cache( unsigned int n_slots );
void reset_cache(void *cache);
int cache_avail_mb();
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LAV_IO_H
#define LAV_IO_H
#include <config.h>
#include <libel/avilib.h>
#include <libvje/vje.h>
#ifdef SUPPORT_READ_DV2
#include <libel/rawdv.h>
#endif
// play with mlt here, avformat producer/several consumers (we can write to)
// for normalized output (720x576/480) , dv1394 capture and playback
#include <yuv4mpeg.h>
#define LAV_INTER_UNKNOWN Y4M_UNKNOWN
#define LAV_NOT_INTERLACED Y4M_ILACE_NONE
#define LAV_INTER_TOP_FIRST Y4M_ILACE_TOP_FIRST
#define LAV_INTER_BOTTOM_FIRST Y4M_ILACE_BOTTOM_FIRST
/* chroma_format */
#define CHROMAUNKNOWN 0
#define CHROMA420 1
#define CHROMA422 2
#define CHROMA444 3
#define CHROMA411 4
/* raw data format of a single frame */
#define DATAFORMAT_MJPG 0
#define DATAFORMAT_DV2 1
#define DATAFORMAT_YUV420 2
#define DATAFORMAT_YUV422 3
#define DATAFORMAT_DIVX 4
#define DATAFORMAT_MPEG4 5
typedef struct
{
avi_t *avi_fd;
#ifdef SUPPORT_READ_DV2
dv_t *dv_fd;
#endif
void *qt_fd;
int jpeg_fd;
char *jpeg_filename;
#ifdef USE_GDK_PIXBUF
void *picture;
#endif
int format;
int interlacing;
int sar_w; /* "clip aspect ratio" width */
int sar_h; /* "clip aspect ratio" height */
int has_audio;
int bps;
int is_MJPG;
int MJPG_chroma;
int mmap_size;
int bogus_len;
} lav_file_t;
int lav_detect_endian (void);
int lav_query_APP_marker(char format);
int lav_query_APP_length(char format);
int lav_query_polarity(char format);
lav_file_t *lav_open_output_file(char *filename, char format,
int width, int height, int interlaced, double fps,
int asize, int achans, long arate);
int lav_close(lav_file_t *lav_file);
int lav_write_frame(lav_file_t *lav_file, uint8_t *buff, long size, long count);
int lav_write_audio(lav_file_t *lav_file, uint8_t *buff, long samps);
long lav_video_frames(lav_file_t *lav_file);
int lav_video_width(lav_file_t *lav_file);
int lav_video_height(lav_file_t *lav_file);
double lav_frame_rate(lav_file_t *lav_file);
int lav_video_interlacing(lav_file_t *lav_file);
void lav_video_clipaspect(lav_file_t *lav_file, int *sar_w, int *sar_h);
int lav_video_is_MJPG(lav_file_t *lav_file);
int lav_is_DV(lav_file_t *lav_file);
int lav_video_MJPG_chroma(lav_file_t *lav_file);
const char *lav_video_compressor(lav_file_t *lav_file);
int lav_video_compressor_type(lav_file_t *lav_file);
int lav_audio_channels(lav_file_t *lav_file);
int lav_audio_bits(lav_file_t *lav_file);
long lav_audio_rate(lav_file_t *lav_file);
long lav_audio_clips(lav_file_t *lav_file);
long lav_frame_size(lav_file_t *lav_file, long frame);
int lav_seek_start(lav_file_t *lav_file);
int lav_set_video_position(lav_file_t *lav_file, long frame);
int lav_read_frame(lav_file_t *lav_file, uint8_t *vidbuf);
int lav_set_audio_position(lav_file_t *lav_file, long clip);
int lav_read_audio(lav_file_t *lav_file, uint8_t *audbuf, long samps);
int lav_filetype(lav_file_t *lav_file);
lav_file_t *lav_open_input_file(char *filename, int mmap_size);
int lav_get_field_size(uint8_t * jpegdata, long jpeglen);
const char *lav_strerror(void);
int lav_fileno( lav_file_t *lav_file );
void lav_set_default_chroma(int c);
int lav_bogus_video_length( lav_file_t *lav_file );
void lav_bogus_set_length( lav_file_t *lav_file , int len );
#ifdef USE_GDK_PIXBUF
VJFrame *lav_get_frame_ptr( lav_file_t *lav_file );
void lav_set_project( int w, int h, float fps, int shift );
#endif
#endif

View File

@@ -0,0 +1,445 @@
/* veejay - Linux VeeJay
* (C) 2002-2005 Niels Elburg <nelburg@looze.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#ifdef USE_GDK_PIXBUF
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <libvjmsg/vj-msg.h>
#include <libvjmem/vjmem.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libvje/vje.h>
#include <libvje/effects/common.h>
#include <libyuv/yuvconv.h>
#include <libel/pixbuf.h>
#include <veejay/vims.h>
#include AVCODEC_INC
#include SWSCALE_INC
#include <libyuv/yuvconv.h>
#ifdef STRICT_CHECKING
#include <assert.h>
#endif
#define RUP8(num)(((num)+8)&~8)
typedef struct
{
char *filename;
VJFrame *picA;
VJFrame *picB;
VJFrame *img;
uint8_t *space;
int display_w;
int display_h;
int real_w;
int real_h;
int fmt;
} vj_pixbuf_t;
typedef struct
{
char *filename;
char *type;
int out_w;
int out_h;
} vj_pixbuf_out_t;
static int __initialized = 0;
extern int get_ffmpeg_pixfmt(int id);
extern uint8_t *vj_perform_get_preview_buffer();
static VJFrame *open_pixbuf( const char *filename, int dst_w, int dst_h, int dst_fmt,
uint8_t *dY, uint8_t *dU, uint8_t *dV )
{
GdkPixbuf *image =
gdk_pixbuf_new_from_file( filename, NULL );
if(!image)
{
veejay_msg(VEEJAY_MSG_ERROR, "Unable to load image '%s'", filename);
return NULL;
}
/* convert image to veejay frame in proper dimensions, free image */
int img_fmt = PIX_FMT_RGB24;
if( gdk_pixbuf_get_has_alpha( image ))
img_fmt = PIX_FMT_RGBA;
VJFrame *dst = yuv_yuv_template( dY, dU, dV, dst_w, dst_h, dst_fmt );
VJFrame *src = yuv_rgb_template(
(uint8_t*) gdk_pixbuf_get_pixels( image ),
gdk_pixbuf_get_width( image ),
gdk_pixbuf_get_height( image ),
img_fmt // PIX_FMT_RGB24
);
int stride = gdk_pixbuf_get_rowstride(image);
if( stride != src->stride[0] )
src->stride[0] = stride;
veejay_msg(VEEJAY_MSG_DEBUG,"Image is %dx%d (src=%d, stride=%d, dstfmt=%d), scaling to %dx%d",
src->width,src->height,img_fmt, stride,dst_fmt,dst->width,dst->height );
yuv_convert_any_ac( src, dst, src->format, dst->format );
gdk_pixbuf_unref( image );
free(src);
return dst;
}
void vj_picture_cleanup( void *pic )
{
vj_pixbuf_t *picture = ( vj_pixbuf_t*) pic;
if(picture)
{
if( picture->filename )
free(picture->filename );
if(picture->img)
free( picture->img );
if(picture->space)
free(picture->space);
if( picture )
free(picture);
}
picture = NULL;
}
VJFrame *vj_picture_get(void *pic)
{
if(!pic)
return NULL;
vj_pixbuf_t *picture = (vj_pixbuf_t*) pic;
return picture->img;
}
int vj_picture_get_height( void *pic )
{
vj_pixbuf_t *picture = (vj_pixbuf_t*) pic;
if(!picture)
return 0;
return picture->real_h;
}
int vj_picture_get_width( void *pic )
{
vj_pixbuf_t *picture = (vj_pixbuf_t*) pic;
if(!picture)
return 0;
return picture->real_w;
}
void *vj_picture_open( const char *filename, int v_outw, int v_outh, int v_outf )
{
vj_pixbuf_t *pic = NULL;
if(filename == NULL )
{
veejay_msg(0, "No image filename given");
return NULL;
}
if(v_outw <= 0 || v_outh <= 0 )
{
veejay_msg(0, "No image dimensions setup");
return NULL;
}
pic = (vj_pixbuf_t*) vj_calloc(sizeof(vj_pixbuf_t));
if(!pic)
{
veejay_msg(0, "Memory allocation error in %s", __FUNCTION__ );
return NULL;
}
pic->filename = strdup( filename );
pic->display_w = v_outw;
pic->display_h = v_outh;
pic->fmt = v_outf;
int len = v_outw * v_outh;
int ulen = len;
switch( v_outf )
{
case PIX_FMT_YUV420P:
case PIX_FMT_YUVJ420P:
ulen = len / 4;
break;
case PIX_FMT_YUV422P:
case PIX_FMT_YUVJ422P:
ulen = len / 2;
break;
default:
#ifdef STRICT_CHECKING
assert(0);
#endif
break;
}
pic->space = (uint8_t*) vj_malloc( sizeof(uint8_t) * (3 * len));
#ifdef STRICT_CHECKING
assert(pic->space != NULL );
#endif
pic->img = open_pixbuf(
filename,
v_outw,
v_outh,
v_outf,
pic->space,
pic->space + len,
pic->space + len + ulen );
return (void*) pic;
}
int vj_picture_probe( const char *filename )
{
int ret = 0;
GdkPixbuf *image =
gdk_pixbuf_new_from_file( filename, NULL );
if(image)
{
ret = 1;
gdk_pixbuf_unref( image );
}
return ret;
}
/* image saving */
static void add_if_writeable( GdkPixbufFormat *data, GSList **list)
{
if( gdk_pixbuf_format_is_writable( data ))
*list = g_slist_prepend( *list, data );
gchar *name = gdk_pixbuf_format_get_name( data );
if(name) g_free(name);
}
char *vj_picture_get_filename( void *pic )
{
vj_pixbuf_out_t *p = (vj_pixbuf_out_t*) pic;
if(!p) return NULL;
return p->filename;
}
void * vj_picture_prepare_save(
const char *filename, char *type, int out_w, int out_h)
{
if(!type || !filename )
{
veejay_msg(0, "Missing filename or file extension");
return NULL;
}
vj_pixbuf_out_t *pic = (vj_pixbuf_out_t*) vj_calloc(sizeof(vj_pixbuf_out_t));
if(!pic)
return NULL;
if(filename)
pic->filename = strdup( filename );
else
pic->filename = NULL;
if(strncasecmp(type,"jpg",3 ) == 0)
pic->type = strdup("jpeg");
else
pic->type = strdup( type );
pic->out_w = out_w;
pic->out_h = out_h;
return (void*) pic;
}
static void display_if_writeable( GdkPixbufFormat *data, GSList **list)
{
if( gdk_pixbuf_format_is_writable( data ))
*list = g_slist_prepend( *list, data );
gchar *name = gdk_pixbuf_format_get_name( data );
if( name ) g_free(name);
}
void vj_picture_display_formats()
{
GSList *f = gdk_pixbuf_get_formats();
GSList *res = NULL;
g_slist_foreach( f, display_if_writeable, &res);
g_slist_free( f );
g_slist_free( res );
}
static void vj_picture_out_cleanup( vj_pixbuf_out_t *pic )
{
if(pic)
{
if(pic->filename)
free(pic->filename);
if(pic->type)
free(pic->type);
free(pic);
}
pic = NULL;
}
static void *pic_scaler_ = NULL;
static int pic_data_[3] = { 0,0,0};
static int pic_changed_ = 0;
static sws_template *pic_template_ = NULL;
void vj_picture_init( void *templ )
{
if(!__initialized)
{
// cool stuff
g_type_init();
veejay_msg(VEEJAY_MSG_DEBUG, "Using gdk pixbuf %s", gdk_pixbuf_version );
__initialized = 1;
}
pic_template_ = (sws_template*) templ;
}
int vj_picture_save( void *picture, uint8_t **frame, int w, int h , int fmt )
{
int ret = 0;
vj_pixbuf_out_t *pic = (vj_pixbuf_out_t*) picture;
GdkPixbuf *img_ = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, w, h );
if(!img_)
{
veejay_msg(VEEJAY_MSG_ERROR, "Cant allocate buffer for RGB");
return 0;
}
// convert frame to yuv
VJFrame *src = yuv_yuv_template( frame[0],frame[1],frame[2],w,h, fmt );
VJFrame *dst = yuv_rgb_template(
(uint8_t*) gdk_pixbuf_get_pixels( img_ ),
gdk_pixbuf_get_width( img_ ),
gdk_pixbuf_get_height( img_ ),
PIX_FMT_RGB24
);
yuv_convert_any_ac( src, dst, fmt, PIX_FMT_RGB24 );
if( gdk_pixbuf_savev( img_, pic->filename, pic->type, NULL, NULL, NULL ))
{
veejay_msg(VEEJAY_MSG_INFO, "Save frame as %s of type %s",
pic->filename, pic->type );
ret = 1;
}
else
{
veejay_msg(VEEJAY_MSG_ERROR,
"Cant save file as %s (%s) size %d x %d", pic->filename,pic->type, pic->out_w, pic->out_h);
}
if( img_ )
gdk_pixbuf_unref( img_ );
free(src);
free(dst);
vj_picture_out_cleanup( pic );
return ret;
}
void vj_picture_free()
{
}
#define pic_has_changed(a,b,c) ( (a == pic_data_[0] && b == pic_data_[1] && c == pic_data_[2] ) ? 0: 1)
#define update_pic_data(a,b,c) { pic_data_[0] = a; pic_data_[1] = b; pic_data_[2] = c;}
void vj_fast_picture_save_to_mem( VJFrame *frame, int out_w, int out_h, int pixfmt )
{
VJFrame *src1 = yuv_yuv_template( frame->data[0],frame->data[1],frame->data[2],
frame->width,frame->height, pixfmt );
uint8_t *dest[3];
dest[0] = vj_perform_get_preview_buffer();
dest[1] = dest[0] + (out_w * out_h);
dest[2] = dest[1] + ( (out_w * out_h)/4 );
VJFrame *dst1 = yuv_yuv_template( dest[0], dest[1], dest[2], out_w, out_h, PIX_FMT_YUV420P );
pic_changed_ = pic_has_changed( out_w,out_h, pixfmt );
if(pic_changed_ )
{
if(pic_scaler_)
yuv_free_swscaler( pic_scaler_ );
pic_scaler_ = yuv_init_swscaler( src1,dst1, pic_template_, yuv_sws_get_cpu_flags());
update_pic_data( out_w, out_h, pixfmt );
}
if( frame->width == out_w && frame->height == out_h )
yuv_convert_any_ac( src1, dst1, src1->format, dst1->format );
else
yuv_convert_and_scale( pic_scaler_, src1,dst1);
free(src1);
free(dst1);
}
void vj_fastbw_picture_save_to_mem( VJFrame *frame, int out_w, int out_h, int pixfmt )
{
VJFrame *src1 = yuv_yuv_template( frame->data[0],frame->data[1],frame->data[2],
frame->width,frame->height, pixfmt );
uint8_t *planes[3];
planes[0] = vj_perform_get_preview_buffer();
planes[1] = planes[0] + (out_w * out_h );
planes[2] = planes[1] + (out_w * out_h );
VJFrame *dst1 = yuv_yuv_template( planes[0], planes[1], planes[2],
out_w , out_h, PIX_FMT_GRAY8 );
pic_changed_ = pic_has_changed( out_w,out_h, pixfmt );
if(pic_changed_ )
{
if(pic_scaler_)
yuv_free_swscaler( pic_scaler_ );
pic_scaler_ = yuv_init_swscaler( src1,dst1, pic_template_, yuv_sws_get_cpu_flags());
update_pic_data( out_w, out_h, pixfmt );
}
if( frame->width == out_w && frame->height == out_h )
yuv_convert_any_ac( src1,dst1,src1->format, dst1->format );
else
yuv_convert_and_scale( pic_scaler_, src1, dst1);
free(src1);
free(dst1);
}
#endif

View File

@@ -0,0 +1,53 @@
/* veejay - Linux VeeJay
* (C) 2002-2005 Niels Elburg <nelburg@looze.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef VJ_PIXBUF_H
#define VJ_PIXBUF_H
#include <config.h>
#include <libvje/vje.h>
typedef struct
{
int w;
int h;
} veejay_image_t;
#ifdef USE_GDK_PIXBUF
void vj_picture_init(void *templ);
void vj_picture_cleanup( void *pic );
VJFrame *vj_picture_get( void *pic );
int vj_picture_probe( const char *filename );
void *vj_picture_open( const char *filename, int v_outw, int v_outh, int v_outf );
int vj_picture_get_width(void *pic);
int vj_picture_get_height(void *pic);
void vj_picture_display_formats(void);
char *vj_picture_get_filename( void *pic );
void * vj_picture_prepare_save( const char *filename, char *type, int out_w, int out_h);
int vj_picture_save( void *picture, uint8_t **frame, int w, int h , int fmt );
void vj_picture_display_formats(void);
veejay_image_t *vj_picture_save_bw_to_memory( uint8_t **frame, int w, int h , int out_w, int out_h, int fmt );
veejay_image_t *vj_picture_save_to_memory( uint8_t **frame, int w, int h , int out_w, int out_h, int fmt );
void vj_fastbw_picture_save_to_mem( VJFrame *f, int out_w, int out_h, int fmt );
void vj_fast_picture_save_to_mem(VJFrame *f, int out_w, int out_h, int fmt );
void vj_picture_free();
#endif
#endif

View File

@@ -0,0 +1,329 @@
/*
* Linux VeeJay
*
* Copyright(C)2002-2004 Niels Elburg <nelburg@looze.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License , or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
*/
#include <config.h>
#include <sys/types.h>
#ifdef SUPPORT_READ_DV2
#include <libel/rawdv.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <libvjmsg/vj-msg.h>
#include <libvjmem/vjmem.h>
#include <libel/vj-mmap.h>
#include <libdv/dv.h>
#include <ffmpeg/avcodec.h>
#include <errno.h>
#define DV_PAL_SIZE 144000
#define DV_NTSC_SIZE 120000
static void rawdv_free(dv_t *dv)
{
if(dv->filename) free(dv->filename);
if(dv->buf) free(dv->buf);
if(dv) free(dv);
}
int rawdv_close(dv_t *dv)
{
close(dv->fd);
mmap_free(dv->mmap_region);
rawdv_free( dv);
return 1;
}
int rawdv_sampling(dv_t *dv)
{
switch(dv->fmt)
{
case e_dv_sample_411: return 4;
case e_dv_sample_422: return 2;
case e_dv_sample_420: return 1;
}
return 3;
}
#define DV_HEADER_SIZE 120000
dv_t *rawdv_open_input_file(const char *filename, int mmap_size)
{
dv_t *dv = (dv_t*) vj_malloc(sizeof(dv_t));
if(!dv) return NULL;
memset(dv, 0, sizeof(dv_t));
dv_decoder_t *decoder = NULL;
uint8_t *tmp = (uint8_t*) vj_malloc(sizeof(uint8_t) * DV_HEADER_SIZE);
memset( tmp, 0, sizeof(uint8_t) * DV_HEADER_SIZE);
off_t file_size = 0;
int n = 0;
decoder = dv_decoder_new( 1,0,0);
dv->fd = open( filename, O_RDONLY );
if(!dv->fd)
{
dv_decoder_free(decoder);
rawdv_free(dv);
veejay_msg(VEEJAY_MSG_ERROR, "Cannot open '%s'",filename);
if(tmp)free(tmp);
return NULL;
}
/* fseek sometimes lies about filesize - seek to end (lseek returns file offset from start)*/
file_size = lseek( dv->fd, 0, SEEK_END );
if( file_size < DV_HEADER_SIZE)
{
dv_decoder_free(decoder);
veejay_msg(VEEJAY_MSG_ERROR, "% is too small! ", filename);
rawdv_free(dv);
if(tmp) free(tmp);
return NULL;
}
/* And back to start offset */
if( lseek(dv->fd,0, SEEK_SET ) < 0)
{
dv_decoder_free(decoder);
veejay_msg(VEEJAY_MSG_ERROR, "Seek errror");
rawdv_free(dv);
if(tmp) free(tmp);
return NULL;
}
dv->mmap_region = NULL;
if( mmap_size > 0 ) // user wants mmap
{
dv->mmap_region = mmap_file( dv->fd, 0, (mmap_size * 720 * 576 * 3),
file_size );
}
if( dv->mmap_region == NULL )
{
if(mmap_size>0)
veejay_msg(VEEJAY_MSG_DEBUG, "Mmap failed - fallback to read");
n = read( dv->fd, tmp, DV_HEADER_SIZE );
}
else
{
n = mmap_read( dv->mmap_region, 0, DV_HEADER_SIZE, tmp );
}
if( n <= 0 )
{
dv_decoder_free(decoder);
rawdv_free(dv);
if(tmp) free(tmp);
veejay_msg(VEEJAY_MSG_ERROR, "Cannot read from '%s'", filename);
return NULL;
}
if( dv_parse_header( decoder, tmp) < 0 )
{
dv_decoder_free( decoder );
rawdv_free(dv);
if(tmp) free(tmp);
veejay_msg(VEEJAY_MSG_ERROR, "Cannot parse header");
return NULL;
}
/* if(decoder->sampling == e_dv_sample_411)
{
dv_decoder_free( decoder );
rawdv_free(dv);
if(tmp) free(tmp);
return NULL;
}*/
if(dv_is_PAL( decoder ) )
dv->chunk_size = DV_PAL_SIZE;
else
dv->chunk_size = DV_NTSC_SIZE;
dv->width = decoder->width;
dv->height = decoder->height;
dv->audio_rate = decoder->audio->frequency;
dv->audio_chans = decoder->audio->num_channels;
dv->audio_qbytes = decoder->audio->quantization;
dv->fps = ( dv_is_PAL( decoder) ? 25.0 : 29.97 );
dv->size = decoder->frame_size;
dv->num_frames = (file_size - DV_HEADER_SIZE) / dv->size;
dv->fmt = decoder->sampling;
// dv->fmt = ( decoder->sampling == e_dv_sample_422 ? 1 : 0);
dv->buf = (uint8_t*) vj_malloc(sizeof(uint8_t*) * dv->size);
dv->offset = 0;
veejay_msg(VEEJAY_MSG_DEBUG,
"DV properties %d x %d, %f, %d frames, %d sampling",
dv->width,dv->height, dv->fps, dv->num_frames,
dv->fmt );
dv_decoder_free( decoder );
if(tmp)
free(tmp);
/* if(dv->audio_rate)
{
int i;
for( i = 0; i < 4; i ++ )
dv->audio_buffers[i] = (int16_t*) vj_malloc(sizeof(int16_t) * 2 * DV_AUDIO_MAX_SAMPLES);
}*/
/*
veejay_msg(VEEJAY_MSG_DEBUG,
"rawDV: num frames %ld, dimensions %d x %d, at %2.2f in %s",
dv->num_frames,
dv->width,
dv->height,
dv->fps,
(dv->fmt==1?"422":"420"));
veejay_msg(VEEJAY_MSG_DEBUG,
"rawDV: frame size %d, rate %d, channels %d, bits %d",
dv->size,
dv->audio_rate,
dv->audio_chans,
dv->audio_qbytes);*/
return dv;
}
int rawdv_set_position(dv_t *dv, long nframe)
{
off_t offset = nframe * dv->size;
if(nframe <= 0 )
offset = 0;
else
if(nframe > dv->num_frames)
offset = dv->num_frames * dv->size;
dv->offset = offset;
if( lseek( dv->fd, offset, SEEK_SET ) < 0 )
return -1;
return 0;
}
int rawdv_read_frame(dv_t *dv, uint8_t *buf )
{
int n = 0;
if(dv->mmap_region == NULL)
{
n = read( dv->fd, dv->buf, dv->size );
memcpy( buf, dv->buf, dv->size );
}
else
{
n = mmap_read( dv->mmap_region, dv->offset, dv->size, buf );
}
return n;
}
int rawdv_read_audio_frame(dv_t *dv, uint8_t *audio )
{
return 0;
/*
int n = dv_decode_full_audio( dv->decoder, dv->buf, dv->audio_buffers );
// interleave buffers to audio
int n_samples = dv_get_num_samples( dv->decoder );
int n_chans = dv->audio_chans;
int16_t *ch0 = dv->audio_buffers[0];
int16_t *ch1 = dv->audio_buffers[1];
int i,j;
for( i = 0; i < n_samples; i ++ )
{
*(audio) = *(ch0) & 0xff;
*(audio+1) = (*(ch0) << 8) & 0xff;
*(audio+2) = *(ch1) & 0xff;
*(audio+3) = (*(ch1)<<8) & 0xff;
*(ch0) ++;
*(ch1) ++;
*(audio) += 4;
}
return n_samples * 4;
*/
}
int rawdv_video_frames(dv_t *dv)
{
return dv->num_frames;
}
int rawdv_width(dv_t *dv)
{
return dv->width;
}
int rawdv_height(dv_t *dv)
{
return dv->height;
}
double rawdv_fps(dv_t *dv)
{
return (double) dv->fps;
}
int rawdv_compressor(dv_t *dv)
{
return CODEC_ID_DVVIDEO;
}
char *rawdv_video_compressor(dv_t *dv)
{
char *res = "dvsd\0";
return res;
}
int rawdv_audio_channels(dv_t *dv)
{
return dv->audio_chans;
}
int rawdv_audio_bits(dv_t *dv)
{
return dv->audio_qbytes;
}
int rawdv_audio_format(dv_t *dv)
{
// pcm wave format
return (0x0001);
}
int rawdv_audio_rate(dv_t *dv)
{
return dv->audio_rate;
}
int rawdv_audio_bps(dv_t *dv)
{
return 4;
}
int rawdv_frame_size(dv_t *dv)
{
return dv->size;
}
int rawdv_interlacing(dv_t *dv)
{
return 0;
}
#endif

View File

@@ -0,0 +1,67 @@
#ifndef RAWDV_H
#define RAWDV_H
/*
* Linux VeeJay
*
* Copyright(C)2002-2004 Niels Elburg <nelburg@looze.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License , or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
*/
#include <config.h>
#include <stdint.h>
#include <sys/types.h>
#include <libdv/dv.h>
#include <libel/vj-mmap.h>
typedef struct
{
int fd;
char *filename;
long num_frames;
int width;
int height;
float fps;
int chunk_size;
long audio_rate;
int audio_chans;
int audio_qbytes;
dv_decoder_t *decoder;
int16_t *audio_buffers[4];
off_t offset;
uint8_t *buf;
int size;
int fmt;
mmap_region_t *mmap_region;
} dv_t;
int rawdv_sampling(dv_t *dv);
int rawdv_close(dv_t *dv);
dv_t *rawdv_open_input_file(const char *filename, int mmap_size);
int rawdv_set_position(dv_t *dv, long nframe);
int rawdv_read_frame(dv_t *dv, uint8_t *buf );
int rawdv_read_audio_frame(dv_t *dv, uint8_t *buf);
int rawdv_video_frames(dv_t *dv);
int rawdv_width(dv_t *dv);
int rawdv_height(dv_t *dv);
double rawdv_fps(dv_t *dv);
int rawdv_compressor(dv_t *dv);
char *rawdv_video_compressor(dv_t *dv);
int rawdv_audio_channels(dv_t *dv);
int rawdv_audio_bits(dv_t *dv);
int rawdv_audio_format(dv_t *dv);
int rawdv_audio_rate(dv_t *dv);
int rawdv_audio_bps(dv_t *dv);
int rawdv_frame_size(dv_t *dv);
int rawdv_interlacing(dv_t *dv);
#endif

View File

@@ -0,0 +1,475 @@
/* veejay - Linux VeeJay
* (C) 2002-2004 Niels Elburg <nelburg@looze.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <libel/vj-avcodec.h>
#include <libel/vj-el.h>
#include <libvjmsg/vj-msg.h>
#include <libvjmem/vjmem.h>
#include <stdint.h>
#include <string.h>
#include <libyuv/yuvconv.h>
#include <liblzo/lzo.h>
#ifdef SUPPORT_READ_DV2
#define __FALLBACK_LIBDV
#include <libel/vj-dv.h>
#endif
#include AVCODEC_INC
#include AVUTIL_INC
#define YUV420_ONLY_CODEC(id) ( ( id == CODEC_ID_MJPEG || id == CODEC_ID_MJPEGB || id == CODEC_ID_MSMPEG4V3 || id == CODEC_ID_MPEG4) ? 1: 0)
static int out_pixel_format = FMT_420;
char* vj_avcodec_get_codec_name(int codec_id )
{
char name[20];
switch(codec_id)
{
case CODEC_ID_MJPEG: sprintf(name, "MJPEG"); break;
case CODEC_ID_MPEG4: sprintf(name, "MPEG4"); break;
case CODEC_ID_MSMPEG4V3: sprintf(name, "DIVX"); break;
case CODEC_ID_DVVIDEO: sprintf(name, "DVVideo"); break;
case 999 : sprintf(name, "RAW YUV 4:2:0 Planar"); break;
case 998 : sprintf(name, "RAW YUV 4:2:2 Planar"); break;
case 900 : sprintf(name, "LZO YUV 4:2:2 Planar"); break;
default:
sprintf(name, "Unknown"); break;
}
char *res = strdup(name);
return res;
}
static vj_encoder *vj_avcodec_new_encoder( int id, editlist *el, int pixel_format)
{
vj_encoder *e = (vj_encoder*) vj_calloc(sizeof(vj_encoder));
if(!e) return NULL;
if( YUV420_ONLY_CODEC(id ))
{
e->data[0] = (uint8_t*) vj_calloc(sizeof(uint8_t) *
el->video_width * el->video_height );
e->data[1] = (uint8_t*) vj_calloc(sizeof(uint8_t) *
el->video_width * el->video_height /2 );
e->data[2] = (uint8_t*) vj_calloc(sizeof(uint8_t) *
el->video_width * el->video_height /2);
}
if( id == 900 )
{
e->lzo = lzo_new();
}
if(id != 998 && id != 999 && id != 900)
{
#ifdef __FALLBACK_LIBDV
if(id != CODEC_ID_DVVIDEO)
{
#endif
e->codec = avcodec_find_encoder( id );
if(!e->codec)
{
char *descr = vj_avcodec_get_codec_name(id);
veejay_msg(VEEJAY_MSG_ERROR, "Cannot find Encoder codec %s", descr );
free(descr);
}
#ifdef __FALLBACK_LIBDV
}
#endif
}
if( id != 998 && id != 999 && id!= 900)
{
#ifdef __FALLBACK_LIBDV
if(id != CODEC_ID_DVVIDEO )
{
#endif
e->context = avcodec_alloc_context();
e->context->bit_rate = 2750 * 1024;
e->context->width = el->video_width;
e->context->height = el->video_height;
#if LIBAVCODEC_BUILD > 5010
e->context->time_base = (AVRational) { 1, el->video_fps };
#else
e->context->frame_rate = el->video_fps;
e->context->frame_rate_base = 1;
#endif
e->context->qcompress = 0.0;
e->context->qblur = 0.0;
e->context->max_b_frames = 0;
e->context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
e->context->flags = CODEC_FLAG_QSCALE;
e->context->gop_size = 0;
e->context->sub_id = 0;
e->context->me_method = 0; // motion estimation algorithm
e->context->workaround_bugs = FF_BUG_AUTODETECT;
e->context->prediction_method = 0;
e->context->dct_algo = FF_DCT_AUTO; //global_quality?
switch(pixel_format)
{
case FMT_420:
e->context->pix_fmt = PIX_FMT_YUV420P;
break;
case FMT_420F:
e->context->pix_fmt = PIX_FMT_YUVJ420P;
break;
case FMT_422F:
e->context->pix_fmt = PIX_FMT_YUVJ422P;
break;
default:
e->context->pix_fmt = PIX_FMT_YUV422P;
break;
}
char *descr = vj_avcodec_get_codec_name( id );
if ( avcodec_open( e->context, e->codec ) < 0 )
{
veejay_msg(VEEJAY_MSG_ERROR, "Cannot open codec '%s'" , descr );
if(e->context) free(e->context);
if(e) free(e);
if(descr) free(descr);
return NULL;
}
else
{
veejay_msg(VEEJAY_MSG_DEBUG, "\tOpened encoder %s", descr );
free(descr);
}
#ifdef __FALLBACK_LIBDV
}
#endif
}
e->len = el->video_width * el->video_height;
if(el->pixel_format == FMT_422 || el->pixel_format == FMT_422F)
e->uv_len = e->len / 2;
else
e->uv_len = e->len / 4;
e->width = el->video_width;
e->height = el->video_height;
e->out_fmt = el->pixel_format;
e->encoder_id = id;
/*
if( el->has_audio )
{
e->audiocodec = avcodec_find_encoder( CODEC_ID_PCM_U8 );
if(!e->audiocodec)
{
veejay_msg(VEEJAY_MSG_ERROR, "Error initializing audio codec");
if(e) free(e);
}
e->context->sample_rate = el->audio_rate;
e->context->channels = el->audio_chans;
if( avcodec_open( e->context, e->audiocodec ) < 0)
{
veejay_msg(VEEJAY_MSG_ERROR, "Cannot open audio context");
if(e) free(e);
return NULL;
}
}
*/
return e;
}
void vj_avcodec_close_encoder( vj_encoder *av )
{
if(av)
{
if(av->context)
{
avcodec_close( av->context );
free(av->context);
av->context = NULL;
}
if(av->data[0])
free(av->data[0]);
if(av->data[1])
free(av->data[1]);
if(av->data[2])
free(av->data[2]);
if(av->lzo)
lzo_free(av->lzo);
free(av);
}
av = NULL;
}
int vj_avcodec_find_codec( int encoder )
{
switch( encoder)
{
case ENCODER_MJPEG:
case ENCODER_QUICKTIME_MJPEG:
return CODEC_ID_MJPEG;
case ENCODER_DVVIDEO:
case ENCODER_QUICKTIME_DV:
return CODEC_ID_DVVIDEO;
case ENCODER_YUV420:
return 999;
case ENCODER_YUV422:
return 998;
case ENCODER_MPEG4:
return CODEC_ID_MPEG4;
case ENCODER_DIVX:
return CODEC_ID_MSMPEG4V3;
case ENCODER_LZO:
return 900;
default:
veejay_msg(VEEJAY_MSG_DEBUG, "Unknown format %d selected", encoder );
return 0;
}
return 0;
}
int vj_avcodec_stop( void *encoder , int fmt)
{
if(!encoder)
return 0;
#ifdef SUPPORT_READ_DV2
if( fmt == CODEC_ID_DVVIDEO )
{
vj_dv_free_encoder(encoder);
encoder = NULL;
return 1;
}
#endif
if( fmt == 900 )
{
return 1;
}
vj_encoder *env = (vj_encoder*) encoder;
vj_avcodec_close_encoder( env );
encoder = NULL;
return 1;
}
void *vj_avcodec_start( editlist *el, int encoder )
{
int codec_id = vj_avcodec_find_codec( encoder );
void *ee = NULL;
#ifdef SUPPORT_READ_DV2
if(codec_id == CODEC_ID_DVVIDEO )
{
if(!is_dv_resolution(el->video_width, el->video_height ))
{
veejay_msg(VEEJAY_MSG_ERROR,"\tVideo dimensions do not match required resolution");
return NULL;
}
else
{
ee = (void*)vj_dv_init_encoder( (void*)el , out_pixel_format);
return ee;
}
}
#else
if( codec_id == CODEC_ID_DVVIDEO )
return NULL;
#endif
ee = vj_avcodec_new_encoder( codec_id, el , encoder );
if(!ee)
{
veejay_msg(VEEJAY_MSG_ERROR, "\tFailed to start encoder %x",encoder);
return NULL;
}
return ee;
}
int vj_avcodec_init( int pixel_format, int verbose)
{
out_pixel_format = pixel_format;
if( !verbose )
av_log_set_level( AV_LOG_QUIET);
else
av_log_set_level( AV_LOG_VERBOSE );
av_register_all();
veejay_msg(VEEJAY_MSG_INFO, "FFmpeg AVCodec initialized (http://ffmpeg.sourceforge.net)");
return 1;
}
int vj_avcodec_free()
{
return 1;
}
static void long2str(unsigned char *dst, int32_t n)
{
dst[0] = (n )&0xff;
dst[1] = (n>> 8)&0xff;
dst[2] = (n>>16)&0xff;
dst[3] = (n>>24)&0xff;
}
static int vj_avcodec_lzo( vj_encoder *av, uint8_t *src[3], uint8_t *dst , int buf_len )
{
uint8_t *dstI = dst + (3 * 4);
int size1 = 0, size2=0,size3=0;
int i;
i = lzo_compress( av->lzo, src[0], dstI, &size1 , av->len);
if( i == 0 )
{
veejay_msg(0,"\tunable to compress Y plane");
return 0;
}
dstI += size1;
i = lzo_compress( av->lzo, src[1], dstI, &size2 , av->uv_len );
if( i == 0 )
{
veejay_msg(0,"\tunable to compress U plane");
return 0;
}
dstI += size2;
i = lzo_compress( av->lzo, src[2], dstI, &size3 , av->uv_len );
if( i == 0 )
{
veejay_msg(0,"\tunable to compress V plane");
return 0;
}
long2str( dst, size1 );
long2str( dst+4,size2);
long2str( dst+8,size3);
return (size1 + size2 + size3 + 12);
}
static int vj_avcodec_copy_frame( vj_encoder *av, uint8_t *src[3], uint8_t *dst )
{
if(!av)
{
veejay_msg(VEEJAY_MSG_ERROR, "No encoder !!");
return 0;
}
if( (av->encoder_id == 999 && (av->out_fmt == FMT_420 ||av->out_fmt == FMT_420F)) || (av->encoder_id == 998 && (av->out_fmt == FMT_422||av->out_fmt == FMT_422F)))
{
/* copy */
veejay_memcpy( dst, src[0], av->len );
veejay_memcpy( dst+(av->len), src[1], av->uv_len );
veejay_memcpy( dst+(av->len+av->uv_len) , src[2], av->uv_len);
return ( av->len + av->uv_len + av->uv_len );
}
/* copy by converting */
if( av->encoder_id == 999 && (av->out_fmt == FMT_422 || av->out_fmt==FMT_422F))
{
VJFrame *srci= yuv_yuv_template( src[0],src[1],src[2], av->width,av->height, get_ffmpeg_pixfmt( av->out_fmt));
VJFrame *dsti= yuv_yuv_template( dst,dst+av->len,dst+av->len+(av->len/4), av->width,av->height, PIX_FMT_YUV420P );
yuv_convert_any_ac( srci,dsti, srci->format, dsti->format );
free(srci);
free(dsti);
return ( av->len + (av->len/4) + (av->len/4));
}
if( av->encoder_id == 998 && (av->out_fmt == FMT_420||av->out_fmt==FMT_420F))
{
VJFrame *srci = yuv_yuv_template( src[0],src[1],src[2], av->width,av->height,get_ffmpeg_pixfmt(av->out_fmt));
VJFrame *dsti = yuv_yuv_template( dst, dst + av->len, dst + (av->len + (av->len/2)),
av->width,av->height, PIX_FMT_YUV422P);
free(srci);
free(dsti);
return ( av->len + av->len );
}
return 0;
}
int vj_avcodec_encode_frame(void *encoder, int nframe,int format, uint8_t *src[3], uint8_t *buf, int buf_len)
{
AVFrame pict;
int res=0;
memset( &pict, 0, sizeof(pict));
if(format == ENCODER_LZO )
return vj_avcodec_lzo( encoder, src, buf, buf_len );
if(format == ENCODER_YUV420 || format == ENCODER_YUV422) // no compression, just copy
return vj_avcodec_copy_frame( encoder,src, buf );
#ifdef __FALLBACK_LIBDV
if(format == ENCODER_DVVIDEO || format == ENCODER_QUICKTIME_DV )
return vj_dv_encode_frame( encoder,src, buf );
#endif
vj_encoder *av = (vj_encoder*) encoder;
pict.quality = 1;
pict.pts = (int64_t)( (int64_t)nframe );
int src_fmt = get_ffmpeg_pixfmt( out_pixel_format );
if(av->context->pix_fmt != src_fmt )
{
pict.data[0] = av->data[0];
pict.data[1] = av->data[1];
pict.data[2] = av->data[2];
pict.linesize[0] = av->context->width;
pict.linesize[1] = av->context->width >> 1;
pict.linesize[2] = av->context->width >> 1;
VJFrame *srci = yuv_yuv_template( src[0],src[1],src[2], av->context->width,av->context->height, src_fmt );
VJFrame *dsti = yuv_yuv_template( av->data[0],av->data[1],av->data[2],av->context->width,av->context->height,
av->context->pix_fmt );
yuv_convert_any_ac( srci,dsti, srci->format, dsti->format );
free(srci);
free(dsti);
}
else
{
pict.data[0] = src[0];
pict.data[1] = src[1];
pict.data[2] = src[2];
pict.linesize[0] = av->context->width;
pict.linesize[1] = pict.linesize[0]>>1;
pict.linesize[2] = pict.linesize[0]>>1;
}
res = avcodec_encode_video( av->context, buf, buf_len, &pict );
return res;
}
int vj_avcodec_encode_audio( void *encoder, int format, uint8_t *src, uint8_t *dst, int len, int nsamples )
{
if(format == ENCODER_YUV420 || ENCODER_YUV422 == format)
return 0;
vj_encoder *av = encoder;
int ret = avcodec_encode_audio( av->context, src, len, nsamples );
return ret;
}

View File

@@ -0,0 +1,82 @@
/* veejay - Linux VeeJay
* (C) 2002-2004 Niels Elburg <nelburg@looze.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef VJ_AVCODEC_H
#define VJ_AVCODEC_H
//bad
#include AVCODEC_INC
#include "vj-el.h"
#define ENCODER_MJPEG 0
#define ENCODER_DVVIDEO 1
#define ENCODER_DIVX 2
#define ENCODER_MPEG4 3
#define ENCODER_YUV420 4
#define ENCODER_YUV422 5
#define ENCODER_QUICKTIME_DV 6
#define ENCODER_QUICKTIME_MJPEG 7
#define ENCODER_LZO 8
#define NUM_ENCODERS 9
typedef struct
{
AVCodec *codec;
AVCodec *audiocodec;
AVFrame *frame;
AVCodecContext *context;
int out_fmt;
int uv_len;
int len;
int sub_sample;
int super_sample;
int encoder_id;
int width;
int height;
uint8_t *data[3];
void *lzo;
} vj_encoder;
int vj_avcodec_init(int pix, int verbose);
int vj_avcodec_encode_frame(void *encoder,int nframe, int format, uint8_t *src[3], uint8_t *dst, int dst_len);
int vj_avcodec_free();
/* color space conversion routines, should go somewhere else someday
together with subsample.c/colorspace.c into some lib
*/
void yuv_planar_to_rgb24(uint8_t *src[3], int fmt, uint8_t *dst, int w, int h );
// from yuv 4:2:0 planar to yuv 4:2:2 planar
int yuv420p_to_yuv422p( uint8_t *Y, uint8_t *Cb, uint8_t *Cr, uint8_t *dst[3], int w, int h );
void yuv422p_to_yuv420p2( uint8_t *src[3], uint8_t *dst[3], int w, int h, int f );
int yuv420p_to_yuv422p2( uint8_t *sY,uint8_t *sCb, uint8_t *sCr, uint8_t *dst[3], int w, int h );
void yuv422p_to_yuv420p3( uint8_t *src, uint8_t *dst[3], int w, int h);
void *vj_avcodec_start( editlist *el, int encoder );
int vj_avcodec_stop( void *encoder , int fmt);
void vj_avcodec_close_encoder( vj_encoder *av );
#endif

View File

@@ -0,0 +1,370 @@
/*
* Linux VeeJay
*
* Copyright(C)2002-2004 Niels Elburg <nelburg@looze.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License , or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
*/
#include <config.h>
#include <stdint.h>
#include <libvjmem/vjmem.h>
#include <libvjmsg/vj-msg.h>
#ifdef SUPPORT_READ_DV2
#include <libdv/dv.h>
#include <libel/vj-el.h>
#include <stdint.h>
#include <libel/vj-dv.h>
#include <libel/vj-avcodec.h>
#include <libyuv/yuvconv.h>
#include <string.h>
#define NTSC_W 720
#define NTSC_H 480
#define PAL_W 720
#define PAL_H 576
#define DV_PAL_SIZE 144000
#define DV_NTSC_SIZE 120000
#define DV_AUDIO_MAX_SAMPLES 1944
#ifdef STRICT_CHECKING
#include <assert.h>
#endif
int is_dv_resolution(int w, int h)
{
if( h == NTSC_H && w == NTSC_W )
return 1;
if( h == PAL_H && w == PAL_W )
return 1;
return 0;
}
/* init the dv decoder and decode buffer*/
vj_dv_decoder *vj_dv_decoder_init(int quality, int width, int height, int pixel_format)
{
int dv_q = DV_QUALITY_COLOR;
vj_dv_decoder *d = (vj_dv_decoder*)vj_malloc(sizeof(vj_dv_decoder));
if(!d) return NULL;
d->decoder = dv_decoder_new( 1,1,0 );
if( quality == 0 )
dv_q = DV_QUALITY_FASTEST;
if( quality == 1 )
dv_q = DV_QUALITY_BEST;
d->decoder->quality = dv_q;
d->dv_video = (uint8_t*) vj_malloc(sizeof(uint8_t) * width * height * 4);
memset( d->dv_video, 0, (width*height*4));
d->fmt = pixel_format;
d->audio = 0; // audio off
return d;
}
/* init the dv encoder and encode buffer */
vj_dv_encoder *vj_dv_init_encoder(void * edl, int pixel_format)
{
editlist *el = (editlist*) edl;
vj_dv_encoder *e = (vj_dv_encoder*) vj_malloc(sizeof(vj_dv_encoder));
if(!e) return NULL;
e->encoder = dv_encoder_new(0,0,0);
e->encoder->isPAL = (el->video_norm == 'p' ? 1 : 0);
e->encoder->is16x9 = (el->video_width / el->video_height >= 1.777 ? 1: 0);
e->encoder->vlc_encode_passes = 3;
e->encoder->static_qno = 0;
e->encoder->force_dct = DV_DCT_AUTO;
e->fmt = pixel_format;
e->dv_video =
(uint8_t *) vj_malloc(sizeof(uint8_t) *
(e->encoder->isPAL ?
DV_PAL_SIZE : DV_NTSC_SIZE));
memset( e->dv_video, 0 ,
(e->encoder->isPAL ? DV_PAL_SIZE: DV_NTSC_SIZE ) );
return e;
}
/* encode frame to dv format, dv frame will be in output_buf */
int vj_dv_encode_frame(vj_dv_encoder *encoder, uint8_t *input_buf[3], uint8_t *output_buf)
{
time_t now = time(NULL);
uint8_t *pixels[3];
int w=0; int h = 0;
if (!input_buf)
return 0;
pixels[0] = (uint8_t *) encoder->dv_video;
if (encoder->encoder->isPAL)
{
h = PAL_H;
w = PAL_W;
}
else
{
h = NTSC_H;
w = NTSC_W;
}
if( encoder->fmt == FMT_420 || encoder->fmt == FMT_420F)
{
pixels[1] = (uint8_t *) encoder->dv_video + (w * h);
pixels[2] = (uint8_t *) encoder->dv_video + (w * h * 5) / 4;
yuv420p_to_yuv422(input_buf, encoder->dv_video, w, h );
}
else
{ // convert 422 planar to packed
int off = w * h / 2;
pixels[1] = (uint8_t *) encoder->dv_video + (w * h );
pixels[2] = (uint8_t *) encoder->dv_video + (w * h) + off;
yuv422p_to_yuv422(input_buf,encoder->dv_video,w,h);
}
dv_encode_full_frame( encoder->encoder, pixels, e_dv_color_yuv,
output_buf);
dv_encode_metadata(output_buf, encoder->encoder->isPAL,
encoder->encoder->is16x9, &now, 0);
dv_encode_timecode(output_buf, encoder->encoder->isPAL, 0);
if(encoder->encoder->isPAL) return DV_PAL_SIZE;
return DV_NTSC_SIZE;
}
void vj_dv_free_encoder(vj_dv_encoder *e)
{
if(e)
{
if(e->encoder)
dv_encoder_free( e->encoder);
if(e->dv_video)
free(e->dv_video);
free(e);
}
}
void vj_dv_free_decoder(vj_dv_decoder *d) {
if(d->decoder)
dv_decoder_free( d->decoder );
if(d->dv_video)
free(d->dv_video);
if(d)
free(d);
}
void vj_dv_decoder_set_audio(vj_dv_decoder *d, int audio)
{
}
void vj_dv_decoder_get_audio(vj_dv_decoder *d, uint8_t *audio_buf)
{
if(!d->audio) return;
int n_samples = dv_get_num_samples( d->decoder);
// int channels = dv_get_num_channels( d->decoder );
int i;
int16_t *ch0 = d->audio_buffers[0];
int16_t *ch1 = d->audio_buffers[1];
// convert short to uint8_t,
// interleave audio into single buffer
for(i = 0; i < n_samples; i ++ )
{
*(audio_buf) = ch0[i] & 0xff; //lo
*(audio_buf+1) = (ch0[i] >> 8) & 0xff; //hi
*(audio_buf+2) = ch1[i] & 0xff; //lo
*(audio_buf+3) = (ch1[i] >> 8) & 0xff; //hi
}
}
/*
* Unpack libdv's 4:2:2-packed into our 4:2:0-planar or 4:2:2-planar,
* treating each interlaced field independently
*
*/
static inline void frame_YUV422_to_planar(uint8_t **output, uint8_t *input,
int width, int height, int chroma422)
{
int i, j, w2;
uint8_t *y, *cb, *cr;
w2 = width/2;
y = output[0];
cb = output[1];
cr = output[2];
for (i=0; i<height;) {
/* process two scanlines (one from each field, interleaved) */
/* ...top-field scanline */
for (j=0; j<w2; j++) {
/* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */
*(y++) = *(input++);
*(cb++) = *(input++);
*(y++) = *(input++);
*(cr++) = *(input++);
}
i++;
/* ...bottom-field scanline */
for (j=0; j<w2; j++) {
/* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */
*(y++) = *(input++);
*(cb++) = *(input++);
*(y++) = *(input++);
*(cr++) = *(input++);
}
i++;
if (chroma422)
continue;
/* process next two scanlines (one from each field, interleaved) */
/* ...top-field scanline */
for (j=0; j<w2; j++) {
/* skip every second line for U and V */
*(y++) = *(input++);
input++;
*(y++) = *(input++);
input++;
}
i++;
/* ...bottom-field scanline */
for (j=0; j<w2; j++) {
/* skip every second line for U and V */
*(y++) = *(input++);
input++;
*(y++) = *(input++);
input++;
}
i++;
}
}
int vj_dv_scan_frame( vj_dv_decoder *d, uint8_t * input_buf )
{
if (dv_parse_header(d->decoder, input_buf) < 0)
{
veejay_msg(0, "Unable to read DV header");
return -1;
}
if( d->decoder->system == e_dv_system_none )
{
veejay_msg(0, "No valid PAL or NTSC video frame detected");
return -1;
}
char sampling[8];
switch( d->decoder->sampling )
{
case e_dv_sample_411:
veejay_msg(0, "YUV 4:1:1 not supported.");
return -1;
case e_dv_sample_420:
sprintf(sampling, "4:2:0"); break;
case e_dv_sample_422:
sprintf(sampling, "4:2:2"); break;
case e_dv_sample_none:
veejay_msg(0 ,"No sampling format, cant handle this file (yet)");
return -1;
default:
veejay_msg(0, "Unknown sampling format in DV file");
return -1;
}
veejay_msg( VEEJAY_MSG_DEBUG, "\tDetected DV sampling format %s", sampling );
if ( d->decoder->sampling == e_dv_sample_422)
return FMT_422;
if( d->decoder->sampling == e_dv_sample_420 )
return FMT_420;
return -1;
}
int vj_dv_decode_frame(vj_dv_decoder *d, uint8_t * input_buf, uint8_t * Y,
uint8_t * Cb, uint8_t * Cr, int width, int height, int fmt)
{
int pitches[3];
if (!input_buf)
return 0;
if (dv_parse_header(d->decoder, input_buf) < 0)
{
veejay_msg(0, "Unable to read DV header");
return 0;
}
if( d->decoder->system == e_dv_system_none )
{
veejay_msg(0, "No valid PAL or NTSC video frame detected");
return 0;
}
if( d->decoder->system == e_dv_system_625_50 )
{
d->yuy2 = 0;
}
else
{
d->yuy2 = 1;
}
if (!((d->decoder->num_dif_seqs == 10)
|| (d->decoder->num_dif_seqs == 12)))
{
veejay_msg(0, "Dont know how to handle %d dif seqs",
d->decoder->num_dif_seqs );
return 0;
}
#ifdef STRICT_CHECKING
// if ( d->decoder->sampling == e_dv_sample_420 )
// assert( d->fmt == FMT_420 || d->fmt == FMT_420F );
// if ( d->decoder->sampling == e_dv_sample_422 )
// assert( d->fmt == FMT_422 || d->fmt == FMT_422F );
#endif
if ( d->decoder->sampling == e_dv_sample_422)
{
pitches[0] = width * 2;
pitches[1] = 0;
pitches[2] = 0;
uint8_t *pixels[3] = { Y , Cb, Cr };
dv_decode_full_frame(d->decoder, input_buf,
e_dv_color_yuv, pixels, pitches);
frame_YUV422_to_planar( pixels, pixels[0], width, height, fmt );
return 1;
} else if( d->decoder->sampling == e_dv_sample_420 )
{
uint8_t *pixels[3];
pixels[0] = d->dv_video;
pixels[1] = d->dv_video + (width * height);
pixels[2] = d->dv_video + (width * height * 5)/4;
pitches[0] = width * 2;
pitches[1] = 0;
pitches[2] = 0;
dv_decode_full_frame( d->decoder, input_buf, e_dv_color_yuv, pixels,pitches);
if(fmt==FMT_422 || fmt == FMT_422F)
yuy2toyv16( Y,Cb,Cr, d->dv_video, width ,height );
else //@ FIXME broken!
vj_yuy2toyv12( Y,Cb,Cr, d->dv_video, width, height );
return 1;
}
return 0;
}
#endif

View File

@@ -0,0 +1,61 @@
/*
* Linux VeeJay
*
* Copyright(C)2002-2004 Niels Elburg <nelburg@looze.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License , or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
*/
#ifndef VJ_DV_H
#define VJ_DV_H
#include <config.h>
#ifdef SUPPORT_READ_DV2
#include <libdv/dv.h>
typedef struct
{
dv_decoder_t *decoder;
uint8_t *dv_video;
int fmt;
int yuy2;
int audio;
int16_t **audio_buffers;
} vj_dv_decoder;
typedef struct
{
dv_encoder_t *encoder;
uint8_t *dv_video;
int fmt;
} vj_dv_encoder;
vj_dv_decoder *vj_dv_decoder_init(int quality,int width, int height, int pixel_format);
vj_dv_encoder *vj_dv_init_encoder(void * el, int pixel_format);
void vj_dv_decoder_get_audio(vj_dv_decoder *d, uint8_t *audio_buf);
int vj_dv_scan_frame( vj_dv_decoder *d, uint8_t * input_buf );
void vj_dv_decoder_set_audio(vj_dv_decoder *d, int audio);
int vj_dv_decode_frame(vj_dv_decoder *d,uint8_t * in, uint8_t * Y,
uint8_t * Cb, uint8_t * Cr, int w, int h, int fmt);
int vj_dv_encode_frame(vj_dv_encoder *e,uint8_t * in[3], uint8_t * out);
void vj_dv_free_encoder(vj_dv_encoder *e);
void vj_dv_free_decoder(vj_dv_decoder *d);
int is_dv_resolution( int w, int h );
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
/* veejay - Linux VeeJay
* (C) 2002-2004 Niels Elburg <nelburg@looze.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef VJ_MLT_EL_H
#define VJ_MLT_EL_H
#include <config.h>
#include <libel/lav_io.h>
#include <libvje/vje.h>
#include <veejay/vims.h>
#define N_EL_FRAME(x) ( (x)&0xfffffffffffffLLU )
#define N_EL_FILE(x) (uint32_t) ( ((x)>>52)&0xfffU )
/* ((file)&0xfff<<52) */
#define EL_ENTRY(file,frame) ( ((file)<<52) | ((frame)& 0xfffffffffffffLLU) )
//#define FMT_420 0
//#define FMT_422 1
//#define MAX_EDITLIST_FILES 4096
typedef struct
{
int has_video;
int is_empty;
int video_width;
int video_height;
int video_inter;
float video_fps;
int video_sar_width;
int video_sar_height;
char video_norm;
int has_audio;
long audio_rate;
int audio_chans;
int audio_bits;
int audio_bps;
long video_frames;
long total_frames;
long num_video_files;
long max_frame_size;
int MJPG_chroma;
char *(video_file_list[MAX_EDIT_LIST_FILES]);
lav_file_t *(lav_fd[MAX_EDIT_LIST_FILES]);
int yuv_taste[MAX_EDIT_LIST_FILES];
long num_frames[MAX_EDIT_LIST_FILES];
uint64_t *frame_list;
int last_afile;
long last_apos;
int auto_deinter;
int pixel_format;
void *cache;
int is_clone;
} editlist;
int test_video_frame( lav_file_t *lav,int out_pix_fmt);
editlist *vj_el_init_with_args(char **filenames, int n, int flags, int deinter, int force, char norm, int fmt);
int vj_el_cache_size();
void vj_el_prepare(void); // reset cache
void vj_el_init(int out);
void vj_el_init_chunk(int n);
int vj_el_is_dv(editlist *el);
void vj_el_free(editlist *el);
int vj_el_get_audio_frame_at(editlist *el, uint32_t nframe, uint8_t *dst, int speed );
int vj_el_append_video_file(editlist *el, char *filename);
int vj_el_write_editlist( char *filename, long start, long end, editlist *el );
int vj_el_get_video_frame(editlist *el, long nframe, uint8_t *dst[3]);
void vj_el_break_cache( editlist *el );
void vj_el_setup_cache( editlist *el );
int vj_el_get_audio_frame(editlist *el, uint32_t nframe, uint8_t *dst);
int vj_el_get_file_fourcc(editlist *el, int num, char *buf);
void vj_el_print(editlist *el);
int vj_el_init_420_frame(editlist *el, VJFrame *frame);
int vj_el_init_422_frame(editlist *el, VJFrame *frame);
void vj_el_frame_cache(int n);
void vj_el_show_formats(void);
editlist *vj_el_dummy(int flags, int deinterlace, int chroma, char norm, int width, int height, float fps, int fmt);
int vj_el_get_file_entry( editlist *el,long *start_pos, long *end_pos, long entry );
editlist *vj_el_clone(editlist *el);
editlist *vj_el_soft_clone(editlist *el);
int vj_el_framelist_clone( editlist *src, editlist *dst);
char *vj_el_write_line_ascii( editlist *el, int *bytes_written );
void vj_el_deinit();
void vj_el_clear_cache( editlist *el );
int get_ffmpeg_pixfmt( int pf );
void vj_el_set_image_output_size(editlist *el,int w, int h, float fps, int pf);
int open_video_file(char *filename, editlist * el, int preserve_pathname, int deinter, int force, char override_norm);
void vj_el_set_caching(int status);
int vj_el_bogus_length( editlist *el, long nframe );
int vj_el_set_bogus_length( editlist *el, long nframe, int len );
void vj_el_get_video_fourcc(editlist *el, int num, char *fourcc);
#endif

View File

@@ -0,0 +1,139 @@
/*
* Linux VeeJay
*
* Copyright(C)2002-2004 Niels Elburg <nelburg@looze.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License , or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
*/
#include <libel/vj-mmap.h>
#include <libvjmsg/vj-msg.h>
#include <sys/mman.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <libvjmem/vjmem.h>
#define PADDED(a,m) ( a > 0 ? (a / m->page_size) * m->page_size : 0)
void mmap_free(mmap_region_t *map)
{
if(map)
{
if(map->map_start)
munmap_file(map);
free(map);
}
map = NULL;
}
mmap_region_t * mmap_file(int fd, int offset, int length, int fs)
{
mmap_region_t *map = (mmap_region_t*) malloc(sizeof( mmap_region_t ));
memset( map, 0, sizeof( mmap_region_t ));
map->fd = fd;
map->page_size = getpagesize();
map->map_length = length;
map->map_start = NULL;
map->eof = fs;
map->mem_offset = offset;
remap_file( map, offset );
veejay_msg(VEEJAY_MSG_DEBUG, "Memory map region is %f Mb",
( (float) length / 1048576.0 ) );
return map;
}
int is_mapped( mmap_region_t *map, int offset, int size )
{
// check if memory is in mapped region
off_t real_offset = PADDED( offset, map );
size_t padding = offset % map->page_size;
long rel_o = (map->mem_offset > 0 ? offset - map->mem_offset : offset );
if( (rel_o + size) > map->map_length )
{
return 0;
}
if( real_offset >= map->start_region &&
real_offset + size <= map->end_region )
return 1;
return 0;
}
int remap_file( mmap_region_t *map, int offset )
{
size_t padding = offset % map->page_size;
size_t new_length = map->map_length;
size_t real_length = 0;
off_t real_offset = PADDED( offset, map );
real_length = (padding + new_length);
if( real_length > map->eof )
{
real_length = PADDED(map->eof ,map);
}
if(map->map_start != NULL)
{
munmap_file( map );
}
map->mem_offset = offset;
map->map_start = mmap( 0, real_length, PROT_READ, MAP_SHARED, map->fd, real_offset );
if( map->map_start == MAP_FAILED)
{
veejay_msg(VEEJAY_MSG_ERROR, "mmap error %s", strerror(errno));
return 0;
}
map->data_start = map->map_start + padding;
map->start_region = real_offset;
map->end_region = real_length + real_offset;
return 1;
}
int munmap_file( mmap_region_t *map )
{
if(map->map_start == NULL)
return 1;
int n = munmap( map->map_start, map->map_length );
if(n==-1)
{
veejay_msg(VEEJAY_MSG_ERROR, "leaving garbage %s",
strerror(errno));
}
map->map_start = NULL;
return n;
}
int mmap_read( mmap_region_t *map,int offset, int bytes, uint8_t *buf )
{
size_t padding = offset % map->page_size;
if( !is_mapped( map, offset, bytes ))
{
remap_file( map, offset );
}
int rel_offset = (map->mem_offset > 0 ? offset - map->mem_offset : offset );
uint8_t *d1 = map->data_start + rel_offset;
veejay_memcpy( buf, d1, bytes );
return bytes;
}

View File

@@ -0,0 +1,53 @@
/*
* Linux VeeJay
*
* Copyright(C)2002-2004 Niels Elburg <nelburg@looze.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License , or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
*/
#ifndef VJ_MMAP_H
#define VJ_MMAP_H
#include <sys/types.h>
#include <sys/mman.h>
#include <stdint.h>
typedef struct
{
unsigned char *map_start; /* result of mmap() */
unsigned char *data_start; /* start of data */
uint64_t start_region;
uint64_t end_region;
off_t mem_offset; /* start of image */
int fd; /* file descriptor */
size_t page_size; /* page size */
size_t map_length; /* requested map size */
long eof; /* file size */
} mmap_region_t;
// map file portion to memory, return mapped region
mmap_region_t * mmap_file(int fd, int offset, int length, int fs);
// see if requested boundaries is mapped in memory
int is_mapped( mmap_region_t *map, int offset, int size );
// remap a portion of a file in memory
int remap_file( mmap_region_t *map, int offset );
// unmap memory
int munmap_file( mmap_region_t *map );
void mmap_free(mmap_region_t *map );
int mmap_read( mmap_region_t *map, int offset, int bytes, uint8_t *buf);
#endif

View File

@@ -0,0 +1,9 @@
What a GOOM!
============
Copyright (c)2000-2004, Jean-Christophe Hoelt <jeko@ios-software.com>
Programmer and Software Designer at iOS software.
iTunes port/PowerPC/Core-Hacking: Guillaume Borios <gyom@ios-software.com>
WINAMP/WMP port: Fred

Some files were not shown because too many files have changed in this diff Show More