Streaming live video feed on a website with a mjpeg server

Basic video streaming on a webpage can be quite handy when you want to show a live view from an IP camera or other similar source. From many solutions available I'll showcase here a simple MJPEG server streaming a video source and displaying it on a webpage.

MJPEG server in Python

There is a lot of examples for a MJPEG server. For this showcase I've decided to use a simple bootrino/maryjane server. Just install Sanic and you can launch the server.

This server will stream contents of a /dev/shm/img.jpeg file in a loop. You can change the path to match your system.

The stream will available under http://0.0.0.0:8080/maryjane/ URL. To display it on a web page all you need is an img tag:

<html>
<head>
    <title>Server test</title>
    <style>
        body {
            background-color: black;
        }
        img {
            max-width: 100%;
        }
    </style>
</head>
<body>
    <img alt="streaming test" src="http://0.0.0.0:8080/maryjane/"/>
</body>
</html>

This should display a static image (assuming the image path set in the server exists). To turn it into a video we have to use another tool to stream data and save it said JPEG file.

Video streaming options

To stream some data into a JPEG file we can use ffmpeg. On Linux/macOS we can stream a video file like this:

ffmpeg -y -re -stream_loop -1 -i MOVIE_FILE.XYZ -f image2 -update 1 /path/to/img.jpeg
Video file streamed by the server
Video file streamed by the server (source: Snakecharmer YT)

For Linux desktop environment using X.org you can capture and stream your desktop with this:

ffmpeg -fflags nobuffer -f x11grab -r 15 -video_size 1920x1080 -i :0 -f image2 -update 1 /path/to/img.jpeg
Streaming local Linux desktop
Streaming local Linux desktop

Where you can adjust the resolution of the captured area (from 1920x1080 to your screen resolution).

And the options do not end there. If you have other source of video frames that can be saved as JPEG then you can stream it. Some IP cameras offer such options if not providing their own MJPEG stream in the first place.

I've also used one of machine vision/astronomical camera to capture frames - QHY174MM. You can find more details about it in my previous article - Scripting machine vision and astronomical cameras in Python. I've set it to save given frame under the same file that then was streamed by the mjpeg server:

Stream from a QHY174MM monochromatic camera
Stream from a QHY174MM monochromatic camera
QHY174MM with a C-mount lens
QHY174MM with a C-mount lens
Stream live example

Alternatively you could edit the server so that so it gets it data on it own so that so a intermediate file is not needed.

Quality and compatibility of MJPEG streams

If you would want to show your stream outside of localhost you can proxy it with ngrok, but for a production setup you will have to do it on a server. The MJPEG stream has some disadvantages like compression and relatively high bandwidth requirements than newer solutions using H.264 or better. The stream quality will depend on source material - if it's already compressed then end result will be much worse. The img tag stream is supported by modern browsers. You do not have any control over the stream on the webpage and it can't do audio. From my testing the stream could also occasionally break and stop displaying the image. Page would have to be reloaded to make it work again.

FFMPEG streaming does lower the image quality by a lot versus original file on the right
FFMPEG streaming does lower the image quality by a lot versus original file on the right

If you want something more reliable and advanced you can check for example restreamer.

Comment article