1
votes

To do video streaming with flask, this link and this link both suggest streaming with generator. The following is my working example to stream one video. But my question is: how to stream multiple videos at the same time?

My folder structure looks like this:

root_folder/
    templates/
        index.html
    server.py
    video1.mp4
    video2.mp4

server.py

Camera class reads video file and convert to .jpeg format. Route '/video_feed/<index>' is pointing to video feed with assigned index.

import cv2
from flask import Flask, render_template, Response

app = Flask(__name__)


class Camera:
    def __init__(self, index):
        self.path = f'video{index}.mp4'
        self.cap = cv2.VideoCapture(self.path)

    def get_frame(self):
        while 1:
            success, image = self.cap.read()
            # to replay video infinitely
            if not success:
                print('replay')
                self.cap = cv2.VideoCapture(self.path)
                success, image = self.cap.read()

            _, encoded = cv2.imencode(".jpg", image)

            yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
                  bytearray(encoded) + b'\r\n')


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/video_feed/<index>')
def video_feed(index):
    return Response(Camera(index).get_frame(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


if __name__ == '__main__':
    app.run(debug=True)

index.html

<img src="{{ url_for('video_feed', index='1') }}">
<!--<img src="{{ url_for('video_feed', index='2') }}">-->

This works great when only one img tag is asking for video feed. But how do I stream multiple videos at the same time? When I uncomment the other img tag, frontend got stuck. Streams were not playing and CPU usage skyrocketed.

I think I completely messed up. What is going on with my code?

In normal python programs (not with flask), I would deal with multiple videos with multiprocess or threading. However, I'm confused with the threading concepts in flask and can't figure out how to implement.

Any suggestion is appreciated. Thank you!

1

1 Answers

1
votes

I am not a Falsk Guru, but here's the only idea I had, after struggling with the same problem:

  1. Have an identifier to your stream like:
    @app.route('/video/<vid_id>.html')
    def render_video(vid_id):
        return render_template('pages/video_stream.html', name=vid_id)
  1. Then, in your video_stream.html, you can do something like img.src = '/video_feed/' + {{name}}

** I think you need to store the name in a JS variable first, then use the variable

  1. Now, when providing the frames, you can route Flask to the proper generator like so:
    @app.route('/video_feed/<vid_id>')
    def video_feed(vid_id):
        print("Feeding video %s" % vid_id)
        # Do whatever
  1. Either way, I cannot see how to escape the need of a global variable to map from a string to the instance.

  2. Additionally, I am not sure how to garbage-collect the video streamers with ease.

  • One way is having the JS sending a message just-before-window-close, which doesn't seem like a trustable method
  • Another is to store timestamp of last sent frame, and manually kill.
  1. Having said all that, I am still struggling with Flask keeping on serving images to the JS, also when I stop the img refresh timer (so the video in the browser is stopped, but Flask enthusiastically continues to send image to nobody)