You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用io.Pipe接收FFmpeg执行结果时程序冻结问题排查

解决exec.Cmd配合io.Pipe时的冻结与无数据问题

问题根源分析

1. 程序冻结的原因

io.Pipe的读写操作是完全阻塞式的:当FFmpeg进程往io.PipeWriter写入数据时,如果没有goroutine从对应的io.PipeReader读取,写操作会一直阻塞。而你在主goroutine中调用cmd.Wait()时,主goroutine会等待FFmpeg进程退出,但FFmpeg因写Pipe被阻塞无法继续执行,最终形成双向死锁:主goroutine等FFmpeg结束,FFmpeg等Pipe有空间写数据,双方都卡住。

2. 移除Wait后无数据的原因

cmd.Wait()是用来等待子进程完全执行完毕的,移除它后,主goroutine会直接继续执行(甚至退出),此时FFmpeg进程可能还没来得及往Pipe写入数据就被终止,导致Pipe中没有内容。

解决方案

核心是协调读Pipe的goroutine、子进程启动、Wait操作和Pipe关闭的顺序,具体步骤:

  • 先启动读Pipe的goroutine,确保子进程写入时能被及时读取,避免阻塞
  • 子进程启动后,不能立即在主goroutine调用Wait,要等读操作的goroutine做好准备
  • 子进程执行完毕后,必须关闭io.PipeWriter,让读端收到EOF信号,避免读goroutine一直阻塞

修正后的代码示例

func TestCmdRunner(t *testing.T) {
    pr, pw := io.Pipe()
    defer pr.Close()

    var wg sync.WaitGroup
    wg.Add(1)
    // 先启动读数据的goroutine
    go func() {
        defer wg.Done()
        buf := make([]byte, 1024)
        for {
            n, err := pr.Read(buf)
            if err == io.EOF {
                break
            }
            if err != nil {
                t.Errorf("读取Pipe出错: %v", err)
                return
            }
            // 这里处理预览数据,比如写入临时文件或解析视频帧
            _ = buf[:n]
        }
    }()

    runner := NewCmdRunner()
    // 注意给FFmpeg指定输出格式(比如-f mp4),否则它可能不会输出到stdout
    cmd := runner.BuildCmd("ffmpeg", []string{"-i", "input.mp4", "-f", "mp4", "-"}, pw)
    if err := cmd.Start(); err != nil {
        t.Fatal(err)
    }

    // 单独goroutine等待子进程完成,完成后关闭PipeWriter
    go func() {
        if err := cmd.Wait(); err != nil {
            t.Errorf("FFmpeg执行出错: %v", err)
        }
        pw.Close() // 关闭写端,让读端收到EOF
    }()

    // 等待读操作完成
    wg.Wait()
}

额外注意点

  • FFmpeg默认可能不会将输出写入stdout,必须通过-f <格式>参数指定输出格式,同时用-表示输出到stdout
  • 必须确保io.PipeWriter被关闭,否则读goroutine会一直阻塞在Read操作上
  • 不要在主goroutine中同时做启动子进程和等待子进程的操作,要利用goroutine拆分阻塞操作

内容的提问来源于stack exchange,提问作者alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 13:52:47