Я пытаюсь создать сервер, который обслуживает видеофайлы клиентам, использующим 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()
, но это не работает, клиент (vl c) ) только делает один запрос, а затем завершает воспроизведение и не воспроизводит весь файл. fe
ниже приведены взаимодействия между vl c и скриптом
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
, другие запросы не выполняются vl c, и видео воспроизводится только для этого чанка.
странно если я заменю Content-Length
размером файла, то есть
self.send_header("Content-Length", str(self.file_size))
, тогда VL C отправляет дополнительные запросы и воспроизводит весь файл, также поддерживая случайный поиск, но я думаю, что это неверно, так как в Mozilla docs , в нем четко сказано, что длина контента должна быть «реальной длиной контента» в запросах диапазона, а не полным размером запрошенного ресурса.
Итак, мой вопрос: есть ли другой способ исправить код, указанный выше, при отправке правильного Content-Length
, я использую VL C для воспроизведения потока.