How to Create a Preview Video Thumbnail of a Video with FFmpeg & PHP

In this tutorial, we will learn how to create a video thumbnail preview from a full video using FFmpeg & PHP. It will be a single low-resolution file containing a sequence of 2-second clips from various parts of the original video.

 

Before we go any further, here is an example of what the final output will look like:

 

 

Preview

 

Get the Duration of the Video in Seconds

The first step is to get the duration of the input video in seconds so we can determine where to get clips from it. This is done using ffprobe and rounding the output to an integer.

 

$video_path = 'path/to/example_preview/input.mp4';

$dur = shell_exec("ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 '$video_path'");
$seconds = round($dur);

 

Setting the Seconds from the Video to Create Clips from

Now we will create four intervals from where each clip will start from using PHP gmdate() function.

 

$thumb_0 = gmdate('H:i:s', $seconds / 8);
$thumb_1 = gmdate('H:i:s', $seconds / 4);
$thumb_2 = gmdate('H:i:s', $seconds / 2 + $seconds / 8);
$thumb_3 = gmdate('H:i:s', $seconds / 2 + $seconds / 4);

 

Creating The Clips

The next step is to create the clips. To do this we will loop four times and create a 2-second clip at each interval.

 

The path to each file will is stored in a list.txt file, which we will need to reference when joining these clips together. We will also store a $preview_array of the clips so we can delete them later.

 

In each iteration, the FFmpeg command seeks to the thumb interval value and creates a 2-second video at a resolution of 320wx180h.

 

$path_clip = 'path/to/example_preview/;

$preview_list = fopen($path_clip . 'list.txt', "w");
$preview_array = [];

for ($i=0; $i <= 3; $i++) {
  $thumb = ${'thumb_'.$i};
  shell_exec("ffmpeg -i '$video_path' -an -ss $thumb -t 2 -vf 'scale=320:180:force_original_aspect_ratio=decrease,pad=320:180:(ow-iw)/2:(oh-ih)/2,setsar=1' -y $path_clip/$i.p.mp4");

  $output = $path_clip . $i.'.p.mp4';

  if (file_exists($output)) {
   fwrite($preview_list, "file '". $output . "'\n");
   array_push($preview_array, $output);
  }
}

fclose($preview_list);

 

Concatenating the Clips

Now we can concatenate the clips into one file like this:

 

shell_exec("ffmpeg -f concat -safe 0 -i $path_clip/list.txt -y $path_clip/preview.mp4");

 

Removing the Clips and File List

Finally, remove the clips and the list.txt to clean up files we will no longer need:

 

if (!empty($preview_array)) {
  foreach ($preview_array as $v) {
    unlink($v);
  }
}

// remove preview list
unlink($path_clip . 'list.txt');

 

 

Full Example

Here is a full example of the code:

 

$video_path = 'path/to/example_preview/input.mp4';

$dur = shell_exec("ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 '$video_path'");
$seconds = round($dur);

$thumb_0 = gmdate('H:i:s', $seconds / 8);
$thumb_1 = gmdate('H:i:s', $seconds / 4);
$thumb_2 = gmdate('H:i:s', $seconds / 2 + $seconds / 8);
$thumb_3 = gmdate('H:i:s', $seconds / 2 + $seconds / 4);

$path_clip = 'path/to/example_preview/;

$preview_list = fopen($path_clip . 'list.txt', "w");
$preview_array = [];

for ($i=0; $i <= 3; $i++) {
  $thumb = ${'thumb_'.$i};
  shell_exec("ffmpeg -i '$video_path' -an -ss $thumb -t 2 -vf 'scale=320:180:force_original_aspect_ratio=decrease,pad=320:180:(ow-iw)/2:(oh-ih)/2,setsar=1' -y $path_clip/$i.p.mp4");

  $output = $path_clip . $i.'.p.mp4';

  if (file_exists($output)) {
    fwrite($preview_list, "file '". $output . "'\n");
    array_push($preview_array, $output);
  }
}

fclose($preview_list);

shell_exec("ffmpeg -f concat -safe 0 -i $path_clip/list.txt -y $path_clip/preview.mp4");

if (!empty($preview_array)) {
  foreach ($preview_array as $v) {
    unlink($v);
  }
}

// remove preview list
unlink($path_clip . 'list.txt');
ffmpeg video thumbnail