Flask分段视频流在iPad和iPhone上无法加载的问题求助
Flask流式MP4在苹果移动设备无法播放的问题排查与修复
问题根源
苹果移动设备(iPad/iPhone)的视频播放器会先发送Range: bytes=0-1的请求来获取视频元数据(时长、编码信息等),但你的Flask代码在解析这种带有明确结束位置的Range头时存在逻辑错误:
- 原代码仅处理了
bytes=xxx-这种无结束位置的请求,当遇到bytes=0-1时,计算出的end值是min(0+1MB, 文件大小-1),返回了远大于请求范围的数据,导致苹果设备无法解析元数据,最终播放器显示为空、无法启动播放。
修复方案
1. 修正Range头解析逻辑
区分两种Range格式:bytes=start-end(指定起止)和bytes=start-(仅指定起始),分别计算对应的end值,确保返回的数据严格匹配请求范围。
2. 精确读取请求范围内的数据
根据计算出的start和end读取对应长度的字节,而不是固定读取1MB数据。
修改后的Flask代码
替换原getMovie函数:
@stream.route("/movie/<id>/<ver>", methods=['GET']) def getMovie(id, ver): range_header = request.headers.get("range") if not range_header: return Response("Requires Range header", status=400) videoPath: str = getMovieById(id).get("versions")[int(ver)][1] videoSize: int = os.stat(videoPath).st_size # 正确解析Range头,兼容两种格式:bytes=start- 或 bytes=start-end CHUNK_SIZE = 10**6 # 1MB,仅在未指定end时使用 range_part = range_header.split("=")[-1] start_str, end_str = range_part.split("-", 1) start = int(start_str) if start_str else 0 # 处理end的两种情况 if end_str: end = int(end_str) end = min(end, videoSize - 1) # 确保不超过文件边界 else: end = min(start + CHUNK_SIZE, videoSize - 1) # 计算要返回的内容长度并精确读取数据 content_length = end - start + 1 with open(videoPath, "rb") as v: v.seek(start) data = v.read(content_length) headers = { "Content-Range": f'bytes {start}-{end}/{videoSize}', "Accept-Ranges": "bytes", "Content-Length": str(content_length), "Content-Type": "video/mp4", } return Response(data, status=206, headers=headers, direct_passthrough=True)
额外检查点
- MP4文件格式兼容性:苹果设备要求视频的
moov元数据原子尽量在文件开头(而非末尾),可以用ffmpeg重新封装修复:ffmpeg -i input.mp4 -movflags faststart output.mp4 - 编码格式:确保视频采用苹果原生支持的编码(H.264视频 + AAC音频),避免使用小众编码格式。
内容的提问来源于stack exchange,提问作者LennikGamez
相关产品推荐
相关产品推荐

