Introduction

One of the most used features of ffglitch is the ability to tinker around with motion vectors in MPEG-2 files.

I’m not going to go in full details explaining what motion vectors are but basically they describe movements between frames in video files. If we alter those values, we can make all sorts of funky glitches.

In this post I will show how to do this with a very simple script.

0 - Generate input file

First and foremost, we want to be playing around with a file that does have motion vectors. Usually the encoder will not write motion vectors to the bitstream if there are no motion vectors to write (duh), but we want to force them everywhere. We also want to force that no I macroblocks will be written to the bitstream in P frames (no need to understand this now). We also want to make sure we have a long run of P frames, because I frames effectively deglitch the video, and we don’t want that to happen.

All of this preparation can be done with the modified ffmpeg build that comes with ffglitch. Run the following command line, replacing input_file with the original video file you want to glitch, and temp_file.mpg with a filename that will be used as your input to glitch.

$ ./ffmpeg -i input_file -an -mpv_flags +nopimb+forcemv -qscale:v 0 -g 1000 -vcodec mpeg2video -f rawvideo -y temp_file.mpg

Great! Now you have an MPEG-2 file ready to be glitched (it’s temp_file.mpg).

For this tutorial, I will use the Rush Hour Traffic Circa 1956 public domain video.

1 - Glitch file with Javascript

To glitch the file using ffglitch’s native scripting capabilities (made possible by integrating quickjs), you will have to write code in Javascript.

This file should have a function called glitch_frame, which will be called once for each frame.

The frame object passed to glitch_frame will have an object for each feature that was requested (in our case, mv for motion vectors), and we modify them directly.

The motion vector object might have a backward object if we are dealing with B frames (ignore this for now), and might have a forward object for P frames (this is what we will use).

In the backward or forward objects, there will be one array for each row of macroblocks, and these arrays will each have one array of 2 values (for horizontal and vertical motion vectors), for each macroblock.

The structure for motion vectors in frame looks like this:

"mv": {
    "forward": [
        [ [ x, y ], [ x, y ], ..., [ x, y ] ],
        [ [ x, y ], [ x, y ], ..., [ x, y ] ],
        [ [ x, y ], [ x, y ], ..., [ x, y ] ],
        ...
        [ [ x, y ], [ x, y ], ..., [ x, y ] ]
    ],
    "backward": [
        [ [ x, y ], [ x, y ], ..., [ x, y ] ],
        [ [ x, y ], [ x, y ], ..., [ x, y ] ],
        [ [ x, y ], [ x, y ], ..., [ x, y ] ],
        ...
        [ [ x, y ], [ x, y ], ..., [ x, y ] ]
    ]
}

With all that being said, here’s the script that we will be using. Save it as a file named mv_sink_and_rise.js:

function glitch_frame(frame)
{
    // bail out if we have no motion vectors
    let mvs = frame["mv"];
    if ( !mvs )
        return;
    // bail out if we have no forward motion vectors
    let fwd_mvs = mvs["forward"];
    if ( !fwd_mvs )
        return;

    // clear horizontal element of all motion vectors
    for ( let i = 0; i < fwd_mvs.length; i++ )
    {
        // loop through all rows
        let row = fwd_mvs[i];
        for ( let j = 0; j < row.length; j++ )
        {
            // loop through all macroblocks
            let mv = row[j];

            // THIS IS WHERE THE MAGIC HAPPENS

            mv[0] = 0; // this sets the horizontal motion vector to zero
            // mv[1] = 0; // you could also change the vertical motion vector
        }
    }
}

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

$ ./ffedit -i temp_file.mpg -f mv -s mv_sink_and_rise.js -o glitched_file.mpg

And this is the resulting glitched_file.mpg:

Conclusion

I don’t like writing posts with introductions and conclusions, but since there was an introduction section, there is also a conclusion section.

Go wild with your scripts and glitch the fuck out of those motion vectors…