Raspberry Camera Mjpg Video Streaming Over the Internet
by vboretskyi in Circuits > Raspberry Pi
2199 Views, 3 Favorites, 0 Comments
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.
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()
Downloads
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" } }
Downloads
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);
});
Downloads
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: