diff --git a/services/capture/src/capture-manager.js b/services/capture/src/capture-manager.js index 39f9d87..5ab6e93 100644 --- a/services/capture/src/capture-manager.js +++ b/services/capture/src/capture-manager.js @@ -552,7 +552,8 @@ class CaptureManager { return { inputArgs: [ - '-use_wallclock_as_timestamps', '1', + // No -use_wallclock_as_timestamps — framecache delivers CFR frames + // at the original ingest rate; -framerate produces correct timestamps. '-thread_queue_size', '512', '-f', 'rawvideo', '-pix_fmt', 'uyvy422', @@ -680,16 +681,21 @@ class CaptureManager { return { inputArgs: [ // fc_pipe stdout → ffmpeg rawvideo input 0 (video) - // -use_wallclock_as_timestamps aligns video+audio by arrival time, - // same as the legacy FIFO path. - '-use_wallclock_as_timestamps', '1', + // DO NOT use -use_wallclock_as_timestamps here. The framecache ring + // delivers frame-accurate 60fps from the SDI clock, so -framerate + // produces correct CFR timestamps from frame 0, immune to ffmpeg + // startup jitter and NVENC cold-start. Wallclock timestamping caused + // wrong framerate in the recorded file (e.g. 56.06 instead of 59.94) + // because arrival-time jitter at ffmpeg startup skewed the PTS. '-thread_queue_size', '512', '-f', 'rawvideo', '-pix_fmt', 'uyvy422', '-video_size', fcSize, '-framerate', fcFps, '-i', 'pipe:0', - // Audio FIFO → ffmpeg input 1 (unchanged from legacy path) + // Audio FIFO → ffmpeg input 1. Keep wallclock on audio so A/V sync + // aligns by arrival time; aresample=async=1 (applied on the master + // output) resamples audio to match the video CFR timestamps. '-use_wallclock_as_timestamps', '1', '-thread_queue_size', '512', '-f', 's16le',