Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stream local video to browser in FastAPI?

I have this minimal reproducible example here, and I can't get it to work. I tried returning all of this:

  1. Response with just data and media_type of "video/mp4" as well as "multipart/x-mixed-replace"
  2. StreamingResponse with data inside BytesIO with either of "video/mp4" and "multipart/x-mixed-replace" media_type.

At best it does two requests that return <1MB of data and a 206 status. However, making a query to /video with bytes={start}-{end} seems to work properly. What am I missing here? Am I getting it right that the video tag in index.html should automatically do requests to its source with the necessary headers?

like image 536
UberStreuneR Avatar asked Oct 15 '25 15:10

UberStreuneR


1 Answers

The problem in your code lies in the path parameters start and end. This was creating the problem when reading the parameters from the Header. This caused an 500 Internal Server Error exception, which was not visible, unless navigating to /video endpoint.

Here's two possible solutions, taken from the docs https://fastapi.tiangolo.com/advanced/custom-response/?h=streamingre#using-streamingresponse-with-file-like-objects

Option 1

FileResponse

@app.get("/video")
async def video_endpoint():
    return FileResponse(video_path)

Option 2

StreamingResponse

@app.get("/video")
async def video_endpoint():
    def iterfile():
        with open(video_path, mode="rb") as file_like:
            yield from file_like

    return StreamingResponse(iterfile(), media_type="video/mp4")

This will allow you to stream the video without getting a headache of handling single chunks.

Option 2 is the suggested one, as this will asynchronously stream the video the client's browser. This will allow to do automatically the start end parameters instead of controlling them yourself.

Nevertheless, if you still want to specify a start and an end, you can create the endpoint with the following parameters. Reading and returning the partial file is not a simple task, because some information may be at the beginning of the file or at the end (depending on the data format). that I'm not sure how to do (nor sure if it's possible with fastapi)

@app.get("/video")
async def video_endpoint(start: int = None, end: int = None):
    if start and end:
        if end - start < 0:
            return
    else:
        if start is None:
            start = 0
        end = start + CHUNK_SIZE
    # Read and return the file
like image 84
lsabi Avatar answered Oct 17 '25 10:10

lsabi