我正在尝试使用 youtube-dl 和 ffmpeg 创建音乐流服务。当用户发送带有视频 URL 的 POST 请求时,我的处理程序代码的工作原理如下所示:
router.POST("/submit", func(c *gin.Context) {
body := Body{}
if err := c.BindJSON(&body); err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
}
w := c.Writer
header := w.Header()
header.Set("Content-Type", "audio/mp3")
w.WriteHeader(http.StatusOK)
fetchMusic(c, body.Data)
})
func fetchMusic(c *gin.Context, data string) {
r, w := io.Pipe()
defer r.Close()
ydl := exec.Command("youtube-dl", data, "-o-")
ffmpeg := exec.Command("ffmpeg", "-i", "/dev/stdin", "-vn", "-f", "mp3", "-")
ydl.Stdout = w
ydl.Stderr = os.Stderr
ffmpeg.Stdin = r
ffmpeg.Stdout = c.Writer
ffmpeg.Stderr = os.Stderr
fmt.Println("Starting-----------------------")
go func() {
if err := ydl.Run(); err != nil {
panic(err)
}
}()
if err := ffmpeg.Run(); err != nil {
panic(err)
}
fmt.Println("Done-----------------------")
}
我用 ffmpeg 和 youtube-dl 创建了一个管道。在测试阶段,我发送了 POST 请求,但请求未完成。如果我查看日志,我看不到“完成----------------”。我认为这个过程似乎被卡住了。你有什么主意吗?我的用法正确吗?
这非常接近了——我们还需要关闭
*io.PipeWriter
。
否则
ffmpeg
认为可以传输更多数据。这将在程序中显示为 EOF
。
这是我拼凑在一起的一个可运行示例,使用
echo
和 cat
代替。您应该能够通过注释掉新的 defer w.Close()
: 来重现该问题
package main
import (
"fmt"
"io"
"os"
"os/exec"
)
func main() {
r, w := io.Pipe()
defer r.Close()
echo := exec.Command("echo", "hello")
cat := exec.Command("cat")
echo.Stdout = w
echo.Stderr = os.Stderr
cat.Stdin = r
cat.Stdout = os.Stdout
cat.Stderr = os.Stderr
fmt.Println("Starting-----------------------")
go func() {
// -- I added this --
defer w.Close()
if err := echo.Run(); err != nil {
panic(err)
}
}()
if err := cat.Run(); err != nil {
panic(err)
}
fmt.Println("Done-----------------------")
}