7

我有一个 Go 应用程序,我想在其中将实时未压缩音频流式传输到浏览器。我希望通过让浏览器打开与流对应的 URL 来通过 HTTP 流式传输,然后将该连接与音频数据一起提供。

我计划使用 WAV 发送未压缩的数据,但是 WAV 文件格式要求在标题中预定义文件大小。是否有更好的容器格式来进行这种流式传输,我可以在 Go 中轻松使用?

我知道一种方法是使用适当的流媒体服务器并通过它对我的音频进行转码,但如果我自己实现这一点,是否有一种相当简单的方法可以起步?也许一个 Go 库可以让这更容易?

谢谢

编辑我已经通过 ffmpeg 解决了这个问题,如下面的回答中所述

4

2 回答 2

2

如果您仍在考虑使用未压缩的 WAV 以获得最终质量,那么我认为您有两种选择

  1. 位于标题中 - 说 WAV 很长(说是 2GB)
  2. 将额外的块添加到 RIFF 容器中

第一个选择很容易实现,但意味着天真的浏览器会尝试下载 2GB 文件而不是流式传输。我希望任何实现 HTML5 的东西都不会那么天真,但我认为你需要尝试一下。

第二种选择,添加额外的块似乎受到RIFF 规范的支持,其中WAV 文件是一个子集。然后,您可以编写一个 WAV 文件,其中包含多个较短的声音数据块。这应该被 WAV 播放器支持,但可能不是因为 WAV 文件从来没有特别好的标准化,而且很多播放器只是寻找不太符合 RIFF 的 44 字节标题!

如果我是你,我会先尝试第一个选项,看看效果如何。

于 2013-03-06T09:02:29.473 回答
0

好的,这就是我最终要做的事情,我的 Go 代码通过 ffmpeg 进程将原始 PCM 数据通过管道传输,该进程将其转换为 mp3。我假设packets是我的音频数据出现的通道,并且response是 http.ResponseWriter

cmd := exec.Command("ffmpeg", "-v", "verbose", "-f", "u16le", "-ar", "44100", "-ac", "1", "-i", "-", "-f", "mp3", "-")
audioIn, err := cmd.StdinPipe()
if err != nil {
    log.Println("Failed to create stdin pipe")
}
audioOut, err := cmd.StdoutPipe()
if err != nil {
    log.Println("Failed to create stdout pipe")
}
err = cmd.Start()
if err != nil {
    log.Println("Failed to start ffmpeg command, error: ", err)
}
go func() {
    for {
        packet := <-packets
        audioIn.Write(packet.Payload)
    }
}
go func() {
    amount, err := io.Copy(response, audioOut)
    if err != nil {
        log.Println("io copy terminated with an error", err)
    }
    log.Printf("Done copying audio data: %d bytes\n", amount)
}()
err = cmd.Wait()
if err != nil {
    log.Println("ffmpeg command terminated incorrectly", err)
}
于 2013-03-07T23:00:32.970 回答