As everybody using Avisynth knows, arrays are not supported natively by the scripting language.

However, a library named [AVSLib] exists that provides a functional interface for creating and manipulating arrays. Coupled with Avisynth's OOP style for calling functions, one can treat arrays as objects with methods, which is a familiar and easy to understand and code scripting concept.

Therefore, two preparatory steps are needed before being able to create and manipulate process arrays into your script:

Now you are ready to create your first array! In order to provide an almost real case example let's assume the following (which are commonplace in many situations) about the script you want to create:

Having done that, let's proceed to the actual code:


First, we create the array; ..1.., ..2.., etc. are actual filename strings. Clip loading is made by AviSource in the example but DirectShowSource may also be specified.

inp = ArrayCreate( \
    AVISource(..1..), \
    AVISource(..2..), \
    ... \
    AVISource(..n..) )

Then we convert to same fps, audio, colorspace and size by using AssumeFPS, ConvertAudioTo16bit, ConvertToYV12 and BilinearResize respectively. We use OOP + chaining to make compact expressions.

Note that since Avisynth does not provide a way for in-place variable modification we must reassign to an array variable after each array operation (usually the same).

inp = inp.ArrayOpFunc("AssumeFPS", "24").ArrayOpFunc("ConvertAudioTo16bit" \
    ).ArrayOpFunc("ConvertToYV12").ArrayOpFunc("BilinearResize", "640,480")

To perform trimming we will use arrays of other types also. Below ts stands for first frame to trim, te for last; each number corresponds to a clip in inp variable.

ts = ArrayCreate(12, 24, ..., 33) # n numbers in total
te = ArrayCreate(8540, 7834, ..., 5712) # n numbers in total

We also need a counter to make things easier; we will use [ArrayRange] to create an array of 0,1,2,...

cnt = ArrayRange(0, inp.ArrayLen()-1)

In addition we must define a user function that will accept inp, ts, te and cnt and do the trimming.

Since [ArrayOpArrayFunc] only accepts two arrays for per-element processing, it is easier to pass inp and cnt as array elements and ts, te as entire arrays.

Function MyTrim(clip c, int count, string fs, string fe) {
    return c.Trim(fs.ArrayGet(count), fe.ArrayGet(count))
}

Now we are ready to do the trim (line below).

inp = ArrayOpArrayFunc(inp, cnt, "MyTrim", StrQuote(ts)+","+StrQuote(te))

We will finish the processing with a final tweak on brightness with different settings on each clip and on hue with same settings for all clips.

bright = ArrayCreate(2.0, 1.5, ..., 3.1) # n numbers in total
 
Function MyTweak(clip c, float br) { return c.Tweak(bright=br, hue=12.3) }
 
inp = ArrayOpArrayFunc(inp, bright, "MyTweak") 

And now we are ready to combine the results and return them as script's output. We will use Dissolve for a smoother transition.

return inp.ArraySum(sum_func="Dissolve", sum_args="5")

This is it; the n input clips have been converted to a common video and audio format, trimmed and tweaked with individual settings and returned as a single video stream with only 11 lines of code (excluding comments).

Other types of array processing are also possible (slicing ie operation on a subset of elements, joining, multiplexing, etc.) but these are topics to be discussed in other pages. Those that are interested can browse the [AVSLib documentation].

A final note, relating to memory usage is the following:

Because most of the array functions above create copies of the initial clips (since they don't know where the result will be assigned) it is possible that one may run into memory shortage if the clips are large or there is a large number of them. The workaround is to combine the chained calls to filters into a single user function; you save one array copy for each filter call entered to the user function after the first one.

The following example, which is the same as above stripped by most of the comments plus the workaround, illustrates the concept. In addition, to make the argument list shorter some arrays were declared global:


inp = ArrayCreate( \
    AVISource(..1..), \
    AVISource(..2..), \
    ... \
    AVISource(..n..) )     # n clips in total
cnt = ArrayRange(0, inp.ArrayLen()-1)

global ts = ArrayCreate(12, 24, ..., 33) # n numbers in total
global te = ArrayCreate(8540, 7834, ..., 5712) # n numbers in total
global br = ArrayCreate(2.0, 1.5, ..., 3.1) # n numbers in total

Function MyFilterTrimTweak(clip c, int count) {
    c = c.AssumeFPS(24).ConvertAudioTo16bit().ConvertToYV12( \
        ).BilinearResize(640,480)
    c = c.Trim(ts.ArrayGet(count), te.ArrayGet(count))
    return c.Tweak(bright=br.ArrayGet(count), hue=12.3)
}

inp = ArrayOpArrayFunc(inp, cnt, "MyFilterTrimTweak")
return inp.ArraySum(sum_func="Dissolve", sum_args="5")

Note: This article has been based on documentation from AVSLib [website]; thus derivative works should follow the [initial licence] (FDL).

Back to IntermediateTips