Text on video ffmpeg - ffmpeg

How can I add text overlay on my video in ffmpeg?
i.e. given a video "video1.flv", how can I add "StackOverflow" text during the whole video, positioned in the middle of the screen, with white text and a border?

Use the drawtext filter for simple text on video. If you need more complex timing, formatting, or dynamic text see the subtitles filter. This answer focuses on the drawtext filter.
Example
Print Stack Overflow in white text onto center of video, with black background box of 50% opacity:
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2" -codec:a copy output.mp4
The audio is stream copied in this example (like a copy and paste).
#0.5 controls background box opacity. 0.5 is 50%. Remove #0.5 if you do not want any transparency.
See the drawtext filter documentation for a complete list and explanations of options.
Preview
You can use ffplay to preview your text without having to wait for a file to encode:
ffplay -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2" input.mp4
Alternatively you can use mpv but the syntax is slightly different:
mpv --vf="lavfi=[drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2]" input.mp4
Multiple texts
You can chain multiple drawtext filters:
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2,drawtext=fontfile=/path/to/font.ttf:text='Bottom right text':fontcolor=black:fontsize=14:x=w-tw-10:y=h-th-10" -codec:a copy output.mp4
Position
x and y determine text position:
Position
x:y
With 10 px padding
Top left
x=0:y=0
x=10:y=10
Top center
x=(w-text_w)/2:y=0
x=(w-text_w)/2:y=10
Top right
x=w-tw:y=0
x=w-tw-10:y=10
Centered
x=(w-text_w)/2:y=(h-text_h)/2
Bottom left
x=0:y=h-th
x=10:y=h-th-10
Bottom center
x=(w-text_w)/2:y=h-th
x=(w-text_w)/2:y=h-th-10
Bottom right
x=w-tw:y=h-th
x=w-tw-10:y=h-th-10
Random
See this answer
Repositioning text on demand
You can reposition the text with the sendcmd and zmq filters:
sendcmd if you have predetermined positions and timing. See Sendcmd in ffmpeg and FFmpeg drawtext filter - is it possible to use variables with live data for x,y coordinates?
zmq for live, on-the-fly positioning. See ffmpeg cli filter that require user input.
Moving / animated / looping / scrolling text
See:
ffmpeg moving text drawtext
Loop text that wipes left to right using FFMPEG drawtext filter
Scrolling from RIGHT to LEFT in ffmpeg / drawtext
Timing
Use the enable option to control when the text appears.
Show text between 5-10 seconds:
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2:enable='between(t,5,10)'" -codec:a copy output.mp4
Show text after 3 seconds:
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2:enable='gte(t,3)'" -codec:a copy output.mp4
Blinking text. For every 10 seconds show text for 5 seconds:
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2:enable='lt(mod(t,10),5)'" -codec:a copy output.mp4
Random position every 30 seconds:
See ffmpeg - Dynamic letters and random position watermark to video?
Changing / updating text
Add the textfile and reload options for drawtext:
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:textfile=text.txt:reload=1:fontcolor=white:fontsize=24:box=1:boxcolor=black#0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2" -codec:a copy output.mp4
Update text.txt every time you want the text to change.
Important: You must update the text file atomically or it may fail. You can do this with the mv command on Linux or macOS.
If you have many text changes, such as making subtitles, it is easier to make a subtitle file (such as an .ass file via Aegisub) and using the subtitles filter.
Font family instead of font file
You can declare the font family, such as Times New Roman, instead of having to point to a font file. See How to include font in FFMPEG command without using the fontfile option?
Requirements
The drawtext filter requires ffmpeg to be compiled with --enable-libfreetype. If you get No such filter: 'drawtext' it is missing --enable-libfreetype. Most of the ffmpeg static builds available support this: see the FFmpeg Download page for links.

