go - 写入 ffmpeg 标准输入会卡住程序

标签 go ffmpeg stdin

我正在尝试使用 ffmpeg 将内存中的文件使用标准输入和标准输出转换为另一种格式,但是每次我尝试写入标准输入时,我的 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 问题,而是我如何管道/读取/写入数据的一些问题。
我的 speech.mp4 文件大约 2MB。

最佳答案

因此, secret 在于在将字节转储到标准输入时读取标准输出,因为写入管道 block 。感谢@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

关于go - 写入 ffmpeg 标准输入会卡住程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70466094/

相关文章:

c++ - 从文本文件或标准输入中读取

c - 从 stdin 读取的程序比从文件读取的效率如何?

go - 将工作外包出去,但限制 worker 数量

go - 在 golang 中更新 grpc 的接收和发送消息大小

go - 如何按Gorm中的角色过滤用户?

ffmpeg - 将视频文件容器更改为 mp4

android - 如何使用 FFmpeg 在单个命令中修剪、裁剪和添加叠加层

list - foo.Name undefined(类型接口(interface){}没有字段或方法名称)

python - 如何有效地利用多处理和多线程并行使用 python 将 1000 个视频文件转换为音频

C: Stdin - 删除多余数据