提问人:LennikGamez 提问时间:11/14/2023 最后编辑:LennikGamez 更新时间:11/18/2023 访问量:43
Flask 部分视频流在 Ipad 和 Iphone 上不起作用
Flask Partial Video Stream not working on Ipad and Iphone
问:
我正在尝试编写一个 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>
这是相关的 Flask 文件:
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
答:
0赞
LennikGamez
11/18/2023
#1
因此,在花了越来越多的时间试图弄清楚发生了什么之后,我发现手机上的浏览器会发送一个测试请求,只要求咬一口,然后接受更大的范围。 我通过检查范围标头是否为“bytes=0-1”来修复它,如果是这样,我只返回浏览器请求的视频的一口,而不是发送回 1MB 的块。
评论