Files
live/backend/services/transcoder.py
T

76 lines
2.7 KiB
Python

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, qualities: list[dict]):
if stream_key in self._processes:
return
procs = []
segment_seconds = max(1, settings.hls_segment_seconds)
for quality in qualities:
label = quality["label"]
width = quality["width"]
height = quality["height"]
fps = quality.get("fps", 30)
codec = quality.get("codec", "libx264")
bitrate = quality["bitrate"]
crf = quality.get("crf", 23)
preset = quality.get("preset", "ultrafast")
audio_bitrate = quality.get("audio_bitrate", "128k")
keyframe_seconds = quality.get("keyframe_seconds", segment_seconds)
keyframe_frames = keyframe_seconds * fps
hls_dir = f"/tmp/hls/{stream_key}/{label}"
os.makedirs(hls_dir, exist_ok=True)
cmd = [
"ffmpeg", "-y",
"-i", input_url,
"-c:v", codec, "-preset", preset,
"-r", str(fps), "-b:v", bitrate, "-crf", str(crf),
"-s", f"{width}x{height}",
"-sc_threshold", "0",
"-g", str(keyframe_frames),
"-keyint_min", str(keyframe_frames),
"-force_key_frames", f"expr:gte(t,n_forced*{keyframe_seconds})",
"-copyts", "-start_at_zero",
"-c:a", "aac", "-b:a", audio_bitrate,
"-f", "hls",
"-hls_time", str(segment_seconds),
"-hls_list_size", "6",
"-hls_flags", "delete_segments+independent_segments+program_date_time",
"-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()