Working on doing some upgrades for one of my clients and I hit on an idea. He has a lot of videos available, but each one only has a static image as a thumbnail, taken at a set point in the video (by default; the owner or and admin can go in and recreate the thumbnail at a different time point if they want.) But what if, instead, we could create an animated GIF composed of several frames from the video?
From a user’s perspective, a single frame might not tell you a lot about a video. But ten frames taken over the course of the whole video can tell you a lot more about the video than the single frame would. How would we implement something like that?
What we actually did was generate two thumbnails, a static one and an animated one. On mobile devices, only the static one is displayed. On desktop devices, the static one is the default and, when you mouse over the thumbnail, we swap the static one for the animated one.
Turns out, this is rather easy to implement, if not very straightforward. My first thought was to increate the frame rate of the video and use PHP-FFMPEG’s built-in GIF generator, but this didn’t work. You can’t do it in a single step that I was able to find.
Doing this consists of three steps:
- Extracting the frames from given points in a video.
- Resizing each frame down to thumbnail size.
- Combining them all into an animated GIF.
Because this is modern PHP in the 21st century, we will be using
composer and the following packages to save us a lot of time:
As a note,
php-ffmpeg will require that you have
ffmpeg installed on your system or in your container.
gif-creator requires ImageMagick support in PHP.
image will need either GD or ImageMagick as well.
The final function is something like this:
As you can see from the above, we’re taking a video and extracting a frame every 10% of the video until we reach the end. We shrink them down and mash them together into an animated GIF and store that on the filesystem, removing the intermediate files at the end.
As this takes some time to run, it would be a good idea to run this code using some type of out-of-band processing. Laravel’s Queue’s are a good example that I have used before, as are Gearman, Redis, Beanstalk, etc. Basically, don’t run this in
php-fpm because you want those tasks to complete quickly.