使用 FastAPI 在前端流式传输视频的不同方法

FastAPI 是一个快速、现代的 Web 框架,以支持异步 REST API 和易于使用而闻名。

在本文中,我们将了解如何使用 FastAPI 在前端流式传输视频。

流式响应

1. 流式传输本地视频

FastAPI 提供了一个专门用于流式传输的 StreamingResponse 类。StreamingResponse 类接收一个生成器或迭代器,并对响应进行流式处理。

下面是一个将本地视频流传输到浏览器的简单示例。

# localvid.py
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()

# Video path
vid_path = 'sample_video.mp4'

# Function to stream local video
def stream_local_video():
    with open(vid_path, 'rb') as vid_file:
        yield from vid_file

# Path to stream video
@app.get("/")
def video_stream():
    return StreamingResponse(stream_local_video(), media_type='video/mp4')

我们从 fastapi.responses 模块中导入了 StreamingResponse 类。

video_stream() 路径操作函数中,我们使用 StreamingResponse 返回了响应。我们将生成器函数 stream_local_video()media_type 作为参数传递给 StreamingResponse 类。

生成器函数 stream_local_video() 会读取视频的字节,然后对字节进行迭代,迭代后的每一部分都会被生成。

以下命令将在 http://127.0.0.1:8000/ 上运行服务器并流式传输视频。

> fastapi dev localvid.py

 ╭────────── FastAPI CLI - Development mode ───────────╮
 │                                                     │
 │  Serving at: http://127.0.0.1:8000                  │
 │                                                     │
 │  API docs: http://127.0.0.1:8000/docs               │
 │                                                     │
 │  Running in development mode, for production use:   │
 │                                                     │
 │  fastapi run                                        │
 │                                                     │
 ╰─────────────────────────────────────────────────────╯

2. 流式传输在线视频

# onlinevid.py
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import requests

app = FastAPI()

# Video URL
vid_url = 'https://cdn.pixabay.com/video/2023/07/28/173530-849610807_large.mp4'

# Function to stream online video
def stream_online_video(url):
    response = requests.get(url, stream=True)
    for portion in response.iter_content(chunk_size=1024*1024):
        yield portion

# Path to stream video
@app.get("/")
def video_stream():
    return StreamingResponse(stream_online_video(vid_url), media_type='video/mp4')

在本例中,我们使用 requests 库从 URL 抓取视频内容,并设置了 stream=True(避免一次性将视频读入内存)。然后,我们迭代并分块生成视频内容(每次 1024 字节)。

当我们运行服务器时,它将从 URL 提供视频。

我们可以在端点中指定 URL,而不是硬编码 URL。

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import requests

app = FastAPI()

# Function to stream online video
def stream_online_video(url):
    response = requests.get(url, stream=True)
    for portion in response.iter_content(chunk_size=1024*1024):
        yield portion

# Path to stream video
@app.get("/")
def video_stream(url):
    return StreamingResponse(stream_online_video(url), media_type='video/mp4')

在本例中,我们修改了路径操作函数 video_stream() 以接受 URL。

现在,我们可以在端点中以以下格式指定视频的 URL。

http://127.0.0.1:8000/?url=https://cdn.pixabay.com/video/2023/07/28/173530-849610807_large.mp4

我们还可以使用 async 使路径操作函数异步。

文件响应

