将HTTP响应导入管道中。

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

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(&quot;youtube-dl&quot;)
    if err != nil {
        log.Fatal(&quot;LookPath: &quot;, err)
    }
    path_ff, err_ff := exec.LookPath(&quot;ffmpeg&quot;)
    if err != nil {
        log.Fatal(&quot;LookPath: &quot;, err_ff)
    }

    streamLink := exec.Command(path,&quot;-f&quot;, &quot;140&quot;, &quot;-g&quot;, &quot;https://www.youtube.com/watch?v=VIDEOID&quot;)
    
    var out bytes.Buffer
    streamLink.Stdout = &amp;out
    cmdFF := exec.Command(path_ff, &quot;-i&quot;, &quot;pipe:0&quot;, &quot;-acodec&quot;, &quot;libmp3lame&quot;, &quot;-f&quot;, &quot;mp3&quot;, &quot;-&quot;)
    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 &lt;- cmdFF.Run()
    }()

    // close the pipeline to signal the end of the stream
    // pw.Close()
    // pr.Close()

    // check for an error from ffmpeg
    if err := &lt;-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(&quot;youtube-dl&quot;, &quot;-f&quot;, &quot;140&quot;, &quot;-g&quot;, &quot;https://www.youtube.com/watch?v=VIDEOID&quot;)
	out, err := streamLink.Output()
	if err != nil {
		log.Fatal(err)
	}

	cmdFF := exec.Command(&quot;ffmpeg&quot;, &quot;-i&quot;, &quot;pipe:0&quot;, &quot;-acodec&quot;, &quot;libmp3lame&quot;, &quot;-f&quot;, &quot;mp3&quot;, &quot;-&quot;)
	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.Bodyhttp.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(&quot;ffmpeg&quot;, 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(&quot;ffmpeg&quot;, ......, 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(&quot;/stream/:ytid&quot;, func(params martini.Params, rw http.ResponseWriter,
                            req *http.Request) string {
	ytid := params[&quot;ytid&quot;]
	stream_link := exec.Command(&quot;youtube-dl&quot;,&quot;-f&quot;, &quot;140&quot;, &quot;-g&quot;, &quot;https://www.youtube.com/watch?v=&quot; + ytid)
	var out bytes.Buffer
	stream_link.Stdout = &amp;out
	errr := stream_link.Run()
	if err != nil {
		log.Fatal(err)
	}
	log.Println(&quot;Link&quot;, out.String())

	cmd_ff := exec.Command(&quot;ffmpeg&quot;, &quot;-i&quot;, &quot;pipe:0&quot;, &quot;-acodec&quot;, &quot;libmp3lame&quot;, &quot;-f&quot;, &quot;mp3&quot;, &quot;-&quot;)
	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 &quot;Youtube ID: &quot; + ytid
})
m.Run()

huangapple
  • 本文由 发表于 2014年7月30日 03:33:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/25023502.html
匿名

发表评论

匿名网友

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

确定