今天想要记录一下困扰我几天的一个问题,关于FastAPI返回音视频流。首先FastAPI挂载静态资源其实超级简单,但是对于音视频流,如果你想要有播放进度可以拖动,需要单独处理。
有以下几点想跟大家分享:
请参考以下代码,要想进度条可拖动,主要需要两个响应头,一个是Content-Length
,另一个是 Content-Range
; 其中 Content-Range
需要根据文件大小和请求头中的Range
进行计算。
最后使用StreamingResponse
流式响应头返回即可。
参考代码拿走就可以用,拿走不谢。
@app.get("/video/get")
async def main(request: Request):
request_range = request.headers.get("Range")
range = int(request_range[request_range.find("=")+1: request_range.find("-")])
video_path = "./"
video_name = f'test.mp4'
file_name = f"{video_path}/{video_name}"
file_size = os.path.getsize(file_name)
file_like = open(file_name, mode="rb")
headers = {
"Accept-Ranges": "bytes",
"Content-Length": f"{file_size}",
"Content-Type": "video/mp4",
"Content-Disposition": f"attachment;file_name={video_name}",
"Content-Range": f"{range + file_size - 1}"
}
return StreamingResponse(file_like, headers=headers)
这个问题真的是一个让人哭笑不得的问题,我一直以为是我上述代码封装的原因,各种百度无果,甚至都已经放弃了,选择使用flv.js+ffmepg转码flv的方式去实现。
奈何flv.js问题点比较多,我又回过头来从代码上找原因;灵感往往就是在一瞬间,会不会是视频本身的原因?
一番查询,找到了我想要的结果:
ffmepg转码后的视频会将视频元信息放到最后一帧,所以需要等视频完全加载才能够显示进度以及播放。
这他喵的谁懂哇,并不是我代码写的有问题,而是转码后的视频有问题。
又一番百度发现ffmepg有命令可以将视频的元信息复制到第一帧:
ffmpeg -y -i “{input_path}” -c copy -map 0 -movflags +faststart -vcodec h264 “{output_path}”
转码时加上 -c copy -map 0 -movflags +faststart
参数即可。
到此,两个问题解决,我也不用再费劲去考虑什么flv.js了。
愿看到的小伙伴不迷路,欢迎大家留言探讨!