mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
update
This commit is contained in:
@@ -17,29 +17,15 @@ SNAPSHOT_PATH="${WORKDIR}/snapshot.jpg"
|
|||||||
rm -f "${SNAPSHOT_PATH}"
|
rm -f "${SNAPSHOT_PATH}"
|
||||||
# push
|
# push
|
||||||
cleanup() {
|
cleanup() {
|
||||||
[[ -n "${FFMPEG_PID:-}" ]] && kill "${FFMPEG_PID}" 2>/dev/null || true
|
|
||||||
[[ -n "${HTTP_PID:-}" ]] && kill "${HTTP_PID}" 2>/dev/null || true
|
[[ -n "${HTTP_PID:-}" ]] && kill "${HTTP_PID}" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
trap 'exit 0' SIGTERM INT
|
trap 'exit 0' SIGTERM INT
|
||||||
|
|
||||||
FFMPEG_INPUT_ARGS=(-f v4l2 -input_format "${INPUT_FORMAT}" -video_size "${RESOLUTION}" -i "${DEVICE}")
|
|
||||||
FFMPEG_FILTERS=()
|
|
||||||
if [[ "${INPUT_FORMAT}" == bayer_* ]]; then
|
|
||||||
# Convert raw Bayer to a JPEG-friendly pixel format.
|
|
||||||
FFMPEG_FILTERS=(-pix_fmt yuv420p)
|
|
||||||
fi
|
|
||||||
|
|
||||||
/usr/bin/ffmpeg -y \
|
|
||||||
-loglevel warning -nostats \
|
|
||||||
"${FFMPEG_INPUT_ARGS[@]}" \
|
|
||||||
"${FFMPEG_FILTERS[@]}" \
|
|
||||||
-q:v "${QUALITY}" \
|
|
||||||
-f image2 -update 1 "${SNAPSHOT_PATH}" &
|
|
||||||
FFMPEG_PID=$!
|
|
||||||
|
|
||||||
cat > "${WORKDIR}/mjpeg_server.py" <<'PY'
|
cat > "${WORKDIR}/mjpeg_server.py" <<'PY'
|
||||||
import os
|
import os
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
|
||||||
@@ -61,6 +47,10 @@ FFMPEG_FILTERS = []
|
|||||||
if INPUT_FORMAT.startswith("bayer_"):
|
if INPUT_FORMAT.startswith("bayer_"):
|
||||||
FFMPEG_FILTERS = ["-pix_fmt", "yuv420p"]
|
FFMPEG_FILTERS = ["-pix_fmt", "yuv420p"]
|
||||||
|
|
||||||
|
FRAME_LOCK = threading.Lock()
|
||||||
|
FRAME_EVENT = threading.Event()
|
||||||
|
LATEST_FRAME = b""
|
||||||
|
|
||||||
def spawn_mjpeg():
|
def spawn_mjpeg():
|
||||||
cmd = [
|
cmd = [
|
||||||
"/usr/bin/ffmpeg",
|
"/usr/bin/ffmpeg",
|
||||||
@@ -69,41 +59,84 @@ def spawn_mjpeg():
|
|||||||
*FFMPEG_FILTERS,
|
*FFMPEG_FILTERS,
|
||||||
"-r", str(MJPEG_FPS),
|
"-r", str(MJPEG_FPS),
|
||||||
"-q:v", str(MJPEG_QUALITY),
|
"-q:v", str(MJPEG_QUALITY),
|
||||||
"-f", "mpjpeg",
|
"-f", "mjpeg",
|
||||||
"-",
|
"-",
|
||||||
]
|
]
|
||||||
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||||
|
|
||||||
class Handler(BaseHTTPRequestHandler):
|
def update_frame(frame_bytes):
|
||||||
def do_GET(self):
|
global LATEST_FRAME
|
||||||
if self.path == "/" or self.path == "/snapshot.jpg":
|
with FRAME_LOCK:
|
||||||
|
LATEST_FRAME = frame_bytes
|
||||||
|
FRAME_EVENT.set()
|
||||||
try:
|
try:
|
||||||
with open(SNAPSHOT_PATH, "rb") as fh:
|
with open(SNAPSHOT_PATH, "wb") as fh:
|
||||||
data = fh.read()
|
fh.write(frame_bytes)
|
||||||
self.send_response(200)
|
except OSError:
|
||||||
self.send_header("Content-Type", "image/jpeg")
|
pass
|
||||||
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":
|
def frame_reader():
|
||||||
self.send_response(200)
|
while True:
|
||||||
self.send_header("Content-Type", "multipart/x-mixed-replace; boundary=ffmpeg")
|
|
||||||
self.end_headers()
|
|
||||||
proc = spawn_mjpeg()
|
proc = spawn_mjpeg()
|
||||||
|
buffer = b""
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
chunk = proc.stdout.read(8192)
|
chunk = proc.stdout.read(8192)
|
||||||
if not chunk:
|
if not chunk:
|
||||||
break
|
break
|
||||||
self.wfile.write(chunk)
|
buffer += chunk
|
||||||
|
while True:
|
||||||
|
start = buffer.find(b"\xff\xd8")
|
||||||
|
end = buffer.find(b"\xff\xd9", start + 2)
|
||||||
|
if start == -1 or end == -1:
|
||||||
|
break
|
||||||
|
frame = buffer[start : end + 2]
|
||||||
|
buffer = buffer[end + 2 :]
|
||||||
|
update_frame(frame)
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
proc.kill()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
class Handler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == "/" or self.path == "/snapshot.jpg":
|
||||||
|
with FRAME_LOCK:
|
||||||
|
frame = LATEST_FRAME
|
||||||
|
if not frame:
|
||||||
|
self.send_error(404, "snapshot missing")
|
||||||
|
return
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "image/jpeg")
|
||||||
|
self.send_header("Content-Length", str(len(frame)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(frame)
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.path == "/stream.mjpg":
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "multipart/x-mixed-replace; boundary=frame")
|
||||||
|
self.end_headers()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
FRAME_EVENT.wait(timeout=2)
|
||||||
|
FRAME_EVENT.clear()
|
||||||
|
with FRAME_LOCK:
|
||||||
|
frame = LATEST_FRAME
|
||||||
|
if not frame:
|
||||||
|
continue
|
||||||
|
header = (
|
||||||
|
b"--frame\r\n"
|
||||||
|
b"Content-Type: image/jpeg\r\n"
|
||||||
|
+ f"Content-Length: {len(frame)}\r\n\r\n".encode("ascii")
|
||||||
|
)
|
||||||
|
self.wfile.write(header)
|
||||||
|
self.wfile.write(frame)
|
||||||
|
self.wfile.write(b"\r\n")
|
||||||
except BrokenPipeError:
|
except BrokenPipeError:
|
||||||
pass
|
pass
|
||||||
finally:
|
|
||||||
proc.kill()
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.send_error(404, "not found")
|
self.send_error(404, "not found")
|
||||||
@@ -112,6 +145,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
threading.Thread(target=frame_reader, daemon=True).start()
|
||||||
addr = ("0.0.0.0", int(os.environ.get("PORT", "8088")))
|
addr = ("0.0.0.0", int(os.environ.get("PORT", "8088")))
|
||||||
ThreadingHTTPServer(addr, Handler).serve_forever()
|
ThreadingHTTPServer(addr, Handler).serve_forever()
|
||||||
|
|
||||||
@@ -122,4 +156,4 @@ PY
|
|||||||
/usr/bin/python3 -u "${WORKDIR}/mjpeg_server.py" &
|
/usr/bin/python3 -u "${WORKDIR}/mjpeg_server.py" &
|
||||||
HTTP_PID=$!
|
HTTP_PID=$!
|
||||||
|
|
||||||
wait -n "${FFMPEG_PID}" "${HTTP_PID}"
|
wait -n "${HTTP_PID}"
|
||||||
|
|||||||
Reference in New Issue
Block a user