将内容翻译为中文: 写入到ffpmeg的标准输入会导致程序冻结。

huangapple go评论120阅读模式
英文:

Writing to ffpmeg stdin freezes program

问题

我正在尝试使用ffmpeg将内存中的文件转换为另一种格式,通过使用stdin和stdout,但每次我尝试写入stdin时,我的ffmpeg命令就会卡住。

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "os"
  7. "os/exec"
  8. )
  9. func test(bytes []byte) ([]byte, error) {
  10. cmd := exec.Command(
  11. "ffmpeg",
  12. "-i", "pipe:0", // 从stdin读取
  13. "-vcodec", "copy",
  14. "-acodec", "copy",
  15. "-f", "matroska",
  16. "pipe:1",
  17. )
  18. in, err := cmd.StdinPipe()
  19. if err != nil {
  20. panic(err)
  21. }
  22. out, err := cmd.StdoutPipe()
  23. if err != nil {
  24. panic(err)
  25. }
  26. fmt.Println("starting")
  27. err = cmd.Start()
  28. if err != nil {
  29. panic(err)
  30. }
  31. fmt.Println("writing")
  32. w := bufio.NewWriter(in)
  33. _, err = w.Write(bytes)
  34. if err != nil {
  35. panic(err)
  36. }
  37. err = w.Flush()
  38. if err != nil {
  39. panic(err)
  40. }
  41. err = in.Close()
  42. if err != nil {
  43. panic(err)
  44. }
  45. fmt.Println("reading")
  46. outBytes, err := io.ReadAll(out)
  47. if err != nil {
  48. panic(err)
  49. }
  50. fmt.Println("waiting")
  51. err = cmd.Wait()
  52. if err != nil {
  53. panic(err)
  54. }
  55. return outBytes, nil
  56. }
  57. func main() {
  58. dat, err := os.ReadFile("speech.mp4")
  59. if err != nil {
  60. panic(err)
  61. }
  62. out, err := test(dat)
  63. if err != nil {
  64. panic(err)
  65. }
  66. err = os.WriteFile("test.m4v", out, 0644)
  67. if err != nil {
  68. panic(err)
  69. }
  70. }

它打印出:

  1. starting
  2. 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。

英文:

I'm trying to convert a file in memory using ffmpeg to another format by using stdin and stdout, but everytime I try to write to stdin, of my ffmpeg command, it just freezes there.

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "os"
  7. "os/exec"
  8. )
  9. func test(bytes []byte) ([]byte, error) {
  10. cmd := exec.Command(
  11. "ffmpeg",
  12. "-i", "pipe:0", // read from stdin
  13. "-vcodec", "copy",
  14. "-acodec", "copy",
  15. "-f", "matroska",
  16. "pipe:1",
  17. )
  18. in, err := cmd.StdinPipe()
  19. if err != nil {
  20. panic(err)
  21. }
  22. out, err := cmd.StdoutPipe()
  23. if err != nil {
  24. panic(err)
  25. }
  26. fmt.Println("starting")
  27. err = cmd.Start()
  28. if err != nil {
  29. panic(err)
  30. }
  31. fmt.Println("writing")
  32. w := bufio.NewWriter(in)
  33. _, err = w.Write(bytes)
  34. if err != nil {
  35. panic(err)
  36. }
  37. err = w.Flush()
  38. if err != nil {
  39. panic(err)
  40. }
  41. err = in.Close()
  42. if err != nil {
  43. panic(err)
  44. }
  45. fmt.Println("reading")
  46. outBytes, err := io.ReadAll(out)
  47. if err != nil {
  48. panic(err)
  49. }
  50. fmt.Println("waiting")
  51. err = cmd.Wait()
  52. if err != nil {
  53. panic(err)
  54. }
  55. return outBytes, nil
  56. }
  57. func main() {
  58. dat, err := os.ReadFile("speech.mp4")
  59. if err != nil {
  60. panic(err)
  61. }
  62. out, err := test(dat)
  63. if err != nil {
  64. panic(err)
  65. }
  66. err = os.WriteFile("test.m4v", out, 0644)
  67. if err != nil {
  68. panic(err)
  69. }
  70. }

It prints

  1. starting
  2. writing

and gets stuck there. I tried similar code with grep, and the everything worked fine, so this seems to be some ffmpeg specific problem.

I tried running

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

and that works fine, so it's not an ffmpeg problem, but some problem with how I'm piping/reading/writing my data.

My speech.mp4 file is around 2MB.

答案1

得分: 1

所以秘密就在于在将字节转储到stdin时读取stdout,因为写入管道会阻塞。感谢@JimB帮助我找出这个问题。

你只需要在写入时进行读取:

  1. cmd := exec.Command(
  2. "ffmpeg",
  3. "-i", "pipe:0", // 从stdin读取
  4. "-vcodec", "copy",
  5. "-acodec", "copy",
  6. "-f", "matroska",
  7. "pipe:1",
  8. )
  9. out, err := cmd.StdoutPipe()
  10. if err != nil {
  11. panic(err)
  12. }
  13. in, err := cmd.StdinPipe()
  14. writer := bufio.NewWriter(in)
  15. if err != nil {
  16. panic(err)
  17. }
  18. fmt.Println("开始")
  19. err = cmd.Start()
  20. if err != nil {
  21. panic(err)
  22. }
  23. go func() {
  24. defer writer.Flush()
  25. defer in.Close()
  26. fmt.Println("写入")
  27. _, err = writer.Write(bytes)
  28. if err != nil {
  29. panic(err)
  30. }
  31. }()
  32. var outBytes []byte
  33. defer out.Close()
  34. fmt.Println("读取")
  35. outBytes, err = io.ReadAll(out)
  36. if err != nil {
  37. panic(err)
  38. }
  39. fmt.Println("等待")
  40. err = cmd.Wait()
  41. if err != nil {
  42. panic(err)
  43. }
  44. return outBytes, nil
英文:

So the secret lied in reading stdout as you dumped the bytes into stdin, since writing to the pipe blocks. Thanks @JimB for helping me figure this out.

You just have to read as you write:

  1. cmd := exec.Command(
  2. "ffmpeg",
  3. "-i", "pipe:0", // read from stdin
  4. "-vcodec", "copy",
  5. "-acodec", "copy",
  6. "-f", "matroska",
  7. "pipe:1",
  8. )
  9. out, err := cmd.StdoutPipe()
  10. if err != nil {
  11. panic(err)
  12. }
  13. in, err := cmd.StdinPipe()
  14. writer := bufio.NewWriter(in)
  15. if err != nil {
  16. panic(err)
  17. }
  18. fmt.Println("starting")
  19. err = cmd.Start()
  20. if err != nil {
  21. panic(err)
  22. }
  23. go func() {
  24. defer writer.Flush()
  25. defer in.Close()
  26. fmt.Println("writing")
  27. _, err = writer.Write(bytes)
  28. if err != nil {
  29. panic(err)
  30. }
  31. }()
  32. var outBytes []byte
  33. defer out.Close()
  34. fmt.Println("reading")
  35. outBytes, err = io.ReadAll(out)
  36. if err != nil {
  37. panic(err)
  38. }
  39. fmt.Println("waiting")
  40. err = cmd.Wait()
  41. if err != nil {
  42. panic(err)
  43. }
  44. return outBytes, nil

huangapple
  • 本文由 发表于 2021年12月24日 02:28:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/70466094.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定