python - 使用 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 播放流。
解决方案
推荐阅读
- javascript - 无法按索引从数组中删除项目
- flutter - 无法在带有 BluetoothThermalPrinter 包的 Chrome 设备上运行 Flutter web
- python - 如何使输出打印出数字列表?
- python - Python如何删除文本文件中特定字符串之后或之前的特定行数
- java - 如何在 flink sql 中将多集数据类型转换为字符串?
- git - 如何在 android studio 中重置代码并获得新的 repo
- angular - Rxjs combineLatest 确实在订阅中返回 observable
- java - 按降序对二维数组元素进行排序
- django - CreateAPIView 的递归和嵌套序列化程序
- android - altbeacon [2.19]+ 如何在 startRangingBeacons(region) 和 stopRangingBeacons(region) 中关闭自动绑定