GoLang http webserver提供视频(mp4) [英] GoLang http webserver provide video (mp4)

查看:274
本文介绍了GoLang http webserver提供视频(mp4)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用golang开发了一个网络服务器。漂亮的平面的东西,它只是提供了html / js / css和图像,它们完美地工作得很好:

  func main(){
http.Handle(/,new(viewHandler))
http.ListenAndServe(:8080,nil)
}

func(vh * viewHandler)ServeHTTP (w http.ResponseWriter,r * http.Request){
path:= r.URL.Path [1:]
log.Println(path)
data,err:= ioutil。 ReadFile(string(path))

if err nil {

var contentType string

if strings.HasSuffix(path,.html ){
contentType =text / html
} else if strings.HasSuffix(path,.css){
contentType =text / css
} else如果strings.HasSuffix(path,.js){
contentType =application / javascript
} else if strings.HasSuffix(path,.png){
contentType = image / png
else if strings.HasSuffix(path,.jpg){
contentType =image / j peg
}

w.Header()。Add(Content-Type,contentType)
w.Write(data)
} else {
log.Println(ERROR!)
w.WriteHeader(404)
w.Write([] byte(404 - + http.StatusText(404)))
}
}

我尝试在mp4格式的视频中添加相同的视频

 < video width =685height =525autoplay loop style =margin-top:20px > 
< source src =../ public / video / marketing.mp4type =video / mp4>您的浏览器不支持视频标签。< / video>

并增强了我的go应用程序的内容类型部分:

  else if strings.HasSuffix(path,.mp4){
contentType =video / mp4
}

当我直接在Chrome中打开html文件时,视频播放正确,但如果我通过调用Web服务器在







对此有何看法?提前感谢。



更新:



建议我也试过另一个视频,它工作得很好!但我不知道为什么,我比较了这两个视频:




难道是大小?



干杯和感谢!



UPDATE2:



icza是正确的,我将他的帖子标记为我的问题的正确答案。但让我解释一下我最终做了些什么来实现它:

我试图在不使用http.FileServe方法的情况下解决我的问题。因此,我执行如下:

 } else if strings.HasSuffix(path,.mp4){
contentType =video / mp4
size:= binary.Size(data)
if size> $ {
requestedBytes:= r.Header.Get(Range)
w.Header()。Add(Accept-Ranges,bytes)
w.Header()添加(Content-Range,bytes+ requestedBytes [6:len(requestedBytes)] + strconv。 Itoa(size-1)+/+ strconv.Itoa(size))
w.WriteHeader(206)
}
}

w.Header( ).Add(Content-Type,contentType)
w.Write(data)

这是我第一次播放视频。但是,因为我希望它循环它应该直接从头开始,但它坚持在视频的最后一帧。

所以我实现了ServeFile()方法:

  if contentType ==video / mp4{
http.ServeFile(w,r,path)
} else {
w.Header()。Add(Content-Type,contentType)
w.Write(data)
}

现在视频也在正确循环播放。但是我仍然不知道为什么ServeFile()正在工作,而另一种方法却没有,尽管两种方法的响应都完全相同。尽管如此,内容现在看起来像这样:



欢呼和感谢所有帮助过我的人。

你的问题与视频长度/大小有关。我不知道Chrome使用的默认缓冲区(它可能取决于多项功能,如可用内存,可用磁盘空间等),但您不应该依赖它来播放视频!



您的一个视频缩短了几秒,几乎是另一个视频的三分之一。 Chrome浏览器完全缓冲了较小的视频(可能在内存中),而对另一个则不起作用。由于它比缓冲区大,因此它需要服务器支持范围请求(部分内容服务)。您提供视频内容的方式并不支持部分内容投放(Chrome对大型视频的期望),因此Chrome拒绝处理/播放视频。



您应该使用 http.ServeFile () ,它支持服务范围请求(对于大于特定大小的视频需要)。请参阅相关问题: 如何通过Go提供http部分内容?



一旦你这样做了,你的视频文件都可以正常播放。

