英文:
Pipe a HTTP response
问题
如何在Go中实现类似NodeJS中的HTTP响应管道?以下是我在NodeJS中使用的代码片段:
request({
url: audio_file_url,
}).pipe(ffmpeg_process.stdin);
我如何在Go中实现相同的结果?
我正在尝试将来自HTTP的音频流导入到FFmpeg进程中,以便在转换过程中实时转换,并将转换后的文件返回给客户端。
这是目前我的源代码:
func encodeAudio(w http.ResponseWriter, req *http.Request) {
path, err := exec.LookPath("youtube-dl")
if err != nil {
log.Fatal("LookPath: ", err)
}
path_ff, err_ff := exec.LookPath("ffmpeg")
if err != nil {
log.Fatal("LookPath: ", err_ff)
}
streamLink := exec.Command(path, "-f", "140", "-g", "https://www.youtube.com/watch?v=VIDEOID")
var out bytes.Buffer
streamLink.Stdout = &out
cmdFF := exec.Command(path_ff, "-i", "pipe:0", "-acodec", "libmp3lame", "-f", "mp3", "-")
resp, err := http.Get(out.String())
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
cmdFF.Stdin = resp.Body
cmdFF.Stdout = w
streamLink.Run()
errCh := make(chan error, 1)
go func() {
errCh <- cmdFF.Run()
}()
if err := <-errCh; err != nil {
// 处理FFmpeg错误
}
}
错误:2014/07/29 23:04:02 Get : unsupported protocol scheme ""
请注意,这只是一个翻译结果,我无法运行和测试您的代码。如果您有任何问题,请随时提问。
英文:
How do I pipe an HTTP response like in NodeJS. Here is the snippet I am using in NodeJS:
request({
url: audio_file_url,
}).pipe(ffmpeg_process.stdin);
How can I achieve the same result in Go?
I am trying to pipe a audio stream from HTTP into an FFmpeg process so that it converts it on the fly and returns the converted file back to the client.
Just so its clear to everyone here is my source code so far:
func encodeAudio(w http.ResponseWriter, req *http.Request) {
path, err := exec.LookPath("youtube-dl")
if err != nil {
log.Fatal("LookPath: ", err)
}
path_ff, err_ff := exec.LookPath("ffmpeg")
if err != nil {
log.Fatal("LookPath: ", err_ff)
}
streamLink := exec.Command(path,"-f", "140", "-g", "https://www.youtube.com/watch?v=VIDEOID")
var out bytes.Buffer
streamLink.Stdout = &out
cmdFF := exec.Command(path_ff, "-i", "pipe:0", "-acodec", "libmp3lame", "-f", "mp3", "-")
resp, err := http.Get(out.String())
if err != nil {
log.Fatal(err)
}
// pr, pw := io.Pipe()
defer resp.Body.Close()
cmdFF.Stdin = resp.Body
cmdFF.Stdout = w
streamLink.Run()
//get ffmpeg running in another goroutine to receive data
errCh := make(chan error, 1)
go func() {
errCh <- cmdFF.Run()
}()
// close the pipeline to signal the end of the stream
// pw.Close()
// pr.Close()
// check for an error from ffmpeg
if err := <-errCh; err != nil {
// ff error
}
}
Error: 2014/07/29 23:04:02 Get : unsupported protocol scheme ""
答案1
得分: 3
这是一个使用标准的HTTP处理函数的可能答案。我没有测试这个代码,但是可以使用一些简单的shell命令作为代理来测试。
func encodeAudio(w http.ResponseWriter, req *http.Request) {
streamLink := exec.Command("youtube-dl", "-f", "140", "-g", "https://www.youtube.com/watch?v=VIDEOID")
out, err := streamLink.Output()
if err != nil {
log.Fatal(err)
}
cmdFF := exec.Command("ffmpeg", "-i", "pipe:0", "-acodec", "libmp3lame", "-f", "mp3", "-")
resp, err := http.Get(string(out))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
cmdFF.Stdin = resp.Body
cmdFF.Stdout = w
if err := cmdFF.Run(); err != nil {
log.Fatal(err)
}
}
希望对你有帮助!
英文:
Here's a possible answer using a standard http handler function. I don't have the programs to test this directly, but it does work with some simple shell commands standing in as a proxy.
func encodeAudio(w http.ResponseWriter, req *http.Request) {
streamLink := exec.Command("youtube-dl", "-f", "140", "-g", "https://www.youtube.com/watch?v=VIDEOID")
out, err := streamLink.Output()
if err != nil {
log.Fatal(err)
}
cmdFF := exec.Command("ffmpeg", "-i", "pipe:0", "-acodec", "libmp3lame", "-f", "mp3", "-")
resp, err := http.Get(string(out))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
cmdFF.Stdin = resp.Body
cmdFF.Stdout = w
if err := cmdFF.Run(); err != nil {
log.Fatal(err)
}
}
答案2
得分: 1
http.Request.Body
是一个 io.ReadCloser
,所以你可以将它导入到 exec.Cmd
.Stdin 中:
func Handler(rw http.ResponseWriter, req *http.Request) {
cmd := exec.Command("ffmpeg", other, args, ...)
cmd.Stdin = req.Body
go func() {
defer req.Body.Close()
if err := cmd.Run(); err != nil {
// 做一些处理
}
}()
// 重定向用户并检查进度?
}
// 编辑:我误解了问题,但是答案仍然有效,http.Get
版本:
http.Response.Body
和 http.Request.Body
一样,都是 io.ReadCloser
。
func EncodeUrl(url, fn string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
cmd := exec.Command("ffmpeg", ......, fn)
cmd.Stdin = resp.Body
return cmd.Run()
}
// 编辑2:
根据 martini 文档,这个 应该 可以工作,但是我强烈建议学习使用 ServeMux 或者至少使用 Gorilla。
m := martini.Classic()
m.Get("/stream/:ytid", func(params martini.Params, rw http.ResponseWriter,
req *http.Request) string {
ytid := params["ytid"]
stream_link := exec.Command("youtube-dl","-f", "140", "-g", "https://www.youtube.com/watch?v=" + ytid)
var out bytes.Buffer
stream_link.Stdout = &out
errr := stream_link.Run()
if err != nil {
log.Fatal(err)
}
log.Println("Link", out.String())
cmd_ff := exec.Command("ffmpeg", "-i", "pipe:0", "-acodec", "libmp3lame", "-f", "mp3", "-")
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
cmd_ff.Stdin = resp.Body
go func() {
defer resp.Body.Close()
if err := cmd_ff.Run(); err != nil {
log.Fatal(err)
}
}()
return "Youtube ID: " + ytid
})
m.Run()
英文:
http.Request.Body
is an io.ReadCloser
, so you could pipe it into exec.Cmd
.Stdin:
func Handler(rw http.ResponseWriter, req *http.Request) {
cmd := exec.Command("ffmpeg", other, args, ...)
cmd.Stdin = req.Body
go func() {
defer req.Body.Close()
if err := cmd.Run(); err != nil {
// do something
}
}()
//redirect the user and check for progress?
}
//edit I misunderstood the question, however the answer still stands, the http.Get
version:
http.Response.Body
is an io.ReadCloser
just like http.Request.Body
.
func EncodeUrl(url, fn string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
cmd := exec.Command("ffmpeg", ......, fn)
cmd.Stdin = resp.Body
return cmd.Run()
}
//edit2:
this should work, according to the martini documentation, but again, I highly recommend learning to use ServeMux or at least use Gorilla.
m := martini.Classic()
m.Get("/stream/:ytid", func(params martini.Params, rw http.ResponseWriter,
req *http.Request) string {
ytid := params["ytid"]
stream_link := exec.Command("youtube-dl","-f", "140", "-g", "https://www.youtube.com/watch?v=" + ytid)
var out bytes.Buffer
stream_link.Stdout = &out
errr := stream_link.Run()
if err != nil {
log.Fatal(err)
}
log.Println("Link", out.String())
cmd_ff := exec.Command("ffmpeg", "-i", "pipe:0", "-acodec", "libmp3lame", "-f", "mp3", "-")
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
cmd_ff.Stdin = resp.Body
go func() {
defer resp.Body.Close()
if err := cmd_ff.Run(); err != nil {
log.Fatal(err)
}
}()
return "Youtube ID: " + ytid
})
m.Run()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论