通过Golang exec运行FFMPEG命令

4

我需要运行一个ffmpeg命令,从图像中创建一个视频,并在图像之间使用淡入淡出作为过渡效果。该命令源自这个帖子。我需要通过Golang的os/exec包来运行它。我需要运行的命令是:

ffmpeg -loop 1 -t 5 -i img-0.png -loop 1 -t 5 -i img-1.png -loop 1 -t 5 -i img-2.png -filter_complex "[1:v][0:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b1v];[2:v][1:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b2v];[0:v][b1v][1:v][b2v][2:v]concat=n=5:v=1:a=0,format=yuv420p[v]" -map '[v]' -c:v libx264 -pix_fmt yuv420p -r 30 -s 1280x720 -aspect 16:9 -crf 1 -preset ultrafast output.mp4

如果你直接在终端运行这个命令,它可以正常工作。然而,在我的代码中它无法正常工作。这是我的代码,它接受一个字符串命令并通过os/exec包来运行:

command := "ffmpeg -loop 1 -t 5 -i img-0.png -loop 1 -t 5 -i img-1.png -loop 1 -t 5 -i img-2.png -filter_complex "[1:v][0:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b1v];[2:v][1:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b2v];[0:v][b1v][1:v][b2v][2:v]concat=n=5:v=1:a=0,format=yuv420p[v]" -map '[v]' -c:v libx264 -pix_fmt yuv420p -r 30 -s 1280x720 -aspect 16:9 -crf 1 -preset ultrafast output.mp4"

lastQuote := rune(0)
f := func(c rune) bool {
    switch {
    case c == lastQuote:
        lastQuote = rune(0)
        return false
    case lastQuote != rune(0):
        return false
    case unicode.In(c, unicode.Quotation_Mark):
        lastQuote = c
        return false
    default:
        return unicode.IsSpace(c)
    }
}
parts := strings.FieldsFunc(command, f)

cmd := exec.Command(parts[0], parts[1:]...)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout

err := cmd.Run()
if err != nil {
    return err
}

当我运行这个命令时,出现ffmpeg错误:没有这样的过滤器:'"',配置过滤器时出错。我知道这与必须在视频过滤器中使用引号有关,但我已经尝试了一切来使其工作,但我无法弄清楚原因。
非常感谢您的帮助!

你的字段函数没有移除包含的引号。不要试图对shell输入进行词法分析,为什么不使用一个正确处理它的包,或者直接将字符串传递给shell执行呢? - JimB
我尝试运行没有过滤器复杂性周围的引号的命令,因为即使直接从终端运行也可以工作,但是我收到了这个错误:在“gte(T”中缺少“)”或太多参数 [AVFilterGraph @ 0x3b94ee0] 错误初始化带有参数'all_expr=A*(if(gte(T'的过滤器'blend' 配置过滤器时出错。 - jrkt
1
是的,我不确定你想用那个开关实现什么,但我的感觉是你不应该有任何那样的东西。只需将“ffmpeg”作为第一个参数传递,然后使用反引号来创建字符串文字(因为标记使其成为代码片段而无法在此处执行),以便您可以保留命令中必需的引号,并将ffmpeg之后的所有内容作为单个字符串传递,而不是将其分开并尝试使用parts [1:]...扩展数组。除非您真的需要微调这些参数,否则我认为您只是增加了不必要的工作量。 - evanmcdonnal
该开关通过遵守周围引号来将可能包含空格的参数组合为一个参数。 - jrkt
1
在 shell 中引用参数不会将引号传递给程序。你可以正确地对其进行词法分析,或者让 shell 为你运行命令。 - JimB
无论你认为我做得完全错误,它都不起作用。这就是提问的目的。我已经尝试了多种方法来使其工作。你给出了两个可能的解决方案,但没有任何示例。 - jrkt
1个回答

7
实际上,这确实可以正常工作:
exec.Command("ffmpeg", "-loop", "1", "-t", "5", "-i", "img-0.png", "-loop",  "1", "-t", "5", "-i", "img-1.png", "-loop", "1", "-t", "5", "-i", "img-2.png", "-filter_complex", "[1:v][0:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b1v];[2:v][1:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b2v];[0:v][b1v][1:v][b2v][2:v]concat=n=5:v=1:a=0,format=yuv420p[v]", "-map", "[v]", "-c:v", "libx264", "-pix_fmt", "yuv420p", "-r", "30", "-s", "1280x720", "-aspect", "16:9", "-crf", "1", "-preset", "ultrafast", "output.mp4")

请注意,我从-filter_complex参数中删除了起始和结束双引号,并从-map参数中删除了两个单引号。
虽然是手动操作的,但不确定是否有一个strings函数可以自动完成。

谢谢你的帮助。 - Murtadha S.
@MurtadhaS. 你找到解决方案了吗?使用 strings.replace 不起作用。 - Stefanos Chrs

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