展望未来,没有实际的理由不使用 http.ServeFile()。它不会像你所做的那样将完整的文件加载到内存中,对于大的(视频)文件来说这是一个非常糟糕的主意。 http.ServeFile()处理范围请求(如果这样做),并正确设置响应头,包括 Content-Type (并知道 .mp4 文件需要 video / mp4 MIME类型)。

分析一个大视频文件的请求



测试这个简单的应用程序: b

  func fileh(w http.ResponseWriter,r * http.Request){
http.ServeFile(w,r,/path/to/a/big/video.mp4)


func main(){
http.HandleFunc(/,fileh)
panic(http.ListenAndServe(localhost:8080,nil))

然后打开 http:// localhost:8080 ,浏览器发出2个请求(我故意过滤掉了不重要/不相关的请求 - 响应头文件):

请求#1



  GET / HTTP / 1.1 





回应#1



  HTTP / 1.1 200 OK 
Accept-Ranges:bytes
Content-Length:104715956
Content-Type:video / mp4

正如您所看到的,Go应用报告视频大小约为100 MB。 http.ServeFile()还包含响应头 Accept-Ranges:bytes ,让客户知道之前我们支持Range请求。



Chrome如何回应此问题?在收到32 KB(32.2 KB包含头文件;这足以查看流并告诉它可以做什么)后关闭连接,然后触发另一个请求(即使 Accept-



请求#2


$
响应标题未发送 - 您的示例代码不会发送它) b $ b

  GET / HTTP / 1.1 
Referer:http:// localhost:8080 /
范围:bytes = 0-

Chrome会触发范围请求(询问第一个字节中的所有内容),因此如果您的Go应用程序不支持此操作,那么您麻烦。

响应#2



  HTTP / 1.1 206部分内容
接受范围:字节
内容长度:104715956
内容范围:字节0-104715955 / 104715956
内容类型:视频/ mp4

http.ServeFile()表现良好, Range请求( HTTP 206部分内容状态码和 Content-Range 标头),并发送请求的范围(本例中的所有内容)。



您的示例代码不会响应 HTTP 206部分内容,但是简单的 HTTP 200 OK 。当Chrome收到意外的 HTTP 200 OK 时,这就是放弃播放视频的时刻。如果视频文件很小,Chrome就不会做出什么大事,因为它只会接受 HTTP 200 OK 响应(并且可能只是将小视频存储在内存或缓存文件)。


I developed a webserver using golang. Pretty plane stuff, it just provides html/js/css and images which works perfectly fine:

func main() {
    http.Handle("/", new(viewHandler))
    http.ListenAndServe(":8080", nil)
}

func (vh *viewHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    path := r.URL.Path[1:]
    log.Println(path)
    data, err := ioutil.ReadFile(string(path))

    if err == nil {

        var contentType string

        if strings.HasSuffix(path, ".html") {
            contentType = "text/html"
        } else if strings.HasSuffix(path, ".css") {
            contentType = "text/css"
        } else if strings.HasSuffix(path, ".js") {
            contentType = "application/javascript"
        } else if strings.HasSuffix(path, ".png") {
            contentType = "image/png"
        } else if strings.HasSuffix(path, ".jpg") {
            contentType = "image/jpeg"
        } 

        w.Header().Add("Content-Type", contentType)
        w.Write(data)
    } else {
        log.Println("ERROR!")
        w.WriteHeader(404)
        w.Write([]byte("404 - " + http.StatusText(404)))
    }
}

I tried to add a video in mp4 format to my website in the same way:

<video width="685" height="525" autoplay loop style="margin-top: 20px">
   <source src="../public/video/marketing.mp4" type="video/mp4">Your browser does not support the video tag.</video>

and enhanced the content type part of my go application with:

else if strings.HasSuffix(path, ".mp4") {
            contentType = "video/mp4"
        }

When I open the html file directly in Chrome the Video is playing correctly, but if I open the website by calling the Web Server at http://localhost... it can not be loaded and therefor not played.

There is no video loaded, if I try to hit it directly the browser just shows some video contols without loading the file:

Any ideas on this? thanks in advance.

UPDATE:

As suggested I also tried another video which is working perfectly fine! but I have no clue why, I compared both videos:

Could it be the size??

Cheers and thanks!

UPDATE2:

icza is right and I marked his post as correct answer to my question. But let me explain what I finally did to get it working:

I tried to solve my problem without using the http.FileServe method. Therefore I implemented like so:

} else if strings.HasSuffix(path, ".mp4") {
            contentType = "video/mp4"
            size := binary.Size(data)
            if size > 0 {
                requestedBytes := r.Header.Get("Range")
                w.Header().Add("Accept-Ranges", "bytes")
                w.Header().Add("Content-Length", strconv.Itoa(size))
                w.Header().Add("Content-Range", "bytes "+requestedBytes[6:len(requestedBytes)]+strconv.Itoa(size-1)+"/"+strconv.Itoa(size))
                w.WriteHeader(206)
            }
        }

        w.Header().Add("Content-Type", contentType)
        w.Write(data)

That worked for the first time I played the video. But since I want it to loop it should directly start from the beginning but it stuck at the very last frame of the video.

So I implemented the ServeFile() method like:

if contentType == "video/mp4" {
            http.ServeFile(w, r, path)
        } else {
            w.Header().Add("Content-Type", contentType)
            w.Write(data)
        }

The video is also playing in a loop correctly now. But I still have no idea why ServeFile() is working and the other method not though the response is exactly the same for both methods. Nevertheless the content is looking like that now:

Cheers and thanks to all of you who helped me.

解决方案

Your "issue" is related to the video length / size. I don't know the default buffer Chrome uses (it may depend on multiple things like free memory, free disk space etc.), but you shouldn't rely on it for your video to play!

One of your video is a few seconds shorter and almost 3rd the size of the other. Chrome buffers completely the smaller video (likely in memory), while does not do the same with the other. And since it's bigger than the buffer, it needs the server to support Range requests (partial content serving). The way you serve the content of your video, you are not supporting partial content serving (which Chrome expects in case of "large" videos), so Chrome simply denies to handle / play the video.

You should serve your files using http.ServeFile() which supports serving Range requests (required for videos that are bigger than a certain size). See related question: How to serve http partial content with Go?

Once you do this, both your video files will play fine.

Going forward, there is no practical reason not to use http.ServeFile(). It won't load the complete file into memory as you did which is a really bad idea in case of big (video) files. http.ServeFile() handles Range requests if asked so, and also properly sets response headers including the Content-Type (and knows that .mp4 files require video/mp4 MIME type).

Analyzing requests of a big video file

Testing this simple application:

func fileh(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "/path/to/a/big/video.mp4")    
}

func main() {
    http.HandleFunc("/", fileh)
    panic(http.ListenAndServe("localhost:8080", nil))
}

And opening http://localhost:8080 from Chrome, the browser makes 2 requests (I intentionally filtered out unimportant / unrelated request-response headers):

Request #1

GET / HTTP/1.1

To get the requested (root) path.

Response #1

HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 104715956
Content-Type: video/mp4

As you can see, the Go app reports the video size is around 100 MB. http.ServeFile() also includes the response header Accept-Ranges: bytes which lets clients know prior that we support Range requests.

How does Chrome respond to this? Closes the connection after receiving 32 KB (32.2 KB including headers; which is enough to look into the stream and tell what it can do with it), then fires another request (which also happens even if the Accept-Ranges response header is not sent - your example code does not send it):

Request #2

GET / HTTP/1.1
Referer: http://localhost:8080/
Range: bytes=0-

Chrome fires a Range request (asking everything from the first byte), so if your Go app does not support this, you're in trouble. See response #2.

Response #2

HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Length: 104715956
Content-Range: bytes 0-104715955/104715956
Content-Type: video/mp4

http.ServeFile() behaves well, and responds properly to the Range request (HTTP 206 Partial Content status code and Content-Range header), and sends the range that was requested (everything in this case).

Your example code does not respond with an HTTP 206 Partial Content but with a simple HTTP 200 OK. When Chrome receives the unexpected HTTP 200 OK, that's the point when it gives up on playing your video. If the video file is small, Chrome will not make a big deal out of it as it will just accept the HTTP 200 OK response too (and likely just store the small video in memory or in a cache file).

这篇关于GoLang http webserver提供视频(mp4)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