Here is the cheat sheet for overlay transition in all 4 direction...
************************* Text **********************
1) left to right given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': y=53.48 :x=min(t*250-2*250\,41): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': y=53.48 :x=min(t*250-3*250\,90): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 leftToRight.mp4
2) right to left given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': y=53.48 :x=w-min(t*250-2*250\,(w\-41)): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': y=53.48 :x=w-min(t*250-3*250\,(w\-90)): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 rightToLeft.mp4
3) top to bottom given y=58 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': x=41 :y=min(t*250-2*250\,53.48): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': x=90 :y=min(t*250-3*250\,53.48): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 topToBottom.mp4
4) bottom to up given y=90 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': x=41 :y=h-min(t*250-2*250\,(h\-53.48)): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': x=90 :y=h-min(t*250-3*250\,(h\-53.48)): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 bottomToTop.mp4
************************ Image *********************
1) single left to right given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -filter_complex "[1:v]scale=-2:100[png];[0:v][png]overlay=x=min(t*250-2*250\,41):y=60:shortest=1:enable='between(t,2,10)'" -t 11 imageLeftToRight1.mp4
ffmpeg -y -i 'https://player.vimeo.com/external/181472383.sd.mp4?s=103f42915141758d95a118f070d08190845bdf73&profile_id=164' -loop 1 -i image.png -filter_complex "[1:v]scale=-2:100[png];[0:v][png]overlay=x=min(t*250-2*250\,41):y=60:shortest=1:enable='between(t,2,10)'" -t 11 imageLeftToRight.mp4
2) Already added text then added single image left to right
ffmpeg -y -i leftToRight.mp4 -loop 1 -i image.png -filter_complex "[1:v]scale=-2:100[png];[0:v][png]overlay=x=min(t*250-2*250\,41):y=200:shortest=1:enable='between(t,2,10)'" -t 11 imageTextLeftToRight.mp4
3) 2 images left to right given x=41, x=100 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[0][img1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=min(t*250-3*250\,100):y=200:enable='between(t,3,10)':shortest=1" -t 11 multiImageLeftToRight.mp4
4) 3 images left to right given x=41, x=100, x=300 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=min(t*250-3*250\,130):y=130:enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=min(t*250-4*250\,260):y=190:enable='between(t,4,10)':shortest=1" -t 11 threeImageLeftToRight.mp4
5) 3 images right to left given x=41, x=100, x=300 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=W-min(t*250-2*250\,(W\-41)):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=W-min(t*250-3*250\,(W\-130)):y=130:enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=W-min(t*250-4*250\,(W\-260)):y=190:enable='between(t,4,10)':shortest=1" -t 11 threeImageRightToLeft.mp4
6) 3 images top to bottom given y=41, y=100, y=300 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=41:y=min(t*250-2*250\,60):enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=130:y=min(t*250-3*250\,130):enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=260:y=min(t*250-4*250\,190):enable='between(t,4,10)':shortest=1" -t 11 threeImageTopToBottom.mp4
7) 3 images bottom to top given y=41, y=100, y=300 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=41:y=H-min(t*250-2*250\,(H\-60)):enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=130:y=H-min(t*250-3*250\,(H\-130)):enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=260:y=H-min(t*250-4*250\,(H\-190)):enable='between(t,4,10)':shortest=1" -t 11 threeImageBottomToTop.mp4
************************ GIF *********************
1) single left to right given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -filter_complex "[1:v]scale=-2:100[ovrl];[0:v][ovrl]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)'" -t 11 gifLeftToRight.mp4
2) double left to right given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[0][gif1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=min(t*250-3*250\,150):y=170:enable='between(t,3,10)':shortest=1" -t 11 doubleGifLeftToRight.mp4
3) three left to right given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=min(t*250-3*250\,150):y=170:enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=min(t*250-4*250\,240):y=240:enable='between(t,4,10)':shortest=1" -t 11 threeGifLeftToRight.mp4
3) three right to left given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=W-min(t*250-2*250\,(W\-41)):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=W-min(t*250-3*250\,(W\-150)):y=170:enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=W-min(t*250-4*250\,(W\-240)):y=240:enable='between(t,4,10)':shortest=1" -t 11 threeGifRightToLeft.mp4
3) three top to bottom given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=41:y=min(t*250-2*250\,60):enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=150:y=min(t*250-3*250\,170):enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=240:y=min(t*250-4*250\,240):enable='between(t,4,10)':shortest=1" -t 11 threeGifTopToBottom.mp4
3) three bottom to top given x=41 position
ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=41:y=H-min(t*250-2*250\,(H\-60)):enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=150:y=H-min(t*250-3*250\,(H\-170)):enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=240:y=H-min(t*250-4*250\,(H\-240)):enable='between(t,4,10)':shortest=1" -t 11 threeGifBottomToTop.mp4

On macOS with enable='between(t,0,10)'
On macOS the syntax of enable='between(t,start_second, end_seconds)' is different. Input should be in seconds, not in hh:mm:ss.
My ffmpeg version 4.3.1
ffmpeg -i input.mp4 -vf "drawtext=text='My Text':enable='between(t,20,120)': x=(w-text_h)/2: y=(h-text_h)/2: fontsize=32: fontcolor=white: box=1: boxcolor=black#0.5: boxborderw=5:" -c:a copy output.mp4

Related

I want to pipe these two ffmpeg commands for to convert a video to grayscale frames

