Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I stream large videos in Flask [closed]

I have 10 minute videos that I want to be able to stream from my Flask website. How do I do this so that the users don't have to download the entire video before it can play? I am currently running the app through the development server as it is only for a personal project. However, if running through an actual WSGI will fix the issue then I am willing to do so.

like image 473
cubecubed Avatar asked Oct 14 '25 13:10

cubecubed


1 Answers

If it was a camera feed, you'd have to use generator-based code taking into consideration efficiency as in this demo. Here is the for streaming demo improved from here:

First you need to give out the video file in chunks using generators (the yield statement)

def get_chunk(filename, byte1=None, byte2=None):
    filesize = os.path.getsize(filename)
    yielded = 0
    yield_size = 1024 * 1024

    if byte1 is not None:
        if not byte2:
            byte2 = filesize
        yielded = byte1
        filesize = byte2

    with open(filename, 'rb') as f:
        content = f.read()

    while True:
        remaining = filesize - yielded
        if yielded == filesize:
            break
        if remaining >= yield_size:
            yield content[yielded:yielded+yield_size]
            yielded += yield_size
        else:
            yield content[yielded:yielded+remaining]
            yielded += remaining

Then stream the file on request:

@app.route('/')
def get_file():
    filename = 'try2.mp4'
    filesize = os.path.getsize(filename)
    range_header = flask_request.headers.get('Range', None)

    if range_header:
        byte1, byte2 = None, None
        match = re.search(r'(\d+)-(\d*)', range_header)
        groups = match.groups()

        if groups[0]:
            byte1 = int(groups[0])
        if groups[1]:
            byte2 = int(groups[1])

        if not byte2:
            byte2 = byte1 + 1024 * 1024
            if byte2 > filesize:
                byte2 = filesize

        length = byte2 + 1 - byte1

        resp = Response(
            get_chunk(filename, byte1, byte2),
            status=206, mimetype='video/mp4',
            content_type='video/mp4',
            direct_passthrough=True
        )

        resp.headers.add('Content-Range',
                         'bytes {0}-{1}/{2}'
                         .format(byte1,
                                 length,
                                 filesize))
        return resp

    return Response(
        get_chunk(),
        status=200, mimetype='video/mp4'
    )

Add the required headers using after_request

@app.after_request
def after_request(response):
    response.headers.add('Accept-Ranges', 'bytes')
    return response
like image 159
Abdur-Rahmaan Janhangeer Avatar answered Oct 21 '25 02:10

Abdur-Rahmaan Janhangeer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!