Tubo de uma resposta HTTP
Pergunta
Como faço para tubo de uma resposta HTTP, como em NodeJS.Aqui está o trecho que eu estou usando no NodeJS:
request({
url: audio_file_url,
}).pipe(ffmpeg_process.stdin);
Como posso obter o mesmo resultado no Ir?
Eu estou tentando canalizar um fluxo de áudio a partir de HTTP em um FFmpeg processo para que ele converte rapidamente e retorna o arquivo convertido de volta ao cliente.
Para que seu claro para todos aqui é o meu código-fonte até o momento:
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
}
}
Erro: 2014/07/29 23:04:02 Obter :protocolo não suportado "regime"
Solução
Aqui está uma resposta possível utilizar uma função de manipulador de http padrão.Não tenho programas para testar isso diretamente, mas ele não funciona com alguns simples comandos do shell de pé como um 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)
}
}
Outras dicas
http.Request.Body
é um io.ReadCloser
, de modo que você pode canalizar em 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 me entendeu mal a pergunta, no entanto, a resposta ainda está de pé, a http.Get
versão:
http.Response.Body
é um io.ReadCloser
assim como 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:
este deve trabalho, de acordo com o martini documentação, mas, novamente, eu recomendo aprender a usar ServeMux ou, pelo menos, usar Gorila.
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()