Raspberry Camera Mjpg Video Streaming Over the Internet

Introduction: Raspberry Camera Mjpg Video Streaming Over the Internet

I saw attempts to stream a video from a raspberry pi to your web application running on NodeJS. Most of the ideas used non standard solutions eg sending base64 image strings over WebSockets to a web client.

This is a simple example of how you can create mjpg stream, expose it to the internet from your local raspberry pi and have access to it from anywhere over the internet or use it in your application UI.

The instruction assumes you have nodejs installed and camera set up on you rasperry pi.

Step 1: Create Local Python Http Server and Capture Video Stream From Your Raspberry

stream.py:

<pre style="color: rgb(0, 0, 0); white-space: pre-wrap;">import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server

PORT = 9090
FRAME_RATE = 24
RESOLUTION = '640x480'

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            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

with picamera.PiCamera(resolution=RESOLUTION, framerate=FRAME_RATE) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', PORT)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

Step 2: Create Config File for Our JS App

package.json:

{
"name": "mjpeg-video-stream", "version": "1.0.0", "description": "mjpeg video stream", "main": "main.js", "scripts": { "start": "node main.js" }, "author": "givehug", "license": "MIT", "dependencies": { "ngrok": "3.2.5" } }

Step 3: Create Main JS File to Run Application

main.js:

const ngrok = require('ngrok');
const {spawn} = require('child_process');
const stream = spawn('python3',  ['./stream.py']);

stream.stdout.once('data', async() => {
	const url = await ngrok.connect(9090);
});

Attachments

Step 4: Run a Program

Thats almost it, run

npm i
npm start

Now you have control over your ngrok generated video stream url here

const url = await ngrok.connect(9090);

use it however you prefer. I usually send it to my NodeJS web server in cloud and then to my web application as src to an image element:

<img src="https://user:pwd@c038f6f8.ngrok.io" />


PS:

- generated url will be different every time, you may want to opt in for prepaid static url by ngrok

- you may want to password protect your video stream, here is an example:

const url = await ngrok.connect({
	addr: 9090,
	auth: 'user:pwd',
});

- if you do not use NodeJS, you can install standalone ngrok executable directly on your raspberry pi (or look for similar python modules). Run your stream.py script and start ngrok at port 9090:

./ngrok http 9090

then follow the url displayed in the terminal window.

References:

- full source code
- ngrok
- ngrok js
- picamera web streaming

Be the First to Share

    Recommendations

    • Big and Small Contest

      Big and Small Contest
    • Make It Bridge

      Make It Bridge
    • For the Home Contest

      For the Home Contest

    4 Comments

    0
    koushika1234
    koushika1234

    Question 2 years ago

    We have followed all the steps and downloaded the files. We have our stream running on port 8081. But we are getting the following error:attached image. Pls pls help! Thank you!

    Error mjpeg.jpeg
    0
    vboretskyi
    vboretskyi

    Answer 2 years ago

    Hey @koushika1234, looks like you don’t have node modules installed, try running ‘npm install’ command

    0
    koushika1234
    koushika1234

    Reply 2 years ago

    Thank you!