Another project for the Aegisub repository...

Originally committed to SVN as r1475.
This commit is contained in:
Niels Martin Hansen 2007-08-11 19:59:48 +00:00
parent 98e837da5c
commit 0211960d8e
19 changed files with 29583 additions and 0 deletions

22915
OverLua/CImg.h Normal file

File diff suppressed because it is too large Load diff

339
OverLua/GPLv2.txt Normal file
View file

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

View file

@ -0,0 +1,508 @@
CeCILL-C FREE SOFTWARE LICENSE AGREEMENT
Notice
This Agreement is a Free Software license agreement that is the result
of discussions between its authors in order to ensure compliance with
the two main principles guiding its drafting:
* firstly, compliance with the principles governing the distribution
of Free Software: access to source code, broad rights granted to
users,
* secondly, the election of a governing law, French law, with which
it is conformant, both as regards the law of torts and
intellectual property law, and the protection that it offers to
both authors and holders of the economic rights over software.
The authors of the CeCILL-C (for Ce[a] C[nrs] I[nria] L[logiciel] L[ibre])
license are:
Commissariat à l'Energie Atomique - CEA, a public scientific, technical
and industrial research establishment, having its principal place of
business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France.
Centre National de la Recherche Scientifique - CNRS, a public scientific
and technological establishment, having its principal place of business
at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
Institut National de Recherche en Informatique et en Automatique -
INRIA, a public scientific and technological establishment, having its
principal place of business at Domaine de Voluceau, Rocquencourt, BP
105, 78153 Le Chesnay cedex, France.
Preamble
The purpose of this Free Software license agreement is to grant users the
right to modify and re-use the software governed by this license.
The exercising of this right is conditional on the obligation to make
available to the community the modifications made to the source code of the
software so as to contribute to its evolution.
In consideration of access to the source code and the rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors only have limited liability.
In this respect, the risks associated with loading, using, modifying
and/or developing or reproducing the software by the user are brought to
the user's attention, given its Free Software status, which may make it
complicated to use, with the result that its use is reserved for
developers and experienced professionals having in-depth computer
knowledge. Users are therefore encouraged to load and test the suitability
of the software as regards their requirements in conditions enabling the
security of their systems and/or data to be ensured and, more generally, to
use and operate it in the same conditions of security. This Agreement may be
freely reproduced and published, provided it is not altered, and that no
provisions are either added or removed herefrom.
This Agreement may apply to any or all software for which the holder of
the economic rights decides to submit the use thereof to its provisions.
Article 1 - DEFINITIONS
For the purpose of this Agreement, when the following expressions
commence with a capital letter, they shall have the following meaning:
Agreement: means this license agreement, and its possible subsequent
versions and annexes.
Software: means the software in its Object Code and/or Source Code form
and, where applicable, its documentation, "as is" when the Licensee
accepts the Agreement.
Initial Software: means the Software in its Source Code and possibly its
Object Code form and, where applicable, its documentation, "as is" when
it is first distributed under the terms and conditions of the Agreement.
Modified Software: means the Software modified by at least one Integrated
Contribution.
Source Code: means all the Software's instructions and program lines to
which access is required so as to modify the Software.
Object Code: means the binary files originating from the compilation of
the Source Code.
Holder: means the holder(s) of the economic rights over the Initial
Software.
Licensee: means the Software user(s) having accepted the Agreement.
Contributor: means a Licensee having made at least one Integrated
Contribution.
Licensor: means the Holder, or any other individual or legal entity, who
distributes the Software under the Agreement.
Integrated Contribution: means any or all modifications, corrections,
translations, adaptations and/or new functions integrated into the Source
Code by any or all Contributors.
Related Module: means a set of sources files including their documentation
that, without modification to the Source Code, enables supplementary
functions or services in addition to those offered by the Software.
Derivative Software: means any combination of the Software, modified or not,
and of a Related Module.
Parties: mean both the Licensee and the Licensor.
These expressions may be used both in singular and plural form.
Article 2 - PURPOSE
The purpose of the Agreement is the grant by the Licensor to the
Licensee of a non-exclusive, transferable and worldwide license for the
Software as set forth in Article 5 hereinafter for the whole term of the
protection granted by the rights over said Software.
Article 3 - ACCEPTANCE
3.1 The Licensee shall be deemed as having accepted the terms and
conditions of this Agreement upon the occurrence of the first of the
following events:
* (i) loading the Software by any or all means, notably, by
downloading from a remote server, or by loading from a physical
medium;
* (ii) the first time the Licensee exercises any of the rights
granted hereunder.
3.2 One copy of the Agreement, containing a notice relating to the
characteristics of the Software, to the limited warranty, and to the
fact that its use is restricted to experienced users has been provided
to the Licensee prior to its acceptance as set forth in Article 3.1
hereinabove, and the Licensee hereby acknowledges that it has read and
understood it.
Article 4 - EFFECTIVE DATE AND TERM
4.1 EFFECTIVE DATE
The Agreement shall become effective on the date when it is accepted by
the Licensee as set forth in Article 3.1.
4.2 TERM
The Agreement shall remain in force for the entire legal term of
protection of the economic rights over the Software.
Article 5 - SCOPE OF RIGHTS GRANTED
The Licensor hereby grants to the Licensee, who accepts, the following
rights over the Software for any or all use, and for the term of the
Agreement, on the basis of the terms and conditions set forth hereinafter.
Besides, if the Licensor owns or comes to own one or more patents
protecting all or part of the functions of the Software or of its
components, the Licensor undertakes not to enforce the rights granted by
these patents against successive Licensees using, exploiting or
modifying the Software. If these patents are transferred, the Licensor
undertakes to have the transferees subscribe to the obligations set
forth in this paragraph.
5.1 RIGHT OF USE
The Licensee is authorized to use the Software, without any limitation
as to its fields of application, with it being hereinafter specified
that this comprises:
1. permanent or temporary reproduction of all or part of the Software
by any or all means and in any or all form.
2. loading, displaying, running, or storing the Software on any or
all medium.
3. entitlement to observe, study or test its operation so as to
determine the ideas and principles behind any or all constituent
elements of said Software. This shall apply when the Licensee
carries out any or all loading, displaying, running, transmission
or storage operation as regards the Software, that it is entitled
to carry out hereunder.
5.2 RIGHT OF MODIFICATION
The right of modification includes the right to translate, adapt, arrange,
or make any or all modifications to the Software, and the right to
reproduce the resulting Software. It includes, in particular, the right
to create a Derivative Software.
The Licensee is authorized to make any or all modification to the
Software provided that it includes an explicit notice that it is the
author of said modification and indicates the date of the creation thereof.
5.3 RIGHT OF DISTRIBUTION
In particular, the right of distribution includes the right to publish,
transmit and communicate the Software to the general public on any or
all medium, and by any or all means, and the right to market, either in
consideration of a fee, or free of charge, one or more copies of the
Software by any means.
The Licensee is further authorized to distribute copies of the modified
or unmodified Software to third parties according to the terms and
conditions set forth hereinafter.
5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
The Licensee is authorized to distribute true copies of the Software in
Source Code or Object Code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's
warranty and liability as set forth in Articles 8 and 9,
and that, in the event that only the Object Code of the Software is
redistributed, the Licensee allows effective access to the full Source Code
of the Software at a minimum during the entire period of its distribution
of the Software, it being understood that the additional cost of acquiring
the Source Code shall not exceed the cost of transferring the data.
5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
When the Licensee makes an Integrated Contribution to the Software, the terms
and conditions for the distribution of the resulting Modified Software become
subject to all the provisions of this Agreement.
The Licensee is authorized to distribute the Modified Software, in source
code or object code form, provided that said distribution complies with all
the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's warranty and
liability as set forth in Articles 8 and 9,
and that, in the event that only the object code of the Modified Software is
redistributed, the Licensee allows effective access to the full source code
of the Modified Software at a minimum during the entire period of its
distribution of the Modified Software, it being understood that the
additional cost of acquiring the source code shall not exceed the cost of
transferring the data.
5.3.3 DISTRIBUTION OF DERIVATIVE SOFTWARE
When the Licensee creates Derivative Software, this Derivative Software may
be distributed under a license agreement other than this Agreement, subject
to compliance with the requirement to include a notice concerning the rights
over the Software as defined in Article 6.4. In the event the creation of the
Derivative Software required modification of the Source Code, the Licensee
undertakes that:
1. the resulting Modified Software will be governed by this Agreement,
2. the Integrated Contributions in the resulting Modified Software will be
clearly identified and documented,
3. the Licensee will allow effective access to the source code of the
Modified Software, at a minimum during the entire period of
distribution of the Derivative Software, such that such modifications
may be carried over in a subsequent version of the Software; it being
understood that the additional cost of purchasing the source code of
the Modified Software shall not exceed the cost of transferring the
data.
5.3.4 COMPATIBILITY WITH THE CeCILL LICENSE
When a Modified Software contains an Integrated Contribution subject to the
CeCill license agreement, or when a Derivative Software contains a Related
Module subject to the CeCill license agreement, the provisions set forth in
the third item of Article 6.4 are optional.
Article 6 - INTELLECTUAL PROPERTY
6.1 OVER THE INITIAL SOFTWARE
The Holder owns the economic rights over the Initial Software. Any or
all use of the Initial Software is subject to compliance with the terms
and conditions under which the Holder has elected to distribute its work
and no one shall be entitled to modify the terms and conditions for the
distribution of said Initial Software.
The Holder undertakes that the Initial Software will remain ruled at
least by the current license, for the duration set forth in Article 4.2.
6.2 OVER THE INTEGRATED CONTRIBUTIONS
A Licensee who develops an Integrated Contribution is the owner of the
intellectual property rights over this Contribution as defined by
applicable law.
6.3 OVER THE RELATED MODULES
A Licensee who develops an Related Module is the owner of the
intellectual property rights over this Related Module as defined by
applicable law and is free to choose the type of agreement that shall
govern its distribution under the conditions defined in Article 5.3.3.
6.4 NOTICE OF RIGHTS
The Licensee expressly undertakes:
1. not to remove, or modify, in any manner, the intellectual property
notices attached to the Software;
2. to reproduce said notices, in an identical manner, in the copies
of the Software modified or not;
3. to ensure that use of the Software, its intellectual property
notices and the fact that it is governed by the Agreement is
indicated in a text that is easily accessible, specifically from
the interface of any Derivative Software.
The Licensee undertakes not to directly or indirectly infringe the
intellectual property rights of the Holder and/or Contributors on the
Software and to take, where applicable, vis-à-vis its staff, any and all
measures required to ensure respect of said intellectual property rights
of the Holder and/or Contributors.
Article 7 - RELATED SERVICES
7.1 Under no circumstances shall the Agreement oblige the Licensor to
provide technical assistance or maintenance services for the Software.
However, the Licensor is entitled to offer this type of services. The
terms and conditions of such technical assistance, and/or such
maintenance, shall be set forth in a separate instrument. Only the
Licensor offering said maintenance and/or technical assistance services
shall incur liability therefor.
7.2 Similarly, any Licensor is entitled to offer to its licensees, under
its sole responsibility, a warranty, that shall only be binding upon
itself, for the redistribution of the Software and/or the Modified
Software, under terms and conditions that it is free to decide. Said
warranty, and the financial terms and conditions of its application,
shall be subject of a separate instrument executed between the Licensor
and the Licensee.
Article 8 - LIABILITY
8.1 Subject to the provisions of Article 8.2, the Licensee shall be
entitled to claim compensation for any direct loss it may have suffered
from the Software as a result of a fault on the part of the relevant
Licensor, subject to providing evidence thereof.
8.2 The Licensor's liability is limited to the commitments made under
this Agreement and shall not be incurred as a result of in particular:
(i) loss due the Licensee's total or partial failure to fulfill its
obligations, (ii) direct or consequential loss that is suffered by the
Licensee due to the use or performance of the Software, and (iii) more
generally, any consequential loss. In particular the Parties expressly
agree that any or all pecuniary or business loss (i.e. loss of data,
loss of profits, operating loss, loss of customers or orders,
opportunity cost, any disturbance to business activities) or any or all
legal proceedings instituted against the Licensee by a third party,
shall constitute consequential loss and shall not provide entitlement to
any or all compensation from the Licensor.
Article 9 - WARRANTY
9.1 The Licensee acknowledges that the scientific and technical
state-of-the-art when the Software was distributed did not enable all
possible uses to be tested and verified, nor for the presence of
possible defects to be detected. In this respect, the Licensee's
attention has been drawn to the risks associated with loading, using,
modifying and/or developing and reproducing the Software which are
reserved for experienced users.
The Licensee shall be responsible for verifying, by any or all means,
the suitability of the product for its requirements, its good working order,
and for ensuring that it shall not cause damage to either persons or
properties.
9.2 The Licensor hereby represents, in good faith, that it is entitled
to grant all the rights over the Software (including in particular the
rights set forth in Article 5).
9.3 The Licensee acknowledges that the Software is supplied "as is" by
the Licensor without any other express or tacit warranty, other than
that provided for in Article 9.2 and, in particular, without any warranty
as to its commercial value, its secured, safe, innovative or relevant
nature.
Specifically, the Licensor does not warrant that the Software is free
from any error, that it will operate without interruption, that it will
be compatible with the Licensee's own equipment and software
configuration, nor that it will meet the Licensee's requirements.
9.4 The Licensor does not either expressly or tacitly warrant that the
Software does not infringe any third party intellectual property right
relating to a patent, software or any other property right. Therefore,
the Licensor disclaims any and all liability towards the Licensee
arising out of any or all proceedings for infringement that may be
instituted in respect of the use, modification and redistribution of the
Software. Nevertheless, should such proceedings be instituted against
the Licensee, the Licensor shall provide it with technical and legal
assistance for its defense. Such technical and legal assistance shall be
decided on a case-by-case basis between the relevant Licensor and the
Licensee pursuant to a memorandum of understanding. The Licensor
disclaims any and all liability as regards the Licensee's use of the
name of the Software. No warranty is given as regards the existence of
prior rights over the name of the Software or as regards the existence
of a trademark.
Article 10 - TERMINATION
10.1 In the event of a breach by the Licensee of its obligations
hereunder, the Licensor may automatically terminate this Agreement
thirty (30) days after notice has been sent to the Licensee and has
remained ineffective.
10.2 A Licensee whose Agreement is terminated shall no longer be
authorized to use, modify or distribute the Software. However, any
licenses that it may have granted prior to termination of the Agreement
shall remain valid subject to their having been granted in compliance
with the terms and conditions hereof.
Article 11 - MISCELLANEOUS
11.1 EXCUSABLE EVENTS
Neither Party shall be liable for any or all delay, or failure to
perform the Agreement, that may be attributable to an event of force
majeure, an act of God or an outside cause, such as defective
functioning or interruptions of the electricity or telecommunications
networks, network paralysis following a virus attack, intervention by
government authorities, natural disasters, water damage, earthquakes,
fire, explosions, strikes and labor unrest, war, etc.
11.2 Any failure by either Party, on one or more occasions, to invoke
one or more of the provisions hereof, shall under no circumstances be
interpreted as being a waiver by the interested Party of its right to
invoke said provision(s) subsequently.
11.3 The Agreement cancels and replaces any or all previous agreements,
whether written or oral, between the Parties and having the same
purpose, and constitutes the entirety of the agreement between said
Parties concerning said purpose. No supplement or modification to the
terms and conditions hereof shall be effective as between the Parties
unless it is made in writing and signed by their duly authorized
representatives.
11.4 In the event that one or more of the provisions hereof were to
conflict with a current or future applicable act or legislative text,
said act or legislative text shall prevail, and the Parties shall make
the necessary amendments so as to comply with said act or legislative
text. All other provisions shall remain effective. Similarly, invalidity
of a provision of the Agreement, for any reason whatsoever, shall not
cause the Agreement as a whole to be invalid.
11.5 LANGUAGE
The Agreement is drafted in both French and English and both versions
are deemed authentic.
Article 12 - NEW VERSIONS OF THE AGREEMENT
12.1 Any person is authorized to duplicate and distribute copies of this
Agreement.
12.2 So as to ensure coherence, the wording of this Agreement is
protected and may only be modified by the authors of the License, who
reserve the right to periodically publish updates or new versions of the
Agreement, each with a separate number. These subsequent versions may
address new issues encountered by Free Software.
12.3 Any Software distributed under a given version of the Agreement
may only be subsequently distributed under the same version of the
Agreement or a subsequent version.
Article 13 - GOVERNING LAW AND JURISDICTION
13.1 The Agreement is governed by French law. The Parties agree to
endeavor to seek an amicable solution to any disagreements or disputes
that may arise during the performance of the Agreement.
13.2 Failing an amicable solution within two (2) months as from their
occurrence, and unless emergency proceedings are necessary, the
disagreements or disputes shall be referred to the Paris Courts having
jurisdiction, by the more diligent Party.
Version 1.0 dated 2006-07-12.

