How to stream desktop with flask

Viewed 709

I need to stream my desktop using flask but I'm confused. I saw here - https://blog.miguelgrinberg.com/post/video-streaming-with-flask that I can "fool" flask to think I have a webcam and stream another images. I tried to get the desktop image using the gen(camera) method and made a few changes to the Camera class but I still get a blank screen and couldn't find a solution online. My code:

import mss
import numpy

class Camera(object):
    def __init__(self):
        with mss.mss() as sct:
            # Part of the screen to capture
            monitor = {"top": 40, "left": 0, "width": 800, "height": 640}
        self.frames = sct.grab(monitor)

    def get_frame(self):
        return self.frames
from flask import Response
from flask import Flask
from flask import render_template
import threading
import numpy
import time
import cv2
import mss
from camera import Camera


app = Flask(__name__)

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

def gen(camera):
    while True:
        frame = camera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

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

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)
1 Answers

I think the problem arises from the fact that you are not encoding the raw data as JPEG.

The following implementation is based on excerpts from the code here. I've shortened the code a bit. Please take a look at the original to find out the missing parts. You should be able to put it together into a working completed variant.

import cv2
import mss
import numpy

import threading
import time

class Camera(object):
    thread = None
    frame = None
    last_access = 0

    def __init__(self):
        if Camera.thread is None:
            Camera.last_access = time.time()
            Camera.thread = threading.Thread(target=self._thread)
            Camera.thread.start()

            while self.get_frame() is None:
                time.sleep(0)

    def get_frame(self):
        '''Get the current frame.'''
        Camera.last_access = time.time()

        return Camera.frame

    @staticmethod
    def frames():
        '''Create a new frame every 2 seconds.'''
        monitor = {
            'top': 40,
            'left': 0,
            'width': 800,
            'height': 640
        }
        with mss.mss() as sct:
            while True:
                time.sleep(2)
                raw = sct.grab(monitor)
                # Use numpy and opencv to convert the data to JPEG. 
                img = cv2.imencode('.jpg', numpy.array(raw))[1].tobytes()
                yield(img)

    @classmethod
    def _thread(cls):
        '''As long as there is a connection and the thread is running, reassign the current frame.'''
        print('Starting camera thread.')
        frames_iter = cls.frames()
        for frame in frames_iter:
            Camera.frame = frame
            if time.time() - cls.last_access > 10:
                frames_iter.close()
                print('Stopping camera thread due to inactivity.')
                break
        cls.thread = None

In your example, only one image is created when the respective instance of the camera is initialized.
In the version above, a new picture is taken continuously every 2 seconds within a thread. This is then set as the current frame and streamed. If there is no connection to a client, the thread is terminated. The memory management has also been significantly revised.

Related