基于fastapi的流媒体服务器
一、背景
打算做一个点播系统,主要功能是播放视频,但是视频流如何传到web端是一个主要问题。如果是以MP4整个文件传输会导致如下问题:一是文件过大,加载过慢,二是流量消耗过多,中途可能直接关闭视频。
解决这个问题采用m3u8格式,将MP4视频进行切片,一次一次的加载。
二、准备
我准备了一个MP4视频huahai.mp4,没错就是周董的《花海》。
使用python3,最好是3.7及以上版本支持asyncio模块,其他需要fastapi、ffmpy3模块
先看整个目录结构和内容,理论的内容大家自行百度,我也说不明白,直接上代码。
其中html文件是前端,播放的界面,py就是服务端,huahai是存放媒体的目录,MP4是我们视频文件。
整个流程就是先将MP4生成m3u8文件,然后开启api服务器,久可以在前端访问了。
三、代码
1、前端代码,很简单涉及videojs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文档标题</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video-js.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video.min.js"></script>
</head>
<body>
<div>
<video id="example_video" class="video-js vjs-default-skin" controls preload="none"
poster="https://i1.hdslb.com/bfs/archive/3123c64f3be9669ae2d2b3ef82549b1b2bd035e5.jpg@480w_270h_1c">
<source src="http://127.0.0.1:5000/video/huahai.m3u8" type="application/x-mpegURL">
<!-- <source src="C:/Users/WYC/Desktop/fastapitest/testffm/huahai2/huahai.m3u8" type="application/x-mpegURL"> -->
</video>
</div>
</body>
<script>
var player = videojs('example_video', {
muted: true,//静音
controls: true,//控制组件
width: 1000,
loop: true,//循环播放
playbackRates: [0.5, 1, 1.5, 2]//控制速度
});
</script>
</html>
2、后端代码,很简单涉及fastapi和ffmpeg的操作
import uvicorn
from fastapi import FastAPI,Response
from starlette.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from ffmpy3 import FFmpeg
import os
inputs={'./huahai/huahai.mp4': None}
# 配置生成指令
outputs={None:'-c:v libx264 -c:a aac -strict -2 -f segment -segment_time 10 -segment_list_entry_prefix http://127.0.0.1:5000/video/ -segment_list ./huahai/huahai.m3u8 ./huahai/huahai-%4d.ts'}
app = FastAPI()
origins = [
"*"
]
# 配置允许跨域
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/video/{fileName}")
async def video(response: Response,fileName:str):
response.headers["Content-Type"] = "application/x-mpegURL"
return FileResponse('./huahai/'+fileName, filename=fileName)
# 处理视频文件 生成 m3u8
def chuliVideo(path):
# 判断文件是否存在
if not os.path.exists('./huahai/'+path):
return False#文件不存在
# 提取文件名
ff = FFmpeg(inputs=inputs, outputs=outputs)
ff.run()
if __name__ == '__main__':
chuliVideo('huahai.mp4')
uvicorn.run("apifastMain:app", host="127.0.0.1", port=5000, log_level="info", reload=True, debug=True)
3、结果说明
处理之后生成的文件
前端播放效果,可以看到支持慢加载
服务器路由请求路径,可以看出一个一个加载
四、说明
1、关于m3u8文件的生成和处理
我们看一下m3u8文件内容,每个ts都进行了处理,补充了完整的路由,这是因为videojs在自动加载的时候是根据m3u8的内容进行的,不断读取ts路径,关于这个文件我们也可以动态的生成和修改,因为路由在开发过程中是不确定的。
2、关于ffmpeg命令补充
outputs={None:'-c:v libx264 -c:a aac -strict -2 -f segment -segment_time 10 -segment_list_entry_prefix http://127.0.0.1:5000/video/ -segment_list ./huahai/huahai.m3u8 ./huahai/huahai-%4d.ts'}
对于上面的代码,主要考虑如下参数:
-segment_time + 多少秒分割
-segment_list_entry_prefix + 每个ts文件前加的字符串,组成绝对路径
-segment_list + 输出的文件位置,包括文件名
这个%4d是后缀,意思四位数字,不够补零
具体效果可以思考 huhai目录以及里面的文件
3、关于fastapi跨域
需要注意,没有解决跨域问题,前端videojs会报错的,打开浏览器调式窗口可以看到。
五、总结
我在写本篇博客之前百度了很多内容,但是大多是理论的东西,告诉你可以用HLS实现,但是没有具体实现方法,又或者是爬虫之类的得到m3u8的路径直接放进前端videojs处理,现在将所做分享给大家,希望和大家一起学习进步,当然后面还有很多的工作需要完善。