125
OverLua/avisynth.cpp Normal file
View file

@ -0,0 +1,125 @@
/*
* Avisynth interface for OverLua
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
#include <windows.h>
#include <string.h>
#include <memory.h>
#include "avisynth.h"
#include "overlua.h"
// Lots of code lifted from the CSRI avisynth.cpp
class OverLuaAvisynth : public GenericVideoFilter {
private:
OverLuaScript *script;
double spf; // seconds per frame - for frame/timestamp conversion
public:
OverLuaAvisynth(PClip _child, IScriptEnvironment *env, const char *file)
: GenericVideoFilter(_child)
{
switch (vi.pixel_type) {
case VideoInfo::CS_BGR24:
case VideoInfo::CS_BGR32:
// safe
break;
default:
env->ThrowError("OverLua: Unsupported pixel format, only RGB formats supported");
}
try {
script = new OverLuaScript(file);
spf = (double)vi.fps_denominator / (double)vi.fps_numerator;
}
catch (const char *e) {
env->ThrowError(e);
}
catch (...) {
env->ThrowError("Unknown exception in OverLua");
}
}
~OverLuaAvisynth()
{
delete script;
}
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *env)
{
OutputDebugStringW(L"Entering OverLua GetFrame\n");
PVideoFrame avsframe = child->GetFrame(n, env);
env->MakeWritable(&avsframe);
double frametime = n * spf;
ptrdiff_t stride = avsframe->GetPitch();
unsigned char *plane = avsframe->GetWritePtr();
plane += (vi.height - 1) * stride;
stride = -stride;
try {
switch (vi.pixel_type) {
case VideoInfo::CS_BGR24: {
OverLuaVideoFrameBGR *frame = new OverLuaVideoFrameBGR(vi.width, vi.height, stride, plane);
script->RenderFrameRGB(*frame, frametime);
} break;
case VideoInfo::CS_BGR32: {
OverLuaVideoFrameBGRX *frame = new OverLuaVideoFrameBGRX(vi.width, vi.height, stride, plane);
script->RenderFrameRGB(*frame, frametime);
} break;
}
}
catch (const char *e) {
wchar_t *ew = new wchar_t[2048];
MultiByteToWideChar(CP_UTF8, 0, e, -1, ew, 2048);
MessageBoxW(0, ew, L"OverLua execution error", MB_ICONERROR);
delete[] ew;
env->ThrowError(e);
}
catch (...) {
MessageBoxW(0, L"Unknown error", L"OverLua execution error", MB_ICONERROR);
env->ThrowError("OverLua: unknown execution error");
}
OutputDebugStringW(L"Leaving OverLua GetFrame\n");
return avsframe;
}
static AVSValue __cdecl Create(AVSValue args, void* user_data, IScriptEnvironment* env)
{
return new OverLuaAvisynth(args[0].AsClip(), env, args[1].AsString());
}
};
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
{
env->AddFunction("OverLua", "cs", OverLuaAvisynth::Create, 0);
return "OverLua";
}

754
OverLua/avisynth.h Normal file
View file

@ -0,0 +1,754 @@
// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
// http://www.avisynth.org
// 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, or visit
// http://www.gnu.org/copyleft/gpl.html .
//
// Linking Avisynth statically or dynamically with other modules is making a
// combined work based on Avisynth. Thus, the terms and conditions of the GNU
// General Public License cover the whole combination.
//
// As a special exception, the copyright holders of Avisynth give you
// permission to link Avisynth with independent modules that communicate with
// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
// terms of these independent modules, and to copy and distribute the
// resulting combined work under terms of your choice, provided that
// every copy of the combined work is accompanied by a complete copy of
// the source code of Avisynth (the version of Avisynth used to produce the
// combined work), being distributed under the terms of the GNU General
// Public License plus this exception. An independent module is a module
// which is not derived from or based on Avisynth, such as 3rd-party filters,
// import and export plugins, or graphical user interfaces.
#ifndef __AVISYNTH_H__
#define __AVISYNTH_H__
enum { AVISYNTH_INTERFACE_VERSION = 3 };
/* Define all types necessary for interfacing with avisynth.dll
Moved from internal.h */
// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc.
#include <windef.h>
// COM interface macros
#include <objbase.h>
// Raster types used by VirtualDub & Avisynth
#define in64 (__int64)(unsigned short)
typedef unsigned long Pixel; // this will break on 64-bit machines!
typedef unsigned long Pixel32;
typedef unsigned char Pixel8;
typedef long PixCoord;
typedef long PixDim;
typedef long PixOffset;
/* Compiler-specific crap */
// Tell MSVC to stop precompiling here
#ifdef _MSC_VER
#pragma hdrstop
#endif
// Set up debugging macros for MS compilers; for others, step down to the
// standard <assert.h> interface
#ifdef _MSC_VER
#include <crtdbg.h>
#else
#define _RPT0(a,b) ((void)0)
#define _RPT1(a,b,c) ((void)0)
#define _RPT2(a,b,c,d) ((void)0)
#define _RPT3(a,b,c,d,e) ((void)0)
#define _RPT4(a,b,c,d,e,f) ((void)0)
#define _ASSERTE(x) assert(x)
#define _ASSERT(x) assert(x)
#include <assert.h>
#endif
// I had problems with Premiere wanting 1-byte alignment for its structures,
// so I now set the Avisynth struct alignment explicitly here.
#pragma pack(push,8)
#define FRAME_ALIGN 16
// Default frame alignment is 16 bytes, to help P4, when using SSE2
// The VideoInfo struct holds global information about a clip (i.e.
// information that does not depend on the frame number). The GetVideoInfo
// method in IClip returns this struct.
// Audio Sample information
typedef float SFLOAT;
enum {SAMPLE_INT8 = 1<<0,
SAMPLE_INT16 = 1<<1,
SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware.
SAMPLE_INT32 = 1<<3,
SAMPLE_FLOAT = 1<<4};
enum {
PLANAR_Y=1<<0,
PLANAR_U=1<<1,
PLANAR_V=1<<2,
PLANAR_ALIGNED=1<<3,
PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED,
PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED,
PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED,
};
struct VideoInfo {
int width, height; // width=0 means no video
unsigned fps_numerator, fps_denominator;
int num_frames;
// This is more extensible than previous versions. More properties can be added seeminglesly.
// Colorspace properties.
enum {
CS_BGR = 1<<28,
CS_YUV = 1<<29,
CS_INTERLEAVED = 1<<30,
CS_PLANAR = 1<<31
};
// Specific colorformats
enum { CS_UNKNOWN = 0,
CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED,
CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED,
CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED,
CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, planar
CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, planar
CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above
};
int pixel_type; // changed to int as of 2.5
int audio_samples_per_second; // 0 means no audio
int sample_type; // as of 2.5
__int64 num_audio_samples; // changed as of 2.5
int nchannels; // as of 2.5
// Imagetype properties
int image_type;
enum {
IT_BFF = 1<<0,
IT_TFF = 1<<1,
IT_FIELDBASED = 1<<2
};
// useful functions of the above
bool HasVideo() const { return (width!=0); }
bool HasAudio() const { return (audio_samples_per_second!=0); }
bool IsRGB() const { return !!(pixel_type&CS_BGR); }
bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties
bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; }
bool IsYUV() const { return !!(pixel_type&CS_YUV ); }
bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; }
bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); }
bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); }
bool Is(int property) const { return ((pixel_type & property)==property ); }
bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); }
bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); }
bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); }
bool IsBFF() const { return !!(image_type & IT_BFF); }
bool IsTFF() const { return !!(image_type & IT_TFF); }
bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this
int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes
int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images
int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); }
__int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; }
int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; }
__int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; }
__int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); }
int AudioChannels() const { return nchannels; }
int SampleType() const{ return sample_type;}
bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);}
int SamplesPerSecond() const { return audio_samples_per_second; }
int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();}
void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; }
void Set(int property) { image_type|=property; }
void Clear(int property) { image_type&=~property; }
int BitsPerPixel() const {
switch (pixel_type) {
case CS_BGR24:
return 24;
case CS_BGR32:
return 32;
case CS_YUY2:
return 16;
case CS_YV12:
case CS_I420:
return 12;
default:
return 0;
}
}
int BytesPerChannelSample() const {
switch (sample_type) {
case SAMPLE_INT8:
return sizeof(signed char);
case SAMPLE_INT16:
return sizeof(signed short);
case SAMPLE_INT24:
return 3;
case SAMPLE_INT32:
return sizeof(signed int);
case SAMPLE_FLOAT:
return sizeof(SFLOAT);
default:
_ASSERTE("Sample type not recognized!");
return 0;
}
}
// useful mutator
void SetFPS(unsigned numerator, unsigned denominator) {
if ((numerator == 0) || (denominator == 0)) {
fps_numerator = 0;
fps_denominator = 1;
}
else {
unsigned x=numerator, y=denominator;
while (y) { // find gcd
unsigned t = x%y; x = y; y = t;
}
fps_numerator = numerator/x;
fps_denominator = denominator/x;
}
}
// Range protected multiply-divide of FPS
void MulDivFPS(unsigned multiplier, unsigned divisor) {
unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier);
unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor);
unsigned __int64 x=numerator, y=denominator;
while (y) { // find gcd
unsigned __int64 t = x%y; x = y; y = t;
}
numerator /= x; // normalize
denominator /= x;
unsigned __int64 temp = numerator | denominator; // Just looking top bit
unsigned u = 0;
#ifdef __GNUC__
while (temp & 0xffffffff80000000LL) { // or perhaps > 16777216*2
#else
while (temp & 0xffffffff80000000) { // or perhaps > 16777216*2
#endif
temp = Int64ShrlMod32(temp, 1);
u++;
}
if (u) { // Scale to fit
const unsigned round = 1 << (u-1);
SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u),
(unsigned)Int64ShrlMod32(denominator + round, u) );
}
else {
fps_numerator = (unsigned)numerator;
fps_denominator = (unsigned)denominator;
}
}
// Test for same colorspace
bool IsSameColorspace(const VideoInfo& vi) const {
if (vi.pixel_type == pixel_type) return TRUE;
if (IsYV12() && vi.IsYV12()) return TRUE;
return FALSE;
}
};
// VideoFrameBuffer holds information about a memory block which is used
// for video data. For efficiency, instances of this class are not deleted
// when the refcount reaches zero; instead they're stored in a linked list
// to be reused. The instances are deleted when the corresponding AVS
// file is closed.
class VideoFrameBuffer {
BYTE* const data;
const int data_size;
// sequence_number is incremented every time the buffer is changed, so
// that stale views can tell they're no longer valid.
long sequence_number;
friend class VideoFrame;
friend class Cache;
friend class ScriptEnvironment;
long refcount;
public:
VideoFrameBuffer(int size);
VideoFrameBuffer();
~VideoFrameBuffer();
const BYTE* GetReadPtr() const { return data; }
BYTE* GetWritePtr() { ++sequence_number; return data; }
int GetDataSize() { return data_size; }
int GetSequenceNumber() { return sequence_number; }
int GetRefcount() { return refcount; }
};
class IClip;
class PClip;
class PVideoFrame;
class IScriptEnvironment;
class AVSValue;
// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new
// is overloaded to recycle class instances.
class VideoFrame {
int refcount;
VideoFrameBuffer* const vfb;
const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture.
friend class PVideoFrame;
void AddRef() { InterlockedIncrement((long *)&refcount); }
void Release() { if (refcount==1) InterlockedDecrement(&vfb->refcount); InterlockedDecrement((long *)&refcount); }
friend class ScriptEnvironment;
friend class Cache;
VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height);
VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV);
void* operator new(size_t size);
// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard!
public:
int GetPitch() const { return pitch; }
int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; }
int GetRowSize() const { return row_size; }
int GetRowSize(int plane) const {
switch (plane) {
case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0;
case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED:
if (pitchUV) {
int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize
if (r<=pitchUV)
return r;
return row_size>>1;
} else return 0;
case PLANAR_Y_ALIGNED:
int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize
if (r<=pitch)
return r;
return row_size;
}
return row_size; }
int GetHeight() const { return height; }
int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; }
// generally you shouldn't use these three
VideoFrameBuffer* GetFrameBuffer() const { return vfb; }
int GetOffset() const { return offset; }
int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; }
// in plugins use env->SubFrame()
VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const;
VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const;
const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; }
const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); }
bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); }
BYTE* GetWritePtr() const {
if (vfb->GetRefcount()>1) {
_ASSERT(FALSE);
//throw AvisynthError("Internal Error - refcount was more than one!");
}
return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
}
BYTE* GetWritePtr(int plane) const {
if (plane==PLANAR_Y) {
if (vfb->GetRefcount()>1) {
_ASSERT(FALSE);
// throw AvisynthError("Internal Error - refcount was more than one!");
}
return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0;
}
return vfb->data + GetOffset(plane);
}
~VideoFrame() { InterlockedDecrement(&vfb->refcount); }
};
enum {
CACHE_NOTHING=0,
CACHE_RANGE=1,
CACHE_ALL=2,
CACHE_AUDIO=3,
CACHE_AUDIO_NONE=4
};
// Base class for all filters.
class IClip {
friend class PClip;
friend class AVSValue;
int refcnt;
void AddRef() { InterlockedIncrement((long *)&refcnt); }
void Release() { InterlockedDecrement((long *)&refcnt); if (!refcnt) delete this; }
public:
IClip() : refcnt(0) {}
virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; }
virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0;
virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame
virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples
virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter.
virtual const VideoInfo& __stdcall GetVideoInfo() = 0;
virtual __stdcall ~IClip() {}
};
// smart pointer to IClip
class PClip {
IClip* p;
IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; }
friend class AVSValue;
friend class VideoFrame;
void Init(IClip* x) {
if (x) x->AddRef();
p=x;
}
void Set(IClip* x) {
if (x) x->AddRef();
if (p) p->Release();
p=x;
}
public:
PClip() { p = 0; }
PClip(const PClip& x) { Init(x.p); }
PClip(IClip* x) { Init(x); }
void operator=(IClip* x) { Set(x); }
void operator=(const PClip& x) { Set(x.p); }
IClip* operator->() const { return p; }
// useful in conditional expressions
operator void*() const { return p; }
bool operator!() const { return !p; }
~PClip() { if (p) p->Release(); }
};
// smart pointer to VideoFrame
class PVideoFrame {
VideoFrame* p;
void Init(VideoFrame* x) {
if (x) x->AddRef();
p=x;
}
void Set(VideoFrame* x) {
if (x) x->AddRef();
if (p) p->Release();
p=x;
}
public:
PVideoFrame() { p = 0; }
PVideoFrame(const PVideoFrame& x) { Init(x.p); }
PVideoFrame(VideoFrame* x) { Init(x); }
void operator=(VideoFrame* x) { Set(x); }
void operator=(const PVideoFrame& x) { Set(x.p); }
VideoFrame* operator->() const { return p; }
// for conditional expressions
operator void*() const { return p; }
bool operator!() const { return !p; }
~PVideoFrame() { if (p) p->Release();}
};
class AVSValue {
public:
AVSValue() { type = 'v'; }
AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); }
AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); }
AVSValue(bool b) { type = 'b'; boolean = b; }
AVSValue(int i) { type = 'i'; integer = i; }
// AVSValue(__int64 l) { type = 'l'; longlong = l; }
AVSValue(float f) { type = 'f'; floating_pt = f; }
AVSValue(double f) { type = 'f'; floating_pt = float(f); }
AVSValue(const char* s) { type = 's'; string = s; }
AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; }
AVSValue(const AVSValue& v) { Assign(&v, true); }
~AVSValue() { if (IsClip() && clip) clip->Release(); }
AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; }
// Note that we transparently allow 'int' to be treated as 'float'.
// There are no int<->bool conversions, though.
bool Defined() const { return type != 'v'; }
bool IsClip() const { return type == 'c'; }
bool IsBool() const { return type == 'b'; }
bool IsInt() const { return type == 'i'; }
// bool IsLong() const { return (type == 'l'|| type == 'i'); }
bool IsFloat() const { return type == 'f' || type == 'i'; }
bool IsString() const { return type == 's'; }
bool IsArray() const { return type == 'a'; }
PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; }
bool AsBool() const { _ASSERTE(IsBool()); return boolean; }
int AsInt() const { _ASSERTE(IsInt()); return integer; }
// int AsLong() const { _ASSERTE(IsLong()); return longlong; }
const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; }
double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; }
bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; }
int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; }
double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; }
const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; }
int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; }
const AVSValue& operator[](int index) const {
_ASSERTE(IsArray() && index>=0 && index<array_size);
return (IsArray() && index>=0 && index<array_size) ? array[index] : *this;
}
private:
short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong
short array_size;
union {
IClip* clip;
bool boolean;
int integer;
float floating_pt;
const char* string;
const AVSValue* array;
// __int64 longlong;
};
void Assign(const AVSValue* src, bool init) {
if (src->IsClip() && src->clip)
src->clip->AddRef();
if (!init && IsClip() && clip)
clip->Release();
// make sure this copies the whole struct!
((__int32*)this)[0] = ((__int32*)src)[0];
((__int32*)this)[1] = ((__int32*)src)[1];
}
};
// instantiable null filter
class GenericVideoFilter : public IClip {
protected:
PClip child;
VideoInfo vi;
public:
GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); }
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); }
void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); }
const VideoInfo& __stdcall GetVideoInfo() { return vi; }
bool __stdcall GetParity(int n) { return child->GetParity(n); }
void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter.
};
class AvisynthError /* exception */ {
public:
const char* const msg;
AvisynthError(const char* _msg) : msg(_msg) {}
};
/* Helper classes useful to plugin authors */
class AlignPlanar : public GenericVideoFilter
{
public:
AlignPlanar(PClip _clip);
static PClip Create(PClip clip);
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
class FillBorder : public GenericVideoFilter
{
public:
FillBorder(PClip _clip);
static PClip Create(PClip clip);
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
class ConvertAudio : public GenericVideoFilter
/**
* Helper class to convert audio to any format
**/
{
public:
ConvertAudio(PClip _clip, int prefered_format);
void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env);
void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache!
static PClip Create(PClip clip, int sample_type, int prefered_type);
static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_8bit(AVSValue args, void*, IScriptEnvironment*);
virtual ~ConvertAudio();
private:
void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count);
void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count);
void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count);
void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count);
void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count);
void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count);
void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count);
void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count);
__inline int Saturate_int8(float n);
__inline short Saturate_int16(float n);
__inline int Saturate_int24(float n);
__inline int Saturate_int32(float n);
char src_format;
char dst_format;
int src_bps;
char *tempbuffer;
SFLOAT *floatbuffer;
int tempbuffer_size;
};
// For GetCPUFlags. These are backwards-compatible with those in VirtualDub.
enum {
/* slowest CPU to support extension */
CPUF_FORCE = 0x01, // N/A
CPUF_FPU = 0x02, // 386/486DX
CPUF_MMX = 0x04, // P55C, K6, PII
CPUF_INTEGER_SSE = 0x08, // PIII, Athlon
CPUF_SSE = 0x10, // PIII, Athlon XP/MP
CPUF_SSE2 = 0x20, // PIV, Hammer
CPUF_3DNOW = 0x40, // K6-2
CPUF_3DNOW_EXT = 0x80, // Athlon
CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which only Hammer
// will have anyway)
CPUF_SSE3 = 0x100, // Some P4 & Athlon 64.
};
#define MAX_INT 0x7fffffff
#define MIN_INT -0x7fffffff
class IScriptEnvironment {
public:
virtual __stdcall ~IScriptEnvironment() {}
virtual /*static*/ long __stdcall GetCPUFlags() = 0;
virtual char* __stdcall SaveString(const char* s, int length = -1) = 0;
virtual char* __stdcall Sprintf(const char* fmt, ...) = 0;
// note: val is really a va_list; I hope everyone typedefs va_list to a pointer
virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0;
__declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0;
class NotFound /*exception*/ {}; // thrown by Invoke and GetVar
typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env);
virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0;
virtual bool __stdcall FunctionExists(const char* name) = 0;
virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0;
virtual AVSValue __stdcall GetVar(const char* name) = 0;
virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0;
virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0;
virtual void __stdcall PushContext(int level=0) = 0;
virtual void __stdcall PopContext() = 0;
// align should be 4 or 8
virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0;
virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0;
virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0;
typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env);
virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0;
virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0;
virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0;
virtual int __stdcall SetMemoryMax(int mem) = 0;
virtual int __stdcall SetWorkingDir(const char * newdir) = 0;
virtual void* __stdcall ManageCache(int key, void* data) = 0;
enum PlanarChromaAlignmentMode {
PlanarChromaAlignmentOff,
PlanarChromaAlignmentOn,
PlanarChromaAlignmentTest };
virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0;
virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0;
};
// avisynth.dll exports this; it's a way to use it as a library, without
// writing an AVS script or without going through AVIFile.
IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION);
#pragma pack(pop)
#endif //__AVISYNTH_H__

