diff --git a/services/capture/src/capture-manager.js b/services/capture/src/capture-manager.js index e46627a..ad20cef 100644 --- a/services/capture/src/capture-manager.js +++ b/services/capture/src/capture-manager.js @@ -360,12 +360,8 @@ const CONTAINER_EXT = { // keeps a short GOP. Muxed to a raw `mpeg2video` elementary stream (no // container) so raw2bmx ingests it via --mpeg2lg_*. const GROWING_VIDEO_ELEMENTARY_ARGS = [ - '-c:v', 'h264_nvenc', '-profile:v', 'high', - '-preset', 'p1', '-tune', 'll', - '-rc', 'constqp', '-qp', '21', - '-pix_fmt', 'yuv422p', - '-g', '1', - '-aud', '1', // Access Unit Delimiters required for raw2bmx --avc_high wrapper + '-c:v', 'mpeg2video', '-pix_fmt', 'yuv422p', + '-dc', '10', '-g', '15', '-bf', '2', ]; const GROWING_DEFAULT_BITRATE = '25M'; const GROWING_EXT = 'mxf'; @@ -416,11 +412,14 @@ function deriveGrowingRaster(resolution, framerate, scanHint = null) { if (height == null) height = 1080; // default raster // ffmpeg rate + raw2bmx rate strings for the common broadcast rates. + // CRITICAL: XDCAM HD422 (MPEG-2 422 Long GOP) at 1080 lines does NOT support + // 1080p59.94 — raw2bmx rejects MPEG-2 422 @ 60000/1001 outright. A 1080p59.94 + // SDI feed is therefore wrapped as 1080i59.94 (= 30000/1001 frame rate), which + // is exactly what every previously-working growing file on the share used and + // what Premiere's edit-while-ingest path reads. So 59.94 maps to 30000/1001. function rates(fps) { if (fps == null) return { ff: '30000/1001', raw: '30000/1001' }; // 1080i59.94 default - if (Math.abs(fps - 59.94) < 0.2) - return { ff: '60000/1001', raw: '60000/1001' }; - if (Math.abs(fps - 29.97) < 0.05) + if (Math.abs(fps - 59.94) < 0.2 || Math.abs(fps - 29.97) < 0.05) return { ff: '30000/1001', raw: '30000/1001' }; if (Math.abs(fps - 60) < 0.05) return { ff: '60', raw: '60' }; if (Math.abs(fps - 50) < 0.05) return { ff: '25', raw: '25' }; // 1080i50 → 25 fps frames @@ -430,17 +429,18 @@ function deriveGrowingRaster(resolution, framerate, scanHint = null) { return { ff: String(fps), raw: String(fps) }; } - // Default scan: 1080 → interlaced (broadcast SDI default), 720/below → p. - // scanHint ('p'/'i') overrides this default so progressive Deltacast captures - // are wrapped as progressive MXFs. - if (scan == null) scan = scanHint || ((height >= 1080) ? 'i' : 'p'); + // Scan for the MPEG-2 422 essence. raw2bmx CANNOT wrap MPEG-2 422 as 1080p at + // 59.94, so a 1080-line raster is always wrapped as INTERLACED (1080i59.94), + // regardless of the progressive scanHint. 720 and below stay progressive. + if (height >= 1080) scan = 'i'; + else if (scan == null) scan = scanHint || 'p'; const r = rates(fpsNum); let rawFlag; if (height >= 1080) { - rawFlag = '--avci100_1080p'; + rawFlag = '--mpeg2lg_422p_hl_1080i'; } else if (height >= 720) { - rawFlag = '--avci100_720p'; + rawFlag = '--mpeg2lg_422p_hl_720p'; if (fpsNum == null) { r.ff = '60000/1001'; r.raw = '60000/1001'; } } else { rawFlag = '--mpeg2lg_422p_ml_576i'; @@ -863,7 +863,7 @@ class CaptureManager { ...GROWING_VIDEO_ELEMENTARY_ARGS, '-b:v', vb, '-minrate', vb, '-maxrate', vb, '-bufsize', vb, '-r', ffRate, - '-f', 'h264', '@VF@', + '-f', 'mpeg2video', '@VF@', // (b) PCM s16le audio → "$AF" '-map', audioMap, '-c:a', 'pcm_s16le', '-ar', '48000', '-ac', String(ach), @@ -912,7 +912,7 @@ class CaptureManager { // fields with the live frame count every 3s (Premiere reads the header // Duration on each refresh; without the patch it sees duration=N/A). const bmx = [ - 'raw2bmx', '-t', 'op1a', '-o', '"$OUT"', '-f', frameRate, + 'raw2bmx', '-t', 'rdd9', '-o', '"$OUT"', '-f', frameRate, '--part', String(GROWING_PART_INTERVAL_FRAMES), '--index-follows', rawFlag, '"$VF"',