skip to Main Content

I have the following server side route code for stream

movies_list = ['./mov1.mp4', './mov2.mp4', './mov3.mp4',]

@app.route("/video", methods=["GET"])
def video():
    headers = request.headers
    if not "range" in headers:
        return current_app.response_class(status=400)

    video_path = os.path.abspath(os.path.join("media", movies_list[0]))
    size = os.stat(video_path)
    size = size.st_size

    chunk_size = (10 ** 6) * 3 #1000kb makes 1mb * 3 = 3mb (this is based on your choice)
    start = int(re.sub("D", "", headers["range"]))
    end = min(start + chunk_size, size - 1)

    content_lenght = end - start + 1

    def get_chunk(video_path, start, chunk_size):
        with open(video_path, "rb") as f:
            f.seek(start)
            chunk = f.read(chunk_size)
        return chunk

    headers = {
        "Content-Range": f"bytes {start}-{end}/{size}",
        "Accept-Ranges": "bytes",
        "Content-Length": content_lenght,
        "Content-Type": "video/mp4",
    }

    return current_app.response_class(get_chunk(video_path, start,chunk_size), 206, headers)

Also client side html page

<video width="720" controls>
  <source src="/video" type="video/mp4">
</video>

How can I send a request from the client side to the server so that it changes the source and starts playing?

2

Answers


  1. Chosen as BEST ANSWER
    @app.route("/video/<int:index>", methods=["GET"])
    def video(index):
        # ... use index to select file ...
        video_path = os.path.abspath(os.path.join("media", movies_list[index])) 
    

    and source change via JS by click button It works, thanks


  2. If you use url /video/<int:index> in Flask to select file by index

    @app.route("/video/<int:index>", methods=["GET"])
    def video(index):
    
        # ... use index to select file ...
        video_path = os.path.abspath(os.path.join("media", movies_list[index])) 
    

    then you can use JavaScript to replace src= in <source> with different index and browser will load different stream.

    video  = document.querySelector('video');
    source = document.querySelector('video source');
    
    source.src = '/video/1';
    video.load();
    video.play();
    

    JavaScript with buttons can look like this:

    <video width="720" controls>
      <source src="/video/0" type="video/mp4">
    </video><br/>
    
    <button onclick="change_stream(0)">VIDEO #1</button>
    <button onclick="change_stream(1)">VIDEO #2</button>
    <button onclick="change_stream(2)">VIDEO #3</button>
    
    <script>
    video  = document.querySelector('video');
    source = document.querySelector('video source');
    
    function change_stream(index) {
        console.log(`change source: ${source.src} -> /video/${index}`);
        source.src = `/video/${index}`;
        //video.currentTime = 0;
        video.load();    
        video.play();
    }       
    </script>
    

    Full working example:

    I use render_template_string so everyone can easily copy and run code.

    import os
    from flask import Flask, request, render_template_string
    import re
    
    app = Flask(__name__)
    
    @app.route('/', )
    def index():
        return render_template_string('''<!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
    
    <video width="720" controls>
      <source src="/video/0" type="video/mp4">
    </video><br/>
    
    <button onclick="change_stream(0)">VIDEO #1</button>
    <button onclick="change_stream(1)">VIDEO #2</button>
    <button onclick="change_stream(2)">VIDEO #3</button>
    
    <script>
    video  = document.querySelector('video');
    source = document.querySelector('video source');
    
    function change_stream(index) {
        console.log(`change source: ${source.src} -> /video/${index}`);
        source.src = `/video/${index}`;
        //video.currentTime = 0;
        video.load();    
        video.play();
    }       
    </script>
    
    </body>
    </html>''')
    
    movies_list = ['./mov1.mp4', './mov2.mp4', './mov3.mp4']
    
    @app.route("/video/<int:index>")
    def video(index):
    
        headers = request.headers
        if not "range" in headers:
            return app.response_class(status=400)
    
        video_path = os.path.abspath(os.path.join("media", movies_list[index]))
        size = os.stat(video_path)
        size = size.st_size
    
        chunk_size = (10 ** 6) * 3 #1000kb makes 1mb * 3 = 3mb (this is based on your choice)
        start = int(re.sub("D", "", headers["range"]))
        end = min(start + chunk_size, size - 1)
    
        content_lenght = end - start + 1
    
        def get_chunk(video_path, start, chunk_size):
            with open(video_path, "rb") as f:
                f.seek(start)
                chunk = f.read(chunk_size)
            return chunk
    
        headers = {
            "Content-Range": f"bytes {start}-{end}/{size}",
            "Accept-Ranges": "bytes",
            "Content-Length": content_lenght,
            "Content-Type": "video/mp4",
        }
    
        return app.response_class(get_chunk(video_path, start,chunk_size), 206, headers)
        
    
    if __name__ == '__main__':
        #app.debug = True 
        app.run()
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search