From d52b56d2d99548e996e978c4ae96305f73b24c13 Mon Sep 17 00:00:00 2001 From: yum Date: Tue, 14 Oct 2025 13:56:57 -0700 Subject: offload segment serving to nginx --- README.md | 2 ++ etc/nginx/sites-available/yummers.dev | 15 +++++++-------- opt/obsproxy/server.py | 28 +++++----------------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d84fb76..b2e6aeb 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,10 @@ Shitty service to proxy data from OBS into an HTTP Live Streaming (HLS) feed VRC Environmental knobs: - `OBS_STREAM_KEY` / `STREAM_PSK`: required PSK for the single ingest client. +- `INGEST_THREAD_QUEUE_SIZE`: RTMP demux queue depth before frames are dropped (defaults to `4096`). - `HLS_SEGMENT_TIME`: length (in seconds) of the `.ts` segments emitted by FFmpeg (defaults to `2`). - `HLS_PLAYLIST_SIZE`: number of segments retained in the rolling playlist (defaults to `6`). +- `HLS_DELETE_THRESHOLD`: additional historical HLS segments to keep on disk before pruning (defaults to `2`). - `HOST`: interface Waitress binds to (defaults to `0.0.0.0`). - `PORT`: TCP port Waitress listens on (defaults to `5000`). - `FFMPEG_LOGLEVEL`: override the log verbosity passed to FFmpeg (defaults to `info`). diff --git a/etc/nginx/sites-available/yummers.dev b/etc/nginx/sites-available/yummers.dev index 0b40a41..5a40c66 100644 --- a/etc/nginx/sites-available/yummers.dev +++ b/etc/nginx/sites-available/yummers.dev @@ -38,17 +38,16 @@ server { # OBS Proxy HLS playlist + segments location /hls/ { - proxy_pass http://127.0.0.1:5000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; + alias /var/www/streams/live/; + add_header Cache-Control "no-cache" always; add_header Access-Control-Allow-Origin "*" always; + expires -1; - proxy_connect_timeout 1h; - proxy_send_timeout 1h; - proxy_read_timeout 1h; + autoindex off; + limit_except GET HEAD { + deny all; + } } # OBS Proxy health check diff --git a/opt/obsproxy/server.py b/opt/obsproxy/server.py index 27933b8..16d10cf 100755 --- a/opt/obsproxy/server.py +++ b/opt/obsproxy/server.py @@ -6,7 +6,7 @@ import subprocess import threading import shutil from pathlib import Path -from flask import Flask, request, send_from_directory +from flask import Flask, request import logging import atexit @@ -17,8 +17,10 @@ load_dotenv() # Configuration INGEST_PSK = os.environ.get('OBS_STREAM_KEY') or os.environ.get('STREAM_PSK') +INGEST_THREAD_QUEUE_SIZE = int(os.environ.get('INGEST_THREAD_QUEUE_SIZE', '4096')) HLS_SEGMENT_TIME = float(os.environ.get('HLS_SEGMENT_TIME', '2')) HLS_PLAYLIST_SIZE = int(os.environ.get('HLS_PLAYLIST_SIZE', '6')) +HLS_DELETE_THRESHOLD = int(os.environ.get('HLS_DELETE_THRESHOLD', '2')) BASE_DIR = Path(os.environ.get('STREAM_DIR', '/var/www/streams')) SERVER_DOMAIN = os.environ.get('SERVER_DOMAIN', 'yummers.dev') STREAM_HEX = secrets.token_hex(16) @@ -78,6 +80,7 @@ def start_ffmpeg_process(): '-hide_banner', '-loglevel', os.environ.get('FFMPEG_LOGLEVEL', 'info'), '-fflags', '+genpts', + '-thread_queue_size', str(INGEST_THREAD_QUEUE_SIZE), '-i', f'rtmp://localhost/live/{INGEST_PSK}', '-map', '0:v:0?', '-map', '0:a:0?', @@ -90,6 +93,7 @@ def start_ffmpeg_process(): '-hls_time', str(HLS_SEGMENT_TIME), '-hls_list_size', str(HLS_PLAYLIST_SIZE), '-hls_flags', 'delete_segments+independent_segments', + '-hls_delete_threshold', str(HLS_DELETE_THRESHOLD), '-hls_segment_filename', str(STREAM_PATH / 'segment-%05d.ts'), str(STREAM_PATH / 'stream.m3u8') ] @@ -178,28 +182,6 @@ def cleanup_stream(): # Routes -@app.route(f"{HLS_ROUTE_PREFIX}/stream.m3u8") -def serve_hls_manifest(): - """Serve the HLS master playlist""" - if not stream_active: - return "Stream not found", 404 - - manifest_file = STREAM_PATH / "stream.m3u8" - if not manifest_file.exists(): - return "Manifest not ready", 503 - - return send_from_directory(str(STREAM_PATH), "stream.m3u8") - - -@app.route(f"{HLS_ROUTE_PREFIX}/") -def serve_hls_segments(filename): - """Serve the HLS segment files""" - if not stream_active: - return "Stream not found", 404 - - return send_from_directory(str(STREAM_PATH), filename) - - @app.route('/rtmp_callbacks/on_publish', methods=['POST']) def on_publish(): """Callback when a stream starts""" -- cgit v1.2.3