写入 ffmpeg stdin 会冻结程序

Writing to ffpmeg stdin freezes program

我正在尝试使用 stdin 和 stdout 将使用 ffmpeg 的内存中的文件转换为另一种格式,但每次我尝试写入 stdin 时,我的 ffmpeg 命令都会冻结在那里。

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "os/exec"
)

func test(bytes []byte) ([]byte, error) {

    cmd := exec.Command(
        "ffmpeg",
        "-i", "pipe:0", // read from stdin
        "-vcodec", "copy",
        "-acodec", "copy",
        "-f", "matroska",
        "pipe:1",
    )

    in, err := cmd.StdinPipe()
    if err != nil {
        panic(err)
    }
    out, err := cmd.StdoutPipe()
    if err != nil {
        panic(err)
    }

    fmt.Println("starting")
    err = cmd.Start()
    if err != nil {
        panic(err)
    }

    fmt.Println("writing")
    w := bufio.NewWriter(in)
    _, err = w.Write(bytes)
    if err != nil {
        panic(err)
    }

    err = w.Flush()
    if err != nil {
        panic(err)
    }

    err = in.Close()
    if err != nil {
        panic(err)
    }

    fmt.Println("reading")
    outBytes, err := io.ReadAll(out)
    if err != nil {
        panic(err)
    }

    fmt.Println("waiting")
    err = cmd.Wait()
    if err != nil {
        panic(err)
    }

    return outBytes, nil
}

func main() {
    dat, err := os.ReadFile("speech.mp4")
    if err != nil {
        panic(err)
    }

    out, err := test(dat)
    if err != nil {
        panic(err)
    }

    err = os.WriteFile("test.m4v", out, 0644)
    if err != nil {
        panic(err)
    }
}


它打印

starting
writing

然后卡在那里。我用 grep 尝试了类似的代码,一切正常,所以这似乎是一些 ffmpeg 特定的问题。

我试过了运行

cat speech.mp4 | ffmpeg -i pipe:0 -vcodec copy -acodec copy -f matroska pipe:1 | cat > test.mkv

而且效果很好,所以这不是 ffmpeg 问题,而是我 piping/reading/writing 我的数据存在一些问题。

我的 speech.mp4 文件大约有 2MB。

所以秘密在于当您将字节转储到标准输入时读取标准输出,因为写入管道块。感谢@JimB 帮我解决了这个问题。

你只需要边写边读:

cmd := exec.Command(
    "ffmpeg",
    "-i", "pipe:0", // read from stdin
    "-vcodec", "copy",
    "-acodec", "copy",
    "-f", "matroska",
    "pipe:1",
)

out, err := cmd.StdoutPipe()
if err != nil {
    panic(err)
}

in, err := cmd.StdinPipe()
writer := bufio.NewWriter(in)
if err != nil {
    panic(err)
}

fmt.Println("starting")
err = cmd.Start()
if err != nil {
    panic(err)
}

go func() {
    defer writer.Flush()
    defer in.Close()
    fmt.Println("writing")
    _, err = writer.Write(bytes)
    if err != nil {
        panic(err)
    }
}()

var outBytes []byte

defer out.Close()
fmt.Println("reading")
outBytes, err = io.ReadAll(out)
if err != nil {
    panic(err)
}
fmt.Println("waiting")
err = cmd.Wait()
if err != nil {
    panic(err)
}

return outBytes, nil