lets see . . .

This commit is contained in:
legop3
2026-01-13 17:21:32 -05:00
parent 4ab6bad1b8
commit f3e13f6ab7
25 changed files with 841 additions and 175 deletions
+90 -7
View File
@@ -2,13 +2,15 @@
set -euo pipefail
# Configurable via environment
DEVICE="${DEVICE:-/dev/video0}"
RESOLUTION="${RESOLUTION:-640x480}"
QUALITY="${QUALITY:-10}" # ffmpeg MJPEG quality (lower is better)
PORT="${PORT:-8088}"
WORKDIR="${WORKDIR:-/run/roomcam}"
export DEVICE="${DEVICE:-/dev/video0}"
export RESOLUTION="${RESOLUTION:-640x480}"
export QUALITY="${QUALITY:-10}" # ffmpeg MJPEG quality (lower is better)
export PORT="${PORT:-8088}"
export WORKDIR="${WORKDIR:-/run/roomcam}"
# Optional: set INPUT_FORMAT=bayer_grbg8 to transcode raw Bayer cams (e.g., OV534) to JPEG.
INPUT_FORMAT="${INPUT_FORMAT:-mjpeg}"
export INPUT_FORMAT="${INPUT_FORMAT:-mjpeg}"
export MJPEG_FPS="${MJPEG_FPS:-15}"
export MJPEG_QUALITY="${MJPEG_QUALITY:-8}"
mkdir -p "${WORKDIR}"
SNAPSHOT_PATH="${WORKDIR}/snapshot.jpg"
@@ -36,7 +38,88 @@ fi
-f image2 -update 1 "${SNAPSHOT_PATH}" &
FFMPEG_PID=$!
/usr/bin/python3 -u -m http.server "${PORT}" --directory "${WORKDIR}" --bind 0.0.0.0 &
cat > "${WORKDIR}/mjpeg_server.py" <<'PY'
import os
import subprocess
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
DEVICE = os.environ.get("DEVICE", "/dev/video0")
RESOLUTION = os.environ.get("RESOLUTION", "640x480")
INPUT_FORMAT = os.environ.get("INPUT_FORMAT", "mjpeg")
MJPEG_FPS = os.environ.get("MJPEG_FPS", "15")
MJPEG_QUALITY = os.environ.get("MJPEG_QUALITY", "8")
WORKDIR = os.environ.get("WORKDIR", "/run/roomcam")
SNAPSHOT_PATH = os.path.join(WORKDIR, "snapshot.jpg")
FFMPEG_INPUT_ARGS = [
"-f", "v4l2",
"-input_format", INPUT_FORMAT,
"-video_size", RESOLUTION,
"-i", DEVICE,
]
FFMPEG_FILTERS = []
if INPUT_FORMAT.startswith("bayer_"):
FFMPEG_FILTERS = ["-pix_fmt", "yuv420p"]
def spawn_mjpeg():
cmd = [
"/usr/bin/ffmpeg",
"-loglevel", "warning", "-nostats",
*FFMPEG_INPUT_ARGS,
*FFMPEG_FILTERS,
"-r", str(MJPEG_FPS),
"-q:v", str(MJPEG_QUALITY),
"-f", "mpjpeg",
"-",
]
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/" or self.path == "/snapshot.jpg":
try:
with open(SNAPSHOT_PATH, "rb") as fh:
data = fh.read()
self.send_response(200)
self.send_header("Content-Type", "image/jpeg")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except FileNotFoundError:
self.send_error(404, "snapshot missing")
return
if self.path == "/stream.mjpg":
self.send_response(200)
self.send_header("Content-Type", "multipart/x-mixed-replace; boundary=ffmpeg")
self.end_headers()
proc = spawn_mjpeg()
try:
while True:
chunk = proc.stdout.read(8192)
if not chunk:
break
self.wfile.write(chunk)
except BrokenPipeError:
pass
finally:
proc.kill()
return
self.send_error(404, "not found")
def log_message(self, format, *args):
return
def main():
addr = ("0.0.0.0", int(os.environ.get("PORT", "8088")))
ThreadingHTTPServer(addr, Handler).serve_forever()
if __name__ == "__main__":
main()
PY
/usr/bin/python3 -u "${WORKDIR}/mjpeg_server.py" &
HTTP_PID=$!
wait -n "${FFMPEG_PID}" "${HTTP_PID}"