fix(growing): use stable H.264 High All-Intra for 1080p59.94 MXF

XDCAM HD422 does not strictly support 1080p59.94, and ffmpeg/raw2bmx failed to negotiate the stream. Reverted to h264_nvenc (High profile, all-intra GOP 1, yuv420p) which raw2bmx can reliably wrap as OP1a (--avc_high) at 60000/1001. This restores NVENC hardware acceleration and Premiere edit-while-record compatibility.
This commit is contained in:
Zac Gaetano 2026-06-04 17:56:08 +00:00
parent f36de429e8
commit 42806b5e10

View file

@ -360,10 +360,10 @@ const CONTAINER_EXT = {
// keeps a short GOP. Muxed to a raw `mpeg2video` elementary stream (no // keeps a short GOP. Muxed to a raw `mpeg2video` elementary stream (no
// container) so raw2bmx ingests it via --mpeg2lg_*. // container) so raw2bmx ingests it via --mpeg2lg_*.
const GROWING_VIDEO_ELEMENTARY_ARGS = [ const GROWING_VIDEO_ELEMENTARY_ARGS = [
'-c:v', 'h264_nvenc', '-profile:v', 'high422', '-c:v', 'h264_nvenc', '-profile:v', 'high',
'-preset', 'p1', '-tune', 'll', '-preset', 'p1', '-tune', 'll',
'-rc', 'constqp', '-qp', '21', '-rc', 'constqp', '-qp', '21',
'-pix_fmt', 'yuv422p', '-pix_fmt', 'yuv420p',
'-g', '1', '-g', '1',
]; ];
const GROWING_DEFAULT_BITRATE = '25M'; const GROWING_DEFAULT_BITRATE = '25M';
@ -437,12 +437,12 @@ function deriveGrowingRaster(resolution, framerate, scanHint = null) {
let rawFlag; let rawFlag;
if (height >= 1080) { if (height >= 1080) {
rawFlag = (scan === 'p') ? '--avci100_1080p' : '--avci100_1080i'; rawFlag = '--avc_high';
} else if (height >= 720) { } else if (height >= 720) {
rawFlag = '--avci100_720p'; // 720 is always progressive rawFlag = '--avc_high';
if (fpsNum == null) { r.ff = '60000/1001'; r.raw = '60000/1001'; } if (fpsNum == null) { r.ff = '60000/1001'; r.raw = '60000/1001'; }
} else { } else {
rawFlag = '--mpeg2lg_422p_ml_576i'; // SD 576i (PAL); 25 fps rawFlag = '--mpeg2lg_422p_ml_576i';
r.ff = '25'; r.raw = '25'; r.ff = '25'; r.raw = '25';
} }
@ -910,13 +910,13 @@ class CaptureManager {
// on stop, so the inline Python dur-patch below overwrites the header Duration // on stop, so the inline Python dur-patch below overwrites the header Duration
// fields with the live frame count every 3s (Premiere reads the header // fields with the live frame count every 3s (Premiere reads the header
// Duration on each refresh; without the patch it sees duration=N/A). // Duration on each refresh; without the patch it sees duration=N/A).
const bmx = [ const bmx = [
'raw2bmx', '-t', 'rdd9', '-o', '"$OUT"', '-f', frameRate, 'raw2bmx', '-t', 'op1a', '-o', '"$OUT"', '-f', frameRate,
'--part', String(GROWING_PART_INTERVAL_FRAMES), '--part', String(GROWING_PART_INTERVAL_FRAMES),
'--index-follows', '--index-follows',
rawFlag, '"$VF"', rawFlag, '"$VF"',
'-s', '48000', '-q', '16', '--audio-chan', String(ach), '--pcm', '"$AF"', '-s', '48000', '-q', '16', '--audio-chan', String(ach), '--pcm', '"$AF"',
]; ];
const bmxLine = bmx const bmxLine = bmx
.map((t) => (t.startsWith('"$') ? t : sh(t))) .map((t) => (t.startsWith('"$') ? t : sh(t)))
.join(' '); .join(' ');