FFmpeg在多行上绘制文本

19
我有这段代码:
import subprocess , os

ffmpeg = "C:\\ffmpeg_10_6_11.exe"
inVid = "C:\\test_in.avi"
outVid = "C:\\test_out.avi"

if os.path.exists( outVid ):
os.remove( outVid )
proc = subprocess.Popen(ffmpeg + " -i " + inVid + ''' -vf drawtext=fontfile=/Windows/Fonts/arial.ttf:text="onLine1 onLine2 onLine3":fontcolor=white:fontsize=20 -y ''' + outVid , shell=True, stderr=subprocess.PIPE)
proc.wait()
print proc.stderr.read()
os.startfile( outVid )

如何将文本写入视频文件?但我想要将多行文本写出,而不仅仅是一行。
我该如何做到这一点?
6个回答

32
您可以使用[in]标签并使用逗号列出每个drawtext来在一个文件上指定多个drawtexts。这样可以通过各自的定位方法来使每个drawtext朝向不同的方向,从而使用多行文本。在您的示例中,命令行应该类似于这样(将第一行放在屏幕中间,并将每个后续行向下移动25像素):
ffmpeg -i test_in.avi -vf "[in]drawtext=fontsize=20:fontcolor=White:fontfile='/Windows/Fonts/arial.ttf':text='onLine1':x=(w)/2:y=(h)/2, drawtext=fontsize=20:fontcolor=White:fontfile='/Windows/Fonts/arial.ttf':text='onLine2':x=(w)/2:y=((h)/2)+25, drawtext=fontsize=20:fontcolor=White:fontfile='/Windows/Fonts/arial.ttf':text='onLine3':x=(w)/2:y=((h)/2)+50[out]" -y test_out.avi

1
工作正常 :) 但有点繁琐。 - Dorian Grv

23

查看 ffmpeg (vs_drawtext.c) 中的源代码:

static inline int is_newline(uint32_t c)
{
    return c == '\n' || c == '\r' || c == '\f' || c == '\v';
}

因此您可以尝试在文本行中插入\f\v,它们分别对应于^L^K字符。例如:

-filter_complex "[in] drawtext=fontsize=40:fontcolor=white:fontfile=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf:x=(w-tw)/2:y=(h-th)/2:box=1:boxcolor=black@0.5:text='two^Llines'[out]"

^L 表示实际的 Ctrl-L 字符,而不是明显的 ^L 分别表示的两个字符。


8
谢谢您对源代码的提及,欢迎来到Stack Overflow! - GargantuChet
2
在大多数终端中输入 ^L,您可以先按 Ctrl-V 然后再按 Ctrl-L - neuro_sys
1
我无法让它与此配合工作,有人能否将字符发送给我到其他网站或其他地方? - Gaspar
无法工作(在MacOS上使用ffmpeg v4.3.1),我得到了“two^Llines”写在我的视频上。 - Vincent
不适用于带有FFmpeg版本4.3.2-2021-02-27-full_build-www.gyan.dev的Windows操作系统。 - Dorian Grv
显示剩余2条评论

14

我只是在命令中添加了新的行,ffmpeg就能够正确处理它。

ffmpeg -i input.avi -vf "[in]drawtext=fontsize=20:text='hello
world':x=(w)/2:y=(h)/2:fontcolor=white[out]" -y out.mp4

不需要使用Ctrl+L,Ctrl+K的技巧!

也就是说,我在“hello”后面按了Enter键。

您可以在编辑脚本文件甚至bash命令行中执行此操作。


6

我已经通过指定“textfile”参数并将文本放入该文件中,成功地从命令行中使其工作。

请参见http://ffmpeg.org/libavfilter.html#drawtext以获取更多帮助。在Windows上使用ffmpeg build N-35057-g2c44aed,但重要的是您拥有最近版本的libavfilter。


是的,我已经把那个作为一个解决方法放在那里了,但我不喜欢我的脚本不停地创建和删除文件的事实。顺便说一下,你也可以多次调用drawtext标记,并通过在Y轴上偏移文本来创建新行。我已经测试过并使其运行正常,但正如我的问题所述,我希望能够使用一个drawtext标记添加多行文本,而不必创建外部文件。不过还是感谢你抽出时间来回答。非常感激 :) - Jay

0
只需将文本按一定长度(20个字符,您可以根据需要进行设置)拆分成行,然后再传递给ffmpeg
import subprocess , os

ffmpeg = "C:\\ffmpeg_10_6_11.exe"
inVid = "C:\\test_in.avi"
outVid = "C:\\test_out.avi"
length = 20
txt = "onLine1 onLine2 onLine3"
inpTxt = split_txt_into_multi_lines(txt,length)

if os.path.exists( outVid ):
  os.remove( outVid )
  proc = subprocess.Popen(ffmpeg + " -i " + inVid + f''' -vf drawtext=fontfile=/Windows/Fonts/arial.ttf:text={inpTxt}:fontcolor=white:fontsize=20 -y ''' + outVid , shell=True, 
  stderr=subprocess.PIPE)
  proc.wait()
  print proc.stderr.read()
  os.startfile( outVid )


#################################################################
def split_txt_into_multi_lines(input_str: str, line_length: int):
    words = input_str.split(" ")
    line_count = 0
    split_input = ""
    for word in words:
        line_count += 1
        line_count += len(word)
        if line_count > line_length:
            split_input += "\n"
            line_count = len(word) + 1
            split_input += word
            split_input += " "
        else:
            split_input += word
            split_input += " "
    
    return split_input
        



0
TEXT=$(printf "$1") 

在一个shell脚本中
将您的文本作为shell脚本参数,包括换行符

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接