Advanced Scripting in AVISynth

This guide will cover more complicated and interesting ways in which you can script things in AVISynth. Since we're beyond the whole introduction here, I will dispense with trying to come up with logical reasons to do what I'm doing, and just do them for the sake of showing you what can be done. :)

For some framerate altering scripts, see AD's additions below.

So lets say I want to put Kevin Caldwell's Engel right after his Believe video and play them in one file. I've got Engel sitting as an AVI file on my hard drive, and it's already in 320x240 resolution and it's at 29.97 frames per second just like my Believe file is.

I'll try to create an AVS file that says this:

DirectShowSource("d:\believe.mpg") + AVISource("D:\engel.avi")

The + basically says take these two things and tack the second one onto the end of the first one. In fact, the + is an alias for AlignedSplice() - i.e. The code:

AlignedSplice(DirectShowSource("D:\believe.mpg"),AVISource("D:\engel.avi")

...would do the exact same thing, except it's much less readable. :)

But uh oh! It didn't work. Why is that?

Well since Believe is in 352x240 resolution and Engel is in 320x240, AVISynth can't combine them! So how can I get them to fit together? Well I can make the script look like this:

DirectShowSource("d:\believe.mpg").BicubicResize(320,240) + AVISource("D:\engel.avi")

The dot-notation is also an alias. Doing Source.Transform(options) is the same thing as doing Transform(options,source) so in this case the above code is the same as:

AlignedSplice(BicubicResize(320,240,DirectShowSource("D:\believe.mpg")),AVISource("D:\engel.avi")))

Yuck. Now is that ugly or what?

However this time it works, because all the various properties of the files match up. So remember that you can only splice clips together which are the same resolution, framerate, and in the same colorspace.

So with my newfound knowledge, I decide to make an AVISynth playlist of several of my new XviD encodes of my videos to make a video reel. However, not all my files are the same resolution and framerate and they all have my bumper attached to the front. Sure, I love my bumper and it's cool, but I wouldn't want to watch it 4 times in between every video. :)

So lets say I want to take Closer To God 2 (512x272, 29.97fps), Cowboy Blues (480x360, 23.976fps), Go Speed Go (480x360, 29.97fps) and Evil Light (512x272, 23.976fps) and stick them all together into the same file. This could take some work! So how can I do this? Well to make things easier to deal with, I can use variables.

Just like in a programming language, you can use variables to store various things and then call upon them later. For instance, if I wanted to use StackHorizontal on two clips in order to see the effect of a FieldDeinterlace filter side-by-side with the original, I could do the following:

before = AVISource("testclip.avi")
after = AVISource("testclip.avi").FieldDeinterlace()
StackHorizontal(before,after)

That is essentially the same thing as saying:

StackHorizontal(AVISource("testclip.avi"),AVISource("testclip.avi").FieldDeinterlace())

...but the first way is a heck of a lot easier to read and understand what's going on!

So now I will take my various clips and turn them all into the same resolution and the same framerate. First off, I'll abstract the sources to variables so I don't get confused.

a = AVISource("D:\ErMaC Studios - Closer to God 2.avi")
b = AVISource("D:\ErMaC Studios - Cowboy Blues.avi")
c = AVISource("D:\ErMaC Studios - Go Speed Go.avi")
d = AVISource("D:\ErMaC Studios - Evil Light.avi")

Now I need to convert the resolutions and framerates to be the same. First I will enlarge the smaller videos to be 512x384.

b = b.BicubicResize(512,384)
c = c.BicubicResize(512,384)

Note how I am reassigning the values of the variables. After this, the value of "b" is actually AVISource("D:\ErMaC Studios - Cowboy Blues.avi").BicubicResize(512,384)!

Now I also want to add black borders to the two widescreen videos. I'll use the "AddBorders" command to do that:

a = a.AddBorders(0,56,0,56)
d = d.AddBorders(0,56,0,56)

Now all my videos are in 512x384 resolution. But what about the two videos that are in the wrong framerate? Well I can use AVISynth's ChangeFPS() command which will duplicated or decimate frames to match whatever new framerate I want.

b = b.ChangeFPS(29.97)
d = d.ChangeFPS(29.97)

Now I've got all my files in the same resolution and framerate, so I can splice them together without getting errors.

