前端vue3 setup,后端fastapi,视频展示

介绍

在 Web 开发中,视频播放是一个常见的需求。HLS(HTTP Live Streaming)和 FLV(Flash Video)是两种常见的视频流媒体传输协议。以下是它们的详细介绍和实现方法。

FLV(Flash Video)

简介

  • FLV 是 Adobe 开发的视频格式,曾经广泛用于 Flash 播放器。

  • 虽然 Flash 已被淘汰,但 FLV 格式仍然可以通过 HTML5 和 JavaScript 播放。

优点

  • 文件体积较小,适合低带宽环境。

  • 支持流式传输,延迟较低。

缺点

  • 兼容性较差,现代浏览器不再支持 Flash。

  • 需要额外的 JavaScript 库(如 flv.js)来播放 FLV 视频。

后端

依赖

  1. FastAPI:

    • 用于构建 API 的 Web 框架。

    • 安装命令:

      pip install fastapi
  2. Uvicorn:

    • 用于运行 FastAPI 应用的 ASGI 服务器。

    • 安装命令:

      pip install uvicorn

代码

from fastapi import HTTPException, FastAPI, Query, Header
from fastapi.responses import JSONResponse, FileResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from typing import Generator, Optional
import json
import os
import uvicorn


app = FastAPI()

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法
    allow_headers=["*"],  # 允许所有头部
)


class BaseResponse:
    def __init__(self, code, msg):
        self.code = code
        self.msg = msg


class MyFile:
    def __init__(self, filename, knowledge_base_name):
        self.filename = filename
        self.filepath = os.path.join(knowledge_base_name, filename)


def iter_file(file_path: str, start: int = 0, end: Optional[int] = None) -> Generator[bytes, None, None]:
    with open(file_path, "rb") as file:
        file.seek(start)
        while chunk := file.read(8192):
            yield chunk
            if end and file.tell() >= end:
                break


@app.get("/knowledge_base/download_video")
def stream_video(
        filename: str = Query(..., description="FLV文件名称", examples=["test.flv"]),
        range: Optional[str] = Header(None)
):
    """
    流式传输FLV视频,支持范围请求
    """
    file_path = os.path.join(os.getcwd(), "files", filename)

    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="文件未找到")

    file_size = os.path.getsize(file_path)
    start = 0
    end = file_size - 1

    if range:
        # Parse the range header
        match = range.replace("bytes=", "").split("-")
        start = int(match[0])
        if len(match) > 1 and match[1]:
            end = int(match[1])

    content_length = end - start + 1
    headers = {
        "Content-Range": f"bytes {start}-{end}/{file_size}",
        "Accept-Ranges": "bytes",
        "Content-Length": str(content_length),
        "Content-Type": "video/x-flv"
    }

    return StreamingResponse(
        iter_file(file_path, start=start, end=end + 1),
        status_code=206,
        headers=headers,
        media_type="video/x-flv"
    )


def convert_json_to_vtt(json_file, vtt_file):
    # Read JSON data from a file
    with open(json_file, 'r', encoding='utf-8') as f:
        json_data = json.load(f)

    vtt_data = "WEBVTT\n\n"
    for i, item in enumerate(json_data):
        start_time = float(item['start'])
        end_time = start_time + float(item['duration'])
        start_time_min, start_time_sec = divmod(start_time, 60)
        end_time_min, end_time_sec = divmod(end_time, 60)
        vtt_data += f"{i+1}\n"
        vtt_data += f"{int(start_time_min):02}:{start_time_sec:06.3f} --> {int(end_time_min):02}:{end_time_sec:06.3f}\n"
        vtt_data += f"{item['text']}\n\n"

    # Write VTT data to a file
    with open(vtt_file, 'w', encoding='utf-8') as f:
        f.write(vtt_data)

@app.get("/knowledge_base/download_vtt")
def download_vtt(
        file_name: str = Query(..., description="文件名称"),
        preview: bool = Query(False, description="是:浏览器内预览;否:下载")
):
    """
    下载字幕文件
    """
    vtt_dir = "./files/vtt_dir"
    json_dir = "./files/vtt_dir"
    name =  os.path.splitext(os.path.basename(file_name))[0]
    vtt_name = name + ".vtt"
    vtt_file_path = vtt_dir + "/" +vtt_name
    if not os.path.exists(vtt_file_path):
        json_file_path = json_dir + "/" + name + ".json"
        convert_json_to_vtt(json_file_path,vtt_file_path)
    if preview:
        content_disposition_type = "inline"
    else:
        content_disposition_type = None
    try:
        kb_file = MyFile(filename=vtt_name, knowledge_base_name=vtt_dir)
        if os.path.exists(kb_file.filepath):
            response = FileRespon
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值