1. 流式传输本地视频

    FileResponse仅获取一个文件并流式传输响应。

    from fastapi import FastAPI
    from fastapi.responses import FileResponse
    
    app = FastAPI()
    
    # Video path
    vid_path = 'video.mp4'
    
    # Path to stream video
    @app.get("/")
    def video_stream():
        return FileResponse(vid_path, media_type='video/mp4')

    在上面的示例中,我们只是在 FileResponse 类中传递了一个视频文件并返回了响应。

    我们并没有像在 StreamingResponse 中那样读取和遍历视频的字节来对其进行流式处理。

    FileResponse 类非常适合相对较小或中等大小的文件,因为它会在内存中加载文件。大文件将消耗更多内存。

    2. 流式传输在线视频

    使用 FileResponse 从 URL 流式传输视频与流式传输本地视频不同。我们知道,FileResponse 类接收文件并将其流式传输。

    from fastapi import FastAPI
    from fastapi.responses import FileResponse
    import requests
    import os
    
    app = FastAPI()
    
    # Video URL
    vid_url = 'https://cdn.pixabay.com/video/2023/07/28/173530-849610807_large.mp4'
    local_vid = 'sample_video.mp4'
    
    # Function to save video from URL
    def save_as_file(url, path):
        if not os.path.exists(path):
            response = requests.get(url)
            with open('sample_video.mp4', 'wb') as vid:
                vid.write(response.content)
    
    save_as_file(vid_url, local_vid)
    
    # Path to stream video
    @app.get("/")
    def video_stream():
        return FileResponse(local_vid, media_type='video/mp4')

    在本例中,我们使用 FileResponse 从 URL 流式传输视频,而不是流式传输本地视频。

    这并不是最好的做法,因为我们首先将 URL 中的视频保存在本地机器中,然后才串流视频。

    FileResponse 类最好用于本地文件,而不是网络内容。

    这就是将视频直接流式传输到浏览器的全部过程,但我们并不想每次都这样做,相反,我们希望在网站的登陆页面上流式传输视频。

    在前端流式传输视频

    那么,如何使用 FastAPI 在前端流式传输视频呢?我们需要使用 HTML 创建一个前端,然后流式传输视频。

    首先,创建一个名为 serve_video 或其他任何你想命名的目录,并创建以下文件和子目录。

    serve_video/
       - templates/
          - display_video.html
       - app.py

    app.py文件将包含我们的后端代码,该display_video.html文件将包含前端代码。

    app.py

    from fastapi import FastAPI, Request
    from fastapi.responses import StreamingResponse, HTMLResponse
    from fastapi.templating import Jinja2Templates
    import requests
    
    app = FastAPI()
    templates = Jinja2Templates(directory="templates")
    
    vid_urls = [
        "https://cdn.pixabay.com/video/2023/07/28/173530-849610807_large.mp4",
        'https://cdn.pixabay.com/video/2024/03/31/206294_large.mp4',
        'https://cdn.pixabay.com/video/2023/10/11/184510-873463500_large.mp4',
        'https://cdn.pixabay.com/video/2023/06/17/167569-837244635_large.mp4'
    ]
    
    # Stream the video from the URL
    def stream_video(url):
        response = requests.get(url, stream=True)
        for portion in response.iter_content(chunk_size=1024*1024):
            yield portion
    
    # Endpoint to render the HTML template with the video player
    @app.get("/", response_class=HTMLResponse)
    async def video_template(request: Request):
        return templates.TemplateResponse("display_video.html", {"request": request})
    
    # Endpoint to stream the video
    @app.get("/video/{video_id}")
    async def video_stream(vid_id: int):
        if 0 <= vid_id < len(vid_urls):
            return StreamingResponse(stream_video(vid_urls[vid_id]), media_type="video/mp4")
        else:
            return HTMLResponse("Video not found", status_code=404)

    display_video.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Stooooockzz</title>
    </head>
    <body>
        <h1>What we do?</h1>
        <p>We create awesome stock videos for free usage</p>
        <h3>Video Samples</h3>
        <div style="display: flex; justify-content: space-evenly;">
            <video width='20%' height='30%' style="border-radius: 10px;" controls autoplay>
                <source src="/video/0" type="video/mp4">
            </video>
            <video width='20%' height='30%' style="border-radius: 10px;" controls autoplay>
                <source src="/video/1" type="video/mp4">
            </video>
            <video width='20%' height='30%' style="border-radius: 10px;" controls autoplay>
                <source src="/video/2" type="video/mp4">
            </video>
            <video width='20%' height='30%' style="border-radius: 10px;" controls autoplay>
                <source src="/video/3" type="video/mp4">
            </video>
        </div>
    </body>
    </html>

    该 HTML 文件包含多个<video>标签,其中源指向基于/video/{video_id}端点,该端点根据 ID 流式传输视频。

    > fastapi dev app.py

    使用上述命令运行服务器后,我们在前端可以看到:

    使用 FastAPI 在前端流式传输视频的不同方法

    结论

    我们已经使用 StreaminResponseFileResponse 类在浏览器上直接流式传输本地和网络视频,此外,我们还使用 StreamingResponse 在浏览器上流式传输使用 HTML 文件渲染的多个视频。

    在本文中,我们使用了互联网上的视频 URL,但您也可以从数据库、本地文件、磁盘等获取 URL。

    作者:Sachin Pal

    版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

    (0)

    相关推荐

    发表回复

    登录后才能评论