Objective
This article will guide you through the steps of creating a video slideshow based on a list of images. The process does not entail using any editing software, but using a PHP script allowing you to create videos programmatically. If you follow this article you will learn the basics for creating your image to video converter.
The objective of this tutorial is to turn these 5 images into a video:
I will propose 2 alternatives for this:
- Using FFMPEG commands from a PHP script that runs in your own server
- Using a video editing API from a PHP script that runs in the cloud
Why should I care where the video is created?
Video processing is a resource expensive task that consumes memory and CPU. Depending on your usage estimate you might need to consider upgrading your servers or creating a dedicated cluster of servers for video processing.
On the other hand, using a cloud-based video API solution allows you to have a scale-proof, pay-as-you-go platform you don't need to worry about. Depending on your volume, you may fall into the free-tier and you don't have any cost.
This means that you can now focus exclusively on writing reusable code without having to worry about managing infrastructure.
Read more about what you should take into consideration when editing video with PHP scripts.
Self-hosted solution with FFMPEG and PHP
Create video from images with FFMPEG + PHP
There are many ways to do this, but I went with the two I think are the easiest. As you may know, FFMPEG is a powerful set of tools that can convert and process videos. But such power comes with a step learning curve, sometimes cryptic parameters and some frustration by newbies.
The examples below work for turning JPEG, PNG and WEBP still images into a video slideshow. You just need to replace the JPG file in the example codes with your PNG file, to turn the ffmpeg images to video.
Option 1: with no transitions
I will pass each of the 5 input images to ffmpeg
in this format:
-loop 1 -t 2 -i london-0X.jpg
-loop 1
makes the image to loop itself-t N
makes the image stream to last N seconds-i london-0X.jpg
defines the london-0X.jpg image as source, where X is the image number
Then, I'll tell ffmpeg
to concat them all into a output stream:
-filter_complex "[0][1][2][3][4] concat=n=5 [out]"
-filter_complex
allows to pass complex filters to ffmpeg[0][1][2][3][4]
sets the 5 input sources for the concat filter (starting from 0 to 4)concat=n=5
orders ffmpeg to concat the 5 passed inputs[out]
set the name of the output stream to "out"
And finally, I'll save the output stream into output.mp4:
-map "[out]" output.mp4 -y
-map "[out]"
forwards the "out" stream to the output fileoutput.mp4
sets the output file name and format (mp4)-y
forces ffmpeg to overwrite the output file if it exists
All together now:
ffmpeg \
-loop 1 -t 2 -i london-01.jpg \
-loop 1 -t 3 -i london-02.jpg \
-loop 1 -t 2 -i london-03.jpg \
-loop 1 -t 3 -i london-04.jpg \
-loop 1 -t 4 -i london-05.jpg \
-filter_complex "[0][1][2][3][4] concat=n=5 [out]" \
-map "[out]" output.mp4 -y
Now let's make the call from PHP:
<?php
$cmd = "ffmpeg \
-loop 1 -t 2 -i london-01.jpg \
-loop 1 -t 3 -i london-02.jpg \
-loop 1 -t 2 -i london-03.jpg \
-loop 1 -t 3 -i london-04.jpg \
-loop 1 -t 4 -i london-05.jpg \
-filter_complex \"[0][1][2][3][4] concat=n=5 [out]\" \
-map \"[out]\" output.mp4";
$r = exec($cmd);
You must make sure ffmpeg
is in the same folder than your script or it's in a directory included in the PATH.
The resulting video is a slideshow of images, each with slide with different durations (2, 3, 2, 3 and 4 seconds):
Option 2: with transitions
Adding transitions is a little bit more tricky because we must fade each image with the next one.
I will use the xfade
filter to apply the transition, in this format:
[input1][input2] xfade=transition={transition_name}:duration={duration}:offset={offset}
[input1]
refers to the first input stream to apply the transition to[input2]
refers to the second input stream to apply the transition toxfade
is the name of the filter to applytransition={transition_name}
sets what transition to useduration={duration}
sets the duration of the transition in secondsoffset={offset}
sets the offset (at what point) the transition will be applied
Because this encoding is a little bit more complex, we must tell FFMPEG what codec and format to use to make sure the output is compatible with most of the video players, for example with QuickTime:
-pix_fmt yuv420p -vcodec libx264
All together now:
ffmpeg \
-loop 1 -t 5 -i london-01.jpg \
-loop 1 -t 5 -i london-02.jpg \
-loop 1 -t 5 -i london-03.jpg \
-loop 1 -t 5 -i london-04.jpg \
-loop 1 -t 5 -i london-05.jpg \
-filter_complex " \
[0][1] xfade=transition=slideup:duration=1:offset=4 [a]; \
[a][2] xfade=transition=slideright:duration=1:offset=8 [b]; \
[b][3] xfade=transition=slidedown:duration=1:offset=12 [c]; \
[c][4] xfade=transition=slideleft:duration=1:offset=16 [out] \
" \
-pix_fmt yuv420p -vcodec libx264 \
-map "[out]" output.mp4 -y
I used 4 different transitions, one for each slide. You can check the available transitions in the xfade FFMPEG documentation
Now let's make the call from PHP:
<?php
$cmd = "ffmpeg \
-loop 1 -t 5 -i london-01.jpg \
-loop 1 -t 5 -i london-02.jpg \
-loop 1 -t 5 -i london-03.jpg \
-loop 1 -t 5 -i london-04.jpg \
-loop 1 -t 5 -i london-05.jpg \
-filter_complex \" \
[0][1] xfade=transition=slideup:duration=1:offset=4 [a]; \
[a][2] xfade=transition=slideright:duration=1:offset=8 [b]; \
[b][3] xfade=transition=slidedown:duration=1:offset=12 [c]; \
[c][4] xfade=transition=slideleft:duration=1:offset=16 [out] \
\" \
-pix_fmt yuv420p -vcodec libx264 \
-map \"[out]\" output.mp4 -y";
$r = exec($cmd);
The resulting video looks like this:
As a bonus, if you continue reading, at the end of the article, I will show you how you can add a background music.
😉
Cloud-hosted solution with JSON2Video and PHP
Now, let's do the same but serverless, fully-scalable and with maintainable code.
With JSON2Video you use an abstraction to make things much easier:
- You have movie project
- Each movie can have multiple scenes
- In each scene you add elements (like images, other videos, audio, voice-over, text animations, ...)
The best thing in terms of development is that you can easily describe your video programmatically
without knowing cryptic parameters like -t 5
, -pix_fmt yuv420p
or concat=n=5
.
And one month later, you (or someone in your team) will still be able to understand the code.
Create video from images with PHP + JSON2Video
- First, I start creating a Movie object and setting it up
- Second, I create an scene for each slide/image, defining the scene duration and the transition to apply. Each scene has only one image element on it.
- Third, I send the movie to render and wait for the render to finish
Agreed, it's longer than the FFMPEG version, but you must admit that it's way easier to understand and maintain.
The result is the same but you don't need back-end resources and your code is easier to maintain:
BONUS TRACK: Add a background music
As promised, here it is how to convert image and audio to video with FFMPEG and PHP.
Adding audio with FFMPEG can be easier or harder depending on what you want to achieve. A simple background music with no sync with the jpeg images is pretty straight forward as we will see below. Something more sophisticated, like different audios sync'ed with the slideshow can be much more complex and require a longer FFMPEG command.
To add the audio to the video slideshow of images, I'm adding an additional input source to the FFMPEG command:
-i music.mp3
And I'm finally mapping this input source (input #5, remember it starts counting from 0) into the final output video. Because the audio file is longer (2 minutes) than the video slideshow, I must tell FFMPEG to set the video length to the shorter between the video stream and the audio stream:
-map 5:a -shortest
The final command is:
<?php
$cmd = "ffmpeg \
-loop 1 -t 5 -i london-01.jpg \
-loop 1 -t 5 -i london-02.jpg \
-loop 1 -t 5 -i london-03.jpg \
-loop 1 -t 5 -i london-04.jpg \
-loop 1 -t 5 -i london-05.jpg \
-i music.mp3 \
-filter_complex \" \
[0][1] xfade=transition=slideup:duration=1:offset=4 [a]; \
[a][2] xfade=transition=slideright:duration=1:offset=8 [b]; \
[b][3] xfade=transition=slidedown:duration=1:offset=12 [c]; \
[c][4] xfade=transition=slideleft:duration=1:offset=16 [out] \
\" \
-pix_fmt yuv420p -vcodec libx264 \
-map \"[out]\" -map 5:a -shortest output.mp4 -y";
$r = exec($cmd);
This is the result:
Final thoughts on creating a video from images
As you read above, the basics of creating a MP4 slideshow from images are pretty simple with FFMPEG. However, if you are really planning to turn this into a production project with real users that could scale with several users simultaneously, you should take into consideration SaaS alternatives like JSON2Video. The headache of running a high-performance, ready-to-scale server cluster is something you should not underestimate.
On the other hand, using FFMPEG requires extensive experience. If your code needs to be maintained by a team of developers this could be a handicap. JSON2Video allows you to solve this as well providing a simple and readable interface to video editing.
Published on January 9th, 2022