Go调用ffmpeg最稳妥方式是直接执行系统命令而非cgo绑定:需设Context超时、用参数切片防注入、解析stderr获进度、正确关闭Stdin、结合退出码与错误信息判断成败,并注意Windows路径编码问题。

Go 直接调用 ffmpeg 命令是最简单可靠的方式
Go 标准库没有内置 FFmpeg 绑定,强行用 cgo 接入 libav 系列库不仅编译链脆弱、跨平台麻烦,还极易因版本不匹配触发段错误或内存泄漏。绝大多数实际场景下,直接执行系统已安装的 ffmpeg 二进制更稳——只要确保环境里有它(比如 Docker 镜像里 apt install ffmpeg 或 Alpine 的 apk add ffmpeg),就能快速落地。
关键不是“能不能调”,而是“怎么调得安全、可观察、不卡死”:
-
exec.Command启动时务必设置Context并传入超时(如context.WithTimeout(ctx, 30*time.Second)),避免视频转码卡住整个 goroutine - 必须显式捕获
cmd.CombinedOutput()或分别读取StdoutPipe/StderrPipe,否则 stderr 被丢弃会导致失败无声无息 - 不要拼接字符串构造命令行,用参数切片:
exec.Command("ffmpeg", "-i", inputPath, "-vf", "scale=640:360", outputPath),防止路径含空格或特殊字符被 shell 解析错 - 若需实时获取进度(如上报转码百分比),得解析
ffmpeg的 stderr 输出流,匹配类似frame= 1234 fps= 24 q=28.0 size= 5678kB time=00:00:45.23 bitrate=1024kbits/s这样的行,别指望 JSON 进度输出(-progress需额外 pipe 处理)
处理长视频时必须重定向 Stdin 并关闭,否则 ffmpeg 可能阻塞
当用 ffmpeg -i - 从 stdin 读取数据(例如接收 HTTP 流或内存 buffer),Go 侧必须显式调用 cmd.Stdin.Close() 告诉 ffmpeg “输入结束了”。否则它会一直等,直到上下文超时或进程被杀。
典型写法:
立即学习“go语言免费学习笔记(深入)”;
cmd := exec.CommandContext(ctx, "ffmpeg", "-i", "-", "-c:v", "libx264", "-f", "mp4", outputPath)
stdin, _ := cmd.StdinPipe()
go func() {
defer stdin.Close()
io.Copy(stdin, videoReader) // videoReader 可以是 bytes.Reader、http.Response.Body 等
}()
err := cmd.Run()
注意:io.Copy 完成后必须 Close(),且不能在 cmd.Run() 之后才关——顺序错了就卡死。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
ffmpeg 返回非零码不等于失败,要检查具体错误类型
ffmpeg 对某些“软性问题”(如输入文件末尾损坏、个别帧解码失败)默认仍返回 0,而有些警告(如 bit rate 不匹配)却可能返回 1。不能只看 err != nil 就判定失败。
实操建议:
- 始终检查
cmd.ProcessState.ExitCode(),但更要结合 stderr 内容判断——比如出现Invalid data found when processing input或moov atom not found才真出问题 - 对关键任务(如用户上传视频转码),建议加一道验证:用
ffprobe -v quiet -show_entries format=duration -of default=nw=1 input.mp4确认输出文件能被正确解析且时长合理 - 如果只是截图(
-vframes 1),即使输入视频严重损坏,ffmpeg也可能成功生成首帧图并返回 0,这时需额外校验输出文件是否为有效 JPEG/PNG
Windows 下路径和编码容易翻车,优先用绝对路径 + UTF-8 环境
Windows 默认控制台是 GBK 编码,而 Go 源文件多为 UTF-8,一旦文件路径含中文,exec.Command 传入的字符串可能被错误解码,导致 ffmpeg 报 No such file or directory 却找不到原因。
稳妥做法:
- 所有输入/输出路径统一转为绝对路径(
filepath.Abs(path)),避免相对路径在不同工作目录下行为不一致 - 开发机和部署机都设系统环境变量
GODEBUG=mmap=1(非必需)+ 确保终端支持 UTF-8(Windows Terminal 默认 OK,旧版 cmd.exe 建议换) - 实在绕不开编码问题,可先将文件复制到临时路径(如
os.TempDir()下的英文名文件),再让ffmpeg处理那个临时路径
跨平台脚本里,永远假设 Windows 是最挑剔的那个——不是它不行,是它报错方式太沉默。

