"But wait!" you cry. "What of your dreaded bumper and it's impending doom?" Ah yes I'd almost forgotten the bumper! Well, since I'm trying to show all the superneato stuff you can do with AVISynth, I think I'll write a function to remove the bumper. Yep - you can actually write functions within AVISynth. No, this isn't just for show, it can actually be very useful.

So I'll write a function that returns a clip after Trimming the first 484 frames off of it (since that's how long my bumper is in 29.97fps). I'll shorten TrimBumper to TB for ease of typing later:

function TB(clip input)
{
return input.Trim(484,0)
}

Now that I've written this function, I can apply it to each of the video sources and splice them all together, then output the result:

return a.TB() + b.TB() + c.TB() + d.TB()

and tada! My script is done. For a complete rundown, here is the final script in its entirity:

function TB(clip input)
{
return input.Trim(484,0)
}
a = AVISource("D:\ErMaC Studios - Closer to God 2.avi")
b = AVISource("D:\ErMaC Studios - Cowboy Blues.avi")
c = AVISource("D:\ErMaC Studios - Go Speed Go.avi")
d = AVISource("D:\ErMaC Studios - Evil Light.avi")
b = b.BicubicResize(512,384)
c = c.BicubicResize(512,384)
a = a.AddBorders(0,56,0,56)
d = d.AddBorders(0,56,0,56)
b = b.ChangeFPS(29.97)
d = d.ChangeFPS(29.97)
return a.TB() + b.TB() + c.TB() + d.TB()

Note that I moved the function up to the top since that's the best place for defining functions, but it could go anywhere in the script as long as it's before the first time TB() is used.

If you'd like to see the nastiest AVISynth script I've ever written, here it is. It was a script which I fed into an MPEG2 encoder to make my own Read or Die subtitled, progressive DVD. It looks fantastic, BTW :D

function Sub(clip clip, string filename)
{
LoadVirtualdubPlugin("C:\program files\virtualdub\plugins\subtitler.vdf", "_VD_Subtitler")
return clip._VD_Subtitler(1, filename, 0, 0)
}
LoadPlugin("D:\MPEG2DEC.DLL")
LoadPlugin("D:\Decomb.DLL")
rod1 = MPEG2Source("E:\ReadOrDie1DVD\rod1.d2v").Telecide(chroma=true,post=false,threshold=35).Decimate(cycle=5).ConvertToRGB().Sub("E:\ReadOrDie1DVD\Read Or Die Ep 01 [FINAL 230601].ssa")
rod2 = MPEG2Source("E:\rod2.d2v").Telecide(chroma=true,post=false,threshold=35).Decimate(cycle=5).ConvertToRGB().Sub("E:\ReadOrDie2DVD\RoD2.v5.Edit.silencer.ssa")
rod3 = MPEG2Source("E:\ReadOrDie3DVD\rod3.d2v").Telecide(chroma=true,post=false,threshold=35).Decimate(cycle=5).ConvertToRGB().Sub("E:\ReadOrDie3DVD\ROD3-Edit4.ssa")

return rod1 + BlankClip(length=3,height=480,width=720,fps=23.976,audio_rate=0) + rod2 + rod3

Framerate and format conversion scripts:

All of which you can probably work out for yourself, but useful for reference:

Converting Film Footage at 23.976fps to Interlaced 29.97fps

AssumeFrameBased
SeparateFields
SelectEvery(8, 0,1, 2,3,2, 5,4, 7,6,7)
Weave

This produces Bottom Field First interlaced footage, if you need Top Field First then do:

AssumeFrameBased
ComplementParity
SeparateFields
SelectEvery(8, 0,1, 2,3,2, 5,4, 7,6,7)
Weave

Converting Progressive PAL to NTSC (will desync audio)

AssumeFPS(23.976)
AssumeFrameBased
SeparateFields
SelectEvery(8, 0,1, 2,3,2, 5,4, 7,6,7)
Weave
LanczosResize(720,480)

Converting Interlaced PAL to NTSC (will desync audio, other methods also work)

Telecide()
Decimate(mode=1)
AssumeFPS(23.976)
AssumeFrameBased
SeparateFields
SelectEvery(8, 0,1, 2,3,2, 5,4, 7,6,7)
Weave
LanczosResize(720,480)