Использование http диапазона запроса для потоковой передачи видеофайлов - PullRequest
0 голосов
/ 27 апреля 2020

Я пытаюсь создать сервер, который обслуживает видеофайлы клиентам, использующим 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 для воспроизведения потока.

...