Automatically turn images into a slideshow using FFmpeg and Editframe (Updated)

Published on June 8, 2023
Last updated on September 25, 2024

6 min read

You might not associate the word “slideshow” with new, modern, technology-forward presentations. But from sales and marketing assets to social media content, this tried-and-true storytelling method is still alive and well in the digital age. With the right editing, slideshows can make for an eye-popping way to show off your brand, promote an event, or elevate the look of your social media feeds.

In this tutorial, we’ll show you how to programmatically create a slideshow by merging and combining multiple images into a single video using two methods: FFmpeg, and Editframe. The final output will be a video MP4. You can even take this a step further and use either FFmpeg or Editframe (whichever method best suits you) to incorporate audio and transition effects that take your slideshow to the next level.

By the end of this tutorial, you’ll know how to make an amazing photo or video slideshow programmatically and at scale, and you’ll forget all about the dusty projector in your grandma’s basement.

Let’s get started.

File assets

Here are the sample image files provided by unsplash.com(opens in a new tab) that we will use in our tutorial:

file1.jpg

file2.jpg

file3.jpg

Part 1: Using FFmpeg

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

Required Tools

  • Sample video and audio files (provided above)
  • FFmpeg(opens in a new tab): (You’ll need to install FFmpeg and set up the appropriate environment variables before beginning this tutorial)
  • Create a video.txt file.
touch video.txt
  • Paste the path to use the images for the video in video.txt. For example:
file '/Users/mac/dev/ffmpeg-tutorials/file1.jpg'
duration 4
file '/Users/mac/dev/ffmpeg-tutorials/file2.jpg'
duration 2
file '/Users/mac/dev/ffmpeg-tutorials/file3.jpg'
duration 2
  • Run this script to import all images and make a video from them:
ffmpeg -safe 0 -f concat -i video.txt -c:v libx264 \
-vf "scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920" -pix_fmt yuv420p slideshow.mp4

Let’s break down what the code above is doing.

  • In this line, we concat all images inside video.txt, and disable file safety using -safe 0. We also set the video encoder to libx264:
ffmpeg -safe 0 -f concat -i video.txt -c:v libx264
  • In this line, we will resize and crop all images to 1080x1920 while keeping their aspect ratio. We also add the pixel format to render images -pix_fmt yuv420p:
-vf "scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920" -pix_fmt yuv420p

slideshow.mp4

Using named files

  • In this folder, we’ll have file1.jpg, file2.jpg, and file3.jpg. Instead of adding their path manually, we can use this method to add all of them:
ffmpeg -framerate 1 -i file%d.jpg -vf "scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920" -c:v libx264 -pix_fmt yuv420p output.mp4

Let’s break down the code above.

  • In this line, we specify a frame rate of one frame per second, and import all of our files with file%d.jpg:
ffmpeg -framerate 1 -i file%d.jpg
  • In this line, we resize and crop all images to 1080x1920 while keeping their aspect ratio. Also, we specify the pixel format for rendering out images with -pix_fmt yuv420p:
-vf scale=1080:1920  -c:v libx264

Here is the output video from the FFmpeg command:

slideshow.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
  • No need to have FFmpeg installed on your machine
  • Editframe API Token (you can create an account from this link(opens in a new tab))

Let’s get started:

  1. Setup a new Node.js project using the Editframe CLI:
npx @editframe/create@beta
  1. Install the required dependencies:
cd slide-show-images && npm install
  1. Add assets to the project:

Add file1.jpg, file2.jpg, and file3.jpg to the src/assets folder.

  1. Update the index.html file with the following code:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script type="module" src="./src/index.js"></script>
    <link rel="stylesheet" href="./src/styles.css" />
  </head>
  <body>
    <ef-timegroup
      mode="sequence"
      class="w-[1080px] h-[1920px] relative overflow-hidden"
    >
      <ef-timegroup
        mode="fixed"
        duration="4s"
      >
        <ef-image class="w-full object-cover object-center" src="/assets/file1.jpg"></ef-image>
      </ef-timegroup>
      <ef-timegroup
        mode="fixed"
        duration="2s"
      >
        <ef-image class="w-full object-cover object-center" src="/assets/file2.jpg"></ef-image>
      </ef-timegroup>
      <ef-timegroup
      mode="fixed"
      duration="2s"
    >
      <ef-image class="w-full object-cover object-center" src="/assets/file3.jpg"></ef-image>
    </ef-timegroup>
    </ef-timegroup>
  </body>
</html>

Let’s walk through what the code in this file is doing.

  • In these lines, we import the index.js file and the styles.css file which contains the styles for the video and @editframe/elements:
<head>
    <meta charset="UTF-8" />
    <script type="module" src="./src/index.js"></script>
    <link rel="stylesheet" href="./src/styles.css" />
  </head>
  • In this line, we create a new video composition using the ef-timegroup element.
<ef-timegroup
      mode="sequence"
      class="w-[1080px] h-[1920px] overflow-hidden"
    >
    { /* Add elements here */ }
</ef-timegroup>
  • In these lines, we add a timegroup where we will have the ef-image elements:
<ef-timegroup
    mode="fixed"
    duration="4s"
  >
  { /* Add elements here */ }
  </ef-timegroup>
  • In these lines, we add a black overlay with the quote text in the center of the video:
<div class="bg-black/50 w-full h-full z-[100] relative flex flex-col  justify-center items-center">
    <h1 class="text-white text-left px-6 text-[120px]">“We cannot solve problems with the kind of thinking we employed when we came up with them.” — Albert Einstein</h1>
  </div>
  • In these lines, we import each image as a timegroup element to make a sequence of images:
<ef-timegroup
    mode="fixed"
    duration="4s"
  >
    <ef-image class="w-full object-cover object-center" src="/assets/file1.jpg"></ef-image>
  </ef-timegroup>
  <ef-timegroup
    mode="fixed"
    duration="2s"
  >
    <ef-image class="w-full object-cover object-center" src="/assets/file2.jpg"></ef-image>
  </ef-timegroup>
  <ef-timegroup
  mode="fixed"
  duration="2s"
>
  <ef-image class="w-full object-cover object-center" src="/assets/file3.jpg"></ef-image>
</ef-timegroup>
  • ef-image is an Editframe element that allows you to add images to your video.

  1. Preview the project:
npx vite .
  1. Update the .env file with your Editframe API token:
EF_TOKEN="YOUR_API_TOKEN"
  1. Render the video:
npx @editframe/cli render .

Here is the output video from the Editframe API:

editframe-slideshow.mp4

Note: You can also add transitions, filters, trim videos, and much more using the Editframe compositional API. Learn more about using Editframe at the Editframe API docs.

Comparison video between FFmpeg and Editframe API

Here is a comparison of the videos created with FFmpeg (left) and Editframe (right):

compare.mp4