Felix - 14.01.2023

Converting a 3d Video to Anaglyph with JS

This is a simple guide on how to convert a 3d video to anaglyph with javascript. Sample video files can be found on yts.mx.

Why Javascript?

A few years ago I wrote the library movie-fleur that converts a 3d video to anaglyph. It was written in Java and honestly it is quite badly written, slow, buggy and as I kind of got away from Java and more and more into Javascript/Typescript I decided to rewrite parts of it in Javascript.

To this date I not aware of any other library that do this in Javascript. So I thought I would share my findings and the code I wrote. I hope it helps someone. And even thou it is a JavaScript project, most of the important stuff is done with the ffmpeg library. So it is not really a pure JavaScript article.

Removing a color channel from a video

To remove the red color using ffmpeg, we'll use the colorchannelmixer filter and set the red channel to zero. In ffmpeg, the command would look like this:

Removing the red channel
ffmpeg -i input.mp4 -vf colorchannelmixer=rr=0 -c:a copy output.mp4
Removing the blue and green channels
ffmpeg -i input.mp4 -vf colorchannelmixer=gg=0:bb=0 -c:a copy output.mp4

This command will take the input video and apply the colorchannelmixer filter with the red channel set to zero. The -c:a copy flag is used to copy the audio stream from the input to the output without re-encoding it.

In JavaScript, you can use a library such as fluent-ffmpeg to execute FFmpeg commands.

const ffmpeg = require('fluent-ffmpeg');

ffmpeg()
    .input('input.mp4')
    .complexFilter(['colorchannelmixer=rr=0'])
    .output('output.mp4')
    .on('end', () => {
        console.log('Processing finished!');
    })
    .run();

This code uses the fluent-ffmpeg library to create a new FFmpeg process, set the input video to "input.mp4", apply the colorchannelmixer filter with red channel set to zero, set the output video to "output.mp4" and runs the process.

Keep in mind that, you will need to have ffmpeg installed on your system and this code is meant to be run on a server-side javascript, like Node.js, not on a browser.

Crop and resize video

To use the left side of a mp4 file and stretch it using Ffmpeg, you can use the crop and scale filter. Here is an example command:

ffmpeg -i input.mp4 -vf "crop=iw/2:ih:0:0,scale=2*iw:ih" -c:a copy output.mp4

This command will take the input video "input.mp4", apply the crop filter to select the left half of the video with the dimensions iw/2:ih:0:0, and then apply the scale filter to stretch the left half to twice its original width. The -c: a copy flag is used to copy the audio stream from the input to the output without re-encoding it.

const ffmpeg = require('fluent-ffmpeg');

ffmpeg()
    .input('input.mp4')
    .complexFilter(['crop=iw/2:ih:0:0', 'scale=2*iw:ih'])
    .output('output.mp4')
    .on('end', () => {
        console.log('Processing finished!');
    })
    .run();

This code applies the crop filter to select the left half of the video with the dimensions "iw/2:ih:0:0" and then the scale filter to stretch the left half to twice its original width and set the output video to "output.mp4".

Combining the filters

const ffmpeg = require('fluent-ffmpeg');

ffmpeg()
    .input('input.mp4')
    .complexFilter(['crop=iw/2:ih:0:0', 'scale=2*iw:ih', 'colorchannelmixer=rr=0'])
    .output('output.mp4')
    .on('end', () => {
        console.log('Processing finished!');
    })
    .run();

To add a progress indication to the previous we can use the progress event:

const ffmpeg = require('fluent-ffmpeg');

const command = ffmpeg()
    .input('input.mp4')
    .complexFilter(['colorchannelmixer=rr=0', 'crop=iw/2:ih:0:0', 'scale=2*iw:ih'])
    .output('output.mp4');

command.on('progress', (progress) => {
    console.log(`Processing: ${Math.round(progress.percent)}% done`);
});

command.on('end', () => {
    console.log('Processing finished!');
});

command.run();