How to Add Subtitles to Your Video Using FFmpeg

It’s no secret that video content is eating the internet. These days, practically all social networks are video-forward spaces where clips and reels dominate the user feed. In order to get value out of a video, however, users need to know what is being said. Since most social networks mute videos in feeds by default, it’s up to creators to make sure their words come across to viewers.

Luckily, there’s a simple solution to this: Adding subtitles. Subtitles instantly make your videos more meaningful and accessible and are very likely to increase click-through and engagement rates.

This guide will show you two programmatic approaches to adding subtitles to a video—one using FFmpeg, and another leveraging the Editframe video API. With these skills under your belt, you’ll be able to do things like:

  • Improve page SEO by increasing your average time-on-page
  • Increase your overall video engagement
  • Make awesome lyric videos
  • Improve the conversion of video ads
  • Automate subtitle creation or video transcription at scale

Let’s do this.

File assets

Here is a sample video file provided by pexels.com that we will use in this tutorial.

sample.mp4

Part 1: Using FFmpeg

First, we’ll walk through this workflow using FFmpeg.

Required Tools

  • Sample video file overlay (provided above)
  • FFmpeg: (You’ll need to install FFmpeg and set up the appropriate environment variables before beginning this tutorial)

Using Filter complex:

First, let’s create an SRT file, example.srt, that will contain the subtitles for our video:

touch example.srt
1
00:00:00,000 --> 00:00:01,500
This an example subtitle

2
00:00:01,600 --> 00:00:02,500
<i>Italic style</i>

3
00:00:03,000 --> 00:00:15,000
Video by Tiger Lily on pexels.com

Here is the FFmpeg command that will sync our subtitles with our video:

ffmpeg -i sample.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080,\subtitles=example.srt:force_style='OutlineColour=&H100000000, /BorderStyle=3,Outline=0,Fontsize=20'" subtitle.mp4

Let’s break down what this command is doing.

  • Here, we import the sample.mp4 video file and example.srt SRT file, and resize/crop the output video to 1920x1080:
ffmpeg -i sample.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080,\
  • In this line, overwrite the default FFmpeg style for subtitles, and change the background color to black:
subtitles=example.srt:force_style='OutlineColour=&H100000000, /
  • Here, we will overwrite the border style to 3, enable the text outline color, and change the font size to 20px:
BorderStyle=3,Outline=1,Fontsize=20'" subtitle.mp4

Here is the output video using the FFmpeg command:

subtitle.mp4

Part 2: Using Editframe

Now let’s perform the same task using Editframe instead of FFmpeg.

Required tools:

  • Node.js installed on your machine (v16+)
  • Editframe Client ID and Token (you can create an account from this link)

*No need to have FFmpeg installed on your machine

  • Create a folder for the project:
mkdir editframe-subtitle
  • Initialize a Node.js project:
yarn init -y
  • Install the Editframe Node.js SDK and subtitle, a library that will help us parse the sample.srt file content:
yarn add @editframe/editframe-js subtitle

  • Create a create-video.js file to merge the videos into one:
const { Editframe } = require('@editframe/editframe-js')
const { parse } = require('subtitle')
const fs = require('fs')

const main = async () => {
  const editframe = new Editframe({
    develop: true,
    clientId: 'YOUR_EDITFRAME_CLIENT_ID',
    token: 'YOUR_EDITFRAME_TOKEN',
  })
  const composition = await editframe.videos.new({
    dimensions: {
      height: 1080,
      width: 1920,
    },
    duration: 7,
  })
  await composition.addVideo(`${__dirname}/sample.mp4`, {
    size: { format: 'fit' },
  })
  const inputStream = fs.createReadStream(`${__dirname}/example.srt`)
  inputStream
    .pipe(parse())
    .on('data', async (node) => {
     composition.addText(
        {
          text: node.data.text,
          fontSize: 70,
          color: "#ffffff",
          fontFamily: "Arial",
          padding: 50,
        },
        {
          position: {
            x: "center",
            y: "bottom",
          },
          timeline: {
            start: node.data.start / 1000,
          },
          trim: {
            end: node.data.end / 1000 - node.data.start / 1000,
          },
        }
      );
    })
    .on('error', console.error)
    .on('finish', async () => {
      const video = await composition.encodeSync()
      console.log(video)
    })
}

main()

Let’s break down what the code in this file is doing.

  • In these lines, we initialize an Editframe instance with our Editframe Client ID and token (which we obtain by creating an Editframe application). Also, we set the develop key to true, which will open the output video in new tab when encoding has finished:
const editframe = new Editframe({
  develop: true,
  clientId: 'YOUR_EDITFRAME_CLIENT_ID',
  token: 'YOUR_EDITFRAME_TOKEN',
})
const composition = await editframe.videos.new({
  dimensions: {
    height: 1080,
    width: 1920,
  },
  duration: 7,
})
  • In these lines, we add a video file to the Editframe video composition using composition.addVideo method:
await composition.addVideo(`${__dirname}/sample.mp4`, {
  size: { format: 'fit' },
})
  • Here, we parse the example.srt file, and add each line of text to the video using composition.addText method:
const inputStream = fs.createReadStream(`${__dirname}/example.srt`)
inputStream
  .pipe(parse())
  .on('data', async (node) => {
   composition.addText(
        {
          text: node.data.text,
          fontSize: 70,
          color: "#ffffff",
          fontFamily: "Arial",
          padding: 50,
        },
        {
          position: {
            x: "center",
            y: "bottom",
          },
          timeline: {
            start: node.data.start / 1000,
          },
          trim: {
            end: node.data.end / 1000 - node.data.start / 1000,
          },
        }
      );
  })
  .on('error', console.error)
    .on("finish", async () => {
      const video = await composition.encodeSync();
      console.log(video);
    });
  • Now, let’s run the video script:
node create-video

Here is the output video from the Editframe API:

editframe-subtitle.mp4

Note: Editframe also lets you add transitions, filter and trim videos, and do much more. You can learn about other ways to use Editframe from the Editframe API docs.

Comparing videos created with FFmpeg and the Editframe API

Here is a comparison showing the video created with FFmpeg (on the left) and Editframe (on the right):

compare.mp4

© 2022 Editframe
Making video creation easier for software developers.