写入 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
我正在尝试使用 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