Convert GIF files to MP4 Videos Using Fluent Ffmpeg

2024-05-10
By: O Wolfson

In this article I'll outline step-by-step how to up a script that will convert GIF files to MP4 videos using fluent-ffmpeg. You will understand the code, and know how to run the script.

Gif

cat sandwich gif

Video

Step 1: Setting Up Your Project

1.1 Install Node.js

Ensure that Node.js is installed on your system. If not, download and install it from nodejs.org.

1.2 Create a Project Directory

Create a new directory for your project and navigate into it:

bash
mkdir gif-to-mp4
cd gif-to-mp4

1.3 Initialize the Node.js Project

Run the following command to create a package.json file:

bash
npm init -y

1.4 Install Dependencies

Install fluent-ffmpeg and ffmpeg-static by running:

bash
npm install fluent-ffmpeg ffmpeg-static

Make sure that FFmpeg is correctly installed and accessible in your environment's PATH. The ffmpeg-static package provides an FFmpeg binary that fluent-ffmpeg can use.

Step 2: Create the Script

2.1 Create the JavaScript File

Create a file named convert.js:

bash
touch convert.js

2.2 Write the Script

Paste the following code into convert.js:

javascript
const ffmpeg = require("fluent-ffmpeg");
const fs = require("fs");
const path = require("path");
const ffmpegStatic = require("ffmpeg-static");

// Set FFmpeg binary path
ffmpeg.setFfmpegPath(ffmpegStatic);

const inputDir = "./_input";
const outputDir = "./_videos";

// Ensure output directory exists
if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir);
}

// Read files from input directory
fs.readdir(inputDir, (err, files) => {
  if (err) {
    console.error("Error reading input directory:", err);
    return;
  }

  files
    .filter((file) => path.extname(file).toLowerCase() === ".gif")
    .forEach((file) => {
      const inputFilePath = path.join(inputDir, file);
      const outputFilePath = path.join(
        outputDir,
        path.basename(file, ".gif") + ".mp4"
      );

      // Convert GIF to MP4
      ffmpeg(inputFilePath)
        .complexFilter([
          {
            // Scale filter: Adjusts the height of the video to maintain a 16:9 aspect ratio based on the original height
            // and scales the width accordingly, setting it to automatically calculate so that the aspect ratio is preserved.
            filter: "scale",
            options: "ih*16/9:-1",
            inputs: "[0:v]",
            outputs: "[scaled]",
          },
          {
            // Colorlevels filter: Adjusts the minimum input levels for red, green, and blue channels to 1.
            // This can be used to manipulate image contrast or correct color levels that are too dark or washed out. Here I am using it to black-out the background.
            filter: "colorlevels",
            options: "rimin=1:gimin=1:bimin=1",
            inputs: "[scaled]",
            outputs: "[bg]",
          },
          {
            // Overlay filter: Places the original input video over the scaled and color-adjusted background.
            // The placement coordinates ensure that the video is centered on both axes.
            filter: "overlay",
            options: "(W-w)/2:(H-h)/2",
            inputs: ["[bg]", "[0:v]"],
            outputs: "[overlayed]",
          },
          {
            // Crop filter: Crops the overlayed video to maintain the 16:9 aspect ratio by adjusting the height.
            // It calculates the height to be proportional to the current width keeping the aspect ratio.
            filter: "crop",
            inputs: "[overlayed]",
            options: { h: "iw*9/16" },
            outputs: "[cropped]",
          },
          {
            // Scale filter: Finally scales the cropped video to a fixed resolution of 640x360 pixels,
            // which is a standard resolution maintaining a 16:9 aspect ratio.
            filter: "scale",
            options: "640:360",
            inputs: "[cropped]",
            output: "[final]",
          },
        ])
        .output(outputFilePath)
        .run();
    });
});

Step 3: Prepare the Files

3.1 Create Input and Output Directories

bash
mkdir _input _videos

3.2 Add GIF Files

Add some GIF files to the _input directory.

Step 4: Run the Script

Execute the script by running:

bash
node convert.js

This will start the conversion process, where each GIF file in the _input directory is processed and saved as an MP4 file in the _videos directory. The script logs the status of each file, indicating whether the conversion was successful or if there were errors.

This tutorial covers the essential aspects of setting up a Node.js project to convert GIF files to MP4 using fluent-ffmpeg. Adjust the filter and encoding settings in the script as needed to fit your specific requirements.