added python cameraweb streamer
authorNils Forssén <forssennils@gmail.com>
Thu, 13 Jun 2024 22:36:46 +0000 (00:36 +0200)
committerNils Forssén <forssennils@gmail.com>
Thu, 13 Jun 2024 22:36:46 +0000 (00:36 +0200)
README.md
py/cam_stream_web.py [new file with mode: 0755]

index 218312d5b71dc50dc55b55243f6aed916792cc2d..aece5e7dd1d00b34fd1f80b20a857e580b081eb4 100755 (executable)
--- 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 (executable)
index 0000000..1b427d0
--- /dev/null
@@ -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 = """\
+<html>
+<head>
+<title>picamera2 MJPEG streaming demo</title>
+</head>
+<body>
+<h1>Picamera2 MJPEG Streaming Demo</h1>
+<img src="stream.mjpg" width="640" height="480" />
+</body>
+</html>
+"""
+
+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