2446
OverLua/cairo_wrap.cpp Normal file

File diff suppressed because it is too large Load diff

627
OverLua/cairo_wrap.h Normal file
View file

@ -0,0 +1,627 @@
/*
* Lua interface for the Cairo graphics library
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
#ifndef CAIRO_WRAP_H
#define CAIRO_WRAP_H
#include "../lua51/src/lua.h"
#include <cairo.h>
#include <string>
#include <map>
int luaopen_cairo(lua_State *L);
template <class ChildClass>
class LuaCairoBase {
private:
// Default handlers for metatable stuff
static int lua_index(lua_State *L)
{
LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1);
return (*obj)->internal_lua_index(L);
}
static int lua_newindex(lua_State *L)
{
LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1);
return (*obj)->internal_lua_newindex(L);
}
static int lua_callobj(lua_State *L)
{
LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1);
return (*obj)->internal_lua_callobj(L);
}
static int lua_gc(lua_State *L)
{
LuaCairoBase **obj = (LuaCairoBase**)lua_touserdata(L, 1);
delete *obj;
return 0;
}
// Hidden constructors
LuaCairoBase() { }
LuaCairoBase(const LuaCairoBase &obj) { }
// List of callables
typedef std::map<std::string, lua_CFunction> CallableMap;
CallableMap callables;
// "Magic" value - used to test that pointers are really valid
lua_CFunction magic;
protected:
virtual int internal_lua_index(lua_State *L)
{
if (lua_type(L, 2) == LUA_TSTRING) {
const char *field = lua_tostring(L, 2);
CallableMap::iterator func = callables.find(field);
if (func != callables.end()) {
lua_pushvalue(L, 1);
lua_pushcclosure(L, func->second, 1);
return 1;
}
if (strcmp("_type", lua_tostring(L, 2))) {
lua_pushstring(L, GetTypeName());
return 1;
}
}
return 0;
}
virtual int internal_lua_newindex(lua_State *L)
{
lua_pushfstring(L, "Cairo object of type '%s' can not have field set", GetTypeName());
lua_error(L);
return 0;
}
virtual int internal_lua_callobj(lua_State *L)
{
lua_pushfstring(L, "Cairo objct of type '%s' can not be called", GetTypeName());
lua_error(L);
return 0;
}
virtual const char *GetTypeName() { return "_base"; }
virtual void CreateMetaTable(lua_State *L)
{
lua_newtable(L);
lua_pushcclosure(L, lua_index, 0);
lua_setfield(L, -2, "__index");
lua_pushcclosure(L, lua_newindex, 0);
lua_setfield(L, -2, "__newindex");
lua_pushcclosure(L, lua_callobj, 0);
lua_setfield(L, -2, "__call");
lua_pushcclosure(L, lua_gc, 0);
lua_setfield(L, -2, "__gc");
}
void AddCallable(lua_CFunction func, const char *name)
{
callables[name] = func;
}
// Primary constructor for use with inherited stuff
LuaCairoBase(lua_State *L)
{
LuaCairoBase **ud = (LuaCairoBase**)lua_newuserdata(L, sizeof(ChildClass*));
*ud = this;
CreateMetaTable(L);
lua_setmetatable(L, -2);
magic = luaopen_cairo;
}
public:
virtual ~LuaCairoBase() { }
// Helper: Get the object pointer from a callback
static ChildClass *GetObjPointer(lua_State *L, int index)
{
if (!lua_isuserdata(L, index)) {
lua_pushliteral(L, "Passed non-userdata where one expected");
lua_error(L);
}
ChildClass *obj = CheckPointer(*(void**)lua_touserdata(L, index));
return obj;
}
// Check whether a pointer plausibly points to an object of this class
static ChildClass *CheckPointer(void *ptr)
{
ChildClass *testptr = (ChildClass*)ptr;
if (testptr->magic == luaopen_cairo)
return testptr;
else
return 0;
}
};
#define CALLABLE(name) static int lua_ ## name (lua_State *L)
class LuaCairoContext : public LuaCairoBase<LuaCairoContext> {
private:
cairo_t *context;
CALLABLE(reference);
CALLABLE(status);
CALLABLE(save);
CALLABLE(restore);
CALLABLE(get_target);
CALLABLE(push_group);
CALLABLE(push_group_with_content);
CALLABLE(pop_group);
CALLABLE(pop_group_to_source);
CALLABLE(get_group_target);
CALLABLE(set_source_rgb);
CALLABLE(set_source_rgba);
CALLABLE(set_source);
CALLABLE(set_source_surface);
CALLABLE(get_source);
CALLABLE(set_antialias);
CALLABLE(get_antialias);
CALLABLE(set_dash);
CALLABLE(get_dash_count);
CALLABLE(get_dash);
CALLABLE(set_fill_rule);
CALLABLE(get_fill_rule);
CALLABLE(set_line_cap);
CALLABLE(get_line_cap);
CALLABLE(set_line_join);
CALLABLE(get_line_join);
CALLABLE(set_line_width);
CALLABLE(get_line_width);
CALLABLE(set_miter_limit);
CALLABLE(get_miter_limit);
CALLABLE(set_operator);
CALLABLE(get_operator);
CALLABLE(set_tolerance);
CALLABLE(get_tolerance);
CALLABLE(clip);
CALLABLE(clip_preserve);
CALLABLE(clip_extents);
CALLABLE(reset_clip);
// rectangle_list_destroy is not needed,
// copy_clip_rectangle_list will convert the rect list into a pure Lua structure
CALLABLE(copy_clip_rectangle_list);
CALLABLE(fill);
CALLABLE(fill_preserve);
CALLABLE(fill_extents);
CALLABLE(in_fill);
CALLABLE(mask);
CALLABLE(mask_surface);
CALLABLE(paint);
CALLABLE(paint_with_alpha);
CALLABLE(stroke);
CALLABLE(stroke_preserve);
CALLABLE(stroke_extents);
CALLABLE(in_stroke);
CALLABLE(copy_page);
CALLABLE(show_page);
// Path operations
CALLABLE(copy_path);
CALLABLE(copy_path_flat);
CALLABLE(append_path);
CALLABLE(get_current_point);
CALLABLE(new_path);
CALLABLE(new_sub_path);
CALLABLE(close_path);
CALLABLE(arc);
CALLABLE(arc_negative);
CALLABLE(curve_to);
CALLABLE(line_to);
CALLABLE(move_to);
CALLABLE(rectangle);
CALLABLE(glyph_path);
CALLABLE(text_path);
CALLABLE(rel_curve_to);
CALLABLE(rel_line_to);
CALLABLE(rel_move_to);
// Transformations
CALLABLE(translate);
CALLABLE(scale);
CALLABLE(rotate);
CALLABLE(transform);
CALLABLE(set_matrix);
CALLABLE(get_matrix);
CALLABLE(identity_matrix);
CALLABLE(user_to_device);
CALLABLE(user_to_device_distance);
CALLABLE(device_to_user);
CALLABLE(device_to_user_distance);
// Text/font operations
CALLABLE(select_font_face);
CALLABLE(set_font_size);
CALLABLE(set_font_matrix);
CALLABLE(get_font_matrix);
CALLABLE(set_font_options);
CALLABLE(get_font_options);
CALLABLE(set_font_face);
CALLABLE(get_font_face);
CALLABLE(set_scaled_font);
CALLABLE(get_scaled_font);
CALLABLE(show_text);
CALLABLE(show_glyphs);
CALLABLE(font_extents);
CALLABLE(text_extents);
CALLABLE(glyph_extents);
protected:
const char *GetTypeName();
public:
// Create another reference for a context
LuaCairoContext(lua_State *L, cairo_t *_context);
// Destructor
virtual ~LuaCairoContext();
};
class LuaCairoSurface : public LuaCairoBase<LuaCairoSurface> {
private:
CALLABLE(create_similar);
CALLABLE(reference);
CALLABLE(status);
// Create Cairo context for this surface
// This deviates from the regular Cairo API
CALLABLE(create_context);
CALLABLE(finish);
CALLABLE(flush);
CALLABLE(get_font_options);
CALLABLE(get_content);
CALLABLE(mark_dirty);
CALLABLE(mark_dirty_rectangle);
CALLABLE(set_device_offset);
CALLABLE(get_device_offset);
CALLABLE(set_fallback_resolution);
CALLABLE(get_type);
// Image surface functions
CALLABLE(image_get_format);
CALLABLE(image_get_width);
CALLABLE(image_get_height);
// These replace the get_data and get_stride functions
CALLABLE(image_set_pixel);
CALLABLE(image_get_pixel);
protected:
// Protected because inheriting classes might want it too
cairo_surface_t *surface;
const char *GetTypeName();
// For child classes that will set surface themselves
LuaCairoSurface(lua_State *L);
public:
// Create another reference for a surface
LuaCairoSurface(lua_State *L, cairo_surface_t *_surface);
// Destructor
virtual ~LuaCairoSurface();
cairo_surface_t *GetSurface() { return surface; }
// Creation functions - these aren't in image surface objects but in a global table
CALLABLE(image_surface_create);
};
class LuaCairoFontFace : public LuaCairoBase<LuaCairoFontFace> {
private:
cairo_font_face_t *font_face;
CALLABLE(create_scaled_font);
CALLABLE(reference);
CALLABLE(status);
CALLABLE(get_type);
protected:
const char *GetTypeName();
public:
// Create another reference for a font face
LuaCairoFontFace(lua_State *L, cairo_font_face_t *_font_face);
// Destructor
virtual ~LuaCairoFontFace();
cairo_font_face_t *GetFontFace() { return font_face; }
};
class LuaCairoScaledFont : public LuaCairoBase<LuaCairoScaledFont> {
private:
cairo_scaled_font_t *scaled_font;
CALLABLE(reference);
CALLABLE(status);
CALLABLE(extents);
CALLABLE(text_extents);
CALLABLE(glyph_extents);
CALLABLE(get_font_face);
CALLABLE(get_font_options);
CALLABLE(get_font_matrix);
CALLABLE(get_ctm);
CALLABLE(get_type);
protected:
const char *GetTypeName();
public:
// Create another reference for a scaled font
LuaCairoScaledFont(lua_State *L, cairo_scaled_font_t *_scaled_font);
// Destructor
virtual ~LuaCairoScaledFont();
cairo_scaled_font_t *GetScaledFont() { return scaled_font; }
};
class LuaCairoFontOptions : public LuaCairoBase<LuaCairoFontOptions> {
private:
cairo_font_options_t *font_options;
bool owned;
CALLABLE(copy);
CALLABLE(status);
CALLABLE(merge);
CALLABLE(hash);
CALLABLE(equal);
CALLABLE(set_antialias);
CALLABLE(get_antialias);
CALLABLE(set_subpixel_order);
CALLABLE(get_subpixel_order);
CALLABLE(set_hint_style);
CALLABLE(get_hint_style);
CALLABLE(set_hint_metrics);
CALLABLE(get_hint_metrics);
void RegFontOptionsCallables();
protected:
const char *GetTypeName();
// Extend the meta table with an equality operator
void CreateMetaTable(lua_State *L);
public:
// Create a new font options object - will be owned
LuaCairoFontOptions(lua_State *L);
// Wrap an existing font options object - will not be owned
LuaCairoFontOptions(lua_State *L, cairo_font_options_t *_font_options);
// Destructor - only destroy font_options if owned
virtual ~LuaCairoFontOptions();
cairo_font_options_t *GetFontOptions() { return font_options; }
// Creation function - global
CALLABLE(create);
};
class LuaCairoMatrix : public LuaCairoBase<LuaCairoMatrix> {
private:
cairo_matrix_t matrix;
CALLABLE(init);
CALLABLE(init_identity);
CALLABLE(init_translate);
CALLABLE(init_scale);
CALLABLE(init_rotate);
CALLABLE(translate);
CALLABLE(scale);
CALLABLE(rotate);
// Matrix inversion
CALLABLE(invert);
// Matrix multiplication
CALLABLE(multiply);
CALLABLE(transform_distance);
CALLABLE(transform_point);
// Pointwise arithmetic on matrices - not part of Cairo API
CALLABLE(op_add);
CALLABLE(op_sub);
CALLABLE(op_mul);
CALLABLE(op_div);
CALLABLE(op_unm);
// Equality operator
CALLABLE(op_eq);
// Not in Cairo API
CALLABLE(copy);
void RegMatrixCallables();
protected:
virtual int internal_lua_index(lua_State *L);
virtual int internal_lua_newindex(lua_State *L);
const char *GetTypeName();
// Extend the meta table with various operators
void CreateMetaTable(lua_State *L);
public:
// Create new matrix, inited to identity matrix
LuaCairoMatrix(lua_State *L);
// Duplicate exixting matrix
LuaCairoMatrix(lua_State *L, const cairo_matrix_t *_matrix);
// Destructor
virtual ~LuaCairoMatrix();
cairo_matrix_t *GetMatrix();
// Creation function - global
CALLABLE(create);
};
class LuaCairoPath : public LuaCairoBase<LuaCairoPath> {
private:
cairo_path_t *path;
// TODO: figure out what methods are needed
// Something to iterate over the parts at least
// Support for creating/modifying paths?
// Functional programming support
CALLABLE(map); // transform each path segment with a function
CALLABLE(map_coords); // transform each coordinate pair with a function
CALLABLE(fold); // fold path segments into a single result value
CALLABLE(fold_coords); // fold coordinate pairs into a single result value
protected:
virtual int internal_lua_index(lua_State *L);
const char *GetTypeName();
public:
// Create object based on path - does not copy path, but it will be implicitly owned
LuaCairoPath(lua_State *L, cairo_path_t *_path);
// Destructor
virtual ~LuaCairoPath();
cairo_path_t *GetPath() { return path; }
};
class LuaCairoPattern : public LuaCairoBase<LuaCairoPattern> {
private:
cairo_pattern_t *pattern;
CALLABLE(add_color_stop_rgb);
CALLABLE(add_color_stop_rgba);
CALLABLE(get_color_stop_count);
CALLABLE(get_color_stop_rgba);
CALLABLE(get_rgba);
CALLABLE(get_surface);
CALLABLE(get_linear_points);
CALLABLE(get_radial_circles);
CALLABLE(reference);
CALLABLE(status);
CALLABLE(set_extend);
CALLABLE(get_extend);
CALLABLE(set_filter);
CALLABLE(get_filter);
CALLABLE(set_matrix);
CALLABLE(get_matrix);
CALLABLE(get_type);
protected:
const char *GetTypeName();
public:
// Create another reference for a pattern object
LuaCairoPattern(lua_State *L, cairo_pattern_t *_pattern);
// Destructor
virtual ~LuaCairoPattern();
cairo_pattern_t *GetPattern() { return pattern; }
// Creation functions - these aren't in pattern objects but in a global table
CALLABLE(create_rgb);
CALLABLE(create_rgba);
CALLABLE(create_for_surface);
CALLABLE(create_linear);
CALLABLE(create_radial);
};
#undef CALLABLE
#endif

202
OverLua/csri.cpp Normal file
View file

@ -0,0 +1,202 @@
/*
* CSRI interface for OverLua
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
#include <string.h>
#include <memory.h>
#define CSRI_OWN_HANDLES
#define CSRIAPI extern "C" __declspec(dllexport)
// Nothing special required here
typedef int csri_rend;
// Forward instance data
struct csri_inst;
#include "../csri/include/csri/csri.h"
#include "../csri/include/csri/logging.h"
#include "overlua.h"
// Instance data
struct csri_inst {
csri_fmt frame_format;
OverLuaScript *script;
};
// Renderer information definition
static const csri_info overlua_csri_info = {
"overlua",
"overlua-001",
"OverLua Lua-based advanced effects renderer",
"Niels Martin Hansen",
"Copyright 2007 Niels Martin Hansen (GPLv2)"
};
// Just something we can pass a pointer to
static const csri_rend overlua_csri_rend = 0;
// Name of the "overlua" extension format
static const char *overlua_format_ext_name = "jfs.overlua";
CSRIAPI csri_inst *csri_open_file(csri_rend *renderer,
const char *filename, struct csri_openflag *flags)
{
if (renderer != &overlua_csri_rend) return 0;
csri_inst *inst = new csri_inst;
inst->script = new OverLuaScript(filename);
return inst;
}
CSRIAPI csri_inst *csri_open_mem(csri_rend *renderer,
const void *data, size_t length, struct csri_openflag *flags)
{
if (renderer != &overlua_csri_rend) return 0;
csri_inst *inst = new csri_inst;
inst->script = new OverLuaScript(data, length);
return inst;
}
CSRIAPI void csri_close(csri_inst *inst)
{
delete inst->script;
delete inst;
return;
}
CSRIAPI int csri_request_fmt(csri_inst *inst, const struct csri_fmt *fmt)
{
// only support RGB formats
if (!csri_is_rgb(fmt->pixfmt))
return 0;
// get a private copy of it
memcpy(&inst->frame_format, fmt, sizeof(csri_fmt));
return 1;
}
CSRIAPI void csri_render(csri_inst *inst, struct csri_frame *frame, double time)
{
// check for correct pixfmt
if (frame->pixfmt != inst->frame_format.pixfmt) return;
OverLuaFrameAggregate *olframe = 0;
switch (frame->pixfmt) {
#define HANDLE_RGB_FORMAT(fmtname, Rpos, Gpos, Bpos, PixelWidth) \
case fmtname: \
olframe = new OverLuaFrameAggregateImpl<Rpos,Gpos,Bpos,PixelWidth>(inst->frame_format.width, inst->frame_format.height, frame->strides[0], frame->planes[0]); \
break;
HANDLE_RGB_FORMAT(CSRI_F_RGBA, 0, 1, 2, 4)
HANDLE_RGB_FORMAT(CSRI_F_ARGB, 1, 2, 3, 4)
HANDLE_RGB_FORMAT(CSRI_F_BGRA, 2, 1, 0, 4)
HANDLE_RGB_FORMAT(CSRI_F_ABGR, 3, 2, 1, 4)
HANDLE_RGB_FORMAT(CSRI_F_RGB_, 0, 1, 2, 4)
HANDLE_RGB_FORMAT(CSRI_F__RGB, 1, 2, 3, 4)
HANDLE_RGB_FORMAT(CSRI_F_BGR_, 2, 1, 0, 4)
HANDLE_RGB_FORMAT(CSRI_F__BGR, 3, 2, 1, 4)
HANDLE_RGB_FORMAT(CSRI_F_RGB, 0, 1, 2, 3)
HANDLE_RGB_FORMAT(CSRI_F_BGR, 2, 1, 0, 3)
default: break; // what, we don't support this!
#undef HANDLE_RGB_FORMAT
}
if (olframe) {
inst->script->RenderFrameRGB(*olframe, time);
}
}
CSRIAPI void *csri_query_ext(csri_rend *rend, csri_ext_id extname)
{
if (rend != &overlua_csri_rend)
return 0;
// Check for the OverLua format extension
if (strcmp(extname, overlua_format_ext_name) == 0)
// Nonsense return
return &overlua_format_ext_name;
// TODO: support logging
if (strcmp(extname, CSRI_EXT_LOGGING) == 0)
return 0;
return 0;
}
CSRIAPI struct csri_info *csri_renderer_info(csri_rend *rend)
{
if (rend == &overlua_csri_rend)
return (csri_info*)&overlua_csri_info;
return 0;
}
CSRIAPI csri_rend *csri_renderer_byname(const char *name,
const char *specific)
{
if (strcmp(name, overlua_csri_info.name) == 0)
if (!specific || strcmp(specific, overlua_csri_info.specific) == 0)
return (csri_rend*)&overlua_csri_rend;
return 0;
}
CSRIAPI csri_rend *csri_renderer_byext(unsigned n_ext, csri_ext_id *ext)
{
// Check if every extension is supported
while (n_ext-- > 0) {
if (!csri_query_ext((csri_rend*)&overlua_csri_rend, *ext))
return 0;
ext++;
}
return (csri_rend*)&overlua_csri_rend;
}
CSRIAPI csri_rend *csri_renderer_default()
{
return (csri_rend*)&overlua_csri_rend;
}
CSRIAPI csri_rend *csri_renderer_next(csri_rend *prev)
{
if (prev == 0)
return (csri_rend*)&overlua_csri_rend;
else
return 0;
}

292
OverLua/docs/lua-cairo.txt Normal file
View file

@ -0,0 +1,292 @@
Documentation for the Cairo interface provided in OverLua
=========================================================
First, this file will mostly attempt to describe the differences between the
Cairo C API and the provided Lua API. If you want more general and in-depth
information on Cairo, please see the documentation for the C API:
<http://cairographics.org/manual/>
Note that almost all of the *_reference functions are unimplemented currently.
They should not be explicitly needed since Lua does its own management on
objects as well, you can just copy and keep a Lua Cairo object and be
guaranteed the underlying Cairo object won't be deleted until all Lua objects
referring to it are gone.
There are no *_destroy and *_get_reference_count functions either,
for this reason.
Finally the *_user_data functions are also removed from the API.
Conventions in this file
------------------------
Variable name Cairo object
surf Surface (cairo_surface_t)
ctx Context (cairo_t)
face Font face (cairo_font_face_t)
sf Scaled font (cairo_scaled_font_t)
fo Font options (cairo_font_options_t)
mat Matrix (cairo_matrix_t)
path Path (cairo_path_t)
pat Pattern (cairo_pattern_t)
x, y Coordinates
r, g, b, a Colour values (red, green, blue, alpha)
If more than one of an object type is used they will get numeric suffixes.
For matrix operations you might also see "matR", this is "result matrix".
More "OO-like" syntax
---------------------
This Lua Cairo API provides a more common "OO-like" syntax for calls.
For example, the cairo_set_source_surface(ctx, surf, x, y) function maps to
ctx.set_source_surface(surf, x, y).
Creating initial objects
------------------------
Many of the objects you will use are created from or by other objects, but
you will need to create some non-dependant objects, most importantly image
surface objects. All the object creation functions live in the global "cairo"
table.
surf = cairo.image_surface_create(width, height, pixel_format)
Create a blank image surface object.
width and height are in pixels. pixel_format is a string and must be one
of "argb32", "rgb24", "a8" and "a1".
fo = cairo.font_options_create()
Create a new font options object.
mat = cairo.matrix_create()
Create a new matrix. It is initially the identity matrix.
pat = cairo.pattern_create_rgb(r, g, b)
pat = cairo.pattern_create_rgba(r, g, b, a)
pat = cairo.pattern_create_for_surface(surf)
pat = cairo.pattern_create_linear(x0, y0, x1, y1)
pat = cairo.pattern_create_radial(x0, y0, r0, x1, y1, r1)
Create various kinds of pattern objects.
ctx = surf.create_context()
Not strictly an "initial object", but Cairo context objects are important
enough to explicitly list here. They are created by calling the
create_context() method in a surface object. This will create a context
object that draws to the surface it was created with.
Other functions that have changed API
-------------------------------------
Some functions have changed API to better match the Lua programming model.
ctx.set_dash()
ctx.set_dash(0)
ctx.set_dash(num[, offset])
ctx.set_dash(dashes[, offset])
There are several forms of the set_dash function. The two first disable
dashing entirely.
The third creates a repeating pattern of equal length on and off potions,
each "num" units long. The offset argument is optional, its default is 0.
The last creates a complex pattern. "dashes" must be a table of numbers
describing the dashing pattern. offset is optional, default is 0.
dashes, offset = ctx.get_dash()
Returns current dashing setting, in same format as the last form of set_dash
takes. If dashing is disabled, dashes will be an empty table.
(You won't need to use the ctx.get_dash_count() function.)
x0, y0, x1, y1 = ctx.clip_extents()
x0, y0, x1, y1 = ctx.fill_extents()
x0, y0, x1, y1 = ctx.stroke_extents()
Return the smallest rectangle bounding the area that would be affected if
performing a clip/fill/stroke operation.
x, y = ctx.get_current_point()
Get the current point for path gneration operations.
mat = ctx.get_matrix()
Get the current geometry transformation matrix.
x, y = ctx.user_to_device(x, y)
x, y = ctx.user_to_device_distance(x, y)
x, y = ctx.device_to_user(x, y)
x, y = ctx.device_to_user_distance(x, y)
Returns the transformation of a point between device and user-space
coordinates.
offset, r, g, b, a = pat.get_color_stop_rgba(index)
Returns nothing if the pattern is not a gradient pattern or the stop index
is out of range.
r, g, b, a = pat.get_rgba()
Returns nothing if the pattern is not a solid colour fill pattern.
surf = pat.get_surface()
Returns nothing if the pattern is not a surface pattern.
x0, y0, x1, y1 = pat.get_linear_points()
Returns nothing if the pattern is not a linear gradient pattern.
x0, y0, r0, x1, y1, r1 = pat.get_radial_circles()
Returns nothing if the pattern is not a radial gradient pattern.
extents = ctx.font_extents()
extents = sf.font_extents()
Get extents metrics for current font. The returned object is a Lua table
with fields identical to the C struct cairo_font_extents_t.
extents = ctx.tex_extents(utf8)
extents = sf.text_extents(utf8)
Get extents metrics for writing text given in utf8 with current font. The
returned object is a Lua table with fields identical to the C
struct cairo_text_extents_t.
fo = sf.get_font_options()
Get font options for a scaled font.
mat = sf.get_font_matrix()
Get text transformation matrix.
mat = sf.get_ctm()
Get the CTM. (Character transformation matrix?)
fo1.merge(fo2)
Merge font options fo2 into fo1.
hash = fo.hash()
Returns a hexadecimal string hash of fo.
fo1.equal(fo2)
Return true is fo1 equals fo2.
fo = surf.get_font_options()
Get current font options for surface.
x, y = surf.get_device_offset()
Get current device offset for surface.
a, r, g, b = surf.get_pixel(x, y)
r, g, b = surf.get_pixel(x, y)
a = surf.get_pixel(x, y)
Get colour value of a pixel on an image surface. This function replaces the
cairo_image_surface_get_data(surf) function for reading surface contents.
The number and meanings of return values depend on the surface pixel format.
surf.set_pixel() is not implemented yet.
matR = mat.copy()
Duplicate a matrix. Not in Cairo C API.
mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0
Access the individual numbers in a matrix. These are both read and write.
Functional programming on path objects
--------------------------------------
The path object still hasn't been completely implemented, but two useful
functions do exist for it. These are functional programming style map and
fold functions.
path.map_coords(func)
Transform every coordinate pair in path using func.
func must be a function of type (x,y)->(x,y) ie. takes two arguments which
are the x and y coordinates of the point and returns two numbers which are
the new x and y coordinates of the point.
Example: Produce a "wavy" effect.
path.map_coords(function(x,y) return math.sin(x), math.cos(y) end)
res = path.fold_coords(func, start)
Produce a value by combining all the coordinate pairs using func.
func must be a function of type (r,x,y)->(r) ie. takes three argument which
are the current result and the x/y coordinates of the point, and returns a
new result.
When all points have been processed path.fold_coords returns the final result.
Example: Find the maximum X coordinate.
maxx = path.fold_coords(
function(maxx,x,y)
if not maxx then
return x
elseif x > maxx then
return x
else
return maxx
end
end, nil)

133
OverLua/docs/overlua.txt Normal file
View file

@ -0,0 +1,133 @@
OverLua provides a Lua 5.1 runtime environment with access to all
standard libraries.
API the Lua script must implement
---------------------------------
Any initialisation, such as loading external data files, should be done
in the Lua script's global environment.
OverLua expects one function in the script:
function render_frame(frame, timestamp)
The function name must be literal "render_frame". It must not be local.
The "frame" parameter is a userdata object representing the video frame
there must be rendered to. Other functions take this object as parameter.
The "timestamp" parameter is a value of type "number", representing the
timestamp of the frame to be rendered, in seconds. The timestamp may be
non-integer with any precision.
The render_frame function should not return anything. Instead it modifies
the frame object.
The render_frame function should not assume that frames are requested in
any specific order.
The frame object
----------------
The "frame" object passed to the render_frame function has a number of
fields accessible.
The frame is always stored as RGB. No alpha channel is supported.
frame.width
An integer number storing the width of the frame in pixels.
Read only.
frame.height
An integer number storing the height of the frame in pixels.
Read only.
red, green, blue = frame(x, y)
"red", "green" and "blue" will be numbers in range 0..255 that will receive
the respective colour channel values for the requested pixel.
"x" and "y" are the pixel coordinates for the pixel to retrieve
Pixel coordinates are counted from zero and start in the upper left corner.
A pixel with coordinates (X, Y) has pixel number Y*frame.width+X.
frame[n] = {red, green, blue}
Set the value of the given pixel.
The table on the right side of the equal sign must have at least three
entries which must all be numbers. They are taken as red, green and blue
values respectively, in regular enumeration order.
"n" is the pixel number to be set.
A pixel with coordinates (X, Y) has pixel number Y*frame.width+X.
Using a table constructor as shown is recommended.
surface = frame.create_cairo_surface()
Create a Cairo rgb24 surface from the video frame. Drawing to the surface
will _not_ affect the video frame. If you want the changes to the surface
visible on the video you will need to overlay this surface on the video.
frame.overlay_cairo_surface(surface, x, y)
Overlay the given Cairo surface at the video frame such that the upper,
left corner of the surface is positioned at pixel (x, y) on the video.
Only argb32 and rgb24 type surfaces are supported.
Proper alpha blending is used for argb32 surfaces.
Setting a pixel value for a pixel outside the frame has no effect.
Specifically, it will not produce an error or a warning message.
Reading a pixel value for a pixel outside the frame will return black,
ie. (0, 0, 0).
Vector graphics interface
-------------------------
OverLua uses the Cairo library for all vector graphics handling, including
text handling.
See lua-cairo.txt for details.
Raster graphics processing interface
------------------------------------
A raster graphics processing interface is also provided, to post-process
the graphics produced by the vector graphics interface.
The raster graphics interface operates directly on Cairo surfaces.
raster.gaussian_blur(surface, sigma)
Applies a strength sigma gaussian blur on the surface.
raster.box3(surface, repetitions)
raster.box5(sutface, repetitions)
raster.box15(surface, repetitions)
Applies a box filter (blur) of various sizes to the surface as many times as
specified. Please note that no specific optimisation is done for applying
box filters over more general filters and using box blur over gaussian blur
is probably no faster and might even be slower.
More filtering functions are planned, though no specifics yet.
Wishes/suggestions are welcome, and so are patches to add more functions.

14
OverLua/docs/test1.lua Normal file
View file

@ -0,0 +1,14 @@
function render_frame(f, t)
local w, h = f.width, f.height
for x = 0, 20 do
for y = 0, 20 do
f[y*w+x] = {x*10,y*10,255}
end
end
for x = 21, 40 do
for y = 0, h-1 do
local r, g, b = f(x,y)
f[y*w+x] = {255-r, 255-g, 255-b}
end
end
end

42
OverLua/docs/test2.lua Normal file
View file

@ -0,0 +1,42 @@
function render_frame(f, t)
--local surf = cairo.image_surface_create(200,200,"argb32")
local surf = f.create_cairo_surface()
local ctx = surf.create_context()
ctx.set_source_rgba(1, 0.5, 0.5, 0.75)
ctx.move_to(10, 10)
ctx.line_to(10, 200)
ctx.line_to(300, 10)
ctx.close_path()
ctx.fill_preserve()
ctx.set_source_rgba(0,0,0,1)
ctx.stroke()
ctx.push_group()
ctx.select_font_face("Arial", "italic", "")
ctx.set_font_size(35)
ctx.move_to(100,100)
ctx.text_path(string.format("Time: %.3fs", t))
ctx.set_source_rgba(0,1,0,0.8)
ctx.set_line_width(4)
ctx.stroke_preserve()
ctx.set_source_rgba(0,0,1,1)
ctx.fill()
ctx.pop_group_to_source()
ctx.paint_with_alpha(0.5)
f.overlay_cairo_surface(surf, 0, 0)
surf = cairo.image_surface_create(400, 200, "argb32")
ctx = surf.create_context()
ctx.select_font_face("Arial", "", "bold")
ctx.set_source_rgba(1, 1, 1, 1)
ctx.set_font_size(40)
ctx.move_to(100, 100)
ctx.text_path("OverLua")
ctx.fill()
raster.gaussian_blur(surf, (1-math.cos(t*10))*2)
f.overlay_cairo_surface(surf, 200, 50)
end

5
OverLua/docs/test3.lua Normal file
View file

@ -0,0 +1,5 @@
function render_frame(f, t)
local surf = f.create_cairo_surface()
raster.gaussian_blur(surf, t)--1+(1-math.cos(t*10))*2)
f.overlay_cairo_surface(surf, 0, 0)
end

140
OverLua/overlua.cpp Normal file
View file

@ -0,0 +1,140 @@
/*
* C++ interface for OverLua
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
#include "overlua.h"
#include <stdio.h>
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <windows.h>
#endif
struct FileScriptReader {
static const size_t datasize = 0x10000;
char *data;
FILE *file;
FileScriptReader() { data = new char[datasize]; }
~FileScriptReader() { delete[] data; }
static const char *reader(lua_State *L, void *data, size_t *size)
{
FileScriptReader *self = (FileScriptReader*)data;
*size = fread(self->data, 1, self->datasize, self->file);
if (*size) return self->data;
else return 0;
}
};
OverLuaScript::OverLuaScript(const char *filename)
{
FileScriptReader reader;
#ifdef WIN32
wchar_t *filenamew = new wchar_t[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenamew, MAX_PATH);
reader.file = _wfopen(filenamew, L"r");
delete[] filenamew;
#else
reader.file = fopen(filename, "r");
#endif
Create(reader, filename);
fclose(reader.file);
}
struct MemScriptReader {
const void *memdata;
size_t memdatasize;
static const char *reader(lua_State *L, void *data, size_t *size)
{
MemScriptReader *self = (MemScriptReader*)data;
*size = self->memdatasize;
self->memdatasize = 0;
if (*size) return (const char*)self->memdata;
else return 0;
}
};
int OverLuaScript::lua_debug_print(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
#ifdef WIN32
OutputDebugStringA(str);
#else
printf(str);
#endif
return 0;
}
OverLuaScript::OverLuaScript(const void *data, size_t length)
{
MemScriptReader reader;
reader.memdata = data;
reader.memdatasize = length;
Create(reader, "Memory script");
int err;
L = luaL_newstate();
err = lua_load(L, reader.reader, &reader, "Memory script");
// todo: better error handling
if (err == LUA_ERRSYNTAX) throw "Syntax error";
if (err = LUA_ERRMEM) throw "Memory error";
err = lua_pcall(L, 0, 0, 0);
if (err == LUA_ERRRUN) throw "Runtime error";
if (err == LUA_ERRMEM) throw "Memory error";
if (err == LUA_ERRERR) throw "Error-handler error";
}
OverLuaScript::~OverLuaScript()
{
lua_close(L);
}
void OverLuaScript::RenderFrameRGB(OverLuaFrameAggregate &frame, double time)
{
OutputDebugStringW(L"RenderFrameRGB: get frame func\n");
lua_getglobal(L, "render_frame");
OutputDebugStringW(L"RenderFrameRGB: CreateLuaObject\n");
frame.CreateLuaObject(L);
lua_pushnumber(L, time);
OutputDebugStringW(L"RenderFrameRGB: call\n");
if (lua_pcall(L, 2, 0, 0)) {
const char *err = lua_tostring(L, -1);
//MessageBoxA(0, err, "OverLua", MB_ICONERROR);
throw err;
}
OutputDebugStringW(L"RenderFrameRGB: garbage collect\n");
lua_gc(L, LUA_GCCOLLECT, 0);
OutputDebugStringW(L"RenderFrameRGB: done rendering frame\n");
}

90
OverLua/overlua.h Normal file
View file

@ -0,0 +1,90 @@
/*
* C++ interface for OverLua
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
#ifndef OVERLUA_H
#define OVERLUA_H
// assume we're in aegisub's svn tree and
// are building with the aegisub patched lua
#include "../lua51/src/lua.h"
#include "../lua51/src/lualib.h"
#include "../lua51/src/lauxlib.h"
#include <stddef.h>
#include "video_frame.h"
#include "cairo_wrap.h"
#include "raster_ops.h"
class OverLuaScript {
private:
lua_State *L;
// No default constructor
OverLuaScript() { }
template <class ScriptReaderClass>
void Create(ScriptReaderClass &reader, const char *chunkname)
{
int err;
L = luaL_newstate();
// Base Lua libs
luaL_openlibs(L);
// Cairo lib
lua_pushcfunction(L, luaopen_cairo); lua_call(L, 0, 0);
// Raster library
lua_pushcfunction(L, luaopen_raster); lua_call(L, 0, 0);
// Debug print
lua_pushcclosure(L, lua_debug_print, 0);
lua_setglobal(L, "dprint");
err = lua_load(L, reader.reader, &reader, chunkname);
// todo: better error handling
if (err == LUA_ERRSYNTAX) throw lua_tostring(L, -1);
if (err == LUA_ERRMEM) throw "Memory error";
err = lua_pcall(L, 0, 0, 0);
if (err == LUA_ERRRUN) throw lua_tostring(L, -1);
if (err == LUA_ERRMEM) throw "Memory error";
if (err == LUA_ERRERR) throw "Error-handler error";
}
static int lua_debug_print(lua_State *L);
public:
OverLuaScript(const char *filename);
OverLuaScript(const void *data, size_t length);
virtual ~OverLuaScript();
void RenderFrameRGB(OverLuaFrameAggregate &frame, double time);
};
#endif

391
OverLua/raster_ops.cpp Normal file
View file

@ -0,0 +1,391 @@
/*
* Raster image operations for OverLua
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
#include "cairo_wrap.h"
#include <math.h>
#include <windows.h>
#include <omp.h>
#include "raster_ops.h"
#include "../lua51/src/lauxlib.h"
/*#define cimg_display_type 0
#include "CImg.h"
using namespace cimg_library;
// Type of images processed
typedef CImg<unsigned char> Img;
// Make an Img representing the image of a Cairo image surface
// from the Lua wrapper of Cairo.
static inline Img ImgFromSurf(lua_State *L, int idx)
{
LuaCairoSurface *surfobj = LuaCairoSurface::GetObjPointer(L, idx);
cairo_surface_t *surf = surfobj->GetSurface();
if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_IMAGE) {
lua_pushliteral(L, "Object for raster operation is not an image surface. Video frames are not accepted.");
lua_error(L);
}
cairo_surface_flush(surf);
int width = cairo_image_surface_get_width(surf);
int height = cairo_image_surface_get_height(surf);
int stride = cairo_image_surface_get_stride(surf);
int dim = 0;
switch (cairo_image_surface_get_format(surf)) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
dim = 4;
break;
case CAIRO_FORMAT_A8:
dim = 1;
break;
case CAIRO_FORMAT_A1:
lua_pushliteral(L, "1 bpp image surfaces are not supported for raster operations");
lua_error(L);
break;
default:
lua_pushliteral(L, "Unknown pixel format for image surface");
lua_error(L);
}
unsigned char *data = cairo_image_surface_get_data(surf);
Img res;
// Copy over data
if (dim == 4) {
res = Img(width, height, 1, 4);
unsigned char *ptrA, *ptrR, *ptrG, *ptrB;
ptrA = res.ptr(0, 0, 0, 0);
ptrR = res.ptr(0, 0, 0, 1);
ptrG = res.ptr(0, 0, 0, 2);
ptrB = res.ptr(0, 0, 0, 3);
// Can't use cimg_mapXY since we need to take stride into account
for (int row = 0; row < height; row++) {
unsigned char *ptrI = data + row*stride;
for (int x = width-1; x > 0; x--) {
*(ptrA)++ = *(ptrI++);
*(ptrR)++ = *(ptrI++);
*(ptrG)++ = *(ptrI++);
*(ptrB)++ = *(ptrI++);
}
}
}
else if (dim == 1) {
// Also need to take stride into account here
res = Img(width, height, 1, 1);
unsigned char *ptrO = res.ptr(0, 0, 0, 0);
for (int row = 0; row < height; row++) {
unsigned char *ptrI = data + row*stride;
for (int x = width-1; x > 0; x--) {
*(ptrO++) = *(ptrI++);
}
}
}
return res;
}
static inline void ImgToSurf(lua_State *L, int idx, const Img &img)
{
// Assume it has already been checked that a suitable surface is in the stack index
LuaCairoSurface *surfobj = LuaCairoSurface::GetObjPointer(L, idx);
cairo_surface_t *surf = surfobj->GetSurface();
int width = cairo_image_surface_get_width(surf);
int height = cairo_image_surface_get_height(surf);
int stride = cairo_image_surface_get_stride(surf);
int dim = 0;
switch (cairo_image_surface_get_format(surf)) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
dim = 4;
break;
case CAIRO_FORMAT_A8:
dim = 1;
break;
case CAIRO_FORMAT_A1:
lua_pushliteral(L, "1 bpp image surfaces are not supported for raster operations");
lua_error(L);
break;
default:
lua_pushliteral(L, "Unknown pixel format for image surface");
lua_error(L);
}
if (width != img.dimx() || height != img.dimy() || dim != img.dimv()) {
lua_pushliteral(L, "Internal error, attempting to write back CImg to image surface with mismatching dimensions");
lua_error(L);
}
unsigned char *data = cairo_image_surface_get_data(surf);
// Copy over data
if (dim == 4) {
const unsigned char *ptrA, *ptrR, *ptrG, *ptrB;
ptrA = img.ptr(0, 0, 0, 0);
ptrR = img.ptr(0, 0, 0, 1);
ptrG = img.ptr(0, 0, 0, 2);
ptrB = img.ptr(0, 0, 0, 3);
// Can't use cimg_mapXY since we need to take stride into account
for (int row = 0; row < height; row++) {
unsigned char *ptrO = data + row*stride;
for (int x = width-1; x > 0; x--) {
*(ptrO)++ = *(ptrA++);
*(ptrO)++ = *(ptrR++);
*(ptrO)++ = *(ptrG++);
*(ptrO)++ = *(ptrB++);
}
}
}
else if (dim == 1) {
// Also need to take stride into account here
const unsigned char *ptrI = img.ptr(0, 0, 0, 0);
for (int row = 0; row < height; row++) {
unsigned char *ptrO = data + row*stride;
for (int x = width-1; x > 0; x--) {
*(ptrO++) = *(ptrI++);
}
}
}
cairo_surface_mark_dirty(surf);
}*/
static inline double NormalDist(double sigma, double x)
{
if (sigma <= 0 && x == 0) return 1;
else if (sigma <= 0) return 0;
else return exp(-(x*x)/(2*sigma*sigma)) / (sigma * sqrt(2*3.1415926535));
}
// Filter an image in horizontal direction with a one-dimensional filter
// PixelWidth is the distance in bytes between pixels
template<ptrdiff_t PixelWidth>
void SeparableFilterX(unsigned char *src, unsigned char *dst, int width, int height, ptrdiff_t stride, int *kernel, int kernel_size, int divisor)
{
#pragma omp parallel for
for (int y = 0; y < height; y++) {
unsigned char *in = src + y*stride;
unsigned char *out = dst + y*stride;
for (int x = 0; x < width; x++) {
int accum = 0;
for (int k = 0; k < kernel_size; k++) {
int xofs = k - kernel_size/2;
//if (x+xofs < 0 || x+xofs >= width) continue;
if (x+xofs < 0) xofs += width;
if (x+xofs >= width) xofs -= width;
accum += (int)(in[xofs*PixelWidth] * kernel[k]);
}
accum /= divisor;
if (accum > 255) accum = 255;
if (accum < 0) accum = 0;
*out = (unsigned char)accum;
in+=PixelWidth;
out+=PixelWidth;
}
}
}
// Filter an image in vertical direction with a one-dimensional filter
// This one templated with PixelWidth since the channel interlacing is horizontal only,
// filtering once vertically will automatically catch all channels.
// (Width must be multiplied by pixel width for that to happen though.)
void SeparableFilterY(unsigned char *src, unsigned char *dst, int width, int height, ptrdiff_t stride, int *kernel, int kernel_size, int divisor)
{
#pragma omp parallel for
for (int x = 0; x < width; x++) {
unsigned char *in = src + x;
unsigned char *out = dst + x;
for (int y = 0; y < height; y++) {
int accum = 0;
for (int k = 0; k < kernel_size; k++) {
int yofs = k - kernel_size/2;
//if (y+yofs < 0 || y+yofs >= height) continue;
if (y+yofs < 0) yofs += height;
if (y+yofs >= height) yofs -= height;
accum += (int)(in[yofs*stride] * kernel[k]);
}
accum /= divisor;
if (accum > 255) accum = 255;
if (accum < 0) accum = 0;
*out = (unsigned char)accum;
in += stride;
out += stride;
}
}
}
void ApplySeparableFilter(lua_State *L, cairo_surface_t *surf, int *kernel, int kernel_size, int divisor)
{
// Get surface properties
if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_IMAGE) {
lua_pushliteral(L, "Object for raster operation is not an image surface. Video frames are not accepted.");
lua_error(L);
}
cairo_surface_flush(surf);
int width = cairo_image_surface_get_width(surf);
int height = cairo_image_surface_get_height(surf);
ptrdiff_t stride = (ptrdiff_t)cairo_image_surface_get_stride(surf);
cairo_format_t format = cairo_image_surface_get_format(surf);
unsigned char *data = cairo_image_surface_get_data(surf);
if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24 && format != CAIRO_FORMAT_A8) {
lua_pushliteral(L, "Unsupported image format for raster operation");
lua_error(L);
}
// Work image
unsigned char *wimg = new unsigned char[height*stride];
// Do the filtering
if (format == CAIRO_FORMAT_ARGB32 || format == CAIRO_FORMAT_RGB24) {
// Horizontal
SeparableFilterX<4>(data+0, wimg+0, width, height, stride, kernel, kernel_size, divisor);
SeparableFilterX<4>(data+1, wimg+1, width, height, stride, kernel, kernel_size, divisor);
SeparableFilterX<4>(data+2, wimg+2, width, height, stride, kernel, kernel_size, divisor);
SeparableFilterX<4>(data+3, wimg+3, width, height, stride, kernel, kernel_size, divisor);
// Vertical
//memcpy(data, wimg, height*stride);
SeparableFilterY(wimg, data, width*4, height, stride, kernel, kernel_size, divisor);
} else if (format == CAIRO_FORMAT_A8) {
// Horizontal
SeparableFilterX<1>(data, wimg, width, height, stride, kernel, kernel_size, divisor);
// Vertical
SeparableFilterY(wimg, data, width, height, stride, kernel, kernel_size, divisor);
}
// Clean up
cairo_surface_mark_dirty(surf);
delete[] wimg;
}
// raster.gaussian_blur(imgsurf, sigma)
static int gaussian_blur(lua_State *L)
{
// Get arguments
LuaCairoSurface *surfobj = LuaCairoSurface::GetObjPointer(L, 1);
double sigma = luaL_checknumber(L, 2);
// Generate gaussian kernel
int kernel_size = (int)(sigma*3 + 0.5) | 1; // binary-or with 1 to make sure the number is odd
if (kernel_size < 3) kernel_size = 3;
int *kernel = new int[kernel_size];
kernel[kernel_size/2] = (int)(NormalDist(sigma, 0) * 255);
int ksum = kernel[kernel_size/2];
for (int x = kernel_size/2-1; x >= 0; x--) {
int val = (int)(NormalDist(sigma, kernel_size/2-x) * 255 + 0.5);
ksum += val*2;
kernel[x] = val;
kernel[kernel_size - x - 1] = val;
}
/*while (ksum < 255) {
kernel[ksum%kernel_size]++;
ksum++;
}
while (ksum > 255) {
kernel[ksum%kernel_size]--;
ksum--;
}*/
ApplySeparableFilter(L, surfobj->GetSurface(), kernel, kernel_size, ksum);
delete[] kernel;
return 0;
}
// n tap box blur
template <size_t taps, int tapval>
static int box_blur(lua_State *L)
{
LuaCairoSurface *surfobj = LuaCairoSurface::GetObjPointer(L, 1);
int applications = luaL_optint(L, 1, 1);
int kernel[taps];
for (size_t i = 0; i < taps; i++)
kernel[i] = tapval;
while (applications-- > 0)
ApplySeparableFilter(L, surfobj->GetSurface(), kernel, taps, 255);
return 0;
}
static int invert_image(lua_State *L)
{
LuaCairoSurface *surfobj = LuaCairoSurface::GetObjPointer(L, 1);
cairo_surface_t *surf = surfobj->GetSurface();
if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_IMAGE) {
lua_pushliteral(L, "Object for raster operation is not an image surface. Video frames are not accepted.");
lua_error(L);
}
cairo_surface_flush(surf);
size_t width = (size_t)cairo_image_surface_get_width(surf);
size_t height = (size_t)cairo_image_surface_get_height(surf);
ptrdiff_t stride = (ptrdiff_t)cairo_image_surface_get_stride(surf);
unsigned char *data = cairo_image_surface_get_data(surf);
cairo_format_t format = cairo_image_surface_get_format(surf);
size_t datawidth = stride;
if (format == CAIRO_FORMAT_ARGB32 || format == CAIRO_FORMAT_RGB24)
datawidth = width*4;
else if (format == CAIRO_FORMAT_A8)
datawidth = width;
else if (format == CAIRO_FORMAT_A1)
datawidth = (width+31)/8 & ~4; // make sure this is rounded up to nearest four bytes
// This could be faster if done over 32 bit quantities
for (size_t y = 0; y < height; y++) {
unsigned char *line = data + y*stride;
for (size_t x = 0; x < datawidth; x++, line++)
*line = ~ *line;
}
cairo_surface_mark_dirty(surf);
return 0;
}
// Registration
static luaL_Reg rasterlib[] = {
{"gaussian_blur", gaussian_blur},
{"box3", box_blur<3,85>}, {"box5", box_blur<5,51>}, {"box15", box_blur<15,17>},
{NULL, NULL}
};
int luaopen_raster(lua_State *L)
{
luaL_register(L, "raster", rasterlib);
return 0;
}

