Basically, AviSynth works like this: First, you create a simple text document with special commands, called a script. These commands make references to one or more videos and the filters you wish to run on them. Then, you run a video application, such as VirtualDub, and open the script file. This is when AviSynth takes action. It opens the videos you referenced in the script, runs the specified filters, and feeds the output to video application. The application, however, is not aware that AviSynth is working in the background. Instead, the application thinks that it is directly opening a filtered AVI file that resides on your hard drive.
There is much new and re-discovered functionality in AviSynth2. To make those
items clearly visible (especially when the feature was not well documented in
the past) they are marked with
v2
Linear Editing:
The simplest thing you can do with AviSynth is the sort of editing you can do in VirtualDub. The scripts for this are easy to write because you don't have to worry about variables and complicated expressions if you don't want.
For testing create a file called test.avs and put the following single line of text in it:
Version |
Now open this file with e.g. Windows Media Player and you should see a ten-second video clip showing Avisynth's version number and a copyright notice.
Version is what's called a "source filter", meaning that it generates a clip instead of modifying one. The first command in an Avisynth script will always be a source filter.
Now add a second line to the script file, so that it reads like this:
Version ReduceBy2 |
Reopen the file in Media Player. You should see the copyright notice again,
but now half as large as before.
ReduceBy2 is a "transformation filter," meaning that it takes
the previous clip and modifies it in some way. You can chain together lots of
transformation filters, just as in VirtualDub.
Let's add another one to make the video fade to black at the end. Add another
line to the script file so that it reads:
Version ReduceBy2 FadeOut(15) |
Now reopen the file. The clip should be the same for the first 9 seconds, and
then in the last second it should fade smoothly to black.
The FadeOut filter takes a numerical argument, which indicates the
number of frames to fade. The video generated by Version happens to
run at 15fps, so an argument of 15 to FadeOut makes the fade start
one second from the end.
It takes a long time before the fade starts, so let's trim the beginning of
the clip to reduce the wait. The clip produced by Version is 150 frames
long (15 fps times 10 sec).
Avisynth starts numbering frames from 0.
So the frames are 0 through 149. FadeOut happens to add one extra frame,
so at the end of this script so far, the frames run from 0 to 150. Let's discard
the first 120 of them:
Version ReduceBy2 FadeOut(15) Trim(120,150) # chop off the first eight seconds |
In this example we used a comment for the first time.
Comments start with the # character and continue to the end of the line, and
are ignored completely by Avisynth.
The Trim filter takes two arguments, separated by a comma: the first
and the last frame to keep from the clip. If you put 0 for the last frame, it's
the same as "end of clip," so this trim command could just as easily
have been written Trim(120,0).
Keeping track of frame numbers this way is a chore. It's much easier to open a partially-completed script in an application like VirtualDub which will display the frame numbers for you. You can also use the ShowFrameNumber filter, which prints each frame's number onto the frame itself.
In practice a much more useful source filter than Version is AVISource,
which reads in an AVI file (or one of several other types of files) from disk.
If you have an AVI file handy, you can try applying these same filters to your
file:
AVISource("d:\capture.avi") # or whatever the actual pathname is ReduceBy2 FadeOut(15) Trim(120,0) |
Even a single-line script containing only the AVISource command can be useful for adding support for >2GB AVI files to applications which only support <2GB ones.
Non-Linear Editing:
Now we're getting to the fun part. Make an AVS file with the following script in it:
StackVertical(Version, Version) |
Now open it. Result: An output video with two identical lines of version information,
one on top of the other.
Instead of taking numbers or strings as arguments, StackVertical takes
video clips as arguments. In this script, the Version filter is being called
twice. Each time, it returns a copy of the version clip. These two clips are
then given to StackVertical, which joins them together (without knowing
where they came from).
One of the most useful filters of this type is UnalignedSplice, which joins video clips end-to-end. Here's a script which loads three AVI files (such as might be produced by AVI_IO) and concatenates them together.
UnalignedSplice(AVISource("d:\capture.00.avi"), AVISource("d:\capture.01.avi"), AVISource("d:\capture.02.avi")) |
Both StackVertical and UnalignedSplice can take as few as
two arguments or as many as sixty.
You can use the + operator as a shorthand for UnalignedSplice.
For example, this script does the same thing as the previous example:
AVISource("d:\capture.00.avi") + AVISource("d:\capture.01.avi") + AVISource("d:\capture.02.avi") |
Now let's suppose you're capturing with an application that also saves the
video in multiple AVI segments, but puts the audio in a separate WAV file.
Can we recombine everything? You bet:
AudioDub(AVISource("d:\capture.00.avi")+AVISource("d:\capture.01.avi")+AVISource("d:\capture.02.avi"), WAVSource("d:\audio.wav")) |
Expressions:
An Avisynth script consists of multiple lines of statements looking like this:
variable_name = expression |
In this example expression is evaluated and the result is assigned to variable_name.
Very important is the common shortcut form:
expression |
In this case, expression is evaluated and the result is assigned to the special
clip variable last.
This is the same as
last = expression |
The end of the script always looks like:
return expression |
Here expression is evaluated and is used as the "return value" of the script--that is, the video clip that will be seen by the application which opens the AVS file.
The basic form of an expression which invokes a function is
Function(args) |
Clip functions always produce a new video clip and never modify an existing
one,
Args is a list of function arguments separated by commas. The list can be empty
(which means all or some arguments can be optional).
AviSynth supports a maximum of 1024 arguments.
If the filter function expects a video clip as its first argument, and that argument is not supplied, then the clip in the special variable last will be used.
Avisynth filters can take named arguments. The named arguments can be specified
in any order,
and the filter will choose default values for any that you leave off (named
arguments are always optional).
This makes certain filters much easier to use.
You can write Subtitle("Hello, World!", text_color=$00FF00, x=100, y=200) instead of Subtitle("Hello, World!", 100, 200, 0, 999999, "Arial", 24, $00FF00) |
An alternate syntax (called "OOP notation") for clip functions is
expression.Function(args) |
This is equivalent to
Function(expression, args) |
and can be thought of Function applied to expression.
One disadvantage of OOP notation is that it can only be used with filters which
take a single video-clip argument, not with filters which take several.
All avisynth functions produce defined number of output frames and framerate,
even if the statement seems very complex.
Avisynth knows after having read the script how long the output will be, which
framerate it has and the "cutting sequence" of all used inputs
This is all calculated on opening the script. Only the actual filtering is done
runtime on request.
Comments: Avisynth ignores anything from a # character to the end of that line.
Ignore Case: aViSouRCe is just as good as AVISource.
Continue on next or from previous line: \
Subtitle ("Test-Text") |
Subtitle ( \ "Test-Text") |
Subtitle ( \ "Test-Text") |
Variables:
A variable name can be up to 50 characters long and can contain letters, digits,
and underscores (_), but no other characters. The name cannot start with a digit.
The following types of variables can be used:
clip: a video clip containing video and / or audio. At least one variable
for a clip must be used and returned by the script.
string: surrounded either by "quotation marks" or by ``TeX-style quotes''.
A text string can contain any character except the terminating quotation mark
or double-apostrophe. If you need to put a quotation mark inside a string, use
the TeX-style notation. Alternately, you can use Windows extended-ASCII curly-quotes
instead of straight quotes to get around this limitation.
int: entered as a string of digits, optionally with a + or - at the
beginning.
float: entered as a string of digits with a period (.) somewhere in
it and an optional + or -. For example, +1. is treated as a floating-point number.
val: as type of a function argument where it does not matter if it
is int or float
bool : can be TRUE or FALSE
hexadecimal numbers: entered by preceding it with a $. This variable
is treated as an integer. Several filters use this notation for specifying colors.
For example, $FF8800 is a shade of orange.
global: defines a global variable, which can be used by all user-defined
functions and the main script in common. v2
Here's another version of the example from above that's more manageable and
easier to understand:
a = AVISource("d:\capture.00.avi") b = AVISource("d:\capture.01.avi") c = AVISource("d:\capture.02.avi") sound_track = WAVSource("d:\audio.wav") AudioDub(a+b+c, sound_track) |
For all types of operands (clip, int, float, string, bool) you can use:
== is equal
!= not equal
|| or
&& and
For numeric types (int, float):
+ add
- subtract
* multiply
/ divide
% mod
>= greater or equal than
<= less or equal than
< less than
> greater than
AviSynth parses expressions from right to left, which can give unexpected results: a = 10 - 5 - 5 gives 10 - (5 - 5) = 10 ! b = 100. / 2. / 4. gives 100. / (2. / 4.) = 200 ! |
For string type:
+ add
>= greater or equal than (case-insensitive)
<= less or equal than (case-insensitive)
< less than (case-insensitive)
> greater than (case-insensitive)
For clip type:
+ the same as the function UnalignedSplice
++ the same as the function AlignedSplice
For bool type:
?: execute code conditionally
b = (a==true) ? 1 : 2 |
The input and output of these functions are not clips, but some other variables used in the script.
Numerical functions:
Floor (float): converts from float to int | Floor(1.2) = 1 Floor(1.6) = 1 Floor(-1.2) = -2 Floor(-1.6) = -2 |
Ceil (float): converts from float to int | Ceil(1.2) = 2.0 Ceil(1.6) = 2.0 Ceil(-1.2) = -1 Ceil(-1.6) = -1 |
Round (float): converts from float to int | Round(1.2) = 1 Round(1.6) = 2 Round(-1.2) = -1 Round(-1.6) = -2 |
Int(float): converts a float to int (rounds down). v2.07 | Int(1.2) = 1 Int(1.6) = 1 Int(-1.2) = -1 Int(-1.6) = -1 |
Float(int): converts an int to a float. v2.07 | |
Frac(float): returns the fraction of the float. v2.07 | Frac(3.7) = 0.7 Frac(-1.8) = -0.8 |
Abs (integer) / Abs(float): absolute
value for integer and float. v2.07 |
Abs(-3.8) = 1.8 |
Sign(int) / Sign(float): returns the sign
of the number as -1, 0 or 1. v2.07 |
Sign(-3.5) = -1 Sign(3.5) = 1 Sign(0) = 0 |
HexValue(string) Returns the value of a hex string. v2.07 | HexValue ( "FF00" ) = 65280 |
Sin (float) v2 | |
Cos (float) v2 | |
Pi () v2 | |
Log (float) v2 | |
Exp (float) v2 | |
Pow (float base, float power) v2 | |
Sqrt (float} v2 | |
Rand([int max] [,bool scale] [,bool seed]): returns
random integer between 0 and max. v2.07 defaults: max = 32768 scale = TRUE ( TRUE = normal mode, FALSE = modulus mode) seed = FALSE (TRUE = use time as seed) |
Rand(100) = integer number between 0 and 99 |
String functions:
UCase(string): returns the string in uppercase v2.07 | UCase("AviSynth") = "AVISYNTH" |
LCase(string): returns the string in lowerrcase v2.07 | LCase("AviSynth") = "avisynth" |
RevStr(string): returns the string in reverse. v2.07 | RevStr("AviSynth") = "htnySivA" |
StrLen(string): returns the length of string. v2.07 | StrLen("AviSynth") = 8 |
Findstr(string1,string2):
v2.07 returns the offset of string2 inside string1. The search is case-sensitive. |
Findstr("AviSynth","syn") = 4 |
LeftStr(string, length) / RightStr(string,
length): v2.07 returns left or right portion of string specified by length |
LeftStr("AviSynth",3) = "Avi" |
MidStr(string, start [,length]):
v2.07 returns portion of string starting at start (for the first character start=1) for the number of characters specified by length or to the end. |
MidStr("AviSynth",3,2) = "iS" |
VersionNumber() v2.07 |
VersionNumber() = 2.07 |
VersionString() v2.07 | VersionString() = "AviSynth 2.08 (avisynth.org) 22 nov. 2002" |
Conversions:
Value(string) Returns the value of an string. v2.07 | Value( "-2.7" ) = 2.7 |
String (float / int / string): converts a number to a string. v2 | e.g.Subtitle( "Clip height is " + String(last.height) ) |
Test functions:
IsBool (var)
IsInt (var)
IsFloat (var)
IsString (var)
IsClip (var)
Other functions:
Select(index, item0 [,item1...]). Returns item selected by the index
(0=item0). Items can be any variable or clip and can even be mixed.
v2.07
Defined (var): for defining optional parameters in user-defined
functions.
Default (x,d): returns x if Defined(x), d otherwise.
Exist(filename): returns TRUE or FALSE after checking if the file exists
v2.07
NOP returns NULL, provided mainly for conditional execution with non-return
value items such as import and no "else" condition desired.
v2.07
Eval (string)
Apply (func-string,arg,...): Eval("f(x)") is equivalent to f(x) is
equivalent to Apply("f", x))
You can use Eval for something like: |
Import (filename): evals contents of another avisynth script (imports the text of another script)
For error reporting and catching bad input to user-defined function you can
use:
Assert (bool, string error-message): for error reporting
AssertEval (string)
There is a function for checking if an error WILL arise:
Try { AviSource("file.avi") } catch(err_msg) { Blackness.Subtitle(err_msg) } |
SetMemoryMax(int): Sets the maximum memory that AviSynth uses (in
MB)
v2
In some versions there is a default setting of 5MB, which is quite low. If you
encounter problems (e.g. low speed) try to set this values to at least 32MB.
SetWorkingDir(string): Sets the default directory for Avisynth.
v2
This is primarily for easy loading of source clips, etc. Does not affect plugin
autoloading. Return value: 0 if successful, -1 otherwise.
Width (clip)
Height (clip)
Framecount (clip)
Framerate (clip)
Audiorate (clip)
Audiolength (clip)
Audiochannels (clip)
Audiobits (clip)
IsRGB (clip)
IsRGB24 (clip) v2.07
IsRGB32 (clip) v2.07
IsYUY2 (clip)
IsRGB24(clip) (clip)
IsRGB32(clip) (clip)
IsFieldBased (clip)
IsFrameBased (clip)
GetParity (clip)
Don't forget: you can use the Properties with the implicit variable LAST or in OOP-notation: |
You can define your own functions. This is best explained by an example:
Function NTSC2PAL( clip c) { Assert(c.height == 480, "NTSC2PAL: input clip must have 480 scan lines") Bob(c, height=576) return Weave() } |
Even recursive functions can be defined.
function TRANSITION(clip clip, int start, int expo, int overlap) { return ( start >= clip.framecount-expo ? \ Trim(clip,start,0) : \ Dissolve(Trim(clip,start,start+expo-1), \ TRANSITION(clip,start+expo,expo,overlap), \ overlap \ ) } |
Functions with more than one input clip
There are some functions which combine two or more clips in different ways. How the video content is calculated is described for each function, but here is a summary which properties the result clip will have.
The input clips must always have the same color format and - with the exception of Layer - the same dimensions.
frame-rate
|
frame-count
|
audio content
|
audio sampling rate
|
||
AlignedSplice, UnalignedSplice |
first clip
|
sum of all clips
|
see filter description
|
first clip
|
|
Dissolve |
sum of all clips minus the overlap
|
see filter description
|
|||
MergeLuma, MergeChroma |
first clip
|
the last frame
of the shorter clip is repeated until the end of the clip |
first clip
|
||
Layer | |||||
Subtract |
longer clip
|
||||
StackHorizontal, StackVertical | |||||
Interleave |
(fps of first clip)
x (number of clips) |
2x frame-count of longer clip
|
As you can see the functions are not completely symmetric but take some attributes from the FIRST clip.
With these functions you can add external functions to AviSynth.
The order in which same-named functions are called is:
v2
1. Functions from external plugins
2. User-defined functions
3. Build-in functions
LoadPlugin ("filename"[,...])
Loads one or more external avisynth plugins (DLLs).
LoadVirtualDubPlugin ("filename","filtername", preroll)
This loads a plugin written for VirtualDub. "filename" is the name of the .vdf file. After calling this function, the filter will be known as "filtername" in avisynth. VirtualDub filters only supports RGB32. If the video happens to be in RGB24-format, then you must use ConvertToRGB32 (ConvertToRGB won't suffice).
Some filters output depends on previous frames; for those preroll should be set to at least the number of frames the filter needs to pre-process to fill its buffers and/or updates its internal variables.
LoadVFAPIPlugin ("filename","filtername")
This allows you to use VFAPI plugins (TMPGEnc import plugins).
Plugin autoload and name precedence v2
It is possible to put all plugins and script files with user-defined functions or (global) variables in a directory from where all files with the extension .AVSI, .DLL and .VDF are loaded at startup, unloaded and then loaded dynamically as the script needs them (AVSI is used for scripts specially designed as import function).
Scripts in this directory should only contain function definitions and global variables, no main processing section (else strange errors may occur), it also is not recommended to put other files in that directory.
The directory is stored in the registry. You can use double-clicking a .REG-file with the following lines to set the path (of course inserting your actual path):
REGEDIT4 [HKEY_LOCAL_MACHINE\SOFTWARE\Avisynth] "PluginDir"="c:\\program files\\avisynth\\plugins" |
The order in which function names take precedence is as follows:
plugin-function (always have the highest priority) user-defined function (have higher priority than built-in functions - you can override a built-in function) built-in function
Inside those groups the function loaded at last takes precedence, there is no error in a namespace conflict.