A previous post gave an average tutorial on how to glitch motion vectors by using an average of motion vectors.

A lot has changed since then, and ffglitch (starting with version 0.10.0) now has optimized code to speed up array manipulations and calculations in JavaScript. You can check out the documentation (yes, there is documentation now!) to check the full extent of the added functionality.

Here’s the original video again:

And the optimized script mv_average_010.js:

// global variable holding forward motion vectors from previous frames
let prev_fwd_mvs = [ ];
let total_sum;

// change this value to use a smaller or greater number of frames to
// perform the average of motion vectors
// you can also change it using the `-sp <num>` command line option
let tail_length = 10;
let tail_length_mv;

export function setup(args)
{
    // select motion vector feature
    args.features = [ "mv" ];

    // parse tail_length param from command line if available
    if ( "params" in args )
        tail_length = args.params;
    tail_length_mv = MV(tail_length, tail_length);
}

export function glitch_frame(frame)
{
    // bail out if we have no forward motion vectors
    const fwd_mvs = frame.mv?.forward;
    if ( !fwd_mvs )
        return;

    // set motion vector overflow behaviour in ffedit to "truncate"
    frame.mv.overflow = "truncate";

    // update variable holding forward motion vectors from previous
    // frames. note that we perform a deep copy of the clean motion
    // vector values before modifying them.
    const deep_copy = fwd_mvs.dup();
    // push to the end of array
    prev_fwd_mvs.push(deep_copy);

    // initialize total_sum to a [0,0] MV2DArray.
    if ( !total_sum )
        total_sum = new MV2DArray(fwd_mvs.width, fwd_mvs.height);

    // update total_sum by removing the motion vector values from the
    // oldest frame and adding the values from the current frame.
    if ( prev_fwd_mvs.length > tail_length )
    {
        total_sum.sub(prev_fwd_mvs[0]);
        prev_fwd_mvs = prev_fwd_mvs.slice(1);
    }
    total_sum.add(deep_copy);

    // set new values for current frame to (total_sum / tail_length)
    if ( prev_fwd_mvs.length == tail_length )
    {
        fwd_mvs.assign(total_sum);
        fwd_mvs.div(tail_length_mv);
    }
}

Now run ffedit with mv_average_010.js to glitch the file:

$ ffedit -i trompette_eating.mpg -s mv_average_010.js -sp 10 -o trompette_eating_glitched.mpg

(note the -sp 10 script parameter, which can be used to set tail_length inside the script from the command line. check the ffedit documentation for more information on command line parameters)

And this is the resulting trompette_eating_glitched.mpg:

Prior to 0.10.0, with the old version of the script, I used to get around 15 fps. With the optimized script, I get around 300 fps.

That’s a whopping 20x speedup!