From ba56e9c3b4e888dd645177a370b4fe77f3d5bad4 Mon Sep 17 00:00:00 2001 From: Jeff Moe Date: Sat, 24 Sep 2022 12:09:34 -0600 Subject: [PATCH] Quick & dirty mjpeg stream on PoE CM4 --- requirements.txt | 6 +++ scripts/stream-mjpeg.py | 89 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 requirements.txt create mode 100755 scripts/stream-mjpeg.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..72f031d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +depthai +numpy +numpy +opencv-python +pillow +blobconverter diff --git a/scripts/stream-mjpeg.py b/scripts/stream-mjpeg.py new file mode 100755 index 0000000..b0de3a3 --- /dev/null +++ b/scripts/stream-mjpeg.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +import json +import socketserver +import threading +import time +from http.server import BaseHTTPRequestHandler, HTTPServer +from io import BytesIO +from pathlib import Path +import sys +from socketserver import ThreadingMixIn +from time import sleep +import depthai as dai +import numpy as np +import cv2 +from PIL import Image +import blobconverter + +HTTP_SERVER_PORT = 8080 + +class TCPServerRequest(socketserver.BaseRequestHandler): + def handle(self): + header = 'HTTP/1.0 200 OK\r\nServer: Mozarella/2.2\r\nAccept-Range: bytes\r\nConnection: close\r\nMax-Age: 0\r\nExpires: 0\r\nCache-Control: no-cache, private\r\nPragma: no-cache\r\nContent-Type: application/json\r\n\r\n' + self.request.send(header.encode()) + while True: + sleep(0.1) + if hasattr(self.server, 'datatosend'): + self.request.send(self.server.datatosend.encode() + "\r\n".encode()) + +# HTTPServer MJPEG +class VideoStreamHandler(BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200) + self.send_header('Content-type', 'multipart/x-mixed-replace; boundary=--jpgboundary') + self.end_headers() + while True: + sleep(0.1) + if hasattr(self.server, 'frametosend'): + image = Image.fromarray(cv2.cvtColor(self.server.frametosend, cv2.COLOR_BGR2RGB)) + stream_file = BytesIO() + image.save(stream_file, 'JPEG') + self.wfile.write("--jpgboundary".encode()) + + self.send_header('Content-type', 'image/jpeg') + self.send_header('Content-length', str(stream_file.getbuffer().nbytes)) + self.end_headers() + image.save(self.wfile, 'JPEG') + + +class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): + """Handle requests in a separate thread.""" + pass + +# start MJPEG HTTP Server +server_HTTP = ThreadedHTTPServer(('0.0.0.0', HTTP_SERVER_PORT), VideoStreamHandler) +th = threading.Thread(target=server_HTTP.serve_forever) +th.daemon = True +th.start() + + +# Create pipeline +pipeline = dai.Pipeline() + +# Define source and output +camRgb = pipeline.createColorCamera() +xoutVideo = pipeline.createXLinkOut() + +xoutVideo.setStreamName("rgb") + +# Properties +camRgb.setBoardSocket(dai.CameraBoardSocket.RGB) +camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P) +camRgb.setVideoSize(1920, 1080) + +xoutVideo.input.setBlocking(False) +xoutVideo.input.setQueueSize(1) + +# Linking +camRgb.video.link(xoutVideo.input) + +# Connect to device and start pipeline +with dai.Device(pipeline) as device: + previewQueue = device.getOutputQueue(name="rgb", maxSize=1, blocking=False) + + while True: + inPreview = previewQueue.get() + frame = inPreview.getCvFrame() + server_HTTP.frametosend = frame +