Skip to content

Instantly share code, notes, and snippets.

@naezith
Last active June 26, 2018 23:14
Show Gist options
  • Save naezith/fe2a69163058659aa724140dd3c775ee to your computer and use it in GitHub Desktop.
Save naezith/fe2a69163058659aa724140dd3c775ee to your computer and use it in GitHub Desktop.
picamera mjpeg stream, view on HTML page. Camera closes if noone watches.
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
PAGE="""\
<html>
<head>
<title>naezith pi camera mjpeg stream</title>
</head>
<body>
<center>
<h1>naezith pi camera mjpeg stream</h1>
<img src="stream.mjpg" width="640" height="480" />
</center>
</body>
</html>
"""
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)
camera = 0
viewer_count = 0
output = StreamingOutput()
def start_recording():
global camera
global viewer_count
viewer_count += 1
if camera == 0:
camera = picamera.PiCamera(resolution='640x480', framerate=24)
camera.start_recording(output, format='mjpeg')
def stop_recording():
global camera
global viewer_count
viewer_count -= 1
if camera != 0 and viewer_count <= 0:
camera.stop_recording()
camera.close()
camera = 0
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':
start_recording()
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:
stop_recording()
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
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment