基于fastapi的流媒体服务器

  • 一、背景
  • 二、准备
  • 三、代码
  • 1、前端代码,很简单涉及videojs
  • 2、后端代码,很简单涉及fastapi和ffmpeg的操作
  • 3、结果说明
  • 四、说明
  • 1、关于m3u8文件的生成和处理
  • 2、关于ffmpeg命令补充
  • 3、关于fastapi跨域
  • 五、总结


一、背景

打算做一个点播系统,主要功能是播放视频,但是视频流如何传到web端是一个主要问题。如果是以MP4整个文件传输会导致如下问题:一是文件过大,加载过慢,二是流量消耗过多,中途可能直接关闭视频。
解决这个问题采用m3u8格式,将MP4视频进行切片,一次一次的加载。

二、准备

我准备了一个MP4视频huahai.mp4,没错就是周董的《花海》。

使用python3,最好是3.7及以上版本支持asyncio模块,其他需要fastapi、ffmpy3模块

先看整个目录结构和内容,理论的内容大家自行百度,我也说不明白,直接上代码。

python mp4 流媒体播放 python 流媒体服务器_fastapi


其中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、结果说明

处理之后生成的文件

python mp4 流媒体播放 python 流媒体服务器_python_02


前端播放效果,可以看到支持慢加载

python mp4 流媒体播放 python 流媒体服务器_python_03

服务器路由请求路径,可以看出一个一个加载

python mp4 流媒体播放 python 流媒体服务器_fastapi_04

四、说明

1、关于m3u8文件的生成和处理

我们看一下m3u8文件内容,每个ts都进行了处理,补充了完整的路由,这是因为videojs在自动加载的时候是根据m3u8的内容进行的,不断读取ts路径,关于这个文件我们也可以动态的生成和修改,因为路由在开发过程中是不确定的。

python mp4 流媒体播放 python 流媒体服务器_ffmpeg_05

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处理,现在将所做分享给大家,希望和大家一起学习进步,当然后面还有很多的工作需要完善。