Using FFMPEG to use mutiple static images - ffmpeg

I know how to combine a single image with an mp3 to create a video like this
"ffmpeg.exe" -loglevel 0 -loop 1 -i c:\path\foo.jpg -i c:\path\foo.mp3 -c:v libx264 -pix_fmt yuv420p -crf 0 -c:a copy -shortest c:\path\foo.mkv
How can I make ffmpeg create a video using multiple images that it cycles through at regular intervals, or even randomly? Basically I want to use more than one image in a video rather than just 1.

You can use the examples from the wiki to create a slideshow from images.
For example:
ffmpeg -framerate 1/3 -pattern_type glob -i '*.jpg' -c:v libx264 out.mp4
Keep in mind that all images must have the same size!
In my test the resulting mp4 file was approximately the same size as the sum of the input files;
> du out.mp4
768 out.mp4
> du -c *.jpg|grep total
648 total
Note that photos from a digital camera are generally a lot bigger than even a HD movie, so you might want to scale the images.
This can be done using the scale filter, or with an external program like ImageMagick. In my example I scaled the images before making a movie out of them.

Related

ffmpeg - Apply padding to input images while combining multiple images and audio track

I am using below command to create a slideshow using ffmpeg:
ffmpeg -r 1 -i IMG_%04d.jpeg -i audio.mp3 -c:v libx264 -c:a aac -pix_fmt yuv420p -r 24 -y output.mp4 -vf pad=ceil(iw/2)*2:ceil(ih/2)*2
I had to add pad=ceil(iw/2)*2:ceil(ih/2)*2 to make width or height even number because if one of the input image width/height is odd, ffmpeg throws error. Now my problem is; input images can be of different resolution and aspect ratio. I want to add padding (left/right or top/bottom) to all images to make them of equal size before they are converted into video frames. How can I achieve this in efficient way?
It would be nice if I can specify output resolution and all images are either scaled down or up keeping their aspect ratio intact according to that resolution.
I have got it working through this way:
ffmpeg -r 1 -i image%4d.png -i audio.mp3 -filter_complex scale=w=%d:h=%d:force_original_aspect_ratio=1,pad=%d:%d:(ow-iw)/2:(oh-ih)/2 -c:v libx264 -c:a aac -pix_fmt yuv420p -r 1 -y output.mp4
This way aspect ratio of input images remain intact and also it solves odd image width/height issue. I hope this answer would help other users facing same issue.

Fastest way to Add Image into Video using FFMPEG at First 20 Seconds

Anyone knows the fastest way to add image into video at first 20 seconds?
I have tried it, but it seemed like FFMPEG re-encoded the whole video even after 20 seconds which took a long time..
here my code:
ffmpeg -i input.mp4 -i logo.png -filter_complex "overlay=5:5:enable='between(t,0,20)'" output.mp4
Fast
Use a faster -preset and stream copy (re-mux) the audio instead of re-encoding it:
ffmpeg -i input.mp4 -i logo.png -filter_complex "overlay=5:5:enable='between(t,0,20)'" -preset fast -c:a copy output.mp4
Faster
You could encode the ~20 segment conforming to the same parameters as the main input, then concatenate with the concat demuxer in stream copy mode. However, this will be troublesome because conforming parameters is not trivial for most users, the concat inpoint directive is not guaranteed to seek accurately with non-intra inputs, and you could end up with timestamp issues anyway.
Fastest
The most fastest way is to use a player to overlay the logo:
mpv --lavfi-complex="[vid1][vid2]overlay=5:5:enable='between(t,0,20)[vo]" video.mp4 --external-file=image.png

FFmpeg resize without upscaling

I am working on a script that searches for all media files in the current directory and subdirectories and then batch encodes them to H.265. I was hoping to put in some max frame sizes to make things that are 1080p to be 720p. That is the straightforward part but I have some that are 480p and I don't want those to end up as 720p. How can I modify my ffmpeg filters to take that into account?
The command:
ffmpeg -i input -c:v hevc_nvenc -preset medium -crf 28 -c:a copy output.mp4
Use:
-vf "scale=-2:min'(720,ih)'"
or
-vf "scale=min'(1280,iw)':-2"
See :
FFmpeg Arithmetic Expression for a list of accepted functions
FFmpeg Filters: Scale for more info on the scale filter

