Search code examples
pythonflaskwebserver

Flask read in frame from diffrent process


I have a programm, that starts many processes and gets videoframes from one of them. The frames are in a multiprocessing queue and I can access them in the main program at any time.

Now I want to implement a flask webserver, that runs as a seperate process, started by the main process.

The server currently looks like this:


from flask import Flask, render_template, Response

class FlaskAppWrapper(object):
    def __init__(self, app, **configs):
        self.app = app
        self.configs(**configs)
        self.frame = None

    def configs(self, **configs):
        for config, value in configs:
            self.app.config[config.upper()] = value

    def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, methods=['GET'], *args, **kwargs):
        self.app.add_url_rule(endpoint, endpoint_name, handler, methods=methods, *args, **kwargs)
    
    def run(self, **kwargs):
        self.app.run(**kwargs)

    def index():
        return render_template('index.html')

    def gen(self):
        while True:
            yield (b'--frame\r\n'
                b'Content-Type: image/jpeg\r\n\r\n' + self.frame + b'\r\n\r\n')
            
    def video_feed(self):
        return Response(self.gen(),
                        mimetype='multipart/x-mixed-replace; boundary=frame')

def run_webserver():
    flask_app = Flask(__name__)
    app = FlaskAppWrapper(flask_app)

    app.add_endpoint('/index', 'index', app.index, methods=['GET'])
    app.add_endpoint('/video_feed', 'video_feed', app.video_feed, methods=['GET'])


    app.run(host='0.0.0.0',port='5000', debug=True)

In theory I only need to apply the new frame to the self.frame value and it should work. But I dont know how to update the self.frame, because if the app runs it blocks the process.


Solution

  • You might use a seperate thread to read framse from the multiprocessing queue and update self.frame

    import threading
    from queue import Queue
    from flask import Flask, render_template, Response
    
    class FlaskAppWrapper(object):
        def __init__(self, app, **configs):
            self.app = app
            self.configs(**configs)
            self.frame = None
            self.frame_queue = Queue()
            self.thread = threading.Thread(target=self._update_frame)
            self.thread.daemon = True
            self.thread.start()
    
        def configs(self, **configs):
            for config, value in configs:
                self.app.config[config.upper()] = value
    
        def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, methods=['GET'], *args, **kwargs):
            self.app.add_url_rule(endpoint, endpoint_name, handler, methods=methods, *args, **kwargs)
        
        def run(self, **kwargs):
            self.app.run(**kwargs)
    
        def index(self):
            return render_template('index.html')
    
        def gen(self):
            while True:
                frame = self.frame_queue.get()
                yield (b'--frame\r\n'
                    b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
                
        def video_feed(self):
            return Response(self.gen(),
                            mimetype='multipart/x-mixed-replace; boundary=frame')
    
        def _update_frame(self):
            while True:
                frame = self.get_frame_from_queue()
                self.frame = frame
    
        def get_frame_from_queue(self):
            # logic for getting a frame from the multiprocessing queue here
            return frame
    
    def run_webserver():
        flask_app = Flask(__name__)
        app = FlaskAppWrapper(flask_app)
    
        app.add_endpoint('/index', 'index', app.index, methods=['GET'])
        app.add_endpoint('/video_feed', 'video_feed', app.video_feed, methods=['GET'])
    
        app.run(host='0.0.0.0', port='5000', debug=True)