I'm working on a project with my Raspberry Pi 0 and a camera. I'm writing my code in Python using the PiCamera module. This file handles setting up the camera and Starting Web streaming. I had no clue on how to work with HTML and web streaming, so I followed the example in the PiCamera documentation.
Here's my file (it's very similar with the example):
import io
import picamera
import logging
import socketserver
from time import sleep
from threading import Condition
from http import server
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(301)
self.send_header('Location', '/index.html')
self.end_headers()
elif self.path == '/index.html':
content = SetupPage().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
def SetupPage():
page="""\
<html>
<head>
<title>Testing stream</title>
</head>
<body>
<center><h1>Live Broadcast</h1>
<img src="stream.mjpg" width="1280" height="720" /></center>
</body>
</html>"""
return page
def SetupCamera():
print('Initializing camera.')
camera = picamera.PiCamera()
camera.resolution = (1280,720)
camera.framerate = 30
camera.rotation = 90
print('Camera initialized.')
return camera
camera = SetupCamera()
output = StreamingOutput()
camera.start_recording(output, format='mjpeg')
print('RECORDING!')
try:
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
except KeyboardInterrupt:
pass
finally:
print(' TERMINATING!')
camera.stop_recording()
print('STOPPED RECORDING!')
print('Closing...')
This code works and does the streaming perfectly. But I wanted to turn the last bit into a function, so I can import it in another file. Something like this:
def StartStream():
camera = SetupCamera()
output = StreamingOutput()
camera.start_recording(output, format='mjpeg')
print('RECORDING!')
try:
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
except KeyboardInterrupt:
pass
finally:
print(' TERMINATING!')
camera.stop_recording()
print('STOPPED RECORDING!')
print('Closing...')
StartStream()
But now, it does not work. The website will display, but there will be no streaming. The console will present this output uppon running the file.
Initializing camera.
Camera initialized.
RECORDING!
<my ip> - - [19/Jun/2019 16:54:25] "GET /index.html HTTP/1.1" 200 -
<my ip> - - [19/Jun/2019 16:54:25] "GET /stream.mjpg HTTP/1.1" 200 -
WARNING:root:Removed streaming client ('<my ip>', 58487): name 'output' is not defined
Why does it not work? Is it simply not do-able? If so, how can I import this in another file?
output
variable was global but used internal to some of your other functions. When you put it into a function too, it was no longer global but rather local to the new function. When the original function was called, it no longer had a definition for it.