FFmpeg Slideshow issues

trying to get my head around ffmpeg to create a slideshow where each image is displayed for ~5 seconds with some audio. created a bat file to run the following so far:
ffmpeg -f image2 -i image-%%03d.jpg -i music.mp3 output.mpg
It gets the images and displayes them all very fast in the first second of the video, it then plays out the rest of the audio while showing the last image.
I want to make the images stay up longer (about 5 seconds), and stop the video after the last frame (not playing the rest of the song), are either of these things possible? i could hack the frame rate thing i guess by having hundreds of the same image in order to keep it up longer, but this is far from ideal!
Thanks
The default encoder for mpg output, mpeg1video, is strict about the allowed frame rates, so an input and an output -r are required:
ffmpeg -r 1/5 -i image-%03d.jpg -i music.mp3 -r 25 -qscale:v 2 -shortest -codec:a copy output.mpg
The input images will have a frame rate of 1 frame every 5 seconds and the output will duplicate frames to reach 25 frames per second.
-f image2 is generally not required.
-qscale:v can control output quality. A sane range is 2-5.
-shortest will make the output duration the same as the shortest input duration.
-codec:a copy copy your MP3 audio instead of re-encoding.
MPEG-1 video has more modern alternatives. See the FFmpeg and x264 Encoding Guide for more info.
Also see:
* FFmpeg FAQ: How do I encode single pictures into movies?
* FFmpeg Wiki: Create a video slideshow from images
You could use the filter fps instead of output framerate
ffmpeg -r 1/5 -i img%03d.png -i musicfile -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4
This however skips the last image for me strangely.

How to create a video from a series of images with varying image durations?

I'd like to programmatically create a video file that is composed of a series of images. However, I'd also like to be able to specify a duration for each image. I often see ffmpeg examples suggested for similar tasks, but they always assume the same duration for each image. Is there an efficient way to accomplish this? (An inefficient solution might be setting the frame rate to something high and repeatedly copying each image until it matches the intended duration)
I will be dynamically generating each of the images as well, so if there is way to encode the image data into video frames without writing each image to disk, that's even better. This, however, is not a requirement.
Edit: To be clear, I don't necessarily need to use ffmpeg. Other free command-line tools are fine, as are video-processing libraries. I'm just looking for a good solution.
I was able to solve the exact same problem with the following commands.
vframes is set to the number of seconds * fps
In the example the first video has 100 frames (100 frame / 25 fps = 4 seconds) and second one has 200 frames (8 seconds)
ffmpeg -f image2 -loop 1 -vframes 100 -r 25 -i a.jpg -vcodec mpeg4 a.avi
ffmpeg -f image2 -loop 1 -vframes 200 -r 25 -i b.jpg -vcodec mpeg4 b.avi
mencoder -ovc copy -o out.mp4 a.mp4 b.mp4
The mencoder part is just like the one of d33pika
You can use the concat demuxer to manually order images and to provide a specific duration for each image.
ffmpeg -f concat -i input.txt -vsync vfr -pix_fmt yuv420p output.mp4
Your input.txt should look like this.
file '/path/to/dog.png'
duration 5
file '/path/to/cat.png'
duration 1
file '/path/to/rat.png'
duration 3
file '/path/to/tapeworm.png'
duration 2
file '/path/to/tapeworm.png'
You can write this txt file dynamically according to your needs and excute the command.
For more info refer to https://trac.ffmpeg.org/wiki/Slideshow
It seems like there is no way to have different durations for different images using ffmpeg. I would create separate videos for each of the images and then concat them using mencoder like this:
ffmpeg -f image2 -vframes 30 -i a.jpg -vcodec libx264 -r 1 a.mp4
ffmpeg -f image2 -vframmes 10 -i bjpg -vcodec libx264 -r 1 b.mp4
mencoder -ovc copy -o out.mp4 a.mp4 b.mp4
mencoder for the concat operation needs all the output videos to have same resolution,framerate and codec.
Here a.mp4 has 30 frames of duration 30 seconds and b.mp4 has 10 frames of 10 seconds.

Resources