首页 > 解决方案 > 使用 http 范围请求流式传输视频文件

问题描述

我正在尝试制作一个使用 http 字节服务(范围请求)向客户端提供视频文件的服务器,请考虑以下代码

from http.server import BaseHTTPRequestHandler, HTTPStatus
import socketserver
from os import path

PORT = 8000

class MyServer(BaseHTTPRequestHandler):
    file = R"C:\Users\Prince\Downloads\video.mkv"
    file_size = path.getsize(file)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_GET(self):
        headers = self.headers
        print(headers)

        [start, end] = self.get_range(headers)
        print(start, end)
        body = bytes()
        with open(self.file, 'rb') as f:
            f.seek(start)
            body = f.read(end - start)
        end = start + len(body) - 1

        self.send_response(HTTPStatus.PARTIAL_CONTENT)
        self.send_header("Accept-Ranges", "bytes")
        self.send_header("Content-Type", "video/x-matroska")
        self.send_header("Content-Length", len(body))
        self.send_header("Content-Range", "bytes %d-%d/%d" % (start, end, self.file_size))
        self.end_headers()
        self.wfile.write(body)


    def get_range(self, headers):
        start,size = 0, 1024*1024
        try:
            rkey = headers['Range']
            if not rkey:
                raise "no range header"
            [unit,range] = rkey.split('=')
            if unit != 'bytes':
                raise "unknown unit"
            [s,e] = range.split('-')
            start = int(s)
            e = int(e)
            end = e if not e == 0 else start+size
            return [start, end]
        except:
            return [start, start+size]

handler = MyServer

with socketserver.TCPServer(("", PORT), handler) as httpd:
    print("Server started at localhost:" + str(PORT))
    httpd.serve_forever()

但这不起作用,客户端(vlc)只发出一个请求,然后结束播放并且不播放整个文件。fe
下面是vlc和脚本的交互

http debug: outgoing request: GET / HTTP/1.1 Host: localhost:8000 Accept: */* Accept-Language: en_US User-Agent: VLC/3.0.8 LibVLC/3.0.8 Range: bytes=0- 
http debug: incoming response: HTTP/1.0 206 Partial Content Server: BaseHTTP/0.6 Python/3.7.5 Date: Mon, 27 Apr 2020 16:07:43 GMT Accept-Range: bytes Content-Type: video/x-matroska Content-Length: 1048576 Content-Range: bytes 0-1048575/285618825 

vlc 没有发出其他请求,并且仅为此块播放视频。

奇怪的是,如果我Content-Length用文件大小替换,即

        self.send_header("Content-Length", str(self.file_size))

然后 VLC 提出进一步的请求并播放整个文件,也支持随机搜索,但我认为这是不正确的,因为在 Mozilla docs中,它明确表示内容长度应该是范围请求中的“真实内容长度”,而不是完整大小请求的资源。

所以我的问题是有没有其他方法可以在发送正确的同时实际修复上述代码Content-Length,我正在使用 VLC 播放流。

标签: pythonsocketshttpvideovideo-streaming

解决方案


推荐阅读