fix(capture): growing TS is 8-bit 4:2:0 (Premiere-importable) + honor bitrate

Growing master was H.264 High 4:2:2 Intra (high422/yuv422p) — ffprobe/VLC
open it but Adobe Premiere's H.264 importer only accepts 8-bit 4:2:0, so it
refused ("won't import"). Switch growing video to -profile:v high
-pix_fmt yuv420p (still -g 1 all-intra). Also the growing branch ignored the
operator's bitrate; now applies -b:v/-maxrate/-bufsize. Modal notes that
growing mode fixes codec/container (bitrate still applies).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Zac Gaetano 2026-05-31 21:56:58 -04:00
parent 64bbb221f7
commit 7b878d48c9
2 changed files with 35 additions and 4 deletions

View file

@ -242,8 +242,22 @@ const CONTAINER_EXT = {
//
// Audio: AAC (a TS-native codec Premiere imports). PCM-in-TS is tagged as
// SMPTE-302M `bin_data`, which Premiere does not reliably import as audio.
//
// THIRD-ATTEMPT FIX — profile/pixel format. The previous attempt used
// `-profile:v high422 -pix_fmt yuv422p`, which produces an H.264 "High 4:2:2
// Intra" stream. ffmpeg/ffprobe/VLC decode that fine (which is why prior static
// checks passed), but Adobe Premiere's H.264 importer ONLY supports 8-bit 4:2:0
// (Baseline/Main/High); it silently refuses High 4:2:2 (Intra) — the exact
// "ffprobe opens it but Premiere won't import" symptom the user reported.
// Verified live on zampp2 against the deployed capture image:
// high422/yuv422p -> profile "High 4:2:2 Intra" (decodes in ffmpeg, rejected by Premiere)
// high /yuv420p -> profile "High" (decodes mid-write, Premiere-importable)
// 4:2:0 is the only chroma subsampling Premiere ingests for H.264; the
// 4:2:2 mezzanine path is the (non-growing) ProRes/DNxHR master, not this
// growing TS. `-g 1` still makes every frame an IDR so a partially-written file
// decodes to its last complete frame (edit-while-record).
const GROWING_VIDEO_ARGS = [
'-c:v', 'libx264', '-profile:v', 'high422', '-pix_fmt', 'yuv422p',
'-c:v', 'libx264', '-profile:v', 'high', '-pix_fmt', 'yuv420p',
'-preset', 'veryfast', '-g', '1',
];
const GROWING_EXT = 'ts';
@ -336,15 +350,24 @@ function buildEncodeArgs({
container, isNetwork, isProxy = false,
growing = false,
}) {
// ── Growing master: force MPEG-TS + H.264 all-intra, ignoring the configured
// MOV/ProRes container/codec. This is a format VLC and Premiere both open
// WHILE GROWING (no footer/moov to wait on — see GROWING_VIDEO_ARGS above).
// ── Growing master: MPEG-TS + H.264 all-intra. The CODEC and CONTAINER are
// necessarily fixed here (H.264-in-TS is the only all-intra format Premiere
// opens WHILE growing — no footer/moov to wait on; ProRes/DNxHR/PCM are not
// valid TS payloads), so the operator's codec/container selections cannot be
// honoured for a growing recorder. The operator's TARGET BITRATE, framerate,
// and audio-channel count CAN and now ARE honoured — previously the
// configured bitrate was dropped entirely, so "master recording settings
// don't do anything" was literally true for a growing recorder (it always
// encoded at libx264's default CRF regardless of the UI value).
// Audio is forced to AAC, a TS-native codec Premiere imports (PCM-in-TS is
// tagged as bin_data and not reliably importable as audio).
if (growing) {
const args = [];
if (isNetwork) args.push('-map', '0:v:0?', '-map', '0:a:0?');
args.push(...GROWING_VIDEO_ARGS);
// Honour the operator-configured target bitrate (e.g. "60M"). Without this
// libx264 falls back to its default CRF and the UI bitrate is ignored.
if (videoBitrate) args.push('-b:v', videoBitrate, '-maxrate', videoBitrate, '-bufsize', videoBitrate);
if (framerate && framerate !== 'native') args.push('-r', framerate);
args.push('-c:a', 'aac', '-b:a', '256k');
if (audioChannels) args.push('-ac', String(audioChannels));

View file

@ -506,6 +506,14 @@ function NewRecorderModal({ open, onClose }) {
Write the live master to the SMB share so editors can cut while it's still recording.
Requires the SMB share to be configured in Settings Storage.
</div>
{growingOn && (
<div style={{ fontSize: 11, color: 'var(--warn, #d9a441)', marginTop: 6 }}>
Growing-files mode records H.264 All-Intra (4:2:0) in MPEG-TS the only format
Premiere can import while it's still being written. The codec and container above
are overridden for this recorder (the target bitrate still applies). Turn growing
off to record your selected master codec/container.
</div>
)}
</div>
</div>