Raspberry Pi: MJPEG Streaming Web Server (Picamera2)

In this guide, you’ll learn how to set up a video streaming web server with a Raspberry Pi and a camera using a simple script with the Picamera2 library. You’ll be able to access the streaming web server on any web browser in your local network.

Raspberry Pi MJPEG Streaming Web Server Picamera2

Prerequisites

Before proceeding, make sure you check the following prerequisites:

Picamera2 Python Library

Picamera2 is a Python library for interacting with the Raspberry Pi’s camera. It is based on the libcamera camera stack and it is maintained by the Raspberry Pi foundation. It’s no longer recommended to use the older PiCamera library with the latest Raspberry Pi OS versions.

The Picamera2 library is supported on all Raspberry Pi models from the Pi Zero to the RPi 5.

Installing Picamera2 Library

Having an SSH connection established with your Raspberry Pi, update and upgrade your Raspberry Pi, if any updates are available. Run the following command:

sudo apt update && sudo apt upgrade -y

Run the next command to install the Picamera2 library in your Raspberry Pi.

sudo apt install -y python3-picamera2

It is strongly recommended to install and update Picamera2 using the apt command described earlier which will avoid compatibility problems. I’ve encountered many compilation issues while trying to install the Picamera2 library with the pip command on a virtual environment.

Preparing the Raspberry Pi Camera

The Raspberry Pi camera is a small and low-cost camera module compatible with the Raspberry Pi boards. Even though it can be good enough for most projects, some USB cameras will provide better image quality. For this guide, we’ll be using the Raspberry Pi Camera V2 module shown in the following picture:

Raspberry Pi Camera Module V2

This guide also works with the Raspberry Pi Camera V3 and the camera is compatible with all Raspberry Pi models.

Enable the Raspberry Pi Camera Module

If you are running the latest version of Raspberry Pi OS, the official Raspberry Pi cameras will be detected and enabled automatically.

Connect the camera

Connecting the Raspberry Pi Camera Module is very straightforward. With the Pi shutdown, connect the camera to the Pi CSI port as shown in the following figure.

Raspberry Pi 5 Pi Camera Module v2 connected cable

MJPEG Streaming Web Server – Python Script

Running a streaming web server is fairly easy with the Raspberry Pi camera thanks to the Picamera2 Python library.

Create a new file called stream_server.py by running the following command:

nano stream_server.py

Copy the following code to your newly created file:

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-mjpeg-streaming-web-server-picamera2/

# Mostly copied from https://picamera.readthedocs.io/en/release-1.13/recipes2.html
# Run this script, then point a web browser at http:<this-ip-address>:7123
# Note: needs simplejpeg to be installed (pip3 install simplejpeg).

import io
import logging
import socketserver
from http import server
from threading import Condition

from picamera2 import Picamera2
from picamera2.encoders import JpegEncoder
from picamera2.outputs import FileOutput

PAGE = """\
<html>
<head>
<title>picamera2 MJPEG streaming demo</title>
</head>
<body>
<h1>Picamera2 MJPEG Streaming Demo</h1>
<img src="stream.mjpg" width="640" height="480" />
</body>
</html>
"""

class StreamingOutput(io.BufferedIOBase):
    def __init__(self):
        self.frame = None
        self.condition = Condition()

    def write(self, buf):
        with self.condition:
            self.frame = buf
            self.condition.notify_all()


class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()


class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True


picam2 = Picamera2()
picam2.configure(picam2.create_video_configuration(main={"size": (640, 480)}))
output = StreamingOutput()
picam2.start_recording(JpegEncoder(), FileOutput(output))

try:
    address = ('', 7123)
    server = StreamingServer(address, StreamingHandler)
    server.serve_forever()
finally:
    picam2.stop_recording()

View raw code

Press Ctrl+X to save your file, type Y and Enter.

You can customize the web page by changing the HTML and adding some CSS on the PAGE variable. The stream.mjpg refers to the streaming files (the actual video).

PAGE = """\
<html>
<head>
<title>picamera2 MJPEG streaming demo</title>
</head>
<body>
<h1>Picamera2 MJPEG Streaming Demo</h1>
<img src="stream.mjpg" width="640" height="480" />
</body>
</html>
"""

Running the Script

Run the following command to get the Raspberry Pi IP address. You’ll need the IP address to access your web server.

hostname -I
Raspberry Pi IP Address

Then, start your web server by running the following command on your project directory:

python stream_server.py
stream server picamera2 run Python command

Finally, open any web browser on your local network and type the Raspberry Pi IP address followed by the port number :7123.

http://raspberry-pi-ip-address:7123

That’s it! Your Raspberry Pi web server is streaming the MJPEG files.

Streaming video MJPEG server Picamera2 Python example script

Wrapping Up

In this quick guide, you learn how to set up an IP camera using the Raspberry Pi and the Raspberry Pi camera. This can be useful to monitor something on your network in real-time. One of the most used applications is to take an eye on 3D printers, but this can also be used for a wide range of applications like smart doorbells or security cameras.

We hope you’ve found this tutorial useful. You may also want to check other camera-related tutorials.

Finally, you can check all our Raspberry Pi projects on the following link:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

4 thoughts on “Raspberry Pi: MJPEG Streaming Web Server (Picamera2)”

  1. The procedure works great. If it is started from the cli terminal or via ssh, it is possible to add no-hang-up and work in the background so that it continues to work safely even after the termination of the ssh connection or shutdown of the cli-terminal:

    nohup python stream_server.py &

    Reply
  2. sudo apt install -y python3-picamera2
    installation in a virtual environment does not work.
    You need to make common modules of the global and virtual environment, then this works:

    Create a virtual environment with access to global packages:
    python3 -m venv myenv –system-site-packages

    Activate the virtual environment:
    source myenv/bin/activate

    Check availability of picamera2 library:
    python -c “import picamera2; print(picamera2.version)”

    Reply
  3. Thanks for the content! Question, how would it be possible to fetch the camera feed from the raspberry pi (and the camera module) and then send it to another server which hosts the webserver? In this configuration, the raspberry PI hosts both the picamera python script and the webserver. How can these two be “decouple”?

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.