96

如何在 ffmpeg 中的视频上添加文本覆盖?

即给定一个视频“video1.flv”,如何在整个视频中添加“StackOverflow”文本,位于屏幕中间,带有白色文本和边框?

4

3 回答 3

201

对视频上的简单文本使用drawtext 过滤器。如果您需要更复杂的时间、格式或动态文本,请参阅字幕过滤器。这个答案侧重于drawtext过滤器。

例子

以视频为中心的文字

以白色文本打印Stack Overflow到视频中心,黑色背景框为 50% 不透明度:

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
  • 在此示例中,音频是流式复制的(如复制和粘贴)。
  • @0.5控制背景框的不透明度。0.5 是 50%。@0.5如果您不想要任何透明度,请删除。
  • 有关选项的完整列表和说明,请参阅drawtext 过滤器文档

预习

您可以使用ffplay预览文本而无需等待文件进行编码:

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

或者,您可以使用mpv,但语法略有不同:

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

多个文本

您可以链接多个绘图文本过滤器:

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

位置

xy确定文本位置:

位置 xy 使用 10 像素填充
左上方 x=0:y=0 x=10:y=10
顶部中心 x=(w-text_w)/2:y=0 x=(w-text_w)/2:y=10
右上 x=w-tw:y=0 x=w-tw-10:y=10
居中 x=(w-text_w)/2:y=(h-text_h)/2
左下方 x=0:y=h-th x=10:y=h-th-10
底部中心 x=(w-text_w)/2:y=h-th x=(w-text_w)/2:y=h-th-10
右下角 x=w-tw:y=h-th x=w-tw-10:y=h-th-10
随机的 看到这个答案

按需重新定位文本

您可以使用sendcmdzmq过滤器重新定位文本:

移动/动画/循环/滚动文本

看:

定时

使用该enable选项来控制文本出现的时间。

在 5-10 秒之间显示文本:

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

3 秒后显示文本:

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

闪烁的文字。每 10 秒显示文本 5 秒:

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

每 30 秒随机位置:

请参阅ffmpeg - 视频的动态字母和随机位置水印?

更改/更新文本

为drawtext添加textfile和选项:reload

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
  • text.txt每次您希望文本更改时更新。
  • 重要提示:您必须自动更新文本文件,否则可能会失败。您可以mv在 Linux 或 macOS 上使用该命令执行此操作。
  • 如果您有很多文本更改,例如制作字幕,则制作字幕文件(例如.ass通过 Aegisub 制作的文件)和使用字幕过滤器会更容易。

字体系列而不是字体文件

您可以声明字体系列,例如Times New Roman,而不必指向字体文件。请参阅如何在不使用 fontfile 选项的情况下在 FFMPEG 命令中包含字体?

要求

drawtext 过滤器需要ffmpeg使用--enable-libfreetype. 如果你得到No such filter: 'drawtext'它就不见了--enable-libfreetype。大多数ffmpeg可用的静态构建都支持这一点:有关链接,请参见FFmpeg 下载页面。

于 2013-07-12T21:14:39.837 回答
1

在具有 enable='between(t,0,10)' 的 macOS 上

在 macOS 上,enable='between(t,start_second, end_seconds)'的语法不同。输入应该以秒为单位,而不是 hh:mm:ss。

我的 ffmpeg 版本 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
于 2021-07-07T11:13:12.990 回答
0

这是所有 4 个方向的叠加过渡的备忘单...

************************* 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

************************ 图片 *********************

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

************************ 动图 *********************

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
于 2022-01-13T09:39:55.727 回答