0

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?

  • 1
    This is just a Python programming question. Nothing really to do with Raspberry Pi. – Brick Jun 19 at 18:07
  • It looks like you got the scope wrong. The 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. – Brick Jun 19 at 18:10
  • I'm currently running into the exactly same issue as yours. Wonder if you find out any solution. – James Wong Jul 6 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.