我正在尝试编写一个 Flask 网页,将特定范围的字节流传输到客户端,这样您就可以从网络驱动器观看大型视频文件(mp4),而无需加载整个视频。它已经可以在我的笔记本电脑和托管网页的电脑上运行,但当我尝试在苹果移动设备上使用该网页时,我不断遇到问题。视频只是无法加载。视频播放器保持空白,不显示视频持续时间,并且无法启动和观看视频。
我已经尝试过使用其他浏览器。我尝试了 Safari、Google 和 Firefox,但没有任何效果。
这是流媒体页面的 HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<video controls="true" width="650" playsinline autoplay muted loop>
<source src="{{url_for('stream.getMovie',id=id, ver=version)}}" type="video/mp4">
</video>
</body>
</html>
这是相关的烧瓶文件:
import mimetypes
from flask import Response, render_template, request, Blueprint
import os
from helper import getMovieById, getMovieList
stream = Blueprint("stream", __name__)
def removeNonDigit(str):
final = ""
for i in str:
if i in "0123456789":
final += i
return final
@stream.route("/movie/<id>/<ver>", methods=['GET'])
def getMovie(id, ver):
range = request.headers.get("range")
if not range:
return Response("Requires Range header",status=400)
videoPath: str = getMovieById(id).get("versions")[int(ver)][1]
videoSize: bytes = os.stat(videoPath).st_size
# parse Range
# "bytes=3323-"
CHUNK_SIZE = (10 ** 6)*1 # about 1 MB
x = range[:range.find("-")]
start = int(removeNonDigit(x))
end = min(start + CHUNK_SIZE, videoSize-1)
# read the data
with open(videoPath, "rb") as v:
v.seek(start)
data = v.read(CHUNK_SIZE)
content_length = end - start + 1
headers = {
"Content-Range": f'bytes {start}-{end}/{videoSize}',
"Accept-Ranges": "bytes",
"Content-Length": content_length,
"Content-Type": "video/mp4",
}
return Response(data, status=206, headers=headers, mimetype=mimetypes.guess_type(videoPath)[0],direct_passthrough=True)
@stream.route("/watch/<id>/<version>")
def player(id, version):
return render_template("movie.html", title=getMovieById(id).get("name"), version=version, id=id)
@stream.route("/banner/<id>")
def banner(id):
img = getMovieById(id).get("img")
with open(img, "rb") as f:
data = f.read()
return Response(data, status=202)
这可能有点混乱,我已经尝试了很长时间了
这是当我从 PC 连接而不启动视频时从 Flask 控制台获得的输出:
127.0.0.1 - - [13/Nov/2023 20:14:02] "GET /watch/1/1 HTTP/1.1" 200 -
127.0.0.1 - - [13/Nov/2023 20:14:04] "GET /movie/1/1 HTTP/1.1" 206 -
127.0.0.1 - - [13/Nov/2023 20:14:04] "GET /movie/1/1 HTTP/1.1" 206 -
但是从我的 iPad 连接时我只得到这个输出:
192.xxx.xxx.xxx - - [13/Nov/2023 20:15:36] "GET /watch/1/0 HTTP/1.1" 200 -
192.xxx.xxx.xxx - - [13/Nov/2023 20:15:38] "GET /movie/1/0 HTTP/1.1" 206 -
我还发现来自 iPad 的请求中的标头的字节范围为“bytes=0-1”,来自 PC 的字节范围为“bytes=0-”
我不是请求方面的专家,但这也许有帮助......
如果您需要更多详细信息或代码片段,请告诉我。
提前谢谢您:3
因此,经过一番尝试后,我发现手机上的浏览器会发送一个测试请求,在接受更大的范围之前仅请求一口。 我通过检查范围标头是否为“bytes=0-1”来修复此问题,如果是,我只返回浏览器请求的视频的一部分,而不是发回 1MB 块。