From 01c0c54de6c05312d7c22aff836f539cb4a4bbdd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Nils=20Forss=C3=A9n?= Date: Fri, 14 Jun 2024 00:36:46 +0200 Subject: [PATCH] added python cameraweb streamer --- README.md | 2 +- py/cam_stream_web.py | 93 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100755 py/cam_stream_web.py diff --git a/README.md b/README.md index 218312d..aece5e7 100755 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Enable fan pin 20 through raspi-config ``` -sudo apt install -y cmake build-essential checkinstall zlib1g-dev libssl-dev python3 python3-pip ninja-build git ufw +sudo apt install -y cmake build-essential checkinstall zlib1g-dev libssl-dev python3 python3-pip ninja-build git ufw python3-picamera2 --no-install-recommends ``` based a bit on example [this is my link](https://github.com/mavlink/mavlink/blob/master/examples/c/udp_example.c) diff --git a/py/cam_stream_web.py b/py/cam_stream_web.py new file mode 100755 index 0000000..1b427d0 --- /dev/null +++ b/py/cam_stream_web.py @@ -0,0 +1,93 @@ +#!/usr/bin/python3 + +# This is the same as mjpeg_server.py, but uses the h/w MJPEG encoder. + +import io +import logging +import socketserver +from http import server +from threading import Condition + +from picamera2 import Picamera2 +from picamera2.encoders import MJPEGEncoder +from picamera2.outputs import FileOutput + +PAGE = """\ + + +picamera2 MJPEG streaming demo + + +

Picamera2 MJPEG Streaming Demo

+ + + +""" + +class StreamingOutput(io.BufferedIOBase): + def __init__(self): + self.frame = None + self.condition = Condition() + + def write(self, buf): + with self.condition: + self.frame = buf + self.condition.notify_all() + + +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': + 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 + + +picam2 = Picamera2() +picam2.configure(picam2.create_video_configuration(main={"size": (640, 480)})) +output = StreamingOutput() +picam2.start_recording(MJPEGEncoder(), FileOutput(output)) + +try: + address = ('', 8000) + server = StreamingServer(address, StreamingHandler) + server.serve_forever() +finally: + picam2.stop_recording() \ No newline at end of file -- 2.30.2