Please, I want to pipe these two commands.
ffmpeg -i input.flv -vf fps=1 out%d.png | ffmpeg -i input -vf format=gray output
If you just need frames, try this:
ffmpeg -i input.flv -r 1 -pix_fmt gray out%d.png
There is no need to call it twice
-r sets the output frame rate (1 frame/sec) dropping excess frames
pix_fmt sets the output pixel format
[edit]
Try this to output both grayscale video and images:
ffmpeg -i input.flv \
-filter_complex format=gray,split[v0][v1]
-map [v0] -r 1 out%d.png
-map [v1] output.mp4

How to overlay a video on another video and also fade in a PNG

I am looking to overlay a video on top of another video and then also add a fade in and fade out PNG.
I have the current command which works perfectly in merging two video files one on top of the other.
ffmpeg -y -i output.mp4 -i transparent.mp4 -filter_complex "[1:v][0:v]scale2ref[ua][b];[ua]setsar=1,format=yuva444p,colorchannelmixer=aa=.7[u];[b][u]overlay=eof_action=pass[v]" -map [v] awsome.mp4
I need to now add a PNG on it as well that fades in at 1s and fades out at 9.5s.
Appreciate any and all advice.
Use
ffmpeg -y -i output.mp4 -i transparent.mp4 -loop 1 -t 10 -i image.png -filter_complex "[1:v][0:v]scale2ref[ua][b];[ua]setsar=1,format=yuva444p,colorchannelmixer=aa=.7[u];[b][u]overlay=eof_action=pass[v];[2]fade=in:st=0:d=1:alpha=1,fade=out:st=8.5:d=1:alpha=1[i];[v][i]overlay[v]" -map [v] awsome.mp4
If the PNG needs to be scaled to video size, use scale2ref for the image as well.
ffmpeg -y -i output.mp4 -i transparent.mp4 -loop 1 -t 10 -i image.png -filter_complex "[1:v][0:v]scale2ref[ua][b];[ua]setsar=1,format=yuva444p,colorchannelmixer=aa=.7[u];[b][u]overlay=eof_action=pass[v];[2][v]scale2ref[i][v];[i]fade=in:st=0:d=1:alpha=1,fade=out:st=8.5:d=1:alpha=1[i];[v][i]overlay[v]" -map [v] awsome.mp4

FFMPEG zoompan image is cut off

Hi I'm using zoompan to resize an image overlay on a video using ffmpeg, but my image got cut off by the boundary after setting its size, like the following:
ffmpeg -y -i 6.mp4 -loop 1 -i watermark.png -filter_complex "[1:v]zoompan=z=2:d=50:x=0:y=0:s='280x105'[1v];[0:v][1v]overlay=x=0:y=0" -t 8 test.mp4
If I remove the size, it becomes really big covering all screen, like following:
ffmpeg -y -i 6.mp4 -loop 1 -i watermark.png -filter_complex "[1:v]zoompan=z=2:d=50:x=0:y=0[1v];[0:v][1v]overlay=x=0:y=0" -t 8 test.mp4
How do we zoom an overlay image while scaling its size?

ffmpeg adjust contrast, show histogram

I'm trying to first adjust the contrast of a frame extracted from an mp4, then overlay the histogram of the resultant frame on top. My command here does all of this, but also adjusts the contrast of the histogram itself. Is there a single ffmpeg command that can do what I wish?
ffmpeg -ss 3.5 -i in.mp4 -an -y -vf \
"split=2[a][b],[b]eq=0.5:0:1:1:1:1:1,histogram=levels_mode=logarithmic:\
components=1:level_height=100, [a]overlay,eq=0.5:0:1:1:1:1:1" \
-vframes 1 -q:v 2 out.jpg
Use
ffmpeg -ss 3.5 -i in.mp4 -an -y -filter_complex \
"eq=0.5:0:1:1:1:1:1,split=2[a][b];[b]histogram=levels_mode=logarithmic:\
components=1:level_height=100[b];[a][b]overlay" -vframes 1 -q:v 2 out.jpg

How to add 'drawtext' to overlay in ffmpeg?

The command is ffmpeg -loop 1 -t 5 -i "demo_1.jpg" -filter_complex "nullsrc=size=640x360[background];[background][0:v]overlay=shortest=1:x='min(-(t)*20,0)'" -qscale 1 -y out.mp4
I am animating the image from right to left. In the above command, I need to add text, How to integrate the drawtext feature of ffmpeg to that.
The video animation is https://youtu.be/teXUiPKX83o.
Need to add text to that video.
Use
ffmpeg -loop 1 -t 5 -i "demo_1.jpg" -filter_complex
"nullsrc=size=640x360[background];
[background][0:v]overlay=shortest=1:x='min(-(t)*20,0)',
drawtext=fontfile='/path/to/font':fontsize=30:fontcolor=yellow:x=50:y=50:text='Text'"
-qscale 1 -y out.mp4
See drawtext docs for more info.

Resources