diff --git a/streamer/src/ffmpeg.ts b/streamer/src/ffmpeg.ts index 558a957..2dfc76a 100644 --- a/streamer/src/ffmpeg.ts +++ b/streamer/src/ffmpeg.ts @@ -19,14 +19,17 @@ export class Ffmpeg extends EventEmitter { start(): { videoIn: Writable; audioIn: Writable } { const args = [ "-loglevel", "warning", - // video in (mjpeg pipe on fd 3) + // video in (mjpeg pipe on fd 3) — yuvj420p source, large queue for stable pacing "-f", "image2pipe", "-c:v", "mjpeg", + "-thread_queue_size", "1024", "-r", String(this.opts.framerate), "-i", "pipe:3", // audio in (s16le pcm pipe on fd 4) - "-f", "s16le", "-ar", "48000", "-ac", "2", "-i", "pipe:4", + "-f", "s16le", "-ar", "48000", "-ac", "2", + "-thread_queue_size", "1024", + "-i", "pipe:4", // video encode "-c:v", "libx264", "-preset", "veryfast", - "-pix_fmt", "yuv420p", + "-pix_fmt", "yuv420p", "-color_range", "tv", "-b:v", this.opts.videoBitrate, "-maxrate", this.opts.videoBitrate, "-bufsize", "9000k", "-g", String(this.opts.framerate * 2), "-keyint_min", String(this.opts.framerate * 2), @@ -48,6 +51,12 @@ export class Ffmpeg extends EventEmitter { this.proc.stderr.on("data", (d) => this.emit("log", d.toString())); this.proc.on("exit", (code) => this.emit("exit", code)); + // ffmpeg exiting (e.g. RTMP drop) closes its stdins — subsequent writes + // emit EPIPE on these sockets, which would crash the supervisor as + // unhandled. Catch them; the proc.on("exit") handler does the actual restart. + videoIn.on("error", (err) => this.emit("log", `videoIn: ${err.message}`)); + audioIn.on("error", (err) => this.emit("log", `audioIn: ${err.message}`)); + return { videoIn, audioIn }; }