30
OverLua/raster_ops.h Normal file
View file

@ -0,0 +1,30 @@
/*
* Raster image operations for OverLua
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
// Everything is implemented in the .cpp file as static functions.
int luaopen_raster(lua_State *L);

45
OverLua/readme.txt Normal file
View file

@ -0,0 +1,45 @@
OverLua is a plugin library that runs a Lua script to process video frames,
primarily intended to produce advanced overlay graphics. The target audience
is currently primarily programmers.
The name is intended as a pun on Overlay and Lua.
To help produce overlay graphics, OverLua provides an interface to the
Cairo vector graphics library. A library of functions to do raster-based
graphics processing is also included.
Curerently the only known-working plugin interface to OverLua is the Avisynth
interface. A CSRI interface is also included but it's neither tested nor
actively maintained. Patches to make the CSRI interface work are most welcome.
Further interfaces would also be appreciated, eg. one for mencoder.
The most thorough documentation is still the source code but I'm working on
throwing together something more useful. See the other text files included
in the distribution.
Notes on the pre-built DLL file
-------------------------------
The included pre-built DLL is compiled with Microsoft Visual C++ 2005 SP1
and so will require the runtime library for that version of the compiler.
You can download the required runtime library at this location:
<http://www.microsoft.com/downloads/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647&DisplayLang=en>
The DLL is built with SSE2 optimisations, meaning it will very likely crash
if you attempt to use it on a computer without SSE2 support.
Finally, the DLL is built with OpenMP optimisations enabled, which means it
will take advantage of multi-core and other SMP systems if available. The
OpenMP optimisations are only in the raster image filtering and the
Cairo surface/video frame interaction functions. If you do not use the raster
graphics operations much you won't see much gain from this SMP support either.
Licensing
---------
OverLua is licensed under version 2 of the GNU General Public License. This
means that you get no warranties of any kind.
See the file GPLv2.txt for details.

485
OverLua/video_frame.h Normal file
View file

@ -0,0 +1,485 @@
/*
* OverLua video frame access interface
*
Copyright 2007 Niels Martin Hansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Contact:
E-mail: <jiifurusu@gmail.com>
IRC: jfs in #aegisub on irc.rizon.net
*/
#ifndef VIDEO_FRAME_H
#define VIDEO_FRAME_H
#include "../lua51/src/lua.h"
#include "cairo_wrap.h"
#include <stddef.h>
#include <memory.h>
#include <stdint.h>
#include <omp.h>
// Forward
class OverLuaFrameAggregate;
// store a colour value
struct RGBPixel {
unsigned char r, g, b;
RGBPixel(unsigned char R, unsigned char G, unsigned char B) : r(R), g(G), b(B) { }
};
// Support any interleaved RGB format with 8 bit per channel
// You usually don't want to instance this class directly,
// look at OverLuaFrameAggregate defined below
template<ptrdiff_t Rpos, ptrdiff_t Gpos, ptrdiff_t Bpos, ptrdiff_t PixelWidth>
class OverLuaVideoFrame {
public:
typedef OverLuaVideoFrame<Rpos,Gpos,Bpos,PixelWidth> MyType;
// video properties
unsigned width;
unsigned height;
ptrdiff_t stride;
unsigned char *data;
// read a pixel value
inline const RGBPixel GetPixel(unsigned x, unsigned y)
{
RGBPixel res(0, 0, 0);
unsigned char *ptr = data + y*stride + x*PixelWidth;
res.r = ptr[Rpos];
res.g = ptr[Gpos];
res.b = ptr[Bpos];
return res;
}
// write a pixel value
inline void SetPixel(unsigned x, unsigned y, const RGBPixel &val)
{
unsigned char *ptr = data + y*stride + x*PixelWidth;
ptr[Rpos] = val.r;
ptr[Gpos] = val.g;
ptr[Bpos] = val.b;
}
OverLuaVideoFrame(unsigned _width, unsigned _height, ptrdiff_t _stride, unsigned char *_data)
: width(_width), height(_height), stride(_stride), data(_data)
{
owndata = false;
// nothing further to init
}
OverLuaVideoFrame(const MyType &src, bool copydata = false)
{
width = src.width;
height = src.height;
stride = src.stride;
owndata = copydata;
if (copydata) {
data = new unsigned char[height*stride];
memcpy(data, src.data, height*stride);
} else {
data = src.data;
}
}
~OverLuaVideoFrame()
{
if (owndata)
delete[] data;
}
// should never be called more than once on the same C++ object
void CreateLuaObject(lua_State *L, OverLuaFrameAggregate *aggregate = 0)
{
// create userdata object
MyType **ud = (MyType**)lua_newuserdata(L, sizeof(MyType*));
*ud = this;
// create metatable
lua_newtable(L);
lua_pushcclosure(L, lua_indexget, 0);
lua_setfield(L, -2, "__index");
lua_pushcclosure(L, lua_indexset, 0);
lua_setfield(L, -2, "__newindex");
lua_pushcclosure(L, lua_getpixel, 0);
lua_setfield(L, -2, "__call");
lua_pushcclosure(L, lua_finalize, 0);
lua_setfield(L, -2, "__gc");
if (aggregate) {
lua_pushlightuserdata(L, aggregate);
lua_setfield(L, -2, "videoframe");
}
lua_setmetatable(L, -2);
}
private:
bool owndata;
// set a pixel colour
static int lua_indexset(lua_State *L)
{
// first arg = object
// second arg = index
// third arg = value
MyType **ud = (MyType**)lua_touserdata(L, 1);
if (lua_isnumber(L, 2)) {
if (lua_istable(L, 3)) {
int n = (int)lua_tointeger(L, 2);
unsigned x = n % (*ud)->width;
unsigned y = n / (*ud)->width;
if (x < 0 || y < 0 || x >= (*ud)->width || y >= (*ud)->height) return 0;
// read first three entries from table
RGBPixel color(0,0,0);
lua_pushnil(L);
if (!lua_next(L, 3)) goto badtable;
if (!lua_isnumber(L, -1)) goto badtable;
color.r = (unsigned char)lua_tointeger(L, -1);
lua_pop(L, 1);
if (!lua_next(L, 3)) goto badtable;
if (!lua_isnumber(L, -1)) goto badtable;
color.g = (unsigned char)lua_tointeger(L, -1);
lua_pop(L, 1);
if (!lua_next(L, 3)) goto badtable;
if (!lua_isnumber(L, -1)) goto badtable;
color.b = (unsigned char)lua_tointeger(L, -1);
lua_pop(L, 2);
(*ud)->SetPixel(x, y, color);
return 0;
} else {
badtable:
lua_pushliteral(L, "Value set into video frame pixel must be a table with at least 3 entries");
lua_error(L);
return 0;
}
}
lua_pushliteral(L, "Undefined field in video frame");
lua_error(L);
return 0;
}
// get a pixel colour or some other property
static int lua_indexget(lua_State *L)
{
// first arg = object
// second arg = index
MyType **ud = (MyType**)lua_touserdata(L, 1);
if (lua_type(L, 2) == LUA_TSTRING) {
const char *fieldname = lua_tostring(L, 2);
if (strcmp(fieldname, "width") == 0) {
lua_pushnumber(L, (*ud)->width);
} else if (strcmp(fieldname, "height") == 0) {
lua_pushnumber(L, (*ud)->height);
} else if (strcmp(fieldname, "copy") == 0) {
lua_pushvalue(L, 1);
lua_pushcclosure(L, lua_copyfunc, 1);
} else if (strcmp(fieldname, "create_cairo_surface") == 0) {
lua_pushvalue(L, 1);
lua_pushcclosure(L, lua_create_cairo_surface, 1);
} else if (strcmp(fieldname, "overlay_cairo_surface") == 0) {
lua_pushvalue(L, 1);
lua_pushcclosure(L, lua_overlay_cairo_surface, 1);
} else {
lua_pushfstring(L, "Undefined field name in video frame: %s", fieldname);
lua_error(L);
}
return 1;
}
lua_pushfstring(L, "Unhandled field type indexing video frame: %s", lua_typename(L, lua_type(L, 2)));
lua_error(L);
return 0;
}
static int lua_getpixel(lua_State *L)
{
// first arg = object
// second arg = x
// third arg = y
MyType **ud = (MyType**)lua_touserdata(L, 1);
unsigned x = luaL_checkint(L, 2);
unsigned y = luaL_checkint(L, 3);
RGBPixel color(0,0,0);
if (x < 0 || y < 0 || x >= (*ud)->width || y >= (*ud)->height) {
// already black, leave it
} else {
// get it
color = (*ud)->GetPixel(x, y);
}
lua_pushinteger(L, color.r);
lua_pushinteger(L, color.g);
lua_pushinteger(L, color.b);
return 3;
}
static int lua_finalize(lua_State *L)
{
MyType **ud = (MyType**)lua_touserdata(L, 1);
delete *ud;
return 0;
}
static int lua_copyfunc(lua_State *L)
{
MyType **ud = (MyType**)lua_touserdata(L, lua_upvalueindex(1));
MyType *copy = new MyType(**ud, true);
copy->CreateLuaObject(L);
return 1;
}
static int lua_create_cairo_surface(lua_State *L)
{
MyType **ud = (MyType**)lua_touserdata(L, lua_upvalueindex(1));
// Create a new surface of same resolution
// Always RGB24 format since we don't support video with alpha
cairo_surface_t *surf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, (*ud)->width, (*ud)->height);
if (!surf || cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
lua_pushliteral(L, "Unable to create Cairo surface from video frame");
lua_error(L);
return 0;
}
// Prepare copying pixels from frame to surface
unsigned char *surfdata = cairo_image_surface_get_data(surf);
int surfstride = cairo_image_surface_get_stride(surf);
// Copy pixels
int height = (*ud)->height;
int width = (*ud)->width;
#pragma omp parallel for
for (int y = 0; y < height; y++) {
uint32_t *opix = (uint32_t*)(surfdata + y*surfstride);
for (int x = 0; x < width; x++) {
// Hoping this will get optimised at least a bit by the compiler
RGBPixel ipix = (*ud)->GetPixel(x, y);
*opix = ipix.r << 16 | ipix.g << 8 | ipix.b;
opix++;
}
}
cairo_surface_mark_dirty(surf);
// Create Lua object
LuaCairoSurface *lsurf = new LuaCairoSurface(L, surf);
// Release our reference to the surface
cairo_surface_destroy(surf);
// Return it to Lua
return 1;
}
static int lua_overlay_cairo_surface(lua_State *L)
{
// Get inputs
MyType **ud = (MyType**)lua_touserdata(L, lua_upvalueindex(1));
LuaCairoSurface *surfwrap = LuaCairoSurface::CheckPointer(*(void**)lua_touserdata(L, 1));
if (!surfwrap) {
lua_pushliteral(L, "Argument to frame.overlay_cairo_surface is not a Cairo surface");
lua_error(L);
return 0;
}
int xpos = luaL_checkint(L, 2);
int ypos = luaL_checkint(L, 3);
// More argument checks
cairo_surface_t *surf = surfwrap->GetSurface();
if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_IMAGE) {
lua_pushliteral(L, "Argument to frame.overlay_cairo_surface is not a Cairo image surface");
lua_error(L);
return 0;
}
// Prepare some data
int fwidth = (*ud)->width, fheight = (*ud)->height;
int swidth = cairo_image_surface_get_width(surf), sheight = cairo_image_surface_get_height(surf);
int sstride = cairo_image_surface_get_stride(surf);
// Prepare and get read pointer for source image
cairo_surface_flush(surf);
unsigned char *sdata = cairo_image_surface_get_data(surf);
// Check that the overlaid surface won't be entirely outside the frame
if (xpos <= -swidth || ypos <= -sheight || xpos > fwidth || ypos > fheight)
return 0;
// Pick overlay algorithm
cairo_format_t sformat = cairo_image_surface_get_format(surf);
if (sformat == CAIRO_FORMAT_ARGB32) {
// This has pre-multipled alpha
int fy = ypos; // frame y
int sy = 0; // source y
if (fy < 0) fy = 0, sy = -ypos;
int slines_to_compose = sheight-sy, flines_to_compose = fheight;
int lines_to_compose = (slines_to_compose<flines_to_compose)?slines_to_compose:flines_to_compose;
#pragma omp parallel for
for (int composition_line = 0; composition_line < lines_to_compose; composition_line++) {
uint32_t *sline = (uint32_t*)(sdata + sy*sstride);
int fx = xpos;
int sx = 0;
if (fx < 0) fx = 0, sx = -xpos;
for ( ; sx < swidth && fx < fwidth; fx++, sx++) {
RGBPixel pix = (*ud)->GetPixel(fx, fy);
unsigned char a = 0xff - ((sline[sx] & 0xff000000) >> 24);
pix.r = ((sline[sx] & 0x00ff0000) >> 16) + a*pix.r/255;
pix.g = ((sline[sx] & 0x0000ff00) >> 8) + a*pix.g/255;
pix.b = (sline[sx] & 0x000000ff) + a*pix.b/255;
(*ud)->SetPixel(fx, fy, pix);
}
fy++, sy++;
}
}
else if (sformat == CAIRO_FORMAT_RGB24) {
// Assume opaque alpha for all pixels
int fy = ypos; // frame y
int sy = 0; // source y
if (fy < 0) fy = 0, sy = -ypos;
int slines_to_compose = sheight-sy, flines_to_compose = fheight;
int lines_to_compose = (slines_to_compose<flines_to_compose)?slines_to_compose:flines_to_compose;
#pragma omp parallel for
for (int composition_line = 0; composition_line < lines_to_compose; composition_line++) {
uint32_t *sline = (uint32_t*)(sdata + sy*sstride);
int fx = xpos;
int sx = 0;
if (fx < 0) fx = 0, sx = -xpos;
for ( ; sx < swidth && fx < fwidth; fx++, sx++) {
RGBPixel pix(
(sline[sx] & 0x00ff0000) >> 16,
(sline[sx] & 0x0000ff00) >> 8,
sline[sx] & 0x000000ff);
(*ud)->SetPixel(fx, fy, pix);
}
}
}
else if (sformat == CAIRO_FORMAT_A8) {
// This one is problematic - it doesn't contain any colour information
// Two primary choices would be to fill with either black or white,
// but neither would be an optimum solution.
// A third option would be to take a fourth argument to this function,
// specifying the colour to be used.
lua_pushliteral(L, "8 bpp alpha images are not (yet) supported for overlay operations");
lua_error(L);
return 0;
}
else if (sformat == CAIRO_FORMAT_A1) {
lua_pushliteral(L, "1 bpp alpha images are not supported for overlay operations");
lua_error(L);
return 0;
}
else {
lua_pushliteral(L, "Unknown source image format for overlay operation");
lua_error(L);
return 0;
}
return 0;
}
};
// Now, escape from the template madness that is OverLuaVideoFrame.
// OverLuaFrameAggregate is the class that will be used for most passing around
// in the C++ code. It nicely hides all templatyness away into various implementations.
// This could probably have been designed better. Shame on me.
class OverLuaFrameAggregate {
public:
virtual RGBPixel GetPixel(unsigned x, unsigned y) = 0;
virtual void SetPixel(unsigned x, unsigned y, const RGBPixel &val) = 0;
virtual unsigned GetWidth() = 0;
virtual unsigned GetHeight() = 0;
virtual void CreateLuaObject(lua_State *L) = 0;
};
template <ptrdiff_t Rpos, ptrdiff_t Gpos, ptrdiff_t Bpos, ptrdiff_t PixelWidth>
class OverLuaFrameAggregateImpl : public OverLuaFrameAggregate {
public:
typedef OverLuaVideoFrame<Rpos, Gpos, Bpos, PixelWidth> VideoFrameType;
private:
VideoFrameType *frame;
bool ownframe;
public:
OverLuaFrameAggregateImpl(unsigned _width, unsigned _height, ptrdiff_t _stride, unsigned char *_data)
{
frame = new VideoFrameType(_width, _height, _stride, _data);
ownframe = true;
}
OverLuaFrameAggregateImpl(VideoFrameType *_frame)
{
frame = _frame;
ownframe = false;
}
RGBPixel GetPixel(unsigned x, unsigned y)
{
return frame->GetPixel(x, y);
}
void SetPixel(unsigned x, unsigned y, const RGBPixel &val)
{
frame->SetPixel(x, y, val);
}
unsigned GetWidth()
{
return frame->width;
}
unsigned GetHeight()
{
return frame->height;
}
void CreateLuaObject(lua_State *L)
{
frame->CreateLuaObject(L, this);
}
};
// All common, sensible formats
typedef OverLuaFrameAggregateImpl<2, 1, 0, 3> OverLuaVideoFrameBGR;
typedef OverLuaFrameAggregateImpl<2, 1, 0, 4> OverLuaVideoFrameBGRX;
typedef OverLuaFrameAggregateImpl<2, 1, 0, 4> OverLuaVideoFrameBGRA;
typedef OverLuaFrameAggregateImpl<0, 1, 2, 3> OverLuaVideoFrameRGB;
typedef OverLuaFrameAggregateImpl<0, 1, 2, 4> OverLuaVideoFrameRGBX;
typedef OverLuaFrameAggregateImpl<0, 1, 2, 4> OverLuaVideoFrameRGBA;
typedef OverLuaFrameAggregateImpl<1, 2, 3, 4> OverLuaVideoFrameXRGB;
typedef OverLuaFrameAggregateImpl<1, 2, 3, 4> OverLuaVideoFrameARGB;
typedef OverLuaFrameAggregateImpl<3, 2, 1, 4> OverLuaVideoFrameXBGR;
typedef OverLuaFrameAggregateImpl<3, 2, 1, 4> OverLuaVideoFrameABGR;
#endif