Initial commit: LiveStream Platform
Backend: FastAPI + SQLAlchemy + SQLite Frontend: React + Vite + Ant Design (serif Anthropic theme) Media server: MediaMTX with edge node support Load balancing: round-robin / weighted / least-conn Multicast detection with automatic fallback Transcoding support via FFmpeg (configurable quality) hls.js player with line & quality switching Admin panel with password auth Windows compatible scripts
This commit is contained in:
commit
2e4594fa77
43 files changed
+2196
No files matched your search
@@ -0,0 +1,63 @@
|
||||
import asyncio
|
||||
import subprocess
|
||||
import os
|
||||
from config import settings
|
||||
|
||||
|
||||
class TranscodeManager:
|
||||
_processes: dict[str, list[subprocess.Popen]] = {}
|
||||
|
||||
def start_transcode(self, stream_key: str, input_url: str):
|
||||
if stream_key in self._processes:
|
||||
return
|
||||
|
||||
procs = []
|
||||
for quality in settings.qualities:
|
||||
label = quality["label"]
|
||||
width = quality["width"]
|
||||
height = quality["height"]
|
||||
bitrate = quality["bitrate"]
|
||||
hls_dir = f"/tmp/hls/{stream_key}/{label}"
|
||||
os.makedirs(hls_dir, exist_ok=True)
|
||||
cmd = [
|
||||
"ffmpeg", "-y",
|
||||
"-i", input_url,
|
||||
"-c:v", "libx264", "-preset", "ultrafast",
|
||||
"-b:v", bitrate,
|
||||
"-s", f"{width}x{height}",
|
||||
"-c:a", "aac", "-b:a", "128k",
|
||||
"-f", "hls",
|
||||
"-hls_time", "4",
|
||||
"-hls_list_size", "6",
|
||||
"-hls_flags", "delete_segments",
|
||||
"-hls_segment_filename", f"{hls_dir}/segment_%03d.ts",
|
||||
f"{hls_dir}/index.m3u8",
|
||||
]
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
||||
)
|
||||
procs.append(proc)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
self._processes[stream_key] = procs
|
||||
|
||||
def stop_transcode(self, stream_key: str):
|
||||
procs = self._processes.pop(stream_key, [])
|
||||
for proc in procs:
|
||||
try:
|
||||
proc.terminate()
|
||||
proc.wait(timeout=5)
|
||||
except Exception:
|
||||
try:
|
||||
proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def stop_all(self):
|
||||
for key in list(self._processes.keys()):
|
||||
self.stop_transcode(key)
|
||||
|
||||
|
||||
transcode_mgr = TranscodeManager()
|
||||
Reference in new issue
Block a user